diff --git a/code/controllers/subsystems/mobs.dm b/code/controllers/subsystems/mobs.dm
index c124b5573e..66352c9c9e 100644
--- a/code/controllers/subsystems/mobs.dm
+++ b/code/controllers/subsystems/mobs.dm
@@ -43,6 +43,11 @@ SUBSYSTEM_DEF(mobs)
else if(M.low_priority && !(M.loc && get_z(M) && process_z[get_z(M)]))
slept_mobs++
continue
+ //CHOMPEdit Start - Enable pausing mobs (For transformation, holding until reformation, etc.)
+ else if(!M.enabled)
+ slept_mobs++
+ continue
+ //CHOMPEdit End
M.Life(times_fired)
@@ -90,4 +95,4 @@ SUBSYSTEM_DEF(mobs)
/datum/controller/subsystem/mobs/critfail()
..()
- log_recent()
\ No newline at end of file
+ log_recent()
diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm
index 75fddde40e..4fa7e7d983 100644
--- a/code/game/objects/items/devices/defib.dm
+++ b/code/game/objects/items/devices/defib.dm
@@ -291,7 +291,7 @@
/obj/item/weapon/shockpaddles/proc/can_revive(mob/living/carbon/human/H) //This is checked right before attempting to revive
var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[O_BRAIN]
- if(H.should_have_organ(O_BRAIN) && (!brain || brain.defib_timer <= 0 ) )
+ if(H.should_have_organ(O_BRAIN) && (!brain || (istype(brain) && brain.defib_timer <= 0 ) ) ) //CHOMPEdit - Fix a runtime when brain is an MMI
return "buzzes, \"Resuscitation failed - Excessive neural degeneration. Further attempts futile.\""
H.updatehealth()
diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm
index 43ce4a33cc..a0f977d789 100644
--- a/code/modules/vore/eating/belly_obj_vr.dm
+++ b/code/modules/vore/eating/belly_obj_vr.dm
@@ -321,6 +321,10 @@
return
if(OldLoc in contents)
return //Someone dropping something (or being stripdigested)
+ //CHOMPEdit Start - Prevent reforming causing a lot of log spam/sounds
+ if(istype(OldLoc, /mob/observer) || istype(OldLoc, /obj/item/device/mmi))
+ return //Someone getting reformed most likely (And if not, uh... shouldn't happen anyways?)
+ //CHOMPEdit end
//Generic entered message
if(!owner.mute_entry) //CHOMPEdit
@@ -801,10 +805,31 @@
/obj/belly/proc/digestion_death(mob/living/M)
add_attack_logs(owner, M, "Digested in [lowertext(name)]")
+ //CHOMPEdit Start - Reverts TF on death. This fixes a bug with posibrains or similar, and also makes reforming easier.
+ if(M.tf_mob_holder && M.tf_mob_holder.loc == M)
+ M.tf_mob_holder.ckey = M.ckey
+ M.tf_mob_holder.enabled = TRUE
+ M.tf_mob_holder.loc = M.loc
+ M.tf_mob_holder.forceMove(M.loc)
+ QDEL_LIST_NULL(M.tf_mob_holder.vore_organs)
+ M.tf_mob_holder.vore_organs = list()
+ for(var/obj/belly/B as anything in M.vore_organs)
+ B.loc = M.tf_mob_holder
+ B.forceMove(M.tf_mob_holder)
+ B.owner = M.tf_mob_holder
+ M.tf_mob_holder.vore_organs |= B
+ M.vore_organs -= B
+
+ if(M.tf_mob_holder)
+ M.tf_mob_holder = null
+ //CHOMPEdit End
+
// If digested prey is also a pred... anyone inside their bellies gets moved up.
if(is_vore_predator(M))
M.release_vore_contents(include_absorbed = TRUE, silent = TRUE)
+ var/obj/item/device/mmi/hasMMI // CHOMPEdit - Adjust how MMI's are handled
+
//Drop all items into the belly.
if(config.items_survive_digestion)
for(var/obj/item/W in M)
@@ -813,6 +838,7 @@
var/obj/item/device/mmi/brainbox = MMI.removed()
if(brainbox)
items_preserved += brainbox
+ hasMMI = brainbox // CHOMPEdit - Adjust how MMI's are handled
for(var/slot in slots)
var/obj/item/I = M.get_equipped_item(slot = slot)
if(I)
@@ -840,10 +866,42 @@
//Incase they have the loop going, let's double check to stop it.
M.stop_sound_channel(CHANNEL_PREYLOOP)
// Delete the digested mob
- var/mob/observer/G = M.ghostize() //CHOMPEdit start. Make sure they're out, so we can copy attack logs and such.
- if(G)
- G.forceMove(src) //CHOMPEdit end.
- qdel(M)
+ //CHOMPEdit start - Changed qdel to a forceMove to allow reforming, and... handled robots special.
+ if(isrobot(M))
+ var/mob/living/silicon/robot/R = M
+ if(R.mmi && R.mind && R.mmi.brainmob)
+ R.mmi.loc = src
+ items_preserved += R.mmi
+ var/obj/item/weapon/robot_module/MB = locate() in R.contents
+ if(MB)
+ R.mmi.brainmob.languages = MB.original_languages
+ else
+ R.mmi.brainmob.languages = R.languages
+ R.mmi.brainmob.remove_language("Robot Talk")
+ hasMMI = R.mmi
+ M.mind.transfer_to(hasMMI.brainmob)
+ R.mmi = null
+ else if(!R.shell) // Shells don't have brainmobs in their MMIs.
+ to_chat(R, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.")
+ if(R.shell) // Let the standard procedure for shells handle this.
+ qdel(R)
+ return
+
+ if(istype(hasMMI))
+ hasMMI.body_backup = M
+ M.enabled = FALSE
+ M.forceMove(hasMMI)
+ else
+ //Another CHOMPEdit started here. I left the comment here, though obviously we're doing a lot more now as well.
+ var/mob/observer/G = M.ghostize(FALSE) //CHOMPEdit start. Make sure they're out, so we can copy attack logs and such.
+ if(G)
+ G.forceMove(src)
+ G.body_backup = M
+ M.enabled = FALSE
+ M.forceMove(G)
+ else
+ qdel(M)
+ //CHOMPEdit End
// Handle a mob being absorbed
/obj/belly/proc/absorb_living(mob/living/M)
diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm
index 8ab067efca..01610d895e 100644
--- a/code/modules/vore/eating/vorepanel_vr.dm
+++ b/code/modules/vore/eating/vorepanel_vr.dm
@@ -814,6 +814,10 @@
var/list/available_options = list("Examine", "Eject", "Move", "Transfer")
if(ishuman(target))
available_options += "Transform"
+ //CHOMPEdit Begin - Add Reforming
+ if(isobserver(target) || istype(target,/obj/item/device/mmi))
+ available_options += "Reform"
+ //CHOMPEdit End
if(isliving(target))
var/mob/living/datarget = target
if(datarget.client)
@@ -899,6 +903,154 @@
V.tgui_interact(user)
return TRUE
+ //CHOMPEdit Begin - Add Reforming
+ if("Reform")
+ if(host.stat)
+ to_chat(user,"You can't do that in your state!")
+ return TRUE
+
+ if(isobserver(target))
+ var/mob/observer/T = target
+ if(!ismob(T.body_backup) || prevent_respawns.Find(T.mind.name) || ispAI(T.body_backup))
+ to_chat(user,"They don't seem to be reformable!")
+ return TRUE
+
+ var/accepted = tgui_alert(T, "[host] is trying to reform your body! Would you like to get reformed inside [host]'s [lowertext(host.vore_selected.name)]?", "Reforming Attempt", list("Yes", "No"))
+ if(accepted != "Yes")
+ to_chat(user,"[T] refused to be reformed!")
+ return TRUE
+
+ if(isliving(T.body_backup))
+ var/mob/living/body_backup = T.body_backup
+ if(ishuman(body_backup))
+ var/mob/living/carbon/human/H = body_backup
+ body_backup.adjustBruteLoss(-6)
+ body_backup.adjustFireLoss(-6)
+ body_backup.setOxyLoss(0)
+ if(H.isSynthetic())
+ H.adjustToxLoss(-H.getToxLoss())
+ else
+ H.adjustToxLoss(-6)
+ body_backup.adjustCloneLoss(-6)
+ body_backup.updatehealth()
+ // Now we do the check to see if we should revive...
+ var/should_proceed_with_revive = TRUE
+ var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[O_BRAIN]
+ should_proceed_with_revive &&= !H.should_have_organ(O_BRAIN) || (brain && (!istype(brain) || brain.defib_timer > 0))
+ if(!H.isSynthetic())
+ should_proceed_with_revive &&= !(HUSK in H.mutations) && H.can_defib
+ if(should_proceed_with_revive)
+ for(var/organ_tag in H.species.has_organ)
+ var/obj/item/organ/O = H.species.has_organ[organ_tag]
+ var/vital = initial(O.vital) //check for vital organs
+ if(vital)
+ O = H.internal_organs_by_name[organ_tag]
+ if(!O || O.damage > O.max_damage)
+ should_proceed_with_revive = FALSE
+ break
+ if(should_proceed_with_revive)
+ dead_mob_list.Remove(H)
+ if((H in living_mob_list) || (H in dead_mob_list))
+ WARNING("Mob [H] was defibbed but already in the living or dead list still!")
+ living_mob_list += H
+
+ H.timeofdeath = 0
+ H.set_stat(UNCONSCIOUS) //Life() can bring them back to consciousness if it needs to.
+ H.failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
+ H.reload_fullscreen()
+ else
+ body_backup.revive()
+ body_backup.forceMove(T.loc)
+ body_backup.enabled = TRUE
+ body_backup.ajourn = 0
+ body_backup.key = T.key
+ body_backup.teleop = null
+ T.body_backup = null
+ host.vore_selected.release_specific_contents(T, TRUE)
+ if(istype(body_backup, /mob/living/simple_mob))
+ var/mob/living/simple_mob/sm = body_backup
+ if(sm.icon_rest && sm.resting)
+ sm.icon_state = sm.icon_rest
+ else
+ sm.icon_state = sm.icon_living
+ T.update_icon()
+ announce_ghost_joinleave(T.mind, 0, "They now occupy their body again.")
+ else if(istype(target,/obj/item/device/mmi)) // A good bit of repeated code, sure, but... cleanest way to do this.
+ var/obj/item/device/mmi/MMI = target
+ if(!ismob(MMI.body_backup) || !MMI.brainmob.mind || prevent_respawns.Find(MMI.brainmob.mind.name))
+ to_chat(user,"They don't seem to be reformable!")
+ return TRUE
+ var/accepted = tgui_alert(MMI.brainmob, "[host] is trying to reform your body! Would you like to get reformed inside [host]'s [lowertext(host.vore_selected.name)]?", "Reforming Attempt", list("Yes", "No"))
+ if(accepted != "Yes")
+ to_chat(user,"[MMI] refused to be reformed!")
+ return TRUE
+
+ if(isliving(MMI.body_backup))
+ var/mob/living/body_backup = MMI.body_backup
+ body_backup.enabled = TRUE
+ body_backup.forceMove(MMI.loc)
+ body_backup.ajourn = 0
+ body_backup.teleop = null
+ //And now installing the MMI into the body...
+ if(isrobot(body_backup)) //Just do the reverse of getting the MMI pulled out in /obj/belly/proc/digestion_death
+ var/mob/living/silicon/robot/R = body_backup
+ R.revive()
+ MMI.brainmob.mind.transfer_to(R)
+ MMI.loc = R
+ R.mmi = MMI
+ R.mmi.brainmob.add_language("Robot Talk")
+ else //reference /datum/surgery_step/robotics/install_mmi/end_step
+ var/obj/item/organ/internal/mmi_holder/holder
+ if(istype(MMI, /obj/item/device/mmi/digital/posibrain))
+ var/obj/item/organ/internal/mmi_holder/posibrain/holdertmp = new(body_backup, 1)
+ holder = holdertmp
+ else if(istype(MMI, /obj/item/device/mmi/digital/robot))
+ var/obj/item/organ/internal/mmi_holder/robot/holdertmp = new(body_backup, 1)
+ holder = holdertmp
+ else
+ holder = new(body_backup, 1)
+ body_backup.internal_organs_by_name["brain"] = holder
+ MMI.loc = holder
+ holder.stored_mmi = MMI
+ holder.update_from_mmi()
+
+ if(MMI.brainmob && MMI.brainmob.mind)
+ MMI.brainmob.mind.transfer_to(body_backup)
+ body_backup.languages = MMI.brainmob.languages
+ //You've hopefully already named yourself, so... not implementing that bit.
+ var/mob/living/carbon/human/H = body_backup
+ body_backup.adjustBruteLoss(-6, TRUE)
+ body_backup.adjustFireLoss(-6, TRUE)
+ body_backup.setOxyLoss(0)
+ H.adjustToxLoss(-H.getToxLoss())
+ body_backup.adjustCloneLoss(-6)
+ body_backup.updatehealth()
+ // Now we do the check to see if we should revive...
+ var/should_proceed_with_revive = TRUE
+ var/obj/item/organ/internal/brain/brain = H.internal_organs_by_name[O_BRAIN]
+ should_proceed_with_revive &&= !H.should_have_organ(O_BRAIN) || (brain && brain.defib_timer > 0 )
+ if(should_proceed_with_revive)
+ for(var/organ_tag in H.species.has_organ)
+ var/obj/item/organ/O = H.species.has_organ[organ_tag]
+ var/vital = initial(O.vital) //check for vital organs
+ if(vital)
+ O = H.internal_organs_by_name[organ_tag]
+ if(!O || O.damage > O.max_damage)
+ should_proceed_with_revive = FALSE
+ break
+ if(should_proceed_with_revive)
+ dead_mob_list.Remove(H)
+ if((H in living_mob_list) || (H in dead_mob_list))
+ WARNING("Mob [H] was defibbed but already in the living or dead list still!")
+ living_mob_list += H
+
+ H.timeofdeath = 0
+ H.set_stat(UNCONSCIOUS) //Life() can bring them back to consciousness if it needs to.
+ H.failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
+ H.reload_fullscreen()
+ MMI.body_backup = null
+ return TRUE
+ //CHOMPEdit End
if("Process")
var/mob/living/ourtarget = target
var/list/process_options = list()
diff --git a/modular_chomp/code/modules/mob/dead/observer/observer.dm b/modular_chomp/code/modules/mob/dead/observer/observer.dm
new file mode 100644
index 0000000000..7928b41556
--- /dev/null
+++ b/modular_chomp/code/modules/mob/dead/observer/observer.dm
@@ -0,0 +1,7 @@
+/mob/observer
+ var/mob/living/body_backup = null //add reforming
+
+/mob/observer/Destroy()
+ if(body_backup)
+ qdel(body_backup)
+ ..()
diff --git a/modular_chomp/code/modules/mob/living/carbon/brain/MMI.dm b/modular_chomp/code/modules/mob/living/carbon/brain/MMI.dm
new file mode 100644
index 0000000000..ae2da9c9d3
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/carbon/brain/MMI.dm
@@ -0,0 +1,7 @@
+/obj/item/device/mmi
+ var/mob/living/body_backup = null //add reforming
+
+/obj/item/device/mmi/Destroy()
+ if(body_backup)
+ qdel(body_backup)
+ ..()
diff --git a/modular_chomp/code/modules/mob/mob.dm b/modular_chomp/code/modules/mob/mob.dm
index 56eb7ea782..be6e3daee9 100644
--- a/modular_chomp/code/modules/mob/mob.dm
+++ b/modular_chomp/code/modules/mob/mob.dm
@@ -1,9 +1,10 @@
/mob
var/voice_freq = 42500 // Preference for character voice frequency
var/list/voice_sounds_list = list() // The sound list containing our voice sounds!
+ var/enabled = TRUE //Pauses a mob if disabled (Prevents life ticks from happening)
var/died_in_vr = FALSE //For virtual reality sleepers
/mob/is_incorporeal()
if(incorporeal_move)
return 1
- ..()
\ No newline at end of file
+ ..()
diff --git a/vorestation.dme b/vorestation.dme
index 9341f6948d..49af4423c3 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -4534,8 +4534,10 @@
#include "modular_chomp\code\modules\mining\shelters_ch.dm"
#include "modular_chomp\code\modules\mob\holder.dm"
#include "modular_chomp\code\modules\mob\mob.dm"
+#include "modular_chomp\code\modules\mob\dead\observer\observer.dm"
#include "modular_chomp\code\modules\mob\living\emote.dm"
#include "modular_chomp\code\modules\mob\living\living.dm"
+#include "modular_chomp\code\modules\mob\living\carbon\brain\MMI.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\human.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\human_defines.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\update_icons.dm"