From 78db44e96f43553713f4ca8c797c5b792b593ce2 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sun, 25 May 2014 21:50:43 +0930 Subject: [PATCH 1/2] Squashed hardsuit and suit cycler commits: Basic preliminary breach handling. Breached spacesuits act more sanely and now result in pressure loss. Preliminary work for upgrading hardsuits. Adds suit cycler. Working on breach data for hardsuits. More tweaks to the suit cycler. More rig changes/tweaks. --- baystation12.dme | 1 + code/game/machinery/suit_storage_unit.dm | 640 +++++++++++++++++- code/modules/clothing/spacesuits/breaches.dm | 221 ++++++ code/modules/clothing/spacesuits/rig.dm | 217 ++++++ .../mob/living/carbon/human/human_damage.dm | 2 + .../mob/living/carbon/human/human_defense.dm | 12 + code/modules/mob/living/carbon/human/life.dm | 18 +- 7 files changed, 1107 insertions(+), 4 deletions(-) create mode 100644 code/modules/clothing/spacesuits/breaches.dm diff --git a/baystation12.dme b/baystation12.dme index 187127d978f..fadec6c84cb 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -754,6 +754,7 @@ #include "code\modules\clothing\shoes\magboots.dm" #include "code\modules\clothing\shoes\miscellaneous.dm" #include "code\modules\clothing\spacesuits\alien.dm" +#include "code\modules\clothing\spacesuits\breaches.dm" #include "code\modules\clothing\spacesuits\captain.dm" #include "code\modules\clothing\spacesuits\ert.dm" #include "code\modules\clothing\spacesuits\miscellaneous.dm" diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 1d8fd6a36b7..069994dbf85 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -567,4 +567,642 @@ return -//////////////////////////////REMINDER: Make it lock once you place some fucker inside. \ No newline at end of file +//////////////////////////////REMINDER: Make it lock once you place some fucker inside. + +//God this entire file is fucking awful +//Suit painter for Bay's special snowflake aliums. + +/obj/machinery/suit_cycler + + name = "suit cycler" + desc = "An industrial machine for repairing, painting and equipping hardsuits." + anchored = 1 + density = 1 + + icon = 'icons/obj/suitstorage.dmi' + icon_state = "suitstorage000000100" + + req_access = list(access_captain,access_heads) + + var/active = 0 // PLEASE HOLD. + var/safeties = 1 // The cycler won't start with a living thing inside it unless safeties are off. + var/irradiating = 0 // If this is > 0, the cycler is decontaminating whatever is inside it. + var/radiation_level = 2 // 1 is removing germs, 2 is removing blood, 3 is removing phoron. + var/model_text = "" // Some flavour text for the topic box. + var/locked = 1 // If locked, nothing can be taken from or added to the cycler. + var/panel_open = 0 // Hacking! + + // Wiring bollocks. + var/wires = 15 + var/electrified = 0 + var/const/WIRE_EXTEND = 1 // Safeties + var/const/WIRE_SCANID = 2 // Locked status + var/const/WIRE_SHOCK = 3 // What it says on the tin. + + //Departments that the cycler can paint suits to look like. + var/list/departments = list("Engineering","Mining","Medical","Security","Atmos") + //Species that the suits can be configured to fit. + var/list/species = list("Human","Skrell","Unathi","Tajaran") + + var/target_department = "Engineering" + var/target_species = "Human" + + var/mob/living/carbon/human/occupant = null + var/obj/item/clothing/suit/space/rig/suit = null + var/obj/item/clothing/head/helmet/space/helmet = null + +/obj/machinery/suit_cycler/engineering + name = "Engineering suit cycler" + model_text = "Engineering" + req_access = list(access_construction) + departments = list("Engineering","Atmos") + species = list("Human","Unathi","Tajaran") + +/obj/machinery/suit_cycler/mining + name = "Mining suit cycler" + model_text = "Mining" + req_access = list(access_mining) + departments = list("Mining") + species = list("Human","Unathi","Tajaran") + +/obj/machinery/suit_cycler/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/suit_cycler/attack_paw(mob/user as mob) + user << "\blue The console controls are far too complicated for your tiny brain!" + return + +/obj/machinery/suit_cycler/attackby(obj/item/I as obj, mob/user as mob) + + if(electrified != 0) + if(src.shock(user, 100)) + return + + //Hacking init. + if(istype(I, /obj/item/device/multitool) || istype(I, /obj/item/weapon/wirecutters)) + if(panel_open) + attack_hand(user) + return + //Other interface stuff. + if(istype(I, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/G = I + + if(!(ismob(G.affecting))) + return + + if(locked) + user << "\red The suit cycler is locked." + return + + if(src.contents.len > 0) + user << "\red There is no room inside the cycler for [G.affecting.name]." + return + + visible_message("[user] starts putting [G.affecting.name] into the suit cycler.", 3) + + if(do_after(user, 20)) + if(!G || !G.affecting) return + var/mob/M = G.affecting + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + src.occupant = M + + src.add_fingerprint(user) + del(G) + + src.updateUsrDialog() + + return + else if(istype(I,/obj/item/weapon/screwdriver)) + + panel_open = !panel_open + user << "You [panel_open ? "open" : "close"] the maintenance panel." + src.updateUsrDialog() + return + + else if(istype(I,/obj/item/weapon/card/emag)) + + if(emagged) + user << "\red The cycler has already been subverted." + return + + var/obj/item/weapon/card/emag/E = I + src.updateUsrDialog() + E.uses-- + + //Clear the access reqs, disable the safeties, and open up all paintjobs. + user << "\red You run the sequencer across the interface, corrupting the operating protocols." + departments = list("Engineering","Mining","Medical","Security","Atmos","^%###^%$") + emagged = 1 + safeties = 0 + req_access = list() + return + + else if(istype(I,/obj/item/clothing/head/helmet/space)) + + if(locked) + user << "\red The suit cycler is locked." + return + + if(helmet) + user << "The cycler already contains a helmet." + return + + user << "You fit \the [I] into the suit cycler." + user.drop_item() + I.loc = src + helmet = I + + src.update_icon() + src.updateUsrDialog() + return + + else if(istype(I,/obj/item/clothing/suit/space/rig)) + + if(locked) + user << "\red The suit cycler is locked." + return + + if(suit) + user << "The cycler already contains a hardsuit." + return + + var/obj/item/clothing/suit/space/rig/S = I + + if(S.helmet) + user << "\The [S] will not fit into the cycler with a helmet attached." + return + + if(S.boots) + user << "\The [S] will not fit into the cycler with boots attached." + return + + user << "You fit \the [I] into the suit cycler." + user.drop_item() + I.loc = src + suit = I + + src.update_icon() + src.updateUsrDialog() + return + + ..() + +/obj/machinery/suit_cycler/attack_hand(mob/user as mob) + + add_fingerprint(user) + + if(..() || stat & (BROKEN|NOPOWER)) + return + + if(electrified != 0) + if(src.shock(user, 100)) + return + + usr.set_machine(src) + + var/dat = "Suit Cycler Interface" + + if(src.active) + dat+= "
The [model_text ? "[model_text] " : ""]suit cycler is currently in use. Please wait..." + + else if(locked) + dat += "
The [model_text ? "[model_text] " : ""]suit cycler is currently locked. Please contact your system administrator." + if(src.allowed(usr)) + dat += "
\[unlock unit\]" + else + dat += "

