Files
Bubberstation/code/datums/components/manual_blinking.dm
SmArtKar 640a1229ca Adds blinking and a new Fluoride Stare quirk (#88927)
## About The Pull Request

Spessmen now need to blink! If you have non-robotic eyes, you'll
automatically blink every once in a while. Lizards have asynchronous
blinking, and whenever they blink one of their eyes (chosen at random)
will blink slightly sooner.


https://github.com/user-attachments/assets/e62020ef-d2f8-4634-9399-a27244326cfe

You can also blink manually, as emotes now fire the animations.


https://github.com/user-attachments/assets/80d6304f-f3c2-424a-a5aa-96a4aee7acdc

Adds a new eye-related quirk, Fluoride Stare! It will spawn you without
eyelids, preventing random or manual blinking and forcing you to wet
your eyes with some saline solution (of which you get a bottle, and a
dropper to apply it) every minute or so.
Additionally, eyes now display their color on their organ sprite,
instead of always showing up as blue.

(Don't tell roleplayers, but Fully Immerse smite now blinds you when you
blink, for true full immersion)

## Why It's Good For The Game

Spessmen blinking is just soulful, and brings some life into the game.
As for the quirk, its just a funny bit/reference that people can use
to... torture themselves?

## Changelog
🆑
add: Spessmen now blink.
add: Added a new Fluoride Stare quirk, keep those eyeballs wet, lest
they crack!
image: Eyes now display their color on their organ sprite, instead of
always being displayed as blue.
/🆑
2025-01-09 10:24:49 +01:00

121 lines
4.2 KiB
Plaintext

/datum/component/manual_blinking
dupe_mode = COMPONENT_DUPE_UNIQUE
var/obj/item/organ/eyes/parent_eyes
var/warn_grace = FALSE
var/warn_dying = FALSE
var/last_blink
var/check_every = 20 SECONDS
var/grace_period = 6 SECONDS
/// Organ damage taken per tick
var/damage_rate = 1
/// How much saline needs to be dropper at once for it to count as "blinking"
var/min_saline = 1
/// Do we display a message when adding/removing the component
var/display_message = TRUE
var/list/valid_emotes = list(/datum/emote/living/carbon/human/blink, /datum/emote/living/carbon/human/blink_r)
/datum/component/manual_blinking/Initialize(damage_rate = 1, check_every = 20 SECONDS, grace_period = 6 SECONDS, display_message = TRUE)
if(!iscarbon(parent))
return COMPONENT_INCOMPATIBLE
src.damage_rate = damage_rate
src.check_every = check_every
src.grace_period = grace_period
src.display_message = display_message
var/mob/living/carbon/carbon_parent = parent
ADD_TRAIT(carbon_parent, TRAIT_PREVENT_BLINK_LOOPS, REF(src))
carbon_parent.update_body()
parent_eyes = carbon_parent.get_organ_slot(ORGAN_SLOT_EYES)
if(!parent_eyes || IS_ROBOTIC_ORGAN(parent_eyes))
return
START_PROCESSING(SSdcs, src)
last_blink = world.time
if (display_message)
to_chat(carbon_parent, span_notice("You suddenly realize you're blinking manually."))
/datum/component/manual_blinking/Destroy(force)
REMOVE_TRAIT(parent, TRAIT_PREVENT_BLINK_LOOPS, REF(src))
parent_eyes = null
STOP_PROCESSING(SSdcs, src)
if (display_message)
to_chat(parent, span_notice("You revert back to automatic blinking."))
var/mob/living/carbon/carbon_parent = parent
carbon_parent.cure_blind(REF(src))
carbon_parent.update_body()
return ..()
/datum/component/manual_blinking/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOB_EMOTE, PROC_REF(check_emote))
RegisterSignal(parent, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(check_added_organ))
RegisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(check_removed_organ))
RegisterSignal(parent, COMSIG_LIVING_REVIVE, PROC_REF(restart))
RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(pause))
RegisterSignal(parent, COMSIG_MOB_REAGENTS_DROPPED_INTO_EYES, PROC_REF(on_dropper))
/datum/component/manual_blinking/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_MOB_EMOTE, COMSIG_CARBON_GAIN_ORGAN, COMSIG_CARBON_LOSE_ORGAN, COMSIG_LIVING_REVIVE, COMSIG_LIVING_DEATH, COMSIG_MOB_REAGENTS_DROPPED_INTO_EYES))
/datum/component/manual_blinking/proc/restart()
SIGNAL_HANDLER
START_PROCESSING(SSdcs, src)
/datum/component/manual_blinking/proc/pause()
SIGNAL_HANDLER
STOP_PROCESSING(SSdcs, src)
/datum/component/manual_blinking/process()
if(world.time > (last_blink + check_every + grace_period))
if(!warn_dying)
to_chat(parent, span_userdanger("Your eyes begin to wither, you need to blink!"))
warn_dying = TRUE
parent_eyes.apply_organ_damage(damage_rate)
else if(world.time > (last_blink + check_every))
if(!warn_grace)
to_chat(parent, span_danger("You feel a need to blink!"))
warn_grace = TRUE
/datum/component/manual_blinking/proc/check_added_organ(mob/who_cares, obj/item/organ/added_organ)
SIGNAL_HANDLER
if(istype(added_organ, /obj/item/organ/eyes))
parent_eyes = added_organ
if (IS_ROBOTIC_ORGAN(parent_eyes))
parent_eyes = null
return
last_blink = world.time
START_PROCESSING(SSdcs, src)
/datum/component/manual_blinking/proc/check_removed_organ(mob/who_cares, obj/item/organ/removed_organ)
SIGNAL_HANDLER
if(removed_organ == parent_eyes)
parent_eyes = null
STOP_PROCESSING(SSdcs, src)
/datum/component/manual_blinking/proc/check_emote(mob/living/carbon/user, datum/emote/emote)
SIGNAL_HANDLER
if(!(emote.type in valid_emotes))
return
warn_grace = FALSE
warn_dying = FALSE
last_blink = world.time
user.become_blind(REF(src))
addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living, remove_status_effect), /datum/status_effect/grouped/blindness, REF(src)), 0.15 SECONDS)
/datum/component/manual_blinking/proc/on_dropper(datum/source, mob/living/user, atom/dropper, datum/reagents/reagents, fraction)
SIGNAL_HANDLER
var/saline_amount = reagents.get_reagent_amount(/datum/reagent/medicine/salglu_solution) * fraction
if (saline_amount >= min_saline)
warn_grace = FALSE
warn_dying = FALSE
last_blink = world.time