From 5d80346f8fd028368e31044220419ba991b15a3a Mon Sep 17 00:00:00 2001 From: kevinz000 <2003111+kevinz000@users.noreply.github.com> Date: Thu, 5 Dec 2019 21:44:25 -0700 Subject: [PATCH] Merge pull request #9993 from Ghommie/Ghommie-cit412 Ports tgstation loom changes, and durathred golems. --- code/__DEFINES/status_effects.dm | 2 + code/__DEFINES/traits.dm | 1 + code/datums/status_effects/debuffs.dm | 32 + code/game/objects/items/tools/wirecutters.dm | 277 +- .../objects/structures/ghost_role_spawners.dm | 3 + code/game/objects/structures/loom.dm | 63 +- code/modules/cargo/packs/materials.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 2289 +++++++++-------- .../mob/living/carbon/human/human_defense.dm | 1610 ++++++------ .../mob/living/carbon/human/species.dm | 4 + .../carbon/human/species_types/golems.dm | 15 + code/modules/mob/living/carbon/life.dm | 2 +- code/modules/ruins/lavaland_ruin_code.dm | 3 +- 13 files changed, 2177 insertions(+), 2126 deletions(-) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 1ab4fd3f..4cc12b46 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -58,6 +58,8 @@ #define MAX_MANIA_SEVERITY 100 //how high the mania severity can go #define MANIA_DAMAGE_TO_CONVERT 90 //how much damage is required before it'll convert affected targets +#define STATUS_EFFECT_CHOKINGSTRAND /datum/status_effect/strandling //Choking Strand + #define STATUS_EFFECT_HISWRATH /datum/status_effect/his_wrath //His Wrath. #define STATUS_EFFECT_SUMMONEDGHOST /datum/status_effect/cultghost //is a cult ghost and can't use manifest runes diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 3bfb2da0..01297457 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -126,6 +126,7 @@ #define TRAIT_LAW_ENFORCEMENT_METABOLISM "law-enforcement-metabolism" #define TRAIT_STRONG_GRABBER "strong_grabber" #define TRAIT_CALCIUM_HEALER "calcium_healer" +#define TRAIT_MAGIC_CHOKE "magic_choke" #define TRAIT_ALCOHOL_LIGHTWEIGHT "alcohol_lightweight" //Skyrat port #define TRAIT_CURSED_BLOOD "cursed_blood" //Yo dawg I heard you like bloodborne references so I put a #define TRAIT_HEAT_DETECT "heat_detect" diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index a9ba87b1..237afdd5 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -609,6 +609,38 @@ icon_state = "ichorial_stain" alerttooltipstyle = "clockcult" + +//GOLEM GANG + +/datum/status_effect/strandling //get it, strand as in durathread strand + strangling = strandling hahahahahahahahahahhahahaha i want to die + id = "strandling" + status_type = STATUS_EFFECT_UNIQUE + alert_type = /obj/screen/alert/status_effect/strandling + +/datum/status_effect/strandling/on_apply() + ADD_TRAIT(owner, TRAIT_MAGIC_CHOKE, "dumbmoron") + return ..() + +/datum/status_effect/strandling/on_remove() + REMOVE_TRAIT(owner, TRAIT_MAGIC_CHOKE, "dumbmoron") + return ..() + +/obj/screen/alert/status_effect/strandling + name = "Choking strand" + desc = "A magical strand of Durathread is wrapped around your neck, preventing you from breathing! Click this icon to remove the strand." + icon_state = "his_grace" + alerttooltipstyle = "hisgrace" + +/obj/screen/alert/status_effect/strandling/Click(location, control, params) + . = ..() + to_chat(mob_viewer, "You attempt to remove the durathread strand from around your neck.") + if(do_after(mob_viewer, 35, null, mob_viewer)) + if(isliving(mob_viewer)) + var/mob/living/L = mob_viewer + to_chat(mob_viewer, "You succesfuly remove the durathread strand.") + L.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND) + + datum/status_effect/pacify id = "pacify" status_type = STATUS_EFFECT_REPLACE diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm index dc4353d1..8586fd47 100644 --- a/code/game/objects/items/tools/wirecutters.dm +++ b/code/game/objects/items/tools/wirecutters.dm @@ -1,135 +1,144 @@ -/obj/item/wirecutters - name = "wirecutters" - desc = "This cuts wires." - icon = 'icons/obj/tools.dmi' - icon_state = "cutters_map" - item_state = "cutters" - lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - flags_1 = CONDUCT_1 - slot_flags = ITEM_SLOT_BELT - force = 6 - throw_speed = 3 - throw_range = 7 - w_class = WEIGHT_CLASS_SMALL - materials = list(MAT_METAL=80) - attack_verb = list("pinched", "nipped") - hitsound = 'sound/items/wirecutter.ogg' - usesound = 'sound/items/wirecutter.ogg' - - tool_behaviour = TOOL_WIRECUTTER - toolspeed = 1 - armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30) - var/random_color = TRUE - var/static/list/wirecutter_colors = list( - "blue" = "#1861d5", - "red" = "#951710", - "pink" = "#d5188d", - "brown" = "#a05212", - "green" = "#0e7f1b", - "cyan" = "#18a2d5", - "yellow" = "#d58c18" - ) - - -/obj/item/wirecutters/Initialize() - . = ..() - if(random_color) //random colors! - icon_state = "cutters" - var/our_color = pick(wirecutter_colors) - add_atom_colour(wirecutter_colors[our_color], FIXED_COLOUR_PRIORITY) - update_icon() - -/obj/item/wirecutters/update_icon() - if(!random_color) //icon override - return - cut_overlays() - var/mutable_appearance/base_overlay = mutable_appearance(icon, "cutters_cutty_thingy") - base_overlay.appearance_flags = RESET_COLOR - add_overlay(base_overlay) - -/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) - if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) - user.visible_message("[user] cuts [C]'s restraints with [src]!") - qdel(C.handcuffed) - return - else - ..() - -/obj/item/wirecutters/suicide_act(mob/user) - user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") - playsound(loc, usesound, 50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/brass - name = "brass wirecutters" - desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." - resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "cutters_brass" - random_color = FALSE - toolspeed = 0.5 - -/obj/item/wirecutters/bronze - name = "bronze plated wirecutters" - desc = "A pair of wirecutters plated with bronze." - icon_state = "cutters_brass" - random_color = FALSE - toolspeed = 0.95 //Wire cutters have 0 time bars though - -/obj/item/wirecutters/abductor - name = "alien wirecutters" - desc = "Extremely sharp wirecutters, made out of a silvery-green metal." - icon = 'icons/obj/abductor.dmi' - icon_state = "cutters" - toolspeed = 0.1 - random_color = FALSE - -/obj/item/wirecutters/cyborg - name = "wirecutters" - desc = "This cuts wires." - toolspeed = 0.5 - -/obj/item/wirecutters/power - name = "jaws of life" - desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." - icon_state = "jaws_cutter" - item_state = "jawsoflife" - - materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) - usesound = 'sound/items/jaws_cut.ogg' - toolspeed = 0.25 - random_color = FALSE - -/obj/item/wirecutters/power/suicide_act(mob/user) - user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") - playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) - if(iscarbon(user)) - var/mob/living/carbon/C = user - var/obj/item/bodypart/BP = C.get_bodypart(BODY_ZONE_HEAD) - if(BP) - BP.drop_limb() - playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) - return (BRUTELOSS) - -/obj/item/wirecutters/power/attack_self(mob/user) - playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) - var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power(drop_location()) - to_chat(user, "You attach the pry jaws to [src].") - qdel(src) - user.put_in_active_hand(pryjaws) - -/obj/item/wirecutters/power/attack(mob/living/carbon/C, mob/user) - if(istype(C) && C.handcuffed) - user.visible_message("[user] cuts [C]'s restraints with [src]!") - qdel(C.handcuffed) - return - else - ..() - -/obj/item/wirecutters/advanced - name = "advanced wirecutters" - desc = "A set of reproduction alien wirecutters, they have a silver handle with an exceedingly sharp blade." - icon = 'icons/obj/advancedtools.dmi' - icon_state = "cutters" - toolspeed = 0.2 +/obj/item/wirecutters + name = "wirecutters" + desc = "This cuts wires." + icon = 'icons/obj/tools.dmi' + icon_state = "cutters_map" + item_state = "cutters" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + flags_1 = CONDUCT_1 + slot_flags = ITEM_SLOT_BELT + force = 6 + throw_speed = 3 + throw_range = 7 + w_class = WEIGHT_CLASS_SMALL + materials = list(MAT_METAL=80) + attack_verb = list("pinched", "nipped") + hitsound = 'sound/items/wirecutter.ogg' + usesound = 'sound/items/wirecutter.ogg' + + tool_behaviour = TOOL_WIRECUTTER + toolspeed = 1 + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30) + var/random_color = TRUE + var/static/list/wirecutter_colors = list( + "blue" = "#1861d5", + "red" = "#951710", + "pink" = "#d5188d", + "brown" = "#a05212", + "green" = "#0e7f1b", + "cyan" = "#18a2d5", + "yellow" = "#d58c18" + ) + + +/obj/item/wirecutters/Initialize() + . = ..() + if(random_color) //random colors! + icon_state = "cutters" + var/our_color = pick(wirecutter_colors) + add_atom_colour(wirecutter_colors[our_color], FIXED_COLOUR_PRIORITY) + update_icon() + +/obj/item/wirecutters/update_icon() + if(!random_color) //icon override + return + cut_overlays() + var/mutable_appearance/base_overlay = mutable_appearance(icon, "cutters_cutty_thingy") + base_overlay.appearance_flags = RESET_COLOR + add_overlay(base_overlay) + +/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user) + if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable)) + user.visible_message("[user] cuts [C]'s restraints with [src]!") + qdel(C.handcuffed) + return + else + ..() + +/obj/item/wirecutters/suicide_act(mob/user) + user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, usesound, 50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/brass + name = "brass wirecutters" + desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." + resistance_flags = FIRE_PROOF | ACID_PROOF + icon_state = "cutters_brass" + random_color = FALSE + toolspeed = 0.5 + +/obj/item/wirecutters/bronze + name = "bronze plated wirecutters" + desc = "A pair of wirecutters plated with bronze." + icon_state = "cutters_brass" + random_color = FALSE + toolspeed = 0.95 //Wire cutters have 0 time bars though + +/obj/item/wirecutters/abductor + name = "alien wirecutters" + desc = "Extremely sharp wirecutters, made out of a silvery-green metal." + icon = 'icons/obj/abductor.dmi' + icon_state = "cutters" + toolspeed = 0.1 + random_color = FALSE + +/obj/item/wirecutters/cyborg + name = "wirecutters" + desc = "This cuts wires." + toolspeed = 0.5 + +/obj/item/wirecutters/power + name = "jaws of life" + desc = "A set of jaws of life, compressed through the magic of science. It's fitted with a cutting head." + icon_state = "jaws_cutter" + item_state = "jawsoflife" + + materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25) + usesound = 'sound/items/jaws_cut.ogg' + toolspeed = 0.25 + random_color = FALSE + +/obj/item/wirecutters/power/suicide_act(mob/user) + user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!") + playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1) + if(iscarbon(user)) + var/mob/living/carbon/C = user + var/obj/item/bodypart/BP = C.get_bodypart(BODY_ZONE_HEAD) + if(BP) + BP.drop_limb() + playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + return (BRUTELOSS) + +/obj/item/wirecutters/power/attack_self(mob/user) + playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1) + var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power(drop_location()) + to_chat(user, "You attach the pry jaws to [src].") + qdel(src) + user.put_in_active_hand(pryjaws) + +/obj/item/wirecutters/power/attack(mob/living/carbon/C, mob/user) + if(istype(C)) + if(C.handcuffed) + user.visible_message("[user] cuts [C]'s restraints with [src]!") + qdel(C.handcuffed) + return + else if(C.has_status_effect(STATUS_EFFECT_CHOKINGSTRAND)) + var/man = C == user ? "your" : "[C]'\s" + user.visible_message("[user] attempts to remove the durathread strand from around [man] neck.", \ + "You attempt to remove the durathread strand from around [man] neck.") + if(do_after(user, 15, null, C)) + user.visible_message("[user] succesfuly removes the durathread strand.", + "You succesfuly remove the durathread strand.") + C.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND) + return + ..() + +/obj/item/wirecutters/advanced + name = "advanced wirecutters" + desc = "A set of reproduction alien wirecutters, they have a silver handle with an exceedingly sharp blade." + icon = 'icons/obj/advancedtools.dmi' + icon_state = "cutters" + toolspeed = 0.2 random_color = FALSE \ No newline at end of file diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index af2d7407..4b0b944f 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -154,6 +154,9 @@ log_admin("[key_name(new_spawn)] possessed a golem shell enslaved to [key_name(owner)].") if(ishuman(new_spawn)) var/mob/living/carbon/human/H = new_spawn + if(has_owner) + var/datum/species/golem/G = H.dna.species + G.owner = owner H.set_cloned_appearance() if(!name) if(has_owner) diff --git a/code/game/objects/structures/loom.dm b/code/game/objects/structures/loom.dm index 7d1ee27e..1b4cac9d 100644 --- a/code/game/objects/structures/loom.dm +++ b/code/game/objects/structures/loom.dm @@ -1,5 +1,7 @@ -//Loom, turns raw cotton and durathread into their respective fabrics. +#define FABRIC_PER_SHEET 4 + +///This is a loom. It's usually made out of wood and used to weave fabric like durathread or cotton into their respective cloth types. /obj/structure/loom name = "loom" desc = "A simple device used to weave cloth and other thread-based fabrics together into usable material." @@ -9,73 +11,34 @@ anchored = TRUE /obj/structure/loom/attackby(obj/item/I, mob/user) - if (user.a_intent != INTENT_HELP) - return ..() - if (istype(I, /obj/item/stack/sheet)) - if (!anchored) - return to_chat(user, "You have to anchor [src] first!") - - var/obj/item/stack/sheet/W = I - if(W.is_fabric && W.amount > 1) - user.visible_message("", - "You start weaving the [W.name] through the loom.") - - if(W.use_tool(src, user, W.pull_effort)) - new W.loom_result(drop_location()) - to_chat(user, "You weave the [W.name] into a workable fabric.") - W.amount = (W.amount - 2) - if(W.amount < 1) - qdel(W) - else if(W.is_fabric) - to_chat("You need at least 2 [W.name] to loom into fabric!") + if(weave(I, user)) return - else - switch (I.tool_behaviour) - if (TOOL_SCREWDRIVER) - user.visible_message("[user] starts disassembling [src]...", - "You start disassembling [src]...") - I.play_tool_sound(src) - if(I.use_tool(src, user, 60)) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) - deconstruct(TRUE) - return - if (TOOL_WRENCH) - if (anchored) - to_chat(user, "You unsecure the [src].") - I.play_tool_sound(src) - anchored = FALSE - else - to_chat(user, "You secure the [src].") - I.play_tool_sound(src) - anchored = TRUE - return return ..() -/obj/structure/loom/deconstruct(disassembled = TRUE) - new /obj/item/stack/sheet/mineral/wood (get_turf(src), 10) - qdel(src) +/obj/structure/loom/wrench_act(mob/living/user, obj/item/I) + ..() + default_unfasten_wrench(user, I, 5) + return TRUE - - -/*///Handles the weaving. +///Handles the weaving. /obj/structure/loom/proc/weave(obj/item/stack/sheet/S, mob/user) if(!istype(S) || !S.is_fabric) return FALSE if(!anchored) - user.show_message("The loom needs to be wrenched down.", MSG_VISUAL) + user.show_message("The loom needs to be wrenched down.", 1) return FALSE if(S.amount < FABRIC_PER_SHEET) user.show_message("You need at least [FABRIC_PER_SHEET] units of fabric before using this.", 1) return FALSE - user.show_message("You start weaving \the [S.name] through the loom..", MSG_VISUAL) + user.show_message("You start weaving \the [S.name] through the loom..", 1) if(S.use_tool(src, user, S.pull_effort)) if(S.amount >= FABRIC_PER_SHEET) new S.loom_result(drop_location()) S.use(FABRIC_PER_SHEET) - user.show_message("You weave \the [S.name] into a workable fabric.", MSG_VISUAL) + user.show_message("You weave \the [S.name] into a workable fabric.", 1) return TRUE /obj/structure/loom/unanchored anchored = FALSE -#undef FABRIC_PER_SHEET */ +#undef FABRIC_PER_SHEET diff --git a/code/modules/cargo/packs/materials.dm b/code/modules/cargo/packs/materials.dm index ab408ffe..af589879 100644 --- a/code/modules/cargo/packs/materials.dm +++ b/code/modules/cargo/packs/materials.dm @@ -195,7 +195,7 @@ name = "Loom" desc = "A large pre-made loom." cost = 1000 - contains = list(/obj/structure/loom) + contains = list(/obj/structure/loom/unanchored) crate_name = "loom crate" crate_type = /obj/structure/closet/crate/large diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index d7e93a92..100e9f43 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1,1137 +1,1152 @@ -/mob/living/carbon/human - name = "Unknown" - real_name = "Unknown" - icon = 'icons/mob/human.dmi' - icon_state = "caucasian_m" - appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE - -/mob/living/carbon/human/Initialize() - verbs += /mob/living/proc/mob_sleep - verbs += /mob/living/proc/lay_down - verbs += /mob/living/carbon/human/proc/underwear_toggle //fwee - time_initialized = world.time - - //initialize limbs first - create_bodyparts() - - //initialize dna. for spawned humans; overwritten by other code - create_dna(src) - randomize_human(src) - dna.initialize_dna() - - if(dna.species) - set_species(dna.species.type) - - //initialise organs - create_internal_organs() //most of it is done in set_species now, this is only for parent call - physiology = new() - - handcrafting = new() - - . = ..() - - if(CONFIG_GET(flag/disable_stambuffer)) - togglesprint() - - AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /mob/living/carbon/human/clean_blood))) - - -/mob/living/carbon/human/ComponentInitialize() - . = ..() - if(!CONFIG_GET(flag/disable_human_mood)) - AddComponent(/datum/component/mood) - AddElement(/datum/element/mob_holder/micro, "micro") - -/mob/living/carbon/human/Destroy() - QDEL_NULL(physiology) - QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff - return ..() - - -/mob/living/carbon/human/OpenCraftingMenu() - handcrafting.ui_interact(src) - -/mob/living/carbon/human/prepare_data_huds() - //Update med hud images... - ..() - //...sec hud images... - sec_hud_set_ID() - sec_hud_set_implants() - sec_hud_set_security_status() - //...and display them. - add_to_all_human_data_huds() - - -/mob/living/carbon/human/Stat() - ..() - //Same thing from mob - if(statpanel("Status")) - if(tickrefresh == 1) - sList2 = list() - sList2 += "Intent: [a_intent]" - sList2 += "Move Mode: [m_intent]" - if (internal) - if (!internal.air_contents) - qdel(internal) - else - sList2 += "Internal Atmosphere Info: "+ "[internal.name]" - sList2 += "Tank Pressure: "+ "[internal.air_contents.return_pressure()]" - sList2 += "Distribution Pressure: "+ "[internal.distribute_pressure]" - if(mind) - var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) - if(changeling) - sList2 += "Chemical Storage: " + "[changeling.chem_charges]/[changeling.chem_storage]" - sList2 += "Absorbed DNA: "+ "[changeling.absorbedcount]" - if (sList2 != null) - stat(null, "[sList2.Join("\n\n")]") - - //NINJACODE - if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja. - var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit - if(statpanel("SpiderOS")) - stat("SpiderOS Status:","[SN.s_initialized ? "Initialized" : "Disabled"]") - stat("Current Time:", "[STATION_TIME_TIMESTAMP("hh:mm:ss")]") - if(SN.s_initialized) - //Suit gear - stat("Energy Charge:", "[round(SN.cell.charge/100)]%") - stat("Smoke Bombs:", "\Roman [SN.s_bombs]") - //Ninja status - stat("Fingerprints:", "[md5(dna.uni_identity)]") - stat("Unique Identity:", "[dna.unique_enzymes]") - stat("Overall Status:", "[stat > 1 ? "dead" : "[health]% healthy"]") - stat("Nutrition Status:", "[nutrition]") - stat("Oxygen Loss:", "[getOxyLoss()]") - stat("Toxin Levels:", "[getToxLoss()]") - stat("Burn Severity:", "[getFireLoss()]") - stat("Brute Trauma:", "[getBruteLoss()]") - stat("Radiation Levels:","[radiation] rad") - stat("Body Temperature:","[bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)") - - //Diseases - if(diseases.len) - stat("Viruses:", null) - for(var/thing in diseases) - var/datum/disease/D = thing - stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]") - - -/mob/living/carbon/human/show_inv(mob/user) - user.set_machine(src) - var/has_breathable_mask = istype(wear_mask, /obj/item/clothing/mask) - var/list/obscured = check_obscured_slots() - var/list/dat = list() - - dat += "" - for(var/i in 1 to held_items.len) - var/obj/item/I = get_item_for_held_index(i) - dat += "" - dat += "" - - dat += "" - - dat += "" - - if(SLOT_WEAR_MASK in obscured) - dat += "" - else - dat += "" - - if(SLOT_NECK in obscured) - dat += "" - else - dat += "" - - if(SLOT_GLASSES in obscured) - dat += "" - else - dat += "" - - if(SLOT_EARS in obscured) - dat += "" - else - dat += "" - - dat += "" - - dat += "" - if(wear_suit) - dat += "" - else - dat += "" - - if(SLOT_SHOES in obscured) - dat += "" - else - dat += "" - - if(SLOT_GLOVES in obscured) - dat += "" - else - dat += "" - - if(SLOT_W_UNIFORM in obscured) - dat += "" - else - dat += "" - - if((w_uniform == null && !(dna && dna.species.nojumpsuit)) || (SLOT_W_UNIFORM in obscured)) - dat += "" - dat += "" - dat += "" - else - dat += "" - dat += "" - dat += "" - - if(handcuffed) - dat += "" - if(legcuffed) - dat += "" - - dat += {"
[get_held_index_name(i)]:[(I && !(I.item_flags & ABSTRACT)) ? I : "Empty"]
 