Suit cycler

" + dat += "Welcome to the [model_text ? "[model_text] " : ""]suit cycler control panel. \[lock unit\]
" + + dat += "

Maintenance

" + dat += "Helmet: [helmet ? "\the [helmet]" : "no helmet stored" ]. \[eject\]
" + dat += "Suit: [suit ? "\the [suit]" : "no suit stored" ]. \[eject\]" + + if(suit && istype(suit)) + dat += "[(suit.damage ? " \[repair\]" : "")]" + + dat += "
UV decontamination systems: SYSTEM ERROR" : "green'>READY"]
" + dat += "Output level: [radiation_level]
" + dat += "\[select power level\] \[begin decontamination cycle\]

" + + dat += "

Customisation

" + dat += "Target product: [target_department], [target_species]." + dat += "
\[apply customisation routine\]


" + + if(panel_open) + var/list/vendwires = list( + "Violet" = 1, + "Orange" = 2, + "Goldenrod" = 3, + ) + dat += "

Access Panel

" + for(var/wiredesc in vendwires) + var/is_uncut = src.wires & APCWireColorToFlag[vendwires[wiredesc]] + dat += "[wiredesc] wire: " + if(!is_uncut) + dat += "Mend" + else + dat += "Cut " + dat += "Pulse " + dat += "
" + + dat += "
" + dat += "The orange light is [(electrified == 0) ? "off" : "on"].
" + dat += "The red light is [safeties ? "blinking" : "off"].
" + dat += "The yellow light is [locked ? "on" : "off"].
" + + user << browse(dat, "window=suit_cycler") + onclose(user, "suit_cycler") + return + +/obj/machinery/suit_cycler/Topic(href, href_list) + if(href_list["eject_suit"]) + if(!suit) return + suit.loc = get_turf(src) + suit = null + else if(href_list["eject_helmet"]) + if(!helmet) return + helmet.loc = get_turf(src) + helmet = null + else if(href_list["select_department"]) + target_department = input("Please select the target department paintjob.","Suit cycler",null) as null|anything in departments + else if(href_list["select_species"]) + target_species = input("Please select the target species configuration.","Suit cycler",null) as null|anything in species + else if(href_list["select_rad_level"]) + var/choices = list(1,2,3) + if(emagged) + choices = list(1,2,3,4,5) + radiation_level = input("Please select the desired radiation level.","Suit cycler",null) as null|anything in choices + else if(href_list["repair_suit"]) + + if(!suit) return + active = 1 + spawn(100) + repair_suit() + finished_job() + + else if(href_list["apply_paintjob"]) + + if(!suit && !helmet) return + active = 1 + spawn(100) + apply_paintjob() + finished_job() + + else if(href_list["toggle_safties"]) + safeties = !safeties + + else if(href_list["toggle_lock"]) + + if(src.allowed(usr)) + locked = !locked + usr << "You [locked ? "" : "un"]lock \the [src]." + else + usr << "\red Access denied." + + else if(href_list["begin_decontamination"]) + + if(safeties && occupant) + usr << "\red The cycler has detected an occupant. Please remove the occupant before commencing the decontamination cycle." + return + + active = 1 + irradiating = 10 + src.updateUsrDialog() + + sleep(10) + + if(helmet) + if(radiation_level > 2) + helmet.decontaminate() + if(radiation_level > 1) + helmet.clean_blood() + + if(suit) + if(radiation_level > 2) + suit.decontaminate() + if(radiation_level > 1) + suit.clean_blood() + + else if ((href_list["cutwire"]) && (src.panel_open)) + var/twire = text2num(href_list["cutwire"]) + if (!( istype(usr.get_active_hand(), /obj/item/weapon/wirecutters) )) + usr << "You need wirecutters!" + return + if (src.isWireColorCut(twire)) + src.mend(twire) + else + src.cut(twire) + + else if ((href_list["pulsewire"]) && (src.panel_open)) + var/twire = text2num(href_list["pulsewire"]) + if (!istype(usr.get_active_hand(), /obj/item/device/multitool)) + usr << "You need a multitool!" + return + if (src.isWireColorCut(twire)) + usr << "You can't pulse a cut wire." + return + else + src.pulse(twire) + + src.updateUsrDialog() + return + +/obj/machinery/suit_cycler/process() + + if(electrified > 0) + electrified-- + + if(!active) + return + + if(active && stat & (BROKEN|NOPOWER)) + active = 0 + irradiating = 0 + electrified = 0 + return + + if(irradiating == 1) + finished_job() + irradiating = 0 + return + + irradiating-- + + if(occupant) + if(prob(radiation_level*2)) occupant.emote("scream") + if(radiation_level > 2) + occupant.take_organ_damage(0,radiation_level*2 + rand(1,3)) + if(radiation_level > 1) + occupant.take_organ_damage(0,radiation_level + rand(1,3)) + occupant.radiation += radiation_level*10 + +/obj/machinery/suit_cycler/proc/finished_job() + var/turf/T = get_turf(src) + T.visible_message("\The [src] pings loudly.") + icon_state = initial(icon_state) + active = 0 + src.updateUsrDialog() + +/obj/machinery/suit_cycler/proc/repair_suit() + if(!suit || !suit.damage || !suit.can_breach) + return + + suit.breaches = list() + suit.calc_breach_damage() + + return + +/obj/machinery/suit_cycler/verb/leave() + set name = "Eject Cycler" + set category = "Object" + set src in oview(1) + + if (usr.stat != 0) + return + + eject_occupant(usr) + +/obj/machinery/suit_cycler/proc/eject_occupant(mob/user as mob) + + if(locked || active) + user << "\red The cycler is locked." + return + + if (!occupant) + return + + if (occupant.client) + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + + occupant.loc = get_turf(occupant) + occupant = null + + add_fingerprint(usr) + src.updateUsrDialog() + src.update_icon() + + return + +//HACKING PROCS, MOSTLY COPIED FROM VENDING MACHINES +/obj/machinery/suit_cycler/proc/isWireColorCut(var/wireColor) + var/wireFlag = APCWireColorToFlag[wireColor] + return ((src.wires & wireFlag) == 0) + +/obj/machinery/suit_cycler/proc/isWireCut(var/wireIndex) + var/wireFlag = APCIndexToFlag[wireIndex] + return ((src.wires & wireFlag) == 0) + +/obj/machinery/suit_cycler/proc/cut(var/wireColor) + var/wireFlag = APCWireColorToFlag[wireColor] + var/wireIndex = APCWireColorToIndex[wireColor] + src.wires &= ~wireFlag + switch(wireIndex) + + if(WIRE_EXTEND) + safeties = 0 + if(WIRE_SHOCK) + electrified = -1 + if (WIRE_SCANID) + locked = 0 + +/obj/machinery/suit_cycler/proc/mend(var/wireColor) + var/wireFlag = APCWireColorToFlag[wireColor] + var/wireIndex = APCWireColorToIndex[wireColor] //not used in this function + src.wires |= wireFlag + switch(wireIndex) + if(WIRE_SHOCK) + src.electrified = 0 + +/obj/machinery/suit_cycler/proc/pulse(var/wireColor) + var/wireIndex = APCWireColorToIndex[wireColor] + switch(wireIndex) + if(WIRE_EXTEND) + safeties = !locked + if(WIRE_SHOCK) + electrified = 30 + if (WIRE_SCANID) + locked = !locked + +/obj/machinery/suit_cycler/proc/shock(mob/user, prb) + if(stat & (BROKEN|NOPOWER)) // unpowered, no shock + return 0 + if(!prob(prb)) + return 0 + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + if (electrocute_mob(user, get_area(src), src, 0.7)) + return 1 + else + return 0 + +//There HAS to be a less bloated way to do this. TODO: some kind of table/icon name coding? ~Z +/obj/machinery/suit_cycler/proc/apply_paintjob() + + if(!target_species || !target_department) + return + + switch(target_species) + if("Human" || "Skrell") + if(helmet) helmet.species_restricted = list("exclude","Unathi","Tajaran","Diona","Vox") + if(suit) suit.species_restricted = list("exclude","Unathi","Tajaran","Diona","Vox") + if("Unathi") + if(helmet) helmet.species_restricted = list("Unathi") + if(suit) suit.species_restricted = list("Unathi") + if("Tajaran") + if(helmet) helmet.species_restricted = list("Tajaran") + if(suit) suit.species_restricted = list("Tajaran") + + if(target_department == "Engineering") + + if(helmet) helmet.name = "engineering hardsuit helmet" + if(suit) suit.name = "engineering hardsuit" + + switch(target_species) + if("Human") + if(helmet) + helmet.icon_state = "rig0-engineering" + helmet.item_state = "eng_helm" + helmet.item_color = "engineering" + if(suit) + suit.icon_state = "rig-engineering" + suit.item_state = "eng_hardsuit" + if("Skrell") + return //TODO + if("Unathi") + return //TODO + if("Tajaran") + if(helmet) + helmet.icon_state = "rig0-taj-helmet" + helmet.item_state = "rig0-taj-helmet" + helmet.item_color = "taj-helmet" + if(suit) + suit.icon_state = "rig-taj" + suit.item_state = "rig-taj" + + else if(target_department == "Mining") + + if(helmet) helmet.name = "mining hardsuit helmet" + if(suit) suit.name = "mining hardsuit" + + switch(target_species) + if("Human") + if(helmet) + helmet.icon_state = "rig0-mining" + helmet.item_state = "mining_helm" + helmet.item_color = "mining" + if(suit) + suit.icon_state = "rig-mining" + suit.item_state = "mining_hardsuit" + if("Skrell") + return //TODO + if("Unathi") + return //TODO + if("Tajaran") + return //TODO + + else if(target_department == "^%###^%$") + + if(helmet) helmet.name = "blood-red hardsuit helmet" + if(suit) suit.name = "blood-red hardsuit" + + switch(target_species) + if("Human") + if(helmet) + helmet.icon_state = "rig0-syndie-human" + helmet.item_state = "syndie_helm" + helmet.item_color = "syndie-human" + if(suit) + suit.item_state = "syndie_hardsuit" + suit.icon_state = "rig-syndie-human" + if("Skrell") + if(helmet) + helmet.icon_state = "rig0-syndie-skrell" + helmet.item_state = "syndie_helm" + helmet.item_color = "syndie-skrell" + if(suit) + suit.item_state = "syndie_hardsuit" + suit.icon_state = "rig-syndie-skrell" + if("Unathi") + if(helmet) + helmet.icon_state = "rig0-syndie-unathi" + helmet.item_state = "syndie_helm" + helmet.item_color = "syndie-unathi" + if(suit) + suit.item_state = "syndie_hardsuit" + suit.icon_state = "rig-syndie-unathi" + if("Tajaran") + if(helmet) + helmet.icon_state = "rig0-syndie-taj" + helmet.item_state = "syndie_helm" + helmet.item_color = "syndie-taj" + if(suit) + suit.item_state = "syndie_hardsuit" + suit.icon_state = "rig-syndie-taj" + + else if(target_department == "Medical") + + if(helmet) helmet.name = "medical hardsuit helmet" + if(suit) suit.name = "medical hardsuit" + + switch(target_species) + if("Human") + if(helmet) + helmet.icon_state = "rig0-medical" + helmet.item_state = "medical_helm" + helmet.item_color = "medical" + if(suit) + suit.icon_state = "rig-medical" + suit.item_state = "medical_hardsuit" + if("Skrell") + return //TODO + if("Unathi") + return //TODO + if("Tajaran") + return //TODO + + else if(target_department == "Security") + + if(helmet) helmet.name = "security hardsuit helmet" + if(suit) suit.name = "security hardsuit" + + switch(target_species) + if("Human") + if(helmet) + helmet.icon_state = "rig0-sec" + helmet.item_state = "sec_helm" + helmet.item_color = "sec" + if(suit) + suit.icon_state = "rig-sec" + suit.item_state = "sec_hardsuit" + if("Skrell") + return //TODO + if("Unathi") + return //TODO + if("Tajaran") + return //TODO + + else if(target_department == "Atmos") + + if(helmet) helmet.name = "atmospherics hardsuit helmet" + if(suit) suit.name = "atmospherics hardsuit" + + switch(target_species) + if("Human") + if(helmet) + helmet.icon_state = "rig0-atmos" + helmet.item_state = "atmos_helm" + helmet.item_color = "atmos" + if(suit) + suit.icon_state = "rig-atmos" + suit.item_state = "atmos_hardsuit" + if("Skrell") + return //TODO + if("Unathi") + return //TODO + if("Tajaran") + return //TODO \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/breaches.dm b/code/modules/clothing/spacesuits/breaches.dm new file mode 100644 index 00000000000..19f795561c0 --- /dev/null +++ b/code/modules/clothing/spacesuits/breaches.dm @@ -0,0 +1,221 @@ +//A 'wound' system for space suits. +//Breaches greatly increase the amount of lost gas and decrease the armour rating of the suit. +//They can be healed with plastic or metal sheeting. + +/datum/breach + var/class = 0 // Size. Lower is smaller. + var/descriptor // 'gaping hole' etc. + var/damtype = BURN // Punctured or melted + var/obj/item/clothing/suit/space/holder // Suit containing the list of breaches holding this instance. + +/obj/item/clothing/suit/space + + var/can_breach = 1 // Set to 0 to disregard all breaching. + var/list/breaches = list() // Breach datum container. + var/resilience = 0.2 // Multiplier that turns damage into breach class. 1 is 100% of damage to breach, 0.1 is 10%. + var/breach_threshold = 3 // Min damage before a breach is possible. + var/damage = 0 // Current total damage + var/brute_damage = 0 // Specifically brute damage. + var/burn_damage = 0 // Specifically burn damage. + var/base_name // Used to keep the original name safe while we apply modifiers. + +/obj/item/clothing/suit/space/New() + ..() + base_name = "[name]" + +//Some simple descriptors for breaches. Global because lazy, TODO: work out a better way to do this. + +var/global/list/breach_brute_descriptors = list( + "tiny puncture", + "ragged tear", + "large split", + "huge tear", + "gaping wound" + ) + +var/global/list/breach_burn_descriptors = list( + "small burn", + "melted patch", + "sizable burn", + "large scorched area", + "huge scorched area" + ) + +/datum/breach/proc/update_descriptor() + + //Sanity... + class = max(1,min(class,5)) + //Apply the correct descriptor. + if(damtype == BURN) + descriptor = breach_burn_descriptors[class] + else if(damtype == BRUTE) + descriptor = breach_brute_descriptors[class] + +//Repair a certain amount of brute or burn damage to the suit. +/obj/item/clothing/suit/space/proc/repair_breaches(var/damtype, var/amount, var/mob/user) + + if(!can_breach || !breaches || !breaches.len || !damage) + user << "There are no breaches to repair on \the [src]." + return + + var/list/valid_breaches = list() + + for(var/datum/breach/B in breaches) + if(B.damtype == damtype) + valid_breaches += B + + if(!valid_breaches.len) + user << "There are no breaches to repair on \the [src]." + return + + var/amount_left = amount + for(var/datum/breach/B in valid_breaches) + if(!amount_left) break + + if(B.class <= amount_left) + amount_left -= B.class + valid_breaches -= B + breaches -= B + else + B.class -= amount_left + amount_left = 0 + B.update_descriptor() + + user.visible_message("[user] patches some of the damage on \the [src].") + calc_breach_damage() + +/obj/item/clothing/suit/space/proc/create_breaches(var/damtype, var/amount) + + if(!can_breach || !amount) + return + + if(!breaches) + breaches = list() + + if(damage > 25) return //We don't need to keep tracking it when it's at 250% pressure loss, really. + + if(!loc) return + var/turf/T = get_turf(src) + if(!T) return + + amount = amount * src.resilience + + //Increase existing breaches. + for(var/datum/breach/existing in breaches) + + if(existing.damtype != damtype) + continue + + if (existing.class < 5) + var/needs = 5 - existing.class + if(amount < needs) + existing.class += amount + amount = 0 + else + existing.class = 5 + amount -= needs + + if(existing.damtype == BRUTE) + T.visible_message("\The [existing.descriptor] on [src] gapes wider!") + else if(existing.damtype == BURN) + T.visible_message("\The [existing.descriptor] on [src] widens!") + + if (amount) + //Spawn a new breach. + var/datum/breach/B = new() + breaches += B + + B.class = min(amount,5) + + B.damtype = damtype + B.update_descriptor() + B.holder = src + + if(B.damtype == BRUTE) + T.visible_message("\A [B.descriptor] opens up on [src]!") + else if(B.damtype == BURN) + T.visible_message("\A [B.descriptor] marks the surface of [src]!") + + calc_breach_damage() + +//Calculates the current extent of the damage to the suit. +/obj/item/clothing/suit/space/proc/calc_breach_damage() + + damage = 0 + brute_damage = 0 + burn_damage = 0 + + if(!can_breach || !breaches || !breaches.len) + name = base_name + return 0 + + for(var/datum/breach/B in breaches) + if(!B.class) + src.breaches -= B + del(B) + else + damage += B.class + if(B.damtype == BRUTE) + brute_damage += B.class + else if(B.damtype == BURN) + burn_damage += B.class + + if(damage >= 3) + if(brute_damage >= 3 && brute_damage > burn_damage) + name = "punctured [base_name]" + else if(burn_damage >= 3 && burn_damage > brute_damage) + name = "scorched [base_name]" + else + name = "damaged [base_name]" + else + name = "[base_name]" + + return damage + +//Handles repairs (and also upgrades). + +/obj/item/clothing/suit/space/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W,/obj/item/stack/sheet/mineral/plastic) || istype(W,/obj/item/stack/sheet/metal)) + + if(istype(src.loc,/mob/living)) + user << "\red How do you intend to patch a hardsuit while someone is wearing it?" + return + + if(!damage || !burn_damage) + user << "There is no surface damage on \the [src] to repair." + return + + var/obj/item/stack/sheet/P = W + if(P.amount < 3) + P.use(P.amount) + repair_breaches(BURN, ( istype(P,/obj/item/stack/sheet/mineral/plastic) ? P.amount : (P.amount*2) ), user) + else + P.use(3) + repair_breaches(BURN, ( istype(P,/obj/item/stack/sheet/mineral/plastic) ? 3 : 5), user) + return + + else if(istype(W, /obj/item/weapon/weldingtool)) + + if(istype(src.loc,/mob/living)) + user << "\red How do you intend to patch a hardsuit while someone is wearing it?" + return + + if (!damage || ! brute_damage) + user << "There is no structural damage on \the [src] to repair." + return + + var/obj/item/weapon/weldingtool/WT = W + if(!WT.remove_fuel(5)) + user << "\red You need more welding fuel to repair this suit." + return + + repair_breaches(BRUTE, 3, user) + return + + ..() + +/obj/item/clothing/suit/space/examine() + ..() + if(can_breach && breaches && breaches.len) + for(var/datum/breach/B in breaches) + usr << "\red It has \a [B.descriptor]." \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/rig.dm b/code/modules/clothing/spacesuits/rig.dm index 9a527b32135..cf591b0544b 100644 --- a/code/modules/clothing/spacesuits/rig.dm +++ b/code/modules/clothing/spacesuits/rig.dm @@ -53,6 +53,223 @@ max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE species_restricted = list("exclude","Unathi","Tajaran","Diona","Vox") + //Breach thresholds, should ideally be inherited by most (if not all) hardsuits. + breach_threshold = 18 + can_breach = 1 + + //Component/device holders. + var/obj/item/weapon/stock_parts/gloves = null // Basic capacitor allows insulation, upgrades allow shock gloves etc. + + var/attached_boots = 1 // Can't wear boots if some are attached + var/obj/item/clothing/shoes/magboots/boots = null // Deployable boots, if any. + var/attached_helmet = 1 // Can't wear a helmet if one is deployable. + var/obj/item/clothing/head/helmet/helmet = null // Deployable helmet, if any. + + var/list/max_mounted_devices = 0 // Maximum devices. Easy. + var/list/can_mount = null // Types of device that can be hardpoint mounted. + var/list/mounted_devices = null // Holder for the above device. + var/obj/item/active_device = null // Currently deployed device, if any. + +/obj/item/clothing/suit/space/rig/equipped(mob/M) + ..() + + var/mob/living/carbon/human/H = M + + if(!istype(H)) return + + if(H.wear_suit != src) + return + + if(attached_helmet && helmet) + if(H.head) + M << "You are unable to deploy your suit's helmet as \the [H.head] is in the way." + else + M << "Your suit's helmet deploys with a hiss." + //TODO: Species check, skull damage for forcing an unfitting helmet on? + helmet.loc = H + H.equip_to_slot(helmet, slot_head) + helmet.canremove = 0 + + if(attached_boots && boots) + if(H.shoes) + M << "You are unable to deploy your suit's magboots as \the [H.shoes] are in the way." + else + M << "Your suit's boots deploy with a hiss." + boots.loc = H + H.equip_to_slot(boots, slot_shoes) + boots.canremove = 0 + +/obj/item/clothing/suit/space/rig/dropped() + ..() + + var/mob/living/carbon/human/H + + H = helmet.loc + if(istype(H)) + if(helmet && H.head == helmet) + helmet.canremove = 1 + H.drop_from_inventory(helmet) + helmet.loc = src + + H = boots.loc + if(istype(H)) + if(boots && H.shoes == boots) + boots.canremove = 1 + H.drop_from_inventory(boots) + boots.loc = src + +/obj/item/clothing/suit/space/rig/verb/get_mounted_device() + + set name = "Deploy Mounted Device" + set category = "Object" + set src in usr + + if(!can_mount) + verbs -= /obj/item/clothing/suit/space/rig/verb/get_mounted_device + verbs -= /obj/item/clothing/suit/space/rig/verb/stow_mounted_device + return + + if(!istype(usr, /mob/living)) return + if(usr.stat) return + + if(active_device) + usr << "You already have \the [active_device] deployed." + return + + if(!mounted_devices.len) + usr << "You do not have any devices mounted on \the [src]." + return + +/obj/item/clothing/suit/space/rig/verb/stow_mounted_device() + + set name = "Stow Mounted Device" + set category = "Object" + set src in usr + + if(!can_mount) + verbs -= /obj/item/clothing/suit/space/rig/verb/get_mounted_device + verbs -= /obj/item/clothing/suit/space/rig/verb/stow_mounted_device + return + + if(!istype(usr, /mob/living)) return + + if(usr.stat) return + + if(!active_device) + usr << "You have no device currently deployed." + return + +/obj/item/clothing/suit/space/rig/verb/toggle_helmet() + + set name = "Toggle Helmet" + set category = "Object" + set src in usr + + if(!helmet) + usr << "There is no helmet installed." + return + + var/mob/living/carbon/human/H = usr + if(!istype(H)) return + + if(H.stat) return + + if(H.head == helmet) + helmet.canremove = 1 + H.drop_from_inventory(helmet) + helmet.loc = src + H << "\blue You retract your hardsuit helmet." + else + if(H.head) + H << "\red You cannot deploy your helmet while wearing another helmet." + return + //TODO: Species check, skull damage for forcing an unfitting helmet on? + helmet.loc = H + H.equip_to_slot(helmet, slot_head) + helmet.canremove = 0 + H << "\blue You deploy your hardsuit helmet, sealing you off from the world." + +/obj/item/clothing/suit/space/rig/attackby(obj/item/W as obj, mob/user as mob) + + if(!istype(user,/mob/living)) return + + if(user.a_intent == "help") + + if(istype(src.loc,/mob/living)) + user << "How do you propose to modify a hardsuit while it is being worn?" + return + + var/target_zone = user.zone_sel.selecting + + if(target_zone == "head") + + //Installing a component into or modifying the contents of the helmet. + if(!attached_helmet) + user << "\The [src] does not have a helmet mount." + return + + if(istype(W,/obj/item/weapon/screwdriver)) + if(!helmet) + user << "\The [src] does not have a helmet installed." + else + user << "You detatch \the [helmet] from \the [src]'s helmet mount." + helmet.loc = get_turf(src) + src.helmet = null + return + else if(istype(W,/obj/item/clothing/head/helmet/space)) + if(helmet) + user << "\The [src] already has a helmet installed." + else + user << "You attach \the [W] to \the [src]'s helmet mount." + user.drop_item() + W.loc = src + src.helmet = W + return + else + return ..() + + else if(target_zone == "l_leg" || target_zone == "r_leg" || target_zone == "l_foot" || target_zone == "r_foot") + + //Installing a component into or modifying the contents of the feet. + if(!attached_boots) + user << "\The [src] does not have boot mounts." + return + + if(istype(W,/obj/item/weapon/screwdriver)) + if(!boots) + user << "\The [src] does not have any boots installed." + else + user << "You detatch \the [boots] from \the [src]'s boot mounts." + boots.loc = get_turf(src) + boots = null + return + else if(istype(W,/obj/item/clothing/shoes/magboots)) + if(boots) + user << "\The [src] already has magboots installed." + else + user << "You attach \the [W] to \the [src]'s boot mounts." + user.drop_item() + W.loc = src + boots = W + else + return ..() + + else if(target_zone == "l_arm" || target_zone == "r_arm" || target_zone == "l_hand" || target_zone == "r_hand") + + //Installing a component into or modifying the contents of the hands. + + else if(target_zone == "torso" || target_zone == "groin") + + //Modifying the cell or mounted devices + + if(!mounted_devices) + return + + else //wat + return ..() + + ..() + //Chief Engineer's rig /obj/item/clothing/head/helmet/space/rig/elite name = "advanced hardsuit helmet" diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 1b12f625620..3583b6822e4 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -229,6 +229,8 @@ This function restores all organs. /mob/living/carbon/human/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/sharp = 0, var/obj/used_weapon = null) + handle_suit_punctures(damagetype, damage) + //visible_message("Hit debug. [damage] | [damagetype] | [def_zone] | [blocked] | [sharp] | [used_weapon]") if((damagetype != BRUTE) && (damagetype != BURN)) ..(damage, damagetype, def_zone, blocked) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 44deb248ca8..12a16567c56 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -53,6 +53,7 @@ emp_act if(check_shields(P.damage, "the [P.name]")) P.on_hit(src, 2, def_zone) + handle_suit_punctures(P.damage_type, P.damage) return 2 //BEGIN BOOK'S TASER NERF. @@ -296,3 +297,14 @@ emp_act if(w_uniform) w_uniform.add_blood(source) update_inv_w_uniform(0) + +/mob/living/carbon/human/proc/handle_suit_punctures(var/damtype, var/damage) + + if(!wear_suit) return + if(!istype(wear_suit,/obj/item/clothing/suit/space)) return + if(damtype != BURN && damtype != BRUTE) return + + var/obj/item/clothing/suit/space/SS = wear_suit + var/penetrated_dam = max(0,(damage - max(0,(SS.breach_threshold - SS.damage)))) + + if(penetrated_dam) SS.create_breaches(damtype, penetrated_dam) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 036a84b8b1a..a687940ea2b 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -133,12 +133,24 @@ var/pressure_difference = abs( pressure - ONE_ATMOSPHERE ) var/pressure_adjustment_coefficient = 1 //Determins how much the clothing you are wearing protects you in percent. - if(wear_suit && (wear_suit.flags & STOPSPRESSUREDMAGE)) - pressure_adjustment_coefficient -= PRESSURE_SUIT_REDUCTION_COEFFICIENT + if(head && (head.flags & STOPSPRESSUREDMAGE)) pressure_adjustment_coefficient -= PRESSURE_HEAD_REDUCTION_COEFFICIENT - pressure_adjustment_coefficient = max(pressure_adjustment_coefficient,0) //So it isn't less than 0 + + if(wear_suit && (wear_suit.flags & STOPSPRESSUREDMAGE)) + pressure_adjustment_coefficient -= PRESSURE_SUIT_REDUCTION_COEFFICIENT + + //Handles breaches in your space suit. 10 suit damage equals a 100% loss of pressure reduction. + if(istype(wear_suit,/obj/item/clothing/suit/space)) + var/obj/item/clothing/suit/space/S = wear_suit + if(S.can_breach && S.damage) + var/pressure_loss = S.damage * 0.1 + pressure_adjustment_coefficient += pressure_loss + + pressure_adjustment_coefficient = min(1,max(pressure_adjustment_coefficient,0)) //So it isn't less than 0 or larger than 1. + pressure_difference = pressure_difference * pressure_adjustment_coefficient + if(pressure > ONE_ATMOSPHERE) return ONE_ATMOSPHERE + pressure_difference else From 9b93600d6e2d0cc938039759520459ae4baf3ea9 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sun, 25 May 2014 21:57:39 +0930 Subject: [PATCH 2/2] Prevented toggling a suit helmet while holding the suit. --- code/modules/clothing/spacesuits/rig.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/clothing/spacesuits/rig.dm b/code/modules/clothing/spacesuits/rig.dm index cf591b0544b..8a17cee5fb7 100644 --- a/code/modules/clothing/spacesuits/rig.dm +++ b/code/modules/clothing/spacesuits/rig.dm @@ -165,14 +165,17 @@ set category = "Object" set src in usr + if(!istype(src.loc,/mob/living)) return + if(!helmet) usr << "There is no helmet installed." return var/mob/living/carbon/human/H = usr - if(!istype(H)) return + if(!istype(H)) return if(H.stat) return + if(H.wear_suit != src) return if(H.head == helmet) helmet.canremove = 1