diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm b/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm
index f2b233cccf5..fd040e64dd9 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm
@@ -16,10 +16,9 @@
spawn_flags = SPECIES_CAN_JOIN
wikilink="https://wiki.vore-station.net/Promethean"
genders = list(MALE, FEMALE, PLURAL, NEUTER)
-
color_mult = 1
mob_size = MOB_MEDIUM //As of writing, original was MOB_SMALL - Allows normal swapping
-
+ //var/mob/living/simple_mob/slime/promethean/stored_blob = null
appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | RADIATION_GLOWS | HAS_UNDERWEAR
inherent_verbs = list(
@@ -32,6 +31,48 @@
/mob/living/carbon/human/proc/shapeshifter_select_wings,
/mob/living/carbon/human/proc/shapeshifter_select_tail,
/mob/living/carbon/human/proc/shapeshifter_select_ears,
+ /mob/living/carbon/human/proc/prommie_blobform,
/mob/living/proc/set_size,
/mob/living/carbon/human/proc/promethean_select_opaqueness,
)
+
+/mob/living/carbon/human/proc/prommie_blobform()
+ set name = "Toggle Blobform"
+ set desc = "Switch between amorphous and humanoid forms."
+ set category = "Abilities"
+ set hidden = FALSE
+
+ var/atom/movable/to_locate = temporary_form || src
+ if(!isturf(to_locate.loc))
+ to_chat(to_locate,"You need more space to perform this action!")
+ return
+ /*
+ //Blob form
+ if(temporary_form)
+ if(temporary_form.stat)
+ to_chat(temporary_form,"You can only do this while not stunned.")
+ else
+ prommie_outofblob(temporary_form)
+ */
+ //Human form
+ else if(stat || paralysis || stunned || weakened || restrained())
+ to_chat(src,"You can only do this while not stunned.")
+ return
+ else
+ prommie_intoblob()
+
+/datum/species/shapeshifter/promethean/handle_death(var/mob/living/carbon/human/H)
+ if(!H)
+ return // Iono!
+
+ if(H.temporary_form)
+ H.forceMove(H.temporary_form.drop_location())
+ H.ckey = H.temporary_form.ckey
+ QDEL_NULL(H.temporary_form)
+ //else if(H.stored_blob) // Should prevent phantom blobs in the aether. I don't anticipate this being an issue, but if it is just uncomment.
+ // qdel(stored_blob)
+ // stored_blob = null
+
+ spawn(1)
+ if(H)
+ H.gib()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/station/prommie_blob.dm b/code/modules/mob/living/carbon/human/species/station/prommie_blob.dm
new file mode 100644
index 00000000000..5ec9a83bb71
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/station/prommie_blob.dm
@@ -0,0 +1,498 @@
+// Prommies are slimes, lets make them a subtype of slimes.
+/mob/living/simple_mob/slime/promethean
+ name = "Promethean Blob"
+ desc = "A promethean expressing their true form."
+ //ai_holder_type = null
+ color = null // Uses a special icon_state.
+ slime_color = "rainbow"
+ unity = TRUE
+ water_resist = 100 // Lets not kill the prommies
+ cores = 0
+ movement_cooldown = 3
+ //appearance_flags = RADIATION_GLOWS
+ shock_resist = 0 // Lets not be immune to zaps.
+ friendly = list("nuzzles", "glomps", "snuggles", "cuddles", "squishes") // lets be cute :3
+ melee_damage_upper = 0
+ melee_damage_lower = 0
+ player_msg = "You're a little squisher! Your cuteness level has increased tenfold."
+ heat_damage_per_tick = 20 // Hot and cold are bad, but cold is AS bad for prommies as it is for slimes.
+ cold_damage_per_tick = 20
+ //glow_range = 0
+ //glow_intensity = 0
+
+ var/mob/living/carbon/human/humanform
+ var/datum/modifier/healing
+
+ var/obj/prev_left_hand
+ var/obj/prev_right_hand
+ var/human_brute = 0
+ var/human_burn = 0
+ var/is_wide = FALSE
+ var/rad_glow = 0
+
+ var/list/default_emotes = list(
+ /decl/emote/audible/squish,
+ /decl/emote/audible/chirp,
+ /decl/emote/visible/bounce,
+ /decl/emote/visible/jiggle,
+ /decl/emote/visible/lightup,
+ /decl/emote/visible/vibrate,
+ /decl/emote/visible/flip,
+ /decl/emote/visible/spin,
+ /decl/emote/visible/floorspin
+ )
+/mob/living/simple_mob/slime/promethean/Initialize(mapload, null)
+ //verbs -= /mob/living/proc/ventcrawl
+ verbs += /mob/living/simple_mob/slime/promethean/proc/prommie_blobform
+ verbs += /mob/living/proc/set_size
+ verbs += /mob/living/proc/hide
+ verbs += /mob/living/simple_mob/proc/animal_nom
+ verbs += /mob/living/proc/shred_limb
+ verbs += /mob/living/simple_mob/slime/promethean/proc/toggle_expand
+ verbs += /mob/living/simple_mob/slime/promethean/proc/prommie_select_colour
+ verbs += /mob/living/simple_mob/slime/promethean/proc/toggle_shine
+ update_mood()
+ if(rad_glow)
+ rad_glow = CLAMP(rad_glow,0,250)
+ set_light(max(1,min(5,rad_glow/15)), max(1,min(10,rad_glow/25)), color)
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/update_icon()
+ icon_living = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_wide ? "adult" : "baby"][""]"
+ ..()
+
+/mob/living/simple_mob/slime/promethean/Destroy()
+ humanform = null
+ vore_organs = null
+ vore_selected = null
+ set_light(0)
+ return ..()
+
+/mob/living/carbon/human/Destroy()
+ if(stored_blob)
+ stored_blob = null
+ qdel(stored_blob)
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/Stat()
+ ..()
+ if(humanform)
+ humanform.species.Stat(humanform)
+
+/mob/living/simple_mob/slime/promethean/handle_special() // Should disable default slime healing, we'll use nutrition based heals instead.
+ if(rad_glow)
+ rad_glow = CLAMP(rad_glow,0,250)
+ set_light(max(1,min(5,rad_glow/15)), max(1,min(10,rad_glow/25)), color)
+ else
+ set_light(0)
+ update_icon()
+
+ if(!humanform) // If we somehow have a blob with no human, lets just clean up.
+ log_debug("Cleaning up blob with no prommie!")
+ qdel(src)
+ return
+
+//Constructor allows passing the human to sync damages
+/mob/living/simple_mob/slime/promethean/New(var/newloc, var/mob/living/carbon/human/H)
+ ..()
+ if(H)
+ humanform = H
+ updatehealth()
+
+ else
+ qdel(src)
+
+/mob/living/simple_mob/slime/promethean/updatehealth()
+ if(!humanform)
+ return ..()
+
+ //Set the max
+ maxHealth = humanform.getMaxHealth()*2 //HUMANS, and their 'double health', bleh.
+ //Set us to their health, but, human health ignores robolimbs so we do it 'the hard way'
+ human_brute = humanform.getActualBruteLoss()
+ human_burn = humanform.getActualFireLoss()
+ health = maxHealth - humanform.getOxyLoss() - humanform.getToxLoss() - humanform.getCloneLoss() - human_brute - human_burn
+
+ //Alive, becoming dead
+ if((stat < DEAD) && (health <= 0))
+ death()
+
+ //Overhealth
+ if(health > getMaxHealth())
+ health = getMaxHealth()
+
+ //Grab any other interesting values
+ confused = humanform.confused
+ radiation = humanform.radiation
+ paralysis = humanform.paralysis
+
+ //Update our hud if we have one
+ if(healths)
+ if(stat != DEAD)
+ var/heal_per = (health / getMaxHealth()) * 100
+ switch(heal_per)
+ if(100 to INFINITY)
+ healths.icon_state = "health0"
+ if(80 to 100)
+ healths.icon_state = "health1"
+ if(60 to 80)
+ healths.icon_state = "health2"
+ if(40 to 60)
+ healths.icon_state = "health3"
+ if(20 to 40)
+ healths.icon_state = "health4"
+ if(0 to 20)
+ healths.icon_state = "health5"
+ else
+ healths.icon_state = "health6"
+ else
+ healths.icon_state = "health7"
+
+// All the damage and such to the blob translates to the human
+/mob/living/simple_mob/slime/promethean/apply_effect(var/effect = 0, var/effecttype = STUN, var/blocked = 0, var/check_protection = 1)
+ if(humanform)
+ return humanform.apply_effect(effect, effecttype, blocked, check_protection)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/adjustBruteLoss(var/amount,var/include_robo)
+ amount *= 0.75
+ if(humanform)
+ return humanform.adjustBruteLoss(amount)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/adjustFireLoss(var/amount,var/include_robo)
+ amount *= 2
+ if(humanform)
+ return humanform.adjustFireLoss(amount)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/adjustToxLoss(amount)
+ if(humanform)
+ return humanform.adjustToxLoss(amount)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/adjustOxyLoss(amount)
+ if(humanform)
+ return humanform.adjustOxyLoss(amount)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/adjustHalLoss(amount)
+ if(humanform)
+ return humanform.adjustHalLoss(amount)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/adjustCloneLoss(amount)
+ if(humanform)
+ return humanform.adjustCloneLoss(amount)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/ex_act(severity)
+ if(humanform)
+ return humanform.ex_act(severity)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/rad_act(severity)
+ rad_glow += severity
+ rad_glow = CLAMP(rad_glow,0,250)
+ if(rad_glow > 1)
+ set_light(max(1,min(5,rad_glow/15)), max(1,min(10,rad_glow/25)), color)
+ update_icon()
+
+/mob/living/simple_mob/slime/promethean/bullet_act(obj/item/projectile/P)
+ if(humanform)
+ return humanform.bullet_act(P)
+ else
+ return ..()
+
+/mob/living/simple_mob/slime/promethean/death(gibbed, deathmessage = "rapidly loses cohesion, splattering across the ground...")
+ if(humanform)
+ humanform.death(gibbed, deathmessage)
+ else
+ animate(src, alpha = 0, time = 2 SECONDS)
+ sleep(2 SECONDS)
+
+ if(!QDELETED(src)) // Human's handle death should have taken us, but maybe we were adminspawned or something without a human counterpart
+ qdel(src)
+
+/mob/living/simple_mob/slime/promethean/Login()
+ . = ..()
+ copy_from_prefs_vr(bellies = FALSE)
+
+/mob/living/simple_mob/slime/promethean/proc/prommie_blobform()
+ set name = "Toggle Blobform"
+ set desc = "Switch between amorphous and humanoid forms."
+ set category = "Abilities"
+ set hidden = FALSE
+
+ var/atom/movable/to_locate = src
+ if(!isturf(to_locate.loc))
+ to_chat(src,"You need more space to perform this action!")
+ return
+
+ //Blob form
+ if(!ishuman(src))
+ if(humanform.temporary_form.stat || paralysis || stunned || weakened || restrained())
+ to_chat(src,"You can only do this while not stunned.")
+ else
+ humanform.prommie_outofblob(src)
+
+/mob/living/simple_mob/slime/promethean/proc/toggle_expand()
+ set name = "Toggle Width"
+ set desc = "Switch between smole and lorge."
+ set category = "Abilities"
+ set hidden = FALSE
+
+ if(stat || world.time < last_special)
+ return
+
+ last_special = world.time + 25
+
+ if(is_wide)
+ is_wide = FALSE
+ src.visible_message("[src.name] pulls together, compacting themselves into a small ball!")
+ update_icon()
+ else
+ is_wide = TRUE
+ src.visible_message("[src.name] flows outwards, their goop expanding!")
+ update_icon()
+
+/mob/living/simple_mob/slime/promethean/proc/toggle_shine()
+ set name = "Toggle Shine"
+ set desc = "Shine on you crazy diamond."
+ set category = "Abilities"
+ set hidden = FALSE
+
+ if(stat || world.time < last_special)
+ return
+
+ last_special = world.time + 25
+
+ if(shiny)
+ shiny = FALSE
+ src.visible_message("[src.name] dulls their shine, becoming more translucent.")
+ update_icon()
+ else
+ shiny = TRUE
+ src.visible_message("[src.name] glistens and sparkles, shining brilliantly.")
+ update_icon()
+
+/mob/living/simple_mob/slime/promethean/proc/prommie_select_colour()
+
+ set name = "Select Body Colour"
+ set category = "Abilities"
+
+ if(stat || world.time < last_special)
+ return
+
+ last_special = world.time + 25
+
+ var/new_skin = input(usr, "Please select a new body color.", "Shapeshifter Colour", color) as null|color
+ if(!new_skin)
+ return
+ color = new_skin
+ update_icon()
+
+/mob/living/simple_mob/slime/promethean/get_description_interaction()
+ return
+
+
+/mob/living/simple_mob/slime/promethean/get_description_info()
+ return
+
+/mob/living/simple_mob/slime/promethean/init_vore()
+ return
+
+/mob/living/simple_mob/slime/promethean/get_available_emotes()
+ var/list/fulllist = _slime_default_emotes
+ fulllist += default_emotes
+ return fulllist
+/mob/living/carbon/human
+ var/mob/living/simple_mob/slime/promethean/stored_blob = null
+// Helpers - Unsafe, WILL perform change.
+/mob/living/carbon/human/proc/prommie_intoblob(force)
+ if(!force && !isturf(loc))
+ to_chat(src,"You can't change forms while inside something.")
+ return
+
+ handle_grasp() //It's possible to blob out before some key parts of the life loop. This results in things getting dropped at null. TODO: Fix the code so this can be done better.
+ remove_micros(src, src) //Living things don't fare well in roblobs.
+ if(buckled)
+ buckled.unbuckle_mob()
+ if(LAZYLEN(buckled_mobs))
+ for(var/buckledmob in buckled_mobs)
+ riding_datum.force_dismount(buckledmob)
+ if(pulledby)
+ pulledby.stop_pulling()
+ stop_pulling()
+
+ //Record where they should go
+ var/atom/creation_spot = drop_location()
+ var/mob/living/simple_mob/slime/promethean/blob = null
+ //Create our new blob
+ if(!stored_blob)
+ blob = new(creation_spot,src)
+ blob.mood = ":3"
+ qdel(blob.ai_holder)
+ blob.ai_holder = null
+ else
+ blob = stored_blob
+ blob.forceMove(creation_spot)
+
+ //Drop all our things
+ var/list/things_to_drop = contents.Copy()
+ var/list/things_to_not_drop = list(w_uniform,nif,l_store,r_store,wear_id,l_ear,r_ear) //And whatever else we decide for balancing.
+ var/obj/item/clothing/head/new_hat
+ var/has_hat = FALSE
+ things_to_drop -= things_to_not_drop //Crunch the lists
+ things_to_drop -= organs //Mah armbs
+ things_to_drop -= internal_organs //Mah sqeedily spooch
+
+ for(var/obj/item/clothing/head/H in things_to_drop)
+ if(H)
+ new_hat = H
+ has_hat = TRUE
+ drop_from_inventory(H)
+ things_to_drop -= H
+
+ for(var/obj/item/I in things_to_drop) //rip hoarders
+ drop_from_inventory(I)
+
+ if(w_uniform && istype(w_uniform,/obj/item/clothing)) //No webbings tho. We do this after in case a suit was in the way
+ var/obj/item/clothing/uniform = w_uniform
+ if(LAZYLEN(uniform.accessories))
+ for(var/obj/item/clothing/accessory/A in uniform.accessories)
+ if(is_type_in_list(A, disallowed_protean_accessories))
+ uniform.remove_accessory(null,A) //First param is user, but adds fingerprints and messages
+
+ //Size update
+ blob.transform = matrix()*size_multiplier
+ blob.size_multiplier = size_multiplier
+
+ if(l_hand) blob.prev_left_hand = l_hand //Won't save them if dropped above, but necessary if handdrop is disabled.
+ if(r_hand) blob.prev_right_hand = r_hand
+
+ //Put our owner in it (don't transfer var/mind)
+ blob.Weaken(2)
+ blob.transforming = TRUE
+ blob.ckey = ckey
+ blob.transforming = FALSE
+ blob.name = name
+ blob.nutrition = nutrition
+ blob.color = rgb(r_skin, g_skin, b_skin)
+ playsound(src.loc, "sound/effects/slime_squish.ogg", 15)
+ if(radiation > 0)
+ blob.rad_glow = CLAMP(radiation,0,250)
+ set_light(0)
+ blob.set_light(max(1,min(5,radiation/15)), max(1,min(10,radiation/25)), blob.color)
+ blob.handle_light()
+ if(has_hat)
+ blob.hat = new_hat
+ new_hat.forceMove(src)
+
+ blob.update_icon()
+ blob.verbs -= /mob/living/proc/ventcrawl // Absolutely not.
+ blob.verbs -= /mob/living/simple_mob/proc/set_name // We already have a name.
+ temporary_form = blob
+ //Mail them to nullspace
+ moveToNullspace()
+
+ //Message
+ blob.visible_message("[src.name] squishes into their true form!")
+
+ //Transfer vore organs
+ blob.vore_organs = vore_organs
+ blob.vore_selected = vore_selected
+ for(var/obj/belly/B as anything in vore_organs)
+ B.forceMove(blob)
+ B.owner = blob
+
+ //We can still speak our languages!
+ blob.languages = languages.Copy()
+
+ //Return our blob in case someone wants it
+ return blob
+
+/mob/living/carbon/human/proc/prommie_outofblob(var/mob/living/simple_mob/slime/promethean/blob, force)
+ if(!istype(blob))
+ return
+
+ if(!force && !isturf(blob.loc))
+ to_chat(blob,"You can't change forms while inside something.")
+ return
+
+ if(buckled)
+ buckled.unbuckle_mob()
+ if(LAZYLEN(buckled_mobs))
+ for(var/buckledmob in buckled_mobs)
+ riding_datum.force_dismount(buckledmob)
+ if(pulledby)
+ pulledby.stop_pulling()
+ stop_pulling()
+
+ //Message
+ blob.visible_message("[src.name] pulls together, forming a humanoid shape!")
+
+ //Record where they should go
+ var/atom/reform_spot = blob.drop_location()
+
+ //Size update
+ resize(blob.size_multiplier, FALSE, ignore_prefs = TRUE)
+
+ //Move them back where the blob was
+ forceMove(reform_spot)
+
+ //Put our owner in it (don't transfer var/mind)
+ Weaken(2)
+ playsound(src.loc, "sound/effects/slime_squish.ogg", 15)
+ transforming = TRUE
+ ckey = blob.ckey
+ transforming = FALSE
+ blob.name = "Promethean Blob"
+ var/obj/item/hat = blob.hat
+ blob.drop_hat()
+ drop_from_inventory(hat) // Hat me baby
+ equip_to_slot_if_possible(hat, slot_head)
+ nutrition = blob.nutrition // food good
+
+
+ temporary_form = null
+
+ shapeshifter_set_colour(blob.color)
+ if(blob.rad_glow > 0)
+ radiation = CLAMP(blob.rad_glow,0,250)
+ set_light(max(1,min(5,radiation/15)), max(1,min(10,radiation/25)), species.get_flesh_colour(src))
+ update_icon()
+
+ //Transfer vore organs
+ vore_selected = blob.vore_selected
+ for(var/obj/belly/B as anything in blob.vore_organs)
+ B.forceMove(src)
+ B.owner = src
+
+ //vore_organs.Cut()
+ if(blob.prev_left_hand) put_in_l_hand(blob.prev_left_hand) //The restore for when reforming.
+ if(blob.prev_right_hand) put_in_r_hand(blob.prev_right_hand)
+
+ Life(1) //Fix my blindness right meow //Has to be moved up here, there exists a circumstance where blob could be deleted without vore organs moving right.
+
+ //Get rid of friend blob
+ stored_blob = blob
+ blob.set_light(0)
+ blob.moveToNullspace()
+ //qdel(blob)
+
+ //Return ourselves in case someone wants it
+ return src
+
+/mob/living/simple_mob/slime/promethean/examine(mob/user)
+ . = ..()
+ if(hat)
+ . += "They are wearing \a [hat]."
\ No newline at end of file
diff --git a/vorestation.dme b/vorestation.dme
index ec74fd632c5..ca58989588f 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -2841,6 +2841,7 @@
#include "code\modules\mob\living\carbon\human\species\station\monkey_vr.dm"
#include "code\modules\mob\living\carbon\human\species\station\prometheans.dm"
#include "code\modules\mob\living\carbon\human\species\station\prometheans_vr.dm"
+#include "code\modules\mob\living\carbon\human\species\station\prommie_blob.dm"
#include "code\modules\mob\living\carbon\human\species\station\station.dm"
#include "code\modules\mob\living\carbon\human\species\station\station_special_abilities_vr.dm"
#include "code\modules\mob\living\carbon\human\species\station\station_special_vr.dm"