mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
Adds a Tactical IFF Visor and slightly refactors eye rendering (#95547)
## About The Pull Request A new cybernetic eye implant, the tactical IFF visor, has been added to the game, available in the combat implants research node. Its main features are a cool LED display, dynamic color correction to make distinguishing important objects easier, and inbuilt IFF systems capable of distinguishing and highlighting allies and potential threats. They also give flash/welding protection and mild night-vision capabilities. However, this comes at a downside of making the user completely unable to distinguish appearances or voices, or even examine others. Everyone will simply show up as Unknown and be completely covered in static, bar the threat assessment outline. Examining will only display their threat status according to threat settings in the visor. The parameters for threat assessment (both ID access and security flag-based), as well as the visor display, can be configured by the user at any time. When emagged, the visor will instead completely hide and mute all mobs except the user themselves, leaving them completely "alone" on the station. Deathsquads get an unmodifiable version, configured to treat anyone but CentCom personnel as hostiles. Settings can also be adjusted before installation with a multitool, and locked using a screwdriver, preventing users from accessing them when installed. --- Eye rendering has been slightly refactored in order to support the monovisor, as well as to get rid of duplicate code (and missing features) on dismembered heads. Also moth eyes once again should block emissives properly. ## Why It's Good For The Game New content for both gameplay and roleplay, and fits deathsquad's purpose very well.
This commit is contained in:
@@ -286,45 +286,46 @@
|
||||
return ..() || (owner.stat != DEAD && !HAS_TRAIT(owner, TRAIT_KNOCKEDOUT) && (owner.is_blind() || owner.is_nearsighted()))
|
||||
|
||||
/// This proc generates a list of overlays that the eye should be displayed using for the given parent
|
||||
/obj/item/organ/eyes/proc/generate_body_overlay(mob/living/carbon/human/parent)
|
||||
if(!istype(parent) || parent.get_organ_by_type(/obj/item/organ/eyes) != src)
|
||||
CRASH("Generating a body overlay for [src] targeting an invalid parent '[parent]'.")
|
||||
|
||||
/obj/item/organ/eyes/proc/generate_body_overlay(mob/living/carbon/human/parent, obj/item/bodypart/limb)
|
||||
if(isnull(eye_icon_state))
|
||||
return list()
|
||||
|
||||
var/mutable_appearance/eye_left = mutable_appearance(eye_icon, "[eye_icon_state]_l", -EYES_LAYER, parent)
|
||||
var/mutable_appearance/eye_right = mutable_appearance(eye_icon, "[eye_icon_state]_r", -EYES_LAYER, parent)
|
||||
var/mutable_appearance/eye_left = mutable_appearance(eye_icon, "[eye_icon_state]_l", -EYES_LAYER, parent || limb)
|
||||
var/mutable_appearance/eye_right = mutable_appearance(eye_icon, "[eye_icon_state]_r", -EYES_LAYER, parent || limb)
|
||||
var/list/overlays = list(eye_left, eye_right)
|
||||
|
||||
if(!(parent.obscured_slots & HIDEEYES))
|
||||
overlays += get_emissive_overlays(eye_left, eye_right, parent)
|
||||
if(!(parent?.obscured_slots & HIDEEYES))
|
||||
overlays += get_emissive_overlays(eye_left, eye_right, parent || limb)
|
||||
|
||||
var/obj/item/bodypart/head/my_head = parent.get_bodypart(BODY_ZONE_HEAD)
|
||||
|
||||
if(!my_head)
|
||||
if(!limb)
|
||||
return overlays
|
||||
|
||||
if(my_head.head_flags & HEAD_EYECOLOR)
|
||||
eye_right.color = parent.get_right_eye_color()
|
||||
eye_left.color = parent.get_left_eye_color()
|
||||
var/list/eyelids = setup_eyelids(eye_left, eye_right, parent)
|
||||
if (LAZYLEN(eyelids))
|
||||
overlays += eyelids
|
||||
// Futureproofing for HARS/weird species
|
||||
var/obj/item/bodypart/head/head = astype(limb, /obj/item/bodypart/head)
|
||||
if(head?.head_flags & HEAD_EYECOLOR)
|
||||
if (parent)
|
||||
eye_right.color = parent.get_right_eye_color()
|
||||
eye_left.color = parent.get_left_eye_color()
|
||||
var/list/eyelids = setup_eyelids(eye_left, eye_right, parent)
|
||||
if (LAZYLEN(eyelids))
|
||||
overlays += eyelids
|
||||
else
|
||||
eye_right.color = eye_color_right
|
||||
eye_left.color = eye_color_left
|
||||
|
||||
if (scarring & RIGHT_EYE_SCAR)
|
||||
var/mutable_appearance/right_scar = mutable_appearance('icons/mob/human/human_eyes.dmi', "eye_scar_right", -EYES_LAYER, parent)
|
||||
right_scar.color = my_head.draw_color
|
||||
var/mutable_appearance/right_scar = mutable_appearance('icons/mob/human/human_eyes.dmi', "eye_scar_right", -EYES_LAYER, parent || limb)
|
||||
right_scar.color = limb.draw_color
|
||||
overlays += right_scar
|
||||
|
||||
if (scarring & LEFT_EYE_SCAR)
|
||||
var/mutable_appearance/left_scar = mutable_appearance('icons/mob/human/human_eyes.dmi', "eye_scar_left", -EYES_LAYER, parent)
|
||||
left_scar.color = my_head.draw_color
|
||||
var/mutable_appearance/left_scar = mutable_appearance('icons/mob/human/human_eyes.dmi', "eye_scar_left", -EYES_LAYER, parent || limb)
|
||||
left_scar.color = limb.draw_color
|
||||
overlays += left_scar
|
||||
|
||||
if(my_head.worn_face_offset)
|
||||
if(head?.worn_face_offset)
|
||||
for (var/mutable_appearance/overlay as anything in overlays)
|
||||
my_head.worn_face_offset.apply_offset(overlay)
|
||||
head.worn_face_offset.apply_offset(overlay)
|
||||
|
||||
return overlays
|
||||
|
||||
@@ -336,9 +337,14 @@
|
||||
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)
|
||||
else
|
||||
return_list += emissive_blocker(eye_left.icon, eye_left.icon_state, spokesman, -EYES_LAYER, alpha = eye_left.alpha)
|
||||
return_list += emissive_blocker(eye_right.icon, eye_right.icon_state, spokesman, -EYES_LAYER, alpha = eye_right.alpha)
|
||||
|
||||
return return_list
|
||||
|
||||
/obj/item/organ/eyes/update_overlays()
|
||||
@@ -606,604 +612,3 @@
|
||||
#undef NIGHTVISION_LIGHT_LOW
|
||||
#undef NIGHTVISION_LIGHT_MID
|
||||
#undef NIGHTVISION_LIGHT_HIG
|
||||
|
||||
/obj/item/organ/eyes/night_vision/mushroom
|
||||
name = "fung-eye"
|
||||
desc = "While on the outside they look inert and dead, the eyes of mushroom people are actually very advanced."
|
||||
low_light_cutoff = list(0, 15, 20)
|
||||
medium_light_cutoff = list(0, 20, 35)
|
||||
high_light_cutoff = list(0, 40, 50)
|
||||
pupils_name = "photosensory openings"
|
||||
penlight_message = "are attached to fungal stalks"
|
||||
|
||||
/obj/item/organ/eyes/zombie
|
||||
name = "undead eyes"
|
||||
desc = "Somewhat counterintuitively, these half-rotten eyes actually have superior vision to those of a living human."
|
||||
color_cutoffs = list(25, 35, 5)
|
||||
penlight_message = "are rotten and decayed!"
|
||||
|
||||
/obj/item/organ/eyes/zombie/penlight_examine(mob/living/viewer, obj/item/examtool)
|
||||
return span_danger("[owner.p_Their()] eyes [penlight_message]")
|
||||
|
||||
/obj/item/organ/eyes/alien
|
||||
name = "alien eyes"
|
||||
desc = "It turned out they had them after all!"
|
||||
sight_flags = SEE_MOBS
|
||||
color_cutoffs = list(25, 5, 42)
|
||||
|
||||
/obj/item/organ/eyes/golem
|
||||
name = "resonating crystal"
|
||||
desc = "Golems somehow measure external light levels and detect nearby ore using this sensitive mineral lattice."
|
||||
icon_state = "adamantine_cords"
|
||||
eye_icon_state = null
|
||||
blink_animation = FALSE
|
||||
iris_overlay = null
|
||||
color = COLOR_GOLEM_GRAY
|
||||
visual = FALSE
|
||||
organ_flags = ORGAN_MINERAL
|
||||
color_cutoffs = list(10, 15, 5)
|
||||
actions_types = list(/datum/action/cooldown/golem_ore_sight)
|
||||
penlight_message = "glimmer, their crystaline structure refracting light inwards"
|
||||
pupils_name = "lensing gems" ///given it says these are a "mineral lattice" that collects light i assume they work like artifical ruby laser foci
|
||||
|
||||
/// Send an ore detection pulse on a cooldown
|
||||
/datum/action/cooldown/golem_ore_sight
|
||||
name = "Ore Resonance"
|
||||
desc = "Causes nearby ores to vibrate, revealing their location."
|
||||
button_icon = 'icons/obj/devices/scanner.dmi'
|
||||
button_icon_state = "manual_mining"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
cooldown_time = 10 SECONDS
|
||||
|
||||
/datum/action/cooldown/golem_ore_sight/Activate(atom/target)
|
||||
. = ..()
|
||||
mineral_scan_pulse(get_turf(target), scanner = target)
|
||||
|
||||
///Robotic
|
||||
|
||||
/obj/item/organ/eyes/robotic
|
||||
name = "robotic eyes"
|
||||
desc = "Your vision is augmented."
|
||||
icon_state = "eyes_cyber"
|
||||
organ_flags = ORGAN_ROBOTIC
|
||||
failing_desc = "seems to be broken."
|
||||
pupils_name = "apertures"
|
||||
penlight_message = "are cybernetic, click-whirring as they refocus"
|
||||
|
||||
/obj/item/organ/eyes/robotic/emp_act(severity)
|
||||
. = ..()
|
||||
if((. & EMP_PROTECT_SELF) || !owner)
|
||||
return
|
||||
if(prob(10 * severity))
|
||||
return
|
||||
to_chat(owner, span_warning("Static obfuscates your vision!"))
|
||||
owner.flash_act(visual = 1)
|
||||
|
||||
/obj/item/organ/eyes/robotic/basic
|
||||
name = "basic robotic eyes"
|
||||
desc = "A pair of basic cybernetic eyes that restore vision, but at some vulnerability to light."
|
||||
icon_state = "eyes_cyber_basic"
|
||||
iris_overlay = null
|
||||
eye_color_left = "#2f3032"
|
||||
eye_color_right = "#2f3032"
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
penlight_message = "are low grade cybernetics, poorly compensating for the light"
|
||||
|
||||
/obj/item/organ/eyes/robotic/basic/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
return
|
||||
if(prob(10 * severity))
|
||||
apply_organ_damage(20 * severity)
|
||||
to_chat(owner, span_warning("Your eyes start to fizzle in their sockets!"))
|
||||
do_sparks(2, TRUE, owner)
|
||||
owner.emote("scream")
|
||||
|
||||
/obj/item/organ/eyes/robotic/xray
|
||||
name = "x-ray eyes"
|
||||
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
|
||||
icon_state = "eyes_cyber_xray"
|
||||
iris_overlay = null
|
||||
eye_color_left = "#3cb8a5"
|
||||
eye_color_right = "#3cb8a5"
|
||||
sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
organ_traits = list(TRAIT_XRAY_VISION)
|
||||
penlight_message = "are replaced by small radiation emitters and detectors"
|
||||
|
||||
/obj/item/organ/eyes/robotic/thermals
|
||||
name = "thermal eyes"
|
||||
desc = "These cybernetic eye implants will give you thermal vision. Vertical slit pupil included."
|
||||
icon_state = "eyes_cyber_thermal"
|
||||
iris_overlay = null
|
||||
eye_color_left = "#ce2525"
|
||||
eye_color_right = "#ce2525"
|
||||
// We're gonna downshift green and blue a bit so darkness looks yellow
|
||||
color_cutoffs = list(25, 8, 5)
|
||||
sight_flags = SEE_MOBS
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
pupils_name = "slit aperatures"
|
||||
penlight_message = "are cybernetic, with vertically slit metalic lenses."
|
||||
|
||||
/obj/item/organ/eyes/robotic/flashlight
|
||||
name = "flashlight eyes"
|
||||
desc = "It's two flashlights rigged together with some wire. Why would you put these in someone's head?"
|
||||
icon_state = "flashlight_eyes"
|
||||
eye_color_left = "#fee5a3"
|
||||
eye_color_right = "#fee5a3"
|
||||
iris_overlay = null
|
||||
flash_protect = FLASH_PROTECTION_WELDER
|
||||
tint = INFINITY
|
||||
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 1.9)
|
||||
var/obj/item/flashlight/eyelight/eye
|
||||
light_reactive = FALSE
|
||||
pupils_name = "flashlights"
|
||||
penlight_message = "are actually two flashlights taped together. ...why"
|
||||
|
||||
/obj/item/organ/eyes/robotic/flashlight/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
||||
|
||||
/obj/item/organ/eyes/robotic/flashlight/on_mob_insert(mob/living/carbon/victim)
|
||||
. = ..()
|
||||
if(!eye)
|
||||
eye = new /obj/item/flashlight/eyelight()
|
||||
eye.set_light_on(TRUE)
|
||||
eye.forceMove(victim)
|
||||
eye.update_brightness(victim)
|
||||
victim.become_blind(FLASHLIGHT_EYES)
|
||||
|
||||
/obj/item/organ/eyes/robotic/flashlight/on_mob_remove(mob/living/carbon/victim)
|
||||
. = ..()
|
||||
eye.set_light_on(FALSE)
|
||||
eye.update_brightness(victim)
|
||||
eye.forceMove(src)
|
||||
victim.cure_blind(FLASHLIGHT_EYES)
|
||||
|
||||
// Welding shield implant
|
||||
/obj/item/organ/eyes/robotic/shield
|
||||
name = "shielded robotic eyes"
|
||||
desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision."
|
||||
icon_state = "eyes_cyber_shield"
|
||||
iris_overlay = null
|
||||
eye_color_left = "#353845"
|
||||
eye_color_right = "#353845"
|
||||
flash_protect = FLASH_PROTECTION_WELDER
|
||||
pupils_name = "flash shields"
|
||||
penlight_message = "have polarized cybernetic lenses, blocking bright lights"
|
||||
|
||||
/obj/item/organ/eyes/robotic/shield/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
||||
|
||||
#define MATCH_LIGHT_COLOR 1
|
||||
#define USE_CUSTOM_COLOR 0
|
||||
#define UPDATE_LIGHT 0
|
||||
#define UPDATE_EYES_LEFT 1
|
||||
#define UPDATE_EYES_RIGHT 2
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow
|
||||
name = "high luminosity eyes"
|
||||
desc = "Special glowing eyes, used by snowflakes who want to be special."
|
||||
icon_state = "eyes_cyber_glow"
|
||||
iris_overlay = "eyes_cyber_glow_iris"
|
||||
eye_color_left = "#19191a"
|
||||
eye_color_right = "#19191a"
|
||||
actions_types = list(/datum/action/item_action/organ_action/use, /datum/action/item_action/organ_action/toggle)
|
||||
var/max_light_beam_distance = 5
|
||||
var/obj/item/flashlight/eyelight/glow/eye
|
||||
/// base icon state for eye overlays
|
||||
var/base_eye_state = "eyes_glow_gs"
|
||||
/// Whether or not to match the eye color to the light or use a custom selection
|
||||
var/eye_color_mode = USE_CUSTOM_COLOR
|
||||
/// The selected color for the light beam itself
|
||||
var/light_color_string = "#ffffff"
|
||||
/// The custom selected eye color for the left eye. Defaults to the mob's natural eye color
|
||||
var/left_eye_color_string
|
||||
/// The custom selected eye color for the right eye. Defaults to the mob's natural eye color
|
||||
var/right_eye_color_string
|
||||
penlight_message = "shine back with cybernetic LEDs"
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/Initialize(mapload)
|
||||
. = ..()
|
||||
eye = new /obj/item/flashlight/eyelight/glow
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/Destroy()
|
||||
. = ..()
|
||||
deactivate(close_ui = TRUE)
|
||||
QDEL_NULL(eye)
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/emp_act(severity)
|
||||
. = ..()
|
||||
if(!eye.light_on || . & EMP_PROTECT_SELF)
|
||||
return
|
||||
deactivate(close_ui = TRUE)
|
||||
|
||||
/// Set the initial color of the eyes on insert to be the mob's previous eye color.
|
||||
/obj/item/organ/eyes/robotic/glow/on_mob_insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags)
|
||||
. = ..()
|
||||
left_eye_color_string = eye_color_left
|
||||
right_eye_color_string = eye_color_right
|
||||
update_mob_eye_color(eye_recipient)
|
||||
deactivate(close_ui = TRUE)
|
||||
eye.forceMove(eye_recipient)
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/on_mob_remove(mob/living/carbon/eye_owner)
|
||||
deactivate(eye_owner, close_ui = TRUE)
|
||||
if(!QDELETED(eye))
|
||||
eye.forceMove(src)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_state(mob/user)
|
||||
return GLOB.default_state
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_status(mob/user, datum/ui_state/state)
|
||||
if(!QDELETED(owner))
|
||||
if(owner == user)
|
||||
return min(
|
||||
ui_status_user_is_abled(user, src),
|
||||
ui_status_only_living(user),
|
||||
)
|
||||
else return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "HighLuminosityEyesMenu")
|
||||
ui.autoupdate = FALSE
|
||||
ui.open()
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["eyeColor"] = list(
|
||||
mode = eye_color_mode,
|
||||
hasOwner = owner ? TRUE : FALSE,
|
||||
left = left_eye_color_string,
|
||||
right = right_eye_color_string,
|
||||
)
|
||||
data["lightColor"] = light_color_string
|
||||
data["range"] = eye.light_range
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_act(action, list/params, datum/tgui/ui)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("set_range")
|
||||
var/new_range = params["new_range"]
|
||||
set_beam_range(new_range)
|
||||
return TRUE
|
||||
if("pick_color")
|
||||
var/new_color = tgui_color_picker(
|
||||
usr,
|
||||
"Choose eye color color:",
|
||||
"High Luminosity Eyes Menu",
|
||||
light_color_string
|
||||
)
|
||||
if(new_color)
|
||||
var/to_update = params["to_update"]
|
||||
set_beam_color(new_color, to_update)
|
||||
return TRUE
|
||||
if("enter_color")
|
||||
var/new_color = LOWER_TEXT(params["new_color"])
|
||||
var/to_update = params["to_update"]
|
||||
set_beam_color(new_color, to_update, sanitize = TRUE)
|
||||
return TRUE
|
||||
if("random_color")
|
||||
var/to_update = params["to_update"]
|
||||
randomize_color(to_update)
|
||||
return TRUE
|
||||
if("toggle_eye_color")
|
||||
toggle_eye_color_mode()
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_action_click(mob/user, action)
|
||||
if(istype(action, /datum/action/item_action/organ_action/toggle))
|
||||
toggle_active()
|
||||
else if(istype(action, /datum/action/item_action/organ_action/use))
|
||||
ui_interact(user)
|
||||
|
||||
/**
|
||||
* Activates the light
|
||||
*
|
||||
* Turns on the attached flashlight object, updates the mob overlay to be added.
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/activate()
|
||||
if(eye.light_range)
|
||||
eye.set_light_on(TRUE)
|
||||
else
|
||||
eye.light_on = TRUE // at range 0 we are just going to make the eyes glow emissively, no light overlay
|
||||
update_mob_eye_color()
|
||||
|
||||
/**
|
||||
* Deactivates the light
|
||||
*
|
||||
* Turns off the attached flashlight object, closes UIs, updates the mob overlay to be removed.
|
||||
* Arguments:
|
||||
* * mob/living/carbon/eye_owner - the mob who the eyes belong to
|
||||
* * close_ui - whether or not to close the ui
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/deactivate(mob/living/carbon/eye_owner = owner, close_ui = FALSE)
|
||||
if(close_ui)
|
||||
SStgui.close_uis(src)
|
||||
eye.set_light_on(FALSE)
|
||||
update_mob_eye_color(eye_owner)
|
||||
|
||||
/**
|
||||
* Randomizes the light color
|
||||
*
|
||||
* Picks a random color and sets the beam color to that
|
||||
* Arguments:
|
||||
* * to_update - whether we are setting the color for the light beam itself, or the individual eyes
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/randomize_color(to_update = UPDATE_LIGHT)
|
||||
var/new_color = "#"
|
||||
for(var/i in 1 to 3)
|
||||
new_color += num2hex(rand(0, 255), 2)
|
||||
set_beam_color(new_color, to_update)
|
||||
|
||||
/**
|
||||
* Setter function for the light's range
|
||||
*
|
||||
* Sets the light range of the attached flashlight object
|
||||
* Includes some 'unique' logic to accomodate for some quirks of the lighting system
|
||||
* Arguments:
|
||||
* * new_range - the new range to set
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/set_beam_range(new_range)
|
||||
var/old_light_range = eye.light_range
|
||||
if(old_light_range == 0 && new_range > 0 && eye.light_on) // turn bring back the light overlay if we were previously at 0 (aka emissive eyes only)
|
||||
eye.light_on = FALSE // this is stupid, but this has to be FALSE for set_light_on() to work.
|
||||
eye.set_light_on(TRUE)
|
||||
eye.set_light_range(clamp(new_range, 0, max_light_beam_distance))
|
||||
|
||||
/**
|
||||
* Setter function for the light's color
|
||||
*
|
||||
* Sets the light color of the attached flashlight object. Sets the eye color vars of this eye organ as well and then updates the mob's eye color.
|
||||
* Arguments:
|
||||
* * newcolor - the new color hex string to set
|
||||
* * to_update - whether we are setting the color for the light beam itself, or the individual eyes
|
||||
* * sanitize - whether the hex string should be sanitized
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/set_beam_color(newcolor, to_update = UPDATE_LIGHT, sanitize = FALSE)
|
||||
var/newcolor_string
|
||||
if(sanitize)
|
||||
newcolor_string = sanitize_hexcolor(newcolor)
|
||||
else
|
||||
newcolor_string = newcolor
|
||||
switch(to_update)
|
||||
if(UPDATE_LIGHT)
|
||||
light_color_string = newcolor_string
|
||||
eye.set_light_color(newcolor_string)
|
||||
if(UPDATE_EYES_LEFT)
|
||||
left_eye_color_string = newcolor_string
|
||||
if(UPDATE_EYES_RIGHT)
|
||||
right_eye_color_string = newcolor_string
|
||||
|
||||
update_mob_eye_color()
|
||||
|
||||
/**
|
||||
* Toggle the attached flashlight object on or off
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/toggle_active()
|
||||
if(eye.light_on)
|
||||
deactivate()
|
||||
else
|
||||
activate()
|
||||
|
||||
/**
|
||||
* Toggles for the eye color mode
|
||||
*
|
||||
* Toggles the eye color mode on or off and then calls an update on the mob's eye color
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/toggle_eye_color_mode()
|
||||
eye_color_mode = !eye_color_mode
|
||||
update_mob_eye_color()
|
||||
|
||||
/**
|
||||
* Updates the mob eye color
|
||||
*
|
||||
* Updates the eye color to reflect on the mob's body if it's possible to do so
|
||||
* Arguments:
|
||||
* * mob/living/carbon/eye_owner - the mob to update the eye color appearance of
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/update_mob_eye_color(mob/living/carbon/eye_owner = owner)
|
||||
switch(eye_color_mode)
|
||||
if(MATCH_LIGHT_COLOR)
|
||||
eye_color_left = light_color_string
|
||||
eye_color_right = light_color_string
|
||||
if(USE_CUSTOM_COLOR)
|
||||
eye_color_left = left_eye_color_string
|
||||
eye_color_right = right_eye_color_string
|
||||
|
||||
if(QDELETED(eye_owner) || !ishuman(eye_owner)) //Other carbon mobs don't have eye color.
|
||||
return
|
||||
|
||||
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 |= 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
|
||||
#undef USE_CUSTOM_COLOR
|
||||
#undef UPDATE_LIGHT
|
||||
#undef UPDATE_EYES_LEFT
|
||||
#undef UPDATE_EYES_RIGHT
|
||||
|
||||
/obj/item/organ/eyes/moth
|
||||
name = "moth eyes"
|
||||
desc = "These eyes seem to have increased sensitivity to bright light, with no improvement to low light vision."
|
||||
icon_state = "eyes_moth"
|
||||
eye_icon_state = "motheyes"
|
||||
blink_animation = FALSE
|
||||
iris_overlay = null
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
pupils_name = "ommatidia" //yes i know compound eyes have no pupils shut up
|
||||
penlight_message = "are bulbous and insectoid"
|
||||
|
||||
/obj/item/organ/eyes/robotic/moth
|
||||
name = "robotic moth eyes"
|
||||
desc = "Your vision is augmented. Much like actual moth eyes, very sensitive to bright lights."
|
||||
icon_state = "eyes_moth_cyber"
|
||||
eye_icon_state = "motheyes_cyber"
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
pupils_name = "aperture clusters"
|
||||
penlight_message = "are metal hemispheres, resembling insect eyes"
|
||||
|
||||
/obj/item/organ/eyes/robotic/basic/moth
|
||||
name = "basic robotic moth eyes"
|
||||
icon_state = "eyes_moth_cyber_basic"
|
||||
eye_icon_state = "motheyes_white"
|
||||
eye_color_left = "#65686f"
|
||||
eye_color_right = "#65686f"
|
||||
blink_animation = FALSE
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
pupils_name = "aperture clusters"
|
||||
penlight_message = "are metal hemispheres, resembling insect eyes"
|
||||
|
||||
/obj/item/organ/eyes/robotic/xray/moth
|
||||
name = "moth x-ray eyes"
|
||||
desc = "These cybernetic imitation moth eyes will give you X-ray vision. Blinking is futile. Much like actual moth eyes, very sensitive to bright lights."
|
||||
icon_state = "eyes_moth_cyber_xray"
|
||||
eye_icon_state = "motheyes_white"
|
||||
eye_color_left = "#3c4e52"
|
||||
eye_color_right = "#3c4e52"
|
||||
blink_animation = FALSE
|
||||
flash_protect = FLASH_PROTECTION_HYPER_SENSITIVE
|
||||
pupils_name = "aperture clusters"
|
||||
|
||||
/obj/item/organ/eyes/robotic/shield/moth
|
||||
name = "shielded robotic moth eyes"
|
||||
icon_state = "eyes_moth_cyber_shield"
|
||||
eye_icon_state = "motheyes_white"
|
||||
eye_color_left = "#353845"
|
||||
eye_color_right = "#353845"
|
||||
blink_animation = FALSE
|
||||
pupils_name = "aperture clusters"
|
||||
penlight_message = "have shutters, protecting insectoid compound eyes."
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/moth
|
||||
name = "high luminosity moth eyes"
|
||||
desc = "Special glowing eyes, to be one with the lamp. Much like actual moth eyes, very sensitive to bright lights."
|
||||
icon_state = "eyes_moth_cyber_glow"
|
||||
eye_icon_state = "motheyes_cyber"
|
||||
iris_overlay = "eyes_moth_cyber_glow_iris"
|
||||
blink_animation = FALSE
|
||||
base_eye_state = "eyes_mothglow"
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
penlight_message = "are bulbous clusters of LEDs and cameras"
|
||||
pupils_name = "aperture clusters"
|
||||
|
||||
/obj/item/organ/eyes/robotic/thermals/moth
|
||||
name = "thermal moth eyes"
|
||||
icon_state = "eyes_moth_cyber_thermal"
|
||||
eye_icon_state = "motheyes_white"
|
||||
eye_color_left = "#901f38"
|
||||
eye_color_right = "#901f38"
|
||||
blink_animation = FALSE
|
||||
flash_protect = FLASH_PROTECTION_HYPER_SENSITIVE
|
||||
pupils_name = "sensor clusters"
|
||||
penlight_message = "are two clustered hemispheres of thermal sensors"
|
||||
|
||||
/obj/item/organ/eyes/ghost
|
||||
name = "ghost eyes"
|
||||
desc = "Despite lacking pupils, these can see pretty well."
|
||||
icon_state = "eyes-ghost"
|
||||
blink_animation = FALSE
|
||||
movement_type = PHASING
|
||||
organ_flags = parent_type::organ_flags | ORGAN_GHOST
|
||||
|
||||
/obj/item/organ/eyes/snail
|
||||
name = "snail eyes"
|
||||
desc = "These eyes seem to have a large range, but might be cumbersome with glasses."
|
||||
icon_state = "eyes_snail"
|
||||
eye_icon_state = "snail_eyes"
|
||||
blink_animation = FALSE
|
||||
pupils_name = "eyestalks" //many species of snails can retract their eyes into their face! (my lame science excuse for not having better writing here)
|
||||
penlight_message = "are sat upon retractable tentacles"
|
||||
|
||||
/obj/item/organ/eyes/jelly
|
||||
name = "jelly eyes"
|
||||
desc = "These eyes are made of a soft jelly. Unlike all other eyes, though, there are three of them."
|
||||
icon_state = "eyes_jelly"
|
||||
eye_icon_state = "jelleyes"
|
||||
blink_animation = FALSE
|
||||
iris_overlay = null
|
||||
pupils_name = "lensing bubbles" //imagine a water lens physics demo but with goo. thats how these work.
|
||||
penlight_message = "are three bubbles of refractive jelly"
|
||||
|
||||
/obj/item/organ/eyes/lizard
|
||||
name = "reptile eyes"
|
||||
desc = "A pair of reptile eyes with thin vertical slits for pupils."
|
||||
icon_state = "lizard_eyes"
|
||||
synchronized_blinking = FALSE
|
||||
pupils_name = "slit pupils"
|
||||
penlight_message = "have vertically slit pupils and tinted whites"
|
||||
|
||||
/obj/item/organ/eyes/night_vision/maintenance_adapted
|
||||
name = "adapted eyes"
|
||||
desc = "These red eyes look like two foggy marbles. They give off a particularly worrying glow in the dark."
|
||||
icon_state = "eyes_adapted"
|
||||
eye_color_left = "#f74a4d"
|
||||
eye_color_right = "#f74a4d"
|
||||
eye_icon_state = "eyes_glow"
|
||||
iris_overlay = null
|
||||
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)
|
||||
high_light_cutoff = list(30, 35, 50)
|
||||
penlight_message = "glow a foggy red, sizzling under the light!"
|
||||
|
||||
/obj/item/organ/eyes/night_vision/maintenance_adapted/penlight_examine(mob/living/viewer, obj/item/examtool)
|
||||
if(!owner.is_blind())
|
||||
to_chat(owner, span_danger("Your eyes sizzle agonizingly as light is shone on them!"))
|
||||
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_life(seconds_per_tick)
|
||||
if(owner.get_eye_protection() <= FLASH_PROTECTION_SENSITIVE && !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!"))
|
||||
apply_organ_damage(10) //blind quickly
|
||||
playsound(owner, 'sound/machines/grill/grillsizzle.ogg', 50)
|
||||
else
|
||||
apply_organ_damage(-10) //heal quickly
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/eyes/pod
|
||||
name = "pod eyes"
|
||||
desc = "Strangest salad you've ever seen."
|
||||
icon_state = "eyes_pod"
|
||||
eye_color_left = "#375846"
|
||||
eye_color_right = "#375846"
|
||||
iris_overlay = null
|
||||
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"
|
||||
|
||||
@@ -0,0 +1,965 @@
|
||||
/obj/item/organ/eyes/robotic
|
||||
name = "robotic eyes"
|
||||
desc = "Your vision is augmented."
|
||||
icon_state = "eyes_cyber"
|
||||
organ_flags = ORGAN_ROBOTIC
|
||||
failing_desc = "seems to be broken."
|
||||
pupils_name = "apertures"
|
||||
penlight_message = "are cybernetic, click-whirring as they refocus"
|
||||
|
||||
/obj/item/organ/eyes/robotic/emp_act(severity)
|
||||
. = ..()
|
||||
if((. & EMP_PROTECT_SELF) || !owner)
|
||||
return
|
||||
if(prob(10 * severity))
|
||||
return
|
||||
to_chat(owner, span_warning("Static obfuscates your vision!"))
|
||||
owner.flash_act(visual = 1)
|
||||
|
||||
/obj/item/organ/eyes/robotic/basic
|
||||
name = "basic robotic eyes"
|
||||
desc = "A pair of basic cybernetic eyes that restore vision, but at some vulnerability to light."
|
||||
icon_state = "eyes_cyber_basic"
|
||||
iris_overlay = null
|
||||
eye_color_left = "#2f3032"
|
||||
eye_color_right = "#2f3032"
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
penlight_message = "are low grade cybernetics, poorly compensating for the light"
|
||||
|
||||
/obj/item/organ/eyes/robotic/basic/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
return
|
||||
if(prob(10 * severity))
|
||||
apply_organ_damage(20 * severity)
|
||||
to_chat(owner, span_warning("Your eyes start to fizzle in their sockets!"))
|
||||
do_sparks(2, TRUE, owner)
|
||||
owner.emote("scream")
|
||||
|
||||
/obj/item/organ/eyes/robotic/xray
|
||||
name = "x-ray eyes"
|
||||
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
|
||||
icon_state = "eyes_cyber_xray"
|
||||
iris_overlay = null
|
||||
eye_color_left = "#3cb8a5"
|
||||
eye_color_right = "#3cb8a5"
|
||||
sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
organ_traits = list(TRAIT_XRAY_VISION)
|
||||
penlight_message = "are replaced by small radiation emitters and detectors"
|
||||
|
||||
/obj/item/organ/eyes/robotic/thermals
|
||||
name = "thermal eyes"
|
||||
desc = "These cybernetic eye implants will give you thermal vision. Vertical slit pupil included."
|
||||
icon_state = "eyes_cyber_thermal"
|
||||
iris_overlay = null
|
||||
eye_color_left = "#ce2525"
|
||||
eye_color_right = "#ce2525"
|
||||
// We're gonna downshift green and blue a bit so darkness looks yellow
|
||||
color_cutoffs = list(25, 8, 5)
|
||||
sight_flags = SEE_MOBS
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
pupils_name = "slit aperatures"
|
||||
penlight_message = "are cybernetic, with vertically slit metalic lenses."
|
||||
|
||||
/obj/item/organ/eyes/robotic/flashlight
|
||||
name = "flashlight eyes"
|
||||
desc = "It's two flashlights rigged together with some wire. Why would you put these in someone's head?"
|
||||
icon_state = "flashlight_eyes"
|
||||
eye_color_left = "#fee5a3"
|
||||
eye_color_right = "#fee5a3"
|
||||
iris_overlay = null
|
||||
flash_protect = FLASH_PROTECTION_WELDER
|
||||
tint = INFINITY
|
||||
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 1.9)
|
||||
var/obj/item/flashlight/eyelight/eye
|
||||
light_reactive = FALSE
|
||||
pupils_name = "flashlights"
|
||||
penlight_message = "are actually two flashlights taped together. ...why"
|
||||
|
||||
/obj/item/organ/eyes/robotic/flashlight/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
||||
|
||||
/obj/item/organ/eyes/robotic/flashlight/on_mob_insert(mob/living/carbon/victim)
|
||||
. = ..()
|
||||
if(!eye)
|
||||
eye = new /obj/item/flashlight/eyelight()
|
||||
eye.set_light_on(TRUE)
|
||||
eye.forceMove(victim)
|
||||
eye.update_brightness(victim)
|
||||
victim.become_blind(FLASHLIGHT_EYES)
|
||||
|
||||
/obj/item/organ/eyes/robotic/flashlight/on_mob_remove(mob/living/carbon/victim)
|
||||
. = ..()
|
||||
eye.set_light_on(FALSE)
|
||||
eye.update_brightness(victim)
|
||||
eye.forceMove(src)
|
||||
victim.cure_blind(FLASHLIGHT_EYES)
|
||||
|
||||
// Welding shield implant
|
||||
/obj/item/organ/eyes/robotic/shield
|
||||
name = "shielded robotic eyes"
|
||||
desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision."
|
||||
icon_state = "eyes_cyber_shield"
|
||||
iris_overlay = null
|
||||
eye_color_left = "#353845"
|
||||
eye_color_right = "#353845"
|
||||
flash_protect = FLASH_PROTECTION_WELDER
|
||||
pupils_name = "flash shields"
|
||||
penlight_message = "have polarized cybernetic lenses, blocking bright lights"
|
||||
|
||||
/obj/item/organ/eyes/robotic/shield/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
||||
|
||||
#define MATCH_LIGHT_COLOR 1
|
||||
#define USE_CUSTOM_COLOR 0
|
||||
#define UPDATE_LIGHT 0
|
||||
#define UPDATE_EYES_LEFT 1
|
||||
#define UPDATE_EYES_RIGHT 2
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow
|
||||
name = "high luminosity eyes"
|
||||
desc = "Special glowing eyes, used by snowflakes who want to be special."
|
||||
icon_state = "eyes_cyber_glow"
|
||||
iris_overlay = "eyes_cyber_glow_iris"
|
||||
eye_color_left = "#19191a"
|
||||
eye_color_right = "#19191a"
|
||||
actions_types = list(/datum/action/item_action/organ_action/use, /datum/action/item_action/organ_action/toggle)
|
||||
var/max_light_beam_distance = 5
|
||||
var/obj/item/flashlight/eyelight/glow/eye
|
||||
/// base icon state for eye overlays
|
||||
var/base_eye_state = "eyes_glow_gs"
|
||||
/// Whether or not to match the eye color to the light or use a custom selection
|
||||
var/eye_color_mode = USE_CUSTOM_COLOR
|
||||
/// The selected color for the light beam itself
|
||||
var/light_color_string = "#ffffff"
|
||||
/// The custom selected eye color for the left eye. Defaults to the mob's natural eye color
|
||||
var/left_eye_color_string
|
||||
/// The custom selected eye color for the right eye. Defaults to the mob's natural eye color
|
||||
var/right_eye_color_string
|
||||
penlight_message = "shine back with cybernetic LEDs"
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/Initialize(mapload)
|
||||
. = ..()
|
||||
eye = new /obj/item/flashlight/eyelight/glow
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/Destroy()
|
||||
. = ..()
|
||||
deactivate(close_ui = TRUE)
|
||||
QDEL_NULL(eye)
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/emp_act(severity)
|
||||
. = ..()
|
||||
if(!eye.light_on || . & EMP_PROTECT_SELF)
|
||||
return
|
||||
deactivate(close_ui = TRUE)
|
||||
|
||||
/// Set the initial color of the eyes on insert to be the mob's previous eye color.
|
||||
/obj/item/organ/eyes/robotic/glow/on_mob_insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags)
|
||||
. = ..()
|
||||
left_eye_color_string = eye_color_left
|
||||
right_eye_color_string = eye_color_right
|
||||
update_mob_eye_color(eye_recipient)
|
||||
deactivate(close_ui = TRUE)
|
||||
eye.forceMove(eye_recipient)
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/on_mob_remove(mob/living/carbon/eye_owner)
|
||||
deactivate(eye_owner, close_ui = TRUE)
|
||||
if(!QDELETED(eye))
|
||||
eye.forceMove(src)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_state(mob/user)
|
||||
return GLOB.default_state
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_status(mob/user, datum/ui_state/state)
|
||||
if(!QDELETED(owner))
|
||||
if(owner == user)
|
||||
return min(
|
||||
ui_status_user_is_abled(user, src),
|
||||
ui_status_only_living(user),
|
||||
)
|
||||
else return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "HighLuminosityEyesMenu")
|
||||
ui.autoupdate = FALSE
|
||||
ui.open()
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["eyeColor"] = list(
|
||||
mode = eye_color_mode,
|
||||
hasOwner = owner ? TRUE : FALSE,
|
||||
left = left_eye_color_string,
|
||||
right = right_eye_color_string,
|
||||
)
|
||||
data["lightColor"] = light_color_string
|
||||
data["range"] = eye.light_range
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_act(action, list/params, datum/tgui/ui)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("set_range")
|
||||
var/new_range = params["new_range"]
|
||||
set_beam_range(new_range)
|
||||
return TRUE
|
||||
if("pick_color")
|
||||
var/new_color = tgui_color_picker(
|
||||
usr,
|
||||
"Choose eye color color:",
|
||||
"High Luminosity Eyes Menu",
|
||||
light_color_string
|
||||
)
|
||||
if(new_color)
|
||||
var/to_update = params["to_update"]
|
||||
set_beam_color(new_color, to_update)
|
||||
return TRUE
|
||||
if("enter_color")
|
||||
var/new_color = LOWER_TEXT(params["new_color"])
|
||||
var/to_update = params["to_update"]
|
||||
set_beam_color(new_color, to_update, sanitize = TRUE)
|
||||
return TRUE
|
||||
if("random_color")
|
||||
var/to_update = params["to_update"]
|
||||
randomize_color(to_update)
|
||||
return TRUE
|
||||
if("toggle_eye_color")
|
||||
toggle_eye_color_mode()
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/ui_action_click(mob/user, action)
|
||||
if(istype(action, /datum/action/item_action/organ_action/toggle))
|
||||
toggle_active()
|
||||
else if(istype(action, /datum/action/item_action/organ_action/use))
|
||||
ui_interact(user)
|
||||
|
||||
/**
|
||||
* Activates the light
|
||||
*
|
||||
* Turns on the attached flashlight object, updates the mob overlay to be added.
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/activate()
|
||||
if(eye.light_range)
|
||||
eye.set_light_on(TRUE)
|
||||
else
|
||||
eye.light_on = TRUE // at range 0 we are just going to make the eyes glow emissively, no light overlay
|
||||
update_mob_eye_color()
|
||||
|
||||
/**
|
||||
* Deactivates the light
|
||||
*
|
||||
* Turns off the attached flashlight object, closes UIs, updates the mob overlay to be removed.
|
||||
* Arguments:
|
||||
* * mob/living/carbon/eye_owner - the mob who the eyes belong to
|
||||
* * close_ui - whether or not to close the ui
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/deactivate(mob/living/carbon/eye_owner = owner, close_ui = FALSE)
|
||||
if(close_ui)
|
||||
SStgui.close_uis(src)
|
||||
eye.set_light_on(FALSE)
|
||||
update_mob_eye_color(eye_owner)
|
||||
|
||||
/**
|
||||
* Randomizes the light color
|
||||
*
|
||||
* Picks a random color and sets the beam color to that
|
||||
* Arguments:
|
||||
* * to_update - whether we are setting the color for the light beam itself, or the individual eyes
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/randomize_color(to_update = UPDATE_LIGHT)
|
||||
var/new_color = "#"
|
||||
for(var/i in 1 to 3)
|
||||
new_color += num2hex(rand(0, 255), 2)
|
||||
set_beam_color(new_color, to_update)
|
||||
|
||||
/**
|
||||
* Setter function for the light's range
|
||||
*
|
||||
* Sets the light range of the attached flashlight object
|
||||
* Includes some 'unique' logic to accomodate for some quirks of the lighting system
|
||||
* Arguments:
|
||||
* * new_range - the new range to set
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/set_beam_range(new_range)
|
||||
var/old_light_range = eye.light_range
|
||||
if(old_light_range == 0 && new_range > 0 && eye.light_on) // turn bring back the light overlay if we were previously at 0 (aka emissive eyes only)
|
||||
eye.light_on = FALSE // this is stupid, but this has to be FALSE for set_light_on() to work.
|
||||
eye.set_light_on(TRUE)
|
||||
eye.set_light_range(clamp(new_range, 0, max_light_beam_distance))
|
||||
|
||||
/**
|
||||
* Setter function for the light's color
|
||||
*
|
||||
* Sets the light color of the attached flashlight object. Sets the eye color vars of this eye organ as well and then updates the mob's eye color.
|
||||
* Arguments:
|
||||
* * newcolor - the new color hex string to set
|
||||
* * to_update - whether we are setting the color for the light beam itself, or the individual eyes
|
||||
* * sanitize - whether the hex string should be sanitized
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/set_beam_color(newcolor, to_update = UPDATE_LIGHT, sanitize = FALSE)
|
||||
var/newcolor_string
|
||||
if(sanitize)
|
||||
newcolor_string = sanitize_hexcolor(newcolor)
|
||||
else
|
||||
newcolor_string = newcolor
|
||||
switch(to_update)
|
||||
if(UPDATE_LIGHT)
|
||||
light_color_string = newcolor_string
|
||||
eye.set_light_color(newcolor_string)
|
||||
if(UPDATE_EYES_LEFT)
|
||||
left_eye_color_string = newcolor_string
|
||||
if(UPDATE_EYES_RIGHT)
|
||||
right_eye_color_string = newcolor_string
|
||||
|
||||
update_mob_eye_color()
|
||||
|
||||
/**
|
||||
* Toggle the attached flashlight object on or off
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/toggle_active()
|
||||
if(eye.light_on)
|
||||
deactivate()
|
||||
else
|
||||
activate()
|
||||
|
||||
/**
|
||||
* Toggles for the eye color mode
|
||||
*
|
||||
* Toggles the eye color mode on or off and then calls an update on the mob's eye color
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/toggle_eye_color_mode()
|
||||
eye_color_mode = !eye_color_mode
|
||||
update_mob_eye_color()
|
||||
|
||||
/**
|
||||
* Updates the mob eye color
|
||||
*
|
||||
* Updates the eye color to reflect on the mob's body if it's possible to do so
|
||||
* Arguments:
|
||||
* * mob/living/carbon/eye_owner - the mob to update the eye color appearance of
|
||||
*/
|
||||
/obj/item/organ/eyes/robotic/glow/proc/update_mob_eye_color(mob/living/carbon/eye_owner = owner)
|
||||
switch(eye_color_mode)
|
||||
if(MATCH_LIGHT_COLOR)
|
||||
eye_color_left = light_color_string
|
||||
eye_color_right = light_color_string
|
||||
if(USE_CUSTOM_COLOR)
|
||||
eye_color_left = left_eye_color_string
|
||||
eye_color_right = right_eye_color_string
|
||||
|
||||
if(QDELETED(eye_owner) || !ishuman(eye_owner)) //Other carbon mobs don't have eye color.
|
||||
return
|
||||
|
||||
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 |= 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
|
||||
#undef USE_CUSTOM_COLOR
|
||||
#undef UPDATE_LIGHT
|
||||
#undef UPDATE_EYES_LEFT
|
||||
#undef UPDATE_EYES_RIGHT
|
||||
|
||||
// Moth variations
|
||||
|
||||
/obj/item/organ/eyes/robotic/moth
|
||||
name = "robotic moth eyes"
|
||||
desc = "Your vision is augmented. Much like actual moth eyes, very sensitive to bright lights."
|
||||
icon_state = "eyes_moth_cyber"
|
||||
eye_icon_state = "motheyes_cyber"
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
pupils_name = "aperture clusters"
|
||||
penlight_message = "are metal hemispheres, resembling insect eyes"
|
||||
|
||||
/obj/item/organ/eyes/robotic/basic/moth
|
||||
name = "basic robotic moth eyes"
|
||||
icon_state = "eyes_moth_cyber_basic"
|
||||
eye_icon_state = "motheyes_white"
|
||||
eye_color_left = "#65686f"
|
||||
eye_color_right = "#65686f"
|
||||
blink_animation = FALSE
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
pupils_name = "aperture clusters"
|
||||
penlight_message = "are metal hemispheres, resembling insect eyes"
|
||||
|
||||
/obj/item/organ/eyes/robotic/xray/moth
|
||||
name = "moth x-ray eyes"
|
||||
desc = "These cybernetic imitation moth eyes will give you X-ray vision. Blinking is futile. Much like actual moth eyes, very sensitive to bright lights."
|
||||
icon_state = "eyes_moth_cyber_xray"
|
||||
eye_icon_state = "motheyes_white"
|
||||
eye_color_left = "#3c4e52"
|
||||
eye_color_right = "#3c4e52"
|
||||
blink_animation = FALSE
|
||||
flash_protect = FLASH_PROTECTION_HYPER_SENSITIVE
|
||||
pupils_name = "aperture clusters"
|
||||
|
||||
/obj/item/organ/eyes/robotic/shield/moth
|
||||
name = "shielded robotic moth eyes"
|
||||
icon_state = "eyes_moth_cyber_shield"
|
||||
eye_icon_state = "motheyes_white"
|
||||
eye_color_left = "#353845"
|
||||
eye_color_right = "#353845"
|
||||
blink_animation = FALSE
|
||||
pupils_name = "aperture clusters"
|
||||
penlight_message = "have shutters, protecting insectoid compound eyes."
|
||||
|
||||
/obj/item/organ/eyes/robotic/glow/moth
|
||||
name = "high luminosity moth eyes"
|
||||
desc = "Special glowing eyes, to be one with the lamp. Much like actual moth eyes, very sensitive to bright lights."
|
||||
icon_state = "eyes_moth_cyber_glow"
|
||||
eye_icon_state = "motheyes_cyber"
|
||||
iris_overlay = "eyes_moth_cyber_glow_iris"
|
||||
blink_animation = FALSE
|
||||
base_eye_state = "eyes_mothglow"
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
penlight_message = "are bulbous clusters of LEDs and cameras"
|
||||
pupils_name = "aperture clusters"
|
||||
|
||||
/obj/item/organ/eyes/robotic/thermals/moth
|
||||
name = "thermal moth eyes"
|
||||
icon_state = "eyes_moth_cyber_thermal"
|
||||
eye_icon_state = "motheyes_white"
|
||||
eye_color_left = "#901f38"
|
||||
eye_color_right = "#901f38"
|
||||
blink_animation = FALSE
|
||||
flash_protect = FLASH_PROTECTION_HYPER_SENSITIVE
|
||||
pupils_name = "sensor clusters"
|
||||
penlight_message = "are two clustered hemispheres of thermal sensors"
|
||||
|
||||
// Chaplain's special boy
|
||||
/obj/item/organ/eyes/night_vision/maintenance_adapted
|
||||
name = "adapted eyes"
|
||||
desc = "These red eyes look like two foggy marbles. They give off a particularly worrying glow in the dark."
|
||||
icon_state = "eyes_adapted"
|
||||
eye_color_left = "#f74a4d"
|
||||
eye_color_right = "#f74a4d"
|
||||
eye_icon_state = "eyes_glow"
|
||||
iris_overlay = null
|
||||
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)
|
||||
high_light_cutoff = list(30, 35, 50)
|
||||
penlight_message = "glow a foggy red, sizzling under the light!"
|
||||
|
||||
/obj/item/organ/eyes/night_vision/maintenance_adapted/penlight_examine(mob/living/viewer, obj/item/examtool)
|
||||
if(!owner.is_blind())
|
||||
to_chat(owner, span_danger("Your eyes sizzle agonizingly as light is shone on them!"))
|
||||
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_life(seconds_per_tick)
|
||||
if(owner.get_eye_protection() <= FLASH_PROTECTION_SENSITIVE && !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!"))
|
||||
apply_organ_damage(10) //blind quickly
|
||||
playsound(owner, 'sound/machines/grill/grillsizzle.ogg', 50)
|
||||
else
|
||||
apply_organ_damage(-10) //heal quickly
|
||||
return ..()
|
||||
|
||||
#define VISOR_DISPLAY_CROSS "Cross"
|
||||
#define VISOR_DISPLAY_EYES "Eyes"
|
||||
#define VISOR_DISPLAY_LINE "Line"
|
||||
|
||||
#define IFF_HOSTILE 1
|
||||
#define IFF_NEUTRAL 2
|
||||
#define IFF_FRIENDLY 3
|
||||
|
||||
#define IFF_FACTION_NONE "None"
|
||||
#define IFF_FACTION_SYNDICATE "Syndicate"
|
||||
#define IFF_FACTION_CREW "Crew"
|
||||
#define IFF_FACTION_SEC_COMMAND "Security & Command"
|
||||
#define IFF_FACTION_CENTCOM "CentCom"
|
||||
#define IFF_FACTION_EVERYONE "Non-Allies"
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor
|
||||
name = "tactical EFF visor"
|
||||
desc = "A failed attempt at integrating IFF systems directly into soldiers' prefrontal cortex, this complex sensor array has proved to be impractical as the additional load impared the user's ability to recognize people's appearances or voices. The screen is there just for intimidation."
|
||||
icon_state = "eyes_tacvisor"
|
||||
eye_icon_state = "eyes_tacvisor"
|
||||
blink_animation = FALSE
|
||||
no_glasses = TRUE
|
||||
iris_overlay = null
|
||||
eye_color_left = COLOR_WHITE
|
||||
eye_color_right = COLOR_WHITE
|
||||
flash_protect = FLASH_PROTECTION_WELDER
|
||||
lighting_cutoff = LIGHTING_CUTOFF_MEDIUM
|
||||
pupils_name = "faceplate"
|
||||
penlight_message = "are a wide reinforced faceplate with an inbuilt screen and a multitude of combat sensors"
|
||||
light_reactive = FALSE
|
||||
actions_types = list(/datum/action/item_action/organ_action/use)
|
||||
/// Used to detect when unmasked mobs enter range
|
||||
var/datum/proximity_monitor/tacvisor/proximity_monitor
|
||||
/// List of mob refs -> their overlays
|
||||
var/list/mob_overlays = list()
|
||||
/// List of mobs in our direct view range who we need to update dynamically
|
||||
var/list/direct_view_tracking = list()
|
||||
/// Current visual displayed on the screen
|
||||
var/visor_display = VISOR_DISPLAY_CROSS
|
||||
/// Allied faction highlight
|
||||
var/friendly_faction = IFF_FACTION_SEC_COMMAND
|
||||
/// Hostile faction highlight
|
||||
var/hostile_faction = IFF_FACTION_NONE
|
||||
/// Threat flags for hostile detection, if any are chosen
|
||||
var/threat_flags = JUDGE_IDCHECK | JUDGE_WEAPONCHECK | JUDGE_RECORDCHECK
|
||||
/// Can the user change the parameters?
|
||||
var/user_controls = TRUE
|
||||
|
||||
/// Valid options for friendly factions
|
||||
var/static/list/valid_friendly_factions = list(
|
||||
IFF_FACTION_NONE,
|
||||
IFF_FACTION_CREW,
|
||||
IFF_FACTION_SEC_COMMAND,
|
||||
IFF_FACTION_CENTCOM,
|
||||
IFF_FACTION_SYNDICATE,
|
||||
)
|
||||
/// Valid options for hostile factions
|
||||
var/static/list/valid_hostile_factions = list(
|
||||
IFF_FACTION_NONE,
|
||||
IFF_FACTION_CREW,
|
||||
IFF_FACTION_SEC_COMMAND,
|
||||
IFF_FACTION_CENTCOM,
|
||||
IFF_FACTION_SYNDICATE,
|
||||
IFF_FACTION_EVERYONE,
|
||||
)
|
||||
/// Threat flags and their tooltips
|
||||
var/static/list/threat_flag_options = list(
|
||||
"Valid ID" = JUDGE_IDCHECK,
|
||||
"Weapon Permit" = JUDGE_WEAPONCHECK,
|
||||
"Security Status" = JUDGE_RECORDCHECK,
|
||||
)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/generate_body_overlay(mob/living/carbon/human/parent, obj/item/bodypart/limb)
|
||||
var/mutable_appearance/visor_overlay = mutable_appearance(eye_icon, eye_icon_state, -EYES_LAYER, parent || limb)
|
||||
var/list/eye_overlays = list(visor_overlay)
|
||||
|
||||
if (parent && parent.appears_alive() && !HAS_TRAIT(parent, TRAIT_KNOCKEDOUT))
|
||||
var/mutable_appearance/display_overlay = mutable_appearance(eye_icon, "[eye_icon_state]_[LOWER_TEXT(visor_display)]", -EYES_LAYER, parent)
|
||||
eye_overlays += display_overlay
|
||||
if(!(parent.obscured_slots & HIDEEYES))
|
||||
eye_overlays += emissive_appearance(eye_icon, "[eye_icon_state]_[LOWER_TEXT(visor_display)]", parent, -EYES_LAYER)
|
||||
|
||||
if(!limb)
|
||||
return eye_overlays
|
||||
|
||||
var/obj/item/bodypart/head/head = astype(limb, /obj/item/bodypart/head)
|
||||
if(head?.worn_face_offset)
|
||||
for (var/mutable_appearance/overlay as anything in eye_overlays)
|
||||
head?.worn_face_offset.apply_offset(overlay)
|
||||
|
||||
return eye_overlays
|
||||
|
||||
// Hides and mutes all people on the screen
|
||||
/obj/item/organ/eyes/robotic/tacvisor/emag_act(mob/user, obj/item/card/emag/emag_card)
|
||||
if(obj_flags & EMAGGED)
|
||||
return FALSE
|
||||
obj_flags |= EMAGGED
|
||||
balloon_alert(user, "perceptual scanners overriden")
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/on_mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
receiver.add_client_colour(/datum/client_colour/tacvisor, REF(src))
|
||||
receiver.apply_status_effect(/datum/status_effect/grouped/see_no_names, REF(src))
|
||||
proximity_monitor = new(receiver, 9)
|
||||
proximity_monitor.owner = src
|
||||
|
||||
RegisterSignal(receiver, COMSIG_MOB_CLIENT_LOGIN, PROC_REF(on_login))
|
||||
RegisterSignal(receiver, COMSIG_MOVABLE_PRE_HEAR, PROC_REF(on_hear))
|
||||
RegisterSignal(receiver, COMSIG_MOB_EXAMINING, PROC_REF(on_examine))
|
||||
if (receiver.client)
|
||||
create_illusions(receiver)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
UnregisterSignal(organ_owner, list(COMSIG_MOB_CLIENT_LOGIN, COMSIG_MOVABLE_PRE_HEAR, COMSIG_MOB_EXAMINING))
|
||||
organ_owner.remove_client_colour(REF(src))
|
||||
organ_owner.remove_status_effect(/datum/status_effect/grouped/see_no_names, REF(src))
|
||||
QDEL_NULL(proximity_monitor)
|
||||
organ_owner.client?.images -= assoc_to_values(mob_overlays)
|
||||
for (var/mob/living/thing as anything in mob_overlays)
|
||||
UnregisterSignal(thing, list(
|
||||
COMSIG_MOVABLE_Z_CHANGED,
|
||||
COMSIG_QDELETING,
|
||||
COMSIG_ATOM_UPDATE_APPEARANCE,
|
||||
COMSIG_LIVING_POST_UPDATE_TRANSFORM,
|
||||
COMSIG_MOB_EQUIPPED_ITEM,
|
||||
COMSIG_MOB_UNEQUIPPED_ITEM,
|
||||
COMSIG_LIVING_UPDATE_OFFSETS,
|
||||
))
|
||||
mob_overlays.Cut()
|
||||
direct_view_tracking.Cut()
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/on_hear(datum/source, list/hearing_args)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (hearing_args[HEARING_SPEAKER] == owner || !isliving(hearing_args[HEARING_SPEAKER]))
|
||||
return
|
||||
|
||||
if (obj_flags & EMAGGED)
|
||||
return COMSIG_MOVABLE_CANCEL_HEARING
|
||||
|
||||
var/list/message_mods = hearing_args[HEARING_MESSAGE_MODE]
|
||||
message_mods[MODE_SPEAKER_NAME_OVERRIDE] = "Unknown"
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/on_login(mob/living/source, client/user_client)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (!length(mob_overlays))
|
||||
create_illusions(source)
|
||||
else
|
||||
user_client.images |= assoc_to_values(mob_overlays)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/create_illusions(mob/living/user)
|
||||
for(var/mob/living/target as anything in ((obj_flags & EMAGGED) ? GLOB.mob_living_list : GLOB.carbon_list))
|
||||
if (target == user)
|
||||
continue
|
||||
|
||||
if (get_dist(user, target) <= proximity_monitor.current_range)
|
||||
on_entered(target)
|
||||
else
|
||||
refresh_overlay(target)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/on_mob_delete(mob/living/source)
|
||||
SIGNAL_HANDLER
|
||||
owner.client?.images -= mob_overlays[source]
|
||||
mob_overlays -= source
|
||||
direct_view_tracking -= source
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/refresh_overlay(mob/living/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (mob_overlays[source])
|
||||
owner.client?.images -= mob_overlays[source]
|
||||
else
|
||||
RegisterSignal(source, COMSIG_QDELETING, PROC_REF(on_mob_delete))
|
||||
RegisterSignal(source, COMSIG_ATOM_UPDATE_APPEARANCE, PROC_REF(refresh_overlay))
|
||||
RegisterSignal(source, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_z_change))
|
||||
// Lying down/being pushed
|
||||
RegisterSignal(source, COMSIG_LIVING_POST_UPDATE_TRANSFORM, PROC_REF(refresh_overlay))
|
||||
RegisterSignal(source, COMSIG_LIVING_UPDATE_OFFSETS, PROC_REF(refresh_overlay))
|
||||
|
||||
mob_overlays[source] = make_overlay(source)
|
||||
owner.client?.images |= mob_overlays[source]
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/on_z_change(mob/living/source)
|
||||
SIGNAL_HANDLER
|
||||
var/image/overlay = mob_overlays[source]
|
||||
SET_PLANE_EXPLICIT(overlay, ABOVE_GAME_PLANE, source)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/make_overlay(mob/living/target)
|
||||
if (obj_flags & EMAGGED)
|
||||
var/image/overlay_image = image(mutable_appearance('icons/effects/effects.dmi', "nothing"), target)
|
||||
overlay_image.name = "Unknown"
|
||||
overlay_image.override = TRUE
|
||||
overlay_image.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
SET_PLANE_EXPLICIT(overlay_image, ABOVE_GAME_PLANE, target)
|
||||
return overlay_image
|
||||
|
||||
var/mutable_appearance/appearance_copy = new(target.appearance)
|
||||
appearance_copy.appearance_flags |= KEEP_APART|KEEP_TOGETHER
|
||||
var/outline_color = "#FFD500CC"
|
||||
switch (get_iff_signature(target))
|
||||
if (IFF_FRIENDLY)
|
||||
outline_color = "#0099FFCC"
|
||||
if (IFF_HOSTILE)
|
||||
outline_color = "#FF0022CC"
|
||||
appearance_copy.add_filter("target_lock_outline", 2, outline_filter(1, outline_color))
|
||||
var/mutable_appearance/static_effect = mutable_appearance('icons/effects/effects.dmi', "static_base")
|
||||
static_effect.color = "#373642"
|
||||
static_effect.blend_mode = BLEND_INSET_OVERLAY
|
||||
appearance_copy.overlays += static_effect
|
||||
appearance_copy.override = TRUE
|
||||
var/image/overlay_image = image(appearance_copy, target)
|
||||
overlay_image.name = "Unknown"
|
||||
overlay_image.override = TRUE
|
||||
SET_PLANE_EXPLICIT(overlay_image, ABOVE_GAME_PLANE, target)
|
||||
return overlay_image
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/get_iff_signature(mob/living/target)
|
||||
. = IFF_NEUTRAL
|
||||
if (hostile_faction == IFF_FACTION_EVERYONE)
|
||||
. = IFF_HOSTILE
|
||||
|
||||
if (!istype(target))
|
||||
return .
|
||||
|
||||
// This hasn't been used for like, over a decade, but by god will I make it great again
|
||||
var/lasercolor = null
|
||||
if (istype(owner.get_item_by_slot(ITEM_SLOT_OCLOTHING), /obj/item/clothing/suit/redtag) || istype(owner.get_item_by_slot(ITEM_SLOT_BELT), /obj/item/gun/energy/laser/redtag) || owner.is_holding_item_of_type(/obj/item/gun/energy/laser/redtag))
|
||||
lasercolor = "r"
|
||||
else if (istype(owner.get_item_by_slot(ITEM_SLOT_OCLOTHING), /obj/item/clothing/suit/bluetag) || istype(owner.get_item_by_slot(ITEM_SLOT_BELT), /obj/item/gun/energy/laser/bluetag) || owner.is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag))
|
||||
lasercolor = "b"
|
||||
|
||||
if (threat_flags && target.assess_threat(threat_flags, lasercolor) >= THREAT_ASSESS_DANGEROUS)
|
||||
return IFF_HOSTILE
|
||||
|
||||
var/obj/item/card/id/idcard = target.get_idcard()
|
||||
if (!istype(idcard))
|
||||
return .
|
||||
|
||||
// Ignores RETA access so we directly access access instead of using the wrapper
|
||||
if (ACCESS_SYNDICATE in idcard.access)
|
||||
if (hostile_faction == IFF_FACTION_SYNDICATE)
|
||||
return IFF_HOSTILE
|
||||
if (friendly_faction == IFF_FACTION_SYNDICATE)
|
||||
return IFF_FRIENDLY
|
||||
|
||||
if (istype(idcard.trim, /datum/id_trim/job))
|
||||
// Cham cards get a pass
|
||||
if (hostile_faction == IFF_FACTION_CREW && idcard.trim?.threat_modifier >= 0)
|
||||
return IFF_HOSTILE
|
||||
if (friendly_faction == IFF_FACTION_CREW)
|
||||
return IFF_FRIENDLY
|
||||
|
||||
if ((ACCESS_COMMAND in idcard.access) || (ACCESS_SECURITY in idcard.access))
|
||||
if (hostile_faction == IFF_FACTION_SEC_COMMAND)
|
||||
return IFF_HOSTILE
|
||||
if (friendly_faction == IFF_FACTION_SEC_COMMAND)
|
||||
return IFF_FRIENDLY
|
||||
|
||||
if (ACCESS_CENT_GENERAL in idcard.access)
|
||||
if (hostile_faction == IFF_FACTION_CENTCOM)
|
||||
return IFF_HOSTILE
|
||||
if (friendly_faction == IFF_FACTION_CENTCOM)
|
||||
return IFF_FRIENDLY
|
||||
|
||||
return .
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/on_examine(mob/source, atom/target, list/examine_strings, list/examine_overrides)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (target == owner || !iscarbon(target) && !(isliving(target) && (obj_flags & EMAGGED)))
|
||||
return
|
||||
|
||||
var/list/override_strings = list(span_warning("You're struggling to make out any details..."))
|
||||
|
||||
if (!threat_flags && !(obj_flags & EMAGGED))
|
||||
examine_overrides[EXAMINE_OVERRIDE_PRIORITY_IFF] = override_strings
|
||||
return
|
||||
|
||||
var/lasercolor = null
|
||||
var/mob/living/victim = target
|
||||
if (istype(owner.get_item_by_slot(ITEM_SLOT_OCLOTHING), /obj/item/clothing/suit/redtag) || istype(owner.get_item_by_slot(ITEM_SLOT_BELT), /obj/item/gun/energy/laser/redtag) || owner.is_holding_item_of_type(/obj/item/gun/energy/laser/redtag))
|
||||
lasercolor = "r"
|
||||
else if (istype(owner.get_item_by_slot(ITEM_SLOT_OCLOTHING), /obj/item/clothing/suit/bluetag) || istype(owner.get_item_by_slot(ITEM_SLOT_BELT), /obj/item/gun/energy/laser/bluetag) || owner.is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag))
|
||||
lasercolor = "b"
|
||||
|
||||
var/threat_level = victim.assess_threat(threat_flags, lasercolor)
|
||||
switch (threat_level)
|
||||
if (THREAT_ASSESS_MAXIMUM to INFINITY)
|
||||
override_strings += span_boldwarning("Assessed threat level of [threat_level]! Extreme danger of criminal activity!")
|
||||
if (THREAT_ASSESS_DANGEROUS to THREAT_ASSESS_MAXIMUM)
|
||||
override_strings += span_warning("Assessed threat level of [threat_level]. Criminal scum detected!")
|
||||
if (1 to THREAT_ASSESS_DANGEROUS)
|
||||
override_strings += span_notice("Assessed threat level of [threat_level]. Probably not dangerous... yet.")
|
||||
else
|
||||
override_strings += span_notice("Seems to be a trustworthy individual.")
|
||||
|
||||
examine_overrides[EXAMINE_OVERRIDE_PRIORITY_IFF] = override_strings
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/ui_state(mob/user)
|
||||
return GLOB.default_state
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/ui_status(mob/user, datum/ui_state/state)
|
||||
if(!QDELETED(owner))
|
||||
if(owner == user && user_controls)
|
||||
return min(
|
||||
ui_status_user_is_abled(user, src),
|
||||
ui_status_only_living(user),
|
||||
)
|
||||
return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "TacVisorEyesMenu")
|
||||
ui.open()
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["friendlyFaction"] = friendly_faction
|
||||
data["hostileFaction"] = hostile_faction
|
||||
data["visorDisplay"] = visor_display
|
||||
data["threatFlags"] = threat_flags
|
||||
return data
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["validFriendlyFactions"] = valid_friendly_factions
|
||||
data["validHostileFactions"] = valid_hostile_factions
|
||||
data["visorOptions"] = list(VISOR_DISPLAY_CROSS, VISOR_DISPLAY_EYES, VISOR_DISPLAY_LINE)
|
||||
data["threatOptions"] = threat_flag_options
|
||||
return data
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/ui_act(action, list/params, datum/tgui/ui)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if ("set_friendly")
|
||||
var/chosen_faction = params["faction"]
|
||||
if (!(chosen_faction in valid_friendly_factions))
|
||||
chosen_faction = IFF_FACTION_NONE
|
||||
friendly_faction = chosen_faction
|
||||
update_mob_overlays()
|
||||
|
||||
if ("set_hostile")
|
||||
var/chosen_faction = params["faction"]
|
||||
if (!(chosen_faction in valid_hostile_factions))
|
||||
chosen_faction = IFF_FACTION_NONE
|
||||
hostile_faction = chosen_faction
|
||||
update_mob_overlays()
|
||||
|
||||
if ("set_threat_flags")
|
||||
threat_flags = text2num(params["threat_flags"])
|
||||
update_mob_overlays()
|
||||
|
||||
if ("set_display")
|
||||
visor_display = params["display"]
|
||||
if (visor_display != VISOR_DISPLAY_EYES && visor_display != VISOR_DISPLAY_LINE && visor_display != VISOR_DISPLAY_CROSS)
|
||||
visor_display = VISOR_DISPLAY_CROSS
|
||||
owner?.update_body()
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/update_mob_overlays()
|
||||
for (var/mob/living/target as anything in direct_view_tracking)
|
||||
refresh_overlay(target)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/ui_action_click(mob/user, action)
|
||||
if(istype(action, /datum/action/item_action/organ_action/use) && user_controls)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/multitool_act(mob/living/user, obj/item/tool)
|
||||
ui_interact(user)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
user_controls = !user_controls
|
||||
balloon_alert(user, "user controls [user_controls ? "enabled" : "disabled"]")
|
||||
if (user_controls)
|
||||
add_item_action(/datum/action/item_action/organ_action/use)
|
||||
else
|
||||
for(var/datum/action/action as anything in actions)
|
||||
remove_item_action(action)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/examine(mob/user)
|
||||
. = ..()
|
||||
. += span_notice("Its settings can be changed with a [EXAMINE_HINT("multitool")].")
|
||||
. += span_notice("User configuration switch is currently in the [user_controls ? "on" : "off"] position, and could be flipped wtih a [EXAMINE_HINT("screwdriver")].")
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/on_entered(mob/living/source)
|
||||
if (source in direct_view_tracking)
|
||||
return
|
||||
|
||||
refresh_overlay(source)
|
||||
direct_view_tracking += source
|
||||
// Track equipping/unequipping items for threat levels/ID identity
|
||||
RegisterSignal(source, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(check_equippped_item))
|
||||
RegisterSignal(source, COMSIG_MOB_UNEQUIPPED_ITEM, PROC_REF(refresh_overlay)) // Can't see the slot of the dropped item so we need to blanket update
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/check_equippped_item(mob/living/source, obj/item/equipped_item, slot)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
// Anywhere where an ID or a gun would count
|
||||
if (slot & (ITEM_SLOT_BELT | ITEM_SLOT_ID | ITEM_SLOT_HANDS | ITEM_SLOT_BACK))
|
||||
refresh_overlay(source)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/proc/on_exited(mob/living/source)
|
||||
if (!(source in direct_view_tracking))
|
||||
return
|
||||
|
||||
direct_view_tracking -= source
|
||||
UnregisterSignal(source, list(
|
||||
COMSIG_MOB_EQUIPPED_ITEM,
|
||||
COMSIG_MOB_UNEQUIPPED_ITEM,
|
||||
))
|
||||
|
||||
/datum/proximity_monitor/tacvisor
|
||||
var/obj/item/organ/eyes/robotic/tacvisor/owner
|
||||
|
||||
/datum/proximity_monitor/tacvisor/Destroy()
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/datum/proximity_monitor/tacvisor/on_moved(atom/movable/source, atom/old_loc)
|
||||
return
|
||||
|
||||
/datum/proximity_monitor/tacvisor/on_entered(atom/source, atom/movable/arrived, turf/old_loc)
|
||||
if (arrived != host && (iscarbon(arrived) || isliving(arrived) && (owner.obj_flags & EMAGGED)))
|
||||
owner.on_entered(arrived)
|
||||
|
||||
/datum/proximity_monitor/tacvisor/on_uncrossed/on_uncrossed(turf/old_location, mob/exited, direction)
|
||||
if (exited != host && (iscarbon(exited) || isliving(exited) && (owner.obj_flags & EMAGGED)) && get_dist(exited, host) > current_range)
|
||||
owner.on_exited(exited)
|
||||
|
||||
/datum/proximity_monitor/tacvisor/on_initialized(turf/location, atom/created, init_flags)
|
||||
if (created != host && (iscarbon(created) || isliving(created) && (owner.obj_flags & EMAGGED)))
|
||||
owner.on_entered(created)
|
||||
|
||||
/datum/client_colour/tacvisor
|
||||
priority = CLIENT_COLOR_ORGAN_PRIORITY
|
||||
|
||||
/datum/client_colour/tacvisor/New(mob/owner)
|
||||
. = ..()
|
||||
color = color_matrix_filter(list(
|
||||
1, 0, 0,
|
||||
0, 1.75, 0,
|
||||
0, 0, 0.75,
|
||||
0, -0.75, 0,
|
||||
), COLORSPACE_HSL)
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/deathsquad
|
||||
friendly_faction = IFF_FACTION_CENTCOM
|
||||
hostile_faction = IFF_FACTION_EVERYONE
|
||||
actions_types = null
|
||||
user_controls = FALSE
|
||||
|
||||
/obj/item/organ/eyes/robotic/tacvisor/deathsquad/ui_status(mob/user, datum/ui_state/state)
|
||||
return UI_CLOSE
|
||||
|
||||
#undef VISOR_DISPLAY_CROSS
|
||||
#undef VISOR_DISPLAY_EYES
|
||||
#undef VISOR_DISPLAY_LINE
|
||||
|
||||
#undef IFF_HOSTILE
|
||||
#undef IFF_NEUTRAL
|
||||
#undef IFF_FRIENDLY
|
||||
|
||||
#undef IFF_FACTION_NONE
|
||||
#undef IFF_FACTION_SYNDICATE
|
||||
#undef IFF_FACTION_CREW
|
||||
#undef IFF_FACTION_SEC_COMMAND
|
||||
#undef IFF_FACTION_CENTCOM
|
||||
#undef IFF_FACTION_EVERYONE
|
||||
@@ -0,0 +1,113 @@
|
||||
/obj/item/organ/eyes/night_vision/mushroom
|
||||
name = "fung-eye"
|
||||
desc = "While on the outside they look inert and dead, the eyes of mushroom people are actually very advanced."
|
||||
low_light_cutoff = list(0, 15, 20)
|
||||
medium_light_cutoff = list(0, 20, 35)
|
||||
high_light_cutoff = list(0, 40, 50)
|
||||
pupils_name = "photosensory openings"
|
||||
penlight_message = "are attached to fungal stalks"
|
||||
|
||||
/obj/item/organ/eyes/zombie
|
||||
name = "undead eyes"
|
||||
desc = "Somewhat counterintuitively, these half-rotten eyes actually have superior vision to those of a living human."
|
||||
color_cutoffs = list(25, 35, 5)
|
||||
penlight_message = "are rotten and decayed!"
|
||||
|
||||
/obj/item/organ/eyes/zombie/penlight_examine(mob/living/viewer, obj/item/examtool)
|
||||
return span_danger("[owner.p_Their()] eyes [penlight_message]")
|
||||
|
||||
/obj/item/organ/eyes/alien
|
||||
name = "alien eyes"
|
||||
desc = "It turned out they had them after all!"
|
||||
sight_flags = SEE_MOBS
|
||||
color_cutoffs = list(25, 5, 42)
|
||||
|
||||
/obj/item/organ/eyes/golem
|
||||
name = "resonating crystal"
|
||||
desc = "Golems somehow measure external light levels and detect nearby ore using this sensitive mineral lattice."
|
||||
icon_state = "adamantine_cords"
|
||||
eye_icon_state = null
|
||||
blink_animation = FALSE
|
||||
iris_overlay = null
|
||||
color = COLOR_GOLEM_GRAY
|
||||
visual = FALSE
|
||||
organ_flags = ORGAN_MINERAL
|
||||
color_cutoffs = list(10, 15, 5)
|
||||
actions_types = list(/datum/action/cooldown/golem_ore_sight)
|
||||
penlight_message = "glimmer, their crystaline structure refracting light inwards"
|
||||
pupils_name = "lensing gems" // Given it says these are a "mineral lattice" that collects light i assume they work like artifical ruby laser foci
|
||||
|
||||
/// Send an ore detection pulse on a cooldown
|
||||
/datum/action/cooldown/golem_ore_sight
|
||||
name = "Ore Resonance"
|
||||
desc = "Causes nearby ores to vibrate, revealing their location."
|
||||
button_icon = 'icons/obj/devices/scanner.dmi'
|
||||
button_icon_state = "manual_mining"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
cooldown_time = 10 SECONDS
|
||||
|
||||
/datum/action/cooldown/golem_ore_sight/Activate(atom/target)
|
||||
. = ..()
|
||||
mineral_scan_pulse(get_turf(target), scanner = target)
|
||||
|
||||
/obj/item/organ/eyes/moth
|
||||
name = "moth eyes"
|
||||
desc = "These eyes seem to have increased sensitivity to bright light, with no improvement to low light vision."
|
||||
icon_state = "eyes_moth"
|
||||
eye_icon_state = "motheyes"
|
||||
blink_animation = FALSE
|
||||
iris_overlay = null
|
||||
flash_protect = FLASH_PROTECTION_SENSITIVE
|
||||
pupils_name = "ommatidia" //yes i know compound eyes have no pupils shut up
|
||||
penlight_message = "are bulbous and insectoid"
|
||||
|
||||
/obj/item/organ/eyes/ghost
|
||||
name = "ghost eyes"
|
||||
desc = "Despite lacking pupils, these can see pretty well."
|
||||
icon_state = "eyes-ghost"
|
||||
blink_animation = FALSE
|
||||
movement_type = PHASING
|
||||
organ_flags = parent_type::organ_flags | ORGAN_GHOST
|
||||
|
||||
/obj/item/organ/eyes/snail
|
||||
name = "snail eyes"
|
||||
desc = "These eyes seem to have a large range, but might be cumbersome with glasses."
|
||||
icon_state = "eyes_snail"
|
||||
eye_icon_state = "snail_eyes"
|
||||
blink_animation = FALSE
|
||||
pupils_name = "eyestalks" //many species of snails can retract their eyes into their face! (my lame science excuse for not having better writing here)
|
||||
penlight_message = "are sat upon retractable tentacles"
|
||||
|
||||
/obj/item/organ/eyes/jelly
|
||||
name = "jelly eyes"
|
||||
desc = "These eyes are made of a soft jelly. Unlike all other eyes, though, there are three of them."
|
||||
icon_state = "eyes_jelly"
|
||||
eye_icon_state = "jelleyes"
|
||||
blink_animation = FALSE
|
||||
iris_overlay = null
|
||||
pupils_name = "lensing bubbles" //imagine a water lens physics demo but with goo. thats how these work.
|
||||
penlight_message = "are three bubbles of refractive jelly"
|
||||
|
||||
/obj/item/organ/eyes/lizard
|
||||
name = "reptile eyes"
|
||||
desc = "A pair of reptile eyes with thin vertical slits for pupils."
|
||||
icon_state = "lizard_eyes"
|
||||
synchronized_blinking = FALSE
|
||||
pupils_name = "slit pupils"
|
||||
penlight_message = "have vertically slit pupils and tinted whites"
|
||||
|
||||
/obj/item/organ/eyes/pod
|
||||
name = "pod eyes"
|
||||
desc = "Strangest salad you've ever seen."
|
||||
icon_state = "eyes_pod"
|
||||
eye_color_left = "#375846"
|
||||
eye_color_right = "#375846"
|
||||
iris_overlay = null
|
||||
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"
|
||||
Reference in New Issue
Block a user