diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index 7ed8ee558b..c808a7fda2 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -72,6 +72,7 @@ #define COMSIG_ATOM_SCREWDRIVER_ACT "atom_screwdriver_act" //from base of atom/screwdriver_act(): (mob/living/user, obj/item/I) #define COMSIG_ATOM_INTERCEPT_TELEPORT "intercept_teleport" //called when teleporting into a protected turf: (channel, turf/origin) #define COMPONENT_BLOCK_TELEPORT 1 +#define COMSIG_ATOM_HEARER_IN_VIEW "atom_hearer_in_view" //called when an atom with HEAR_1 is added to the hearers on /proc/get_hearers_in_view(): (list/processing_list, list/hearers) ///////////////// #define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost" //from base of atom/attack_ghost(): (mob/dead/observer/ghost) #define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" //from base of atom/attack_hand(): (mob/user) @@ -122,8 +123,10 @@ #define COMSIG_MIND_TRANSFER "mind_transfer" //from base of mind/transfer_to(): (new_character, old_character) // /mob signals +#define COMSIG_MOB_EXAMINATE "mob_examinate" //from base of /mob/verb/examinate(): (atom/A) + #define COMPONENT_ALLOW_EXAMINE 1 #define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed) -#define COMSIG_MOB_GHOSTIZE "mob_ghostize" //from base of mob/Ghostize() (can_reenter_corpse) +#define COMSIG_MOB_GHOSTIZE "mob_ghostize" //from base of mob/Ghostize(): (can_reenter_corpse) #define COMPONENT_BLOCK_GHOSTING 1 #define COMSIG_MOB_ALLOWED "mob_allowed" //from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj #define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 19d0755085..88754d1436 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -264,6 +264,7 @@ var/atom/A = processing_list[1] if(A.flags_1 & HEAR_1) . += A + SEND_SIGNAL(A, COMSIG_ATOM_HEARER_IN_VIEW, processing_list, .) processing_list.Cut(1, 2) processing_list += A.contents diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 58eabbdbcf..e9f50d9212 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -321,8 +321,7 @@ return /atom/proc/ShiftClick(mob/user) SEND_SIGNAL(src, COMSIG_CLICK_SHIFT, user) - if(user.client && user.client.eye == user || user.client.eye == user.loc) - user.examinate(src) + user.examinate(src) return /* diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 345212cc1b..3247b890c6 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -80,7 +80,7 @@ return TRUE if(ishuman(L)) //Are you immune? var/mob/living/carbon/human/H = L - var/thermal_protection = H.get_thermal_protection() + var/thermal_protection = H.easy_thermal_protection() if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT) return TRUE if(isliving(L))// if we're a non immune mob inside an immune mob we have to reconsider if that mob is immune to protect ourselves diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 1a8bc7ece4..73aadc99d0 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -109,7 +109,7 @@ var/atom/movable/AM = i var/obj/item/bodypart/head/as_head = AM var/obj/item/mmi/as_mmi = AM - var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || isbrain(AM) + var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || isbrain(AM) || istype(AM, /obj/item/dullahan_relay) if(brain_holder) emergency_stop(AM) else if(isliving(AM)) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index ccd13d8d4a..728a394196 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -211,7 +211,7 @@ if(ishuman(occupant)) var/mob/living/carbon/human/H = occupant - cold_protection = H.get_cold_protection(air1.temperature) + cold_protection = H.get_thermal_protection(air1.temperature, TRUE) if(abs(temperature_delta) > 1) var/air_heat_capacity = air1.heat_capacity() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 9395283aeb..d581ccd3f3 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -3,7 +3,7 @@ //NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick! // bitflags for the percentual amount of protection a piece of clothing which covers the body part offers. -// Used with human/proc/get_heat_protection() and human/proc/get_cold_protection() +// Used with human/proc/get_thermal_protection() // The values here should add up to 1. // Hands and feet have 2.5%, arms and legs 7.5%, each of the torso parts has 15% and the head has 30% #define THERMAL_PROTECTION_HEAD 0.3 @@ -53,16 +53,17 @@ /mob/living/carbon/human/calculate_affecting_pressure(pressure) - if (wear_suit && head && istype(wear_suit, /obj/item/clothing) && istype(head, /obj/item/clothing)) + var/headless = !get_bodypart(BODY_ZONE_HEAD) //should the mob be perennially headless (see dullahans), we only take the suit into account, so they can into space. + if (wear_suit && istype(wear_suit, /obj/item/clothing) && (headless || (head && istype(head, /obj/item/clothing)))) var/obj/item/clothing/CS = wear_suit var/obj/item/clothing/CH = head - if (CS.clothing_flags & CH.clothing_flags & STOPSPRESSUREDAMAGE) + if (CS.clothing_flags & STOPSPRESSUREDAMAGE && (headless || (CH.clothing_flags & STOPSPRESSUREDAMAGE))) return ONE_ATMOSPHERE if(isbelly(loc)) //START OF CIT CHANGES - Makes it so you don't suffocate while inside vore organs. Remind me to modularize this some time - Bhijn return ONE_ATMOSPHERE if(istype(loc, /obj/item/dogborg/sleeper)) return ONE_ATMOSPHERE //END OF CIT CHANGES - return pressure + return ..() /mob/living/carbon/human/handle_traits() @@ -136,7 +137,7 @@ if(dna) dna.species.handle_fire(src) -/mob/living/carbon/human/proc/get_thermal_protection() +/mob/living/carbon/human/proc/easy_thermal_protection() var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures //CITADEL EDIT Vore code required overrides if(istype(loc, /obj/item/dogborg/sleeper)) @@ -167,7 +168,17 @@ last_fire_update = null ..() //END FIRE CODE - +#define THERMAL_PROTECTION_HEAD 0.3 +#define THERMAL_PROTECTION_CHEST 0.15 +#define THERMAL_PROTECTION_GROIN 0.15 +#define THERMAL_PROTECTION_LEG_LEFT 0.075 +#define THERMAL_PROTECTION_LEG_RIGHT 0.075 +#define THERMAL_PROTECTION_FOOT_LEFT 0.025 +#define THERMAL_PROTECTION_FOOT_RIGHT 0.025 +#define THERMAL_PROTECTION_ARM_LEFT 0.075 +#define THERMAL_PROTECTION_ARM_RIGHT 0.075 +#define THERMAL_PROTECTION_HAND_LEFT 0.025 +#define THERMAL_PROTECTION_HAND_RIGHT 0.025 //This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, CHEST, GROIN, etc. See setup.dm for the full list) /mob/living/carbon/human/proc/get_heat_protection_flags(temperature) //Temperature is the temperature you're being exposed to. @@ -194,37 +205,6 @@ return thermal_protection_flags -/mob/living/carbon/human/proc/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to. - var/thermal_protection_flags = get_heat_protection_flags(temperature) - - var/thermal_protection = 0 - if(thermal_protection_flags) - if(thermal_protection_flags & HEAD) - thermal_protection += THERMAL_PROTECTION_HEAD - if(thermal_protection_flags & CHEST) - thermal_protection += THERMAL_PROTECTION_CHEST - if(thermal_protection_flags & GROIN) - thermal_protection += THERMAL_PROTECTION_GROIN - if(thermal_protection_flags & LEG_LEFT) - thermal_protection += THERMAL_PROTECTION_LEG_LEFT - if(thermal_protection_flags & LEG_RIGHT) - thermal_protection += THERMAL_PROTECTION_LEG_RIGHT - if(thermal_protection_flags & FOOT_LEFT) - thermal_protection += THERMAL_PROTECTION_FOOT_LEFT - if(thermal_protection_flags & FOOT_RIGHT) - thermal_protection += THERMAL_PROTECTION_FOOT_RIGHT - if(thermal_protection_flags & ARM_LEFT) - thermal_protection += THERMAL_PROTECTION_ARM_LEFT - if(thermal_protection_flags & ARM_RIGHT) - thermal_protection += THERMAL_PROTECTION_ARM_RIGHT - if(thermal_protection_flags & HAND_LEFT) - thermal_protection += THERMAL_PROTECTION_HAND_LEFT - if(thermal_protection_flags & HAND_RIGHT) - thermal_protection += THERMAL_PROTECTION_HAND_RIGHT - - - return min(1,thermal_protection) - //See proc/get_heat_protection_flags(temperature) for the description of this proc. /mob/living/carbon/human/proc/get_cold_protection_flags(temperature) var/thermal_protection_flags = 0 @@ -251,17 +231,42 @@ return thermal_protection_flags -/mob/living/carbon/human/proc/get_cold_protection(temperature) -//CITADEL EDIT Mandatory for vore code. - if(istype(loc, /obj/item/dogborg/sleeper)) - return TRUE //freezing to death in sleepers ruins fun. - if(isbelly(loc)) - return TRUE - if(ismob(loc)) - return TRUE //because lazy and being inside somemone insulates you from space -//END EDIT - temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. - var/thermal_protection_flags = get_cold_protection_flags(temperature) +/mob/living/carbon/human/proc/get_thermal_protection(temperature, cold = FALSE) + if(cold) + //CITADEL EDIT Mandatory for vore code. + if(istype(loc, /obj/item/dogborg/sleeper) || isbelly(loc) || ismob(loc)) + return 1 //freezing to death in sleepers ruins fun. + //END EDIT + temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. + var/thermal_protection_flags = cold ? get_cold_protection_flags(temperature) : get_heat_protection_flags(temperature) + var/missing_body_parts_flags = missing_body_parts_flags() + var/max_protection = 1 + if(missing_body_parts_flags) //I don't like copypasta as much as proc overhead. Do you want me to make these into a macro? + DISABLE_BITFIELD(thermal_protection_flags, missing_body_parts_flags) + if(missing_body_parts_flags & HEAD) + max_protection -= THERMAL_PROTECTION_HEAD + if(missing_body_parts_flags & CHEST) + max_protection -= THERMAL_PROTECTION_CHEST + if(missing_body_parts_flags & GROIN) + max_protection -= THERMAL_PROTECTION_GROIN + if(missing_body_parts_flags & LEG_LEFT) + max_protection -= THERMAL_PROTECTION_LEG_LEFT + if(missing_body_parts_flags & LEG_RIGHT) + max_protection -= THERMAL_PROTECTION_LEG_RIGHT + if(missing_body_parts_flags & FOOT_LEFT) + max_protection -= THERMAL_PROTECTION_FOOT_LEFT + if(missing_body_parts_flags & FOOT_RIGHT) + max_protection -= THERMAL_PROTECTION_FOOT_RIGHT + if(missing_body_parts_flags & ARM_LEFT) + max_protection -= THERMAL_PROTECTION_ARM_LEFT + if(missing_body_parts_flags & ARM_RIGHT) + max_protection -= THERMAL_PROTECTION_ARM_RIGHT + if(missing_body_parts_flags & HAND_LEFT) + max_protection -= THERMAL_PROTECTION_HAND_LEFT + if(missing_body_parts_flags & HAND_RIGHT) + max_protection -= THERMAL_PROTECTION_HAND_RIGHT + if(max_protection == 0) //Is it even a man if it doesn't have a body at all? Early return to avoid division by zero. + return 1 var/thermal_protection = 0 if(thermal_protection_flags) @@ -288,7 +293,7 @@ if(thermal_protection_flags & HAND_RIGHT) thermal_protection += THERMAL_PROTECTION_HAND_RIGHT - return min(1,thermal_protection) + return round(thermal_protection/max_protection, 0.001) /mob/living/carbon/human/handle_random_events() //Puke if toxloss is too high diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 1f67f2b13c..bf9c0be906 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -2034,13 +2034,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) natural = H.natural_bodytemperature_stabilization() var/thermal_protection = 1 if(loc_temp < H.bodytemperature) //Place is colder than we are - thermal_protection -= H.get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + thermal_protection -= H.get_thermal_protection(loc_temp, TRUE) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. if(H.bodytemperature < BODYTEMP_NORMAL) //we're cold, insulation helps us retain body heat and will reduce the heat we lose to the environment H.adjust_bodytemperature((thermal_protection+1)*natural + max(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX)) else //we're sweating, insulation hinders our ability to reduce heat - and it will reduce the amount of cooling you get from the environment H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + max((thermal_protection * (loc_temp - H.bodytemperature) + BODYTEMP_NORMAL - H.bodytemperature) / BODYTEMP_COLD_DIVISOR , BODYTEMP_COOLING_MAX)) //Extra calculation for hardsuits to bleed off heat else //Place is hotter than we are - thermal_protection -= H.get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + thermal_protection -= H.get_thermal_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. if(H.bodytemperature < BODYTEMP_NORMAL) //and we're cold, insulation enhances our ability to retain body heat but reduces the heat we get from the environment H.adjust_bodytemperature((thermal_protection+1)*natural + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX)) else //we're sweating, insulation hinders out ability to reduce heat - but will reduce the amount of heat we get from the environment @@ -2179,7 +2179,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!(I.resistance_flags & FIRE_PROOF)) I.take_damage(H.fire_stacks, BURN, "fire", 0) - var/thermal_protection = H.get_thermal_protection() + var/thermal_protection = H.easy_thermal_protection() if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT && !no_protection) return diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index eba4ff6d2f..9a23767050 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -18,6 +18,8 @@ var/obj/item/dullahan_relay/myhead /datum/species/dullahan/pumpkin + name = "Pumpkin Head Dullahan" + id = "pumpkindullahan" pumpkin = TRUE /datum/species/dullahan/check_roundstart_eligible() @@ -126,21 +128,25 @@ . = ..() owner = new_owner START_PROCESSING(SSobj, src) + if(owner) + RegisterSignal(owner, COMSIG_MOB_EXAMINATE, .proc/examinate_check) + RegisterSignal(owner, COMSIG_ATOM_HEARER_IN_VIEW, .proc/include_owner) + else + return INITIALIZE_HINT_QDEL + +/obj/item/dullahan_relay/proc/examinate_check(mob/source, atom/A) + if(source.client.eye == src && ((A in view(source.client.view, src)) || (isturf(A) && source.sight & SEE_TURFS) || (ismob(A) && source.sight & SEE_MOBS) || (isobj(A) && source.sight & SEE_OBJS))) + return COMPONENT_ALLOW_EXAMINE + +/obj/item/dullahan_relay/proc/include_owner(list/processing_list, list/hearers) + if(!QDELETED(owner)) + hearers += owner /obj/item/dullahan_relay/process() if(!istype(loc, /obj/item/bodypart/head) || QDELETED(owner)) . = PROCESS_KILL qdel(src) -/obj/item/dullahan_relay/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) - . = ..() - if(!QDELETED(owner)) - message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode) - to_chat(owner,message) - else - qdel(src) - - /obj/item/dullahan_relay/Destroy() if(!QDELETED(owner)) var/mob/living/carbon/human/H = owner diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 618baf245f..0b1ade05f2 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -307,8 +307,11 @@ set name = "Examine" set category = "IC" - if(isturf(A) && !(sight & SEE_TURFS) && !(A in view(client ? client.view : world.view, src))) - // shift-click catcher may issue examinate() calls for out-of-sight turfs + if(!client) + return + + if(!(SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A) & COMPONENT_ALLOW_EXAMINE) && ((client.eye != src && client.eye != loc) || (isturf(A) && !(sight & SEE_TURFS) && !(A in view(client ? client.view : world.view, src))))) + //cameras & co don't allow users to examine far away things, also shift-click catcher may issue examinate() calls for out-of-sight turfs return if(is_blind(src)) diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index d520fbb917..aacaf49f70 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -18,8 +18,6 @@ return FALSE - - /mob/proc/has_left_hand(check_disabled = TRUE) return TRUE @@ -335,3 +333,19 @@ else S.adjusted = ALT_STYLE H.update_inv_wear_suit() + +/mob/living/carbon/proc/missing_body_parts_flags() + for(var/X in bodyparts) + var/obj/item/bodypart/L = X + switch(L.body_part) + if(CHEST) + . |= GROIN + if(LEG_LEFT) + . |= FOOT_LEFT + if(LEG_RIGHT) + . |= FOOT_RIGHT + if(ARM_LEFT) + . |= HAND_LEFT + if(ARM_RIGHT) + . |= HAND_RIGHT + . |= L.body_part \ No newline at end of file