From 47ec82bc71b92bb1c2b13be63543bfc84a104384 Mon Sep 17 00:00:00 2001
From: CHOMPStation2StaffMirrorBot
<94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com>
Date: Thu, 8 Jan 2026 14:45:40 -0700
Subject: [PATCH] [MIRROR] vore fx and resist code cleanup (#12236)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
---
code/modules/tgs_commands/vorestation.dm | 5 +-
code/modules/vore/eating/belly_obj_resist.dm | 291 +++++++++++++
code/modules/vore/eating/belly_obj_vfx.dm | 165 ++++++++
code/modules/vore/eating/belly_obj_vr.dm | 412 -------------------
vorestation.dme | 2 +
5 files changed, 461 insertions(+), 414 deletions(-)
create mode 100644 code/modules/vore/eating/belly_obj_resist.dm
create mode 100644 code/modules/vore/eating/belly_obj_vfx.dm
diff --git a/code/modules/tgs_commands/vorestation.dm b/code/modules/tgs_commands/vorestation.dm
index 2576fc63a6..b7750a9335 100644
--- a/code/modules/tgs_commands/vorestation.dm
+++ b/code/modules/tgs_commands/vorestation.dm
@@ -191,8 +191,9 @@ GLOBAL_LIST_EMPTY(pending_discord_registrations)
for(var/list/item in GLOB.PDA_Manifest)
outp += "\n__**[item["cat"]]:**__"
for(var/list/person in item["elems"])
- total |= person
- outp += "\n[person["name"]] -:- [person["rank"]]"
+ var/output_string = "[person["name"]] -:- [person["rank"]]"
+ total |= output_string
+ outp += "\n[output_string]"
return "**Total crew members:** [total.len]\n" + outp
diff --git a/code/modules/vore/eating/belly_obj_resist.dm b/code/modules/vore/eating/belly_obj_resist.dm
new file mode 100644
index 0000000000..1a60075c43
--- /dev/null
+++ b/code/modules/vore/eating/belly_obj_resist.dm
@@ -0,0 +1,291 @@
+//Handle a mob struggling
+// Called from /mob/living/carbon/relaymove()
+/obj/belly/proc/relay_resist(mob/living/R, obj/item/C)
+ if (!(R in contents))
+ if(!C)
+ return // User is not in this belly
+
+ R.setClickCooldown(50)
+
+ if(owner.stat) //If owner is stat (dead, KO) we can actually escape
+ resist_default_escape(R, C)
+ return
+
+ if(displayed_message_flags & MS_FLAG_STRUGGLE_OUTSIDE)
+ resist_struggle_outside(R)
+
+ if((vore_sprite_flags & DM_FLAG_VORESPRITE_BELLY) && (owner.vore_capacity_ex[belly_sprite_to_affect] >= 1) && !private_struggle && resist_triggers_animation && affects_vore_sprites)
+ owner.vs_animate(belly_sprite_to_affect)
+
+ if(!private_struggle)
+ resist_play_sound()
+
+ if(prob(belchchance))//Unsure if this should go in escapable or not, leaving it here for now.
+ owner.emote("belch")
+
+ if(escapable) //If the stomach has escapable enabled.
+ if(resist_check_escapechance(R, C))
+ return
+ if(resist_check_transferchance(R, C))
+ return
+ if(resist_check_secondary_transferchance(R,C))
+ return
+ if(resist_check_absorbchance(R))
+ return
+ if(resist_check_digestchance(R))
+ return
+ if(resist_check_selectchance(R))
+ return
+
+ var/struggle_user_message = span_valert(belly_format_string(struggle_messages_inside, R))
+ to_chat(R, struggle_user_message)
+ to_chat(owner, span_vwarning("Your prey appears to be unable to make any progress in escaping your [lowertext(name)]."))
+
+ return
+
+ var/struggle_user_message = span_valert(belly_format_string(struggle_messages_inside, R))
+ to_chat(R, struggle_user_message)
+
+/obj/belly/proc/resist_default_escape(mob/living/R, obj/item/C)
+ var/escape_attempt_owner_message = span_vwarning(belly_format_string(escape_attempt_messages_owner, R))
+ var/escape_attempt_prey_message = span_vwarning(belly_format_string(escape_attempt_messages_prey, R))
+ var/escape_fail_owner_message = span_vwarning(belly_format_string(escape_fail_messages_owner, R))
+ var/escape_fail_prey_message = span_vnotice(belly_format_string(escape_fail_messages_prey, R))
+ escape_attempt_prey_message = span_vwarning("[escape_attempt_prey_message] (will take around [escapetime/10] seconds.)")
+ to_chat(R, escape_attempt_prey_message)
+ to_chat(owner, escape_attempt_owner_message)
+
+ if(do_after(R, escapetime, owner, target = src, timed_action_flags = IGNORE_INCAPACITATED))
+ if((owner.stat || escapable)) //Can still escape?
+ if(C)
+ release_specific_contents(C)
+ return
+
+ if(R.loc == src)
+ release_specific_contents(R)
+ return
+
+ if(R.loc != src) //Aren't even in the belly. Quietly fail.
+ return
+
+ //Belly became inescapable or mob revived
+ to_chat(R, escape_fail_prey_message)
+ to_chat(owner, escape_fail_owner_message)
+
+/obj/belly/proc/resist_struggle_outside(mob/living/R)
+ var/struggle_outer_message = span_valert(belly_format_string(struggle_messages_outside, R))
+ if(private_struggle)
+ to_chat(owner, struggle_outer_message)
+ return
+
+ for(var/mob/M in hearers(4, owner))
+ M.show_message(struggle_outer_message, 2) // hearable
+
+/obj/belly/proc/resist_play_sound()
+ if(is_wet)
+ var/sound/struggle_snuggle
+ if(!fancy_vore)
+ struggle_snuggle = sound(get_sfx("classic_struggle_sounds"))
+ else
+ struggle_snuggle = sound(get_sfx("fancy_prey_struggle"))
+ playsound(src, struggle_snuggle, vary = 1, vol = 75, falloff = VORE_SOUND_FALLOFF, frequency = noise_freq, preference = /datum/preference/toggle/digestion_noises, volume_channel = VOLUME_CHANNEL_VORE)
+ return
+ var/sound/struggle_rustle = sound(get_sfx("rustle"))
+ playsound(src, struggle_rustle, vary = 1, vol = 75, falloff = VORE_SOUND_FALLOFF, frequency = noise_freq, preference = /datum/preference/toggle/digestion_noises, volume_channel = VOLUME_CHANNEL_VORE)
+
+/obj/belly/proc/resist_check_escapechance(mob/living/R, obj/item/C)
+ if(!prob(escapechance)) //Let's have it check to see if the prey escapes first.
+ return FALSE
+
+ var/escape_attempt_owner_message = span_vwarning(belly_format_string(escape_attempt_messages_owner, R))
+ var/escape_attempt_prey_message = span_vwarning(belly_format_string(escape_attempt_messages_prey, R))
+ var/escape_fail_owner_message = span_vwarning(belly_format_string(escape_fail_messages_owner, R))
+ var/escape_fail_prey_message = span_vnotice(belly_format_string(escape_fail_messages_prey, R))
+ to_chat(R, escape_attempt_prey_message)
+ to_chat(owner, escape_attempt_owner_message)
+ if(do_after(R, escapetime, target = src))
+ if(escapable && C)
+ var/escape_item_owner_message = span_vwarning(belly_format_string(escape_item_messages_owner, R, item = C))
+ var/escape_item_prey_message = span_vwarning(belly_format_string(escape_item_messages_prey, R, item = C))
+ var/escape_item_outside_message = span_vwarning(belly_format_string(escape_item_messages_outside, R, item = C))
+
+ release_specific_contents(C)
+ to_chat(R, escape_item_prey_message)
+ to_chat(owner, escape_item_owner_message)
+ if(!private_struggle)
+ for(var/mob/M in hearers(4, owner))
+ M.show_message(escape_item_outside_message, 2)
+ return TRUE
+
+ if(escapable && (R.loc == src) && !R.absorbed) //Does the owner still have escapable enabled?
+ var/escape_owner_message = span_vwarning(belly_format_string(escape_messages_owner, R))
+ var/escape_prey_message = span_vwarning(belly_format_string(escape_messages_prey, R))
+ var/escape_outside_message = span_vwarning(belly_format_string(escape_messages_outside, R))
+
+ release_specific_contents(R)
+ to_chat(R, escape_prey_message)
+ to_chat(owner, escape_owner_message)
+ if(!private_struggle)
+ for(var/mob/M in hearers(4, owner))
+ M.show_message(escape_outside_message, 2)
+ return TRUE
+
+ if(!(R.loc == src)) //Aren't even in the belly. Quietly fail.
+ return TRUE
+
+ //Belly became inescapable.
+ to_chat(R, escape_fail_prey_message)
+ to_chat(owner, escape_fail_owner_message)
+ return TRUE
+
+/obj/belly/proc/resist_check_transferchance(mob/living/R, obj/item/C)
+ if(!prob(transferchance) || !transferlocation) //Next, let's have it see if they end up getting into an even bigger mess then when they started.
+ return FALSE
+
+ var/obj/belly/dest_belly
+ for(var/obj/belly/B as anything in owner.vore_organs)
+ if(B.name == transferlocation)
+ dest_belly = B
+ break
+
+ if(!dest_belly)
+ to_chat(owner, span_vwarning("Something went wrong with your belly transfer settings. Your [lowertext(name)] has had it's transfer chance and transfer location cleared as a precaution."))
+ transferchance = 0
+ transferlocation = null
+ return TRUE
+
+ var/primary_transfer_owner_message = span_vwarning(belly_format_string(primary_transfer_messages_owner, R, dest = transferlocation))
+ var/primary_transfer_prey_message = span_vwarning(belly_format_string(primary_transfer_messages_prey, R, dest = transferlocation))
+
+ to_chat(R, primary_transfer_prey_message)
+ to_chat(owner, primary_transfer_owner_message)
+ if(C)
+ transfer_contents(C, dest_belly)
+ return TRUE
+
+ transfer_contents(R, dest_belly)
+ return TRUE
+
+/obj/belly/proc/resist_check_secondary_transferchance(mob/living/R, obj/item/C)
+ if(!prob(transferchance_secondary) || !transferlocation_secondary) //After the first potential mess getting into, run the secondary one which might be even bigger of a mess.
+ return FALSE
+
+ var/obj/belly/dest_belly
+ for(var/obj/belly/B as anything in owner.vore_organs)
+ if(B.name == transferlocation_secondary)
+ dest_belly = B
+ break
+
+ if(!dest_belly)
+ to_chat(owner, span_vwarning("Something went wrong with your belly transfer settings. Your [lowertext(name)] has had it's transfer chance and transfer location cleared as a precaution."))
+ transferchance_secondary = 0
+ transferlocation_secondary = null
+ return TRUE
+
+ var/secondary_transfer_owner_message = span_vwarning(belly_format_string(secondary_transfer_messages_owner, R, dest = transferlocation_secondary))
+ var/secondary_transfer_prey_message = span_vwarning(belly_format_string(secondary_transfer_messages_prey, R, dest = transferlocation_secondary))
+
+ to_chat(R, secondary_transfer_prey_message)
+ to_chat(owner, secondary_transfer_owner_message)
+ if(C)
+ transfer_contents(C, dest_belly)
+ return TRUE
+
+ transfer_contents(R, dest_belly)
+ return TRUE
+
+/obj/belly/proc/resist_check_absorbchance(mob/living/R)
+ if(!prob(absorbchance) || digest_mode == DM_ABSORB) //After that, let's have it run the absorb chance.
+ return FALSE
+ var/absorb_chance_owner_message = span_vwarning(belly_format_string(absorb_chance_messages_owner, R))
+ var/absorb_chance_prey_message = span_vwarning(belly_format_string(absorb_chance_messages_prey, R))
+
+ to_chat(R, absorb_chance_prey_message)
+ to_chat(owner, absorb_chance_owner_message)
+ digest_mode = DM_ABSORB
+ return TRUE
+
+/obj/belly/proc/resist_check_digestchance(mob/living/R)
+ if(!prob(digestchance) || digest_mode == DM_DIGEST) //Then, let's see if it should run the digest chance.
+ return FALSE
+ var/digest_chance_owner_message = span_vwarning(belly_format_string(digest_chance_messages_owner, R))
+ var/digest_chance_prey_message = span_vwarning(belly_format_string(digest_chance_messages_prey, R))
+
+ to_chat(R, digest_chance_prey_message)
+ to_chat(owner, digest_chance_owner_message)
+ digest_mode = DM_DIGEST
+ return TRUE
+
+/obj/belly/proc/resist_check_selectchance(mob/living/R)
+ if(!prob(selectchance) || digest_mode == DM_SELECT) //Finally, let's see if it should run the selective mode chance.
+ return FALSE
+ var/select_chance_owner_message = span_vwarning(belly_format_string(select_chance_messages_owner, R))
+ var/select_chance_prey_message = span_vwarning(belly_format_string(select_chance_messages_prey, R))
+
+ to_chat(R, select_chance_prey_message)
+ to_chat(owner, select_chance_owner_message)
+ digest_mode = DM_SELECT
+ return TRUE
+
+// Absorbed resist handling
+/obj/belly/proc/relay_absorbed_resist(mob/living/R)
+ if (!(R in contents) || !R.absorbed)
+ return // User is not in this belly or isn't actually absorbed
+
+ R.setClickCooldown(50)
+
+ if(displayed_message_flags & MS_FLAG_STRUGGLE_ABSORBED_OUTSIDE)
+ absorbed_resist_struggle_outside(R)
+
+ if(!private_struggle)
+ resist_play_sound()
+
+ //absorb resists
+ if(escapable || owner.stat) //If the stomach has escapable enabled or the owner is dead/unconscious
+ if(absorbed_resist_check_escapechance(R))
+ return
+
+ var/struggle_user_message = span_valert(belly_format_string(absorbed_struggle_messages_inside, R, use_absorbed_count = TRUE))
+ to_chat(R, struggle_user_message)
+
+/obj/belly/proc/absorbed_resist_struggle_outside(mob/living/R)
+ var/struggle_outer_message = span_valert(belly_format_string(absorbed_struggle_messages_outside, R, use_absorbed_count = TRUE))
+ if(private_struggle)
+ to_chat(owner, struggle_outer_message)
+ return
+
+ for(var/mob/M in hearers(4, owner))
+ M.show_message(struggle_outer_message, 2) // hearable
+
+/obj/belly/proc/absorbed_resist_check_escapechance(mob/living/R)
+ if(!(prob(escapechance_absorbed) || owner.stat)) //Let's have it check to see if the prey's escape attempt starts.
+ return FALSE
+ var/escape_attempt_absorbed_owner_message = span_vwarning(belly_format_string(escape_attempt_absorbed_messages_owner, R))
+ var/escape_attempt_absorbed_prey_message = span_vwarning(belly_format_string(escape_attempt_absorbed_messages_prey, R))
+
+ to_chat(R, escape_attempt_absorbed_prey_message)
+ to_chat(owner, escape_attempt_absorbed_owner_message)
+ if(do_after(R, escapetime, target = src))
+ if((escapable || owner.stat) && (R.loc == src) && prob(escapechance_absorbed)) //Does the escape attempt succeed?
+ var/escape_absorbed_owner_message = span_vwarning(belly_format_string(escape_absorbed_messages_owner, R))
+ var/escape_absorbed_prey_message = span_vwarning(belly_format_string(escape_absorbed_messages_prey, R))
+ var/escape_absorbed_outside_message = span_vwarning(belly_format_string(escape_absorbed_messages_outside, R))
+
+ release_specific_contents(R)
+ to_chat(R, escape_absorbed_prey_message)
+ to_chat(owner, escape_absorbed_owner_message)
+ if(!private_struggle)
+ for(var/mob/M in hearers(4, owner))
+ M.show_message(escape_absorbed_outside_message, 2)
+ return TRUE
+
+ if(!(R.loc == src)) //Aren't even in the belly. Quietly fail.
+ return TRUE
+
+ //Belly became inescapable or you failed your roll.
+ var/escape_fail_absorbed_owner_message = span_vwarning(belly_format_string(escape_fail_absorbed_messages_owner, R))
+ var/escape_fail_absorbed_prey_message = span_vnotice(belly_format_string(escape_fail_absorbed_messages_prey, R))
+
+ to_chat(R, escape_fail_absorbed_prey_message)
+ to_chat(owner, escape_fail_absorbed_owner_message)
+ return TRUE
diff --git a/code/modules/vore/eating/belly_obj_vfx.dm b/code/modules/vore/eating/belly_obj_vfx.dm
new file mode 100644
index 0000000000..5e42d283b5
--- /dev/null
+++ b/code/modules/vore/eating/belly_obj_vfx.dm
@@ -0,0 +1,165 @@
+// SEND_SIGNAL(COMSIG_BELLY_UPDATE_VORE_FX) is sometimes used when calling vore_fx() to send belly visuals
+// to certain non-belly atoms. Not called here as vore_fx() is usually only called if a mob is in the belly.
+// Don't forget it if you need to rework vore_fx().
+/obj/belly/proc/vore_fx(mob/living/L, var/severity = 0)
+ if(!istype(L))
+ return
+ if(!L.client)
+ return
+ if(L.previewing_belly && L.previewing_belly != src)
+ return
+ if(L.previewing_belly == src && L.vore_selected != src)
+ L.previewing_belly = null
+ return
+ if(!L.show_vore_fx)
+ L.clear_fullscreen("belly")
+ L.previewing_belly = null
+ return
+ if(!belly_fullscreen)
+ L.clear_fullscreen("belly")
+ check_hud_disable(L)
+ return
+
+ if(colorization_enabled)
+ var/atom/movable/screen/fullscreen/F = L.overlay_fullscreen("belly", /atom/movable/screen/fullscreen/belly, severity) // preserving save data
+ var/datum/belly_overlays/lookup_belly_path = text2path("/datum/belly_overlays/[lowertext(belly_fullscreen)]")
+ if(!lookup_belly_path)
+ var/used_fullscreen = belly_fullscreen
+ to_chat(owner, span_warning("The belly overlay ([used_fullscreen]) you've selected for [src] no longer exists. Please reselect your overlay."))
+ belly_fullscreen = null
+ log_runtime("Icon datum was not defined for [used_fullscreen]")
+
+ var/alpha = min(belly_fullscreen_alpha, L.max_voreoverlay_alpha)
+ F.icon = initial(lookup_belly_path.belly_icon)
+ F.cut_overlays()
+ var/image/I = image(F.icon, belly_fullscreen) //Would be cool if I could just include color and alpha in the image define so we don't have to copy paste
+ I.color = belly_fullscreen_color
+ I.alpha = alpha
+ F.add_overlay(I)
+ I = image(F.icon, belly_fullscreen+"-2")
+ I.color = belly_fullscreen_color2
+ I.alpha = alpha
+ F.add_overlay(I)
+ I = image(F.icon, belly_fullscreen+"-3")
+ I.color = belly_fullscreen_color3
+ I.alpha = alpha
+ F.add_overlay(I)
+ I = image(F.icon, belly_fullscreen+"-4")
+ I.color = belly_fullscreen_color4
+ I.alpha = alpha
+ F.add_overlay(I)
+ var/extra_mush = 0
+ var/extra_mush_color = mush_color
+ if(L.liquidbelly_visuals && ishuman(owner) && metabolism_overlay && metabolism_mush_ratio > 0)
+ var/mob/living/carbon/human/H = owner
+ var/datum/reagents/metabolism/ingested = H.ingested
+ if(ingested && ingested.total_volume > 0)
+ if(custom_ingested_color)
+ extra_mush_color = custom_ingested_color
+ else
+ extra_mush_color = ingested.get_color()
+ extra_mush = ingested.total_volume * metabolism_mush_ratio
+ if(!mush_overlay)
+ I = get_mush_overlay(extra_mush_color, min(custom_ingested_alpha, L.max_voreoverlay_alpha), max_ingested, ingested.total_volume)
+ F.add_overlay(I)
+ if(show_liquids && L.liquidbelly_visuals && mush_overlay && (owner.nutrition > 0 || max_mush == 0 || min_mush > 0 || (LAZYLEN(contents) * item_mush_val) > 0))
+ I = get_mush_overlay(mush_color, min(mush_alpha, L.max_voreoverlay_alpha), max_mush, owner.nutrition + LAZYLEN(contents) * item_mush_val + extra_mush)
+ var/stored_y = I.pixel_y
+ F.add_overlay(I)
+ if(metabolism_overlay && metabolism_mush_ratio > 0 && extra_mush > 0)
+ var/total_mush_content = owner.nutrition + LAZYLEN(contents) * item_mush_val + extra_mush
+ I = get_mush_extra_overlay(extra_mush_color, min(mush_alpha, (extra_mush / max(total_mush_content, 1)) * mush_alpha), stored_y)
+ F.add_overlay(I)
+ if(show_liquids && L.liquidbelly_visuals && liquid_overlay && reagents.total_volume)
+ I = get_liquid_overlay()
+ I.alpha = min(I.alpha, L.max_voreoverlay_alpha)
+ F.add_overlay(I)
+ F.update_for_view(L.client.view)
+ return
+
+ var/atom/movable/screen/fullscreen/F = L.overlay_fullscreen("belly", /atom/movable/screen/fullscreen/belly/fixed, severity) //preserving save data
+ F.icon = 'icons/mob/vore_fullscreens/ui_lists/screen_full_vore.dmi'
+ F.cut_overlays()
+ F.add_overlay(image(F.icon, belly_fullscreen))
+ F.add_overlay(image(F.icon, belly_fullscreen+"-2"))
+ F.add_overlay(image(F.icon, belly_fullscreen+"-3"))
+ F.add_overlay(image(F.icon, belly_fullscreen+"-4"))
+ var/image/I
+ var/extra_mush = 0
+ var/extra_mush_color = mush_color
+ if(L.liquidbelly_visuals && ishuman(owner) && metabolism_overlay && metabolism_mush_ratio > 0)
+ var/mob/living/carbon/human/H = owner
+ var/datum/reagents/metabolism/ingested = H.ingested
+ if(ingested && ingested.total_volume > 0)
+ if(custom_ingested_color)
+ extra_mush_color = custom_ingested_color
+ else
+ extra_mush_color = ingested.get_color()
+ extra_mush = ingested.total_volume * metabolism_mush_ratio
+ if(!mush_overlay)
+ I = get_mush_overlay(extra_mush_color, custom_ingested_alpha, max_ingested, ingested.total_volume)
+ F.add_overlay(I)
+ if(show_liquids && L.liquidbelly_visuals && mush_overlay && (owner.nutrition > 0 || max_mush == 0 || min_mush > 0 || (LAZYLEN(contents) * item_mush_val) > 0))
+ I = get_mush_overlay(mush_color, mush_alpha, max_mush, owner.nutrition + LAZYLEN(contents) * item_mush_val + extra_mush)
+ I.alpha = mush_alpha
+ var/stored_y = I.pixel_y
+ F.add_overlay(I)
+ if(metabolism_overlay && metabolism_mush_ratio > 0 && extra_mush > 0)
+ var/total_mush_content = owner.nutrition + LAZYLEN(contents) * item_mush_val + extra_mush
+ I = get_mush_extra_overlay(extra_mush_color, min(mush_alpha, (extra_mush / max(total_mush_content, 1)) * mush_alpha), stored_y)
+ F.add_overlay(I)
+ if(show_liquids && L.liquidbelly_visuals && liquid_overlay && reagents.total_volume)
+ I = get_liquid_overlay()
+ F.add_overlay(I)
+ F.update_for_view(L.client.view)
+ check_hud_disable(L)
+
+/obj/belly/proc/check_hud_disable(var/mob/living/living_prey)
+ if(disable_hud && living_prey != owner)
+ if(living_prey?.hud_used?.hud_shown)
+ to_chat(living_prey, span_vnotice("((Your pred has disabled huds in their belly. Turn off vore FX and hit F12 to get it back; or relax, and enjoy the serenity.))"))
+ living_prey.toggle_hud_vis(TRUE)
+
+/obj/belly/proc/get_mush_overlay(color, alpha, limit, content)
+ var/image/I = image('icons/mob/vore_fullscreens/bubbles.dmi', "mush")
+ I.color = color
+ I.pixel_y = -450 + (450 / max(limit, 1) * max(min(limit, content), 1))
+ if(I.pixel_y < -450 + (450 / 100 * min_mush))
+ I.pixel_y = -450 + (450 / 100 * min_mush)
+ I.alpha = alpha
+ return I
+
+/obj/belly/proc/get_mush_extra_overlay(color, alpha, stored_y)
+ var/image/I = image('icons/mob/vore_fullscreens/bubbles.dmi', "mush")
+ I.color = color
+ I.pixel_y = stored_y
+ I.alpha = alpha
+ return I
+
+/obj/belly/proc/get_liquid_overlay()
+ var/image/I
+ if(digest_mode == DM_HOLD && item_digest_mode == IM_HOLD)
+ I = image('icons/mob/vore_fullscreens/bubbles.dmi', "calm")
+ else
+ I = image('icons/mob/vore_fullscreens/bubbles.dmi', "bubbles")
+ if(custom_reagentcolor)
+ I.color = custom_reagentcolor
+ else
+ I.color = reagentcolor
+ if(custom_reagentalpha)
+ I.alpha = custom_reagentalpha
+ else
+ I.alpha = max(150, min(custom_max_volume, 255)) - (255 - belly_fullscreen_alpha)
+ I.pixel_y = -450 + min((450 / custom_max_volume * reagents.total_volume), 450 / 100 * max_liquid_level)
+ return I
+
+/obj/belly/proc/vore_preview(mob/living/L)
+ if(!istype(L) || !L.client)
+ L.previewing_belly = null
+ return
+ L.previewing_belly = src
+ vore_fx(L)
+
+/obj/belly/proc/clear_preview(mob/living/L)
+ L.previewing_belly = null
+ L.clear_fullscreen("belly")
diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm
index fe091d19c8..626e89230c 100644
--- a/code/modules/vore/eating/belly_obj_vr.dm
+++ b/code/modules/vore/eating/belly_obj_vr.dm
@@ -664,181 +664,6 @@
// Note, this should be refactored to drop priority overlays
I.add_overlay(I.d_stage_overlay, TRUE)
-// SEND_SIGNAL(COMSIG_BELLY_UPDATE_VORE_FX) is sometimes used when calling vore_fx() to send belly visuals
-// to certain non-belly atoms. Not called here as vore_fx() is usually only called if a mob is in the belly.
-// Don't forget it if you need to rework vore_fx().
-/obj/belly/proc/vore_fx(mob/living/L, var/severity = 0)
- if(!istype(L))
- return
- if(!L.client)
- return
- if(L.previewing_belly && L.previewing_belly != src)
- return
- if(L.previewing_belly == src && L.vore_selected != src)
- L.previewing_belly = null
- return
- if(!L.show_vore_fx)
- L.clear_fullscreen("belly")
- L.previewing_belly = null
- return
- if(belly_fullscreen)
- if(colorization_enabled)
- var/atom/movable/screen/fullscreen/F = L.overlay_fullscreen("belly", /atom/movable/screen/fullscreen/belly, severity) // preserving save data
- var/datum/belly_overlays/lookup_belly_path = text2path("/datum/belly_overlays/[lowertext(belly_fullscreen)]")
- if(!lookup_belly_path)
- var/used_fullscreen = belly_fullscreen
- to_chat(owner, span_warning("The belly overlay ([used_fullscreen]) you've selected for [src] no longer exists. Please reselect your overlay."))
- belly_fullscreen = null
- log_runtime("Icon datum was not defined for [used_fullscreen]")
-
- var/alpha = min(belly_fullscreen_alpha, L.max_voreoverlay_alpha)
- F.icon = initial(lookup_belly_path.belly_icon)
- F.cut_overlays()
- var/image/I = image(F.icon, belly_fullscreen) //Would be cool if I could just include color and alpha in the image define so we don't have to copy paste
- I.color = belly_fullscreen_color
- I.alpha = alpha
- F.add_overlay(I)
- I = image(F.icon, belly_fullscreen+"-2")
- I.color = belly_fullscreen_color2
- I.alpha = alpha
- F.add_overlay(I)
- I = image(F.icon, belly_fullscreen+"-3")
- I.color = belly_fullscreen_color3
- I.alpha = alpha
- F.add_overlay(I)
- I = image(F.icon, belly_fullscreen+"-4")
- I.color = belly_fullscreen_color4
- I.alpha = alpha
- F.add_overlay(I)
- var/extra_mush = 0
- var/extra_mush_color = mush_color
- if(L.liquidbelly_visuals && ishuman(owner) && metabolism_overlay && metabolism_mush_ratio > 0)
- var/mob/living/carbon/human/H = owner
- var/datum/reagents/metabolism/ingested = H.ingested
- if(ingested && ingested.total_volume > 0)
- if(custom_ingested_color)
- extra_mush_color = custom_ingested_color
- else
- extra_mush_color = ingested.get_color()
- extra_mush = ingested.total_volume * metabolism_mush_ratio
- if(!mush_overlay)
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "mush")
- I.color = extra_mush_color
- I.alpha = min(custom_ingested_alpha, L.max_voreoverlay_alpha)
- I.pixel_y = -450 + ((450 / max(max_ingested, 1)) * min(max_ingested, ingested.total_volume))
- F.add_overlay(I)
- if(show_liquids && L.liquidbelly_visuals && mush_overlay && (owner.nutrition > 0 || max_mush == 0 || min_mush > 0 || (LAZYLEN(contents) * item_mush_val) > 0))
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "mush")
- I.color = mush_color
- I.alpha = min(mush_alpha, L.max_voreoverlay_alpha)
- var/total_mush_content = owner.nutrition + LAZYLEN(contents) * item_mush_val + extra_mush
- I.pixel_y = -450 + (450 / max(max_mush, 1) * max(min(max_mush, total_mush_content), 1))
- if(I.pixel_y < -450 + (450 / 100 * min_mush))
- I.pixel_y = -450 + (450 / 100 * min_mush)
- var/stored_y = I.pixel_y
- F.add_overlay(I)
- if(metabolism_overlay && metabolism_mush_ratio > 0 && extra_mush > 0)
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "mush")
- I.color = extra_mush_color
- I.alpha = min(mush_alpha, (extra_mush / max(total_mush_content, 1)) * mush_alpha)
- I.pixel_y = stored_y
- F.add_overlay(I)
- if(show_liquids && L.liquidbelly_visuals && liquid_overlay && reagents.total_volume)
- if(digest_mode == DM_HOLD && item_digest_mode == IM_HOLD)
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "calm")
- else
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "bubbles")
- if(custom_reagentcolor)
- I.color = custom_reagentcolor
- else
- I.color = reagentcolor
- if(custom_reagentalpha)
- I.alpha = custom_reagentalpha
- else
- I.alpha = max(150, min(custom_max_volume, 255)) - (255 - belly_fullscreen_alpha)
- I.pixel_y = -450 + min((450 / custom_max_volume * reagents.total_volume), 450 / 100 * max_liquid_level)
- I.alpha = min(I.alpha, L.max_voreoverlay_alpha)
- F.add_overlay(I)
- F.update_for_view(L.client.view)
- else
- var/atom/movable/screen/fullscreen/F = L.overlay_fullscreen("belly", /atom/movable/screen/fullscreen/belly/fixed, severity) //preserving save data
- F.icon = 'icons/mob/vore_fullscreens/ui_lists/screen_full_vore.dmi'
- F.cut_overlays()
- F.add_overlay(image(F.icon, belly_fullscreen))
- F.add_overlay(image(F.icon, belly_fullscreen+"-2"))
- F.add_overlay(image(F.icon, belly_fullscreen+"-3"))
- F.add_overlay(image(F.icon, belly_fullscreen+"-4"))
- var/image/I
- var/extra_mush = 0
- var/extra_mush_color = mush_color
- if(L.liquidbelly_visuals && ishuman(owner) && metabolism_overlay && metabolism_mush_ratio > 0)
- var/mob/living/carbon/human/H = owner
- var/datum/reagents/metabolism/ingested = H.ingested
- if(ingested && ingested.total_volume > 0)
- if(custom_ingested_color)
- extra_mush_color = custom_ingested_color
- else
- extra_mush_color = ingested.get_color()
- extra_mush = ingested.total_volume * metabolism_mush_ratio
- if(!mush_overlay)
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "mush")
- I.color = extra_mush_color
- I.alpha = custom_ingested_alpha
- I.pixel_y = -450 + (450 / max(max_ingested, 1) * max(min(max_ingested, ingested.total_volume), 1))
- F.add_overlay(I)
- if(show_liquids && L.liquidbelly_visuals && mush_overlay && (owner.nutrition > 0 || max_mush == 0 || min_mush > 0 || (LAZYLEN(contents) * item_mush_val) > 0))
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "mush")
- I.color = mush_color
- I.alpha = mush_alpha
- var/total_mush_content = owner.nutrition + LAZYLEN(contents) * item_mush_val + extra_mush
- I.pixel_y = -450 + (450 / max(max_mush, 1) * max(min(max_mush, total_mush_content), 1))
- if(I.pixel_y < -450 + (450 / 100 * min_mush))
- I.pixel_y = -450 + (450 / 100 * min_mush)
- var/stored_y = I.pixel_y
- F.add_overlay(I)
- if(metabolism_overlay && metabolism_mush_ratio > 0 && extra_mush > 0)
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "mush")
- I.color = extra_mush_color
- I.alpha = min(mush_alpha, (extra_mush / max(total_mush_content, 1)) * mush_alpha)
- I.pixel_y = stored_y
- F.add_overlay(I)
- if(show_liquids && L.liquidbelly_visuals && liquid_overlay && reagents.total_volume)
- if(digest_mode == DM_HOLD && item_digest_mode == IM_HOLD)
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "calm")
- else
- I = image('icons/mob/vore_fullscreens/bubbles.dmi', "bubbles")
- if(custom_reagentcolor)
- I.color = custom_reagentcolor
- else
- I.color = reagentcolor
- if(custom_reagentalpha)
- I.alpha = custom_reagentalpha
- else
- I.alpha = max(150, min(custom_max_volume, 255)) - (255 - belly_fullscreen_alpha)
- I.pixel_y = -450 + min((450 / custom_max_volume * reagents.total_volume), 450 / 100 * max_liquid_level)
- F.add_overlay(I)
- F.update_for_view(L.client.view)
- else
- L.clear_fullscreen("belly")
-
- if(disable_hud && L != owner)
- if(L?.hud_used?.hud_shown)
- to_chat(L, span_vnotice("((Your pred has disabled huds in their belly. Turn off vore FX and hit F12 to get it back; or relax, and enjoy the serenity.))"))
- L.toggle_hud_vis(TRUE)
-
-/obj/belly/proc/vore_preview(mob/living/L)
- if(!istype(L) || !L.client)
- L.previewing_belly = null
- return
- L.previewing_belly = src
- vore_fx(L)
-
-/obj/belly/proc/clear_preview(mob/living/L)
- L.previewing_belly = null
- L.clear_fullscreen("belly")
-
-
-
// Release all contents of this belly into the owning mob's location.
// If that location is another mob, contents are transferred into whichever of its bellies the owning mob is in.
// Returns the number of mobs so released.
@@ -1270,243 +1095,6 @@
/obj/belly/onDropInto(atom/movable/AM)
return null
-//Handle a mob struggling
-// Called from /mob/living/carbon/relaymove()
-/obj/belly/proc/relay_resist(mob/living/R, obj/item/C)
- if (!(R in contents))
- if(!C)
- return // User is not in this belly
-
- R.setClickCooldown(50)
-
- var/escape_attempt_owner_message = span_vwarning(belly_format_string(escape_attempt_messages_owner, R))
- var/escape_attempt_prey_message = span_vwarning(belly_format_string(escape_attempt_messages_prey, R))
- var/escape_fail_owner_message = span_vwarning(belly_format_string(escape_fail_messages_owner, R))
- var/escape_fail_prey_message = span_vnotice(belly_format_string(escape_fail_messages_prey, R))
-
- if(owner.stat) //If owner is stat (dead, KO) we can actually escape
- escape_attempt_prey_message = span_vwarning("[escape_attempt_prey_message] (will take around [escapetime/10] seconds.)")
- to_chat(R, escape_attempt_prey_message)
- to_chat(owner, escape_attempt_owner_message)
-
- if(do_after(R, escapetime, owner, target = src, timed_action_flags = IGNORE_INCAPACITATED))
- if((owner.stat || escapable)) //Can still escape?
- if(C)
- release_specific_contents(C)
- return
- if(R.loc == src)
- release_specific_contents(R)
- return
- else if(R.loc != src) //Aren't even in the belly. Quietly fail.
- return
- else //Belly became inescapable or mob revived
- to_chat(R, escape_fail_prey_message)
- to_chat(owner, escape_fail_owner_message)
- return
- return
-
- var/struggle_user_message = span_valert(belly_format_string(struggle_messages_inside, R))
-
- if(displayed_message_flags & MS_FLAG_STRUGGLE_OUTSIDE)
- var/struggle_outer_message = span_valert(belly_format_string(struggle_messages_outside, R))
- if(private_struggle)
- to_chat(owner, struggle_outer_message)
- else
- for(var/mob/M in hearers(4, owner))
- M.show_message(struggle_outer_message, 2) // hearable
-
- var/sound/struggle_snuggle
- var/sound/struggle_rustle = sound(get_sfx("rustle"))
-
- if((vore_sprite_flags & DM_FLAG_VORESPRITE_BELLY) && (owner.vore_capacity_ex[belly_sprite_to_affect] >= 1) && !private_struggle && resist_triggers_animation && affects_vore_sprites)
- owner.vs_animate(belly_sprite_to_affect)
-
- if(!private_struggle)
- if(is_wet)
- if(!fancy_vore)
- struggle_snuggle = sound(get_sfx("classic_struggle_sounds"))
- else
- struggle_snuggle = sound(get_sfx("fancy_prey_struggle"))
- playsound(src, struggle_snuggle, vary = 1, vol = 75, falloff = VORE_SOUND_FALLOFF, frequency = noise_freq, preference = /datum/preference/toggle/digestion_noises, volume_channel = VOLUME_CHANNEL_VORE)
- else
- playsound(src, struggle_rustle, vary = 1, vol = 75, falloff = VORE_SOUND_FALLOFF, frequency = noise_freq, preference = /datum/preference/toggle/digestion_noises, volume_channel = VOLUME_CHANNEL_VORE)
- if(prob(belchchance))//Unsure if this should go in escapable or not, leaving it here for now.
- owner.emote("belch")
- if(escapable) //If the stomach has escapable enabled.
- if(prob(escapechance)) //Let's have it check to see if the prey escapes first.
- to_chat(R, escape_attempt_prey_message)
- to_chat(owner, escape_attempt_owner_message)
- if(do_after(R, escapetime, target = src))
- if(escapable && C)
- var/escape_item_owner_message = span_vwarning(belly_format_string(escape_item_messages_owner, R, item = C))
- var/escape_item_prey_message = span_vwarning(belly_format_string(escape_item_messages_prey, R, item = C))
- var/escape_item_outside_message = span_vwarning(belly_format_string(escape_item_messages_outside, R, item = C))
-
- release_specific_contents(C)
- to_chat(R, escape_item_prey_message)
- to_chat(owner, escape_item_owner_message)
- if(!private_struggle)
- for(var/mob/M in hearers(4, owner))
- M.show_message(escape_item_outside_message, 2)
- return
- if(escapable && (R.loc == src) && !R.absorbed) //Does the owner still have escapable enabled?
- var/escape_owner_message = span_vwarning(belly_format_string(escape_messages_owner, R))
- var/escape_prey_message = span_vwarning(belly_format_string(escape_messages_prey, R))
- var/escape_outside_message = span_vwarning(belly_format_string(escape_messages_outside, R))
-
- release_specific_contents(R)
- to_chat(R, escape_prey_message)
- to_chat(owner, escape_owner_message)
- if(!private_struggle)
- for(var/mob/M in hearers(4, owner))
- M.show_message(escape_outside_message, 2)
- return
- else if(!(R.loc == src)) //Aren't even in the belly. Quietly fail.
- return
- else //Belly became inescapable.
- to_chat(R, escape_fail_prey_message)
- to_chat(owner, escape_fail_owner_message)
- return
-
- else if(prob(transferchance) && transferlocation) //Next, let's have it see if they end up getting into an even bigger mess then when they started.
- var/obj/belly/dest_belly
- for(var/obj/belly/B as anything in owner.vore_organs)
- if(B.name == transferlocation)
- dest_belly = B
- break
-
- if(!dest_belly)
- to_chat(owner, span_vwarning("Something went wrong with your belly transfer settings. Your [lowertext(name)] has had it's transfer chance and transfer location cleared as a precaution."))
- transferchance = 0
- transferlocation = null
- return
- var/primary_transfer_owner_message = span_vwarning(belly_format_string(primary_transfer_messages_owner, R, dest = transferlocation))
- var/primary_transfer_prey_message = span_vwarning(belly_format_string(primary_transfer_messages_prey, R, dest = transferlocation))
-
- to_chat(R, primary_transfer_prey_message)
- to_chat(owner, primary_transfer_owner_message)
- if(C)
- transfer_contents(C, dest_belly)
- return
- transfer_contents(R, dest_belly)
- return
-
- else if(prob(transferchance_secondary) && transferlocation_secondary) //After the first potential mess getting into, run the secondary one which might be even bigger of a mess.
- var/obj/belly/dest_belly
- for(var/obj/belly/B as anything in owner.vore_organs)
- if(B.name == transferlocation_secondary)
- dest_belly = B
- break
-
- if(!dest_belly)
- to_chat(owner, span_vwarning("Something went wrong with your belly transfer settings. Your [lowertext(name)] has had it's transfer chance and transfer location cleared as a precaution."))
- transferchance_secondary = 0
- transferlocation_secondary = null
- return
-
- var/secondary_transfer_owner_message = span_vwarning(belly_format_string(secondary_transfer_messages_owner, R, dest = transferlocation_secondary))
- var/secondary_transfer_prey_message = span_vwarning(belly_format_string(secondary_transfer_messages_prey, R, dest = transferlocation_secondary))
-
- to_chat(R, secondary_transfer_prey_message)
- to_chat(owner, secondary_transfer_owner_message)
- if(C)
- transfer_contents(C, dest_belly)
- return
- transfer_contents(R, dest_belly)
- return
-
- else if(prob(absorbchance) && digest_mode != DM_ABSORB) //After that, let's have it run the absorb chance.
- var/absorb_chance_owner_message = span_vwarning(belly_format_string(absorb_chance_messages_owner, R))
- var/absorb_chance_prey_message = span_vwarning(belly_format_string(absorb_chance_messages_prey, R))
-
- to_chat(R, absorb_chance_prey_message)
- to_chat(owner, absorb_chance_owner_message)
- digest_mode = DM_ABSORB
- return
-
- else if(prob(digestchance) && digest_mode != DM_DIGEST) //Then, let's see if it should run the digest chance.
- var/digest_chance_owner_message = span_vwarning(belly_format_string(digest_chance_messages_owner, R))
- var/digest_chance_prey_message = span_vwarning(belly_format_string(digest_chance_messages_prey, R))
-
- to_chat(R, digest_chance_prey_message)
- to_chat(owner, digest_chance_owner_message)
- digest_mode = DM_DIGEST
- return
- else if(prob(selectchance) && digest_mode != DM_SELECT) //Finally, let's see if it should run the selective mode chance.
- var/select_chance_owner_message = span_vwarning(belly_format_string(select_chance_messages_owner, R))
- var/select_chance_prey_message = span_vwarning(belly_format_string(select_chance_messages_prey, R))
-
- to_chat(R, select_chance_prey_message)
- to_chat(owner, select_chance_owner_message)
- digest_mode = DM_SELECT
-
- else //Nothing interesting happened.
- to_chat(R, struggle_user_message)
- to_chat(owner, span_vwarning("Your prey appears to be unable to make any progress in escaping your [lowertext(name)]."))
- return
- to_chat(R, struggle_user_message)
-
-/obj/belly/proc/relay_absorbed_resist(mob/living/R)
- if (!(R in contents) || !R.absorbed)
- return // User is not in this belly or isn't actually absorbed
-
- R.setClickCooldown(50)
-
- var/struggle_user_message = span_valert(belly_format_string(absorbed_struggle_messages_inside, R, use_absorbed_count = TRUE))
-
- if(displayed_message_flags & MS_FLAG_STRUGGLE_ABSORBED_OUTSIDE)
- var/struggle_outer_message = span_valert(belly_format_string(absorbed_struggle_messages_outside, R, use_absorbed_count = TRUE))
- if(private_struggle)
- to_chat(owner, struggle_outer_message)
- else
- for(var/mob/M in hearers(4, owner))
- M.show_message(struggle_outer_message, 2) // hearable
-
- var/sound/struggle_snuggle
- var/sound/struggle_rustle = sound(get_sfx("rustle"))
-
- if(!private_struggle)
- if(is_wet)
- if(!fancy_vore)
- struggle_snuggle = sound(get_sfx("classic_struggle_sounds"))
- else
- struggle_snuggle = sound(get_sfx("fancy_prey_struggle"))
- playsound(src, struggle_snuggle, vary = 1, vol = 75, falloff = VORE_SOUND_FALLOFF, frequency = noise_freq, preference = /datum/preference/toggle/digestion_noises, volume_channel = VOLUME_CHANNEL_VORE)
- else
- playsound(src, struggle_rustle, vary = 1, vol = 75, falloff = VORE_SOUND_FALLOFF, frequency = noise_freq, preference = /datum/preference/toggle/digestion_noises, volume_channel = VOLUME_CHANNEL_VORE)
-
- //absorb resists
- if(escapable || owner.stat) //If the stomach has escapable enabled or the owner is dead/unconscious
- if(prob(escapechance) || owner.stat) //Let's have it check to see if the prey's escape attempt starts.
- var/escape_attempt_absorbed_owner_message = span_vwarning(belly_format_string(escape_attempt_absorbed_messages_owner, R))
- var/escape_attempt_absorbed_prey_message = span_vwarning(belly_format_string(escape_attempt_absorbed_messages_prey, R))
-
- to_chat(R, escape_attempt_absorbed_prey_message)
- to_chat(owner, escape_attempt_absorbed_owner_message)
- if(do_after(R, escapetime, target = src))
- if((escapable || owner.stat) && (R.loc == src) && prob(escapechance_absorbed)) //Does the escape attempt succeed?
- var/escape_absorbed_owner_message = span_vwarning(belly_format_string(escape_absorbed_messages_owner, R))
- var/escape_absorbed_prey_message = span_vwarning(belly_format_string(escape_absorbed_messages_prey, R))
- var/escape_absorbed_outside_message = span_vwarning(belly_format_string(escape_absorbed_messages_outside, R))
-
- release_specific_contents(R)
- to_chat(R, escape_absorbed_prey_message)
- to_chat(owner, escape_absorbed_owner_message)
- if(!private_struggle)
- for(var/mob/M in hearers(4, owner))
- M.show_message(escape_absorbed_outside_message, 2)
- return
- else if(!(R.loc == src)) //Aren't even in the belly. Quietly fail.
- return
- else //Belly became inescapable or you failed your roll.
- var/escape_fail_absorbed_owner_message = span_vwarning(belly_format_string(escape_fail_absorbed_messages_owner, R))
- var/escape_fail_absorbed_prey_message = span_vnotice(belly_format_string(escape_fail_absorbed_messages_prey, R))
-
- to_chat(R, escape_fail_absorbed_prey_message)
- to_chat(owner, escape_fail_absorbed_owner_message)
- return
- to_chat(R, struggle_user_message)
-
/obj/belly/proc/get_mobs_and_objs_in_belly()
var/list/see = list()
var/list/belly_mobs = list()
diff --git a/vorestation.dme b/vorestation.dme
index d4170ca9bb..708c3f5f93 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -5002,6 +5002,8 @@
#include "code\modules\vore\eating\belly_import.dm"
#include "code\modules\vore\eating\belly_messages.dm"
#include "code\modules\vore\eating\belly_obj_liquids.dm"
+#include "code\modules\vore\eating\belly_obj_resist.dm"
+#include "code\modules\vore\eating\belly_obj_vfx.dm"
#include "code\modules\vore\eating\belly_obj_vr.dm"
#include "code\modules\vore\eating\bellymodes_datum_vr.dm"
#include "code\modules\vore\eating\bellymodes_vr.dm"