Back:[(back && !(back.item_flags & ABSTRACT)) ? back : "Empty"]" - if(has_breathable_mask && istype(back, /obj/item/tank)) - dat += " [internal ? "Disable Internals" : "Set Internals"]" - - dat += "
 
Head:[(head && !(head.item_flags & ABSTRACT)) ? head : "Empty"]
Mask:Obscured
Mask:[(wear_mask && !(wear_mask.item_flags & ABSTRACT)) ? wear_mask : "Empty"]
Neck:Obscured
Neck:[(wear_neck && !(wear_neck.item_flags & ABSTRACT)) ? wear_neck : "Empty"]
Eyes:Obscured
Eyes:[(glasses && !(glasses.item_flags & ABSTRACT)) ? glasses : "Empty"]
Ears:Obscured
Ears:[(ears && !(ears.item_flags & ABSTRACT)) ? ears : "Empty"]
 
Exosuit:[(wear_suit && !(wear_suit.item_flags & ABSTRACT)) ? wear_suit : "Empty"]
 ↳Suit Storage:[(s_store && !(s_store.item_flags & ABSTRACT)) ? s_store : "Empty"]" - if(has_breathable_mask && istype(s_store, /obj/item/tank)) - dat += " [internal ? "Disable Internals" : "Set Internals"]" - dat += "
 ↳Suit Storage:
Shoes:Obscured
Shoes:[(shoes && !(shoes.item_flags & ABSTRACT)) ? shoes : "Empty"]
Gloves:Obscured
Gloves:[(gloves && !(gloves.item_flags & ABSTRACT)) ? gloves : "Empty"]
Uniform:Obscured
Uniform:[(w_uniform && !(w_uniform.item_flags & ABSTRACT)) ? w_uniform : "Empty"]
 ↳Pockets:
 ↳ID:
 ↳Belt:
 ↳Belt:[(belt && !(belt.item_flags & ABSTRACT)) ? belt : "Empty"]" - if(has_breathable_mask && istype(belt, /obj/item/tank)) - dat += " [internal ? "Disable Internals" : "Set Internals"]" - dat += "
 ↳Pockets:[(l_store && !(l_store.item_flags & ABSTRACT)) ? "Left (Full)" : "Left (Empty)"]" - dat += " [(r_store && !(r_store.item_flags & ABSTRACT)) ? "Right (Full)" : "Right (Empty)"]
 ↳ID:[(wear_id && !(wear_id.item_flags & ABSTRACT)) ? wear_id : "Empty"]
