mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 00:29:02 +01:00
529 lines
21 KiB
Plaintext
529 lines
21 KiB
Plaintext
/datum/action/innate/vore_mode
|
|
name = "Vore Mode"
|
|
desc = "<b>Left Click</b> to switch into vore mode<br><b>Right click</b> to see the vore UI<br>When aggressively grabbing someone in vore mode:<br><ul><li>Click on <b>yourself</b> to eat them</li><li>Click on <b>them</b> to feed yourself to them</li><li>Click on <b>someone else</b> to feed them who you're holding</li></ul>"
|
|
click_action = TRUE
|
|
ranged_mousepointer = 'modular_zubbers/icons/effects/mouse_pointers/vore.dmi'
|
|
default_button_position = "EAST-4:-10,SOUTH:5" // We're bottom left, it's bottom right, it's perfect
|
|
|
|
background_icon = 'modular_zubbers/icons/mob/actions/vore.dmi'
|
|
background_icon_state = "bg"
|
|
button_icon = 'modular_zubbers/icons/mob/actions/vore.dmi'
|
|
button_icon_state = "nom"
|
|
|
|
// This is here so that we can use our custom background with support for bg_active
|
|
/datum/action/innate/vore_mode/apply_button_background(atom/movable/screen/movable/action_button/current_button, force = FALSE)
|
|
// Determine which icon to use
|
|
background_icon_state = is_action_active(current_button) ? "bg_active" : "bg"
|
|
|
|
if(current_button.active_underlay_icon_state == background_icon_state && !force)
|
|
return
|
|
|
|
// Make the underlay
|
|
current_button.underlays.Cut()
|
|
current_button.underlays += image(icon = background_icon, icon_state = background_icon_state)
|
|
current_button.active_underlay_icon_state = background_icon_state
|
|
|
|
/datum/action/innate/vore_mode/Trigger(trigger_flags)
|
|
var/datum/component/vore/V = target
|
|
if(trigger_flags & TRIGGER_SECONDARY_ACTION)
|
|
V.ui_interact(owner)
|
|
return TRUE
|
|
return ..()
|
|
|
|
/datum/action/innate/vore_mode/do_ability(mob/living/clicker, atom/clicked_on)
|
|
var/datum/component/vore/V = target
|
|
return V.on_voremode_click(clicker, clicked_on)
|
|
|
|
/datum/action/innate/vore_mode/create_button()
|
|
var/atom/movable/screen/movable/action_button/button = ..()
|
|
button.mouse_drag_pointer = 'modular_zubbers/icons/effects/mouse_pointers/vore_drag.dmi'
|
|
return button
|
|
|
|
/// This is a tricky little thing to guarantee that `\ref[prey.appearance]` works in the vore panel
|
|
/// Basically, we force the pred to load the prey's appearance by putting the prey in this screen object's vis_contents
|
|
/atom/movable/screen/secret_appearance_holder
|
|
invisibility = INVISIBILITY_MAXIMUM
|
|
|
|
/// REMINDER: This component serves triple duty!
|
|
/// Everyone participating in mechanical vore must have this component for the UI
|
|
/// Preds must have this component to handle their bellies
|
|
/// Prey must have this component to handle the prey panel
|
|
/// Feeders must have this component to handle feeding preys to preds
|
|
/datum/component/vore
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE
|
|
|
|
var/obj/vore_belly/selected_belly = null
|
|
var/list/obj/vore_belly/vore_bellies = null
|
|
|
|
// Save backups
|
|
var/backup_number = 0
|
|
var/our_owner_ckey = null
|
|
var/non_owner_modified_settings = null
|
|
|
|
var/vore_mode = FALSE
|
|
var/datum/action/innate/vore_mode/vore_mode_action = null
|
|
var/atom/movable/screen/secret_appearance_holder/appearance_holder = null
|
|
|
|
/datum/component/vore/Initialize(...)
|
|
. = ..()
|
|
if(!is_type_in_typecache(parent, GLOB.vore_allowed_mob_types))
|
|
return COMPONENT_INCOMPATIBLE
|
|
load_vore_prefs(parent)
|
|
vore_mode_action = new(src)
|
|
// Set screen_loc
|
|
if(issilicon(parent))
|
|
vore_mode_action.default_button_position = "CENTER+4:-30,SOUTH+1:6"
|
|
if(isanimal_or_basicmob(parent))
|
|
vore_mode_action.default_button_position = "EAST-2:-8,SOUTH+1:6"
|
|
appearance_holder = new()
|
|
var/mob/living/living_parent = parent
|
|
our_owner_ckey = living_parent.ckey
|
|
|
|
/datum/component/vore/RegisterWithParent()
|
|
vore_mode_action?.Grant(parent)
|
|
add_appearance_holder()
|
|
// Add the appearance holder back every time they login
|
|
RegisterSignal(parent, COMSIG_MOB_LOGIN, PROC_REF(add_appearance_holder))
|
|
|
|
/datum/component/vore/proc/add_appearance_holder()
|
|
var/mob/living/L = parent
|
|
if(L.client && appearance_holder)
|
|
L.client.screen += appearance_holder
|
|
|
|
// This has to be careful because it's called as a result of COMPONENT_INCOMPATIBLE
|
|
/datum/component/vore/UnregisterFromParent()
|
|
vore_mode_action?.Remove(parent)
|
|
var/mob/living/L = parent
|
|
if(L.client && appearance_holder)
|
|
L.client.screen -= appearance_holder
|
|
UnregisterSignal(parent, COMSIG_MOB_LOGIN)
|
|
|
|
/datum/component/vore/Destroy(force)
|
|
if(isliving(parent))
|
|
var/mob/living/pred = parent
|
|
pred.client?.screen -= appearance_holder
|
|
selected_belly = null
|
|
QDEL_LAZYLIST(vore_bellies)
|
|
QDEL_NULL(appearance_holder)
|
|
QDEL_NULL(vore_mode_action)
|
|
return ..()
|
|
|
|
/datum/component/vore/proc/load_vore_prefs(mob/living/living_parent)
|
|
if(living_parent.client)
|
|
// Used for when people infect a second mob with vore, like aghosting
|
|
var/datum/vore_preferences/vore_prefs = get_parent_vore_prefs()
|
|
vore_prefs?.reset_belly_layout_slot()
|
|
load_bellies_from_prefs(living_parent.client)
|
|
return
|
|
|
|
return create_default_belly()
|
|
|
|
/datum/component/vore/proc/get_parent_vore_prefs()
|
|
var/mob/living/living_parent = parent
|
|
if(living_parent.client)
|
|
return living_parent.get_vore_prefs()
|
|
return null
|
|
|
|
/datum/component/vore/proc/load_bellies_from_prefs()
|
|
var/datum/vore_preferences/vore_prefs = get_parent_vore_prefs()
|
|
if(!vore_prefs)
|
|
return create_default_belly() // We always have to have our default belly
|
|
var/list/belly_tree = vore_prefs.get_bellies()
|
|
if(!LAZYLEN(belly_tree))
|
|
return create_default_belly()
|
|
|
|
for(var/belly in belly_tree)
|
|
var/obj/vore_belly/new_belly = new /obj/vore_belly(parent, src)
|
|
new_belly.deserialize(belly)
|
|
if(!selected_belly)
|
|
selected_belly = new_belly
|
|
|
|
/datum/component/vore/proc/clear_bellies()
|
|
selected_belly = null
|
|
QDEL_LAZYLIST(vore_bellies)
|
|
|
|
/datum/component/vore/proc/create_default_belly()
|
|
selected_belly = new /obj/vore_belly(parent, src)
|
|
save_bellies()
|
|
|
|
/// Returns TRUE if any of our bellies have prey in them
|
|
/datum/component/vore/proc/has_prey()
|
|
for(var/obj/vore_belly/B as anything in vore_bellies)
|
|
if(length(B.contents))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/component/vore/proc/count_prey()
|
|
var/count = 0
|
|
for(var/obj/vore_belly/B as anything in vore_bellies)
|
|
// Note: this must be changed if object vore is ever a thing
|
|
count += LAZYLEN(B.contents)
|
|
return count
|
|
|
|
/datum/component/vore/proc/download_belly_backup()
|
|
var/mob/living/living_parent = parent
|
|
if(living_parent.ckey)
|
|
var/full_path = get_player_save_folder(living_parent.ckey)
|
|
var/list/all_savefiles = flist("[full_path]/")
|
|
|
|
var/list/entries_to_show = list()
|
|
for(var/name in all_savefiles)
|
|
if(findtext(name, "vore_backup_"))
|
|
entries_to_show += "[name] - [time2text(ftime("[full_path]/[name]"))]"
|
|
|
|
var/selected = tgui_input_list(usr, "Select a backup to download", "Vore Backups", entries_to_show)
|
|
if(selected)
|
|
var/filename = splittext(selected, " - ")[1]
|
|
usr << ftp(file("[full_path]/[filename]"))
|
|
to_chat(usr, "Attempting to send [selected], this may take a few minutes.")
|
|
|
|
/datum/component/vore/proc/save_belly_backup(special_name)
|
|
var/datum/vore_preferences/vore_prefs = get_parent_vore_prefs()
|
|
if(!vore_prefs)
|
|
return
|
|
var/mob/living/living_parent = parent
|
|
if(living_parent.ckey)
|
|
backup_number = (backup_number + 1) % BELLY_BACKUP_COUNT
|
|
var/savefile_path = "[get_player_save_folder(living_parent.ckey)]/vore_backup_[backup_number].json"
|
|
if(special_name)
|
|
savefile_path = "[get_player_save_folder(living_parent.ckey)]/vore_backup_[special_name].json"
|
|
rustg_file_write(json_encode(vore_prefs.get_belly_export(), JSON_PRETTY_PRINT), savefile_path)
|
|
|
|
/// Slot argument allows you to forcibly save to a different slot
|
|
/datum/component/vore/proc/save_bellies(slot)
|
|
// No usr, no save
|
|
if(!usr?.ckey)
|
|
return
|
|
|
|
// Do not save if they are not our owner
|
|
if(usr.ckey != our_owner_ckey)
|
|
non_owner_modified_settings = usr.real_name
|
|
return
|
|
|
|
if(non_owner_modified_settings)
|
|
var/confirmation = tgui_alert(usr, "Warning: Your bellies were changed by [non_owner_modified_settings]. Do you want to save these changes permanently?", "Dirty Belly Prefs", list("No", "Yes"))
|
|
if(confirmation != "Yes")
|
|
var/restore = tgui_alert(usr, "Do you want to undo all changes by [non_owner_modified_settings] and revert to your preferences? A backup of their changes will be created.", "Revert?", list("No", "Yes"))
|
|
if(restore == "Yes")
|
|
save_belly_backup("modified_[sanitize_filename(non_owner_modified_settings)]")
|
|
clear_bellies()
|
|
load_bellies_from_prefs()
|
|
return
|
|
save_belly_backup("modified_[sanitize_filename(non_owner_modified_settings)]")
|
|
non_owner_modified_settings = null
|
|
|
|
var/datum/vore_preferences/vore_prefs = get_parent_vore_prefs()
|
|
if(!vore_prefs)
|
|
return
|
|
save_belly_backup()
|
|
|
|
var/list/bellies = list()
|
|
for(var/obj/vore_belly/B in vore_bellies)
|
|
UNTYPED_LIST_ADD(bellies, B.serialize())
|
|
|
|
vore_prefs.set_bellies(bellies, slot)
|
|
|
|
/datum/component/vore/proc/on_voremode_click(mob/living/user, mob/living/clicked_on)
|
|
if(user != parent)
|
|
return FALSE
|
|
|
|
if(!istype(clicked_on))
|
|
return FALSE
|
|
|
|
if(!user.can_perform_action(clicked_on, clicked_on.interaction_flags_click | FORBID_TELEKINESIS_REACH))
|
|
return
|
|
|
|
if(user.click_intercept == vore_mode_action)
|
|
vore_mode_action.unset_ranged_ability(user)
|
|
vore_mode_action.build_all_button_icons(UPDATE_BUTTON_BACKGROUND | UPDATE_BUTTON_STATUS)
|
|
|
|
if(!check_vore_grab(user))
|
|
to_chat(user, span_danger("You must have an aggressive grab to do vore."))
|
|
return TRUE
|
|
var/mob/living/pulled = user.pulling
|
|
|
|
if(clicked_on == user) // Parent wants to eat pulled
|
|
vore_other()
|
|
else if(clicked_on == pulled) // Parent wants to feed themselves to pulled
|
|
feed_self_to_other()
|
|
else // Parent wants to feed pulled to clicked_on
|
|
feed_other_to_other(clicked_on)
|
|
return TRUE
|
|
|
|
/// This is so complicated because we have to support three distinct use cases all in one proc:
|
|
/// 1. Pred eating prey, user = pred
|
|
/// 2. Prey feeding themselves to pred, user = prey
|
|
/// 3. A feeder feeding prey to pred, user = feeder
|
|
/// assume_active_consent is used for the secondary check after the do_after to avoid prompting prey/preds twice
|
|
/proc/check_vore_preferences(mob/living/user, mob/living/pred, mob/living/prey, assume_active_consent = FALSE)
|
|
if(!istype(pred) || !istype(prey))
|
|
return FALSE
|
|
var/datum/component/vore/pred_component = pred.GetComponent(/datum/component/vore)
|
|
if(!pred_component)
|
|
log_game("[user] tried to feed [prey] to [pred] but pred had vore disabled")
|
|
to_chat(user, span_danger("[pred] isn't interested in mechanical vore."))
|
|
return FALSE
|
|
if(!pred_component.selected_belly)
|
|
to_chat(user, span_danger("[pred] doesn't have a belly selected."))
|
|
return FALSE
|
|
if(pred_component.count_prey() >= MAX_PREY)
|
|
to_chat(user, span_danger("[pred] is too full to eat more."))
|
|
return FALSE
|
|
var/datum/component/vore/prey_component = prey.GetComponent(/datum/component/vore)
|
|
if(!prey_component)
|
|
log_game("[user] tried to feed [prey] to [pred] but prey had vore disabled")
|
|
to_chat(user, span_danger("[prey] isn't interested in mechanical vore."))
|
|
return FALSE
|
|
if(MATRYOSHKA_BANNED && prey_component.has_prey())
|
|
return FALSE
|
|
if(REQUIRES_PLAYER)
|
|
if(!pred.client)
|
|
log_game("[user] tried to feed [prey] to [pred] but pred was logged off")
|
|
to_chat(user, span_danger("[pred] isn't logged on."))
|
|
return FALSE
|
|
if(!prey.client)
|
|
log_game("[user] tried to feed [prey] to [pred] but prey was logged off")
|
|
to_chat(user, span_danger("[prey] isn't logged on."))
|
|
return FALSE
|
|
if(NO_DEAD)
|
|
if(pred.stat)
|
|
to_chat(user, span_danger("[pred] doesn't look healthy enough to feed."))
|
|
return FALSE
|
|
if(prey.stat)
|
|
to_chat(user, span_danger("[prey] doesn't look healthy enough to eat."))
|
|
return FALSE
|
|
if(!is_type_in_typecache(pred, GLOB.vore_allowed_mob_types))
|
|
return FALSE
|
|
if(!is_type_in_typecache(prey, GLOB.vore_allowed_mob_types))
|
|
return FALSE
|
|
|
|
if(prey.buckled)
|
|
to_chat(user, span_danger("[prey] is buckled."))
|
|
return FALSE
|
|
if(prey.has_buckled_mobs())
|
|
to_chat(user, span_danger("[prey] has buckled mobs."))
|
|
return FALSE
|
|
|
|
// Check pred prefs
|
|
// These are structured like this so that we automatically succeed for components without a client
|
|
// REQUIRES_PLAYER is checked above
|
|
var/datum/vore_preferences/pred_prefs = pred.get_vore_prefs()
|
|
if(pred_prefs)
|
|
var/allowed_to_pred = FALSE
|
|
|
|
var/pred_trinary = pred_prefs.read_preference(/datum/vore_pref/trinary/pred)
|
|
switch(pred_trinary)
|
|
if(PREF_TRINARY_NEVER)
|
|
allowed_to_pred = FALSE
|
|
if(PREF_TRINARY_PROMPT)
|
|
// presumably they consent to what they're doing if they initiated it
|
|
if(assume_active_consent || pred == user)
|
|
allowed_to_pred = TRUE
|
|
else
|
|
to_chat(user, span_warning("Please wait, [pred] is deciding if they want to eat [prey]..."))
|
|
if(tgui_alert(pred, "[user] is trying to feed [prey] to you, are you okay with this?", "Pred Pref", list("Yes", "No")) == "Yes")
|
|
allowed_to_pred = TRUE
|
|
if(PREF_TRINARY_ALWAYS)
|
|
allowed_to_pred = TRUE
|
|
|
|
if(!allowed_to_pred)
|
|
log_game("[key_name(user)] tried to feed [key_name(prey)] to [key_name(pred)] and was rejected by pred [key_name(pred)]")
|
|
to_chat(user, span_warning("[pred] isn't interested in being a pred."))
|
|
return FALSE
|
|
|
|
// Check prey prefs
|
|
var/datum/vore_preferences/prey_prefs = prey.get_vore_prefs()
|
|
if(prey_prefs)
|
|
var/allowed_to_prey = FALSE
|
|
|
|
var/prey_trinary = prey_prefs.read_preference(/datum/vore_pref/trinary/prey)
|
|
switch(prey_trinary)
|
|
if(PREF_TRINARY_NEVER)
|
|
allowed_to_prey = FALSE
|
|
if(PREF_TRINARY_PROMPT)
|
|
// presumably they consent to what they're doing if they initiated it
|
|
if(assume_active_consent || prey == user)
|
|
allowed_to_prey = TRUE
|
|
else
|
|
to_chat(user, span_warning("Please wait, [prey] is deciding if they want to be fed to [pred]..."))
|
|
if(tgui_alert(prey, "[user] is trying to feed you to [pred], are you okay with this?", "Prey Pref", list("Yes", "No")) == "Yes")
|
|
allowed_to_prey = TRUE
|
|
if(PREF_TRINARY_ALWAYS)
|
|
allowed_to_prey = TRUE
|
|
|
|
if(!allowed_to_prey)
|
|
log_game("[key_name(user)] tried to feed [key_name(prey)] to [key_name(pred)] and was rejected by prey [key_name(prey)]")
|
|
to_chat(user, span_warning("[prey] isn't interested in being prey."))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/proc/check_vore_grab(mob/living/grabber)
|
|
var/mob/living/grabee = grabber.pulling
|
|
var/minimum_grab_state = iscyborg(grabee) ? GRAB_PASSIVE : GRAB_AGGRESSIVE
|
|
if(!istype(grabee))
|
|
return FALSE
|
|
if(ishuman(grabber) && grabber.grab_state < minimum_grab_state)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/component/vore/proc/vore_other()
|
|
var/mob/living/pred = parent
|
|
if(!check_vore_grab(pred))
|
|
to_chat(parent, span_danger("You must have a[ishuman(pred) ? "n aggressive" : ""] grab to eat someone."))
|
|
return
|
|
var/mob/living/prey = pred.pulling
|
|
if(!check_vore_preferences(parent, pred, prey))
|
|
return
|
|
#ifdef VORE_DELAY
|
|
pred.visible_message(span_danger("[pred] is attempting to [LOWER_TEXT(selected_belly.insert_verb)] [prey] into their [LOWER_TEXT(selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
|
|
if(!do_after(pred, VORE_DELAY, prey))
|
|
return
|
|
if(!check_vore_grab(pred) || !check_vore_preferences(parent, pred, prey, assume_active_consent = TRUE))
|
|
return
|
|
#endif
|
|
pred.visible_message(span_danger("[pred] manages to [LOWER_TEXT(selected_belly.insert_verb)] [prey] into their [LOWER_TEXT(selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
|
|
complete_vore(prey)
|
|
|
|
/datum/component/vore/proc/feed_self_to_other()
|
|
var/mob/living/prey = parent
|
|
if(!check_vore_grab(prey))
|
|
to_chat(parent, span_danger("You must have a[ishuman(prey) ? "n aggressive" : ""] grab to feed yourself to someone."))
|
|
return
|
|
var/mob/living/pred = prey.pulling
|
|
if(!check_vore_preferences(parent, pred, prey))
|
|
return
|
|
// check_vore_preferences asserts this exists
|
|
var/datum/component/vore/pred_component = pred.GetComponent(/datum/component/vore)
|
|
#ifdef VORE_DELAY
|
|
prey.visible_message(span_danger("[prey] is attempting to make [pred] [LOWER_TEXT(pred_component.selected_belly.insert_verb)] [prey] into their [LOWER_TEXT(pred_component.selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
|
|
if(!do_after(prey, VORE_DELAY, pred))
|
|
return
|
|
if(!check_vore_grab(prey) || !check_vore_preferences(parent, pred, prey, assume_active_consent = TRUE))
|
|
return
|
|
#endif
|
|
prey.visible_message(span_danger("[prey] manages to make [pred] [LOWER_TEXT(pred_component.selected_belly.insert_verb)] [prey] into their [LOWER_TEXT(pred_component.selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
|
|
pred_component.complete_vore(prey)
|
|
|
|
/datum/component/vore/proc/feed_other_to_other(mob/living/pred)
|
|
var/mob/living/feeder = parent
|
|
if(!check_vore_grab(feeder))
|
|
to_chat(feeder, span_danger("You must have a[ishuman(feeder) ? "n aggressive" : ""] grab to feed someone to someone else."))
|
|
return
|
|
if(!feeder.can_perform_action(pred, pred.interaction_flags_click | FORBID_TELEKINESIS_REACH))
|
|
return
|
|
var/mob/living/prey = feeder.pulling
|
|
if(!check_vore_preferences(feeder, pred, prey))
|
|
return
|
|
// check_vore_preferences asserts this exists
|
|
var/datum/component/vore/pred_component = pred.GetComponent(/datum/component/vore)
|
|
#ifdef VORE_DELAY
|
|
feeder.visible_message(span_danger("[feeder] is attempting to make [pred] [LOWER_TEXT(pred_component.selected_belly.insert_verb)] [prey] into their [LOWER_TEXT(pred_component.selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
|
|
if(!do_after(feeder, VORE_DELAY, pred))
|
|
return
|
|
if(!check_vore_grab(feeder) || !check_vore_preferences(feeder, pred, prey, assume_active_consent = TRUE))
|
|
return
|
|
if(!feeder.can_perform_action(pred, pred.interaction_flags_click | FORBID_TELEKINESIS_REACH))
|
|
return
|
|
#endif
|
|
feeder.visible_message(span_danger("[feeder] manages to make [pred] [LOWER_TEXT(pred_component.selected_belly.insert_verb)] [prey] into their [LOWER_TEXT(pred_component.selected_belly.name)]!"), pref_to_check = /datum/preference/toggle/erp/vore_enable)
|
|
pred_component.complete_vore(prey)
|
|
|
|
/datum/component/vore/proc/complete_vore(mob/living/prey)
|
|
prey.forceMove(selected_belly)
|
|
|
|
|
|
/************/
|
|
/* Sounds */
|
|
/************/
|
|
/// Plays a different prey and pred sound to our owner and ALL of our prey
|
|
/datum/component/vore/proc/play_vore_sound_preypred(preysound, predsound, volume = VORE_SOUND_VOLUME, range = 2, vary = FALSE, pref = /datum/vore_pref/toggle/eating_noises)
|
|
var/turf/turf_source = get_turf(parent)
|
|
var/sound/prey_sound = isdatum(preysound) ? preysound : sound(get_vore_sfx(preysound))
|
|
var/sound/pred_sound = isdatum(predsound) ? predsound : sound(get_vore_sfx(predsound))
|
|
|
|
// We never go through walls so get_hearers_in_view is fine
|
|
// It'll also cover our parent and their belly contents via spatial_grid
|
|
var/list/listeners = get_hearers_in_view(range, parent)
|
|
|
|
// Note: because ghosts can't have vore prefs, we can't send sounds to them :(
|
|
for(var/mob/living/listening_mob in listeners)
|
|
if(get_dist(listening_mob, turf_source) > range)
|
|
continue
|
|
var/datum/vore_preferences/listener_vore_prefs = listening_mob.get_vore_prefs()
|
|
if(!listener_vore_prefs)
|
|
continue
|
|
var/pref_enabled = listener_vore_prefs.read_preference(pref)
|
|
if(!pref_enabled)
|
|
continue
|
|
|
|
// Needed because playsound_local runtimes at range = 1
|
|
var/range_to_use = range
|
|
if(range_to_use < 2)
|
|
range_to_use = 0
|
|
|
|
if(istype(listening_mob.loc, /obj/vore_belly))
|
|
listening_mob.playsound_local(
|
|
turf_source, preysound, volume, vary,
|
|
sound_to_use = prey_sound,
|
|
max_distance = range,
|
|
)
|
|
else
|
|
listening_mob.playsound_local(
|
|
turf_source, predsound, volume, vary,
|
|
sound_to_use = pred_sound,
|
|
max_distance = range,
|
|
)
|
|
|
|
/datum/component/vore/proc/play_vore_sound(soundin, volume = VORE_SOUND_VOLUME, range = 2, vary = FALSE, pref = /datum/vore_pref/toggle/eating_noises)
|
|
var/turf/turf_source = get_turf(parent)
|
|
var/sound/S = isdatum(soundin) ? soundin : sound(get_vore_sfx(soundin))
|
|
|
|
// We never go through walls so get_hearers_in_view is fine
|
|
// It'll also cover our parent and their belly contents via spatial_grid
|
|
var/list/listeners = get_hearers_in_view(range, parent)
|
|
|
|
// Note: because ghosts can't have vore prefs, we can't send sounds to them :(
|
|
for(var/mob/living/listening_mob in listeners)
|
|
if(get_dist(listening_mob, turf_source) > range)
|
|
continue
|
|
var/datum/vore_preferences/listener_vore_prefs = listening_mob.get_vore_prefs()
|
|
if(!listener_vore_prefs)
|
|
continue
|
|
var/pref_enabled = listener_vore_prefs.read_preference(pref)
|
|
if(!pref_enabled)
|
|
continue
|
|
|
|
// Needed because playsound_local runtimes at range = 1
|
|
var/range_to_use = range
|
|
if(range_to_use < 2)
|
|
range_to_use = 0
|
|
|
|
listening_mob.playsound_local(
|
|
turf_source, soundin, volume, vary,
|
|
sound_to_use = S,
|
|
max_distance = range,
|
|
)
|
|
|
|
/proc/get_vore_sfx(soundin)
|
|
switch(soundin)
|
|
if("vore_sounds_death_fancy")
|
|
return pick(GLOB.vore_sounds_death_fancy)
|
|
if("vore_sounds_death_fancy_prey")
|
|
return pick(GLOB.vore_sounds_death_fancy_prey)
|
|
if("vore_sounds_death_classic")
|
|
return pick(GLOB.vore_sounds_death_classic)
|
|
if("vore_sounds_digestion_classic")
|
|
return pick(GLOB.vore_sounds_digestion_classic)
|
|
if("vore_sounds_digestion_fancy")
|
|
return pick(GLOB.vore_sounds_digestion_fancy)
|
|
if("vore_sounds_digestion_fancy_prey")
|
|
return pick(GLOB.vore_sounds_digestion_fancy_prey)
|
|
if("vore_sounds_struggle_fancy")
|
|
return pick(GLOB.vore_sounds_struggle_fancy)
|
|
if("vore_sounds_struggle_classic")
|
|
return pick(GLOB.vore_sounds_struggle_classic)
|
|
if("rustle")
|
|
return get_sfx(SFX_RUSTLE)
|
|
return soundin
|