mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-21 03:55:05 +01:00
Merge branch 'master' into splint_nerf
This commit is contained in:
@@ -101,7 +101,7 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, damaging the bone in [target]'s [affected.name] with \the [tool]!</span>" , \
|
||||
"<span class='warning'> Your hand slips, damaging the bone in [target]'s [affected.name] with \the [tool]!</span>")
|
||||
affected.createwound(BRUISE, 5)
|
||||
affected.take_damage(5)
|
||||
return 0
|
||||
|
||||
/datum/surgery_step/mend_skull
|
||||
@@ -135,7 +135,7 @@
|
||||
user.visible_message("<span class='warning'>[user]'s hand slips, damaging [target]'s face with \the [tool]!</span>" , \
|
||||
"<span class='warning'>Your hand slips, damaging [target]'s face with \the [tool]!</span>")
|
||||
var/obj/item/organ/external/head/h = affected
|
||||
h.createwound(BRUISE, 10)
|
||||
h.take_damage(10)
|
||||
h.disfigured = 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
//Procedures in this file: Putting items in body cavity. Implant removal. Items removal.
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// ITEM PLACEMENT SURGERY //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/surgery/cavity_implant
|
||||
name = "Cavity Implant/Removal"
|
||||
steps = list(/datum/surgery_step/generic/cut_open,/datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/open_encased/saw,
|
||||
@@ -68,7 +61,7 @@
|
||||
var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!</span>", \
|
||||
"<span class='warning'> Your hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!</span>")
|
||||
affected.createwound(CUT, 20)
|
||||
affected.take_damage(20)
|
||||
|
||||
/datum/surgery_step/cavity/make_space
|
||||
name = "make cavity space"
|
||||
@@ -195,202 +188,18 @@
|
||||
"<span class='notice'> You put \the [tool] inside [target]'s [get_cavity(affected)] cavity.</span>" )
|
||||
if((tool.w_class > get_max_wclass(affected)/2 && prob(50) && !(affected.status & ORGAN_ROBOT)))
|
||||
to_chat(user, "<span class='warning'> You tear some vessels trying to fit the object in the cavity.</span>")
|
||||
var/datum/wound/internal_bleeding/I = new ()
|
||||
affected.wounds += I
|
||||
affected.internal_bleeding = TRUE
|
||||
affected.owner.custom_pain("You feel something rip in your [affected.name]!", 1)
|
||||
user.drop_item()
|
||||
target.internal_organs += tool
|
||||
affected.hidden = tool
|
||||
tool.forceMove(affected)
|
||||
return 1
|
||||
else
|
||||
if(IC)
|
||||
user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "<span class='notice'>You pull [IC] out of [target]'s [target_zone].</span>")
|
||||
user.put_in_hands(IC)
|
||||
target.internal_organs -= IC
|
||||
affected.hidden = null
|
||||
return 1
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You don't find anything in [target]'s [target_zone].</span>")
|
||||
return 0
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// IMPLANT/ITEM REMOVAL SURGERY //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/surgery/cavity_implant_rem
|
||||
name = "Implant Removal"
|
||||
steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin,/datum/surgery_step/cavity/implant_removal,/datum/surgery_step/cavity/close_space,/datum/surgery_step/generic/cauterize/)
|
||||
possible_locs = list("chest")//head is for borers..i can put it elsewhere
|
||||
|
||||
/datum/surgery/cavity_implant_rem/synth
|
||||
name = "Implant Removal"
|
||||
steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/cavity/implant_removal,/datum/surgery_step/robotics/external/close_hatch)
|
||||
possible_locs = list("chest")//head is for borers..i can put it elsewhere
|
||||
|
||||
/datum/surgery/cavity_implant_rem/can_start(mob/user, mob/living/carbon/human/target)
|
||||
if(!istype(target))
|
||||
return 0
|
||||
var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(affected.status & ORGAN_ROBOT)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/surgery/cavity_implant_rem/synth/can_start(mob/user, mob/living/carbon/human/target)
|
||||
if(!istype(target))
|
||||
return 0
|
||||
var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(!(affected.status & ORGAN_ROBOT))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/cavity/implant_removal
|
||||
name = "extract implant"
|
||||
allowed_tools = list(
|
||||
/obj/item/weapon/hemostat = 100, \
|
||||
/obj/item/weapon/wirecutters = 75, \
|
||||
/obj/item/weapon/kitchen/utensil/fork = 20
|
||||
)
|
||||
var/obj/item/weapon/implant/I = null
|
||||
time = 64
|
||||
|
||||
/datum/surgery_step/cavity/implant_removal/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
I = locate(/obj/item/weapon/implant) in target
|
||||
user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \
|
||||
"You start poking around inside [target]'s [affected.name] with \the [tool]." )
|
||||
target.custom_pain("The pain in your [affected.name] is living hell!",1)
|
||||
..()
|
||||
|
||||
/datum/surgery_step/cavity/implant_removal/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
I = locate(/obj/item/weapon/implant) in target
|
||||
if(I && (target_zone == "chest")) //implant removal only works on the chest.
|
||||
user.visible_message("<span class='notice'>[user] takes something out of [target]'s [affected.name] with \the [tool].</span>", \
|
||||
"<span class='notice'>You take [I] out of [target]'s [affected.name]s with \the [tool].</span>" )
|
||||
|
||||
I.removed(target)
|
||||
|
||||
var/obj/item/weapon/implantcase/case
|
||||
|
||||
if(istype(user.get_item_by_slot(slot_l_hand), /obj/item/weapon/implantcase))
|
||||
case = user.get_item_by_slot(slot_l_hand)
|
||||
else if(istype(user.get_item_by_slot(slot_r_hand), /obj/item/weapon/implantcase))
|
||||
case = user.get_item_by_slot(slot_r_hand)
|
||||
else
|
||||
case = locate(/obj/item/weapon/implantcase) in get_turf(target)
|
||||
|
||||
if(case && !case.imp)
|
||||
case.imp = I
|
||||
I.loc = case
|
||||
case.update_icon()
|
||||
user.visible_message("[user] places [I] into [case]!", "<span class='notice'>You place [I] into [case].</span>")
|
||||
else
|
||||
qdel(I)
|
||||
return 1
|
||||
else
|
||||
user.visible_message("<span class='notice'> [user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.</span>", \
|
||||
"<span class='notice'>You could not find anything inside [target]'s [affected.name].</span>")
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/cavity/implant_removal/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
..()
|
||||
var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
|
||||
if(affected.implants.len)
|
||||
var/fail_prob = 10
|
||||
fail_prob += 100 - tool_quality(tool)
|
||||
if(prob(fail_prob))
|
||||
var/obj/item/weapon/implant/imp = affected.implants[1]
|
||||
user.visible_message("<span class='warning'> Something beeps inside [target]'s [affected.name]!</span>")
|
||||
playsound(imp.loc, 'sound/items/countdown.ogg', 75, 1, -3)
|
||||
spawn(25)
|
||||
imp.activate()
|
||||
return 0
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// EMBEDDED ITEM REOMOVAL //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/surgery/embedded_removal
|
||||
name = "Removal of Embedded Objects"
|
||||
steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/remove_object, /datum/surgery_step/generic/cauterize)
|
||||
possible_locs = list("r_arm","l_arm","r_leg","l_leg","r_hand","r_foot","l_hand","l_foot","groin","chest","head")
|
||||
|
||||
/datum/surgery/embedded_removal/synth
|
||||
steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch, /datum/surgery_step/remove_object, /datum/surgery_step/robotics/external/close_hatch)
|
||||
possible_locs = list("r_arm","l_arm","r_leg","l_leg","r_hand","r_foot","l_hand","l_foot","groin","chest","head")
|
||||
|
||||
|
||||
/datum/surgery/embedded_removal/can_start(mob/user, mob/living/carbon/human/target)
|
||||
if(!istype(target))
|
||||
return 0
|
||||
var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(affected.status & ORGAN_ROBOT)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/surgery/embedded_removal/synth/can_start(mob/user, mob/living/carbon/human/target)
|
||||
if(!istype(target))
|
||||
return 0
|
||||
var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(!(affected.status & ORGAN_ROBOT))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/remove_object
|
||||
name = "remove embedded objects"
|
||||
time = 32
|
||||
allowed_tools = list(
|
||||
/obj/item/weapon/scalpel/laser/manager = 100, \
|
||||
/obj/item/weapon/hemostat = 100, \
|
||||
/obj/item/stack/cable_coil = 75, \
|
||||
/obj/item/device/assembly/mousetrap = 20
|
||||
)
|
||||
var/obj/item/organ/external/L = null
|
||||
|
||||
|
||||
/datum/surgery_step/remove_object/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
L = target.get_organ(target_zone)
|
||||
if(L)
|
||||
user.visible_message("[user] looks for objects embedded in [target]'s [target_zone].", "<span class='notice'>You look for objects embedded in [target]'s [target_zone]...</span>")
|
||||
else
|
||||
user.visible_message("[user] looks for [target]'s [target_zone].", "<span class='notice'>You look for [target]'s [target_zone]...</span>")
|
||||
|
||||
|
||||
/datum/surgery_step/remove_object/end_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
if(L)
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/objects = 0
|
||||
for(var/obj/item/I in L.implants)
|
||||
if(!istype(I,/obj/item/weapon/implant))
|
||||
objects++
|
||||
I.forceMove(get_turf(H))
|
||||
L.implants -= I
|
||||
|
||||
//Handle possessive brain borers.
|
||||
if(H.has_brain_worms() && target_zone == "head")//remove worms outside the loop
|
||||
var/mob/living/simple_animal/borer/worm = H.has_brain_worms()
|
||||
if(worm.controlling)
|
||||
target.release_control()
|
||||
worm.detach()
|
||||
worm.leave_host()
|
||||
user.visible_message("a slug like creature wiggles out of [H]'s [target_zone]!")
|
||||
|
||||
if(objects > 0)
|
||||
user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L.limb_name]!", "<span class='notice'>You sucessfully remove [objects] objects from [H]'s [L.limb_name].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You find no objects embedded in [H]'s [L.limb_name]!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't find [target]'s [target_zone], let alone any objects embedded in it!</span>")
|
||||
|
||||
return 1
|
||||
return 0
|
||||
@@ -61,7 +61,7 @@
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, cracking [target]'s [affected.encased] with \the [tool]!</span>" , \
|
||||
"<span class='warning'> Your hand slips, cracking [target]'s [affected.encased] with \the [tool]!</span>" )
|
||||
|
||||
affected.createwound(CUT, 20)
|
||||
affected.take_damage(20)
|
||||
affected.fracture()
|
||||
|
||||
return 0
|
||||
@@ -113,7 +113,7 @@
|
||||
var/self_msg = "<span class='warning'> Your hand slips, cracking [target]'s [affected.encased]!</span>"
|
||||
user.visible_message(msg, self_msg)
|
||||
|
||||
affected.createwound(BRUISE, 20)
|
||||
affected.take_damage(20)
|
||||
affected.fracture()
|
||||
|
||||
return 0
|
||||
@@ -164,7 +164,7 @@
|
||||
var/self_msg = "<span class='warning'> Your hand slips, bending [target]'s [affected.encased] the wrong way!</span>"
|
||||
user.visible_message(msg, self_msg)
|
||||
|
||||
affected.createwound(BRUISE, 20)
|
||||
affected.take_damage(20)
|
||||
affected.fracture()
|
||||
|
||||
return 0
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, slicing [target]'s throat wth \the [tool]!</span>" , \
|
||||
"<span class='warning'> Your hand slips, slicing [target]'s throat wth \the [tool]!</span>" )
|
||||
affected.createwound(CUT, 60)
|
||||
affected.take_damage(60)
|
||||
target.AdjustLoseBreath(4)
|
||||
|
||||
return 0
|
||||
@@ -106,7 +106,7 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, tearing skin on [target]'s face with \the [tool]!</span>", \
|
||||
"<span class='warning'> Your hand slips, tearing skin on [target]'s face with \the [tool]!</span>")
|
||||
target.apply_damage(10, BRUTE, affected, sharp=1, edge=1)
|
||||
target.apply_damage(10, BRUTE, affected, sharp = 1)
|
||||
return 0
|
||||
|
||||
/datum/surgery_step/face/cauterize
|
||||
@@ -131,7 +131,6 @@
|
||||
user.visible_message("<span class='notice'> [user] cauterizes the incision on [target]'s face and neck with \the [tool].</span>", \
|
||||
"<span class='notice'> You cauterize the incision on [target]'s face and neck with \the [tool].</span>")
|
||||
affected.open = 0
|
||||
affected.status &= ~ORGAN_BLEEDING
|
||||
var/obj/item/organ/external/head/h = affected
|
||||
h.disfigured = 0
|
||||
h.update_icon()
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
if(affected == null)
|
||||
return 0
|
||||
if(affected.status & ORGAN_DESTROYED)
|
||||
return 0
|
||||
if(affected.status & ORGAN_ROBOT)
|
||||
return 0
|
||||
return 1
|
||||
@@ -47,14 +45,13 @@
|
||||
user.visible_message("<span class='notice'> [user] has made an incision on [target]'s [affected.name] with \the [tool].</span>", \
|
||||
"<span class='notice'> You have made an incision on [target]'s [affected.name] with \the [tool].</span>",)
|
||||
affected.open = 1
|
||||
affected.status |= ORGAN_BLEEDING
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/generic/cut_open/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, slicing open [target]'s [affected.name] in a wrong spot with \the [tool]!</span>", \
|
||||
"<span class='warning'> Your hand slips, slicing open [target]'s [affected.name] in a wrong spot with \the [tool]!</span>")
|
||||
affected.createwound(CUT, 10)
|
||||
affected.take_damage(10)
|
||||
return 0
|
||||
|
||||
/datum/surgery_step/generic/clamp_bleeders
|
||||
@@ -81,7 +78,6 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='notice'> [user] clamps bleeders in [target]'s [affected.name] with \the [tool]</span>.", \
|
||||
"<span class='notice'> You clamp bleeders in [target]'s [affected.name] with \the [tool].</span>")
|
||||
affected.clamp()
|
||||
spread_germs_to_organ(affected, user, tool)
|
||||
return 1
|
||||
|
||||
@@ -89,7 +85,7 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, tearing blood vessals and causing massive bleeding in [target]'s [affected.name] with \the [tool]!</span>", \
|
||||
"<span class='warning'> Your hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.name] with \the [tool]!</span>",)
|
||||
affected.createwound(CUT, 10)
|
||||
affected.take_damage(10)
|
||||
return 0
|
||||
|
||||
/datum/surgery_step/generic/retract_skin
|
||||
@@ -143,7 +139,7 @@
|
||||
msg = "<span class='warning'> [user]'s hand slips, damaging several organs [target]'s lower abdomen with \the [tool]</span>"
|
||||
self_msg = "<span class='warning'> Your hand slips, damaging several organs [target]'s lower abdomen with \the [tool]!</span>"
|
||||
user.visible_message(msg, self_msg)
|
||||
target.apply_damage(12, BRUTE, affected, sharp=1)
|
||||
target.apply_damage(12, BRUTE, affected, sharp = 1)
|
||||
return 0
|
||||
|
||||
/datum/surgery_step/generic/cauterize
|
||||
@@ -173,7 +169,6 @@
|
||||
"<span class='notice'> You cauterize the incision on [target]'s [affected.name] with \the [tool].</span>")
|
||||
affected.open = 0
|
||||
affected.germ_level = 0
|
||||
affected.status &= ~ORGAN_BLEEDING
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/generic/cauterize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
@@ -218,8 +213,6 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
if(affected == null)
|
||||
return 0
|
||||
if(affected.status & ORGAN_DESTROYED)
|
||||
return 0
|
||||
return !affected.cannot_amputate
|
||||
|
||||
/datum/surgery_step/generic/amputate/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
@@ -236,7 +229,7 @@
|
||||
|
||||
add_logs(user, target, "surgically removed [affected.name] from", addition="INTENT: [uppertext(user.a_intent)]")//log it
|
||||
|
||||
var/atom/movable/thing = affected.droplimb(1,DROPLIMB_EDGE)
|
||||
var/atom/movable/thing = affected.droplimb(1,DROPLIMB_SHARP)
|
||||
if(istype(thing,/obj/item))
|
||||
user.put_in_hands(thing)
|
||||
return 1
|
||||
@@ -245,6 +238,6 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, sawing through the bone in [target]'s [affected.name] with \the [tool]!</span>", \
|
||||
"<span class='warning'> Your hand slips, sawwing through the bone in [target]'s [affected.name] with \the [tool]!</span>")
|
||||
affected.createwound(CUT, 30)
|
||||
affected.take_damage(30)
|
||||
affected.fracture()
|
||||
return 0
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
if(affecting)
|
||||
affecting.open = 0
|
||||
affecting.germ_level = 0
|
||||
affecting.status &= ~ORGAN_BLEEDING
|
||||
qdel(current_surgery)
|
||||
else if(current_surgery.can_cancel)
|
||||
to_chat(user, "<span class='warning'>You need to hold a cautery in inactive hand to stop [M]'s surgery!</span>")
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// IMPLANT REMOVAL SURGERY //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/surgery/implant_removal
|
||||
name = "Implant Removal"
|
||||
steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin,/datum/surgery_step/extract_implant,/datum/surgery_step/generic/cauterize)
|
||||
possible_locs = list("chest")
|
||||
|
||||
/datum/surgery/implant_removal/synth
|
||||
name = "Implant Removal"
|
||||
steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/extract_implant,/datum/surgery_step/robotics/external/close_hatch)
|
||||
possible_locs = list("chest")
|
||||
|
||||
/datum/surgery/implant_removal/can_start(mob/user, mob/living/carbon/human/target)
|
||||
if(!istype(target))
|
||||
return 0
|
||||
var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(affected.status & ORGAN_ROBOT)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/surgery/implant_removal/synth/can_start(mob/user, mob/living/carbon/human/target)
|
||||
if(!istype(target))
|
||||
return 0
|
||||
var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(!(affected.status & ORGAN_ROBOT))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/extract_implant
|
||||
name = "extract implant"
|
||||
allowed_tools = list(/obj/item/weapon/hemostat = 100, /obj/item/weapon/crowbar = 65)
|
||||
time = 64
|
||||
var/obj/item/weapon/implant/I = null
|
||||
|
||||
/datum/surgery_step/extract_implant/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
I = locate(/obj/item/weapon/implant) in target
|
||||
user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \
|
||||
"You start poking around inside [target]'s [affected.name] with \the [tool]." )
|
||||
target.custom_pain("The pain in your [affected.name] is living hell!",1)
|
||||
..()
|
||||
|
||||
/datum/surgery_step/extract_implant/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
I = locate(/obj/item/weapon/implant) in target
|
||||
if(I && (target_zone == "chest")) //implant removal only works on the chest.
|
||||
user.visible_message("<span class='notice'>[user] takes something out of [target]'s [affected.name] with \the [tool].</span>", \
|
||||
"<span class='notice'>You take [I] out of [target]'s [affected.name]s with \the [tool].</span>" )
|
||||
|
||||
I.removed(target)
|
||||
|
||||
var/obj/item/weapon/implantcase/case
|
||||
|
||||
if(istype(user.get_item_by_slot(slot_l_hand), /obj/item/weapon/implantcase))
|
||||
case = user.get_item_by_slot(slot_l_hand)
|
||||
else if(istype(user.get_item_by_slot(slot_r_hand), /obj/item/weapon/implantcase))
|
||||
case = user.get_item_by_slot(slot_r_hand)
|
||||
else
|
||||
case = locate(/obj/item/weapon/implantcase) in get_turf(target)
|
||||
|
||||
if(case && !case.imp)
|
||||
case.imp = I
|
||||
I.forceMove(case)
|
||||
case.update_icon()
|
||||
user.visible_message("[user] places [I] into [case]!", "<span class='notice'>You place [I] into [case].</span>")
|
||||
else
|
||||
qdel(I)
|
||||
else
|
||||
user.visible_message("<span class='notice'> [user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.</span>", \
|
||||
"<span class='notice'>You could not find anything inside [target]'s [affected.name].</span>")
|
||||
return 1
|
||||
@@ -0,0 +1,57 @@
|
||||
/datum/surgery/limb_augmentation
|
||||
name = "Augment Limb"
|
||||
steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/augment)
|
||||
possible_locs = list("chest","l_arm","r_arm","r_leg","l_leg")
|
||||
|
||||
/datum/surgery/limb_augmentation/can_start(mob/user, mob/living/carbon/target)
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(affected.status & ORGAN_BROKEN) //The arm has to be in prime condition to augment it.
|
||||
return 0
|
||||
if(affected.status & ORGAN_ROBOT)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/augment
|
||||
name = "augment limb with robotic part"
|
||||
allowed_tools = list(/obj/item/robot_parts = 100)
|
||||
time = 32
|
||||
|
||||
/datum/surgery_step/augment/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/obj/item/robot_parts/p = tool
|
||||
if(p.part)
|
||||
if(!(target_zone in p.part))
|
||||
to_chat(user, "<span class='warning'>[tool] cannot be used to augment this limb!</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/augment/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("[user] starts augmenting [affected] with [tool].", "You start augmenting [affected] with [tool].")
|
||||
|
||||
/datum/surgery_step/augment/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/obj/item/robot_parts/L = tool
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='notice'>[user] has finished augmenting [affected] with [tool].</span>", \
|
||||
"<span class='notice'>You augment [affected] with [tool].</span>")
|
||||
|
||||
if(L.part)
|
||||
for(var/part_name in L.part)
|
||||
if(!target.get_organ(part_name))
|
||||
continue
|
||||
affected.robotize(L.model_info, make_tough = 1, convert_all = 0)
|
||||
if(L.sabotaged)
|
||||
affected.sabotaged = 1
|
||||
break
|
||||
target.update_body()
|
||||
target.updatehealth()
|
||||
target.UpdateDamageIcon()
|
||||
|
||||
qdel(tool)
|
||||
|
||||
affected.open = 0
|
||||
affected.germ_level = 0
|
||||
return 1
|
||||
@@ -126,7 +126,7 @@
|
||||
var/obj/item/organ/external/E = tool
|
||||
user.visible_message("<span class='alert'>[user]'s hand slips, damaging [target]'s [E.amputation_point]!</span>", \
|
||||
"<span class='alert'>Your hand slips, damaging [target]'s [E.amputation_point]!</span>")
|
||||
target.apply_damage(10, BRUTE, null, sharp=1)
|
||||
target.apply_damage(10, BRUTE, null, sharp = 1)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -165,10 +165,6 @@
|
||||
H.h_style = "Bald"
|
||||
H.f_style = "Shaved"
|
||||
target.m_styles["head"] = "None"
|
||||
E.status &= ~ORGAN_DESTROYED
|
||||
if(E.children)
|
||||
for(var/obj/item/organ/external/C in E.children)
|
||||
C.status &= ~ORGAN_DESTROYED
|
||||
|
||||
|
||||
/datum/surgery_step/limb/connect
|
||||
@@ -197,13 +193,6 @@
|
||||
var/obj/item/organ/external/E = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='notice'>[user] has connected tendons and muscles in [target]'s [E.amputation_point] with [tool].</span>", \
|
||||
"<span class='notice'>You have connected tendons and muscles in [target]'s [E.amputation_point] with [tool].</span>")
|
||||
E.status &= ~ORGAN_DESTROYED
|
||||
var/obj/item/organ/external/stump = target.bodyparts_by_name["limb stump"]
|
||||
if(stump)
|
||||
stump.remove(target)
|
||||
if(E.children)
|
||||
for(var/obj/item/organ/external/C in E.children)
|
||||
C.status &= ~ORGAN_DESTROYED
|
||||
target.update_body()
|
||||
target.updatehealth()
|
||||
target.UpdateDamageIcon()
|
||||
@@ -213,7 +202,7 @@
|
||||
var/obj/item/organ/external/E = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='alert'>[user]'s hand slips, damaging [target]'s [E.amputation_point]!</span>", \
|
||||
"<span class='alert'>Your hand slips, damaging [target]'s [E.amputation_point]!</span>")
|
||||
target.apply_damage(10, BRUTE, null, sharp=1)
|
||||
target.apply_damage(10, BRUTE, null, sharp = 1)
|
||||
return 0
|
||||
|
||||
/datum/surgery_step/limb/mechanize
|
||||
@@ -254,10 +243,6 @@
|
||||
var/new_limb_type = organ_data["path"]
|
||||
var/obj/item/organ/external/new_limb = new new_limb_type(target)
|
||||
new_limb.robotize(L.model_info)
|
||||
new_limb.status &= ~ORGAN_DESTROYED
|
||||
if(new_limb.children)
|
||||
for(var/obj/item/organ/external/C in new_limb.children)
|
||||
C.status &= ~ORGAN_DESTROYED
|
||||
if(L.sabotaged)
|
||||
new_limb.sabotaged = 1
|
||||
target.update_body()
|
||||
@@ -271,5 +256,5 @@
|
||||
/datum/surgery_step/limb/mechanize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
user.visible_message("<span class='alert'>[user]'s hand slips, damaging [target]'s flesh!</span>", \
|
||||
"<span class='alert'>Your hand slips, damaging [target]'s flesh!</span>")
|
||||
target.apply_damage(10, BRUTE, null, sharp=1)
|
||||
target.apply_damage(10, BRUTE, null, sharp = 1)
|
||||
return 0
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
/obj/item/organ/internal/cyberimp/arm
|
||||
name = "arm-mounted implant"
|
||||
desc = "You shouldn't see this! Adminhelp and report this as an issue on github!"
|
||||
parent_organ = "r_arm"
|
||||
slot = "r_arm_device"
|
||||
icon_state = "implant-toolkit"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
actions_types = list(/datum/action/item_action/organ_action/toggle)
|
||||
|
||||
var/list/items_list = list()
|
||||
// Used to store a list of all items inside, for multi-item implants.
|
||||
// I would use contents, but they shuffle on every activation/deactivation leading to interface inconsistencies.
|
||||
|
||||
var/obj/item/holder = null
|
||||
// You can use this var for item path, it would be converted into an item on New()
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/New()
|
||||
..()
|
||||
if(ispath(holder))
|
||||
holder = new holder(src)
|
||||
|
||||
update_icon()
|
||||
slot = parent_organ + "_device"
|
||||
items_list = contents.Copy()
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/update_icon()
|
||||
if(parent_organ == "r_arm")
|
||||
transform = null
|
||||
else // Mirroring the icon
|
||||
transform = matrix(-1, 0, 0, 0, 1, 0)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/examine(mob/user)
|
||||
..()
|
||||
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)
|
||||
..()
|
||||
if(isscrewdriver(W))
|
||||
if(parent_organ == "r_arm")
|
||||
parent_organ = "l_arm"
|
||||
else
|
||||
parent_organ = "r_arm"
|
||||
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))
|
||||
emag_act()
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/remove(mob/living/carbon/M, special = 0)
|
||||
Retract()
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/emag_act()
|
||||
return 0
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/gun/emp_act(severity)
|
||||
if(prob(15/severity) && owner)
|
||||
to_chat(owner, "<span class='warning'>[src] is hit by EMP!</span>")
|
||||
// give the owner an idea about why his implant is glitching
|
||||
Retract()
|
||||
..()
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/proc/Retract()
|
||||
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>",
|
||||
"<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
|
||||
F.set_light(0)
|
||||
|
||||
owner.unEquip(holder, 1)
|
||||
holder.forceMove(src)
|
||||
holder = null
|
||||
playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/proc/Extend(var/obj/item/item)
|
||||
if(!(item in src))
|
||||
return
|
||||
|
||||
|
||||
holder = item
|
||||
|
||||
holder.flags |= NODROP
|
||||
holder.unacidable = 1
|
||||
holder.slot_flags = null
|
||||
holder.w_class = WEIGHT_CLASS_HUGE
|
||||
holder.materials = null
|
||||
|
||||
if(istype(holder, /obj/item/device/flash/armimplant))
|
||||
var/obj/item/device/flash/F = holder
|
||||
F.set_light(7)
|
||||
|
||||
var/arm_slot = (parent_organ == "r_arm" ? slot_r_hand : slot_l_hand)
|
||||
var/obj/item/arm_item = owner.get_item_by_slot(arm_slot)
|
||||
|
||||
if(arm_item)
|
||||
if(!owner.unEquip(arm_item))
|
||||
to_chat(owner, "<span class='warning'>Your [arm_item] interferes with [src]!</span>")
|
||||
return
|
||||
else
|
||||
to_chat(owner, "<span class='notice'>You drop [arm_item] to activate [src]!</span>")
|
||||
|
||||
if(parent_organ == "r_arm" ? !owner.put_in_r_hand(holder) : !owner.put_in_l_hand(holder))
|
||||
to_chat(owner, "<span class='warning'>Your [src] fails to activate!</span>")
|
||||
return
|
||||
|
||||
// Activate the hand that now holds our item.
|
||||
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>",
|
||||
"<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)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/ui_action_click()
|
||||
if(crit_fail || (!holder && !contents.len))
|
||||
to_chat(owner, "<span class='warning'>The implant doesn't respond. It seems to be broken...</span>")
|
||||
return
|
||||
|
||||
// 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())
|
||||
return
|
||||
|
||||
if(!holder || (holder in src))
|
||||
holder = null
|
||||
if(contents.len == 1)
|
||||
Extend(contents[1])
|
||||
else // TODO: make it similar to borg's storage-like module selection
|
||||
var/obj/item/choise = input("Activate which item?", "Arm Implant", null, null) as null|anything in items_list
|
||||
if(owner && owner == usr && owner.stat != DEAD && (src in owner.internal_organs) && !holder && istype(choise) && (choise in contents))
|
||||
// This monster sanity check is a nice example of how bad input() is.
|
||||
Extend(choise)
|
||||
else
|
||||
Retract()
|
||||
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/gun/emp_act(severity)
|
||||
if(prob(30/severity) && owner && !crit_fail)
|
||||
Retract()
|
||||
owner.visible_message("<span class='danger'>A loud bang comes from [owner]\'s [parent_organ == "r_arm" ? "right" : "left"] arm!</span>")
|
||||
playsound(get_turf(owner), 'sound/weapons/flashbang.ogg', 100, 1)
|
||||
to_chat(owner, "<span class='userdanger'>You feel an explosion erupt inside your [parent_organ == "r_arm" ? "right" : "left"] arm as your implant breaks!</span>")
|
||||
owner.adjust_fire_stacks(20)
|
||||
owner.IgniteMob()
|
||||
owner.adjustFireLoss(25)
|
||||
crit_fail = 1
|
||||
else // The gun will still discharge anyway.
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/gun/laser
|
||||
name = "arm-mounted laser implant"
|
||||
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)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/gun/laser/l
|
||||
parent_organ = "l_arm"
|
||||
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/gun/taser
|
||||
name = "arm-mounted taser implant"
|
||||
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)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/gun/taser/l
|
||||
parent_organ = "l_arm"
|
||||
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/toolset
|
||||
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)
|
||||
|
||||
/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))
|
||||
to_chat(usr, "<span class='notice'>You unlock [src]'s integrated knife!</span>")
|
||||
items_list += new /obj/item/weapon/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)
|
||||
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)
|
||||
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)
|
||||
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
|
||||
F.I = src
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/baton
|
||||
name = "arm electrification implant"
|
||||
desc = "An illegal combat implant that allows the user to administer disabling shocks from their arm."
|
||||
contents = newlist(/obj/item/borg/stun)
|
||||
origin_tech = "materials=3;combat=5;biotech=4;powerstorage=4;syndicate=3"
|
||||
|
||||
/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)
|
||||
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
|
||||
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)
|
||||
origin_tech = "materials=3;engineering=3;biotech=3;programming=2;magnets=3"
|
||||
|
||||
// lets make IPCs even *more* vulnerable to EMPs!
|
||||
/obj/item/organ/internal/cyberimp/arm/power_cord
|
||||
name = "APC-compatible power adapter implant"
|
||||
desc = "An implant commonly installed inside IPCs in order to allow them to easily collect energy from their environment"
|
||||
origin_tech = "materials=3;biotech=2;powerstorage=3"
|
||||
contents = newlist(/obj/item/apc_powercord)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/power_cord/emp_act(severity)
|
||||
// To allow repair via nanopaste/screwdriver
|
||||
// also so IPCs don't also catch on fire and fall even more apart upon EMP
|
||||
damage = 1
|
||||
crit_fail = TRUE
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/power_cord/surgeryize()
|
||||
if(crit_fail && owner)
|
||||
to_chat(owner, "<span class='notice'>Your [src] feels functional again.</span>")
|
||||
crit_fail = FALSE
|
||||
|
||||
|
||||
/obj/item/apc_powercord
|
||||
name = "power cable"
|
||||
desc = "Insert into a nearby APC to draw power from it."
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "wire1"
|
||||
flags = NOBLUDGEON
|
||||
|
||||
/obj/item/apc_powercord/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
if(!istype(target, /obj/machinery/power/apc) || !ishuman(user) || !proximity_flag)
|
||||
return ..()
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
var/obj/machinery/power/apc/A = target
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.get_int_organ(/obj/item/organ/internal/cell))
|
||||
if(A.emagged || A.stat & BROKEN)
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
|
||||
s.set_up(3, 1, A)
|
||||
s.start()
|
||||
to_chat(H, "<span class='warning'>The APC power currents surge erratically, damaging your chassis!</span>")
|
||||
H.adjustFireLoss(10,0)
|
||||
else if(A.cell && A.cell.charge > 0)
|
||||
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)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There is no charge to draw from that APC.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You lack a cell in which to store charge!</span>")
|
||||
|
||||
/obj/item/apc_powercord/proc/powerdraw_loop(obj/machinery/power/apc/A, mob/living/carbon/human/H)
|
||||
H.visible_message("<span class='notice'>[H] inserts a power connector into \the [A].</span>", "<span class='notice'>You begin to draw power from \the [A].</span>")
|
||||
while(do_after(H, 10, target = A))
|
||||
if(loc != H)
|
||||
to_chat(H, "<span class='warning'>You must keep your connector out while charging!</span>")
|
||||
break
|
||||
if(A.cell.charge == 0)
|
||||
to_chat(H, "<span class='warning'>\The [A] has no more charge.</span>")
|
||||
break
|
||||
A.charging = 1
|
||||
if(A.cell.charge >= 500)
|
||||
H.nutrition += 50
|
||||
A.cell.charge -= 500
|
||||
to_chat(H, "<span class='notice'>You siphon off some of the stored charge for your own use.</span>")
|
||||
else
|
||||
H.nutrition += A.cell.charge/10
|
||||
A.cell.charge = 0
|
||||
to_chat(H, "<span class='notice'>You siphon off the last of \the [A]'s charge.</span>")
|
||||
break
|
||||
if(H.nutrition > NUTRITION_LEVEL_WELL_FED)
|
||||
to_chat(H, "<span class='notice'>You are now fully charged.</span>")
|
||||
break
|
||||
H.visible_message("<span class='notice'>[H] unplugs from \the [A].</span>", "<span class='notice'>You unplug from \the [A].</span>")
|
||||
@@ -6,8 +6,8 @@
|
||||
status = ORGAN_ROBOT
|
||||
var/implant_color = "#FFFFFF"
|
||||
var/implant_overlay
|
||||
tough = 1 //not easyly broken by combat damage
|
||||
sterile = 1 //not very germy
|
||||
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)
|
||||
@@ -144,6 +144,24 @@
|
||||
spawn(90 / severity)
|
||||
crit_fail = 0
|
||||
|
||||
|
||||
//[[[[MOUTH]]]]
|
||||
/obj/item/organ/internal/cyberimp/mouth
|
||||
parent_organ = "mouth"
|
||||
|
||||
/obj/item/organ/internal/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 = "breathing_tube"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
origin_tech = "materials=2;biotech=3"
|
||||
|
||||
/obj/item/organ/internal/cyberimp/mouth/breathing_tube/emp_act(severity)
|
||||
if(prob(60/severity) && owner)
|
||||
to_chat(owner, "<span class='warning'>Your breathing tube suddenly closes!</span>")
|
||||
owner.AdjustLoseBreath(2)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/brain/clown_voice
|
||||
name = "Comical implant"
|
||||
desc = "<span class='sans'>Uh oh.</span>"
|
||||
@@ -255,175 +273,6 @@
|
||||
if(H.stat == CONSCIOUS)
|
||||
to_chat(H, "<span class='notice'>You feel your heart beating again!</span>")
|
||||
|
||||
//ARM...THAT GO IN THE CHEST
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod//dummy parent item for making arm-mod implants. works best with nodrop items that are sent to nullspace upon being dropped.
|
||||
name = "Arm-mounted item implant"
|
||||
desc = "You shouldn't see this! Adminhelp and report this as an issue on github!"
|
||||
icon_state = "chest_implant"
|
||||
implant_color = "#007ACC"
|
||||
slot = "shoulders"
|
||||
origin_tech = "materials=5;biotech=4;powerstorage=4"
|
||||
actions_types = list(/datum/action/item_action/organ_action/toggle)
|
||||
var/obj/holder//is defined as the retractable item itself. ensure this is defined somewhere!
|
||||
var/out = 0//determines if the item is in the owner's hand or not
|
||||
var/overloaded = 0//is set to 1 when owner gets EMPed. if set to 1, implant doesn't work.
|
||||
var/lasthand = null
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/ui_action_click()
|
||||
toggle_item()
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/proc/toggle_item()
|
||||
if(overloaded)//ensure the implant isn't broken
|
||||
to_chat(owner, "<span class='warning'>The implant doesn't respond. It seems to be broken...</span>")
|
||||
return
|
||||
owner.changeNext_move(CLICK_CD_MELEE)
|
||||
if(owner.next_move < world.time)
|
||||
return // No spam
|
||||
if(out)//check if the owner has the item out already
|
||||
owner.unEquip(holder, 1)//if he does, take it away. then,
|
||||
holder.loc = null//stash it in nullspace
|
||||
out = 0//and set this to clarify the item isn't out.
|
||||
owner.visible_message("<span class='notice'>[owner] retracts [holder].</span>","<span class='notice'>You retract [holder].</span>")
|
||||
playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
else//if he doesn't have the item out
|
||||
if(owner.put_in_hands(holder))//put it in his hands.
|
||||
lasthand = owner.get_active_hand()
|
||||
out = 1
|
||||
owner.visible_message("<span class='notice'>[owner] extends [holder]!</span>","<span class='notice'>You extend [holder]!</span>")
|
||||
playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
else//if this fails to put the item in his hands,
|
||||
holder.loc = null//keep it in nullspace
|
||||
to_chat(owner, "<span class='warning'>You can't extend [holder] if you can't use your hands!</span>")
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/emp_act(severity)//if the implant gets EMPed...
|
||||
if(!owner || overloaded)//ensure that it's in an owner and that it's not already EMPed, then...
|
||||
return
|
||||
if(out)//check if he has the item out...
|
||||
owner.unEquip(holder, 1)//if he does, take it away.
|
||||
holder.loc = null
|
||||
out = 0
|
||||
owner.visible_message("<span class='notice'>[holder] forcibly retracts into [owner]'s arm.</span>")
|
||||
overload() // Make sure this doesn't happen again
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/proc/overload()
|
||||
owner.visible_message("<span class='danger'>A loud bang comes from [owner]...</span>")
|
||||
playsound(get_turf(owner), 'sound/effects/bang.ogg', 100, 1)
|
||||
to_chat(owner, "<span class='warning'>You feel an explosion erupt inside you as your chest implant breaks. Is it hot in here?</span>")
|
||||
owner.adjust_fire_stacks(20)
|
||||
owner.IgniteMob()//ignite the owner, as well as
|
||||
owner.say("AUUUUUUUUUUUUUUUUUUGH!!")
|
||||
if(prob(50))
|
||||
if(lasthand == "r_hand")
|
||||
var/obj/item/organ/external/limb = owner.get_organ("r_arm")
|
||||
limb.droplimb(0, DROPLIMB_EDGE)
|
||||
else if(lasthand == "l_hand")
|
||||
var/obj/item/organ/external/limb = owner.get_organ("l_arm")
|
||||
limb.droplimb(0, DROPLIMB_EDGE)
|
||||
owner.say("I HAVE BEEN DISARMED!!!")
|
||||
owner.adjustFireLoss(25)//severely injure him!
|
||||
overloaded = TRUE
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/tase//mounted, self-charging taser!
|
||||
name = "Arm-cannon taser implant"
|
||||
desc = "A variant of the arm cannon implant that fires electrodes and disabler shots. The cannon emerges from the subject's arms and remains in the shoulders when not in use."
|
||||
icon_state = "armcannon_tase_implant"
|
||||
origin_tech = "materials=5;combat=5;biotech=4;powerstorage=4"
|
||||
actions_types = list(/datum/action/item_action/organ_action/toggle)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/tase/New()//when the implant is created...
|
||||
..()
|
||||
holder = new /obj/item/weapon/gun/energy/gun/advtaser/mounted(src)//assign a brand new item to it. (in this case, a gun)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/lase//mounted, self-charging laser!
|
||||
name = "Arm-cannon laser implant"
|
||||
desc = "A variant of the arm cannon implant that fires lethal laser beams. The cannon emerges from the subject's arms and remains in the shoulders when not in use."
|
||||
icon_state = "armcannon_lase_implant"
|
||||
origin_tech = "materials=4;combat=4;biotech=4;powerstorage=4;syndicate=3"
|
||||
actions_types = list(/datum/action/item_action/organ_action/toggle)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/lase/New()
|
||||
..()
|
||||
holder = new /obj/item/weapon/gun/energy/laser/mounted(src)
|
||||
|
||||
// lets make IPCs even *more* vulnerable to EMPs!
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/power_cord
|
||||
name = "APC-compatible power adapter implant"
|
||||
desc = "An implant commonly installed inside IPCs in order to allow them to easily collect energy from their environment"
|
||||
origin_tech = "materials=3;biotech=2;powerstorage=3"
|
||||
slot = "shoulders2"
|
||||
actions_types = list(/datum/action/item_action/organ_action/toggle)
|
||||
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/power_cord/New()
|
||||
..()
|
||||
holder = new /obj/item/apc_powercord(src)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/power_cord/overload()
|
||||
// To allow repair via nanopaste/screwdriver
|
||||
// also so IPCs don't also catch on fire and fall even more apart upon EMP
|
||||
damage = 1
|
||||
overloaded = TRUE
|
||||
|
||||
/obj/item/organ/internal/cyberimp/chest/arm_mod/power_cord/surgeryize()
|
||||
if(overloaded && owner)
|
||||
to_chat(owner, "<span class='notice'>Your [src] feels functional again.</span>")
|
||||
overloaded = FALSE
|
||||
|
||||
|
||||
/obj/item/apc_powercord
|
||||
name = "power cable"
|
||||
desc = "Insert into a nearby APC to draw power from it."
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "wire1"
|
||||
flags = NODROP | NOBLUDGEON
|
||||
|
||||
/obj/item/apc_powercord/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
if(!istype(target, /obj/machinery/power/apc) || !ishuman(user) || !proximity_flag)
|
||||
return ..()
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
var/obj/machinery/power/apc/A = target
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.get_int_organ(/obj/item/organ/internal/cell))
|
||||
if(A.emagged || A.stat & BROKEN)
|
||||
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
|
||||
s.set_up(3, 1, A)
|
||||
s.start()
|
||||
to_chat(H, "<span class='warning'>The APC power currents surge erratically, damaging your chassis!</span>")
|
||||
H.adjustFireLoss(10,0)
|
||||
else if(A.cell && A.cell.charge > 0)
|
||||
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)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There is no charge to draw from that APC.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You lack a cell in which to store charge!</span>")
|
||||
|
||||
/obj/item/apc_powercord/proc/powerdraw_loop(obj/machinery/power/apc/A, mob/living/carbon/human/H)
|
||||
H.visible_message("<span class='notice'>[H] inserts a power connector into \the [A].</span>", "<span class='notice'>You begin to draw power from \the [A].</span>")
|
||||
while(do_after(H, 10, target = A))
|
||||
if(loc != H)
|
||||
to_chat(H, "<span class='warning'>You must keep your connector out while charging!</span>")
|
||||
break
|
||||
if(A.cell.charge == 0)
|
||||
to_chat(H, "<span class='warning'>\The [A] has no more charge.</span>")
|
||||
break
|
||||
A.charging = 1
|
||||
if(A.cell.charge >= 500)
|
||||
H.nutrition += 50
|
||||
A.cell.charge -= 500
|
||||
to_chat(H, "<span class='notice'>You siphon off some of the stored charge for your own use.</span>")
|
||||
else
|
||||
H.nutrition += A.cell.charge/10
|
||||
A.cell.charge = 0
|
||||
to_chat(H, "<span class='notice'>You siphon off the last of \the [A]'s charge.</span>")
|
||||
break
|
||||
if(H.nutrition > NUTRITION_LEVEL_WELL_FED)
|
||||
to_chat(H, "<span class='notice'>You are now fully charged.</span>")
|
||||
break
|
||||
H.visible_message("<span class='notice'>[H] unplugs from \the [A].</span>", "<span class='notice'>You unplug from \the [A].</span>")
|
||||
|
||||
//BOX O' IMPLANTS
|
||||
|
||||
/obj/item/weapon/storage/box/cyber_implants
|
||||
|
||||
@@ -2,379 +2,287 @@
|
||||
BLOOD SYSTEM
|
||||
****************************************************/
|
||||
|
||||
/mob/living/carbon/human/var/datum/reagents/vessel //Container for blood and BLOOD ONLY. Do not transfer other chems here.
|
||||
|
||||
//Initializes blood vessels
|
||||
/mob/living/carbon/human/proc/make_blood()
|
||||
|
||||
if(vessel)
|
||||
/mob/living/carbon/human/proc/suppress_bloodloss(amount)
|
||||
if(bleedsuppress)
|
||||
return
|
||||
|
||||
vessel = new/datum/reagents(max_blood)
|
||||
vessel.my_atom = src
|
||||
|
||||
if(species && species.exotic_blood)
|
||||
vessel.add_reagent(species.exotic_blood, max_blood)
|
||||
else
|
||||
vessel.add_reagent("blood", max_blood)
|
||||
for(var/datum/reagent/blood/B in vessel.reagent_list)
|
||||
if(B.id == "blood")
|
||||
B.data = list(
|
||||
"donor" = src,
|
||||
"viruses" = null,
|
||||
"blood_DNA" = dna.unique_enzymes,
|
||||
"blood_colour" = species.blood_color,
|
||||
"blood_type" = b_type,
|
||||
"resistances" = null,
|
||||
"trace_chem" = null)
|
||||
spawn(1)
|
||||
fixblood()
|
||||
bleedsuppress = TRUE
|
||||
addtimer(src, "resume_bleeding", amount)
|
||||
|
||||
//Resets blood data
|
||||
/mob/living/carbon/human/proc/fixblood()
|
||||
for(var/datum/reagent/blood/B in vessel.reagent_list)
|
||||
if(B.id == "blood")
|
||||
B.data = list(
|
||||
"donor" = src,
|
||||
"viruses" = null,
|
||||
"blood_DNA" = dna.unique_enzymes,
|
||||
"blood_colour" = species.blood_color,
|
||||
"blood_type" = b_type,
|
||||
"resistances" = null,
|
||||
"trace_chem" = null)
|
||||
/mob/living/carbon/human/proc/resume_bleeding()
|
||||
bleedsuppress = FALSE
|
||||
if(stat != DEAD && bleed_rate)
|
||||
to_chat(src, "<span class='warning'>The blood soaks through your bandage.</span>")
|
||||
|
||||
// Takes care blood loss and regeneration
|
||||
/mob/living/carbon/human/proc/handle_blood()
|
||||
var/blood_volume
|
||||
if(species && species.flags & NO_BLOOD)
|
||||
/mob/living/carbon/human/handle_blood()
|
||||
var/list/blood_data = get_blood_data(get_blood_id())//PROCCEPTION
|
||||
|
||||
if(NO_BLOOD in species.species_traits)
|
||||
bleed_rate = 0
|
||||
return
|
||||
if(stat != DEAD && bodytemperature >= 170) //Dead or cryosleep people do not pump the blood.
|
||||
if(species.exotic_blood)
|
||||
var/blood_reagent = species.exotic_blood // This is a string of the name of the species' blood reagent
|
||||
blood_volume = round(vessel.get_reagent_amount(blood_reagent))
|
||||
if(blood_volume < max_blood && blood_volume)
|
||||
vessel.add_reagent(blood_reagent, 0.1) // regenerate blood VERY slowly
|
||||
if(reagents.has_reagent(blood_reagent))
|
||||
vessel.add_reagent(blood_reagent, 0.4)
|
||||
|
||||
else
|
||||
blood_volume = round(vessel.get_reagent_amount("blood"))
|
||||
//Blood regeneration if there is some space
|
||||
if(blood_volume < max_blood && blood_volume)
|
||||
var/datum/reagent/blood/B = locate() in vessel.reagent_list //Grab some blood
|
||||
if(B) // Make sure there's some blood at all
|
||||
if(mind) //Handles vampires "eating" blood that isn't their own.
|
||||
if(mind in ticker.mode.vampires)
|
||||
for(var/datum/reagent/blood/BL in vessel.reagent_list)
|
||||
if(nutrition >= NUTRITION_LEVEL_WELL_FED)
|
||||
break //We don't want blood tranfusions making vampires fat.
|
||||
if(BL.data["donor"] != src)
|
||||
nutrition += (15 * REAGENTS_METABOLISM)
|
||||
BL.volume -= REAGENTS_METABOLISM
|
||||
if(BL.volume <= 0)
|
||||
qdel(BL)
|
||||
break //Only process one blood per tick, to maintain the same metabolism as nutriment for non-vampires.
|
||||
if(bodytemperature >= 225 && !(NOCLONE in mutations)) //cryosleep or husked people do not pump the blood.
|
||||
|
||||
if(B.data["donor"] != src) //If it's not theirs, then we look for theirs
|
||||
for(var/datum/reagent/blood/D in vessel.reagent_list)
|
||||
if(D.data["donor"] == src)
|
||||
B = D
|
||||
break
|
||||
|
||||
vessel.add_reagent("blood", 0.1) // regenerate blood VERY slowly
|
||||
//Blood regeneration if there is some space
|
||||
if(blood_volume < max_blood && blood_volume)
|
||||
if(mind) //Handles vampires "eating" blood that isn't their own.
|
||||
if(mind in ticker.mode.vampires)
|
||||
if(nutrition >= NUTRITION_LEVEL_WELL_FED)
|
||||
return //We don't want blood tranfusions making vampires fat.
|
||||
if(blood_data["donor"] != src)
|
||||
nutrition += (15 * REAGENTS_METABOLISM)
|
||||
return //Only process one blood per tick, to maintain the same metabolism as nutriment for non-vampires.
|
||||
if(blood_volume < BLOOD_VOLUME_NORMAL)
|
||||
blood_volume += 0.1 // regenerate blood VERY slowly
|
||||
|
||||
|
||||
//Effects of bloodloss
|
||||
var/oxy_immune = species.flags & NO_BREATHE //Some species have blood, but don't breathe; they should still suffer the effects of bloodloss.
|
||||
|
||||
var/word = pick("dizzy","woozy","faint")
|
||||
switch(blood_volume)
|
||||
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
|
||||
if(prob(5))
|
||||
to_chat(src, "<span class='warning'>You feel [pick("dizzy","woozy","faint")].</span>")
|
||||
if(oxy_immune)
|
||||
adjustToxLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1))
|
||||
else
|
||||
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1))
|
||||
to_chat(src, "<span class='warning'>You feel [word].</span>")
|
||||
apply_damage_type(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1), species.blood_damage_type)
|
||||
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
|
||||
if(oxy_immune)
|
||||
adjustToxLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
|
||||
else
|
||||
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
|
||||
apply_damage_type(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1), species.blood_damage_type)
|
||||
if(prob(5))
|
||||
EyeBlurry(6)
|
||||
var/word = pick("dizzy","woozy","faint")
|
||||
to_chat(src, "<span class='warning'>You feel very [word].</span>")
|
||||
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
|
||||
if(oxy_immune)
|
||||
adjustToxLoss(5)
|
||||
else
|
||||
adjustOxyLoss(5)
|
||||
apply_damage_type(5, species.blood_damage_type)
|
||||
if(prob(15))
|
||||
Paralyse(rand(1,3))
|
||||
var/word = pick("dizzy","woozy","faint")
|
||||
to_chat(src, "<span class='warning'>You feel extremely [word].</span>")
|
||||
if(0 to BLOOD_VOLUME_SURVIVE)
|
||||
death()
|
||||
|
||||
var/temp_bleed = 0
|
||||
var/internal_bleeding_rate = 0
|
||||
//Bleeding out
|
||||
var/blood_max = 0
|
||||
for(var/obj/item/organ/external/temp in bodyparts)
|
||||
if(!(temp.status & ORGAN_BLEEDING) || temp.status & ORGAN_ROBOT)
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/organ/external/BP = X
|
||||
var/brutedamage = BP.brute_dam
|
||||
|
||||
if(BP.status & ORGAN_ROBOT)
|
||||
continue
|
||||
for(var/datum/wound/W in temp.wounds)
|
||||
if(W.bleeding())
|
||||
blood_max += W.damage / 4
|
||||
if(temp.open)
|
||||
blood_max += 2 //Yer stomach is cut open
|
||||
drip(blood_max)
|
||||
|
||||
//Makes a blood drop, leaking certain amount of blood from the mob
|
||||
/mob/living/carbon/human/proc/drip(var/amt as num)
|
||||
//We want an accurate reading of .len
|
||||
listclearnulls(BP.embedded_objects)
|
||||
temp_bleed += 0.5*BP.embedded_objects.len
|
||||
|
||||
if(species && species.flags & NO_BLOOD) //TODO: Make drips come from the reagents instead.
|
||||
return
|
||||
if(brutedamage >= 20)
|
||||
temp_bleed += (brutedamage * 0.013)
|
||||
|
||||
if(!amt)
|
||||
return
|
||||
if(BP.open)
|
||||
temp_bleed += 0.5
|
||||
|
||||
var/amm = 0.1 * amt
|
||||
var/turf/T = get_turf(src)
|
||||
if(BP.internal_bleeding)
|
||||
internal_bleeding_rate += 0.5
|
||||
|
||||
if(species.exotic_blood)
|
||||
vessel.remove_reagent(species.exotic_blood,amm)
|
||||
if(vessel.total_volume)
|
||||
var/fraction = amm / vessel.total_volume
|
||||
vessel.reaction(T, TOUCH, fraction)
|
||||
return
|
||||
bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
|
||||
|
||||
else
|
||||
vessel.remove_reagent("blood",amm)
|
||||
blood_splatter(src, src)
|
||||
if(internal_bleeding_rate && !(status_flags & FAKEDEATH))
|
||||
bleed(internal_bleeding_rate)
|
||||
|
||||
if(bleed_rate && !bleedsuppress && !(status_flags & FAKEDEATH))
|
||||
bleed(bleed_rate)
|
||||
|
||||
//Makes a blood drop, leaking amt units of blood from the mob
|
||||
/mob/living/carbon/proc/bleed(amt)
|
||||
if(blood_volume)
|
||||
blood_volume = max(blood_volume - amt, 0)
|
||||
if(isturf(loc)) //Blood loss still happens in locker, floor stays clean
|
||||
if(amt >= 10)
|
||||
add_splatter_floor(loc)
|
||||
else
|
||||
add_splatter_floor(loc, 1)
|
||||
|
||||
/mob/living/carbon/human/bleed(amt)
|
||||
if(!(NO_BLOOD in species.species_traits))
|
||||
..()
|
||||
if(species.exotic_blood)
|
||||
var/datum/reagent/R = chemical_reagents_list[get_blood_id()]
|
||||
if(istype(R) && isturf(loc))
|
||||
R.reaction_turf(get_turf(src), amt)
|
||||
|
||||
/mob/living/proc/restore_blood()
|
||||
blood_volume = initial(blood_volume)
|
||||
|
||||
/mob/living/carbon/human/restore_blood()
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
bleed_rate = 0
|
||||
|
||||
/****************************************************
|
||||
BLOOD TRANSFERS
|
||||
****************************************************/
|
||||
|
||||
//Gets blood from mob to the container, preserving all data in it.
|
||||
/mob/living/carbon/proc/take_blood(obj/item/weapon/reagent_containers/container, var/amount)
|
||||
var/datum/reagent/B = get_blood(container.reagents)
|
||||
if(!istype(B, /datum/reagent/blood)) B = new /datum/reagent/blood
|
||||
B.holder = container
|
||||
B.volume += amount
|
||||
//Gets blood from mob to a container or other mob, preserving all data in it.
|
||||
/mob/living/proc/transfer_blood_to(atom/movable/AM, amount, forced)
|
||||
if(!blood_volume || !AM.reagents)
|
||||
return 0
|
||||
if(blood_volume < BLOOD_VOLUME_BAD && !forced)
|
||||
return 0
|
||||
|
||||
//set reagent data
|
||||
B.data["donor"] = src
|
||||
B.data["viruses"] = list()
|
||||
if(blood_volume < amount)
|
||||
amount = blood_volume
|
||||
|
||||
for(var/datum/disease/D in viruses)
|
||||
B.data["viruses"] += D.Copy()
|
||||
if(resistances && resistances.len)
|
||||
B.data["resistances"] = resistances.Copy()
|
||||
var/blood_id = get_blood_id()
|
||||
if(!blood_id)
|
||||
return 0
|
||||
|
||||
B.data["blood_DNA"] = copytext(src.dna.unique_enzymes,1,0)
|
||||
B.data["blood_type"] = copytext(src.dna.b_type,1,0)
|
||||
blood_volume -= amount
|
||||
|
||||
// Putting this here due to return shenanigans.
|
||||
if(istype(src,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = src
|
||||
B.data["blood_colour"] = H.species.blood_color
|
||||
B.color = B.data["blood_colour"]
|
||||
var/list/blood_data = get_blood_data(blood_id)
|
||||
|
||||
var/list/temp_chem = list()
|
||||
for(var/datum/reagent/R in src.reagents.reagent_list)
|
||||
temp_chem += R.id
|
||||
temp_chem[R.id] = R.volume
|
||||
B.data["trace_chem"] = list2params(temp_chem)
|
||||
if(mind)
|
||||
B.data["mind"] = mind
|
||||
if(ckey)
|
||||
B.data["ckey"] = ckey
|
||||
if(iscarbon(AM))
|
||||
var/mob/living/carbon/C = AM
|
||||
if(blood_id == C.get_blood_id())//both mobs have the same blood substance
|
||||
if(blood_id == "blood") //normal blood
|
||||
if(blood_data["viruses"])
|
||||
for(var/thing in blood_data["viruses"])
|
||||
var/datum/disease/D = thing
|
||||
if((D.spread_flags & SPECIAL) || (D.spread_flags & NON_CONTAGIOUS))
|
||||
continue
|
||||
C.ForceContractDisease(D)
|
||||
if(!(blood_data["blood_type"] in get_safe_blood(C.dna.b_type)))
|
||||
C.reagents.add_reagent("toxin", amount * 0.5)
|
||||
return 1
|
||||
|
||||
if(!suiciding)
|
||||
B.data["cloneable"] = 1
|
||||
B.data["gender"] = gender
|
||||
B.data["real_name"] = real_name
|
||||
B.data["factions"] = faction
|
||||
return B
|
||||
C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_NORMAL)
|
||||
return 1
|
||||
|
||||
//For humans, blood does not appear from blue, it comes from vessels.
|
||||
/mob/living/carbon/human/take_blood(obj/item/weapon/reagent_containers/container, var/amount)
|
||||
if(src.species.exotic_blood)
|
||||
if(vessel.get_reagent_amount(src.species.exotic_blood) < amount)
|
||||
return null
|
||||
var/datum/reagent/W = new /datum/reagent
|
||||
W.holder = container
|
||||
W.volume += amount
|
||||
AM.reagents.add_reagent(blood_id, amount, blood_data, bodytemperature)
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/proc/get_blood_data(blood_id)
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/get_blood_data(blood_id)
|
||||
if(blood_id == "blood") //actual blood reagent
|
||||
var/blood_data = list()
|
||||
//set the blood data
|
||||
blood_data["donor"] = src
|
||||
blood_data["viruses"] = list()
|
||||
|
||||
for(var/thing in viruses)
|
||||
var/datum/disease/D = thing
|
||||
blood_data["viruses"] += D.Copy()
|
||||
|
||||
blood_data["blood_DNA"] = copytext(dna.unique_enzymes,1,0)
|
||||
if(resistances && resistances.len)
|
||||
blood_data["resistances"] = resistances.Copy()
|
||||
var/list/temp_chem = list()
|
||||
for(var/datum/reagent/R in src.reagents.reagent_list)
|
||||
temp_chem += R.id
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
temp_chem[R.id] = R.volume
|
||||
W.data["trace_chem"] = list2params(temp_chem)
|
||||
vessel.remove_reagent(src.species.exotic_blood,amount) // Removes blood if human
|
||||
return W
|
||||
if(species && species.flags & NO_BLOOD)
|
||||
return null
|
||||
else
|
||||
if(vessel.get_reagent_amount("blood") < amount)
|
||||
return null
|
||||
. = ..()
|
||||
vessel.remove_reagent("blood",amount) // Removes blood if human
|
||||
blood_data["trace_chem"] = list2params(temp_chem)
|
||||
if(mind)
|
||||
blood_data["mind"] = mind
|
||||
if(ckey)
|
||||
blood_data["ckey"] = ckey
|
||||
if(!suiciding)
|
||||
blood_data["cloneable"] = 1
|
||||
blood_data["blood_type"] = copytext(src.dna.b_type,1,0)
|
||||
blood_data["gender"] = gender
|
||||
blood_data["real_name"] = real_name
|
||||
blood_data["blood_color"] = species.blood_color
|
||||
blood_data["factions"] = faction
|
||||
return blood_data
|
||||
|
||||
//Transfers blood from container ot vessels
|
||||
/mob/living/carbon/proc/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
|
||||
var/datum/reagent/blood/injected = get_blood(container.reagents)
|
||||
//get the id of the substance this mob use as blood.
|
||||
/mob/proc/get_blood_id()
|
||||
return
|
||||
|
||||
if(!istype(injected))
|
||||
/mob/living/simple_animal/get_blood_id()
|
||||
if(blood_volume)
|
||||
return "blood"
|
||||
|
||||
/mob/living/carbon/human/get_blood_id()
|
||||
if(species.exotic_blood)//some races may bleed water..or kethcup..
|
||||
return species.exotic_blood
|
||||
else if((NO_BLOOD in species.species_traits) || (NOCLONE in mutations))
|
||||
return
|
||||
|
||||
var/list/chems = list()
|
||||
chems = params2list(injected.data["trace_chem"])
|
||||
for(var/C in chems)
|
||||
src.reagents.add_reagent(C, (text2num(chems[C]) / BLOOD_VOLUME_NORMAL) * amount)//adds trace chemicals to owner's blood
|
||||
reagents.update_total()
|
||||
|
||||
container.reagents.remove_reagent("blood", amount)
|
||||
|
||||
//Transfers blood from container ot vessels, respecting blood types compatability.
|
||||
/mob/living/carbon/human/inject_blood(obj/item/weapon/reagent_containers/container, var/amount)
|
||||
|
||||
var/datum/reagent/blood/injected = get_blood(container.reagents)
|
||||
|
||||
if(!istype(injected)) //Sanity..
|
||||
return
|
||||
|
||||
if(species && species.flags & NO_BLOOD)
|
||||
reagents.add_reagent("blood", amount, injected.data)
|
||||
reagents.update_total()
|
||||
return
|
||||
|
||||
var/datum/reagent/blood/our = get_blood(vessel)
|
||||
|
||||
if(!istype(our)) // Do we not have blood?
|
||||
vessel.add_reagent("blood", amount, injected.data) // This is only ran once, so we need to add back their DNA.
|
||||
vessel.update_total()
|
||||
..()
|
||||
our = get_blood(vessel) // Get the new blood.
|
||||
our.data["blood_DNA"] = dna.unique_enzymes // Give it the proper DNA we had before (src.dna)
|
||||
our.data["blood_type"] = dna.b_type // Proper blood type.
|
||||
our.data["donor"] = src // Without this, it'd be random each time it was extracted or Null.
|
||||
return
|
||||
|
||||
if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"]) )
|
||||
reagents.add_reagent("toxin",amount * 0.5)
|
||||
reagents.update_total()
|
||||
else
|
||||
vessel.add_reagent("blood", amount, injected.data)
|
||||
vessel.update_total()
|
||||
..()
|
||||
|
||||
//Gets human's own blood.
|
||||
/mob/living/carbon/proc/get_blood(datum/reagents/container)
|
||||
var/datum/reagent/blood/res = locate() in container.reagent_list //Grab some blood
|
||||
if(res) // Make sure there's some blood at all
|
||||
if(res.data["donor"] != src) //If it's not theirs, then we look for theirs
|
||||
for(var/datum/reagent/blood/D in container.reagent_list)
|
||||
if(D.data["donor"] == src)
|
||||
return D
|
||||
return res
|
||||
|
||||
/mob/living/carbon/human/get_blood(datum/reagents/container)
|
||||
if(species.exotic_blood)
|
||||
return container.get_reagent_from_id(species.exotic_blood)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/proc/get_blood_name()
|
||||
return "blood"
|
||||
|
||||
/mob/living/carbon/human/get_blood_name()
|
||||
if(species.exotic_blood)
|
||||
return species.exotic_blood
|
||||
else
|
||||
return ..()
|
||||
// This is has more potential uses, and is probably faster than the old proc.
|
||||
/proc/get_safe_blood(bloodtype)
|
||||
. = list()
|
||||
if(!bloodtype)
|
||||
return
|
||||
switch(bloodtype)
|
||||
if("A-")
|
||||
return list("A-", "O-")
|
||||
if("A+")
|
||||
return list("A-", "A+", "O-", "O+")
|
||||
if("B-")
|
||||
return list("B-", "O-")
|
||||
if("B+")
|
||||
return list("B-", "B+", "O-", "O+")
|
||||
if("AB-")
|
||||
return list("A-", "B-", "O-", "AB-")
|
||||
if("AB+")
|
||||
return list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+")
|
||||
if("O-")
|
||||
return list("O-")
|
||||
if("O+")
|
||||
return list("O-", "O+")
|
||||
|
||||
/proc/blood_incompatible(donor,receiver)
|
||||
//to add a splatter of blood or other mob liquid.
|
||||
/mob/living/proc/add_splatter_floor(turf/T, small_drip)
|
||||
if(get_blood_id() != "blood")//is it blood or welding fuel?
|
||||
return
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
|
||||
var/donor_antigen = copytext(donor,1,lentext(donor))
|
||||
var/receiver_antigen = copytext(receiver,1,lentext(receiver))
|
||||
var/donor_rh = findtext("+",donor)
|
||||
var/receiver_rh = findtext("+",receiver)
|
||||
var/list/temp_blood_DNA
|
||||
var/list/b_data = get_blood_data(get_blood_id())
|
||||
|
||||
if(donor_rh && !receiver_rh) return 1
|
||||
switch(receiver_antigen)
|
||||
if("A")
|
||||
if(donor_antigen != "A" && donor_antigen != "O") return 1
|
||||
if("B")
|
||||
if(donor_antigen != "B" && donor_antigen != "O") return 1
|
||||
if("O")
|
||||
if(donor_antigen != "O") return 1
|
||||
//AB is a universal receiver.
|
||||
return 0
|
||||
|
||||
/*
|
||||
Target: Thing/tile to get bloody
|
||||
Source: Human or blood reagent
|
||||
Large: Whether the splat should be big or not
|
||||
*/
|
||||
/proc/blood_splatter(var/target,var/source,var/large = 0)
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/B
|
||||
var/decal_type = /obj/effect/decal/cleanable/blood/splatter
|
||||
var/turf/T = get_turf(target)
|
||||
var/datum/reagent/blood/bld
|
||||
if(istype(source,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = source
|
||||
bld = H.get_blood(H.vessel)
|
||||
if(H.species.exotic_blood)
|
||||
H.vessel.reaction(T, TOUCH)
|
||||
if(small_drip)
|
||||
// Only a certain number of drips (or one large splatter) can be on a given turf.
|
||||
var/obj/effect/decal/cleanable/blood/drip/drop = locate() in T
|
||||
if(drop)
|
||||
if(drop.drips < 3)
|
||||
drop.drips++
|
||||
drop.overlays |= pick(drop.random_icon_states)
|
||||
drop.transfer_mob_blood_dna(src)
|
||||
drop.basecolor = b_data["blood_color"]
|
||||
drop.update_icon()
|
||||
else
|
||||
temp_blood_DNA = list()
|
||||
temp_blood_DNA |= drop.blood_DNA.Copy() //we transfer the dna from the drip to the splatter
|
||||
qdel(drop)
|
||||
else
|
||||
drop = new(T)
|
||||
drop.transfer_mob_blood_dna(src)
|
||||
drop.basecolor = b_data["blood_color"]
|
||||
drop.update_icon()
|
||||
return
|
||||
else if(H.species.flags & NO_BLOOD)
|
||||
return
|
||||
else if(istype(source, /datum/reagent))
|
||||
bld = source
|
||||
if(!istype(bld, /datum/reagent/blood))
|
||||
var/datum/reagent/R = bld
|
||||
if(istype(R))
|
||||
R.reaction_turf(T, R.volume)
|
||||
return
|
||||
else if(source)
|
||||
log_runtime(EXCEPTION("Non-human or reagent blood source. Area: [get_area(source)], Name: [source]"), source)
|
||||
|
||||
// Are we dripping or splattering?
|
||||
var/list/drips = list()
|
||||
// Only a certain number of drips (or one large splatter) can be on a given turf.
|
||||
for(var/obj/effect/decal/cleanable/blood/drip/drop in T)
|
||||
drips |= drop.drips
|
||||
qdel(drop)
|
||||
if(!large && drips.len < 3)
|
||||
decal_type = /obj/effect/decal/cleanable/blood/drip
|
||||
|
||||
// Find a blood decal or create a new one.
|
||||
B = locate(decal_type) in T
|
||||
var/obj/effect/decal/cleanable/blood/B = locate() in T
|
||||
if(!B)
|
||||
B = new decal_type(T)
|
||||
B = new /obj/effect/decal/cleanable/blood/splatter(T)
|
||||
B.transfer_mob_blood_dna(src) //give blood info to the blood decal.
|
||||
if(temp_blood_DNA)
|
||||
B.blood_DNA |= temp_blood_DNA
|
||||
B.update_icon()
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/drip/drop = B
|
||||
if(istype(drop) && drips && drips.len && !large)
|
||||
drop.overlays |= drips
|
||||
drop.drips |= drips
|
||||
/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip)
|
||||
if(!(NO_BLOOD in species.species_traits))
|
||||
..()
|
||||
|
||||
// If there's no data to copy, call it quits here.
|
||||
if(!bld)
|
||||
return B
|
||||
/mob/living/carbon/alien/add_splatter_floor(turf/T, small_drip)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
var/obj/effect/decal/cleanable/blood/xeno/B = locate() in T.contents
|
||||
if(!B)
|
||||
B = new(T)
|
||||
B.blood_DNA["UNKNOWN DNA"] = "X*"
|
||||
|
||||
// Update appearance.
|
||||
if(bld.data["blood_colour"])
|
||||
B.basecolor = bld.data["blood_colour"]
|
||||
B.update_icon()
|
||||
|
||||
// Update blood information.
|
||||
if(bld.data["blood_DNA"])
|
||||
B.blood_DNA = list()
|
||||
if(bld.data["blood_type"])
|
||||
B.blood_DNA[bld.data["blood_DNA"]] = bld.data["blood_type"]
|
||||
else
|
||||
B.blood_DNA[bld.data["blood_DNA"]] = "O+"
|
||||
|
||||
return B
|
||||
/mob/living/silicon/robot/add_splatter_floor(turf/T, small_drip)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
var/obj/effect/decal/cleanable/blood/oil/B = locate() in T.contents
|
||||
if(!B)
|
||||
B = new(T)
|
||||
@@ -30,9 +30,7 @@
|
||||
return returnorg
|
||||
|
||||
/mob/living/carbon/get_organ_slot(slot)
|
||||
for(var/obj/item/organ/internal/O in internal_organs)
|
||||
if(slot == O.slot)
|
||||
return O
|
||||
return internal_organs_slot[slot]
|
||||
|
||||
/mob/living/carbon/get_int_organ_tag(tag)
|
||||
for(var/obj/item/organ/internal/O in internal_organs)
|
||||
|
||||
@@ -29,8 +29,9 @@ var/list/organ_cache = list()
|
||||
var/freezer_update_period = 100
|
||||
var/is_in_freezer = 0
|
||||
|
||||
var/sterile = 0 //can the organ be infected by germs?
|
||||
var/tough = 0 //can organ be easily damaged?
|
||||
var/sterile = FALSE //can the organ be infected by germs?
|
||||
var/tough = FALSE //can organ be easily damaged?
|
||||
|
||||
|
||||
/obj/item/organ/Destroy()
|
||||
processing_objects.Remove(src)
|
||||
@@ -45,7 +46,6 @@ var/list/organ_cache = list()
|
||||
|
||||
/obj/item/organ/New(var/mob/living/carbon/holder)
|
||||
..(holder)
|
||||
create_reagents(5)
|
||||
if(!max_damage)
|
||||
max_damage = min_broken_damage * 2
|
||||
if(istype(holder))
|
||||
@@ -95,16 +95,11 @@ var/list/organ_cache = list()
|
||||
return
|
||||
|
||||
//Process infections
|
||||
if((status & ORGAN_ROBOT) || sterile ||(owner && owner.species && (owner.species.flags & IS_PLANT)))
|
||||
if((status & ORGAN_ROBOT) || sterile || (owner && (IS_PLANT in owner.species.species_traits)))
|
||||
germ_level = 0
|
||||
return
|
||||
|
||||
if(!owner)
|
||||
if(reagents && prob(40))
|
||||
reagents.remove_any(0.1)
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
R.reaction_turf(get_turf(src), 0.1)
|
||||
|
||||
// Maybe scale it down a bit, have it REALLY kick in once past the basic infection threshold
|
||||
// Another mercy for surgeons preparing transplant organs
|
||||
germ_level++
|
||||
@@ -115,27 +110,20 @@ var/list/organ_cache = list()
|
||||
if(germ_level >= INFECTION_LEVEL_THREE)
|
||||
necrotize()
|
||||
|
||||
if(damage >= max_damage)
|
||||
necrotize()
|
||||
|
||||
else if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs
|
||||
//** Handle antibiotics and curing infections
|
||||
handle_antibiotics()
|
||||
handle_germ_effects()
|
||||
|
||||
//check if we've hit max_damage
|
||||
if(damage >= max_damage)
|
||||
necrotize()
|
||||
|
||||
/obj/item/organ/proc/is_preserved()
|
||||
if(istype(loc,/obj/item/device/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/item/bodybag/cryobag))
|
||||
return 1
|
||||
if(is_found_within(/obj/structure/closet/crate/freezer))
|
||||
return 1
|
||||
if(istype(loc,/turf))
|
||||
if(is_found_within(/obj/machinery/clonepod))
|
||||
return 1
|
||||
if(isturf(loc))
|
||||
if(world.time - last_freezer_update_time > freezer_update_period)
|
||||
// I don't want to loop through everything in the tile constantly, especially since it'll be a pile of organs
|
||||
// if the virologist releases gibbingtons again or something
|
||||
@@ -178,12 +166,12 @@ var/list/organ_cache = list()
|
||||
if(antibiotics < 5 && parent.germ_level < germ_level && ( parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30) ))
|
||||
parent.germ_level++
|
||||
|
||||
/obj/item/organ/internal/handle_germ_effects()
|
||||
..()
|
||||
if(germ_level >= INFECTION_LEVEL_TWO)
|
||||
if(prob(3)) //about once every 30 seconds
|
||||
take_damage(1,silent=prob(30))
|
||||
|
||||
/obj/item/organ/proc/receive_chem(chemical as obj)
|
||||
return 0
|
||||
|
||||
/obj/item/organ/proc/rejuvenate()
|
||||
damage = 0
|
||||
germ_level = 0
|
||||
@@ -203,7 +191,7 @@ var/list/organ_cache = list()
|
||||
return damage >= min_bruised_damage
|
||||
|
||||
/obj/item/organ/proc/is_broken()
|
||||
return (damage >= min_broken_damage || (status & ORGAN_CUT_AWAY) || ((status & ORGAN_BROKEN) && !(status & ORGAN_SPLINTED)))
|
||||
return (damage >= min_broken_damage || ((status & ORGAN_BROKEN) && !(status & ORGAN_SPLINTED)))
|
||||
|
||||
//Germs
|
||||
/obj/item/organ/proc/handle_antibiotics()
|
||||
@@ -233,7 +221,7 @@ var/list/organ_cache = list()
|
||||
W.time_inflicted = world.time
|
||||
|
||||
//Note: external organs have their own version of this proc
|
||||
/obj/item/organ/proc/take_damage(amount, var/silent=0)
|
||||
/obj/item/organ/proc/take_damage(amount, silent = 0)
|
||||
if(tough)
|
||||
return
|
||||
if(status & ORGAN_ROBOT)
|
||||
@@ -247,36 +235,43 @@ var/list/organ_cache = list()
|
||||
if(parent && !silent)
|
||||
owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1)
|
||||
|
||||
//check if we've hit max_damage
|
||||
if(damage >= max_damage)
|
||||
necrotize()
|
||||
|
||||
/obj/item/organ/proc/robotize() //Being used to make robutt hearts, etc
|
||||
robotic = 2
|
||||
status &= ~ORGAN_BROKEN
|
||||
status &= ~ORGAN_BLEEDING
|
||||
status &= ~ORGAN_SPLINTED
|
||||
status &= ~ORGAN_CUT_AWAY
|
||||
status &= ~ORGAN_ATTACHABLE
|
||||
status &= ~ORGAN_DESTROYED
|
||||
status |= ORGAN_ROBOT
|
||||
status |= ORGAN_ASSISTED
|
||||
|
||||
/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/emp_act(severity)
|
||||
/obj/item/organ/external/emp_act(severity)
|
||||
if(!(status & ORGAN_ROBOT))
|
||||
return
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
take_damage(0,20)
|
||||
return
|
||||
if(2.0)
|
||||
take_damage(0,7)
|
||||
return
|
||||
if(3.0)
|
||||
take_damage(0,3)
|
||||
if(tough)
|
||||
switch(severity)
|
||||
if(1)
|
||||
take_damage(0, 5.5)
|
||||
if(owner)
|
||||
owner.Stun(10)
|
||||
if(2)
|
||||
take_damage(0, 2.8)
|
||||
if(owner)
|
||||
owner.Stun(5)
|
||||
else
|
||||
switch(severity)
|
||||
if(1)
|
||||
take_damage(0, 20)
|
||||
if(2)
|
||||
take_damage(0, 7)
|
||||
|
||||
/obj/item/organ/internal/emp_act(severity)
|
||||
if(!robotic)
|
||||
@@ -284,13 +279,11 @@ var/list/organ_cache = list()
|
||||
if(robotic == 2)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
take_damage(20,1)
|
||||
take_damage(20, 1)
|
||||
if(2.0)
|
||||
take_damage(7,1)
|
||||
if(3.0)
|
||||
take_damage(3,1)
|
||||
take_damage(7, 1)
|
||||
else if(robotic == 1)
|
||||
take_damage(11,1)
|
||||
take_damage(11, 1)
|
||||
|
||||
/obj/item/organ/internal/heart/emp_act(intensity)
|
||||
if(owner && robotic == 2)
|
||||
@@ -310,10 +303,6 @@ var/list/organ_cache = list()
|
||||
|
||||
loc = get_turf(owner)
|
||||
processing_objects |= src
|
||||
var/datum/reagent/blood/organ_blood
|
||||
if(reagents) organ_blood = reagents.get_reagent_from_id(owner.get_blood_name())
|
||||
if((!organ_blood || !organ_blood.data["blood_DNA"]) && (owner && !(owner.species.flags & NO_BLOOD)))
|
||||
owner.vessel.trans_to(src, 5, 1, 1)
|
||||
|
||||
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)
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
var/brute_dam = 0
|
||||
var/burn_dam = 0
|
||||
var/max_size = 0
|
||||
var/last_dam = -1
|
||||
var/icon/mob_icon
|
||||
var/gendered_icon = 0
|
||||
var/limb_name
|
||||
@@ -34,18 +33,13 @@
|
||||
var/cannot_break
|
||||
var/s_tone = null
|
||||
var/list/s_col = null // If this is instantiated, it should be a list of length 3
|
||||
var/list/wounds = list()
|
||||
var/list/child_icons = list()
|
||||
var/number_wounds = 0 // cache the number of wounds, which is NOT wounds.len!
|
||||
var/perma_injury = 0
|
||||
// 0: Don't fail when at full damage
|
||||
// 1: Neatly pop off at full damage, stop damage propogation
|
||||
// 2: Disintegrate at full damage, continue damage propogation
|
||||
var/fail_at_full_damage = 0
|
||||
|
||||
var/dismember_at_max_damage = FALSE
|
||||
|
||||
var/obj/item/organ/external/parent
|
||||
var/list/obj/item/organ/external/children
|
||||
var/list/convertable_children = list()
|
||||
|
||||
// Internal organs of this body part
|
||||
var/list/internal_organs = list()
|
||||
@@ -58,15 +52,11 @@
|
||||
var/encased // Needs to be opened with a saw to access the organs.
|
||||
|
||||
var/obj/item/hidden = null
|
||||
var/list/implants = list()
|
||||
|
||||
// how often wounds should be updated, a higher number means less often
|
||||
var/wound_update_accuracy = 1
|
||||
|
||||
var/list/embedded_objects = list()
|
||||
var/internal_bleeding = FALSE
|
||||
var/amputation_point // Descriptive string used in amputation.
|
||||
var/can_grasp
|
||||
var/can_stand
|
||||
var/wound_cleanup_timer
|
||||
|
||||
var/splinted_count = 0 //Time when this organ was last splinted
|
||||
|
||||
@@ -79,7 +69,6 @@
|
||||
if(owner)
|
||||
to_chat(owner, "<span class='notice'>You can't feel your [name] anymore...</span>")
|
||||
owner.update_body(update_sprite)
|
||||
owner.bad_external_organs |= src
|
||||
if(vital)
|
||||
owner.death()
|
||||
|
||||
@@ -100,13 +89,7 @@
|
||||
|
||||
QDEL_LIST(children)
|
||||
|
||||
if(wound_cleanup_timer)
|
||||
deltimer(wound_cleanup_timer)
|
||||
wound_cleanup_timer = null
|
||||
|
||||
QDEL_LIST(wounds)
|
||||
|
||||
QDEL_LIST(implants)
|
||||
QDEL_LIST(embedded_objects)
|
||||
|
||||
QDEL_NULL(hidden)
|
||||
|
||||
@@ -116,26 +99,24 @@
|
||||
switch(open)
|
||||
if(0)
|
||||
if(istype(W,/obj/item/weapon/scalpel))
|
||||
spread_germs_to_organ(src,user, W)
|
||||
spread_germs_to_organ(src, user, W)
|
||||
user.visible_message("<span class='danger'><b>[user]</b> cuts [src] open with [W]!</span>")
|
||||
open++
|
||||
return
|
||||
if(1)
|
||||
if(istype(W,/obj/item/weapon/retractor))
|
||||
spread_germs_to_organ(src,user, W)
|
||||
spread_germs_to_organ(src, user, W)
|
||||
user.visible_message("<span class='danger'><b>[user]</b> cracks [src] open like an egg with [W]!</span>")
|
||||
open++
|
||||
return
|
||||
if(2)
|
||||
if(istype(W,/obj/item/weapon/hemostat))
|
||||
spread_germs_to_organ(src,user, W)
|
||||
spread_germs_to_organ(src, user, W)
|
||||
if(contents.len)
|
||||
var/obj/item/removing = pick(contents)
|
||||
var/obj/item/organ/internal/O = removing
|
||||
if(istype(O))
|
||||
O.status |= ORGAN_CUT_AWAY
|
||||
if(!O.sterile)
|
||||
spread_germs_to_organ(O,user, W) // This wouldn't be any cleaner than the actual surgery
|
||||
spread_germs_to_organ(O, user, W) // This wouldn't be any cleaner than the actual surgery
|
||||
user.put_in_hands(removing)
|
||||
user.visible_message("<span class='danger'><b>[user]</b> extracts [removing] from [src] with [W]!</span>")
|
||||
else
|
||||
@@ -162,7 +143,6 @@
|
||||
|
||||
/obj/item/organ/external/replaced(var/mob/living/carbon/human/target)
|
||||
owner = target
|
||||
status = status & ~ORGAN_DESTROYED
|
||||
forceMove(owner)
|
||||
if(istype(owner))
|
||||
if(!isnull(owner.bodyparts_by_name[limb_name]))
|
||||
@@ -178,12 +158,7 @@
|
||||
if(!parent.children)
|
||||
parent.children = list()
|
||||
parent.children.Add(src)
|
||||
//Remove all stump wounds since limb is not missing anymore
|
||||
for(var/datum/wound/lost_limb/W in parent.wounds)
|
||||
parent.wounds -= W
|
||||
qdel(W)
|
||||
break
|
||||
parent.update_damages()
|
||||
parent.check_fracture()
|
||||
|
||||
/obj/item/organ/external/attempt_become_organ(obj/item/organ/external/parent,mob/living/carbon/human/H)
|
||||
if(parent_organ != parent.limb_name)
|
||||
@@ -195,15 +170,17 @@
|
||||
DAMAGE PROCS
|
||||
****************************************************/
|
||||
|
||||
/obj/item/organ/external/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list())
|
||||
/obj/item/organ/external/take_damage(brute, burn, sharp, used_weapon = null, list/forbidden_limbs = list(), ignore_resists = FALSE)
|
||||
if(tough && !ignore_resists)
|
||||
brute = max(0, brute - 5)
|
||||
burn = max(0, burn - 4)
|
||||
|
||||
if((brute <= 0) && (burn <= 0))
|
||||
return 0
|
||||
|
||||
if(status & ORGAN_DESTROYED)
|
||||
return 0
|
||||
|
||||
brute *= brute_mod
|
||||
burn *= burn_mod
|
||||
if(!ignore_resists)
|
||||
brute *= brute_mod
|
||||
burn *= burn_mod
|
||||
|
||||
// Threshold needed to have a chance of hurting internal bits with something sharp
|
||||
#define LIMB_SHARP_THRESH_INT_DMG 5
|
||||
@@ -216,9 +193,8 @@
|
||||
// Damage an internal organ
|
||||
if(internal_organs && internal_organs.len)
|
||||
var/obj/item/organ/internal/I = pick(internal_organs)
|
||||
if(!I.tough)//mostly for cybernetic organs
|
||||
I.take_damage(brute / 2)
|
||||
brute -= brute / 2
|
||||
I.take_damage(brute * 0.5)
|
||||
brute -= brute * 0.5
|
||||
|
||||
if(status & ORGAN_BROKEN && prob(40) && brute)
|
||||
owner.emote("scream") //getting hit on broken hand hurts
|
||||
@@ -229,74 +205,63 @@
|
||||
if(used_weapon)
|
||||
add_autopsy_data("[used_weapon]", brute + burn)
|
||||
|
||||
var/can_cut = (prob(brute*2) || sharp) && !(status & ORGAN_ROBOT)
|
||||
// If the limbs can break, make sure we don't exceed the maximum damage a limb can take before breaking
|
||||
if((brute_dam + burn_dam + brute + burn) < max_damage || !config.limbs_can_break)
|
||||
if(brute)
|
||||
if(can_cut)
|
||||
createwound( CUT, brute )
|
||||
else
|
||||
createwound( BRUISE, brute )
|
||||
if(burn)
|
||||
createwound( BURN, burn )
|
||||
// Make sure we don't exceed the maximum damage a limb can take before dismembering
|
||||
if((brute_dam + burn_dam + brute + burn) < max_damage)
|
||||
brute_dam += brute
|
||||
burn_dam += burn
|
||||
check_for_internal_bleeding(brute)
|
||||
else
|
||||
//If we can't inflict the full amount of damage, spread the damage in other ways
|
||||
//How much damage can we actually cause?
|
||||
var/can_inflict = max_damage * config.organ_health_multiplier - (brute_dam + burn_dam)
|
||||
var/can_inflict = max_damage - (brute_dam + burn_dam)
|
||||
if(can_inflict)
|
||||
if(brute > 0)
|
||||
//Inflict all burte damage we can
|
||||
if(can_cut)
|
||||
createwound( CUT, min(brute,can_inflict) )
|
||||
else
|
||||
createwound( BRUISE, min(brute,can_inflict) )
|
||||
brute_dam = min(brute_dam + brute, brute_dam + can_inflict)
|
||||
var/temp = can_inflict
|
||||
//How much mroe damage can we inflict
|
||||
can_inflict = max(0, can_inflict - brute)
|
||||
//How much brute damage is left to inflict
|
||||
brute = max(0, brute - temp)
|
||||
check_for_internal_bleeding(brute)
|
||||
|
||||
if(burn > 0 && can_inflict)
|
||||
//Inflict all burn damage we can
|
||||
createwound(BURN, min(burn,can_inflict))
|
||||
burn_dam = min(burn_dam + burn, burn_dam + can_inflict)
|
||||
//How much burn damage is left to inflict
|
||||
burn = max(0, burn - can_inflict)
|
||||
//If there are still hurties to dispense
|
||||
if(burn || brute)
|
||||
if(fail_at_full_damage == 1 && body_part != UPPER_TORSO && body_part != LOWER_TORSO)
|
||||
droplimb(1) //Clean loss, just drop the limb and be done
|
||||
else
|
||||
//List organs we can pass it to
|
||||
var/list/obj/item/organ/external/possible_points = list()
|
||||
if(parent)
|
||||
possible_points += parent
|
||||
if(children) for(var/organ in children)
|
||||
if(organ) possible_points += organ
|
||||
if(forbidden_limbs.len)
|
||||
possible_points -= forbidden_limbs
|
||||
if(possible_points.len)
|
||||
//And pass the pain around
|
||||
var/obj/item/organ/external/target = pick(possible_points)
|
||||
target.take_damage(brute, burn, sharp, edge, used_weapon, forbidden_limbs + src)
|
||||
if(fail_at_full_damage == 2 && body_part != UPPER_TORSO && body_part != LOWER_TORSO)
|
||||
var/losstype
|
||||
if(burn > brute)
|
||||
losstype = DROPLIMB_BURN
|
||||
else
|
||||
losstype = DROPLIMB_BLUNT
|
||||
droplimb(0, losstype) // less clean than a robot arm, doesn't buffer damage either
|
||||
//List organs we can pass it to
|
||||
var/list/obj/item/organ/external/possible_points = list()
|
||||
if(parent)
|
||||
possible_points += parent
|
||||
if(children)
|
||||
for(var/organ in children)
|
||||
if(organ)
|
||||
possible_points += organ
|
||||
if(forbidden_limbs.len)
|
||||
possible_points -= forbidden_limbs
|
||||
if(possible_points.len)
|
||||
//And pass the pain around
|
||||
var/obj/item/organ/external/target = pick(possible_points)
|
||||
target.take_damage(brute, burn, sharp, used_weapon, forbidden_limbs + src, ignore_resists = TRUE) //If the damage was reduced before, don't reduce it again
|
||||
|
||||
// sync the organ's damage with its wounds
|
||||
src.update_damages()
|
||||
if(dismember_at_max_damage && body_part != UPPER_TORSO && body_part != LOWER_TORSO) // We've ensured all damage to the mob is retained, now let's drop it, if necessary.
|
||||
droplimb(1) //Clean loss, just drop the limb and be done
|
||||
|
||||
// See if bones need to break
|
||||
check_fracture()
|
||||
var/mob/living/carbon/owner_old = owner //Need to update health, but need a reference in case the below check cuts off a limb.
|
||||
//If limb took enough damage, try to cut or tear it off
|
||||
if(owner && loc == owner)
|
||||
if(!cannot_amputate && config.limbs_can_break && (brute_dam) >= (max_damage * config.organ_health_multiplier))
|
||||
if(!cannot_amputate && (brute_dam) >= (max_damage))
|
||||
if(prob(brute / 2))
|
||||
if(edge)
|
||||
droplimb(0,DROPLIMB_EDGE)
|
||||
if(sharp)
|
||||
droplimb(0, DROPLIMB_SHARP)
|
||||
|
||||
if(owner_old) owner_old.updatehealth()
|
||||
if(owner_old)
|
||||
owner_old.updatehealth()
|
||||
return update_icon()
|
||||
|
||||
#undef LIMB_SHARP_THRESH_INT_DMG
|
||||
@@ -308,34 +273,16 @@
|
||||
if(status & ORGAN_ROBOT && !robo_repair)
|
||||
return
|
||||
|
||||
//Heal damage on the individual wounds
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(brute == 0 && burn == 0)
|
||||
break
|
||||
|
||||
// heal brute damage
|
||||
if(W.damage_type == CUT || W.damage_type == BRUISE)
|
||||
brute = W.heal_damage(brute)
|
||||
else if(W.damage_type == BURN)
|
||||
burn = W.heal_damage(burn)
|
||||
brute_dam = max(brute_dam - brute, 0)
|
||||
burn_dam = max(burn_dam - burn, 0)
|
||||
|
||||
if(internal)
|
||||
status &= ~ORGAN_BROKEN
|
||||
perma_injury = 0
|
||||
|
||||
/*
|
||||
if((brute || burn) && children && children.len && (owner.species.flags & REGENERATES_LIMBS))
|
||||
var/obj/item/organ/external/stump/S = locate() in children
|
||||
if(S)
|
||||
// to_chat(world, "Extra healing to go around ([brute+burn]) and [owner] needs a replacement limb.")
|
||||
*/
|
||||
|
||||
//Sync the organ's damage with its wounds
|
||||
src.update_damages()
|
||||
owner.updatehealth()
|
||||
|
||||
var/result = update_icon()
|
||||
return result
|
||||
return update_icon()
|
||||
|
||||
/*
|
||||
This function completely restores a damaged organ to perfect condition.
|
||||
@@ -353,7 +300,7 @@ This function completely restores a damaged organ to perfect condition.
|
||||
brute_dam = 0
|
||||
burn_dam = 0
|
||||
open = 0 //Closing all wounds.
|
||||
wounds.Cut() //Clears all wounds! Good as new.
|
||||
internal_bleeding = FALSE
|
||||
if(istype(src, /obj/item/organ/external/head) && disfigured) //If their head's disfigured, refigure it.
|
||||
disfigured = 0
|
||||
|
||||
@@ -364,104 +311,19 @@ This function completely restores a damaged organ to perfect condition.
|
||||
for(var/obj/item/organ/external/EO in contents)
|
||||
EO.rejuvenate()
|
||||
|
||||
// remove embedded objects and drop them on the floor
|
||||
for(var/obj/implanted_object in implants)
|
||||
if(!istype(implanted_object,/obj/item/weapon/implant)) // We don't want to remove REAL implants. Just shrapnel etc.
|
||||
implanted_object.loc = owner.loc
|
||||
implants -= implanted_object
|
||||
|
||||
owner.updatehealth()
|
||||
update_icon()
|
||||
if(!owner)
|
||||
processing_objects |= src
|
||||
|
||||
|
||||
/obj/item/organ/external/proc/createwound(var/type = CUT, var/damage)
|
||||
if(damage == 0) return
|
||||
|
||||
//moved this before the open_wound check so that having many small wounds for example doesn't somehow protect you from taking internal damage
|
||||
//Possibly trigger an internal wound, too.
|
||||
var/local_damage = brute_dam + burn_dam + damage
|
||||
if(damage > 15 && type != BURN && local_damage > 30 && prob(damage) && !(status & ORGAN_ROBOT))
|
||||
var/datum/wound/internal_bleeding/I = new ()
|
||||
wounds += I
|
||||
owner.custom_pain("You feel something rip in your [name]!", 1)
|
||||
|
||||
// first check whether we can widen an existing wound
|
||||
if(wounds.len > 0 && prob(max(50+(number_wounds-1)*10,90)))
|
||||
if((type == CUT || type == BRUISE) && damage >= 5)
|
||||
//we need to make sure that the wound we are going to worsen is compatible with the type of damage...
|
||||
var/list/compatible_wounds = list()
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.can_worsen(type, damage))
|
||||
compatible_wounds += W
|
||||
|
||||
if(compatible_wounds.len)
|
||||
var/datum/wound/W = pick(compatible_wounds)
|
||||
W.open_wound(damage)
|
||||
if(prob(25))
|
||||
if(status & ORGAN_ROBOT)
|
||||
owner.visible_message("<span class='alert'>The damage to [owner.name]'s [name] worsens.</span>",\
|
||||
"<span class='alert'>The damage to your [name] worsens.</span>",\
|
||||
"You hear the screech of abused metal.")
|
||||
else
|
||||
owner.visible_message("<span class='alert'>The wound on [owner.name]'s [name] widens with a nasty ripping noise.</span>",\
|
||||
"<span class='alert'>The wound on your [name] widens with a nasty ripping noise.</span>",\
|
||||
"You hear a nasty ripping noise, as if flesh is being torn apart.")
|
||||
return
|
||||
|
||||
//Creating wound
|
||||
var/wound_type = get_wound_type(type, damage)
|
||||
|
||||
if(wound_type)
|
||||
var/datum/wound/W = new wound_type(damage)
|
||||
|
||||
//Check whether we can add the wound to an existing wound
|
||||
for(var/datum/wound/other in wounds)
|
||||
if(other.can_merge(W))
|
||||
other.merge_wound(W)
|
||||
W = null // to signify that the wound was added
|
||||
break
|
||||
if(W)
|
||||
wounds += W
|
||||
|
||||
/****************************************************
|
||||
PROCESSING & UPDATING
|
||||
****************************************************/
|
||||
|
||||
//Determines if we even need to process this organ.
|
||||
|
||||
/obj/item/organ/external/proc/need_process()
|
||||
if(status & (ORGAN_CUT_AWAY|ORGAN_GAUZED|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DESTROYED|ORGAN_SPLINTED|ORGAN_DEAD|ORGAN_MUTATED))
|
||||
return 1
|
||||
if(brute_dam || burn_dam)
|
||||
return 1
|
||||
if(last_dam != brute_dam + burn_dam) // Process when we are fully healed up.
|
||||
last_dam = brute_dam + burn_dam
|
||||
return 1
|
||||
else
|
||||
last_dam = brute_dam + burn_dam
|
||||
if(germ_level)
|
||||
return 1
|
||||
if(!wound_cleanup_timer && wounds.len)
|
||||
wound_cleanup_timer = addtimer(src, "cleanup_wounds", SecondsToTicks(600), 1, wounds)
|
||||
|
||||
if(update_icon())
|
||||
owner.UpdateDamageIcon(1)
|
||||
return 0
|
||||
|
||||
/obj/item/organ/external/process()
|
||||
if(owner)
|
||||
if(parent)
|
||||
if(parent.status & ORGAN_DESTROYED)
|
||||
status |= ORGAN_DESTROYED
|
||||
owner.update_body(1)
|
||||
return
|
||||
|
||||
// Process wounds, doing healing etc. Only do this every few ticks to save processing power
|
||||
if(owner.life_tick % wound_update_accuracy == 0)
|
||||
update_wounds()
|
||||
|
||||
//Chem traces slowly vanish
|
||||
if(owner.life_tick % 10 == 0)
|
||||
for(var/chemID in trace_chemicals)
|
||||
@@ -498,7 +360,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|ORGAN_DESTROYED) || (owner.species && owner.species.flags & IS_PLANT)) //Robotic limbs shouldn't be infected, nor should nonexistant limbs.
|
||||
if((status & ORGAN_ROBOT) || (IS_PLANT in owner.species.species_traits)) //Robotic limbs shouldn't be infected, nor should nonexistant limbs.
|
||||
germ_level = 0
|
||||
return
|
||||
|
||||
@@ -514,17 +376,10 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
|
||||
/obj/item/organ/external/proc/handle_germ_sync()
|
||||
var/antibiotics = owner.reagents.get_reagent_amount("spaceacillin")
|
||||
for(var/datum/wound/W in wounds)
|
||||
//Open wounds can become infected
|
||||
if(owner.germ_level > W.germ_level && W.infection_check())
|
||||
W.germ_level++
|
||||
|
||||
if(antibiotics < 5)
|
||||
for(var/datum/wound/W in wounds)
|
||||
//Infected wounds raise the organ's germ level
|
||||
if(W.germ_level > germ_level)
|
||||
germ_level++
|
||||
break //limit increase to a maximum of one per second
|
||||
//Open wounds can become infected
|
||||
if(owner.germ_level > germ_level && infection_check())
|
||||
germ_level++
|
||||
|
||||
/obj/item/organ/external/handle_germ_effects()
|
||||
|
||||
@@ -571,99 +426,20 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
germ_level++
|
||||
owner.adjustToxLoss(1)
|
||||
|
||||
//Updating wounds. Handles wound natural I had some free spachealing, internal bleedings and infections
|
||||
/obj/item/organ/external/proc/update_wounds()
|
||||
|
||||
if((status & ORGAN_ROBOT)) //Robotic limbs don't heal or get worse.
|
||||
return
|
||||
|
||||
for(var/datum/wound/W in wounds)
|
||||
|
||||
// Internal wounds get worse over time. Low temperatures (cryo) stop them.
|
||||
if(W.internal && !W.can_autoheal() && owner.bodytemperature >= 170)
|
||||
var/bicardose = owner.reagents.get_reagent_amount("styptic_powder")
|
||||
if(!bicardose) //styptic powder stops internal wounds from growing bigger with time, and also stop bleeding
|
||||
W.open_wound(0.1 * wound_update_accuracy)
|
||||
owner.vessel.remove_reagent("blood",0.05 * W.damage * wound_update_accuracy)
|
||||
|
||||
owner.vessel.remove_reagent("blood",0.02 * W.damage * wound_update_accuracy)
|
||||
if(prob(1 * wound_update_accuracy))
|
||||
owner.custom_pain("You feel a stabbing pain in your [name]!",1)
|
||||
|
||||
//overdose of styptic powder begins healing IB
|
||||
if(owner.reagents.get_reagent_amount("styptic_powder") >= 30)
|
||||
W.damage = max(0, W.damage - 0.2)
|
||||
|
||||
// slow healing
|
||||
var/heal_amt = 0
|
||||
|
||||
// if damage >= 50 AFTER treatment then it's probably too severe to heal within the timeframe of a round.
|
||||
if(W.can_autoheal() && W.wound_damage() < 50)
|
||||
heal_amt += 0.5
|
||||
|
||||
//we only update wounds once in [wound_update_accuracy] ticks so have to emulate realtime
|
||||
heal_amt = heal_amt * wound_update_accuracy
|
||||
//configurable regen speed woo, no-regen hardcore or instaheal hugbox, choose your destiny
|
||||
heal_amt = heal_amt * config.organ_regeneration_multiplier
|
||||
// amount of healing is spread over all the wounds
|
||||
heal_amt = heal_amt / (wounds.len + 1)
|
||||
// making it look prettier on scanners
|
||||
heal_amt = round(heal_amt,0.1)
|
||||
W.heal_damage(heal_amt)
|
||||
|
||||
// Salving also helps against infection
|
||||
if(W.germ_level > 0 && W.salved && prob(2))
|
||||
W.disinfected = 1
|
||||
W.germ_level = 0
|
||||
|
||||
// sync the organ's damage with its wounds
|
||||
src.update_damages()
|
||||
if(update_icon())
|
||||
owner.UpdateDamageIcon(1)
|
||||
|
||||
//Updates brute_damn and burn_damn from wound damages. Updates BLEEDING status.
|
||||
/obj/item/organ/external/proc/update_damages()
|
||||
number_wounds = 0
|
||||
brute_dam = 0
|
||||
burn_dam = 0
|
||||
status &= ~ORGAN_BLEEDING
|
||||
var/clamped = 0
|
||||
/obj/item/organ/external/proc/check_fracture()
|
||||
if(config.bones_can_break && brute_dam > min_broken_damage && !(status & ORGAN_ROBOT))
|
||||
fracture()
|
||||
|
||||
var/mob/living/carbon/human/H
|
||||
if(istype(owner,/mob/living/carbon/human))
|
||||
H = owner
|
||||
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.damage_type == CUT || W.damage_type == BRUISE)
|
||||
brute_dam += W.damage
|
||||
else if(W.damage_type == BURN)
|
||||
burn_dam += W.damage
|
||||
|
||||
if(!(status & ORGAN_ROBOT) && W.bleeding())
|
||||
W.bleed_timer--
|
||||
if(H && (H.species.flags & NO_BLOOD)) // Bloodless organic races are finicky
|
||||
W.clamped = 1
|
||||
W.bleed_timer = 0
|
||||
else
|
||||
status |= ORGAN_BLEEDING
|
||||
|
||||
clamped |= W.clamped
|
||||
|
||||
number_wounds += W.amount
|
||||
|
||||
if(open && !clamped && (H && !(H.species.flags & NO_BLOOD)))
|
||||
status |= ORGAN_BLEEDING
|
||||
|
||||
//Bone fractures
|
||||
if(config.bones_can_break && brute_dam > min_broken_damage * config.organ_health_multiplier && !(status & ORGAN_ROBOT))
|
||||
src.fracture()
|
||||
/obj/item/organ/external/proc/check_for_internal_bleeding(damage)
|
||||
var/local_damage = brute_dam + damage
|
||||
if(damage > 15 && local_damage > 30 && prob(damage) && !(status & ORGAN_ROBOT))
|
||||
internal_bleeding = TRUE
|
||||
owner.custom_pain("You feel something rip in your [name]!", 1)
|
||||
|
||||
// new damage icon system
|
||||
// returns just the brute/burn damage code
|
||||
/obj/item/organ/external/proc/damage_state_text()
|
||||
if(status & ORGAN_DESTROYED)
|
||||
return "--"
|
||||
|
||||
var/tburn = 0
|
||||
var/tbrute = 0
|
||||
|
||||
@@ -709,10 +485,10 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
return
|
||||
|
||||
if(!disintegrate)
|
||||
disintegrate = DROPLIMB_EDGE
|
||||
disintegrate = DROPLIMB_SHARP
|
||||
|
||||
switch(disintegrate)
|
||||
if(DROPLIMB_EDGE)
|
||||
if(DROPLIMB_SHARP)
|
||||
if(!clean)
|
||||
var/gore_sound = "[(status & ORGAN_ROBOT) ? "tortured metal" : "ripping tendons and flesh"]"
|
||||
owner.visible_message(
|
||||
@@ -736,22 +512,16 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed().
|
||||
// Let people make limbs become fun things when removed
|
||||
var/atom/movable/dropped_part = remove(null, ignore_children)
|
||||
victim.traumatic_shock += 30
|
||||
|
||||
wounds.Cut()
|
||||
if(parent && !nodamage)
|
||||
var/datum/wound/lost_limb/W = new (src, disintegrate, clean)
|
||||
if(parent)
|
||||
parent.children -= src
|
||||
if(clean)
|
||||
parent.wounds |= W
|
||||
parent.update_damages()
|
||||
else
|
||||
var/obj/item/organ/external/stump/stump = new (victim, 0, src)
|
||||
if(status & ORGAN_ROBOT)
|
||||
stump.robotize()
|
||||
stump.wounds |= W
|
||||
victim.bodyparts |= stump
|
||||
stump.update_damages()
|
||||
if(!nodamage)
|
||||
var/total_brute = brute_dam
|
||||
var/total_burn = burn_dam
|
||||
for(var/obj/item/organ/external/E in children) //Factor in the children's brute and burn into how much will transfer
|
||||
total_brute += E.brute_dam
|
||||
total_burn += E.burn_dam
|
||||
parent.take_damage(total_brute, total_burn, ignore_resists = TRUE) //Transfer the full damage to the parent, bypass limb damage reduction.
|
||||
parent = null
|
||||
|
||||
spawn(1)
|
||||
@@ -761,9 +531,9 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
victim.regenerate_icons()
|
||||
dir = 2
|
||||
switch(disintegrate)
|
||||
if(DROPLIMB_EDGE)
|
||||
if(DROPLIMB_SHARP)
|
||||
compile_icon()
|
||||
add_blood(victim)
|
||||
add_blood(victim.blood_DNA, victim.species.blood_color)
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(rand(180))
|
||||
src.transform = M
|
||||
@@ -772,6 +542,8 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
if(src && istype(loc,/turf))
|
||||
dropped_part.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),30)
|
||||
dir = 2
|
||||
brute_dam = 0
|
||||
burn_dam = 0 //Reset the damage on the limb; the damage should have transferred to the parent; we don't want extra damage being re-applie when then limb is re-attached
|
||||
return dropped_part
|
||||
else
|
||||
qdel(src) // If you flashed away to ashes, YOU FLASHED AWAY TO ASHES
|
||||
@@ -780,9 +552,6 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
/****************************************************
|
||||
HELPERS
|
||||
****************************************************/
|
||||
/obj/item/organ/external/proc/is_stump()
|
||||
return 0
|
||||
|
||||
/obj/item/organ/external/proc/release_restraints(var/mob/living/carbon/human/holder)
|
||||
if(!holder)
|
||||
holder = owner
|
||||
@@ -799,41 +568,6 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
"\The [holder.legcuffed.name] falls off you.")
|
||||
holder.unEquip(holder.legcuffed)
|
||||
|
||||
|
||||
/obj/item/organ/external/proc/bandage()
|
||||
var/rval = 0
|
||||
src.status &= ~ORGAN_BLEEDING
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.internal) continue
|
||||
rval |= !W.bandaged
|
||||
W.bandaged = 1
|
||||
return rval
|
||||
|
||||
/obj/item/organ/external/proc/disinfect()
|
||||
var/rval = 0
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.internal) continue
|
||||
rval |= !W.disinfected
|
||||
W.disinfected = 1
|
||||
W.germ_level = 0
|
||||
return rval
|
||||
|
||||
/obj/item/organ/external/proc/clamp()
|
||||
var/rval = 0
|
||||
src.status &= ~ORGAN_BLEEDING
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.internal) continue
|
||||
rval |= !W.clamped
|
||||
W.clamped = 1
|
||||
return rval
|
||||
|
||||
/obj/item/organ/external/proc/salve()
|
||||
var/rval = 0
|
||||
for(var/datum/wound/W in wounds)
|
||||
rval |= !W.salved
|
||||
W.salved = 1
|
||||
return rval
|
||||
|
||||
/obj/item/organ/external/proc/fracture()
|
||||
if(status & ORGAN_ROBOT)
|
||||
return //ORGAN_BROKEN doesn't have the same meaning for robot limbs
|
||||
@@ -845,7 +579,7 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
"<span class='warning'>You hear a loud cracking sound coming from \the [owner].</span>",\
|
||||
"<span class='danger'>Something feels like it shattered in your [name]!</span>",\
|
||||
"You hear a sickening crack.")
|
||||
if(owner.species && !(owner.species.flags & NO_PAIN))
|
||||
if(owner.species && !(NO_PAIN in owner.species.species_traits))
|
||||
owner.emote("scream")
|
||||
|
||||
status |= ORGAN_BROKEN
|
||||
@@ -859,25 +593,24 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
/obj/item/organ/external/proc/mend_fracture()
|
||||
if(status & ORGAN_ROBOT)
|
||||
return 0 //ORGAN_BROKEN doesn't have the same meaning for robot limbs
|
||||
if(brute_dam > min_broken_damage * config.organ_health_multiplier)
|
||||
if(brute_dam > min_broken_damage)
|
||||
return 0 //will just immediately fracture again
|
||||
|
||||
status &= ~ORGAN_BROKEN
|
||||
return 1
|
||||
|
||||
// I put these two next to each other to highlight that both exist. This should likely be resolved.
|
||||
/obj/item/organ/external/robotize()
|
||||
/obj/item/organ/external/robotize(company, make_tough = 0, convert_all = 1)
|
||||
..()
|
||||
//robot limbs take reduced damage
|
||||
brute_mod = 0.66
|
||||
burn_mod = 0.66
|
||||
if(!make_tough)
|
||||
brute_mod = 0.66
|
||||
burn_mod = 0.66
|
||||
dismember_at_max_damage = TRUE
|
||||
else
|
||||
tough = TRUE
|
||||
// Robot parts also lack bones
|
||||
// This is so surgery isn't kaput, let's see how this does
|
||||
encased = null
|
||||
fail_at_full_damage = 1
|
||||
|
||||
/obj/item/organ/external/robotize(var/company)
|
||||
..()
|
||||
|
||||
if(company && istext(company))
|
||||
set_company(company)
|
||||
@@ -885,8 +618,8 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
cannot_break = 1
|
||||
get_icon()
|
||||
for(var/obj/item/organ/external/T in children)
|
||||
if(T)
|
||||
T.robotize()
|
||||
if((convert_all) || (T.type in convertable_children))
|
||||
T.robotize(company, make_tough, convert_all)
|
||||
|
||||
|
||||
|
||||
@@ -912,35 +645,17 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
return max(brute_dam + burn_dam - perma_injury, perma_injury) //could use health?
|
||||
|
||||
/obj/item/organ/external/proc/has_infected_wound()
|
||||
for(var/datum/wound/W in wounds)
|
||||
if(W.germ_level > INFECTION_LEVEL_ONE)
|
||||
return 1
|
||||
return 0
|
||||
if(germ_level > INFECTION_LEVEL_ONE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/organ/external/proc/is_usable()
|
||||
if((status & ORGAN_ROBOT) && get_damage() >= max_damage) //robot limbs just become inoperable at max damage
|
||||
if(((status & ORGAN_ROBOT) && get_damage() >= max_damage) && !tough) //robot limbs just become inoperable at max damage
|
||||
return
|
||||
return !(status & (ORGAN_DESTROYED|ORGAN_MUTATED|ORGAN_DEAD))
|
||||
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))
|
||||
|
||||
/obj/item/organ/external/proc/embed(var/obj/item/weapon/W, var/silent = 0)
|
||||
if(!owner || loc != owner)
|
||||
return
|
||||
if(!silent)
|
||||
owner.visible_message("<span class='danger'>\The [W] sticks in the wound!</span>")
|
||||
implants += W
|
||||
owner.embedded_flag = 1
|
||||
owner.verbs += /mob/proc/yank_out_object
|
||||
W.add_blood(owner)
|
||||
if(ismob(W.loc))
|
||||
var/mob/living/H = W.loc
|
||||
H.drop_item()
|
||||
W.loc = owner
|
||||
|
||||
/obj/item/organ/external/proc/open_enough_for_surgery()
|
||||
return (encased ? (open == 3) : (open == 2))
|
||||
return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam) && !tough)
|
||||
|
||||
/obj/item/organ/external/remove(var/mob/living/user, var/ignore_children)
|
||||
|
||||
@@ -949,15 +664,18 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
var/is_robotic = status & ORGAN_ROBOT
|
||||
var/mob/living/carbon/human/victim = owner
|
||||
|
||||
. = ..()
|
||||
|
||||
status |= ORGAN_DESTROYED
|
||||
victim.bad_external_organs -= src
|
||||
if(status & ORGAN_SPLINTED)
|
||||
victim.splinted_limbs -= src
|
||||
|
||||
for(var/implant in implants) //todo: check if this can be left alone
|
||||
qdel(implant)
|
||||
for(var/obj/item/I in embedded_objects)
|
||||
embedded_objects -= I
|
||||
I.forceMove(src)
|
||||
if(!owner.has_embedded_objects())
|
||||
owner.clear_alert("embeddedobject")
|
||||
|
||||
. = ..()
|
||||
|
||||
// Attached organs also fly off.
|
||||
if(!ignore_children)
|
||||
@@ -1012,17 +730,18 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
return 0
|
||||
return src == O.bodyparts_by_name[limb_name]
|
||||
|
||||
// The callback we use to remove wounds from an un-processed limb
|
||||
/obj/item/organ/external/proc/cleanup_wounds(var/list/slated_wounds)
|
||||
wound_cleanup_timer = null
|
||||
for(var/datum/wound/W in slated_wounds)
|
||||
if(!W)
|
||||
continue
|
||||
if(W.damage > 0)
|
||||
continue
|
||||
wounds -= W
|
||||
qdel(W)
|
||||
/obj/item/organ/external/proc/infection_check()
|
||||
var/total_damage = brute_dam + burn_dam
|
||||
if(total_damage)
|
||||
if(total_damage < 10) //small amounts of damage aren't infectable
|
||||
return FALSE
|
||||
|
||||
if(owner && owner.bleedsuppress && total_damage < 25)
|
||||
return FALSE
|
||||
|
||||
var/dam_coef = round(total_damage / 10)
|
||||
return prob(dam_coef * 10)
|
||||
return FALSE
|
||||
|
||||
/obj/item/organ/external/serialize()
|
||||
var/list/data = ..()
|
||||
@@ -1038,3 +757,22 @@ Note that amputating the affected organ does in fact remove the infection from t
|
||||
..() // Parent call loads in the DNA
|
||||
if(data["dna"])
|
||||
sync_colour_to_dna()
|
||||
|
||||
//Remove all embedded objects from all limbs on the carbon mob
|
||||
/mob/living/carbon/human/proc/remove_all_embedded_objects()
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/organ/external/L = X
|
||||
for(var/obj/item/I in L.embedded_objects)
|
||||
L.embedded_objects -= I
|
||||
I.forceMove(T)
|
||||
|
||||
clear_alert("embeddedobject")
|
||||
|
||||
/mob/living/carbon/human/proc/has_embedded_objects()
|
||||
. = 0
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/organ/external/L = X
|
||||
for(var/obj/item/I in L.embedded_objects)
|
||||
return 1
|
||||
@@ -49,7 +49,7 @@ var/global/list/limb_icon_cache = list()
|
||||
if(!isnull(dna.GetUIValue(DNA_UI_SKIN_TONE)) && ((species.bodyflags & HAS_SKIN_TONE) || (species.bodyflags & HAS_ICON_SKIN_TONE)))
|
||||
s_col = null
|
||||
s_tone = dna.GetUIValue(DNA_UI_SKIN_TONE)
|
||||
if(species.flags & HAS_SKIN_COLOR)
|
||||
if(species.bodyflags & HAS_SKIN_COLOR)
|
||||
s_tone = null
|
||||
s_col = list(dna.GetUIValue(DNA_UI_SKIN_R), dna.GetUIValue(DNA_UI_SKIN_G), dna.GetUIValue(DNA_UI_SKIN_B))
|
||||
|
||||
@@ -58,7 +58,7 @@ var/global/list/limb_icon_cache = list()
|
||||
var/obj/item/organ/internal/eyes/eyes = owner.get_int_organ(/obj/item/organ/internal/eyes)//owner.internal_bodyparts_by_name["eyes"]
|
||||
if(eyes) eyes.update_colour()
|
||||
|
||||
/obj/item/organ/external/head/remove()
|
||||
/obj/item/organ/external/head/remove(mob/living/user, ignore_children)
|
||||
get_icon()
|
||||
. = ..()
|
||||
|
||||
@@ -115,7 +115,7 @@ var/global/list/limb_icon_cache = list()
|
||||
mob_icon.Blend(eyes_icon, ICON_OVERLAY)
|
||||
overlays |= eyes_icon
|
||||
|
||||
if(owner.lip_style && (species && (species.flags & HAS_LIPS)))
|
||||
if(owner.lip_style && (LIPS in species.species_traits))
|
||||
var/icon/lip_icon = new/icon('icons/mob/human_face.dmi', "lips_[owner.lip_style]_s")
|
||||
overlays |= lip_icon
|
||||
mob_icon.Blend(lip_icon, ICON_OVERLAY)
|
||||
@@ -139,7 +139,7 @@ var/global/list/limb_icon_cache = list()
|
||||
|
||||
if(f_style)
|
||||
var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style]
|
||||
if(facial_hair_style && ((facial_hair_style.species_allowed && (species.name in facial_hair_style.species_allowed)) || (src.species.flags & ALL_RPARTS)))
|
||||
if(facial_hair_style && ((facial_hair_style.species_allowed && (species.name in facial_hair_style.species_allowed)) || (src.species.bodyflags & ALL_RPARTS)))
|
||||
var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
|
||||
if(species.name == "Slime People") // I am el worstos
|
||||
facial_s.Blend(rgb(owner.r_skin, owner.g_skin, owner.b_skin, 160), ICON_AND)
|
||||
@@ -149,7 +149,7 @@ var/global/list/limb_icon_cache = list()
|
||||
|
||||
if(h_style && !(owner.head && (owner.head.flags & BLOCKHEADHAIR)))
|
||||
var/datum/sprite_accessory/hair_style = hair_styles_list[h_style]
|
||||
if(hair_style && ((species.name in hair_style.species_allowed) || (src.species.flags & ALL_RPARTS)))
|
||||
if(hair_style && ((species.name in hair_style.species_allowed) || (src.species.bodyflags & ALL_RPARTS)))
|
||||
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
|
||||
if(species.name == "Slime People") // I am el worstos
|
||||
hair_s.Blend(rgb(owner.r_skin, owner.g_skin, owner.b_skin, 160), ICON_AND)
|
||||
@@ -172,7 +172,7 @@ var/global/list/limb_icon_cache = list()
|
||||
gender = "f"
|
||||
else
|
||||
gender = "m"
|
||||
if(limb_name == "head" && !is_stump() && !(status & ORGAN_DESTROYED))
|
||||
if(limb_name == "head")
|
||||
var/obj/item/organ/external/head/head_organ = src
|
||||
head_organ.handle_alt_icon()
|
||||
|
||||
@@ -192,7 +192,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) && (species.flags & CAN_BE_FAT))
|
||||
if(fat && !skeletal && !(status & ORGAN_ROBOT) && (CAN_BE_FAT in species.species_traits))
|
||||
result[2] += "_fat"
|
||||
return result
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
force = 1
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throwforce = 0
|
||||
var/zone = "chest"
|
||||
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
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
owner = M
|
||||
|
||||
M.internal_organs |= src
|
||||
M.internal_organs_slot[slot] = src
|
||||
var/obj/item/organ/external/parent
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
@@ -52,6 +53,8 @@
|
||||
owner = null
|
||||
if(M)
|
||||
M.internal_organs -= src
|
||||
if(M.internal_organs_slot[slot] == src)
|
||||
M.internal_organs_slot.Remove(slot)
|
||||
if(vital && !special)
|
||||
if(M.stat != DEAD)//safety check!
|
||||
M.death()
|
||||
@@ -208,7 +211,7 @@
|
||||
|
||||
/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(H.species.flags & NO_BLOOD || H.species.exotic_blood)
|
||||
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)
|
||||
@@ -221,10 +224,11 @@
|
||||
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
|
||||
H.vessel.remove_reagent("blood", blood_loss)
|
||||
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
|
||||
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*
|
||||
|
||||
@@ -253,13 +257,14 @@
|
||||
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(istype(H))
|
||||
H.vessel.add_reagent("blood", (cursed_heart.blood_loss*0.5))//gain half the blood back from a failure
|
||||
if(owner.client)
|
||||
owner.client.color = ""
|
||||
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)
|
||||
H.adjustBruteLoss(-cursed_heart.heal_brute)
|
||||
H.adjustFireLoss(-cursed_heart.heal_burn)
|
||||
H.adjustOxyLoss(-cursed_heart.heal_oxy)
|
||||
|
||||
/obj/item/organ/internal/lungs
|
||||
name = "lungs"
|
||||
@@ -286,7 +291,7 @@
|
||||
if(is_bruised())
|
||||
if(prob(2))
|
||||
owner.custom_emote(1, "coughs up blood!")
|
||||
owner.drip(10)
|
||||
owner.bleed(1)
|
||||
if(prob(4))
|
||||
owner.custom_emote(1, "gasps for air!")
|
||||
owner.AdjustLoseBreath(5)
|
||||
@@ -426,20 +431,17 @@
|
||||
//High toxins levels are dangerous
|
||||
if(owner.getToxLoss() >= 60 && !owner.reagents.has_reagent("charcoal"))
|
||||
//Healthy liver suffers on its own
|
||||
if(src.damage < min_broken_damage)
|
||||
src.damage += 0.2 * PROCESS_ACCURACY
|
||||
if(damage < min_broken_damage)
|
||||
take_damage(0.2 * PROCESS_ACCURACY)
|
||||
//Damaged one shares the fun
|
||||
else
|
||||
var/obj/item/organ/internal/O = pick(owner.internal_organs)
|
||||
if(O)
|
||||
O.damage += 0.2 * PROCESS_ACCURACY
|
||||
O.take_damage(0.2 * PROCESS_ACCURACY)
|
||||
|
||||
//Detox can heal small amounts of damage
|
||||
if(src.damage && src.damage < src.min_bruised_damage && owner.reagents.has_reagent("charcoal"))
|
||||
src.damage -= 0.2 * PROCESS_ACCURACY
|
||||
|
||||
if(src.damage < 0)
|
||||
src.damage = 0
|
||||
if(damage && damage < min_bruised_damage && owner.reagents.has_reagent("charcoal"))
|
||||
take_damage(-0.2 * PROCESS_ACCURACY)
|
||||
|
||||
// Get the effectiveness of the liver.
|
||||
var/filter_effect = 3
|
||||
@@ -449,7 +451,7 @@
|
||||
filter_effect -= 2
|
||||
|
||||
// Damaged liver means some chemicals are very dangerous
|
||||
if(src.damage >= src.min_bruised_damage)
|
||||
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))
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/obj/item/organ/external/stump
|
||||
name = "limb stump"
|
||||
icon_name = ""
|
||||
var/can_intake_reagents = 0
|
||||
|
||||
/obj/item/organ/external/stump/New(var/mob/living/carbon/holder, var/internal, var/obj/item/organ/external/limb)
|
||||
if(istype(limb))
|
||||
limb_name = limb.limb_name
|
||||
body_part = limb.body_part
|
||||
amputation_point = limb.amputation_point
|
||||
parent_organ = limb.parent_organ
|
||||
wounds = limb.wounds
|
||||
..(holder, internal)
|
||||
if(istype(limb))
|
||||
max_damage = limb.max_damage
|
||||
if((limb.status & ORGAN_ROBOT) && (!parent || (parent.status & ORGAN_ROBOT)))
|
||||
robotize() //if both limb and the parent are robotic, the stump is robotic too
|
||||
|
||||
/obj/item/organ/external/stump/is_stump()
|
||||
return 1
|
||||
|
||||
/obj/item/organ/external/stump/remove()
|
||||
..()
|
||||
qdel(src)
|
||||
return null
|
||||
|
||||
/obj/item/organ/external/stump/is_usable()
|
||||
return 0
|
||||
@@ -47,7 +47,8 @@ mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0
|
||||
mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength)
|
||||
if(stat >= 1) return
|
||||
|
||||
if(species && species.flags & NO_PAIN) return
|
||||
if(NO_PAIN in species.species_traits)
|
||||
return
|
||||
|
||||
if(reagents.has_reagent("morphine"))
|
||||
return
|
||||
@@ -66,7 +67,7 @@ mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength)
|
||||
mob/living/carbon/human/proc/handle_pain()
|
||||
// not when sleeping
|
||||
|
||||
if(species && species.flags & NO_PAIN)
|
||||
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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var/global/list/all_robolimbs = list()
|
||||
var/global/list/chargen_robolimbs = list()
|
||||
var/global/list/selectable_robolimbs = list()
|
||||
var/global/datum/robolimb/basic_robolimb
|
||||
|
||||
/proc/populate_robolimb_list()
|
||||
@@ -11,12 +12,15 @@ var/global/datum/robolimb/basic_robolimb
|
||||
if(R != "head" && R != "chest" && R != "groin" ) //Part of the method that ensures only IPCs can access head, chest and groin prosthetics.
|
||||
if(R.has_subtypes) //Ensures solos get added to the list as well be incorporating has_subtypes == 1 and has_subtypes == 2.
|
||||
chargen_robolimbs[R.company] = R //List only main brands and solo parts.
|
||||
if(R.selectable)
|
||||
selectable_robolimbs[R.company] = R
|
||||
|
||||
/datum/robolimb
|
||||
var/company = "Unbranded" // Shown when selecting the limb.
|
||||
var/desc = "A generic unbranded robotic prosthesis." // Seen when examining a limb.
|
||||
var/icon = 'icons/mob/human_races/robotic.dmi' // Icon base to draw from.
|
||||
var/unavailable_at_chargen // If set, not available at chargen.
|
||||
var/selectable = 1 // If set, is it available for selection on attack_self with a robo limb?
|
||||
var/is_monitor // If set, limb is a monitor and should be getting monitor styles.
|
||||
var/has_subtypes = 2 // If null, object is a model. If 1, object is a brand (that serves as the default model) with child models. If 2, object is a brand that has no child models and thus also serves as the model..
|
||||
var/parts = list("chest", "groin", "head", "r_arm", "r_hand", "r_leg", "r_foot", "l_leg", "l_foot", "l_arm", "l_hand") // Defines what parts said brand can replace on a body.
|
||||
@@ -31,6 +35,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
company = "Bishop Cybernetics alt."
|
||||
icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_alt1.dmi'
|
||||
parts = list("head")
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/bishop/monitor
|
||||
@@ -38,6 +43,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_monitor.dmi'
|
||||
parts = list("head")
|
||||
is_monitor = 1
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/hesphiastos
|
||||
@@ -51,6 +57,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
icon = 'icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_alt1.dmi'
|
||||
parts = list("head")
|
||||
is_monitor = 1
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/hesphiastos/monitor
|
||||
@@ -58,6 +65,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
icon = 'icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_monitor.dmi'
|
||||
parts = list("head")
|
||||
is_monitor = 1
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/morpheus
|
||||
@@ -74,6 +82,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
parts = list("head")
|
||||
unavailable_at_chargen = null
|
||||
is_monitor = null
|
||||
selectable = 0
|
||||
has_subtypes = 2 //Edge case. We want to be able to pick this one, and if we had it left as null for has_subtypes we'd be assuming it'll be chosen as a child model,
|
||||
//and since the parent is unavailable at chargen, we wouldn't be able to see it in the list anyway. Now, we'll be able to select the Morpheus Ckt. Alt. head as a solo-model.
|
||||
|
||||
@@ -87,6 +96,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
company = "Ward-Takahashi alt."
|
||||
icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt1.dmi'
|
||||
parts = list("head")
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/wardtakahashi/monitor
|
||||
@@ -94,6 +104,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_monitor.dmi'
|
||||
parts = list("head")
|
||||
is_monitor = 1
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/xion
|
||||
@@ -106,6 +117,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
company = "Xion Manufacturing Group alt."
|
||||
icon = 'icons/mob/human_races/cyberlimbs/xion/xion_alt1.dmi'
|
||||
parts = list("head")
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/xion/monitor
|
||||
@@ -113,6 +125,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
icon = 'icons/mob/human_races/cyberlimbs/xion/xion_monitor.dmi'
|
||||
parts = list("head")
|
||||
is_monitor = 1
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/zenghu
|
||||
@@ -131,6 +144,7 @@ var/global/datum/robolimb/basic_robolimb
|
||||
company = "Shellguard Munitions Elite Series"
|
||||
icon = 'icons/mob/human_races/cyberlimbs/shellguard/shellguard_alt1.dmi'
|
||||
parts = list("head")
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
|
||||
/datum/robolimb/shellguard/monitor
|
||||
@@ -138,4 +152,5 @@ var/global/datum/robolimb/basic_robolimb
|
||||
icon = 'icons/mob/human_races/cyberlimbs/shellguard/shellguard_monitor.dmi'
|
||||
parts = list("head")
|
||||
is_monitor = 1
|
||||
selectable = 0
|
||||
has_subtypes = null
|
||||
@@ -40,7 +40,7 @@
|
||||
/obj/item/organ/internal/headpocket/on_owner_death()
|
||||
empty_contents()
|
||||
|
||||
/obj/item/organ/internal/headpocket/remove()
|
||||
/obj/item/organ/internal/headpocket/remove(mob/living/carbon/M, special = 0)
|
||||
empty_contents()
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
parent_organ = null
|
||||
encased = "ribcage"
|
||||
var/fat = FALSE
|
||||
convertable_children = list(/obj/item/organ/external/groin)
|
||||
|
||||
/obj/item/organ/external/chest/proc/makeFat(update_body_icon = 1)
|
||||
fat = TRUE
|
||||
@@ -45,6 +46,7 @@
|
||||
w_class = WEIGHT_CLASS_BULKY // if you know what I mean ;)
|
||||
body_part = LOWER_TORSO
|
||||
vital = 1
|
||||
cannot_amputate = TRUE
|
||||
parent_organ = "chest"
|
||||
amputation_point = "lumbar"
|
||||
gendered_icon = 1
|
||||
@@ -60,6 +62,7 @@
|
||||
parent_organ = "chest"
|
||||
amputation_point = "left shoulder"
|
||||
can_grasp = 1
|
||||
convertable_children = list(/obj/item/organ/external/hand)
|
||||
|
||||
/obj/item/organ/external/arm/right
|
||||
limb_name = "r_arm"
|
||||
@@ -67,6 +70,7 @@
|
||||
icon_name = "r_arm"
|
||||
body_part = ARM_RIGHT
|
||||
amputation_point = "right shoulder"
|
||||
convertable_children = list(/obj/item/organ/external/hand/right)
|
||||
|
||||
/obj/item/organ/external/leg
|
||||
limb_name = "l_leg"
|
||||
@@ -80,6 +84,7 @@
|
||||
parent_organ = "groin"
|
||||
amputation_point = "left hip"
|
||||
can_stand = 1
|
||||
convertable_children = list(/obj/item/organ/external/foot)
|
||||
|
||||
/obj/item/organ/external/leg/right
|
||||
limb_name = "r_leg"
|
||||
@@ -88,6 +93,7 @@
|
||||
body_part = LEG_RIGHT
|
||||
icon_position = RIGHT
|
||||
amputation_point = "right hip"
|
||||
convertable_children = list(/obj/item/organ/external/foot/right)
|
||||
|
||||
/obj/item/organ/external/foot
|
||||
limb_name = "l_foot"
|
||||
@@ -214,8 +220,8 @@
|
||||
|
||||
..()
|
||||
|
||||
/obj/item/organ/external/head/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list())
|
||||
..(brute, burn, sharp, edge, used_weapon, forbidden_limbs)
|
||||
/obj/item/organ/external/head/take_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))
|
||||
|
||||
@@ -2,28 +2,18 @@
|
||||
origin_tech = "biotech=5"
|
||||
icon_state = "xgibmid2"
|
||||
var/list/alien_powers = list()
|
||||
tough = 1
|
||||
sterile = 1
|
||||
|
||||
///obj/item/organ/internal/xenos/New()
|
||||
// for(var/A in alien_powers)
|
||||
// if(ispath(A))
|
||||
// alien_powers -= A
|
||||
// alien_powers += new A(src)
|
||||
// ..()
|
||||
tough = TRUE
|
||||
sterile = TRUE
|
||||
|
||||
///can be changed if xenos get an update..
|
||||
/obj/item/organ/internal/xenos/insert(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
for(var/P in alien_powers)
|
||||
M.verbs |= P
|
||||
//M.verbs |= alien_powers.Copy()
|
||||
|
||||
/obj/item/organ/internal/xenos/remove(mob/living/carbon/M, special = 0)
|
||||
for(var/P in alien_powers)
|
||||
M.verbs -= P
|
||||
//M.verbs -= alien_powers.Copy()
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/xenos/prepare_eat()
|
||||
|
||||
@@ -38,7 +38,6 @@ var/static/regex/multispin_words = regex("like a record baby")
|
||||
/obj/item/organ/internal/vocal_cords //organs that are activated through speech with the :x channel
|
||||
name = "vocal cords"
|
||||
icon_state = "appendix"
|
||||
zone = "mouth"
|
||||
slot = "vocal_cords"
|
||||
parent_organ = "mouth"
|
||||
var/spans = null
|
||||
@@ -245,7 +244,7 @@ var/static/regex/multispin_words = regex("like a record baby")
|
||||
//BLEED
|
||||
else if((findtext(message, bleed_words)))
|
||||
for(var/mob/living/carbon/human/H in listeners)
|
||||
H.drip(100 * power_multiplier)
|
||||
H.bleed_rate += (5 * power_multiplier)
|
||||
next_command = world.time + cooldown_damage
|
||||
|
||||
//FIRE
|
||||
@@ -436,7 +435,7 @@ var/static/regex/multispin_words = regex("like a record baby")
|
||||
playsound(get_turf(owner), 'sound/items/bikehorn.ogg', 300, 1)
|
||||
if(owner.mind && owner.mind.assigned_role == "Clown")
|
||||
for(var/mob/living/carbon/C in listeners)
|
||||
C.slip(0,7 * power_multiplier)
|
||||
C.slip("your feet", 0, 7 * power_multiplier)
|
||||
next_command = world.time + cooldown_stun
|
||||
else
|
||||
next_command = world.time + cooldown_meme
|
||||
|
||||
@@ -1,344 +0,0 @@
|
||||
|
||||
/****************************************************
|
||||
WOUNDS
|
||||
****************************************************/
|
||||
/datum/wound
|
||||
// number representing the current stage
|
||||
var/current_stage = 0
|
||||
|
||||
// description of the wound
|
||||
var/desc = "wound" //default in case something borks
|
||||
|
||||
// amount of damage this wound causes
|
||||
var/damage = 0
|
||||
// ticks of bleeding left.
|
||||
var/bleed_timer = 0
|
||||
// amount of damage the current wound type requires(less means we need to apply the next healing stage)
|
||||
var/min_damage = 0
|
||||
|
||||
// is the wound bandaged?
|
||||
var/bandaged = 0
|
||||
// Similar to bandaged, but works differently
|
||||
var/clamped = 0
|
||||
// is the wound salved?
|
||||
var/salved = 0
|
||||
// is the wound disinfected?
|
||||
var/disinfected = 0
|
||||
var/created = 0
|
||||
// number of wounds of this type
|
||||
var/amount = 1
|
||||
// amount of germs in the wound
|
||||
var/germ_level = 0
|
||||
|
||||
/* These are defined by the wound type and should not be changed */
|
||||
|
||||
// stages such as "cut", "deep cut", etc.
|
||||
var/list/stages
|
||||
// internal wounds can only be fixed through surgery
|
||||
var/internal = 0
|
||||
// maximum stage at which bleeding should still happen. Beyond this stage bleeding is prevented.
|
||||
var/max_bleeding_stage = 0
|
||||
// one of CUT, BRUISE, BURN
|
||||
var/damage_type = CUT
|
||||
// whether this wound needs a bandage/salve to heal at all
|
||||
// the maximum amount of damage that this wound can have and still autoheal
|
||||
var/autoheal_cutoff = 15
|
||||
|
||||
|
||||
|
||||
|
||||
// helper lists
|
||||
var/tmp/list/desc_list = list()
|
||||
var/tmp/list/damage_list = list()
|
||||
|
||||
New(var/damage)
|
||||
|
||||
created = world.time
|
||||
|
||||
// reading from a list("stage" = damage) is pretty difficult, so build two separate
|
||||
// lists from them instead
|
||||
for(var/V in stages)
|
||||
desc_list += V
|
||||
damage_list += stages[V]
|
||||
|
||||
src.damage = damage
|
||||
|
||||
// initialize with the appropriate stage
|
||||
src.init_stage(damage)
|
||||
|
||||
bleed_timer += damage
|
||||
|
||||
// returns 1 if there's a next stage, 0 otherwise
|
||||
proc/init_stage(var/initial_damage)
|
||||
current_stage = stages.len
|
||||
|
||||
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= initial_damage / src.amount)
|
||||
src.current_stage--
|
||||
|
||||
src.min_damage = damage_list[current_stage]
|
||||
src.desc = desc_list[current_stage]
|
||||
|
||||
// the amount of damage per wound
|
||||
proc/wound_damage()
|
||||
return src.damage / src.amount
|
||||
|
||||
proc/can_autoheal()
|
||||
if(src.wound_damage() <= autoheal_cutoff)
|
||||
return 1
|
||||
|
||||
return is_treated()
|
||||
|
||||
// checks whether the wound has been appropriately treated
|
||||
proc/is_treated()
|
||||
if(damage_type == BRUISE || damage_type == CUT)
|
||||
return bandaged
|
||||
else if(damage_type == BURN)
|
||||
return salved
|
||||
|
||||
// Checks whether other other can be merged into src.
|
||||
proc/can_merge(var/datum/wound/other)
|
||||
if(other.type != src.type) return 0
|
||||
if(other.current_stage != src.current_stage) return 0
|
||||
if(other.damage_type != src.damage_type) return 0
|
||||
if(!(other.can_autoheal()) != !(src.can_autoheal())) return 0
|
||||
if(!(other.bandaged) != !(src.bandaged)) return 0
|
||||
if(!(other.clamped) != !(src.clamped)) return 0
|
||||
if(!(other.salved) != !(src.salved)) return 0
|
||||
if(!(other.disinfected) != !(src.disinfected)) return 0
|
||||
//if(other.germ_level != src.germ_level) return 0
|
||||
return 1
|
||||
|
||||
proc/merge_wound(var/datum/wound/other)
|
||||
src.damage += other.damage
|
||||
src.amount += other.amount
|
||||
src.bleed_timer += other.bleed_timer
|
||||
src.germ_level = max(src.germ_level, other.germ_level)
|
||||
src.created = max(src.created, other.created) //take the newer created time
|
||||
|
||||
// checks if wound is considered open for external infections
|
||||
// untreated cuts (and bleeding bruises) and burns are possibly infectable, chance higher if wound is bigger
|
||||
proc/infection_check()
|
||||
if(damage < 10) //small cuts, tiny bruises, and moderate burns shouldn't be infectable.
|
||||
return 0
|
||||
if(is_treated() && damage < 25) //anything less than a flesh wound (or equivalent) isn't infectable if treated properly
|
||||
return 0
|
||||
if(disinfected)
|
||||
germ_level = 0 //reset this, just in case
|
||||
return 0
|
||||
|
||||
if(damage_type == BRUISE && !bleeding()) //bruises only infectable if bleeding
|
||||
return 0
|
||||
|
||||
var/dam_coef = round(damage/10)
|
||||
switch(damage_type)
|
||||
if(BRUISE)
|
||||
return prob(dam_coef*5)
|
||||
if(BURN)
|
||||
return prob(dam_coef*10)
|
||||
if(CUT)
|
||||
return prob(dam_coef*20)
|
||||
|
||||
return 0
|
||||
|
||||
// heal the given amount of damage, and if the given amount of damage was more
|
||||
// than what needed to be healed, return how much heal was left
|
||||
// set @heals_internal to also heal internal organ damage
|
||||
proc/heal_damage(amount, heals_internal = 0)
|
||||
if(src.internal && !heals_internal)
|
||||
// heal nothing
|
||||
return amount
|
||||
|
||||
var/healed_damage = min(src.damage, amount)
|
||||
amount -= healed_damage
|
||||
src.damage -= healed_damage
|
||||
|
||||
while(src.wound_damage() < damage_list[current_stage] && current_stage < src.desc_list.len)
|
||||
current_stage++
|
||||
desc = desc_list[current_stage]
|
||||
src.min_damage = damage_list[current_stage]
|
||||
|
||||
// return amount of healing still leftover, can be used for other wounds
|
||||
return amount
|
||||
|
||||
// opens the wound again
|
||||
proc/open_wound(damage)
|
||||
src.damage += damage
|
||||
bleed_timer += damage
|
||||
|
||||
while(src.current_stage > 1 && src.damage_list[current_stage-1] <= src.damage / src.amount)
|
||||
src.current_stage--
|
||||
|
||||
src.desc = desc_list[current_stage]
|
||||
src.min_damage = damage_list[current_stage]
|
||||
|
||||
// returns whether this wound can absorb the given amount of damage.
|
||||
// this will prevent large amounts of damage being trapped in less severe wound types
|
||||
proc/can_worsen(damage_type, damage)
|
||||
if(src.damage_type != damage_type)
|
||||
return 0 //incompatible damage types
|
||||
|
||||
if(src.amount > 1)
|
||||
return 0
|
||||
|
||||
//with 1.5*, a shallow cut will be able to carry at most 30 damage,
|
||||
//37.5 for a deep cut
|
||||
//52.5 for a flesh wound, etc.
|
||||
var/max_wound_damage = 1.5*src.damage_list[1]
|
||||
if(src.damage + damage > max_wound_damage)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
proc/bleeding()
|
||||
if(src.internal)
|
||||
return 0 // internal wounds don't bleed in the sense of this function
|
||||
|
||||
if(current_stage > max_bleeding_stage)
|
||||
return 0
|
||||
|
||||
if(bandaged||clamped)
|
||||
return 0
|
||||
|
||||
if(wound_damage() <= 30 && bleed_timer <= 0)
|
||||
return 0 //Bleed timer has run out. Wounds with more than 30 damage don't stop bleeding on their own.
|
||||
|
||||
return (damage_type == BRUISE && wound_damage() >= 20 || damage_type == CUT && wound_damage() >= 5)
|
||||
|
||||
/** WOUND DEFINITIONS **/
|
||||
|
||||
//Note that the MINIMUM damage before a wound can be applied should correspond to
|
||||
//the damage amount for the stage with the same name as the wound.
|
||||
//e.g. /datum/wound/cut/deep should only be applied for 15 damage and up,
|
||||
//because in it's stages list, "deep cut" = 15.
|
||||
/proc/get_wound_type(var/type = CUT, var/damage)
|
||||
switch(type)
|
||||
if(CUT)
|
||||
switch(damage)
|
||||
if(70 to INFINITY)
|
||||
return /datum/wound/cut/massive
|
||||
if(60 to 70)
|
||||
return /datum/wound/cut/gaping_big
|
||||
if(50 to 60)
|
||||
return /datum/wound/cut/gaping
|
||||
if(25 to 50)
|
||||
return /datum/wound/cut/flesh
|
||||
if(15 to 25)
|
||||
return /datum/wound/cut/deep
|
||||
if(0 to 15)
|
||||
return /datum/wound/cut/small
|
||||
if(BRUISE)
|
||||
return /datum/wound/bruise
|
||||
if(BURN)
|
||||
switch(damage)
|
||||
if(50 to INFINITY)
|
||||
return /datum/wound/burn/carbonised
|
||||
if(40 to 50)
|
||||
return /datum/wound/burn/deep
|
||||
if(30 to 40)
|
||||
return /datum/wound/burn/severe
|
||||
if(15 to 30)
|
||||
return /datum/wound/burn/large
|
||||
if(0 to 15)
|
||||
return /datum/wound/burn/moderate
|
||||
return null //no wound
|
||||
|
||||
/** CUTS **/
|
||||
/datum/wound/cut/small
|
||||
// Minor cuts have max_bleeding_stage set to the stage that bears the wound type's name.
|
||||
// The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor).
|
||||
max_bleeding_stage = 3
|
||||
stages = list("ugly ripped cut" = 20, "ripped cut" = 10, "cut" = 5, "healing cut" = 2, "small scab" = 0)
|
||||
damage_type = CUT
|
||||
|
||||
/datum/wound/cut/deep
|
||||
max_bleeding_stage = 3
|
||||
stages = list("ugly deep ripped cut" = 25, "deep ripped cut" = 20, "deep cut" = 15, "clotted cut" = 8, "scab" = 2, "fresh skin" = 0)
|
||||
damage_type = CUT
|
||||
|
||||
/datum/wound/cut/flesh
|
||||
max_bleeding_stage = 4
|
||||
stages = list("ugly ripped flesh wound" = 35, "ugly flesh wound" = 30, "flesh wound" = 25, "blood soaked clot" = 15, "large scab" = 5, "fresh skin" = 0)
|
||||
damage_type = CUT
|
||||
|
||||
/datum/wound/cut/gaping
|
||||
max_bleeding_stage = 3
|
||||
stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "blood soaked clot" = 15, "small angry scar" = 5, "small straight scar" = 0)
|
||||
damage_type = CUT
|
||||
|
||||
/datum/wound/cut/gaping_big
|
||||
max_bleeding_stage = 3
|
||||
stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large blood soaked clot" = 25, "large angry scar" = 10, "large straight scar" = 0)
|
||||
damage_type = CUT
|
||||
|
||||
datum/wound/cut/massive
|
||||
max_bleeding_stage = 3
|
||||
stages = list("massive wound" = 70, "massive healing wound" = 50, "massive blood soaked clot" = 25, "massive angry scar" = 10, "massive jagged scar" = 0)
|
||||
damage_type = CUT
|
||||
|
||||
/** BRUISES **/
|
||||
/datum/wound/bruise
|
||||
stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,
|
||||
"moderate bruise" = 20, "small bruise" = 10, "tiny bruise" = 5)
|
||||
max_bleeding_stage = 3 //only large bruise and above can bleed.
|
||||
autoheal_cutoff = 30
|
||||
damage_type = BRUISE
|
||||
|
||||
/** BURNS **/
|
||||
/datum/wound/burn/moderate
|
||||
stages = list("ripped burn" = 10, "moderate burn" = 5, "healing moderate burn" = 2, "fresh skin" = 0)
|
||||
damage_type = BURN
|
||||
|
||||
/datum/wound/burn/large
|
||||
stages = list("ripped large burn" = 20, "large burn" = 15, "healing large burn" = 5, "fresh skin" = 0)
|
||||
damage_type = BURN
|
||||
|
||||
/datum/wound/burn/severe
|
||||
stages = list("ripped severe burn" = 35, "severe burn" = 30, "healing severe burn" = 10, "burn scar" = 0)
|
||||
damage_type = BURN
|
||||
|
||||
/datum/wound/burn/deep
|
||||
stages = list("ripped deep burn" = 45, "deep burn" = 40, "healing deep burn" = 15, "large burn scar" = 0)
|
||||
damage_type = BURN
|
||||
|
||||
/datum/wound/burn/carbonised
|
||||
stages = list("carbonised area" = 50, "healing carbonised area" = 20, "massive burn scar" = 0)
|
||||
damage_type = BURN
|
||||
|
||||
/** INTERNAL BLEEDING **/
|
||||
/datum/wound/internal_bleeding
|
||||
internal = 1
|
||||
stages = list("severed artery" = 30, "cut artery" = 20, "damaged artery" = 10, "bruised artery" = 5)
|
||||
autoheal_cutoff = 5
|
||||
max_bleeding_stage = 4 //all stages bleed. It's called internal bleeding after all.
|
||||
|
||||
|
||||
/** EXTERNAL ORGAN LOSS **/
|
||||
/datum/wound/lost_limb
|
||||
|
||||
/datum/wound/lost_limb/New(var/obj/item/organ/external/lost_limb, var/losstype, var/clean)
|
||||
var/damage_amt = lost_limb.max_damage
|
||||
if(clean) damage_amt /= 2
|
||||
|
||||
switch(losstype)
|
||||
if(DROPLIMB_EDGE, DROPLIMB_BLUNT)
|
||||
damage_type = CUT
|
||||
max_bleeding_stage = 3 //clotted stump and above can bleed.
|
||||
stages = list(
|
||||
"ripped stump" = damage_amt*1.3,
|
||||
"bloody stump" = damage_amt,
|
||||
"clotted stump" = damage_amt*0.5,
|
||||
"scarred stump" = 0
|
||||
)
|
||||
if(DROPLIMB_BURN)
|
||||
damage_type = BURN
|
||||
stages = list(
|
||||
"ripped charred stump" = damage_amt*1.3,
|
||||
"charred stump" = damage_amt,
|
||||
"scarred stump" = damage_amt*0.5,
|
||||
"scarred stump" = 0
|
||||
)
|
||||
|
||||
..(damage_amt)
|
||||
|
||||
/datum/wound/lost_limb/can_merge(var/datum/wound/other)
|
||||
return 0 //cannot be merged
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
/datum/surgery/organ_manipulation_boneless
|
||||
name = "Organ Manipulation"
|
||||
possible_locs = list("chest","head","groin", "eyes", "mouth")
|
||||
possible_locs = list("chest","head","groin", "eyes", "mouth", "l_arm", "r_arm")
|
||||
steps = list(/datum/surgery_step/generic/cut_open,/datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/internal/manipulate_organs,/datum/surgery_step/generic/cauterize)
|
||||
requires_organic_bodypart = 1
|
||||
|
||||
@@ -159,6 +159,11 @@
|
||||
else if(implement_type in implements_extract)
|
||||
current_type = "extract"
|
||||
var/list/organs = target.get_organs_zone(target_zone)
|
||||
var/mob/living/simple_animal/borer/B = target.has_brain_worms()
|
||||
if(target_zone == "head" && B)
|
||||
user.visible_message("[user] begins to extract [B] from [target]'s [parse_zone(target_zone)].",
|
||||
"<span class='notice'>You begin to extract [B] from [target]'s [parse_zone(target_zone)]...</span>")
|
||||
return TRUE
|
||||
if(!organs.len)
|
||||
to_chat(user, "<span class='notice'>There are no removeable organs in [target]'s [parse_zone(target_zone)]!</span>")
|
||||
return -1
|
||||
@@ -195,7 +200,7 @@
|
||||
return
|
||||
|
||||
for(var/obj/item/organ/internal/I in affected.internal_organs)
|
||||
if(I && I.damage > 0)
|
||||
if(I && I.damage)
|
||||
if(I.robotic < 2 && !istype (tool, /obj/item/stack/nanopaste))
|
||||
if(!(I.sterile))
|
||||
spread_germs_to_organ(I, user, tool)
|
||||
@@ -233,7 +238,7 @@
|
||||
for(var/obj/item/organ/internal/I in affected.internal_organs)
|
||||
if(I)
|
||||
I.surgeryize()
|
||||
if(I && I.damage > 0)
|
||||
if(I && I.damage)
|
||||
if(I.robotic < 2 && !istype (tool, /obj/item/stack/nanopaste))
|
||||
user.visible_message("<span class='notice'> [user] treats damage to [target]'s [I.name] with [tool_name].</span>", \
|
||||
"<span class='notice'> You treat damage to [target]'s [I.name] with [tool_name].</span>" )
|
||||
@@ -259,16 +264,20 @@
|
||||
user.visible_message("<span class='notice'> [user] has transplanted [tool] into [target]'s [parse_zone(target_zone)].</span>",
|
||||
"<span class='notice'> You have transplanted [tool] into [target]'s [parse_zone(target_zone)].</span>")
|
||||
|
||||
I.status &= ~ORGAN_CUT_AWAY
|
||||
|
||||
else if(current_type == "extract")
|
||||
var/mob/living/simple_animal/borer/B = target.has_brain_worms()
|
||||
if(target_zone == "head" && B && B.host == target)
|
||||
user.visible_message("[user] successfully extracts [B] from [target]'s [parse_zone(target_zone)]!",
|
||||
"<span class='notice'>You successfully extract [B] from [target]'s [parse_zone(target_zone)].</span>")
|
||||
add_logs(user, target, "surgically removed [B] from", addition="INTENT: [uppertext(user.a_intent)]")
|
||||
B.leave_host()
|
||||
return FALSE
|
||||
if(I && I.owner == target)
|
||||
user.visible_message("<span class='notice'> [user] has separated and extracts [target]'s [I] with [tool].</span>",
|
||||
"<span class='notice'> You have separated and extracted [target]'s [I] with [tool].</span>")
|
||||
|
||||
add_logs(user, target, "surgically removed [I.name] from", addition="INTENT: [uppertext(user.a_intent)]")
|
||||
spread_germs_to_organ(I, user, tool)
|
||||
I.status |= ORGAN_CUT_AWAY
|
||||
var/obj/item/thing = I.remove(target)
|
||||
if(!istype(thing))
|
||||
thing.forceMove(get_turf(target))
|
||||
@@ -341,10 +350,10 @@
|
||||
else if(istype(tool, /obj/item/stack/medical/bruise_pack) || istype(tool, /obj/item/stack/nanopaste))
|
||||
dam_amt = 5
|
||||
target.adjustToxLoss(10)
|
||||
affected.createwound(CUT, 5)
|
||||
affected.take_damage(5)
|
||||
|
||||
for(var/obj/item/organ/internal/I in affected.internal_organs)
|
||||
if(I && I.damage > 0 && !(I.tough))
|
||||
if(I && I.damage && !(I.tough))
|
||||
I.take_damage(dam_amt,0)
|
||||
|
||||
return 0
|
||||
@@ -389,7 +398,7 @@
|
||||
if(affected)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, damaging [target]'s [affected.name] with [tool]!</span>", \
|
||||
"<span class='warning'> Your hand slips, damaging [target]'s [affected.name] with [tool]!</span>")
|
||||
affected.createwound(BRUISE, 20)
|
||||
affected.take_damage(20)
|
||||
else
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, damaging [target]'s [parse_zone(target_zone)] with [tool]!</span>", \
|
||||
"<span class='warning'> Your hand slips, damaging [target]'s [parse_zone(target_zone)] with [tool]!</span>")
|
||||
@@ -409,7 +418,7 @@
|
||||
var/self_msg = "<span class='warning'> Your hand slips, tearing skin!</span>"
|
||||
user.visible_message(msg, self_msg)
|
||||
if(affected)
|
||||
affected.createwound(BRUISE, 20)
|
||||
affected.take_damage(20)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -33,14 +33,10 @@
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting)
|
||||
if(!affected) return 0
|
||||
if(!affected)
|
||||
return 0
|
||||
|
||||
var/internal_bleeding = 0
|
||||
for(var/datum/wound/W in affected.wounds)
|
||||
if(W.internal)
|
||||
internal_bleeding = 1
|
||||
break
|
||||
if(internal_bleeding)
|
||||
if(affected.internal_bleeding)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -75,15 +71,10 @@
|
||||
|
||||
/datum/surgery_step/fix_vein/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
if(!affected) return 0
|
||||
if(!affected)
|
||||
return 0
|
||||
|
||||
var/internal_bleeding = 0
|
||||
for(var/datum/wound/W in affected.wounds)
|
||||
if(W.internal)
|
||||
internal_bleeding = 1
|
||||
break
|
||||
|
||||
return internal_bleeding
|
||||
return affected.internal_bleeding
|
||||
|
||||
/datum/surgery_step/fix_vein/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
@@ -97,9 +88,7 @@
|
||||
user.visible_message("<span class='notice'> [user] has patched the damaged vein in [target]'s [affected.name] with \the [tool].</span>", \
|
||||
"<span class='notice'> You have patched the damaged vein in [target]'s [affected.name] with \the [tool].</span>")
|
||||
|
||||
for(var/datum/wound/W in affected.wounds) if(W.internal)
|
||||
affected.wounds -= W
|
||||
affected.update_damages()
|
||||
affected.internal_bleeding = FALSE
|
||||
if(ishuman(user) && prob(40))
|
||||
var/mob/living/carbon/human/U = user
|
||||
U.bloody_hands(target, 0)
|
||||
@@ -159,7 +148,7 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("<span class='warning'> [user]'s hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!</span>", \
|
||||
"<span class='warning'> Your hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!</span>")
|
||||
affected.createwound(CUT, 20, 1)
|
||||
affected.take_damage(20)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/datum/surgery/embedded_removal
|
||||
name = "Removal of Embedded Objects"
|
||||
steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/remove_object,/datum/surgery_step/generic/cauterize)
|
||||
possible_locs = list("head", "chest", "l_arm", "l_hand", "r_arm", "r_hand","r_leg", "r_foot", "l_leg", "l_foot", "groin")
|
||||
|
||||
/datum/surgery/embedded_removal/synth
|
||||
steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/remove_object,/datum/surgery_step/robotics/external/close_hatch)
|
||||
|
||||
/datum/surgery/embedded_removal/can_start(mob/user, mob/living/carbon/human/target)
|
||||
if(!istype(target))
|
||||
return 0
|
||||
var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(affected.status & ORGAN_ROBOT)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/surgery/embedded_removal/synth/can_start(mob/user, mob/living/carbon/human/target)
|
||||
if(!istype(target))
|
||||
return 0
|
||||
var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
|
||||
if(!affected)
|
||||
return 0
|
||||
if(!(affected.status & ORGAN_ROBOT))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/remove_object
|
||||
name = "Remove Embedded Objects"
|
||||
time = 32
|
||||
accept_hand = 1
|
||||
var/obj/item/organ/external/L = null
|
||||
|
||||
|
||||
/datum/surgery_step/remove_object/begin_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
L = surgery.organ_ref
|
||||
if(L)
|
||||
user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_sel.selecting)].", "<span class='notice'>You look for objects embedded in [target]'s [parse_zone(user.zone_sel.selecting)]...</span>")
|
||||
else
|
||||
user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_sel.selecting)].", "<span class='notice'>You look for [target]'s [parse_zone(user.zone_sel.selecting)]...</span>")
|
||||
|
||||
|
||||
/datum/surgery_step/remove_object/end_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
if(L)
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/objects = 0
|
||||
for(var/obj/item/I in L.embedded_objects)
|
||||
objects++
|
||||
I.forceMove(get_turf(H))
|
||||
L.embedded_objects -= I
|
||||
if(!H.has_embedded_objects())
|
||||
H.clear_alert("embeddedobject")
|
||||
|
||||
if(objects > 0)
|
||||
user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L]!", "<span class='notice'>You successfully remove [objects] objects from [H]'s [L.name].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You find no objects embedded in [H]'s [L]!</span>")
|
||||
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't find [target]'s [parse_zone(user.zone_sel.selecting)], let alone any objects embedded in it!</span>")
|
||||
|
||||
return 1
|
||||
@@ -12,7 +12,7 @@
|
||||
/datum/surgery/cybernetic_repair/internal
|
||||
name = "Internal Component Manipulation"
|
||||
steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/robotics/manipulate_robotic_organs)
|
||||
possible_locs = list("eyes", "chest","head","groin")
|
||||
possible_locs = list("eyes", "chest","head","groin","l_arm","r_arm")
|
||||
requires_organic_bodypart = 0
|
||||
|
||||
/datum/surgery/cybernetic_amputation
|
||||
@@ -56,8 +56,6 @@
|
||||
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
||||
if(affected == null)
|
||||
return 0
|
||||
if(affected.status & ORGAN_DESTROYED)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/surgery_step/robotics/external
|
||||
@@ -400,7 +398,7 @@
|
||||
|
||||
var/found_damaged_organ = FALSE
|
||||
for(var/obj/item/organ/internal/I in affected.internal_organs)
|
||||
if(I && I.damage > 0 && I.robotic >= 2)
|
||||
if(I && I.damage && I.robotic >= 2)
|
||||
user.visible_message("[user] starts mending the damage to [target]'s [I.name]'s mechanisms.", \
|
||||
"You start mending the damage to [target]'s [I.name]'s mechanisms.")
|
||||
found_damaged_organ = TRUE
|
||||
@@ -425,7 +423,7 @@
|
||||
if(!hasorgans(target))
|
||||
return
|
||||
for(var/obj/item/organ/internal/I in affected.internal_organs)
|
||||
if(I && I.damage > 0)
|
||||
if(I && I.damage)
|
||||
if(I.robotic >= 2)
|
||||
user.visible_message("<span class='notice'> [user] repairs [target]'s [I.name] with [tool].</span>", \
|
||||
"<span class='notice'> You repair [target]'s [I.name] with [tool].</span>" )
|
||||
@@ -443,8 +441,6 @@
|
||||
user.visible_message("<span class='notice'> [user] has reattached [target]'s [I].</span>" , \
|
||||
"<span class='notice'> You have reattached [target]'s [I].</span>")
|
||||
|
||||
if(I && istype(I))
|
||||
I.status &= ~ORGAN_CUT_AWAY
|
||||
else if(current_type == "install")
|
||||
user.visible_message("<span class='notice'> [user] has installed \the [tool] into [target]'s [affected.name].</span>", \
|
||||
"<span class='notice'> You have installed \the [tool] into [target]'s [affected.name].</span>")
|
||||
@@ -461,7 +457,6 @@
|
||||
|
||||
add_logs(user, target, "surgically removed [I.name] from", addition="INTENT: [uppertext(user.a_intent)]")
|
||||
spread_germs_to_organ(I, user)
|
||||
I.status |= ORGAN_CUT_AWAY
|
||||
var/obj/item/thing = I.remove(target)
|
||||
if(!istype(thing))
|
||||
thing.forceMove(get_turf(target))
|
||||
@@ -490,7 +485,7 @@
|
||||
"<span class='warning'> Your hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!</span>")
|
||||
|
||||
target.adjustToxLoss(5)
|
||||
affected.createwound(CUT, 5)
|
||||
affected.take_damage(5)
|
||||
|
||||
for(var/obj/item/organ/internal/I in affected.internal_organs)
|
||||
if(I)
|
||||
@@ -538,7 +533,7 @@
|
||||
|
||||
add_logs(user, target, "surgically removed [affected.name] from", addition="INTENT: [uppertext(user.a_intent)]")//log it
|
||||
|
||||
var/atom/movable/thing = affected.droplimb(1,DROPLIMB_EDGE)
|
||||
var/atom/movable/thing = affected.droplimb(1,DROPLIMB_SHARP)
|
||||
if(istype(thing,/obj/item))
|
||||
user.put_in_hands(thing)
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
return null
|
||||
|
||||
/proc/spread_germs_to_organ(obj/item/organ/E, mob/living/carbon/human/user, obj/item/tool)
|
||||
if(!istype(user) || !istype(E))
|
||||
if(!istype(user) || !istype(E) || !(E.status & ORGAN_ROBOT) || E.sterile)
|
||||
return
|
||||
|
||||
var/germ_level = user.germ_level
|
||||
@@ -189,20 +189,19 @@
|
||||
//germ spread from surgeon touching the patient
|
||||
if(user.gloves)
|
||||
germ_level = user.gloves.germ_level
|
||||
if(!(E.status & ORGAN_ROBOT)) //Germs on robotic limbs bad
|
||||
E.germ_level = max(germ_level,E.germ_level) //as funny as scrubbing microbes out with clean gloves is - no.
|
||||
spread_germs_by_incision(E,tool)//germ spread from environement to patient
|
||||
E.germ_level += germ_level
|
||||
spread_germs_by_incision(E, tool) //germ spread from environement to patient
|
||||
|
||||
/proc/spread_germs_by_incision(obj/item/organ/external/E,obj/item/tool)
|
||||
if(!istype(E,/obj/item/organ/external))
|
||||
if(!istype(E, /obj/item/organ/external))
|
||||
return
|
||||
|
||||
var/germs = 0
|
||||
|
||||
for(var/mob/living/carbon/human/H in view(2, E.loc))//germs from people
|
||||
if(AStar(E.loc, H.loc, /turf/proc/Distance, 2, simulated_only = 0))
|
||||
if((!(NO_BREATH in H.mutations) || !(H.species.flags & NO_BREATH)) && !H.wear_mask) //wearing a mask helps preventing people from breathing cooties into open incisions
|
||||
germs+=H.germ_level/4
|
||||
if((!(NO_BREATH in H.mutations) || !(NO_BREATH in H.species.species_traits)) && !H.wear_mask) //wearing a mask helps preventing people from breathing cooties into open incisions
|
||||
germs += H.germ_level * 0.25
|
||||
|
||||
for(var/obj/effect/decal/cleanable/M in view(2, E.loc))//germs from messes
|
||||
if(AStar(E.loc, M.loc, /turf/proc/Distance, 2, simulated_only = 0))
|
||||
@@ -213,7 +212,7 @@
|
||||
germs += 30
|
||||
|
||||
if(E.internal_organs.len)
|
||||
germs = germs / E.internal_organs.len
|
||||
germs = germs / (E.internal_organs.len + 1) // +1 for the external limb this eventually applies to; let's not multiply germs now.
|
||||
for(var/obj/item/organ/internal/O in E.internal_organs)
|
||||
if(!(O.status & ORGAN_ROBOT))
|
||||
O.germ_level += germs
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
flags = CONDUCT
|
||||
force = 15.0
|
||||
sharp = 1
|
||||
edge = 1
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
origin_tech = "materials=1;biotech=1"
|
||||
attack_verb = list("drilled")
|
||||
@@ -63,7 +62,6 @@
|
||||
flags = CONDUCT
|
||||
force = 10.0
|
||||
sharp = 1
|
||||
edge = 1
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
throwforce = 5.0
|
||||
throw_speed = 3
|
||||
@@ -123,7 +121,6 @@
|
||||
flags = CONDUCT
|
||||
force = 15.0
|
||||
sharp = 1
|
||||
edge = 1
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
throwforce = 9.0
|
||||
throw_speed = 3
|
||||
|
||||
Reference in New Issue
Block a user