Handcuffed: Remove
Legcuffed
- Close - "} - - var/datum/browser/popup = new(user, "mob[REF(src)]", "[src]", 440, 510) - popup.set_content(dat.Join()) - popup.open() - -// called when something steps onto a human -// this could be made more general, but for now just handle mulebot -/mob/living/carbon/human/Crossed(atom/movable/AM) - var/mob/living/simple_animal/bot/mulebot/MB = AM - if(istype(MB)) - MB.RunOver(src) - - //Hyper Change - Step on people - var/mob/living/carbon/human/H = AM - if(istype(H) && lying && H.a_intent != INTENT_HELP) - H.handle_micro_bump_other(src) - - spreadFire(AM) - -/mob/living/carbon/human/Topic(href, href_list) - if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) - if(href_list["embedded_object"]) - var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts - if(!L) - return - var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects - if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore - return - var/time_taken = I.embedding.embedded_unsafe_removal_time/I.w_class //Citadel Change from * to / - usr.visible_message("[usr] attempts to remove [I] from [usr.p_their()] [L.name].","You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)") - if(do_after(usr, time_taken, needhand = 1, target = src)) - remove_embedded_unsafe(L, I, usr) - /* CITADEL EDIT: remove_embedded_unsafe replaces this code - if(!I || !L || I.loc != src || !(I in L.embedded_objects)) - return - L.embedded_objects -= I - L.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class)//It hurts to rip it out, get surgery you dingus. - I.forceMove(get_turf(src)) - usr.put_in_hands(I) - usr.emote("scream") - usr.visible_message("[usr] successfully rips [I] out of [usr.p_their()] [L.name]!","You successfully remove [I] from your [L.name].") - if(!has_embedded_objects()) - clear_alert("embeddedobject") - SEND_SIGNAL(usr, COMSIG_CLEAR_MOOD_EVENT, "embedded") */ - return - - if(href_list["item"]) - var/slot = text2num(href_list["item"]) - if(slot in check_obscured_slots()) - to_chat(usr, "You can't reach that! Something is covering it.") - return - - if(href_list["pockets"]) - var/pocket_side = href_list["pockets"] - var/pocket_id = (pocket_side == "right" ? SLOT_R_STORE : SLOT_L_STORE) - var/obj/item/pocket_item = (pocket_id == SLOT_R_STORE ? r_store : l_store) - var/obj/item/place_item = usr.get_active_held_item() // Item to place in the pocket, if it's empty - - var/delay_denominator = 1 - if(pocket_item && !(pocket_item.item_flags & ABSTRACT)) - if(HAS_TRAIT(pocket_item, TRAIT_NODROP)) - to_chat(usr, "You try to empty [src]'s [pocket_side] pocket, it seems to be stuck!") - to_chat(usr, "You try to empty [src]'s [pocket_side] pocket.") - else if(place_item && place_item.mob_can_equip(src, usr, pocket_id, 1) && !(place_item.item_flags & ABSTRACT)) - to_chat(usr, "You try to place [place_item] into [src]'s [pocket_side] pocket.") - delay_denominator = 4 - else - return - - if(do_mob(usr, src, POCKET_STRIP_DELAY/delay_denominator, ignorehelditem = TRUE)) //placing an item into the pocket is 4 times faster - if(pocket_item) - if(pocket_item == (pocket_id == SLOT_R_STORE ? r_store : l_store)) //item still in the pocket we search - dropItemToGround(pocket_item) - if(!usr.can_hold_items() || !usr.put_in_hands(pocket_item)) - pocket_item.forceMove(drop_location()) - else - if(place_item) - if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE)) - usr.temporarilyRemoveItemFromInventory(place_item, TRUE) - equip_to_slot(place_item, pocket_id, TRUE) - //do nothing otherwise - - // Update strip window - if(usr.machine == src && in_range(src, usr)) - show_inv(usr) - else - // Display a warning if the user mocks up - to_chat(src, "You feel your [pocket_side] pocket being fumbled with!") - - ..() //CITADEL CHANGE - removes a tab from behind this ..() so that flavortext can actually be examined - - -///////HUDs/////// - if(href_list["hud"]) - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - var/perpname = get_face_name(get_id_name("")) - if(istype(H.glasses, /obj/item/clothing/glasses/hud) || istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud)) - var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general) - if(href_list["photo_front"] || href_list["photo_side"]) - if(R) - if(!H.canUseHUD()) - return - else if(!istype(H.glasses, /obj/item/clothing/glasses/hud) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/medical)) - return - var/obj/item/photo/P = null - if(href_list["photo_front"]) - P = R.fields["photo_front"] - else if(href_list["photo_side"]) - P = R.fields["photo_side"] - if(P) - P.show(H) - - if(href_list["hud"] == "m") - if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/medical)) - if(href_list["p_stat"]) - var/health_status = input(usr, "Specify a new physical status for this person.", "Medical HUD", R.fields["p_stat"]) in list("Active", "Physically Unfit", "*Unconscious*", "*Deceased*", "Cancel") - if(R) - if(!H.canUseHUD()) - return - else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/health) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/medical)) - return - if(health_status && health_status != "Cancel") - R.fields["p_stat"] = health_status - return - if(href_list["m_stat"]) - var/health_status = input(usr, "Specify a new mental status for this person.", "Medical HUD", R.fields["m_stat"]) in list("Stable", "*Watch*", "*Unstable*", "*Insane*", "Cancel") - if(R) - if(!H.canUseHUD()) - return - else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/health) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/medical)) - return - if(health_status && health_status != "Cancel") - R.fields["m_stat"] = health_status - return - if(href_list["evaluation"]) - if(!getBruteLoss() && !getFireLoss() && !getOxyLoss() && getToxLoss() < 20) - to_chat(usr, "No external injuries detected.
") - return - var/span = "notice" - var/status = "" - if(getBruteLoss()) - to_chat(usr, "Physical trauma analysis:") - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - var/brutedamage = BP.brute_dam - if(brutedamage > 0) - status = "received minor physical injuries." - span = "notice" - if(brutedamage > 20) - status = "been seriously damaged." - span = "danger" - if(brutedamage > 40) - status = "sustained major trauma!" - span = "userdanger" - if(brutedamage) - to_chat(usr, "[BP] appears to have [status]") - if(getFireLoss()) - to_chat(usr, "Analysis of skin burns:") - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - var/burndamage = BP.burn_dam - if(burndamage > 0) - status = "signs of minor burns." - span = "notice" - if(burndamage > 20) - status = "serious burns." - span = "danger" - if(burndamage > 40) - status = "major burns!" - span = "userdanger" - if(burndamage) - to_chat(usr, "[BP] appears to have [status]") - if(getOxyLoss()) - to_chat(usr, "Patient has signs of suffocation, emergency treatment may be required!") - if(getToxLoss() > 20) - to_chat(usr, "Gathered data is inconsistent with the analysis, possible cause: poisoning.") - - if(href_list["hud"] == "s") - if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) - if(usr.stat || usr == src) //|| !usr.canmove || usr.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at. - return //Non-fluff: This allows sec to set people to arrest as they get disarmed or beaten - // Checks the user has security clearence before allowing them to change arrest status via hud, comment out to enable all access - var/allowed_access = null - var/obj/item/clothing/glasses/G = H.glasses - if (!(G.obj_flags |= EMAGGED)) - if(H.wear_id) - var/list/access = H.wear_id.GetAccess() - if(ACCESS_SEC_DOORS in access) - allowed_access = H.get_authentification_name() - else - allowed_access = "@%&ERROR_%$*" - - - if(!allowed_access) - to_chat(H, "ERROR: Invalid Access") - return - - if(perpname) - R = find_record("name", perpname, GLOB.data_core.security) - if(R) - if(href_list["status"]) - var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", R.fields["criminal"]) in list("None", "*Arrest*", "Incarcerated", "Paroled", "Discharged", "Cancel") - if(setcriminal != "Cancel") - if(R) - if(H.canUseHUD()) - if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) - investigate_log("[key_name(src)] has been set from [R.fields["criminal"]] to [setcriminal] by [key_name(usr)].", INVESTIGATE_RECORDS) - R.fields["criminal"] = setcriminal - sec_hud_set_security_status() - return - - if(href_list["view"]) - if(R) - if(!H.canUseHUD()) - return - else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) - return - to_chat(usr, "Name: [R.fields["name"]] Criminal Status: [R.fields["criminal"]]") - to_chat(usr, "Minor Crimes:") - for(var/datum/data/crime/c in R.fields["mi_crim"]) - to_chat(usr, "Crime: [c.crimeName]") - to_chat(usr, "Details: [c.crimeDetails]") - to_chat(usr, "Added by [c.author] at [c.time]") - to_chat(usr, "----------") - to_chat(usr, "Major Crimes:") - for(var/datum/data/crime/c in R.fields["ma_crim"]) - to_chat(usr, "Crime: [c.crimeName]") - to_chat(usr, "Details: [c.crimeDetails]") - to_chat(usr, "Added by [c.author] at [c.time]") - to_chat(usr, "----------") - to_chat(usr, "Notes: [R.fields["notes"]]") - return - - if(href_list["add_crime"]) - switch(alert("What crime would you like to add?","Security HUD","Minor Crime","Major Crime","Cancel")) - if("Minor Crime") - if(R) - var/t1 = stripped_input("Please input minor crime names:", "Security HUD", "", null) - var/t2 = stripped_multiline_input("Please input minor crime details:", "Security HUD", "", null) - if(R) - if (!t1 || !t2 || !allowed_access) - return - else if(!H.canUseHUD()) - return - else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) - return - var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, STATION_TIME_TIMESTAMP("hh:mm:ss")) - GLOB.data_core.addMinorCrime(R.fields["id"], crime) - investigate_log("New Minor Crime: [t1]: [t2] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS) - to_chat(usr, "Successfully added a minor crime.") - return - if("Major Crime") - if(R) - var/t1 = stripped_input("Please input major crime names:", "Security HUD", "", null) - var/t2 = stripped_multiline_input("Please input major crime details:", "Security HUD", "", null) - if(R) - if (!t1 || !t2 || !allowed_access) - return - else if (!H.canUseHUD()) - return - else if (!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) - return - var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, STATION_TIME_TIMESTAMP("hh:mm:ss")) - GLOB.data_core.addMajorCrime(R.fields["id"], crime) - investigate_log("New Major Crime: [t1]: [t2] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS) - to_chat(usr, "Successfully added a major crime.") - return - - if(href_list["view_comment"]) - if(R) - if(!H.canUseHUD()) - return - else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) - return - to_chat(usr, "Comments/Log:") - var/counter = 1 - while(R.fields[text("com_[]", counter)]) - to_chat(usr, R.fields[text("com_[]", counter)]) - to_chat(usr, "----------") - counter++ - return - - if(href_list["add_comment"]) - if(R) - var/t1 = stripped_multiline_input("Add Comment:", "Secure. records", null, null) - if(R) - if (!t1 || !allowed_access) - return - else if(!H.canUseHUD()) - return - else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) - return - var/counter = 1 - while(R.fields[text("com_[]", counter)]) - counter++ - R.fields[text("com_[]", counter)] = text("Made by [] on [] [], []
[]", allowed_access, STATION_TIME_TIMESTAMP("hh:mm:ss"), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1) - to_chat(usr, "Successfully added comment.") - return - to_chat(usr, "Unable to locate a data core entry for this person.") - -/mob/living/carbon/human/proc/canUseHUD() - return !(src.stat || IsKnockdown() || IsStun() || src.restrained()) - -/mob/living/carbon/human/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE, bypass_immunity = FALSE) - . = 1 // Default to returning true. - if(user && !target_zone) - target_zone = user.zone_selected - if(HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && !bypass_immunity) - . = 0 - // If targeting the head, see if the head item is thin enough. - // If targeting anything else, see if the wear suit is thin enough. - if (!penetrate_thick) - if(above_neck(target_zone)) - if(head && istype(head, /obj/item/clothing)) - var/obj/item/clothing/CH = head - if (CH.clothing_flags & THICKMATERIAL) - . = 0 - else - if(wear_suit && istype(wear_suit, /obj/item/clothing)) - var/obj/item/clothing/CS = wear_suit - if (CS.clothing_flags & THICKMATERIAL) - . = 0 - if(!. && error_msg && user) - // Might need re-wording. - to_chat(user, "There is no exposed flesh or thin material [above_neck(target_zone) ? "on [p_their()] head" : "on [p_their()] body"].") - -/mob/living/carbon/human/proc/check_obscured_slots() - var/list/obscured = list() - - if(wear_suit) - if(wear_suit.flags_inv & HIDEGLOVES) - obscured |= SLOT_GLOVES - if(wear_suit.flags_inv & HIDEJUMPSUIT) - obscured |= SLOT_W_UNIFORM - if(wear_suit.flags_inv & HIDESHOES) - obscured |= SLOT_SHOES - - if(head) - if(head.flags_inv & HIDEMASK) - obscured |= SLOT_WEAR_MASK - if(head.flags_inv & HIDEEYES) - obscured |= SLOT_GLASSES - if(head.flags_inv & HIDEEARS) - obscured |= SLOT_EARS - - if(wear_mask) - if(wear_mask.flags_inv & HIDEEYES) - obscured |= SLOT_GLASSES - - if(obscured.len) - return obscured - else - return null - -/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) - if(judgement_criteria & JUDGE_EMAGGED) - return 10 //Everyone is a criminal! - - var/threatcount = 0 - - //Lasertag bullshit - if(lasercolor) - if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve - if(istype(wear_suit, /obj/item/clothing/suit/redtag)) - threatcount += 4 - if(is_holding_item_of_type(/obj/item/gun/energy/laser/redtag)) - threatcount += 4 - if(istype(belt, /obj/item/gun/energy/laser/redtag)) - threatcount += 2 - - if(lasercolor == "r") - if(istype(wear_suit, /obj/item/clothing/suit/bluetag)) - threatcount += 4 - if(is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag)) - threatcount += 4 - if(istype(belt, /obj/item/gun/energy/laser/bluetag)) - threatcount += 2 - - return threatcount - - //Check for ID - var/obj/item/card/id/idcard = get_idcard(FALSE) - if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown") - threatcount += 4 - - //Check for weapons - if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck) - if(!idcard || !(ACCESS_WEAPONS in idcard.access)) - for(var/obj/item/I in held_items) //if they're holding a gun - if(weaponcheck.Invoke(I)) - threatcount += 4 - if(weaponcheck.Invoke(belt) || weaponcheck.Invoke(back)) //if a weapon is present in the belt or back slot - threatcount += 2 //not enough to trigger look_for_perp() on it's own unless they also have criminal status. - - //Check for arrest warrant - if(judgement_criteria & JUDGE_RECORDCHECK) - var/perpname = get_face_name(get_id_name()) - var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) - if(R && R.fields["criminal"]) - switch(R.fields["criminal"]) - if("*Arrest*") - threatcount += 5 - if("Incarcerated") - threatcount += 2 - if("Paroled") - threatcount += 2 - - //Check for dresscode violations - if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/syndi) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi)) - threatcount += 4 //fuk u antags <3 //no you - - //mindshield implants imply trustworthyness - if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) - threatcount -= 1 - - //Agent cards lower threatlevel. - if(istype(idcard, /obj/item/card/id/syndicate)) - threatcount -= 2 - - return threatcount - - -//Used for new human mobs created by cloning/goleming/podding -/mob/living/carbon/human/proc/set_cloned_appearance() - if(gender == MALE) - facial_hair_style = "Full Beard" - else - facial_hair_style = "Shaved" - hair_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") - underwear = "Nude" - undershirt = "Nude" - update_body() - update_hair() - update_genitals() - -/mob/living/carbon/human/singularity_pull(S, current_size) - ..() - if(current_size >= STAGE_THREE) - for(var/obj/item/hand in held_items) - if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && dropItemToGround(hand)) - step_towards(hand, src) - to_chat(src, "\The [S] pulls \the [hand] from your grip!") - rad_act(current_size * 3) - if(mob_negates_gravity()) - return - -/mob/living/carbon/human/proc/do_cpr(mob/living/carbon/C) - CHECK_DNA_AND_SPECIES(C) - - if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH))) - to_chat(src, "[C.name] is dead!") - return - if(is_mouth_covered()) - to_chat(src, "Remove your mask first!") - return 0 - if(C.is_mouth_covered()) - to_chat(src, "Remove [p_their()] mask first!") - return 0 - - if(C.cpr_time < world.time + 30) - visible_message("[src] is trying to perform CPR on [C.name]!", \ - "You try to perform CPR on [C.name]... Hold still!") - if(!do_mob(src, C)) - to_chat(src, "You fail to perform CPR on [C]!") - return 0 - - var/they_breathe = !HAS_TRAIT(C, TRAIT_NOBREATH) - var/they_lung = C.getorganslot(ORGAN_SLOT_LUNGS) - - if(C.health > C.crit_threshold) - return - - src.visible_message("[src] performs CPR on [C.name]!", "You perform CPR on [C.name].") - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "perform_cpr", /datum/mood_event/perform_cpr) - C.cpr_time = world.time - log_combat(src, C, "CPRed") - - if(they_breathe && they_lung) - var/suff = min(C.getOxyLoss(), 7) - C.adjustOxyLoss(-suff) - C.updatehealth() - to_chat(C, "You feel a breath of fresh air enter your lungs... It feels good...") - else if(they_breathe && !they_lung) - to_chat(C, "You feel a breath of fresh air... but you don't feel any better...") - else - to_chat(C, "You feel a breath of fresh air... which is a sensation you don't recognise...") - -/mob/living/carbon/human/cuff_resist(obj/item/I) - if(dna && dna.check_mutation(HULK)) - say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") - if(..(I, cuff_break = FAST_CUFFBREAK)) - dropItemToGround(I) - else - if(..()) - dropItemToGround(I) - -/mob/living/carbon/human/clean_blood() - var/mob/living/carbon/human/H = src - if(H.gloves) - if(H.gloves.clean_blood()) - H.update_inv_gloves() - else - ..() // Clear the Blood_DNA list - if(H.bloody_hands) - H.bloody_hands = 0 - H.update_inv_gloves() - update_icons() //apply the now updated overlays to the mob - -/mob/living/carbon/human/wash_cream() - if(creamed) //clean both to prevent a rare bug - cut_overlay(mutable_appearance('icons/effects/creampie.dmi', "creampie_lizard")) - cut_overlay(mutable_appearance('icons/effects/creampie.dmi', "creampie_human")) - cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_normal")) - cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_large")) - creamed = FALSE - - -//Turns a mob black, flashes a skeleton overlay -//Just like a cartoon! -/mob/living/carbon/human/proc/electrocution_animation(anim_duration) - //Handle mutant parts if possible - if(dna && dna.species) - add_atom_colour("#000000", TEMPORARY_COLOUR_PRIORITY) - var/static/mutable_appearance/electrocution_skeleton_anim - if(!electrocution_skeleton_anim) - electrocution_skeleton_anim = mutable_appearance(icon, "electrocuted_base") - electrocution_skeleton_anim.appearance_flags |= RESET_COLOR|KEEP_APART - add_overlay(electrocution_skeleton_anim) - addtimer(CALLBACK(src, .proc/end_electrocution_animation, electrocution_skeleton_anim), anim_duration) - - else //or just do a generic animation - flick_overlay_view(image(icon,src,"electrocuted_generic",ABOVE_MOB_LAYER), src, anim_duration) - -/mob/living/carbon/human/proc/end_electrocution_animation(mutable_appearance/MA) - remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#000000") - cut_overlay(MA) - -/mob/living/carbon/human/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) - if(incapacitated() || lying ) - to_chat(src, "You can't do that right now!") - return FALSE - if(!Adjacent(M) && (M.loc != src)) - if((be_close == 0) || (!no_tk && (dna.check_mutation(TK) && tkMaxRangeCheck(src, M)))) - return TRUE - to_chat(src, "You are too far away!") - return FALSE - return TRUE - -/mob/living/carbon/human/resist_restraints() - if(wear_suit && wear_suit.breakouttime) - changeNext_move(CLICK_CD_BREAKOUT) - last_special = world.time + CLICK_CD_BREAKOUT - cuff_resist(wear_suit) - else - ..() - -/mob/living/carbon/human/replace_records_name(oldname,newname) // Only humans have records right now, move this up if changed. - for(var/list/L in list(GLOB.data_core.general,GLOB.data_core.medical,GLOB.data_core.security,GLOB.data_core.locked)) - var/datum/data/record/R = find_record("name", oldname, L) - if(R) - R.fields["name"] = newname - -/mob/living/carbon/human/get_total_tint() - . = ..() - if(glasses) - . += glasses.tint - -/mob/living/carbon/human/update_health_hud() - if(!client || !hud_used) - return - if(dna.species.update_health_hud()) - return - else - if(hud_used.healths) - var/health_amount = health - CLAMP(getStaminaLoss()-50, 0, 80)//CIT CHANGE - makes staminaloss have less of an impact on the health hud - if(..(health_amount)) //not dead - switch(hal_screwyhud) - if(SCREWYHUD_CRIT) - hud_used.healths.icon_state = "health6" - if(SCREWYHUD_DEAD) - hud_used.healths.icon_state = "health7" - if(SCREWYHUD_HEALTHY) - hud_used.healths.icon_state = "health0" - if(hud_used.healthdoll) - hud_used.healthdoll.cut_overlays() - if(stat != DEAD) - hud_used.healthdoll.icon_state = "healthdoll_OVERLAY" - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - var/damage = BP.burn_dam + BP.brute_dam - var/comparison = (BP.max_damage/5) - var/icon_num = 0 - if(damage) - icon_num = 1 - if(damage > (comparison)) - icon_num = 2 - if(damage > (comparison*2)) - icon_num = 3 - if(damage > (comparison*3)) - icon_num = 4 - if(damage > (comparison*4)) - icon_num = 5 - if(hal_screwyhud == SCREWYHUD_HEALTHY) - icon_num = 0 - if(icon_num) - hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[BP.body_zone][icon_num]")) - for(var/t in get_missing_limbs()) //Missing limbs - hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]6")) - for(var/t in get_disabled_limbs()) //Disabled limbs - hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]7")) - else - hud_used.healthdoll.icon_state = "healthdoll_DEAD" - -/mob/living/carbon/human/fully_heal(admin_revive = 0) - if(admin_revive) - regenerate_limbs() - regenerate_organs() - remove_all_embedded_objects() - set_heartattack(FALSE) - drunkenness = 0 - for(var/datum/mutation/human/HM in dna.mutations) - if(HM.quality != POSITIVE) - dna.remove_mutation(HM.name) - if(blood_volume < (BLOOD_VOLUME_NORMAL*blood_ratio)) - blood_volume = (BLOOD_VOLUME_NORMAL*blood_ratio) - ..() - -/mob/living/carbon/human/check_weakness(obj/item/weapon, mob/living/attacker) - . = ..() - if (dna && dna.species) - . += dna.species.check_weakness(weapon, attacker) - -/mob/living/carbon/human/is_literate() - return 1 - -/mob/living/carbon/human/can_hold_items() - return TRUE - -/mob/living/carbon/human/update_gravity(has_gravity,override = 0) - if(dna && dna.species) //prevents a runtime while a human is being monkeyfied - override = dna.species.override_float - ..() - -/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = 0, stun = 1, distance = 0, message = 1, toxic = 0) - if(blood && (NOBLOOD in dna.species.species_traits)) - if(message) - visible_message("[src] dry heaves!", \ - "You try to throw up, but there's nothing in your stomach!") - if(stun) - Knockdown(200) - return 1 - ..() - -/mob/living/carbon/human/vv_get_dropdown() - . = ..() - . += "---" - .["Make monkey"] = "?_src_=vars;[HrefToken()];makemonkey=[REF(src)]" - .["Set Species"] = "?_src_=vars;[HrefToken()];setspecies=[REF(src)]" - .["Make cyborg"] = "?_src_=vars;[HrefToken()];makerobot=[REF(src)]" - .["Make alien"] = "?_src_=vars;[HrefToken()];makealien=[REF(src)]" - .["Make slime"] = "?_src_=vars;[HrefToken()];makeslime=[REF(src)]" - .["Toggle Purrbation"] = "?_src_=vars;[HrefToken()];purrbation=[REF(src)]" - .["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]" - .["Add/Remove Quirks"] = "?_src_=vars;[HrefToken()];modquirks=[REF(src)]" - -/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user) - if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS) - //If they dragged themselves and we're currently aggressively grabbing them try to piggyback - if(user == target && can_piggyback(target)) - piggyback(target) - return - //If you dragged them to you and you're aggressively grabbing try to fireman carry them - else if(user != target) - fireman_carry(target) - return - . = ..() - -//src is the user that will be carrying, target is the mob to be carried -/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target) - return (istype(target) && target.stat == CONSCIOUS) - -/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target) - return (ishuman(target) && target.lying) - -/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target) - if(can_be_firemanned(target)) - visible_message("[src] starts lifting [target] onto their back...", - "You start lifting [target] onto your back...") - if(do_after(src, 30, TRUE, target)) - //Second check to make sure they're still valid to be carried - if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE)) - target.resting = FALSE - buckle_mob(target, TRUE, TRUE, 90, 1, 0) - return - visible_message("[src] fails to fireman carry [target]!") - else - to_chat(src, "You can't fireman carry [target] while they're standing!") - -/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target) - if(can_piggyback(target)) - visible_message("[target] starts to climb onto [src]...") - if(do_after(target, 15, target = src)) - if(can_piggyback(target)) - if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE)) - target.visible_message("[target] can't hang onto [src]!") - return - buckle_mob(target, TRUE, TRUE, FALSE, 0, 2) - else - visible_message("[target] fails to climb onto [src]!") - else - to_chat(target, "You can't piggyback ride [src] right now!") - -/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0) - if(!force)//humans are only meant to be ridden through piggybacking and special cases - return - if(!is_type_in_typecache(target, can_ride_typecache)) - target.visible_message("[target] really can't seem to mount [src]...") - return - buckle_lying = lying_buckle - var/datum/component/riding/human/riding_datum = LoadComponent(/datum/component/riding/human) - if(target_hands_needed) - riding_datum.ride_check_rider_restrained = TRUE - if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled) - return - var/equipped_hands_self - var/equipped_hands_target - if(hands_needed) - equipped_hands_self = riding_datum.equip_buckle_inhands(src, hands_needed, target) - if(target_hands_needed) - equipped_hands_target = riding_datum.equip_buckle_inhands(target, target_hands_needed) - - if(hands_needed || target_hands_needed) - if(hands_needed && !equipped_hands_self) - src.visible_message("[src] can't get a grip on [target] because their hands are full!", - "You can't get a grip on [target] because your hands are full!") - return - else if(target_hands_needed && !equipped_hands_target) - target.visible_message("[target] can't get a grip on [src] because their hands are full!", - "You can't get a grip on [src] because your hands are full!") - return - - stop_pulling() - riding_datum.handle_vehicle_layer() - . = ..(target, force, check_loc) - -/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this - for(var/obj/item/clothing/C in get_equipped_items()) //doesn't include pockets - if(C.blocks_shove_knockdown) - return TRUE - return FALSE - -/mob/living/carbon/human/proc/clear_shove_slowdown() - remove_movespeed_modifier(SHOVE_SLOWDOWN_ID) - var/active_item = get_active_held_item() - if(is_type_in_typecache(active_item, GLOB.shove_disarming_types)) - visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE) - -/mob/living/carbon/human/do_after_coefficent() - . = ..() - . *= physiology.do_after_speed - -/mob/living/carbon/human/species - var/race = null - -/mob/living/carbon/human/species/Initialize() - . = ..() - set_species(race) - -/mob/living/carbon/human/species/abductor - race = /datum/species/abductor - -/mob/living/carbon/human/species/android - race = /datum/species/android - -/mob/living/carbon/human/species/angel - race = /datum/species/angel - -/mob/living/carbon/human/species/corporate - race = /datum/species/corporate - -/mob/living/carbon/human/species/dullahan - race = /datum/species/dullahan - -/mob/living/carbon/human/species/felinid - race = /datum/species/human/felinid - -/mob/living/carbon/human/species/fly - race = /datum/species/fly - -/mob/living/carbon/human/species/golem - race = /datum/species/golem - -/mob/living/carbon/human/species/golem/random - race = /datum/species/golem/random - -/mob/living/carbon/human/species/golem/adamantine - race = /datum/species/golem/adamantine - -/mob/living/carbon/human/species/golem/plasma - race = /datum/species/golem/plasma - -/mob/living/carbon/human/species/golem/diamond - race = /datum/species/golem/diamond - -/mob/living/carbon/human/species/golem/gold - race = /datum/species/golem/gold - -/mob/living/carbon/human/species/golem/silver - race = /datum/species/golem/silver - -/mob/living/carbon/human/species/golem/plasteel - race = /datum/species/golem/plasteel - -/mob/living/carbon/human/species/golem/titanium - race = /datum/species/golem/titanium - -/mob/living/carbon/human/species/golem/plastitanium - race = /datum/species/golem/plastitanium - -/mob/living/carbon/human/species/golem/alien_alloy - race = /datum/species/golem/alloy - -/mob/living/carbon/human/species/golem/wood - race = /datum/species/golem/wood - -/mob/living/carbon/human/species/golem/uranium - race = /datum/species/golem/uranium - -/mob/living/carbon/human/species/golem/sand - race = /datum/species/golem/sand - -/mob/living/carbon/human/species/golem/glass - race = /datum/species/golem/glass - -/mob/living/carbon/human/species/golem/bluespace - race = /datum/species/golem/bluespace - -/mob/living/carbon/human/species/golem/bananium - race = /datum/species/golem/bananium - -/mob/living/carbon/human/species/golem/blood_cult - race = /datum/species/golem/runic - -/mob/living/carbon/human/species/golem/cloth - race = /datum/species/golem/cloth - -/mob/living/carbon/human/species/golem/plastic - race = /datum/species/golem/plastic - -/mob/living/carbon/human/species/golem/clockwork - race = /datum/species/golem/clockwork - -/mob/living/carbon/human/species/golem/clockwork/no_scrap - race = /datum/species/golem/clockwork/no_scrap - -/mob/living/carbon/human/species/jelly - race = /datum/species/jelly - -/mob/living/carbon/human/species/jelly/slime - race = /datum/species/jelly/slime - -/mob/living/carbon/human/species/jelly/stargazer - race = /datum/species/jelly/stargazer - -/mob/living/carbon/human/species/jelly/luminescent - race = /datum/species/jelly/luminescent - -/mob/living/carbon/human/species/lizard - race = /datum/species/lizard - -/mob/living/carbon/human/species/lizard/ashwalker - race = /datum/species/lizard/ashwalker - -/mob/living/carbon/human/species/moth - race = /datum/species/moth - -/mob/living/carbon/human/species/mush - race = /datum/species/mush - -/mob/living/carbon/human/species/plasma - race = /datum/species/plasmaman - -/mob/living/carbon/human/species/pod - race = /datum/species/pod - -/mob/living/carbon/human/species/shadow - race = /datum/species/shadow - -/mob/living/carbon/human/species/shadow/nightmare - race = /datum/species/shadow/nightmare - -/mob/living/carbon/human/species/skeleton - race = /datum/species/skeleton - -/mob/living/carbon/human/species/synth - race = /datum/species/synth - -/mob/living/carbon/human/species/synth/military - race = /datum/species/synth/military - -/mob/living/carbon/human/species/vampire - race = /datum/species/vampire - -/mob/living/carbon/human/species/zombie - race = /datum/species/zombie - -/mob/living/carbon/human/species/zombie/infectious - race = /datum/species/zombie/infectious - -/mob/living/carbon/human/species/zombie/krokodil_addict - race = /datum/species/krokodil_addict - -/mob/living/carbon/human/species/mammal - race = /datum/species/mammal - -/mob/living/carbon/human/species/insect - race = /datum/species/insect - -/mob/living/carbon/human/species/xeno - race = /datum/species/xeno - -/mob/living/carbon/human/species/ipc - race = /datum/species/ipc - -/mob/living/carbon/human/species/roundstartslime - race = /datum/species/jelly/roundstartslime -//define holder_type on nerds we wanna commit scoop to -/* /mob/living/carbon/human - var/holder_type = /obj/item/clothing/head/mob_holder/micro - can_be_held = "micro" -*/ - +/mob/living/carbon/human + name = "Unknown" + real_name = "Unknown" + icon = 'icons/mob/human.dmi' + icon_state = "caucasian_m" + appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE + +/mob/living/carbon/human/Initialize() + verbs += /mob/living/proc/mob_sleep + verbs += /mob/living/proc/lay_down + verbs += /mob/living/carbon/human/proc/underwear_toggle //fwee + time_initialized = world.time + + //initialize limbs first + create_bodyparts() + + //initialize dna. for spawned humans; overwritten by other code + create_dna(src) + randomize_human(src) + dna.initialize_dna() + + if(dna.species) + set_species(dna.species.type) + + //initialise organs + create_internal_organs() //most of it is done in set_species now, this is only for parent call + physiology = new() + + handcrafting = new() + + . = ..() + + if(CONFIG_GET(flag/disable_stambuffer)) + togglesprint() + + AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /mob/living/carbon/human/clean_blood))) + + +/mob/living/carbon/human/ComponentInitialize() + . = ..() + if(!CONFIG_GET(flag/disable_human_mood)) + AddComponent(/datum/component/mood) + AddElement(/datum/element/mob_holder/micro, "micro") + +/mob/living/carbon/human/Destroy() + QDEL_NULL(physiology) + QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff + return ..() + + +/mob/living/carbon/human/OpenCraftingMenu() + handcrafting.ui_interact(src) + +/mob/living/carbon/human/prepare_data_huds() + //Update med hud images... + ..() + //...sec hud images... + sec_hud_set_ID() + sec_hud_set_implants() + sec_hud_set_security_status() + //...and display them. + add_to_all_human_data_huds() + + +/mob/living/carbon/human/Stat() + ..() + //Same thing from mob + if(statpanel("Status")) + if(tickrefresh == 1) + sList2 = list() + sList2 += "Intent: [a_intent]" + sList2 += "Move Mode: [m_intent]" + if (internal) + if (!internal.air_contents) + qdel(internal) + else + sList2 += "Internal Atmosphere Info: "+ "[internal.name]" + sList2 += "Tank Pressure: "+ "[internal.air_contents.return_pressure()]" + sList2 += "Distribution Pressure: "+ "[internal.distribute_pressure]" + if(mind) + var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) + if(changeling) + sList2 += "Chemical Storage: " + "[changeling.chem_charges]/[changeling.chem_storage]" + sList2 += "Absorbed DNA: "+ "[changeling.absorbedcount]" + if (sList2 != null) + stat(null, "[sList2.Join("\n\n")]") + + //NINJACODE + if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja. + var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit + if(statpanel("SpiderOS")) + stat("SpiderOS Status:","[SN.s_initialized ? "Initialized" : "Disabled"]") + stat("Current Time:", "[STATION_TIME_TIMESTAMP("hh:mm:ss")]") + if(SN.s_initialized) + //Suit gear + stat("Energy Charge:", "[round(SN.cell.charge/100)]%") + stat("Smoke Bombs:", "\Roman [SN.s_bombs]") + //Ninja status + stat("Fingerprints:", "[md5(dna.uni_identity)]") + stat("Unique Identity:", "[dna.unique_enzymes]") + stat("Overall Status:", "[stat > 1 ? "dead" : "[health]% healthy"]") + stat("Nutrition Status:", "[nutrition]") + stat("Oxygen Loss:", "[getOxyLoss()]") + stat("Toxin Levels:", "[getToxLoss()]") + stat("Burn Severity:", "[getFireLoss()]") + stat("Brute Trauma:", "[getBruteLoss()]") + stat("Radiation Levels:","[radiation] rad") + stat("Body Temperature:","[bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)") + + //Diseases + if(diseases.len) + stat("Viruses:", null) + for(var/thing in diseases) + var/datum/disease/D = thing + stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]") + + +/mob/living/carbon/human/show_inv(mob/user) + user.set_machine(src) + var/has_breathable_mask = istype(wear_mask, /obj/item/clothing/mask) + var/list/obscured = check_obscured_slots() + var/list/dat = list() + + dat += "" + for(var/i in 1 to held_items.len) + var/obj/item/I = get_item_for_held_index(i) + dat += "" + dat += "" + + dat += "" + + dat += "" + + if(SLOT_WEAR_MASK in obscured) + dat += "" + else + dat += "" + + if(SLOT_NECK in obscured) + dat += "" + else + dat += "" + + if(SLOT_GLASSES in obscured) + dat += "" + else + dat += "" + + if(SLOT_EARS in obscured) + dat += "" + else + dat += "" + + dat += "" + + dat += "" + if(wear_suit) + dat += "" + else + dat += "" + + if(SLOT_SHOES in obscured) + dat += "" + else + dat += "" + + if(SLOT_GLOVES in obscured) + dat += "" + else + dat += "" + + if(SLOT_W_UNIFORM in obscured) + dat += "" + else + dat += "" + + if((w_uniform == null && !(dna && dna.species.nojumpsuit)) || (SLOT_W_UNIFORM in obscured)) + dat += "" + dat += "" + dat += "" + else + dat += "" + dat += "" + dat += "" + + if(handcuffed) + dat += "" + if(legcuffed) + dat += "" + + dat += {"
[get_held_index_name(i)]:[(I && !(I.item_flags & ABSTRACT)) ? I : "Empty"]
 
