From 21eb698c2300564bd4b4cd42f2a7f468282006fe Mon Sep 17 00:00:00 2001 From: VerySoft Date: Fri, 18 Feb 2022 06:48:55 -0500 Subject: [PATCH] Buffs Morphs Allows morphs a couple of neat new things Resting: While resting and morphed, morphs do not 'look strange'. If a morph stops resting while someone is on their turf, they may instantly, stealthily eat the person. (If prefs allow) Take over prey: A morph may choose to attempt to completely take over their prey's form, actually assuming control of their prey's body. This interaction allows the morph to pick any non-simple mob in any of their bellies that has a ckey. The morph gets a confirmation prompt, and the prey gets a double confirmation prompt. The prompt can only appear if the prey has the preference for allowing body impersonation enabled. For lack of an easy better option, this interaction is undone by way of the transformed morph ejecting the prey from their belly. Instead of actually ejecting the prey, it will restore both to their original conditions. (And THEN you can eject them if that's what you want to do) There is text explaining this to the morph when they succeed at the takeover. OOC escape does also work with this, despite its complicated interaction. OOC escape returns both parties to their original bodies and undoes the effects of the interaction. --- .../simple_mob/subtypes/vore/morph/morph.dm | 108 +++++++++++++++++- code/modules/vore/eating/belly_obj_vr.dm | 4 + code/modules/vore/eating/living_vr.dm | 6 +- 3 files changed, 116 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm index 329b747f971..c20182fe58e 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm @@ -42,6 +42,8 @@ showvoreprefs = 0 vore_active = 1 + vore_default_mode = DM_HOLD + var/morphed = FALSE var/tooltip = TRUE @@ -50,6 +52,8 @@ var/atom/movable/form = null var/morph_time = 0 var/our_size_multiplier = 1 + var/original_ckey + var/prey_ckey var/static/list/blacklist_typecache = typecacheof(list( /obj/screen, /obj/singularity, @@ -58,6 +62,7 @@ /mob/living/simple_mob/vore/hostile/morph/Initialize() verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/simple_mob/vore/hostile/morph/proc/take_over_prey return ..() /mob/living/simple_mob/vore/hostile/morph/Destroy() @@ -70,7 +75,7 @@ /mob/living/simple_mob/vore/hostile/morph/examine(mob/user) if(morphed) . = form.examine(user) - if(get_dist(user, src) <= 3) + if(get_dist(user, src) <= 3 && !resting) . += "[form] doesn't look quite right..." else . = ..() @@ -193,6 +198,22 @@ var/temp_state = icon_state ..() icon_state = temp_state + //Stolen from protean blobs, ambush noms from resting! Doesn't hide you any better, but makes noms sneakier. + if(resting) + plane = ABOVE_OBJ_PLANE + to_chat(src,"Your form settles in, appearing more 'normal'... laying in wait.") + else + plane = MOB_PLANE + to_chat(src,"Your form quivers back to life, allowing you to move again!") + if(can_be_drop_pred) //Toggleable in vore panel + var/list/potentials = living_mobs(0) + if(potentials.len) + var/mob/living/target = pick(potentials) + if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected) + if(target.buckled) + target.buckled.unbuckle_mob(target, force = TRUE) + target.forceMove(vore_selected) + to_chat(target,"\The [src] quickly engulfs you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!") else ..() @@ -215,3 +236,88 @@ src.transform = M else ..() + +/mob/living/simple_mob/vore/hostile/morph/proc/take_over_prey() + set name = "Take Over Prey" + set category = "Abilities" + set desc = "Take command of your prey's body." + if(morphed) + to_chat(src, "You must restore to your original form first!") + return + var/list/possible_mobs = list() + for(var/obj/belly/B in src.vore_organs) + for(var/mob/living/carbon/human/H in B) + if(ishuman(H) && H.ckey) + possible_mobs += H + else + continue + var/mob/living/carbon/human/M + var/input = tgui_input_list(src, "Select a mob to take over:", "Take Over Prey", possible_mobs) + if(!input) + return + M = input + if(!M) + return + if(M.resleeve_lock && ckey != M.resleeve_lock) + to_chat(src, "\The [M] cannot be impersonated!") + return + if(tgui_alert(src, "You selected [M] to attempt to take over. Are you sure?", "Take Over Prey",list("No","Yes")) == "Yes") + log_admin("[key_name_admin(src)] offered [M] to swap bodies as a morph.") + if(tgui_alert(M, "\The [src] has elected to attempt to take over your body and control you. Is this something you will allow to happen?", "Allow Morph To Take Over",list("No","Yes")) == "Yes") + if(tgui_alert(M, "Are you sure? The only way to undo this on your own is to OOC Escape.", "Allow Morph To Take Over",list("No","Yes")) == "Yes") + original_ckey = ckey + log_and_message_admins("[key_name_admin(src)] has swapped bodies with [key_name_admin(M)] as a morph at [get_area(src)] - [COORD(src)].") + new /mob/living/simple_mob/vore/hostile/morph/dominated_prey(M.vore_selected, M.ckey, src, M) + else + to_chat(src, "\The [M] declined your request for control.") + else + to_chat(src, "\The [M] declined your request for control.") + +/mob/living/simple_mob/vore/hostile/morph/dominated_prey + name = "subservient node" + color = "#171717" + digestable = 0 + devourable = 0 + var/mob/living/simple_mob/vore/hostile/morph/parent_morph + var/mob/living/carbon/human/prey_body + + +/mob/living/simple_mob/vore/hostile/morph/dominated_prey/New(loc, pckey, parent, prey) + . = ..() + if(pckey) + prey_ckey = pckey + parent_morph = parent + prey_body = prey + prey_body.forceMove(get_turf(parent_morph)) + ckey = prey_ckey + prey_body.ckey = parent_morph.original_ckey + parent_morph.forceMove(src) + name = "[prey_body.name]" + to_chat(prey_body, "You have completely assumed the form of [prey_body]. Your form is now unable to change anymore until you restore control back to them. You can do this by 'ejecting' them from your [prey_body.vore_selected]. This will not actually release them from your body in this state, but instead return control to them, and restore you to your original form.") + else + qdel(src) + +/mob/living/simple_mob/vore/hostile/morph/dominated_prey/death(gibbed) + . = ..() + undo_prey_takeover(FALSE) + + +/mob/living/simple_mob/vore/hostile/morph/dominated_prey/Destroy() + . = ..() + parent_morph = null + prey_body = null + +/mob/living/simple_mob/vore/hostile/morph/dominated_prey/proc/undo_prey_takeover(ooc_escape) + if(ooc_escape) + prey_body.forceMove(get_turf(src)) + parent_morph.forceMove(get_turf(src)) + parent_morph.ckey = parent_morph.original_ckey + prey_body.ckey = prey_ckey + log_and_message_admins("[key_name_admin(prey_body)] used the OOC escape button to get out of [key_name_admin(parent_morph)]. They have been returned to their original bodies. [ADMIN_FLW(src)]") + else + parent_morph.forceMove(get_turf(prey_body)) + parent_morph.ckey = parent_morph.original_ckey + prey_body.ckey = prey_ckey + prey_body.forceMove(parent_morph.vore_selected) + log_and_message_admins("[key_name_admin(prey_body)] and [key_name_admin(parent_morph)] have been returned to their original bodies. [get_area(src)] - [COORD(src)].") + qdel(src) diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm index f96af5c204c..10d1dd44f32 100644 --- a/code/modules/vore/eating/belly_obj_vr.dm +++ b/code/modules/vore/eating/belly_obj_vr.dm @@ -354,6 +354,10 @@ if (!(M in contents)) return 0 // They weren't in this belly anyway + if(istype(M, /mob/living/simple_mob/vore/hostile/morph/dominated_prey)) + var/mob/living/simple_mob/vore/hostile/morph/dominated_prey/p = M + p.undo_prey_takeover(FALSE) + return 0 for(var/mob/living/L in M.contents) L.muffled = 0 for(var/obj/item/weapon/holder/H in M.contents) diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index ffaaa5ec09c..7a9cab7a2b6 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -405,6 +405,11 @@ //You're in a belly! if(isbelly(loc)) + //You've been taken over by a morph + if(istype(src, /mob/living/simple_mob/vore/hostile/morph/dominated_prey)) + var/mob/living/simple_mob/vore/hostile/morph/dominated_prey/s = src + s.undo_prey_takeover(TRUE) + return var/obj/belly/B = loc var/confirm = tgui_alert(src, "You're in a mob. Don't use this as a trick to get out of hostile animals. This is for escaping from preference-breaking and if you're otherwise unable to escape from endo (pred AFK for a long time).", "Confirmation", list("Okay", "Cancel")) if(confirm != "Okay" || loc != B) @@ -445,7 +450,6 @@ crystal.bound_mob = null crystal.bound_mob = capture_crystal = 0 log_and_message_admins("[key_name(src)] used the OOC escape button to get out of [crystal] owned by [crystal.owner]. [ADMIN_FLW(src)]") - //Don't appear to be in a vore situation else to_chat(src,"You aren't inside anyone, though, is the thing.")