mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 16:47:13 +01:00
Knit Flesh can insert organs into carbons (#91817)
Co-authored-by: Lucy <lucy@absolucy.moe>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
name = "Knit Flesh"
|
||||
desc = "A touch spell that allows you to either harvest or restore flesh of target. \
|
||||
Left-clicking will extract the organs of a victim without needing to complete surgery or disembowel. \
|
||||
You can also pick up a loose organ and insert it into your vitcim. \
|
||||
Right-clicking, if done on summons or minions, will restore health. Can also be used to heal damaged organs."
|
||||
background_icon_state = "bg_heretic"
|
||||
overlay_icon_state = "bg_heretic_border"
|
||||
@@ -24,22 +25,37 @@
|
||||
var/monster_brute_healing = 10
|
||||
/// If used on a heretic mob, how much burn do we heal
|
||||
var/monster_burn_healing = 5
|
||||
/// The organ being held in the touch attack - which will be implanted into mobs.
|
||||
var/obj/item/organ/held_organ
|
||||
/// Can we implant cybernetic organs?
|
||||
var/allow_cyber_organs = FALSE
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/is_valid_target(atom/cast_on)
|
||||
return isliving(cast_on) || isorgan(cast_on)
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/cast_on_hand_hit(obj/item/melee/touch_attack/hand, atom/victim, mob/living/carbon/caster)
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/remove_hand(mob/living/hand_owner, reset_cooldown_after)
|
||||
var/obj/item/organ/the_organ = held_organ
|
||||
if(the_organ)
|
||||
unregister_held_organ(the_organ)
|
||||
the_organ.forceMove(hand_owner.drop_location())
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/cast_on_hand_hit(obj/item/melee/touch_attack/flesh_surgery/hand, atom/victim, mob/living/carbon/caster)
|
||||
if(isorgan(victim))
|
||||
return heal_organ(hand, victim, caster)
|
||||
grab_organ(hand, victim, caster)
|
||||
return FALSE
|
||||
|
||||
if(isliving(victim))
|
||||
if(held_organ)
|
||||
return insert_organ_into_mob(held_organ, hand, victim, caster)
|
||||
return steal_organ_from_mob(hand, victim, caster)
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/cast_on_secondary_hand_hit(obj/item/melee/touch_attack/hand, atom/victim, mob/living/carbon/caster)
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/cast_on_secondary_hand_hit(obj/item/melee/touch_attack/flesh_surgery/hand, atom/victim, mob/living/carbon/caster)
|
||||
if(isorgan(victim))
|
||||
return SECONDARY_ATTACK_CALL_NORMAL
|
||||
return heal_organ(hand, victim, caster)
|
||||
|
||||
if(isliving(victim))
|
||||
var/mob/living/mob_victim = victim
|
||||
@@ -54,11 +70,17 @@
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/register_hand_signals()
|
||||
. = ..()
|
||||
RegisterSignal(attached_hand, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET, PROC_REF(add_item_context))
|
||||
RegisterSignal(attached_hand, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(hand_interacted_with))
|
||||
attached_hand.item_flags |= ITEM_HAS_CONTEXTUAL_SCREENTIPS
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/unregister_hand_signals()
|
||||
. = ..()
|
||||
UnregisterSignal(attached_hand, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET)
|
||||
UnregisterSignal(attached_hand, list(COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET, COMSIG_ATOM_ITEM_INTERACTION))
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/hand_interacted_with(obj/item/melee/touch_attack/source, mob/living/user, obj/item/tool)
|
||||
SIGNAL_HANDLER
|
||||
if(isorgan(tool))
|
||||
return grab_organ(source, tool, user)
|
||||
|
||||
/// Signal proc for [COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET] to add some context to the hand.
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/add_item_context(obj/item/melee/touch_attack/source, list/context, atom/victim, mob/living/user)
|
||||
@@ -70,7 +92,10 @@
|
||||
var/mob/living/mob_victim = victim
|
||||
|
||||
if(iscarbon(mob_victim))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Extract organ"
|
||||
if(held_organ)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Insert organ"
|
||||
else
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Extract organ"
|
||||
. = CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
if(HAS_TRAIT(mob_victim, TRAIT_HERETIC_SUMMON))
|
||||
@@ -78,13 +103,56 @@
|
||||
. = CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
else if(isorgan(victim))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Heal organ"
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Pick up organ"
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Heal organ"
|
||||
. = CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
return .
|
||||
|
||||
/// If cast on an organ, we'll restore its health and even un-fail it.
|
||||
/// If cast on an organ with left-click, we'll try to grab it.
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/grab_organ(obj/item/melee/touch_attack/hand, obj/item/organ/to_grab, mob/living/carbon/caster)
|
||||
if(held_organ)
|
||||
hand.balloon_alert(caster, "already holding organ!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
if(to_grab.organ_flags & ORGAN_ROBOTIC && !allow_cyber_organs)
|
||||
hand.balloon_alert(caster, "cybernetic organs not allowed!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
if(!caster.transferItemToLoc(to_grab, hand))
|
||||
hand.balloon_alert(caster, "couldn't grab organ!")
|
||||
return ITEM_INTERACT_FAILURE
|
||||
register_held_organ(to_grab, hand)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/register_held_organ(obj/item/organ/new_held_organ, obj/item/melee/touch_attack/hand)
|
||||
hand.vis_contents += new_held_organ
|
||||
held_organ = new_held_organ
|
||||
new_held_organ.flags_1 |= IS_ONTOP_1
|
||||
new_held_organ.vis_flags |= VIS_INHERIT_PLANE
|
||||
RegisterSignal(new_held_organ, COMSIG_MOVABLE_MOVED, PROC_REF(unregister_held_organ))
|
||||
RegisterSignal(new_held_organ, COMSIG_QDELETING, PROC_REF(unregister_held_organ))
|
||||
// We gotta offset ourselves via pixel_w/z, so we don't end up z fighting with the touch attack
|
||||
new_held_organ.pixel_w = new_held_organ.pixel_x
|
||||
new_held_organ.pixel_z = new_held_organ.pixel_y
|
||||
new_held_organ.pixel_x = 0
|
||||
new_held_organ.pixel_y = 0
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/unregister_held_organ(obj/item/organ/removed_organ)
|
||||
LAZYREMOVE(attached_hand.vis_contents, removed_organ)
|
||||
held_organ = null
|
||||
removed_organ.flags_1 &= ~IS_ONTOP_1
|
||||
removed_organ.vis_flags &= ~VIS_INHERIT_PLANE
|
||||
UnregisterSignal(removed_organ, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING))
|
||||
// Reset item offsets
|
||||
removed_organ.pixel_x = removed_organ.pixel_w
|
||||
removed_organ.pixel_y = removed_organ.pixel_z
|
||||
removed_organ.pixel_w = 0
|
||||
removed_organ.pixel_z = 0
|
||||
|
||||
/// If cast on an organ with right-click, we'll restore its health and even un-fail it.
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/heal_organ(obj/item/melee/touch_attack/hand, obj/item/organ/to_heal, mob/living/carbon/caster)
|
||||
if(held_organ)
|
||||
hand.balloon_alert(caster, "drop held organ first!")
|
||||
return FALSE
|
||||
if(to_heal.damage == 0)
|
||||
to_heal.balloon_alert(caster, "already in good condition!")
|
||||
return FALSE
|
||||
@@ -214,16 +282,109 @@
|
||||
addtimer(CALLBACK(caster, TYPE_PROC_REF(/mob, put_in_hands), picked_organ), 0.1 SECONDS)
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/insert_organ_into_mob(obj/item/organ/inserted_organ, obj/item/melee/touch_attack/flesh_surgery/hand, mob/living/carbon/victim, mob/living/carbon/caster)
|
||||
if(!istype(victim))
|
||||
hand.balloon_alert(caster, "no organs!")
|
||||
return FALSE
|
||||
|
||||
var/zone_organ_goes_in = inserted_organ.zone
|
||||
if(!victim.get_bodypart(deprecise_zone(zone_organ_goes_in)))
|
||||
hand.balloon_alert(caster, "nowhere for organ to go!")
|
||||
return FALSE
|
||||
|
||||
var/slot_organ_goes_in = inserted_organ.slot
|
||||
var/obj/item/organ/organ_victim_already_has = victim.get_organ_slot(slot_organ_goes_in)
|
||||
if(organ_victim_already_has?.organ_flags & ORGAN_VITAL|ORGAN_UNREMOVABLE)
|
||||
hand.balloon_alert(caster, "can't replace organ!")
|
||||
return FALSE
|
||||
|
||||
var/time_it_takes
|
||||
var/using_on_self = victim == caster
|
||||
var/replacing_with_failing = !(organ_victim_already_has?.organ_flags & ORGAN_FAILING) && inserted_organ.organ_flags & ORGAN_FAILING
|
||||
if(using_on_self)
|
||||
time_it_takes = inserted_organ.w_class * 2 SECONDS
|
||||
else if(victim.stat == DEAD)
|
||||
time_it_takes = inserted_organ.w_class * 1 SECONDS
|
||||
else if(replacing_with_failing)
|
||||
time_it_takes = 15 SECONDS
|
||||
else
|
||||
time_it_takes = inserted_organ.w_class * 3 SECONDS
|
||||
|
||||
if(using_on_self && replacing_with_failing)
|
||||
var/are_you_sure = tgui_alert(caster,
|
||||
"Are you sure you want to replace your [organ_victim_already_has.name] with a non-functional [inserted_organ.name]?",
|
||||
"Are you sure?",
|
||||
list("Yes", "No"))
|
||||
if(!are_you_sure)
|
||||
return FALSE
|
||||
|
||||
if(!insertion_checks(inserted_organ, hand, victim, caster))
|
||||
return FALSE
|
||||
|
||||
if(using_on_self)
|
||||
caster.visible_message(
|
||||
span_danger("[caster]'s hand glows a brilliant red as [caster.p_they()] begin[caster.p_es()] forcing [inserted_organ] into [caster.p_their()] [zone_organ_goes_in]!!"),
|
||||
span_userdanger("You begin forcing [inserted_organ] into your [zone_organ_goes_in]!")
|
||||
)
|
||||
else
|
||||
caster.visible_message(
|
||||
span_danger("[caster]'s hand glows a brilliant red as [caster.p_they()] begin[caster.p_es()] forcing [inserted_organ] into [victim]'s [zone_organ_goes_in]!!"),
|
||||
span_notice("You begin forcing [inserted_organ] into [victim]'s [zone_organ_goes_in].")
|
||||
)
|
||||
|
||||
victim.balloon_alert(caster, "inserting [inserted_organ]...")
|
||||
playsound(victim, 'sound/items/weapons/slice.ogg', 50, TRUE)
|
||||
victim.add_atom_colour(COLOR_DARK_RED, TEMPORARY_COLOUR_PRIORITY)
|
||||
if(!do_after(caster, time_it_takes, victim, extra_checks = CALLBACK(src, PROC_REF(insertion_checks), inserted_organ, hand, victim, caster)))
|
||||
victim.balloon_alert(caster, "interrupted!")
|
||||
victim.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_DARK_RED)
|
||||
return FALSE
|
||||
|
||||
organ_victim_already_has = victim.get_organ_slot(slot_organ_goes_in) // This COULD have changed over the course of the do_after
|
||||
|
||||
if(using_on_self)
|
||||
caster.visible_message(
|
||||
span_danger("[caster] crams [inserted_organ] into [caster.p_their()] own [zone_organ_goes_in][organ_victim_already_has ? ", forcing out [caster.p_their()] [organ_victim_already_has.name]": ""]!"),
|
||||
span_userdanger("You finish inserting [inserted_organ] into your [zone_organ_goes_in][organ_victim_already_has ? ", forcing out your [organ_victim_already_has]" : ""]!")
|
||||
)
|
||||
else
|
||||
caster.visible_message(
|
||||
span_danger("[caster] crams [inserted_organ] into [victim]'s [zone_organ_goes_in][organ_victim_already_has ? ", forcing out [victim.p_their()] [organ_victim_already_has.name]": ""]!"),
|
||||
span_notice("You finish inserting [inserted_organ] into [victim]'s [zone_organ_goes_in][organ_victim_already_has ? ", forcing out [victim.p_their()] [organ_victim_already_has.name]": ""].")
|
||||
)
|
||||
|
||||
unregister_held_organ(inserted_organ)
|
||||
inserted_organ.Insert(victim)
|
||||
victim.balloon_alert(caster, "[inserted_organ] inserted")
|
||||
victim.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_DARK_RED)
|
||||
playsound(victim, 'sound/effects/dismember.ogg', 50, TRUE)
|
||||
if(victim.stat == CONSCIOUS)
|
||||
victim.emote("scream")
|
||||
if(!using_on_self)
|
||||
victim.adjust_timed_status_effect(15 SECONDS, /datum/status_effect/speech/slurring/heretic)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Extra checks ran while we're extracting an organ to make sure we can continue to do.
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/extraction_checks(obj/item/organ/picked_organ, obj/item/melee/touch_attack/hand, mob/living/carbon/victim, mob/living/carbon/caster)
|
||||
if(QDELETED(src) || QDELETED(hand) || QDELETED(picked_organ) || QDELETED(victim) || !IsAvailable())
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/extraction_checks(obj/item/organ/picked_organ, obj/item/melee/touch_attack/flesh_surgery/hand, mob/living/carbon/victim, mob/living/carbon/caster)
|
||||
if(QDELETED(src) || QDELETED(hand) || QDELETED(picked_organ) || QDELETED(victim) || held_organ || !IsAvailable())
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Extra checks ran while we're healing something (organ, mob).
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/heal_checks(obj/item/melee/touch_attack/hand, atom/healing, mob/living/carbon/caster)
|
||||
if(QDELETED(src) || QDELETED(hand) || QDELETED(healing) || !IsAvailable())
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/heal_checks(obj/item/melee/touch_attack/flesh_surgery/hand, atom/healing, mob/living/carbon/caster)
|
||||
if(QDELETED(src) || QDELETED(hand) || QDELETED(healing) || held_organ || !IsAvailable())
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Extra checks ran while we're inserting an organ.
|
||||
/datum/action/cooldown/spell/touch/flesh_surgery/proc/insertion_checks(obj/item/organ/inserted_organ, obj/item/melee/touch_attack/flesh_surgery/hand, mob/living/carbon/victim, mob/living/carbon/caster)
|
||||
if(QDELETED(src) || QDELETED(hand) || QDELETED(victim) || QDELETED(inserted_organ) || (held_organ != inserted_organ) || !IsAvailable())
|
||||
return FALSE
|
||||
var/obj/item/organ/organ_victim_already_has = victim.get_organ_slot(inserted_organ.slot)
|
||||
if(organ_victim_already_has?.organ_flags & ORGAN_VITAL|ORGAN_UNREMOVABLE)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
Reference in New Issue
Block a user