Vore code to json and more (#5789)
* Vore 2.0 Initial commit * double checked porting * Fixes compile issues * converts Ash Drake bellies to new system digs out lingering datum/belly stuff too * Let's just work on this later * System operational * Update preferences.dm
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
// THIS IS NOW MERELY LEGACY, because memes. hopefully it won't be dumb.
|
||||
|
||||
//
|
||||
// The belly object is what holds onto a mob while they're inside a predator.
|
||||
// It takes care of altering the pred's decription, digesting the prey, relaying struggles etc.
|
||||
//
|
||||
|
||||
// If you change what variables are on this, then you need to update the copy() proc.
|
||||
|
||||
//
|
||||
// Parent type of all the various "belly" varieties.
|
||||
//
|
||||
/datum/belly
|
||||
var/name // Name of this location
|
||||
var/inside_flavor // Flavor text description of inside sight/sound/smells/feels.
|
||||
var/vore_sound = 'sound/vore/pred/swallow_01.ogg' // Sound when ingesting someone
|
||||
var/vore_verb = "ingest" // Verb for eating with this in messages
|
||||
var/human_prey_swallow_time = 10 SECONDS // Time in deciseconds to swallow /mob/living/carbon/human
|
||||
var/nonhuman_prey_swallow_time = 5 SECONDS // Time in deciseconds to swallow anything else
|
||||
var/emoteTime = 30 SECONDS // How long between stomach emotes at prey
|
||||
var/digest_brute = 0 // Brute damage per tick in digestion mode
|
||||
var/digest_burn = 1 // Burn damage per tick in digestion mode
|
||||
var/digest_tickrate = 9 // Modulus this of air controller tick number to iterate gurgles on
|
||||
var/immutable = FALSE // Prevents this belly from being deleted
|
||||
var/escapable = FALSE // Belly can be resisted out of at any time
|
||||
var/escapetime = 60 SECONDS // Deciseconds, how long to escape this belly
|
||||
var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles
|
||||
// var/silenced = FALSE // Will the heartbeat/fleshy internal loop play?
|
||||
var/escapechance = 0 // % Chance of prey beginning to escape if prey struggles.
|
||||
|
||||
var/datum/belly/transferlocation = null // Location that the prey is released if they struggle and get dropped off.
|
||||
var/transferchance = 0 // % Chance of prey being transferred to transfer location when resisting
|
||||
var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location
|
||||
var/autotransferwait = 10 // Time between trying to transfer.
|
||||
var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone.
|
||||
|
||||
var/tmp/digest_mode = DM_HOLD // Whether or not to digest. Default to not digest.
|
||||
var/tmp/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY) // Possible digest modes
|
||||
var/tmp/mob/living/owner // The mob whose belly this is.
|
||||
var/tmp/list/internal_contents = list() // People/Things you've eaten into this belly!
|
||||
var/tmp/is_full // Flag for if digested remeans are present. (for disposal messages)
|
||||
var/tmp/emotePend = FALSE // If there's already a spawned thing counting for the next emote
|
||||
var/swallow_time = 10 SECONDS // for mob transfering automation
|
||||
var/vore_capacity = 1 // The capacity (in people) this person can hold
|
||||
|
||||
// Don't forget to watch your commas at the end of each line if you change these.
|
||||
var/list/struggle_messages_outside = list(
|
||||
"%pred's %belly wobbles with a squirming meal.",
|
||||
"%pred's %belly jostles with movement.",
|
||||
"%pred's %belly briefly swells outward as someone pushes from inside.",
|
||||
"%pred's %belly fidgets with a trapped victim.",
|
||||
"%pred's %belly jiggles with motion from inside.",
|
||||
"%pred's %belly sloshes around.",
|
||||
"%pred's %belly gushes softly.",
|
||||
"%pred's %belly lets out a wet squelch.")
|
||||
|
||||
var/list/struggle_messages_inside = list(
|
||||
"Your useless squirming only causes %pred's slimy %belly to squelch over your body.",
|
||||
"Your struggles only cause %pred's %belly to gush softly around you.",
|
||||
"Your movement only causes %pred's %belly to slosh around you.",
|
||||
"Your motion causes %pred's %belly to jiggle.",
|
||||
"You fidget around inside of %pred's %belly.",
|
||||
"You shove against the walls of %pred's %belly, making it briefly swell outward.",
|
||||
"You jostle %pred's %belly with movement.",
|
||||
"You squirm inside of %pred's %belly, making it wobble around.")
|
||||
|
||||
var/list/digest_messages_owner = list(
|
||||
"You feel %prey's body succumb to your digestive system, which breaks it apart into soft slurry.",
|
||||
"You hear a lewd glorp as your %belly muscles grind %prey into a warm pulp.",
|
||||
"Your %belly lets out a rumble as it melts %prey into sludge.",
|
||||
"You feel a soft gurgle as %prey's body loses form in your %belly. They're nothing but a soft mass of churning slop now.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your thighs.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your rump.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your belly.",
|
||||
"Your %belly groans as %prey falls apart into a thick soup. You can feel their remains soon flowing deeper into your body to be absorbed.",
|
||||
"Your %belly kneads on every fiber of %prey, softening them down into mush to fuel your next hunt.",
|
||||
"Your %belly churns %prey down into a hot slush. You can feel the nutrients coursing through your digestive track with a series of long, wet glorps.")
|
||||
|
||||
var/list/digest_messages_prey = list(
|
||||
"Your body succumbs to %pred's digestive system, which breaks you apart into soft slurry.",
|
||||
"%pred's %belly lets out a lewd glorp as their muscles grind you into a warm pulp.",
|
||||
"%pred's %belly lets out a rumble as it melts you into sludge.",
|
||||
"%pred feels a soft gurgle as your body loses form in their %belly. You're nothing but a soft mass of churning slop now.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's thighs.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's rump.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's belly.",
|
||||
"%pred's %belly groans as you fall apart into a thick soup. Your remains soon flow deeper into %pred's body to be absorbed.",
|
||||
"%pred's %belly kneads on every fiber of your body, softening you down into mush to fuel their next hunt.",
|
||||
"%pred's %belly churns you down into a hot slush. Your nutrient-rich remains course through their digestive track with a series of long, wet glorps.")
|
||||
|
||||
var/list/examine_messages = list(
|
||||
"They have something solid in their %belly!",
|
||||
"It looks like they have something in their %belly!")
|
||||
|
||||
//Mostly for being overridden on precreated bellies on mobs. Could be VV'd into
|
||||
//a carbon's belly if someone really wanted. No UI for carbons to adjust this.
|
||||
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
|
||||
var/list/emote_lists = list()
|
||||
|
||||
//OLD: This only exists for legacy conversion purposes
|
||||
//It's called whenever an old datum-style belly is loaded
|
||||
/datum/belly/proc/copy(obj/belly/new_belly)
|
||||
|
||||
//// Non-object variables
|
||||
new_belly.name = name
|
||||
new_belly.desc = inside_flavor
|
||||
new_belly.vore_sound = vore_sound
|
||||
new_belly.vore_verb = vore_verb
|
||||
new_belly.human_prey_swallow_time = human_prey_swallow_time
|
||||
new_belly.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
|
||||
new_belly.emote_time = emoteTime
|
||||
new_belly.digest_brute = digest_brute
|
||||
new_belly.digest_burn = digest_burn
|
||||
new_belly.immutable = immutable
|
||||
new_belly.can_taste = can_taste
|
||||
new_belly.escapable = escapable
|
||||
new_belly.escapetime = escapetime
|
||||
new_belly.digestchance = digestchance
|
||||
new_belly.escapechance = escapechance
|
||||
new_belly.transferchance = transferchance
|
||||
new_belly.transferlocation = transferlocation
|
||||
|
||||
//// Object-holding variables
|
||||
//struggle_messages_outside - strings
|
||||
new_belly.struggle_messages_outside.Cut()
|
||||
for(var/I in struggle_messages_outside)
|
||||
new_belly.struggle_messages_outside += I
|
||||
|
||||
//struggle_messages_inside - strings
|
||||
new_belly.struggle_messages_inside.Cut()
|
||||
for(var/I in struggle_messages_inside)
|
||||
new_belly.struggle_messages_inside += I
|
||||
|
||||
//digest_messages_owner - strings
|
||||
new_belly.digest_messages_owner.Cut()
|
||||
for(var/I in digest_messages_owner)
|
||||
new_belly.digest_messages_owner += I
|
||||
|
||||
//digest_messages_prey - strings
|
||||
new_belly.digest_messages_prey.Cut()
|
||||
for(var/I in digest_messages_prey)
|
||||
new_belly.digest_messages_prey += I
|
||||
|
||||
//examine_messages - strings
|
||||
new_belly.examine_messages.Cut()
|
||||
for(var/I in examine_messages)
|
||||
new_belly.examine_messages += I
|
||||
|
||||
//emote_lists - index: digest mode, key: list of strings
|
||||
new_belly.emote_lists.Cut()
|
||||
for(var/K in emote_lists)
|
||||
new_belly.emote_lists[K] = list()
|
||||
for(var/I in emote_lists[K])
|
||||
new_belly.emote_lists[K] += I
|
||||
|
||||
return new_belly
|
||||
|
||||
// // // // // // // // // // // //
|
||||
// // // LEGACY USE ONLY!! // // //
|
||||
// // // // // // // // // // // //
|
||||
// See top of file! //
|
||||
// // // // // // // // // // // //
|
||||
@@ -0,0 +1,655 @@
|
||||
//#define VORE_SOUND_FALLOFF 0.05
|
||||
|
||||
//
|
||||
// Belly system 2.0, now using objects instead of datums because EH at datums.
|
||||
// How many times have I rewritten bellies and vore now? -Aro
|
||||
//
|
||||
|
||||
// If you change what variables are on this, then you need to update the copy() proc.
|
||||
|
||||
//
|
||||
// Parent type of all the various "belly" varieties.
|
||||
//
|
||||
/obj/belly
|
||||
name = "belly" // Name of this location
|
||||
desc = "It's a belly! You're in it!" // Flavor text description of inside sight/sound/smells/feels.
|
||||
var/vore_sound = 'sound/vore/pred/swallow_01.ogg' // Sound when ingesting someone
|
||||
var/vore_verb = "ingest" // Verb for eating with this in messages
|
||||
var/release_sound = 'sound/effects/splat.ogg'
|
||||
var/human_prey_swallow_time = 100 // Time in deciseconds to swallow /mob/living/carbon/human
|
||||
var/nonhuman_prey_swallow_time = 30 // Time in deciseconds to swallow anything else
|
||||
var/emote_time = 60 SECONDS // How long between stomach emotes at prey
|
||||
var/digest_brute = 2 // Brute damage per tick in digestion mode
|
||||
var/digest_burn = 2 // Burn damage per tick in digestion mode
|
||||
var/immutable = FALSE // Prevents this belly from being deleted
|
||||
var/escapable = TRUE // Belly can be resisted out of at any time
|
||||
var/escapetime = 20 SECONDS // Deciseconds, how long to escape this belly
|
||||
var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles
|
||||
var/absorbchance = 0 // % Chance of stomach beginning to absorb if prey struggles
|
||||
var/escapechance = 100 // % Chance of prey beginning to escape if prey struggles.
|
||||
var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone.
|
||||
var/bulge_size = 0.25 // The minimum size the prey has to be in order to show up on examine.
|
||||
// var/shrink_grow_size = 1 // This horribly named variable determines the minimum/maximum size it will shrink/grow prey to.
|
||||
var/silent = FALSE
|
||||
|
||||
var/transferlocation = null // Location that the prey is released if they struggle and get dropped off.
|
||||
var/transferchance = 0 // % Chance of prey being transferred to transfer location when resisting
|
||||
var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location
|
||||
var/autotransferwait = 10 // Time between trying to transfer.
|
||||
var/swallow_time = 10 SECONDS // for mob transfering automation
|
||||
var/vore_capacity = 1 // simple animal nom capacity
|
||||
|
||||
//I don't think we've ever altered these lists. making them static until someone actually overrides them somewhere.
|
||||
var/tmp/static/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY) // Possible digest modes
|
||||
|
||||
var/tmp/mob/living/owner // The mob whose belly this is.
|
||||
var/tmp/digest_mode = DM_HOLD // Current mode the belly is set to from digest_modes (+transform_modes if human)
|
||||
var/tmp/next_process = 0 // Waiting for this SSbellies times_fired to process again.
|
||||
var/tmp/list/items_preserved = list() // Stuff that wont digest so we shouldn't process it again.
|
||||
var/tmp/next_emote = 0 // When we're supposed to print our next emote, as a belly controller tick #
|
||||
var/tmp/recent_sound = FALSE // Prevent audio spam
|
||||
|
||||
// Don't forget to watch your commas at the end of each line if you change these.
|
||||
var/list/struggle_messages_outside = list(
|
||||
"%pred's %belly wobbles with a squirming meal.",
|
||||
"%pred's %belly jostles with movement.",
|
||||
"%pred's %belly briefly swells outward as someone pushes from inside.",
|
||||
"%pred's %belly fidgets with a trapped victim.",
|
||||
"%pred's %belly jiggles with motion from inside.",
|
||||
"%pred's %belly sloshes around.",
|
||||
"%pred's %belly gushes softly.",
|
||||
"%pred's %belly lets out a wet squelch.")
|
||||
|
||||
var/list/struggle_messages_inside = list(
|
||||
"Your useless squirming only causes %pred's slimy %belly to squelch over your body.",
|
||||
"Your struggles only cause %pred's %belly to gush softly around you.",
|
||||
"Your movement only causes %pred's %belly to slosh around you.",
|
||||
"Your motion causes %pred's %belly to jiggle.",
|
||||
"You fidget around inside of %pred's %belly.",
|
||||
"You shove against the walls of %pred's %belly, making it briefly swell outward.",
|
||||
"You jostle %pred's %belly with movement.",
|
||||
"You squirm inside of %pred's %belly, making it wobble around.")
|
||||
|
||||
var/list/digest_messages_owner = list(
|
||||
"You feel %prey's body succumb to your digestive system, which breaks it apart into soft slurry.",
|
||||
"You hear a lewd glorp as your %belly muscles grind %prey into a warm pulp.",
|
||||
"Your %belly lets out a rumble as it melts %prey into sludge.",
|
||||
"You feel a soft gurgle as %prey's body loses form in your %belly. They're nothing but a soft mass of churning slop now.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your thighs.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your rump.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your belly.",
|
||||
"Your %belly groans as %prey falls apart into a thick soup. You can feel their remains soon flowing deeper into your body to be absorbed.",
|
||||
"Your %belly kneads on every fiber of %prey, softening them down into mush to fuel your next hunt.",
|
||||
"Your %belly churns %prey down into a hot slush. You can feel the nutrients coursing through your digestive track with a series of long, wet glorps.")
|
||||
|
||||
var/list/digest_messages_prey = list(
|
||||
"Your body succumbs to %pred's digestive system, which breaks you apart into soft slurry.",
|
||||
"%pred's %belly lets out a lewd glorp as their muscles grind you into a warm pulp.",
|
||||
"%pred's %belly lets out a rumble as it melts you into sludge.",
|
||||
"%pred feels a soft gurgle as your body loses form in their %belly. You're nothing but a soft mass of churning slop now.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's thighs.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's rump.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's belly.",
|
||||
"%pred's %belly groans as you fall apart into a thick soup. Your remains soon flow deeper into %pred's body to be absorbed.",
|
||||
"%pred's %belly kneads on every fiber of your body, softening you down into mush to fuel their next hunt.",
|
||||
"%pred's %belly churns you down into a hot slush. Your nutrient-rich remains course through their digestive track with a series of long, wet glorps.")
|
||||
|
||||
var/list/examine_messages = list(
|
||||
"They have something solid in their %belly!",
|
||||
"It looks like they have something in their %belly!")
|
||||
|
||||
//Mostly for being overridden on precreated bellies on mobs. Could be VV'd into
|
||||
//a carbon's belly if someone really wanted. No UI for carbons to adjust this.
|
||||
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
|
||||
var/tmp/list/emote_lists = list()
|
||||
|
||||
//For serialization, keep this updated, required for bellies to save correctly.
|
||||
/obj/belly/vars_to_save()
|
||||
return ..() + list(
|
||||
"name",
|
||||
"desc",
|
||||
"vore_sound",
|
||||
"vore_verb",
|
||||
"release_sound",
|
||||
"human_prey_swallow_time",
|
||||
"nonhuman_prey_swallow_time",
|
||||
"emote_time",
|
||||
"digest_brute",
|
||||
"digest_burn",
|
||||
"immutable",
|
||||
"can_taste",
|
||||
"escapable",
|
||||
"escapetime",
|
||||
"digestchance",
|
||||
"absorbchance",
|
||||
"escapechance",
|
||||
"transferchance",
|
||||
"transferlocation",
|
||||
"bulge_size",
|
||||
"struggle_messages_outside",
|
||||
"struggle_messages_inside",
|
||||
"digest_messages_owner",
|
||||
"digest_messages_prey",
|
||||
"examine_messages",
|
||||
"emote_lists",
|
||||
"silent"
|
||||
)
|
||||
|
||||
//ommitted list
|
||||
// "shrink_grow_size",
|
||||
/obj/belly/New(var/newloc)
|
||||
. = ..(newloc)
|
||||
//If not, we're probably just in a prefs list or something.
|
||||
if(isliving(newloc))
|
||||
owner = loc
|
||||
owner.vore_organs |= src
|
||||
SSbellies.belly_list += src
|
||||
|
||||
/obj/belly/Destroy()
|
||||
SSbellies.belly_list -= src
|
||||
if(owner)
|
||||
owner.vore_organs -= src
|
||||
owner = null
|
||||
. = ..()
|
||||
|
||||
// Called whenever an atom enters this belly
|
||||
/obj/belly/Entered(var/atom/movable/thing,var/atom/OldLoc)
|
||||
if(OldLoc in contents)
|
||||
return //Someone dropping something (or being stripdigested)
|
||||
|
||||
//Generic entered message
|
||||
to_chat(owner,"<span class='notice'>[thing] slides into your [lowertext(name)].</span>")
|
||||
|
||||
//Sound w/ antispam flag setting
|
||||
if(!silent && !recent_sound)
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(owner),"[src.vore_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
recent_sound = TRUE
|
||||
|
||||
//Messages if it's a mob
|
||||
if(isliving(thing))
|
||||
var/mob/living/M = thing
|
||||
if(desc)
|
||||
to_chat(M, "<span class='notice'><B>[desc]</B></span>")
|
||||
var/taste
|
||||
if(can_taste && (taste = M.get_taste_message(FALSE)))
|
||||
to_chat(owner, "<span class='notice'>[M] tastes of [taste].</span>")
|
||||
|
||||
// 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.
|
||||
/obj/belly/proc/release_all_contents(var/include_absorbed = FALSE)
|
||||
var/atom/destination = drop_location()
|
||||
var/count = 0
|
||||
for(var/thing in contents)
|
||||
var/atom/movable/AM = thing
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.absorbed && !include_absorbed)
|
||||
continue
|
||||
L.absorbed = FALSE
|
||||
for(var/mob/living/W in AM)
|
||||
W.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
AM.forceMove(destination) // Move the belly contents into the same location as belly's owner.
|
||||
count++
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(owner),"[src.release_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
items_preserved.Cut()
|
||||
owner.visible_message("<font color='green'><b>[owner] expels everything from their [lowertext(name)]!</b></font>")
|
||||
owner.update_icons()
|
||||
|
||||
return count
|
||||
|
||||
// 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.
|
||||
/obj/belly/proc/release_specific_contents(var/atom/movable/M)
|
||||
if (!(M in contents))
|
||||
return FALSE // They weren't in this belly anyway
|
||||
|
||||
M.forceMove(drop_location()) // Move the belly contents into the same location as belly's owner.
|
||||
items_preserved -= M
|
||||
for(var/mob/living/P in M)
|
||||
P.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
if(release_sound)
|
||||
for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(H.client && H.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(owner),"[src.release_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
|
||||
if(istype(M,/mob/living))
|
||||
var/mob/living/ML = M
|
||||
var/mob/living/OW = owner
|
||||
if(ML.absorbed)
|
||||
ML.absorbed = FALSE
|
||||
if(ishuman(M) && ishuman(OW))
|
||||
var/mob/living/carbon/human/Prey = M
|
||||
var/mob/living/carbon/human/Pred = OW
|
||||
var/absorbed_count = 2 //Prey that we were, plus the pred gets a portion
|
||||
for(var/mob/living/P in contents)
|
||||
if(P.absorbed)
|
||||
absorbed_count++
|
||||
Pred.reagents.trans_to(Prey, Pred.reagents.total_volume / absorbed_count)
|
||||
|
||||
owner.visible_message("<font color='green'><b>[owner] expels [M] from their [lowertext(name)]!</b></font>")
|
||||
owner.update_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.
|
||||
/obj/belly/proc/nom_mob(var/mob/prey, var/mob/user)
|
||||
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
|
||||
if(owner.stat == DEAD)
|
||||
return
|
||||
if (prey.buckled)
|
||||
prey.buckled.unbuckle_mob(prey,TRUE)
|
||||
|
||||
prey.forceMove(src)
|
||||
prey.playsound_local(loc,preyloop,70,0, channel = CHANNEL_PREYLOOP)
|
||||
owner.updateVRPanel()
|
||||
|
||||
for(var/mob/living/M in contents)
|
||||
M.updateVRPanel()
|
||||
|
||||
// Setup the autotransfer checks if needed
|
||||
if(transferlocation && autotransferchance > 0)
|
||||
addtimer(CALLBACK(src, /obj/belly/.proc/check_autotransfer, prey), autotransferwait)
|
||||
|
||||
/obj/belly/proc/check_autotransfer(var/mob/prey)
|
||||
// Some sanity checks
|
||||
if(transferlocation && (autotransferchance > 0) && (prey in contents))
|
||||
if(prob(autotransferchance))
|
||||
// Double check transferlocation isn't insane
|
||||
if(verify_transferlocation())
|
||||
transfer_contents(prey, transferlocation)
|
||||
else
|
||||
// Didn't transfer, so wait before retrying
|
||||
addtimer(CALLBACK(src, /obj/belly/.proc/check_autotransfer, prey), autotransferwait)
|
||||
|
||||
/obj/belly/proc/verify_transferlocation()
|
||||
for(var/I in owner.vore_organs)
|
||||
var/obj/belly/B = owner.vore_organs[I]
|
||||
if(B == transferlocation)
|
||||
return TRUE
|
||||
|
||||
for(var/I in owner.vore_organs)
|
||||
var/obj/belly/B = owner.vore_organs[I]
|
||||
if(B == transferlocation)
|
||||
transferlocation = B
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
// 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.
|
||||
/obj/belly/proc/get_examine_msg()
|
||||
if(contents.len && examine_messages.len)
|
||||
var/formatted_message
|
||||
var/raw_message = pick(examine_messages)
|
||||
var/total_bulge = 0
|
||||
|
||||
formatted_message = replacetext(raw_message,"%belly",lowertext(name))
|
||||
formatted_message = replacetext(formatted_message,"%pred",owner)
|
||||
formatted_message = replacetext(formatted_message,"%prey",english_list(contents))
|
||||
for(var/mob/living/P in contents)
|
||||
if(!P.absorbed) //This is required first, in case there's a person absorbed and not absorbed in a stomach.
|
||||
total_bulge += P.mob_size
|
||||
if(total_bulge >= bulge_size && bulge_size != 0)
|
||||
return("<span class='warning'>[formatted_message]</span><BR>")
|
||||
else
|
||||
return ""
|
||||
|
||||
// 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.
|
||||
/obj/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.
|
||||
/obj/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)
|
||||
testing("[owner] tried to set [lowertext(name)] with 11+ messages")
|
||||
|
||||
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)
|
||||
testing("[owner] tried to set [lowertext(name)] with >121 or <10 char message")
|
||||
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.
|
||||
/obj/belly/proc/digestion_death(var/mob/living/M)
|
||||
//M.death(1) // "Stop it he's already dead..." Basically redundant and the reason behind screaming mouse carcasses.
|
||||
if(M.ckey)
|
||||
message_admins("[key_name(owner)] has digested [key_name(M)] in their [lowertext(name)] ([owner ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[owner.x];Y=[owner.y];Z=[owner.z]'>JMP</a>" : "null"])")
|
||||
log_attack("[key_name(owner)] digested [key_name(M)].")
|
||||
|
||||
// If digested prey is also a pred... anyone inside their bellies gets moved up.
|
||||
if(is_vore_predator(M))
|
||||
for(var/belly in M.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
for(var/thing in B)
|
||||
var/atom/movable/AM = thing
|
||||
AM.forceMove(owner.loc)
|
||||
if(isliving(AM))
|
||||
to_chat(AM,"As [M] melts away around you, you find yourself in [owner]'s [lowertext(name)]")
|
||||
|
||||
//Drop all items into the belly
|
||||
for(var/obj/item/W in M)
|
||||
if(!M.dropItemToGround(W))
|
||||
qdel(W)
|
||||
|
||||
/* //Reagent transfer //maybe someday
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/Pred = owner
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/Prey = M
|
||||
Prey.bloodstr.del_reagent("numbenzyme")
|
||||
Prey.bloodstr.trans_to_holder(Pred.bloodstr, Prey.bloodstr.total_volume, 0.5, TRUE) // Copy=TRUE because we're deleted anyway
|
||||
Prey.ingested.trans_to_holder(Pred.bloodstr, Prey.ingested.total_volume, 0.5, TRUE) // Therefore don't bother spending cpu
|
||||
Prey.touching.trans_to_holder(Pred.bloodstr, Prey.touching.total_volume, 0.5, TRUE) // On updating the prey's reagents
|
||||
else if(M.reagents)
|
||||
M.reagents.trans_to_holder(Pred.bloodstr, M.reagents.total_volume, 0.5, TRUE) */
|
||||
|
||||
// Delete the digested mob
|
||||
qdel(M)
|
||||
|
||||
// Handle a mob being absorbed
|
||||
/obj/belly/proc/absorb_living(var/mob/living/M)
|
||||
M.absorbed = TRUE
|
||||
to_chat(M,"<span class='notice'>[owner]'s [lowertext(name)] absorbs your body, making you part of them.</span>")
|
||||
to_chat(owner,"<span class='notice'>Your [lowertext(name)] absorbs [M]'s body, making them part of you.</span>")
|
||||
|
||||
// Reagent sharing is neat, but eh. I'll figure it out later
|
||||
/* if(ishuman(M) && ishuman(owner))
|
||||
var/mob/living/carbon/human/Prey = M
|
||||
var/mob/living/carbon/human/Pred = owner
|
||||
//Reagent sharing for absorbed with pred - Copy so both pred and prey have these reagents.
|
||||
Prey.bloodstr.trans_to_holder(Pred.bloodstr, Prey.bloodstr.total_volume, copy = TRUE)
|
||||
Prey.ingested.trans_to_holder(Pred.bloodstr, Prey.ingested.total_volume, copy = TRUE)
|
||||
Prey.touching.trans_to_holder(Pred.bloodstr, Prey.touching.total_volume, copy = TRUE)
|
||||
// TODO - Find a way to make the absorbed prey share the effects with the pred.
|
||||
// Currently this is infeasible because reagent containers are designed to have a single my_atom, and we get
|
||||
// problems when A absorbs B, and then C absorbs A, resulting in B holding onto an invalid reagent container.
|
||||
*/
|
||||
//This is probably already the case, but for sub-prey, it won't be.
|
||||
if(M.loc != src)
|
||||
M.forceMove(src)
|
||||
|
||||
//Seek out absorbed prey of the prey, absorb them too.
|
||||
//This in particular will recurse oddly because if there is absorbed prey of prey of prey...
|
||||
//it will just move them up one belly. This should never happen though since... when they were
|
||||
//absobred, they should have been absorbed as well!
|
||||
for(var/belly in M.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
for(var/mob/living/Mm in B)
|
||||
if(Mm.absorbed)
|
||||
absorb_living(Mm)
|
||||
|
||||
//Update owner
|
||||
owner.updateVRPanel()
|
||||
|
||||
//Digest a single item
|
||||
//Receives a return value from digest_act that's how much nutrition
|
||||
//the item should be worth
|
||||
/obj/belly/proc/digest_item(var/obj/item/item)
|
||||
var/digested = item.digest_act(src, owner)
|
||||
if(!digested)
|
||||
items_preserved |= item
|
||||
else
|
||||
// owner.nutrition += (5 * digested) // haha no.
|
||||
if(iscyborg(owner))
|
||||
var/mob/living/silicon/robot/R = owner
|
||||
R.cell.charge += (50 * digested)
|
||||
|
||||
//Determine where items should fall out of us into.
|
||||
//Typically just to the owner's location.
|
||||
/obj/belly/drop_location()
|
||||
//Should be the case 99.99% of the time
|
||||
if(owner)
|
||||
return owner.loc
|
||||
//Sketchy fallback for safety, put them somewhere safe.
|
||||
else if(ismob(src))
|
||||
testing("[src] (\ref[src]) doesn't have an owner, and dropped someone at a latespawn point!")
|
||||
SSjob.SendToLateJoin(src)
|
||||
// wew lad. let's see if this never gets used, hopefully
|
||||
else
|
||||
qdel(src) //final option, I guess.
|
||||
testing("[src] (\ref[src]) was QDEL'd for not having a drop_location!")
|
||||
|
||||
//Handle a mob struggling
|
||||
// Called from /mob/living/carbon/relaymove()
|
||||
/obj/belly/proc/relay_resist(var/mob/living/R)
|
||||
if (!(R in contents))
|
||||
return // User is not in this belly
|
||||
|
||||
R.setClickCooldown(50)
|
||||
|
||||
if(owner.stat || !owner.client && R.a_intent != INTENT_HELP) //If owner is stat (dead, KO) we can actually escape
|
||||
to_chat(R,"<span class='warning'>You attempt to climb out of \the [lowertext(name)]. (This will take around 5 seconds.)</span>")
|
||||
to_chat(owner,"<span class='warning'>Someone is attempting to climb out of your [lowertext(name)]!</span>")
|
||||
|
||||
if(do_after(R, 50, owner))
|
||||
if(owner.stat && (R in contents) && R.a_intent != INTENT_HELP) //Can still escape and want to?
|
||||
release_specific_contents(R)
|
||||
return
|
||||
else if(!(R in contents)) //Aren't even in the belly. Quietly fail.
|
||||
return
|
||||
else //Belly became inescapable or mob revived
|
||||
to_chat(R,"<span class='warning'>Your attempt to escape [lowertext(name)] has failed!</span>")
|
||||
to_chat(owner,"<span class='notice'>The attempt to escape from your [lowertext(name)] has failed!</span>")
|
||||
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 = "<span class='alert'>" + struggle_outer_message + "</span>"
|
||||
struggle_user_message = "<span class='alert'>" + struggle_user_message + "</span>"
|
||||
|
||||
for(var/mob/M in get_hearers_in_view(3, get_turf(owner)))
|
||||
M.show_message(struggle_outer_message, 2) // hearable
|
||||
to_chat(R,struggle_user_message)
|
||||
|
||||
if(!silent)
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(owner),"struggle_sound",35,0,-5,1,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
R.stop_sound_channel(CHANNEL_PRED)
|
||||
var/sound/prey_struggle = sound(get_sfx("prey_struggle"))
|
||||
R.playsound_local(get_turf(R),prey_struggle,45,0)
|
||||
|
||||
if(R.a_intent != INTENT_HELP) //If on non help intent
|
||||
to_chat(R,"<span class='warning'>You start to climb out of \the [lowertext(name)].</span>")
|
||||
to_chat(owner,"<span class='warning'>Someone is attempting to climb out of your [lowertext(name)]!</span>")
|
||||
if(do_after(R, escapetime, owner))
|
||||
if((owner.stat || !owner.client || escapable) && (R in contents))
|
||||
release_specific_contents(R)
|
||||
to_chat(R,"<span class='warning'>You climb out of \the [lowertext(name)].</span>")
|
||||
to_chat(owner,"<span class='warning'>[R] climbs out of your [lowertext(name)]!</span>")
|
||||
for(var/mob/M in hearers(4, owner))
|
||||
M.show_message("<span class='warning'>[R] climbs out of [owner]'s [lowertext(name)]!</span>", 2)
|
||||
return
|
||||
else if(!istype(loc, /obj/belly)) //Aren't even in the belly. Quietly fail.
|
||||
return
|
||||
else //Belly became inescapable.
|
||||
to_chat(R,"<span class='warning'>Your attempt to escape [lowertext(name)] has failed!</span>")
|
||||
to_chat(owner,"<span class='notice'>The attempt to escape from your [lowertext(name)] has failed!</span>")
|
||||
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/belly in owner.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
if(B.name == transferlocation)
|
||||
dest_belly = B
|
||||
break
|
||||
if(!dest_belly)
|
||||
to_chat(owner, "<span class='warning'>Something went wrong with your belly transfer settings. Your <b>[lowertext(name)]</b> has had it's transfer chance and transfer location cleared as a precaution.</span>")
|
||||
transferchance = 0
|
||||
transferlocation = null
|
||||
return
|
||||
|
||||
to_chat(R,"<span class='warning'>Your attempt to escape [lowertext(name)] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!</span>")
|
||||
to_chat(owner,"<span class='warning'>Someone slid into your [transferlocation] due to their struggling inside your [lowertext(name)]!</span>")
|
||||
transfer_contents(R, dest_belly)
|
||||
return
|
||||
/*
|
||||
else if(prob(absorbchance) && digest_mode != DM_ABSORB) //After that, let's have it run the absorb chance.
|
||||
to_chat(R,"<span class='warning'>In response to your struggling, \the [lowertext(name)] begins to cling more tightly...</span>")
|
||||
to_chat(owner,"<span class='warning'>You feel your [lowertext(name)] start to cling onto its contents...</span>")
|
||||
digest_mode = DM_ABSORB
|
||||
return
|
||||
|
||||
else if(prob(digestchance) && digest_mode != DM_ITEMWEAK && digest_mode != DM_DIGEST) //Finally, let's see if it should run the digest chance.
|
||||
to_chat(R,"<span class='warning'>In response to your struggling, \the [lowertext(name)] begins to get more active...</span>")
|
||||
to_chat(owner,"<span class='warning'>You feel your [lowertext(name)] beginning to become active!</span>")
|
||||
digest_mode = DM_ITEMWEAK
|
||||
return
|
||||
|
||||
else if(prob(digestchance) && digest_mode == DM_ITEMWEAK) //Oh god it gets even worse if you fail twice!
|
||||
to_chat(R,"<span class='warning'>In response to your struggling, \the [lowertext(name)] begins to get even more active!</span>")
|
||||
to_chat(owner,"<span class='warning'>You feel your [lowertext(name)] beginning to become even more active!</span>")
|
||||
digest_mode = DM_DIGEST
|
||||
return */
|
||||
else if(prob(digestchance)) //Finally, let's see if it should run the digest chance.)
|
||||
to_chat(R, "<span class='warning'>In response to your struggling, \the [name] begins to get more active...</span>")
|
||||
to_chat(owner, "<span class='warning'>You feel your [name] beginning to become active!</span>")
|
||||
digest_mode = DM_DIGEST
|
||||
return
|
||||
|
||||
else //Nothing interesting happened.
|
||||
to_chat(R,"<span class='warning'>You make no progress in escaping [owner]'s [lowertext(name)].</span>")
|
||||
to_chat(owner,"<span class='warning'>Your prey appears to be unable to make any progress in escaping your [lowertext(name)].</span>")
|
||||
return
|
||||
|
||||
//Transfers contents from one belly to another
|
||||
/obj/belly/proc/transfer_contents(var/atom/movable/content, var/obj/belly/target, silent = FALSE)
|
||||
if(!(content in src) || !istype(target))
|
||||
return
|
||||
target.nom_mob(content, target.owner)
|
||||
if(!silent)
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(owner),"[src.vore_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
owner.updateVRPanel()
|
||||
for(var/mob/living/M in contents)
|
||||
M.updateVRPanel()
|
||||
|
||||
// Belly copies and then returns the copy
|
||||
// Needs to be updated for any var changes
|
||||
/obj/belly/proc/copy(mob/new_owner)
|
||||
var/obj/belly/dupe = new /obj/belly(new_owner)
|
||||
|
||||
//// Non-object variables
|
||||
dupe.name = name
|
||||
dupe.desc = desc
|
||||
dupe.vore_sound = vore_sound
|
||||
dupe.vore_verb = vore_verb
|
||||
dupe.release_sound = release_sound
|
||||
dupe.human_prey_swallow_time = human_prey_swallow_time
|
||||
dupe.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
|
||||
dupe.emote_time = emote_time
|
||||
dupe.digest_brute = digest_brute
|
||||
dupe.digest_burn = digest_burn
|
||||
dupe.immutable = immutable
|
||||
dupe.can_taste = can_taste
|
||||
dupe.escapable = escapable
|
||||
dupe.escapetime = escapetime
|
||||
dupe.digestchance = digestchance
|
||||
dupe.absorbchance = absorbchance
|
||||
dupe.escapechance = escapechance
|
||||
dupe.transferchance = transferchance
|
||||
dupe.transferlocation = transferlocation
|
||||
dupe.bulge_size = bulge_size
|
||||
// dupe.shrink_grow_size = shrink_grow_size
|
||||
|
||||
//// 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
|
||||
dupe.silent = silent
|
||||
|
||||
return dupe
|
||||
@@ -1,467 +0,0 @@
|
||||
//
|
||||
// The belly object is what holds onto a mob while they're inside a predator.
|
||||
// It takes care of altering the pred's decription, digesting the prey, relaying struggles etc.
|
||||
//
|
||||
|
||||
// If you change what variables are on this, then you need to update the copy() proc.
|
||||
|
||||
//
|
||||
// Parent type of all the various "belly" varieties.
|
||||
//
|
||||
/datum/belly
|
||||
var/name // Name of this location
|
||||
var/inside_flavor // Flavor text description of inside sight/sound/smells/feels.
|
||||
var/vore_sound = 'sound/vore/pred/swallow_01.ogg' // Sound when ingesting someone
|
||||
var/vore_verb = "ingest" // Verb for eating with this in messages
|
||||
var/human_prey_swallow_time = 10 SECONDS // Time in deciseconds to swallow /mob/living/carbon/human
|
||||
var/nonhuman_prey_swallow_time = 5 SECONDS // Time in deciseconds to swallow anything else
|
||||
var/emoteTime = 30 SECONDS // How long between stomach emotes at prey
|
||||
var/digest_brute = 0 // Brute damage per tick in digestion mode
|
||||
var/digest_burn = 1 // Burn damage per tick in digestion mode
|
||||
var/digest_tickrate = 9 // Modulus this of air controller tick number to iterate gurgles on
|
||||
var/immutable = FALSE // Prevents this belly from being deleted
|
||||
var/escapable = FALSE // Belly can be resisted out of at any time
|
||||
var/escapetime = 60 SECONDS // Deciseconds, how long to escape this belly
|
||||
var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles
|
||||
// var/silenced = FALSE // Will the heartbeat/fleshy internal loop play?
|
||||
var/escapechance = 0 // % Chance of prey beginning to escape if prey struggles.
|
||||
|
||||
var/datum/belly/transferlocation = null // Location that the prey is released if they struggle and get dropped off.
|
||||
var/transferchance = 0 // % Chance of prey being transferred to transfer location when resisting
|
||||
var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location
|
||||
var/autotransferwait = 10 // Time between trying to transfer.
|
||||
var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone.
|
||||
|
||||
var/tmp/digest_mode = DM_HOLD // Whether or not to digest. Default to not digest.
|
||||
var/tmp/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY) // Possible digest modes
|
||||
var/tmp/mob/living/owner // The mob whose belly this is.
|
||||
var/tmp/list/internal_contents = list() // People/Things you've eaten into this belly!
|
||||
var/tmp/is_full // Flag for if digested remeans are present. (for disposal messages)
|
||||
var/tmp/emotePend = FALSE // If there's already a spawned thing counting for the next emote
|
||||
var/swallow_time = 10 SECONDS // for mob transfering automation
|
||||
var/vore_capacity = 1 // The capacity (in people) this person can hold
|
||||
|
||||
// Don't forget to watch your commas at the end of each line if you change these.
|
||||
var/list/struggle_messages_outside = list(
|
||||
"%pred's %belly wobbles with a squirming meal.",
|
||||
"%pred's %belly jostles with movement.",
|
||||
"%pred's %belly briefly swells outward as someone pushes from inside.",
|
||||
"%pred's %belly fidgets with a trapped victim.",
|
||||
"%pred's %belly jiggles with motion from inside.",
|
||||
"%pred's %belly sloshes around.",
|
||||
"%pred's %belly gushes softly.",
|
||||
"%pred's %belly lets out a wet squelch.")
|
||||
|
||||
var/list/struggle_messages_inside = list(
|
||||
"Your useless squirming only causes %pred's slimy %belly to squelch over your body.",
|
||||
"Your struggles only cause %pred's %belly to gush softly around you.",
|
||||
"Your movement only causes %pred's %belly to slosh around you.",
|
||||
"Your motion causes %pred's %belly to jiggle.",
|
||||
"You fidget around inside of %pred's %belly.",
|
||||
"You shove against the walls of %pred's %belly, making it briefly swell outward.",
|
||||
"You jostle %pred's %belly with movement.",
|
||||
"You squirm inside of %pred's %belly, making it wobble around.")
|
||||
|
||||
var/list/digest_messages_owner = list(
|
||||
"You feel %prey's body succumb to your digestive system, which breaks it apart into soft slurry.",
|
||||
"You hear a lewd glorp as your %belly muscles grind %prey into a warm pulp.",
|
||||
"Your %belly lets out a rumble as it melts %prey into sludge.",
|
||||
"You feel a soft gurgle as %prey's body loses form in your %belly. They're nothing but a soft mass of churning slop now.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your thighs.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your rump.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your belly.",
|
||||
"Your %belly groans as %prey falls apart into a thick soup. You can feel their remains soon flowing deeper into your body to be absorbed.",
|
||||
"Your %belly kneads on every fiber of %prey, softening them down into mush to fuel your next hunt.",
|
||||
"Your %belly churns %prey down into a hot slush. You can feel the nutrients coursing through your digestive track with a series of long, wet glorps.")
|
||||
|
||||
var/list/digest_messages_prey = list(
|
||||
"Your body succumbs to %pred's digestive system, which breaks you apart into soft slurry.",
|
||||
"%pred's %belly lets out a lewd glorp as their muscles grind you into a warm pulp.",
|
||||
"%pred's %belly lets out a rumble as it melts you into sludge.",
|
||||
"%pred feels a soft gurgle as your body loses form in their %belly. You're nothing but a soft mass of churning slop now.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's thighs.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's rump.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's belly.",
|
||||
"%pred's %belly groans as you fall apart into a thick soup. Your remains soon flow deeper into %pred's body to be absorbed.",
|
||||
"%pred's %belly kneads on every fiber of your body, softening you down into mush to fuel their next hunt.",
|
||||
"%pred's %belly churns you down into a hot slush. Your nutrient-rich remains course through their digestive track with a series of long, wet glorps.")
|
||||
|
||||
var/list/examine_messages = list(
|
||||
"They have something solid in their %belly!",
|
||||
"It looks like they have something in their %belly!")
|
||||
|
||||
//Mostly for being overridden on precreated bellies on mobs. Could be VV'd into
|
||||
//a carbon's belly if someone really wanted. No UI for carbons to adjust this.
|
||||
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
|
||||
var/list/emote_lists = list()
|
||||
|
||||
// Constructor that sets the owning mob
|
||||
/datum/belly/New(var/mob/living/owning_mob)
|
||||
owner = owning_mob
|
||||
|
||||
// Toggle digestion on/off and notify user of the new setting.
|
||||
// If multiple digestion modes are avaliable (i.e. unbirth) then user should be prompted.
|
||||
/datum/belly/proc/toggle_digestion()
|
||||
return
|
||||
|
||||
// Checks if any mobs are present inside the belly
|
||||
// return True if the belly is empty.
|
||||
/datum/belly/proc/is_empty()
|
||||
return internal_contents.len == 0
|
||||
|
||||
// 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.
|
||||
/datum/belly/proc/release_all_contents()
|
||||
if (internal_contents.len == 0)
|
||||
return 0
|
||||
for (var/atom/movable/M in internal_contents)
|
||||
M.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner.
|
||||
for(var/mob/living/W in M)
|
||||
W.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
internal_contents.Remove(M) // Remove from the belly contents
|
||||
|
||||
var/datum/belly/B = check_belly(owner) // This makes sure that the mob behaves properly if released into another mob
|
||||
if(B)
|
||||
B.internal_contents.Add(M)
|
||||
|
||||
owner.visible_message("<font color='green'><b>[owner] expels everything from their [lowertext(name)]!</b></font>")
|
||||
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.
|
||||
for(var/mob/living/W in M)
|
||||
W.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
src.internal_contents.Remove(M) // Remove from the belly contents
|
||||
|
||||
var/datum/belly/B = check_belly(owner)
|
||||
if(B)
|
||||
B.internal_contents.Add(M)
|
||||
|
||||
owner.visible_message("<font color='green'><b>[owner] expels [M] from their [lowertext(name)]!</b></font>")
|
||||
// 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)
|
||||
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
|
||||
|
||||
prey.forceMove(owner)
|
||||
internal_contents.Add(prey)
|
||||
prey.playsound_local(get_turf(prey),preyloop,40,0, channel = CHANNEL_PREYLOOP)
|
||||
|
||||
// Handle prey messages
|
||||
if(inside_flavor)
|
||||
to_chat(prey, "<span class='warning'><B>[src.inside_flavor]</B></span>")
|
||||
if(isliving(prey))
|
||||
var/mob/living/M = prey
|
||||
if(can_taste && M.get_taste_message(0))
|
||||
to_chat(owner, "<span class='notice'>[M] tastes of [M.get_taste_message(0)].</span>")
|
||||
|
||||
// Setup the autotransfer checks if needed
|
||||
if(transferlocation && autotransferchance > 0)
|
||||
addtimer(CALLBACK(src, /datum/belly/.proc/check_autotransfer, prey), autotransferwait)
|
||||
|
||||
/datum/belly/proc/check_autotransfer(var/mob/prey)
|
||||
// Some sanity checks
|
||||
if(transferlocation && (autotransferchance > 0) && (prey in internal_contents))
|
||||
if(prob(autotransferchance))
|
||||
// Double check transferlocation isn't insane
|
||||
if(verify_transferlocation())
|
||||
transfer_contents(prey, transferlocation)
|
||||
else
|
||||
// Didn't transfer, so wait before retrying
|
||||
addtimer(CALLBACK(src, /datum/belly/.proc/check_autotransfer, prey), autotransferwait)
|
||||
|
||||
/datum/belly/proc/verify_transferlocation()
|
||||
for(var/I in owner.vore_organs)
|
||||
var/datum/belly/B = owner.vore_organs[I]
|
||||
if(B == transferlocation)
|
||||
return TRUE
|
||||
|
||||
for(var/I in owner.vore_organs)
|
||||
var/datum/belly/B = owner.vore_organs[I]
|
||||
if(B.name == transferlocation.name)
|
||||
transferlocation = B
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// 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))
|
||||
formatted_message = replacetext(formatted_message,"%pred",owner)
|
||||
formatted_message = replacetext(formatted_message,"%prey",english_list(internal_contents))
|
||||
|
||||
return("<span class='warning'>[formatted_message]</span><BR>")
|
||||
|
||||
// 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)
|
||||
M.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
// 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)
|
||||
to_chat(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)
|
||||
var/sound/prey_struggle = sound(get_sfx("prey_struggle"))
|
||||
|
||||
if(owner.stat) //If owner is stat (dead, KO) we can actually escape
|
||||
to_chat(R, "<span class='warning'>You attempt to climb out of \the [name]. (This will take around [escapetime/10] seconds.)</span>")
|
||||
to_chat(owner, "<span class='warning'>Someone is attempting to climb out of your [name]!</span>")
|
||||
|
||||
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
|
||||
to_chat(R, "<span class='warning'>Your attempt to escape [name] has failed!</span>")
|
||||
to_chat(owner, "<span class='notice'>The attempt to escape from your [name] has failed!</span>")
|
||||
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 = "<span class='alert'>" + struggle_outer_message + "</span>"
|
||||
struggle_user_message = "<span class='alert'>" + struggle_user_message + "</span>"
|
||||
|
||||
R.visible_message( "<span class='alert'>[struggle_outer_message]</span>", "<span class='alert'>[struggle_user_message]</span>")
|
||||
playsound(get_turf(owner),"struggle_sound",35,0,-6,1,channel=151,ignore_walls = FALSE)
|
||||
R.stop_sound_channel(151)
|
||||
R.playsound_local(get_turf(R),prey_struggle,45,0)
|
||||
|
||||
if(escapable && R.a_intent != "help") //If the stomach has escapable enabled and the person is actually trying to kick out
|
||||
to_chat(R, "<span class='warning'>You attempt to climb out of \the [name].</span>")
|
||||
to_chat(owner, "<span class='warning'>Someone is attempting to climb out of your [name]!</span>")
|
||||
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)
|
||||
to_chat(R, "<span class='warning'>You climb out of \the [name].</span>")
|
||||
to_chat(owner, "<span class='warning'>[R] climbs out of your [name]!</span>")
|
||||
for(var/mob/M in viewers(4, owner))
|
||||
M.visible_message("<span class='warning'>[R] climbs out of [owner]'s [name]!</span>", 2)
|
||||
return
|
||||
else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
|
||||
return
|
||||
else //Belly became inescapable.
|
||||
to_chat(R, "<span class='warning'>Your attempt to escape [name] has failed!</span>")
|
||||
to_chat(owner, "<span class='notice'>The attempt to escape from your [name] has failed!/span>")
|
||||
return
|
||||
|
||||
else if(prob(transferchance) && istype(transferlocation)) //Next, let's have it see if they end up getting into an even bigger mess then when they started.
|
||||
var/location_ok = verify_transferlocation()
|
||||
|
||||
if(!location_ok)
|
||||
to_chat(owner, "<span class='warning'>Something went wrong with your belly transfer settings.</span>")
|
||||
transferlocation = null
|
||||
return
|
||||
|
||||
to_chat(R, "<span class='warning'>Your attempt to escape [name] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!</span>")
|
||||
to_chat(owner, "<span class='warning'>Someone slid into your [transferlocation] due to their struggling inside your [name]!</span>")
|
||||
transfer_contents(R, transferlocation)
|
||||
return
|
||||
|
||||
else if(prob(digestchance)) //Finally, let's see if it should run the digest chance.)
|
||||
to_chat(R, "<span class='warning'>In response to your struggling, \the [name] begins to get more active...</span>")
|
||||
to_chat(owner, "<span class='warning'>You feel your [name] beginning to become active!</span>")
|
||||
digest_mode = DM_DIGEST
|
||||
return
|
||||
else //Nothing interesting happened.
|
||||
to_chat(R, "<span class='warning'>But make no progress in escaping [owner]'s [name].</span>")
|
||||
to_chat(owner, "<span class='warning'>But appears to be unable to make any progress in escaping your [name].</span>")
|
||||
return
|
||||
|
||||
//Transfers contents from one belly to another
|
||||
/datum/belly/proc/transfer_contents(var/atom/movable/content, var/datum/belly/target, silent = 0)
|
||||
if(!(content in internal_contents))
|
||||
return
|
||||
internal_contents.Remove(content)
|
||||
// Re-use nom_mob
|
||||
target.nom_mob(content, target.owner)
|
||||
if(!silent)
|
||||
playsound(get_turf(owner),"[target].vore_sound",35,0,-6,1,ignore_walls = FALSE)
|
||||
/*
|
||||
//Handles creation of temporary 'vore chest' upon digestion
|
||||
/datum/belly/proc/slimy_mass(var/obj/item/content, var/mob/living/M)
|
||||
if(!content in internal_contents)
|
||||
return
|
||||
internal_contents += new /obj/structure/closet/crate/vore(src)
|
||||
internal_contents.Remove(content)
|
||||
M.transferItemToLoc(content, /obj/structure/closet/crate/vore)
|
||||
if(!M.transferItemToLoc(W))
|
||||
qdel(W)
|
||||
|
||||
/datum/belly/proc/regurgitate_items(var/obj/structure/closet/crate/vore/C)
|
||||
*/
|
||||
|
||||
// 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.can_taste = can_taste
|
||||
dupe.escapable = escapable
|
||||
dupe.escapetime = escapetime
|
||||
dupe.digestchance = digestchance
|
||||
dupe.escapechance = escapechance
|
||||
dupe.transferchance = transferchance
|
||||
dupe.transferlocation = transferlocation
|
||||
dupe.autotransferchance = autotransferchance
|
||||
dupe.autotransferwait = autotransferwait
|
||||
|
||||
//// 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
|
||||
@@ -1,34 +1,53 @@
|
||||
// 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()
|
||||
var/sound/prey_gurgle = sound(get_sfx("digest_prey"))
|
||||
var/sound/prey_digest = sound(get_sfx("death_prey"))
|
||||
/obj/belly/proc/process_belly(var/times_fired,var/wait) //Passed by controller
|
||||
if((times_fired < next_process) || !contents.len)
|
||||
recent_sound = FALSE
|
||||
return SSBELLIES_IGNORED
|
||||
|
||||
if(loc != owner)
|
||||
if(istype(owner))
|
||||
loc = owner
|
||||
else
|
||||
qdel(src)
|
||||
return SSBELLIES_PROCESSED
|
||||
|
||||
next_process = times_fired + (6 SECONDS/wait) //Set up our next process time.
|
||||
|
||||
/////////////////////////// Auto-Emotes ///////////////////////////
|
||||
if((digest_mode in emote_lists) && !emotePend)
|
||||
emotePend = TRUE
|
||||
if(contents.len && next_emote <= times_fired)
|
||||
next_emote = times_fired + round(emote_time/wait,1)
|
||||
var/list/EL = emote_lists[digest_mode]
|
||||
for(var/mob/living/M in contents)
|
||||
if(M.digestable || !(digest_mode == DM_DIGEST)) // don't give digesty messages to indigestible people
|
||||
to_chat(M,"<span class='notice'>[pick(EL)]</span>")
|
||||
|
||||
/////////////////////////// Exit Early ////////////////////////////
|
||||
var/list/touchable_items = contents - items_preserved
|
||||
if(!length(touchable_items))
|
||||
return SSBELLIES_PROCESSED
|
||||
|
||||
////////////////////////// Sound vars /////////////////////////////
|
||||
var/sound/prey_digest = sound(get_sfx("digest_prey"))
|
||||
var/sound/prey_death = sound(get_sfx("death_prey"))
|
||||
|
||||
spawn(emoteTime)
|
||||
var/list/EL = emote_lists[digest_mode]
|
||||
for(var/mob/living/M in internal_contents)
|
||||
M << "<span class='notice'>[pick(EL)]</span>"
|
||||
src.emotePend = FALSE
|
||||
|
||||
///////////////////////////// DM_HOLD /////////////////////////////
|
||||
if(digest_mode == DM_HOLD)
|
||||
return //Pretty boring, huh
|
||||
return SSBELLIES_PROCESSED
|
||||
|
||||
//////////////////////////// DM_DIGEST ////////////////////////////
|
||||
if(digest_mode == DM_DIGEST)
|
||||
for (var/mob/living/M in internal_contents)
|
||||
else if(digest_mode == DM_DIGEST)
|
||||
for (var/mob/living/M in contents)
|
||||
if(prob(25))
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(owner),"digest_pred",50,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(H.client && H.client.prefs.toggles & DIGESTION_NOISES)
|
||||
playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
M.playsound_local(get_turf(M), prey_digest, 45)
|
||||
|
||||
//Pref protection!
|
||||
if (!M.digestable)
|
||||
if (!M.digestable || M.absorbed)
|
||||
continue
|
||||
|
||||
//Person just died in guts!
|
||||
@@ -51,10 +70,13 @@
|
||||
M.visible_message("<span class='notice'>You watch as [owner]'s form loses its additions.</span>")
|
||||
|
||||
owner.nutrition += 400 // so eating dead mobs gives you *something*.
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(owner),"death_pred",45,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_digest)
|
||||
M.stop_sound_channel(DIGESTION_NOISES)
|
||||
for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(H.client && H.client.prefs.toggles & DIGESTION_NOISES)
|
||||
playsound(get_turf(owner),"death_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
|
||||
M.stop_sound_channel(DIGESTION_NOISES)
|
||||
M.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
M.playsound_local(get_turf(M), prey_death, 65)
|
||||
digestion_death(M)
|
||||
owner.update_icons()
|
||||
continue
|
||||
@@ -64,44 +86,57 @@
|
||||
if(!(M.status_flags & GODMODE))
|
||||
M.adjustFireLoss(digest_burn)
|
||||
owner.nutrition += 1
|
||||
return
|
||||
|
||||
//Contaminate or gurgle items
|
||||
var/obj/item/T = pick(touchable_items)
|
||||
if(istype(T))
|
||||
if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ))
|
||||
digest_item(T)
|
||||
|
||||
owner.updateVRPanel()
|
||||
|
||||
///////////////////////////// DM_HEAL /////////////////////////////
|
||||
if(digest_mode == DM_HEAL)
|
||||
for (var/mob/living/M in internal_contents)
|
||||
for (var/mob/living/M in contents)
|
||||
if(prob(25))
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(owner),"digest_pred",35,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(H.client && H.client.prefs.toggles & DIGESTION_NOISES)
|
||||
playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
M.playsound_local(get_turf(M), prey_digest, 65)
|
||||
|
||||
if(M.stat != DEAD)
|
||||
if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
|
||||
M.adjustBruteLoss(-1)
|
||||
M.adjustFireLoss(-1)
|
||||
owner.nutrition -= 10
|
||||
M.adjustBruteLoss(-3)
|
||||
M.adjustFireLoss(-3)
|
||||
owner.nutrition -= 5
|
||||
return
|
||||
|
||||
////////////////////////// DM_NOISY /////////////////////////////////
|
||||
//for when you just want people to squelch around
|
||||
if(digest_mode == DM_NOISY)
|
||||
for (var/mob/living/M in internal_contents)
|
||||
for (var/mob/living/M in contents)
|
||||
if(prob(35))
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(H.client && H.client.prefs.toggles & DIGESTION_NOISES)
|
||||
playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(owner),"digest_pred",35,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
|
||||
M.playsound_local(get_turf(M), prey_digest, 65)
|
||||
|
||||
|
||||
//////////////////////////DM_DRAGON /////////////////////////////////////
|
||||
//because dragons need snowflake guts
|
||||
if(digest_mode == DM_DRAGON)
|
||||
for (var/mob/living/M in internal_contents)
|
||||
for (var/mob/living/M in contents)
|
||||
if(prob(25))
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(owner),"digest_pred",50,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(H.client && H.client.prefs.toggles & DIGESTION_NOISES)
|
||||
playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
M.playsound_local(get_turf(M), prey_digest, 65)
|
||||
|
||||
//No digestion protection for megafauna.
|
||||
|
||||
@@ -124,12 +159,14 @@
|
||||
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
|
||||
M.visible_message("<span class='notice'>You watch as [owner]'s guts loudly rumble as it finishes off a meal.</span>")
|
||||
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
playsound(get_turf(owner),"death_pred",45,0,-6,0,channel=CHANNEL_PRED)
|
||||
M.stop_sound_channel(CHANNEL_PRED)
|
||||
M.playsound_local(get_turf(M), null, 45, S = prey_digest)
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
|
||||
if(H.client && H.client.prefs.toggles & DIGESTION_NOISES)
|
||||
playsound(get_turf(owner),"death_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
|
||||
M.stop_sound_channel(CHANNEL_DIGEST)
|
||||
M.playsound_local(get_turf(M), prey_death, 65)
|
||||
M.spill_organs(FALSE,TRUE,TRUE)
|
||||
M << sound(null, repeat = 0, wait = 0, volume = 80, channel = CHANNEL_PREYLOOP)
|
||||
M.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
digestion_death(M)
|
||||
owner.update_icons()
|
||||
continue
|
||||
@@ -138,6 +175,12 @@
|
||||
// Deal digestion damage (and feed the pred)
|
||||
if(!(M.status_flags & GODMODE))
|
||||
M.adjustFireLoss(digest_burn)
|
||||
M.adjustToxLoss(4) // something something plasma based acids
|
||||
M.adjustCloneLoss(3) // eventually this'll kill you if you're healing everything else, you nerds.
|
||||
return
|
||||
M.adjustToxLoss(2) // something something plasma based acids
|
||||
M.adjustCloneLoss(1) // eventually this'll kill you if you're healing everything else, you nerds.
|
||||
//Contaminate or gurgle items
|
||||
var/obj/item/T = pick(touchable_items)
|
||||
if(istype(T))
|
||||
if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ))
|
||||
digest_item(T)
|
||||
|
||||
owner.updateVRPanel()
|
||||
@@ -0,0 +1,119 @@
|
||||
//Please make sure to:
|
||||
//return FALSE: You are not going away, stop asking me to digest.
|
||||
//return non-negative integer: Amount of nutrition/charge gained (scaled to nutrition, other end can multiply for charge scale).
|
||||
|
||||
// Ye default implementation.
|
||||
/obj/item/proc/digest_act(var/atom/movable/item_storage = null)
|
||||
for(var/obj/item/O in contents)
|
||||
if(istype(O,/obj/item/storage/internal)) //Dump contents from dummy pockets.
|
||||
for(var/obj/item/SO in O)
|
||||
if(item_storage)
|
||||
SO.forceMove(item_storage)
|
||||
qdel(O)
|
||||
else if(item_storage)
|
||||
O.forceMove(item_storage)
|
||||
|
||||
qdel(src)
|
||||
return w_class
|
||||
|
||||
/////////////
|
||||
// Some indigestible stuff
|
||||
/////////////
|
||||
/obj/item/hand_tele/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/card/id/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/aicard/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/paicard/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/pinpointer/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/disk/nuclear/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/device/perfect_tele_beacon/digest_act(...)
|
||||
return FALSE //Sorta important to not digest your own beacons.
|
||||
/obj/item/device/pda/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/gun/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/clothing/shoes/magboots/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/clothing/head/helmet/space/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/clothing/suit/space/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/reagent_containers/hypospray/CMO/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/tank/jetpack/oxygen/captain/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/clothing/accessory/medal/gold/captain/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/clothing/suit/armor/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/documents/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/nuke_core/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/nuke_core_container/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/areaeditor/blueprints/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/documents/syndicate/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/bombcore/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/grenade/digest_act(...)
|
||||
return FALSE
|
||||
/obj/item/storage/digest_act(...)
|
||||
return FALSE
|
||||
|
||||
/////////////
|
||||
// Some special treatment
|
||||
/////////////
|
||||
/*
|
||||
//PDAs need to lose their ID to not take it with them, so we can get a digested ID
|
||||
/obj/item/device/pda/digest_act(var/atom/movable/item_storage = null)
|
||||
if(id)
|
||||
id = null
|
||||
|
||||
. = ..()
|
||||
*/
|
||||
|
||||
/obj/item/reagent_containers/food/digest_act(var/atom/movable/item_storage = null)
|
||||
if(isbelly(item_storage))
|
||||
var/obj/belly/B = item_storage
|
||||
if(ishuman(B.owner))
|
||||
var/mob/living/carbon/human/H = B.owner
|
||||
reagents.trans_to(H, (reagents.total_volume * 0.3), 1, 0)
|
||||
else if(iscyborg(B.owner))
|
||||
var/mob/living/silicon/robot/R = B.owner
|
||||
R.cell.charge += 150
|
||||
|
||||
. = ..()
|
||||
|
||||
/*
|
||||
/obj/item/holder/digest_act(var/atom/movable/item_storage = null)
|
||||
for(var/mob/living/M in contents)
|
||||
if(item_storage)
|
||||
M.forceMove(item_storage)
|
||||
held_mob = null
|
||||
|
||||
. = ..() */
|
||||
|
||||
/obj/item/organ/digest_act(var/atom/movable/item_storage = null)
|
||||
if((. = ..()))
|
||||
. += 70 //Organs give a little more
|
||||
|
||||
/obj/item/storage/digest_act(var/atom/movable/item_storage = null)
|
||||
for(var/obj/item/I in contents)
|
||||
I.screen_loc = null
|
||||
|
||||
. = ..()
|
||||
|
||||
/////////////
|
||||
// Some more complicated stuff
|
||||
/////////////
|
||||
/obj/item/device/mmi/digital/posibrain/digest_act(var/atom/movable/item_storage = null)
|
||||
//Replace this with a VORE setting so all types of posibrains can/can't be digested on a whim
|
||||
return FALSE
|
||||
@@ -1,23 +1,24 @@
|
||||
///////////////////// Mob Living /////////////////////
|
||||
/mob/living
|
||||
var/digestable = TRUE // Can the mob be digested inside a belly?
|
||||
var/datum/belly/vore_selected // Default to no vore capability.
|
||||
var/obj/belly/vore_selected // Default to no vore capability.
|
||||
var/list/vore_organs = list() // List of vore containers inside a mob
|
||||
var/devourable = FALSE // Can the mob be vored at all?
|
||||
// var/feeding = FALSE // Are we going to feed someone else?
|
||||
var/vore_taste = null // What the character tastes like
|
||||
var/no_vore = FALSE // If the character/mob can vore.
|
||||
var/openpanel = 0 // Is the vore panel open?
|
||||
var/noisy = FALSE // tummies are rumbly?
|
||||
var/absorbed = FALSE //are we absorbed?
|
||||
|
||||
//
|
||||
// Hook for generic creation of stuff on new creatures
|
||||
//
|
||||
/hook/living_new/proc/vore_setup(mob/living/M)
|
||||
M.verbs += /mob/living/proc/lick
|
||||
M.verbs += /mob/living/proc/preyloop_refresh
|
||||
if(M.no_vore) //If the mob isn's supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach.
|
||||
M << "<span class='warning'>The creature that you are can not eat others.</span>"
|
||||
return TRUE
|
||||
M.verbs += /mob/living/proc/lick
|
||||
if(M.no_vore) //If the mob isn't supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach.
|
||||
return 1
|
||||
M.verbs += /mob/living/proc/insidePanel
|
||||
|
||||
//Tries to load prefs if a client is present otherwise gives freebie stomach
|
||||
@@ -27,44 +28,36 @@
|
||||
|
||||
if(M.client && M.client.prefs_vr)
|
||||
if(!M.copy_from_prefs_vr())
|
||||
M << "<span class='warning'>ERROR: You seem to have saved vore prefs, but they couldn't be loaded.</span>"
|
||||
return FALSE
|
||||
to_chat(M,"<span class='warning'>ERROR: You seem to have saved vore prefs, but they couldn't be loaded.</span>")
|
||||
return 0
|
||||
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)
|
||||
var/obj/belly/B = new /obj/belly(M)
|
||||
M.vore_selected = B
|
||||
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]"
|
||||
B.can_taste = TRUE
|
||||
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.")
|
||||
B.desc = "It appears to be rather warm and wet. Makes sense, considering it's inside \the [M.name]."
|
||||
B.can_taste = FALSE
|
||||
|
||||
//Return 1 to hook-caller
|
||||
return 1
|
||||
|
||||
/*
|
||||
// Hide vore organs in contents
|
||||
//
|
||||
/datum/proc/view_variables_filter_contents(list/L)
|
||||
return 0
|
||||
|
||||
/mob/living/view_variables_filter_contents(list/L)
|
||||
. = ..()
|
||||
var/len_before = L.len
|
||||
L -= vore_organs
|
||||
. += len_before - L.len*/
|
||||
|
||||
// Handle being clicked, perhaps with something to devour
|
||||
//
|
||||
|
||||
@@ -126,33 +119,37 @@
|
||||
var/belly = user.vore_selected
|
||||
return perform_dragon(user, prey, user, belly)
|
||||
|
||||
/mob/living/proc/perform_dragon(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/belly, swallow_time = 20)
|
||||
/mob/living/proc/perform_dragon(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/obj/belly/belly, swallow_time = 20)
|
||||
//Sanity
|
||||
if(!user || !prey || !pred || !belly || !(belly in pred.vore_organs))
|
||||
if(!user || !prey || !pred || !istype(belly) || !(belly in pred.vore_organs))
|
||||
testing("[user] attempted to feed [prey] to [pred], via [lowertext(belly.name)] but it went wrong.")
|
||||
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)"
|
||||
|
||||
/* //Final distance check. Time has passed, menus have come and gone. Can't use do_after adjacent because doesn't behave for held micros
|
||||
var/user_to_pred = get_dist(get_turf(user),get_turf(pred))
|
||||
var/user_to_prey = get_dist(get_turf(user),get_turf(prey)) */
|
||||
|
||||
// Prepare messages
|
||||
if(user == pred) //Feeding someone to yourself
|
||||
attempt_msg = text("<span class='warning'>[] starts to [] [] into their []!</span>",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
success_msg = text("<span class='warning'>[] manages to [] [] into their []!</span>",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
attempt_msg = text("<span class='warning'>[] starts to [] [] into their []!</span>",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
|
||||
success_msg = text("<span class='warning'>[] manages to [] [] into their []!</span>",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
|
||||
|
||||
// Announce that we start the attempt!
|
||||
user.visible_message(attempt_msg)
|
||||
|
||||
if(!do_mob(src, user, swallow_time)) // one second should be good enough, right?
|
||||
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(get_turf(user), belly_target.vore_sound,75,0,-6,0)
|
||||
playsound(get_turf(user), "[belly.vore_sound]",75,0,-6,0)
|
||||
|
||||
// Actually shove prey into the belly.
|
||||
belly_target.nom_mob(prey, user)
|
||||
belly.nom_mob(prey, user)
|
||||
if (pred == user)
|
||||
message_admins("[key_name(pred)] ate [key_name(prey)].")
|
||||
log_attack("[key_name(pred)] ate [key_name(prey)]")
|
||||
@@ -161,43 +158,55 @@
|
||||
// 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)
|
||||
/mob/living/proc/perform_the_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/obj/belly/belly, var/delay)
|
||||
//Sanity
|
||||
if(!user || !prey || !pred || !belly || !(belly in pred.vore_organs))
|
||||
if(!user || !prey || !pred || !istype(belly) || !(belly in pred.vore_organs))
|
||||
testing("[user] attempted to feed [prey] to [pred], via [lowertext(belly.name)] but it went wrong.")
|
||||
return
|
||||
if (!prey.devourable)
|
||||
to_chat(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)"
|
||||
|
||||
/* //Final distance check. Time has passed, menus have come and gone. Can't use do_after adjacent because doesn't behave for held micros
|
||||
var/user_to_pred = get_dist(get_turf(user),get_turf(pred))
|
||||
var/user_to_prey = get_dist(get_turf(user),get_turf(prey)) */
|
||||
|
||||
// Prepare messages
|
||||
if(user == pred) //Feeding someone to yourself
|
||||
attempt_msg = text("<span class='warning'>[] is attemping to [] [] into their []!</span>",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
success_msg = text("<span class='warning'>[] manages to [] [] into their []!</span>",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
attempt_msg = text("<span class='warning'>[] is attemping to [] [] into their []!</span>",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
|
||||
success_msg = text("<span class='warning'>[] manages to [] [] into their []!</span>",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
|
||||
else //Feeding someone to another person
|
||||
attempt_msg = text("<span class='warning'>[] is attempting to make [] [] [] into their []!</span>",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
success_msg = text("<span class='warning'>[] manages to make [] [] [] into their []!</span>",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
attempt_msg = text("<span class='warning'>[] is attempting to make [] [] [] into their []!</span>",user,pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
|
||||
success_msg = text("<span class='warning'>[] manages to make [] [] [] into their []!</span>",user,pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
|
||||
|
||||
// Announce that we start the attempt!
|
||||
user.visible_message(attempt_msg)
|
||||
|
||||
// Now give the prey time to escape... return if they did
|
||||
var/swallow_time = delay || ishuman(prey) ? belly.human_prey_swallow_time : belly.nonhuman_prey_swallow_time
|
||||
|
||||
|
||||
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(get_turf(user), belly_target.vore_sound,75,0,-6,0,ignore_walls = FALSE)
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(user)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(user),"[belly.vore_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
|
||||
// Actually shove prey into the belly.
|
||||
belly_target.nom_mob(prey, user)
|
||||
belly.nom_mob(prey, user)
|
||||
// user.update_icons()
|
||||
stop_pulling()
|
||||
|
||||
// Flavor handling
|
||||
if(belly.can_taste && prey.get_taste_message(FALSE))
|
||||
to_chat(belly.owner, "<span class='notice'>[prey] tastes of [prey.get_taste_message(FALSE)].</span>")
|
||||
|
||||
// Inform Admins
|
||||
var/prey_braindead
|
||||
var/prey_stat
|
||||
@@ -250,50 +259,38 @@
|
||||
|
||||
return 0
|
||||
*/
|
||||
|
||||
//
|
||||
// Release everything in every vore organ
|
||||
//
|
||||
/mob/living/proc/release_vore_contents(var/include_absorbed = TRUE)
|
||||
for(var/belly in vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
B.release_all_contents(include_absorbed)
|
||||
|
||||
//
|
||||
// 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)
|
||||
if(isbelly(loc))
|
||||
var/obj/belly/B = loc
|
||||
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)
|
||||
|
||||
// internal slimy button in case the loop stops playing but the player wants to hear it
|
||||
/mob/living/proc/preyloop_refresh()
|
||||
set name = "Internal loop refresh"
|
||||
set category = "Vore"
|
||||
if(ismob(src.loc))
|
||||
if(istype(src.loc, /obj/belly))
|
||||
src.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case
|
||||
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
|
||||
src.playsound_local(get_turf(src),preyloop,40,0, channel = CHANNEL_PREYLOOP)
|
||||
src.playsound_local(get_turf(src),preyloop,80,0, channel = CHANNEL_PREYLOOP)
|
||||
else
|
||||
to_chat(src, "<span class='alert'>You aren't inside anything, you clod.</span>")
|
||||
|
||||
@@ -309,7 +306,7 @@
|
||||
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]
|
||||
var/obj/belly/B = pred.vore_organs[I]
|
||||
B.release_specific_contents(src)
|
||||
|
||||
for(var/mob/living/simple_animal/SA in range(10))
|
||||
@@ -355,9 +352,15 @@
|
||||
|
||||
P.digestable = src.digestable
|
||||
P.devourable = src.devourable
|
||||
P.belly_prefs = src.vore_organs
|
||||
P.vore_taste = src.vore_taste
|
||||
|
||||
var/list/serialized = list()
|
||||
for(var/belly in src.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
serialized += list(B.serialize()) //Can't add a list as an object to another list in Byond. Thanks.
|
||||
|
||||
P.belly_prefs = serialized
|
||||
|
||||
return TRUE
|
||||
|
||||
//
|
||||
@@ -370,16 +373,52 @@
|
||||
|
||||
var/datum/vore_preferences/P = client.prefs_vr
|
||||
|
||||
src.digestable = P.digestable
|
||||
src.devourable = P.devourable
|
||||
src.vore_organs = list()
|
||||
src.vore_taste = P.vore_taste
|
||||
digestable = P.digestable
|
||||
devourable = P.devourable
|
||||
vore_taste = P.vore_taste
|
||||
|
||||
for(var/I in P.belly_prefs)
|
||||
var/datum/belly/Bp = P.belly_prefs[I]
|
||||
src.vore_organs[Bp.name] = Bp.copy(src)
|
||||
vore_organs.Cut()
|
||||
for(var/entry in P.belly_prefs)
|
||||
list_to_object(entry,src)
|
||||
|
||||
return TRUE
|
||||
|
||||
//
|
||||
// Returns examine messages for bellies
|
||||
//
|
||||
/mob/living/proc/examine_bellies()
|
||||
if(!show_pudge()) //Some clothing or equipment can hide this.
|
||||
return ""
|
||||
|
||||
var/message = ""
|
||||
for (var/belly in vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
message += B.get_examine_msg()
|
||||
|
||||
return message
|
||||
|
||||
//
|
||||
// Whether or not people can see our belly messages
|
||||
//
|
||||
/mob/living/proc/show_pudge()
|
||||
return TRUE //Can override if you want.
|
||||
|
||||
/mob/living/carbon/human/show_pudge()
|
||||
//A uniform could hide it.
|
||||
if(istype(w_uniform,/obj/item/clothing))
|
||||
var/obj/item/clothing/under = w_uniform
|
||||
if(under.hides_bulges)
|
||||
return FALSE
|
||||
|
||||
//We return as soon as we find one, no need for 'else' really.
|
||||
if(istype(wear_suit,/obj/item/clothing))
|
||||
var/obj/item/clothing/suit = wear_suit
|
||||
if(suit.hides_bulges)
|
||||
return FALSE
|
||||
|
||||
|
||||
return ..()
|
||||
|
||||
//
|
||||
// Clearly super important. Obviously.
|
||||
//
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
//
|
||||
// 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))
|
||||
/mob/living/simple_animal/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!"
|
||||
|
||||
@@ -23,6 +23,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
|
||||
// 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
|
||||
//
|
||||
@@ -40,21 +41,23 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
|
||||
//Actual preferences
|
||||
var/digestable = TRUE
|
||||
var/devourable = FALSE
|
||||
// var/allowmobvore = TRUE
|
||||
var/list/belly_prefs = list()
|
||||
var/vore_taste
|
||||
var/vore_taste = "nothing in particular"
|
||||
// var/can_be_drop_prey = FALSE
|
||||
// var/can_be_drop_pred = FALSE
|
||||
|
||||
//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)
|
||||
load_vore()
|
||||
|
||||
//
|
||||
// Check if an object is capable of eating things, based on vore_organs
|
||||
@@ -68,46 +71,60 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
|
||||
|
||||
//
|
||||
// Belly searching for simplifying other procs
|
||||
// Mostly redundant now with belly-objects and isbelly(loc)
|
||||
//
|
||||
/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
|
||||
return isbelly(A.loc)
|
||||
|
||||
//
|
||||
// Save/Load Vore Preferences
|
||||
//
|
||||
/datum/vore_preferences/proc/load_path(ckey,slot,filename="character",ext="json")
|
||||
if(!ckey || !slot) return
|
||||
path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/vore/[filename][slot].[ext]"
|
||||
|
||||
|
||||
/datum/vore_preferences/proc/load_vore()
|
||||
if(!client || !client_ckey) return FALSE //No client, how can we save?
|
||||
if(!client || !client_ckey)
|
||||
return FALSE //No client, how can we save?
|
||||
if(!client.prefs || !client.prefs.default_slot)
|
||||
return FALSE //Need to know what character to load!
|
||||
|
||||
slot = client.prefs.default_slot
|
||||
|
||||
path = client.prefs.path
|
||||
load_path(client_ckey,slot)
|
||||
|
||||
if(!path) return FALSE //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 FALSE //Savefile object couldn't be created?
|
||||
var/list/json_from_file = json_decode(file2text(path))
|
||||
if(!json_from_file)
|
||||
return FALSE //My concern grows
|
||||
|
||||
S.cd = "/character[slot]"
|
||||
var/version = json_from_file["version"]
|
||||
json_from_file = patch_version(json_from_file,version)
|
||||
|
||||
S["digestable"] >> digestable
|
||||
S["devourable"] >> devourable
|
||||
S["belly_prefs"] >> belly_prefs
|
||||
S["vore_taste"] >> vore_taste
|
||||
digestable = json_from_file["digestable"]
|
||||
devourable = json_from_file["devourable"]
|
||||
// allowmobvore = json_from_file["allowmobvore"]
|
||||
vore_taste = json_from_file["vore_taste"]
|
||||
// can_be_drop_prey = json_from_file["can_be_drop_prey"]
|
||||
// can_be_drop_prey = json_from_file["can_be_drop_pred"]
|
||||
belly_prefs = json_from_file["belly_prefs"]
|
||||
|
||||
//Quick sanitize
|
||||
if(isnull(digestable))
|
||||
digestable = TRUE
|
||||
if(isnull(devourable))
|
||||
devourable = FALSE
|
||||
/* if(isnull(allowmobvore))
|
||||
allowmobvore = TRUE
|
||||
if(isnull(can_be_drop_prey))
|
||||
allowmobvore = FALSE
|
||||
if(isnull(can_be_drop_pred))
|
||||
allowmobvore = FALSE */
|
||||
if(isnull(belly_prefs))
|
||||
belly_prefs = list()
|
||||
|
||||
@@ -115,28 +132,37 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
|
||||
|
||||
/datum/vore_preferences/proc/save_vore()
|
||||
if(!path) return FALSE
|
||||
if(!slot) return FALSE
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S) return FALSE
|
||||
S.cd = "/character[slot]"
|
||||
|
||||
WRITE_FILE(S["digestable"], digestable)
|
||||
WRITE_FILE(S["devourable"], devourable)
|
||||
WRITE_FILE(S["belly_prefs"], belly_prefs)
|
||||
WRITE_FILE(S["vore_taste"], vore_taste)
|
||||
var/version = 1 //For "good times" use in the future
|
||||
var/list/settings_list = list(
|
||||
"version" = version,
|
||||
"digestable" = digestable,
|
||||
"devourable" = devourable,
|
||||
"vore_taste" = vore_taste,
|
||||
"belly_prefs" = belly_prefs,
|
||||
)
|
||||
|
||||
/* commented out list things
|
||||
"allowmobvore" = allowmobvore,
|
||||
"can_be_drop_prey" = can_be_drop_prey,
|
||||
"can_be_drop_pred" = can_be_drop_pred, */
|
||||
|
||||
//List to JSON
|
||||
var/json_to_file = json_encode(settings_list)
|
||||
if(!json_to_file)
|
||||
testing("Saving: [path] failed jsonencode")
|
||||
return FALSE
|
||||
|
||||
//Write it out
|
||||
if(fexists(path))
|
||||
fdel(path) //Byond only supports APPENDING to files, not replacing.
|
||||
text2file(json_to_file,path)
|
||||
if(!fexists(path))
|
||||
testing("Saving: [path] failed file write")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
#ifdef TESTING
|
||||
//DEBUG
|
||||
//Some crude tools for testing savefiles
|
||||
//path is the savefile path
|
||||
/client/verb/vore_savefile_export(path as text)
|
||||
var/savefile/S = new /savefile(path)
|
||||
S.ExportText("/",file("[path].txt"))
|
||||
//path is the savefile path
|
||||
/client/verb/vore_savefile_import(path as text)
|
||||
var/savefile/S = new /savefile(path)
|
||||
S.ImportText("/",file("[path].txt"))
|
||||
|
||||
#endif
|
||||
//Can do conversions here
|
||||
/datum/vore_preferences/proc/patch_version(var/list/json_from_file,var/version)
|
||||
return json_from_file
|
||||
@@ -16,7 +16,7 @@
|
||||
/obj/item/projectile/sickshot
|
||||
name = "sickshot pulse"
|
||||
icon_state = "e_netting"
|
||||
damage = 1
|
||||
damage = 0
|
||||
damage_type = STAMINA
|
||||
range = 2
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
var/mob/living/carbon/H = target
|
||||
if(prob(5))
|
||||
for(var/X in H.vore_organs)
|
||||
var/datum/belly/B = H.vore_organs[X]
|
||||
B.release_all_contents()
|
||||
H.release_vore_contents()
|
||||
H.visible_message("<span class='danger'>[H] contracts strangely, spewing out contents on the floor!</span>", \
|
||||
"<span class='userdanger'>You spew out everything inside you on the floor!</span>")
|
||||
return
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
var/datum/vore_look/picker_holder = new()
|
||||
picker_holder.loop = picker_holder
|
||||
picker_holder.selected = vore_organs[vore_selected]
|
||||
picker_holder.selected = vore_selected
|
||||
|
||||
var/dat = picker_holder.gen_vui(src)
|
||||
|
||||
@@ -22,11 +22,23 @@
|
||||
picker_holder.popup.set_content(dat)
|
||||
picker_holder.popup.open()
|
||||
|
||||
/mob/living/proc/updateVRPanel() //Panel popup update call from belly events.
|
||||
if(src.openpanel == 1)
|
||||
var/datum/vore_look/picker_holder = new()
|
||||
picker_holder.loop = picker_holder
|
||||
picker_holder.selected = 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/obj/belly/selected
|
||||
var/show_interacts = TRUE
|
||||
var/datum/browser/popup
|
||||
var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action.
|
||||
@@ -44,29 +56,38 @@
|
||||
/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)
|
||||
var/atom/userloc = user.loc
|
||||
if (isbelly(userloc))
|
||||
var/obj/belly/inside_belly = userloc
|
||||
var/mob/living/eater = inside_belly.owner
|
||||
|
||||
//Don't display this part if we couldn't find the belly since could be held in hand.
|
||||
if(inside_belly)
|
||||
dat += "<font color = 'green'>You are currently inside</font> <font color = 'yellow'>[eater]'s</font> <font color = 'red'>[inside_belly]</font>!<br><br>"
|
||||
dat += "<font color = 'green'>You are currently [user.absorbed ? "absorbed into " : "inside "]</font> <font color = 'yellow'>[eater]'s</font> <font color = 'red'>[inside_belly]</font>!<br><br>"
|
||||
|
||||
if(inside_belly.inside_flavor)
|
||||
dat += "[inside_belly.inside_flavor]<br><br>"
|
||||
if(inside_belly.desc)
|
||||
dat += "[inside_belly.desc]<br><br>"
|
||||
|
||||
if (inside_belly.internal_contents.len > 1)
|
||||
if (inside_belly.contents.len > 1)
|
||||
dat += "You can see the following around you:<br>"
|
||||
for (var/atom/movable/O in inside_belly.internal_contents)
|
||||
for (var/atom/movable/O in inside_belly)
|
||||
if(istype(O,/mob/living))
|
||||
var/mob/living/M = O
|
||||
//That's just you
|
||||
if(M == user)
|
||||
continue
|
||||
|
||||
//That's an absorbed person you're checking
|
||||
if(M.absorbed)
|
||||
if(user.absorbed)
|
||||
dat += "<a href='?src=\ref[src];outsidepick=\ref[O];outsidebelly=\ref[inside_belly]'><span style='color:purple;'>[O]</span></a>"
|
||||
continue
|
||||
else
|
||||
continue
|
||||
|
||||
//Anything else
|
||||
dat += "<a href='?src=\ref[src];outsidepick=\ref[O];outsidebelly=\ref[inside_belly]'>[O]</a>"
|
||||
dat += "<a href='?src=\ref[src];outsidepick=\ref[O];outsidebelly=\ref[inside_belly]'>[O]​</a>"
|
||||
|
||||
//Zero-width space, for wrapping
|
||||
dat += "​"
|
||||
else
|
||||
@@ -75,8 +96,8 @@
|
||||
dat += "<HR>"
|
||||
|
||||
dat += "<ol style='list-style: none; padding: 0; overflow: auto;'>"
|
||||
for(var/K in user.vore_organs) //Fuggin can't iterate over values
|
||||
var/datum/belly/B = user.vore_organs[K]
|
||||
for(var/belly in user.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
if(B == selected)
|
||||
dat += "<li style='float: left'><a href='?src=\ref[src];bellypick=\ref[B]'><b>[B.name]</b>"
|
||||
else
|
||||
@@ -90,8 +111,10 @@
|
||||
spanstyle = "color:red;"
|
||||
if(DM_HEAL)
|
||||
spanstyle = "color:green;"
|
||||
if(DM_NOISY)
|
||||
spanstyle = "color:purple;"
|
||||
|
||||
dat += "<span style='[spanstyle]'> ([B.internal_contents.len])</span></a></li>"
|
||||
dat += "<span style='[spanstyle]'> ([B.contents.len])</span></a></li>"
|
||||
|
||||
if(user.vore_organs.len < BELLIES_MAX)
|
||||
dat += "<li style='float: left'><a href='?src=\ref[src];newbelly=1'>New+</a></li>"
|
||||
@@ -102,15 +125,27 @@
|
||||
if(!selected)
|
||||
dat += "No belly selected. Click one to select it."
|
||||
else
|
||||
if(selected.internal_contents.len > 0)
|
||||
if(selected.contents.len)
|
||||
dat += "<b>Contents:</b> "
|
||||
for(var/O in selected.internal_contents)
|
||||
for(var/O in selected)
|
||||
|
||||
//Mobs can be absorbed, so treat them separately from everything else
|
||||
if(istype(O,/mob/living))
|
||||
var/mob/living/M = O
|
||||
|
||||
//Absorbed gets special color OOoOOOOoooo
|
||||
if(M.absorbed)
|
||||
dat += "<a href='?src=\ref[src];insidepick=\ref[O]'><span style='color:purple;'>[O]</span></a>"
|
||||
continue
|
||||
|
||||
//Anything else
|
||||
dat += "<a href='?src=\ref[src];insidepick=\ref[O]'>[O]</a>"
|
||||
|
||||
//Zero-width space, for wrapping
|
||||
dat += "​"
|
||||
|
||||
//If there's more than one thing, add an [All] button
|
||||
if(selected.internal_contents.len > 1)
|
||||
if(selected.contents.len > 1)
|
||||
dat += "<a href='?src=\ref[src];insidepick=1;pickall=1'>\[All\]</a>"
|
||||
|
||||
dat += "<HR>"
|
||||
@@ -129,14 +164,15 @@
|
||||
|
||||
//Inside flavortext
|
||||
dat += "<br><a href='?src=\ref[src];b_desc=\ref[selected]'>Flavor Text:</a>"
|
||||
dat += " '[selected.inside_flavor]'"
|
||||
dat += " '[selected.desc]'"
|
||||
|
||||
//Belly sound
|
||||
dat += "<br><a href='?src=\ref[src];b_sound=\ref[selected]'>Set Vore Sound</a>"
|
||||
dat += "<a href='?src=\ref[src];b_soundtest=\ref[selected]'>Test</a>"
|
||||
|
||||
// //Belly silence
|
||||
// dat += "<br><a href='?src=\ref[src];silenced=\ref[selected]'>Belly Silence ([selected.silenced ? "Silenced" : "Noisy"])</a>"
|
||||
//Release sound
|
||||
dat += "<br><a href='?src=\ref[src];b_release=\ref[selected]'>Set Release Sound</a>"
|
||||
dat += "<a href='?src=\ref[src];b_releasesoundtest=\ref[selected]'>Test</a>"
|
||||
|
||||
//Belly messages
|
||||
dat += "<br><a href='?src=\ref[src];b_msgs=\ref[selected]'>Belly Messages</a>"
|
||||
@@ -145,6 +181,10 @@
|
||||
dat += "<br><a href='?src=\ref[src];b_tastes=\ref[selected]'>Can Taste:</a>"
|
||||
dat += " [selected.can_taste ? "Yes" : "No"]"
|
||||
|
||||
//Minimum size prey must be to show up.
|
||||
dat += "<br><a href='?src=\ref[src];b_bulge_size=\ref[selected]'>Required examine size:</a>"
|
||||
dat += " [selected.bulge_size*100]%"
|
||||
|
||||
//Belly escapability
|
||||
dat += "<br><a href='?src=\ref[src];b_escapable=\ref[selected]'>Belly Interactions ([selected.escapable ? "On" : "Off"])</a>"
|
||||
if(selected.escapable)
|
||||
@@ -173,15 +213,21 @@
|
||||
dat += " [selected.digestchance]%"
|
||||
dat += "<HR>"
|
||||
|
||||
// Belly Silence
|
||||
dat += "<br><a href='?src=\ref[src];b_silent=\ref[selected]'>Belly Silence (for not belly bellies):</a>"
|
||||
dat += " [selected.silent ? "Yes" : "No"]"
|
||||
|
||||
//Delete button
|
||||
dat += "<br><a style='background:#990000;' href='?src=\ref[src];b_del=\ref[selected]'>Delete Belly</a>"
|
||||
|
||||
dat += "<a href='?src=\ref[src];setflavor=1'>Set Flavor</a>"
|
||||
dat += "<a href='?src=\ref[src];togglenoisy=1'>Toggle Hunger Noises</a>"
|
||||
|
||||
dat += "<HR>"
|
||||
|
||||
//Under the last HR, save and stuff.
|
||||
dat += "<a href='?src=\ref[src];saveprefs=1'>Save Prefs</a>"
|
||||
dat += "<a href='?src=\ref[src];refresh=1'>Refresh</a>"
|
||||
dat += "<a href='?src=\ref[src];setflavor=1'>Set Flavor</a>"
|
||||
|
||||
dat += "<HR>"
|
||||
switch(user.digestable)
|
||||
@@ -221,8 +267,8 @@
|
||||
|
||||
if(href_list["outsidepick"])
|
||||
var/atom/movable/tgt = locate(href_list["outsidepick"])
|
||||
var/datum/belly/OB = locate(href_list["outsidebelly"])
|
||||
if(!(tgt in OB.internal_contents)) //Aren't here anymore, need to update menu.
|
||||
var/obj/belly/OB = locate(href_list["outsidebelly"])
|
||||
if(!(tgt in OB)) //Aren't here anymore, need to update menu.
|
||||
return TRUE
|
||||
var/intent = "Examine"
|
||||
|
||||
@@ -234,42 +280,49 @@
|
||||
M.examine(user)
|
||||
|
||||
if("Help Out") //Help the inside-mob out
|
||||
to_chat(user, "<font color='green'>You begin to push [M] to freedom!</font>")
|
||||
to_chat(M, "[usr] begins to push you to freedom!")
|
||||
M.loc << "<span class='warning'>Someone is trying to escape from inside you!</span>"
|
||||
if(user.stat || user.absorbed || M.absorbed)
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return 1
|
||||
|
||||
to_chat(user,"<font color='green'>You begin to push [M] to freedom!</font>")
|
||||
to_chat(M,"[usr] begins to push you to freedom!")
|
||||
to_chat(M.loc,"<span class='warning'>Someone is trying to escape from inside you!</span>")
|
||||
sleep(50)
|
||||
if(prob(33))
|
||||
OB.release_specific_contents(M)
|
||||
to_chat(usr, "<font color='green'>You manage to help [M] to safety!</font>")
|
||||
to_chat(M, "<font color='green'>[user] pushes you free!</font>")
|
||||
M.loc << "<span class='alert'>[M] forces free of the confines of your body!</span>"
|
||||
to_chat(usr,"<font color='green'>You manage to help [M] to safety!</font>")
|
||||
to_chat(M,"<font color='green'>[user] pushes you free!</font>")
|
||||
to_chat(OB.owner,"<span class='alert'>[M] forces free of the confines of your body!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='alert'>[M] slips back down inside despite your efforts.</span>")
|
||||
to_chat(M, "<span class='alert'> Even with [user]'s help, you slip back inside again.</span>")
|
||||
M.loc << "<font color='green'>Your body efficiently shoves [M] back where they belong.</font>"
|
||||
to_chat(user,"<span class='alert'>[M] slips back down inside despite your efforts.</span>")
|
||||
to_chat(M,"<span class='alert'> Even with [user]'s help, you slip back inside again.</span>")
|
||||
to_chat(OB.owner,"<font color='green'>Your body efficiently shoves [M] back where they belong.</font>")
|
||||
|
||||
|
||||
if("Devour") //Eat the inside mob
|
||||
if(user.absorbed || user.stat)
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return 1
|
||||
|
||||
if(!user.vore_selected)
|
||||
to_chat(user, "<span class='warning'>Pick a belly on yourself first!</span>")
|
||||
return
|
||||
to_chat(user,"<span class='warning'>Pick a belly on yourself first!</span>")
|
||||
return 1
|
||||
|
||||
var/datum/belly/TB = user.vore_organs[user.vore_selected]
|
||||
to_chat(user, "<span class='warning'>You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!</span>")
|
||||
to_chat(M, "<span class='warning'>[user] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!</span>")
|
||||
M.loc << "<span class='warning'>Someone inside you is eating someone else!</span>"
|
||||
var/obj/belly/TB = user.vore_selected
|
||||
to_chat(user,"<span class='warning'>You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!</span>")
|
||||
to_chat(M,"<span class='warning'>[user] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!</span>")
|
||||
to_chat(OB.owner,"<span class='warning'>Someone inside you is eating someone else!</span>")
|
||||
|
||||
sleep(TB.nonhuman_prey_swallow_time)
|
||||
if((user in OB.internal_contents) && (M in OB.internal_contents))
|
||||
to_chat(user, "<span class='warning'>You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!</span>")
|
||||
to_chat(M, "<span class='warning'>[user] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!</span>")
|
||||
M.loc << "<span class='warning'>Someone inside you has eaten someone else!</span>"
|
||||
M.loc = user
|
||||
sleep(TB.nonhuman_prey_swallow_time) //Can't do after, in a stomach, weird things abound.
|
||||
if((user in OB) && (M in OB)) //Make sure they're still here.
|
||||
to_chat(user,"<span class='warning'>You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!</span>")
|
||||
to_chat(M,"<span class='warning'>[user] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!</span>")
|
||||
to_chat(OB.owner,"<span class='warning'>Someone inside you has eaten someone else!</span>")
|
||||
TB.nom_mob(M)
|
||||
OB.internal_contents -= M
|
||||
|
||||
else if(istype(tgt,/obj/item))
|
||||
var/obj/item/T = tgt
|
||||
if(!(tgt in OB.internal_contents))
|
||||
if(!(tgt in OB.contents))
|
||||
//Doesn't exist anymore, update.
|
||||
return TRUE
|
||||
intent = alert("What do you want to do to that?","Query","Examine","Use Hand")
|
||||
@@ -301,27 +354,29 @@
|
||||
return
|
||||
|
||||
selected.release_all_contents()
|
||||
playsound(get_turf(user),'sound/vore/pred/escape.ogg',50,0,-5,0,ignore_walls = FALSE)
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(user)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(user),'sound/vore/pred/escape.ogg',50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
to_chat(user.loc,"<span class='danger'>Everything is released from [user]!</span>")
|
||||
|
||||
if("Move all")
|
||||
if(user.stat)
|
||||
to_chat(user, "<span class='warning'>You can't do that in your state!</span>")
|
||||
return
|
||||
return FALSE
|
||||
|
||||
var/choice = input("Move all where?","Select Belly") in user.vore_organs + "Cancel - Don't Move"
|
||||
var/obj/belly/choice = input("Move all where?","Select Belly") as null|anything in user.vore_organs
|
||||
if(!choice)
|
||||
return FALSE
|
||||
|
||||
if(choice == "Cancel - Don't Move")
|
||||
return
|
||||
else
|
||||
var/datum/belly/B = user.vore_organs[choice]
|
||||
for(var/atom/movable/tgt in selected.internal_contents)
|
||||
to_chat(tgt, "<span class='warning'>You're squished from [user]'s [selected] to their [B]!</span>")
|
||||
selected.transfer_contents(tgt, B, 1)
|
||||
playsound(get_turf(user),'sound/vore/pred/stomachmove.ogg',50,0,-5,0,ignore_walls = FALSE)
|
||||
for(var/atom/movable/tgt in selected)
|
||||
selected.transfer_contents(tgt, choice, 1)
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(user)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(user),'sound/vore/pred/stomachmove.ogg',50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
to_chat(tgt,"<span class='warning'>You're squished from [user]'s [lowertext(selected)] to their [lowertext(choice.name)]!</span>")
|
||||
|
||||
var/atom/movable/tgt = locate(href_list["insidepick"])
|
||||
if(!(tgt in selected.internal_contents)) //Old menu, needs updating because they aren't really there.
|
||||
if(!(tgt in selected)) //Old menu, needs updating because they aren't really there.
|
||||
return TRUE//Forces update
|
||||
intent = "Examine"
|
||||
intent = alert("Examine, Eject, Move? Examine if you want to leave this box.","Query","Examine","Eject","Move")
|
||||
@@ -335,48 +390,54 @@
|
||||
return FALSE
|
||||
|
||||
selected.release_specific_contents(tgt)
|
||||
playsound(get_turf(user),'sound/effects/splat.ogg',50,0,-5,0,ignore_walls = FALSE)
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(user)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(user),'sound/vore/pred/escape.ogg',50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
user.loc << "<span class='danger'>[tgt] is released from [user]!</span>"
|
||||
|
||||
if("Move")
|
||||
if(user.stat)
|
||||
to_chat(user, "<span class='warning'>You can't do that in your state!</span>")
|
||||
return FALSE
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return 0
|
||||
|
||||
var/choice = input("Move [tgt] where?","Select Belly") in user.vore_organs + "Cancel - Don't Move"
|
||||
var/obj/belly/choice = input("Move [tgt] where?","Select Belly") as null|anything in user.vore_organs
|
||||
if(!choice || !(tgt in selected))
|
||||
return 0
|
||||
|
||||
if(choice == "Cancel - Don't Move")
|
||||
return
|
||||
else
|
||||
var/datum/belly/B = user.vore_organs[choice]
|
||||
if (!(tgt in selected.internal_contents))
|
||||
return FALSE
|
||||
to_chat(tgt, "<span class='warning'>You're moved from [user]'s [lowertext(selected.name)] to their [lowertext(B.name)]!</span>")
|
||||
playsound(get_turf(user),'sound/vore/pred/stomachmove.ogg',50,0,-5,0,ignore_walls = FALSE)
|
||||
selected.transfer_contents(tgt, B)
|
||||
to_chat(tgt,"<span class='warning'>You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(choice.name)]!</span>")
|
||||
selected.transfer_contents(tgt, choice)
|
||||
for(var/mob/M in get_hearers_in_view(5, get_turf(user)))
|
||||
if(M.client && M.client.prefs.toggles & EATING_NOISES)
|
||||
playsound(get_turf(user),'sound/vore/pred/stomachmove.ogg',50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
|
||||
|
||||
if(href_list["newbelly"])
|
||||
if(user.vore_organs.len >= BELLIES_MAX)
|
||||
return TRUE
|
||||
return 0
|
||||
|
||||
var/new_name = html_encode(input(usr,"New belly's name:","New Belly") as text|null)
|
||||
|
||||
var/failure_msg
|
||||
if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN)
|
||||
to_chat(usr, "<span class='warning'>Entered belly name is too long.</span>")
|
||||
return FALSE
|
||||
if(new_name in user.vore_organs)
|
||||
to_chat(usr, "<span class='warning'>No duplicate belly names, please.</span>")
|
||||
return FALSE
|
||||
failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])."
|
||||
// else if(whatever) //Next test here.
|
||||
else
|
||||
for(var/belly in user.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
if(lowertext(new_name) == lowertext(B.name))
|
||||
failure_msg = "No duplicate belly names, please."
|
||||
break
|
||||
|
||||
var/datum/belly/NB = new(user)
|
||||
if(failure_msg) //Something went wrong.
|
||||
alert(user,failure_msg,"Error!")
|
||||
return 0
|
||||
|
||||
var/obj/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
|
||||
user.vore_selected = selected
|
||||
|
||||
////
|
||||
//Please keep these the same order they are on the panel UI for ease of coding
|
||||
@@ -384,41 +445,40 @@
|
||||
if(href_list["b_name"])
|
||||
var/new_name = html_encode(input(usr,"Belly's new name:","New Name") as text|null)
|
||||
|
||||
var/failure_msg
|
||||
if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN)
|
||||
to_chat(usr, "<span class='warning'>Entered belly name length invalid (must be longer than 2, shorter than 12).</span>")
|
||||
return FALSE
|
||||
if(new_name in user.vore_organs)
|
||||
to_chat(usr, "<span class='warning'>No duplicate belly names, please.</span>")
|
||||
return FALSE
|
||||
failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])."
|
||||
// else if(whatever) //Next test here.
|
||||
else
|
||||
for(var/belly in user.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
if(lowertext(new_name) == lowertext(B.name))
|
||||
failure_msg = "No duplicate belly names, please."
|
||||
break
|
||||
|
||||
if(failure_msg) //Something went wrong.
|
||||
alert(user,failure_msg,"Error!")
|
||||
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
|
||||
var/new_mode = input("Choose Mode (currently [selected.digest_mode])") as null|anything in menu_list
|
||||
if(!new_mode)
|
||||
return 0
|
||||
selected.digest_mode = new_mode
|
||||
|
||||
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)
|
||||
var/new_desc = html_encode(input(usr,"Belly Description ([BELLIES_DESC_MAX] char limit):","New Description",selected.desc) as message|null)
|
||||
|
||||
if(new_desc)
|
||||
new_desc = readd_quotes(new_desc)
|
||||
if(length(new_desc) > BELLIES_DESC_MAX)
|
||||
to_chat(usr, "<span class='warning'>Entered belly desc too long. [BELLIES_DESC_MAX] character limit.</span>")
|
||||
alert("Entered belly desc too long. [BELLIES_DESC_MAX] character limit.","Error")
|
||||
return FALSE
|
||||
|
||||
selected.inside_flavor = new_desc
|
||||
selected.desc = new_desc
|
||||
else //Returned null
|
||||
return FALSE
|
||||
|
||||
@@ -429,12 +489,11 @@
|
||||
"Struggle Message (outside)",
|
||||
"Struggle Message (inside)",
|
||||
"Examine Message (when full)",
|
||||
"Reset All To Default",
|
||||
"Cancel - No Changes"
|
||||
"Reset All To Default"
|
||||
)
|
||||
|
||||
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/choice = input(user,"Select a type to modify. Messages from each topic are pulled at random when needed.","Pick Type") as null|anything 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)
|
||||
@@ -459,7 +518,7 @@
|
||||
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'). "+help,"Examine Message (when full)",selected.get_messages("em")) as message
|
||||
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')."+help,"Examine Message (when full)",selected.get_messages("em")) as message
|
||||
if(new_message)
|
||||
selected.set_messages(new_message,"em")
|
||||
|
||||
@@ -471,40 +530,57 @@
|
||||
selected.struggle_messages_outside = initial(selected.struggle_messages_outside)
|
||||
selected.struggle_messages_inside = initial(selected.struggle_messages_inside)
|
||||
|
||||
if("Cancel - No Changes")
|
||||
return
|
||||
|
||||
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) > BELLIES_NAME_MAX || length(new_verb) < BELLIES_NAME_MIN)
|
||||
to_chat(usr, "<span class='warning'>Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).</span>")
|
||||
return FALSE
|
||||
alert("Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).","Error")
|
||||
return 0
|
||||
|
||||
selected.vore_verb = new_verb
|
||||
|
||||
if(href_list["b_sound"])
|
||||
var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") in GLOB.pred_vore_sounds + "Cancel - No Changes"
|
||||
if(href_list["b_release"])
|
||||
var/choice = input(user,"Currently set to [selected.release_sound]","Select Sound") as null|anything in GLOB.release_sound
|
||||
|
||||
if(choice == "Cancel")
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
selected.release_sound = GLOB.release_sound[choice]
|
||||
|
||||
if(href_list["b_releasesoundtest"])
|
||||
var/soundfile = GLOB.release_sound[selected.release_sound]
|
||||
if(soundfile)
|
||||
user << soundfile
|
||||
|
||||
if(href_list["b_sound"])
|
||||
var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in GLOB.pred_vore_sounds
|
||||
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
selected.vore_sound = GLOB.pred_vore_sounds[choice]
|
||||
|
||||
if(href_list["b_soundtest"])
|
||||
user << selected.vore_sound
|
||||
/*
|
||||
if(href_list["silenced"])
|
||||
if(selected.silenced == FALSE)
|
||||
selected.silenced = TRUE
|
||||
to_chat(usr,"<span class='warning'>The [selected.name] is now silenced, it will not play the internal loop to prey within it.</span>")
|
||||
else if(selected.silenced == TRUE)
|
||||
selected.silenced = FALSE
|
||||
to_chat(usr,"<span class='warning'>The [selected.name] will play the internal loop to prey within it.</span>")
|
||||
*/
|
||||
var/soundfile = GLOB.pred_vore_sounds[selected.vore_sound]
|
||||
if(soundfile)
|
||||
user << soundfile
|
||||
|
||||
if(href_list["b_tastes"])
|
||||
selected.can_taste = !selected.can_taste
|
||||
|
||||
if(href_list["b_bulge_size"])
|
||||
var/new_bulge = input(user, "Choose the required size prey must be to show up on examine, ranging from 25% to 200% Set this to 0 for no text on examine.", "Set Belly Examine Size.") as num|null
|
||||
if(new_bulge == null)
|
||||
return
|
||||
if(new_bulge == 0) //Disable.
|
||||
selected.bulge_size = 0
|
||||
to_chat(user,"<span class='notice'>Your stomach will not be seen on examine.</span>")
|
||||
else if (!IsInRange(new_bulge,25,200))
|
||||
selected.bulge_size = 0.25 //Set it to the default.
|
||||
to_chat(user,"<span class='notice'>Invalid size.</span>")
|
||||
else if(new_bulge)
|
||||
selected.bulge_size = (new_bulge/100)
|
||||
|
||||
if(href_list["b_escapable"])
|
||||
if(selected.escapable == FALSE) //Possibly escapable and special interactions.
|
||||
selected.escapable = TRUE
|
||||
@@ -515,7 +591,7 @@
|
||||
show_interacts = FALSE //Force the hiding of the panel
|
||||
else
|
||||
to_chat(usr,"<span class='warning'>Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.") //If they somehow have a varable that's not 0 or 1
|
||||
selected.escapable = FALSE
|
||||
selected.escapable = TRUE
|
||||
show_interacts = FALSE //Force the hiding of the panel
|
||||
|
||||
if(href_list["b_escapechance"])
|
||||
@@ -537,68 +613,73 @@
|
||||
var/choice = input("Where do you want your [selected.name] to lead if prey resists?","Select Belly") as null|anything in (user.vore_organs + "None - Remove" - selected.name)
|
||||
|
||||
if(!choice) //They cancelled, no changes
|
||||
return
|
||||
return FALSE
|
||||
else if(choice == "None - Remove")
|
||||
selected.transferlocation = null
|
||||
else
|
||||
selected.transferlocation = user.vore_organs[choice]
|
||||
|
||||
if(href_list["b_absorbchance"])
|
||||
var/absorb_chance_input = input(user, "Set belly absorb mode chance on resist (as %)", "Prey Absorb Chance") as num|null
|
||||
if(!isnull(absorb_chance_input))
|
||||
selected.absorbchance = sanitize_integer(absorb_chance_input, 0, 100, initial(selected.absorbchance))
|
||||
|
||||
if(href_list["b_digestchance"])
|
||||
var/digest_chance_input = input(user, "Set belly digest mode chance on resist (as %)", "Prey Digest Chance") as num|null
|
||||
if(!isnull(digest_chance_input))
|
||||
selected.digestchance = sanitize_integer(digest_chance_input, 0, 100, initial(selected.digestchance))
|
||||
|
||||
if(href_list["b_silent"])
|
||||
selected.silent = !selected.silent
|
||||
|
||||
if(href_list["b_del"])
|
||||
var/dest_for = FALSE //Check to see if it's the destination of another vore organ.
|
||||
for(var/I in user.vore_organs)
|
||||
var/datum/belly/B = user.vore_organs[I]
|
||||
var/alert = alert("Are you sure you want to delete your [lowertext(selected.name)]?","Confirmation","Delete","Cancel")
|
||||
if(!alert == "Delete")
|
||||
return FALSE
|
||||
|
||||
var/failure_msg = ""
|
||||
|
||||
var/dest_for //Check to see if it's the destination of another vore organ.
|
||||
for(var/belly in user.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
if(B.transferlocation == selected)
|
||||
dest_for = B.name
|
||||
failure_msg += "This is the destiantion for at least '[dest_for]' belly transfers. Remove it as the destination from any bellies before deleting it. "
|
||||
break
|
||||
|
||||
if(dest_for)
|
||||
alert("This is the destiantion for at least '[dest_for]' belly transfers. Remove it as the destination from any bellies before deleting it.","Error")
|
||||
return TRUE
|
||||
else if(selected.internal_contents.len)
|
||||
alert("Can't delete bellies with contents!","Error")
|
||||
return TRUE
|
||||
if(selected.internal_contents.len)
|
||||
to_chat(usr, "<span class='warning'>Can't delete bellies with contents!</span>")
|
||||
return
|
||||
else if(selected.immutable)
|
||||
to_chat(usr, "<span class='warning'>This belly is marked as undeletable.</span>")
|
||||
return
|
||||
else if(user.vore_organs.len == 1)
|
||||
to_chat(usr, "<span class='warning'>You must have at least one belly.</span>")
|
||||
return
|
||||
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]
|
||||
to_chat(usr,"<span class='warning'>Note: If you had this organ selected as a transfer location, please remove the transfer location by selecting Cancel - None - Remove on this stomach.</span>")
|
||||
if(selected.contents.len)
|
||||
failure_msg += "You cannot delete bellies with contents! " //These end with spaces, to be nice looking. Make sure you do the same.
|
||||
if(selected.immutable)
|
||||
failure_msg += "This belly is marked as undeletable. "
|
||||
if(user.vore_organs.len == 1)
|
||||
failure_msg += "You must have at least one belly. "
|
||||
|
||||
if(failure_msg)
|
||||
alert(user,failure_msg,"Error!")
|
||||
return FALSE
|
||||
|
||||
qdel(selected)
|
||||
selected = user.vore_organs[1]
|
||||
user.vore_selected = user.vore_organs[1]
|
||||
|
||||
if(href_list["saveprefs"])
|
||||
if(user.save_vore_prefs())
|
||||
to_chat(user, "<span class='notice'>Belly Preferences saved!</span>")
|
||||
if(!user.save_vore_prefs())
|
||||
to_chat(user, "<span class='warning'>Belly Preferences not saved!</span>")
|
||||
|
||||
else
|
||||
to_chat(user, "<span class='warning'>ERROR: Belly Preferences were not saved!</span>")
|
||||
to_chat(user, "<span class='notice'>Belly Preferences were saved!</span>")
|
||||
log_admin("Could not save vore prefs on USER: [user].")
|
||||
|
||||
if(href_list["setflavor"])
|
||||
var/new_flavor = html_encode(input(usr,"What your character tastes like (40ch limit). This text will be printed to the pred after 'X tastes of...' so just put something like 'strawberries and cream':","Character Flavor",user.vore_taste) as text|null)
|
||||
if(!new_flavor)
|
||||
return 0
|
||||
|
||||
if(new_flavor)
|
||||
new_flavor = readd_quotes(new_flavor)
|
||||
if(length(new_flavor) > FLAVOR_MAX)
|
||||
alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error")
|
||||
return FALSE
|
||||
user.vore_taste = new_flavor
|
||||
else //Returned null
|
||||
return FALSE
|
||||
new_flavor = readd_quotes(new_flavor)
|
||||
if(length(new_flavor) > FLAVOR_MAX)
|
||||
alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error!")
|
||||
return 0
|
||||
user.vore_taste = new_flavor
|
||||
|
||||
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")
|
||||
@@ -626,5 +707,15 @@
|
||||
if(user.client.prefs_vr)
|
||||
user.client.prefs_vr.devourable = user.devourable
|
||||
|
||||
if(href_list["togglenoisy"])
|
||||
var/choice = alert(user, "Toggle audible hunger noises. Currently: [user.noisy ? "Enabled" : "Disabled"]", "", "Enable audible hunger", "Cancel", "Disable audible hunger")
|
||||
switch(choice)
|
||||
if("Cancel")
|
||||
return 0
|
||||
if("Enable audible hunger")
|
||||
user.noisy = TRUE
|
||||
if("Disable audible hunger")
|
||||
user.noisy = FALSE
|
||||
|
||||
//Refresh when interacted with, returning 1 makes vore_look.Topic update
|
||||
return TRUE
|
||||
return 1
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Returns a byond list that can be passed to the "deserialize" proc
|
||||
* to bring a new instance of this atom to its original state
|
||||
*
|
||||
* If we want to store this info, we can pass it to `json_encode` or some other
|
||||
* interface that suits our fancy, to make it into an easily-handled string
|
||||
*/
|
||||
/datum/proc/serialize()
|
||||
var/data = list("type" = "[type]")
|
||||
return data
|
||||
|
||||
/*
|
||||
* This is given the byond list from above, to bring this atom to the state
|
||||
* described in the list.
|
||||
* This will be called after `New` but before `initialize`, so linking and stuff
|
||||
* would probably be handled in `initialize`
|
||||
*
|
||||
* Also, this should only be called by `list_to_object` in persistence.dm - at least
|
||||
* with current plans - that way it can actually initialize the type from the list
|
||||
*/
|
||||
/datum/proc/deserialize(var/list/data)
|
||||
return
|
||||
|
||||
/atom
|
||||
// This var isn't actually used for anything, but is present so that
|
||||
// DM's map reader doesn't forfeit on reading a JSON-serialized map
|
||||
var/map_json_data
|
||||
|
||||
// This is so specific atoms can override these, and ignore certain ones
|
||||
/atom/proc/vars_to_save()
|
||||
return list("color","dir","icon","icon_state","name","pixel_x","pixel_y")
|
||||
|
||||
/atom/proc/map_important_vars()
|
||||
// A list of important things to save in the map editor
|
||||
return list("color","dir","icon","icon_state","layer","name","pixel_x","pixel_y")
|
||||
|
||||
/area/map_important_vars()
|
||||
// Keep the area default icons, to keep things nice and legible
|
||||
return list("name")
|
||||
|
||||
// No need to save any state of an area by default
|
||||
/area/vars_to_save()
|
||||
return list("name")
|
||||
|
||||
/atom/serialize()
|
||||
var/list/data = ..()
|
||||
for(var/thing in vars_to_save())
|
||||
if(vars[thing] != initial(vars[thing]))
|
||||
data[thing] = vars[thing]
|
||||
return data
|
||||
|
||||
|
||||
/atom/deserialize(var/list/data)
|
||||
for(var/thing in vars_to_save())
|
||||
if(thing in data)
|
||||
vars[thing] = data[thing]
|
||||
..()
|
||||
|
||||
|
||||
/*
|
||||
Whoops, forgot to put documentation here.
|
||||
What this does, is take a JSON string produced by running
|
||||
BYOND's native `json_encode` on a list from `serialize` above, and
|
||||
turns that string into a new instance of that object.
|
||||
|
||||
You can also easily get an instance of this string by calling "Serialize Marked Datum"
|
||||
in the "Debug" tab.
|
||||
|
||||
If you're clever, you can do neat things with SDQL and this, though be careful -
|
||||
some objects, like humans, are dependent that certain extra things are defined
|
||||
in their list
|
||||
*/
|
||||
/proc/object_to_json(var/atom/movable/thing)
|
||||
return json_encode(thing.serialize())
|
||||
|
||||
/proc/json_to_object(var/json_data, var/loc)
|
||||
return list_to_object(json_decode(json_data), loc)
|
||||
|
||||
/proc/list_to_object(var/list/data, var/loc)
|
||||
if(!islist(data))
|
||||
throw EXCEPTION("You didn't give me a list, bucko")
|
||||
if(!("type" in data))
|
||||
throw EXCEPTION("No 'type' field in the data")
|
||||
var/path = text2path(data["type"])
|
||||
if(!path)
|
||||
throw EXCEPTION("Path not found: [path]")
|
||||
|
||||
var/atom/movable/thing = new path(loc)
|
||||
thing.deserialize(data)
|
||||
return thing
|
||||
Reference in New Issue
Block a user