mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-31 00:58:26 +01:00
Merge branch 'master' of https://github.com/tgstation/tgstation into upstream-23-10-2025
This commit is contained in:
@@ -183,14 +183,22 @@
|
||||
/// Sounds when this bodypart is used in an umarmed attack
|
||||
var/sound/unarmed_attack_sound = 'sound/items/weapons/punch1.ogg'
|
||||
var/sound/unarmed_miss_sound = 'sound/items/weapons/punchmiss.ogg'
|
||||
///Lowest possible punch damage this bodypart can give. If this is set to 0, unarmed attacks will always miss.
|
||||
/// Lowest possible punch damage this bodypart can give. If this is set to 0, unarmed attacks will always miss.
|
||||
var/unarmed_damage_low = 1
|
||||
///Highest possible punch damage this bodypart can ive.
|
||||
/// Highest possible punch damage this bodypart can ive.
|
||||
var/unarmed_damage_high = 1
|
||||
///Determines the accuracy bonus, armor penetration and knockdown probability.
|
||||
/// Determines the accuracy bonus, armor penetration and knockdown probability.
|
||||
var/unarmed_effectiveness = 10
|
||||
/// Multiplier applied to effectiveness and damage when attacking a grabbed target.
|
||||
var/unarmed_pummeling_bonus = 1
|
||||
/// If this limb is used to grab (which is only arms right now), how much more effective is the limb? Every integer above or below 0 is one effective grab level. Higher is a bonus, lower is a malus.
|
||||
/// This is more powerful than adjusting grab escape chance. If the arm has both an increased grab level and a chance reduction, it is very hard to escape a grab.
|
||||
var/unarmed_grab_state_bonus = 0
|
||||
/// If this limb is used to grab (which is only arms right now), how much additional damage does it deal to the grabbed individual when they fail to escape the grab?
|
||||
var/unarmed_grab_damage_bonus = 0
|
||||
/// If this limb is used to grab (which is only arms right now), how much more difficult is it to escape the grab, before accounting for grab state? Values above 0 is a malus, values below 0 is a bonus.
|
||||
/// This is less powerful than adjusting grab state. If the arm has both an increased grab level and a chance reduction, it is very hard to escape a grab.
|
||||
var/unarmed_grab_escape_chance_bonus = 0
|
||||
/// The 'sharpness' of the limb. Could indicate claws, teeth or spines. Should default to NONE, or blunt.
|
||||
var/unarmed_sharpness = NONE
|
||||
|
||||
@@ -1129,42 +1137,43 @@
|
||||
if(dropped && dmg_overlay_type)
|
||||
if(brutestate)
|
||||
// divided into two overlays: one that gets colored and one that doesn't.
|
||||
var/image/brute_blood_overlay = image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER)
|
||||
var/image/brute_blood_overlay = image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, dir = SOUTH)
|
||||
brute_blood_overlay.color = get_color_from_blood_list(update_on ? update_on.get_blood_dna_list() : blood_dna_info) // living mobs can just get it fresh, dropped limbs use blood_dna_info
|
||||
var/mutable_appearance/brute_damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0_overlay", -DAMAGE_LAYER, appearance_flags = RESET_COLOR)
|
||||
if(brute_damage_overlay)
|
||||
brute_blood_overlay.overlays += brute_damage_overlay
|
||||
. += brute_blood_overlay
|
||||
if(burnstate)
|
||||
. += image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER)
|
||||
. += image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, dir = SOUTH)
|
||||
|
||||
var/image/limb = image(layer = -BODYPARTS_LAYER)
|
||||
var/image/aux
|
||||
var/image_dir = null
|
||||
if (dropped)
|
||||
image_dir = SOUTH
|
||||
|
||||
// Handles invisibility (not alpha or actual invisibility but invisibility)
|
||||
if(is_invisible)
|
||||
limb.icon = icon_invisible
|
||||
limb.icon_state = "invisible_[body_zone]"
|
||||
. += limb
|
||||
. += image(icon_invisible, "invisible_[body_zone]", -BODYPARTS_LAYER, dir = image_dir)
|
||||
return .
|
||||
|
||||
// Normal non-husk handling
|
||||
// This is the MEAT of limb icon code
|
||||
limb.icon = icon_greyscale
|
||||
// This is the MEAT of limb icon code
|
||||
var/used_icon = icon_greyscale
|
||||
if(!should_draw_greyscale || !icon_greyscale)
|
||||
limb.icon = icon_static
|
||||
used_icon = icon_static
|
||||
|
||||
if(is_dimorphic) //Does this type of limb have sexual dimorphism?
|
||||
limb.icon_state = "[limb_id]_[body_zone]_[limb_gender]"
|
||||
else
|
||||
limb.icon_state = "[limb_id]_[body_zone]"
|
||||
var/used_state = "[limb_id]_[body_zone]"
|
||||
if(is_dimorphic) // Does this type of limb have sexual dimorphism?
|
||||
used_state = "[limb_id]_[body_zone]_[limb_gender]"
|
||||
|
||||
var/image/limb = image(used_icon, used_state, -BODYPARTS_LAYER, dir = image_dir)
|
||||
var/image/aux = null
|
||||
|
||||
icon_exists_or_scream(limb.icon, limb.icon_state) //Prints a stack trace on the first failure of a given iconstate.
|
||||
|
||||
. += limb
|
||||
|
||||
if(aux_zone) //Hand shit
|
||||
aux = image(limb.icon, "[limb_id]_[aux_zone]", -aux_layer)
|
||||
aux = image(limb.icon, "[limb_id]_[aux_zone]", -aux_layer, dir = image_dir)
|
||||
. += aux
|
||||
|
||||
if(is_husked)
|
||||
@@ -1181,50 +1190,67 @@
|
||||
if(aux_zone)
|
||||
aux.color = limb_color // SKYRAT EDIT CHANGE - ORIGINAL: aux.color = "[draw_color]"
|
||||
|
||||
//EMISSIVE CODE START
|
||||
// For some reason this was applied as an overlay on the aux image and limb image before.
|
||||
// I am very sure that this is unnecessary, and i need to treat it as part of the return list
|
||||
// to be able to mask it proper in case this limb is a leg.
|
||||
var/atom/location = loc || owner || src
|
||||
if(blocks_emissive != EMISSIVE_BLOCK_NONE)
|
||||
var/mutable_appearance/limb_em_block = emissive_blocker(limb.icon, limb.icon_state, location, layer = limb.layer, alpha = limb.alpha)
|
||||
if (dropped)
|
||||
limb_em_block = image(limb_em_block, dir = SOUTH)
|
||||
. += limb_em_block
|
||||
|
||||
if(aux_zone)
|
||||
var/mutable_appearance/aux_em_block = emissive_blocker(aux.icon, aux.icon_state, location, layer = aux.layer, alpha = aux.alpha)
|
||||
if (dropped)
|
||||
aux_em_block = image(aux_em_block, dir = SOUTH)
|
||||
. += aux_em_block
|
||||
|
||||
if(!is_husked && is_emissive)
|
||||
var/mutable_appearance/limb_em = emissive_appearance(limb.icon, "[limb.icon_state]_e", location, layer = limb.layer, alpha = limb.alpha)
|
||||
if (dropped)
|
||||
limb_em = image(limb_em, dir = SOUTH)
|
||||
. += limb_em
|
||||
|
||||
if(aux_zone)
|
||||
var/mutable_appearance/aux_em = emissive_appearance(aux.icon, "[aux.icon_state]_e", location, layer = aux.layer, alpha = aux.alpha)
|
||||
if (dropped)
|
||||
aux_em = image(aux_em, dir = SOUTH)
|
||||
. += aux_em
|
||||
//EMISSIVE CODE END
|
||||
|
||||
//No need to handle leg layering if dropped, we only face south anyways
|
||||
// No need to handle leg layering if dropped, we only face south anyways
|
||||
if(!dropped && ((body_zone == BODY_ZONE_R_LEG) || (body_zone == BODY_ZONE_L_LEG)))
|
||||
//Legs are a bit goofy in regards to layering, and we will need two images instead of one to fix that
|
||||
// Legs are a bit goofy in regards to layering, and we will need two images instead of one to fix that
|
||||
var/obj/item/bodypart/leg/leg_source = src
|
||||
for(var/image/limb_image in .)
|
||||
//remove the old, unmasked image
|
||||
// Remove the old, unmasked image
|
||||
. -= limb_image
|
||||
//add two masked images based on the old one
|
||||
// Add two masked images based on the old one
|
||||
. += leg_source.generate_masked_leg(limb_image)
|
||||
|
||||
// And finally put bodypart_overlays on if not husked
|
||||
if(is_husked)
|
||||
return .
|
||||
|
||||
//Draw external organs like horns and frills
|
||||
// Draw external organs like horns and frills
|
||||
for(var/datum/bodypart_overlay/overlay as anything in bodypart_overlays)
|
||||
if(!overlay.can_draw_on_bodypart(src, owner))
|
||||
continue
|
||||
//Some externals have multiple layers for background, foreground and between
|
||||
|
||||
// Some externals have multiple layers for background, foreground and between
|
||||
for(var/external_layer in overlay.all_layers)
|
||||
if(overlay.layers & external_layer)
|
||||
. += overlay.get_overlay(external_layer, src)
|
||||
if(!(overlay.layers & external_layer))
|
||||
continue
|
||||
|
||||
var/external_overlay = overlay.get_overlay(external_layer, src)
|
||||
if (!dropped)
|
||||
. += external_overlay
|
||||
continue
|
||||
|
||||
if (!islist(external_overlay))
|
||||
. += image(external_overlay, dir = SOUTH)
|
||||
continue
|
||||
|
||||
for (var/mutable_appearance/actual_overlay as anything in external_overlay)
|
||||
. += image(actual_overlay, dir = SOUTH)
|
||||
|
||||
for(var/datum/layer in .)
|
||||
overlay.modify_bodypart_appearance(layer)
|
||||
// SKYRAT EDIT ADDITION BEGIN - MARKINGS CODE
|
||||
|
||||
@@ -173,56 +173,46 @@
|
||||
|
||||
/obj/item/bodypart/head/get_limb_icon(dropped, mob/living/carbon/update_on)
|
||||
. = ..()
|
||||
|
||||
. += get_hair_and_lips_icon(dropped)
|
||||
// We need to get the eyes if we are dropped (ugh)
|
||||
if(dropped)
|
||||
var/obj/item/organ/eyes/eyes = locate(/obj/item/organ/eyes) in src
|
||||
// This is a bit of copy/paste code from eyes.dm:generate_body_overlay
|
||||
if(eyes?.eye_icon_state && (head_flags & HEAD_EYESPRITES))
|
||||
var/image/eye_left = image('icons/mob/human/human_face.dmi', "[eyes.eye_icon_state]_l", -EYES_LAYER, SOUTH)
|
||||
var/image/eye_right = image('icons/mob/human/human_face.dmi', "[eyes.eye_icon_state]_r", -EYES_LAYER, SOUTH)
|
||||
if(head_flags & HEAD_EYECOLOR)
|
||||
if(eyes.eye_color_left)
|
||||
eye_left.color = eyes.eye_color_left
|
||||
if(eyes.eye_color_right)
|
||||
eye_right.color = eyes.eye_color_right
|
||||
if(eyes.overlay_ignore_lighting)
|
||||
eye_left.overlays += emissive_appearance(eye_left.icon, eye_left.icon_state, src, alpha = eye_left.alpha)
|
||||
eye_right.overlays += emissive_appearance(eye_right.icon, eye_right.icon_state, src, alpha = eye_right.alpha)
|
||||
else if(blocks_emissive != EMISSIVE_BLOCK_NONE)
|
||||
var/atom/location = loc || owner || src
|
||||
eye_left.overlays += emissive_blocker(eye_left.icon, eye_left.icon_state, location, alpha = eye_left.alpha)
|
||||
eye_right.overlays += emissive_blocker(eye_right.icon, eye_right.icon_state, location, alpha = eye_right.alpha)
|
||||
if(worn_face_offset)
|
||||
worn_face_offset.apply_offset(eye_left)
|
||||
worn_face_offset.apply_offset(eye_right)
|
||||
if(!dropped)
|
||||
return
|
||||
|
||||
// SKYRAT EDIT ADDITION START - Customization (Emissives and synths)
|
||||
if (eyes.is_emissive) // Because it was done all weird up there.
|
||||
var/mutable_appearance/emissive_left = emissive_appearance(eye_left.icon, eye_left.icon_state, src, -BODY_LAYER, eye_left.alpha)
|
||||
var/mutable_appearance/emissive_right = emissive_appearance(eye_right.icon, eye_right.icon_state, src, -BODY_LAYER, eye_right.alpha)
|
||||
var/obj/item/organ/eyes/eyes = locate(/obj/item/organ/eyes) in src
|
||||
if(!eyes)
|
||||
if (!(head_flags & HEAD_EYEHOLES))
|
||||
return
|
||||
var/image/no_eyes = image('icons/mob/human/human_face.dmi', "eyes_missing", -EYES_LAYER, SOUTH)
|
||||
worn_face_offset?.apply_offset(no_eyes)
|
||||
. += no_eyes
|
||||
return
|
||||
|
||||
emissive_left.appearance_flags &= ~RESET_TRANSFORM
|
||||
emissive_right.appearance_flags &= ~RESET_TRANSFORM
|
||||
if(!eyes.eye_icon_state || !(head_flags & HEAD_EYESPRITES))
|
||||
return
|
||||
|
||||
if(worn_face_offset)
|
||||
worn_face_offset.apply_offset(emissive_right)
|
||||
worn_face_offset.apply_offset(emissive_left)
|
||||
// This is a bit of copy/paste code from eyes.dm:generate_body_overlay
|
||||
var/image/eye_left = image('icons/mob/human/human_face.dmi', "[eyes.eye_icon_state]_l", -EYES_LAYER, SOUTH)
|
||||
var/image/eye_right = image('icons/mob/human/human_face.dmi', "[eyes.eye_icon_state]_r", -EYES_LAYER, SOUTH)
|
||||
if(head_flags & HEAD_EYECOLOR)
|
||||
if(eyes.eye_color_left)
|
||||
eye_left.color = eyes.eye_color_left
|
||||
if(eyes.eye_color_right)
|
||||
eye_right.color = eyes.eye_color_right
|
||||
|
||||
eye_left.overlays += emissive_left
|
||||
eye_right.overlays += emissive_right
|
||||
var/list/emissive_overlays = eyes.get_emissive_overlays(eye_left, eye_right, src)
|
||||
if(length(emissive_overlays))
|
||||
eye_left.overlays += image(emissive_overlays[1], dir = SOUTH)
|
||||
eye_right.overlays += image(emissive_overlays[2], dir = SOUTH)
|
||||
else if(blocks_emissive != EMISSIVE_BLOCK_NONE)
|
||||
eye_left.overlays += image(emissive_blocker(eye_left.icon, eye_left.icon_state, src, alpha = eye_left.alpha), dir = SOUTH)
|
||||
eye_right.overlays += image(emissive_blocker(eye_right.icon, eye_right.icon_state, src, alpha = eye_right.alpha), dir = SOUTH)
|
||||
|
||||
// SKYRAT EDIT END
|
||||
if(worn_face_offset)
|
||||
worn_face_offset.apply_offset(eye_left)
|
||||
worn_face_offset.apply_offset(eye_right)
|
||||
|
||||
. += eye_left
|
||||
. += eye_right
|
||||
else if(!eyes && (head_flags & HEAD_EYEHOLES))
|
||||
var/image/no_eyes = image('icons/mob/human/human_face.dmi', "eyes_missing", -EYES_LAYER, SOUTH)
|
||||
worn_face_offset?.apply_offset(no_eyes)
|
||||
. += no_eyes
|
||||
|
||||
return
|
||||
. += eye_left
|
||||
. += eye_right
|
||||
|
||||
/obj/item/bodypart/head/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
facial_hair_hidden = FALSE
|
||||
LAZYNULL(hair_masks)
|
||||
if(human_head_owner)
|
||||
for(var/obj/item/worn_item in human_head_owner.get_equipped_items())
|
||||
for(var/obj/item/worn_item in human_head_owner.get_equipped_items(INCLUDE_ABSTRACT))
|
||||
if(worn_item.hair_mask)
|
||||
LAZYSET(hair_masks, worn_item.hair_mask, TRUE)
|
||||
hair_hidden = !!(human_head_owner.obscured_slots & HIDEHAIR)
|
||||
@@ -62,16 +62,16 @@
|
||||
. = list()
|
||||
|
||||
var/atom/location = loc || owner || src
|
||||
var/image_dir = null
|
||||
if (dropped)
|
||||
image_dir = SOUTH
|
||||
|
||||
var/datum/sprite_accessory/sprite_accessory
|
||||
if(!facial_hair_hidden && lip_style && (head_flags & HEAD_LIPS))
|
||||
//not a sprite accessory, don't ask
|
||||
//Overlay
|
||||
var/image/lip_overlay = image('icons/mob/human/human_face.dmi', "lips_[lip_style]", -BODY_LAYER)
|
||||
var/image/lip_overlay = image('icons/mob/human/human_face.dmi', "lips_[lip_style]", -BODY_LAYER, dir = image_dir)
|
||||
lip_overlay.color = lip_color
|
||||
//Emissive blocker
|
||||
if(blocks_emissive != EMISSIVE_BLOCK_NONE)
|
||||
lip_overlay.overlays += emissive_blocker(lip_overlay.icon, lip_overlay.icon_state, location, alpha = facial_hair_alpha)
|
||||
//Offsets
|
||||
worn_face_offset?.apply_offset(lip_overlay)
|
||||
. += lip_overlay
|
||||
@@ -81,11 +81,14 @@
|
||||
sprite_accessory = SSaccessories.facial_hairstyles_list[facial_hairstyle]
|
||||
if(sprite_accessory)
|
||||
//Overlay
|
||||
facial_hair_overlay = image(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER)
|
||||
facial_hair_overlay = image(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER, dir = image_dir)
|
||||
facial_hair_overlay.alpha = facial_hair_alpha
|
||||
//Emissive blocker
|
||||
if(blocks_emissive != EMISSIVE_BLOCK_NONE)
|
||||
facial_hair_overlay.overlays += emissive_blocker(facial_hair_overlay.icon, facial_hair_overlay.icon_state, location, alpha = facial_hair_alpha)
|
||||
var/mutable_appearance/em_block = emissive_blocker(facial_hair_overlay.icon, facial_hair_overlay.icon_state, location, alpha = facial_hair_alpha)
|
||||
if (dropped)
|
||||
em_block = image(em_block, dir = SOUTH)
|
||||
facial_hair_overlay.overlays += em_block
|
||||
//Offsets
|
||||
worn_face_offset?.apply_offset(facial_hair_overlay)
|
||||
. += facial_hair_overlay
|
||||
@@ -93,7 +96,7 @@
|
||||
var/facial_hair_gradient_style = gradient_styles[GRADIENT_FACIAL_HAIR_KEY]
|
||||
if(facial_hair_gradient_style != "None")
|
||||
var/facial_hair_gradient_color = gradient_colors[GRADIENT_FACIAL_HAIR_KEY]
|
||||
var/image/facial_hair_gradient_overlay = get_gradient_overlay(icon(sprite_accessory.icon, sprite_accessory.icon_state), -HAIR_LAYER, SSaccessories.facial_hair_gradients_list[facial_hair_gradient_style], facial_hair_gradient_color)
|
||||
var/image/facial_hair_gradient_overlay = get_gradient_overlay(icon(sprite_accessory.icon, sprite_accessory.icon_state), -HAIR_LAYER, SSaccessories.facial_hair_gradients_list[facial_hair_gradient_style], facial_hair_gradient_color, dropped)
|
||||
. += facial_hair_gradient_overlay
|
||||
|
||||
var/list/all_hair_overlays = list()
|
||||
@@ -103,7 +106,7 @@
|
||||
//Hair masks
|
||||
var/icon/base_icon = icon(hair_sprite_accessory.getCachedIcon(hair_masks))
|
||||
//Overlay
|
||||
all_hair_overlays += image(base_icon, layer=-HAIR_LAYER)
|
||||
all_hair_overlays += image(base_icon, layer=-HAIR_LAYER, dir = image_dir)
|
||||
//If we have any hair appendages (ponytails, etc.) sticking out on a particular side, we need to add an additional hair layer to go above hats/helmets for the sides they stick out on
|
||||
if(LAZYLEN(hair_sprite_accessory.hair_appendages_outer))
|
||||
var/strictly_masked_zones = NONE
|
||||
@@ -112,7 +115,7 @@
|
||||
for(var/appendage_icon_state in hair_sprite_accessory.hair_appendages_outer)
|
||||
var/appendage_zone = hair_sprite_accessory.hair_appendages_outer[appendage_icon_state]
|
||||
if(!(appendage_zone & strictly_masked_zones)) // if there are no strict masks in this zone
|
||||
all_hair_overlays += image(hair_sprite_accessory.icon, icon_state=appendage_icon_state, layer=-OUTER_HAIR_LAYER)
|
||||
all_hair_overlays += image(hair_sprite_accessory.icon, icon_state=appendage_icon_state, layer=-OUTER_HAIR_LAYER, dir = image_dir)
|
||||
for(var/image/hair_overlay as anything in all_hair_overlays)
|
||||
hair_overlay.alpha = hair_alpha
|
||||
hair_overlay.pixel_z = hair_sprite_accessory.y_offset
|
||||
@@ -123,7 +126,10 @@
|
||||
// SKYRAT EDIT ADDITION END
|
||||
//Emissive blocker
|
||||
if(blocks_emissive != EMISSIVE_BLOCK_NONE)
|
||||
hair_overlay.overlays += emissive_blocker(hair_overlay.icon, hair_overlay.icon_state, location, alpha = hair_alpha)
|
||||
var/mutable_appearance/em_block = emissive_blocker(hair_overlay.icon, hair_overlay.icon_state, location, alpha = hair_alpha)
|
||||
if (dropped)
|
||||
em_block = image(em_block, dir = SOUTH)
|
||||
hair_overlay.overlays += em_block
|
||||
//Offsets
|
||||
worn_face_offset?.apply_offset(hair_overlay)
|
||||
. += hair_overlay
|
||||
@@ -131,7 +137,7 @@
|
||||
var/hair_gradient_style = gradient_styles[GRADIENT_HAIR_KEY]
|
||||
if(hair_gradient_style != "None")
|
||||
var/hair_gradient_color = gradient_colors[GRADIENT_HAIR_KEY]
|
||||
var/image/hair_gradient_overlay = get_gradient_overlay(base_icon, hair_overlay.layer, SSaccessories.hair_gradients_list[hair_gradient_style], hair_gradient_color)
|
||||
var/image/hair_gradient_overlay = get_gradient_overlay(base_icon, hair_overlay.layer, SSaccessories.hair_gradients_list[hair_gradient_style], hair_gradient_color, dropped)
|
||||
hair_gradient_overlay.pixel_z = hair_sprite_accessory.y_offset
|
||||
// SKYRAT EDIT ADDITION - Species hair offset
|
||||
if(LAZYFIND(owner?.dna?.species?.offset_features, OFFSET_HAIR))
|
||||
@@ -141,10 +147,10 @@
|
||||
. += hair_gradient_overlay
|
||||
|
||||
if(show_debrained && (head_flags & HEAD_DEBRAIN))
|
||||
. += get_debrain_overlay()
|
||||
. += get_debrain_overlay(dropped)
|
||||
|
||||
if(show_eyeless && (head_flags & HEAD_EYEHOLES))
|
||||
. += get_eyeless_overlay()
|
||||
. += get_eyeless_overlay(dropped)
|
||||
|
||||
//HAIR COLOR START
|
||||
if(override_hair_color)
|
||||
@@ -166,7 +172,7 @@
|
||||
#undef SET_OVERLAY_VALUE
|
||||
|
||||
/// Returns an appropriate debrained overlay
|
||||
/obj/item/bodypart/head/proc/get_debrain_overlay()
|
||||
/obj/item/bodypart/head/proc/get_debrain_overlay(dropped)
|
||||
RETURN_TYPE(/image)
|
||||
var/debrain_icon = 'icons/mob/human/human_face.dmi'
|
||||
var/debrain_icon_state = "debrained"
|
||||
@@ -181,21 +187,25 @@
|
||||
debrain_icon_state = "debrained"
|
||||
|
||||
var/image/debrain_overlay = mutable_appearance(debrain_icon, debrain_icon_state, -HAIR_LAYER)
|
||||
if (dropped)
|
||||
debrain_overlay = image(debrain_overlay, dir = SOUTH)
|
||||
worn_face_offset?.apply_offset(debrain_overlay)
|
||||
return debrain_overlay
|
||||
|
||||
/// Returns an appropriate missing eyes overlay
|
||||
/obj/item/bodypart/head/proc/get_eyeless_overlay()
|
||||
/obj/item/bodypart/head/proc/get_eyeless_overlay(dropped)
|
||||
RETURN_TYPE(/image)
|
||||
var/eyeless_icon = 'icons/mob/human/human_face.dmi'
|
||||
var/eyeless_icon_state = "eyes_missing"
|
||||
|
||||
var/image/eyeless_overlay = mutable_appearance(eyeless_icon, eyeless_icon_state, -HAIR_LAYER)
|
||||
if (dropped)
|
||||
eyeless_overlay = image(eyeless_overlay, dir = SOUTH)
|
||||
worn_face_offset?.apply_offset(eyeless_overlay)
|
||||
return eyeless_overlay
|
||||
|
||||
/// Returns an appropriate hair/facial hair gradient overlay
|
||||
/obj/item/bodypart/head/proc/get_gradient_overlay(icon/base_icon, layer, datum/sprite_accessory/gradient, grad_color)
|
||||
/obj/item/bodypart/head/proc/get_gradient_overlay(icon/base_icon, layer, datum/sprite_accessory/gradient, grad_color, dropped)
|
||||
RETURN_TYPE(/mutable_appearance)
|
||||
|
||||
var/mutable_appearance/gradient_overlay = mutable_appearance(layer = layer)
|
||||
@@ -204,6 +214,8 @@
|
||||
temp.Blend(temp_hair, ICON_ADD)
|
||||
gradient_overlay.icon = temp
|
||||
gradient_overlay.color = grad_color
|
||||
if (dropped)
|
||||
gradient_overlay = image(gradient_overlay, dir = SOUTH)
|
||||
worn_face_offset?.apply_offset(gradient_overlay)
|
||||
return gradient_overlay
|
||||
|
||||
|
||||
@@ -45,8 +45,10 @@
|
||||
span_notice("[user] completes the surgery on [target]'s ears."),
|
||||
)
|
||||
display_pain(target, "Your head swims, but it seems like you can feel your hearing coming back!")
|
||||
target_ears.deaf = (20) //deafness works off ticks, so this should work out to about 30-40s
|
||||
target_ears.set_organ_damage(0)
|
||||
///makes you temporarily deaf for a duration post-surgery
|
||||
var/deaf_change = 40 SECONDS - target_ears.temporary_deafness
|
||||
target_ears.adjust_temporary_deafness(deaf_change)
|
||||
return ..()
|
||||
|
||||
/datum/surgery_step/fix_ears/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
|
||||
@@ -117,7 +117,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
|
||||
/// Add a Trait to an organ that it will give its owner.
|
||||
/obj/item/organ/proc/add_organ_trait(trait)
|
||||
LAZYADD(organ_traits, trait)
|
||||
LAZYOR(organ_traits, trait)
|
||||
if(isnull(owner))
|
||||
return
|
||||
ADD_TRAIT(owner, trait, REF(src))
|
||||
@@ -251,14 +251,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
damage = clamp(damage + damage_amount, 0, maximum)
|
||||
SEND_SIGNAL(src, COMSIG_ORGAN_ADJUST_DAMAGE, damage_amount, maximum, required_organ_flag)
|
||||
. = (prev_damage - damage) // return net damage
|
||||
var/message = check_damage_thresholds(owner)
|
||||
var/message = check_damage_thresholds()
|
||||
prev_damage = damage
|
||||
|
||||
if(damage >= maxHealth)
|
||||
organ_flags |= ORGAN_FAILING
|
||||
else
|
||||
organ_flags &= ~ORGAN_FAILING
|
||||
|
||||
if(message && owner && owner.stat <= SOFT_CRIT)
|
||||
to_chat(owner, message)
|
||||
|
||||
@@ -272,24 +267,66 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
* description: By checking our current damage against our previous damage, we can decide whether we've passed an organ threshold.
|
||||
* If we have, send the corresponding threshold message to the owner, if such a message exists.
|
||||
*/
|
||||
/obj/item/organ/proc/check_damage_thresholds(mob/organ_owner)
|
||||
/obj/item/organ/proc/check_damage_thresholds()
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(damage == prev_damage)
|
||||
return
|
||||
var/delta = damage - prev_damage
|
||||
var/message = ""
|
||||
if(delta > 0)
|
||||
if(damage >= maxHealth)
|
||||
return now_failing
|
||||
if(damage > high_threshold && prev_damage <= high_threshold)
|
||||
return high_threshold_passed
|
||||
if(damage > low_threshold && prev_damage <= low_threshold)
|
||||
return low_threshold_passed
|
||||
else
|
||||
if(prev_damage > low_threshold && damage <= low_threshold)
|
||||
return low_threshold_cleared
|
||||
if(prev_damage > high_threshold && damage <= high_threshold)
|
||||
return high_threshold_cleared
|
||||
if(prev_damage == maxHealth)
|
||||
return now_fixed
|
||||
on_low_damage_received()
|
||||
message = low_threshold_passed
|
||||
if(damage > high_threshold && prev_damage <= high_threshold)
|
||||
on_high_damage_received()
|
||||
message = high_threshold_passed
|
||||
if(damage >= maxHealth)
|
||||
organ_flags |= ORGAN_FAILING
|
||||
on_begin_failure()
|
||||
message = now_failing
|
||||
return message
|
||||
|
||||
if(prev_damage == maxHealth)
|
||||
organ_flags &= ~ORGAN_FAILING
|
||||
on_failure_recovery()
|
||||
message = now_fixed
|
||||
if(prev_damage > high_threshold && damage <= high_threshold)
|
||||
on_high_damage_healed()
|
||||
message = high_threshold_cleared
|
||||
if(prev_damage > low_threshold && damage <= low_threshold)
|
||||
on_low_damage_healed()
|
||||
message = low_threshold_cleared
|
||||
return message
|
||||
|
||||
/**
|
||||
* Called when the damage surpasses the low damage threshold.
|
||||
*
|
||||
* This and other procs like this one merely exist to make it easier to keep a standard on
|
||||
* damage thresholds for organs. This doesn't mean you cannot make custom thresholds for various stuff,
|
||||
* and you're more than welcome to improve or refactor any portion of the code around these mechanics
|
||||
*/
|
||||
/obj/item/organ/proc/on_low_damage_received()
|
||||
return
|
||||
|
||||
///Called when the damage goes below the low damage threshold
|
||||
/obj/item/organ/proc/on_low_damage_healed()
|
||||
return
|
||||
|
||||
///Called when the damage surpasses the high damage threshold
|
||||
/obj/item/organ/proc/on_high_damage_received()
|
||||
return
|
||||
|
||||
///Called when the damage goes below the high damage threshold
|
||||
/obj/item/organ/proc/on_high_damage_healed()
|
||||
return
|
||||
|
||||
///Called when the organ enters failing stage
|
||||
/obj/item/organ/proc/on_begin_failure()
|
||||
return
|
||||
|
||||
///Called when the organ recovers from failing stage
|
||||
/obj/item/organ/proc/on_failure_recovery()
|
||||
return
|
||||
|
||||
//Looking for brains?
|
||||
//Try code/modules/mob/living/carbon/brain/brain_item.dm
|
||||
@@ -313,9 +350,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
dna.species.regenerate_organs(src, replace_current = FALSE)
|
||||
set_heartattack(FALSE)
|
||||
|
||||
// Ears have aditional vаr "deaf", need to update it too
|
||||
// Ears have aditional var "deaf", need to update it too
|
||||
var/obj/item/organ/ears/ears = get_organ_slot(ORGAN_SLOT_EARS)
|
||||
ears?.adjustEarDamage(0, -INFINITY) // full heal ears deafness
|
||||
ears.adjust_temporary_deafness(-INFINITY)
|
||||
|
||||
return
|
||||
|
||||
@@ -352,7 +389,8 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
if(!ears)
|
||||
ears = new()
|
||||
ears.Insert(src)
|
||||
ears.adjustEarDamage(-INFINITY, -INFINITY) // actually do: set_organ_damage(0) and deaf = 0
|
||||
ears.set_organ_damage(0)
|
||||
ears.adjust_temporary_deafness(-INFINITY)
|
||||
|
||||
///Organs don't die instantly, and neither should you when you get fucked up
|
||||
/obj/item/organ/proc/handle_failing_organs(seconds_per_tick)
|
||||
|
||||
@@ -438,25 +438,31 @@
|
||||
)
|
||||
aug_overlay = "strongarm"
|
||||
|
||||
///The amount of damage the implant adds to our unarmed attacks.
|
||||
var/punch_damage = 5
|
||||
///Biotypes we apply an additional amount of damage too
|
||||
var/biotype_bonus_targets = MOB_BEAST | MOB_SPECIAL | MOB_MINING
|
||||
///Extra damage dealt to our targeted mobs
|
||||
/// The amount of damage the implant adds to the lower punching force of our arm.
|
||||
var/lower_punch_damage = 0
|
||||
/// The amount of damage the implant adds to the upper punching force of our arm.
|
||||
var/upper_punch_damage = 2
|
||||
/// The amount of punch effectiveness (AKA accuracy and crit potential) the implant adds to our arm
|
||||
var/punch_effectiveness_added = 10
|
||||
/// How much extra damage does our implant allow the implanted while grabbing someone and they are unable to break the grapple?
|
||||
var/bonus_grab_damage = 20
|
||||
/// Biotypes we apply an additional amount of damage too
|
||||
var/biotype_bonus_targets = MOB_SPECIAL | MOB_MINING
|
||||
/// Extra damage dealt to our targeted mobs
|
||||
var/biotype_bonus_damage = 20
|
||||
///IF true, the throw attack will not smash people into walls
|
||||
/// IF true, the throw attack will not smash people into walls
|
||||
var/non_harmful_throw = TRUE
|
||||
///How far away your attack will throw your oponent
|
||||
/// How far away your attack will throw your oponent
|
||||
var/attack_throw_range = 1
|
||||
///Minimum throw power of the attack
|
||||
/// Minimum throw power of the attack
|
||||
var/throw_power_min = 1
|
||||
///Maximum throw power of the attack
|
||||
/// Maximum throw power of the attack
|
||||
var/throw_power_max = 4
|
||||
///How long will the implant malfunction if it is EMP'd
|
||||
/// How long will the implant malfunction if it is EMP'd
|
||||
var/emp_base_duration = 9 SECONDS
|
||||
///How long before we get another slam punch; consider that these usually come in pairs of two
|
||||
/// How long before we get another slam punch against a human; consider that these usually come in pairs
|
||||
var/slam_cooldown_duration = 5 SECONDS
|
||||
///Tracks how soon we can perform another slam attack
|
||||
/// Tracks how soon we can perform another slam attack
|
||||
COOLDOWN_DECLARE(slam_cooldown)
|
||||
|
||||
/obj/item/organ/cyberimp/arm/strongarm/Initialize(mapload)
|
||||
@@ -472,6 +478,20 @@
|
||||
. = ..()
|
||||
UnregisterSignal(arm_owner, COMSIG_LIVING_EARLY_UNARMED_ATTACK)
|
||||
|
||||
/obj/item/organ/cyberimp/arm/strongarm/on_bodypart_insert(obj/item/bodypart/arm)
|
||||
. = ..()
|
||||
arm.unarmed_damage_low += lower_punch_damage
|
||||
arm.unarmed_damage_high += upper_punch_damage
|
||||
arm.unarmed_effectiveness += punch_effectiveness_added
|
||||
arm.unarmed_grab_damage_bonus += bonus_grab_damage
|
||||
|
||||
/obj/item/organ/cyberimp/arm/strongarm/on_bodypart_remove(obj/item/bodypart/arm)
|
||||
. = ..()
|
||||
arm.unarmed_damage_low += lower_punch_damage
|
||||
arm.unarmed_damage_high += upper_punch_damage
|
||||
arm.unarmed_effectiveness += punch_effectiveness_added
|
||||
arm.unarmed_grab_damage_bonus += bonus_grab_damage
|
||||
|
||||
/obj/item/organ/cyberimp/arm/strongarm/emp_act(severity)
|
||||
. = ..()
|
||||
if((organ_flags & ORGAN_FAILING) || . & EMP_PROTECT_SELF)
|
||||
@@ -495,13 +515,12 @@
|
||||
return NONE
|
||||
if(HAS_TRAIT(source, TRAIT_HULK)) //NO HULK
|
||||
return NONE
|
||||
if(!COOLDOWN_FINISHED(src, slam_cooldown))
|
||||
if(!COOLDOWN_FINISHED(src, slam_cooldown) && ishuman(target))
|
||||
return NONE
|
||||
if(!source.can_unarmed_attack())
|
||||
return COMPONENT_SKIP_ATTACK
|
||||
|
||||
var/mob/living/living_target = target
|
||||
source.changeNext_move(CLICK_CD_MELEE)
|
||||
var/picked_hit_type = pick("punch", "smash", "pummel", "bash", "slam")
|
||||
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
@@ -514,22 +533,28 @@
|
||||
source.Paralyze(1 SECONDS)
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/human_target = target
|
||||
if(human_target.check_block(source, punch_damage, "[source]'s' [picked_hit_type]"))
|
||||
source.do_attack_animation(target)
|
||||
playsound(living_target.loc, 'sound/items/weapons/punchmiss.ogg', 25, TRUE, -1)
|
||||
log_combat(source, target, "attempted to [picked_hit_type]", "muscle implant")
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
var/ground_bounce = FALSE // funny flavor. if you hit someone who's floored you slam them into the ground, breaking tiles
|
||||
var/turf/target_turf = get_turf(living_target)
|
||||
|
||||
/* Damage calculations operate on the same math used in /datum/species/proc/harm():
|
||||
* Unarmed damage is randomized between an upper and lower value.
|
||||
* The lower value is determined by taking the damage value from the limb, and then increasing that value based on athletics level (min upper value)
|
||||
* The upper value is determiend by taking the damage value from the limb, and then seeing if we have the strength trait, providing extra damage.
|
||||
* The end result is that the more investment into athletics, the more precise the damage is, without necessarily increasing the potential damage.
|
||||
*/
|
||||
|
||||
// Our attacking limb
|
||||
var/obj/item/bodypart/attacking_bodypart = hand
|
||||
var/potential_damage = punch_damage
|
||||
// The upper damage, calculated first as it will be used to cap our potential lower damage.
|
||||
var/potential_upper_damage = attacking_bodypart.unarmed_damage_high + (HAS_TRAIT(source, TRAIT_STRENGTH) ? 2 : 0)
|
||||
// The lower damage, which is capped by potential_upper_damage
|
||||
var/potential_lower_damage = min(attacking_bodypart.unarmed_damage_low + (source.mind?.get_skill_level(/datum/skill/athletics) || 0), potential_upper_damage)
|
||||
// Finally, we determine the actual damage roll.
|
||||
var/potential_damage = rand(potential_lower_damage, potential_upper_damage)
|
||||
// This value is used to determine armour penetration.
|
||||
var/potential_effectiveness = attacking_bodypart.unarmed_effectiveness
|
||||
// This is a damage and penetration multiplier if our target is grabbed when we deliver our punch.
|
||||
var/potential_pummel_bonus = attacking_bodypart.unarmed_pummeling_bonus
|
||||
potential_damage += rand(attacking_bodypart.unarmed_damage_low, attacking_bodypart.unarmed_damage_high)
|
||||
|
||||
if(living_target.pulledby && living_target.pulledby.grab_state >= GRAB_AGGRESSIVE) // get pummeled idiot
|
||||
potential_damage *= potential_pummel_bonus
|
||||
@@ -541,21 +566,18 @@
|
||||
if(biotype_bonus_targets && is_correct_biotype) //If we are punching one of our special biotype targets, increase the damage floor by a factor of two.
|
||||
potential_damage += biotype_bonus_damage
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/human_target = target
|
||||
if(human_target.check_block(source, potential_damage, "[source]'s' [picked_hit_type]"))
|
||||
source.do_attack_animation(target)
|
||||
playsound(living_target.loc, 'sound/items/weapons/punchmiss.ogg', 25, TRUE, -1)
|
||||
log_combat(source, target, "attempted to [picked_hit_type]", "muscle implant")
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
source.do_attack_animation(target, ATTACK_EFFECT_SMASH)
|
||||
playsound(living_target.loc, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1)
|
||||
|
||||
var/target_zone = living_target.get_random_valid_zone(source.zone_selected)
|
||||
var/armor_block = living_target.run_armor_check(target_zone, MELEE, armour_penetration = potential_effectiveness)
|
||||
living_target.apply_damage(potential_damage * 2, attacking_bodypart.attack_type, target_zone, armor_block)
|
||||
|
||||
if(source.body_position != LYING_DOWN) //Throw them if we are standing
|
||||
var/atom/throw_target = get_edge_target_turf(living_target, source.dir)
|
||||
living_target.throw_at(throw_target, attack_throw_range, rand(throw_power_min,throw_power_max), source, gentle = non_harmful_throw)
|
||||
if(ground_bounce)
|
||||
if(isfloorturf(target_turf))
|
||||
var/turf/open/floor/crunched = target_turf
|
||||
crunched.crush() // crunch
|
||||
|
||||
// Some mobs gib when killed, so we're logging early. At this point, we're definitely hitting, so...
|
||||
living_target.visible_message(
|
||||
span_danger("[source] [picked_hit_type]ed [living_target][ground_bounce ? " into [target_turf]" : ""]!"),
|
||||
span_userdanger("You're [picked_hit_type]ed by [source][ground_bounce ? " into [target_turf]" : ""]!"),
|
||||
@@ -568,7 +590,24 @@
|
||||
|
||||
log_combat(source, target, "[picked_hit_type]ed", "muscle implant")
|
||||
|
||||
COOLDOWN_START(src, slam_cooldown, slam_cooldown_duration)
|
||||
if(ishuman(target))
|
||||
COOLDOWN_START(src, slam_cooldown, slam_cooldown_duration)
|
||||
|
||||
var/target_zone = living_target.get_random_valid_zone(source.zone_selected)
|
||||
var/armor_block = living_target.run_armor_check(target_zone, MELEE, armour_penetration = potential_effectiveness)
|
||||
living_target.apply_damage(potential_damage * 2, attacking_bodypart.attack_type, target_zone, armor_block)
|
||||
|
||||
if(source.body_position != LYING_DOWN && !QDELETED(living_target)) //Throw them if we are standing and we didn't somehow just completely obliterate the target
|
||||
var/atom/throw_target = get_edge_target_turf(living_target, source.dir)
|
||||
living_target.throw_at(throw_target, attack_throw_range, rand(throw_power_min,throw_power_max), source, gentle = non_harmful_throw)
|
||||
if(ground_bounce)
|
||||
if(isfloorturf(target_turf))
|
||||
var/turf/open/floor/crunched = target_turf
|
||||
crunched.crush() // crunch
|
||||
else if (ground_bounce) // Just in case our target mob somehow evaporated during this process, we still leave an obliterated tile in their wake
|
||||
if(isfloorturf(target_turf))
|
||||
var/turf/open/floor/crunched = target_turf
|
||||
crunched.crush() // again, crunch
|
||||
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
|
||||
@@ -18,32 +18,36 @@
|
||||
/// Eyecolor from the HUD
|
||||
var/hud_color = "#3CB8A5"
|
||||
|
||||
/obj/item/organ/cyberimp/eyes/hud/Initialize(mapload)
|
||||
. = ..()
|
||||
if(toggled_on)
|
||||
for(var/hud_trait in HUD_traits)
|
||||
add_organ_trait(hud_trait)
|
||||
|
||||
/obj/item/organ/cyberimp/eyes/hud/proc/toggle_hud(mob/living/carbon/human/eye_owner)
|
||||
if(toggled_on)
|
||||
toggled_on = FALSE
|
||||
eye_owner.remove_traits(HUD_traits, ORGAN_TRAIT)
|
||||
for(var/hud_trait in HUD_traits)
|
||||
remove_organ_trait(hud_trait)
|
||||
balloon_alert(eye_owner, "hud disabled")
|
||||
if(hud_color)
|
||||
eye_owner.remove_eye_color(EYE_COLOR_HUD_PRIORITY)
|
||||
return
|
||||
toggled_on = TRUE
|
||||
eye_owner.add_traits(HUD_traits, ORGAN_TRAIT)
|
||||
for(var/hud_trait in HUD_traits)
|
||||
add_organ_trait(hud_trait)
|
||||
balloon_alert(eye_owner, "hud enabled")
|
||||
if(hud_color)
|
||||
eye_owner.add_eye_color_right(hud_color, EYE_COLOR_HUD_PRIORITY)
|
||||
|
||||
/obj/item/organ/cyberimp/eyes/hud/on_mob_insert(mob/living/carbon/human/eye_owner, special = FALSE, movement_flags)
|
||||
. = ..()
|
||||
eye_owner.add_traits(HUD_traits, ORGAN_TRAIT)
|
||||
toggled_on = TRUE
|
||||
if(hud_color)
|
||||
if(toggled_on && hud_color)
|
||||
eye_owner.add_eye_color_right(hud_color, EYE_COLOR_HUD_PRIORITY, !special)
|
||||
|
||||
/obj/item/organ/cyberimp/eyes/hud/on_mob_remove(mob/living/carbon/human/eye_owner, special, movement_flags)
|
||||
. = ..()
|
||||
eye_owner.remove_traits(HUD_traits, ORGAN_TRAIT)
|
||||
toggled_on = FALSE
|
||||
if(hud_color)
|
||||
if(toggled_on && hud_color)
|
||||
eye_owner.remove_eye_color(EYE_COLOR_HUD_PRIORITY, !special)
|
||||
|
||||
/obj/item/organ/cyberimp/eyes/hud/medical
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
now_fixed = span_info("Noise slowly begins filling your ears once more.")
|
||||
low_threshold_cleared = span_info("The ringing in your ears has died down.")
|
||||
|
||||
/// `deaf` measures "ticks" of deafness. While > 0, the person is unable to hear anything.
|
||||
var/deaf = 0
|
||||
/// temporary deafness, measured in seconds. While > 0, the person is unable to hear anything.
|
||||
var/temporary_deafness = 0
|
||||
|
||||
// `damage` in this case measures long term damage to the ears, if too high,
|
||||
// the person will not have either `deaf` or `ear_damage` decrease
|
||||
@@ -39,23 +39,20 @@
|
||||
// no healing if failing
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
return
|
||||
adjustEarDamage(0, -0.5 * seconds_per_tick)
|
||||
adjust_temporary_deafness(-seconds_per_tick SECONDS)
|
||||
if((damage > low_threshold) && SPT_PROB(damage / 60, seconds_per_tick))
|
||||
adjustEarDamage(0, 4)
|
||||
adjust_temporary_deafness(4 SECONDS)
|
||||
SEND_SOUND(owner, sound('sound/items/weapons/flash_ring.ogg'))
|
||||
|
||||
/obj/item/organ/ears/apply_organ_damage(damage_amount, maximum, required_organ_flag)
|
||||
. = ..()
|
||||
update_temp_deafness()
|
||||
|
||||
/obj/item/organ/ears/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
update_temp_deafness()
|
||||
if(temporary_deafness)
|
||||
on_deafened()
|
||||
|
||||
/obj/item/organ/ears/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
|
||||
REMOVE_TRAIT(organ_owner, TRAIT_DEAF, EAR_DAMAGE)
|
||||
if(temporary_deafness)
|
||||
on_undeafened(organ_owner)
|
||||
|
||||
/obj/item/organ/ears/get_status_appendix(advanced, add_tooltips)
|
||||
if(owner.stat == DEAD || !HAS_TRAIT(owner, TRAIT_DEAF))
|
||||
@@ -65,7 +62,7 @@
|
||||
return conditional_tooltip("Subject is permanently deaf.", "Irreparable under normal circumstances.", add_tooltips)
|
||||
if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, GENETIC_MUTATION))
|
||||
return conditional_tooltip("Subject is genetically deaf.", "Use medication such as [/datum/reagent/medicine/mutadone::name].", add_tooltips)
|
||||
if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
|
||||
if((organ_flags & ORGAN_FAILING) || HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
|
||||
return conditional_tooltip("Subject is [(organ_flags & ORGAN_FAILING) ? "permanently": "temporarily"] deaf from ear damage.", "Repair surgically, use medication such as [/datum/reagent/medicine/inacusiate::name], or protect ears with earmuffs.", add_tooltips)
|
||||
return "Subject is deaf."
|
||||
|
||||
@@ -73,52 +70,43 @@
|
||||
// Always show if we have an appendix
|
||||
return ..() || (owner.stat != DEAD && HAS_TRAIT(owner, TRAIT_DEAF))
|
||||
|
||||
/**
|
||||
* Snowflake proc to handle temporary deafness
|
||||
*
|
||||
* * ddmg: Handles normal organ damage
|
||||
* * ddeaf: Handles temporary deafness, 1 ddeaf = 2 seconds of deafness, by default (with no multiplier)
|
||||
*/
|
||||
/obj/item/organ/ears/proc/adjustEarDamage(ddmg = 0, ddeaf = 0)
|
||||
if(HAS_TRAIT(owner, TRAIT_GODMODE))
|
||||
update_temp_deafness()
|
||||
///Adjust the temporary deafness of the person, up or down
|
||||
/obj/item/organ/ears/proc/adjust_temporary_deafness(amount)
|
||||
// organ failure makes us permanently deafened. Also, doesn't do anything if not in someone or during godmode
|
||||
if(amount > 0 && owner && HAS_TRAIT(owner, TRAIT_GODMODE))
|
||||
return
|
||||
|
||||
var/mod_damage = ddmg > 0 ? (ddmg * damage_multiplier) : ddmg
|
||||
if(mod_damage)
|
||||
apply_organ_damage(mod_damage)
|
||||
var/mod_deaf = ddeaf > 0 ? (ddeaf * damage_multiplier) : ddeaf
|
||||
if(mod_deaf)
|
||||
deaf = max(deaf + mod_deaf, 0)
|
||||
update_temp_deafness()
|
||||
temporary_deafness = max(temporary_deafness + amount * damage_multiplier, 0)
|
||||
|
||||
/// Updates status of deafness
|
||||
/obj/item/organ/ears/proc/update_temp_deafness()
|
||||
// if we're failing we always have at least some deaf stacks (and thus deafness)
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
deaf = max(deaf, 1 * damage_multiplier)
|
||||
|
||||
if(isnull(owner))
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
if(HAS_TRAIT(owner, TRAIT_GODMODE))
|
||||
deaf = 0
|
||||
if(temporary_deafness && !HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
|
||||
on_deafened()
|
||||
else if(!temporary_deafness && HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
|
||||
on_undeafened()
|
||||
|
||||
if(deaf > 0)
|
||||
if(!HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
|
||||
RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(adjust_speech))
|
||||
ADD_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE)
|
||||
else
|
||||
REMOVE_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE)
|
||||
UnregisterSignal(owner, COMSIG_MOB_SAY)
|
||||
///Called when temporary deafness begins
|
||||
/obj/item/organ/ears/proc/on_deafened()
|
||||
RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(adjust_speech))
|
||||
ADD_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE)
|
||||
|
||||
///Called when temporary deafness reaches zero. Has to have an 'organ_owner' arg, because by the time it's called on 'on_mob_remove', owner is already null
|
||||
/obj/item/organ/ears/proc/on_undeafened(mob/living/organ_owner = owner)
|
||||
REMOVE_TRAIT(organ_owner, TRAIT_DEAF, EAR_DAMAGE)
|
||||
UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
|
||||
|
||||
/obj/item/organ/ears/on_begin_failure()
|
||||
add_organ_trait(TRAIT_DEAF)
|
||||
|
||||
/obj/item/organ/ears/on_failure_recovery()
|
||||
remove_organ_trait(TRAIT_DEAF)
|
||||
|
||||
/// Being deafened by loud noises makes you shout
|
||||
/obj/item/organ/ears/proc/adjust_speech(datum/source, list/speech_args)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(HAS_TRAIT_NOT_FROM(source, TRAIT_DEAF, EAR_DAMAGE))
|
||||
return
|
||||
if(HAS_TRAIT(source, TRAIT_SIGN_LANG))
|
||||
if(HAS_TRAIT_NOT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE) || HAS_TRAIT(owner, TRAIT_SIGN_LANG))
|
||||
return
|
||||
|
||||
var/message = speech_args[SPEECH_MESSAGE]
|
||||
@@ -240,16 +228,9 @@
|
||||
desc = "Allows the user to more easily hear whispers. The user becomes extra vulnerable to loud noises, however"
|
||||
// Same sensitivity as felinid ears
|
||||
damage_multiplier = 2
|
||||
|
||||
// The original idea was to use signals to do this not traits. Unfortunately, the star effect used for whispers applies before any relevant signals
|
||||
// This seems like the least invasive solution
|
||||
/obj/item/organ/ears/cybernetic/whisper/on_mob_insert(mob/living/carbon/ear_owner)
|
||||
. = ..()
|
||||
ADD_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT)
|
||||
|
||||
/obj/item/organ/ears/cybernetic/whisper/on_mob_remove(mob/living/carbon/ear_owner)
|
||||
. = ..()
|
||||
REMOVE_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT)
|
||||
// The original idea was to use signals to do this not traits. Unfortunately, the star effect used for whispers applies before any relevant signals
|
||||
// This seems like the least invasive solution
|
||||
organ_traits = list(TRAIT_GOOD_HEARING)
|
||||
|
||||
/obj/item/organ/ears/cybernetic/volume
|
||||
name = "volume-adjusting cybernetic ears"
|
||||
@@ -265,14 +246,7 @@
|
||||
desc = "Through the power of modern engineering, allows the user to hear speech through walls. The user becomes extra vulnerable to loud noises, however"
|
||||
// Same sensitivity as felinid ears
|
||||
damage_multiplier = 2
|
||||
|
||||
/obj/item/organ/ears/cybernetic/xray/on_mob_insert(mob/living/carbon/ear_owner)
|
||||
. = ..()
|
||||
ADD_TRAIT(ear_owner, TRAIT_XRAY_HEARING, ORGAN_TRAIT)
|
||||
|
||||
/obj/item/organ/ears/cybernetic/xray/on_mob_remove(mob/living/carbon/ear_owner)
|
||||
. = ..()
|
||||
REMOVE_TRAIT(ear_owner, TRAIT_XRAY_HEARING, ORGAN_TRAIT)
|
||||
organ_traits = list(TRAIT_XRAY_HEARING)
|
||||
|
||||
/obj/item/organ/ears/cybernetic/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
/// Sight flags this eye pair imparts on its user.
|
||||
var/sight_flags = NONE
|
||||
/// changes how the eyes overlay is applied, makes it apply over the lighting layer
|
||||
var/overlay_ignore_lighting = FALSE
|
||||
/// How much innate tint these eyes have
|
||||
var/tint = 0
|
||||
/// How much innare flash protection these eyes have, usually paired with tint
|
||||
@@ -52,8 +50,6 @@
|
||||
|
||||
/// Glasses cannot be worn over these eyes. Currently unused
|
||||
var/no_glasses = FALSE
|
||||
/// indication that the eyes are undergoing some negative effect
|
||||
var/damaged = FALSE
|
||||
/// Native FOV that will be applied if a config is enabled
|
||||
var/native_fov = FOV_90_DEGREES
|
||||
/// Scarring on this organ
|
||||
@@ -82,8 +78,13 @@
|
||||
|
||||
/obj/item/organ/eyes/on_mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
receiver.become_blind(EYE_DAMAGE)
|
||||
if(damage >= low_threshold)
|
||||
receiver.assign_nearsightedness(EYE_DAMAGE, damage >= high_threshold ? 3 : 2, TRUE)
|
||||
|
||||
receiver.cure_blind(NO_EYES)
|
||||
apply_damaged_eye_effects()
|
||||
|
||||
// Ensures that non-player mobs get their eye colors assigned, as players get them from prefs
|
||||
if (ishuman(receiver))
|
||||
var/mob/living/carbon/human/as_human = receiver
|
||||
@@ -91,9 +92,17 @@
|
||||
eye_color_left = as_human.eye_color_left
|
||||
if (!eye_color_right)
|
||||
eye_color_right = as_human.eye_color_right
|
||||
RegisterSignals(receiver, list(
|
||||
SIGNAL_ADDTRAIT(TRAIT_LUMINESCENT_EYES),
|
||||
SIGNAL_REMOVETRAIT(TRAIT_LUMINESCENT_EYES),
|
||||
SIGNAL_ADDTRAIT(TRAIT_REFLECTIVE_EYES),
|
||||
SIGNAL_REMOVETRAIT(TRAIT_REFLECTIVE_EYES),
|
||||
), PROC_REF(on_shiny_eyes_trait_update))
|
||||
|
||||
refresh(receiver, call_update = TRUE)
|
||||
RegisterSignal(receiver, COMSIG_ATOM_BULLET_ACT, PROC_REF(on_bullet_act))
|
||||
RegisterSignal(receiver, COMSIG_COMPONENT_CLEAN_FACE_ACT, PROC_REF(on_face_wash))
|
||||
|
||||
if (scarring)
|
||||
apply_scarring_effects()
|
||||
|
||||
@@ -139,20 +148,38 @@
|
||||
if(!special)
|
||||
human_owner.update_body()
|
||||
|
||||
// become blind (if not special)
|
||||
if(!special)
|
||||
organ_owner.become_blind(NO_EYES)
|
||||
|
||||
// Cure blindness from eye damage
|
||||
organ_owner.cure_blind(EYE_DAMAGE)
|
||||
organ_owner.cure_nearsighted(EYE_DAMAGE)
|
||||
// Eye blind and temp blind go to, even if this is a bit of cheesy way to clear blindness
|
||||
organ_owner.remove_status_effect(/datum/status_effect/eye_blur)
|
||||
organ_owner.remove_status_effect(/datum/status_effect/temporary_blindness)
|
||||
// Then become blind anyways (if not special)
|
||||
if(!special)
|
||||
organ_owner.become_blind(NO_EYES)
|
||||
|
||||
if (scarring)
|
||||
owner.cure_nearsighted(TRAIT_RIGHT_EYE_SCAR)
|
||||
owner.cure_nearsighted(TRAIT_LEFT_EYE_SCAR)
|
||||
owner.cure_blind(EYE_SCARRING_TRAIT)
|
||||
|
||||
organ_owner.update_tint()
|
||||
organ_owner.update_sight()
|
||||
is_emissive = FALSE // SKYRAT EDIT ADDITION
|
||||
UnregisterSignal(organ_owner, list(COMSIG_ATOM_BULLET_ACT, COMSIG_COMPONENT_CLEAN_FACE_ACT))
|
||||
UnregisterSignal(organ_owner, list(
|
||||
COMSIG_ATOM_BULLET_ACT,
|
||||
COMSIG_COMPONENT_CLEAN_FACE_ACT,
|
||||
SIGNAL_ADDTRAIT(TRAIT_LUMINESCENT_EYES),
|
||||
SIGNAL_REMOVETRAIT(TRAIT_LUMINESCENT_EYES),
|
||||
SIGNAL_ADDTRAIT(TRAIT_REFLECTIVE_EYES),
|
||||
SIGNAL_REMOVETRAIT(TRAIT_REFLECTIVE_EYES),
|
||||
))
|
||||
|
||||
///Called whenever the luminescent and/or reflective eyes traits are added or removed
|
||||
/obj/item/organ/eyes/proc/on_shiny_eyes_trait_update(mob/living/carbon/human/source)
|
||||
SIGNAL_HANDLER
|
||||
source.update_eyes()
|
||||
|
||||
/obj/item/organ/eyes/update_atom_colour()
|
||||
. = ..()
|
||||
@@ -290,9 +317,8 @@
|
||||
|
||||
var/list/overlays = list(eye_left, eye_right)
|
||||
|
||||
if(overlay_ignore_lighting && !(parent.obscured_slots & HIDEEYES))
|
||||
overlays += emissive_appearance(eye_left.icon, eye_left.icon_state, parent, -EYES_LAYER, alpha = eye_left.alpha)
|
||||
overlays += emissive_appearance(eye_right.icon, eye_right.icon_state, parent, -EYES_LAYER, alpha = eye_right.alpha)
|
||||
if(!(parent.obscured_slots & HIDEEYES))
|
||||
overlays += get_emissive_overlays(eye_left, eye_right, parent)
|
||||
|
||||
var/obj/item/bodypart/head/my_head = parent.get_bodypart(BODY_ZONE_HEAD)
|
||||
|
||||
@@ -331,6 +357,19 @@
|
||||
|
||||
return overlays
|
||||
|
||||
///Returns the two emissive overlays built for the left and right eyes, in order.
|
||||
/obj/item/organ/eyes/proc/get_emissive_overlays(mutable_appearance/eye_left, mutable_appearance/eye_right, atom/spokesman)
|
||||
var/list/return_list = list()
|
||||
var/emissive_effect
|
||||
if((owner && HAS_TRAIT(owner, TRAIT_LUMINESCENT_EYES)) || (TRAIT_LUMINESCENT_EYES in organ_traits))
|
||||
emissive_effect = EMISSIVE_BLOOM
|
||||
else if((owner && HAS_TRAIT(owner, TRAIT_REFLECTIVE_EYES)) || (TRAIT_REFLECTIVE_EYES in organ_traits))
|
||||
emissive_effect = EMISSIVE_SPECULAR
|
||||
if(emissive_effect)
|
||||
return_list += emissive_appearance(eye_left.icon, eye_left.icon_state, spokesman, -EYES_LAYER, alpha = eye_left.alpha, effect_type = emissive_effect)
|
||||
return_list += emissive_appearance(eye_right.icon, eye_right.icon_state, spokesman, -EYES_LAYER, alpha = eye_right.alpha, effect_type = emissive_effect)
|
||||
return return_list
|
||||
|
||||
/obj/item/organ/eyes/update_overlays()
|
||||
. = ..()
|
||||
if (scarring & RIGHT_EYE_SCAR)
|
||||
@@ -390,13 +429,6 @@
|
||||
owner.cure_blind(EYE_SCARRING_TRAIT)
|
||||
owner.update_body()
|
||||
|
||||
/obj/item/organ/eyes/on_mob_remove(mob/living/carbon/eye_owner)
|
||||
. = ..()
|
||||
if (scarring)
|
||||
eye_owner.cure_nearsighted(TRAIT_RIGHT_EYE_SCAR)
|
||||
eye_owner.cure_nearsighted(TRAIT_LEFT_EYE_SCAR)
|
||||
eye_owner.cure_blind(EYE_SCARRING_TRAIT)
|
||||
|
||||
#undef OFFSET_X
|
||||
#undef OFFSET_Y
|
||||
|
||||
@@ -406,38 +438,28 @@
|
||||
eye_color_left = initial(eye_color_left)
|
||||
eye_color_right = initial(eye_color_right)
|
||||
|
||||
/obj/item/organ/eyes/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag)
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return FALSE
|
||||
apply_damaged_eye_effects()
|
||||
|
||||
/// Applies effects to our owner based on how damaged our eyes are
|
||||
/obj/item/organ/eyes/proc/apply_damaged_eye_effects()
|
||||
// we're in healthy threshold, either try to heal (if damaged) or do nothing
|
||||
if(damage <= low_threshold)
|
||||
if(damaged)
|
||||
damaged = FALSE
|
||||
// clear nearsightedness from damage
|
||||
owner.cure_nearsighted(EYE_DAMAGE)
|
||||
// and cure blindness from damage
|
||||
owner.cure_blind(EYE_DAMAGE)
|
||||
/obj/item/organ/eyes/on_low_damage_received()
|
||||
if(damage >= high_threshold)
|
||||
return
|
||||
owner?.assign_nearsightedness(EYE_DAMAGE, 2, TRUE)
|
||||
|
||||
//various degrees of "oh fuck my eyes", from "point a laser at your eye" to "staring at the Sun" intensities
|
||||
// 50 - blind
|
||||
// 49-31 - nearsighted (2 severity)
|
||||
// 30-20 - nearsighted (1 severity)
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
// become blind from damage
|
||||
owner.become_blind(EYE_DAMAGE)
|
||||
/obj/item/organ/eyes/on_high_damage_received()
|
||||
owner?.assign_nearsightedness(EYE_DAMAGE, 3, TRUE)
|
||||
|
||||
else
|
||||
// become nearsighted from damage
|
||||
var/severity = damage > high_threshold ? 3 : 2
|
||||
owner.assign_nearsightedness(EYE_DAMAGE, severity, TRUE)
|
||||
/obj/item/organ/eyes/on_begin_failure()
|
||||
owner?.become_blind(EYE_DAMAGE)
|
||||
|
||||
damaged = TRUE
|
||||
/obj/item/organ/eyes/on_failure_recovery()
|
||||
owner?.cure_blind(EYE_DAMAGE)
|
||||
|
||||
/obj/item/organ/eyes/on_high_damage_healed()
|
||||
if(damage <= low_threshold)
|
||||
return
|
||||
owner?.assign_nearsightedness(EYE_DAMAGE, 2, TRUE)
|
||||
|
||||
/obj/item/organ/eyes/on_low_damage_healed()
|
||||
// clear nearsightedness from damage
|
||||
owner?.cure_nearsighted(EYE_DAMAGE)
|
||||
|
||||
/obj/item/organ/eyes/feel_for_damage(self_aware)
|
||||
// Eye damage has visual effects, so we don't really need to "feel" it when self-examining
|
||||
@@ -715,16 +737,9 @@
|
||||
eye_color_left = "#3cb8a5"
|
||||
eye_color_right = "#3cb8a5"
|
||||
sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
|
||||
organ_traits = list(TRAIT_XRAY_VISION)
|
||||
penlight_message = "replaced by small radiation emitters and detectors"
|
||||
|
||||
/obj/item/organ/eyes/robotic/xray/on_mob_insert(mob/living/carbon/eye_owner)
|
||||
. = ..()
|
||||
ADD_TRAIT(eye_owner, TRAIT_XRAY_VISION, ORGAN_TRAIT)
|
||||
|
||||
/obj/item/organ/eyes/robotic/xray/on_mob_remove(mob/living/carbon/eye_owner)
|
||||
. = ..()
|
||||
REMOVE_TRAIT(eye_owner, TRAIT_XRAY_VISION, ORGAN_TRAIT)
|
||||
|
||||
/obj/item/organ/eyes/robotic/thermals
|
||||
name = "thermal eyes"
|
||||
desc = "These cybernetic eye implants will give you thermal vision. Vertical slit pupil included."
|
||||
@@ -1051,17 +1066,25 @@
|
||||
if(QDELETED(eye_owner) || !ishuman(eye_owner)) //Other carbon mobs don't have eye color.
|
||||
return
|
||||
|
||||
if(!eye.light_on)
|
||||
eye_icon_state = initial(eye_icon_state)
|
||||
overlay_ignore_lighting = FALSE
|
||||
else
|
||||
overlay_ignore_lighting = TRUE
|
||||
eye_icon_state = base_eye_state
|
||||
|
||||
var/obj/item/bodypart/head/head = eye_owner.get_bodypart(BODY_ZONE_HEAD) //if we have eyes we definently have a head anyway
|
||||
var/previous_flags = head.head_flags
|
||||
head.head_flags = previous_flags | HEAD_EYECOLOR
|
||||
eye_owner.dna.species.handle_body(eye_owner)
|
||||
head.head_flags |= HEAD_EYECOLOR
|
||||
|
||||
///enabling and disabling the TRAIT_LUMINESCENT_EYES trait already calls handle_eyes(), in that case, let's skip that call
|
||||
var/skip_call = FALSE
|
||||
if(!eye.light_on)
|
||||
eye_icon_state = initial(eye_icon_state)
|
||||
skip_call = HAS_TRAIT_FROM_ONLY(eye_owner, TRAIT_LUMINESCENT_EYES, REF(src))
|
||||
remove_organ_trait(TRAIT_LUMINESCENT_EYES)
|
||||
else
|
||||
skip_call = !HAS_TRAIT(eye_owner, TRAIT_LUMINESCENT_EYES)
|
||||
add_organ_trait(TRAIT_LUMINESCENT_EYES)
|
||||
eye_icon_state = base_eye_state
|
||||
|
||||
if(!skip_call && ishuman(eye_owner))
|
||||
var/mob/living/carbon/human/humie = eye_owner
|
||||
humie.update_eyes()
|
||||
|
||||
head.head_flags = previous_flags
|
||||
|
||||
#undef MATCH_LIGHT_COLOR
|
||||
@@ -1187,7 +1210,7 @@
|
||||
eye_color_right = "#f74a4d"
|
||||
eye_icon_state = "eyes_glow"
|
||||
iris_overlay = null
|
||||
overlay_ignore_lighting = TRUE
|
||||
organ_traits = list(TRAIT_UNNATURAL_RED_GLOWY_EYES, TRAIT_LUMINESCENT_EYES)
|
||||
flash_protect = FLASH_PROTECTION_HYPER_SENSITIVE
|
||||
low_light_cutoff = list(5, 12, 20)
|
||||
medium_light_cutoff = list(15, 20, 30)
|
||||
@@ -1200,10 +1223,6 @@
|
||||
apply_organ_damage(20 * examtool.light_power) //that's 0.5 lightpower for a penlight, so one penlight shining is equivalent to two seconds in a lit area
|
||||
return span_danger("[owner.p_Their()] eyes [penlight_message].")
|
||||
|
||||
/obj/item/organ/eyes/night_vision/maintenance_adapted/on_mob_insert(mob/living/carbon/eye_owner)
|
||||
. = ..()
|
||||
ADD_TRAIT(eye_owner, TRAIT_UNNATURAL_RED_GLOWY_EYES, ORGAN_TRAIT)
|
||||
|
||||
/obj/item/organ/eyes/night_vision/maintenance_adapted/on_life(seconds_per_tick, times_fired)
|
||||
if(!owner.is_blind() && isturf(owner.loc) && owner.has_light_nearby(light_amount=0.5)) //we allow a little more than usual so we can produce light from the adapted eyes
|
||||
to_chat(owner, span_danger("Your eyes! They burn in the light!"))
|
||||
@@ -1213,10 +1232,6 @@
|
||||
apply_organ_damage(-10) //heal quickly
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/eyes/night_vision/maintenance_adapted/on_mob_remove(mob/living/carbon/unadapted, special = FALSE, movement_flags)
|
||||
REMOVE_TRAIT(unadapted, TRAIT_UNNATURAL_RED_GLOWY_EYES, ORGAN_TRAIT)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/eyes/pod
|
||||
name = "pod eyes"
|
||||
desc = "Strangest salad you've ever seen."
|
||||
@@ -1226,3 +1241,9 @@
|
||||
// iris_overlay = null BUBBER EDIT - ALLOWS EYE COLOR TO BE CHANGED AGAIN
|
||||
foodtype_flags = PODPERSON_ORGAN_FOODTYPES
|
||||
penlight_message = "are green and plant-like"
|
||||
|
||||
/obj/item/organ/eyes/felinid
|
||||
name = "felinid eyes"
|
||||
desc = "A pair of highly reflective eyes with slit pupils, like those of a cat."
|
||||
pupils_name = "slit pupils"
|
||||
penlight_message = "shine under the pearly light"
|
||||
|
||||
@@ -536,7 +536,7 @@
|
||||
emp_vulnerability = 20
|
||||
metabolism_efficiency = 0.1
|
||||
|
||||
/obj/item/organ/stomach/cybernetic/tier2/stomach_acid_power(atom/movable/nomnom)
|
||||
/obj/item/organ/stomach/cybernetic/tier3/stomach_acid_power(atom/movable/nomnom)
|
||||
if (isliving(nomnom))
|
||||
return 0
|
||||
if (IsEdible(nomnom))
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
attack_verb_continuous = list("licks", "slobbers", "slaps", "frenches", "tongues")
|
||||
attack_verb_simple = list("lick", "slobber", "slap", "french", "tongue")
|
||||
voice_filter = ""
|
||||
organ_traits = list(TRAIT_SPEAKS_CLEARLY)
|
||||
/**
|
||||
* A cached list of paths of all the languages this tongue is capable of speaking
|
||||
*
|
||||
@@ -51,6 +52,8 @@
|
||||
// - then we cache it via string list
|
||||
// this results in tongues with identical possible languages sharing a cached list instance
|
||||
languages_possible = string_list(get_possible_languages())
|
||||
if(!sense_of_taste)
|
||||
add_organ_trait(TRAIT_AGEUSIA)
|
||||
|
||||
/obj/item/organ/tongue/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -137,40 +140,24 @@
|
||||
* ageusia from having a non-tasting tongue.
|
||||
*/
|
||||
REMOVE_TRAIT(receiver, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
|
||||
apply_tongue_effects()
|
||||
|
||||
/obj/item/organ/tongue/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
|
||||
temp_say_mod = ""
|
||||
UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
|
||||
REMOVE_TRAIT(organ_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
|
||||
REMOVE_TRAIT(organ_owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
|
||||
// Carbons by default start with NO_TONGUE_TRAIT caused TRAIT_AGEUSIA
|
||||
ADD_TRAIT(organ_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
|
||||
organ_owner.voice_filter = initial(organ_owner.voice_filter)
|
||||
|
||||
/obj/item/organ/tongue/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag)
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return FALSE
|
||||
apply_tongue_effects()
|
||||
/obj/item/organ/tongue/on_begin_failure()
|
||||
remove_organ_trait(TRAIT_SPEAKS_CLEARLY)
|
||||
add_organ_trait(TRAIT_AGEUSIA)
|
||||
|
||||
/// Applies effects to our owner based on how damaged our tongue is
|
||||
/obj/item/organ/tongue/proc/apply_tongue_effects()
|
||||
/obj/item/organ/tongue/on_failure_recovery()
|
||||
add_organ_trait(TRAIT_SPEAKS_CLEARLY)
|
||||
if(sense_of_taste)
|
||||
//tongues can't taste food when they are failing
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
ADD_TRAIT(owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
|
||||
else
|
||||
REMOVE_TRAIT(owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
|
||||
else
|
||||
//tongues can't taste food when they lack a sense of taste
|
||||
ADD_TRAIT(owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
|
||||
if(organ_flags & ORGAN_FAILING)
|
||||
REMOVE_TRAIT(owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
|
||||
else
|
||||
ADD_TRAIT(owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
|
||||
remove_organ_trait(TRAIT_AGEUSIA)
|
||||
|
||||
/obj/item/organ/tongue/could_speak_language(datum/language/language_path)
|
||||
return (language_path in languages_possible)
|
||||
@@ -579,7 +566,7 @@
|
||||
attack_verb_simple = list("beep", "boop")
|
||||
modifies_speech = TRUE
|
||||
taste_sensitivity = 25 // not as good as an organic tongue
|
||||
organ_traits = list(TRAIT_SILICON_EMOTES_ALLOWED)
|
||||
organ_traits = list(TRAIT_SPEAKS_CLEARLY, TRAIT_SILICON_EMOTES_ALLOWED)
|
||||
voice_filter = "alimiter=0.9,acompressor=threshold=0.2:ratio=20:attack=10:release=50:makeup=2,highpass=f=1000"
|
||||
|
||||
/obj/item/organ/tongue/robot/could_speak_language(datum/language/language_path)
|
||||
@@ -645,7 +632,7 @@
|
||||
say_mod = "meows"
|
||||
liked_foodtypes = SEAFOOD | ORANGES | BUGS | GORE
|
||||
disliked_foodtypes = GROSS | CLOTH | RAW
|
||||
organ_traits = list(TRAIT_WOUND_LICKER, TRAIT_FISH_EATER, TRAIT_CARPOTOXIN_IMMUNE)
|
||||
organ_traits = list(TRAIT_SPEAKS_CLEARLY, TRAIT_WOUND_LICKER, TRAIT_FISH_EATER, TRAIT_CARPOTOXIN_IMMUNE)
|
||||
languages_native = list(/datum/language/nekomimetic)
|
||||
actions_types = list(/datum/action/item_action/organ_action/go_feral)
|
||||
var/feral_mode = FALSE
|
||||
|
||||
@@ -229,7 +229,8 @@
|
||||
moveToNullspace()
|
||||
bodypart_owner = null
|
||||
|
||||
on_bodypart_remove(limb)
|
||||
if(!isnull(limb))
|
||||
on_bodypart_remove(limb)
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -93,22 +93,25 @@
|
||||
// Only followers of Asclepius have the ability to use Healing Touch and perform miracle feats of surgery.
|
||||
// Prevents people from performing multiple simultaneous surgeries unless they're holding a Rod of Asclepius.
|
||||
|
||||
surgery.step_in_progress = TRUE
|
||||
var/speed_mod = 1
|
||||
var/fail_prob = 0//100 - fail_prob = success_prob
|
||||
var/advance = FALSE
|
||||
var/interaction_key = HAS_TRAIT(user, TRAIT_HIPPOCRATIC_OATH) ? target : DOAFTER_SOURCE_SURGERY
|
||||
if(DOING_INTERACTION(user, interaction_key))
|
||||
user.balloon_alert(user, "already doing surgery!")
|
||||
return FALSE
|
||||
|
||||
if(!chem_check(target))
|
||||
user.balloon_alert(user, "missing [LOWER_TEXT(get_chem_list())]!")
|
||||
to_chat(user, span_warning("[target] is missing the [LOWER_TEXT(get_chem_list())] required to perform this surgery step!"))
|
||||
surgery.step_in_progress = FALSE
|
||||
return FALSE
|
||||
|
||||
if(preop(user, target, target_zone, tool, surgery) == SURGERY_STEP_FAIL)
|
||||
update_surgery_mood(target, SURGERY_STATE_FAILURE)
|
||||
surgery.step_in_progress = FALSE
|
||||
return FALSE
|
||||
|
||||
surgery.step_in_progress = TRUE
|
||||
var/speed_mod = 1
|
||||
var/fail_prob = 0//100 - fail_prob = success_prob
|
||||
var/advance = FALSE
|
||||
|
||||
update_surgery_mood(target, SURGERY_STATE_STARTED)
|
||||
play_preop_sound(user, target, target_zone, tool, surgery) // Here because most steps overwrite preop
|
||||
|
||||
@@ -162,7 +165,7 @@
|
||||
|
||||
var/was_sleeping = (target.stat != DEAD && target.IsSleeping())
|
||||
|
||||
if(do_after(user, modded_time, target = target, interaction_key = user.has_status_effect(/datum/status_effect/hippocratic_oath) ? target : DOAFTER_SOURCE_SURGERY)) //If we have the hippocratic oath, we can perform one surgery on each target, otherwise we can only do one surgery in total.
|
||||
if(do_after(user, modded_time, target = target, interaction_key = interaction_key)) //If we have the hippocratic oath, we can perform one surgery on each target, otherwise we can only do one surgery in total.
|
||||
|
||||
if((prob(100-fail_prob) || (iscyborg(user) && !silicons_obey_prob)) && !try_to_fail)
|
||||
if(success(user, target, target_zone, tool, surgery))
|
||||
|
||||
Reference in New Issue
Block a user