Back:[(back && !(back.item_flags & ABSTRACT)) ? back : "Empty"]" + if(has_breathable_mask && istype(back, /obj/item/tank)) + dat += " [internal ? "Disable Internals" : "Set Internals"]" + + dat += "
 
Head:[(head && !(head.item_flags & ABSTRACT)) ? head : "Empty"]
Mask:Obscured
Mask:[(wear_mask && !(wear_mask.item_flags & ABSTRACT)) ? wear_mask : "Empty"]
Neck:Obscured
Neck:[(wear_neck && !(wear_neck.item_flags & ABSTRACT)) ? wear_neck : "Empty"]
Eyes:Obscured
Eyes:[(glasses && !(glasses.item_flags & ABSTRACT)) ? glasses : "Empty"]
Ears:Obscured
Ears:[(ears && !(ears.item_flags & ABSTRACT)) ? ears : "Empty"]
 
Exosuit:[(wear_suit && !(wear_suit.item_flags & ABSTRACT)) ? wear_suit : "Empty"]
 ↳Suit Storage:[(s_store && !(s_store.item_flags & ABSTRACT)) ? s_store : "Empty"]" + if(has_breathable_mask && istype(s_store, /obj/item/tank)) + dat += " [internal ? "Disable Internals" : "Set Internals"]" + dat += "
 ↳Suit Storage:
Shoes:Obscured
Shoes:[(shoes && !(shoes.item_flags & ABSTRACT)) ? shoes : "Empty"]
Gloves:Obscured
Gloves:[(gloves && !(gloves.item_flags & ABSTRACT)) ? gloves : "Empty"]
Uniform:Obscured
Uniform:[(w_uniform && !(w_uniform.item_flags & ABSTRACT)) ? w_uniform : "Empty"]
 ↳Pockets:
 ↳ID:
 ↳Belt:
 ↳Belt:[(belt && !(belt.item_flags & ABSTRACT)) ? belt : "Empty"]" + if(has_breathable_mask && istype(belt, /obj/item/tank)) + dat += " [internal ? "Disable Internals" : "Set Internals"]" + dat += "
 ↳Pockets:[(l_store && !(l_store.item_flags & ABSTRACT)) ? "Left (Full)" : "Left (Empty)"]" + dat += " [(r_store && !(r_store.item_flags & ABSTRACT)) ? "Right (Full)" : "Right (Empty)"]
 ↳ID:[(wear_id && !(wear_id.item_flags & ABSTRACT)) ? wear_id : "Empty"]
