[MIRROR] medical/security modsuit updates and modules [MDB IGNORE] (#15953)
* 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 * medical/security modsuit updates and modules Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com>
@@ -4,3 +4,11 @@
|
||||
/// From /datum/surgery_step/success(): (datum/surgery_step/step, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results)
|
||||
#define COMSIG_MOB_SURGERY_STEP_SUCCESS "mob_surgery_step_success"
|
||||
|
||||
/// From /obj/item/shockpaddles/proc/do_success(): (obj/item/shockpaddles/source)
|
||||
#define COMSIG_DEFIBRILLATOR_SUCCESS "defib_success"
|
||||
#define COMPONENT_DEFIB_STOP (1<<0)
|
||||
|
||||
/// From /datum/surgery/can_start(): (mob/source, datum/surgery/surgery, mob/living/patient)
|
||||
#define COMSIG_SURGERY_STARTING "surgery_starting"
|
||||
#define COMPONENT_CANCEL_SURGERY (1<<0)
|
||||
#define COMPONENT_FORCE_SURGERY (1<<1)
|
||||
|
||||
@@ -156,17 +156,17 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,
|
||||
/proc/body_zone2cover_flags(def_zone)
|
||||
switch(def_zone)
|
||||
if(BODY_ZONE_CHEST)
|
||||
return list(CHEST, GROIN)
|
||||
return CHEST|GROIN
|
||||
if(BODY_ZONE_HEAD)
|
||||
return list(HEAD)
|
||||
return HEAD
|
||||
if(BODY_ZONE_L_ARM)
|
||||
return list(ARM_LEFT, HAND_LEFT)
|
||||
return ARM_LEFT|HAND_LEFT
|
||||
if(BODY_ZONE_R_ARM)
|
||||
return list(ARM_RIGHT, HAND_RIGHT)
|
||||
return ARM_RIGHT|HAND_RIGHT
|
||||
if(BODY_ZONE_L_LEG)
|
||||
return list(LEG_LEFT, FOOT_LEFT)
|
||||
return LEG_LEFT|FOOT_LEFT
|
||||
if(BODY_ZONE_R_LEG)
|
||||
return list(LEG_RIGHT, FOOT_RIGHT)
|
||||
return LEG_RIGHT|FOOT_RIGHT
|
||||
|
||||
//Turns a Body_parts_covered bitfield into a list of organ/limb names.
|
||||
//(I challenge you to find a use for this) -I found a use for it!! | So did I!.
|
||||
|
||||
@@ -167,8 +167,8 @@ GLOBAL_LIST_EMPTY(GPS_list)
|
||||
|
||||
gpstag = a
|
||||
. = TRUE
|
||||
usr.log_message("renamed [parentasatom] to \"global positioning system ([gpstag])\".", LOG_GAME)
|
||||
parentasatom.name = "global positioning system ([gpstag])"
|
||||
usr.log_message("renamed [parentasatom] to \"[initial(parentasatom.name)] ([gpstag])\".", LOG_GAME)
|
||||
parentasatom.name = "[initial(parentasatom.name)] ([gpstag])"
|
||||
|
||||
if("power")
|
||||
toggletracking(usr)
|
||||
|
||||
@@ -44,13 +44,12 @@
|
||||
. = ..()
|
||||
paddles = new paddle_type(src)
|
||||
update_power()
|
||||
return
|
||||
RegisterSignal(paddles, COMSIG_DEFIBRILLATOR_SUCCESS, .proc/on_defib_success)
|
||||
|
||||
/obj/item/defibrillator/loaded/Initialize(mapload) //starts with hicap
|
||||
. = ..()
|
||||
cell = new(src)
|
||||
update_power()
|
||||
return
|
||||
|
||||
/obj/item/defibrillator/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -259,6 +258,12 @@
|
||||
paddles.update_appearance()
|
||||
update_power()
|
||||
|
||||
/obj/item/defibrillator/proc/on_defib_success(obj/item/shockpaddles/source)
|
||||
deductcharge(source.revivecost)
|
||||
source.cooldown = TRUE
|
||||
cooldowncheck()
|
||||
return COMPONENT_DEFIB_STOP
|
||||
|
||||
/obj/item/defibrillator/compact
|
||||
name = "compact defibrillator"
|
||||
desc = "A belt-equipped defibrillator that can be rapidly deployed."
|
||||
@@ -377,14 +382,16 @@
|
||||
visible_message(span_notice("[src] snap back into [defib]."))
|
||||
snap_back()
|
||||
|
||||
/obj/item/shockpaddles/proc/recharge(time)
|
||||
if(req_defib || !time)
|
||||
/obj/item/shockpaddles/proc/recharge(time = 0)
|
||||
if(req_defib)
|
||||
return
|
||||
cooldown = TRUE
|
||||
update_appearance()
|
||||
sleep(time)
|
||||
var/turf/T = get_turf(src)
|
||||
T.audible_message(span_notice("[src] beeps: Unit is recharged."))
|
||||
addtimer(CALLBACK(src, .proc/finish_recharge), time)
|
||||
|
||||
/obj/item/shockpaddles/proc/finish_recharge()
|
||||
var/turf/current_turf = get_turf(src)
|
||||
current_turf.audible_message(span_notice("[src] beeps: Unit is recharged."))
|
||||
playsound(src, 'sound/machines/defib_ready.ogg', 50, FALSE)
|
||||
cooldown = FALSE
|
||||
update_appearance()
|
||||
@@ -484,12 +491,9 @@
|
||||
busy = FALSE
|
||||
|
||||
update_appearance()
|
||||
if(req_defib)
|
||||
defib.deductcharge(revivecost)
|
||||
cooldown = TRUE
|
||||
defib.cooldowncheck()
|
||||
else
|
||||
recharge(recharge_time)
|
||||
if(SEND_SIGNAL(src, COMSIG_DEFIBRILLATOR_SUCCESS) & COMPONENT_DEFIB_STOP)
|
||||
return
|
||||
recharge(recharge_time)
|
||||
|
||||
/// Called whenever the paddles fail to shock something after a do_x proc
|
||||
/obj/item/shockpaddles/proc/do_cancel()
|
||||
@@ -528,7 +532,7 @@
|
||||
span_warning("You overcharge the paddles and begin to place them onto [H]'s chest..."))
|
||||
busy = TRUE
|
||||
update_appearance()
|
||||
if(do_after(user, 1.5 SECONDS, H))
|
||||
if(do_after(user, 1.5 SECONDS, H, extra_checks = CALLBACK(src, .proc/is_wielded)))
|
||||
user.visible_message(span_notice("[user] places [src] on [H]'s chest."),
|
||||
span_warning("You place [src] on [H]'s chest and begin to charge them."))
|
||||
var/turf/T = get_turf(defib)
|
||||
@@ -537,7 +541,7 @@
|
||||
T.audible_message(span_warning("\The [defib] lets out an urgent beep and lets out a steadily rising hum..."))
|
||||
else
|
||||
user.audible_message(span_warning("[src] let out an urgent beep."))
|
||||
if(do_after(user, 1.5 SECONDS, H)) //Takes longer due to overcharging
|
||||
if(do_after(user, 1.5 SECONDS, H, extra_checks = CALLBACK(src, .proc/is_wielded))) //Takes longer due to overcharging
|
||||
if(!H)
|
||||
do_cancel()
|
||||
return
|
||||
@@ -568,11 +572,11 @@
|
||||
user.visible_message(span_warning("[user] begins to place [src] on [H]'s chest."), span_warning("You begin to place [src] on [H]'s chest..."))
|
||||
busy = TRUE
|
||||
update_appearance()
|
||||
if(do_after(user, 3 SECONDS, H)) //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process
|
||||
if(do_after(user, 3 SECONDS, H, extra_checks = CALLBACK(src, .proc/is_wielded))) //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process
|
||||
user.visible_message(span_notice("[user] places [src] on [H]'s chest."), span_warning("You place [src] on [H]'s chest."))
|
||||
playsound(src, 'sound/machines/defib_charge.ogg', 75, FALSE)
|
||||
var/obj/item/organ/internal/heart = H.getorgan(/obj/item/organ/internal/heart)
|
||||
if(do_after(user, 2 SECONDS, H)) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
|
||||
if(do_after(user, 2 SECONDS, H, extra_checks = CALLBACK(src, .proc/is_wielded))) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
|
||||
if((!combat && !req_defib) || (req_defib && !defib.combat))
|
||||
for(var/obj/item/clothing/C in H.get_equipped_items())
|
||||
if((C.body_parts_covered & CHEST) && (C.clothing_flags & THICKMATERIAL)) //check to see if something is obscuring their chest.
|
||||
@@ -661,6 +665,9 @@
|
||||
playsound(src, 'sound/machines/defib_failed.ogg', 50, FALSE)
|
||||
do_cancel()
|
||||
|
||||
/obj/item/shockpaddles/proc/is_wielded()
|
||||
return HAS_TRAIT(src, TRAIT_WIELDED)
|
||||
|
||||
/obj/item/shockpaddles/cyborg
|
||||
name = "cyborg defibrillator paddles"
|
||||
icon = 'icons/obj/medical/defib.dmi'
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
if(tagged)
|
||||
. += "bodybag_label"
|
||||
|
||||
/obj/structure/closet/body_bag/close()
|
||||
/obj/structure/closet/body_bag/close(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
set_density(FALSE)
|
||||
@@ -182,12 +182,47 @@
|
||||
contents_pressure_protection = 0.8
|
||||
contents_thermal_insulation = 0.5
|
||||
foldedbag_path = /obj/item/bodybag/environmental
|
||||
/// The list of weathers we protect from.
|
||||
var/list/weather_protection = list(TRAIT_ASHSTORM_IMMUNE, TRAIT_RADSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE, TRAIT_VOIDSTORM_IMMUNE) // Does not protect against lava or the The Floor Is Lava spell.
|
||||
/// The contents of the gas to be distributed to an occupant. Set in Initialize()
|
||||
var/datum/gas_mixture/air_contents = null
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/Initialize(mapload)
|
||||
. = ..()
|
||||
for(var/trait in weather_protection)
|
||||
ADD_TRAIT(src, trait, ROUNDSTART_TRAIT)
|
||||
refresh_air()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/Destroy()
|
||||
if(air_contents)
|
||||
QDEL_NULL(air_contents)
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/return_air()
|
||||
refresh_air()
|
||||
return air_contents
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/remove_air(amount)
|
||||
refresh_air()
|
||||
return air_contents.remove(amount)
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/return_analyzable_air()
|
||||
refresh_air()
|
||||
return air_contents
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/togglelock(mob/living/user, silent)
|
||||
. = ..()
|
||||
for(var/mob/living/target in contents)
|
||||
to_chat(target, span_warning("You hear a faint hiss, and a white mist fills your vision..."))
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/proc/refresh_air()
|
||||
air_contents = null
|
||||
air_contents = new(50) //liters
|
||||
air_contents.temperature = T20C
|
||||
|
||||
air_contents.assert_gases(/datum/gas/oxygen, /datum/gas/nitrogen)
|
||||
air_contents.gases[/datum/gas/oxygen][MOLES] = (ONE_ATMOSPHERE*50)/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD
|
||||
air_contents.gases[/datum/gas/nitrogen][MOLES] = (ONE_ATMOSPHERE*50)/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/nanotrasen
|
||||
name = "elite environmental protection bag"
|
||||
@@ -227,19 +262,12 @@
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/can_open(mob/living/user, force = FALSE)
|
||||
if(force)
|
||||
return TRUE
|
||||
if(sinched)
|
||||
to_chat(user, span_danger("The buckles on [src] are sinched down, preventing it from opening."))
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/open(mob/living/user, force = FALSE)
|
||||
if(!can_open(user, force))
|
||||
return
|
||||
if(sinched && !force)
|
||||
to_chat(user, span_danger("The buckles on [src] are sinched down, preventing it from opening."))
|
||||
return TRUE
|
||||
if(opened)
|
||||
return
|
||||
return FALSE
|
||||
sinched = FALSE
|
||||
playsound(loc, open_sound, open_sound_volume, TRUE, -3)
|
||||
opened = TRUE
|
||||
@@ -316,55 +344,7 @@
|
||||
user.log_message("[sinched ? "sinched":"unsinched"] secure environmental bag [src]", LOG_GAME)
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized
|
||||
name = "pressurized prisoner transport bag"
|
||||
foldedbag_path = /obj/item/bodybag/environmental/prisoner/pressurized
|
||||
/// The contents of the gas to be distributed to an occupant once sinched down. Set in Initialize()
|
||||
var/datum/gas_mixture/air_contents = null
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized/Initialize(mapload)
|
||||
. = ..()
|
||||
refresh_air()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized/proc/refresh_air()
|
||||
air_contents = null
|
||||
air_contents = new(50) //liters
|
||||
air_contents.temperature = T20C
|
||||
|
||||
air_contents.assert_gases(/datum/gas/oxygen, /datum/gas/nitrogen)
|
||||
air_contents.gases[/datum/gas/oxygen][MOLES] = (ONE_ATMOSPHERE*50)/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD
|
||||
air_contents.gases[/datum/gas/nitrogen][MOLES] = (ONE_ATMOSPHERE*50)/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized/Destroy()
|
||||
if(air_contents)
|
||||
QDEL_NULL(air_contents)
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized/return_air()
|
||||
if(sinched)
|
||||
refresh_air()
|
||||
return air_contents
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized/remove_air(amount)
|
||||
if(sinched)
|
||||
refresh_air()
|
||||
return air_contents.remove(amount) // The internals for this bag are bottomless.
|
||||
return ..(amount)
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized/return_analyzable_air()
|
||||
if(sinched)
|
||||
refresh_air()
|
||||
return air_contents
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized/togglelock(mob/living/user, silent)
|
||||
. = ..()
|
||||
if(sinched)
|
||||
for(var/mob/living/target in contents)
|
||||
to_chat(target, span_warning("You hear a faint hiss, and a white mist fills your vision..."))
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/pressurized/syndicate
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/syndicate
|
||||
name = "syndicate prisoner transport bag"
|
||||
desc = "An alteration of Nanotrasen's environmental protection bag which has been used in several high-profile kidnappings. Designed to keep a victim unconscious, alive, and secured during transport."
|
||||
icon = 'icons/obj/bodybag.dmi'
|
||||
@@ -384,3 +364,27 @@
|
||||
air_contents.assert_gases(/datum/gas/oxygen, /datum/gas/nitrous_oxide)
|
||||
air_contents.gases[/datum/gas/oxygen][MOLES] = (ONE_ATMOSPHERE*50)/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD
|
||||
air_contents.gases[/datum/gas/nitrous_oxide][MOLES] = (ONE_ATMOSPHERE*50)/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/hardlight
|
||||
name = "hardlight bodybag"
|
||||
desc = "A hardlight bag for storing bodies. Resistant to space."
|
||||
icon_state = "holobag_med"
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
foldedbag_path = null
|
||||
weather_protection = list(TRAIT_VOIDSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE)
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/hardlight/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
if(damage_type in list(BRUTE, BURN))
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 80, TRUE)
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/hardlight
|
||||
name = "hardlight prisoner bodybag"
|
||||
desc = "A hardlight bag for storing bodies. Resistant to space, can be sinched to prevent escape."
|
||||
icon_state = "holobag_sec"
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
foldedbag_path = null
|
||||
weather_protection = list(TRAIT_VOIDSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE)
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/hardlight/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
if(damage_type in list(BRUTE, BURN))
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 80, TRUE)
|
||||
|
||||
@@ -206,8 +206,7 @@
|
||||
RegisterSignal(C, COMSIG_MOVABLE_MOVED, .proc/bristle, override = TRUE)
|
||||
|
||||
zones_disabled++
|
||||
for(var/i in body_zone2cover_flags(def_zone))
|
||||
body_parts_covered &= ~i
|
||||
body_parts_covered &= ~body_zone2cover_flags(def_zone)
|
||||
|
||||
if(body_parts_covered == NONE) // if there are no more parts to break then the whole thing is kaput
|
||||
atom_destruction((damage_type == BRUTE ? MELEE : LASER)) // melee/laser is good enough since this only procs from direct attacks anyway and not from fire/bombs
|
||||
|
||||
@@ -323,8 +323,7 @@
|
||||
return adjusted
|
||||
for(var/zone in list(BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) // ugly check to make sure we don't reenable protection on a disabled part
|
||||
if(damage_by_parts[zone] > limb_integrity)
|
||||
for(var/part in body_zone2cover_flags(zone))
|
||||
body_parts_covered &= part
|
||||
body_parts_covered &= body_zone2cover_flags(zone)
|
||||
return adjusted
|
||||
|
||||
/obj/item/clothing/under/rank
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
suit_store = /obj/item/tank/internals/oxygen
|
||||
back = /obj/item/mod/control/pre_equipped/rescue
|
||||
suit = null
|
||||
head = null
|
||||
uniform = /obj/item/clothing/under/rank/medical/chief_medical_officer
|
||||
mask = /obj/item/clothing/mask/breath/medical
|
||||
r_pocket = /obj/item/flashlight/pen/paramedic
|
||||
internals_slot = ITEM_SLOT_SUITSTORE
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
suit_store = /obj/item/tank/internals/oxygen
|
||||
back = /obj/item/mod/control/pre_equipped/medical
|
||||
suit = null
|
||||
head = null
|
||||
uniform = /obj/item/clothing/under/rank/medical/doctor
|
||||
mask = /obj/item/clothing/mask/breath/medical
|
||||
r_pocket = /obj/item/flashlight/pen
|
||||
internals_slot = ITEM_SLOT_SUITSTORE
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -311,7 +311,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"
|
||||
@@ -478,8 +478,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.
|
||||
|
||||
@@ -1360,6 +1360,55 @@
|
||||
build_path = /obj/item/mod/module/holster
|
||||
department_type = MODULE_SECURITY
|
||||
|
||||
/datum/design/module/mod_sonar
|
||||
name = "MOD Module: Active Sonar"
|
||||
id = "mod_sonar"
|
||||
materials = list(/datum/material/titanium = 250, /datum/material/glass = 1000, /datum/material/gold = 500, /datum/material/uranium = 250)
|
||||
build_path = /obj/item/mod/module/active_sonar
|
||||
department_type = MODULE_SECURITY
|
||||
|
||||
/datum/design/module/projectile_dampener
|
||||
name = "MOD Module: Projectile Dampener"
|
||||
id = "mod_projectile_dampener"
|
||||
materials = list(/datum/material/iron = 1000, /datum/material/bluespace = 500)
|
||||
build_path = /obj/item/mod/module/projectile_dampener
|
||||
department_type = MODULE_SECURITY
|
||||
|
||||
/datum/design/module/surgicalprocessor
|
||||
name = "MOD Module: Surgical Processor"
|
||||
id = "mod_surgicalprocessor"
|
||||
materials = list(/datum/material/titanium = 250, /datum/material/glass = 1000, /datum/material/silver = 1500)
|
||||
build_path = /obj/item/mod/module/surgical_processor
|
||||
department_type = MODULE_MEDICAL
|
||||
|
||||
/datum/design/module/threadripper
|
||||
name = "MOD Module: Thread Ripper"
|
||||
id = "mod_threadripper"
|
||||
materials = list(/datum/material/titanium = 250, /datum/material/plastic = 1000, /datum/material/silver = 1500)
|
||||
build_path = /obj/item/mod/module/thread_ripper
|
||||
department_type = MODULE_MEDICAL
|
||||
|
||||
/datum/design/module/defibrillator
|
||||
name = "MOD Module: Defibrillator"
|
||||
id = "mod_defib"
|
||||
materials = list(/datum/material/titanium = 250, /datum/material/diamond = 1000, /datum/material/silver = 1500)
|
||||
build_path = /obj/item/mod/module/defibrillator
|
||||
department_type = MODULE_MEDICAL
|
||||
|
||||
/datum/design/module/patienttransport
|
||||
name = "MOD Module: Patient Transport"
|
||||
id = "mod_patienttransport"
|
||||
materials = list(/datum/material/iron = 1000, /datum/material/bluespace = 1000)
|
||||
build_path = /obj/item/mod/module/criminalcapture/patienttransport
|
||||
department_type = MODULE_MEDICAL
|
||||
|
||||
/datum/design/module/criminalcapture
|
||||
name = "MOD Module: Criminal Capture"
|
||||
id = "mod_criminalcapture"
|
||||
materials = list(/datum/material/iron = 1000, /datum/material/bluespace = 1000)
|
||||
build_path = /obj/item/mod/module/criminalcapture
|
||||
department_type = MODULE_SECURITY
|
||||
|
||||
//MODsuit bepis modules
|
||||
|
||||
/datum/design/module/disposal
|
||||
@@ -1391,17 +1440,3 @@
|
||||
materials = list(/datum/material/iron = 2500, /datum/material/glass = 2000, /datum/material/uranium = 1000, /datum/material/bluespace = 1000)
|
||||
build_path = /obj/item/mod/module/anomaly_locked/kinesis
|
||||
department_type = MODULE_ENGINEERING
|
||||
|
||||
/datum/design/module/mod_sonar
|
||||
name = "MOD Module: Active Sonar"
|
||||
id = "mod_sonar"
|
||||
materials = list(/datum/material/titanium = 250, /datum/material/glass = 1000, /datum/material/gold = 500, /datum/material/uranium = 250)
|
||||
build_path = /obj/item/mod/module/active_sonar
|
||||
department_type = MODULE_SECURITY
|
||||
|
||||
/datum/design/module/projectile_dampener
|
||||
name = "MOD Module: Projectile Dampener"
|
||||
id = "mod_projectile_dampener"
|
||||
materials = list(/datum/material/iron = 1000, /datum/material/bluespace = 500)
|
||||
build_path = /obj/item/mod/module/projectile_dampener
|
||||
department_type = MODULE_SECURITY
|
||||
|
||||
@@ -1653,9 +1653,22 @@
|
||||
"mod_injector",
|
||||
"mod_organ_thrower",
|
||||
"mod_dna_lock",
|
||||
"mod_patienttransport",
|
||||
)
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
|
||||
/datum/techweb_node/mod_advanced_medical
|
||||
id = "mod_advanced_medical"
|
||||
display_name = "Advanced Medical Modular Suits"
|
||||
description = "Advanced medical suits for quicker rescue purposes."
|
||||
prereq_ids = list("mod_medical", "adv_biotech")
|
||||
design_ids = list(
|
||||
"mod_defib",
|
||||
"mod_threadripper",
|
||||
"mod_surgicalprocessor",
|
||||
)
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500)
|
||||
|
||||
/datum/techweb_node/mod_security
|
||||
id = "mod_security"
|
||||
display_name = "Security Modular Suits"
|
||||
@@ -1670,6 +1683,7 @@
|
||||
"mod_holster",
|
||||
"mod_sonar",
|
||||
"mod_projectile_dampener",
|
||||
"mod_criminalcapture",
|
||||
)
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
|
||||
|
||||
@@ -70,14 +70,11 @@
|
||||
if(requires_tech)
|
||||
. = FALSE
|
||||
|
||||
if(iscyborg(user))
|
||||
var/mob/living/silicon/robot/robo_surgeon = user
|
||||
var/obj/item/surgical_processor/surgical_processor = locate() in robo_surgeon.model.modules
|
||||
if(surgical_processor) //no early return for !surgical_processor since we want to check optable should this not exist.
|
||||
if(replaced_by in surgical_processor.advanced_surgeries)
|
||||
return FALSE
|
||||
if(type in surgical_processor.advanced_surgeries)
|
||||
return TRUE
|
||||
var/surgery_signal = SEND_SIGNAL(user, COMSIG_SURGERY_STARTING, src, patient)
|
||||
if(surgery_signal & COMPONENT_FORCE_SURGERY)
|
||||
return TRUE
|
||||
if(surgery_signal & COMPONENT_CANCEL_SURGERY)
|
||||
return FALSE
|
||||
|
||||
var/turf/patient_turf = get_turf(patient)
|
||||
|
||||
|
||||
@@ -245,30 +245,48 @@
|
||||
|
||||
|
||||
/obj/item/surgical_processor //allows medical cyborgs to scan and initiate advanced surgeries
|
||||
name = "\improper Surgical Processor"
|
||||
name = "surgical processor"
|
||||
desc = "A device for scanning and initiating surgeries from a disk or operating computer."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "spectrometer"
|
||||
item_flags = NOBLUDGEON
|
||||
var/list/advanced_surgeries = list()
|
||||
var/list/loaded_surgeries = list()
|
||||
|
||||
/obj/item/surgical_processor/afterattack(obj/item/design_holder, mob/user, proximity)
|
||||
/obj/item/surgical_processor/equipped(mob/user, slot, initial)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
if(slot != ITEM_SLOT_HANDS)
|
||||
UnregisterSignal(user, COMSIG_SURGERY_STARTING)
|
||||
return
|
||||
if(istype(design_holder, /obj/item/disk/surgery))
|
||||
to_chat(user, span_notice("You load the surgery protocol from [design_holder] into [src]."))
|
||||
var/obj/item/disk/surgery/surgery_disk = design_holder
|
||||
if(do_after(user, 10, target = design_holder))
|
||||
advanced_surgeries |= surgery_disk.surgeries
|
||||
return TRUE
|
||||
if(istype(design_holder, /obj/machinery/computer/operating))
|
||||
to_chat(user, span_notice("You copy surgery protocols from [design_holder] into [src]."))
|
||||
var/obj/machinery/computer/operating/OC = design_holder
|
||||
if(do_after(user, 10, target = design_holder))
|
||||
advanced_surgeries |= OC.advanced_surgeries
|
||||
return TRUE
|
||||
return
|
||||
RegisterSignal(user, COMSIG_SURGERY_STARTING, .proc/check_surgery)
|
||||
|
||||
/obj/item/surgical_processor/dropped(mob/user, silent)
|
||||
. = ..()
|
||||
UnregisterSignal(user, COMSIG_SURGERY_STARTING)
|
||||
|
||||
/obj/item/surgical_processor/afterattack(atom/design_holder, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return ..()
|
||||
if(!istype(design_holder, /obj/item/disk/surgery) && !istype(design_holder, /obj/machinery/computer/operating))
|
||||
return ..()
|
||||
balloon_alert(user, "copying designs...")
|
||||
playsound(src, 'sound/machines/terminal_processing.ogg', 25, TRUE)
|
||||
if(do_after(user, 1 SECONDS, target = design_holder))
|
||||
if(istype(design_holder, /obj/item/disk/surgery))
|
||||
var/obj/item/disk/surgery/surgery_disk = design_holder
|
||||
loaded_surgeries |= surgery_disk.surgeries
|
||||
else
|
||||
var/obj/machinery/computer/operating/surgery_computer = design_holder
|
||||
loaded_surgeries |= surgery_computer.advanced_surgeries
|
||||
playsound(src, 'sound/machines/terminal_success.ogg', 25, TRUE)
|
||||
return TRUE
|
||||
|
||||
/obj/item/surgical_processor/proc/check_surgery(mob/user, datum/surgery/surgery, mob/patient)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(surgery.replaced_by in loaded_surgeries)
|
||||
return COMPONENT_CANCEL_SURGERY
|
||||
if(surgery.type in loaded_surgeries)
|
||||
return COMPONENT_FORCE_SURGERY
|
||||
|
||||
/obj/item/scalpel/advanced
|
||||
name = "laser scalpel"
|
||||
|
||||
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 49 KiB |