mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-12 08:36:00 +01:00
medical/security modsuit updates and modules (#69194)
tweaks the colors on the security modsuit to be lighter, i think i did that on the original pr but it got reverted due to merge conflicts makes the standard quick carry module have nitrile level carrying instead of latex level environmental bodybags are now always pressurized adds medical and security hardlight bags, which are environmental bags you can use to move people through space, security ones can be sinched to prevent escape adds a medical version of the prisoner capture module, for patient transport, prisoner capture and patient transport now use the medical/security holobags, medical one deploying them faster. when you move too far out of range the holobag dissipates adds a defibrillator module, extends shock paddles adds a thread ripper module, this module temporarily rips away the matter of clothing, to allow stuff like injections, surgery, defibrillation etc through it adds a surgery processor module, essentially a portable surgery computer like borgs have fixes a bug where you can unwield defibrillator paddles just after starting the do_after to defib onehanded fixes a bug where the modsuit gps would have a broken name when renamed
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
icon_state = "kinesis"
|
||||
module_type = MODULE_ACTIVE
|
||||
complexity = 3
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN*3
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 3
|
||||
incompatible_modules = list(/obj/item/mod/module/anomaly_locked/kinesis)
|
||||
cooldown_time = 0.5 SECONDS
|
||||
overlay_state_inactive = "module_kinesis"
|
||||
|
||||
@@ -297,7 +297,7 @@
|
||||
icon_state = "power_kick"
|
||||
module_type = MODULE_ACTIVE
|
||||
removable = FALSE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN*5
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
|
||||
incompatible_modules = list(/obj/item/mod/module/power_kick)
|
||||
cooldown_time = 5 SECONDS
|
||||
/// Damage on kick.
|
||||
|
||||
@@ -71,10 +71,10 @@
|
||||
incompatible_modules = list(/obj/item/mod/module/quick_carry, /obj/item/mod/module/constructor)
|
||||
|
||||
/obj/item/mod/module/quick_carry/on_suit_activation()
|
||||
ADD_TRAIT(mod.wearer, TRAIT_QUICK_CARRY, MOD_TRAIT)
|
||||
ADD_TRAIT(mod.wearer, TRAIT_QUICKER_CARRY, MOD_TRAIT)
|
||||
|
||||
/obj/item/mod/module/quick_carry/on_suit_deactivation(deleting = FALSE)
|
||||
REMOVE_TRAIT(mod.wearer, TRAIT_QUICK_CARRY, MOD_TRAIT)
|
||||
REMOVE_TRAIT(mod.wearer, TRAIT_QUICKER_CARRY, MOD_TRAIT)
|
||||
|
||||
/obj/item/mod/module/quick_carry/advanced
|
||||
name = "MOD advanced quick carry module"
|
||||
@@ -82,11 +82,11 @@
|
||||
complexity = 0
|
||||
|
||||
/obj/item/mod/module/quick_carry/on_suit_activation()
|
||||
ADD_TRAIT(mod.wearer, TRAIT_QUICKER_CARRY, MOD_TRAIT)
|
||||
. = ..()
|
||||
ADD_TRAIT(mod.wearer, TRAIT_FASTMED, MOD_TRAIT)
|
||||
|
||||
/obj/item/mod/module/quick_carry/on_suit_deactivation(deleting = FALSE)
|
||||
REMOVE_TRAIT(mod.wearer, TRAIT_QUICKER_CARRY, MOD_TRAIT)
|
||||
. = ..()
|
||||
REMOVE_TRAIT(mod.wearer, TRAIT_FASTMED, MOD_TRAIT)
|
||||
|
||||
///Injector - Gives the suit an extendable large-capacity piercing syringe.
|
||||
@@ -212,3 +212,143 @@
|
||||
else
|
||||
organ.forceMove(drop_location())
|
||||
organ = null
|
||||
|
||||
///Patrient Transport - Generates hardlight bags you can put people in.
|
||||
/obj/item/mod/module/criminalcapture/patienttransport
|
||||
name = "MOD patient transport module"
|
||||
desc = "A module built into the forearm of the suit. Countless waves of mostly-lost mining teams being sent to \
|
||||
Indecipheries and other hazardous locations have taught the DeForest Medical Company many lessons. \
|
||||
Physical bodybags are difficult to store, hard to deploy, and even worse to keep intact in tough scenarios. \
|
||||
Enter the hardlight transport bag. Summonable with merely a gesture, weightless, and immunized against \
|
||||
any extreme scenario the wearer could think of, this bag is perfectly designed for \
|
||||
transport of any body in any environment, any time."
|
||||
icon_state = "patient_transport"
|
||||
bodybag_type = /obj/structure/closet/body_bag/environmental/hardlight
|
||||
capture_time = 1.5 SECONDS
|
||||
packup_time = 0.5 SECONDS
|
||||
|
||||
///Defibrillator - Gives the suit an extendable pair of shock paddles.
|
||||
/obj/item/mod/module/defibrillator
|
||||
name = "MOD defibrillator module"
|
||||
desc = "A module built into the gauntlets of the suit; commonly known as the 'Healing Hands' by medical professionals. \
|
||||
The user places their palms above the patient. Onboard computers in the suit calculate the necessary voltage, \
|
||||
and a modded targeting computer determines the best position for the user to push. \
|
||||
Twenty five pounds of force are applied to the patient's skin. Shocks travel from the suit's gloves \
|
||||
and counter-shock the heart, and the wearer returns to Medical a hero. Don't you even think about using it as a weapon; \
|
||||
regulations on manufacture and software locks expressly forbid it."
|
||||
icon_state = "defibrillator"
|
||||
module_type = MODULE_ACTIVE
|
||||
complexity = 2
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 25
|
||||
device = /obj/item/shockpaddles/mod
|
||||
incompatible_modules = list(/obj/item/mod/module/defibrillator)
|
||||
cooldown_time = 0.5 SECONDS
|
||||
var/defib_cooldown = 5 SECONDS
|
||||
|
||||
/obj/item/mod/module/defibrillator/Initialize(mapload)
|
||||
. = ..()
|
||||
RegisterSignal(device, COMSIG_DEFIBRILLATOR_SUCCESS, .proc/on_defib_success)
|
||||
|
||||
/obj/item/mod/module/defibrillator/proc/on_defib_success(obj/item/shockpaddles/source)
|
||||
drain_power(use_power_cost)
|
||||
source.recharge(defib_cooldown)
|
||||
return COMPONENT_DEFIB_STOP
|
||||
|
||||
/obj/item/shockpaddles/mod
|
||||
name = "MOD defibrillator paddles"
|
||||
req_defib = FALSE
|
||||
|
||||
///Thread Ripper - Temporarily rips apart clothing to make it not cover the body.
|
||||
/obj/item/mod/module/thread_ripper
|
||||
name = "MOD thread ripper module"
|
||||
desc = "A custom-built module integrated with the suit's wrist. The thread ripper is built from \
|
||||
recent technology dating back to the start of 2562, after an attempt by a well-known Nanotrasen researcher to \
|
||||
expand on the rapid-tailoring technology found in Autodrobes. Rather than being capable of creating \
|
||||
any fabric pattern under the suns, the thread ripper is capable of rapid disassembly of them. \
|
||||
Anything from kevlar-weave, to leather, to durathread can be quickly pulled open to the wearer's specification \
|
||||
and sewn back together, a development commonly utilized by Medical workers to obtain easy access for \
|
||||
surgery, defibrillation, or injection of chemicals to ease patients into not worrying about their \
|
||||
brand-name fashion being marred."
|
||||
icon_state = "thread_ripper"
|
||||
module_type = MODULE_ACTIVE
|
||||
complexity = 2
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN
|
||||
incompatible_modules = list(/obj/item/mod/module/thread_ripper)
|
||||
cooldown_time = 1.5 SECONDS
|
||||
overlay_state_inactive = "module_threadripper"
|
||||
/// An associated list of ripped clothing and the body part covering slots they covered before
|
||||
var/list/ripped_clothing = list()
|
||||
|
||||
/obj/item/mod/module/thread_ripper/on_select_use(atom/target)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!mod.wearer.Adjacent(target) || !iscarbon(target) || target == mod.wearer)
|
||||
balloon_alert(mod.wearer, "invalid target!")
|
||||
return
|
||||
var/mob/living/carbon/carbon_target = target
|
||||
if(length(ripped_clothing))
|
||||
balloon_alert(mod.wearer, "already ripped!")
|
||||
return
|
||||
balloon_alert(mod.wearer, "ripping clothing...")
|
||||
playsound(src, 'sound/items/zip.ogg', 25, TRUE, frequency = -1)
|
||||
if(!do_after(mod.wearer, 1.5 SECONDS, target = carbon_target))
|
||||
balloon_alert(mod.wearer, "interrupted!")
|
||||
return
|
||||
var/target_zones = body_zone2cover_flags(mod.wearer.zone_selected)
|
||||
for(var/obj/item/clothing as anything in carbon_target.get_all_worn_items())
|
||||
if(!clothing)
|
||||
continue
|
||||
var/shared_flags = target_zones & clothing.body_parts_covered
|
||||
if(shared_flags)
|
||||
ripped_clothing[clothing] = shared_flags
|
||||
clothing.body_parts_covered &= ~shared_flags
|
||||
|
||||
/obj/item/mod/module/thread_ripper/on_process(delta_time)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!length(ripped_clothing))
|
||||
return
|
||||
var/zipped = FALSE
|
||||
for(var/obj/item/clothing as anything in ripped_clothing)
|
||||
if(QDELETED(clothing))
|
||||
ripped_clothing -= clothing
|
||||
continue
|
||||
var/mob/living/carbon/clothing_wearer = clothing.loc
|
||||
if(istype(clothing_wearer) && mod.wearer.Adjacent(clothing_wearer) && !clothing_wearer.is_holding(clothing))
|
||||
continue
|
||||
zipped = TRUE
|
||||
clothing.body_parts_covered |= ripped_clothing[clothing]
|
||||
ripped_clothing -= clothing
|
||||
if(zipped)
|
||||
playsound(src, 'sound/items/zip.ogg', 25, TRUE)
|
||||
balloon_alert(mod.wearer, "clothing mended")
|
||||
|
||||
/obj/item/mod/module/thread_ripper/on_suit_deactivation(deleting)
|
||||
if(!length(ripped_clothing))
|
||||
return
|
||||
for(var/obj/item/clothing as anything in ripped_clothing)
|
||||
if(QDELETED(clothing))
|
||||
ripped_clothing -= clothing
|
||||
continue
|
||||
clothing.body_parts_covered |= ripped_clothing[clothing]
|
||||
ripped_clothing = list()
|
||||
if(!deleting)
|
||||
playsound(src, 'sound/items/zip.ogg', 25, TRUE)
|
||||
|
||||
///Surgical Processor - Lets you do advanced surgeries portably.
|
||||
/obj/item/mod/module/surgical_processor
|
||||
name = "MOD surgical processor module"
|
||||
desc = "A module using an onboard surgical computer which can be connected to other computers to download and \
|
||||
perform advanced surgeries on the go."
|
||||
icon_state = "surgical_processor"
|
||||
module_type = MODULE_ACTIVE
|
||||
complexity = 2
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN
|
||||
device = /obj/item/surgical_processor/mod
|
||||
incompatible_modules = list(/obj/item/mod/module/surgical_processor)
|
||||
cooldown_time = 0.5 SECONDS
|
||||
|
||||
/obj/item/surgical_processor/mod
|
||||
name = "MOD surgical processor"
|
||||
|
||||
@@ -176,34 +176,40 @@
|
||||
speech_args[SPEECH_SPANS] |= voicespan
|
||||
drain_power(use_power_cost)
|
||||
|
||||
///Criminal Capture - Lets you put people in transport bags.
|
||||
///Criminal Capture - Generates hardlight bags you can put people in and sinch.
|
||||
/obj/item/mod/module/criminalcapture
|
||||
name = "MOD criminal capture module"
|
||||
desc = "The private security that had orders to take in people dead were quite \
|
||||
happy with their space-proofed suit, but for those who wanted to bring back \
|
||||
whomever their targets were still breathing needed a way to \"share\" the \
|
||||
space-proofing. And thus: criminal capture! Creates a prisoner transport bag \
|
||||
around the apprehended that has breathable atmos and even stabilizes critical \
|
||||
conditions."
|
||||
icon_state = "criminalcapture"
|
||||
space-proofing. And thus: criminal capture! Creates a hardlight prisoner transport bag \
|
||||
around the apprehended that has breathable atmospheric conditions."
|
||||
icon_state = "criminal_capture"
|
||||
module_type = MODULE_ACTIVE
|
||||
complexity = 2
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
|
||||
incompatible_modules = list(/obj/item/mod/module/criminalcapture)
|
||||
cooldown_time = 0.5 SECONDS
|
||||
/// Max bag capacity.
|
||||
var/max_capacity = 3
|
||||
/// Time to capture a prisoner.
|
||||
var/capture_time = 1 SECONDS
|
||||
/// Time to pack a bodybag up.
|
||||
var/packup_time = 0.5 SECONDS
|
||||
/// List of our capture bags.
|
||||
var/list/criminal_capture_bags = list()
|
||||
var/capture_time = 2.5 SECONDS
|
||||
/// Time to dematerialize a bodybag.
|
||||
var/packup_time = 1 SECONDS
|
||||
/// Typepath of our bodybag
|
||||
var/bodybag_type = /obj/structure/closet/body_bag/environmental/prisoner/hardlight
|
||||
/// Our linked bodybag.
|
||||
var/obj/structure/closet/body_bag/linked_bodybag
|
||||
|
||||
/obj/item/mod/module/criminalcapture/Initialize(mapload)
|
||||
/obj/item/mod/module/criminalcapture/on_process(delta_time)
|
||||
idle_power_cost = linked_bodybag ? (DEFAULT_CHARGE_DRAIN * 3) : 0
|
||||
return ..()
|
||||
|
||||
/obj/item/mod/module/criminalcapture/on_deactivation(display_message, deleting)
|
||||
. = ..()
|
||||
for(var/i in 1 to max_capacity)
|
||||
criminal_capture_bags += new /obj/structure/closet/body_bag/environmental/prisoner/pressurized(src)
|
||||
if(!.)
|
||||
return
|
||||
if(!linked_bodybag)
|
||||
return
|
||||
packup()
|
||||
|
||||
/obj/item/mod/module/criminalcapture/on_select_use(atom/target)
|
||||
. = ..()
|
||||
@@ -211,42 +217,51 @@
|
||||
return
|
||||
if(!mod.wearer.Adjacent(target))
|
||||
return
|
||||
if(isliving(target))
|
||||
var/mob/living/living_target = target
|
||||
var/turf/target_turf = get_turf(living_target)
|
||||
playsound(src, 'sound/items/zip.ogg', 25, TRUE)
|
||||
if(!do_after(mod.wearer, capture_time, target = living_target))
|
||||
if(target == linked_bodybag)
|
||||
playsound(src, 'sound/machines/ding.ogg', 25, TRUE)
|
||||
if(!do_after(mod.wearer, packup_time, target = target))
|
||||
balloon_alert(mod.wearer, "interrupted!")
|
||||
return
|
||||
var/obj/structure/closet/body_bag/environmental/prisoner/dropped_bag = pop(criminal_capture_bags)
|
||||
dropped_bag.forceMove(target_turf)
|
||||
dropped_bag.close()
|
||||
living_target.forceMove(dropped_bag)
|
||||
else if(istype(target, /obj/structure/closet/body_bag/environmental/prisoner) || istype(target, /obj/item/bodybag/environmental/prisoner))
|
||||
var/obj/item/bodybag/environmental/prisoner/bag = target
|
||||
if(criminal_capture_bags.len >= max_capacity)
|
||||
balloon_alert(mod.wearer, "bag limit reached!")
|
||||
return
|
||||
playsound(src, 'sound/items/zip.ogg', 25, TRUE)
|
||||
if(!do_after(mod.wearer, packup_time, target = bag))
|
||||
balloon_alert(mod.wearer, "interrupted!")
|
||||
return
|
||||
if(criminal_capture_bags.len >= max_capacity)
|
||||
balloon_alert(mod.wearer, "bag limit reached!")
|
||||
return
|
||||
if(locate(/mob/living) in bag)
|
||||
balloon_alert(mod.wearer, "living creatures inside!")
|
||||
return
|
||||
if(istype(bag, /obj/item/bodybag/environmental/prisoner))
|
||||
bag = bag.deploy_bodybag(mod.wearer, get_turf(bag))
|
||||
var/obj/structure/closet/body_bag/environmental/prisoner/structure_bag = bag
|
||||
if(!structure_bag.opened)
|
||||
structure_bag.open(mod.wearer, force = TRUE)
|
||||
bag.forceMove(src)
|
||||
criminal_capture_bags += bag
|
||||
balloon_alert(mod.wearer, "bag stored")
|
||||
else
|
||||
balloon_alert(mod.wearer, "invalid target!")
|
||||
packup()
|
||||
return
|
||||
if(linked_bodybag)
|
||||
return
|
||||
var/turf/target_turf = get_turf(target)
|
||||
if(target_turf.is_blocked_turf(exclude_mobs = TRUE))
|
||||
return
|
||||
playsound(src, 'sound/machines/ding.ogg', 25, TRUE)
|
||||
if(!do_after(mod.wearer, capture_time, target = target))
|
||||
balloon_alert(mod.wearer, "interrupted!")
|
||||
return
|
||||
if(linked_bodybag)
|
||||
return
|
||||
linked_bodybag = new bodybag_type(target_turf)
|
||||
linked_bodybag.take_contents()
|
||||
playsound(linked_bodybag, 'sound/weapons/egloves.ogg', 80, TRUE)
|
||||
RegisterSignal(linked_bodybag, COMSIG_MOVABLE_MOVED, .proc/check_range)
|
||||
RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, .proc/check_range)
|
||||
|
||||
/obj/item/mod/module/criminalcapture/proc/packup()
|
||||
if(!linked_bodybag)
|
||||
return
|
||||
playsound(linked_bodybag, 'sound/weapons/egloves.ogg', 80, TRUE)
|
||||
apply_wibbly_filters(linked_bodybag)
|
||||
animate(linked_bodybag, 0.5 SECONDS, alpha = 50, flags = ANIMATION_PARALLEL)
|
||||
addtimer(CALLBACK(src, .proc/delete_bag, linked_bodybag), 0.5 SECONDS)
|
||||
linked_bodybag = null
|
||||
|
||||
/obj/item/mod/module/criminalcapture/proc/check_range()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(get_dist(mod.wearer, linked_bodybag) <= 9)
|
||||
return
|
||||
packup()
|
||||
|
||||
/obj/item/mod/module/criminalcapture/proc/delete_bag(obj/structure/closet/body_bag/bag)
|
||||
if(mod?.wearer)
|
||||
UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, .proc/check_range)
|
||||
balloon_alert(mod.wearer, "bag dissipated")
|
||||
bag.open(force = TRUE)
|
||||
qdel(bag)
|
||||
|
||||
///Mirage grenade dispenser - Dispenses grenades that copy the user's appearance.
|
||||
/obj/item/mod/module/dispenser/mirage
|
||||
@@ -342,7 +357,7 @@
|
||||
/obj/item/mod/module/active_sonar
|
||||
name = "MOD active sonar"
|
||||
desc = "Ancient tech from the 20th century, this module uses sonic waves to detect living creatures within the user's radius. \
|
||||
Its loud ping is much harder to hide in an indoor station than in the outdoor operations it was designed for."
|
||||
Its loud ping is much harder to hide in an indoor station than in the outdoor operations it was designed for."
|
||||
icon_state = "active_sonar"
|
||||
module_type = MODULE_USABLE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
|
||||
@@ -356,7 +371,7 @@
|
||||
return
|
||||
balloon_alert(mod.wearer, "readying sonar...")
|
||||
playsound(mod.wearer, 'sound/mecha/skyfall_power_up.ogg', vol = 20, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
if(!do_after(mod.wearer, 1.1 SECONDS))
|
||||
if(!do_after(mod.wearer, 1.1 SECONDS, target = mod))
|
||||
return
|
||||
var/creatures_detected = 0
|
||||
for(var/mob/living/creature in range(9, mod.wearer))
|
||||
|
||||
@@ -305,7 +305,7 @@
|
||||
icon_state = "magnet_loader"
|
||||
module_type = MODULE_ACTIVE
|
||||
removable = FALSE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN*3
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 3
|
||||
incompatible_modules = list(/obj/item/mod/module/magnet)
|
||||
cooldown_time = 1.5 SECONDS
|
||||
overlay_state_active = "module_magnet"
|
||||
@@ -472,8 +472,8 @@
|
||||
icon_state = "sphere"
|
||||
module_type = MODULE_ACTIVE
|
||||
removable = FALSE
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN*0.5
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN*3
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 3
|
||||
incompatible_modules = list(/obj/item/mod/module/sphere_transform)
|
||||
cooldown_time = 1.25 SECONDS
|
||||
/// Time it takes us to complete the animation.
|
||||
|
||||
Reference in New Issue
Block a user