From 82e0256d3ef471cda8f5148ce6e26eccc71c3fcb Mon Sep 17 00:00:00 2001 From: Nadyr <41974248+Darlantanis@users.noreply.github.com> Date: Sat, 22 Jul 2023 18:23:26 -0400 Subject: [PATCH] Capture crystal vore VFX and vore helper procs (#6632) --- code/__defines/belly_modes_ch.dm | 3 + code/__defines/dcs/signals_ch.dm | 6 + code/game/atoms_movable_ch.dm | 7 + .../objects/items/weapons/capture_crystal.dm | 5 + code/modules/mob/living/login.dm | 1 + code/modules/vore/eating/belly_obj_ch.dm | 5 +- code/modules/vore/eating/belly_obj_vr.dm | 27 ++-- code/modules/vore/eating/bellymodes_vr.dm | 1 + code/modules/vore/eating/living_ch.dm | 17 ++- code/modules/vore/eating/living_vr.dm | 5 +- .../objects/items/weapons/capture_crystal.dm | 128 ++++++++++++++++++ vorestation.dme | 1 + 12 files changed, 191 insertions(+), 15 deletions(-) create mode 100644 code/__defines/dcs/signals_ch.dm diff --git a/code/__defines/belly_modes_ch.dm b/code/__defines/belly_modes_ch.dm index defda89677..f1d93694f8 100644 --- a/code/__defines/belly_modes_ch.dm +++ b/code/__defines/belly_modes_ch.dm @@ -13,3 +13,6 @@ #define DM_FLAG_VORESPRITE_TAIL 0x2 #define DM_FLAG_VORESPRITE_MARKING 0x4 #define DM_FLAG_VORESPRITE_ARTICLE 0x8 + +//For belly fullscreen shennanigans outside of bellies, due to Life() clearing belly fullscreens outside of bellies. +#define ATOM_BELLY_FULLSCREEN "belly_atom_vfx" diff --git a/code/__defines/dcs/signals_ch.dm b/code/__defines/dcs/signals_ch.dm new file mode 100644 index 0000000000..2876a0acc5 --- /dev/null +++ b/code/__defines/dcs/signals_ch.dm @@ -0,0 +1,6 @@ +// Bellies + +///from /obj/belly/HandleBellyReagents() and /obj/belly/update_internal_overlay() +#define COMSIG_BELLY_UPDATE_VORE_FX "update_vore_fx" +///from /obj/belly/process() +#define COMSIG_BELLY_UPDATE_PREY_LOOP "update_prey_loop" diff --git a/code/game/atoms_movable_ch.dm b/code/game/atoms_movable_ch.dm index 33c966a3e0..a01d047e5a 100644 --- a/code/game/atoms_movable_ch.dm +++ b/code/game/atoms_movable_ch.dm @@ -49,3 +49,10 @@ return for (var/atom/movable/location as anything in get_nested_locs(src)|src) LAZYOR(location.recursive_listeners, arrived.recursive_listeners) + +// Helper procs called on entering/exiting a belly. Does nothing by default, override on children for special behavior. +/atom/movable/proc/enter_belly(obj/belly/B) + return + +/atom/movable/proc/exit_belly(obj/belly/B) + return diff --git a/code/game/objects/items/weapons/capture_crystal.dm b/code/game/objects/items/weapons/capture_crystal.dm index 3b982d39ae..1726b9fe8d 100644 --- a/code/game/objects/items/weapons/capture_crystal.dm +++ b/code/game/objects/items/weapons/capture_crystal.dm @@ -36,6 +36,11 @@ if(owner) UnregisterSignal(owner, COMSIG_PARENT_QDELETING) owner = null + if(in_gut) // CHOMPedit start + UnregisterSignal(in_gut, COMSIG_PARENT_QDELETING) + UnregisterSignal(in_gut, COMSIG_BELLY_UPDATE_VORE_FX) + UnregisterSignal(in_gut, COMSIG_BELLY_UPDATE_PREY_LOOP) + in_gut = null // CHOMPedit end return ..() /obj/item/capture_crystal/examine(user) diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index 7d2f490890..062bc6c800 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -22,6 +22,7 @@ verbs |= /mob/living/proc/mute_entry //CHOMPEdit verbs |= /mob/living/proc/center_offset //CHOMPEdit verbs |= /mob/living/proc/liquidbelly_visuals //CHOMPEdit + verbs |= /mob/living/proc/fix_vore_effects //CHOMPedit if(!no_vore) verbs |= /mob/living/proc/vorebelly_printout diff --git a/code/modules/vore/eating/belly_obj_ch.dm b/code/modules/vore/eating/belly_obj_ch.dm index cca366f995..bbcc35747a 100644 --- a/code/modules/vore/eating/belly_obj_ch.dm +++ b/code/modules/vore/eating/belly_obj_ch.dm @@ -169,7 +169,8 @@ gen_interval = 0 else gen_interval++ - if(reagents.total_volume) + if(reagents.total_volume && LAZYLEN(contents)) + SEND_SIGNAL(src, COMSIG_BELLY_UPDATE_VORE_FX, FALSE, reagents.total_volume) // Signals vore_fx() reagents updates. for(var/mob/living/L in contents) if(L.digestable && digest_mode == DM_DIGEST) if(reagents.total_volume) @@ -469,6 +470,8 @@ /////////////////////////// CHOMP PCL END /////////////////////////// /obj/belly/proc/update_internal_overlay() + if(LAZYLEN(contents)) + SEND_SIGNAL(src, COMSIG_BELLY_UPDATE_VORE_FX, TRUE) // Signals vore_fx() to listening atoms. Atoms must handle appropriate isliving() checks. for(var/A in contents) if(isliving(A)) vore_fx(A,1) diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm index 238d556dc2..7be498b3aa 100644 --- a/code/modules/vore/eating/belly_obj_vr.dm +++ b/code/modules/vore/eating/belly_obj_vr.dm @@ -348,6 +348,7 @@ if(!owner) thing.forceMove(get_turf(src)) return + thing.enter_belly(src) // Atom movable proc, does nothing by default. Overridden in children for special behavior. if(owner && istype(owner.loc,/turf/simulated) && !cycle_sloshed && reagents.total_volume > 0) var/turf/simulated/T = owner.loc var/S = pick(T.vorefootstep_sounds["human"]) @@ -422,15 +423,15 @@ to_chat(M, "You splash into a pool of [reagent_name]!") else if(count_items_for_sprite) //CHOMPEdit - If this is enabled also update fullness for non-living things owner.update_fullness() //CHOMPEdit - This is run whenever a belly's contents are changed. - if(istype(thing, /obj/item/capture_crystal)) //CHOMPEdit: Capture crystal occupant gets to see belly text too. - var/obj/item/capture_crystal/CC = thing - if(CC.bound_mob && desc) - if(CC.bound_mob in CC.contents) - var/formatted_desc - formatted_desc = replacetext(desc, "%belly", lowertext(name)) //replace with this belly's name - formatted_desc = replacetext(formatted_desc, "%pred", owner) //replace with this belly's owner - formatted_desc = replacetext(formatted_desc, "%prey", thing) //replace with whatever mob entered into this belly - to_chat(CC.bound_mob, "[formatted_desc]") + //if(istype(thing, /obj/item/capture_crystal)) //CHOMPEdit start: Capture crystal occupant gets to see belly text too. Moved to modular_chomp capture_crystal.dm. + //var/obj/item/capture_crystal/CC = thing + //if(CC.bound_mob && desc) + //if(CC.bound_mob in CC.contents) + //var/formatted_desc + //formatted_desc = replacetext(desc, "%belly", lowertext(name)) //replace with this belly's name + //formatted_desc = replacetext(formatted_desc, "%pred", owner) //replace with this belly's owner + //formatted_desc = replacetext(formatted_desc, "%prey", thing) //replace with whatever mob entered into this belly + //to_chat(CC.bound_mob, "[formatted_desc]") //CHOMPedit end /*/ Intended for simple mobs //CHMOPEdit: Counting belly cycles now. if((!owner.client || autotransfer_enabled) && autotransferlocation && autotransferchance > 0) @@ -440,6 +441,7 @@ // Called whenever an atom leaves this belly /obj/belly/Exited(atom/movable/thing, atom/OldLoc) . = ..() + thing.exit_belly(src) // CHOMPedit - atom movable proc, does nothing by default. Overridden in children for special behavior. if(isliving(thing) && !isbelly(thing.loc)) owner.update_fullness() //CHOMPEdit - This is run whenever a belly's contents are changed. var/mob/living/L = thing @@ -468,6 +470,9 @@ for(var/count in I.d_mult to 1 step 0.25) I.add_overlay(I.d_stage_overlay, TRUE) //CHOMPEdit end +// CHOMPedit: 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/update, var/severity = 0) //CHOMPEdit if(!istype(L)) return @@ -496,7 +501,7 @@ var/obj/screen/fullscreen/F4 = L.overlay_fullscreen("belly4", /obj/screen/fullscreen/belly/colorized/overlay) F4.icon_state = "[belly_fullscreen]_nc" */ //Chomp Disable END - + // Chomp EDIT Begin var/obj/screen/fullscreen/F = L.overlay_fullscreen("belly", /obj/screen/fullscreen/belly, severity) //CHOMPEdit Start: preserving save data F.icon = file("modular_chomp/icons/mob/vore_fullscreens/[belly_fullscreen].dmi") @@ -582,7 +587,7 @@ F4.icon_state = "[belly_fullscreen]_nc" */ //Chomp Disable END //CHOMPedit Start: preserving save data - var/obj/screen/fullscreen/F = L.overlay_fullscreen("belly", /obj/screen/fullscreen/belly, reagents.total_volume) + var/obj/screen/fullscreen/F = L.overlay_fullscreen("belly", /obj/screen/fullscreen/belly, reagents.total_volume) F.icon = file("modular_chomp/icons/mob/vore_fullscreens/[belly_fullscreen].dmi") F.cut_overlays() var/image/I = image(F.icon, belly_fullscreen) diff --git a/code/modules/vore/eating/bellymodes_vr.dm b/code/modules/vore/eating/bellymodes_vr.dm index 3ed6efdaa0..16a07114cd 100644 --- a/code/modules/vore/eating/bellymodes_vr.dm +++ b/code/modules/vore/eating/bellymodes_vr.dm @@ -35,6 +35,7 @@ var/play_sound //Potential sound to play at the end to avoid code duplication. var/to_update = FALSE //Did anything update worthy happen? + SEND_SIGNAL(src, COMSIG_BELLY_UPDATE_PREY_LOOP) // CHOMPedit: signals listening atoms to update prey_loop. May be cancelled by early exit otherwise. /////////////////////////// Exit Early //////////////////////////// var/list/touchable_atoms = contents - items_preserved diff --git a/code/modules/vore/eating/living_ch.dm b/code/modules/vore/eating/living_ch.dm index 1eb7e27d72..f9504e12c7 100644 --- a/code/modules/vore/eating/living_ch.dm +++ b/code/modules/vore/eating/living_ch.dm @@ -325,4 +325,19 @@ set category = "Preferences" set desc = "Toggle liquidbelly fullscreen visual effect." liquidbelly_visuals = !liquidbelly_visuals - to_chat(src, "Liquidbelly overlays [liquidbelly_visuals ? "enabled" : "disabled"].") \ No newline at end of file + to_chat(src, "Liquidbelly overlays [liquidbelly_visuals ? "enabled" : "disabled"].") + +/mob/living/proc/fix_vore_effects() + set name = "Fix Vore Effects" + set category = "OOC" + set desc = "Fix certain vore effects lingering after you've exited a belly." + + if(!isbelly(src.loc)) + if(alert(src, "Only use this verb if you are affected by certain vore effects outside of a belly, such as muffling or a stuck belly fullscreen.", "Clear Vore Effects", "Continue", "Nevermind") != "Continue") + return + + absorbed = FALSE + muffled = FALSE + clear_fullscreen("belly") + clear_fullscreen(ATOM_BELLY_FULLSCREEN) + stop_sound_channel(CHANNEL_PREYLOOP) diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 28067cb97d..4f9ae0f0e5 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -545,6 +545,7 @@ crystal.unleash() crystal.bound_mob = null crystal.bound_mob = capture_crystal = 0 + clear_fullscreen(ATOM_BELLY_FULLSCREEN) // CHOMPedit log_and_message_admins("[key_name(src)] used the OOC escape button to get out of [crystal] owned by [crystal.owner]. [ADMIN_FLW(src)]") //You've been turned into an item! @@ -946,8 +947,8 @@ var/obj/item/capture_crystal/C = I if(C.bound_mob && (C.bound_mob in C.contents)) if(isbelly(C.loc)) - var/obj/belly/B = C.loc - to_chat(C.bound_mob, "Outside of your crystal, you can see; [B.desc]") + //var/obj/belly/B = C.loc //CHOMPedit + //to_chat(C.bound_mob, "Outside of your crystal, you can see; [B.desc]") //CHOMPedit: moved to modular_chomp capture_crystal.dm to_chat(src, "You can taste the the power of command.") // CHOMPedit begin else if(istype(I,/obj/item/device/starcaster_news)) diff --git a/modular_chomp/code/game/objects/items/weapons/capture_crystal.dm b/modular_chomp/code/game/objects/items/weapons/capture_crystal.dm index 49ed39641b..9c7ce07ef5 100644 --- a/modular_chomp/code/game/objects/items/weapons/capture_crystal.dm +++ b/modular_chomp/code/game/objects/items/weapons/capture_crystal.dm @@ -1,5 +1,133 @@ /obj/item/capture_crystal var/spawn_mob_name = "A mob" + var/obj/belly/in_gut = null + +// Signals detect important procs from the host belly. Necessary to update visuals and sound loop for the player inside. +/obj/item/capture_crystal/enter_belly(obj/belly/B) + if(isbelly(B)) // Sanity + in_gut = B + RegisterSignal(in_gut, COMSIG_PARENT_QDELETING, PROC_REF(gut_was_deleted), TRUE) + RegisterSignal(in_gut, COMSIG_BELLY_UPDATE_VORE_FX, PROC_REF(capture_crystal_vfx), TRUE) + RegisterSignal(in_gut, COMSIG_BELLY_UPDATE_PREY_LOOP, PROC_REF(capture_crystal_prey_loop), TRUE) + + var/juice = in_gut.reagents.total_volume + if(!juice) + juice = 0 + capture_crystal_vfx(null, TRUE, juice) + capture_crystal_prey_loop() + for(var/mob/living/contained in src.contents) // For reasons I don't understand, using bound_mob here sets bound_mob to null. + var/formatted_desc + formatted_desc = replacetext(in_gut.desc, "%belly", lowertext(in_gut.name)) //replace with this belly's name + formatted_desc = replacetext(formatted_desc, "%pred", in_gut.owner) //replace with this belly's owner + formatted_desc = replacetext(formatted_desc, "%prey", contained) //replace with whatever mob entered into this belly + to_chat(contained, "[formatted_desc]") + +/obj/item/capture_crystal/exit_belly() + for(var/mob/living/contained in src.contents) + contained.clear_fullscreen(ATOM_BELLY_FULLSCREEN) // Clear fullscreens. + contained.stop_sound_channel(CHANNEL_PREYLOOP) // Clear sound loop. + contained.next_preyloop = world.time + + if(isbelly(in_gut)) // Sanity + UnregisterSignal(in_gut, COMSIG_PARENT_QDELETING) + UnregisterSignal(in_gut, COMSIG_BELLY_UPDATE_VORE_FX) + UnregisterSignal(in_gut, COMSIG_BELLY_UPDATE_PREY_LOOP) + in_gut = null + +// Inelegant copy-pasta since I can't steal the proc from bellies. +/obj/item/capture_crystal/proc/capture_crystal_vfx(var/update, var/severity = 0) + if(isbelly(in_gut)) + for(var/mob/living/contained in src.contents) // I guess this works if multi-catch crystals ever become a thing. + if(!contained.client) + return + if(!contained.show_vore_fx) + contained.clear_fullscreen(ATOM_BELLY_FULLSCREEN) + return + if(update) + contained.clear_fullscreen(ATOM_BELLY_FULLSCREEN) + if(in_gut.belly_fullscreen) + if(in_gut.colorization_enabled) + var/obj/screen/fullscreen/F = contained.overlay_fullscreen(ATOM_BELLY_FULLSCREEN, /obj/screen/fullscreen/belly, severity) //CHOMPEdit Start: preserving save data + F.icon = file("modular_chomp/icons/mob/vore_fullscreens/[in_gut.belly_fullscreen].dmi") + F.cut_overlays() + var/image/I = image(F.icon, in_gut.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 = in_gut.belly_fullscreen_color + I.alpha = in_gut.belly_fullscreen_alpha + F.add_overlay(I) + I = image(F.icon, in_gut.belly_fullscreen+"-2") + I.color = in_gut.belly_fullscreen_color2 + I.alpha = in_gut.belly_fullscreen_alpha + F.add_overlay(I) + I = image(F.icon, in_gut.belly_fullscreen+"-3") + I.color = in_gut.belly_fullscreen_color3 + I.alpha = in_gut.belly_fullscreen_alpha + F.add_overlay(I) + I = image(F.icon, in_gut.belly_fullscreen+"-4") + I.color = in_gut.belly_fullscreen_color4 + I.alpha = in_gut.belly_fullscreen_alpha + F.add_overlay(I) + if(contained.liquidbelly_visuals && in_gut.reagents.total_volume) + if(in_gut.digest_mode == DM_HOLD && in_gut.item_digest_mode == IM_HOLD) + I = image('modular_chomp/icons/mob/vore_fullscreens/bubbles.dmi', "calm") + else + I = image('modular_chomp/icons/mob/vore_fullscreens/bubbles.dmi', "bubbles") + I.color = in_gut.reagentcolor + I.alpha = max(150, min(in_gut.custom_max_volume, 255)) - (255 - in_gut.belly_fullscreen_alpha) + I.pixel_y = -450 + (450 / in_gut.custom_max_volume * in_gut.reagents.total_volume) + F.add_overlay(I) + F.update_for_view(contained.client.view) + else + var/obj/screen/fullscreen/F = contained.overlay_fullscreen(ATOM_BELLY_FULLSCREEN, /obj/screen/fullscreen/belly/fixed, severity) //preserving save data + F.icon = file("modular_chomp/icons/mob/vore_fullscreens/[in_gut.belly_fullscreen].dmi") + F.cut_overlays() + F.add_overlay(image(F.icon, in_gut.belly_fullscreen)) + F.add_overlay(image(F.icon, in_gut.belly_fullscreen+"-2")) + F.add_overlay(image(F.icon, in_gut.belly_fullscreen+"-3")) + F.add_overlay(image(F.icon, in_gut.belly_fullscreen+"-4")) + if(contained.liquidbelly_visuals && in_gut.reagents.total_volume) + var/image/I + if(in_gut.digest_mode == DM_HOLD && in_gut.item_digest_mode == IM_HOLD) + I = image('modular_chomp/icons/mob/vore_fullscreens/bubbles.dmi', "calm") + else + I = image('modular_chomp/icons/mob/vore_fullscreens/bubbles.dmi', "bubbles") + I.color = in_gut.reagentcolor + I.alpha = max(150, min(in_gut.custom_max_volume, 255)) - (255 - in_gut.belly_fullscreen_alpha) + I.pixel_y = -450 + (450 / in_gut.custom_max_volume * in_gut.reagents.total_volume) + F.add_overlay(I) + F.update_for_view(contained.client.view) + else + contained.clear_fullscreen(ATOM_BELLY_FULLSCREEN) + + /* // Disabled (and untested) for now, left to make it easier if we want to enable this later. + if(in_gut.disable_hud) + if(contained?.hud_used?.hud_shown) + to_chat(contained, "((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.))") + contained.toggle_hud_vis(TRUE) */ + +// Inelegant copy-pasta since I can't steal the proc from bellies. +/obj/item/capture_crystal/proc/capture_crystal_prey_loop() + if(isbelly(in_gut)) + for(var/mob/living/contained in src.contents) // Skip empty crystals. + //We don't bother executing any other code if the prey doesn't want to hear the noises. + if(!contained.is_preference_enabled(/datum/client_preference/digestion_noises)) + contained.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case, because byond is whack and you can't trust it + continue + + // We don't want the sounds to overlap, but we do want them to steadily replay. + // We also don't want the sounds to play if the pred hasn't marked this belly as fleshy, or doesn't + // have the right sounds to play. + if(in_gut.is_wet && in_gut.wet_loop && (world.time > contained.next_preyloop)) + contained.stop_sound_channel(CHANNEL_PREYLOOP) + var/sound/preyloop = sound('sound/vore/sunesound/prey/loop.ogg') + contained.playsound_local(get_turf(src), preyloop, 80, 0, channel = CHANNEL_PREYLOOP) + contained.next_preyloop = (world.time + (52 SECONDS)) + +//Cleanup signals if we're in a gut and it gets deleted. +/obj/item/capture_crystal/proc/gut_was_deleted() + UnregisterSignal(in_gut, COMSIG_PARENT_QDELETING) + UnregisterSignal(in_gut, COMSIG_BELLY_UPDATE_VORE_FX) + UnregisterSignal(in_gut, COMSIG_BELLY_UPDATE_PREY_LOOP) + in_gut = null /obj/item/capture_crystal/loadout active = TRUE diff --git a/vorestation.dme b/vorestation.dme index c3f2f18224..d529c693e5 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -119,6 +119,7 @@ #include "code\__defines\dcs\flags.dm" #include "code\__defines\dcs\helpers.dm" #include "code\__defines\dcs\signals.dm" +#include "code\__defines\dcs\signals_ch.dm" #include "code\_global_vars\bitfields.dm" #include "code\_global_vars\misc.dm" #include "code\_global_vars\mobs.dm"