mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-26 05:27:01 +01:00
Shades now drop bodies when killed/destroyed (#24784)
* this was a bit of a pain * yes * damger reviwe * funny review * Apply suggestions from code review Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> --------- Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
This commit is contained in:
@@ -1061,3 +1061,6 @@
|
||||
|
||||
/// Used by admin-tooling to remove radiation
|
||||
#define COMSIG_ADMIN_DECONTAMINATE "admin_decontaminate"
|
||||
|
||||
/// Sent when bodies transfer between shades/shards and constructs
|
||||
#define COMSIG_SHADE_TO_CONSTRUCT_TRANSFER "shade_to_construct_transfer"
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* A component for tracking and manipulating bodies held inside constructs/shades
|
||||
* Will drop the body/brain when the parent dies or is deleted.
|
||||
*/
|
||||
/datum/component/construct_held_body
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
/// A reference to either a mob, or a brain organ that is held inside our parent. Will drop when parent dies/is deleted
|
||||
var/atom/movable/held_body
|
||||
|
||||
/datum/component/construct_held_body/Initialize(atom/movable/new_body)
|
||||
. = ..()
|
||||
add_body(new_body)
|
||||
|
||||
/datum/component/construct_held_body/Destroy(force, silent)
|
||||
if(held_body)
|
||||
stack_trace("/datum/component/construct_held_body had a held body still despite being destroyed. Body is [held_body] ([held_body.type])")
|
||||
held_body = null
|
||||
return ..()
|
||||
|
||||
/datum/component/construct_held_body/PostTransfer()
|
||||
held_body.forceMove(parent) // forcemove them to the new parent
|
||||
|
||||
/datum/component/construct_held_body/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_MOB_DEATH, PROC_REF(drop_body))
|
||||
RegisterSignal(parent, COMSIG_PARENT_QDELETING, PROC_REF(drop_body))
|
||||
RegisterSignal(parent, COMSIG_SHADE_TO_CONSTRUCT_TRANSFER, PROC_REF(transfer_held_body))
|
||||
|
||||
/datum/component/construct_held_body/UnregisterFromParent()
|
||||
UnregisterSignal(parent, COMSIG_MOB_DEATH)
|
||||
UnregisterSignal(parent, COMSIG_PARENT_QDELETING)
|
||||
UnregisterSignal(parent, COMSIG_SHADE_TO_CONSTRUCT_TRANSFER)
|
||||
|
||||
/datum/component/construct_held_body/proc/add_body(atom/movable/new_body)
|
||||
held_body = new_body
|
||||
RegisterSignal(new_body, COMSIG_PARENT_QDELETING, PROC_REF(_null_held_body))
|
||||
new_body.forceMove(parent)
|
||||
|
||||
/datum/component/construct_held_body/proc/_null_held_body()
|
||||
SIGNAL_HANDLER // COMSIG_PARENT_QDELETING
|
||||
UnregisterSignal(held_body, COMSIG_PARENT_QDELETING)
|
||||
held_body = null
|
||||
|
||||
/datum/component/construct_held_body/proc/transfer_held_body(mob/living/current_parent, mob/living/new_body_holder)
|
||||
SIGNAL_HANDLER // COMSIG_SHADE_TO_CONSTRUCT_TRANSFER
|
||||
new_body_holder.TakeComponent(src)
|
||||
|
||||
/datum/component/construct_held_body/proc/drop_body()
|
||||
SIGNAL_HANDLER // COMSIG_MOB_DEATH + COMSIG_PARENT_QDELETING
|
||||
INVOKE_ASYNC(src, PROC_REF(_drop_body))
|
||||
|
||||
/datum/component/construct_held_body/proc/_drop_body() // call me lazy ig
|
||||
if(!held_body) // Null check for empty bodies
|
||||
return
|
||||
var/mob/living/parent_mob = parent
|
||||
held_body.forceMove(get_turf(parent))
|
||||
SSticker.mode?.cult_team?.add_cult_immunity(held_body)
|
||||
|
||||
var/mob/living/held_mob = held_body
|
||||
if(ismob(held_body)) // Check if the held_body is a mob
|
||||
held_mob.key = parent_mob.key
|
||||
held_mob.cancel_camera()
|
||||
else if(istype(held_body, /obj/item/organ/internal/brain)) // Check if the held_body is a brain
|
||||
var/obj/item/organ/internal/brain/brain = held_body
|
||||
if(brain.brainmob) // Check if the brain has a brainmob
|
||||
brain.brainmob.key = parent_mob.key // Set the key to the brainmob
|
||||
held_mob = brain.brainmob
|
||||
|
||||
if(!istype(held_mob) || QDELETED(held_mob))
|
||||
CRASH("/datum/component/construct_held_body/proc/_drop_body attempted to drop a body despite having no body, or a qdeleted body")
|
||||
|
||||
parent_mob.mind.transfer_to(held_mob) // Transfer the mind to the original mob
|
||||
// goodbye construct antag datums!
|
||||
held_mob.mind.remove_antag_datum(/datum/antagonist/cultist, silent_removal = TRUE)
|
||||
held_mob.mind.remove_antag_datum(/datum/antagonist/wizard/construct, silent_removal = TRUE)
|
||||
held_body = null
|
||||
qdel(src) // our job here is done
|
||||
@@ -11,8 +11,8 @@
|
||||
slot_flags = SLOT_FLAG_BELT
|
||||
origin_tech = "bluespace=4;materials=5"
|
||||
|
||||
/// The body/brain of the player inside this construct, transferred over from the soulstone.
|
||||
var/atom/movable/held_body
|
||||
/// Should we show rays? Triggered by a held body
|
||||
var/animate_rays = FALSE
|
||||
/// Does this soulstone ask the victim whether they want to be turned into a shade
|
||||
var/optional = FALSE
|
||||
/// Can this soul stone be used by anyone, or only cultists/wizards?
|
||||
@@ -26,13 +26,6 @@
|
||||
var/opt_in = FALSE
|
||||
var/purified = FALSE
|
||||
|
||||
/obj/item/soulstone/proc/add_held_body(atom/movable/body)
|
||||
held_body = body
|
||||
RegisterSignal(body, COMSIG_PARENT_QDELETING, PROC_REF(remove_held_body))
|
||||
|
||||
/obj/item/soulstone/proc/remove_held_body()
|
||||
SIGNAL_HANDLER
|
||||
held_body = null
|
||||
|
||||
/obj/item/soulstone/proc/can_use(mob/living/user)
|
||||
if(IS_CULTIST(user) && purified && !iswizard(user))
|
||||
@@ -78,13 +71,12 @@
|
||||
/obj/item/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
A.death()
|
||||
remove_held_body()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/soulstone/process()
|
||||
. = ..()
|
||||
if(held_body)
|
||||
if(animate_rays)
|
||||
var/new_filter = isnull(get_filter("ray"))
|
||||
if(!purified)
|
||||
ray_filter_helper(1, 40,"#c926ae", 6, 20)
|
||||
@@ -242,20 +234,19 @@
|
||||
to_chat(user, "<span class='notice'>The shard feels too tough to shatter, you are not holy enough to free its captive!</span>")
|
||||
return
|
||||
|
||||
if(!do_after_once(user, 10 SECONDS, FALSE, src) || !held_body)
|
||||
if(!do_after_once(user, 10 SECONDS, FALSE, src))
|
||||
return
|
||||
|
||||
user.visible_message("[user] shatters the soulstone apart! Releasing [held_body] from their prison!", "You shatter the soulstone holding [held_body], binding them free!", "You hear something shatter with a ghastly crack.")
|
||||
if(ismob(held_body))
|
||||
var/mob/M = held_body
|
||||
M.key = S.key
|
||||
else if(istype(held_body, /obj/item/organ/internal/brain))
|
||||
var/obj/item/organ/internal/brain/B = held_body
|
||||
B.brainmob.key = S.key
|
||||
S.cancel_camera()
|
||||
held_body.forceMove(get_turf(src))
|
||||
SSticker.mode?.cult_team?.add_cult_immunity(held_body)
|
||||
remove_held_body()
|
||||
if(!S)
|
||||
return
|
||||
|
||||
var/datum/component/construct_held_body/body_holder = S.GetComponent(/datum/component/construct_held_body)
|
||||
var/atom/movable/dropped_body = body_holder.held_body
|
||||
body_holder.drop_body()
|
||||
if(!dropped_body)
|
||||
return
|
||||
|
||||
user.visible_message("[user] shatters the soulstone apart! Releasing [dropped_body] from their prison!", "You shatter the soulstone holding [dropped_body], binding them free!", "You hear something shatter with a ghastly crack.")
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(src))
|
||||
playsound(src, 'sound/effects/pylon_shatter.ogg', 40, TRUE)
|
||||
qdel(src)
|
||||
@@ -276,6 +267,7 @@
|
||||
was_used()
|
||||
remove_filter("ray")
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
animate_rays = FALSE
|
||||
|
||||
///////////////////////////Transferring to constructs/////////////////////////////////////////////////////
|
||||
/obj/structure/constructshell
|
||||
@@ -320,9 +312,8 @@
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span> The soul has already fled its mortal frame. You attempt to bring it back...")
|
||||
T.Paralyse(40 SECONDS)
|
||||
if(!get_cult_ghost(T, user, TRUE))
|
||||
add_held_body(T)
|
||||
T.forceMove(src) //If we can't get a ghost, shard the body anyways.
|
||||
START_PROCESSING(SSobj, src)
|
||||
// no luck, dont shard them.
|
||||
to_chat(user, "<span class='userdanger'>No soul responds to the soul stone.</span>")
|
||||
|
||||
if("VICTIM")
|
||||
var/mob/living/carbon/human/T = target
|
||||
@@ -361,6 +352,7 @@
|
||||
name = "soulstone : [T.name]"
|
||||
to_chat(T, "<span class='notice'>Your soul has been recaptured by the soul stone, its arcane energies are reknitting your ethereal form</span>")
|
||||
to_chat(user, "<span class='notice'>Capture successful!</span> [T.name]'s has been recaptured and stored within the soul stone.")
|
||||
animate_rays = TRUE
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
if("CONSTRUCT")
|
||||
@@ -413,9 +405,8 @@
|
||||
to_chat(src, "<span class='userdanger'>You are still bound to serve the cult, follow their orders and help them complete their goals at all costs.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='userdanger'>You are still bound to serve your creator, follow their orders and help them complete their goals at all costs.</span>")
|
||||
SS.held_body.forceMove(src)
|
||||
add_held_body(SS.held_body)
|
||||
SS.remove_held_body()
|
||||
|
||||
SEND_SIGNAL(shade, COMSIG_SHADE_TO_CONSTRUCT_TRANSFER, src)
|
||||
cancel_camera()
|
||||
qdel(shell)
|
||||
qdel(shade)
|
||||
@@ -465,13 +456,13 @@
|
||||
if(!isrobot(M))
|
||||
for(var/obj/item/I in M)
|
||||
M.unEquip(I)
|
||||
|
||||
var/target_body = M
|
||||
if(isbrain(M))
|
||||
var/obj/item/organ/internal/brain/brain_obj = M.loc
|
||||
add_held_body(brain_obj)
|
||||
brain_obj.forceMove(src)
|
||||
else
|
||||
add_held_body(M)
|
||||
M.forceMove(src)
|
||||
target_body = M.loc // get the brain organ instead of the brain mob
|
||||
|
||||
S.AddComponent(/datum/component/construct_held_body, target_body)
|
||||
animate_rays = TRUE
|
||||
|
||||
/obj/item/soulstone/proc/get_shade_type()
|
||||
if(purified)
|
||||
|
||||
@@ -46,38 +46,12 @@
|
||||
|
||||
set_light(2, 3, l_color = GET_CULT_DATA(construct_glow, LIGHT_COLOR_BLOOD_MAGIC))
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Destroy()
|
||||
mind?.remove_antag_datum(/datum/antagonist/cultist, silent_removal = TRUE)
|
||||
mind?.remove_antag_datum(/datum/antagonist/wizard/construct, silent_removal = TRUE)
|
||||
remove_held_body()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/death(gibbed)
|
||||
mind?.remove_antag_datum(/datum/antagonist/cultist, silent_removal = TRUE)
|
||||
mind?.remove_antag_datum(/datum/antagonist/wizard/construct, silent_removal = TRUE)
|
||||
if(held_body) // Null check for empty bodies
|
||||
held_body.forceMove(get_turf(src))
|
||||
SSticker.mode?.cult_team?.add_cult_immunity(held_body)
|
||||
if(ismob(held_body)) // Check if the held_body is a mob
|
||||
held_body.key = key
|
||||
else if(istype(held_body, /obj/item/organ/internal/brain)) // Check if the held_body is a brain
|
||||
var/obj/item/organ/internal/brain/brain = held_body
|
||||
if(brain.brainmob) // Check if the brain has a brainmob
|
||||
brain.brainmob.key = key // Set the key to the brainmob
|
||||
brain.brainmob.mind.transfer_to(brain.brainmob) // Transfer the mind to the brainmob
|
||||
held_body.cancel_camera()
|
||||
// we also drop our heldbody from the /construct_held_body component, as well as our cult/wiz construct antag datums
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(src))
|
||||
playsound(src, 'sound/effects/pylon_shatter.ogg', 40, TRUE)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/proc/add_held_body(atom/movable/body)
|
||||
held_body = body
|
||||
RegisterSignal(body, COMSIG_PARENT_QDELETING, PROC_REF(remove_held_body))
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/proc/remove_held_body()
|
||||
SIGNAL_HANDLER
|
||||
held_body = null
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -34,11 +34,6 @@
|
||||
deathmessage = "lets out a contented sigh as their form unwinds."
|
||||
var/holy = FALSE
|
||||
|
||||
/mob/living/simple_animal/shade/Destroy()
|
||||
mind?.remove_antag_datum(/datum/antagonist/cultist, silent_removal = TRUE)
|
||||
mind?.remove_antag_datum(/datum/antagonist/wizard/construct, silent_removal = TRUE)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/shade/attackby(obj/item/O, mob/user) //Marker -Agouri
|
||||
if(istype(O, /obj/item/soulstone))
|
||||
var/obj/item/soulstone/SS = O
|
||||
|
||||
@@ -400,6 +400,7 @@
|
||||
#include "code\datums\components\codeword_hearing.dm"
|
||||
#include "code\datums\components\connect_mob_behalf.dm"
|
||||
#include "code\datums\components\corpse_description.dm"
|
||||
#include "code\datums\components\cult_held_body.dm"
|
||||
#include "code\datums\components\deadchat_control.dm"
|
||||
#include "code\datums\components\decal.dm"
|
||||
#include "code\datums\components\defibrillator.dm"
|
||||
|
||||
Reference in New Issue
Block a user