Handcuffed: Remove
Legcuffed
+ Close + "} + + var/datum/browser/popup = new(user, "mob[REF(src)]", "[src]", 440, 510) + popup.set_content(dat.Join()) + popup.open() + +// called when something steps onto a human +// this could be made more general, but for now just handle mulebot +/mob/living/carbon/human/Crossed(atom/movable/AM) + var/mob/living/simple_animal/bot/mulebot/MB = AM + if(istype(MB)) + MB.RunOver(src) + + //Hyper Change - Step on people + var/mob/living/carbon/human/H = AM + if(istype(H) && lying && H.a_intent != INTENT_HELP) + H.handle_micro_bump_other(src) + + spreadFire(AM) + +/mob/living/carbon/human/Topic(href, href_list) + if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) + if(href_list["embedded_object"]) + var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts + if(!L) + return + var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects + if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore + return + var/time_taken = I.embedding.embedded_unsafe_removal_time/I.w_class //Citadel Change from * to / + usr.visible_message("[usr] attempts to remove [I] from [usr.p_their()] [L.name].","You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)") + if(do_after(usr, time_taken, needhand = 1, target = src)) + remove_embedded_unsafe(L, I, usr) + /* CITADEL EDIT: remove_embedded_unsafe replaces this code + if(!I || !L || I.loc != src || !(I in L.embedded_objects)) + return + L.embedded_objects -= I + L.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class)//It hurts to rip it out, get surgery you dingus. + I.forceMove(get_turf(src)) + usr.put_in_hands(I) + usr.emote("scream") + usr.visible_message("[usr] successfully rips [I] out of [usr.p_their()] [L.name]!","You successfully remove [I] from your [L.name].") + if(!has_embedded_objects()) + clear_alert("embeddedobject") + SEND_SIGNAL(usr, COMSIG_CLEAR_MOOD_EVENT, "embedded") */ + return + + if(href_list["item"]) + var/slot = text2num(href_list["item"]) + if(slot in check_obscured_slots()) + to_chat(usr, "You can't reach that! Something is covering it.") + return + + if(href_list["pockets"]) + var/pocket_side = href_list["pockets"] + var/pocket_id = (pocket_side == "right" ? SLOT_R_STORE : SLOT_L_STORE) + var/obj/item/pocket_item = (pocket_id == SLOT_R_STORE ? r_store : l_store) + var/obj/item/place_item = usr.get_active_held_item() // Item to place in the pocket, if it's empty + + var/delay_denominator = 1 + if(pocket_item && !(pocket_item.item_flags & ABSTRACT)) + if(HAS_TRAIT(pocket_item, TRAIT_NODROP)) + to_chat(usr, "You try to empty [src]'s [pocket_side] pocket, it seems to be stuck!") + to_chat(usr, "You try to empty [src]'s [pocket_side] pocket.") + else if(place_item && place_item.mob_can_equip(src, usr, pocket_id, 1) && !(place_item.item_flags & ABSTRACT)) + to_chat(usr, "You try to place [place_item] into [src]'s [pocket_side] pocket.") + delay_denominator = 4 + else + return + + if(do_mob(usr, src, POCKET_STRIP_DELAY/delay_denominator, ignorehelditem = TRUE)) //placing an item into the pocket is 4 times faster + if(pocket_item) + if(pocket_item == (pocket_id == SLOT_R_STORE ? r_store : l_store)) //item still in the pocket we search + dropItemToGround(pocket_item) + if(!usr.can_hold_items() || !usr.put_in_hands(pocket_item)) + pocket_item.forceMove(drop_location()) + else + if(place_item) + if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE)) + usr.temporarilyRemoveItemFromInventory(place_item, TRUE) + equip_to_slot(place_item, pocket_id, TRUE) + //do nothing otherwise + + // Update strip window + if(usr.machine == src && in_range(src, usr)) + show_inv(usr) + else + // Display a warning if the user mocks up + to_chat(src, "You feel your [pocket_side] pocket being fumbled with!") + + ..() //CITADEL CHANGE - removes a tab from behind this ..() so that flavortext can actually be examined + + +///////HUDs/////// + if(href_list["hud"]) + if(ishuman(usr)) + var/mob/living/carbon/human/H = usr + var/perpname = get_face_name(get_id_name("")) + if(istype(H.glasses, /obj/item/clothing/glasses/hud) || istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud)) + var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general) + if(href_list["photo_front"] || href_list["photo_side"]) + if(R) + if(!H.canUseHUD()) + return + else if(!istype(H.glasses, /obj/item/clothing/glasses/hud) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/medical)) + return + var/obj/item/photo/P = null + if(href_list["photo_front"]) + P = R.fields["photo_front"] + else if(href_list["photo_side"]) + P = R.fields["photo_side"] + if(P) + P.show(H) + + if(href_list["hud"] == "m") + if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/medical)) + if(href_list["p_stat"]) + var/health_status = input(usr, "Specify a new physical status for this person.", "Medical HUD", R.fields["p_stat"]) in list("Active", "Physically Unfit", "*Unconscious*", "*Deceased*", "Cancel") + if(R) + if(!H.canUseHUD()) + return + else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/health) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/medical)) + return + if(health_status && health_status != "Cancel") + R.fields["p_stat"] = health_status + return + if(href_list["m_stat"]) + var/health_status = input(usr, "Specify a new mental status for this person.", "Medical HUD", R.fields["m_stat"]) in list("Stable", "*Watch*", "*Unstable*", "*Insane*", "Cancel") + if(R) + if(!H.canUseHUD()) + return + else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/health) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/medical)) + return + if(health_status && health_status != "Cancel") + R.fields["m_stat"] = health_status + return + if(href_list["evaluation"]) + if(!getBruteLoss() && !getFireLoss() && !getOxyLoss() && getToxLoss() < 20) + to_chat(usr, "No external injuries detected.
") + return + var/span = "notice" + var/status = "" + if(getBruteLoss()) + to_chat(usr, "Physical trauma analysis:") + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + var/brutedamage = BP.brute_dam + if(brutedamage > 0) + status = "received minor physical injuries." + span = "notice" + if(brutedamage > 20) + status = "been seriously damaged." + span = "danger" + if(brutedamage > 40) + status = "sustained major trauma!" + span = "userdanger" + if(brutedamage) + to_chat(usr, "[BP] appears to have [status]") + if(getFireLoss()) + to_chat(usr, "Analysis of skin burns:") + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + var/burndamage = BP.burn_dam + if(burndamage > 0) + status = "signs of minor burns." + span = "notice" + if(burndamage > 20) + status = "serious burns." + span = "danger" + if(burndamage > 40) + status = "major burns!" + span = "userdanger" + if(burndamage) + to_chat(usr, "[BP] appears to have [status]") + if(getOxyLoss()) + to_chat(usr, "Patient has signs of suffocation, emergency treatment may be required!") + if(getToxLoss() > 20) + to_chat(usr, "Gathered data is inconsistent with the analysis, possible cause: poisoning.") + + if(href_list["hud"] == "s") + if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) + if(usr.stat || usr == src) //|| !usr.canmove || usr.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at. + return //Non-fluff: This allows sec to set people to arrest as they get disarmed or beaten + // Checks the user has security clearence before allowing them to change arrest status via hud, comment out to enable all access + var/allowed_access = null + var/obj/item/clothing/glasses/G = H.glasses + if (!(G.obj_flags |= EMAGGED)) + if(H.wear_id) + var/list/access = H.wear_id.GetAccess() + if(ACCESS_SEC_DOORS in access) + allowed_access = H.get_authentification_name() + else + allowed_access = "@%&ERROR_%$*" + + + if(!allowed_access) + to_chat(H, "ERROR: Invalid Access") + return + + if(perpname) + R = find_record("name", perpname, GLOB.data_core.security) + if(R) + if(href_list["status"]) + var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", R.fields["criminal"]) in list("None", "*Arrest*", "Incarcerated", "Paroled", "Discharged", "Cancel") + if(setcriminal != "Cancel") + if(R) + if(H.canUseHUD()) + if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) + investigate_log("[key_name(src)] has been set from [R.fields["criminal"]] to [setcriminal] by [key_name(usr)].", INVESTIGATE_RECORDS) + R.fields["criminal"] = setcriminal + sec_hud_set_security_status() + return + + if(href_list["view"]) + if(R) + if(!H.canUseHUD()) + return + else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) + return + to_chat(usr, "Name: [R.fields["name"]] Criminal Status: [R.fields["criminal"]]") + to_chat(usr, "Minor Crimes:") + for(var/datum/data/crime/c in R.fields["mi_crim"]) + to_chat(usr, "Crime: [c.crimeName]") + to_chat(usr, "Details: [c.crimeDetails]") + to_chat(usr, "Added by [c.author] at [c.time]") + to_chat(usr, "----------") + to_chat(usr, "Major Crimes:") + for(var/datum/data/crime/c in R.fields["ma_crim"]) + to_chat(usr, "Crime: [c.crimeName]") + to_chat(usr, "Details: [c.crimeDetails]") + to_chat(usr, "Added by [c.author] at [c.time]") + to_chat(usr, "----------") + to_chat(usr, "Notes: [R.fields["notes"]]") + return + + if(href_list["add_crime"]) + switch(alert("What crime would you like to add?","Security HUD","Minor Crime","Major Crime","Cancel")) + if("Minor Crime") + if(R) + var/t1 = stripped_input("Please input minor crime names:", "Security HUD", "", null) + var/t2 = stripped_multiline_input("Please input minor crime details:", "Security HUD", "", null) + if(R) + if (!t1 || !t2 || !allowed_access) + return + else if(!H.canUseHUD()) + return + else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) + return + var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, STATION_TIME_TIMESTAMP("hh:mm:ss")) + GLOB.data_core.addMinorCrime(R.fields["id"], crime) + investigate_log("New Minor Crime: [t1]: [t2] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS) + to_chat(usr, "Successfully added a minor crime.") + return + if("Major Crime") + if(R) + var/t1 = stripped_input("Please input major crime names:", "Security HUD", "", null) + var/t2 = stripped_multiline_input("Please input major crime details:", "Security HUD", "", null) + if(R) + if (!t1 || !t2 || !allowed_access) + return + else if (!H.canUseHUD()) + return + else if (!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) + return + var/crime = GLOB.data_core.createCrimeEntry(t1, t2, allowed_access, STATION_TIME_TIMESTAMP("hh:mm:ss")) + GLOB.data_core.addMajorCrime(R.fields["id"], crime) + investigate_log("New Major Crime: [t1]: [t2] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS) + to_chat(usr, "Successfully added a major crime.") + return + + if(href_list["view_comment"]) + if(R) + if(!H.canUseHUD()) + return + else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) + return + to_chat(usr, "Comments/Log:") + var/counter = 1 + while(R.fields[text("com_[]", counter)]) + to_chat(usr, R.fields[text("com_[]", counter)]) + to_chat(usr, "----------") + counter++ + return + + if(href_list["add_comment"]) + if(R) + var/t1 = stripped_multiline_input("Add Comment:", "Secure. records", null, null) + if(R) + if (!t1 || !allowed_access) + return + else if(!H.canUseHUD()) + return + else if(!istype(H.glasses, /obj/item/clothing/glasses/hud/security) && !istype(H.getorganslot(ORGAN_SLOT_HUD), /obj/item/organ/cyberimp/eyes/hud/security)) + return + var/counter = 1 + while(R.fields[text("com_[]", counter)]) + counter++ + R.fields[text("com_[]", counter)] = text("Made by [] on [] [], []
[]", allowed_access, STATION_TIME_TIMESTAMP("hh:mm:ss"), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1) + to_chat(usr, "Successfully added comment.") + return + to_chat(usr, "Unable to locate a data core entry for this person.") + +/mob/living/carbon/human/proc/canUseHUD() + return !(src.stat || IsKnockdown() || IsStun() || src.restrained()) + +/mob/living/carbon/human/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE, bypass_immunity = FALSE) + . = 1 // Default to returning true. + if(user && !target_zone) + target_zone = user.zone_selected + if(HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && !bypass_immunity) + . = 0 + // If targeting the head, see if the head item is thin enough. + // If targeting anything else, see if the wear suit is thin enough. + if (!penetrate_thick) + if(above_neck(target_zone)) + if(head && istype(head, /obj/item/clothing)) + var/obj/item/clothing/CH = head + if (CH.clothing_flags & THICKMATERIAL) + . = 0 + else + if(wear_suit && istype(wear_suit, /obj/item/clothing)) + var/obj/item/clothing/CS = wear_suit + if (CS.clothing_flags & THICKMATERIAL) + . = 0 + if(!. && error_msg && user) + // Might need re-wording. + to_chat(user, "There is no exposed flesh or thin material [above_neck(target_zone) ? "on [p_their()] head" : "on [p_their()] body"].") + +/mob/living/carbon/human/proc/check_obscured_slots() + var/list/obscured = list() + + if(wear_suit) + if(wear_suit.flags_inv & HIDEGLOVES) + obscured |= SLOT_GLOVES + if(wear_suit.flags_inv & HIDEJUMPSUIT) + obscured |= SLOT_W_UNIFORM + if(wear_suit.flags_inv & HIDESHOES) + obscured |= SLOT_SHOES + + if(head) + if(head.flags_inv & HIDEMASK) + obscured |= SLOT_WEAR_MASK + if(head.flags_inv & HIDEEYES) + obscured |= SLOT_GLASSES + if(head.flags_inv & HIDEEARS) + obscured |= SLOT_EARS + + if(wear_mask) + if(wear_mask.flags_inv & HIDEEYES) + obscured |= SLOT_GLASSES + + if(obscured.len) + return obscured + else + return null + +/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) + if(judgement_criteria & JUDGE_EMAGGED) + return 10 //Everyone is a criminal! + + var/threatcount = 0 + + //Lasertag bullshit + if(lasercolor) + if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve + if(istype(wear_suit, /obj/item/clothing/suit/redtag)) + threatcount += 4 + if(is_holding_item_of_type(/obj/item/gun/energy/laser/redtag)) + threatcount += 4 + if(istype(belt, /obj/item/gun/energy/laser/redtag)) + threatcount += 2 + + if(lasercolor == "r") + if(istype(wear_suit, /obj/item/clothing/suit/bluetag)) + threatcount += 4 + if(is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag)) + threatcount += 4 + if(istype(belt, /obj/item/gun/energy/laser/bluetag)) + threatcount += 2 + + return threatcount + + //Check for ID + var/obj/item/card/id/idcard = get_idcard(FALSE) + if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown") + threatcount += 4 + + //Check for weapons + if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck) + if(!idcard || !(ACCESS_WEAPONS in idcard.access)) + for(var/obj/item/I in held_items) //if they're holding a gun + if(weaponcheck.Invoke(I)) + threatcount += 4 + if(weaponcheck.Invoke(belt) || weaponcheck.Invoke(back)) //if a weapon is present in the belt or back slot + threatcount += 2 //not enough to trigger look_for_perp() on it's own unless they also have criminal status. + + //Check for arrest warrant + if(judgement_criteria & JUDGE_RECORDCHECK) + var/perpname = get_face_name(get_id_name()) + var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) + if(R && R.fields["criminal"]) + switch(R.fields["criminal"]) + if("*Arrest*") + threatcount += 5 + if("Incarcerated") + threatcount += 2 + if("Paroled") + threatcount += 2 + + //Check for dresscode violations + if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/syndi) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi)) + threatcount += 4 //fuk u antags <3 //no you + + //mindshield implants imply trustworthyness + if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) + threatcount -= 1 + + //Agent cards lower threatlevel. + if(istype(idcard, /obj/item/card/id/syndicate)) + threatcount -= 2 + + return threatcount + + +//Used for new human mobs created by cloning/goleming/podding +/mob/living/carbon/human/proc/set_cloned_appearance() + if(gender == MALE) + facial_hair_style = "Full Beard" + else + facial_hair_style = "Shaved" + hair_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") + underwear = "Nude" + undershirt = "Nude" + update_body() + update_hair() + update_genitals() + +/mob/living/carbon/human/singularity_pull(S, current_size) + ..() + if(current_size >= STAGE_THREE) + for(var/obj/item/hand in held_items) + if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && dropItemToGround(hand)) + step_towards(hand, src) + to_chat(src, "\The [S] pulls \the [hand] from your grip!") + rad_act(current_size * 3) + if(mob_negates_gravity()) + return + +/mob/living/carbon/human/proc/do_cpr(mob/living/carbon/C) + CHECK_DNA_AND_SPECIES(C) + + if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH))) + to_chat(src, "[C.name] is dead!") + return + if(is_mouth_covered()) + to_chat(src, "Remove your mask first!") + return 0 + if(C.is_mouth_covered()) + to_chat(src, "Remove [p_their()] mask first!") + return 0 + + if(C.cpr_time < world.time + 30) + visible_message("[src] is trying to perform CPR on [C.name]!", \ + "You try to perform CPR on [C.name]... Hold still!") + if(!do_mob(src, C)) + to_chat(src, "You fail to perform CPR on [C]!") + return 0 + + var/they_breathe = !HAS_TRAIT(C, TRAIT_NOBREATH) + var/they_lung = C.getorganslot(ORGAN_SLOT_LUNGS) + + if(C.health > C.crit_threshold) + return + + src.visible_message("[src] performs CPR on [C.name]!", "You perform CPR on [C.name].") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "perform_cpr", /datum/mood_event/perform_cpr) + C.cpr_time = world.time + log_combat(src, C, "CPRed") + + if(they_breathe && they_lung) + var/suff = min(C.getOxyLoss(), 7) + C.adjustOxyLoss(-suff) + C.updatehealth() + to_chat(C, "You feel a breath of fresh air enter your lungs... It feels good...") + else if(they_breathe && !they_lung) + to_chat(C, "You feel a breath of fresh air... but you don't feel any better...") + else + to_chat(C, "You feel a breath of fresh air... which is a sensation you don't recognise...") + +/mob/living/carbon/human/cuff_resist(obj/item/I) + if(dna && dna.check_mutation(HULK)) + say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") + if(..(I, cuff_break = FAST_CUFFBREAK)) + dropItemToGround(I) + else + if(..()) + dropItemToGround(I) + +/mob/living/carbon/human/clean_blood() + var/mob/living/carbon/human/H = src + if(H.gloves) + if(H.gloves.clean_blood()) + H.update_inv_gloves() + else + ..() // Clear the Blood_DNA list + if(H.bloody_hands) + H.bloody_hands = 0 + H.update_inv_gloves() + update_icons() //apply the now updated overlays to the mob + +/mob/living/carbon/human/wash_cream() + if(creamed) //clean both to prevent a rare bug + cut_overlay(mutable_appearance('icons/effects/creampie.dmi', "creampie_lizard")) + cut_overlay(mutable_appearance('icons/effects/creampie.dmi', "creampie_human")) + cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_normal")) + cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_large")) + creamed = FALSE + + +//Turns a mob black, flashes a skeleton overlay +//Just like a cartoon! +/mob/living/carbon/human/proc/electrocution_animation(anim_duration) + //Handle mutant parts if possible + if(dna && dna.species) + add_atom_colour("#000000", TEMPORARY_COLOUR_PRIORITY) + var/static/mutable_appearance/electrocution_skeleton_anim + if(!electrocution_skeleton_anim) + electrocution_skeleton_anim = mutable_appearance(icon, "electrocuted_base") + electrocution_skeleton_anim.appearance_flags |= RESET_COLOR|KEEP_APART + add_overlay(electrocution_skeleton_anim) + addtimer(CALLBACK(src, .proc/end_electrocution_animation, electrocution_skeleton_anim), anim_duration) + + else //or just do a generic animation + flick_overlay_view(image(icon,src,"electrocuted_generic",ABOVE_MOB_LAYER), src, anim_duration) + +/mob/living/carbon/human/proc/end_electrocution_animation(mutable_appearance/MA) + remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#000000") + cut_overlay(MA) + +/mob/living/carbon/human/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) + if(incapacitated() || lying ) + to_chat(src, "You can't do that right now!") + return FALSE + if(!Adjacent(M) && (M.loc != src)) + if((be_close == 0) || (!no_tk && (dna.check_mutation(TK) && tkMaxRangeCheck(src, M)))) + return TRUE + to_chat(src, "You are too far away!") + return FALSE + return TRUE + +/mob/living/carbon/human/resist_restraints() + if(wear_suit && wear_suit.breakouttime) + changeNext_move(CLICK_CD_BREAKOUT) + last_special = world.time + CLICK_CD_BREAKOUT + cuff_resist(wear_suit) + else + ..() + +/mob/living/carbon/human/replace_records_name(oldname,newname) // Only humans have records right now, move this up if changed. + for(var/list/L in list(GLOB.data_core.general,GLOB.data_core.medical,GLOB.data_core.security,GLOB.data_core.locked)) + var/datum/data/record/R = find_record("name", oldname, L) + if(R) + R.fields["name"] = newname + +/mob/living/carbon/human/get_total_tint() + . = ..() + if(glasses) + . += glasses.tint + +/mob/living/carbon/human/update_health_hud() + if(!client || !hud_used) + return + if(dna.species.update_health_hud()) + return + else + if(hud_used.healths) + var/health_amount = health - CLAMP(getStaminaLoss()-50, 0, 80)//CIT CHANGE - makes staminaloss have less of an impact on the health hud + if(..(health_amount)) //not dead + switch(hal_screwyhud) + if(SCREWYHUD_CRIT) + hud_used.healths.icon_state = "health6" + if(SCREWYHUD_DEAD) + hud_used.healths.icon_state = "health7" + if(SCREWYHUD_HEALTHY) + hud_used.healths.icon_state = "health0" + if(hud_used.healthdoll) + hud_used.healthdoll.cut_overlays() + if(stat != DEAD) + hud_used.healthdoll.icon_state = "healthdoll_OVERLAY" + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + var/damage = BP.burn_dam + BP.brute_dam + var/comparison = (BP.max_damage/5) + var/icon_num = 0 + if(damage) + icon_num = 1 + if(damage > (comparison)) + icon_num = 2 + if(damage > (comparison*2)) + icon_num = 3 + if(damage > (comparison*3)) + icon_num = 4 + if(damage > (comparison*4)) + icon_num = 5 + if(hal_screwyhud == SCREWYHUD_HEALTHY) + icon_num = 0 + if(icon_num) + hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[BP.body_zone][icon_num]")) + for(var/t in get_missing_limbs()) //Missing limbs + hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]6")) + for(var/t in get_disabled_limbs()) //Disabled limbs + hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]7")) + else + hud_used.healthdoll.icon_state = "healthdoll_DEAD" + +/mob/living/carbon/human/fully_heal(admin_revive = 0) + if(admin_revive) + regenerate_limbs() + regenerate_organs() + remove_all_embedded_objects() + set_heartattack(FALSE) + drunkenness = 0 + for(var/datum/mutation/human/HM in dna.mutations) + if(HM.quality != POSITIVE) + dna.remove_mutation(HM.name) + if(blood_volume < (BLOOD_VOLUME_NORMAL*blood_ratio)) + blood_volume = (BLOOD_VOLUME_NORMAL*blood_ratio) + ..() + +/mob/living/carbon/human/check_weakness(obj/item/weapon, mob/living/attacker) + . = ..() + if (dna && dna.species) + . += dna.species.check_weakness(weapon, attacker) + +/mob/living/carbon/human/is_literate() + return 1 + +/mob/living/carbon/human/can_hold_items() + return TRUE + +/mob/living/carbon/human/update_gravity(has_gravity,override = 0) + if(dna && dna.species) //prevents a runtime while a human is being monkeyfied + override = dna.species.override_float + ..() + +/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = 0, stun = 1, distance = 0, message = 1, toxic = 0) + if(blood && (NOBLOOD in dna.species.species_traits)) + if(message) + visible_message("[src] dry heaves!", \ + "You try to throw up, but there's nothing in your stomach!") + if(stun) + Knockdown(200) + return 1 + ..() + +/mob/living/carbon/human/vv_get_dropdown() + . = ..() + . += "---" + .["Make monkey"] = "?_src_=vars;[HrefToken()];makemonkey=[REF(src)]" + .["Set Species"] = "?_src_=vars;[HrefToken()];setspecies=[REF(src)]" + .["Make cyborg"] = "?_src_=vars;[HrefToken()];makerobot=[REF(src)]" + .["Make alien"] = "?_src_=vars;[HrefToken()];makealien=[REF(src)]" + .["Make slime"] = "?_src_=vars;[HrefToken()];makeslime=[REF(src)]" + .["Toggle Purrbation"] = "?_src_=vars;[HrefToken()];purrbation=[REF(src)]" + .["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]" + .["Add/Remove Quirks"] = "?_src_=vars;[HrefToken()];modquirks=[REF(src)]" + +/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user) + if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS) + //If they dragged themselves and we're currently aggressively grabbing them try to piggyback + if(user == target && can_piggyback(target)) + piggyback(target) + return + //If you dragged them to you and you're aggressively grabbing try to fireman carry them + else if(user != target) + fireman_carry(target) + return + . = ..() + +//src is the user that will be carrying, target is the mob to be carried +/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target) + return (istype(target) && target.stat == CONSCIOUS) + +/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target) + return (ishuman(target) && target.lying) + +/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target) + if(can_be_firemanned(target)) + visible_message("[src] starts lifting [target] onto their back...", + "You start lifting [target] onto your back...") + if(do_after(src, 30, TRUE, target)) + //Second check to make sure they're still valid to be carried + if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE)) + target.resting = FALSE + buckle_mob(target, TRUE, TRUE, 90, 1, 0) + return + visible_message("[src] fails to fireman carry [target]!") + else + to_chat(src, "You can't fireman carry [target] while they're standing!") + +/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target) + if(can_piggyback(target)) + visible_message("[target] starts to climb onto [src]...") + if(do_after(target, 15, target = src)) + if(can_piggyback(target)) + if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE)) + target.visible_message("[target] can't hang onto [src]!") + return + buckle_mob(target, TRUE, TRUE, FALSE, 0, 2) + else + visible_message("[target] fails to climb onto [src]!") + else + to_chat(target, "You can't piggyback ride [src] right now!") + +/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0) + if(!force)//humans are only meant to be ridden through piggybacking and special cases + return + if(!is_type_in_typecache(target, can_ride_typecache)) + target.visible_message("[target] really can't seem to mount [src]...") + return + buckle_lying = lying_buckle + var/datum/component/riding/human/riding_datum = LoadComponent(/datum/component/riding/human) + if(target_hands_needed) + riding_datum.ride_check_rider_restrained = TRUE + if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled) + return + var/equipped_hands_self + var/equipped_hands_target + if(hands_needed) + equipped_hands_self = riding_datum.equip_buckle_inhands(src, hands_needed, target) + if(target_hands_needed) + equipped_hands_target = riding_datum.equip_buckle_inhands(target, target_hands_needed) + + if(hands_needed || target_hands_needed) + if(hands_needed && !equipped_hands_self) + src.visible_message("[src] can't get a grip on [target] because their hands are full!", + "You can't get a grip on [target] because your hands are full!") + return + else if(target_hands_needed && !equipped_hands_target) + target.visible_message("[target] can't get a grip on [src] because their hands are full!", + "You can't get a grip on [src] because your hands are full!") + return + + stop_pulling() + riding_datum.handle_vehicle_layer() + . = ..(target, force, check_loc) + +/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this + for(var/obj/item/clothing/C in get_equipped_items()) //doesn't include pockets + if(C.blocks_shove_knockdown) + return TRUE + return FALSE + +/mob/living/carbon/human/proc/clear_shove_slowdown() + remove_movespeed_modifier(SHOVE_SLOWDOWN_ID) + var/active_item = get_active_held_item() + if(is_type_in_typecache(active_item, GLOB.shove_disarming_types)) + visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE) + +/mob/living/carbon/human/do_after_coefficent() + . = ..() + . *= physiology.do_after_speed + +/mob/living/carbon/human/species + var/race = null + +/mob/living/carbon/human/species/Initialize() + . = ..() + set_species(race) + +/mob/living/carbon/human/species/abductor + race = /datum/species/abductor + +/mob/living/carbon/human/species/android + race = /datum/species/android + +/mob/living/carbon/human/species/angel + race = /datum/species/angel + +/mob/living/carbon/human/species/corporate + race = /datum/species/corporate + +/mob/living/carbon/human/species/dullahan + race = /datum/species/dullahan + +/mob/living/carbon/human/species/felinid + race = /datum/species/human/felinid + +/mob/living/carbon/human/species/fly + race = /datum/species/fly + +/mob/living/carbon/human/species/golem + race = /datum/species/golem + +/mob/living/carbon/human/species/golem/random + race = /datum/species/golem/random + +/mob/living/carbon/human/species/golem/adamantine + race = /datum/species/golem/adamantine + +/mob/living/carbon/human/species/golem/plasma + race = /datum/species/golem/plasma + +/mob/living/carbon/human/species/golem/diamond + race = /datum/species/golem/diamond + +/mob/living/carbon/human/species/golem/gold + race = /datum/species/golem/gold + +/mob/living/carbon/human/species/golem/silver + race = /datum/species/golem/silver + +/mob/living/carbon/human/species/golem/plasteel + race = /datum/species/golem/plasteel + +/mob/living/carbon/human/species/golem/titanium + race = /datum/species/golem/titanium + +/mob/living/carbon/human/species/golem/plastitanium + race = /datum/species/golem/plastitanium + +/mob/living/carbon/human/species/golem/alien_alloy + race = /datum/species/golem/alloy + +/mob/living/carbon/human/species/golem/wood + race = /datum/species/golem/wood + +/mob/living/carbon/human/species/golem/uranium + race = /datum/species/golem/uranium + +/mob/living/carbon/human/species/golem/sand + race = /datum/species/golem/sand + +/mob/living/carbon/human/species/golem/glass + race = /datum/species/golem/glass + +/mob/living/carbon/human/species/golem/bluespace + race = /datum/species/golem/bluespace + +/mob/living/carbon/human/species/golem/bananium + race = /datum/species/golem/bananium + +/mob/living/carbon/human/species/golem/blood_cult + race = /datum/species/golem/runic + +/mob/living/carbon/human/species/golem/cloth + race = /datum/species/golem/cloth + +/mob/living/carbon/human/species/golem/plastic + race = /datum/species/golem/plastic + +/mob/living/carbon/human/species/golem/bronze + race = /datum/species/golem/bronze + +/mob/living/carbon/human/species/golem/cardboard + race = /datum/species/golem/cardboard + +/mob/living/carbon/human/species/golem/leather + race = /datum/species/golem/leather + +/mob/living/carbon/human/species/golem/bone + race = /datum/species/golem/bone + +/mob/living/carbon/human/species/golem/durathread + race = /datum/species/golem/durathread + +/mob/living/carbon/human/species/golem/clockwork + race = /datum/species/golem/clockwork + +/mob/living/carbon/human/species/golem/clockwork/no_scrap + race = /datum/species/golem/clockwork/no_scrap + +/mob/living/carbon/human/species/jelly + race = /datum/species/jelly + +/mob/living/carbon/human/species/jelly/slime + race = /datum/species/jelly/slime + +/mob/living/carbon/human/species/jelly/stargazer + race = /datum/species/jelly/stargazer + +/mob/living/carbon/human/species/jelly/luminescent + race = /datum/species/jelly/luminescent + +/mob/living/carbon/human/species/lizard + race = /datum/species/lizard + +/mob/living/carbon/human/species/lizard/ashwalker + race = /datum/species/lizard/ashwalker + +/mob/living/carbon/human/species/moth + race = /datum/species/moth + +/mob/living/carbon/human/species/mush + race = /datum/species/mush + +/mob/living/carbon/human/species/plasma + race = /datum/species/plasmaman + +/mob/living/carbon/human/species/pod + race = /datum/species/pod + +/mob/living/carbon/human/species/shadow + race = /datum/species/shadow + +/mob/living/carbon/human/species/shadow/nightmare + race = /datum/species/shadow/nightmare + +/mob/living/carbon/human/species/skeleton + race = /datum/species/skeleton + +/mob/living/carbon/human/species/synth + race = /datum/species/synth + +/mob/living/carbon/human/species/synth/military + race = /datum/species/synth/military + +/mob/living/carbon/human/species/vampire + race = /datum/species/vampire + +/mob/living/carbon/human/species/zombie + race = /datum/species/zombie + +/mob/living/carbon/human/species/zombie/infectious + race = /datum/species/zombie/infectious + +/mob/living/carbon/human/species/zombie/krokodil_addict + race = /datum/species/krokodil_addict + +/mob/living/carbon/human/species/mammal + race = /datum/species/mammal + +/mob/living/carbon/human/species/insect + race = /datum/species/insect + +/mob/living/carbon/human/species/xeno + race = /datum/species/xeno + +/mob/living/carbon/human/species/ipc + race = /datum/species/ipc + +/mob/living/carbon/human/species/roundstartslime + race = /datum/species/jelly/roundstartslime +//define holder_type on nerds we wanna commit scoop to +/* /mob/living/carbon/human + var/holder_type = /obj/item/clothing/head/mob_holder/micro + can_be_held = "micro" +*/ + diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index d4845acc..4259ba29 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -1,802 +1,808 @@ -/mob/living/carbon/human/getarmor(def_zone, type) - var/armorval = 0 - var/organnum = 0 - - if(def_zone) - if(isbodypart(def_zone)) - var/obj/item/bodypart/bp = def_zone - if(bp.body_part) - return checkarmor(def_zone, type) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(def_zone)) - return checkarmor(affecting, type) - //If a specific bodypart is targetted, check how that bodypart is protected and return the value. - - //If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - armorval += checkarmor(BP, type) - organnum++ - return (armorval/max(organnum, 1)) - - -/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, d_type) - if(!d_type) - return 0 - var/protection = 0 - var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor) - for(var/bp in body_parts) - if(!bp) - continue - if(istype(bp, /obj/item/clothing)) - var/obj/item/clothing/C = bp - if(C.body_parts_covered & def_zone.body_part) - protection += C.armor.getRating(d_type) - protection += physiology.armor.getRating(d_type) - return protection - -/mob/living/carbon/human/on_hit(obj/item/projectile/P) - if(dna && dna.species) - dna.species.on_hit(P, src) - - -/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone) - if(dna && dna.species) - var/spec_return = dna.species.bullet_act(P, src) - if(spec_return) - return spec_return - - if(mind) - if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles! - if(prob(mind.martial_art.deflection_chance)) - if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it - if(mind.martial_art.deflection_chance >= 100) //if they can NEVER be hit, lets clue sec in ;) - visible_message("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!", "You deflect the projectile!") - else - visible_message("[src] deflects the projectile!", "You deflect the projectile!") - playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1) - if(!mind.martial_art.reroute_deflection) - return FALSE - else - P.firer = src - P.setAngle(rand(0, 360))//SHING - return FALSE - return ..() - -/mob/living/carbon/human/check_reflect(def_zone) - if(wear_suit?.IsReflect(def_zone)) - return TRUE - return ..() - -/mob/living/carbon/human/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0) - . = ..() - if(.) - return - var/block_chance_modifier = round(damage / -3) - if(wear_suit) - var/final_block_chance = wear_suit.block_chance - (CLAMP((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier - if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type)) - return TRUE - if(w_uniform) - var/final_block_chance = w_uniform.block_chance - (CLAMP((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier - if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type)) - return TRUE - if(wear_neck) - var/final_block_chance = wear_neck.block_chance - (CLAMP((armour_penetration-wear_neck.armour_penetration)/2,0,100)) + block_chance_modifier - if(wear_neck.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type)) - return TRUE - return FALSE - -/mob/living/carbon/human/can_embed(obj/item/I) - if(I.get_sharpness() || is_pointed(I) || is_type_in_typecache(I, GLOB.can_embed_types)) - return TRUE - return FALSE - -/mob/living/carbon/human/proc/check_block() - if(mind) - if(mind.martial_art && prob(mind.martial_art.block_chance) && mind.martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE)) - return TRUE - return FALSE - -/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) - return dna?.species?.spec_hitby(AM, src) || ..() - -/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0) - if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (HAS_TRAIT(src, TRAIT_FAT)) && ismonkey(pulling)) - devour_mob(pulling) - else - ..() - -/mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE) - if(w_uniform) - w_uniform.add_fingerprint(user) - ..() - - -/mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user) - if(!I || !user) - return 0 - - var/obj/item/bodypart/affecting - if(user == src) - affecting = get_bodypart(check_zone(user.zone_selected)) //stabbing yourself always hits the right target - else - affecting = get_bodypart(ran_zone(user.zone_selected)) - var/target_area = parse_zone(check_zone(user.zone_selected)) //our intended target - - SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting) - - SSblackbox.record_feedback("nested tally", "item_used_for_combat", 1, list("[I.force]", "[I.type]")) - SSblackbox.record_feedback("tally", "zone_targeted", 1, target_area) - - // the attacked_by code varies among species - return dna.species.spec_attacked_by(I, user, affecting, a_intent, src) - - -/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) - if(user.a_intent == INTENT_HARM) - . = ..(user, TRUE) - if(.) - return - var/hulk_verb = pick("smash","pummel") - playsound(loc, user.dna.species.attack_sound, 25, 1, -1) - var/message = "[user] has [hulk_verb]ed [src]!" - visible_message("[message]", \ - "[message]") - adjustBruteLoss(15) - return 1 - -/mob/living/carbon/human/attack_hand(mob/user) - . = ..() - if(.) //To allow surgery to return properly. - return - if(ishuman(user)) - var/mob/living/carbon/human/H = user - dna.species.spec_attack_hand(H, src) - -/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M) - var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) - if(!affecting) - affecting = get_bodypart(BODY_ZONE_CHEST) - if(M.a_intent == INTENT_HELP) - return ..() //shaking - - if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stunned instead. - var/obj/item/I = get_active_held_item() - if(I && dropItemToGround(I)) - playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("[M] disarmed [src]!", \ - "[M] disarmed [src]!") - else if(!M.client || prob(5)) // only natural monkeys get to stun reliably, (they only do it occasionaly) - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - Knockdown(100) - log_combat(M, src, "tackled") - visible_message("[M] has tackled down [src]!", \ - "[M] has tackled down [src]!") - - if(M.limb_destroyer) - dismembering_strike(M, affecting.body_zone) - - if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites. - if(..()) //successful monkey bite, this handles disease contraction. - var/damage = rand(1, 3) - apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee")) - return 1 - -/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M) - . = ..() - if(!.) - return - if(M.a_intent == INTENT_HARM) - if (w_uniform) - w_uniform.add_fingerprint(M) - var/damage = prob(90) ? 20 : 0 - if(!damage) - playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1) - visible_message("[M] has lunged at [src]!", \ - "[M] has lunged at [src]!") - return 0 - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) - if(!affecting) - affecting = get_bodypart(BODY_ZONE_CHEST) - var/armor_block = run_armor_check(affecting, "melee", null, null,10) - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - visible_message("[M] has slashed at [src]!", \ - "[M] has slashed at [src]!") - log_combat(M, src, "attacked") - if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful - return 1 - apply_damage(damage, BRUTE, affecting, armor_block) - if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stun instead. - var/obj/item/I = get_active_held_item() - if(I && dropItemToGround(I)) - playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("[M] disarmed [src]!", \ - "[M] disarmed [src]!") - else - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - if(!lying) //CITADEL EDIT - Knockdown(100, TRUE, FALSE, 30, 25) - else - Knockdown(100) - log_combat(M, src, "tackled") - visible_message("[M] has tackled down [src]!", \ - "[M] has tackled down [src]!") - -/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L) - . = ..() - if(!.) //unsuccessful larva bite. - return - var/damage = rand(1, 3) - if(stat != DEAD) - L.amount_grown = min(L.amount_grown + damage, L.max_grown) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected)) - if(!affecting) - affecting = get_bodypart(BODY_ZONE_CHEST) - var/armor_block = run_armor_check(affecting, "melee") - apply_damage(damage, BRUTE, affecting, armor_block) - - -/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M) - . = ..() - if(.) - var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) - if(!dam_zone) //Dismemberment successful - return TRUE - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) - if(!affecting) - affecting = get_bodypart(BODY_ZONE_CHEST) - var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration) - apply_damage(damage, M.melee_damage_type, affecting, armor) - - -/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M) - . = ..() - if(!.) //unsuccessful slime attack - return - var/damage = rand(5, 25) - if(M.is_adult) - damage = rand(10, 35) - - var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) - if(!dam_zone) //Dismemberment successful - return 1 - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) - if(!affecting) - affecting = get_bodypart(BODY_ZONE_CHEST) - var/armor_block = run_armor_check(affecting, "melee") - apply_damage(damage, BRUTE, affecting, armor_block) - -/mob/living/carbon/human/mech_melee_attack(obj/mecha/M) - - if(M.occupant.a_intent == INTENT_HARM) - M.do_attack_animation(src) - if(M.damtype == "brute") - step_away(src,M,15) - var/obj/item/bodypart/temp = get_bodypart(pick(BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_HEAD)) - if(temp) - var/update = 0 - var/dmg = rand(M.force/2, M.force) - var/atom/throw_target = get_edge_target_turf(src, M.dir) - switch(M.damtype) - if("brute") - if(M.force > 35) // durand and other heavy mechas - Knockdown(50) - src.throw_at(throw_target, rand(1,5), 7) - else if(M.force >= 20 && !IsKnockdown()) // lightweight mechas like gygax - Knockdown(30) - src.throw_at(throw_target, rand(1,3), 7) - update |= temp.receive_damage(dmg, 0) - playsound(src, 'sound/weapons/punch4.ogg', 50, 1) - if("fire") - update |= temp.receive_damage(0, dmg) - playsound(src, 'sound/items/welder.ogg', 50, 1) - if("tox") - M.mech_toxin_damage(src) - else - return - if(update) - update_damage_overlays() - updatehealth() - - visible_message("[M.name] has hit [src]!", \ - "[M.name] has hit [src]!", null, COMBAT_MESSAGE_RANGE) - log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") - - else - ..() - - -/mob/living/carbon/human/ex_act(severity, target, origin) - if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src)) - return - ..() - if (!severity) - return - var/b_loss = 0 - var/f_loss = 0 - var/bomb_armor = getarmor(null, "bomb") - - switch (severity) - if (1) - if(prob(bomb_armor)) - b_loss = 500 - var/atom/throw_target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src))) - throw_at(throw_target, 200, 4) - damage_clothes(400 - bomb_armor, BRUTE, "bomb") - else - for(var/I in contents) - var/atom/A = I - A.ex_act(severity) - gib() - return - - if (2) - b_loss = 60 - f_loss = 60 - if(bomb_armor) - b_loss = 30*(2 - round(bomb_armor*0.01, 0.05)) - f_loss = b_loss - damage_clothes(200 - bomb_armor, BRUTE, "bomb") - if (!istype(ears, /obj/item/clothing/ears/earmuffs)) - adjustEarDamage(30, 120) - if (prob(max(70 - (bomb_armor * 0.5), 0))) - Unconscious(200) - - if(3) - b_loss = 30 - if(bomb_armor) - b_loss = 15*(2 - round(bomb_armor*0.01, 0.05)) - damage_clothes(max(50 - bomb_armor, 0), BRUTE, "bomb") - if (!istype(ears, /obj/item/clothing/ears/earmuffs)) - adjustEarDamage(15,60) - if (prob(max(50 - (bomb_armor * 0.5), 0))) - Unconscious(160) - - take_overall_damage(b_loss,f_loss) - - //attempt to dismember bodyparts - if(severity <= 2 || !bomb_armor) - var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3. - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - if(prob(50/severity) && !prob(getarmor(BP, "bomb")) && BP.body_zone != BODY_ZONE_HEAD && BP.body_zone != BODY_ZONE_CHEST) - BP.brute_dam = BP.max_damage - BP.dismember() - max_limb_loss-- - if(!max_limb_loss) - break - - -/mob/living/carbon/human/blob_act(obj/structure/blob/B) - if(stat == DEAD) - return - show_message("The blob attacks you!") - var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) - apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee")) - - -//Added a safety check in case you want to shock a human mob directly through electrocute_act. -/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE) - if(tesla_shock) - var/total_coeff = 1 - if(gloves) - var/obj/item/clothing/gloves/G = gloves - if(G.siemens_coefficient <= 0) - total_coeff -= 0.5 - if(wear_suit) - var/obj/item/clothing/suit/S = wear_suit - if(S.siemens_coefficient <= 0) - total_coeff -= 0.95 - else if(S.siemens_coefficient == (-1)) - total_coeff -= 1 - siemens_coeff = total_coeff - if(flags_1 & TESLA_IGNORE_1) - siemens_coeff = 0 - else if(!safety) - var/gloves_siemens_coeff = 1 - if(gloves) - var/obj/item/clothing/gloves/G = gloves - gloves_siemens_coeff = G.siemens_coefficient - siemens_coeff = gloves_siemens_coeff - if(undergoing_cardiac_arrest() && !illusion) - if(shock_damage * siemens_coeff >= 1 && prob(25)) - var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART) - heart.beating = TRUE - if(stat == CONSCIOUS) - to_chat(src, "You feel your heart beating again!") - siemens_coeff *= physiology.siemens_coeff - . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun) - if(.) - electrocution_animation(40) - - -/mob/living/carbon/human/emp_act(severity) - . = ..() - if(. & EMP_PROTECT_CONTENTS) - return - var/informed = FALSE - for(var/obj/item/bodypart/L in src.bodyparts) - if(L.status == BODYPART_ROBOTIC) - if(!informed) - to_chat(src, "You feel a sharp pain as your robotic limbs overload.") - informed = TRUE - switch(severity) - if(1) - L.receive_damage(0,10) - Stun(200) - if(2) - L.receive_damage(0,5) - Stun(100) - -/mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit) - var/list/damaged = list() - var/list/inventory_items_to_kill = list() - var/acidity = acidpwr * min(acid_volume*0.005, 0.1) - //HEAD// - if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_HEAD) //only if we didn't specify a zone or if that zone is the head. - var/obj/item/clothing/head_clothes = null - if(glasses) - head_clothes = glasses - if(wear_mask) - head_clothes = wear_mask - if(wear_neck) - head_clothes = wear_neck - if(head) - head_clothes = head - if(head_clothes) - if(!(head_clothes.resistance_flags & UNACIDABLE)) - head_clothes.acid_act(acidpwr, acid_volume) - update_inv_glasses() - update_inv_wear_mask() - update_inv_neck() - update_inv_head() - else - to_chat(src, "Your [head_clothes.name] protects your head and face from the acid!") - else - . = get_bodypart(BODY_ZONE_HEAD) - if(.) - damaged += . - if(ears) - inventory_items_to_kill += ears - - //CHEST// - if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_CHEST) - var/obj/item/clothing/chest_clothes = null - if(w_uniform) - chest_clothes = w_uniform - if(wear_suit) - chest_clothes = wear_suit - if(chest_clothes) - if(!(chest_clothes.resistance_flags & UNACIDABLE)) - chest_clothes.acid_act(acidpwr, acid_volume) - update_inv_w_uniform() - update_inv_wear_suit() - else - to_chat(src, "Your [chest_clothes.name] protects your body from the acid!") - else - . = get_bodypart(BODY_ZONE_CHEST) - if(.) - damaged += . - if(wear_id) - inventory_items_to_kill += wear_id - if(r_store) - inventory_items_to_kill += r_store - if(l_store) - inventory_items_to_kill += l_store - if(s_store) - inventory_items_to_kill += s_store - - - //ARMS & HANDS// - if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_L_ARM || bodyzone_hit == BODY_ZONE_R_ARM) - var/obj/item/clothing/arm_clothes = null - if(gloves) - arm_clothes = gloves - if(w_uniform && ((w_uniform.body_parts_covered & HANDS) || (w_uniform.body_parts_covered & ARMS))) - arm_clothes = w_uniform - if(wear_suit && ((wear_suit.body_parts_covered & HANDS) || (wear_suit.body_parts_covered & ARMS))) - arm_clothes = wear_suit - - if(arm_clothes) - if(!(arm_clothes.resistance_flags & UNACIDABLE)) - arm_clothes.acid_act(acidpwr, acid_volume) - update_inv_gloves() - update_inv_w_uniform() - update_inv_wear_suit() - else - to_chat(src, "Your [arm_clothes.name] protects your arms and hands from the acid!") - else - . = get_bodypart(BODY_ZONE_R_ARM) - if(.) - damaged += . - . = get_bodypart(BODY_ZONE_L_ARM) - if(.) - damaged += . - - - //LEGS & FEET// - if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_L_LEG || bodyzone_hit == BODY_ZONE_R_LEG || bodyzone_hit == "feet") - var/obj/item/clothing/leg_clothes = null - if(shoes) - leg_clothes = shoes - if(w_uniform && ((w_uniform.body_parts_covered & FEET) || (bodyzone_hit != "feet" && (w_uniform.body_parts_covered & LEGS)))) - leg_clothes = w_uniform - if(wear_suit && ((wear_suit.body_parts_covered & FEET) || (bodyzone_hit != "feet" && (wear_suit.body_parts_covered & LEGS)))) - leg_clothes = wear_suit - if(leg_clothes) - if(!(leg_clothes.resistance_flags & UNACIDABLE)) - leg_clothes.acid_act(acidpwr, acid_volume) - update_inv_shoes() - update_inv_w_uniform() - update_inv_wear_suit() - else - to_chat(src, "Your [leg_clothes.name] protects your legs and feet from the acid!") - else - . = get_bodypart(BODY_ZONE_R_LEG) - if(.) - damaged += . - . = get_bodypart(BODY_ZONE_L_LEG) - if(.) - damaged += . - - - //DAMAGE// - for(var/obj/item/bodypart/affecting in damaged) - affecting.receive_damage(acidity, 2*acidity) - - if(affecting.name == BODY_ZONE_HEAD) - if(prob(min(acidpwr*acid_volume/10, 90))) //Applies disfigurement - affecting.receive_damage(acidity, 2*acidity) - emote("scream") - facial_hair_style = "Shaved" - hair_style = "Bald" - update_hair() - ADD_TRAIT(src, TRAIT_DISFIGURED, TRAIT_GENERIC) - - update_damage_overlays() - - //MELTING INVENTORY ITEMS// - //these items are all outside of armour visually, so melt regardless. - if(!bodyzone_hit) - if(back) - inventory_items_to_kill += back - if(belt) - inventory_items_to_kill += belt - - inventory_items_to_kill += held_items - - for(var/obj/item/I in inventory_items_to_kill) - I.acid_act(acidpwr, acid_volume) - return 1 - -/mob/living/carbon/human/singularity_act() - var/gain = 20 - if(mind) - if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") ) - gain = 100 - if(mind.assigned_role == "Clown") - gain = rand(-300, 300) - investigate_log("([key_name(src)]) has been consumed by the singularity.", INVESTIGATE_SINGULO) //Oh that's where the clown ended up! - gib() - return(gain) - -/mob/living/carbon/human/help_shake_act(mob/living/carbon/M) - if(!istype(M)) - return - - if(health >= 0) - if(src == M) - var/to_send = "" - visible_message("[src] examines [p_them()]self.", \ - "You check yourself for injuries.") - - var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - for(var/X in bodyparts) - var/obj/item/bodypart/LB = X - missing -= LB.body_zone - if(LB.is_pseudopart) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades - continue - var/limb_max_damage = LB.max_damage - var/status = "" - var/brutedamage = LB.brute_dam - var/burndamage = LB.burn_dam - var/broken = LB.broken - if(hallucination) - if(prob(30)) - brutedamage += rand(30,40) - if(prob(30)) - burndamage += rand(30,40) - - if(HAS_TRAIT(src, TRAIT_SELF_AWARE)) - status = "[brutedamage] brute damage and [burndamage] burn damage" - if(!brutedamage && !burndamage) - status = "no damage" - - else - if(brutedamage > 0) - status = LB.light_brute_msg - if(brutedamage > (limb_max_damage*0.4)) - status = LB.medium_brute_msg - if(brutedamage > (limb_max_damage*0.8)) - status = LB.heavy_brute_msg - if(brutedamage > 0 && burndamage > 0) - status += " and " - - if(burndamage > (limb_max_damage*0.8)) - status += LB.heavy_burn_msg - else if(burndamage > (limb_max_damage*0.2)) - status += LB.medium_burn_msg - else if(burndamage > 0) - status += LB.light_burn_msg - if(broken == 1) - status = "fractured" - if(status == "") - status = "OK" - var/no_damage - if(status == "OK" || status == "no damage") - no_damage = TRUE - to_send += "\t Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].\n" - - for(var/obj/item/I in LB.embedded_objects) - to_send += "\t There is \a [I] embedded in your [LB.name]!\n" - - for(var/t in missing) - for(var/t in missing) - to_send += "Your [parse_zone(t)] is missing!\n" - - if(bleed_rate) - to_send += "You are bleeding!\n" - if(getStaminaLoss()) - if(getStaminaLoss() > 30) - to_send += "You're completely exhausted.\n" - else - to_send += "You feel fatigued.\n" - if(HAS_TRAIT(src, TRAIT_SELF_AWARE)) - if(toxloss) - if(toxloss > 10) - to_send += "You feel sick.\n" - else if(toxloss > 20) - to_send += "You feel nauseated.\n" - else if(toxloss > 40) - to_send += "You feel very unwell!\n" - if(oxyloss) - if(oxyloss > 10) - to_send += "You feel lightheaded.\n" - else if(oxyloss > 20) - to_send += "Your thinking is clouded and distant.\n" - else if(oxyloss > 30) - to_send += "You're choking!\n" - - switch(nutrition) - if(NUTRITION_LEVEL_FULL to INFINITY) - to_send += "You're completely stuffed!\n" - if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL) - to_send += "You're well fed!\n" - if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED) - to_send += "You're not hungry.\n" - if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED) - to_send += "You could use a bite to eat.\n" - if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) - to_send += "You feel quite hungry.\n" - if(0 to NUTRITION_LEVEL_STARVING) - to_send += "You're starving!\n" - - - //TODO: Convert these messages into vague messages, thereby encouraging actual dignosis. - //Compiles then shows the list of damaged organs and broken organs - var/list/broken = list() - var/list/damaged = list() - var/broken_message - var/damaged_message - var/broken_plural - var/damaged_plural - //Sets organs into their proper list - for(var/O in internal_organs) - var/obj/item/organ/organ = O - if(organ.organ_flags & ORGAN_FAILING) - if(broken.len) - broken += ", " - broken += organ.name - else if(organ.damage > organ.low_threshold) - if(damaged.len) - damaged += ", " - damaged += organ.name - //Checks to enforce proper grammar, inserts words as necessary into the list - if(broken.len) - if(broken.len > 1) - broken.Insert(broken.len, "and ") - broken_plural = TRUE - else - var/holder = broken[1] //our one and only element - if(holder[length(holder)] == "s") - broken_plural = TRUE - //Put the items in that list into a string of text - for(var/B in broken) - broken_message += B - to_chat(src, " Your [broken_message] [broken_plural ? "are" : "is"] non-functional!") - if(damaged.len) - if(damaged.len > 1) - damaged.Insert(damaged.len, "and ") - damaged_plural = TRUE - else - var/holder = damaged[1] - if(holder[length(holder)] == "s") - damaged_plural = TRUE - for(var/D in damaged) - damaged_message += D - to_chat(src, "Your [damaged_message] [damaged_plural ? "are" : "is"] hurt.") - - if(roundstart_quirks.len) - to_send += "You have these quirks: [get_trait_string()].\n" - - to_chat(src, to_send) - else - if(wear_suit) - wear_suit.add_fingerprint(M) - else if(w_uniform) - w_uniform.add_fingerprint(M) - - ..() - - -/mob/living/carbon/human/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone) - if(damage_type != BRUTE && damage_type != BURN) - return - damage_amount *= 0.5 //0.5 multiplier for balance reason, we don't want clothes to be too easily destroyed - var/list/torn_items = list() - - //HEAD// - if(!def_zone || def_zone == BODY_ZONE_HEAD) - var/obj/item/clothing/head_clothes = null - if(glasses) - head_clothes = glasses - if(wear_mask) - head_clothes = wear_mask - if(wear_neck) - head_clothes = wear_neck - if(head) - head_clothes = head - if(head_clothes) - torn_items += head_clothes - else if(ears) - torn_items += ears - - //CHEST// - if(!def_zone || def_zone == BODY_ZONE_CHEST) - var/obj/item/clothing/chest_clothes = null - if(w_uniform) - chest_clothes = w_uniform - if(wear_suit) - chest_clothes = wear_suit - if(chest_clothes) - torn_items += chest_clothes - - //ARMS & HANDS// - if(!def_zone || def_zone == BODY_ZONE_L_ARM || def_zone == BODY_ZONE_R_ARM) - var/obj/item/clothing/arm_clothes = null - if(gloves) - arm_clothes = gloves - if(w_uniform && ((w_uniform.body_parts_covered & HANDS) || (w_uniform.body_parts_covered & ARMS))) - arm_clothes = w_uniform - if(wear_suit && ((wear_suit.body_parts_covered & HANDS) || (wear_suit.body_parts_covered & ARMS))) - arm_clothes = wear_suit - if(arm_clothes) - torn_items |= arm_clothes - - //LEGS & FEET// - if(!def_zone || def_zone == BODY_ZONE_L_LEG || def_zone == BODY_ZONE_R_LEG) - var/obj/item/clothing/leg_clothes = null - if(shoes) - leg_clothes = shoes - if(w_uniform && ((w_uniform.body_parts_covered & FEET) || (w_uniform.body_parts_covered & LEGS))) - leg_clothes = w_uniform - if(wear_suit && ((wear_suit.body_parts_covered & FEET) || (wear_suit.body_parts_covered & LEGS))) - leg_clothes = wear_suit - if(leg_clothes) - torn_items |= leg_clothes - - for(var/obj/item/I in torn_items) - I.take_damage(damage_amount, damage_type, damage_flag, 0) +/mob/living/carbon/human/getarmor(def_zone, type) + var/armorval = 0 + var/organnum = 0 + + if(def_zone) + if(isbodypart(def_zone)) + var/obj/item/bodypart/bp = def_zone + if(bp.body_part) + return checkarmor(def_zone, type) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(def_zone)) + return checkarmor(affecting, type) + //If a specific bodypart is targetted, check how that bodypart is protected and return the value. + + //If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + armorval += checkarmor(BP, type) + organnum++ + return (armorval/max(organnum, 1)) + + +/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, d_type) + if(!d_type) + return 0 + var/protection = 0 + var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor) + for(var/bp in body_parts) + if(!bp) + continue + if(istype(bp, /obj/item/clothing)) + var/obj/item/clothing/C = bp + if(C.body_parts_covered & def_zone.body_part) + protection += C.armor.getRating(d_type) + protection += physiology.armor.getRating(d_type) + return protection + +/mob/living/carbon/human/on_hit(obj/item/projectile/P) + if(dna && dna.species) + dna.species.on_hit(P, src) + + +/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone) + if(dna && dna.species) + var/spec_return = dna.species.bullet_act(P, src) + if(spec_return) + return spec_return + + if(mind) + if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles! + if(prob(mind.martial_art.deflection_chance)) + if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it + if(mind.martial_art.deflection_chance >= 100) //if they can NEVER be hit, lets clue sec in ;) + visible_message("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!", "You deflect the projectile!") + else + visible_message("[src] deflects the projectile!", "You deflect the projectile!") + playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1) + if(!mind.martial_art.reroute_deflection) + return FALSE + else + P.firer = src + P.setAngle(rand(0, 360))//SHING + return FALSE + return ..() + +/mob/living/carbon/human/check_reflect(def_zone) + if(wear_suit?.IsReflect(def_zone)) + return TRUE + return ..() + +/mob/living/carbon/human/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0) + . = ..() + if(.) + return + var/block_chance_modifier = round(damage / -3) + if(wear_suit) + var/final_block_chance = wear_suit.block_chance - (CLAMP((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier + if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type)) + return TRUE + if(w_uniform) + var/final_block_chance = w_uniform.block_chance - (CLAMP((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier + if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type)) + return TRUE + if(wear_neck) + var/final_block_chance = wear_neck.block_chance - (CLAMP((armour_penetration-wear_neck.armour_penetration)/2,0,100)) + block_chance_modifier + if(wear_neck.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type)) + return TRUE + return FALSE + +/mob/living/carbon/human/can_embed(obj/item/I) + if(I.get_sharpness() || is_pointed(I) || is_type_in_typecache(I, GLOB.can_embed_types)) + return TRUE + return FALSE + +/mob/living/carbon/human/proc/check_block() + if(mind) + if(mind.martial_art && prob(mind.martial_art.block_chance) && mind.martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE)) + return TRUE + return FALSE + +/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) + return dna?.species?.spec_hitby(AM, src) || ..() + +/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0) + if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (HAS_TRAIT(src, TRAIT_FAT)) && ismonkey(pulling)) + devour_mob(pulling) + else + ..() + +/mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE) + if(w_uniform) + w_uniform.add_fingerprint(user) + ..() + + +/mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user) + if(!I || !user) + return 0 + + var/obj/item/bodypart/affecting + if(user == src) + affecting = get_bodypart(check_zone(user.zone_selected)) //stabbing yourself always hits the right target + else + affecting = get_bodypart(ran_zone(user.zone_selected)) + var/target_area = parse_zone(check_zone(user.zone_selected)) //our intended target + + SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting) + + SSblackbox.record_feedback("nested tally", "item_used_for_combat", 1, list("[I.force]", "[I.type]")) + SSblackbox.record_feedback("tally", "zone_targeted", 1, target_area) + + // the attacked_by code varies among species + return dna.species.spec_attacked_by(I, user, affecting, a_intent, src) + + +/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) + if(user.a_intent == INTENT_HARM) + . = ..(user, TRUE) + if(.) + return + var/hulk_verb = pick("smash","pummel") + playsound(loc, user.dna.species.attack_sound, 25, 1, -1) + var/message = "[user] has [hulk_verb]ed [src]!" + visible_message("[message]", \ + "[message]") + adjustBruteLoss(15) + return 1 + +/mob/living/carbon/human/attack_hand(mob/user) + . = ..() + if(.) //To allow surgery to return properly. + return + if(ishuman(user)) + var/mob/living/carbon/human/H = user + dna.species.spec_attack_hand(H, src) + +/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M) + var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + if(!affecting) + affecting = get_bodypart(BODY_ZONE_CHEST) + if(M.a_intent == INTENT_HELP) + return ..() //shaking + + if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stunned instead. + var/obj/item/I = get_active_held_item() + if(I && dropItemToGround(I)) + playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) + visible_message("[M] disarmed [src]!", \ + "[M] disarmed [src]!") + else if(!M.client || prob(5)) // only natural monkeys get to stun reliably, (they only do it occasionaly) + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + Knockdown(100) + log_combat(M, src, "tackled") + visible_message("[M] has tackled down [src]!", \ + "[M] has tackled down [src]!") + + if(M.limb_destroyer) + dismembering_strike(M, affecting.body_zone) + + if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites. + if(..()) //successful monkey bite, this handles disease contraction. + var/damage = rand(1, 3) + apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee")) + return 1 + +/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M) + . = ..() + if(!.) + return + if(M.a_intent == INTENT_HARM) + if (w_uniform) + w_uniform.add_fingerprint(M) + var/damage = prob(90) ? 20 : 0 + if(!damage) + playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1) + visible_message("[M] has lunged at [src]!", \ + "[M] has lunged at [src]!") + return 0 + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + if(!affecting) + affecting = get_bodypart(BODY_ZONE_CHEST) + var/armor_block = run_armor_check(affecting, "melee", null, null,10) + playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) + visible_message("[M] has slashed at [src]!", \ + "[M] has slashed at [src]!") + log_combat(M, src, "attacked") + if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful + return 1 + apply_damage(damage, BRUTE, affecting, armor_block) + if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stun instead. + var/obj/item/I = get_active_held_item() + if(I && dropItemToGround(I)) + playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) + visible_message("[M] disarmed [src]!", \ + "[M] disarmed [src]!") + else + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + if(!lying) //CITADEL EDIT + Knockdown(100, TRUE, FALSE, 30, 25) + else + Knockdown(100) + log_combat(M, src, "tackled") + visible_message("[M] has tackled down [src]!", \ + "[M] has tackled down [src]!") + +/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L) + . = ..() + if(!.) //unsuccessful larva bite. + return + var/damage = rand(1, 3) + if(stat != DEAD) + L.amount_grown = min(L.amount_grown + damage, L.max_grown) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected)) + if(!affecting) + affecting = get_bodypart(BODY_ZONE_CHEST) + var/armor_block = run_armor_check(affecting, "melee") + apply_damage(damage, BRUTE, affecting, armor_block) + + +/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M) + . = ..() + if(.) + var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) + var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) + if(!dam_zone) //Dismemberment successful + return TRUE + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + if(!affecting) + affecting = get_bodypart(BODY_ZONE_CHEST) + var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration) + apply_damage(damage, M.melee_damage_type, affecting, armor) + + +/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M) + . = ..() + if(!.) //unsuccessful slime attack + return + var/damage = rand(5, 25) + if(M.is_adult) + damage = rand(10, 35) + + var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) + if(!dam_zone) //Dismemberment successful + return 1 + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + if(!affecting) + affecting = get_bodypart(BODY_ZONE_CHEST) + var/armor_block = run_armor_check(affecting, "melee") + apply_damage(damage, BRUTE, affecting, armor_block) + +/mob/living/carbon/human/mech_melee_attack(obj/mecha/M) + + if(M.occupant.a_intent == INTENT_HARM) + M.do_attack_animation(src) + if(M.damtype == "brute") + step_away(src,M,15) + var/obj/item/bodypart/temp = get_bodypart(pick(BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_HEAD)) + if(temp) + var/update = 0 + var/dmg = rand(M.force/2, M.force) + var/atom/throw_target = get_edge_target_turf(src, M.dir) + switch(M.damtype) + if("brute") + if(M.force > 35) // durand and other heavy mechas + Knockdown(50) + src.throw_at(throw_target, rand(1,5), 7) + else if(M.force >= 20 && !IsKnockdown()) // lightweight mechas like gygax + Knockdown(30) + src.throw_at(throw_target, rand(1,3), 7) + update |= temp.receive_damage(dmg, 0) + playsound(src, 'sound/weapons/punch4.ogg', 50, 1) + if("fire") + update |= temp.receive_damage(0, dmg) + playsound(src, 'sound/items/welder.ogg', 50, 1) + if("tox") + M.mech_toxin_damage(src) + else + return + if(update) + update_damage_overlays() + updatehealth() + + visible_message("[M.name] has hit [src]!", \ + "[M.name] has hit [src]!", null, COMBAT_MESSAGE_RANGE) + log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") + + else + ..() + + +/mob/living/carbon/human/ex_act(severity, target, origin) + if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src)) + return + ..() + if (!severity) + return + var/b_loss = 0 + var/f_loss = 0 + var/bomb_armor = getarmor(null, "bomb") + + switch (severity) + if (1) + if(prob(bomb_armor)) + b_loss = 500 + var/atom/throw_target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src))) + throw_at(throw_target, 200, 4) + damage_clothes(400 - bomb_armor, BRUTE, "bomb") + else + for(var/I in contents) + var/atom/A = I + A.ex_act(severity) + gib() + return + + if (2) + b_loss = 60 + f_loss = 60 + if(bomb_armor) + b_loss = 30*(2 - round(bomb_armor*0.01, 0.05)) + f_loss = b_loss + damage_clothes(200 - bomb_armor, BRUTE, "bomb") + if (!istype(ears, /obj/item/clothing/ears/earmuffs)) + adjustEarDamage(30, 120) + if (prob(max(70 - (bomb_armor * 0.5), 0))) + Unconscious(200) + + if(3) + b_loss = 30 + if(bomb_armor) + b_loss = 15*(2 - round(bomb_armor*0.01, 0.05)) + damage_clothes(max(50 - bomb_armor, 0), BRUTE, "bomb") + if (!istype(ears, /obj/item/clothing/ears/earmuffs)) + adjustEarDamage(15,60) + if (prob(max(50 - (bomb_armor * 0.5), 0))) + Unconscious(160) + + take_overall_damage(b_loss,f_loss) + + //attempt to dismember bodyparts + if(severity <= 2 || !bomb_armor) + var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3. + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + if(prob(50/severity) && !prob(getarmor(BP, "bomb")) && BP.body_zone != BODY_ZONE_HEAD && BP.body_zone != BODY_ZONE_CHEST) + BP.brute_dam = BP.max_damage + BP.dismember() + max_limb_loss-- + if(!max_limb_loss) + break + + +/mob/living/carbon/human/blob_act(obj/structure/blob/B) + if(stat == DEAD) + return + show_message("The blob attacks you!") + var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee")) + + +//Added a safety check in case you want to shock a human mob directly through electrocute_act. +/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE) + if(tesla_shock) + var/total_coeff = 1 + if(gloves) + var/obj/item/clothing/gloves/G = gloves + if(G.siemens_coefficient <= 0) + total_coeff -= 0.5 + if(wear_suit) + var/obj/item/clothing/suit/S = wear_suit + if(S.siemens_coefficient <= 0) + total_coeff -= 0.95 + else if(S.siemens_coefficient == (-1)) + total_coeff -= 1 + siemens_coeff = total_coeff + if(flags_1 & TESLA_IGNORE_1) + siemens_coeff = 0 + else if(!safety) + var/gloves_siemens_coeff = 1 + if(gloves) + var/obj/item/clothing/gloves/G = gloves + gloves_siemens_coeff = G.siemens_coefficient + siemens_coeff = gloves_siemens_coeff + if(undergoing_cardiac_arrest() && !illusion) + if(shock_damage * siemens_coeff >= 1 && prob(25)) + var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART) + heart.beating = TRUE + if(stat == CONSCIOUS) + to_chat(src, "You feel your heart beating again!") + siemens_coeff *= physiology.siemens_coeff + . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun) + if(.) + electrocution_animation(40) + + +/mob/living/carbon/human/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_CONTENTS) + return + var/informed = FALSE + for(var/obj/item/bodypart/L in src.bodyparts) + if(L.status == BODYPART_ROBOTIC) + if(!informed) + to_chat(src, "You feel a sharp pain as your robotic limbs overload.") + informed = TRUE + switch(severity) + if(1) + L.receive_damage(0,10) + Stun(200) + if(2) + L.receive_damage(0,5) + Stun(100) + +/mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit) + var/list/damaged = list() + var/list/inventory_items_to_kill = list() + var/acidity = acidpwr * min(acid_volume*0.005, 0.1) + //HEAD// + if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_HEAD) //only if we didn't specify a zone or if that zone is the head. + var/obj/item/clothing/head_clothes = null + if(glasses) + head_clothes = glasses + if(wear_mask) + head_clothes = wear_mask + if(wear_neck) + head_clothes = wear_neck + if(head) + head_clothes = head + if(head_clothes) + if(!(head_clothes.resistance_flags & UNACIDABLE)) + head_clothes.acid_act(acidpwr, acid_volume) + update_inv_glasses() + update_inv_wear_mask() + update_inv_neck() + update_inv_head() + else + to_chat(src, "Your [head_clothes.name] protects your head and face from the acid!") + else + . = get_bodypart(BODY_ZONE_HEAD) + if(.) + damaged += . + if(ears) + inventory_items_to_kill += ears + + //CHEST// + if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_CHEST) + var/obj/item/clothing/chest_clothes = null + if(w_uniform) + chest_clothes = w_uniform + if(wear_suit) + chest_clothes = wear_suit + if(chest_clothes) + if(!(chest_clothes.resistance_flags & UNACIDABLE)) + chest_clothes.acid_act(acidpwr, acid_volume) + update_inv_w_uniform() + update_inv_wear_suit() + else + to_chat(src, "Your [chest_clothes.name] protects your body from the acid!") + else + . = get_bodypart(BODY_ZONE_CHEST) + if(.) + damaged += . + if(wear_id) + inventory_items_to_kill += wear_id + if(r_store) + inventory_items_to_kill += r_store + if(l_store) + inventory_items_to_kill += l_store + if(s_store) + inventory_items_to_kill += s_store + + + //ARMS & HANDS// + if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_L_ARM || bodyzone_hit == BODY_ZONE_R_ARM) + var/obj/item/clothing/arm_clothes = null + if(gloves) + arm_clothes = gloves + if(w_uniform && ((w_uniform.body_parts_covered & HANDS) || (w_uniform.body_parts_covered & ARMS))) + arm_clothes = w_uniform + if(wear_suit && ((wear_suit.body_parts_covered & HANDS) || (wear_suit.body_parts_covered & ARMS))) + arm_clothes = wear_suit + + if(arm_clothes) + if(!(arm_clothes.resistance_flags & UNACIDABLE)) + arm_clothes.acid_act(acidpwr, acid_volume) + update_inv_gloves() + update_inv_w_uniform() + update_inv_wear_suit() + else + to_chat(src, "Your [arm_clothes.name] protects your arms and hands from the acid!") + else + . = get_bodypart(BODY_ZONE_R_ARM) + if(.) + damaged += . + . = get_bodypart(BODY_ZONE_L_ARM) + if(.) + damaged += . + + + //LEGS & FEET// + if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_L_LEG || bodyzone_hit == BODY_ZONE_R_LEG || bodyzone_hit == "feet") + var/obj/item/clothing/leg_clothes = null + if(shoes) + leg_clothes = shoes + if(w_uniform && ((w_uniform.body_parts_covered & FEET) || (bodyzone_hit != "feet" && (w_uniform.body_parts_covered & LEGS)))) + leg_clothes = w_uniform + if(wear_suit && ((wear_suit.body_parts_covered & FEET) || (bodyzone_hit != "feet" && (wear_suit.body_parts_covered & LEGS)))) + leg_clothes = wear_suit + if(leg_clothes) + if(!(leg_clothes.resistance_flags & UNACIDABLE)) + leg_clothes.acid_act(acidpwr, acid_volume) + update_inv_shoes() + update_inv_w_uniform() + update_inv_wear_suit() + else + to_chat(src, "Your [leg_clothes.name] protects your legs and feet from the acid!") + else + . = get_bodypart(BODY_ZONE_R_LEG) + if(.) + damaged += . + . = get_bodypart(BODY_ZONE_L_LEG) + if(.) + damaged += . + + + //DAMAGE// + for(var/obj/item/bodypart/affecting in damaged) + affecting.receive_damage(acidity, 2*acidity) + + if(affecting.name == BODY_ZONE_HEAD) + if(prob(min(acidpwr*acid_volume/10, 90))) //Applies disfigurement + affecting.receive_damage(acidity, 2*acidity) + emote("scream") + facial_hair_style = "Shaved" + hair_style = "Bald" + update_hair() + ADD_TRAIT(src, TRAIT_DISFIGURED, TRAIT_GENERIC) + + update_damage_overlays() + + //MELTING INVENTORY ITEMS// + //these items are all outside of armour visually, so melt regardless. + if(!bodyzone_hit) + if(back) + inventory_items_to_kill += back + if(belt) + inventory_items_to_kill += belt + + inventory_items_to_kill += held_items + + for(var/obj/item/I in inventory_items_to_kill) + I.acid_act(acidpwr, acid_volume) + return 1 + +/mob/living/carbon/human/singularity_act() + var/gain = 20 + if(mind) + if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") ) + gain = 100 + if(mind.assigned_role == "Clown") + gain = rand(-300, 300) + investigate_log("([key_name(src)]) has been consumed by the singularity.", INVESTIGATE_SINGULO) //Oh that's where the clown ended up! + gib() + return(gain) + +/mob/living/carbon/human/help_shake_act(mob/living/carbon/M) + if(!istype(M)) + return + + if(health >= 0) + if(src == M) + if(has_status_effect(STATUS_EFFECT_CHOKINGSTRAND)) + to_chat(src, "You attempt to remove the durathread strand from around your neck.") + if(do_after(src, 35, null, src)) + to_chat(src, "You succesfuly remove the durathread strand.") + remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND) + return + var/to_send = "" + visible_message("[src] examines [p_them()]self.", \ + "You check yourself for injuries.") + + var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + for(var/X in bodyparts) + var/obj/item/bodypart/LB = X + missing -= LB.body_zone + if(LB.is_pseudopart) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades + continue + var/limb_max_damage = LB.max_damage + var/status = "" + var/brutedamage = LB.brute_dam + var/burndamage = LB.burn_dam + var/broken = LB.broken + if(hallucination) + if(prob(30)) + brutedamage += rand(30,40) + if(prob(30)) + burndamage += rand(30,40) + + if(HAS_TRAIT(src, TRAIT_SELF_AWARE)) + status = "[brutedamage] brute damage and [burndamage] burn damage" + if(!brutedamage && !burndamage) + status = "no damage" + + else + if(brutedamage > 0) + status = LB.light_brute_msg + if(brutedamage > (limb_max_damage*0.4)) + status = LB.medium_brute_msg + if(brutedamage > (limb_max_damage*0.8)) + status = LB.heavy_brute_msg + if(brutedamage > 0 && burndamage > 0) + status += " and " + + if(burndamage > (limb_max_damage*0.8)) + status += LB.heavy_burn_msg + else if(burndamage > (limb_max_damage*0.2)) + status += LB.medium_burn_msg + else if(burndamage > 0) + status += LB.light_burn_msg + if(broken == 1) + status = "fractured" + if(status == "") + status = "OK" + var/no_damage + if(status == "OK" || status == "no damage") + no_damage = TRUE + to_send += "\t Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].\n" + + for(var/obj/item/I in LB.embedded_objects) + to_send += "\t There is \a [I] embedded in your [LB.name]!\n" + + for(var/t in missing) + for(var/t in missing) + to_send += "Your [parse_zone(t)] is missing!\n" + + if(bleed_rate) + to_send += "You are bleeding!\n" + if(getStaminaLoss()) + if(getStaminaLoss() > 30) + to_send += "You're completely exhausted.\n" + else + to_send += "You feel fatigued.\n" + if(HAS_TRAIT(src, TRAIT_SELF_AWARE)) + if(toxloss) + if(toxloss > 10) + to_send += "You feel sick.\n" + else if(toxloss > 20) + to_send += "You feel nauseated.\n" + else if(toxloss > 40) + to_send += "You feel very unwell!\n" + if(oxyloss) + if(oxyloss > 10) + to_send += "You feel lightheaded.\n" + else if(oxyloss > 20) + to_send += "Your thinking is clouded and distant.\n" + else if(oxyloss > 30) + to_send += "You're choking!\n" + + switch(nutrition) + if(NUTRITION_LEVEL_FULL to INFINITY) + to_send += "You're completely stuffed!\n" + if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL) + to_send += "You're well fed!\n" + if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED) + to_send += "You're not hungry.\n" + if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED) + to_send += "You could use a bite to eat.\n" + if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) + to_send += "You feel quite hungry.\n" + if(0 to NUTRITION_LEVEL_STARVING) + to_send += "You're starving!\n" + + + //TODO: Convert these messages into vague messages, thereby encouraging actual dignosis. + //Compiles then shows the list of damaged organs and broken organs + var/list/broken = list() + var/list/damaged = list() + var/broken_message + var/damaged_message + var/broken_plural + var/damaged_plural + //Sets organs into their proper list + for(var/O in internal_organs) + var/obj/item/organ/organ = O + if(organ.organ_flags & ORGAN_FAILING) + if(broken.len) + broken += ", " + broken += organ.name + else if(organ.damage > organ.low_threshold) + if(damaged.len) + damaged += ", " + damaged += organ.name + //Checks to enforce proper grammar, inserts words as necessary into the list + if(broken.len) + if(broken.len > 1) + broken.Insert(broken.len, "and ") + broken_plural = TRUE + else + var/holder = broken[1] //our one and only element + if(holder[length(holder)] == "s") + broken_plural = TRUE + //Put the items in that list into a string of text + for(var/B in broken) + broken_message += B + to_chat(src, " Your [broken_message] [broken_plural ? "are" : "is"] non-functional!") + if(damaged.len) + if(damaged.len > 1) + damaged.Insert(damaged.len, "and ") + damaged_plural = TRUE + else + var/holder = damaged[1] + if(holder[length(holder)] == "s") + damaged_plural = TRUE + for(var/D in damaged) + damaged_message += D + to_chat(src, "Your [damaged_message] [damaged_plural ? "are" : "is"] hurt.") + + if(roundstart_quirks.len) + to_send += "You have these quirks: [get_trait_string()].\n" + + to_chat(src, to_send) + else + if(wear_suit) + wear_suit.add_fingerprint(M) + else if(w_uniform) + w_uniform.add_fingerprint(M) + + ..() + + +/mob/living/carbon/human/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone) + if(damage_type != BRUTE && damage_type != BURN) + return + damage_amount *= 0.5 //0.5 multiplier for balance reason, we don't want clothes to be too easily destroyed + var/list/torn_items = list() + + //HEAD// + if(!def_zone || def_zone == BODY_ZONE_HEAD) + var/obj/item/clothing/head_clothes = null + if(glasses) + head_clothes = glasses + if(wear_mask) + head_clothes = wear_mask + if(wear_neck) + head_clothes = wear_neck + if(head) + head_clothes = head + if(head_clothes) + torn_items += head_clothes + else if(ears) + torn_items += ears + + //CHEST// + if(!def_zone || def_zone == BODY_ZONE_CHEST) + var/obj/item/clothing/chest_clothes = null + if(w_uniform) + chest_clothes = w_uniform + if(wear_suit) + chest_clothes = wear_suit + if(chest_clothes) + torn_items += chest_clothes + + //ARMS & HANDS// + if(!def_zone || def_zone == BODY_ZONE_L_ARM || def_zone == BODY_ZONE_R_ARM) + var/obj/item/clothing/arm_clothes = null + if(gloves) + arm_clothes = gloves + if(w_uniform && ((w_uniform.body_parts_covered & HANDS) || (w_uniform.body_parts_covered & ARMS))) + arm_clothes = w_uniform + if(wear_suit && ((wear_suit.body_parts_covered & HANDS) || (wear_suit.body_parts_covered & ARMS))) + arm_clothes = wear_suit + if(arm_clothes) + torn_items |= arm_clothes + + //LEGS & FEET// + if(!def_zone || def_zone == BODY_ZONE_L_LEG || def_zone == BODY_ZONE_R_LEG) + var/obj/item/clothing/leg_clothes = null + if(shoes) + leg_clothes = shoes + if(w_uniform && ((w_uniform.body_parts_covered & FEET) || (w_uniform.body_parts_covered & LEGS))) + leg_clothes = w_uniform + if(wear_suit && ((wear_suit.body_parts_covered & FEET) || (wear_suit.body_parts_covered & LEGS))) + leg_clothes = wear_suit + if(leg_clothes) + torn_items |= leg_clothes + + for(var/obj/item/I in torn_items) + I.take_damage(damage_amount, damage_type, damage_flag, 0) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 34367af9..7126a794 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1519,6 +1519,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) target.lastattacker = user.real_name target.lastattackerckey = user.ckey + user.dna.species.spec_unarmedattacked(user, target) if(user.limb_destroyer) target.dismembering_strike(user, affecting.body_zone) @@ -1532,6 +1533,9 @@ GLOBAL_LIST_EMPTY(roundstart_races) else if(target.lying) target.forcesay(GLOB.hit_appends) +/datum/species/proc/spec_unarmedattacked(mob/living/carbon/human/user, mob/living/carbon/human/target) + return + /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) // CITADEL EDIT slap mouthy gits and booty var/aim_for_mouth = user.zone_selected == "mouth" diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index d08eb5ae..c482b6df 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -943,6 +943,21 @@ grab_sound = 'sound/weapons/whipgrab.ogg' attack_sound = 'sound/weapons/whip.ogg' +/datum/species/golem/durathread + name = "Durathread Golem" + id = "durathread golem" + prefix = "Durathread" + limbs_id = "d_golem" + special_names = list("Boll","Weave") + species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES) + fixed_mut_color = null + inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) + info_text = "As a Durathread Golem, your strikes will cause those your targets to start choking, but your woven body won't withstand fire as well." + +/datum/species/golem/durathread/spec_unarmedattacked(mob/living/carbon/human/user, mob/living/carbon/human/target) + . = ..() + target.apply_status_effect(STATUS_EFFECT_CHOKINGSTRAND) + /datum/species/golem/bone name = "Bone Golem" id = "bone golem" diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 765c50da..13b4a031 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -109,7 +109,7 @@ var/datum/gas_mixture/breath if(!getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || lungs.organ_flags & ORGAN_FAILING) + if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || HAS_TRAIT(src, TRAIT_MAGIC_CHOKE) || (lungs && lungs.organ_flags & ORGAN_FAILING)) losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath else if(health <= crit_threshold) diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm index 8bed71df..13ca684f 100644 --- a/code/modules/ruins/lavaland_ruin_code.dm +++ b/code/modules/ruins/lavaland_ruin_code.dm @@ -85,7 +85,8 @@ /obj/item/stack/tile/bronze = /datum/species/golem/bronze, /obj/item/stack/sheet/cardboard = /datum/species/golem/cardboard, /obj/item/stack/sheet/leather = /datum/species/golem/leather, - /obj/item/stack/sheet/bone = /datum/species/golem/bone) + /obj/item/stack/sheet/bone = /datum/species/golem/bone, + /obj/item/stack/sheet/cotton/durathread = /datum/species/golem/durathread) if(istype(I, /obj/item/stack)) var/obj/item/stack/O = I