mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-29 06:57:42 +01:00
Merge branch 'master' of https://github.com/ParadiseSS13/Paradise into HereWeGoAgain
This commit is contained in:
@@ -33,7 +33,7 @@
|
||||
..()
|
||||
to_chat(user, "<span class='info'>[src] is assembled in the [parent_organ == "r_arm" ? "right" : "left"] arm configuration. You can use a screwdriver to reassemble it.</span>")
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/attackby(obj/item/weapon/W, mob/user, params)
|
||||
/obj/item/organ/internal/cyberimp/arm/attackby(obj/item/W, mob/user, params)
|
||||
..()
|
||||
if(isscrewdriver(W))
|
||||
if(parent_organ == "r_arm")
|
||||
@@ -43,7 +43,7 @@
|
||||
slot = parent_organ + "_device"
|
||||
to_chat(user, "<span class='notice'>You modify [src] to be installed on the [parent_organ == "r_arm" ? "right" : "left"] arm.</span>")
|
||||
update_icon()
|
||||
else if(istype(W, /obj/item/weapon/card/emag))
|
||||
else if(istype(W, /obj/item/card/emag))
|
||||
emag_act()
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/remove(mob/living/carbon/M, special = 0)
|
||||
@@ -66,12 +66,12 @@
|
||||
if(!holder || (holder in src))
|
||||
return
|
||||
|
||||
owner.visible_message("<span class='notice'>[owner] retracts [holder] back into \his [parent_organ == "r_arm" ? "right" : "left"] arm.</span>",
|
||||
owner.visible_message("<span class='notice'>[owner] retracts [holder] back into [owner.p_their()] [parent_organ == "r_arm" ? "right" : "left"] arm.</span>",
|
||||
"<span class='notice'>[holder] snaps back into your [parent_organ == "r_arm" ? "right" : "left"] arm.</span>",
|
||||
"<span class='italics'>You hear a short mechanical noise.</span>")
|
||||
|
||||
if(istype(holder, /obj/item/device/flash/armimplant))
|
||||
var/obj/item/device/flash/F = holder
|
||||
if(istype(holder, /obj/item/flash/armimplant))
|
||||
var/obj/item/flash/F = holder
|
||||
F.set_light(0)
|
||||
|
||||
owner.unEquip(holder, 1)
|
||||
@@ -92,8 +92,8 @@
|
||||
holder.w_class = WEIGHT_CLASS_HUGE
|
||||
holder.materials = null
|
||||
|
||||
if(istype(holder, /obj/item/device/flash/armimplant))
|
||||
var/obj/item/device/flash/F = holder
|
||||
if(istype(holder, /obj/item/flash/armimplant))
|
||||
var/obj/item/flash/F = holder
|
||||
F.set_light(7)
|
||||
|
||||
var/arm_slot = (parent_organ == "r_arm" ? slot_r_hand : slot_l_hand)
|
||||
@@ -114,7 +114,7 @@
|
||||
if(parent_organ == "r_arm" ? owner.hand : !owner.hand)
|
||||
owner.swap_hand()
|
||||
|
||||
owner.visible_message("<span class='notice'>[owner] extends [holder] from \his [parent_organ == "r_arm" ? "right" : "left"] arm.</span>",
|
||||
owner.visible_message("<span class='notice'>[owner] extends [holder] from [owner.p_their()] [parent_organ == "r_arm" ? "right" : "left"] arm.</span>",
|
||||
"<span class='notice'>You extend [holder] from your [parent_organ == "r_arm" ? "right" : "left"] arm.</span>",
|
||||
"<span class='italics'>You hear a short mechanical noise.</span>")
|
||||
playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
@@ -126,7 +126,7 @@
|
||||
|
||||
// You can emag the arm-mounted implant by activating it while holding emag in it's hand.
|
||||
var/arm_slot = (parent_organ == "r_arm" ? slot_r_hand : slot_l_hand)
|
||||
if(istype(owner.get_item_by_slot(arm_slot), /obj/item/weapon/card/emag) && emag_act())
|
||||
if(istype(owner.get_item_by_slot(arm_slot), /obj/item/card/emag) && emag_act())
|
||||
return
|
||||
|
||||
if(!holder || (holder in src))
|
||||
@@ -163,7 +163,7 @@
|
||||
desc = "A variant of the arm cannon implant that fires lethal laser beams. The cannon emerges from the subject's arm and remains inside when not in use."
|
||||
icon_state = "arm_laser"
|
||||
origin_tech = "materials=4;combat=4;biotech=4;powerstorage=4;syndicate=3"
|
||||
contents = newlist(/obj/item/weapon/gun/energy/laser/mounted)
|
||||
contents = newlist(/obj/item/gun/energy/laser/mounted)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/gun/laser/l
|
||||
parent_organ = "l_arm"
|
||||
@@ -174,7 +174,7 @@
|
||||
desc = "A variant of the arm cannon implant that fires electrodes and disabler shots. The cannon emerges from the subject's arm and remains inside when not in use."
|
||||
icon_state = "arm_taser"
|
||||
origin_tech = "materials=5;combat=5;biotech=4;powerstorage=4"
|
||||
contents = newlist(/obj/item/weapon/gun/energy/gun/advtaser/mounted)
|
||||
contents = newlist(/obj/item/gun/energy/gun/advtaser/mounted)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/gun/taser/l
|
||||
parent_organ = "l_arm"
|
||||
@@ -184,41 +184,41 @@
|
||||
name = "integrated toolset implant"
|
||||
desc = "A stripped-down version of engineering cyborg toolset, designed to be installed on subject's arm. Contains all neccessary tools."
|
||||
origin_tech = "materials=3;engineering=4;biotech=3;powerstorage=4"
|
||||
contents = newlist(/obj/item/weapon/screwdriver/cyborg, /obj/item/weapon/wrench/cyborg, /obj/item/weapon/weldingtool/largetank/cyborg,
|
||||
/obj/item/weapon/crowbar/cyborg, /obj/item/weapon/wirecutters/cyborg, /obj/item/device/multitool/cyborg)
|
||||
contents = newlist(/obj/item/screwdriver/cyborg, /obj/item/wrench/cyborg, /obj/item/weldingtool/largetank/cyborg,
|
||||
/obj/item/crowbar/cyborg, /obj/item/wirecutters/cyborg, /obj/item/multitool/cyborg)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/toolset/l
|
||||
parent_organ = "l_arm"
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/toolset/emag_act()
|
||||
if(!(locate(/obj/item/weapon/kitchen/knife/combat/cyborg) in items_list))
|
||||
if(!(locate(/obj/item/kitchen/knife/combat/cyborg) in items_list))
|
||||
to_chat(usr, "<span class='notice'>You unlock [src]'s integrated knife!</span>")
|
||||
items_list += new /obj/item/weapon/kitchen/knife/combat/cyborg(src)
|
||||
items_list += new /obj/item/kitchen/knife/combat/cyborg(src)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/esword
|
||||
name = "arm-mounted energy blade"
|
||||
desc = "An illegal, and highly dangerous cybernetic implant that can project a deadly blade of concentrated enregy."
|
||||
contents = newlist(/obj/item/weapon/melee/energy/blade/hardlight)
|
||||
contents = newlist(/obj/item/melee/energy/blade/hardlight)
|
||||
origin_tech = "materials=4;combat=5;biotech=3;powerstorage=2;syndicate=5"
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/medibeam
|
||||
name = "integrated medical beamgun"
|
||||
desc = "A cybernetic implant that allows the user to project a healing beam from their hand."
|
||||
contents = newlist(/obj/item/weapon/gun/medbeam)
|
||||
contents = newlist(/obj/item/gun/medbeam)
|
||||
origin_tech = "materials=5;combat=2;biotech=5;powerstorage=4;syndicate=1"
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/flash
|
||||
name = "integrated high-intensity photon projector" //Why not
|
||||
desc = "An integrated projector mounted onto a user's arm, that is able to be used as a powerful flash."
|
||||
contents = newlist(/obj/item/device/flash/armimplant)
|
||||
contents = newlist(/obj/item/flash/armimplant)
|
||||
origin_tech = "materials=4;combat=3;biotech=4;magnets=4;powerstorage=3"
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/flash/New()
|
||||
..()
|
||||
if(locate(/obj/item/device/flash/armimplant) in items_list)
|
||||
var/obj/item/device/flash/armimplant/F = locate(/obj/item/device/flash/armimplant) in items_list
|
||||
if(locate(/obj/item/flash/armimplant) in items_list)
|
||||
var/obj/item/flash/armimplant/F = locate(/obj/item/flash/armimplant) in items_list
|
||||
F.I = src
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/baton
|
||||
@@ -230,19 +230,19 @@
|
||||
/obj/item/organ/internal/cyberimp/arm/combat
|
||||
name = "combat cybernetics implant"
|
||||
desc = "A powerful cybernetic implant that contains combat modules built into the user's arm"
|
||||
contents = newlist(/obj/item/weapon/melee/energy/blade/hardlight, /obj/item/weapon/gun/medbeam, /obj/item/borg/stun, /obj/item/device/flash/armimplant)
|
||||
contents = newlist(/obj/item/melee/energy/blade/hardlight, /obj/item/gun/medbeam, /obj/item/borg/stun, /obj/item/flash/armimplant)
|
||||
origin_tech = "materials=5;combat=7;biotech=5;powerstorage=5;syndicate=6;programming=5"
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/combat/New()
|
||||
..()
|
||||
if(locate(/obj/item/device/flash/armimplant) in items_list)
|
||||
var/obj/item/device/flash/armimplant/F = locate(/obj/item/device/flash/armimplant) in items_list
|
||||
if(locate(/obj/item/flash/armimplant) in items_list)
|
||||
var/obj/item/flash/armimplant/F = locate(/obj/item/flash/armimplant) in items_list
|
||||
F.I = src
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/surgery
|
||||
name = "surgical toolset implant"
|
||||
desc = "A set of surgical tools hidden behind a concealed panel on the user's arm"
|
||||
contents = newlist(/obj/item/weapon/retractor, /obj/item/weapon/hemostat, /obj/item/weapon/cautery, /obj/item/weapon/surgicaldrill, /obj/item/weapon/scalpel, /obj/item/weapon/circular_saw, /obj/item/weapon/bonegel, /obj/item/weapon/FixOVein, /obj/item/weapon/bonesetter)
|
||||
contents = newlist(/obj/item/retractor/augment, /obj/item/hemostat/augment, /obj/item/cautery/augment, /obj/item/surgicaldrill/augment, /obj/item/scalpel/augment, /obj/item/circular_saw/augment, /obj/item/bonegel/augment, /obj/item/FixOVein/augment, /obj/item/bonesetter/augment)
|
||||
origin_tech = "materials=3;engineering=3;biotech=3;programming=2;magnets=3"
|
||||
|
||||
// lets make IPCs even *more* vulnerable to EMPs!
|
||||
@@ -290,7 +290,7 @@
|
||||
if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
|
||||
to_chat(user, "<span class='warning'>You are already fully charged!</span>")
|
||||
else
|
||||
addtimer(src, "powerdraw_loop", 0, TRUE, A, H)
|
||||
INVOKE_ASYNC(src, .proc/powerdraw_loop, A, H)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There is no charge to draw from that APC.</span>")
|
||||
else
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
var/implant_color = "#FFFFFF"
|
||||
var/implant_overlay
|
||||
tough = TRUE // Immune to damage
|
||||
sterile = TRUE // Doesn't accumulate germs
|
||||
robotic = 2 // these are cybernetic after all
|
||||
|
||||
/obj/item/organ/internal/cyberimp/New(var/mob/M = null)
|
||||
. = ..()
|
||||
@@ -277,24 +275,24 @@
|
||||
|
||||
//BOX O' IMPLANTS
|
||||
|
||||
/obj/item/weapon/storage/box/cyber_implants
|
||||
/obj/item/storage/box/cyber_implants
|
||||
name = "boxed cybernetic implant"
|
||||
desc = "A sleek, sturdy box."
|
||||
icon_state = "cyber_implants"
|
||||
|
||||
/obj/item/weapon/storage/box/cyber_implants/New(loc, implant)
|
||||
/obj/item/storage/box/cyber_implants/New(loc, implant)
|
||||
..()
|
||||
new /obj/item/device/autoimplanter(src)
|
||||
new /obj/item/autoimplanter(src)
|
||||
if(ispath(implant))
|
||||
new implant(src)
|
||||
|
||||
/obj/item/weapon/storage/box/cyber_implants/bundle
|
||||
/obj/item/storage/box/cyber_implants/bundle
|
||||
name = "boxed cybernetic implants"
|
||||
var/list/boxed = list(/obj/item/organ/internal/cyberimp/eyes/xray,/obj/item/organ/internal/cyberimp/eyes/thermals,
|
||||
/obj/item/organ/internal/cyberimp/brain/anti_stun, /obj/item/organ/internal/cyberimp/chest/reviver)
|
||||
var/amount = 5
|
||||
|
||||
/obj/item/weapon/storage/box/cyber_implants/bundle/New()
|
||||
/obj/item/storage/box/cyber_implants/bundle/New()
|
||||
..()
|
||||
var/implant
|
||||
while(contents.len <= amount + 1) // +1 for the autoimplanter.
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/obj/item/device/autoimplanter
|
||||
/obj/item/autoimplanter
|
||||
name = "autoimplanter"
|
||||
desc = "A device that automatically injects a cyber-implant into the user without the hassle of extensive surgery. It has a slot to insert implants and a screwdriver slot for removing accidentally added implants."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "autoimplanter"
|
||||
item_state = "walkietalkie"//left as this so as to intentionally not have inhands
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
usesound = 'sound/weapons/circsawhit.ogg'
|
||||
var/obj/item/organ/internal/cyberimp/storedorgan
|
||||
|
||||
/obj/item/device/autoimplanter/attack_self(mob/user)//when the object it used...
|
||||
/obj/item/autoimplanter/attack_self(mob/user)//when the object it used...
|
||||
if(!storedorgan)
|
||||
to_chat(user, "<span class='notice'>[src] currently has no implant stored.</span>")
|
||||
return
|
||||
@@ -16,7 +17,7 @@
|
||||
playsound(get_turf(user), usesound, 50, 1)
|
||||
storedorgan = null
|
||||
|
||||
/obj/item/device/autoimplanter/attackby(obj/item/I, mob/user, params)
|
||||
/obj/item/autoimplanter/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/organ/internal/cyberimp))
|
||||
if(storedorgan)
|
||||
to_chat(user, "<span class='notice'>[src] already has an implant stored.</span>")
|
||||
@@ -26,7 +27,7 @@
|
||||
I.forceMove(src)
|
||||
storedorgan = I
|
||||
to_chat(user, "<span class='notice'>You insert the [I] into [src].</span>")
|
||||
else if(istype(I, /obj/item/weapon/screwdriver))
|
||||
else if(istype(I, /obj/item/screwdriver))
|
||||
if(!storedorgan)
|
||||
to_chat(user, "<span class='notice'>There's no implant in [src] for you to remove.</span>")
|
||||
else
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
return
|
||||
else
|
||||
bleedsuppress = TRUE
|
||||
addtimer(src, "resume_bleeding", amount)
|
||||
addtimer(CALLBACK(src, .proc/resume_bleeding), amount)
|
||||
|
||||
/mob/living/carbon/human/proc/resume_bleeding()
|
||||
bleedsuppress = FALSE
|
||||
@@ -64,7 +64,7 @@
|
||||
var/obj/item/organ/external/BP = X
|
||||
var/brutedamage = BP.brute_dam
|
||||
|
||||
if((BP.status & ORGAN_ROBOT) && !isSynthetic())
|
||||
if(BP.is_robotic() && !isSynthetic())
|
||||
continue
|
||||
|
||||
//We want an accurate reading of .len
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/obj/item/organ/internal/eyes
|
||||
name = "eyeballs"
|
||||
icon_state = "eyes"
|
||||
gender = PLURAL
|
||||
organ_tag = "eyes"
|
||||
parent_organ = "head"
|
||||
slot = "eyes"
|
||||
var/eye_colour = "#000000"
|
||||
var/list/colourmatrix = null
|
||||
var/list/colourblind_matrix = MATRIX_GREYSCALE //Special colourblindness parameters. By default, it's black-and-white.
|
||||
var/list/replace_colours = LIST_GREYSCALE_REPLACE
|
||||
var/dependent_disabilities = null //Gets set by eye-dependent disabilities such as colourblindness so the eyes can transfer the disability during transplantation.
|
||||
var/dark_view = 2 //Default dark_view for Humans.
|
||||
var/weld_proof = null //If set, the eyes will not take damage during welding. eg. IPC optical sensors do not take damage when they weld things while all other eyes will.
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/update_colour()
|
||||
dna.write_eyes_attributes(src)
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/generate_icon(var/mob/living/carbon/human/HA)
|
||||
var/mob/living/carbon/human/H = HA
|
||||
if(!istype(H))
|
||||
H = owner
|
||||
var/icon/eyes_icon = new /icon('icons/mob/human_face.dmi', H.species.eyes)
|
||||
eyes_icon.Blend(eye_colour, ICON_ADD)
|
||||
|
||||
return eyes_icon
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/get_colourmatrix() //Returns a special colour matrix if the eyes are organic and the mob is colourblind, otherwise it uses the current one.
|
||||
if(!is_robotic() && owner.disabilities & COLOURBLIND)
|
||||
return colourblind_matrix
|
||||
else
|
||||
return colourmatrix
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/get_dark_view() //Returns dark_view (if the eyes are organic) for see_invisible handling in species.dm to be autoprocessed by life().
|
||||
return dark_view
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/shine()
|
||||
if(is_robotic() || (dark_view > EYE_SHINE_THRESHOLD))
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/internal/eyes/insert(mob/living/carbon/human/M, special = 0)
|
||||
..()
|
||||
if(istype(M) && eye_colour)
|
||||
M.update_body() //Apply our eye colour to the target.
|
||||
|
||||
if(!(M.disabilities & COLOURBLIND) && (dependent_disabilities & COLOURBLIND)) //If the eyes are colourblind and we're not, carry over the gene.
|
||||
dependent_disabilities &= ~COLOURBLIND
|
||||
M.dna.SetSEState(COLOURBLINDBLOCK,1)
|
||||
genemutcheck(M,COLOURBLINDBLOCK,null,MUTCHK_FORCED)
|
||||
else
|
||||
M.update_client_colour() //If we're here, that means the mob acquired the colourblindness gene while they didn't have eyes. Better handle it.
|
||||
|
||||
/obj/item/organ/internal/eyes/remove(mob/living/carbon/human/M, special = 0)
|
||||
if(!special && (M.disabilities & COLOURBLIND)) //If special is set, that means these eyes are getting deleted (i.e. during set_species())
|
||||
if(!(dependent_disabilities & COLOURBLIND)) //We only want to change COLOURBLINDBLOCK and such it the eyes are being surgically removed.
|
||||
dependent_disabilities |= COLOURBLIND
|
||||
M.dna.SetSEState(COLOURBLINDBLOCK,0)
|
||||
genemutcheck(M,COLOURBLINDBLOCK,null,MUTCHK_FORCED)
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/eyes/surgeryize()
|
||||
if(!owner)
|
||||
return
|
||||
owner.CureNearsighted()
|
||||
owner.CureBlind()
|
||||
owner.SetEyeBlurry(0)
|
||||
owner.SetEyeBlind(0)
|
||||
|
||||
/obj/item/organ/internal/eyes/robotize()
|
||||
colourmatrix = null
|
||||
..() //Make sure the organ's got the robotic status indicators before updating the client colour.
|
||||
if(owner)
|
||||
owner.update_client_colour(0) //Since mechanical eyes give dark_view of 2 and full colour vision atm, just having this here is fine.
|
||||
|
||||
/obj/item/organ/internal/eyes/cybernetic
|
||||
name = "cybernetic eyes"
|
||||
icon_state = "eyes-prosthetic"
|
||||
desc = "An electronic device designed to mimic the functions of a pair of human eyes. It has no benefits over organic eyes, but is easy to produce."
|
||||
origin_tech = "biotech=4"
|
||||
status = ORGAN_ROBOT
|
||||
@@ -0,0 +1,150 @@
|
||||
/obj/item/organ/internal/heart
|
||||
name = "heart"
|
||||
icon_state = "heart-on"
|
||||
organ_tag = "heart"
|
||||
parent_organ = "chest"
|
||||
slot = "heart"
|
||||
origin_tech = "biotech=5"
|
||||
var/beating = TRUE
|
||||
dead_icon = "heart-off"
|
||||
var/icon_base = "heart"
|
||||
|
||||
/obj/item/organ/internal/heart/update_icon()
|
||||
if(beating)
|
||||
icon_state = "[icon_base]-on"
|
||||
else
|
||||
icon_state = "[icon_base]-off"
|
||||
|
||||
/obj/item/organ/internal/heart/remove(mob/living/carbon/M, special = 0)
|
||||
. = ..()
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.stat == DEAD)
|
||||
Stop()
|
||||
return
|
||||
|
||||
spawn(120)
|
||||
if(!owner)
|
||||
Stop()
|
||||
|
||||
/obj/item/organ/internal/heart/emp_act(intensity)
|
||||
if(!is_robotic() || emp_proof)
|
||||
return
|
||||
Stop()
|
||||
|
||||
/obj/item/organ/internal/heart/necrotize()
|
||||
..()
|
||||
Stop()
|
||||
|
||||
/obj/item/organ/internal/heart/attack_self(mob/user)
|
||||
..()
|
||||
if(status & ORGAN_DEAD)
|
||||
to_chat(user, "<span class='warning'>You can't restart a dead heart.</span>")
|
||||
return
|
||||
if(!beating)
|
||||
Restart()
|
||||
spawn(80)
|
||||
if(!owner)
|
||||
Stop()
|
||||
|
||||
/obj/item/organ/internal/heart/safe_replace(mob/living/carbon/human/target)
|
||||
Restart()
|
||||
..()
|
||||
|
||||
/obj/item/organ/internal/heart/proc/Stop()
|
||||
beating = FALSE
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/internal/heart/proc/Restart()
|
||||
beating = TRUE
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/internal/heart/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.icon_state = dead_icon
|
||||
return S
|
||||
|
||||
/obj/item/organ/internal/heart/cursed
|
||||
name = "cursed heart"
|
||||
desc = "it needs to be pumped..."
|
||||
icon_state = "cursedheart-off"
|
||||
icon_base = "cursedheart"
|
||||
origin_tech = "biotech=6"
|
||||
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
|
||||
var/last_pump = 0
|
||||
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/internal/heart/cursed/attack(mob/living/carbon/human/H, mob/living/carbon/human/user, obj/target)
|
||||
if(H == user && istype(H))
|
||||
if(NO_BLOOD in H.species.species_traits)
|
||||
to_chat(H, "<span class = 'userdanger'>\The [src] is not compatible with your form!</span>")
|
||||
return
|
||||
playsound(user,'sound/effects/singlebeat.ogg', 40, 1)
|
||||
user.drop_item()
|
||||
insert(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/internal/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(!(NO_BLOOD in H.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(H.client)
|
||||
H.client.color = "red" //bloody screen so real
|
||||
else
|
||||
last_pump = world.time //lets be extra fair *sigh*
|
||||
|
||||
/obj/item/organ/internal/heart/cursed/insert(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
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>")
|
||||
|
||||
|
||||
/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/internal/heart/cursed))
|
||||
var/obj/item/organ/internal/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(!(NO_BLOOD in H.species.species_traits))
|
||||
H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_NORMAL)
|
||||
if(owner.client)
|
||||
owner.client.color = ""
|
||||
|
||||
H.adjustBruteLoss(-cursed_heart.heal_brute)
|
||||
H.adjustFireLoss(-cursed_heart.heal_burn)
|
||||
H.adjustOxyLoss(-cursed_heart.heal_oxy)
|
||||
|
||||
/obj/item/organ/internal/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-on"
|
||||
icon_base = "heart-c"
|
||||
dead_icon = "heart-c-off"
|
||||
origin_tech = "biotech=5"
|
||||
status = ORGAN_ROBOT
|
||||
@@ -104,8 +104,8 @@
|
||||
if(flying == 1)
|
||||
return TRUE
|
||||
|
||||
var/obj/item/weapon/tank/jetpack/J
|
||||
if(istype(back,/obj/item/weapon/tank/jetpack))
|
||||
var/obj/item/tank/jetpack/J
|
||||
if(istype(back,/obj/item/tank/jetpack))
|
||||
J = back
|
||||
if(J.on == 1)
|
||||
return TRUE
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/obj/item/organ/internal/kidneys
|
||||
name = "kidneys"
|
||||
icon_state = "kidneys"
|
||||
gender = PLURAL
|
||||
organ_tag = "kidneys"
|
||||
parent_organ = "groin"
|
||||
slot = "kidneys"
|
||||
|
||||
/obj/item/organ/internal/kidneys/on_life()
|
||||
// Coffee is really bad for you with busted kidneys.
|
||||
// This should probably be expanded in some way, but fucked if I know
|
||||
// what else kidneys can process in our reagent list.
|
||||
var/datum/reagent/coffee = locate(/datum/reagent/consumable/drink/coffee) in owner.reagents.reagent_list
|
||||
if(coffee)
|
||||
if(is_bruised())
|
||||
owner.adjustToxLoss(0.1 * PROCESS_ACCURACY)
|
||||
else if(is_broken())
|
||||
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
|
||||
|
||||
/obj/item/organ/internal/kidneys/cybernetic
|
||||
name = "cybernetic kidneys"
|
||||
icon_state = "kidneys-c"
|
||||
desc = "An electronic device designed to mimic the functions of human kidneys. It has no benefits over a pair of organic kidneys, but is easy to produce."
|
||||
origin_tech = "biotech=4"
|
||||
status = ORGAN_ROBOT
|
||||
@@ -0,0 +1,58 @@
|
||||
/obj/item/organ/internal/liver
|
||||
name = "liver"
|
||||
icon_state = "liver"
|
||||
organ_tag = "liver"
|
||||
parent_organ = "groin"
|
||||
slot = "liver"
|
||||
var/alcohol_intensity = 1
|
||||
|
||||
/obj/item/organ/internal/liver/on_life()
|
||||
if(germ_level > INFECTION_LEVEL_ONE)
|
||||
if(prob(1))
|
||||
to_chat(owner, "<span class='warning'> Your skin itches.</span>")
|
||||
if(germ_level > INFECTION_LEVEL_TWO)
|
||||
if(prob(1))
|
||||
owner.vomit()
|
||||
|
||||
if(owner.life_tick % PROCESS_ACCURACY == 0)
|
||||
|
||||
//High toxins levels are dangerous
|
||||
if(owner.getToxLoss() >= 60 && !owner.reagents.has_reagent("charcoal"))
|
||||
//Healthy liver suffers on its own
|
||||
if(damage < min_broken_damage)
|
||||
receive_damage(0.2 * PROCESS_ACCURACY)
|
||||
//Damaged one shares the fun
|
||||
else
|
||||
var/obj/item/organ/internal/O = pick(owner.internal_organs)
|
||||
if(O)
|
||||
O.receive_damage(0.2 * PROCESS_ACCURACY)
|
||||
|
||||
//Detox can heal small amounts of damage
|
||||
if(damage && damage < min_bruised_damage && owner.reagents.has_reagent("charcoal"))
|
||||
receive_damage(-0.2 * PROCESS_ACCURACY)
|
||||
|
||||
// Get the effectiveness of the liver.
|
||||
var/filter_effect = 3
|
||||
if(is_bruised())
|
||||
filter_effect -= 1
|
||||
if(is_broken())
|
||||
filter_effect -= 2
|
||||
|
||||
// Damaged liver means some chemicals are very dangerous
|
||||
if(damage >= min_bruised_damage)
|
||||
for(var/datum/reagent/R in owner.reagents.reagent_list)
|
||||
// Ethanol and all drinks are bad
|
||||
if(istype(R, /datum/reagent/consumable/ethanol))
|
||||
owner.adjustToxLoss(0.1 * PROCESS_ACCURACY)
|
||||
|
||||
// Can't cope with toxins at all
|
||||
for(var/toxin in list("toxin", "plasma", "sacid", "facid", "cyanide", "amanitin", "carpotoxin"))
|
||||
if(owner.reagents.has_reagent(toxin))
|
||||
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
|
||||
|
||||
/obj/item/organ/internal/liver/cybernetic
|
||||
name = "cybernetic liver"
|
||||
icon_state = "liver-c"
|
||||
desc = "An electronic device designed to mimic the functions of a human liver. It has no benefits over an organic liver, but is easy to produce."
|
||||
origin_tech = "biotech=4"
|
||||
status = ORGAN_ROBOT
|
||||
@@ -51,6 +51,12 @@
|
||||
var/heat_level_3_damage = HEAT_GAS_DAMAGE_LEVEL_3
|
||||
var/heat_damage_types = list(BURN = 1)
|
||||
|
||||
/obj/item/organ/internal/lungs/emp_act()
|
||||
if(!is_robotic() || emp_proof)
|
||||
return
|
||||
if(owner)
|
||||
owner.LoseBreath(20)
|
||||
|
||||
/obj/item/organ/internal/lungs/insert(mob/living/carbon/M, special = 0, dont_remove_slot = 0)
|
||||
..()
|
||||
for(var/thing in list("oxy", "tox", "co2", "nitro"))
|
||||
@@ -334,4 +340,24 @@
|
||||
cold_level_1_damage = -COLD_GAS_DAMAGE_LEVEL_1 //They heal when the air is cold
|
||||
cold_level_2_damage = -COLD_GAS_DAMAGE_LEVEL_2
|
||||
cold_level_3_damage = -COLD_GAS_DAMAGE_LEVEL_3
|
||||
cold_damage_types = list(BRUTE = 1, BURN = 0.5)
|
||||
cold_damage_types = list(BRUTE = 1, BURN = 0.5)
|
||||
|
||||
/obj/item/organ/internal/lungs/cybernetic
|
||||
name = "cybernetic lungs"
|
||||
desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement."
|
||||
icon_state = "lungs-c"
|
||||
origin_tech = "biotech=4"
|
||||
status = ORGAN_ROBOT
|
||||
|
||||
/obj/item/organ/internal/lungs/cybernetic/upgraded
|
||||
name = "upgraded cybernetic lungs"
|
||||
desc = "A more advanced version of the stock cybernetic lungs. They are capable of filtering out lower levels of toxins and carbon dioxide."
|
||||
icon_state = "lungs-c-u"
|
||||
origin_tech = "biotech=5"
|
||||
|
||||
safe_toxins_max = 20
|
||||
safe_co2_max = 20
|
||||
|
||||
cold_level_1_threshold = 200
|
||||
cold_level_2_threshold = 140
|
||||
cold_level_3_threshold = 100
|
||||
@@ -4,7 +4,7 @@
|
||||
var/dead_icon
|
||||
var/mob/living/carbon/human/owner = null
|
||||
var/status = 0
|
||||
var/vital //Lose a vital limb, die immediately.
|
||||
var/vital = FALSE //Lose a vital limb, die immediately.
|
||||
var/damage = 0 // amount of damage to the organ
|
||||
|
||||
var/min_bruised_damage = 10
|
||||
@@ -13,7 +13,6 @@
|
||||
var/organ_tag = "organ"
|
||||
|
||||
var/parent_organ = "chest"
|
||||
var/robotic = 0 //For being a robot
|
||||
|
||||
var/list/datum/autopsy_data/autopsy_data = list()
|
||||
var/list/trace_chemicals = list() // traces of chemicals in the organ,
|
||||
@@ -30,6 +29,7 @@
|
||||
var/sterile = FALSE //can the organ be infected by germs?
|
||||
var/tough = FALSE //can organ be easily damaged?
|
||||
var/emp_proof = FALSE //is the organ immune to EMPs?
|
||||
var/hidden_pain = FALSE //will it skip pain messages?
|
||||
|
||||
|
||||
/obj/item/organ/Destroy()
|
||||
@@ -73,13 +73,11 @@
|
||||
blood_DNA = list()
|
||||
blood_DNA[dna.unique_enzymes] = dna.b_type
|
||||
|
||||
/obj/item/organ/proc/necrotize(update_sprite=TRUE)
|
||||
if(status & ORGAN_ROBOT)
|
||||
return
|
||||
/obj/item/organ/proc/necrotize(update_sprite = TRUE)
|
||||
damage = max_damage
|
||||
status |= ORGAN_DEAD
|
||||
processing_objects -= src
|
||||
if(dead_icon)
|
||||
if(dead_icon && !is_robotic())
|
||||
icon_state = dead_icon
|
||||
if(owner && vital)
|
||||
owner.death()
|
||||
@@ -94,7 +92,7 @@
|
||||
return
|
||||
|
||||
//Process infections
|
||||
if((status & ORGAN_ROBOT) || sterile || (owner && (IS_PLANT in owner.species.species_traits)))
|
||||
if(is_robotic() || sterile || (owner && (IS_PLANT in owner.species.species_traits)))
|
||||
germ_level = 0
|
||||
return
|
||||
|
||||
@@ -115,7 +113,7 @@
|
||||
handle_germ_effects()
|
||||
|
||||
/obj/item/organ/proc/is_preserved()
|
||||
if(istype(loc,/obj/item/device/mmi))
|
||||
if(istype(loc,/obj/item/mmi))
|
||||
germ_level = max(0, germ_level - 1) // So a brain can slowly recover from being left out of an MMI
|
||||
return 1
|
||||
if(is_found_within(/obj/structure/closet/crate/freezer))
|
||||
@@ -174,10 +172,8 @@
|
||||
/obj/item/organ/proc/rejuvenate()
|
||||
damage = 0
|
||||
germ_level = 0
|
||||
if(status & ORGAN_ROBOT) //Robotic organs stay robotic.
|
||||
if(is_robotic()) //Robotic organs stay robotic.
|
||||
status = ORGAN_ROBOT
|
||||
else if(status & ORGAN_ASSISTED) //Assisted organs stay assisted.
|
||||
status = ORGAN_ASSISTED
|
||||
else
|
||||
status = 0
|
||||
if(!owner)
|
||||
@@ -223,37 +219,30 @@
|
||||
/obj/item/organ/proc/receive_damage(amount, silent = 0)
|
||||
if(tough)
|
||||
return
|
||||
if(status & ORGAN_ROBOT)
|
||||
damage = between(0, damage + (amount * 0.8), max_damage)
|
||||
else
|
||||
damage = between(0, damage + amount, max_damage)
|
||||
damage = between(0, damage + amount, max_damage)
|
||||
|
||||
//only show this if the organ is not robotic
|
||||
if(owner && parent_organ && amount > 0)
|
||||
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
|
||||
if(parent && !silent)
|
||||
owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1)
|
||||
//only show this if the organ is not robotic
|
||||
if(owner && parent_organ && amount > 0)
|
||||
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
|
||||
if(parent && !silent)
|
||||
owner.custom_pain("Something inside your [parent.name] hurts a lot.")
|
||||
|
||||
//check if we've hit max_damage
|
||||
if(damage >= max_damage)
|
||||
necrotize()
|
||||
|
||||
/obj/item/organ/proc/heal_internal_damage(amount, robo_repair = FALSE)
|
||||
if(is_robotic() && !robo_repair)
|
||||
return
|
||||
damage = max(damage - amount, 0)
|
||||
|
||||
/obj/item/organ/proc/robotize() //Being used to make robutt hearts, etc
|
||||
robotic = 2
|
||||
status &= ~ORGAN_BROKEN
|
||||
status &= ~ORGAN_SPLINTED
|
||||
status |= ORGAN_ROBOT
|
||||
|
||||
/obj/item/organ/proc/mechassist() //Used to add things like pacemakers, etc
|
||||
robotize(1) //Skip the icon/name setting that occurs in robotize to avoid having to reset the icon file.
|
||||
status &= ~ORGAN_ROBOT
|
||||
status |= ORGAN_ASSISTED
|
||||
robotic = 1
|
||||
min_bruised_damage = 15
|
||||
min_broken_damage = 35
|
||||
|
||||
/obj/item/organ/external/emp_act(severity)
|
||||
if(!(status & ORGAN_ROBOT) || emp_proof)
|
||||
if(!is_robotic() || emp_proof)
|
||||
return
|
||||
if(tough)
|
||||
switch(severity)
|
||||
@@ -273,25 +262,13 @@
|
||||
receive_damage(0, 7)
|
||||
|
||||
/obj/item/organ/internal/emp_act(severity)
|
||||
if(!robotic || emp_proof)
|
||||
if(!is_robotic() || emp_proof)
|
||||
return
|
||||
if(robotic == 2)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
receive_damage(20, 1)
|
||||
if(2.0)
|
||||
receive_damage(7, 1)
|
||||
else if(robotic == 1)
|
||||
receive_damage(11, 1)
|
||||
|
||||
/obj/item/organ/internal/heart/emp_act(intensity)
|
||||
if(emp_proof)
|
||||
return
|
||||
if(owner && robotic == 2)
|
||||
Stop() // In the name of looooove~!
|
||||
owner.visible_message("<span class='danger'>[owner] clutches their chest and gasps!</span>","<span class='userdanger'>You clutch your chest in pain!</span>")
|
||||
else if(owner && robotic == 1)
|
||||
receive_damage(11,1)
|
||||
switch(severity)
|
||||
if(1)
|
||||
receive_damage(20, 1)
|
||||
if(2)
|
||||
receive_damage(7, 1)
|
||||
|
||||
/obj/item/organ/proc/remove(var/mob/living/user,special = 0)
|
||||
if(!istype(owner))
|
||||
@@ -306,10 +283,7 @@
|
||||
processing_objects |= src
|
||||
|
||||
if(owner && vital && is_primary_organ()) // I'd do another check for species or whatever so that you couldn't "kill" an IPC by removing a human head from them, but it doesn't matter since they'll come right back from the dead
|
||||
if(user)
|
||||
user.create_attack_log("<font color='red'> removed a vital organ ([src]) from [key_name(owner)] (INTENT: [uppertext(user.a_intent)])</font>")
|
||||
owner.create_attack_log("<font color='orange'> had a vital organ ([src]) removed by [key_name(user)] (INTENT: [uppertext(user.a_intent)])</font>")
|
||||
msg_admin_attack("[key_name_admin(user)] removed a vital organ ([src]) from [key_name_admin(owner)]")
|
||||
add_attack_logs(user, owner, "Removed vital organ ([src])", !!user ? ATKLOG_FEW : ATKLOG_ALL)
|
||||
owner.death()
|
||||
owner = null
|
||||
return src
|
||||
@@ -337,20 +311,15 @@ I use this so that this can be made better once the organ overhaul rolls out --
|
||||
return 0
|
||||
return src == O.get_int_organ(organ_tag)
|
||||
|
||||
/obj/item/organ/proc/is_robotic(var/purist = FALSE)
|
||||
if(purist && (robotic > 1 || status & (ORGAN_ROBOT))) //Only the robotiest.
|
||||
/obj/item/organ/proc/is_robotic()
|
||||
if(status & ORGAN_ROBOT)
|
||||
return TRUE
|
||||
if(robotic || status & (ORGAN_ROBOT|ORGAN_ASSISTED)) //Any tech will do.
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/organ/serialize()
|
||||
var/data = ..()
|
||||
if(status != 0)
|
||||
data["status"] = status
|
||||
if(robotic > 0)
|
||||
data["robotic"] = robotic
|
||||
|
||||
// Save the DNA datum if: The owner doesn't exist, or the dna doesn't match
|
||||
// the owner
|
||||
@@ -358,15 +327,10 @@ I use this so that this can be made better once the organ overhaul rolls out --
|
||||
data["dna"] = dna.serialize()
|
||||
return data
|
||||
|
||||
/obj/item/organ/deserialize(var/data)
|
||||
switch(data["robotic"])
|
||||
if(1)
|
||||
mechassist()
|
||||
if(2)
|
||||
robotize()
|
||||
else
|
||||
// Nothing
|
||||
/obj/item/organ/deserialize(data)
|
||||
if(isnum(data["status"]))
|
||||
if(data["status"] & ORGAN_ROBOT)
|
||||
robotize()
|
||||
status = data["status"]
|
||||
if(islist(data["dna"]))
|
||||
// The only thing the official proc does is
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
owner.emote("scream") //getting hit on broken hand hurts
|
||||
if(status & ORGAN_SPLINTED && prob((brute + burn)*4)) //taking damage to splinted limbs removes the splints
|
||||
status &= ~ORGAN_SPLINTED
|
||||
owner.visible_message("<span class='danger'>The splint on [owner]'s left arm unravels from their [name]!</span>","<span class='userdanger'>The splint on your [name] unravels!</span>")
|
||||
owner.visible_message("<span class='danger'>The splint on [owner]'s left arm unravels from [owner.p_their()] [name]!</span>","<span class='userdanger'>The splint on your [name] unravels!</span>")
|
||||
owner.handle_splints()
|
||||
if(used_weapon)
|
||||
add_autopsy_data("[used_weapon]", brute + burn)
|
||||
@@ -239,10 +239,9 @@
|
||||
#undef LIMB_SHARP_THRESH_INT_DMG
|
||||
#undef LIMB_THRESH_INT_DMG
|
||||
#undef LIMB_DMG_PROB
|
||||
#undef LIMB_NO_BONE_DMG_PROB
|
||||
|
||||
/obj/item/organ/external/proc/heal_damage(brute, burn, internal = 0, robo_repair = 0)
|
||||
if(status & ORGAN_ROBOT && !robo_repair)
|
||||
if(is_robotic() && !robo_repair)
|
||||
return
|
||||
|
||||
brute_dam = max(brute_dam - brute, 0)
|
||||
@@ -261,10 +260,8 @@ This function completely restores a damaged organ to perfect condition.
|
||||
*/
|
||||
/obj/item/organ/external/rejuvenate()
|
||||
damage_state = "00"
|
||||
if(status & ORGAN_ROBOT) //Robotic organs stay robotic.
|
||||
if(is_robotic()) //Robotic organs stay robotic.
|
||||
status = ORGAN_ROBOT
|
||||
else if(status & ORGAN_ASSISTED) //Assisted organs stay assisted.
|
||||
status = ORGAN_ASSISTED
|
||||
else
|
||||
status = 0
|
||||
germ_level = 0
|
||||
@@ -273,8 +270,7 @@ This function completely restores a damaged organ to perfect condition.
|
||||
burn_dam = 0
|
||||
open = 0 //Closing all wounds.
|
||||
internal_bleeding = FALSE
|
||||
if(istype(src, /obj/item/organ/external/head) && disfigured) //If their head's disfigured, refigure it.
|
||||
disfigured = 0
|
||||
disfigured = FALSE
|
||||
|
||||
// handle internal organs
|
||||
for(var/obj/item/organ/internal/current_organ in internal_organs)
|
||||
@@ -332,7 +328,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
*/
|
||||
/obj/item/organ/external/proc/update_germs()
|
||||
|
||||
if((status & ORGAN_ROBOT) || (IS_PLANT in owner.species.species_traits)) //Robotic limbs shouldn't be infected, nor should nonexistant limbs.
|
||||
if(is_robotic() || (IS_PLANT in owner.species.species_traits)) //Robotic limbs shouldn't be infected, nor should nonexistant limbs.
|
||||
germ_level = 0
|
||||
return
|
||||
|
||||
@@ -383,12 +379,12 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
//spread the infection to child and parent organs
|
||||
if(children)
|
||||
for(var/obj/item/organ/external/child in children)
|
||||
if(child.germ_level < germ_level && !(child.status & ORGAN_ROBOT))
|
||||
if(child.germ_level < germ_level && !child.is_robotic())
|
||||
if(child.germ_level < INFECTION_LEVEL_ONE*2 || prob(30))
|
||||
child.germ_level++
|
||||
|
||||
if(parent)
|
||||
if(parent.germ_level < germ_level && !(parent.status & ORGAN_ROBOT))
|
||||
if(parent.germ_level < germ_level && !parent.is_robotic())
|
||||
if(parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30))
|
||||
parent.germ_level++
|
||||
|
||||
@@ -400,16 +396,16 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
|
||||
//Updates brute_damn and burn_damn from wound damages. Updates BLEEDING status.
|
||||
/obj/item/organ/external/proc/check_fracture()
|
||||
if(config.bones_can_break && brute_dam > min_broken_damage && !(status & ORGAN_ROBOT))
|
||||
if(config.bones_can_break && brute_dam > min_broken_damage && !is_robotic())
|
||||
fracture()
|
||||
|
||||
/obj/item/organ/external/proc/check_for_internal_bleeding(damage)
|
||||
if(NO_BLOOD in owner.species.species_traits)
|
||||
return
|
||||
var/local_damage = brute_dam + damage
|
||||
if(damage > 15 && local_damage > 30 && prob(damage) && !(status & ORGAN_ROBOT))
|
||||
if(damage > 15 && local_damage > 30 && prob(damage) && !is_robotic())
|
||||
internal_bleeding = TRUE
|
||||
owner.custom_pain("You feel something rip in your [name]!", 1)
|
||||
owner.custom_pain("You feel something rip in your [name]!")
|
||||
|
||||
// new damage icon system
|
||||
// returns just the brute/burn damage code
|
||||
@@ -442,7 +438,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
return
|
||||
if(owner.step_count >= splinted_count + SPLINT_LIFE)
|
||||
status &= ~ORGAN_SPLINTED //oh no, we actually need surgery now!
|
||||
owner.visible_message("<span class='danger'>[owner] screams in pain as their splint pops off their [name]!</span>","<span class='userdanger'>You scream in pain as your splint pops off your [name]!</span>")
|
||||
owner.visible_message("<span class='danger'>[owner] screams in pain as [owner.p_their()] splint pops off their [name]!</span>","<span class='userdanger'>You scream in pain as your splint pops off your [name]!</span>")
|
||||
owner.emote("scream")
|
||||
owner.Stun(2)
|
||||
owner.handle_splints()
|
||||
@@ -464,20 +460,20 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
switch(disintegrate)
|
||||
if(DROPLIMB_SHARP)
|
||||
if(!clean)
|
||||
var/gore_sound = "[(status & ORGAN_ROBOT) ? "tortured metal" : "ripping tendons and flesh"]"
|
||||
var/gore_sound = "[is_robotic() ? "tortured metal" : "ripping tendons and flesh"]"
|
||||
owner.visible_message(
|
||||
"<span class='danger'>\The [owner]'s [src.name] flies off in an arc!</span>",\
|
||||
"<span class='moderate'><b>Your [src.name] goes flying off!</b></span>",\
|
||||
"<span class='danger'>You hear a terrible sound of [gore_sound].</span>")
|
||||
if(DROPLIMB_BURN)
|
||||
var/gore = "[(status & ORGAN_ROBOT) ? "": " of burning flesh"]"
|
||||
var/gore = "[is_robotic() ? "" : " of burning flesh"]"
|
||||
owner.visible_message(
|
||||
"<span class='danger'>\The [owner]'s [src.name] flashes away into ashes!</span>",\
|
||||
"<span class='moderate'><b>Your [src.name] flashes away into ashes!</b></span>",\
|
||||
"<span class='danger'>You hear a crackling sound[gore].</span>")
|
||||
if(DROPLIMB_BLUNT)
|
||||
var/gore = "[(status & ORGAN_ROBOT) ? "": " in shower of gore"]"
|
||||
var/gore_sound = "[(status & ORGAN_ROBOT) ? "rending sound of tortured metal" : "sickening splatter of gore"]"
|
||||
var/gore = "[is_robotic() ? "": " in shower of gore"]"
|
||||
var/gore_sound = "[is_robotic() ? "rending sound of tortured metal" : "sickening splatter of gore"]"
|
||||
owner.visible_message(
|
||||
"<span class='danger'>\The [owner]'s [src.name] explodes[gore]!</span>",\
|
||||
"<span class='moderate'><b>Your [src.name] explodes[gore]!</b></span>",\
|
||||
@@ -575,7 +571,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
//empties the bodypart from its organs and other things inside it
|
||||
/obj/item/organ/external/proc/drop_organs(mob/user)
|
||||
var/turf/T = get_turf(src)
|
||||
if(status != ORGAN_ROBOT)
|
||||
if(!is_robotic())
|
||||
playsound(T, 'sound/effects/splat.ogg', 25, 1)
|
||||
for(var/obj/item/I in src)
|
||||
I.forceMove(T)
|
||||
@@ -600,7 +596,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
holder.unEquip(holder.legcuffed)
|
||||
|
||||
/obj/item/organ/external/proc/fracture()
|
||||
if(status & ORGAN_ROBOT)
|
||||
if(is_robotic())
|
||||
return //ORGAN_BROKEN doesn't have the same meaning for robot limbs
|
||||
|
||||
if((status & ORGAN_BROKEN) || cannot_break)
|
||||
@@ -622,7 +618,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
release_restraints()
|
||||
|
||||
/obj/item/organ/external/proc/mend_fracture()
|
||||
if(status & ORGAN_ROBOT)
|
||||
if(is_robotic())
|
||||
return 0 //ORGAN_BROKEN doesn't have the same meaning for robot limbs
|
||||
if(brute_dam > min_broken_damage)
|
||||
return 0 //will just immediately fracture again
|
||||
@@ -681,12 +677,12 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
return FALSE
|
||||
|
||||
/obj/item/organ/external/proc/is_usable()
|
||||
if(((status & ORGAN_ROBOT) && get_damage() >= max_damage) && !tough) //robot limbs just become inoperable at max damage
|
||||
if((is_robotic() && get_damage() >= max_damage) && !tough) //robot limbs just become inoperable at max damage
|
||||
return
|
||||
return !(status & (ORGAN_MUTATED|ORGAN_DEAD))
|
||||
|
||||
/obj/item/organ/external/proc/is_malfunctioning()
|
||||
return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam) && !tough)
|
||||
return (is_robotic() && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam) && !tough)
|
||||
|
||||
/obj/item/organ/external/remove(var/mob/living/user, var/ignore_children)
|
||||
|
||||
@@ -737,19 +733,14 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
qdel(spark_system)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/organ/external/proc/disfigure(var/type = "brute")
|
||||
/obj/item/organ/external/proc/disfigure()
|
||||
if(disfigured)
|
||||
return
|
||||
if(owner)
|
||||
if(type == "brute")
|
||||
owner.visible_message("<span class='warning'>You hear a sickening cracking sound coming from \the [owner]'s [name].</span>", \
|
||||
"<span class='danger'>Your [name] becomes a mangled mess!</span>", \
|
||||
"<span class='warning'>You hear a sickening crack.</span>")
|
||||
else
|
||||
owner.visible_message("<span class='warning'>\The [owner]'s [name] melts away, turning into mangled mess!</span>", \
|
||||
"<span class='danger'>Your [name] melts away!</span>", \
|
||||
"<span class='warning'>You hear a sickening sizzle.</span>")
|
||||
disfigured = 1
|
||||
owner.visible_message("<span class='warning'>You hear a sickening sound coming from \the [owner]'s [name] as it turns into a mangled mess!</span>", \
|
||||
"<span class='danger'>Your [name] becomes a mangled mess!</span>", \
|
||||
"<span class='warning'>You hear a sickening sound.</span>")
|
||||
disfigured = TRUE
|
||||
|
||||
/obj/item/organ/external/is_primary_organ(var/mob/living/carbon/human/O = null)
|
||||
if(isnull(O))
|
||||
@@ -773,7 +764,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
|
||||
/obj/item/organ/external/serialize()
|
||||
var/list/data = ..()
|
||||
if(robotic == 2)
|
||||
if(is_robotic())
|
||||
data["company"] = model
|
||||
// If we wanted to store wound information, here is where it would go
|
||||
return data
|
||||
|
||||
@@ -25,7 +25,7 @@ var/global/list/limb_icon_cache = list()
|
||||
deform = new_deform ? new_deform : deform
|
||||
|
||||
/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/H)
|
||||
if(status & ORGAN_ROBOT && !(species && species.name == "Machine")) //machine people get skin color
|
||||
if(is_robotic() && !(species && species.name == "Machine")) //machine people get skin color
|
||||
return
|
||||
if(species && H.species && species.name != H.species.name)
|
||||
return
|
||||
@@ -44,7 +44,7 @@ var/global/list/limb_icon_cache = list()
|
||||
change_organ_icobase(C.icobase, C.deform)
|
||||
|
||||
/obj/item/organ/external/proc/sync_colour_to_dna()
|
||||
if(status & ORGAN_ROBOT)
|
||||
if(is_robotic())
|
||||
return
|
||||
if(!isnull(dna.GetUIValue(DNA_UI_SKIN_TONE)) && ((species.bodyflags & HAS_SKIN_TONE) || (species.bodyflags & HAS_ICON_SKIN_TONE)))
|
||||
s_col = null
|
||||
@@ -76,7 +76,7 @@ var/global/list/limb_icon_cache = list()
|
||||
var/icon_file = new_icons[1]
|
||||
var/new_icon_state = new_icons[2]
|
||||
mob_icon = new /icon(icon_file, new_icon_state)
|
||||
if(!skeletal && !(status & ORGAN_ROBOT))
|
||||
if(!skeletal && !is_robotic())
|
||||
if(status & ORGAN_DEAD)
|
||||
mob_icon.ColorTone(rgb(10,50,0))
|
||||
mob_icon.SetIntensity(0.7)
|
||||
@@ -172,7 +172,7 @@ var/global/list/limb_icon_cache = list()
|
||||
|
||||
if(skeletal)
|
||||
icon_file = 'icons/mob/human_races/r_skeleton.dmi'
|
||||
else if(status & ORGAN_ROBOT)
|
||||
else if(is_robotic())
|
||||
icon_file = 'icons/mob/human_races/robotic.dmi'
|
||||
else
|
||||
if(status & ORGAN_MUTATED)
|
||||
@@ -184,7 +184,7 @@ var/global/list/limb_icon_cache = list()
|
||||
|
||||
/obj/item/organ/external/chest/get_icon_state(skeletal)
|
||||
var/result = ..()
|
||||
if(fat && !skeletal && !(status & ORGAN_ROBOT) && (CAN_BE_FAT in species.species_traits))
|
||||
if(fat && !skeletal && !is_robotic() && (CAN_BE_FAT in species.species_traits))
|
||||
result[2] += "_fat"
|
||||
return result
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#define PROCESS_ACCURACY 10
|
||||
|
||||
/obj/item/organ/internal
|
||||
origin_tech = "biotech=3"
|
||||
force = 1
|
||||
@@ -7,7 +5,6 @@
|
||||
throwforce = 0
|
||||
var/slot
|
||||
// DO NOT add slots with matching names to different zones - it will break internal_organs_slot list!
|
||||
vital = 0
|
||||
var/non_primary = 0
|
||||
var/unremovable = FALSE //Whether it shows up as an option to remove during surgery.
|
||||
|
||||
@@ -90,9 +87,9 @@
|
||||
return
|
||||
|
||||
/obj/item/organ/internal/proc/prepare_eat()
|
||||
if(status == ORGAN_ROBOT)
|
||||
if(is_robotic())
|
||||
return //no eating cybernetic implants!
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/organ/S = new
|
||||
var/obj/item/reagent_containers/food/snacks/organ/S = new
|
||||
S.name = name
|
||||
S.desc = desc
|
||||
S.icon = icon
|
||||
@@ -108,12 +105,12 @@
|
||||
insert(H)
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/organ
|
||||
/obj/item/reagent_containers/food/snacks/organ
|
||||
name = "appendix"
|
||||
icon_state = "appendix"
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/organ/New()
|
||||
/obj/item/reagent_containers/food/snacks/organ/New()
|
||||
..()
|
||||
|
||||
reagents.add_reagent("nutriment", 5)
|
||||
@@ -121,7 +118,7 @@
|
||||
/obj/item/organ/internal/attack(mob/living/carbon/M, mob/user)
|
||||
if(M == user && ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/S = prepare_eat()
|
||||
var/obj/item/reagent_containers/food/snacks/S = prepare_eat()
|
||||
if(S)
|
||||
H.drop_item()
|
||||
H.put_in_active_hand(S)
|
||||
@@ -137,310 +134,21 @@
|
||||
|
||||
// Brain is defined in brain_item.dm.
|
||||
|
||||
/obj/item/organ/internal/heart
|
||||
name = "heart"
|
||||
icon_state = "heart-on"
|
||||
organ_tag = "heart"
|
||||
parent_organ = "chest"
|
||||
slot = "heart"
|
||||
origin_tech = "biotech=5"
|
||||
var/beating = 1
|
||||
dead_icon = "heart-off"
|
||||
var/icon_base = "heart"
|
||||
|
||||
/obj/item/organ/internal/heart/update_icon()
|
||||
if(beating)
|
||||
icon_state = "[icon_base]-on"
|
||||
else
|
||||
icon_state = "[icon_base]-off"
|
||||
|
||||
/obj/item/organ/internal/heart/remove(mob/living/carbon/M, special = 0)
|
||||
. = ..()
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.stat == DEAD)
|
||||
Stop()
|
||||
return
|
||||
|
||||
spawn(120)
|
||||
if(!owner)
|
||||
Stop()
|
||||
|
||||
/obj/item/organ/internal/heart/attack_self(mob/user)
|
||||
..()
|
||||
if(!beating)
|
||||
Restart()
|
||||
spawn(80)
|
||||
if(!owner)
|
||||
Stop()
|
||||
|
||||
/obj/item/organ/internal/heart/safe_replace(mob/living/carbon/human/target)
|
||||
Restart()
|
||||
..()
|
||||
|
||||
/obj/item/organ/internal/heart/proc/Stop()
|
||||
beating = 0
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/item/organ/internal/heart/proc/Restart()
|
||||
beating = 1
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/item/organ/internal/heart/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.icon_state = dead_icon
|
||||
return S
|
||||
|
||||
/obj/item/organ/internal/heart/cursed
|
||||
name = "cursed heart"
|
||||
desc = "it needs to be pumped..."
|
||||
icon_state = "cursedheart-off"
|
||||
icon_base = "cursedheart"
|
||||
origin_tech = "biotech=6"
|
||||
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
|
||||
var/last_pump = 0
|
||||
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/internal/heart/cursed/attack(mob/living/carbon/human/H, mob/living/carbon/human/user, obj/target)
|
||||
if(H == user && istype(H))
|
||||
if(NO_BLOOD in H.species.species_traits)
|
||||
to_chat(H, "<span class = 'userdanger'>\The [src] is not compatible with your form!</span>")
|
||||
return
|
||||
playsound(user,'sound/effects/singlebeat.ogg', 40, 1)
|
||||
user.drop_item()
|
||||
insert(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/internal/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(!(NO_BLOOD in H.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(H.client)
|
||||
H.client.color = "red" //bloody screen so real
|
||||
else
|
||||
last_pump = world.time //lets be extra fair *sigh*
|
||||
|
||||
/obj/item/organ/internal/heart/cursed/insert(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
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>")
|
||||
|
||||
|
||||
/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/internal/heart/cursed))
|
||||
var/obj/item/organ/internal/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(!(NO_BLOOD in H.species.species_traits))
|
||||
H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_NORMAL)
|
||||
if(owner.client)
|
||||
owner.client.color = ""
|
||||
|
||||
H.adjustBruteLoss(-cursed_heart.heal_brute)
|
||||
H.adjustFireLoss(-cursed_heart.heal_burn)
|
||||
H.adjustOxyLoss(-cursed_heart.heal_oxy)
|
||||
|
||||
/obj/item/organ/internal/kidneys
|
||||
name = "kidneys"
|
||||
icon_state = "kidneys"
|
||||
gender = PLURAL
|
||||
organ_tag = "kidneys"
|
||||
parent_organ = "groin"
|
||||
slot = "kidneys"
|
||||
|
||||
/obj/item/organ/internal/kidneys/on_life()
|
||||
// Coffee is really bad for you with busted kidneys.
|
||||
// This should probably be expanded in some way, but fucked if I know
|
||||
// what else kidneys can process in our reagent list.
|
||||
var/datum/reagent/coffee = locate(/datum/reagent/consumable/drink/coffee) in owner.reagents.reagent_list
|
||||
if(coffee)
|
||||
if(is_bruised())
|
||||
owner.adjustToxLoss(0.1 * PROCESS_ACCURACY)
|
||||
else if(is_broken())
|
||||
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
|
||||
|
||||
|
||||
/obj/item/organ/internal/eyes
|
||||
name = "eyeballs"
|
||||
icon_state = "eyes"
|
||||
gender = PLURAL
|
||||
organ_tag = "eyes"
|
||||
parent_organ = "head"
|
||||
slot = "eyes"
|
||||
var/eye_colour = "#000000"
|
||||
var/list/colourmatrix = null
|
||||
var/list/colourblind_matrix = MATRIX_GREYSCALE //Special colourblindness parameters. By default, it's black-and-white.
|
||||
var/list/replace_colours = LIST_GREYSCALE_REPLACE
|
||||
var/dependent_disabilities = null //Gets set by eye-dependent disabilities such as colourblindness so the eyes can transfer the disability during transplantation.
|
||||
var/dark_view = 2 //Default dark_view for Humans.
|
||||
var/weld_proof = null //If set, the eyes will not take damage during welding. eg. IPC optical sensors do not take damage when they weld things while all other eyes will.
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/update_colour()
|
||||
dna.write_eyes_attributes(src)
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/generate_icon(var/mob/living/carbon/human/HA)
|
||||
var/mob/living/carbon/human/H = HA
|
||||
if(!istype(H))
|
||||
H = owner
|
||||
var/icon/eyes_icon = new /icon('icons/mob/human_face.dmi', H.species.eyes)
|
||||
eyes_icon.Blend(eye_colour, ICON_ADD)
|
||||
|
||||
return eyes_icon
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/get_colourmatrix() //Returns a special colour matrix if the eyes are organic and the mob is colourblind, otherwise it uses the current one.
|
||||
if(!robotic && owner.disabilities & COLOURBLIND)
|
||||
return colourblind_matrix
|
||||
else
|
||||
return colourmatrix
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/get_dark_view() //Returns dark_view (if the eyes are organic) for see_invisible handling in species.dm to be autoprocessed by life().
|
||||
return dark_view
|
||||
|
||||
/obj/item/organ/internal/eyes/proc/shine()
|
||||
if(is_robotic() || (dark_view > EYE_SHINE_THRESHOLD))
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/internal/eyes/insert(mob/living/carbon/human/M, special = 0)
|
||||
..()
|
||||
if(istype(M) && eye_colour)
|
||||
M.update_body() //Apply our eye colour to the target.
|
||||
|
||||
if(!(M.disabilities & COLOURBLIND) && (dependent_disabilities & COLOURBLIND)) //If the eyes are colourblind and we're not, carry over the gene.
|
||||
dependent_disabilities &= ~COLOURBLIND
|
||||
M.dna.SetSEState(COLOURBLINDBLOCK,1)
|
||||
genemutcheck(M,COLOURBLINDBLOCK,null,MUTCHK_FORCED)
|
||||
else
|
||||
M.update_client_colour() //If we're here, that means the mob acquired the colourblindness gene while they didn't have eyes. Better handle it.
|
||||
|
||||
/obj/item/organ/internal/eyes/remove(mob/living/carbon/human/M, special = 0)
|
||||
if(!special && (M.disabilities & COLOURBLIND)) //If special is set, that means these eyes are getting deleted (i.e. during set_species())
|
||||
if(!(dependent_disabilities & COLOURBLIND)) //We only want to change COLOURBLINDBLOCK and such it the eyes are being surgically removed.
|
||||
dependent_disabilities |= COLOURBLIND
|
||||
M.dna.SetSEState(COLOURBLINDBLOCK,0)
|
||||
genemutcheck(M,COLOURBLINDBLOCK,null,MUTCHK_FORCED)
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/eyes/surgeryize()
|
||||
if(!owner)
|
||||
return
|
||||
owner.CureNearsighted()
|
||||
owner.CureBlind()
|
||||
owner.SetEyeBlurry(0)
|
||||
owner.SetEyeBlind(0)
|
||||
|
||||
/obj/item/organ/internal/robotize(var/icon_bypass) //If icon bypass isn't null, skip the processing here and go straight to the parent call.
|
||||
if(!icon_bypass && !(status & ORGAN_ROBOT)) //Don't override the icons for the already-mechanical IPC organs.
|
||||
/obj/item/organ/internal/robotize()
|
||||
if(!is_robotic())
|
||||
var/list/states = icon_states('icons/obj/surgery.dmi') //Insensitive to specially-defined icon files for species like the Drask or whomever else. Everyone gets the same robotic heart.
|
||||
if(slot == "heart" && ("[slot]-prosthetic-on" in states) && ("[slot]-prosthetic-off" in states)) //Give the robotic heart its robotic heart icons if they exist.
|
||||
if(slot == "heart" && ("[slot]-c-on" in states) && ("[slot]-c-off" in states)) //Give the robotic heart its robotic heart icons if they exist.
|
||||
var/obj/item/organ/internal/heart/H = src
|
||||
H.icon = icon('icons/obj/surgery.dmi')
|
||||
H.icon_base = "[slot]-prosthetic"
|
||||
H.dead_icon = "[slot]-prosthetic-off"
|
||||
H.icon_base = "[slot]-c"
|
||||
H.dead_icon = "[slot]-c-off"
|
||||
H.update_icon()
|
||||
else if("[slot]-prosthetic" in states) //Give the robotic organ its robotic organ icons if they exist.
|
||||
else if("[slot]-c" in states) //Give the robotic organ its robotic organ icons if they exist.
|
||||
icon = icon('icons/obj/surgery.dmi')
|
||||
icon_state = "[slot]-prosthetic"
|
||||
name = "mechanical [slot]"
|
||||
icon_state = "[slot]-c"
|
||||
name = "cybernetic [slot]"
|
||||
..() //Go apply all the organ flags/robotic statuses.
|
||||
|
||||
/obj/item/organ/internal/eyes/robotize()
|
||||
colourmatrix = null
|
||||
dark_view = 2
|
||||
..() //Make sure the organ's got the robotic status indicators before updating the client colour.
|
||||
if(owner)
|
||||
owner.update_client_colour(0) //Since both mechassisted and mechanical eyes give dark_view of 2 and full colour vision atm, just having this here is fine as mechassist() will call it anyway.
|
||||
|
||||
/obj/item/organ/internal/mechassist()
|
||||
..() //Go back, call robotize(), adjust the robotic status indicators and the organ damage parameters.
|
||||
var/list/states = icon_states(icon) //Sensitive to specially-defined icon files since the organs are not fully synthetic.
|
||||
if(slot == "heart" && ("[organ_tag]-assisted-on" in states) && ("[organ_tag]-assisted-off" in states)) //Give the mechassisted heart its mechassisted heart icons if they exist.
|
||||
var/obj/item/organ/internal/heart/H = src
|
||||
H.icon_base = "[organ_tag]-assisted"
|
||||
H.dead_icon = "[organ_tag]-assisted-off"
|
||||
H.update_icon()
|
||||
else if("[organ_tag]-assisted" in states) //Give the mechassisted organ its mechassisted organ icons if they exist.
|
||||
icon_state = "[organ_tag]-assisted"
|
||||
name = "mechanically assisted [initial(name)]" //Avoid setting the organ's name to something like "mechanically assisted mechanical eyes".
|
||||
|
||||
/obj/item/organ/internal/liver
|
||||
name = "liver"
|
||||
icon_state = "liver"
|
||||
organ_tag = "liver"
|
||||
parent_organ = "groin"
|
||||
slot = "liver"
|
||||
var/alcohol_intensity = 1
|
||||
|
||||
/obj/item/organ/internal/liver/on_life()
|
||||
if(germ_level > INFECTION_LEVEL_ONE)
|
||||
if(prob(1))
|
||||
to_chat(owner, "<span class='warning'> Your skin itches.</span>")
|
||||
if(germ_level > INFECTION_LEVEL_TWO)
|
||||
if(prob(1))
|
||||
spawn owner.vomit()
|
||||
|
||||
if(owner.life_tick % PROCESS_ACCURACY == 0)
|
||||
|
||||
//High toxins levels are dangerous
|
||||
if(owner.getToxLoss() >= 60 && !owner.reagents.has_reagent("charcoal"))
|
||||
//Healthy liver suffers on its own
|
||||
if(damage < min_broken_damage)
|
||||
receive_damage(0.2 * PROCESS_ACCURACY)
|
||||
//Damaged one shares the fun
|
||||
else
|
||||
var/obj/item/organ/internal/O = pick(owner.internal_organs)
|
||||
if(O)
|
||||
O.receive_damage(0.2 * PROCESS_ACCURACY)
|
||||
|
||||
//Detox can heal small amounts of damage
|
||||
if(damage && damage < min_bruised_damage && owner.reagents.has_reagent("charcoal"))
|
||||
receive_damage(-0.2 * PROCESS_ACCURACY)
|
||||
|
||||
// Get the effectiveness of the liver.
|
||||
var/filter_effect = 3
|
||||
if(is_bruised())
|
||||
filter_effect -= 1
|
||||
if(is_broken())
|
||||
filter_effect -= 2
|
||||
|
||||
// Damaged liver means some chemicals are very dangerous
|
||||
if(damage >= min_bruised_damage)
|
||||
for(var/datum/reagent/R in owner.reagents.reagent_list)
|
||||
// Ethanol and all drinks are bad
|
||||
if(istype(R, /datum/reagent/consumable/ethanol))
|
||||
owner.adjustToxLoss(0.1 * PROCESS_ACCURACY)
|
||||
|
||||
// Can't cope with toxins at all
|
||||
for(var/toxin in list("toxin", "plasma", "sacid", "facid", "cyanide", "amanitin", "carpotoxin"))
|
||||
if(owner.reagents.has_reagent(toxin))
|
||||
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
|
||||
|
||||
/obj/item/organ/internal/appendix
|
||||
name = "appendix"
|
||||
icon_state = "appendix"
|
||||
|
||||
@@ -1,41 +1,28 @@
|
||||
mob/var/list/pain_stored = list()
|
||||
mob/var/last_pain_message = ""
|
||||
mob/var/next_pain_time = 0
|
||||
/mob/living/carbon/human
|
||||
var/last_pain_message = ""
|
||||
var/next_pain_time = 0
|
||||
|
||||
// partname is the name of a body part
|
||||
// amount is a num from 1 to 100
|
||||
mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0)
|
||||
if(stat >= 2) return
|
||||
/mob/living/carbon/human/proc/pain(partname, amount)
|
||||
if(stat >= UNCONSCIOUS)
|
||||
return
|
||||
if(reagents.has_reagent("sal_acid"))
|
||||
return
|
||||
if(reagents.has_reagent("morphine"))
|
||||
return
|
||||
if(reagents.has_reagent("hydrocodone"))
|
||||
return
|
||||
if(world.time < next_pain_time && !force)
|
||||
if(world.time < next_pain_time)
|
||||
return
|
||||
if(amount > 10 && istype(src,/mob/living/carbon/human))
|
||||
if(paralysis)
|
||||
AdjustParalysis(-round(amount/10))
|
||||
if(amount > 50 && prob(amount / 5))
|
||||
src:drop_item()
|
||||
var/msg
|
||||
if(burning)
|
||||
switch(amount)
|
||||
if(1 to 10)
|
||||
msg = "<span class='danger'>Your [partname] burns.</span>"
|
||||
if(11 to 90)
|
||||
msg = "<span class='danger'><font size=2>Your [partname] burns badly!</font></span>"
|
||||
if(91 to 10000)
|
||||
msg = "<span class='danger'><font size=3>OH GOD! Your [partname] is on fire!</font></span>"
|
||||
else
|
||||
switch(amount)
|
||||
if(1 to 10)
|
||||
msg = "<b>Your [partname] hurts.</b>"
|
||||
if(11 to 90)
|
||||
msg = "<b><font size=2>Your [partname] hurts badly.</font></b>"
|
||||
if(91 to 10000)
|
||||
msg = "<b><font size=3>OH GOD! Your [partname] is hurting terribly!</font></b>"
|
||||
switch(amount)
|
||||
if(1 to 10)
|
||||
msg = "<b>Your [partname] hurts.</b>"
|
||||
if(11 to 90)
|
||||
msg = "<b><font size=2>Your [partname] hurts badly.</font></b>"
|
||||
if(91 to INFINITY)
|
||||
msg = "<b><font size=3>OH GOD! Your [partname] is hurting terribly!</font></b>"
|
||||
if(msg && (msg != last_pain_message || prob(10)))
|
||||
last_pain_message = msg
|
||||
to_chat(src, msg)
|
||||
@@ -43,20 +30,18 @@ mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0
|
||||
|
||||
|
||||
// message is the custom message to be displayed
|
||||
// flash_strength is 0 for weak pain flash, 1 for strong pain flash
|
||||
mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength)
|
||||
if(stat >= 1) return
|
||||
mob/living/carbon/human/proc/custom_pain(message)
|
||||
if(stat >= UNCONSCIOUS)
|
||||
return
|
||||
|
||||
if(NO_PAIN in species.species_traits)
|
||||
return
|
||||
|
||||
if(reagents.has_reagent("morphine"))
|
||||
return
|
||||
if(reagents.has_reagent("hydrocodone"))
|
||||
return
|
||||
var/msg = "<span class='danger'>[message]</span>"
|
||||
if(flash_strength >= 1)
|
||||
msg = "<span class='warning'><font size=3><b>[message]</b></font></span>"
|
||||
|
||||
var/msg = "<span class='userdanger'>[message]</span>"
|
||||
|
||||
// Anti message spam checks
|
||||
if(msg && ((msg != last_pain_message) || (world.time >= next_pain_time)))
|
||||
@@ -67,70 +52,33 @@ mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength)
|
||||
mob/living/carbon/human/proc/handle_pain()
|
||||
// not when sleeping
|
||||
|
||||
if(NO_PAIN in species.species_traits)
|
||||
//While synthetics don't feel pain, they will notice their gears gunking up with residue (toxins)
|
||||
if(isSynthetic())
|
||||
var/toxDamageMessage = null
|
||||
var/toxMessageProb = 1
|
||||
switch(getToxLoss())
|
||||
if(25 to 50)
|
||||
toxMessageProb = 1
|
||||
toxDamageMessage = "Your servos seem to be working harder."
|
||||
if(50 to 75)
|
||||
toxMessageProb = 2
|
||||
toxDamageMessage = "Your joints seem to stick randomly."
|
||||
if(75 to INFINITY)
|
||||
toxMessageProb = 5
|
||||
toxDamageMessage = "Your motors seem to slip; it really grinds your gears!"
|
||||
if(toxDamageMessage && prob(toxMessageProb))
|
||||
src.custom_pain(toxDamageMessage, getToxLoss() >= 15)
|
||||
if(stat >= UNCONSCIOUS)
|
||||
return
|
||||
if(NO_PAIN in species.species_traits)
|
||||
return
|
||||
|
||||
if(stat >= 2) return
|
||||
if(reagents.has_reagent("morphine"))
|
||||
return
|
||||
if(reagents.has_reagent("hydrocodone"))
|
||||
return
|
||||
|
||||
var/maxdam = 0
|
||||
var/obj/item/organ/external/damaged_organ = null
|
||||
for(var/obj/item/organ/external/E in bodyparts)
|
||||
if(E.status & ORGAN_DEAD|ORGAN_ROBOT) continue
|
||||
if((E.status & ORGAN_DEAD|ORGAN_ROBOT) || E.hidden_pain)
|
||||
continue
|
||||
var/dam = E.get_damage()
|
||||
// make the choice of the organ depend on damage,
|
||||
// but also sometimes use one of the less damaged ones
|
||||
if(dam > maxdam && (maxdam == 0 || prob(70)) )
|
||||
if(dam > maxdam && (maxdam == 0 || prob(70)))
|
||||
damaged_organ = E
|
||||
maxdam = dam
|
||||
if(damaged_organ)
|
||||
pain(damaged_organ.name, maxdam, 0)
|
||||
|
||||
pain(damaged_organ.name, maxdam)
|
||||
|
||||
// Damage to internal organs hurts a lot.
|
||||
for(var/obj/item/organ/internal/I in internal_organs)
|
||||
if(istype(I, /obj/item/organ/internal/brain)) //the brain has no pain receptors, and brain damage is meant to be a stealthy damage type.
|
||||
if(I.hidden_pain)
|
||||
continue
|
||||
if(I.damage > 2) if(prob(2))
|
||||
if(I.damage > 2 && prob(2))
|
||||
var/obj/item/organ/external/parent = get_organ(I.parent_organ)
|
||||
src.custom_pain("You feel a sharp pain in your [parent.limb_name]", 1)
|
||||
|
||||
var/toxDamageMessage = null
|
||||
var/toxMessageProb = 1
|
||||
switch(getToxLoss())
|
||||
if(1 to 5)
|
||||
toxMessageProb = 1
|
||||
toxDamageMessage = "Your body stings slightly."
|
||||
if(6 to 10)
|
||||
toxMessageProb = 2
|
||||
toxDamageMessage = "Your whole body hurts a little."
|
||||
if(11 to 15)
|
||||
toxMessageProb = 2
|
||||
toxDamageMessage = "Your whole body hurts."
|
||||
if(15 to 25)
|
||||
toxMessageProb = 3
|
||||
toxDamageMessage = "Your whole body hurts badly."
|
||||
if(26 to INFINITY)
|
||||
toxMessageProb = 5
|
||||
toxDamageMessage = "Your body aches all over, it's driving you mad."
|
||||
|
||||
if(toxDamageMessage && prob(toxMessageProb))
|
||||
src.custom_pain(toxDamageMessage, getToxLoss() >= 15)
|
||||
custom_pain("You feel a sharp pain in your [parent.limb_name]")
|
||||
@@ -35,7 +35,8 @@
|
||||
/obj/item/organ/internal/body_egg/spider_eggs/remove(var/mob/living/carbon/M, var/special = 0)
|
||||
..()
|
||||
M.reagents.del_reagent("spidereggs") //purge all remaining spider eggs reagent if caught, in time.
|
||||
qdel(src) //We don't want people re-implanting these for near instant gibbings.
|
||||
if(!QDELETED(src))
|
||||
qdel(src) // prevent people re-implanting them into others
|
||||
return null
|
||||
|
||||
|
||||
@@ -82,7 +83,7 @@
|
||||
// Actually, let's make it slightly worse... just to discourage people from bringing back infections.
|
||||
alternate_ending = 1
|
||||
to_chat(owner,"<span class='danger'>The shapes extend tendrils out of your wound... no... those are legs! SPIDER LEGS! You have spiderlings growing inside you! You scratch at the wound, but it just aggrivates them - they swarm out of the wound, biting you all over!</span>")
|
||||
owner.visible_message("<span class='danger'>[owner] flails around on the floor as spiderlings erupt from their skin and swarm all over them! </span>")
|
||||
owner.visible_message("<span class='danger'>[owner] flails around on the floor as spiderlings erupt from [owner.p_their()] skin and swarm all over them! </span>")
|
||||
owner.Stun(20)
|
||||
owner.Weaken(20)
|
||||
// yes, this is a long stun - that's intentional. Gotta give the spiderlings time to escape.
|
||||
@@ -114,5 +115,6 @@
|
||||
|
||||
/obj/item/organ/internal/body_egg/terror_eggs/remove(var/mob/living/carbon/M, var/special = 0)
|
||||
..()
|
||||
qdel(src) // prevent people re-implanting them into others
|
||||
if(!QDELETED(src))
|
||||
qdel(src) // prevent people re-implanting them into others
|
||||
return null
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
/obj/item/weapon/skeleton
|
||||
/obj/item/skeleton
|
||||
name ="skeleton"
|
||||
desc = "skeleton parent object."
|
||||
icon = 'icons/mob/human_races/r_skeleton.dmi'
|
||||
|
||||
|
||||
/obj/item/weapon/skeleton/head
|
||||
/obj/item/skeleton/head
|
||||
name = "skull"
|
||||
desc = "a skeleton skull, would make a nice paperweight."
|
||||
icon_state = "head"
|
||||
|
||||
/obj/item/weapon/skeleton/r_hand
|
||||
/obj/item/skeleton/r_hand
|
||||
name = "skeleton right hand"
|
||||
desc = "a skeleton right hand."
|
||||
icon_state = "r_hand"
|
||||
|
||||
/obj/item/weapon/skeleton/r_arm
|
||||
/obj/item/skeleton/r_arm
|
||||
name = "skeleton right arm"
|
||||
desc = "a skeleton right arm."
|
||||
icon_state = "r_arm"
|
||||
|
||||
/obj/item/weapon/skeleton/l_hand
|
||||
/obj/item/skeleton/l_hand
|
||||
name = "skeleton left hand"
|
||||
desc = "a skeleton left hand."
|
||||
icon_state = "l_hand"
|
||||
|
||||
/obj/item/weapon/skeleton/l_arm
|
||||
/obj/item/skeleton/l_arm
|
||||
name = "skeleton left arm"
|
||||
desc = "a skeleton left arm."
|
||||
icon_state = "l_arm"
|
||||
|
||||
/obj/item/weapon/skeleton/r_foot
|
||||
/obj/item/skeleton/r_foot
|
||||
name = "skeleton right foot"
|
||||
desc = "a skeleton right foot."
|
||||
icon_state = "r_foot"
|
||||
|
||||
/obj/item/weapon/skeleton/r_leg
|
||||
/obj/item/skeleton/r_leg
|
||||
name = "skeleton right leg"
|
||||
desc = "a skeleton right leg"
|
||||
icon_state = "r_leg"
|
||||
|
||||
/obj/item/weapon/skeleton/l_foot
|
||||
/obj/item/skeleton/l_foot
|
||||
name = "skeleton left foot"
|
||||
desc = "a skeleton left foot"
|
||||
icon_state = "l_foot"
|
||||
|
||||
/obj/item/weapon/skeleton/l_leg
|
||||
/obj/item/skeleton/l_leg
|
||||
name = "skeleton left leg"
|
||||
desc = "a skeleton left leg"
|
||||
icon_state = "l_leg"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// IPC limbs.
|
||||
/obj/item/organ/external/head/ipc
|
||||
can_intake_reagents = 0
|
||||
vital = 0
|
||||
max_damage = 50 //made same as arm, since it is not vital
|
||||
min_broken_damage = 30
|
||||
encased = null
|
||||
@@ -109,7 +108,7 @@
|
||||
organ_tag = "heart"
|
||||
parent_organ = "chest"
|
||||
slot = "heart"
|
||||
vital = 1
|
||||
vital = TRUE
|
||||
status = ORGAN_ROBOT
|
||||
species = "Machine"
|
||||
|
||||
@@ -142,12 +141,12 @@
|
||||
name = "brain"
|
||||
organ_tag = "brain"
|
||||
parent_organ = "chest"
|
||||
vital = 1
|
||||
vital = TRUE
|
||||
max_damage = 200
|
||||
slot = "brain"
|
||||
status = ORGAN_ROBOT
|
||||
species = "Machine"
|
||||
var/obj/item/device/mmi/stored_mmi
|
||||
var/obj/item/mmi/stored_mmi
|
||||
|
||||
/obj/item/organ/internal/brain/mmi_holder/Destroy()
|
||||
QDEL_NULL(stored_mmi)
|
||||
@@ -167,7 +166,8 @@
|
||||
stored_mmi.forceMove(get_turf(owner))
|
||||
stored_mmi = null
|
||||
..()
|
||||
qdel(src)
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/item/organ/internal/brain/mmi_holder/proc/update_from_mmi()
|
||||
if(!stored_mmi)
|
||||
@@ -180,15 +180,16 @@
|
||||
|
||||
/obj/item/organ/internal/brain/mmi_holder/posibrain/New()
|
||||
robotize()
|
||||
stored_mmi = new /obj/item/device/mmi/posibrain/ipc(src)
|
||||
stored_mmi = new /obj/item/mmi/posibrain/ipc(src)
|
||||
..()
|
||||
spawn(1)
|
||||
if(owner)
|
||||
stored_mmi.name = "positronic brain ([owner.real_name])"
|
||||
stored_mmi.brainmob.real_name = owner.real_name
|
||||
stored_mmi.brainmob.name = stored_mmi.brainmob.real_name
|
||||
stored_mmi.icon_state = "posibrain-occupied"
|
||||
update_from_mmi()
|
||||
else
|
||||
stored_mmi.loc = get_turf(src)
|
||||
qdel(src)
|
||||
if(!QDELETED(src))
|
||||
if(owner)
|
||||
stored_mmi.name = "positronic brain ([owner.real_name])"
|
||||
stored_mmi.brainmob.real_name = owner.real_name
|
||||
stored_mmi.brainmob.name = stored_mmi.brainmob.real_name
|
||||
stored_mmi.icon_state = "posibrain-occupied"
|
||||
update_from_mmi()
|
||||
else
|
||||
stored_mmi.loc = get_turf(src)
|
||||
qdel(src)
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
slot = "headpocket"
|
||||
species = "Skrell"
|
||||
actions_types = list(/datum/action/item_action/organ_action/toggle)
|
||||
var/obj/item/weapon/storage/internal/pocket
|
||||
var/obj/item/storage/internal/pocket
|
||||
|
||||
/obj/item/organ/internal/headpocket/New()
|
||||
..()
|
||||
pocket = new /obj/item/weapon/storage/internal(src)
|
||||
pocket = new /obj/item/storage/internal(src)
|
||||
pocket.storage_slots = 1
|
||||
// Allow adjacency calculation to work properly
|
||||
loc = owner
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
min_broken_damage = 35
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
body_part = UPPER_TORSO
|
||||
vital = 1
|
||||
vital = TRUE
|
||||
amputation_point = "spine"
|
||||
gendered_icon = 1
|
||||
parent_organ = null
|
||||
@@ -44,7 +44,7 @@
|
||||
min_broken_damage = 35
|
||||
w_class = WEIGHT_CLASS_BULKY // if you know what I mean ;)
|
||||
body_part = LOWER_TORSO
|
||||
vital = 1
|
||||
vital = TRUE
|
||||
parent_organ = "chest"
|
||||
amputation_point = "lumbar"
|
||||
gendered_icon = 1
|
||||
@@ -158,7 +158,6 @@
|
||||
min_broken_damage = 35
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
body_part = HEAD
|
||||
vital = 1
|
||||
parent_organ = "chest"
|
||||
amputation_point = "neck"
|
||||
gendered_icon = 1
|
||||
@@ -211,11 +210,8 @@
|
||||
/obj/item/organ/external/head/receive_damage(brute, burn, sharp, used_weapon = null, list/forbidden_limbs = list(), ignore_resists = FALSE)
|
||||
..(brute, burn, sharp, used_weapon, forbidden_limbs, ignore_resists)
|
||||
if(!disfigured)
|
||||
if(brute_dam > 40)
|
||||
if(prob(50))
|
||||
disfigure("brute")
|
||||
if(burn_dam > 40)
|
||||
disfigure("burn")
|
||||
if(brute_dam + burn_dam > 50)
|
||||
disfigure()
|
||||
|
||||
/obj/item/organ/external/head/proc/handle_alt_icon()
|
||||
if(alt_head && alt_heads_list[alt_head])
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
parent_organ = "head"
|
||||
organ_tag = "stack"
|
||||
slot = "vox_stack"
|
||||
robotic = 2
|
||||
vital = 1
|
||||
status = ORGAN_ROBOT
|
||||
vital = TRUE
|
||||
var/stackdamaged = FALSE
|
||||
|
||||
/obj/item/organ/internal/stack/vox
|
||||
|
||||
Reference in New Issue
Block a user