Revert "PLASE"

This reverts commit 8af225e6e3.
This commit is contained in:
Fermi
2019-11-24 03:06:08 +00:00
parent aeb8606ce0
commit ba4fa1ef67
2145 changed files with 1387321 additions and 5257 deletions
+46
View File
@@ -0,0 +1,46 @@
/obj/item/organ/appendix
name = "appendix"
icon_state = "appendix"
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_APPENDIX
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = STANDARD_ORGAN_DECAY
now_failing = "<span class='warning'>An explosion of pain erupts in your lower right abdomen!</span>"
now_fixed = "<span class='info'>The pain in your abdomen has subsided.</span>"
var/inflamed
/obj/item/organ/appendix/on_life()
..()
if(!(organ_flags & ORGAN_FAILING))
return
var/mob/living/carbon/M = owner
if(M)
M.adjustToxLoss(4, TRUE, TRUE) //forced to ensure people don't use it to gain tox as slime person
/obj/item/organ/appendix/update_icon()
if(inflamed)
icon_state = "appendixinflamed"
name = "inflamed appendix"
else
icon_state = "appendix"
name = "appendix"
/obj/item/organ/appendix/Remove(mob/living/carbon/M, special = 0)
for(var/datum/disease/appendicitis/A in M.diseases)
A.cure()
inflamed = TRUE
update_icon()
..()
/obj/item/organ/appendix/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
if(inflamed)
M.ForceContractDisease(new /datum/disease/appendicitis(), FALSE, TRUE)
/obj/item/organ/appendix/prepare_eat()
var/obj/S = ..()
if(inflamed)
S.reagents.add_reagent("bad_food", 5)
return S
@@ -0,0 +1,209 @@
/obj/item/organ/cyberimp/chest
name = "cybernetic torso implant"
desc = "Implants for the organs in your torso."
icon_state = "chest_implant"
implant_overlay = "chest_implant_overlay"
zone = BODY_ZONE_CHEST
/obj/item/organ/cyberimp/chest/nutriment
name = "Nutriment pump implant"
desc = "This implant will synthesize and pump into your bloodstream a small amount of nutriment when you are starving."
icon_state = "chest_implant"
implant_color = "#00AA00"
var/hunger_threshold = NUTRITION_LEVEL_STARVING
var/synthesizing = 0
var/poison_amount = 5
slot = ORGAN_SLOT_STOMACH_AID
/obj/item/organ/cyberimp/chest/nutriment/on_life()
if(synthesizing)
return
if(owner.nutrition <= hunger_threshold)
synthesizing = TRUE
to_chat(owner, "<span class='notice'>You feel less hungry...</span>")
owner.nutrition += 50
addtimer(CALLBACK(src, .proc/synth_cool), 50)
/obj/item/organ/cyberimp/chest/nutriment/proc/synth_cool()
synthesizing = FALSE
/obj/item/organ/cyberimp/chest/nutriment/emp_act(severity)
. = ..()
if(!owner || . & EMP_PROTECT_SELF)
return
owner.reagents.add_reagent("bad_food", poison_amount / severity)
to_chat(owner, "<span class='warning'>You feel like your insides are burning.</span>")
/obj/item/organ/cyberimp/chest/nutriment/plus
name = "Nutriment pump implant PLUS"
desc = "This implant will synthesize and pump into your bloodstream a small amount of nutriment when you are hungry."
icon_state = "chest_implant"
implant_color = "#006607"
hunger_threshold = NUTRITION_LEVEL_HUNGRY
poison_amount = 10
/obj/item/organ/cyberimp/chest/reviver
name = "Reviver implant"
desc = "This implant will attempt to revive and heal you if you lose consciousness. For the faint of heart!"
icon_state = "chest_implant"
implant_color = "#AD0000"
slot = ORGAN_SLOT_HEART_AID
var/revive_cost = 0
var/reviving = 0
var/cooldown = 0
/obj/item/organ/cyberimp/chest/reviver/on_life()
if(reviving)
if(owner.stat == UNCONSCIOUS)
addtimer(CALLBACK(src, .proc/heal), 30)
else
cooldown = revive_cost + world.time
reviving = FALSE
to_chat(owner, "<span class='notice'>Your reviver implant shuts down and starts recharging. It will be ready again in [DisplayTimeText(revive_cost)].</span>")
return
if(cooldown > world.time)
return
if(owner.stat != UNCONSCIOUS)
return
if(owner.suiciding)
return
revive_cost = 0
reviving = TRUE
to_chat(owner, "<span class='notice'>You feel a faint buzzing as your reviver implant starts patching your wounds...</span>")
/obj/item/organ/cyberimp/chest/reviver/proc/heal()
if(owner.getOxyLoss())
owner.adjustOxyLoss(-5)
revive_cost += 5
if(owner.getBruteLoss())
owner.adjustBruteLoss(-2)
revive_cost += 40
if(owner.getFireLoss())
owner.adjustFireLoss(-2)
revive_cost += 40
if(owner.getToxLoss())
owner.adjustToxLoss(-1)
revive_cost += 40
/obj/item/organ/cyberimp/chest/reviver/emp_act(severity)
. = ..()
if(!owner || . & EMP_PROTECT_SELF)
return
if(reviving)
revive_cost += 200
else
cooldown += 200
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
if(H.stat != DEAD && prob(50 / severity) && H.can_heartattack())
H.set_heartattack(TRUE)
to_chat(H, "<span class='userdanger'>You feel a horrible agony in your chest!</span>")
addtimer(CALLBACK(src, .proc/undo_heart_attack), 600 / severity)
/obj/item/organ/cyberimp/chest/reviver/proc/undo_heart_attack()
var/mob/living/carbon/human/H = owner
if(!istype(H))
return
H.set_heartattack(FALSE)
if(H.stat == CONSCIOUS)
to_chat(H, "<span class='notice'>You feel your heart beating again!</span>")
/obj/item/organ/cyberimp/chest/thrusters
name = "implantable thrusters set"
desc = "An implantable set of thruster ports. They use the gas from environment or subject's internals for propulsion in zero-gravity areas. \
Unlike regular jetpacks, this device has no stabilization system."
slot = ORGAN_SLOT_THRUSTERS
icon_state = "imp_jetpack"
implant_overlay = null
implant_color = null
actions_types = list(/datum/action/item_action/organ_action/toggle)
w_class = WEIGHT_CLASS_NORMAL
var/on = FALSE
var/datum/effect_system/trail_follow/ion/ion_trail
/obj/item/organ/cyberimp/chest/thrusters/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
. = ..()
if(!ion_trail)
ion_trail = new
ion_trail.set_up(M)
/obj/item/organ/cyberimp/chest/thrusters/Remove(mob/living/carbon/M, special = 0)
if(on)
toggle(silent = TRUE)
..()
/obj/item/organ/cyberimp/chest/thrusters/ui_action_click()
toggle()
/obj/item/organ/cyberimp/chest/thrusters/proc/toggle(silent = FALSE)
if(!on)
if(crit_fail || (organ_flags & ORGAN_FAILING))
if(!silent)
to_chat(owner, "<span class='warning'>Your thrusters set seems to be broken!</span>")
return 0
on = TRUE
if(allow_thrust(0.01))
ion_trail.start()
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/move_react)
owner.add_movespeed_modifier(MOVESPEED_ID_CYBER_THRUSTER, priority=100, multiplicative_slowdown=-2, movetypes=FLOATING, conflict=MOVE_CONFLICT_JETPACK)
if(!silent)
to_chat(owner, "<span class='notice'>You turn your thrusters set on.</span>")
else
ion_trail.stop()
UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
owner.remove_movespeed_modifier(MOVESPEED_ID_CYBER_THRUSTER)
if(!silent)
to_chat(owner, "<span class='notice'>You turn your thrusters set off.</span>")
on = FALSE
update_icon()
/obj/item/organ/cyberimp/chest/thrusters/update_icon()
if(on)
icon_state = "imp_jetpack-on"
else
icon_state = "imp_jetpack"
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
/obj/item/organ/cyberimp/chest/thrusters/proc/move_react()
allow_thrust(0.01)
/obj/item/organ/cyberimp/chest/thrusters/proc/allow_thrust(num)
if(!on || !owner)
return 0
var/turf/T = get_turf(owner)
if(!T) // No more runtimes from being stuck in nullspace.
return 0
// Priority 1: use air from environment.
var/datum/gas_mixture/environment = T.return_air()
if(environment && environment.return_pressure() > 30)
return 1
// Priority 2: use plasma from internal plasma storage.
// (just in case someone would ever use this implant system to make cyber-alien ops with jetpacks and taser arms)
if(owner.getPlasma() >= num*100)
owner.adjustPlasma(-num*100)
return 1
// Priority 3: use internals tank.
var/obj/item/tank/I = owner.internal
if(I && I.air_contents && I.air_contents.total_moles() > num)
var/datum/gas_mixture/removed = I.air_contents.remove(num)
if(removed.total_moles() > 0.005)
T.assume_air(removed)
return 1
else
T.assume_air(removed)
toggle(silent = TRUE)
return 0
@@ -0,0 +1,144 @@
#define STUN_SET_AMOUNT 40
/obj/item/organ/cyberimp
name = "cybernetic implant"
desc = "A state-of-the-art implant that improves a baseline's functionality."
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
var/implant_color = "#FFFFFF"
var/implant_overlay
var/syndicate_implant = FALSE //Makes the implant invisible to health analyzers and medical HUDs.
/obj/item/organ/cyberimp/New(var/mob/M = null)
if(iscarbon(M))
src.Insert(M)
if(implant_overlay)
var/mutable_appearance/overlay = mutable_appearance(icon, implant_overlay)
overlay.color = implant_color
add_overlay(overlay)
return ..()
//[[[[BRAIN]]]]
/obj/item/organ/cyberimp/brain
name = "cybernetic brain implant"
desc = "Injectors of extra sub-routines for the brain."
icon_state = "brain_implant"
implant_overlay = "brain_implant_overlay"
zone = BODY_ZONE_HEAD
w_class = WEIGHT_CLASS_TINY
/obj/item/organ/cyberimp/brain/emp_act(severity)
. = ..()
if(!owner || . & EMP_PROTECT_SELF)
return
var/stun_amount = 200/severity
owner.Stun(stun_amount)
to_chat(owner, "<span class='warning'>Your body seizes up!</span>")
/obj/item/organ/cyberimp/brain/anti_drop
name = "anti-drop implant"
desc = "This cybernetic brain implant will allow you to force your hand muscles to contract, preventing item dropping. Twitch ear to toggle."
var/active = 0
var/list/stored_items = list()
implant_color = "#DE7E00"
slot = ORGAN_SLOT_BRAIN_ANTIDROP
actions_types = list(/datum/action/item_action/organ_action/toggle)
/obj/item/organ/cyberimp/brain/anti_drop/ui_action_click()
active = !active
if(active)
for(var/obj/item/I in owner.held_items)
stored_items += I
var/list/L = owner.get_empty_held_indexes()
if(LAZYLEN(L) == owner.held_items.len)
to_chat(owner, "<span class='notice'>You are not holding any items, your hands relax...</span>")
active = 0
stored_items = list()
else
for(var/obj/item/I in stored_items)
to_chat(owner, "<span class='notice'>Your [owner.get_held_index_name(owner.get_held_index_of_item(I))]'s grip tightens.</span>")
ADD_TRAIT(I, TRAIT_NODROP, ANTI_DROP_IMPLANT_TRAIT)
else
release_items()
to_chat(owner, "<span class='notice'>Your hands relax...</span>")
/obj/item/organ/cyberimp/brain/anti_drop/emp_act(severity)
. = ..()
if(!owner || . & EMP_PROTECT_SELF)
return
var/range = severity ? 10 : 5
var/atom/A
if(active)
release_items()
for(var/obj/item/I in stored_items)
A = pick(oview(range))
I.throw_at(A, range, 2)
to_chat(owner, "<span class='warning'>Your [owner.get_held_index_name(owner.get_held_index_of_item(I))] spasms and throws the [I.name]!</span>")
stored_items = list()
/obj/item/organ/cyberimp/brain/anti_drop/proc/release_items()
for(var/obj/item/I in stored_items)
REMOVE_TRAIT(I, TRAIT_NODROP, ANTI_DROP_IMPLANT_TRAIT)
stored_items = list()
/obj/item/organ/cyberimp/brain/anti_drop/Remove(var/mob/living/carbon/M, special = 0)
if(active)
ui_action_click()
..()
/obj/item/organ/cyberimp/brain/anti_stun
name = "CNS Rebooter implant"
desc = "This implant will automatically give you back control over your central nervous system, reducing downtime when stunned."
implant_color = "#FFFF00"
slot = ORGAN_SLOT_BRAIN_ANTISTUN
/obj/item/organ/cyberimp/brain/anti_stun/on_life()
..()
if(crit_fail || !(organ_flags & ORGAN_FAILING))
return
owner.adjustStaminaLoss(-3.5) //Citadel edit, makes it more useful in Stamina based combat
if(owner.AmountStun() > STUN_SET_AMOUNT)
owner.SetStun(STUN_SET_AMOUNT)
if(owner.AmountKnockdown() > STUN_SET_AMOUNT)
owner.SetKnockdown(STUN_SET_AMOUNT)
/obj/item/organ/cyberimp/brain/anti_stun/emp_act(severity)
. = ..()
if(crit_fail || (organ_flags & ORGAN_FAILING) || . & EMP_PROTECT_SELF)
return
crit_fail = TRUE
organ_flags |= ORGAN_FAILING
addtimer(CALLBACK(src, .proc/reboot), 90 / severity)
/obj/item/organ/cyberimp/brain/anti_stun/proc/reboot()
crit_fail = FALSE
organ_flags &= ~ORGAN_FAILING
//[[[[MOUTH]]]]
/obj/item/organ/cyberimp/mouth
zone = BODY_ZONE_PRECISE_MOUTH
/obj/item/organ/cyberimp/mouth/breathing_tube
name = "breathing tube implant"
desc = "This simple implant adds an internals connector to your back, allowing you to use internals without a mask and protecting you from being choked."
icon_state = "implant_mask"
slot = ORGAN_SLOT_BREATHING_TUBE
w_class = WEIGHT_CLASS_TINY
/obj/item/organ/cyberimp/mouth/breathing_tube/emp_act(severity)
. = ..()
if(!owner || . & EMP_PROTECT_SELF)
return
if(prob(60/severity))
to_chat(owner, "<span class='warning'>Your breathing tube suddenly closes!</span>")
owner.losebreath += 2
+149
View File
@@ -0,0 +1,149 @@
#define INFINITE -1
/obj/item/autosurgeon
name = "autosurgeon"
desc = "A device that automatically inserts an implant or organ into the user without the hassle of extensive surgery. It has a slot to insert implants/organs and a screwdriver slot for removing accidentally added items."
icon = 'icons/obj/device.dmi'
icon_state = "autoimplanter"
item_state = "nothing"
w_class = WEIGHT_CLASS_SMALL
var/obj/item/organ/storedorgan
var/organ_type = /obj/item/organ
var/uses = INFINITE
var/starting_organ
/obj/item/autosurgeon/Initialize(mapload)
. = ..()
if(starting_organ)
insert_organ(new starting_organ(src))
/obj/item/autosurgeon/proc/insert_organ(var/obj/item/organ/I)
storedorgan = I
I.forceMove(src)
I.organ_flags |= ORGAN_FROZEN //Stops decay
name = "[initial(name)] ([storedorgan.name])"
/obj/item/autosurgeon/attack_self(mob/user)//when the object it used...
if(!uses)
to_chat(user, "<span class='warning'>[src] has already been used. The tools are dull and won't reactivate.</span>")
return
else if(!storedorgan)
to_chat(user, "<span class='notice'>[src] currently has no implant stored.</span>")
return
storedorgan.Insert(user)//insert stored organ into the user
user.visible_message("<span class='notice'>[user] presses a button on [src], and you hear a short mechanical noise.</span>", "<span class='notice'>You feel a sharp sting as [src] plunges into your body.</span>")
playsound(get_turf(user), 'sound/weapons/circsawhit.ogg', 50, 1)
storedorgan = null
name = initial(name)
if(uses != INFINITE)
uses--
if(!uses)
desc = "[initial(desc)] Looks like it's been used up."
/obj/item/autosurgeon/attack_self_tk(mob/user)
return //stops TK fuckery
/obj/item/autosurgeon/attackby(obj/item/I, mob/user, params)
if(istype(I, organ_type))
if(storedorgan)
to_chat(user, "<span class='notice'>[src] already has an implant stored.</span>")
return
else if(!uses)
to_chat(user, "<span class='notice'>[src] has already been used up.</span>")
return
if(!user.transferItemToLoc(I, src))
return
storedorgan = I
to_chat(user, "<span class='notice'>You insert the [I] into [src].</span>")
else
return ..()
/obj/item/autosurgeon/screwdriver_act(mob/living/user, obj/item/I)
if(..())
return TRUE
if(!storedorgan)
to_chat(user, "<span class='notice'>There's no implant in [src] for you to remove.</span>")
else
var/atom/drop_loc = user.drop_location()
for(var/J in src)
var/atom/movable/AM = J
AM.forceMove(drop_loc)
to_chat(user, "<span class='notice'>You remove the [storedorgan] from [src].</span>")
I.play_tool_sound(src)
storedorgan = null
if(uses != INFINITE)
uses--
if(!uses)
desc = "[initial(desc)] Looks like it's been used up."
return TRUE
/obj/item/autosurgeon/cmo
desc = "A single use autosurgeon that contains a medical heads-up display augment. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
starting_organ = /obj/item/organ/cyberimp/eyes/hud/medical
/obj/item/autosurgeon/gloweyes
desc = "A single use autosurgeon that contains a set of Luminescent Eyes augments. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
starting_organ = /obj/item/organ/eyes/robotic/glow
/obj/item/autosurgeon/thermal_eyes
starting_organ = /obj/item/organ/eyes/robotic/thermals
/obj/item/autosurgeon/xray_eyes
starting_organ = /obj/item/organ/eyes/robotic/xray
/obj/item/autosurgeon/anti_stun
starting_organ = /obj/item/organ/cyberimp/brain/anti_stun
/obj/item/autosurgeon/reviver
starting_organ = /obj/item/organ/cyberimp/chest/reviver
/obj/item/autosurgeon/anti_drop
starting_organ = /obj/item/organ/cyberimp/brain/anti_drop
//BOX O' IMPLANTS
/obj/item/storage/box/cyber_implants
name = "boxed cybernetic implants"
desc = "A sleek, sturdy box."
icon_state = "syndiebox"
illustration = "cyber_implants"
var/list/boxed = list(
/obj/item/autosurgeon/thermal_eyes,
/obj/item/autosurgeon/xray_eyes,
/obj/item/autosurgeon/anti_stun,
/obj/item/autosurgeon/reviver)
var/amount = 5
/obj/item/storage/box/cyber_implants/PopulateContents()
var/implant
while(contents.len <= amount)
implant = pick(boxed)
new implant(src)
/obj/item/autosurgeon/penis
desc = "A single use autosurgeon that contains a penis. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
starting_organ = /obj/item/organ/genital/penis
/obj/item/autosurgeon/testicles
desc = "A single use autosurgeon that contains a set of testicles. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
starting_organ = /obj/item/organ/genital/testicles
/obj/item/autosurgeon/vagina
desc = "A single use autosurgeon that contains a vagina. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
starting_organ = /obj/item/organ/genital/vagina
/obj/item/autosurgeon/breasts
desc = "A single use autosurgeon that contains a set of breasts. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
starting_organ = /obj/item/organ/genital/breasts
/obj/item/autosurgeon/womb
desc = "A single use autosurgeon that contains a womb. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
starting_organ = /obj/item/organ/genital/womb
+376
View File
@@ -0,0 +1,376 @@
/obj/item/organ/eyes
name = BODY_ZONE_PRECISE_EYES
icon_state = "eyeballs"
desc = "I see you!"
zone = BODY_ZONE_PRECISE_EYES
slot = ORGAN_SLOT_EYES
gender = PLURAL
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = STANDARD_ORGAN_DECAY
maxHealth = 0.5 * STANDARD_ORGAN_THRESHOLD //half the normal health max since we go blind at 30, a permanent blindness at 50 therefore makes sense unless medicine is administered
high_threshold = 0.3 * STANDARD_ORGAN_THRESHOLD //threshold at 30
low_threshold = 0.15 * STANDARD_ORGAN_THRESHOLD //threshold at 15
low_threshold_passed = "<span class='info'>Distant objects become somewhat less tangible.</span>"
high_threshold_passed = "<span class='info'>Everything starts to look a lot less clear.</span>"
now_failing = "<span class='warning'>Darkness envelopes you, as your eyes go blind!</span>"
now_fixed = "<span class='info'>Color and shapes are once again perceivable.</span>"
high_threshold_cleared = "<span class='info'>Your vision functions passably once more.</span>"
low_threshold_cleared = "<span class='info'>Your vision is cleared of any ailment.</span>"
var/sight_flags = 0
var/see_in_dark = 2
var/eye_damage = 0
var/tint = 0
var/eye_color = "" //set to a hex code to override a mob's eye color
var/old_eye_color = "fff"
var/flash_protect = 0
var/see_invisible = SEE_INVISIBLE_LIVING
var/lighting_alpha
var/damaged = FALSE //damaged indicates that our eyes are undergoing some level of negative effect
/obj/item/organ/eyes/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = FALSE)
..()
if(damage == initial(damage))
clear_eye_trauma()
if(ishuman(owner))
var/mob/living/carbon/human/HMN = owner
old_eye_color = HMN.eye_color
if(eye_color)
HMN.eye_color = eye_color
HMN.regenerate_icons()
else
eye_color = HMN.eye_color
if(HAS_TRAIT(HMN, TRAIT_NIGHT_VISION) && !lighting_alpha)
lighting_alpha = LIGHTING_PLANE_ALPHA_NV_TRAIT
see_in_dark = 8
M.update_tint()
owner.update_sight()
/obj/item/organ/eyes/Remove(mob/living/carbon/M, special = 0)
clear_eye_trauma()
..()
if(ishuman(M) && eye_color)
var/mob/living/carbon/human/HMN = M
HMN.eye_color = old_eye_color
HMN.regenerate_icons()
M.update_tint()
M.update_sight()
/obj/item/organ/eyes/on_life()
..()
var/mob/living/carbon/C = owner
//since we can repair fully damaged eyes, check if healing has occurred
if((organ_flags & ORGAN_FAILING) && (damage < maxHealth))
organ_flags &= ~ORGAN_FAILING
C.cure_blind(EYE_DAMAGE)
//various degrees of "oh fuck my eyes", from "point a laser at your eye" to "staring at the Sun" intensities
if(damage > 20)
damaged = TRUE
if(organ_flags & ORGAN_FAILING)
C.become_blind(EYE_DAMAGE)
else if(damage > 30)
C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
else
C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
//called once since we don't want to keep clearing the screen of eye damage for people who are below 20 damage
else if(damaged)
damaged = FALSE
C.clear_fullscreen("eye_damage")
return
/obj/item/organ/eyes/proc/clear_eye_trauma()
var/mob/living/carbon/C = owner
C.clear_fullscreen("eye_damage")
C.cure_blind(EYE_DAMAGE)
damaged = FALSE
/obj/item/organ/eyes/night_vision
name = "shadow eyes"
desc = "A spooky set of eyes that can see in the dark."
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
actions_types = list(/datum/action/item_action/organ_action/use)
var/night_vision = TRUE
/obj/item/organ/eyes/night_vision/ui_action_click()
sight_flags = initial(sight_flags)
switch(lighting_alpha)
if (LIGHTING_PLANE_ALPHA_VISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
if (LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
if (LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
else
lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
sight_flags &= ~SEE_BLACKNESS
owner.update_sight()
/obj/item/organ/eyes/night_vision/alien
name = "alien eyes"
desc = "It turned out they had them after all!"
sight_flags = SEE_MOBS
/obj/item/organ/eyes/night_vision/zombie
name = "undead eyes"
desc = "Somewhat counterintuitively, these half-rotten eyes actually have superior vision to those of a living human."
sight_flags = SEE_MOBS
/obj/item/organ/eyes/night_vision/nightmare
name = "burning red eyes"
desc = "Even without their shadowy owner, looking at these eyes gives you a sense of dread."
icon_state = "burning_eyes"
/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."
///Robotic
/obj/item/organ/eyes/robotic
name = "robotic eyes"
icon_state = "cybernetic_eyeballs"
desc = "Your vision is augmented."
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
/obj/item/organ/eyes/robotic/emp_act(severity)
. = ..()
if(!owner || . & EMP_PROTECT_SELF)
return
to_chat(owner, "<span class='warning'>Static obfuscates your vision!</span>")
owner.flash_act(visual = 1)
if(severity == EMP_HEAVY)
owner.adjustOrganLoss(ORGAN_SLOT_EYES, 20)
/obj/item/organ/eyes/robotic/xray
name = "\improper X-ray eyes"
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
eye_color = "000"
see_in_dark = 8
sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
/obj/item/organ/eyes/robotic/thermals
name = "thermal eyes"
desc = "These cybernetic eye implants will give you thermal vision. Vertical slit pupil included."
eye_color = "FC0"
sight_flags = SEE_MOBS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
flash_protect = -1
see_in_dark = 8
/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?"
eye_color ="fee5a3"
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight_eyes"
flash_protect = 2
tint = INFINITY
var/obj/item/flashlight/eyelight/eye
/obj/item/organ/eyes/robotic/flashlight/emp_act(severity)
return
/obj/item/organ/eyes/robotic/flashlight/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = FALSE)
..()
if(!eye)
eye = new /obj/item/flashlight/eyelight()
eye.on = TRUE
eye.forceMove(M)
eye.update_brightness(M)
M.become_blind("flashlight_eyes")
/obj/item/organ/eyes/robotic/flashlight/Remove(var/mob/living/carbon/M, special = FALSE)
eye.on = FALSE
eye.update_brightness(M)
eye.forceMove(src)
M.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."
flash_protect = 2
/obj/item/organ/eyes/robotic/shield/emp_act(severity)
return
#define RGB2EYECOLORSTRING(definitionvar) ("[copytext(definitionvar,2,3)][copytext(definitionvar,4,5)][copytext(definitionvar,6,7)]")
/obj/item/organ/eyes/robotic/glow
name = "High Luminosity Eyes"
desc = "Special glowing eyes, used by snowflakes who want to be special."
eye_color = "000"
actions_types = list(/datum/action/item_action/organ_action/use, /datum/action/item_action/organ_action/toggle)
var/current_color_string = "#ffffff"
var/active = FALSE
var/max_light_beam_distance = 5
var/light_beam_distance = 5
var/light_object_range = 1
var/light_object_power = 2
var/list/obj/effect/abstract/eye_lighting/eye_lighting
var/obj/effect/abstract/eye_lighting/on_mob
var/image/mob_overlay
/obj/item/organ/eyes/robotic/glow/Initialize()
. = ..()
mob_overlay = image('icons/mob/human_face.dmi', "eyes_glow_gs")
/obj/item/organ/eyes/robotic/glow/Destroy()
terminate_effects()
. = ..()
/obj/item/organ/eyes/robotic/glow/Remove(mob/living/carbon/M, special = FALSE)
terminate_effects()
. = ..()
/obj/item/organ/eyes/robotic/glow/proc/terminate_effects()
if(owner && active)
deactivate(TRUE)
active = FALSE
clear_visuals(TRUE)
STOP_PROCESSING(SSfastprocess, src)
/obj/item/organ/eyes/robotic/glow/ui_action_click(owner, action)
if(istype(action, /datum/action/item_action/organ_action/toggle))
toggle_active()
else if(istype(action, /datum/action/item_action/organ_action/use))
prompt_for_controls(owner)
/obj/item/organ/eyes/robotic/glow/proc/toggle_active()
if(active)
deactivate()
else
activate()
/obj/item/organ/eyes/robotic/glow/proc/prompt_for_controls(mob/user)
var/C = input(owner, "Select Color", "Select color", "#ffffff") as color|null
if(!C || QDELETED(src) || QDELETED(user) || QDELETED(owner) || owner != user)
return
var/range = input(user, "Enter range (0 - [max_light_beam_distance])", "Range Select", 0) as null|num
set_distance(CLAMP(range, 0, max_light_beam_distance))
assume_rgb(C)
/obj/item/organ/eyes/robotic/glow/proc/assume_rgb(newcolor)
current_color_string = newcolor
eye_color = RGB2EYECOLORSTRING(current_color_string)
sync_light_effects()
cycle_mob_overlay()
if(!QDELETED(owner) && ishuman(owner)) //Other carbon mobs don't have eye color.
owner.dna.species.handle_body(owner)
/obj/item/organ/eyes/robotic/glow/proc/cycle_mob_overlay()
remove_mob_overlay()
mob_overlay.color = current_color_string
add_mob_overlay()
/obj/item/organ/eyes/robotic/glow/proc/add_mob_overlay()
if(!QDELETED(owner))
owner.add_overlay(mob_overlay)
/obj/item/organ/eyes/robotic/glow/proc/remove_mob_overlay()
if(!QDELETED(owner))
owner.cut_overlay(mob_overlay)
/obj/item/organ/eyes/robotic/glow/emp_act()
. = ..()
if(!active || . & EMP_PROTECT_SELF)
return
deactivate(silent = TRUE)
/obj/item/organ/eyes/robotic/glow/proc/activate(silent = FALSE)
start_visuals()
if(!silent)
to_chat(owner, "<span class='warning'>Your [src] clicks and makes a whining noise, before shooting out a beam of light!</span>")
active = TRUE
RegisterSignal(owner, COMSIG_ATOM_DIR_CHANGE, .proc/update_visuals)
cycle_mob_overlay()
/obj/item/organ/eyes/robotic/glow/proc/deactivate(silent = FALSE)
clear_visuals()
if(!silent)
to_chat(owner, "<span class='warning'>Your [src] shuts off!</span>")
active = FALSE
UnregisterSignal(owner, COMSIG_ATOM_DIR_CHANGE)
remove_mob_overlay()
/obj/item/organ/eyes/robotic/glow/proc/update_visuals(datum/source, olddir, newdir)
if((LAZYLEN(eye_lighting) < light_beam_distance) || !on_mob)
regenerate_light_effects()
var/turf/scanfrom = get_turf(owner)
var/scandir = owner.dir
if (newdir && scandir != newdir) // COMSIG_ATOM_DIR_CHANGE happens before the dir change, but with a reference to the new direction.
scandir = newdir
if(!istype(scanfrom))
clear_visuals()
var/turf/scanning = scanfrom
var/stop = FALSE
on_mob.forceMove(scanning)
for(var/i in 1 to light_beam_distance)
scanning = get_step(scanning, scandir)
if(scanning.opacity || scanning.has_opaque_atom)
stop = TRUE
var/obj/effect/abstract/eye_lighting/L = LAZYACCESS(eye_lighting, i)
if(stop)
L.forceMove(src)
else
L.forceMove(scanning)
/obj/item/organ/eyes/robotic/glow/proc/clear_visuals(delete_everything = FALSE)
if(delete_everything)
QDEL_LIST(eye_lighting)
QDEL_NULL(on_mob)
else
for(var/i in eye_lighting)
var/obj/effect/abstract/eye_lighting/L = i
L.forceMove(src)
if(!QDELETED(on_mob))
on_mob.forceMove(src)
/obj/item/organ/eyes/robotic/glow/proc/start_visuals()
if(!islist(eye_lighting))
regenerate_light_effects()
if((LAZYLEN(eye_lighting) < light_beam_distance) || !on_mob)
regenerate_light_effects()
sync_light_effects()
update_visuals()
/obj/item/organ/eyes/robotic/glow/proc/set_distance(dist)
light_beam_distance = dist
regenerate_light_effects()
/obj/item/organ/eyes/robotic/glow/proc/regenerate_light_effects()
clear_visuals(TRUE)
on_mob = new(src)
for(var/i in 1 to light_beam_distance)
LAZYADD(eye_lighting,new /obj/effect/abstract/eye_lighting(src))
sync_light_effects()
/obj/item/organ/eyes/robotic/glow/proc/sync_light_effects()
for(var/I in eye_lighting)
var/obj/effect/abstract/eye_lighting/L = I
L.set_light(light_object_range, light_object_power, current_color_string)
if(on_mob)
on_mob.set_light(1, 1, current_color_string)
/obj/effect/abstract/eye_lighting
var/obj/item/organ/eyes/robotic/glow/parent
/obj/effect/abstract/eye_lighting/Initialize()
. = ..()
parent = loc
if(!istype(parent))
return INITIALIZE_HINT_QDEL
/obj/item/organ/eyes/insect
name = "insect eyes"
desc = "These eyes seem to have increased sensitivity to bright light, with no improvement to low light vision."
flash_protect = -1
+247
View File
@@ -0,0 +1,247 @@
/obj/item/organ/heart
name = "heart"
desc = "I feel bad for the heartless bastard who lost this."
icon_state = "heart-on"
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_HEART
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = 3 * STANDARD_ORGAN_DECAY //designed to fail about 5 minutes after death
low_threshold_passed = "<span class='info'>Prickles of pain appear then die out from within your chest...</span>"
high_threshold_passed = "<span class='warning'>Something inside your chest hurts, and the pain isn't subsiding. You notice yourself breathing far faster than before.</span>"
now_fixed = "<span class='info'>Your heart begins to beat again.</span>"
high_threshold_cleared = "<span class='info'>The pain in your chest has died down, and your breathing becomes more relaxed.</span>"
// Heart attack code is in code/modules/mob/living/carbon/human/life.dm
var/beating = 1
var/icon_base = "heart"
attack_verb = list("beat", "thumped")
var/beat = BEAT_NONE//is this mob having a heatbeat sound played? if so, which?
var/failed = FALSE //to prevent constantly running failing code
var/operated = FALSE //whether the heart's been operated on to fix some of its damages
/obj/item/organ/heart/update_icon()
if(beating)
icon_state = "[icon_base]-on"
else
icon_state = "[icon_base]-off"
/obj/item/organ/heart/Remove(mob/living/carbon/M, special = 0)
..()
if(!special)
addtimer(CALLBACK(src, .proc/stop_if_unowned), 120)
/obj/item/organ/heart/proc/stop_if_unowned()
if(!owner)
Stop()
/obj/item/organ/heart/attack_self(mob/user)
..()
if(!beating)
user.visible_message("<span class='notice'>[user] squeezes [src] to \
make it beat again!</span>","<span class='notice'>You squeeze [src] to make it beat again!</span>")
Restart()
addtimer(CALLBACK(src, .proc/stop_if_unowned), 80)
/obj/item/organ/heart/proc/Stop()
beating = 0
update_icon()
return 1
/obj/item/organ/heart/proc/Restart()
beating = 1
update_icon()
return 1
/obj/item/organ/heart/prepare_eat()
var/obj/S = ..()
S.icon_state = "[icon_base]-off"
return S
/obj/item/organ/heart/on_life()
..()
if(owner.client && beating)
failed = FALSE
var/sound/slowbeat = sound('sound/health/slowbeat.ogg', repeat = TRUE)
var/sound/fastbeat = sound('sound/health/fastbeat.ogg', repeat = TRUE)
var/mob/living/carbon/H = owner
if(H.health <= H.crit_threshold && beat != BEAT_SLOW)
beat = BEAT_SLOW
H.playsound_local(get_turf(H), slowbeat,40,0, channel = CHANNEL_HEARTBEAT)
to_chat(owner, "<span class = 'notice'>You feel your heart slow down...</span>")
if(beat == BEAT_SLOW && H.health > H.crit_threshold)
H.stop_sound_channel(CHANNEL_HEARTBEAT)
beat = BEAT_NONE
if(H.jitteriness)
if(H.health > HEALTH_THRESHOLD_FULLCRIT && (!beat || beat == BEAT_SLOW))
H.playsound_local(get_turf(H),fastbeat,40,0, channel = CHANNEL_HEARTBEAT)
beat = BEAT_FAST
else if(beat == BEAT_FAST)
H.stop_sound_channel(CHANNEL_HEARTBEAT)
beat = BEAT_NONE
if(organ_flags & ORGAN_FAILING) //heart broke, stopped beating, death imminent
if(owner.stat == CONSCIOUS)
owner.visible_message("<span class='userdanger'>[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!</span>")
owner.set_heartattack(TRUE)
failed = TRUE
obj/item/organ/heart/slime
name = "slime heart"
desc = "It seems we've gotten to the slimy core of the matter."
icon_state = "heart-s-on"
icon_base = "heart-s"
/obj/item/organ/heart/cursed
name = "cursed heart"
desc = "A heart that, when inserted, will force you to pump it manually."
icon_state = "cursedheart-off"
icon_base = "cursedheart"
decay_factor = 0
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
var/last_pump = 0
var/add_colour = TRUE //So we're not constantly recreating colour datums
var/pump_delay = 30 //you can pump 1 second early, for lag, but no more (otherwise you could spam heal)
var/blood_loss = 100 //600 blood is human default, so 5 failures (below 122 blood is where humans die because reasons?)
//How much to heal per pump, negative numbers would HURT the player
var/heal_brute = 0
var/heal_burn = 0
var/heal_oxy = 0
/obj/item/organ/heart/cursed/attack(mob/living/carbon/human/H, mob/living/carbon/human/user, obj/target)
if(H == user && istype(H))
playsound(user,'sound/effects/singlebeat.ogg',40,1)
user.temporarilyRemoveItemFromInventory(src, TRUE)
Insert(user)
else
return ..()
/obj/item/organ/heart/cursed/on_life()
if(world.time > (last_pump + pump_delay))
if(ishuman(owner) && owner.client) //While this entire item exists to make people suffer, they can't control disconnects.
var/mob/living/carbon/human/H = owner
if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
H.blood_volume = max(H.blood_volume - blood_loss, 0)
to_chat(H, "<span class = 'userdanger'>You have to keep pumping your blood!</span>")
if(add_colour)
H.add_client_colour(/datum/client_colour/cursed_heart_blood) //bloody screen so real
add_colour = FALSE
else
last_pump = world.time //lets be extra fair *sigh*
/obj/item/organ/heart/cursed/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
if(owner)
to_chat(owner, "<span class ='userdanger'>Your heart has been replaced with a cursed one, you have to pump this one manually otherwise you'll die!</span>")
/obj/item/organ/heart/cursed/Remove(mob/living/carbon/M, special = 0)
..()
M.remove_client_colour(/datum/client_colour/cursed_heart_blood)
/datum/action/item_action/organ_action/cursed_heart
name = "Pump your blood"
//You are now brea- pumping blood manually
/datum/action/item_action/organ_action/cursed_heart/Trigger()
. = ..()
if(. && istype(target, /obj/item/organ/heart/cursed))
var/obj/item/organ/heart/cursed/cursed_heart = target
if(world.time < (cursed_heart.last_pump + (cursed_heart.pump_delay-10))) //no spam
to_chat(owner, "<span class='userdanger'>Too soon!</span>")
return
cursed_heart.last_pump = world.time
playsound(owner,'sound/effects/singlebeat.ogg',40,1)
to_chat(owner, "<span class = 'notice'>Your heart beats.</span>")
var/mob/living/carbon/human/H = owner
if(istype(H))
if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_MAXIMUM)
H.remove_client_colour(/datum/client_colour/cursed_heart_blood)
cursed_heart.add_colour = TRUE
H.adjustBruteLoss(-cursed_heart.heal_brute)
H.adjustFireLoss(-cursed_heart.heal_burn)
H.adjustOxyLoss(-cursed_heart.heal_oxy)
/datum/client_colour/cursed_heart_blood
priority = 100 //it's an indicator you're dieing, so it's very high priority
colour = "red"
/obj/item/organ/heart/cybernetic
name = "cybernetic heart"
desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make."
icon_state = "heart-c"
organ_flags = ORGAN_SYNTHETIC
/obj/item/organ/heart/cybernetic/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
Stop()
addtimer(CALLBACK(src, .proc/Restart), 20/severity SECONDS)
damage += 100/severity
/obj/item/organ/heart/cybernetic/upgraded
name = "upgraded cybernetic heart"
desc = "An electronic device designed to mimic the functions of an organic human heart. Also holds an emergency dose of epinephrine, used automatically after facing severe trauma. This upgraded model can regenerate its dose after use."
icon_state = "heart-c-u"
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
//I put it on upgraded for now.
var/dose_available = TRUE
var/rid = /datum/reagent/medicine/epinephrine
var/ramount = 10
obj/item/organ/heart/cybernetic/upgraded/on_life()
. = ..()
if(dose_available && owner.health <= owner.crit_threshold && !owner.reagents.has_reagent(rid))
owner.reagents.add_reagent(rid, ramount)
used_dose()
if(ramount < 10) //eats your nutrition to regen epinephrine
var/regen_amount = owner.nutrition/2000
owner.nutrition -= regen_amount
ramount += regen_amount
/obj/item/organ/heart/cybernetic/upgraded/proc/used_dose()
. = ..()
addtimer(VARSET_CALLBACK(src, dose_available, TRUE), 5 MINUTES)
ramount = 0
/obj/item/organ/heart/ipc
name = "IPC heart"
desc = "An electronic pump that regulates hydraulic functions, they have an auto-restart after EMPs."
icon_state = "heart-c"
organ_flags = ORGAN_SYNTHETIC
/obj/item/organ/heart/ipc/emp_act()
. = ..()
if(. & EMP_PROTECT_SELF)
return
Stop()
addtimer(CALLBACK(src, .proc/Restart), 10)
/obj/item/organ/heart/freedom
name = "heart of freedom"
desc = "This heart pumps with the passion to give... something freedom."
organ_flags = ORGAN_SYNTHETIC //the power of freedom prevents heart attacks
var/min_next_adrenaline = 0
/obj/item/organ/heart/freedom/on_life()
. = ..()
if(owner.health < 5 && world.time > min_next_adrenaline)
min_next_adrenaline = world.time + rand(250, 600) //anywhere from 4.5 to 10 minutes
to_chat(owner, "<span class='userdanger'>You feel yourself dying, but you refuse to give up!</span>")
owner.heal_overall_damage(15, 15)
if(owner.reagents.get_reagent_amount("ephedrine") < 20)
owner.reagents.add_reagent("ephedrine", 10)
@@ -0,0 +1,367 @@
#define STANDARD_ORGAN_THRESHOLD 100
#define STANDARD_ORGAN_HEALING 0.001
/obj/item/organ
name = "organ"
icon = 'icons/obj/surgery.dmi'
var/mob/living/carbon/owner = null
var/status = ORGAN_ORGANIC
w_class = WEIGHT_CLASS_SMALL
throwforce = 0
var/zone = BODY_ZONE_CHEST
var/slot
// DO NOT add slots with matching names to different zones - it will break internal_organs_slot list!
var/organ_flags = 0
var/maxHealth = STANDARD_ORGAN_THRESHOLD
var/damage = 0 //total damage this organ has sustained
///Healing factor and decay factor function on % of maxhealth, and do not work by applying a static number per tick
var/healing_factor = 0 //fraction of maxhealth healed per on_life(), set to 0 for generic organs
var/decay_factor = 0 //same as above but when without a living owner, set to 0 for generic organs
var/high_threshold = STANDARD_ORGAN_THRESHOLD * 0.45 //when severe organ damage occurs
var/low_threshold = STANDARD_ORGAN_THRESHOLD * 0.1 //when minor organ damage occurs
///Organ variables for determining what we alert the owner with when they pass/clear the damage thresholds
var/prev_damage = 0
var/low_threshold_passed
var/high_threshold_passed
var/now_failing
var/now_fixed
var/high_threshold_cleared
var/low_threshold_cleared
/obj/item/organ/proc/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
if(!iscarbon(M) || owner == M)
return FALSE
var/obj/item/organ/replaced = M.getorganslot(slot)
if(replaced)
replaced.Remove(M, special = 1)
if(drop_if_replaced)
replaced.forceMove(get_turf(M))
else
qdel(replaced)
//Hopefully this doesn't cause problems
organ_flags &= ~ORGAN_FROZEN
owner = M
M.internal_organs |= src
M.internal_organs_slot[slot] = src
moveToNullspace()
for(var/X in actions)
var/datum/action/A = X
A.Grant(M)
STOP_PROCESSING(SSobj, src)
return TRUE
//Special is for instant replacement like autosurgeons
/obj/item/organ/proc/Remove(mob/living/carbon/M, special = FALSE)
owner = null
if(M)
M.internal_organs -= src
if(M.internal_organs_slot[slot] == src)
M.internal_organs_slot.Remove(slot)
if((organ_flags & ORGAN_VITAL) && !special && !(M.status_flags & GODMODE))
M.death()
for(var/X in actions)
var/datum/action/A = X
A.Remove(M)
START_PROCESSING(SSobj, src)
return TRUE
/obj/item/organ/proc/on_find(mob/living/finder)
return
/obj/item/organ/process() //runs decay when outside of a person AND ONLY WHEN OUTSIDE (i.e. long obj).
on_death() //Kinda hate doing it like this, but I really don't want to call process directly.
//Sources; life.dm process_organs
/obj/item/organ/proc/on_death() //Runs when outside AND inside.
decay()
//Applys the slow damage over time decay
/obj/item/organ/proc/decay()
if(!can_decay())
STOP_PROCESSING(SSobj, src)
return
is_cold()
if(organ_flags & ORGAN_FROZEN)
return
applyOrganDamage(maxHealth * decay_factor)
/obj/item/organ/proc/can_decay()
if(CHECK_BITFIELD(organ_flags, ORGAN_NO_SPOIL | ORGAN_SYNTHETIC | ORGAN_FAILING))
return FALSE
return TRUE
//Checks to see if the organ is frozen from temperature
/obj/item/organ/proc/is_cold()
var/freezing_objects = list(/obj/structure/closet/crate/freezer, /obj/structure/closet/secure_closet/freezer, /obj/structure/bodycontainer, /obj/item/autosurgeon)
if(istype(loc, /obj/))//Freezer of some kind, I hope.
if(is_type_in_list(loc, freezing_objects))
if(!(organ_flags & ORGAN_FROZEN))//Incase someone puts them in when cold, but they warm up inside of the thing. (i.e. they have the flag, the thing turns it off, this rights it.)
organ_flags |= ORGAN_FROZEN
return TRUE
return
var/local_temp
if(istype(loc, /turf/))//Only concern is adding an organ to a freezer when the area around it is cold.
var/turf/T = loc
var/datum/gas_mixture/enviro = T.return_air()
local_temp = enviro.temperature
else if(istype(loc, /mob/) && !owner)
var/mob/M = loc
if(is_type_in_list(M.loc, freezing_objects))
if(!(organ_flags & ORGAN_FROZEN))
organ_flags |= ORGAN_FROZEN
return TRUE
var/turf/T = M.loc
var/datum/gas_mixture/enviro = T.return_air()
local_temp = enviro.temperature
if(owner)
//Don't interfere with bodies frozen by structures.
if(is_type_in_list(owner.loc, freezing_objects))
if(!(organ_flags & ORGAN_FROZEN))
organ_flags |= ORGAN_FROZEN
return TRUE
local_temp = owner.bodytemperature
if(!local_temp)//Shouldn't happen but in case
return
if(local_temp < 154)//I have a pretty shaky citation that states -120 allows indefinite cyrostorage
organ_flags |= ORGAN_FROZEN
return TRUE
organ_flags &= ~ORGAN_FROZEN
return FALSE
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing
if(organ_flags & ORGAN_FAILING)
return
if(is_cold())
return
///Damage decrements by a percent of its maxhealth
var/healing_amount = -(maxHealth * healing_factor)
///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's health
healing_amount -= owner.satiety > 0 ? 4 * healing_factor * owner.satiety / MAX_SATIETY : 0
applyOrganDamage(healing_amount) //to FERMI_TWEAK
//Make it so each threshold is stuck.
/obj/item/organ/examine(mob/user)
. = ..()
if(organ_flags & ORGAN_FAILING)
if(status == ORGAN_ROBOTIC)
. += "<span class='warning'>[src] seems to be broken!</span>"
return
. += "<span class='warning'>[src] has decayed for too long, and has turned a sickly color! It doesn't look like it will work anymore!</span>"
return
if(damage > high_threshold)
. += "<span class='warning'>[src] is starting to look discolored.</span>"
/obj/item/organ/proc/prepare_eat()
var/obj/item/reagent_containers/food/snacks/organ/S = new
S.name = name
S.desc = desc
S.icon = icon
S.icon_state = icon_state
S.w_class = w_class
return S
/obj/item/reagent_containers/food/snacks/organ
name = "appendix"
icon_state = "appendix"
icon = 'icons/obj/surgery.dmi'
list_reagents = list("nutriment" = 5)
foodtype = RAW | MEAT | GROSS
/obj/item/organ/Initialize()
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/organ/Destroy()
if(owner)
// The special flag is important, because otherwise mobs can die
// while undergoing transformation into different mobs.
Remove(owner, TRUE)
return ..()
/obj/item/organ/attack(mob/living/carbon/M, mob/user)
if(M == user && ishuman(user))
var/mob/living/carbon/human/H = user
if(status == ORGAN_ORGANIC)
var/obj/item/reagent_containers/food/snacks/S = prepare_eat()
if(S)
qdel(src)
if(H.put_in_active_hand(S))
S.attack(H, H)
else
..()
/obj/item/organ/item_action_slot_check(slot,mob/user)
return //so we don't grant the organ's action to mobs who pick up the organ.
///Adjusts an organ's damage by the amount "d", up to a maximum amount, which is by default max damage
/obj/item/organ/proc/applyOrganDamage(var/d, var/maximum = maxHealth) //use for damaging effects
if(!d) //Micro-optimization.
return
if(maximum < damage)
return
damage = CLAMP(damage + d, 0, maximum)
var/mess = check_damage_thresholds(owner)
prev_damage = damage
if(mess && owner)
to_chat(owner, mess)
///SETS an organ's damage to the amount "d", and in doing so clears or sets the failing flag, good for when you have an effect that should fix an organ if broken
/obj/item/organ/proc/setOrganDamage(var/d) //use mostly for admin heals
applyOrganDamage(d - damage)
/** check_damage_thresholds
* input: M (a mob, the owner of the organ we call the proc on)
* output: returns a message should get displayed.
* 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(var/M)
if(damage == prev_damage)
return
var/delta = damage - prev_damage
if(delta > 0)
if(damage >= maxHealth)
organ_flags |= ORGAN_FAILING
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
organ_flags &= ~ORGAN_FAILING
if(!owner)//Processing is stopped when the organ is dead and outside of someone. This hopefully should restart it if a removed organ is repaired outside of a body.
START_PROCESSING(SSobj, src)
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
//Runs some code on the organ when damage is taken/healed
/obj/item/organ/proc/onDamage(var/d, var/maximum = maxHealth)
return
//Runs some code on the organ when damage is taken/healed
/obj/item/organ/proc/onSetDamage(var/d, var/maximum = maxHealth)
return
//Looking for brains?
//Try code/modules/mob/living/carbon/brain/brain_item.dm
/mob/living/proc/regenerate_organs()
return 0
/mob/living/carbon/regenerate_organs(only_one = FALSE)
var/breathes = TRUE
var/blooded = TRUE
if(dna && dna.species)
if(HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT))
breathes = FALSE
if(NOBLOOD in dna.species.species_traits)
blooded = FALSE
var/has_liver = (!(NOLIVER in dna.species.species_traits))
var/has_stomach = (!(NOSTOMACH in dna.species.species_traits))
if(has_liver && !getorganslot(ORGAN_SLOT_LIVER))
var/obj/item/organ/liver/LI
if(dna.species.mutantliver)
LI = new dna.species.mutantliver()
else
LI = new()
LI.Insert(src)
if(only_one)
return TRUE
if(has_stomach && !getorganslot(ORGAN_SLOT_STOMACH))
var/obj/item/organ/stomach/S
if(dna.species.mutantstomach)
S = new dna.species.mutantstomach()
else
S = new()
S.Insert(src)
if(only_one)
return TRUE
if(breathes && !getorganslot(ORGAN_SLOT_LUNGS))
var/obj/item/organ/lungs/L = new()
L.Insert(src)
if(only_one)
return TRUE
if(blooded && !getorganslot(ORGAN_SLOT_HEART))
var/obj/item/organ/heart/H = new()
H.Insert(src)
if(only_one)
return TRUE
if(!getorganslot(ORGAN_SLOT_TONGUE))
var/obj/item/organ/tongue/T
if(dna && dna.species && dna.species.mutanttongue)
T = new dna.species.mutanttongue()
else
T = new()
// if they have no mutant tongues, give them a regular one
T.Insert(src)
if(only_one)
return TRUE
else if (!only_one)
var/obj/item/organ/tongue/oT = getorganslot(ORGAN_SLOT_TONGUE)
if(oT.name == "fluffy tongue")
var/obj/item/organ/tongue/T
if(dna && dna.species && dna.species.mutanttongue)
T = new dna.species.mutanttongue()
else
T = new()
oT.Remove(src)
qdel(oT)
T.Insert(src)
if(!getorganslot(ORGAN_SLOT_EYES))
var/obj/item/organ/eyes/E
if(dna && dna.species && dna.species.mutanteyes)
E = new dna.species.mutanteyes()
else
E = new()
E.Insert(src)
if(only_one)
return TRUE
if(!getorganslot(ORGAN_SLOT_EARS))
var/obj/item/organ/ears/ears
if(dna && dna.species && dna.species.mutantears)
ears = new dna.species.mutantears
else
ears = new
ears.Insert(src)
if(only_one)
return TRUE
if(!getorganslot(ORGAN_SLOT_TAIL))
var/obj/item/organ/tail/tail
if(dna && dna.species && dna.species.mutanttail)
tail = new dna.species.mutanttail
tail.Insert(src)
if(only_one)
return TRUE
+293
View File
@@ -0,0 +1,293 @@
#define TONGUE_MAX_HEALTH 60
/obj/item/organ/tongue
name = "tongue"
desc = "A fleshy muscle mostly used for lying."
icon_state = "tonguenormal"
zone = BODY_ZONE_PRECISE_MOUTH
slot = ORGAN_SLOT_TONGUE
attack_verb = list("licked", "slobbered", "slapped", "frenched", "tongued")
var/list/languages_possible
var/say_mod = null
var/taste_sensitivity = 15 // lower is more sensitive.
maxHealth = TONGUE_MAX_HEALTH
var/modifies_speech = FALSE
var/static/list/languages_possible_base = typecacheof(list(
/datum/language/common,
/datum/language/draconic,
/datum/language/codespeak,
/datum/language/monkey,
/datum/language/narsie,
/datum/language/beachbum,
/datum/language/ratvar,
/datum/language/aphasia,
/datum/language/slime,
))
healing_factor = STANDARD_ORGAN_HEALING*5 //Fast!!
decay_factor = STANDARD_ORGAN_DECAY/2
/obj/item/organ/tongue/Initialize(mapload)
. = ..()
languages_possible = languages_possible_base
/obj/item/organ/tongue/proc/handle_speech(datum/source, list/speech_args)
/obj/item/organ/tongue/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
if(organ_flags & ORGAN_SYNTHETIC)
var/errormessage = list("Runtime in tongue.dm, line 39: Undefined operation \"zapzap ow my tongue\"", "afhsjifksahgjkaslfhashfjsak", "-1.#IND", "Graham's number", "inside you all along", "awaiting at least 1 approving review before merging this taste request")
owner.say("The pH is appropriately [pick(errormessage)].")
/obj/item/organ/tongue/applyOrganDamage(var/d, var/maximum = maxHealth)
if(!d) //Micro-optimization.
return
if(maximum < damage)
return
damage = CLAMP(damage + d, 0, maximum)
var/mess = check_damage_thresholds(owner)
prev_damage = damage
if(mess && owner)
to_chat(owner, mess)
if ((damage / maxHealth) > 1)
to_chat(owner, "<span class='userdanger'>Your tongue is singed beyond recognition, and disintegrates!</span>")
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Tongues lost to Fermi")
qdel(src)
else if ((damage / maxHealth) > 0.85)
to_chat(owner, "<span class='warning'>Your tongue feels like it's about to fall out!.</span>")
else if ((damage / maxHealth) > 0.5)
to_chat(owner, "<span class='notice'>Your tongue is really starting to hurt.</span>")
/obj/item/organ/tongue/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
if(say_mod && M.dna && M.dna.species)
M.dna.species.say_mod = say_mod
if (modifies_speech)
RegisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech)
M.UnregisterSignal(M, COMSIG_MOB_SAY)
/obj/item/organ/tongue/Remove(mob/living/carbon/M, special = 0)
..()
if(say_mod && M.dna && M.dna.species)
M.dna.species.say_mod = initial(M.dna.species.say_mod)
UnregisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech)
M.RegisterSignal(M, COMSIG_MOB_SAY, /mob/living/carbon/.proc/handle_tongueless_speech)
/obj/item/organ/tongue/could_speak_in_language(datum/language/dt)
return is_type_in_typecache(dt, languages_possible)
/obj/item/organ/tongue/lizard
name = "forked tongue"
desc = "A thin and long muscle typically found in reptilian races, apparently moonlights as a nose."
icon_state = "tonguelizard"
say_mod = "hisses"
taste_sensitivity = 10 // combined nose + tongue, extra sensitive
maxHealth = 40 //extra sensitivity means tongue is more susceptible to damage
modifies_speech = TRUE
/obj/item/organ/tongue/lizard/handle_speech(datum/source, list/speech_args)
var/static/regex/lizard_hiss = new("s+", "g")
var/static/regex/lizard_hiSS = new("S+", "g")
var/message = speech_args[SPEECH_MESSAGE]
if(message[1] != "*")
message = lizard_hiss.Replace(message, "sss")
message = lizard_hiSS.Replace(message, "SSS")
speech_args[SPEECH_MESSAGE] = message
/obj/item/organ/tongue/fly
name = "proboscis"
desc = "A freakish looking meat tube that apparently can take in liquids."
icon_state = "tonguefly"
say_mod = "buzzes"
taste_sensitivity = 25 // you eat vomit, this is a mercy
maxHealth = 80 //years of eatting trash has made your tongue strong
modifies_speech = TRUE
/obj/item/organ/tongue/fly/handle_speech(datum/source, list/speech_args)
var/static/regex/fly_buzz = new("z+", "g")
var/static/regex/fly_buZZ = new("Z+", "g")
var/message = speech_args[SPEECH_MESSAGE]
if(message[1] != "*")
message = fly_buzz.Replace(message, "zzz")
message = fly_buZZ.Replace(message, "ZZZ")
speech_args[SPEECH_MESSAGE] = message
/obj/item/organ/tongue/abductor
name = "superlingual matrix"
desc = "A mysterious structure that allows for instant communication between users. Pretty impressive until you need to eat something."
icon_state = "tongueayylmao"
say_mod = "gibbers"
taste_sensitivity = 101 // ayys cannot taste anything.
maxHealth = 120 //Ayys probe a lot
modifies_speech = TRUE
/obj/item/organ/tongue/abductor/handle_speech(datum/source, list/speech_args)
//Hacks
var/message = speech_args[SPEECH_MESSAGE]
var/mob/living/carbon/human/user = usr
var/rendered = "<span class='abductor'><b>[user.name]:</b> [message]</span>"
user.log_talk(message, LOG_SAY, tag="abductor")
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
var/obj/item/organ/tongue/T = H.getorganslot(ORGAN_SLOT_TONGUE)
if(!T || T.type != type)
continue
if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor")
var/datum/antagonist/abductor/A = user.mind.has_antag_datum(/datum/antagonist/abductor)
if(!A || !(H.mind in A.team.members))
continue
to_chat(H, rendered)
for(var/mob/M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, user)
to_chat(M, "[link] [rendered]")
speech_args[SPEECH_MESSAGE] = ""
/obj/item/organ/tongue/zombie
name = "rotting tongue"
desc = "Between the decay and the fact that it's just lying there you doubt a tongue has ever seemed less sexy."
icon_state = "tonguezombie"
say_mod = "moans"
taste_sensitivity = 32
maxHealth = 65 //Stop! It's already dead...!
modifies_speech = TRUE
/obj/item/organ/tongue/zombie/handle_speech(datum/source, list/speech_args)
var/list/message_list = splittext(speech_args[SPEECH_MESSAGE], " ")
var/maxchanges = max(round(message_list.len / 1.5), 2)
for(var/i = rand(maxchanges / 2, maxchanges), i > 0, i--)
var/insertpos = rand(1, message_list.len - 1)
var/inserttext = message_list[insertpos]
if(!(copytext(inserttext, length(inserttext) - 2) == "..."))
message_list[insertpos] = inserttext + "..."
if(prob(20) && message_list.len > 3)
message_list.Insert(insertpos, "[pick("BRAINS", "Brains", "Braaaiinnnsss", "BRAAAIIINNSSS")]...")
speech_args[SPEECH_MESSAGE] = jointext(message_list, " ")
/obj/item/organ/tongue/alien
name = "alien tongue"
desc = "According to leading xenobiologists the evolutionary benefit of having a second mouth in your mouth is \"that it looks badass\"."
icon_state = "tonguexeno"
say_mod = "hisses"
taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED
maxHealth = 500 //They've a little mouth for a tongue, so it's pretty rhobust
modifies_speech = TRUE // not really, they just hiss
var/static/list/languages_possible_alien = typecacheof(list(
/datum/language/xenocommon,
/datum/language/common,
/datum/language/draconic,
/datum/language/ratvar,
/datum/language/monkey))
/obj/item/organ/tongue/alien/Initialize(mapload)
. = ..()
languages_possible = languages_possible_alien
/obj/item/organ/tongue/alien/handle_speech(datum/source, list/speech_args)
playsound(owner, "hiss", 25, 1, 1)
/obj/item/organ/tongue/bone
name = "bone \"tongue\""
desc = "Apparently skeletons alter the sounds they produce through oscillation of their teeth, hence their characteristic rattling."
icon_state = "tonguebone"
say_mod = "rattles"
organ_flags = ORGAN_NO_SPOIL
attack_verb = list("bitten", "chattered", "chomped", "enamelled", "boned")
taste_sensitivity = 101 // skeletons cannot taste anything
maxHealth = 75 //Take brute damage instead
modifies_speech = TRUE
var/chattering = FALSE
var/phomeme_type = "sans"
var/list/phomeme_types = list("sans", "papyrus")
/obj/item/organ/tongue/bone/Initialize()
. = ..()
phomeme_type = pick(phomeme_types)
/obj/item/organ/tongue/bone/applyOrganDamage(var/d, var/maximum = maxHealth)
if(d < 0)
return
if(!owner)
return
var/target = owner.get_bodypart(BODY_ZONE_HEAD)
owner.apply_damage(d, BURN, target)
to_chat(owner, "<span class='userdanger'>You feel your skull burning! Oof, your bones!</span>")
return
/obj/item/organ/tongue/bone/handle_speech(datum/source, list/speech_args)
if (chattering)
chatter(speech_args[SPEECH_MESSAGE], phomeme_type, source)
switch(phomeme_type)
if("sans")
speech_args[SPEECH_SPANS] |= SPAN_SANS
if("papyrus")
speech_args[SPEECH_SPANS] |= SPAN_PAPYRUS
/obj/item/organ/tongue/bone/plasmaman
name = "plasma bone \"tongue\""
desc = "Like animated skeletons, Plasmamen vibrate their teeth in order to produce speech."
icon_state = "tongueplasma"
modifies_speech = FALSE
/obj/item/organ/tongue/robot
name = "robotic voicebox"
desc = "A voice synthesizer that can interface with organic lifeforms."
status = ORGAN_ROBOTIC
icon_state = "tonguerobot"
say_mod = "states"
attack_verb = list("beeped", "booped")
modifies_speech = TRUE
taste_sensitivity = 25 // not as good as an organic tongue
maxHealth = 100 //RoboTongue!
var/electronics_magic = TRUE
/obj/item/organ/tongue/robot/can_speak_in_language(datum/language/dt)
return ..() || electronics_magic
/obj/item/organ/tongue/robot/handle_speech(datum/source, list/speech_args)
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
/obj/item/organ/tongue/fluffy
name = "fluffy tongue"
desc = "OwO what's this?"
icon_state = "tonguefluffy"
taste_sensitivity = 10 // extra sensitive and inquisitive uwu
maxHealth = 35 //Sensitive tongue!
modifies_speech = TRUE
/obj/item/organ/tongue/fluffy/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(copytext(message, 1, 2) != "*")
message = replacetext(message, "ne", "nye")
message = replacetext(message, "nu", "nyu")
message = replacetext(message, "na", "nya")
message = replacetext(message, "no", "nyo")
message = replacetext(message, "ove", "uv")
message = replacetext(message, "l", "w")
message = replacetext(message, "r", "w")
message = lowertext(message)
speech_args[SPEECH_MESSAGE] = message
/obj/item/organ/tongue/cybernetic
name = "cybernetic tongue"
desc = "A state of the art robotic tongue that can detect the pH of anything drank."
icon_state = "tonguecybernetic"
taste_sensitivity = 10
maxHealth = 60 //It's robotic!
organ_flags = ORGAN_SYNTHETIC
/obj/item/organ/tongue/cybernetic/handle_speech(datum/source, list/speech_args)
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
/obj/item/organ/tongue/robot/ipc
name = "positronic voicebox"
say_mod = "beeps"
desc = "A voice synthesizer used by IPCs to smoothly interface with organic lifeforms."
electronics_magic = FALSE
organ_flags = ORGAN_SYNTHETIC
File diff suppressed because it is too large Load Diff