diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon.dmm index e6404b01774..2bd142d2879 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon.dmm @@ -3159,6 +3159,18 @@ }, /turf/open/floor/wood/large, /area/ruin/space/has_grav/port_tarkon/dorms) +"lu" = ( +/obj/effect/decal/cleanable/cobweb, +/obj/structure/rack, +/obj/item/mod/module/noslip, +/obj/item/soap/omega, +/obj/item/sharpener, +/obj/item/sharpener, +/obj/item/food/cake/lemon, +/obj/item/kitchen/rollingpin/illegal, +/obj/item/grenade/clusterbuster/cleaner, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav) "lw" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 5 @@ -6575,7 +6587,7 @@ /obj/effect/turf_decal/tile/yellow/half{ dir = 1 }, -/obj/effect/mob_spawn/ghost_role/human/tarkon, +/obj/effect/mob_spawn/ghost_role/human/tarkon/service, /turf/open/floor/iron, /area/ruin/space/has_grav/port_tarkon) "yj" = ( @@ -7912,6 +7924,10 @@ /obj/item/stock_parts/power_store/cell/super, /turf/open/floor/iron/white, /area/ruin/space/has_grav/port_tarkon/trauma) +"CP" = ( +/obj/machinery/door/puzzle/keycard/personal_service, +/turf/open/floor/iron/dark, +/area/ruin/space/has_grav) "CQ" = ( /obj/effect/turf_decal/tile/purple/anticorner{ dir = 1 @@ -22318,8 +22334,8 @@ za "} (67,1,1) = {" Vt -TD -Mv +lu +CP jY Mv wY @@ -22567,7 +22583,7 @@ Mv jY Dr Dr -nl +TD Vt za za diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 31eac429115..540cc6eebd1 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -275,6 +275,7 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list( //SKYRAT EDIT ADDITION START - SKYRAT HUD wanted_lvl = null + ammo_counter = null // SKYRAT EDIT ADDITION END - SKYRAT HUD QDEL_LIST_ASSOC_VAL(master_groups) diff --git a/code/modules/loadout/loadout_helpers.dm b/code/modules/loadout/loadout_helpers.dm index 03d83e4326a..2a1a709e06f 100644 --- a/code/modules/loadout/loadout_helpers.dm +++ b/code/modules/loadout/loadout_helpers.dm @@ -76,7 +76,7 @@ var/update = NONE for(var/datum/loadout_item/item as anything in loadout_datums) update |= item.on_equip_item( - equipped_item = locate(item.item_path) in new_contents, + equipped_item = loadout_placement_preference == LOADOUT_OVERRIDE_CASE ? locate(item.item_path) in travel_suitcase : locate(item.item_path) in new_contents, // BUBBER EDIT CHANGE - ORIGINAL: equipped_item = locate(item.item_path) in new_contents, preference_source = preference_source, preference_list = preference_list, equipper = src, diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 23c2516ecd3..986e19ca188 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -10,6 +10,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /mob/living/carbon/human/dummy/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_GODMODE, INNATE_TRAIT) + ADD_TRAIT(src, TRAIT_PREVENT_BLINKING, INNATE_TRAIT) /mob/living/carbon/human/dummy/Destroy() in_use = FALSE diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm index 3e96ccb30ed..ce189def69a 100644 --- a/code/modules/surgery/organs/internal/eyes/_eyes.dm +++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm @@ -461,6 +461,7 @@ /// Animates one eyelid at a time, thanks BYOND and thanks animation chains /obj/item/organ/eyes/proc/animate_eyelid(obj/effect/abstract/eyelid_effect/eyelid, mob/living/carbon/human/parent, sync_blinking = TRUE, list/anim_times = null) . = list() + var/prevent_loops = HAS_TRAIT(parent, TRAIT_PREVENT_BLINK_LOOPS) animate(eyelid, alpha = 0, time = 0, loop = (prevent_loops ? 0 : -1)) @@ -516,6 +517,8 @@ addtimer(CALLBACK(src, PROC_REF(animate_eyelids), owner), blink_delay + duration) /obj/item/organ/eyes/proc/animate_eyelids(mob/living/carbon/human/parent) + if(!CONFIG_GET(flag/blinking)) return // BUBBER EDIT - CONFIG BLINKING + var/sync_blinking = TRUE // synchronized_blinking && (parent.get_organ_loss(ORGAN_SLOT_BRAIN) < ASYNC_BLINKING_BRAIN_DAMAGE) // BUBBER EDIT - REMOVE ASYNC BLINKING UNTIL https://github.com/tgstation/tgstation/issues/90269 is fixed // Randomize order for unsynched animations if (sync_blinking || prob(50)) diff --git a/code/modules/tgui_panel/tgui_panel.dm b/code/modules/tgui_panel/tgui_panel.dm index 2d270ac72aa..24b1e865ffc 100644 --- a/code/modules/tgui_panel/tgui_panel.dm +++ b/code/modules/tgui_panel/tgui_panel.dm @@ -12,6 +12,8 @@ var/datum/tgui_window/window var/broken = FALSE var/initialized_at + /// Each client notifies on protected playback, so this prevents spamming admins. + var/static/admins_warned = FALSE /datum/tgui_panel/New(client/client, id) src.client = client @@ -86,9 +88,18 @@ ), )) return TRUE + if(type == "audio/setAdminMusicVolume") client.admin_music_volume = payload["volume"] return TRUE + + if(type == "audio/protected") + if(!admins_warned) + message_admins(span_notice("Audio returned a protected playback error, likely due to being copyrighted.")) + admins_warned = TRUE + addtimer(VARSET_CALLBACK(src, admins_warned, FALSE), 10 SECONDS) + return TRUE + if(type == "telemetry") analyze_telemetry(payload) return TRUE diff --git a/config/bubbers/bubbers_config.txt b/config/bubbers/bubbers_config.txt index 9626e2b805c..9ea0fa6133e 100644 --- a/config/bubbers/bubbers_config.txt +++ b/config/bubbers/bubbers_config.txt @@ -19,3 +19,6 @@ INTERN_THRESHOLD_COMMAND 20 ## Respawn grace period (deciseconds), which allows to return to the lobby some amount of time after the world loads - default 30 minutes RESPAWN_GRACE_PERIOD 18000 + +#If enabled, /human mobs will ocassionaly blink (somewhat expensive) +BLINKING diff --git a/html/changelogs/AutoChangeLog-bubber-pr-3618.yml b/html/changelogs/AutoChangeLog-bubber-pr-3618.yml new file mode 100644 index 00000000000..4df552e4c83 --- /dev/null +++ b/html/changelogs/AutoChangeLog-bubber-pr-3618.yml @@ -0,0 +1,4 @@ +author: "KazooBard" +delete-after: True +changes: + - qol: "unifies the two existing coco powder related reagents into one" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-bubber-pr-3668.yml b/html/changelogs/AutoChangeLog-bubber-pr-3668.yml deleted file mode 100644 index 89d2772d9f2..00000000000 --- a/html/changelogs/AutoChangeLog-bubber-pr-3668.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TealSeer" -delete-after: True -changes: - - bugfix: "fixed port tarkon bounty pad returning 0 for all sales" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-bubber-pr-3669.yml b/html/changelogs/AutoChangeLog-bubber-pr-3669.yml deleted file mode 100644 index 9ae89cc95ec..00000000000 --- a/html/changelogs/AutoChangeLog-bubber-pr-3669.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "TealSeer" -delete-after: True -changes: - - bugfix: "fixed the featherweight quirk doing nothing when you're picked up" - - bugfix: "fixed rider always layering above carrier when fireman carrying/piggybacking" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-bubber-pr-3688.yml b/html/changelogs/AutoChangeLog-bubber-pr-3688.yml new file mode 100644 index 00000000000..398f11762af --- /dev/null +++ b/html/changelogs/AutoChangeLog-bubber-pr-3688.yml @@ -0,0 +1,4 @@ +author: "MajManatee" +delete-after: True +changes: + - rscadd: "New job on tarkon, Generic Service Man" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-bubber-pr-3703.yml b/html/changelogs/AutoChangeLog-bubber-pr-3703.yml new file mode 100644 index 00000000000..229f525c85e --- /dev/null +++ b/html/changelogs/AutoChangeLog-bubber-pr-3703.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - config: "added config options for toggling blinking" \ No newline at end of file diff --git a/html/changelogs/bubber_archive/2025-04.yml b/html/changelogs/bubber_archive/2025-04.yml index 86ab0fabda8..6aa068a4ed1 100644 --- a/html/changelogs/bubber_archive/2025-04.yml +++ b/html/changelogs/bubber_archive/2025-04.yml @@ -312,7 +312,14 @@ up - bugfix: hairline and compound fractures are no longer instantly healed with bone gel, sorry! + - bugfix: fixed port tarkon bounty pad returning 0 for all sales + - bugfix: fixed the featherweight quirk doing nothing when you're picked up + - bugfix: fixed rider always layering above carrier when fireman carrying/piggybacking nevimer: - code_imp: moffson should work without needing an ai to be damaged now. thegrb93: - rscdel: Remove asynchronous blinking due to eyes getting stuck closed +2025-04-30: + TealSeer: + - bugfix: fixed loadout item customization breaking job equipment under certain + circumstances diff --git a/html/changelogs/bubber_archive/2025-05.yml b/html/changelogs/bubber_archive/2025-05.yml new file mode 100644 index 00000000000..90695000b5a --- /dev/null +++ b/html/changelogs/bubber_archive/2025-05.yml @@ -0,0 +1,38 @@ +2025-05-01: + TealSeer: + - config: the arrivals shuttle should automatically return to the interlink again + Vanilla1040: + - qol: Add Emergency Reboot button in strip menu for entombed people +2025-05-02: + Arturlang: + - bugfix: Fixes NV helmets, frenzy, echolocation quirk leaving screen colors permanently + on + - bugfix: fix nanites leaving bad moods stuck forever + TealSeer: + - bugfix: fixed changelings/paradox clones not copying victim hair gradients +2025-05-03: + KazooBard: + - balance: The Icarus Sunbeam weapons system melts all tiles in it's flame's reach + - balance: The Icarus Sunbeam weapons system husks direct hits and deals damage + in a wider range + SapphoQueer: + - rscadd: Added the IRS outfit back to the autodrobe + Shadow-Quill: + - bugfix: Percy no longer rusts away. + - rscadd: Table clocks are now a loadout item. +2025-05-04: + Arturlang: + - balance: Frenzied bloodsuckers cannot stealthfeed + - balance: Minimum feed timer is now 1 second + - balance: Handcuffs double the feed begin time, meaning it takes longer to start + drinking blood. + - balance: Frenzy now halves feed begin time, instead of setting it to 2 or below. + - balance: Trying to feed while handcuffed and grabbed will always make you feed + aggresively. + - bugfix: Fixes feed detailed description lying about the time it takes to start + feeding +2025-05-05: + LT3: + - bugfix: Everyone's chat log no longer bluescreens due to Admins' bad taste in + music. Their fatal attempts to make you listen to king gizzard the lizard + wizard will now fail silently diff --git a/modular_skyrat/master_files/code/_globalvars/configuration.dm b/modular_skyrat/master_files/code/_globalvars/configuration.dm index f2f60e22a42..3ee51edbb66 100644 --- a/modular_skyrat/master_files/code/_globalvars/configuration.dm +++ b/modular_skyrat/master_files/code/_globalvars/configuration.dm @@ -67,5 +67,7 @@ GLOBAL_VAR_INIT(looc_allowed, TRUE) /// Split the threat budget between roundstart and midrounds /datum/config_entry/flag/split_threat_budget -// How much time arrivals shuttle should stay at station after its engines recharged before returning to interlink. In deciseconds. 150 - 15 seconds. 0 - disables autoreturn +// How much time arrivals shuttle should stay at station after its engines recharged before returning to interlink, in deciseconds. 0 - disables autoreturn /datum/config_entry/number/arrivals_wait + default = 150 + min_val = 0 diff --git a/modular_skyrat/master_files/code/modules/clothing/suits/skinsuits.dm b/modular_skyrat/master_files/code/modules/clothing/suits/skinsuits.dm index 0b78049a650..404ba0c5d3b 100644 --- a/modular_skyrat/master_files/code/modules/clothing/suits/skinsuits.dm +++ b/modular_skyrat/master_files/code/modules/clothing/suits/skinsuits.dm @@ -25,8 +25,8 @@ AddComponent(/datum/component/wetsuit) /obj/item/clothing/under/skinsuit/Destroy() - . = ..() qdel(GetComponent(/datum/component/wetsuit)) + . = ..() /obj/item/clothing/head/helmet/space/skinsuit_helmet name = "\improper Stardress helm" @@ -44,8 +44,8 @@ AddComponent(/datum/component/wetsuit) /obj/item/clothing/head/helmet/space/skinsuit_helmet/Destroy() - . = ..() qdel(GetComponent(/datum/component/wetsuit)) + . = ..() /obj/item/clothing/suit/armor/riot/skinsuit_armor name = "\improper Shorebreaker plating" diff --git a/modular_skyrat/master_files/code/modules/clothing/under/akula_jobs.dm b/modular_skyrat/master_files/code/modules/clothing/under/akula_jobs.dm index c0a9768080f..3887c12167e 100644 --- a/modular_skyrat/master_files/code/modules/clothing/under/akula_jobs.dm +++ b/modular_skyrat/master_files/code/modules/clothing/under/akula_jobs.dm @@ -25,16 +25,16 @@ update_appearance() /obj/item/clothing/under/akula_wetsuit/Destroy() - . = ..() var/mob/user = loc if(!istype(user)) - return + return ..() if(tail_overlay) user.cut_overlay(tail_overlay) tail_overlay = null qdel(GetComponent(/datum/component/wetsuit)) + . = ..() /obj/item/clothing/under/akula_wetsuit/equipped(mob/user, slot) . = ..() @@ -183,15 +183,15 @@ update_appearance() /obj/item/clothing/head/helmet/space/akula_wetsuit/Destroy() - . = ..() var/mob/user = loc if(attached_hat) attached_hat.forceMove(drop_location()) if(!istype(user)) - return + return ..() qdel(GetComponent(/datum/component/wetsuit)) + . = ..() // Wearing hats inside the wetworks helmet /obj/item/clothing/head/helmet/space/akula_wetsuit/examine() diff --git a/modular_skyrat/master_files/code/modules/language/language_holder.dm b/modular_skyrat/master_files/code/modules/language/language_holder.dm index 815d47d7c83..7106f678a87 100644 --- a/modular_skyrat/master_files/code/modules/language/language_holder.dm +++ b/modular_skyrat/master_files/code/modules/language/language_holder.dm @@ -23,8 +23,8 @@ GLOBAL_DATUM_INIT(language_holder_adjustor, /datum/language_holder_adjustor, new language_holder.adjust_languages_to_prefs(new_crewmember.client?.prefs) /datum/language_holder_adjustor/Destroy() - ..() UnregisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED) + . = ..() /datum/language_holder/proc/adjust_languages_to_prefs(datum/preferences/preferences) // no prefs? then don't remove any languages diff --git a/modular_skyrat/modules/advanced_shuttles/code/shuttles.dm b/modular_skyrat/modules/advanced_shuttles/code/shuttles.dm index ebcbf017b3b..77fde6c19b5 100644 --- a/modular_skyrat/modules/advanced_shuttles/code/shuttles.dm +++ b/modular_skyrat/modules/advanced_shuttles/code/shuttles.dm @@ -16,7 +16,7 @@ ///Our shuttle's control console var/obj/machinery/computer/shuttle/arrivals/console - ///How much time are we waiting before returning to interlink. Sets itself automatically from config file + ///How much time are we waiting before returning to interlink. Sets itself automatically from config file. 0 = no auto return var/wait_time ///State variable. True when our shuttle is waiting before autoreturn var/waiting = FALSE // would've been better to use shuttle's mode variable, but check() resets it to SHUTTLE_IDLE so it's more sane way to make this fully modular diff --git a/modular_skyrat/modules/assault_operatives/code/sunbeam.dm b/modular_skyrat/modules/assault_operatives/code/sunbeam.dm index 3cd5c79e1e7..09dc4ab49f3 100644 --- a/modular_skyrat/modules/assault_operatives/code/sunbeam.dm +++ b/modular_skyrat/modules/assault_operatives/code/sunbeam.dm @@ -90,6 +90,10 @@ for(var/turf/open/turf_to_incinerate in circle_range(src, obliteration_range_fire)) turf_to_incinerate.hotspot_expose(5500) new /obj/effect/hotspot(turf_to_incinerate) + turf_to_incinerate.Melt() + for(var/mob/living/mob_to_husk in circle_range(src, obliteration_range_fire)) + mob_to_husk.apply_damage(300, BURN) + mob_to_husk.throw_at(pick(orange(15)), spin = TRUE, diagonals_first = FALSE, force = MOVE_FORCE_STRONG, gentle = FALSE, quickstart = TRUE) if(obliteration_range_flatten) for(var/atom/atom_to_obliterate in circle_range(src, obliteration_range_flatten)) @@ -109,7 +113,8 @@ if(isliving(atom_to_obliterate)) var/mob/living/mob_to_obliterate = atom_to_obliterate - mob_to_obliterate.apply_damage(200, BURN) + mob_to_obliterate.apply_damage(300, BURN) + mob_to_obliterate.add_traits(TRAIT_HUSK, BURN) continue COOLDOWN_START(src, oblirerate_cooldown, obliteration_cooldown) diff --git a/modular_skyrat/modules/borgs/code/robot_items.dm b/modular_skyrat/modules/borgs/code/robot_items.dm index afd3362fb10..df70a29c2b9 100644 --- a/modular_skyrat/modules/borgs/code/robot_items.dm +++ b/modular_skyrat/modules/borgs/code/robot_items.dm @@ -734,7 +734,7 @@ return if(listeningTo) UnregisterSignal(listeningTo, signalCache) - RegisterSignal(user, signalCache, PROC_REF(disrupt)) + RegisterSignals(user, signalCache, PROC_REF(disrupt)) listeningTo = user /obj/item/borg_shapeshifter/proc/deactivate(mob/living/silicon/robot/user) diff --git a/modular_skyrat/modules/colony_fabricator/code/appliances/chem_machines.dm b/modular_skyrat/modules/colony_fabricator/code/appliances/chem_machines.dm index 4addf92cf02..39ebb0a7da5 100644 --- a/modular_skyrat/modules/colony_fabricator/code/appliances/chem_machines.dm +++ b/modular_skyrat/modules/colony_fabricator/code/appliances/chem_machines.dm @@ -101,7 +101,7 @@ /datum/reagent/consumable/powdered_milk, /datum/reagent/consumable/sugar, /datum/reagent/consumable/powdered_lemonade, - /datum/reagent/consumable/powdered_coco, + /datum/reagent/consumable/coco, /datum/reagent/consumable/powdered_coffee, /datum/reagent/consumable/powdered_tea, /datum/reagent/consumable/vanilla, diff --git a/modular_skyrat/modules/colony_fabricator/code/machines/ore_silo.dm b/modular_skyrat/modules/colony_fabricator/code/machines/ore_silo.dm index 6f71fb37498..1d92d7ff861 100644 --- a/modular_skyrat/modules/colony_fabricator/code/machines/ore_silo.dm +++ b/modular_skyrat/modules/colony_fabricator/code/machines/ore_silo.dm @@ -7,10 +7,13 @@ /// What this packs into var/packed_type = /obj/item/flatpacked_machine/ore_silo +/obj/machinery/ore_silo/colony_lathe/Initialize(mapload) + . = ..() + AddElement(/datum/element/repackable, packed_type, 10 SECONDS) + /obj/machinery/ore_silo/colony_lathe/silo_log(obj/machinery/machinery_in_question, action, amount, noun, list/mats) . = ..() playsound(src, 'sound/machines/beep/beep.ogg', 30, TRUE) - AddElement(/datum/element/repackable, packed_type, 10 SECONDS) /obj/machinery/ore_silo/colony_lathe/default_deconstruction_crowbar() return diff --git a/modular_skyrat/modules/customization/datums/dna.dm b/modular_skyrat/modules/customization/datums/dna.dm index 8882b93ebd6..7a1e5afc96d 100644 --- a/modular_skyrat/modules/customization/datums/dna.dm +++ b/modular_skyrat/modules/customization/datums/dna.dm @@ -12,6 +12,8 @@ GLOBAL_LIST_INIT(identity_block_lengths, list( "[DNA_FACIAL_HAIR_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR, "[DNA_EYE_COLOR_LEFT_BLOCK]" = DNA_BLOCK_SIZE_COLOR, "[DNA_EYE_COLOR_RIGHT_BLOCK]" = DNA_BLOCK_SIZE_COLOR, + "[DNA_HAIR_COLOR_GRADIENT_BLOCK]" = DNA_BLOCK_SIZE_COLOR, + "[DNA_FACIAL_HAIR_COLOR_GRADIENT_BLOCK]" = DNA_BLOCK_SIZE_COLOR, )) /** @@ -199,6 +201,8 @@ GLOBAL_LIST_EMPTY(total_uf_len_by_block) eye_color_right = sanitize_hexcolor(get_uni_identity_block(structure, DNA_EYE_COLOR_RIGHT_BLOCK)) set_haircolor(sanitize_hexcolor(get_uni_identity_block(structure, DNA_HAIR_COLOR_BLOCK)), update = FALSE) set_facial_haircolor(sanitize_hexcolor(get_uni_identity_block(structure, DNA_FACIAL_HAIR_COLOR_BLOCK)), update = FALSE) + set_hair_gradient_color(sanitize_hexcolor(get_uni_identity_block(structure, DNA_HAIR_COLOR_GRADIENT_BLOCK)), update = FALSE) + set_facial_hair_gradient_color(sanitize_hexcolor(get_uni_identity_block(structure, DNA_FACIAL_HAIR_COLOR_GRADIENT_BLOCK)), update = FALSE) if(eyeorgancolor_update) add_eye_color_left(eye_color_left, EYE_COLOR_ORGAN_PRIORITY, update_body = FALSE) @@ -208,13 +212,17 @@ GLOBAL_LIST_EMPTY(total_uf_len_by_block) set_facial_hairstyle("Shaved", update = FALSE) else var/style = SSaccessories.facial_hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), SSaccessories.facial_hairstyles_list.len)] + var/gradient_style = SSaccessories.facial_hair_gradients_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_GRADIENT_BLOCK), length(SSaccessories.facial_hair_gradients_list))] set_facial_hairstyle(style, update = FALSE) + set_facial_hair_gradient_style(gradient_style, update = FALSE) if(HAS_TRAIT(src, TRAIT_BALD)) set_hairstyle("Bald", update = FALSE) else var/style = SSaccessories.hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_BLOCK), SSaccessories.hairstyles_list.len)] + var/gradient_style = SSaccessories.hair_gradients_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_GRADIENT_BLOCK), length(SSaccessories.hair_gradients_list))] set_hairstyle(style, update = FALSE) + set_hair_gradient_style(gradient_style, update = FALSE) var/features = dna.unique_features if(dna.features["mcolor"]) diff --git a/modular_skyrat/modules/customization/modules/surgery/organs/taur_body.dm b/modular_skyrat/modules/customization/modules/surgery/organs/taur_body.dm index 0fcc65ae1e2..0bac46b8627 100644 --- a/modular_skyrat/modules/customization/modules/surgery/organs/taur_body.dm +++ b/modular_skyrat/modules/customization/modules/surgery/organs/taur_body.dm @@ -16,9 +16,9 @@ var/right_leg_name = "back legs" /// The mob's old right leg. Used if the person switches to this organ and then back, so they don't just, have no legs anymore. Can be null. - var/obj/item/bodypart/leg/right/old_right_leg = null + var/old_right_leg = null /// The mob's old left leg. Used if the person switches to this organ and then back, so they don't just, have no legs anymore. Can be null. - var/obj/item/bodypart/leg/right/old_left_leg = null + var/old_left_leg = null /// If true, our sprite accessory will not render. var/hide_self @@ -109,8 +109,8 @@ if(sprite_accessory_flags & SPRITE_ACCESSORY_HIDE_SHOES) external_bodyshapes |= BODYSHAPE_HIDE_SHOES - old_right_leg = receiver.get_bodypart(BODY_ZONE_R_LEG) - old_left_leg = receiver.get_bodypart(BODY_ZONE_L_LEG) + var/obj/item/bodypart/leg/right/current_right_leg = receiver.get_bodypart(BODY_ZONE_R_LEG) + var/obj/item/bodypart/leg/left/current_left_leg = receiver.get_bodypart(BODY_ZONE_L_LEG) var/obj/item/bodypart/leg/left/taur/new_left_leg var/obj/item/bodypart/leg/right/taur/new_right_leg @@ -131,58 +131,45 @@ new_left_leg.bodyshape |= external_bodyshapes new_left_leg.replace_limb(receiver, TRUE) - if(old_left_leg) - old_left_leg.forceMove(src) + if(current_left_leg) + old_left_leg = current_left_leg.type + qdel(current_left_leg) new_left_leg.bodytype |= BODYTYPE_TAUR new_right_leg.bodyshape |= external_bodyshapes new_right_leg.replace_limb(receiver, TRUE) - if(old_right_leg) - old_right_leg.forceMove(src) + if(current_right_leg) + old_right_leg = current_right_leg.type + qdel(current_right_leg) new_right_leg.bodytype |= BODYTYPE_TAUR return ..() /obj/item/organ/taur_body/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags) - if(QDELETED(owner)) - return ..() - var/obj/item/bodypart/leg/left/left_leg = organ_owner.get_bodypart(BODY_ZONE_L_LEG) var/obj/item/bodypart/leg/right/right_leg = organ_owner.get_bodypart(BODY_ZONE_R_LEG) if(left_leg) left_leg.drop_limb() - - if(left_leg) - qdel(left_leg) + qdel(left_leg) if(right_leg) right_leg.drop_limb() - - if(right_leg) - qdel(right_leg) + qdel(right_leg) if(old_left_leg) - old_left_leg.replace_limb(organ_owner, TRUE) - old_left_leg = null + var/obj/item/bodypart/leg/left/new_left_leg = new old_left_leg() + new_left_leg.replace_limb(organ_owner, TRUE) if(old_right_leg) - old_right_leg.replace_limb(organ_owner, TRUE) - old_right_leg = null + var/obj/item/bodypart/leg/right/new_right_leg = new old_right_leg() + new_right_leg.replace_limb(organ_owner, TRUE) // We don't call `synchronize_bodytypes()` here, because it's already going to get called in the parent because `external_bodyshapes` has a value. return ..() -/obj/item/organ/taur_body/Destroy() - . = ..() - if(old_left_leg) - QDEL_NULL(old_left_leg) - - if(old_right_leg) - QDEL_NULL(old_right_leg) - /obj/item/organ/taur_body/proc/get_riding_offset(oversized = FALSE) var/size_scaling = (owner.dna.features["body_size"] / BODY_SIZE_NORMAL) - 1 var/scaling_mult = 1 + (size_scaling * riding_offset_scaling_mult) diff --git a/modular_skyrat/modules/exp_corps/code/clothing.dm b/modular_skyrat/modules/exp_corps/code/clothing.dm index a5b57e04cfd..f1a0196d199 100644 --- a/modular_skyrat/modules/exp_corps/code/clothing.dm +++ b/modular_skyrat/modules/exp_corps/code/clothing.dm @@ -229,7 +229,7 @@ if(my_eyes) my_eyes.color_cutoffs = list(10, 30, 10) my_eyes.flash_protect = FLASH_PROTECTION_SENSITIVE - current_user.add_client_colour(/datum/client_colour/glass_colour/lightgreen) + current_user.add_client_colour(/datum/client_colour/glass_colour/lightgreen, REF(src)) /obj/item/clothing/head/helmet/expeditionary_corps/proc/disable_nv() if(current_user) @@ -237,7 +237,7 @@ if(my_eyes) my_eyes.color_cutoffs = initial(my_eyes.color_cutoffs) my_eyes.flash_protect = initial(my_eyes.flash_protect) - current_user.remove_client_colour(/datum/client_colour/glass_colour/lightgreen) + current_user.remove_client_colour(REF(src)) current_user.update_sight() /obj/item/clothing/head/helmet/expeditionary_corps/click_alt(mob/user) diff --git a/modular_skyrat/modules/food_replicator/code/reagents.dm b/modular_skyrat/modules/food_replicator/code/reagents.dm index 2fb2e731404..f6cf80fb5cd 100644 --- a/modular_skyrat/modules/food_replicator/code/reagents.dm +++ b/modular_skyrat/modules/food_replicator/code/reagents.dm @@ -34,24 +34,6 @@ mix_message = "The mixture instantly heats up." reaction_flags = REACTION_INSTANT -/datum/reagent/consumable/powdered_coco - name = "Powdered Coco" - description = "Made with love (citation needed), and reclaimed biomass." - nutriment_factor = 0 - color = "#403010" - taste_description = "dry chocolate" - chemical_flags = REAGENT_CAN_BE_SYNTHESIZED - default_container = /obj/item/reagent_containers/cup/glass/mug/coco - -/datum/chemical_reaction/food/unpowdered_coco - required_reagents = list( - /datum/reagent/consumable/milk = 1, - /datum/reagent/consumable/powdered_coco = 1, - ) - results = list(/datum/reagent/consumable/hot_coco = 2) - mix_message = "The mixture instantly heats up." - reaction_flags = REACTION_INSTANT - /datum/reagent/consumable/powdered_lemonade name = "Powdered Lemonade" description = "Sweet, tangy base of a lemonade. Would be good if you'd mix it with water." diff --git a/modular_skyrat/modules/food_replicator/code/replicator_designs/replicator_food.dm b/modular_skyrat/modules/food_replicator/code/replicator_designs/replicator_food.dm index f16364159e7..164568734fe 100644 --- a/modular_skyrat/modules/food_replicator/code/replicator_designs/replicator_food.dm +++ b/modular_skyrat/modules/food_replicator/code/replicator_designs/replicator_food.dm @@ -111,10 +111,10 @@ /datum/design/cocoa name = "Powdered Hot Chocolate" - id = "slavic_coco" + id = "cocoa" build_type = BIOGENERATOR materials = list(/datum/material/biomass = 4) - make_reagent = /datum/reagent/consumable/powdered_coco + make_reagent = /datum/reagent/consumable/coco category = list( RND_CATEGORY_INITIAL, RND_CATEGORY_NRI_FOOD, diff --git a/modular_skyrat/modules/modular_items/code/modular_glasses.dm b/modular_skyrat/modules/modular_items/code/modular_glasses.dm index 9c7198bf440..4f37b1267c2 100644 --- a/modular_skyrat/modules/modular_items/code/modular_glasses.dm +++ b/modular_skyrat/modules/modular_items/code/modular_glasses.dm @@ -35,8 +35,8 @@ glasses_type = type /obj/item/clothing/glasses/hud/ar/Destroy() - . = ..() STOP_PROCESSING(SSobj, src) + . = ..() /obj/item/clothing/glasses/hud/ar/equipped(mob/living/carbon/human/user, slot) if(mode != MODE_OFF || slot != slot_flags) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/hypnogoggles.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/hypnogoggles.dm index 094bee37fc3..da17f505de3 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/hypnogoggles.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/hypnogoggles.dm @@ -40,12 +40,12 @@ victim = null /obj/item/clothing/glasses/hypno/Destroy() - . = ..() if(!victim) - return + return ..() if(!(victim.glasses == src)) - return + return ..() victim.cure_trauma_type(/datum/brain_trauma/very_special/induced_hypnosis, TRAUMA_RESILIENCE_MAGIC) + . = ..() /obj/item/clothing/glasses/hypno/attack_self(mob/user)//Setting up hypnotising phrase . = ..() diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/dancing_pole.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/dancing_pole.dm index f739d033934..6888dc63fa7 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/dancing_pole.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/dancing_pole.dm @@ -145,7 +145,6 @@ /obj/structure/stripper_pole/Destroy() - . = ..() if(dancer) dancer.SetStun(0) dancer.pixel_y = 0 @@ -154,6 +153,7 @@ dancer.layer = layer dancer.forceMove(get_turf(src)) dancer = null + . = ..() /obj/structure/stripper_pole/click_ctrl_shift(mob/user) add_fingerprint(user) diff --git a/modular_skyrat/modules/modular_vending/code/autodrobe.dm b/modular_skyrat/modules/modular_vending/code/autodrobe.dm index 237d1c32cc7..588e3a98f55 100644 --- a/modular_skyrat/modules/modular_vending/code/autodrobe.dm +++ b/modular_skyrat/modules/modular_vending/code/autodrobe.dm @@ -77,6 +77,8 @@ /obj/item/clothing/shoes/winterboots/christmas = 5, /obj/item/clothing/shoes/winterboots/christmas/green = 5, /obj/item/clothing/under/pants/tactical = 5, + /obj/item/clothing/head/costume/irs = 5, + /obj/item/clothing/suit/costume/irs = 5 ), ), ) diff --git a/modular_skyrat/modules/mutants/code/mutant_cure.dm b/modular_skyrat/modules/mutants/code/mutant_cure.dm index c873827a3ce..495ea4be62f 100644 --- a/modular_skyrat/modules/mutants/code/mutant_cure.dm +++ b/modular_skyrat/modules/mutants/code/mutant_cure.dm @@ -77,10 +77,10 @@ . += "It has an extracted RNA sample in it." /obj/item/rna_extractor/Destroy() - . = ..() if(loaded_vial) loaded_vial.forceMove(loc) loaded_vial = null + . = ..() /obj/item/rna_vial name = "raw RNA vial" diff --git a/modular_skyrat/modules/player_ranks/code/subsystem/player_ranks.dm b/modular_skyrat/modules/player_ranks/code/subsystem/player_ranks.dm index a9f29b56d3f..9204196538a 100644 --- a/modular_skyrat/modules/player_ranks/code/subsystem/player_ranks.dm +++ b/modular_skyrat/modules/player_ranks/code/subsystem/player_ranks.dm @@ -34,11 +34,10 @@ SUBSYSTEM_DEF(player_ranks) /datum/controller/subsystem/player_ranks/Destroy() - . = ..() - QDEL_NULL(donator_controller) QDEL_NULL(mentor_controller) QDEL_NULL(vetted_controller) + . = ..() /** * Returns whether or not the user is qualified as a donator. diff --git a/modular_skyrat/modules/quirks/echolocation/echolocation.dm b/modular_skyrat/modules/quirks/echolocation/echolocation.dm index 64aa4b9fd45..c296a38db6b 100644 --- a/modular_skyrat/modules/quirks/echolocation/echolocation.dm +++ b/modular_skyrat/modules/quirks/echolocation/echolocation.dm @@ -43,8 +43,8 @@ ) esp = human_holder.GetComponent(/datum/component/echolocation) - human_holder.remove_client_colour(/datum/client_colour/monochrome) - esp_color = human_holder.add_client_colour(/datum/client_colour/echolocation_custom) + human_holder.remove_client_colour(REF(src)) + esp_color = human_holder.add_client_colour(/datum/client_colour/echolocation_custom, REF(src)) esp_color.update_color(col) // add an action/spell to allow the player to toggle echolocation off for a bit (eyestrain on longer rounds, or just roleplay) @@ -57,7 +57,7 @@ QDEL_NULL(esp) // echolocation component removal handles graceful disposal of everything above QDEL_NULL(added_action) // remove the stall action, too var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.remove_client_colour(/datum/client_colour/echolocation_custom) // clean up the custom colour override we added + human_holder.remove_client_colour(REF(src)) // clean up the custom colour override we added UnregisterSignal(human_holder, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine_text)) /datum/quirk/echolocation/proc/on_examine_text(client/client_source, mob/user, list/examine_list) diff --git a/modular_skyrat/modules/stasisrework/code/stasissleeper.dm b/modular_skyrat/modules/stasisrework/code/stasissleeper.dm index fc852d7d81d..a7b833c14ef 100644 --- a/modular_skyrat/modules/stasisrework/code/stasissleeper.dm +++ b/modular_skyrat/modules/stasisrework/code/stasissleeper.dm @@ -15,9 +15,6 @@ payment_department = ACCOUNT_MED interaction_flags_click = ALLOW_SILICON_REACH -/obj/machinery/stasissleeper/Destroy() - . = ..() - /obj/machinery/stasissleeper/examine(mob/user) . = ..() . += span_notice("Alt-click to [state_open ? "close" : "open"] the machine.") diff --git a/modular_skyrat/modules/tarkon/code/misc-fluff/card.dm b/modular_skyrat/modules/tarkon/code/misc-fluff/card.dm index aa47c9787b4..76171d7cc60 100644 --- a/modular_skyrat/modules/tarkon/code/misc-fluff/card.dm +++ b/modular_skyrat/modules/tarkon/code/misc-fluff/card.dm @@ -40,6 +40,18 @@ desc = "An access card designated for \"security members\". Everyone wants your guns, partner. Yee-haw." trim = /datum/id_trim/away/tarkon/sec +/datum/id_trim/away/tarkon/service + assignment = "P-T Service Personnel" + access = list(ACCESS_AWAY_GENERAL, ACCESS_WEAPONS, ACCESS_TARKON) + department_color = COLOR_GREEN + department_state = "department" + sechud_icon_state = SECHUD_CHEF + trim_state = "trim_cook" + +/obj/item/card/id/advanced/tarkon/service + name = "P-T service techs access card" + desc = "An access card designated for \"the stations` support\". Cook, clean, and keep everyone on the crew happy." + trim = /datum/id_trim/away/tarkon/service /datum/id_trim/away/tarkon/med assignment = "P-T Trauma Medic" diff --git a/modular_skyrat/modules/tarkon/code/misc-fluff/port_tarkon_fluff.dm b/modular_skyrat/modules/tarkon/code/misc-fluff/port_tarkon_fluff.dm index e72ab792458..f08f10fc3fe 100644 --- a/modular_skyrat/modules/tarkon/code/misc-fluff/port_tarkon_fluff.dm +++ b/modular_skyrat/modules/tarkon/code/misc-fluff/port_tarkon_fluff.dm @@ -96,6 +96,12 @@ color = "#1b50d5" puzzle_id = "tarkon_vaultensign" +/obj/item/keycard/tarkon_job_service + name = "Personal keycard" + desc = "Tarkon industries secure storage lock key. This one has a label reading 'Service Secure Storage'" + color = "#1cac40" + puzzle_id = "tarkon_vaultservice" + // End job specific vault keys // JOB SPECIFIC VAULT DOORS @@ -133,4 +139,10 @@ name = "Personal Ensign Secure Airlock" desc = "Tarkon industries secure storage lock. This one has blue and red markings on it." puzzle_id = "tarkon_vaultensign" + +/obj/machinery/door/puzzle/keycard/personal_service + name = "Personal Service Secure Airlock" + desc = "Tarkon industries secure storage lock. This one has dark green markings on it." + puzzle_id = "tarkon_vaultservice" + // End job specific vault doors diff --git a/modular_skyrat/modules/tarkon/code/misc-fluff/spawner.dm b/modular_skyrat/modules/tarkon/code/misc-fluff/spawner.dm index e5521ae92a2..ec7208e8349 100644 --- a/modular_skyrat/modules/tarkon/code/misc-fluff/spawner.dm +++ b/modular_skyrat/modules/tarkon/code/misc-fluff/spawner.dm @@ -106,6 +106,22 @@ prompt_name = "a port researcher" outfit = /datum/outfit/tarkon/sci +/obj/effect/mob_spawn/ghost_role/human/tarkon/service + name = "Port Tarkon Service Crew Member" + prompt_name = "a port tarkon chef, and janitor" + outfit = /datum/outfit/tarkon/service + +/datum/outfit/tarkon/service + name = "Port Tarkon Service Outfit" + back = /obj/item/storage/backpack + id = /obj/item/card/id/advanced/tarkon/service + id_trim = /datum/id_trim/away/tarkon/service + backpack_contents = list( + /obj/item/storage/box/survival = 1, + /obj/item/keycard/tarkon_job_service, + /obj/item/crowbar = 1, + ) + skillchips = list(/obj/item/skillchip/chefs_kiss, /obj/item/skillchip/intj) /datum/outfit/tarkon/sci name = "Port Tarkon Science Outfit" diff --git a/modular_zubbers/code/_onclick/hud/screen_objects/hud_timer.dm b/modular_zubbers/code/_onclick/hud/screen_objects/hud_timer.dm index 91f9faaaadb..89729506b57 100644 --- a/modular_zubbers/code/_onclick/hud/screen_objects/hud_timer.dm +++ b/modular_zubbers/code/_onclick/hud/screen_objects/hud_timer.dm @@ -134,11 +134,11 @@ attach(source, FALSE) /atom/movable/screen/text/screen_timer/Destroy() - . = ..() if(length(timer_mobs)) remove_from(timer_mobs) STOP_PROCESSING(SSprocessing, src) + . = ..() /atom/movable/screen/text/screen_timer/attached maptext_x = 0 @@ -202,6 +202,6 @@ abstract_move(get_turf(tracked)) /atom/movable/screen/text/screen_timer/attached/Destroy() - . = ..() if(following_object) unregister_follower() + . = ..() diff --git a/modular_zubbers/code/controllers/configuration/entries/blinking.dm b/modular_zubbers/code/controllers/configuration/entries/blinking.dm new file mode 100644 index 00000000000..03e862e26ce --- /dev/null +++ b/modular_zubbers/code/controllers/configuration/entries/blinking.dm @@ -0,0 +1,15 @@ +/datum/config_entry/flag/blinking + default = TRUE + +// blinking won't update without re-running the animate +/datum/config_entry/flag/blinking/vv_edit_var(var_name, var_value) + . = ..() + if(var_name == NAMEOF(src, config_entry_value)) + INVOKE_ASYNC(src, PROC_REF(update_blinkers)) + + +/datum/config_entry/flag/blinking/proc/update_blinkers() + for(var/mob/living/carbon/human/blinker in GLOB.alive_mob_list) + var/obj/item/organ/eyes/eyes = blinker.get_organ_slot(ORGAN_SLOT_EYES) + eyes?.blink() + CHECK_TICK diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm index 5f6f2f26454..19b86646a9a 100644 --- a/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm +++ b/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm @@ -29,9 +29,10 @@ // This also helps for when the modsuit is out of power, as (to my awareness), there is no way currently to turn on someone else's entombed modsuit. return if (!modsuit || life_support_failed) - // we've got no modsuit or life support. take damage ow - human_holder.adjustToxLoss(ENTOMBED_TICK_DAMAGE * seconds_per_tick, updating_health = TRUE, forced = TRUE) - human_holder.set_jitter_if_lower(10 SECONDS) + if (!HAS_TRAIT(human_holder, TRAIT_STASIS)) + // we've got no modsuit or life support and we're not on stasis. take damage ow + human_holder.adjustToxLoss(ENTOMBED_TICK_DAMAGE * seconds_per_tick, updating_health = TRUE, forced = TRUE) + human_holder.set_jitter_if_lower(10 SECONDS) if (!modsuit.active) if (!life_support_timer) diff --git a/modular_zubbers/code/modules/antagonists/bloodsucker/powers/feed.dm b/modular_zubbers/code/modules/antagonists/bloodsucker/powers/feed.dm index 2fb642481ea..bbae8eceea0 100644 --- a/modular_zubbers/code/modules/antagonists/bloodsucker/powers/feed.dm +++ b/modular_zubbers/code/modules/antagonists/bloodsucker/powers/feed.dm @@ -1,5 +1,6 @@ #define FEED_NOTICE_RANGE 2 #define FEED_DEFAULT_TIMER (10 SECONDS) +#define FEED_MIN_TIMER (1 SECONDS) /datum/action/cooldown/bloodsucker/feed name = "Feed" @@ -29,30 +30,35 @@ var/warning_target_bloodvol = BLOOD_VOLUME_MAX_LETHAL ///Reference to the target we've fed off of var/datum/weakref/target_ref - ///Are we feeding with passive grab or not? - var/silent_feed = TRUE ///Have we notified you already that you are at maximum blood? var/notified_overfeeding = FALSE ///assoc list of weakrefs to targets and how much blood we've taken from them. var/list/targets_and_blood = list() + /// What level of protection you need to prevent feeding + var/penetration = INJECT_CHECK_PENETRATE_THICK + ///Did we start feeding with aggressive grab or not, or grabbed by someone else? + var/aggressive_feed = TRUE /datum/action/cooldown/bloodsucker/feed/get_power_explanation_extended() . = list() . += "Activate Feed while next to someone and you will begin to feed blood off of them." - . += "The time needed before you start feeding is [DisplayTimeText(FEED_DEFAULT_TIMER)]." + . += "The time needed before you start feeding is [DisplayTimeText(get_feed_start_time())]." . += "Feeding off of someone while you have them aggressively grabbed will put them to sleep for [DisplayTimeText(get_sleep_time())]." . += "While feeding, you can't speak, as you are using your mouth to drink blood." . += "Feeding while nearby ([FEED_NOTICE_RANGE] tiles away from) a mortal who is unaware of Bloodsuckers' existence, will cause a Masquerade Infraction" . += "If you get too many Masquerade Infractions, you will break the Masquerade." . += "If you are in desperate need of blood, mice can be fed off of, at a cost to your humanity." + . += "If you are handcuffed, you can use feed to feed off whoever is grabbing you, however this is slower, and very obvious." . += "You must use the ability again to stop sucking blood." /datum/action/cooldown/bloodsucker/feed/can_use(mob/living/carbon/user, trigger_flags) . = ..() if(!.) return FALSE - if(target_ref) //already sucking blood. - if(!ContinueActive(user, target_ref?.resolve(), !silent_feed, !silent_feed)) + var/mob/target = target_ref?.resolve() + if(target) //already sucking blood. + var/aggro_feed = check_aggro_feed(target) + if(!ContinueActive(user, target, aggro_feed)) target_ref = null else owner.balloon_alert(owner, "already feeding!") @@ -65,14 +71,12 @@ return FALSE return TRUE -/datum/action/cooldown/bloodsucker/feed/ContinueActive(mob/living/user, mob/living/target, check_grab, check_aggresive_grab) +/datum/action/cooldown/bloodsucker/feed/ContinueActive(mob/living/user, mob/living/target, check_aggresive_grab) if(!target) return FALSE if(!user.Adjacent(target)) return FALSE - if(check_grab && user.pulling != target) - return FALSE - if(check_aggresive_grab && user.grab_state < GRAB_AGGRESSIVE) + if(check_aggresive_grab && !check_aggro_feed(target)) return FALSE return TRUE @@ -107,7 +111,6 @@ // if this happens this means that we didn't properly deactivate the power if(HAS_TRAIT_FROM(owner, TRAIT_IMMOBILIZED, FEED_TRAIT) || HAS_TRAIT_FROM(owner, TRAIT_MUTE, FEED_TRAIT)) DeactivatePower() - silent_feed = TRUE var/mob/living/feed_target = target_ref?.resolve() if(!feed_target) DeactivatePower() @@ -122,17 +125,15 @@ feed_target.death() StartCooldown() return FALSE - var/feed_timer = get_feed_start_time() - if(bloodsuckerdatum_power.frenzied) - feed_timer = min(2 SECONDS, feed_timer) owner.balloon_alert(owner, "feeding off [feed_target]...") owner.face_atom(feed_target) - if(!do_after(owner, feed_timer, feed_target, hidden = TRUE)) + if(!do_after(owner, get_feed_start_time(), feed_target, hidden = TRUE)) owner.balloon_alert(owner, "feed stopped") target_ref = null return FALSE - if(owner.pulling == feed_target && owner.grab_state >= GRAB_AGGRESSIVE) + if(check_aggro_feed(feed_target)) + aggressive_feed = TRUE if(!IS_BLOODSUCKER(feed_target) && !IS_GHOUL(feed_target) && !IS_MONSTERHUNTER(feed_target)) feed_target.Unconscious(get_sleep_time()) if(!feed_target.density) @@ -140,16 +141,24 @@ owner.visible_message( span_warning("[owner] closes [owner.p_their()] mouth around [feed_target]'s neck!"), span_warning("You sink your fangs into [feed_target]'s neck.")) - silent_feed = FALSE //no more mr nice guy else + aggressive_feed = FALSE // Only people who AREN'T the target will notice this action. var/dead_message = feed_target.stat != DEAD ? " [feed_target.p_they(TRUE)] looks dazed, and will not remember this." : "" owner.visible_message( - span_warning("[owner] puts [feed_target]'s wrist up to [owner.p_their()] mouth."), \ - span_notice("You slip your fangs into [feed_target]'s wrist.[dead_message]"), \ - vision_distance = FEED_NOTICE_RANGE, ignored_mobs = feed_target) + span_warning("[owner] puts [feed_target]'s wrist up to [owner.p_their()] mouth."), + span_notice("You slip your fangs into [feed_target]'s wrist.[dead_message]"), + vision_distance = FEED_NOTICE_RANGE, ignored_mobs = feed_target + ) - //check if we were seen + check_if_seen(feed_target) + + ADD_TRAIT(owner, TRAIT_MUTE, FEED_TRAIT) + ADD_TRAIT(owner, TRAIT_IMMOBILIZED, FEED_TRAIT) + RegisterSignal(owner, COMSIG_MOB_CLIENT_PRE_LIVING_MOVE, PROC_REF(notify_move_block)) + return TRUE + +/datum/action/cooldown/bloodsucker/feed/proc/check_if_seen(mob/living/feed_target) for(var/mob/living/watchers in oviewers(FEED_NOTICE_RANGE) - feed_target) if(!watchers.client) continue @@ -165,11 +174,6 @@ bloodsuckerdatum_power.give_masquerade_infraction() break - ADD_TRAIT(owner, TRAIT_MUTE, FEED_TRAIT) - ADD_TRAIT(owner, TRAIT_IMMOBILIZED, FEED_TRAIT) - RegisterSignal(owner, COMSIG_MOB_CLIENT_PRE_LIVING_MOVE, PROC_REF(notify_move_block)) - return TRUE - /datum/action/cooldown/bloodsucker/feed/process(seconds_per_tick) if(!active) //If we aren't active (running on SSfastprocess) return ..() //Manage our cooldown timers @@ -178,11 +182,12 @@ if(!feed_target) DeactivatePower() return - if(!ContinueActive(user, feed_target, !silent_feed, !silent_feed)) - if(!silent_feed) + if(!ContinueActive(user, feed_target, aggressive_feed)) + if(aggressive_feed) user.visible_message( span_warning("[user] is ripped from [feed_target]'s throat. [feed_target.p_Their(TRUE)] blood sprays everywhere!"), - span_warning("Your teeth are ripped from [feed_target]'s throat. [feed_target.p_Their(TRUE)] blood sprays everywhere!")) + span_warning("Your teeth are ripped from [feed_target]'s throat. [feed_target.p_Their(TRUE)] blood sprays everywhere!") + ) // Deal Damage to Target (should have been more careful!) if(iscarbon(feed_target)) var/mob/living/carbon/carbon_target = feed_target @@ -201,18 +206,17 @@ DeactivatePower() return - var/feed_strength_mult = 0 - if(bloodsuckerdatum_power.frenzied) - feed_strength_mult = 2 - else if(owner.pulling == feed_target && owner.grab_state >= GRAB_AGGRESSIVE) + var/feed_strength_mult = 0.3 + if(aggressive_feed) feed_strength_mult = 1 - else - feed_strength_mult = 0.3 + if(bloodsuckerdatum_power.frenzied) + feed_strength_mult *= 2 + var/already_drunk = targets_and_blood[target_ref] || 0 var/blood_eaten = bloodsuckerdatum_power.handle_feeding(feed_target, feed_strength_mult, level_current, already_drunk) blood_taken += blood_eaten targets_and_blood[target_ref] += blood_eaten - decrement_blood_drunk(blood_eaten * 0.5) + modify_blood_drunk(blood_eaten * 0.5) if(feed_strength_mult > 5 && feed_target.stat < DEAD) user.add_mood_event("drankblood", /datum/mood_event/drankblood) @@ -229,9 +233,10 @@ owner.balloon_alert(owner, "your victim's blood is dangerously low.") else if(feed_target.blood_volume <= BLOOD_VOLUME_SAFE && warning_target_bloodvol > BLOOD_VOLUME_SAFE) owner.balloon_alert(owner, "your victim's blood is at an unsafe level.") - else if(feed_target.blood_volume <= BLOOD_VOLUME_SAFE && bloodsuckerdatum_power.GetBloodVolume() >= BLOOD_VOLUME_SAFE && owner.pulling != feed_target) + else if(feed_target.blood_volume <= BLOOD_VOLUME_SAFE && owner.pulling != feed_target) owner.balloon_alert(owner, "you cannot drink more without first getting a better grip!.") DeactivatePower() + return warning_target_bloodvol = feed_target.blood_volume if(bloodsuckerdatum_power.GetBloodVolume() >= bloodsuckerdatum_power.max_blood_volume && !notified_overfeeding) @@ -241,18 +246,31 @@ user.balloon_alert(owner, "no blood left!") DeactivatePower() return - owner.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE) + owner.playsound_local(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, TRUE) //play sound to target to show they're dying. - if(owner.pulling == feed_target && owner.grab_state >= GRAB_AGGRESSIVE) - feed_target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE) + if(aggressive_feed) + feed_target.playsound_local(get_turf(src), 'sound/effects/singlebeat.ogg', 40, TRUE) + +/datum/action/cooldown/bloodsucker/feed/proc/check_aggro_feed(mob/living/feed_target) + var/mob/living/carbon/carbon = owner + if(owner.pulling != feed_target && owner.pulledby != feed_target \ + || (feed_target.pulledby != owner && iscarbon(carbon) && carbon.handcuffed)) + return FALSE + return TRUE /datum/action/cooldown/bloodsucker/feed/proc/find_target() - if(owner.pulling && isliving(owner.pulling)) - if(!can_feed_from(owner.pulling, give_warnings = TRUE)) - return FALSE - set_target(owner.pulling) + // grabbing or grabbed, you're close enough to bite. + if(safe_set_target(owner.pulling)) return TRUE - + if(safe_set_target(owner.pulledby)) + return TRUE + if(bloodsuckerdatum_power.frenzied) + owner.balloon_alert(owner, "beast active! must grab someone to feed!") + return FALSE + var/mob/living/carbon/carbon = owner + if(iscarbon(carbon) && carbon.handcuffed) + owner.balloon_alert(owner, "you cannot stealthily feed while handcuffed!") + return FALSE var/list/close_living_mobs = list() var/list/close_dead_mobs = list() for(var/mob/living/near_targets in oview(1, owner)) @@ -275,6 +293,12 @@ //No one to suck blood from. return FALSE +/datum/action/cooldown/bloodsucker/feed/proc/safe_set_target(mob/living/target, give_warnings = TRUE) + if(!can_feed_from(target, give_warnings)) + return FALSE + set_target(target) + return TRUE + // this lets us compare and access things by weakrefs, if we use the actual same weakref instance in the assoc list /datum/action/cooldown/bloodsucker/feed/proc/set_target(mob/living/target) if(!length(targets_and_blood)) @@ -305,7 +329,7 @@ if(give_warnings) owner.balloon_alert(owner, "no blood!") return FALSE - if(!target_user.can_inject(owner, BODY_ZONE_HEAD, INJECT_CHECK_PENETRATE_THICK)) + if(!target_user.can_inject(owner, BODY_ZONE_HEAD, penetration)) if(give_warnings) owner.balloon_alert(owner, "suit too thick!") return FALSE @@ -323,7 +347,14 @@ return (5 + bloodsuckerdatum_power?.GetRank() || 1) SECONDS /datum/action/cooldown/bloodsucker/feed/proc/get_feed_start_time() - return clamp(round(FEED_DEFAULT_TIMER / (1.25 * (bloodsuckerdatum_power?.GetRank() || 1))), 1, FEED_DEFAULT_TIMER) + var/bloodsucker_level_divider = 1.25 * (bloodsuckerdatum_power?.GetRank() || 1) + var/feed_time = FEED_DEFAULT_TIMER / bloodsucker_level_divider + if(bloodsuckerdatum_power.frenzied) + feed_time *= 0.5 + var/mob/living/carbon/carbon = owner + if(iscarbon(carbon) && carbon.handcuffed) + feed_time *= 2 + return clamp(round(feed_time), FEED_MIN_TIMER, FEED_DEFAULT_TIMER) /datum/action/cooldown/bloodsucker/feed/proc/notify_move_block() SIGNAL_HANDLER @@ -335,7 +366,7 @@ COOLDOWN_START(src, feed_movement_notify_cooldown, 3 SECONDS) owner.balloon_alert(owner, "you cannot move while feeding! Click the power to stop.") -/datum/action/cooldown/bloodsucker/feed/proc/decrement_blood_drunk(amount = 0) +/datum/action/cooldown/bloodsucker/feed/proc/modify_blood_drunk(amount = 0) for(var/datum/weakref/weakref as anything in targets_and_blood) if(weakref == target_ref) continue @@ -345,3 +376,4 @@ #undef FEED_NOTICE_RANGE #undef FEED_DEFAULT_TIMER +#undef FEED_MIN_TIMER diff --git a/modular_zubbers/code/modules/client/client_color.dm b/modular_zubbers/code/modules/client/client_color.dm new file mode 100644 index 00000000000..416694035bd --- /dev/null +++ b/modular_zubbers/code/modules/client/client_color.dm @@ -0,0 +1,10 @@ + +/mob/add_client_colour(datum/client_colour/new_color, source, force = FALSE) + if(!source) + stack_trace("[src] tried to add a client colour with no source.") + . = ..() + +/mob/remove_client_colour(source) + if(ispath(source)) + stack_trace("[src] tried to remove a client colour with a path source.") + . = ..() diff --git a/modular_zubbers/code/modules/loadout/categories/pocket.dm b/modular_zubbers/code/modules/loadout/categories/pocket.dm index 470eb28b36d..3caf0b44153 100644 --- a/modular_zubbers/code/modules/loadout/categories/pocket.dm +++ b/modular_zubbers/code/modules/loadout/categories/pocket.dm @@ -70,6 +70,9 @@ name = "Pocket Watch" item_path = /obj/item/clothing/accessory/pocketwatch +/datum/loadout_item/pocket_items/table_clock + name = "Table Clock" + item_path = /obj/item/table_clock /datum/loadout_item/pocket_items/cigarettesleary name = "Mindbreaker Cigs" diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/suppression.dm b/modular_zubbers/code/modules/nanites/nanite_programs/suppression.dm index 7d539fc8a30..f8b01ba027f 100644 --- a/modular_zubbers/code/modules/nanites/nanite_programs/suppression.dm +++ b/modular_zubbers/code/modules/nanites/nanite_programs/suppression.dm @@ -256,38 +256,30 @@ else extra_settings.Remove(NES_HALLUCINATION_DETAIL) -/datum/nanite_program/good_mood +/datum/nanite_program/mood name = "Happiness Enhancer" desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness." use_rate = 0.1 rogue_types = list(/datum/nanite_program/brain_decay) + var/mood_event = /datum/mood_event/nanite_happiness + var/default_text = "HAPPINESS ENHANCEMENT" + var/mood_category = "nanite_happy" -/datum/nanite_program/good_mood/register_extra_settings() +/datum/nanite_program/mood/register_extra_settings() . = ..() - extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text("HAPPINESS ENHANCEMENT") + extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text(default_text) -/datum/nanite_program/good_mood/enable_passive_effect() +/datum/nanite_program/mood/enable_passive_effect() . = ..() - host_mob.add_mood_event("nanite_happy", /datum/mood_event/nanite_happiness, get_extra_setting_value(NES_MOOD_MESSAGE)) + host_mob.add_mood_event(mood_category, mood_event, get_extra_setting_value(NES_MOOD_MESSAGE)) -/datum/nanite_program/good_mood/disable_passive_effect() +/datum/nanite_program/mood/disable_passive_effect() . = ..() - host_mob.clear_mood_event("nanite_happy") + host_mob.clear_mood_event(mood_category) -/datum/nanite_program/bad_mood +/datum/nanite_program/mood/bad name = "Happiness Suppressor" desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression." - use_rate = 0.1 - rogue_types = list(/datum/nanite_program/brain_decay) - -/datum/nanite_program/bad_mood/register_extra_settings() - . = ..() - extra_settings[NES_MOOD_MESSAGE] = new /datum/nanite_extra_setting/text("HAPPINESS SUPPRESSION") - -/datum/nanite_program/bad_mood/enable_passive_effect() - . = ..() - host_mob.add_mood_event("nanite_unhappy", /datum/mood_event/nanite_sadness, get_extra_setting_value(NES_MOOD_MESSAGE)) - -/datum/nanite_program/bad_mood/disable_passive_effect() - . = ..() - host_mob.add_mood_event("nanite_unhappy") + mood_event = /datum/mood_event/nanite_sadness + default_text = "HAPPINESS SUPPRESSION" + mood_category = "nanite_unhappy" diff --git a/modular_zubbers/code/modules/nanites/nanite_programs/utility.dm b/modular_zubbers/code/modules/nanites/nanite_programs/utility.dm index 5b317979bf2..5c2fd152a23 100644 --- a/modular_zubbers/code/modules/nanites/nanite_programs/utility.dm +++ b/modular_zubbers/code/modules/nanites/nanite_programs/utility.dm @@ -226,10 +226,10 @@ var/decay_timer /datum/nanite_program/nanite_sting/Destroy() - . = ..() if(!decay_timer) - return + return ..() decay_sting() + . = ..() /datum/nanite_program/nanite_sting/on_trigger(comm_message) consume_nanites(-15) diff --git a/modular_zubbers/code/modules/nanites/program_designs.dm b/modular_zubbers/code/modules/nanites/program_designs.dm index 6dbfb469664..1dc20be7da3 100644 --- a/modular_zubbers/code/modules/nanites/program_designs.dm +++ b/modular_zubbers/code/modules/nanites/program_designs.dm @@ -451,14 +451,14 @@ name = "Happiness Enhancer" desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness." id = "good_mood_nanites" - program_type = /datum/nanite_program/good_mood + program_type = /datum/nanite_program/mood category = list("Suppression Nanites") /datum/design/nanites/bad_mood name = "Happiness Suppressor" desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression." id = "bad_mood_nanites" - program_type = /datum/nanite_program/bad_mood + program_type = /datum/nanite_program/mood/bad category = list("Suppression Nanites") ////////////////////SENSOR NANITES////////////////////////////////////// diff --git a/modular_zubbers/code/modules/ratqueen/regalrat.dm b/modular_zubbers/code/modules/ratqueen/regalrat.dm index 57a74975ed8..69609994f7e 100644 --- a/modular_zubbers/code/modules/ratqueen/regalrat.dm +++ b/modular_zubbers/code/modules/ratqueen/regalrat.dm @@ -32,9 +32,9 @@ current_look.apply(src) /mob/living/basic/regal_rat/Destroy() - . = ..() QDEL_NULL(fashion_select) QDEL_NULL(current_look) + . = ..() /// Regal rat swallows sludge to transform themselves into a different looking rat /datum/action/cooldown/rat_fashion diff --git a/modular_zubbers/code/modules/status_effects/buffs/frenzy.dm b/modular_zubbers/code/modules/status_effects/buffs/frenzy.dm index 1726752d560..0c4831d998d 100644 --- a/modular_zubbers/code/modules/status_effects/buffs/frenzy.dm +++ b/modular_zubbers/code/modules/status_effects/buffs/frenzy.dm @@ -48,7 +48,7 @@ was_tooluser = TRUE REMOVE_TRAIT(owner, TRAIT_ADVANCEDTOOLUSER, SPECIES_TRAIT) owner.add_movespeed_modifier(/datum/movespeed_modifier/frenzy_speedup) - owner.add_client_colour(/datum/client_colour/manual_heart_blood) + owner.add_client_colour(/datum/client_colour/manual_heart_blood, REF(src)) var/obj/cuffs = user.get_item_by_slot(ITEM_SLOT_HANDCUFFED) var/obj/legcuffs = user.get_item_by_slot(ITEM_SLOT_LEGCUFFED) if((user.handcuffed && cuffs) || (user.legcuffed && legcuffs)) @@ -64,7 +64,7 @@ ADD_TRAIT(owner, TRAIT_ADVANCEDTOOLUSER, SPECIES_TRAIT) was_tooluser = FALSE owner.remove_movespeed_modifier(/datum/movespeed_modifier/frenzy_speedup) - owner.remove_client_colour(/datum/client_colour/manual_heart_blood) + owner.remove_client_colour(REF(src)) SEND_SIGNAL(bloodsuckerdatum, COMSIG_BLOODSUCKER_EXITS_FRENZY) bloodsuckerdatum.frenzied = FALSE diff --git a/modular_zubbers/maps/offstation/persistence/area.dm b/modular_zubbers/maps/offstation/persistence/area.dm index 6dff743a124..fb8da5bc189 100644 --- a/modular_zubbers/maps/offstation/persistence/area.dm +++ b/modular_zubbers/maps/offstation/persistence/area.dm @@ -6,6 +6,7 @@ icon_state = "syndie-ship" outdoors = FALSE ignore_weather_sfx = TRUE + flags_1 = parent_type::flags_1 & ~(CAN_BE_DIRTY_1) // Stops SSDecay from affecting the Persistance // Cargo diff --git a/modular_zubbers/master_files/code/modules/entombed_quirk/code/entombed_alt_actions.dm b/modular_zubbers/master_files/code/modules/entombed_quirk/code/entombed_alt_actions.dm new file mode 100644 index 00000000000..24dffc324c1 --- /dev/null +++ b/modular_zubbers/master_files/code/modules/entombed_quirk/code/entombed_alt_actions.dm @@ -0,0 +1,28 @@ +// This code handles the strip menu minutae for re-enabling someone's deactivated entombed suit. + +/datum/strippable_item/mob_item_slot/back/get_alternate_actions(atom/source, mob/user) + . = ..() + var/obj/item/mod/control/pre_equipped/entombed/entombed_suit = get_item(source) + if (!istype(entombed_suit)) + return null + + if (!entombed_suit.active) + return list("entombed_emergency_reactivate") + +/datum/strippable_item/mob_item_slot/back/perform_alternate_action(atom/source, mob/user, action_key) + . = ..() + var/obj/item/mod/control/pre_equipped/entombed/entombed_suit = get_item(source) + if (!istype(entombed_suit)) + return null + + switch (action_key) + if ("entombed_emergency_reactivate") + if (!entombed_suit.active) + user.visible_message(span_info("[user] begins initiating emergency reactivation procedures on [entombed_suit]...")) + if (do_after(user, 3 SECONDS, entombed_suit.wearer)) + // deploy all our parts so activation actually works + for (var/obj/item/part as anything in entombed_suit.mod_parts) + entombed_suit.deploy(user, part) + entombed_suit.toggle_activate(user, TRUE) + else + user.balloon_alert(usr, "their suit is already online!") diff --git a/modular_zubbers/master_files/code/modules/entombed_quirk/code/entombed_mod.dm b/modular_zubbers/master_files/code/modules/entombed_quirk/code/entombed_mod.dm index 75f21179ac9..27572b2483f 100644 --- a/modular_zubbers/master_files/code/modules/entombed_quirk/code/entombed_mod.dm +++ b/modular_zubbers/master_files/code/modules/entombed_quirk/code/entombed_mod.dm @@ -39,6 +39,8 @@ /obj/item/mod/module/storage/large_capacity ) +// CUSTOM BEHAVIOR + /obj/item/mod/control/pre_equipped/entombed/canStrip(mob/who) return TRUE //you can always try, and it'll hit doStrip below @@ -82,3 +84,8 @@ /obj/item/mod/control/pre_equipped/entombed/Initialize(mapload, new_theme, new_skin, new_core) . = ..() ADD_TRAIT(src, TRAIT_NODROP, QUIRK_TRAIT) + +/obj/item/mod/control/pre_equipped/entombed/dropped(mob/user) + . = ..() + // we do this so that in the rare event that someone gets gibbed/destroyed, their suit can be retrieved easily w/o requiring admin intervention + REMOVE_TRAIT(src, TRAIT_NODROP, QUIRK_TRAIT) diff --git a/tgstation.dme b/tgstation.dme index 1948d1a8774..7ff023f8e33 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -8844,6 +8844,7 @@ #include "modular_zubbers\code\_globalvars\lists\~maintenance_loot.dm" #include "modular_zubbers\code\_onclick\hud\screen_objects\hud_timer.dm" #include "modular_zubbers\code\controllers\configuration\general.dm" +#include "modular_zubbers\code\controllers\configuration\entries\blinking.dm" #include "modular_zubbers\code\controllers\configuration\entries\nsfw.dm" #include "modular_zubbers\code\controllers\subsystem\air.dm" #include "modular_zubbers\code\controllers\subsystem\job.dm" @@ -9177,6 +9178,7 @@ #include "modular_zubbers\code\modules\changeling_zombies\reagent.dm" #include "modular_zubbers\code\modules\changeling_zombies\virus.dm" #include "modular_zubbers\code\modules\character_preview_background\character_preview_background.dm" +#include "modular_zubbers\code\modules\client\client_color.dm" #include "modular_zubbers\code\modules\client\examine_tgui.dm" #include "modular_zubbers\code\modules\client\preferences.dm" #include "modular_zubbers\code\modules\client\ssd.dm" @@ -9717,6 +9719,7 @@ #include "modular_zubbers\master_files\code\modules\client\preferences\hypnopref.dm" #include "modular_zubbers\master_files\code\modules\client\preferences\obscurity_examine.dm" #include "modular_zubbers\master_files\code\modules\client\preferences\scaling_method.dm" +#include "modular_zubbers\master_files\code\modules\entombed_quirk\code\entombed_alt_actions.dm" #include "modular_zubbers\master_files\code\modules\entombed_quirk\code\entombed_mod.dm" #include "modular_zubbers\master_files\code\modules\events\carp_migration.dm" #include "modular_zubbers\master_files\code\modules\events\gravity_generator_blackout.dm" diff --git a/tgui/packages/tgui-panel/audio/player.ts b/tgui/packages/tgui-panel/audio/player.ts index a916576c5b5..9f5f35987d2 100644 --- a/tgui/packages/tgui-panel/audio/player.ts +++ b/tgui/packages/tgui-panel/audio/player.ts @@ -14,6 +14,15 @@ type AudioOptions = { end?: number; }; +function isProtectedError(error: ErrorEvent): boolean { + return ( + typeof error === 'object' && + error !== null && + 'isTrusted' in error && + error.isTrusted + ); +} + export class AudioPlayer { element: HTMLAudioElement | null; options: AudioOptions; @@ -40,7 +49,13 @@ export class AudioPlayer { this.options = options; - const audio = (this.element = new Audio(url)); + const audio = new Audio(url); + if (!audio) { + logger.log('failed to create audio element'); + return; + } + this.element = audio; + audio.volume = this.volume; audio.playbackRate = this.options.pitch || 1; @@ -52,7 +67,11 @@ export class AudioPlayer { }); audio.addEventListener('error', (error) => { - logger.log('playback error', error); + if (isProtectedError(error)) { + Byond.sendMessage('audio/protected'); + } + logger.log('playback error:', JSON.stringify(error)); + this.stop(); }); if (this.options.end) { @@ -67,7 +86,10 @@ export class AudioPlayer { }); } - audio.play()?.catch((error) => logger.log('playback error', error)); + audio.play()?.catch(() => { + // no error is passed here, it's sent to the event listener + logger.log('playback failed'); + }); this.onPlaySubscribers.forEach((subscriber) => subscriber()); } @@ -78,7 +100,7 @@ export class AudioPlayer { logger.log('stopping'); this.element.pause(); - this.element = null; + this.destroy(); this.onStopSubscribers.forEach((subscriber) => subscriber()); } diff --git a/tgui/packages/tgui/interfaces/StripMenu.tsx b/tgui/packages/tgui/interfaces/StripMenu.tsx index 316febd0482..8e34bc90455 100644 --- a/tgui/packages/tgui/interfaces/StripMenu.tsx +++ b/tgui/packages/tgui/interfaces/StripMenu.tsx @@ -78,6 +78,11 @@ const ALTERNATE_ACTIONS: Record = { icon: 'microchip', text: 'Adjust sensors', }, + // BUBBER EDIT BEGIN - entombed quirk suit reactivation + entombed_emergency_reactivate: { + icon: 'power-off', + text: 'Emergency MODsuit reactivation', + }, // BUBBER EDIT END }; const SLOTS: Record<