diff --git a/code/__DEFINES/voreconstants.dm b/code/__DEFINES/voreconstants.dm
new file mode 100644
index 0000000000..cd4204514c
--- /dev/null
+++ b/code/__DEFINES/voreconstants.dm
@@ -0,0 +1,66 @@
+// Overhauled vore system
+#define DM_HOLD "Hold"
+#define DM_DIGEST "Digest"
+#define DM_HEAL "Heal"
+#define DM_DIGESTF "Fast Digest"
+
+#define VORE_STRUGGLE_EMOTE_CHANCE 40
+
+// Stance for hostile mobs to be in while devouring someone.
+#define HOSTILE_STANCE_EATING 99
+
+
+var/global/list/player_sizes_list = list("Macro" = SIZESCALE_HUGE, "Big" = SIZESCALE_BIG, "Normal" = SIZESCALE_NORMAL, "Small" = SIZESCALE_SMALL, "Tiny" = SIZESCALE_TINY)
+/* // moved to sound.dm
+
+var/global/list/digestion_sounds = list(
+ 'sound/vore/digest1.ogg',
+ 'sound/vore/digest2.ogg',
+ 'sound/vore/digest3.ogg',
+ 'sound/vore/digest4.ogg',
+ 'sound/vore/digest5.ogg',
+ 'sound/vore/digest6.ogg',
+ 'sound/vore/digest7.ogg',
+ 'sound/vore/digest8.ogg',
+ 'sound/vore/digest9.ogg',
+ 'sound/vore/digest10.ogg',
+ 'sound/vore/digest11.ogg',
+ 'sound/vore/digest12.ogg')
+
+var/global/list/death_sounds = list(
+ 'sound/vore/death1.ogg',
+ 'sound/vore/death2.ogg',
+ 'sound/vore/death3.ogg',
+ 'sound/vore/death4.ogg',
+ 'sound/vore/death5.ogg',
+ 'sound/vore/death6.ogg',
+ 'sound/vore/death7.ogg',
+ 'sound/vore/death8.ogg',
+ 'sound/vore/death9.ogg',
+ 'sound/vore/death10.ogg') */
+
+var/global/list/vore_sounds = list(
+ "Gulp" = 'sound/vore/gulp.ogg',
+ "Insert" = 'sound/vore/insert.ogg',
+ "Insertion1" = 'sound/vore/insertion1.ogg',
+ "Insertion2" = 'sound/vore/insertion2.ogg',
+ "Insertion3" = 'sound/vore/insertion3.ogg',
+ "Schlorp" = 'sound/vore/schlorp.ogg',
+ "Squish1" = 'sound/vore/squish1.ogg',
+ "Squish2" = 'sound/vore/squish2.ogg',
+ "Squish3" = 'sound/vore/squish3.ogg',
+ "Squish4" = 'sound/vore/squish4.ogg')
+/* also moved to sound.dmi
+var/global/list/struggle_sounds = list(
+ "Squish1" = 'sound/vore/squish1.ogg',
+ "Squish2" = 'sound/vore/squish2.ogg',
+ "Squish3" = 'sound/vore/squish3.ogg',
+ "Squish4" = 'sound/vore/squish4.ogg')
+
+/proc/log_debug(text)
+ if (config.log_debug)
+ diary << "\[[time_stamp()]]DEBUG: [text][log_end]"
+
+ for(var/client/C in admins)
+ if(C.prefs.toggles & CHAT_DEBUGLOGS)
+ C << "DEBUG: [text]" */
\ No newline at end of file
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 09f5eb1ccc..b4de0ebb0d 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -347,6 +347,8 @@ GLOBAL_LIST(external_rsc_urls)
if(!tooltips)
tooltips = new /datum/tooltip(src)
+ hook_vr("client_new",list(src))
+
//////////////
//DISCONNECT//
//////////////
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index f398062cd5..e51e6e1860 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1535,8 +1535,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("load")
load_preferences()
load_character()
+ attempt_vr(parent.prefs_vr,"load_vore","")
if("changeslot")
+ attempt_vr(parent.prefs_vr,"load_vore","")
if(!load_character(text2num(href_list["num"])))
random_character()
real_name = random_unique_name(gender)
diff --git a/code/modules/client/preferences_vr.dm b/code/modules/client/preferences_vr.dm
new file mode 100644
index 0000000000..0f9b6935d3
--- /dev/null
+++ b/code/modules/client/preferences_vr.dm
@@ -0,0 +1,8 @@
+//File isn't currently being used.
+/datum/preferences
+ var/biological_gender = MALE
+ var/identifying_gender = MALE
+
+/datum/preferences/proc/set_biological_gender(var/gender)
+ biological_gender = gender
+ identifying_gender = gender
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 8306372125..230d64c99a 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -257,6 +257,9 @@
msg += "[t_He] looks like a drunken mess.\n"
if(91.01 to INFINITY)
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
+ for (var/I in src.vore_organs)
+ var/datum/belly/B = vore_organs[I]
+ msg += B.get_examine_msg()
msg += ""
diff --git a/code/modules/mob/living/carbon/human/examine_vr.dm b/code/modules/mob/living/carbon/human/examine_vr.dm
new file mode 100644
index 0000000000..8578db809e
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/examine_vr.dm
@@ -0,0 +1,54 @@
+/mob/living/carbon/human/proc/examine_nutrition()
+ var/message = ""
+ var/nutrition_examine = round(nutrition)
+ var/t_He = "It" //capitalised for use at the start of each line.
+ var/t_His = "Its"
+ var/t_his = "its"
+ var/t_is = "is"
+ var/t_has = "has"
+ switch(gender)
+ if(MALE)
+ t_He = "He"
+ t_his = "his"
+ t_His = "His"
+ if(FEMALE)
+ t_He = "She"
+ t_his = "her"
+ t_His = "Her"
+ if(PLURAL)
+ t_He = "They"
+ t_his = "their"
+ t_His = "Their"
+ t_is = "are"
+ t_has = "have"
+ if(NEUTER)
+ t_He = "It"
+ t_his = "its"
+ t_His = "Its"
+ switch(nutrition_examine)
+ if(0 to 49)
+ message = "[t_He] [t_is] starving! You can hear [t_his] stomach snarling from across the room!\n"
+ if(50 to 99)
+ message = "[t_He] [t_is] extremely hungry. A deep growl occasionally rumbles from [t_his] empty stomach.\n"
+ if(100 to 499)
+ return message //Well that's pretty normal, really.
+ if(500 to 864) // Fat.
+ message = "[t_He] [t_has] a stuffed belly, bloated fat and round from eating too much.\n"
+ if(1200 to 1934) // One person fully digested.
+ message = "[t_He] [t_is] sporting a large, round, sagging stomach. It's contains at least their body weight worth of glorping slush.\n"
+ if(1935 to 3004) // Two people.
+ message = "[t_He] [t_is] engorged with a huge stomach that sags and wobbles as they move. [t_He] must have consumed at least twice their body weight. It looks incredibly soft.\n"
+ if(3005 to 4074) // Three people.
+ message = "[t_His] stomach is firmly packed with digesting slop. [t_He] must have eaten at least a few times worth their body weight! It looks hard for them to stand, and [t_his] gut jiggles when they move.\n"
+ if(4075 to 10000) // Four or more people.
+ message = "[t_He] [t_is] so absolutely stuffed that you aren't sure how it's possible to move. [t_He] can't seem to swell any bigger. The surface of [t_his] belly looks sorely strained!\n"
+ return message
+
+/mob/living/carbon/human/proc/examine_bellies()
+ var/message = ""
+
+ for (var/I in src.vore_organs)
+ var/datum/belly/B = vore_organs[I]
+ message += B.get_examine_msg()
+
+ return message
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 41d850429f..d41b90ed3d 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -160,8 +160,8 @@
return ..()
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
- if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (disabilities & FAT) && ismonkey(pulling))
- devour_mob(pulling)
+ if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
+ vore_attack(user, pulling)
else
..()
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index eddd000747..6d3f26c244 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -42,6 +42,9 @@
return
if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
return
+ if(ismob(loc))
+ return
+
var/datum/gas_mixture/environment
if(loc)
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 02106dd0e9..9bfc9129f9 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -40,6 +40,9 @@
//stuff in the stomach
handle_stomach()
+ // Vore code for belly processes
+ handle_internal_contents()
+
update_gravity(mob_has_gravity())
if(machine)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 7c26ab2cda..e1b0a05961 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -550,6 +550,9 @@
if(buckled && last_special <= world.time)
resist_buckle()
+ // climbing out of a gut
+ if(attempt_vr(src,"vore_process_resist",args)) return TRUE
+
//Breaking out of a container (Locker, sleeper, cryo...)
else if(isobj(loc))
var/obj/C = loc
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index fc7a451c3b..007f28784b 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -10,7 +10,10 @@
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if("grab")
- grabbedby(M)
+ if(grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
+ vore_attack(M, pulling)
+ else
+ grabbedby(M)
if("harm", "disarm")
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 1a308f9c99..4910eff67d 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -28,6 +28,7 @@
GLOB.living_mob_list += src
prepare_huds()
can_ride_typecache = typecacheof(can_ride_typecache)
+ hook_vr("mob_new",list(src))
..()
/atom/proc/prepare_huds()
@@ -110,7 +111,7 @@
if(self_message)
msg = self_message
else
- if(M.see_invisible[owner] expels everything from their [lowertext(name)]!")
+ return TRUE
+
+// Release a specific atom from the contents of this belly into the owning mob's location.
+// If that location is another mob, the atom is transferred into whichever of its bellies the owning mob is in.
+// Returns the number of atoms so released.
+/datum/belly/proc/release_specific_contents(var/atom/movable/M)
+ if (!(M in internal_contents))
+ return FALSE // They weren't in this belly anyway
+
+ M.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner.
+ src.internal_contents.Add(M) // Remove from the belly contents
+ var/datum/belly/B = check_belly(owner)
+ if(B)
+ B.internal_contents.Add(M)
+
+ owner.visible_message("[owner] expels [M] from their [lowertext(name)]!")
+// owner.regenerate_icons()
+ return TRUE
+
+// Actually perform the mechanics of devouring the tasty prey.
+// The purpose of this method is to avoid duplicate code, and ensure that all necessary
+// steps are taken.
+/datum/belly/proc/nom_mob(var/mob/prey, var/mob/user)
+// if (prey.buckled)
+// prey.buckled.unbuckle_mob()
+
+ prey.forceMove(owner)
+ internal_contents.Add(prey)
+
+ if(inside_flavor)
+ prey << "[inside_flavor]"
+
+// Get the line that should show up in Examine message if the owner of this belly
+// is examined. By making this a proc, we not only take advantage of polymorphism,
+// but can easily make the message vary based on how many people are inside, etc.
+// Returns a string which shoul be appended to the Examine output.
+/datum/belly/proc/get_examine_msg()
+ if(internal_contents.len && examine_messages.len)
+ var/formatted_message
+ var/raw_message = pick(examine_messages)
+
+ formatted_message = replacetext(raw_message,"%belly",lowertext(name))
+
+ return("[formatted_message]
")
+
+// The next function gets the messages set on the belly, in human-readable format.
+// This is useful in customization boxes and such. The delimiter right now is \n\n so
+// in message boxes, this looks nice and is easily delimited.
+/datum/belly/proc/get_messages(var/type, var/delim = "\n\n")
+ ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
+ var/list/raw_messages
+
+ switch(type)
+ if("smo")
+ raw_messages = struggle_messages_outside
+ if("smi")
+ raw_messages = struggle_messages_inside
+ if("dmo")
+ raw_messages = digest_messages_owner
+ if("dmp")
+ raw_messages = digest_messages_prey
+ if("em")
+ raw_messages = examine_messages
+
+ var/messages = list2text(raw_messages,delim)
+ return messages
+
+// The next function sets the messages on the belly, from human-readable var
+// replacement strings and linebreaks as delimiters (two \n\n by default).
+// They also sanitize the messages.
+/datum/belly/proc/set_messages(var/raw_text, var/type, var/delim = "\n\n")
+ ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
+
+ var/list/raw_list = text2list(html_encode(raw_text),delim)
+ if(raw_list.len > 10)
+ raw_list.Cut(11)
+
+ for(var/i = 1, i <= raw_list.len, i++)
+ if(length(raw_list[i]) > 160 || length(raw_list[i]) < 10) //160 is fudged value due to htmlencoding increasing the size
+ raw_list.Cut(i,i)
+ else
+ raw_list[i] = readd_quotes(raw_list[i])
+ //Also fix % sign for var replacement
+ raw_list[i] = replacetext(raw_list[i],"%","%")
+
+ ASSERT(raw_list.len <= 10) //Sanity
+
+ switch(type)
+ if("smo")
+ struggle_messages_outside = raw_list
+ if("smi")
+ struggle_messages_inside = raw_list
+ if("dmo")
+ digest_messages_owner = raw_list
+ if("dmp")
+ digest_messages_prey = raw_list
+ if("em")
+ examine_messages = raw_list
+
+ return
+
+// Handle the death of a mob via digestion.
+// Called from the process_Life() methods of bellies that digest prey.
+// Default implementation calls M.death() and removes from internal contents.
+// Indigestable items are removed, and M is deleted.
+/datum/belly/proc/digestion_death(var/mob/living/M)
+ is_full = TRUE
+ internal_contents.Remove(M)
+
+ // If digested prey is also a pred... anyone inside their bellies gets moved up.
+ if (is_vore_predator(M))
+ for (var/bellytype in M.vore_organs)
+ var/datum/belly/belly = M.vore_organs[bellytype]
+ for (var/obj/thing in belly.internal_contents)
+ thing.loc = owner
+ internal_contents.Add(thing)
+ for (var/mob/subprey in belly.internal_contents)
+ subprey.loc = owner
+ internal_contents.Add(subprey)
+ subprey << "As [M] melts away around you, you find yourself in [owner]'s [name]"
+
+ //Drop all items into the belly.
+ for(var/obj/item/W in M)
+ if(!M.dropItemToGround(W))
+ qdel(W)
+
+ message_admins("[key_name(owner)] digested [key_name(M)].")
+ log_attack("[key_name(owner)] digested [key_name(M)].")
+
+ // Delete the digested mob
+ qdel(M)
+
+//Handle a mob struggling
+// Called from /mob/living/carbon/relaymove()
+/datum/belly/proc/relay_resist(var/mob/living/R)
+ if (!(R in internal_contents))
+ return // User is not in this belly, or struggle too soon.
+
+ R.setClickCooldown(50)
+
+ if(owner.stat) //If owner is stat (dead, KO) we can actually escape
+ R << "You attempt to climb out of \the [name]. (This will take around [escapetime/10] seconds.)"
+ owner << "Someone is attempting to climb out of your [name]!"
+
+ if(do_after(R, escapetime, owner))
+ if((owner.stat || escapable) && (R in internal_contents)) //Can still escape?
+ release_specific_contents(R)
+ return
+ else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
+ return
+ else //Belly became inescapable or mob revived
+ R << "Your attempt to escape [name] has failed!"
+ owner << "The attempt to escape from your [name] has failed!"
+ return
+ return
+ var/struggle_outer_message = pick(struggle_messages_outside)
+ var/struggle_user_message = pick(struggle_messages_inside)
+
+ struggle_outer_message = replacetext(struggle_outer_message,"%pred",owner)
+ struggle_outer_message = replacetext(struggle_outer_message,"%prey",R)
+ struggle_outer_message = replacetext(struggle_outer_message,"%belly",lowertext(name))
+
+ struggle_user_message = replacetext(struggle_user_message,"%pred",owner)
+ struggle_user_message = replacetext(struggle_user_message,"%prey",R)
+ struggle_user_message = replacetext(struggle_user_message,"%belly",lowertext(name))
+
+ struggle_outer_message = "" + struggle_outer_message + ""
+ struggle_user_message = "" + struggle_user_message + ""
+
+// for(var/mob/M in hearers(4, owner))
+// M.visible_message(struggle_outer_message) // hearable
+ R.visible_message( "[struggle_outer_message]", "[struggle_user_message]")
+ playsound(R.loc, "struggle_sounds", 50, 0, -5)
+
+ if(escapable && R.a_intent != "help") //If the stomach has escapable enabled and the person is actually trying to kick out
+ R << "You attempt to climb out of \the [name]."
+ owner << "Someone is attempting to climb out of your [name]!"
+ if(prob(escapechance)) //Let's have it check to see if the prey escapes first.
+ if(do_after(R, escapetime))
+ if((escapable) && (R in internal_contents)) //Does the owner still have escapable enabled?
+ release_specific_contents(R)
+ R << "You climb out of \the [name]."
+ owner << "[R] climbs out of your [name]!"
+ for(var/mob/M in hearers(4, owner))
+ M.visible_message("[R] climbs out of [owner]'s [name]!", 2)
+ return
+ else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
+ return
+ else //Belly became inescapable.
+ R << "Your attempt to escape [name] has failed!"
+ owner << "The attempt to escape from your [name] has failed!"
+ return
+
+ else //Nothing interesting happened.
+ R << "But make no progress in escaping [owner]'s [name]."
+ owner << "But appears to be unable to make any progress in escaping your [name]."
+ return
+ else
+ return
+
+// Belly copies and then returns the copy
+// Needs to be updated for any var changes
+/datum/belly/proc/copy(mob/new_owner)
+ var/datum/belly/dupe = new /datum/belly(new_owner)
+
+ //// Non-object variables
+ dupe.name = name
+ dupe.inside_flavor = inside_flavor
+ dupe.vore_sound = vore_sound
+ dupe.vore_verb = vore_verb
+ dupe.human_prey_swallow_time = human_prey_swallow_time
+ dupe.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
+ dupe.emoteTime = emoteTime
+ dupe.digest_brute = digest_brute
+ dupe.digest_burn = digest_burn
+ dupe.digest_tickrate = digest_tickrate
+ dupe.immutable = immutable
+ dupe.escapable = escapable
+ dupe.escapetime = escapetime
+
+ //// Object-holding variables
+ //struggle_messages_outside - strings
+ dupe.struggle_messages_outside.Cut()
+ for(var/I in struggle_messages_outside)
+ dupe.struggle_messages_outside += I
+
+ //struggle_messages_inside - strings
+ dupe.struggle_messages_inside.Cut()
+ for(var/I in struggle_messages_inside)
+ dupe.struggle_messages_inside += I
+
+ //digest_messages_owner - strings
+ dupe.digest_messages_owner.Cut()
+ for(var/I in digest_messages_owner)
+ dupe.digest_messages_owner += I
+
+ //digest_messages_prey - strings
+ dupe.digest_messages_prey.Cut()
+ for(var/I in digest_messages_prey)
+ dupe.digest_messages_prey += I
+
+ //examine_messages - strings
+ dupe.examine_messages.Cut()
+ for(var/I in examine_messages)
+ dupe.examine_messages += I
+
+ //emote_lists - index: digest mode, key: list of strings
+ dupe.emote_lists.Cut()
+ for(var/K in emote_lists)
+ dupe.emote_lists[K] = list()
+ for(var/I in emote_lists[K])
+ dupe.emote_lists[K] += I
+
+ return dupe
\ No newline at end of file
diff --git a/code/modules/vore/eating/bellymodes_vr.dm b/code/modules/vore/eating/bellymodes_vr.dm
new file mode 100644
index 0000000000..559388f542
--- /dev/null
+++ b/code/modules/vore/eating/bellymodes_vr.dm
@@ -0,0 +1,115 @@
+// Process the predator's effects upon the contents of its belly (i.e digestion/transformation etc)
+// Called from /mob/living/Life() proc.
+/datum/belly/proc/process_Life()
+
+/////////////////////////// Auto-Emotes ///////////////////////////
+ if((digest_mode in emote_lists) && !emotePend)
+ emotePend = TRUE
+
+ spawn(emoteTime)
+ var/list/EL = emote_lists[digest_mode]
+ for(var/mob/living/M in internal_contents)
+ M << "[pick(EL)]"
+ src.emotePend = FALSE
+
+///////////////////////////// DM_HOLD /////////////////////////////
+ if(digest_mode == DM_HOLD)
+ return //Pretty boring, huh
+
+//////////////////////////// DM_DIGEST ////////////////////////////
+ if(digest_mode == DM_DIGEST)
+
+ if(prob(50))
+ playsound(owner.loc, "digestion_sounds", 50, 0, -5)
+
+ for (var/mob/living/M in internal_contents)
+ //Pref protection!
+ if (!M.digestable)
+ continue
+
+ //Person just died in guts!
+ if(M.stat == DEAD)
+ var/digest_alert_owner = pick(digest_messages_owner)
+ var/digest_alert_prey = pick(digest_messages_prey)
+
+ //Replace placeholder vars
+ digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
+ digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
+ digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
+
+ digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
+ digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
+ digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
+
+ //Send messages
+ owner << "" + digest_alert_owner + ""
+ M << "" + digest_alert_prey + ""
+
+ owner.nutrition += 400 // so eating dead mobs gives you *something*.
+ playsound(owner.loc, "death_gurgles", 50, 0, -5)
+ digestion_death(M)
+ owner.update_icons()
+ continue
+
+
+ // Deal digestion damage (and feed the pred)
+ if(!(M.status_flags & GODMODE))
+ M.adjustFireLoss(1)
+ owner.nutrition += 1
+ return
+
+//////////////////////////// DM_DIGESTF ////////////////////////////
+ if(digest_mode == DM_DIGESTF)
+
+ if(prob(50))
+ playsound(owner.loc, "digestion_sounds", 55, 0, -3) //slightly louder 'cuz heavier gurgles
+
+ for (var/mob/living/M in internal_contents)
+ //Pref protection!
+ if (!M.digestable)
+ continue
+
+ //Person just died in guts!
+ if(M.stat == DEAD)
+ var/digest_alert_owner = pick(digest_messages_owner)
+ var/digest_alert_prey = pick(digest_messages_prey)
+
+ //Replace placeholder vars
+ digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
+ digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
+ digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
+
+ digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
+ digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
+ digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
+
+ //Send messages
+ owner << "" + digest_alert_owner + ""
+ M << "" + digest_alert_prey + ""
+ M.visible_message("[digest_alert_owner]", "[digest_alert_prey]",
+ "You watch as [owner]'s form lose its additions.")
+ owner.nutrition += 400 // so eating dead mobs gives you *something*.
+ playsound(owner.loc, "death_gurgles", 50, 0, -5)
+ digestion_death(M)
+ owner.update_icons()
+ continue
+
+ // Deal digestion damage (and feed the pred)
+ if(!(M.status_flags & GODMODE))
+ M.adjustBruteLoss(2)
+ M.adjustFireLoss(3)
+ owner.nutrition += 1
+ return
+
+///////////////////////////// DM_HEAL /////////////////////////////
+ if(digest_mode == DM_HEAL)
+ if(prob(50))
+ playsound(owner.loc, "digestion_sounds", 45, 0, -6) //very quiet gurgles, supposedly.
+
+ for (var/mob/living/M in internal_contents)
+ if(M.stat != DEAD)
+ if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
+ M.adjustBruteLoss(-1)
+ M.adjustFireLoss(-1)
+ owner.nutrition -= 10
+ return
\ No newline at end of file
diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm
new file mode 100644
index 0000000000..9a7dbd6708
--- /dev/null
+++ b/code/modules/vore/eating/living_vr.dm
@@ -0,0 +1,326 @@
+///////////////////// Mob Living /////////////////////
+/mob/living
+ var/digestable = 1 // Can the mob be digested inside a belly?
+ var/datum/belly/vore_selected // Default to no vore capability.
+ var/list/vore_organs = list() // List of vore containers inside a mob
+ var/devourable = 0 // Can the mob be vored at all?
+// var/feeding = 0 // Are we going to feed someone else?
+
+
+//
+// Hook for generic creation of stuff on new creatures
+//
+/hook/living_new/proc/vore_setup(mob/living/M)
+ M.verbs += /mob/living/proc/insidePanel
+ M.verbs += /mob/living/proc/escapeOOC
+
+ //Tries to load prefs if a client is present otherwise gives freebie stomach
+ if(!M.vore_organs || !M.vore_organs.len)
+ spawn(20) //Wait a couple of seconds to make sure copy_to or whatever has gone
+ if(!M) return
+
+ if(M.client && M.client.prefs_vr)
+ if(!M.copy_from_prefs_vr())
+ M << "ERROR: You seem to have saved VOREStation prefs, but they couldn't be loaded."
+ return FALSE
+ if(M.vore_organs && M.vore_organs.len)
+ M.vore_selected = M.vore_organs[1]
+
+ if(!M.vore_organs || !M.vore_organs.len)
+ if(!M.vore_organs)
+ M.vore_organs = list()
+ var/datum/belly/B = new /datum/belly(M)
+ B.immutable = TRUE
+ B.name = "Stomach"
+ B.inside_flavor = "It appears to be rather warm and wet. Makes sense, considering it's inside \the [M.name]."
+ M.vore_organs[B.name] = B
+ M.vore_selected = B.name
+
+ //Simple_animal gets emotes. move this to that hook instead?
+ if(istype(src,/mob/living/simple_animal))
+ B.emote_lists[DM_HOLD] = list(
+ "The insides knead at you gently for a moment.",
+ "The guts glorp wetly around you as some air shifts.",
+ "Your predator takes a deep breath and sighs, shifting you somewhat.",
+ "The stomach squeezes you tight for a moment, then relaxes.",
+ "During a moment of quiet, breathing becomes the most audible thing.",
+ "The warm slickness surrounds and kneads on you.")
+
+ B.emote_lists[DM_DIGEST] = list(
+ "The caustic acids eat away at your form.",
+ "The acrid air burns at your lungs.",
+ "Without a thought for you, the stomach grinds inwards painfully.",
+ "The guts treat you like food, squeezing to press more acids against you.",
+ "The onslaught against your body doesn't seem to be letting up; you're food now.",
+ "The insides work on you like they would any other food.")
+
+ //Return 1 to hook-caller
+ return 1
+
+//
+// Handle being clicked, perhaps with something to devour
+//
+
+ // Refactored to use centralized vore code system - Leshana
+
+ // Critical adjustments due to TG grab changes - Poojawa
+
+/mob/living/proc/vore_attack(var/mob/living/user, var/mob/living/prey)
+ if(!user || !prey)
+ return
+
+ if(prey == src && user.zone_selected == "mouth") //you click your target
+// if(!feeding(src))
+// return
+ if(!is_vore_predator(prey))
+ user << "They aren't voracious enough."
+ return
+ feed_self_to_grabbed(user, src)
+
+ if(user == src) //you click yourself
+ if(!is_vore_predator(src))
+ user << "You aren't voracious enough."
+ return
+ user.feed_grabbed_to_self(src, prey)
+
+ else // click someone other than you/prey
+// if(!feeding(src))
+// return
+ if(!is_vore_predator(src))
+ user << "They aren't voracious enough."
+ return
+ feed_grabbed_to_other(user, prey, src)
+//
+// Eating procs depending on who clicked what
+//
+/mob/living/proc/feed_grabbed_to_self(var/mob/living/user, var/mob/living/prey)
+ var/belly = user.vore_selected
+ return perform_the_nom(user, prey, user, belly)
+/*
+/mob/living/proc/eat_held_mob(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
+ var/belly
+ if(user != pred)
+ belly = input("Choose Belly") in pred.vore_organs
+ else
+ belly = pred.vore_selected
+ return perform_the_nom(user, prey, pred, belly)*/
+
+/mob/living/proc/feed_self_to_grabbed(var/mob/living/user, var/mob/living/pred)
+ var/belly = input("Choose Belly") in pred.vore_organs
+ return perform_the_nom(user, user, pred, belly)
+
+/mob/living/proc/feed_grabbed_to_other(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
+ return//disabled until I can make that toggle work
+ var/belly = input("Choose Belly") in pred.vore_organs
+ return perform_the_nom(user, prey, pred, belly)
+
+//
+// Master vore proc that actually does vore procedures
+//
+
+/mob/living/proc/perform_the_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/belly, swallow_time = 100)
+ //Sanity
+ if(!user || !prey || !pred || !belly || !(belly in pred.vore_organs))
+ return
+ if (!prey.devourable)
+ user << "This can't be eaten!"
+ return
+ // The belly selected at the time of noms
+ var/datum/belly/belly_target = pred.vore_organs[belly]
+ var/attempt_msg = "ERROR: Vore message couldn't be created. Notify a dev. (at)"
+ var/success_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
+
+ // Prepare messages
+ if(user == pred) //Feeding someone to yourself
+ attempt_msg = text("[] is attemping to [] [] into their []!",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
+ success_msg = text("[] manages to [] [] into their []!",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
+ else //Feeding someone to another person
+ attempt_msg = text("[] is attempting to make [] [] [] into their []!",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
+ success_msg = text("[] manages to make [] [] [] into their []!",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
+
+ // Announce that we start the attempt!
+ user.visible_message(attempt_msg)
+
+ // Now give the prey time to escape... return if they did
+
+ if(!do_mob(src, user, swallow_time))
+ return FALSE // Prey escaped (or user disabled) before timer expired.
+
+ // If we got this far, nom successful! Announce it!
+ user.visible_message(success_msg)
+ playsound(user, belly_target.vore_sound, 100, 1)
+
+ // Actually shove prey into the belly.
+ belly_target.nom_mob(prey, user)
+// user.update_icons()
+ stop_pulling()
+
+ // Inform Admins
+ var/prey_braindead
+ var/prey_stat
+ if(prey.ckey)
+ prey_stat = prey.stat//only return this if they're not an unmonkey or whatever
+ if(!prey.client)//if they disconnected, tell us
+ prey_braindead = 1
+ if (pred == user)
+ message_admins("[ADMIN_LOOKUPFLW(pred)] ate [ADMIN_LOOKUPFLW(prey)][!prey_braindead ? "" : " (BRAINDEAD)"][prey_stat ? " (DEAD/UNCONSCIOUS)" : ""].")
+ log_attack("[key_name(pred)] ate [key_name(prey)]")
+ else
+ message_admins("[ADMIN_LOOKUPFLW(user)] forced [ADMIN_LOOKUPFLW(pred)] to eat [ADMIN_LOOKUPFLW(prey)].")
+ log_attack("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)].")
+ return TRUE
+
+//
+//End vore code.
+/*
+ //Handle case: /obj/item/weapon/holder
+ if(/obj/item/weapon/holder/micro)
+ var/obj/item/weapon/holder/H = I
+
+ if(!isliving(user)) return 0 // Return 0 to continue upper procs
+ var/mob/living/attacker = user // Typecast to living
+
+ if (is_vore_predator(src))
+ for (var/mob/living/M in H.contents)
+ attacker.eat_held_mob(attacker, M, src)
+ return 1 //Return 1 to exit upper procs
+ else
+ log_attack("[attacker] attempted to feed [H.contents] to [src] ([src.type]) but it failed.")
+
+ // I just can't imagine this not being complained about
+ //Handle case: /obj/item/device/radio/beacon
+ if(/obj/item/device/radio/beacon)
+ var/confirm = alert(user, "[src == user ? "Eat the beacon?" : "Feed the beacon to [src]?"]", "Confirmation", "Yes!", "Cancel")
+ if(confirm == "Yes!")
+ var/bellychoice = input("Which belly?","Select A Belly") in src.vore_organs
+ var/datum/belly/B = src.vore_organs[bellychoice]
+ src.visible_message("[user] is trying to stuff a beacon into [src]'s [bellychoice]!","[user] is trying to stuff a beacon into you!")
+ if(do_after(user,30,src))
+ user.drop_item()
+ I.loc = src
+ B.internal_contents += I
+ src.visible_message("[src] is fed the beacon!","You're fed the beacon!")
+ playsound(src, B.vore_sound, 100, 1)
+ return 1
+ else
+ return 1 //You don't get to hit someone 'later'
+
+ return 0
+*/
+//
+// Custom resist catches for /mob/living
+//
+/mob/living/proc/vore_process_resist()
+
+ //Are we resisting from inside a belly?
+ var/datum/belly/B = check_belly(src)
+ if(B)
+ spawn() B.relay_resist(src)
+ return TRUE //resist() on living does this TRUE thing.
+
+ //Other overridden resists go here
+
+
+ return FALSE
+
+//
+// Proc for updating vore organs and digestion/healing/absorbing
+//
+/mob/living/proc/handle_internal_contents()
+ if(SSmobs.times_fired%6==1)
+ return //The accursed timer
+
+ for (var/I in vore_organs)
+ var/datum/belly/B = vore_organs[I]
+ if(B.internal_contents.len)
+ B.process_Life() //AKA 'do bellymodes_vr.dm'
+
+ for (var/I in vore_organs)
+ var/datum/belly/B = vore_organs[I]
+ if(B.internal_contents.len)
+ listclearnulls(B.internal_contents)
+ for(var/atom/movable/M in B.internal_contents)
+ if(M.loc != src)
+ B.internal_contents.Remove(M)
+
+// OOC Escape code for pref-breaking or AFK preds
+//
+/mob/living/proc/escapeOOC()
+ set name = "Animal Escape"
+ set category = "Vore"
+
+ //You're in an animal!
+ if(istype(src.loc,/mob/living/simple_animal))
+ var/mob/living/simple_animal/pred = src.loc
+ var/confirm = alert(src, "You're in a mob. Use this as a trick to get out of hostile animals. If you are in more than one pred, use this more than once.", "Confirmation", "Okay", "Cancel")
+ if(confirm == "Okay")
+ for(var/I in pred.vore_organs)
+ var/datum/belly/B = pred.vore_organs[I]
+ B.release_specific_contents(src)
+
+ for(var/mob/living/simple_animal/SA in range(10))
+ SA.prey_excludes += src
+ spawn(18000)
+ if(src && SA)
+ SA.prey_excludes -= src
+
+ pred.update_icons()
+
+ else
+ src << "You aren't inside anything, you clod."
+
+//
+// Verb for saving vore preferences to save file
+//
+/mob/living/proc/save_vore_prefs()
+ if(!(client || client.prefs_vr))
+ return FALSE
+ if(!copy_to_prefs_vr())
+ return FALSE
+ if(!client.prefs_vr.save_vore())
+ return FALSE
+
+ return TRUE
+
+/mob/living/proc/apply_vore_prefs()
+ if(!(client || client.prefs_vr))
+ return FALSE
+ if(!client.prefs_vr.load_vore())
+ return FALSE
+ if(!copy_from_prefs_vr())
+ return FALSE
+
+ return TRUE
+
+/mob/living/proc/copy_to_prefs_vr()
+ if(!client || !client.prefs_vr)
+ src << "You attempted to save your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev."
+ return FALSE
+
+ var/datum/vore_preferences/P = client.prefs_vr
+
+ P.digestable = src.digestable
+ P.devourable = src.devourable
+ P.belly_prefs = src.vore_organs
+
+ return TRUE
+
+//
+// Proc for applying vore preferences, given bellies
+//
+/mob/living/proc/copy_from_prefs_vr()
+ if(!client || !client.prefs_vr)
+ src << "You attempted to apply your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev."
+ return FALSE
+
+ var/datum/vore_preferences/P = client.prefs_vr
+
+ src.digestable = P.digestable
+ src.devourable = P.devourable
+ src.vore_organs = list()
+
+ for(var/I in P.belly_prefs)
+ var/datum/belly/Bp = P.belly_prefs[I]
+ src.vore_organs[Bp.name] = Bp.copy(src)
+
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/vore/eating/simple_animal_vr.dm b/code/modules/vore/eating/simple_animal_vr.dm
new file mode 100644
index 0000000000..33417331f5
--- /dev/null
+++ b/code/modules/vore/eating/simple_animal_vr.dm
@@ -0,0 +1,39 @@
+///////////////////// Simple Animal /////////////////////
+/mob/living/simple_animal
+ var/isPredator = 0 //Are they capable of performing and pre-defined vore actions for their species?
+ var/swallowTime = 30 //How long it takes to eat its prey in 1/10 of a second. The default is 3 seconds.
+ var/list/prey_excludes = list() //For excluding people from being eaten.
+
+//
+// Simple nom proc for if you get ckey'd into a simple_animal mob! Avoids grabs.
+/*
+/mob/living/proc/animal_nom(var/mob/living/T in oview(1))
+ set name = "Animal Nom"
+ set category = "Vore"
+ set desc = "Since you can't grab, you get a verb!"
+
+ feed_grabbed_to_self(src,T)
+*/
+//
+// Simple proc for animals to have their digestion toggled on/off externally
+//
+/mob/living/simple_animal/verb/toggle_digestion()
+ set name = "Toggle Animal's Digestion"
+ set desc = "Enables digestion on this mob for 20 minutes."
+ set category = "Vore"
+ set src in oview(1)
+
+ var/datum/belly/B = vore_organs[vore_selected]
+ if(faction != usr.faction)
+ usr << "This predator isn't friendly, and doesn't give a shit about your opinions of it digesting you."
+ return
+ if(B.digest_mode == "Hold")
+ var/confirm = alert(usr, "Enabling digestion on [name] will cause it to digest all stomach contents. Using this to break OOC prefs is against the rules. Digestion will disable itself after 20 minutes.", "Enabling [name]'s Digestion", "Enable", "Cancel")
+ if(confirm == "Enable")
+ B.digest_mode = "Digest"
+ spawn(12000) //12000=20 minutes
+ if(src) B.digest_mode = "Hold"
+ else
+ var/confirm = alert(usr, "This mob is currently set to digest all stomach contents. Do you want to disable this?", "Disabling [name]'s Digestion", "Disable", "Cancel")
+ if(confirm == "Disable")
+ B.digest_mode = "Hold"
\ No newline at end of file
diff --git a/code/modules/vore/eating/vore_vr.dm b/code/modules/vore/eating/vore_vr.dm
new file mode 100644
index 0000000000..f647a78fb0
--- /dev/null
+++ b/code/modules/vore/eating/vore_vr.dm
@@ -0,0 +1,125 @@
+
+/*
+VVVVVVVV VVVVVVVV OOOOOOOOO RRRRRRRRRRRRRRRRR EEEEEEEEEEEEEEEEEEEEEE
+V::::::V V::::::V OO:::::::::OO R::::::::::::::::R E::::::::::::::::::::E
+V::::::V V::::::V OO:::::::::::::OO R::::::RRRRRR:::::R E::::::::::::::::::::E
+V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEEEEE::::E
+ V:::::V V:::::V O::::::O O::::::O R::::R R:::::R E:::::E EEEEEE
+ V:::::V V:::::V O:::::O O:::::O R::::R R:::::R E:::::E
+ V:::::V V:::::V O:::::O O:::::O R::::RRRRRR:::::R E::::::EEEEEEEEEE
+ V:::::V V:::::V O:::::O O:::::O R:::::::::::::RR E:::::::::::::::E
+ V:::::V V:::::V O:::::O O:::::O R::::RRRRRR:::::R E:::::::::::::::E
+ V:::::V V:::::V O:::::O O:::::O R::::R R:::::R E::::::EEEEEEEEEE
+ V:::::V:::::V O:::::O O:::::O R::::R R:::::R E:::::E
+ V:::::::::V O::::::O O::::::O R::::R R:::::R E:::::E EEEEEE
+ V:::::::V O:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEEEE:::::E
+ V:::::V OO:::::::::::::OO R::::::R R:::::RE::::::::::::::::::::E
+ V:::V OO:::::::::OO R::::::R R:::::RE::::::::::::::::::::E
+ VVV OOOOOOOOO RRRRRRRR RRRRRRREEEEEEEEEEEEEEEEEEEEEE
+
+-Aro <3 */
+
+//
+// Overrides/additions to stock defines go here, as well as hooks. Sort them by
+// the object they are overriding. So all /mob/living together, etc.
+//
+//
+// The datum type bolted onto normal preferences datums for storing Vore stuff
+//
+/client
+ var/datum/vore_preferences/prefs_vr
+
+/hook/client_new/proc/add_prefs_vr(client/C)
+ C.prefs_vr = new/datum/vore_preferences(C)
+ if(C.prefs_vr)
+ return TRUE
+
+ return FALSE
+
+/datum/vore_preferences
+ //Actual preferences
+ var/digestable = 1
+ var/devourable = 0
+ var/list/belly_prefs = list()
+
+ //Mechanically required
+ var/path
+ var/slot
+ var/client/client
+ var/client_ckey
+ var/client/parent
+
+/datum/vore_preferences/New(client/C)
+ if(istype(C))
+ client = C
+ client_ckey = C.ckey
+ load_vore(C)
+
+//
+// Check if an object is capable of eating things, based on vore_organs
+//
+/proc/is_vore_predator(var/mob/living/O)
+ if(istype(O,/mob/living))
+ if(O.vore_organs.len > 0)
+ return TRUE
+
+ return FALSE
+
+//
+// Belly searching for simplifying other procs
+//
+/proc/check_belly(atom/movable/A)
+ if(istype(A.loc,/mob/living))
+ var/mob/living/M = A.loc
+ for(var/I in M.vore_organs)
+ var/datum/belly/B = M.vore_organs[I]
+ if(A in B.internal_contents)
+ return(B)
+
+ return FALSE
+
+//
+// Save/Load Vore Preferences
+//
+/datum/vore_preferences/proc/load_vore()
+ if(!client || !client_ckey) return 0 //No client, how can we save?
+
+ slot = client.prefs.default_slot
+
+ path = client.prefs.path
+
+ if(!path) return 0 //Path couldn't be set?
+ if(!fexists(path)) //Never saved before
+ save_vore() //Make the file first
+ return TRUE
+
+ var/savefile/S = new /savefile(path)
+ if(!S) return 0 //Savefile object couldn't be created?
+
+ S.cd = "/character[slot]"
+
+ S["digestable"] >> digestable
+ S["devourable"] >> devourable
+ S["belly_prefs"] >> belly_prefs
+
+ if(isnull(digestable))
+ digestable = 1
+ if(isnull(devourable))
+ devourable = 0
+ if(isnull(belly_prefs))
+ belly_prefs = list()
+
+ return 1
+
+/datum/vore_preferences/proc/save_vore()
+ if(!path) return 0
+ if(!slot) return 0
+ var/savefile/S = new /savefile(path)
+ if(!S) return 0
+ S.cd = "/character[slot]"
+
+ S["digestable"] << digestable
+ S["devourable"] << devourable
+ S["belly_prefs"] << belly_prefs
+
+ return 1
\ No newline at end of file
diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm
new file mode 100644
index 0000000000..e6d00991c8
--- /dev/null
+++ b/code/modules/vore/eating/vorepanel_vr.dm
@@ -0,0 +1,480 @@
+//
+// Vore management panel for players
+//
+
+/mob/living/proc/insidePanel()
+ set name = "Vore Panel"
+ set category = "Vore"
+
+ var/datum/vore_look/picker_holder = new()
+ picker_holder.loop = picker_holder
+ picker_holder.selected = vore_organs[vore_selected]
+
+ var/dat = picker_holder.gen_vui(src)
+
+ picker_holder.popup = new(src, "insidePanel","Vore Panel", 400, 600, picker_holder)
+ picker_holder.popup.set_content(dat)
+ picker_holder.popup.open()
+
+//
+// Callback Handler for the Inside form
+//
+/datum/vore_look
+ var/datum/belly/selected
+ var/datum/browser/popup
+ var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action.
+
+/datum/vore_look/Topic(href,href_list[])
+ if (vp_interact(href, href_list))
+ popup.set_content(gen_vui(usr))
+ usr << output(popup.get_content(), "insidePanel.browser")
+
+/datum/vore_look/proc/gen_vui(var/mob/living/user)
+ var/dat
+
+ if (is_vore_predator(user.loc))
+ var/mob/living/eater = user.loc
+ var/datum/belly/inside_belly
+
+ //This big block here figures out where the prey is
+ inside_belly = check_belly(user)
+
+ if(inside_belly)
+ dat += "You are currently inside [eater]'s [inside_belly]!
"
+
+ if(inside_belly.inside_flavor)
+ dat += "[inside_belly.inside_flavor]
"
+
+ if (inside_belly.internal_contents.len > 1)
+ dat += "You can see the following around you:
"
+ for (var/atom/movable/O in inside_belly.internal_contents)
+ if(istype(O,/mob/living))
+ var/mob/living/M = O
+ //That's just you
+ if(M == user)
+ continue
+ //Anything else
+ dat += "[O]"
+ else
+ dat += "You aren't inside anyone."
+
+ dat += "
"
+
+ dat += ""
+ for(var/K in user.vore_organs) //Fuggin can't iterate over values
+ var/datum/belly/B = user.vore_organs[K]
+ if(B == selected)
+ dat += "- [B.name]"
+ else
+ dat += "
- [B.name]"
+
+ var/spanstyle
+ switch(B.digest_mode)
+ if(DM_HOLD)
+ spanstyle = ""
+ if(DM_DIGEST)
+ spanstyle = "color:red;"
+ if(DM_DIGESTF)
+ spanstyle = "color:purple;"
+ if(DM_HEAL)
+ spanstyle = "color:green;"
+
+ dat += " ([B.internal_contents.len])
"
+
+ if(user.vore_organs.len < 10)
+ dat += "- New+
"
+ dat += "
"
+ dat += "
"
+
+ // Selected Belly (contents, configuration)
+ if(!selected)
+ dat += "No belly selected. Click one to select it."
+ else
+ if(selected.internal_contents.len > 0)
+ dat += "Contents: "
+ for(var/O in selected.internal_contents)
+ dat += "[O]"
+
+ //If there's more than one thing, add an [All] button
+ if(selected.internal_contents.len > 1)
+ dat += "\[All\]"
+
+ dat += "
"
+
+ //Belly Name Button
+ dat += "Name:"
+ dat += " '[selected.name]'"
+
+ //Digest Mode Button
+ dat += "
Belly Mode:"
+ dat += " [selected.digest_mode]"
+
+ //Belly verb
+ dat += "
Vore Verb:"
+ dat += " '[selected.vore_verb]'"
+
+ //Inside flavortext
+ dat += "
Flavor Text:"
+ dat += " '[selected.inside_flavor]'"
+
+ //Belly sound
+ dat += "
Set Vore Sound"
+ dat += "Test"
+
+ //Belly messages
+ dat += "
Belly Messages"
+
+ //Delete button
+ dat += "
Delete Belly"
+
+ dat += "
"
+
+ //Under the last HR, save and stuff.
+ dat += "Save Prefs"
+ dat += "Refresh"
+
+ switch(user.digestable)
+ if(1)
+ dat += "Toggle Digestable"
+ if(0)
+ dat += "Toggle Digestable"
+
+ switch(user.devourable)
+ if(1)
+ dat += "Toggle Devourable"
+ if(0)
+ dat += "Toggle Devourable"
+
+ //Returns the dat html to the vore_look
+ return dat
+
+/datum/vore_look/proc/vp_interact(href, href_list)
+ var/mob/living/user = usr
+ for(var/H in href_list)
+
+ if(href_list["close"])
+ del(src) // Cleanup
+ return
+
+ if(href_list["outsidepick"])
+ var/tgt = locate(href_list["outsidepick"])
+ var/datum/belly/OB = locate(href_list["outsidebelly"])
+ var/intent = "Examine"
+
+ if(istype(tgt,/mob/living))
+ var/mob/living/M = tgt
+ intent = alert("What do you want to do to them?","Query","Examine","Help Out","Devour")
+ switch(intent)
+ if("Examine") //Examine a mob inside another mob
+ M.examine(user)
+
+ if("Help Out") //Help the inside-mob out
+ user << "You begin to push [M] to freedom!"
+ M << "[usr] begins to push you to freedom!"
+ M.loc << "Someone is trying to escape from inside you!"
+ sleep(50)
+ if(prob(33))
+ OB.release_specific_contents(M)
+ usr << "You manage to help [M] to safety!"
+ M << "[user] pushes you free!"
+ M.loc << "[M] forces free of the confines of your body!"
+ else
+ user << "[M] slips back down inside despite your efforts."
+ M << " Even with [user]'s help, you slip back inside again."
+ M.loc << "Your body efficiently shoves [M] back where they belong."
+
+ if("Devour") //Eat the inside mob
+ if(!user.vore_selected)
+ user << "Pick a belly on yourself first!"
+ return 1
+
+ var/datum/belly/TB = user.vore_organs[user.vore_selected]
+ user << "You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!"
+ M << "[user] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!"
+ M.loc << "Someone inside you is eating someone else!"
+
+ sleep(TB.nonhuman_prey_swallow_time)
+ if((user in OB.internal_contents) && (M in OB.internal_contents))
+ user << "You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!"
+ M << "[user] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!"
+ M.loc << "Someone inside you has eaten someone else!"
+ M.loc = user
+ TB.nom_mob(M)
+ OB.internal_contents -= M
+
+ else if(istype(tgt,/obj/item))
+ var/obj/item/T = tgt
+ intent = alert("What do you want to do to that?","Query","Examine","Use Hand")
+ switch(intent)
+ if("Examine")
+ T.examine(user)
+
+ if("Use Hand")
+ if(user.stat)
+ user << "You can't do that in your state!"
+ return 1
+
+ user.ClickOn(T)
+ sleep(5) //Seems to exit too fast for the panel to update
+
+ if(href_list["insidepick"])
+ var/intent
+
+ //Handle the [All] choice. Ugh inelegant. Someone make this pretty.
+ if(href_list["pickall"])
+ intent = alert("Eject all, Move all?","Query","Eject all","Cancel","Move all")
+ switch(intent)
+ if("Cancel")
+ return 1
+
+ if("Eject all")
+ if(user.stat)
+ user << "You can't do that in your state!"
+ return 1
+
+ selected.release_all_contents()
+ playsound(user, 'sound/effects/splat.ogg', 50, 1)
+ user.loc << "Everything is released from [user]!"
+
+ if("Move all")
+ if(user.stat)
+ user << "You can't do that in your state!"
+ return 1
+
+ var/choice = input("Move all where?","Select Belly") in user.vore_organs + "Cancel - Don't Move"
+
+ if(choice == "Cancel - Don't Move")
+ return 1
+ else
+ var/datum/belly/B = user.vore_organs[choice]
+ for(var/atom/movable/tgt in selected.internal_contents)
+ selected.internal_contents -= tgt
+ B.internal_contents += tgt
+
+ tgt << "You're squished from [user]'s [selected] to their [B]!"
+
+ for(var/mob/hearer in range(1,user))
+ hearer << sound('sound/vore/squish2.ogg',volume=80)
+ return 1
+
+
+ var/atom/movable/tgt = locate(href_list["insidepick"])
+ intent = "Examine"
+ intent = alert("Examine, Eject, Move? Examine if you want to leave this box.","Query","Examine","Eject","Move")
+ switch(intent)
+ if("Examine")
+ tgt.examine(user)
+
+ if("Eject")
+ if(user.stat)
+ user << "You can't do that in your state!"
+ return 1
+
+ selected.release_specific_contents(tgt)
+ playsound(user, 'sound/effects/splat.ogg', 50, 1)
+ user.loc << "[tgt] is released from [user]!"
+
+ if("Move")
+ if(user.stat)
+ user << "You can't do that in your state!"
+ return 1
+
+ var/choice = input("Move [tgt] where?","Select Belly") in user.vore_organs + "Cancel - Don't Move"
+
+ if(choice == "Cancel - Don't Move")
+ return 1
+ else
+ var/datum/belly/B = user.vore_organs[choice]
+ selected.internal_contents -= tgt
+ B.internal_contents += tgt
+
+ tgt << "You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(B.name)]!"
+ for(var/mob/hearer in range(1,user))
+ hearer << sound('sound/vore/squish2.ogg',volume=80)
+
+ if(href_list["newbelly"])
+ if(user.vore_organs.len >= 10)
+ return 1
+
+ var/new_name = html_encode(input(usr,"New belly's name:","New Belly") as text|null)
+
+ if(length(new_name) > 12 || length(new_name) < 2)
+ usr << "Entered belly name is too long."
+ return 0
+ if(new_name in user.vore_organs)
+ usr << "No duplicate belly names, please."
+ return 0
+
+ var/datum/belly/NB = new(user)
+ NB.name = new_name
+ NB.owner = user //might be the thing we all needed.
+ user.vore_organs[new_name] = NB
+ selected = NB
+
+ if(href_list["bellypick"])
+ selected = locate(href_list["bellypick"])
+ user.vore_selected = selected.name
+
+ if(href_list["b_name"])
+ var/new_name = html_encode(input(usr,"Belly's new name:","New Name") as text|null)
+
+ if(length(new_name) > 12 || length(new_name) < 2)
+ usr << "Entered belly name length invalid (must be longer than 2, shorter than 12)."
+ return 0
+ if(new_name in user.vore_organs)
+ usr << "No duplicate belly names, please."
+ return 0
+
+ user.vore_organs[new_name] = selected
+ user.vore_organs -= selected.name
+ selected.name = new_name
+
+ if(href_list["b_mode"])
+ var/list/menu_list = selected.digest_modes
+
+ if(selected.digest_modes.len == 1) // Don't do anything
+ return 1
+ if(selected.digest_modes.len == 2) // Just toggle... there's probably a more elegant way to do this...
+ var/index = selected.digest_modes.Find(selected.digest_mode)
+ switch(index)
+ if(1)
+ selected.digest_mode = selected.digest_modes[2]
+ if(2)
+ selected.digest_mode = selected.digest_modes[1]
+ else
+ selected.digest_mode = input("Choose Mode (currently [selected.digest_mode])") in menu_list
+
+ if(href_list["b_desc"])
+ var/new_desc = html_encode(input(usr,"Belly Description (1024 char limit):","New Description",selected.inside_flavor) as message|null)
+ new_desc = readd_quotes(new_desc)
+
+ if(length(new_desc) > 1024)
+ usr << "Entered belly desc too long. 1024 character limit."
+ return FALSE
+
+ selected.inside_flavor = new_desc
+
+ if(href_list["b_msgs"])
+ var/list/messages = list(
+ "Digest Message (to prey)",
+ "Digest Message (to you)",
+ "Struggle Message (outside)",
+ "Struggle Message (inside)",
+ "Examine Message (when full)",
+ "Reset All To Default",
+ "Cancel - No Changes"
+ )
+
+ alert(user,"Setting abusive or deceptive messages will result in a ban. Consider this your warning. Max 150 characters per message, max 10 messages per topic.","Really, don't.")
+ var/choice = input(user,"Select a type to modify. Messages from each topic are pulled at random when needed.","Pick Type") in messages
+ var/help = " Press enter twice to separate messages. '%pred' will be replaced with your name. '%prey' will be replaced with the prey's name. '%belly' will be replaced with your belly's name."
+
+ switch(choice)
+ if("Digest Message (to prey)")
+ var/new_message = input(user,"These are sent to prey when they expire. Write them in 2nd person ('you feel X'). Avoid using %prey in this type."+help,"Digest Message (to prey)",selected.get_messages("dmp")) as message
+ if(new_message)
+ selected.set_messages(new_message,"dmp")
+
+ if("Digest Message (to you)")
+ var/new_message = input(user,"These are sent to you when prey expires in you. Write them in 2nd person ('you feel X'). Avoid using %pred in this type."+help,"Digest Message (to you)",selected.get_messages("dmo")) as message
+ if(new_message)
+ selected.set_messages(new_message,"dmo")
+
+ if("Struggle Message (outside)")
+ var/new_message = input(user,"These are sent to those nearby when prey struggles. Write them in 3rd person ('X's Y bulges')."+help,"Struggle Message (outside)",selected.get_messages("smo")) as message
+ if(new_message)
+ selected.set_messages(new_message,"smo")
+
+ if("Struggle Message (inside)")
+ var/new_message = input(user,"These are sent to prey when they struggle. Write them in 2nd person ('you feel X'). Avoid using %prey in this type."+help,"Struggle Message (inside)",selected.get_messages("smi")) as message
+ if(new_message)
+ selected.set_messages(new_message,"smi")
+
+ if("Examine Message (when full)")
+ var/new_message = input(user,"These are sent to people who examine you when this belly has contents. Write them in 3rd person ('Their %belly is bulging'). Do not use %pred or %prey in this type."+help,"Examine Message (when full)",selected.get_messages("em")) as message
+ if(new_message)
+ selected.set_messages(new_message,"em")
+
+ if("Reset All To Default")
+ var/confirm = alert(user,"This will delete any custom messages. Are you sure?","Confirmation","DELETE","Cancel")
+ if(confirm == "DELETE")
+ selected.digest_messages_prey = initial(selected.digest_messages_prey)
+ selected.digest_messages_owner = initial(selected.digest_messages_owner)
+ selected.struggle_messages_outside = initial(selected.struggle_messages_outside)
+ selected.struggle_messages_inside = initial(selected.struggle_messages_inside)
+
+ if("Cancel - No Changes")
+ return 1
+
+ if(href_list["b_verb"])
+ var/new_verb = html_encode(input(usr,"New verb when eating (infinitive tense, e.g. nom or swallow):","New Verb") as text|null)
+
+ if(length(new_verb) > 12 || length(new_verb) < 2)
+ usr << "Entered verb length invalid (must be longer than 2, shorter than 12)."
+ return FALSE
+
+ selected.vore_verb = new_verb
+
+ if(href_list["b_sound"])
+ var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") in vore_sounds + "Cancel - No Changes"
+
+ if(choice == "Cancel")
+ return 1
+
+ selected.vore_sound = vore_sounds[choice]
+
+ if(href_list["b_soundtest"])
+ user << selected.vore_sound
+
+ if(href_list["b_del"])
+ if(selected.internal_contents.len)
+ usr << "Can't delete bellies with contents!"
+ else if(selected.immutable)
+ usr << "This belly is marked as undeletable."
+ else if(user.vore_organs.len == 1)
+ usr << "You must have at least one belly."
+ else
+ var/alert = alert("Are you sure you want to delete [selected]?","Confirmation","Delete","Cancel")
+ if(alert == "Delete" && !selected.internal_contents.len)
+ user.vore_organs -= selected.name
+ user.vore_organs.Remove(selected)
+ selected = user.vore_organs[1]
+ user.vore_selected = user.vore_organs[1]
+
+ if(href_list["saveprefs"])
+ if(user.save_vore_prefs())
+ user << "Belly Preferences saved!"
+
+ else
+ user << "ERROR: Belly Preferences were not saved!"
+ log_admin("Could not save vore prefs on USER: [user].")
+
+
+ if(href_list["toggledg"])
+ var/choice = alert(user, "This button is for those who don't like being digested. It can make you undigestable to all mobs. Digesting you is currently: [user.digestable ? "Allowed" : "Prevented"]", "", "Allow Digestion", "Cancel", "Prevent Digestion")
+ switch(choice)
+ if("Cancel")
+ return 1
+ if("Allow Digestion")
+ user.digestable = 1
+ if("Prevent Digestion")
+ user.digestable = 0
+
+ if(user.client.prefs_vr)
+ user.client.prefs_vr.digestable = user.digestable
+
+ if(href_list["toggledvor"])
+ var/choice = alert(user, "This button is for those who don't like vore at all. Devouring you is currently: [user.devourable ? "Allowed" : "Prevented"]", "", "Allow Devourment", "Cancel", "Prevent Devourment")
+ switch(choice)
+ if("Cancel")
+ return 1
+ if("Allow Devourment")
+ user.devourable = 1
+ if("Prevent Devourment")
+ user.devourable = 0
+
+ if(user.client.prefs_vr)
+ user.client.prefs_vr.devourable = user.devourable
+
+ //Refresh when interacted with, returning 1 makes vore_look.Topic update
+ return 1
diff --git a/code/modules/vore/hook-defs_vr.dm b/code/modules/vore/hook-defs_vr.dm
new file mode 100644
index 0000000000..629b1ba8f3
--- /dev/null
+++ b/code/modules/vore/hook-defs_vr.dm
@@ -0,0 +1,37 @@
+//The base hooks themselves
+
+//New() hooks
+/hook/client_new
+
+/hook/mob_new
+
+/hook/living_new
+
+/hook/carbon_new
+
+/hook/human_new
+
+/hook/simple_animal_new
+
+//Hooks for interactions
+/hook/living_attackby
+
+//
+//Hook helpers to expand hooks to others
+//
+/hook/mob_new/proc/chain_hooks(mob/M)
+ var/result = 1
+ if(isliving(M))
+ if(!hook_vr("living_new",args))
+ result = 0
+
+ if(iscarbon(M))
+ if(!hook_vr("carbon_new",args))
+ result = 0
+
+ if(ishuman(M))
+ if(!hook_vr("human_new",args))
+ result = 0
+
+ //Return 1 to superhook
+ return result
\ No newline at end of file
diff --git a/code/modules/vore/resizing/grav_pull_vr.dm b/code/modules/vore/resizing/grav_pull_vr.dm
new file mode 100644
index 0000000000..921d1ab2b9
--- /dev/null
+++ b/code/modules/vore/resizing/grav_pull_vr.dm
@@ -0,0 +1,63 @@
+//
+// Gravity Pull effect which draws in movable objects to its center.
+// In this case, "number" refers to the range. directions is ignored.
+//
+/datum/effect/effect/system/grav_pull
+ var/pull_radius = 3
+ var/pull_anchored = 0
+ var/break_windows = 0
+
+/datum/effect/effect/system/grav_pull/set_up(range, num, loca)
+ pull_radius = range
+ number = num
+ if(istype(loca, /turf/))
+ location = loca
+ else
+ location = get_turf(loca)
+
+/datum/effect/effect/system/grav_pull/start()
+ spawn(0)
+ if(holder)
+ src.location = get_turf(holder)
+ for(var/i=0, i < number, i++)
+ do_pull()
+ sleep(25)
+
+/datum/effect/effect/system/grav_pull/proc/do_pull()
+ //following is adapted from supermatter and singulo code
+ if(defer_powernet_rebuild != 2)
+ defer_powernet_rebuild = 1
+
+ // Let's just make this one loop.
+ for(var/atom/X in orange(pull_radius, location))
+ // Movable atoms only
+ if(istype(X, /atom/movable))
+ if(istype(X, /obj/effect/overlay)) continue
+ if(X && !istype(X, /mob/living/carbon/human))
+ if(break_windows && istype(X, /obj/structure/window)) //shatter windows
+ var/obj/structure/window/W = X
+ W.ex_act(2.0)
+
+ if(istype(X, /obj))
+ var/obj/O = X
+ if(O.anchored)
+ if (!pull_anchored) continue // Don't pull anchored stuff unless configured
+ step_towards(X, location) // step just once if anchored
+ continue
+
+ step_towards(X, location) // Step twice
+ step_towards(X, location)
+
+ else if(istype(X,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = X
+ if(istype(H.shoes,/obj/item/clothing/shoes/magboots))
+ var/obj/item/clothing/shoes/magboots/M = H.shoes
+ if(M.magpulse)
+ step_towards(H, location) //step just once with magboots
+ continue
+ step_towards(H, location) //step twice
+ step_towards(H, location)
+
+ if(defer_powernet_rebuild != 2)
+ defer_powernet_rebuild = 0
+ return
diff --git a/code/modules/vore/resizing/holder_micro_vr.dm b/code/modules/vore/resizing/holder_micro_vr.dm
new file mode 100644
index 0000000000..5cdecd9039
--- /dev/null
+++ b/code/modules/vore/resizing/holder_micro_vr.dm
@@ -0,0 +1,33 @@
+// Micro Holders - Extends /obj/item/weapon/holder
+
+/obj/item/weapon/holder/micro
+ name = "micro"
+ desc = "Another crewmember, small enough to fit in your hand."
+ icon_state = "micro"
+ slot_flags = SLOT_FEET | SLOT_HEAD | SLOT_ID
+ w_class = 2
+ item_icons = null // Override value from parent. We don't have magic sprites.
+ pixel_y = 0 // Override value from parent.
+
+/obj/item/weapon/holder/micro/examine(var/mob/user)
+ for(var/mob/living/M in contents)
+ M.examine(user)
+
+/obj/item/weapon/holder/MouseDrop(mob/M as mob)
+ ..()
+ if(M != usr) return
+ if(usr == src) return
+ if(!Adjacent(usr)) return
+ if(istype(M,/mob/living/silicon/ai)) return
+ for(var/mob/living/carbon/human/O in contents)
+ O.show_inv(usr)
+
+/obj/item/weapon/holder/micro/attack_self(var/mob/living/user)
+ for(var/mob/living/carbon/human/M in contents)
+ M.help_shake_act(user)
+
+/obj/item/weapon/holder/micro/update_state()
+ // If any items have been dropped by contained mob, drop them to floor.
+ for(var/obj/O in contents)
+ O.forceMove(get_turf(src))
+ ..()
diff --git a/code/modules/vore/resizing/resize_vr.dm b/code/modules/vore/resizing/resize_vr.dm
new file mode 100644
index 0000000000..06b3b1b2e8
--- /dev/null
+++ b/code/modules/vore/resizing/resize_vr.dm
@@ -0,0 +1,208 @@
+
+//these aren't defines so they can stay in this file
+var/const/SIZESCALE_HUGE = 2
+var/const/SIZESCALE_BIG = 1.5
+var/const/SIZESCALE_NORMAL = 1
+var/const/SIZESCALE_SMALL = 0.85
+var/const/SIZESCALE_TINY = 0.60
+
+//average
+var/const/SIZESCALE_A_HUGEBIG = (SIZESCALE_HUGE + SIZESCALE_BIG) / 2
+var/const/SIZESCALE_A_BIGNORMAL = (SIZESCALE_BIG + SIZESCALE_NORMAL) / 2
+var/const/SIZESCALE_A_NORMALSMALL = (SIZESCALE_NORMAL + SIZESCALE_SMALL) / 2
+var/const/SIZESCALE_A_SMALLTINY = (SIZESCALE_SMALL + SIZESCALE_TINY) / 2
+
+// Adding needed defines to /mob/living
+// Note: Polaris had this on /mob/living/carbon/human We need it higher up for animals and stuff.
+/mob/living
+ var/size_multiplier = 1 //multiplier for the mob's icon size
+
+// Define holder_type on types we want to be scoop-able
+//mob/living/carbon/human
+// holder_type = /obj/item/weapon/holder/micro
+
+/**
+ * Scale up the size of a mob's icon by the size_multiplier.
+ * NOTE: mob/living/carbon/human/update_transform() has a more complicated system and
+ * is already applying this transform. BUT, it does not call ..()
+ * as long as that is true, we should be fine. If that changes we need to
+ * re-evaluate.
+ */
+/mob/living/update_transform()
+ ASSERT(!iscarbon(src))
+ var/matrix/M = matrix()
+ M.Scale(size_multiplier)
+ M.Translate(0, 16*(size_multiplier-1))
+ src.transform = M
+
+/**
+ * Get the effective size of a mob.
+ * Currently this is based only on size_multiplier for micro/macro stuff,
+ * but in the future we may also incorporate the "mob_size", so that
+ * a macro mouse is still only effectively "normal" or a micro dragon is still large etc.
+ */
+/mob/living/proc/get_effective_size()
+ return src.size_multiplier
+
+/**
+ * Resizes the mob immediately to the desired mod, animating it growing/shrinking.
+ * It can be used by anything that calls it.
+ */
+/mob/living/proc/sizescale(var/new_size)
+ var/matrix/sizescale = matrix() // Defines the matrix to change the player's size
+ sizescale.Scale(new_size) //Change the size of the matrix
+
+ if(new_size >= SIZESCALE_NORMAL)
+ sizescale.Translate(0, -1 * (1 - new_size) * 16) //Move the player up in the tile so their feet align with the bottom
+
+ animate(src, transform = sizescale, time = 5) //Animate the player resizing
+ size_multiplier = new_size //Change size_multiplier so that other items can interact with them
+
+/*
+ * Verb proc for a command that lets players change their size OOCly.
+ * Ace was here! Redid this a little so we'd use math for shrinking characters. This is the old code.
+
+/mob/living/proc/set_size()
+ set name = "Set Character Size"
+ set category = "Vore"
+ var/nagmessage = "DO NOT ABUSE THESE COMMANDS. They are not here for you to play with. \
+ We were originally going to remove them but kept them for popular demand. \
+ Do not abuse their existence outside of ERP scenes where they apply, \
+ or reverting OOCly unwanted changes like someone lolshooting the crew with a shrink ray. -Ace"
+
+ var/size_name = input(nagmessage, "Pick a Size") in player_sizes_list
+ if (size_name && player_sizes_list[size_name])
+ src.sizescale(player_sizes_list[size_name])
+ message_admins("[key_name(src)] used the sizescale command in-game to be [size_name]. \
+ ([src ? "JMP" : "null"])")
+
+/** Add the set_size() proc to usable verbs. */
+/hook/living_new/proc/sizescale_setup(mob/living/M)
+ M.verbs += /mob/living/proc/set_size
+ return 1
+
+
+ * Attempt to scoop up this mob up into M's hands, if the size difference is large enough.
+ * @return false if normal code should continue, 1 to prevent normal code.
+
+/mob/living/proc/attempt_to_scoop(var/mob/living/carbon/human/M)
+ if(!istype(M))
+ return 0;
+ if(M.buckled)
+ usr << "You have to unbuckle \the [M] before you pick them up."
+ return 0
+ if(M.get_effective_size() - src.get_effective_size() >= 0.75)
+ var/obj/item/weapon/holder/m_holder = get_scooped(M)
+ if (m_holder)
+ return 1
+ else
+ return 0; // Unable to scoop, let other code run
+*/
+/*
+ * Handle bumping into someone with helping intent.
+ * Called from /mob/living/Bump() in the 'brohugs all around' section.
+ * @return false if normal code should continue, 1 to prevent normal code.
+ * // TODO - can the now_pushing = 0 be moved up? What does it do anyway?
+ */
+/mob/living/proc/handle_micro_bump_helping(var/mob/living/tmob)
+ if(src.get_effective_size() <= SIZESCALE_A_SMALLTINY && tmob.get_effective_size() <= SIZESCALE_A_SMALLTINY)
+ // Both small! Go ahead and
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+ return 1
+ if(abs(src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+
+ if(src.get_effective_size() > tmob.get_effective_size())
+/* var/mob/living/carbon/human/tmob = src
+ if(istype(tmob) && istype(tmob.tail_style, /datum/sprite_accessory/tail/taur/naga))
+ src << "You carefully slither around [tmob]."
+ M << "[src]'s huge tail slithers past beside you!"
+ else
+*/
+ src.forceMove(tmob.loc)
+ src << "You carefully step over [tmob]."
+ tmob << "[src] steps over you carefully!"
+ if(tmob.get_effective_size() > src.get_effective_size())
+/* var/mob/living/carbon/human/M = M
+ if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
+ src << "You jump over [M]'s thick tail."
+ M << "[src] bounds over your tail."
+ else
+*/
+ src.forceMove(tmob.loc)
+ src << "You run between [tmob]'s legs."
+ tmob << "[src] runs between your legs."
+ return 1
+
+/**
+ * Handle bumping into someone without mutual help intent.
+ * Called from /mob/living/Bump()
+ * NW was here, adding even more options for stomping!
+ *
+ * @return false if normal code should continue, 1 to prevent normal code.
+ */
+/mob/living/proc/handle_micro_bump_other(var/mob/living/tmob)
+ ASSERT(isliving(tmob)) // Baby don't hurt me
+
+ if(src.a_intent == "disarm" && src.canmove && !src.buckled)
+ // If bigger than them by at least 0.75, move onto them and print message.
+ if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+ tmob.Stun(4)
+/*
+ var/mob/living/carbon/human/H = src
+ if(istype(H) && istype(H.tail_style, /datum/sprite_accessory/tail/taur/naga))
+ src << "You carefully squish [tmob] under your tail!"
+ tmob << "[src] pins you under their tail!"
+ else
+*/
+ src << "You pin [tmob] beneath your foot!"
+ tmob << "[src] pins you beneath their foot!"
+ return 1
+
+ if(src.a_intent == "harm" && src.canmove && !src.buckled)
+ if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
+ now_pushing = 0
+ src.forceMove(tmob.loc)
+ tmob.adjustStaminaLoss(35)
+ tmob.adjustBruteLoss(5)
+/* var/mob/living/carbon/human/M = src
+ if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
+ src << "You steamroller over [tmob] with your heavy tail!"
+ tmob << "[src] ploughs you down mercilessly with their heavy tail!"
+ else
+*/
+ src << "You bring your foot down heavily upon [tmob]!"
+ tmob << "[src] steps carelessly on your body!"
+ return 1
+
+ // until I figure out grabbing micros with the godawful pull code...
+ if(src.a_intent == "grab" && src.canmove && !src.buckled)
+ if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
+ now_pushing = 0
+ tmob.adjustStaminaLoss(15)
+ src.forceMove(tmob.loc)
+ src << "You press [tmob] beneath your foot!"
+ tmob << "[src] presses you beneath their foot!"
+/*
+ var/mob/living/carbon/human/M = src
+ if(istype(M) && !M.shoes)
+ // User is a human (capable of scooping) and not wearing shoes! Scoop into foot slot!
+ equip_to_slot_if_possible(tmob.get_scooped(M), slot_shoes, 0, 1)
+ if(istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
+ src << "You wrap up [tmob] with your powerful tail!"
+ tmob << "[src] binds you with their powerful tail!"
+ else
+ src << "You clench your toes around [tmob]'s body!"
+ tmob << "[src] grabs your body with their toes!"
+ else if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
+ src << "You carefully squish [tmob] under your tail!"
+ tmob << "[src] pins you under their tail!"
+ else
+ src << "You pin [tmob] beneath your foot!"
+ tmob << "[src] pins you beneath their foot!"
+ return 1
+*/
\ No newline at end of file
diff --git a/code/modules/vore/resizing/sizechemicals.dm b/code/modules/vore/resizing/sizechemicals.dm
new file mode 100644
index 0000000000..78b4bd71ca
--- /dev/null
+++ b/code/modules/vore/resizing/sizechemicals.dm
@@ -0,0 +1,115 @@
+
+////////////////////////////
+/// shrinking serum ///
+////////////////////////////
+
+/datum/reagent/medicine/macrocillin
+ name = "Macrocillin"
+ id = "macrocillin"
+ description = "Glowing yellow liquid."
+ reagent_state = LIQUID
+ color = "#FFFF00" // rgb: 255, 255, 0
+ overdose_threshold = 20
+
+/datum/reagent/medicine/macrocillin/on_mob_life(mob/living/M, method=INGEST)
+ for(var/size in list(SIZESCALE_SMALL, SIZESCALE_NORMAL, SIZESCALE_BIG, SIZESCALE_HUGE))
+ if(M.size_multiplier < size)
+ M.sizescale(size)
+ M << "You grow!"
+ break
+ if(M.reagents.has_reagent("macrocillin"))
+ M.reagents.remove_reagent("macrocillin", 20)
+ ..()
+
+/datum/reagent/medicine/microcillin
+ name = "Microcillin"
+ id = "microcillin"
+ description = "Murky purple liquid."
+ reagent_state = LIQUID
+ color = "#800080"
+ overdose_threshold = 20
+
+/datum/reagent/microcillin/on_mob_life(mob/living/M, method=INGEST)
+ for(var/size in list(SIZESCALE_BIG, SIZESCALE_NORMAL, SIZESCALE_SMALL, SIZESCALE_TINY))
+ if(M.size_multiplier > size)
+ M.sizescale(size)
+ M << "You shrink!"
+ break;
+ if(M.reagents.has_reagent("microcillin"))
+ M.reagents.remove_reagent("microcillin", 20)
+
+ ..()
+
+/datum/reagent/medicine/normalcillin
+ name = "Normalcillin"
+ id = "normalcillin"
+ description = "Translucent cyan liquid."
+ reagent_state = LIQUID
+ color = "#00FFFF"
+ overdose_threshold = 20
+
+/datum/reagent/medicine/normalcillin/on_mob_life(mob/living/M, method=INGEST)
+ if(M.size_multiplier > SIZESCALE_BIG)
+ M.sizescale(SIZESCALE_BIG)
+ M << "You shrink!"
+ else if(M.size_multiplier > SIZESCALE_NORMAL)
+ M.sizescale(SIZESCALE_NORMAL)
+ M << "You shrink!"
+ else if(M.size_multiplier < SIZESCALE_NORMAL)
+ M.sizescale(SIZESCALE_NORMAL)
+ M << "You grow!"
+ else if(M.size_multiplier < SIZESCALE_SMALL)
+ M.sizescale(SIZESCALE_SMALL)
+ M << "You grow!"
+
+ if(M.reagents.has_reagent("normalcillin"))
+ M.reagents.remove_reagent("normalcillin", 20)
+ ..()
+
+
+/datum/reagent/medicine/sizeoxadone
+ name = "Sizeoxadone"
+ id = "sizeoxadone"
+ description = "A volatile liquid used as a precursor to size-altering chemicals. Causes dizziness if taken unprocessed."
+ reagent_state = LIQUID
+ color = "#1E90FF"
+ overdose_threshold = 30
+ metabolization_rate = 0.8 * REAGENTS_METABOLISM
+
+/datum/reagent/sizeoxadone/on_mob_life(var/mob/living/carbon/M, var/removed)
+ if(M.hallucination < volume && prob(20))
+ M.hallucination += 5
+ if(!M.confused) M.confused = 1
+ M.confused = max(M.confused, 20)
+ return
+
+/datum/reagent/medicine/sizeoxadone/overdose_process(mob/living/M)
+ M.adjustBrainLoss(1)
+ M.adjustToxLoss(1)
+ ..()
+ . = 1
+
+////////////////////////// Anti-Noms Drugs //////////////////////////
+
+/datum/reagent/medicine/ickypak
+ name = "Ickypak"
+ id = "ickypak"
+ description = "A foul-smelling green liquid, for inducing muscle contractions to expel accidentally ingested things."
+ reagent_state = LIQUID
+ color = "#0E900E"
+ metabolization_rate = 0.25 * REAGENTS_METABOLISM
+
+/datum/reagent/medicine/ickypak/on_mob_life(var/mob/living/M, method=INGEST)
+ ..()
+ if(M.hallucination < volume && prob(20))
+ M.hallucination += 5
+ M.adjustToxLoss(-5)
+
+ for(var/I in M.vore_organs)
+ var/datum/belly/B = M.vore_organs[I]
+ for(var/atom/movable/A in B.internal_contents)
+ if(prob(55))
+ playsound(M, 'sound/effects/splat.ogg', 50, 1)
+ B.release_specific_contents(A)
+ ..()
+ . = 1
\ No newline at end of file
diff --git a/code/modules/vore/resizing/sizegun_vr.dm b/code/modules/vore/resizing/sizegun_vr.dm
new file mode 100644
index 0000000000..ace5793336
--- /dev/null
+++ b/code/modules/vore/resizing/sizegun_vr.dm
@@ -0,0 +1,172 @@
+//
+// Size Gun
+//
+/*
+/obj/item/weapon/gun/energy/sizegun
+ name = "shrink ray"
+ desc = "A highly advanced ray gun with two settings: Shrink and Grow. Warning: Do not insert into mouth."
+ icon = 'icons/obj/gun_vr.dmi'
+ icon_state = "sizegun-shrink100" // Someone can probably do better. -Ace
+ item_state = null //so the human update icon uses the icon_state instead
+ fire_sound = 'sound/weapons/wave.ogg'
+ charge_cost = 100
+ projectile_type = /obj/item/projectile/beam/shrinklaser
+ origin_tech = "redspace=1;bluespace=4"
+ modifystate = "sizegun-shrink"
+ selfcharge = 1
+ firemodes = list(
+ list(mode_name = "grow",
+ projectile_type = /obj/item/projectile/beam/growlaser,
+ modifystate = "sizegun-grow",
+ fire_sound = 'sound/weapons/pulse3.ogg'
+ ),
+ list(mode_name = "shrink",
+ projectile_type = /obj/item/projectile/beam/shrinklaser,
+ modifystate = "sizegun-shrink",
+ fire_sound = 'sound/weapons/wave.ogg'
+ ))
+
+//
+// Beams for size gun
+//
+// tracers TBD
+
+/obj/item/projectile/beam/shrinklaser
+ name = "shrink beam"
+ icon_state = "xray"
+ nodamage = 1
+ damage = 0
+ check_armour = "laser"
+
+ muzzle_type = /obj/effect/projectile/xray/muzzle
+ tracer_type = /obj/effect/projectile/xray/tracer
+ impact_type = /obj/effect/projectile/xray/impact
+
+/obj/item/projectile/beam/shrinklaser/on_hit(var/atom/target, var/blocked = 0)
+ if(istype(target, /mob/living))
+ var/mob/living/M = target
+ switch(M.size_multiplier)
+ if(SIZESCALE_HUGE to INFINITY)
+ M.sizescale(SIZESCALE_BIG)
+ if(SIZESCALE_BIG to SIZESCALE_HUGE)
+ M.sizescale(SIZESCALE_NORMAL)
+ if(SIZESCALE_NORMAL to SIZESCALE_BIG)
+ M.sizescale(SIZESCALE_SMALL)
+ if((0 - INFINITY) to SIZESCALE_NORMAL)
+ M.sizescale(SIZESCALE_TINY)
+ M.update_transform()
+ return 1
+
+/obj/item/projectile/beam/growlaser
+ name = "growth beam"
+ icon_state = "bluelaser"
+ nodamage = 1
+ damage = 0
+ check_armour = "laser"
+
+ muzzle_type = /obj/effect/projectile/laser_blue/muzzle
+ tracer_type = /obj/effect/projectile/laser_blue/tracer
+ impact_type = /obj/effect/projectile/laser_blue/impact
+
+/obj/item/projectile/beam/growlaser/on_hit(var/atom/target, var/blocked = 0)
+ if(istype(target, /mob/living))
+ var/mob/living/M = target
+ switch(M.size_multiplier)
+ if(SIZESCALE_BIG to SIZESCALE_HUGE)
+ M.sizescale(SIZESCALE_HUGE)
+ if(SIZESCALE_NORMAL to SIZESCALE_BIG)
+ M.sizescale(SIZESCALE_BIG)
+ if(SIZESCALE_SMALL to SIZESCALE_NORMAL)
+ M.sizescale(SIZESCALE_NORMAL)
+ if((0 - INFINITY) to SIZESCALE_TINY)
+ M.sizescale(SIZESCALE_SMALL)
+ M.update_transform()
+ return 1
+*/
+
+datum/design/sizeray
+ name = "Size Ray"
+ desc = "Abuse bluespace tech to alter living matter scale."
+ id = "sizeray"
+ req_tech = list("combat" = 5, "materials" = 4, "engineering" = 5, "bluespace" = 4)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 1000, MAT_GLASS = 1000, MAT_DIAMOND = 2500, MAT_URANIUM = 2500, MAT_TITANIUM = 1000)
+ build_path = /obj/item/weapon/gun/energy/laser/sizeray
+ category = list("Weapons")
+
+/obj/item/projectile/sizeray
+ name = "sizeray beam"
+ icon_state = "omnilaser"
+ hitsound = null
+ damage = 0
+ damage_type = STAMINA
+ flag = "laser"
+ pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
+
+/obj/item/projectile/sizeray/shrinkray
+ icon_state="bluelaser"
+
+/obj/item/projectile/sizeray/growthray
+ icon_state="laser"
+
+/obj/item/projectile/sizeray/shrinkray/on_hit(var/atom/target, var/blocked = 0)
+ if(istype(target, /mob/living))
+ var/mob/living/M = target
+ switch(M.size_multiplier)
+ if(SIZESCALE_HUGE to INFINITY)
+ M.sizescale(SIZESCALE_BIG)
+ if(SIZESCALE_BIG to SIZESCALE_HUGE)
+ M.sizescale(SIZESCALE_NORMAL)
+ if(SIZESCALE_NORMAL to SIZESCALE_BIG)
+ M.sizescale(SIZESCALE_SMALL)
+ if((0 - INFINITY) to SIZESCALE_NORMAL)
+ M.sizescale(SIZESCALE_TINY)
+ M.update_transform()
+ return 1
+
+/obj/item/projectile/sizeray/growthray/on_hit(var/atom/target, var/blocked = 0)
+ if(istype(target, /mob/living))
+ var/mob/living/M = target
+ switch(M.size_multiplier)
+ if(SIZESCALE_BIG to SIZESCALE_HUGE)
+ M.sizescale(SIZESCALE_HUGE)
+ if(SIZESCALE_NORMAL to SIZESCALE_BIG)
+ M.sizescale(SIZESCALE_BIG)
+ if(SIZESCALE_SMALL to SIZESCALE_NORMAL)
+ M.sizescale(SIZESCALE_NORMAL)
+ if((0 - INFINITY) to SIZESCALE_TINY)
+ M.sizescale(SIZESCALE_SMALL)
+ M.update_transform()
+ return 1
+
+/obj/item/ammo_casing/energy/laser/growthray
+ projectile_type = /obj/item/projectile/sizeray/growthray
+ select_name = "Growth"
+
+/obj/item/ammo_casing/energy/laser/shrinkray
+ projectile_type = /obj/item/projectile/sizeray/shrinkray
+ select_name = "Shrink"
+
+
+//Gun here
+/obj/item/weapon/gun/energy/laser/sizeray
+ name = "size ray"
+ icon_state = "bluetag"
+ desc = "Size manipulator using bluespace breakthroughs."
+ item_state = null //so the human update icon uses the icon_state instead.
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray, /obj/item/ammo_casing/energy/laser/growthray)
+ origin_tech = "combat=1;magnets=2"
+ selfcharge = 1
+ charge_delay = 5
+ ammo_x_offset = 2
+ clumsy_check = 1
+
+ attackby(obj/item/W, mob/user)
+ if(W==src)
+ if(icon_state=="bluetag")
+ icon_state="redtag"
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/growthray)
+ else
+ icon_state="bluetag"
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray)
+ return ..()
\ No newline at end of file
diff --git a/code/modules/vore/trycatch_vr.dm b/code/modules/vore/trycatch_vr.dm
new file mode 100644
index 0000000000..1ae5c3bc0c
--- /dev/null
+++ b/code/modules/vore/trycatch_vr.dm
@@ -0,0 +1,62 @@
+/*
+This file is for jamming single-line procs into Polaris procs.
+It will prevent runtimes and allow their code to run if VOREStation's fails.
+It will also log when we mess up our code rather than making it vague.
+
+Call it at the top of a stock proc with...
+
+if(attempt_vr(object,proc to call,args)) return
+
+...if you are replacing an entire proc.
+
+The proc you're attemping should return nonzero values on success.
+*/
+
+/proc/attempt_vr(callon, procname, list/args=null)
+ try
+ if(!callon || !procname)
+ CRASH("attempt_vr: Invalid obj/proc: [callon]/[procname]")
+ return 0
+
+ var/result = call(callon,procname)(arglist(args))
+
+ return result
+
+ catch(var/exception/e)
+ CRASH("attempt_vr runtimed when calling [procname] on [callon].")
+ CRASH("attempt_vr catch: [e] on [e.file]:[e.line]")
+ return 0
+
+/*
+This is the _vr version of calling hooks.
+It's meant to have different messages, and also the try/catch block.
+For when you want hooks and want to know when you ruin everything,
+vs when Polaris ruins everything.
+
+Call it at the top of a stock proc with...
+
+if(hook_vr(proc,args)) return
+
+...if you are replacing an entire proc.
+
+The hooks you're calling should return nonzero values on success.
+*/
+/proc/hook_vr(hook, list/args=null)
+ try
+ var/hook_path = text2path("/hook/[hook]")
+ if(!hook_path)
+ CRASH("hook_vr: Invalid hook '/hook/[hook]' called.")
+ return 0
+
+ var/caller = new hook_path
+ var/status = 1
+ for(var/P in typesof("[hook_path]/proc"))
+ if(!call(caller, P)(arglist(args)))
+ CRASH("hook_vr: Hook '[P]' failed or runtimed.")
+ status = 0
+
+ return status
+
+ catch(var/exception/e)
+ CRASH("hook_vr itself failed or runtimed. Exception below.")
+ CRASH("hook_vr catch: [e] on [e.file]:[e.line]")
\ No newline at end of file
diff --git a/sound/vore/StomachTransfer.ogg b/sound/vore/StomachTransfer.ogg
new file mode 100644
index 0000000000..c81da56f50
Binary files /dev/null and b/sound/vore/StomachTransfer.ogg differ
diff --git a/sound/vore/death1.ogg b/sound/vore/death1.ogg
new file mode 100644
index 0000000000..34f4e189f5
Binary files /dev/null and b/sound/vore/death1.ogg differ
diff --git a/sound/vore/death10.ogg b/sound/vore/death10.ogg
new file mode 100644
index 0000000000..92ce0fd9bd
Binary files /dev/null and b/sound/vore/death10.ogg differ
diff --git a/sound/vore/death2.ogg b/sound/vore/death2.ogg
new file mode 100644
index 0000000000..2476b0f08c
Binary files /dev/null and b/sound/vore/death2.ogg differ
diff --git a/sound/vore/death3.ogg b/sound/vore/death3.ogg
new file mode 100644
index 0000000000..d8a666067d
Binary files /dev/null and b/sound/vore/death3.ogg differ
diff --git a/sound/vore/death4.ogg b/sound/vore/death4.ogg
new file mode 100644
index 0000000000..4fce54da79
Binary files /dev/null and b/sound/vore/death4.ogg differ
diff --git a/sound/vore/death5.ogg b/sound/vore/death5.ogg
new file mode 100644
index 0000000000..371cf17155
Binary files /dev/null and b/sound/vore/death5.ogg differ
diff --git a/sound/vore/death6.ogg b/sound/vore/death6.ogg
new file mode 100644
index 0000000000..78fc1b0637
Binary files /dev/null and b/sound/vore/death6.ogg differ
diff --git a/sound/vore/death7.ogg b/sound/vore/death7.ogg
new file mode 100644
index 0000000000..419a5bedd5
Binary files /dev/null and b/sound/vore/death7.ogg differ
diff --git a/sound/vore/death8.ogg b/sound/vore/death8.ogg
new file mode 100644
index 0000000000..b15ab6a7d2
Binary files /dev/null and b/sound/vore/death8.ogg differ
diff --git a/sound/vore/death9.ogg b/sound/vore/death9.ogg
new file mode 100644
index 0000000000..3709541d60
Binary files /dev/null and b/sound/vore/death9.ogg differ
diff --git a/sound/vore/digest1.ogg b/sound/vore/digest1.ogg
new file mode 100644
index 0000000000..058ca78f7e
Binary files /dev/null and b/sound/vore/digest1.ogg differ
diff --git a/sound/vore/digest10.ogg b/sound/vore/digest10.ogg
new file mode 100644
index 0000000000..5db775ae29
Binary files /dev/null and b/sound/vore/digest10.ogg differ
diff --git a/sound/vore/digest11.ogg b/sound/vore/digest11.ogg
new file mode 100644
index 0000000000..d81ac72dea
Binary files /dev/null and b/sound/vore/digest11.ogg differ
diff --git a/sound/vore/digest12.ogg b/sound/vore/digest12.ogg
new file mode 100644
index 0000000000..6b44127cd8
Binary files /dev/null and b/sound/vore/digest12.ogg differ
diff --git a/sound/vore/digest2.ogg b/sound/vore/digest2.ogg
new file mode 100644
index 0000000000..0e8bef1db8
Binary files /dev/null and b/sound/vore/digest2.ogg differ
diff --git a/sound/vore/digest3.ogg b/sound/vore/digest3.ogg
new file mode 100644
index 0000000000..2077f31399
Binary files /dev/null and b/sound/vore/digest3.ogg differ
diff --git a/sound/vore/digest4.ogg b/sound/vore/digest4.ogg
new file mode 100644
index 0000000000..27a786bc40
Binary files /dev/null and b/sound/vore/digest4.ogg differ
diff --git a/sound/vore/digest5.ogg b/sound/vore/digest5.ogg
new file mode 100644
index 0000000000..849c1335be
Binary files /dev/null and b/sound/vore/digest5.ogg differ
diff --git a/sound/vore/digest6.ogg b/sound/vore/digest6.ogg
new file mode 100644
index 0000000000..5f0cc86eb1
Binary files /dev/null and b/sound/vore/digest6.ogg differ
diff --git a/sound/vore/digest7.ogg b/sound/vore/digest7.ogg
new file mode 100644
index 0000000000..f224cc3fa3
Binary files /dev/null and b/sound/vore/digest7.ogg differ
diff --git a/sound/vore/digest8.ogg b/sound/vore/digest8.ogg
new file mode 100644
index 0000000000..04b742bd49
Binary files /dev/null and b/sound/vore/digest8.ogg differ
diff --git a/sound/vore/digest9.ogg b/sound/vore/digest9.ogg
new file mode 100644
index 0000000000..866c95b874
Binary files /dev/null and b/sound/vore/digest9.ogg differ
diff --git a/sound/vore/gulp.ogg b/sound/vore/gulp.ogg
new file mode 100644
index 0000000000..b463e7fb18
Binary files /dev/null and b/sound/vore/gulp.ogg differ
diff --git a/sound/vore/insert.ogg b/sound/vore/insert.ogg
new file mode 100644
index 0000000000..0574733d4d
Binary files /dev/null and b/sound/vore/insert.ogg differ
diff --git a/sound/vore/insertion1.ogg b/sound/vore/insertion1.ogg
new file mode 100644
index 0000000000..a026591f07
Binary files /dev/null and b/sound/vore/insertion1.ogg differ
diff --git a/sound/vore/insertion2.ogg b/sound/vore/insertion2.ogg
new file mode 100644
index 0000000000..b682e3aaf8
Binary files /dev/null and b/sound/vore/insertion2.ogg differ
diff --git a/sound/vore/insertion3.ogg b/sound/vore/insertion3.ogg
new file mode 100644
index 0000000000..7dabf3f077
Binary files /dev/null and b/sound/vore/insertion3.ogg differ
diff --git a/sound/vore/schlorp.ogg b/sound/vore/schlorp.ogg
new file mode 100644
index 0000000000..c9cd5a3413
Binary files /dev/null and b/sound/vore/schlorp.ogg differ
diff --git a/sound/vore/squish1.ogg b/sound/vore/squish1.ogg
new file mode 100644
index 0000000000..8a87758048
Binary files /dev/null and b/sound/vore/squish1.ogg differ
diff --git a/sound/vore/squish2.ogg b/sound/vore/squish2.ogg
new file mode 100644
index 0000000000..c8f96fc6e2
Binary files /dev/null and b/sound/vore/squish2.ogg differ
diff --git a/sound/vore/squish3.ogg b/sound/vore/squish3.ogg
new file mode 100644
index 0000000000..60e364c80a
Binary files /dev/null and b/sound/vore/squish3.ogg differ
diff --git a/sound/vore/squish4.ogg b/sound/vore/squish4.ogg
new file mode 100644
index 0000000000..e9bd8e7bf5
Binary files /dev/null and b/sound/vore/squish4.ogg differ
diff --git a/sound/vore/stomach_loop.ogg b/sound/vore/stomach_loop.ogg
new file mode 100644
index 0000000000..b9983b2ab6
Binary files /dev/null and b/sound/vore/stomach_loop.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 1c838f0565..914a289082 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -13,9 +13,7 @@
// END_PREFERENCES
// BEGIN_INCLUDE
-#include "_maps\basemap.dm"
-#include "_maps\loadallmaps.dm"
-#include "_maps\tgstation2.dm"
+#include "_maps\runtimestation.dm"
#include "code\_compile_options.dm"
#include "code\world.dm"
#include "code\__DATASTRUCTURES\globals.dm"
@@ -67,6 +65,7 @@
#include "code\__DEFINES\tgui.dm"
#include "code\__DEFINES\tick.dm"
#include "code\__DEFINES\typeids.dm"
+#include "code\__DEFINES\voreconstants.dm"
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\wires.dm"
#include "code\__HELPERS\_lists.dm"
@@ -1148,6 +1147,7 @@
#include "code\modules\client\preferences.dm"
#include "code\modules\client\preferences_savefile.dm"
#include "code\modules\client\preferences_toggles.dm"
+#include "code\modules\client\preferences_vr.dm"
#include "code\modules\client\verbs\looc.dm"
#include "code\modules\client\verbs\ooc.dm"
#include "code\modules\client\verbs\ping.dm"
@@ -1567,6 +1567,7 @@
#include "code\modules\mob\living\carbon\human\death.dm"
#include "code\modules\mob\living\carbon\human\emote.dm"
#include "code\modules\mob\living\carbon\human\examine.dm"
+#include "code\modules\mob\living\carbon\human\examine_vr.dm"
#include "code\modules\mob\living\carbon\human\human.dm"
#include "code\modules\mob\living\carbon\human\human_defense.dm"
#include "code\modules\mob\living\carbon\human\human_defines.dm"
@@ -2130,6 +2131,16 @@
#include "code\modules\vehicles\secway.dm"
#include "code\modules\vehicles\speedbike.dm"
#include "code\modules\vehicles\vehicle.dm"
+#include "code\modules\vore\hook-defs_vr.dm"
+#include "code\modules\vore\trycatch_vr.dm"
+#include "code\modules\vore\eating\belly_vr.dm"
+#include "code\modules\vore\eating\bellymodes_vr.dm"
+#include "code\modules\vore\eating\living_vr.dm"
+#include "code\modules\vore\eating\simple_animal_vr.dm"
+#include "code\modules\vore\eating\vore_vr.dm"
+#include "code\modules\vore\eating\vorepanel_vr.dm"
+#include "code\modules\vore\resizing\resize_vr.dm"
+#include "code\modules\vore\resizing\sizegun_vr.dm"
#include "code\modules\VR\vr_human.dm"
#include "code\modules\VR\vr_sleeper.dm"
#include "code\modules\zombie\items.dm"