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<