|
|
|
@@ -139,7 +139,7 @@
|
|
|
|
|
hot_potato(user)
|
|
|
|
|
return
|
|
|
|
|
log_combat(user, M, "captured [M.name]'s soul", src)
|
|
|
|
|
transfer_soul("VICTIM", M, user)
|
|
|
|
|
capture_soul(M, user)
|
|
|
|
|
|
|
|
|
|
///////////////////Options for using captured souls///////////////////////////////////////
|
|
|
|
|
|
|
|
|
@@ -234,88 +234,72 @@
|
|
|
|
|
if(SS.theme == THEME_HOLY && IS_CULTIST(user))
|
|
|
|
|
SS.hot_potato(user)
|
|
|
|
|
return
|
|
|
|
|
SS.transfer_soul("CONSTRUCT",src,user)
|
|
|
|
|
SS.was_used()
|
|
|
|
|
SS.transfer_to_construct(src, user)
|
|
|
|
|
else
|
|
|
|
|
return ..()
|
|
|
|
|
|
|
|
|
|
////////////////////////////Proc for moving soul in and out off stone//////////////////////////////////////
|
|
|
|
|
/// Procs for moving soul in and out off stone
|
|
|
|
|
|
|
|
|
|
/// transfer the mind of a carbon mob (which is then dusted) into a shade mob inside src. If forced, sacrifical and stat checks are skipped.
|
|
|
|
|
/obj/item/soulstone/proc/capture_soul(mob/living/carbon/victim, mob/user, forced = FALSE)
|
|
|
|
|
if(!iscarbon(victim)) //TODO: Add sacrifice stoning for non-organics, just because you have no body doesnt mean you dont have a soul
|
|
|
|
|
return FALSE
|
|
|
|
|
if(!forced)
|
|
|
|
|
var/datum/antagonist/cult/C = user?.mind?.has_antag_datum(/datum/antagonist/cult,TRUE)
|
|
|
|
|
if(C?.cult_team.is_sacrifice_target(victim.mind))
|
|
|
|
|
to_chat(user, span_cult("<b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\""))
|
|
|
|
|
return FALSE
|
|
|
|
|
if(contents.len)
|
|
|
|
|
return FALSE
|
|
|
|
|
if(!forced && (grab_sleeping ? victim.stat == CONSCIOUS : victim.stat != DEAD))
|
|
|
|
|
to_chat(user, "[span_userdanger("Capture failed!")]: Kill or maim the victim first!")
|
|
|
|
|
return FALSE
|
|
|
|
|
if(victim.client)
|
|
|
|
|
victim.unequip_everything()
|
|
|
|
|
init_shade(victim, user)
|
|
|
|
|
return TRUE
|
|
|
|
|
else
|
|
|
|
|
to_chat(user, "[span_userdanger("Capture failed!")]: The soul has already fled its mortal frame. You attempt to bring it back...")
|
|
|
|
|
return getCultGhost(victim,user)
|
|
|
|
|
|
|
|
|
|
/obj/item/soulstone/proc/transfer_soul(choice as text, target, mob/user)
|
|
|
|
|
switch(choice)
|
|
|
|
|
if("FORCE")
|
|
|
|
|
if(!iscarbon(target)) //TODO: Add sacrifice stoning for non-organics, just because you have no body doesnt mean you dont have a soul
|
|
|
|
|
return FALSE
|
|
|
|
|
if(contents.len)
|
|
|
|
|
return FALSE
|
|
|
|
|
var/mob/living/carbon/T = target
|
|
|
|
|
if(T.client != null)
|
|
|
|
|
for(var/obj/item/W in T)
|
|
|
|
|
T.dropItemToGround(W)
|
|
|
|
|
init_shade(T, user)
|
|
|
|
|
return TRUE
|
|
|
|
|
else
|
|
|
|
|
to_chat(user, "[span_userdanger("Capture failed!")]: The soul has already fled its mortal frame. You attempt to bring it back...")
|
|
|
|
|
return getCultGhost(T,user)
|
|
|
|
|
///captures a shade that was previously released from a soulstone.
|
|
|
|
|
/obj/item/soulstone/proc/capture_shade(mob/living/simple_animal/shade/shade, mob/user)
|
|
|
|
|
if(contents.len)
|
|
|
|
|
to_chat(user, "[span_userdanger("Capture failed!")]: [src] is full! Free an existing soul to make room.")
|
|
|
|
|
return FALSE
|
|
|
|
|
shade.AddComponent(/datum/component/soulstoned, src)
|
|
|
|
|
if(theme == THEME_HOLY)
|
|
|
|
|
icon_state = "purified_soulstone2"
|
|
|
|
|
shade.mind?.remove_antag_datum(/datum/antagonist/cult)
|
|
|
|
|
if(theme == THEME_WIZARD)
|
|
|
|
|
icon_state = "mystic_soulstone2"
|
|
|
|
|
if(theme == THEME_CULT)
|
|
|
|
|
icon_state = "soulstone2"
|
|
|
|
|
name = "soulstone: Shade of [shade.real_name]"
|
|
|
|
|
to_chat(shade, span_notice("Your soul has been captured by [src]. Its arcane energies are reknitting your ethereal form."))
|
|
|
|
|
if(user != shade)
|
|
|
|
|
to_chat(user, "[span_info("<b>Capture successful!</b>:")] [shade.real_name]'s soul has been captured and stored within [src].")
|
|
|
|
|
return TRUE
|
|
|
|
|
|
|
|
|
|
if("VICTIM")
|
|
|
|
|
var/mob/living/carbon/human/T = target
|
|
|
|
|
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
|
|
|
|
if(C?.cult_team.is_sacrifice_target(T.mind))
|
|
|
|
|
to_chat(user, span_cult("<b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\""))
|
|
|
|
|
return FALSE
|
|
|
|
|
if(contents.len)
|
|
|
|
|
to_chat(user, "[span_userdanger("Capture failed!")]: [src] is full! Free an existing soul to make room.")
|
|
|
|
|
else
|
|
|
|
|
if((grab_sleeping && T.stat != CONSCIOUS) || (!grab_sleeping && T.stat == DEAD))
|
|
|
|
|
if(T.client == null)
|
|
|
|
|
to_chat(user, "[span_userdanger("Capture failed!")]: The soul has already fled its mortal frame. You attempt to bring it back...")
|
|
|
|
|
getCultGhost(T,user)
|
|
|
|
|
else
|
|
|
|
|
for(var/obj/item/W in T)
|
|
|
|
|
T.dropItemToGround(W)
|
|
|
|
|
init_shade(T, user, message_user = 1)
|
|
|
|
|
qdel(T)
|
|
|
|
|
else
|
|
|
|
|
to_chat(user, "[span_userdanger("Capture failed!")]: Kill or maim the victim first!")
|
|
|
|
|
///transfer the mind of the shade to a construct mob selected by the user, then deletes both the shade and src.
|
|
|
|
|
/obj/item/soulstone/proc/transfer_to_construct(obj/structure/constructshell/shell, mob/user)
|
|
|
|
|
var/mob/living/simple_animal/shade/shade = locate() in src
|
|
|
|
|
if(!shade)
|
|
|
|
|
to_chat(user, "[span_userdanger("Creation failed!")]: [src] is empty! Go kill someone!")
|
|
|
|
|
return FALSE
|
|
|
|
|
var/construct_class = show_radial_menu(user, src, GLOB.construct_radial_images, custom_check = CALLBACK(src, .proc/check_menu, user, shell), require_near = TRUE, tooltips = TRUE)
|
|
|
|
|
if(!shell || !construct_class)
|
|
|
|
|
return FALSE
|
|
|
|
|
make_new_construct_from_class(construct_class, theme, shade, user, FALSE, shell.loc)
|
|
|
|
|
shade.mind?.remove_antag_datum(/datum/antagonist/cult)
|
|
|
|
|
qdel(shell)
|
|
|
|
|
qdel(src)
|
|
|
|
|
return TRUE
|
|
|
|
|
|
|
|
|
|
if("SHADE")
|
|
|
|
|
var/mob/living/simple_animal/shade/T = target
|
|
|
|
|
if(contents.len)
|
|
|
|
|
to_chat(user, "[span_userdanger("Capture failed!")]: [src] is full! Free an existing soul to make room.")
|
|
|
|
|
else
|
|
|
|
|
T.AddComponent(/datum/component/soulstoned, src)
|
|
|
|
|
if(theme == THEME_HOLY)
|
|
|
|
|
icon_state = "purified_soulstone2"
|
|
|
|
|
T.mind?.remove_antag_datum(/datum/antagonist/cult)
|
|
|
|
|
if(theme == THEME_WIZARD)
|
|
|
|
|
icon_state = "mystic_soulstone2"
|
|
|
|
|
if(theme == THEME_CULT)
|
|
|
|
|
icon_state = "soulstone2"
|
|
|
|
|
name = "soulstone: Shade of [T.real_name]"
|
|
|
|
|
to_chat(T, span_notice("Your soul has been captured by [src]. Its arcane energies are reknitting your ethereal form."))
|
|
|
|
|
if(user != T)
|
|
|
|
|
to_chat(user, "[span_info("<b>Capture successful!</b>:")] [T.real_name]'s soul has been captured and stored within [src].")
|
|
|
|
|
|
|
|
|
|
if("CONSTRUCT")
|
|
|
|
|
var/obj/structure/constructshell/T = target
|
|
|
|
|
var/mob/living/simple_animal/shade/A = locate() in src
|
|
|
|
|
if(A)
|
|
|
|
|
var/construct_class = show_radial_menu(user, src, GLOB.construct_radial_images, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
|
|
|
|
|
if(!T || !T.loc)
|
|
|
|
|
return
|
|
|
|
|
make_new_construct_from_class(construct_class, theme, A, user, FALSE, T.loc)
|
|
|
|
|
A.mind?.remove_antag_datum(/datum/antagonist/cult)
|
|
|
|
|
qdel(T)
|
|
|
|
|
qdel(src)
|
|
|
|
|
else
|
|
|
|
|
to_chat(user, "[span_userdanger("Creation failed!")]: [src] is empty! Go kill someone!")
|
|
|
|
|
|
|
|
|
|
/obj/item/soulstone/proc/check_menu(mob/user)
|
|
|
|
|
/obj/item/soulstone/proc/check_menu(mob/user, obj/structure/constructshell/shell)
|
|
|
|
|
if(!istype(user))
|
|
|
|
|
return FALSE
|
|
|
|
|
if(user.incapacitated() || !user.Adjacent(src))
|
|
|
|
|
if(user.incapacitated() || !user.is_holding(src) || !user.CanReach(shell, src))
|
|
|
|
|
return FALSE
|
|
|
|
|
return TRUE
|
|
|
|
|
|
|
|
|
@@ -422,24 +406,23 @@
|
|
|
|
|
to_chat(user, "[span_info("<b>Capture successful!</b>:")] [dusted_victim.real_name]'s soul has been ripped from [dusted_victim.p_their()] body and stored within [src].")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/user)
|
|
|
|
|
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/victim, mob/user)
|
|
|
|
|
var/mob/dead/observer/chosen_ghost
|
|
|
|
|
|
|
|
|
|
chosen_ghost = T.get_ghost(TRUE,TRUE) //Try to grab original owner's ghost first
|
|
|
|
|
chosen_ghost = victim.get_ghost(TRUE,TRUE) //Try to grab original owner's ghost first
|
|
|
|
|
|
|
|
|
|
if(!chosen_ghost || !chosen_ghost.client) //Failing that, we grab a ghosts
|
|
|
|
|
var/list/consenting_candidates = pollGhostCandidates("Would you like to play as a Shade?", "Cultist", ROLE_CULTIST, 50, POLL_IGNORE_SHADE)
|
|
|
|
|
if(consenting_candidates.len)
|
|
|
|
|
chosen_ghost = pick(consenting_candidates)
|
|
|
|
|
if(!T)
|
|
|
|
|
if(!victim || user.incapacitated() || !user.is_holding(src) || !user.CanReach(victim, src))
|
|
|
|
|
return FALSE
|
|
|
|
|
if(!chosen_ghost || !chosen_ghost.client)
|
|
|
|
|
to_chat(user, span_danger("There were no spirits willing to become a shade."))
|
|
|
|
|
return FALSE
|
|
|
|
|
if(contents.len) //If they used the soulstone on someone else in the meantime
|
|
|
|
|
return FALSE
|
|
|
|
|
for(var/obj/item/W in T)
|
|
|
|
|
T.dropItemToGround(W)
|
|
|
|
|
init_shade(T, user , shade_controller = chosen_ghost)
|
|
|
|
|
qdel(T)
|
|
|
|
|
victim.unequip_everything()
|
|
|
|
|
init_shade(victim, user, shade_controller = chosen_ghost)
|
|
|
|
|
qdel(victim)
|
|
|
|
|
return TRUE
|
|
|
|
|