diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index adb7bf3fa23..ea4d656556f 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -433,7 +433,7 @@
if(!GLOB.admin_objective_list)
generate_admin_objective_list()
-
+
if(old_objective)
if(old_objective.name in GLOB.admin_objective_list)
def_value = old_objective.name
@@ -451,7 +451,7 @@
target_antag.objectives += new_objective
message_admins("[key_name_admin(usr)] added a new objective for [current]: [new_objective.explanation_text]")
log_admin("[key_name(usr)] added a new objective for [current]: [new_objective.explanation_text]")
- else
+ else
if(old_objective.type == selected_type)
//Edit the old
old_objective.admin_edit(usr)
@@ -652,8 +652,8 @@
S.updateButtonIcon()
INVOKE_ASYNC(S, /obj/effect/proc_holder/spell.proc/start_recharge)
-/datum/mind/proc/get_ghost(even_if_they_cant_reenter)
- for(var/mob/dead/observer/G in GLOB.dead_mob_list)
+/datum/mind/proc/get_ghost(even_if_they_cant_reenter, ghosts_with_clients)
+ for(var/mob/dead/observer/G in (ghosts_with_clients ? GLOB.player_list : GLOB.dead_mob_list))
if(G.mind == src)
if(G.can_reenter_corpse || even_if_they_cant_reenter)
return G
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index d18e3daaac3..235cfcf04c8 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -122,7 +122,7 @@
if(suicided)
to_chat(user, "It's started turning slightly grey. They must not have been able to handle the stress of it all.")
else if(brainmob)
- if(brainmob.client)
+ if(brainmob.get_ghost(FALSE, TRUE))
if(brain_death || brainmob.health <= HEALTH_THRESHOLD_DEAD)
to_chat(user, "It's lifeless and severely damaged.")
else if(damaged_brain)
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 4f217a32628..ec13a30ebd9 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -115,17 +115,8 @@
msg += "[t_His] soul seems to have been ripped out of [t_his] body. Revival is impossible.\n"
msg += "[t_He] [t_is] limp and unresponsive; there are no signs of life"
if(getorgan(/obj/item/organ/brain))
- if(!key)
- var/foundghost = 0
- if(mind)
- for(var/mob/dead/observer/G in GLOB.player_list)
- if(G.mind == mind)
- foundghost = 1
- if (G.can_reenter_corpse == 0)
- foundghost = 0
- break
- if(!foundghost)
- msg += " and [t_his] soul has departed"
+ if(!key && !get_ghost(FALSE, TRUE))
+ msg += " and [t_his] soul has departed"
msg += "...\n"
if(get_bodypart(BODY_ZONE_HEAD) && !getorgan(/obj/item/organ/brain))
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index dc7efd1baa2..e4ea939ea56 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -664,9 +664,9 @@
/mob/proc/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //For sec bot threat assessment
return 0
-/mob/proc/get_ghost(even_if_they_cant_reenter = 0)
+/mob/proc/get_ghost(even_if_they_cant_reenter, ghosts_with_clients)
if(mind)
- return mind.get_ghost(even_if_they_cant_reenter)
+ return mind.get_ghost(even_if_they_cant_reenter, ghosts_with_clients)
/mob/proc/grab_ghost(force)
if(mind)
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 4e9731ce2bf..bc52a8b73bf 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -439,13 +439,12 @@
var/obj/item/cavity_item
/obj/item/bodypart/chest/Destroy()
- if(cavity_item)
- qdel(cavity_item)
+ QDEL_NULL(cavity_item)
return ..()
/obj/item/bodypart/chest/drop_organs(mob/user, violent_removal)
if(cavity_item)
- cavity_item.forceMove(user.loc)
+ cavity_item.forceMove(drop_location())
cavity_item = null
..()
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 69a725d061b..1048c905508 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -158,6 +158,14 @@
LB.eyes = src
..()
+/obj/item/organ/ears/transfer_to_limb(obj/item/bodypart/head/LB, mob/living/carbon/human/C)
+ LB.ears = src
+ ..()
+
+/obj/item/organ/tongue/transfer_to_limb(obj/item/bodypart/head/LB, mob/living/carbon/human/C)
+ LB.tongue = src
+ ..()
+
/obj/item/bodypart/chest/drop_limb(special)
if(special)
..()
@@ -312,6 +320,13 @@
brain.Insert(C) //Now insert the brain proper
brain = null //No more brain in the head
+ if(tongue)
+ tongue = null
+ if(ears)
+ ears = null
+ if(eyes)
+ eyes = null
+
if(ishuman(C))
var/mob/living/carbon/human/H = C
H.hair_color = hair_color
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index d838e879cbf..358b495ec13 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -16,6 +16,9 @@
var/mob/living/brain/brainmob = null //The current occupant.
var/obj/item/organ/brain/brain = null //The brain organ
+ var/obj/item/organ/eyes/eyes
+ var/obj/item/organ/ears/ears
+ var/obj/item/organ/tongue/tongue
//Limb appearance info:
var/real_name = "" //Replacement name
@@ -28,11 +31,65 @@
var/facial_hair_style = "Shaved"
//Eye Colouring
- var/obj/item/organ/eyes/eyes = null
-
var/lip_style = null
var/lip_color = "white"
+
+/obj/item/bodypart/head/Destroy()
+ QDEL_NULL(brainmob) //order is sensitive, see warning in handle_atom_del() below
+ QDEL_NULL(brain)
+ QDEL_NULL(eyes)
+ QDEL_NULL(ears)
+ QDEL_NULL(tongue)
+ return ..()
+
+/obj/item/bodypart/head/handle_atom_del(atom/A)
+ if(A == brain)
+ brain = null
+ update_icon_dropped()
+ if(!QDELETED(brainmob)) //this shouldn't happen without badminnery.
+ message_admins("Brainmob: ([brainmob]) was left stranded in [src] at [ADMIN_VERBOSEJMP(src)] without a brain!")
+ log_game("Brainmob: ([brainmob]) was left stranded in [src] at [AREACOORD(src)] without a brain!")
+ if(A == brainmob)
+ brainmob = null
+ if(A == eyes)
+ eyes = null
+ update_icon_dropped()
+ if(A == ears)
+ ears = null
+ if(A == tongue)
+ tongue = null
+ return ..()
+
+/obj/item/bodypart/head/examine(mob/user)
+ ..()
+ if(status == BODYPART_ORGANIC)
+ if(!brain)
+ to_chat(user, "The brain has been removed from [src].")
+ else if(brain.suicided || brainmob?.suiciding)
+ to_chat(user, "There's a pretty dumb expression on [real_name]'s face; they must have really hated life. There is no hope of recovery.")
+ else if(brain.brain_death || brainmob?.health <= HEALTH_THRESHOLD_DEAD)
+ to_chat(user, "It seems to be leaking some kind of... clear fluid? The brain inside must be in pretty bad shape... There is no coming back from that.")
+ else if(brainmob)
+ if(brainmob.get_ghost(FALSE, TRUE))
+ to_chat(user, "It's muscles are still twitching slightly... It still seems to have a bit of life left to it.")
+ else
+ to_chat(user, "It seems seems particularly lifeless. Perhaps there'll be a chance for them later.")
+ else if(brain?.decoy_override)
+ to_chat(user, "It seems seems particularly lifeless. Perhaps there'll be a chance for them later.")
+ else
+ to_chat(user, "It seems completely devoid of life.")
+
+ if(!eyes)
+ to_chat(user, "[real_name]'s eyes appear to have been removed.")
+
+ if(!ears)
+ to_chat(user, "[real_name]'s ears appear to have been removed.")
+
+ if(!tongue)
+ to_chat(user, "[real_name]'s tongue appears to have been removed.")
+
+
/obj/item/bodypart/head/can_dismember(obj/item/I)
if(!((owner.stat == DEAD) || owner.InFullCritical()))
return FALSE
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
index 5abafd26b28..ae5cc676d03 100644
--- a/code/modules/surgery/bodyparts/robot_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -114,44 +114,82 @@
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
- var/wired = 0
+ var/wired = FALSE
var/obj/item/stock_parts/cell/cell = null
+
+/obj/item/bodypart/chest/robot/handle_atom_del(atom/A)
+ if(A == cell)
+ cell = null
+ return ..()
+
+/obj/item/bodypart/chest/robot/Destroy()
+ QDEL_NULL(cell)
+ return ..()
+
/obj/item/bodypart/chest/robot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/stock_parts/cell))
- if(src.cell)
+ if(cell)
to_chat(user, "You have already inserted a cell!")
return
else
if(!user.transferItemToLoc(W, src))
return
- src.cell = W
+ cell = W
to_chat(user, "You insert the cell.")
else if(istype(W, /obj/item/stack/cable_coil))
- if(src.wired)
+ if(wired)
to_chat(user, "You have already inserted wire!")
return
var/obj/item/stack/cable_coil/coil = W
if (coil.use(1))
- src.wired = 1
+ wired = TRUE
to_chat(user, "You insert the wire.")
else
to_chat(user, "You need one length of coil to wire it!")
else
return ..()
-/obj/item/bodypart/chest/robot/Destroy()
- if(cell)
- qdel(cell)
- cell = null
- return ..()
+/obj/item/bodypart/chest/robot/wirecutter_act(mob/living/user, obj/item/I)
+ if(!wired)
+ return
+ . = TRUE
+ I.play_tool_sound(src)
+ to_chat(user, "You cut the wires out of [src].")
+ new /obj/item/stack/cable_coil(drop_location(), 1)
+ wired = FALSE
+/obj/item/bodypart/chest/robot/screwdriver_act(mob/living/user, obj/item/I)
+ ..()
+ . = TRUE
+ if(!cell)
+ to_chat(user, "There's no power cell installed in [src]!")
+ return
+ I.play_tool_sound(src)
+ to_chat(user, "Remove [cell] from [src].")
+ cell.forceMove(drop_location())
+ cell = null
+
+
+/obj/item/bodypart/chest/robot/examine(mob/user)
+ ..()
+ if(cell)
+ to_chat(user, "It has a [cell] inserted.")
+ to_chat(user, "You can use a screwdriver to remove [cell].")
+ else
+ to_chat(user, "It has an empty port for a power cell.")
+ if(wired)
+ to_chat(user, "Its all wired up[cell ? " and ready for usage" : ""].")
+ to_chat(user, "You can use wirecutters to remove the wiring.")
+ else
+ to_chat(user, "It has a couple spots that still need to be wired.")
/obj/item/bodypart/chest/robot/drop_organs(mob/user, violent_removal)
if(wired)
- new /obj/item/stack/cable_coil(user.loc, 1)
+ new /obj/item/stack/cable_coil(drop_location(), 1)
+ wired = FALSE
if(cell)
- cell.forceMove(user.loc)
+ cell.forceMove(drop_location())
cell = null
..()
@@ -180,11 +218,36 @@
var/obj/item/assembly/flash/handheld/flash2 = null
+/obj/item/bodypart/head/robot/handle_atom_del(atom/A)
+ if(A == flash1)
+ flash1 = null
+ if(A == flash2)
+ flash2 = null
+ return ..()
+
+/obj/item/bodypart/head/robot/Destroy()
+ QDEL_NULL(flash1)
+ QDEL_NULL(flash2)
+ return ..()
+
+/obj/item/bodypart/head/robot/examine(mob/user)
+ ..()
+ if(!flash1 && !flash2)
+ to_chat(user, "It has two empty eye sockets for flashes.")
+ else
+ var/single_flash = FALSE
+ if(!flash1 || !flash2)
+ single_flash = TRUE
+ to_chat(user, "One of it's eye sockets are currently occupied by a flash.")
+ to_chat(user, "It has an empty eye socket for another flash.")
+ else
+ to_chat(user, "It has two eye sockets occupied by flashes.")
+ to_chat(user, "You can remove the seated flash[single_flash ? "":"es"] with a crowbar.")
/obj/item/bodypart/head/robot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/assembly/flash/handheld))
var/obj/item/assembly/flash/handheld/F = W
- if(src.flash1 && src.flash2)
+ if(flash1 && flash2)
to_chat(user, "You have already inserted the eyes!")
return
else if(F.crit_fail)
@@ -193,36 +256,28 @@
else
if(!user.transferItemToLoc(F, src))
return
- if(src.flash1)
- src.flash2 = F
- else
- src.flash1 = F
- to_chat(user, "You insert the flash into the eye socket.")
- else if(W.tool_behaviour == TOOL_CROWBAR)
- if(flash1 || flash2)
- W.play_tool_sound(src)
- to_chat(user, "You remove the flash from [src].")
if(flash1)
- flash1.forceMove(user.loc)
- flash1 = null
- if(flash2)
- flash2.forceMove(user.loc)
- flash2 = null
- else
- to_chat(user, "There is no flash to remove from [src].")
-
- else
- return ..()
-
-/obj/item/bodypart/head/robot/Destroy()
- if(flash1)
- qdel(flash1)
- flash1 = null
- if(flash2)
- qdel(flash2)
- flash2 = null
+ flash2 = F
+ else
+ flash1 = F
+ to_chat(user, "You insert the flash into the eye socket.")
+ return
return ..()
+/obj/item/bodypart/head/robot/crowbar_act(mob/living/user, obj/item/I)
+ if(flash1 || flash2)
+ I.play_tool_sound(src)
+ to_chat(user, "You remove the flash from [src].")
+ if(flash1)
+ flash1.forceMove(drop_location())
+ flash1 = null
+ if(flash2)
+ flash2.forceMove(drop_location())
+ flash2 = null
+ else
+ to_chat(user, "There is no flash to remove from [src].")
+ return TRUE
+
/obj/item/bodypart/head/robot/drop_organs(mob/user, violent_removal)
if(flash1)