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:
Fikou
2022-09-01 01:59:39 +02:00
committed by GitHub
parent d5ffb6ae68
commit e82f728b09
22 changed files with 430 additions and 190 deletions
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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.
+144 -4
View File
@@ -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"
+67 -52
View File
@@ -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))
+3 -3
View File
@@ -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.