Move files and tweaks vore panel stuff
This commit is contained in:
@@ -35,8 +35,8 @@
|
||||
/mob/living/simple_animal/proc/update_fullness(var/atom/movable/M)
|
||||
var/new_fullness = 0
|
||||
for(var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
if (!(M in B.internal_contents))
|
||||
var/obj/belly/B = vore_organs[I]
|
||||
if (!(M in B.contents))
|
||||
return FALSE // Nothing's inside
|
||||
new_fullness += M
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
var/obj/belly/B = new /obj/belly(src)
|
||||
vore_selected = B
|
||||
B.immutable = 1
|
||||
B.immutable = TRUE
|
||||
B.name = vore_stomach_name ? vore_stomach_name : "stomach"
|
||||
B.desc = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
|
||||
B.digest_mode = vore_default_mode
|
||||
|
||||
@@ -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,678 @@
|
||||
//#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 = "Gulp" // Sound when ingesting someone
|
||||
var/vore_verb = "ingest" // Verb for eating with this in messages
|
||||
var/release_sound = "Splatter" // Sound for letting someone out.
|
||||
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 = 0 // % 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/transferlocation // 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
|
||||
var/is_wet = TRUE // Is this belly inside slimy parts?
|
||||
var/wet_loop = TRUE // Does this belly have a slimy internal loop?
|
||||
|
||||
//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,DM_ABSORB,DM_UNABSORB) // 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 // Prevent audio spam
|
||||
var/tmp/last_hearcheck = 0
|
||||
var/tmp/list/hearing_mobs
|
||||
|
||||
// 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 AND IN ORDER OF VARS LISTED ABOVE AND IN DUPE AT THE BOTTOM!!, 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",
|
||||
"escapable",
|
||||
"escapetime",
|
||||
"digestchance",
|
||||
"absorbchance",
|
||||
"escapechance",
|
||||
"can_taste",
|
||||
"bulge_size",
|
||||
"transferlocation",
|
||||
"transferchance",
|
||||
"autotransferchance",
|
||||
"autotransferwait",
|
||||
"swallow_time",
|
||||
"vore_capacity",
|
||||
"struggle_messages_outside",
|
||||
"struggle_messages_inside",
|
||||
"digest_messages_owner",
|
||||
"digest_messages_prey",
|
||||
"examine_messages",
|
||||
"emote_lists",
|
||||
"is_wet",
|
||||
"wet_loop"
|
||||
)
|
||||
|
||||
//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(vore_sound && (world.time > recent_sound))
|
||||
var/turf/source = get_turf(owner)
|
||||
var/sound/eating = GLOB.vore_sounds[vore_sound]
|
||||
for(var/mob/living/M in get_hearers_in_view(3, source))
|
||||
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
|
||||
SEND_SOUND(M, eating)
|
||||
recent_sound = (world.time + 20 SECONDS)
|
||||
|
||||
//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>")
|
||||
|
||||
// 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/silent = FALSE)
|
||||
// var/atom/destination = drop_location()
|
||||
//Don't bother if we don't have contents
|
||||
if(!contents.len)
|
||||
return FALSE
|
||||
|
||||
var/count = 0
|
||||
for(var/thing in contents)
|
||||
var/atom/movable/AM = thing
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
var/mob/living/OW = owner
|
||||
if(L.absorbed && !include_absorbed)
|
||||
continue
|
||||
L.absorbed = FALSE
|
||||
L.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
L.cure_blind("belly_[REF(src)]")
|
||||
SEND_SIGNAL(OW, COMSIG_CLEAR_MOOD_EVENT, "fedpred", /datum/mood_event/fedpred)
|
||||
SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey)
|
||||
SEND_SIGNAL(OW, COMSIG_ADD_MOOD_EVENT, "emptypred", /datum/mood_event/emptypred)
|
||||
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey)
|
||||
count += release_specific_contents(AM, silent = TRUE)
|
||||
|
||||
//Clean up our own business
|
||||
items_preserved.Cut()
|
||||
owner.update_icons()
|
||||
|
||||
if(!silent)
|
||||
for(var/mob/living/M in get_hearers_in_view(2, get_turf(owner)))
|
||||
if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
|
||||
var/sound/releasement = GLOB.release_sounds[release_sound]
|
||||
SEND_SOUND(M, releasement)
|
||||
owner.visible_message("<font color='green'><b>[owner] expels everything from their [lowertext(name)]!</b></font>")
|
||||
|
||||
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, var/silent = FALSE)
|
||||
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
|
||||
|
||||
|
||||
if(istype(M,/mob/living))
|
||||
var/mob/living/ML = M
|
||||
var/mob/living/OW = owner
|
||||
if(ML.client)
|
||||
ML.stop_sound_channel(CHANNEL_PREYLOOP) //Stop the internal loop, it'll restart if the isbelly check on next tick anyway
|
||||
ML.cure_blind("belly_[REF(src)]")
|
||||
SEND_SIGNAL(OW, COMSIG_CLEAR_MOOD_EVENT, "fedpred", /datum/mood_event/fedpred)
|
||||
SEND_SIGNAL(ML, COMSIG_CLEAR_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey)
|
||||
SEND_SIGNAL(OW, COMSIG_ADD_MOOD_EVENT, "emptypred", /datum/mood_event/emptypred)
|
||||
SEND_SIGNAL(ML, COMSIG_ADD_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey)
|
||||
|
||||
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)
|
||||
|
||||
//Clean up our own business
|
||||
owner.update_icons()
|
||||
|
||||
if(!silent)
|
||||
for(var/mob/living/H in get_hearers_in_view(2, get_turf(owner)))
|
||||
if(H.client && (H.client.prefs.cit_toggles & EATING_NOISES))
|
||||
var/sound/releasement = GLOB.release_sounds[release_sound]
|
||||
SEND_SOUND(H, releasement)
|
||||
owner.visible_message("<font color='green'><b>[owner] expels [M] from their [lowertext(name)]!</b></font>")
|
||||
|
||||
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)
|
||||
if(owner.stat == DEAD)
|
||||
return
|
||||
if (prey.buckled)
|
||||
prey.buckled.unbuckle_mob(prey,TRUE)
|
||||
|
||||
if(!isbelly(prey.loc))
|
||||
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "fedpred", /datum/mood_event/fedpred)
|
||||
SEND_SIGNAL(prey, COMSIG_ADD_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey)
|
||||
else
|
||||
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "emptypred", /datum/mood_event/emptypred)
|
||||
SEND_SIGNAL(prey, COMSIG_CLEAR_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey)
|
||||
|
||||
prey.forceMove(src)
|
||||
|
||||
owner.updateVRPanel()
|
||||
|
||||
for(var/mob/living/M in contents)
|
||||
M.updateVRPanel()
|
||||
M.become_blind("belly_[REF(src)]")
|
||||
|
||||
// Setup the autotransfer checks if needed
|
||||
if(transferlocation != null && autotransferchance > 0)
|
||||
addtimer(CALLBACK(src, /obj/belly/.proc/check_autotransfer, prey), autotransferwait)
|
||||
|
||||
/obj/belly/proc/check_autotransfer(var/mob/prey, var/obj/belly/target)
|
||||
// Some sanity checks
|
||||
if(transferlocation && (autotransferchance > 0) && (prey in contents))
|
||||
if(prob(autotransferchance))
|
||||
transfer_contents(prey, transferlocation)
|
||||
else
|
||||
// Didn't transfer, so wait before retrying
|
||||
addtimer(CALLBACK(src, /obj/belly/.proc/check_autotransfer, prey), autotransferwait)
|
||||
|
||||
//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
|
||||
content.forceMove(target)
|
||||
for(var/mob/living/M in contents)
|
||||
M.cure_blind("belly_[REF(src)]")
|
||||
// target.nom_mob(content, target.owner)
|
||||
if(!silent)
|
||||
var/sound/eating = GLOB.vore_sounds[vore_sound]
|
||||
for(var/mob/living/M in get_hearers_in_view(3, src))
|
||||
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
|
||||
SEND_SOUND(M, eating)
|
||||
|
||||
owner.updateVRPanel()
|
||||
for(var/mob/living/M in contents)
|
||||
M.updateVRPanel()
|
||||
|
||||
// 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))
|
||||
M.release_vore_contents(include_absorbed = TRUE, silent = TRUE)
|
||||
|
||||
//Drop all items into the belly
|
||||
for(var/obj/item/W in M)
|
||||
if(!M.dropItemToGround(W))
|
||||
qdel(W)
|
||||
|
||||
//Incase they have the loop going, let's double check to stop it.
|
||||
M.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
|
||||
// Delete the digested mob
|
||||
qdel(M)
|
||||
|
||||
//Update owner
|
||||
owner.updateVRPanel()
|
||||
|
||||
// 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>")
|
||||
|
||||
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.drop_location()
|
||||
//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!")
|
||||
|
||||
//Yes, it's ""safe"" to drop items here
|
||||
/obj/belly/AllowDrop()
|
||||
return TRUE
|
||||
/*
|
||||
/obj/belly/onDropInto(var/atom/movable/AM)
|
||||
return null */
|
||||
|
||||
//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) //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 [escapetime/10] seconds.)</span>")
|
||||
to_chat(owner,"<span class='warning'>Someone is attempting to climb out of your [lowertext(name)]!</span>")
|
||||
|
||||
if(do_after(R, owner, escapetime))
|
||||
if((owner.stat || escapable) && (R.loc == src)) //Can still escape?
|
||||
release_specific_contents(R)
|
||||
return
|
||||
else if(R.loc != src) //Aren't even in the belly. Quietly fail.
|
||||
return
|
||||
else //Belly became inescapable or mob revived
|
||||
to_chat(R,"<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>"
|
||||
|
||||
var/sound/struggle_snuggle = sound(get_sfx("struggle_sound"))
|
||||
var/sound/struggle_rustle = sound(get_sfx("rustle"))
|
||||
|
||||
if(is_wet)
|
||||
for(var/mob/living/M in get_hearers_in_view(3, src))
|
||||
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
|
||||
SEND_SOUND(M, struggle_snuggle)
|
||||
|
||||
else
|
||||
for(var/mob/living/M in get_hearers_in_view(3, src))
|
||||
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
|
||||
SEND_SOUND(M, struggle_rustle)
|
||||
|
||||
var/list/watching = hearers(3, owner)
|
||||
for(var/mob/living/M in watching)
|
||||
if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES)) //Might as well censor the normies here too.
|
||||
M.show_message(struggle_outer_message, 1) // visible
|
||||
|
||||
to_chat(R,struggle_user_message)
|
||||
|
||||
if(escapable) //If the stomach has escapable enabled.
|
||||
if(prob(escapechance)) //Let's have it check to see if the prey escapes first.
|
||||
to_chat(R,"<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))
|
||||
if((escapable) && (R.loc == src)) //Can still escape?
|
||||
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>")
|
||||
return
|
||||
else if(R.loc != src) //Aren't even in the belly. Quietly fail.
|
||||
return
|
||||
else //Belly became inescapable or mob revived
|
||||
to_chat(R,"<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_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_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
|
||||
|
||||
/obj/belly/proc/get_mobs_and_objs_in_belly()
|
||||
var/list/see = list()
|
||||
var/list/belly_mobs = list()
|
||||
see["mobs"] = belly_mobs
|
||||
var/list/belly_objs = list()
|
||||
see["objs"] = belly_objs
|
||||
for(var/mob/living/L in loc.contents)
|
||||
belly_mobs |= L
|
||||
for(var/obj/O in loc.contents)
|
||||
belly_objs |= O
|
||||
|
||||
return see
|
||||
|
||||
|
||||
// Belly copies and then returns the copy
|
||||
// Needs to be updated for any var changes AND KEPT IN ORDER OF THE VARS ABOVE AS WELL!
|
||||
/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.escapable = escapable
|
||||
dupe.escapetime = escapetime
|
||||
dupe.digestchance = digestchance
|
||||
dupe.absorbchance = absorbchance
|
||||
dupe.escapechance = escapechance
|
||||
dupe.can_taste = can_taste
|
||||
dupe.bulge_size = bulge_size
|
||||
dupe.transferlocation = transferlocation
|
||||
dupe.transferchance = transferchance
|
||||
dupe.autotransferchance = autotransferchance
|
||||
dupe.autotransferwait = autotransferwait
|
||||
dupe.swallow_time = swallow_time
|
||||
dupe.vore_capacity = vore_capacity
|
||||
dupe.is_wet = is_wet
|
||||
dupe.wet_loop = wet_loop
|
||||
|
||||
//// 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
|
||||
@@ -0,0 +1,294 @@
|
||||
// Process the predator's effects upon the contents of its belly (i.e digestion/transformation etc)
|
||||
/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(!owner)
|
||||
qdel(src)
|
||||
SSbellies.belly_list -= src
|
||||
return SSBELLIES_PROCESSED
|
||||
|
||||
if(loc != owner)
|
||||
if(isliving(owner)) //we don't have machine based bellies. (yet :honk:)
|
||||
forceMove(owner)
|
||||
else
|
||||
SSbellies.belly_list -= src
|
||||
qdel(src)
|
||||
return SSBELLIES_PROCESSED
|
||||
|
||||
next_process = times_fired + (6 SECONDS/wait) //Set up our next process time.
|
||||
|
||||
/////////////////////////// Auto-Emotes ///////////////////////////
|
||||
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>")
|
||||
|
||||
///////////////////// Prey Loop Refresh/hack //////////////////////
|
||||
for(var/mob/living/M in contents)
|
||||
if(isbelly(M.loc))
|
||||
if(world.time > M.next_preyloop)
|
||||
if(is_wet && wet_loop)
|
||||
if(!M.client)
|
||||
continue
|
||||
M.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case
|
||||
if(M.client.prefs.cit_toggles & DIGESTION_NOISES)
|
||||
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
|
||||
M.playsound_local(get_turf(src),preyloop, 80,0, channel = CHANNEL_PREYLOOP)
|
||||
M.next_preyloop = (world.time + 52 SECONDS)
|
||||
|
||||
|
||||
/////////////////////////// Exit Early ////////////////////////////
|
||||
var/list/touchable_items = contents - items_preserved
|
||||
if(!length(touchable_items))
|
||||
return SSBELLIES_PROCESSED
|
||||
|
||||
//////////////////////// Absorbed Handling ////////////////////////
|
||||
for(var/mob/living/M in contents)
|
||||
if(M.absorbed)
|
||||
M.Stun(5)
|
||||
|
||||
////////////////////////// Sound vars /////////////////////////////
|
||||
var/sound/prey_digest = sound(get_sfx("digest_prey"))
|
||||
var/sound/prey_death = sound(get_sfx("death_prey"))
|
||||
var/sound/pred_digest = sound(get_sfx("digest_pred"))
|
||||
var/sound/pred_death = sound(get_sfx("death_pred"))
|
||||
var/turf/source = get_turf(owner)
|
||||
|
||||
///////////////////////////// DM_HOLD /////////////////////////////
|
||||
if(digest_mode == DM_HOLD)
|
||||
return SSBELLIES_PROCESSED
|
||||
|
||||
//////////////////////////// DM_DIGEST ////////////////////////////
|
||||
else if(digest_mode == DM_DIGEST)
|
||||
if(HAS_TRAIT(owner, TRAIT_PACIFISM)) //obvious.
|
||||
digest_mode = DM_NOISY
|
||||
return
|
||||
|
||||
for (var/mob/living/M in contents)
|
||||
if(prob(25))
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/living/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/living/H in hearing_mobs)
|
||||
if(!isbelly(H.loc))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
|
||||
|
||||
//Pref protection!
|
||||
if (!M.digestable || M.absorbed)
|
||||
continue
|
||||
|
||||
//Person just died in guts!
|
||||
if(M.stat == DEAD)
|
||||
var/digest_alert_owner = pick(digest_messages_owner)
|
||||
var/digest_alert_prey = pick(digest_messages_prey)
|
||||
|
||||
//Replace placeholder vars
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
|
||||
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
|
||||
|
||||
//Send messages
|
||||
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
|
||||
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
|
||||
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*.
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/living/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/living/H in hearing_mobs)
|
||||
if(!isbelly(H.loc))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_death)
|
||||
M.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
digestion_death(M)
|
||||
owner.update_icons()
|
||||
continue
|
||||
|
||||
|
||||
// Deal digestion damage (and feed the pred)
|
||||
if(!(M.status_flags & GODMODE))
|
||||
M.adjustFireLoss(digest_burn)
|
||||
owner.nutrition += 1
|
||||
|
||||
//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 contents)
|
||||
if(prob(25))
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/living/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/living/H in hearing_mobs)
|
||||
if(!isbelly(H.loc))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
|
||||
|
||||
if(M.stat != DEAD)
|
||||
if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
|
||||
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)
|
||||
if(prob(35))
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/living/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/living/H in hearing_mobs)
|
||||
if(!isbelly(H.loc))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
|
||||
|
||||
|
||||
//////////////////////////// DM_ABSORB ////////////////////////////
|
||||
else if(digest_mode == DM_ABSORB)
|
||||
|
||||
for (var/mob/living/M in contents)
|
||||
|
||||
if(prob(10))//Less often than gurgles. People might leave this on forever.
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/living/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/living/H in hearing_mobs)
|
||||
if(!isbelly(H.loc))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
|
||||
|
||||
if(M.absorbed)
|
||||
continue
|
||||
|
||||
if(M.nutrition >= 100) //Drain them until there's no nutrients left. Slowly "absorb" them.
|
||||
var/oldnutrition = (M.nutrition * 0.05)
|
||||
M.nutrition = (M.nutrition * 0.95)
|
||||
owner.nutrition += oldnutrition
|
||||
else if(M.nutrition < 100) //When they're finally drained.
|
||||
absorb_living(M)
|
||||
|
||||
//////////////////////////// DM_UNABSORB ////////////////////////////
|
||||
else if(digest_mode == DM_UNABSORB)
|
||||
|
||||
for (var/mob/living/M in contents)
|
||||
if(M.absorbed && owner.nutrition >= 100)
|
||||
M.absorbed = 0
|
||||
to_chat(M,"<span class='notice'>You suddenly feel solid again </span>")
|
||||
to_chat(owner,"<span class='notice'>You feel like a part of you is missing.</span>")
|
||||
owner.nutrition -= 100
|
||||
|
||||
//////////////////////////DM_DRAGON /////////////////////////////////////
|
||||
//because dragons need snowflake guts
|
||||
if(digest_mode == DM_DRAGON)
|
||||
if(HAS_TRAIT(owner, TRAIT_PACIFISM)) //imagine var editing this when you're a pacifist. smh
|
||||
digest_mode = DM_NOISY
|
||||
return
|
||||
|
||||
for (var/mob/living/M in contents)
|
||||
if(prob(55)) //if you're hearing this, you're a vore ho anyway.
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/living/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/living/H in hearing_mobs)
|
||||
if(!isbelly(H.loc))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
|
||||
|
||||
//No digestion protection for megafauna.
|
||||
|
||||
//Person just died in guts!
|
||||
if(M.stat == DEAD)
|
||||
var/digest_alert_owner = pick(digest_messages_owner)
|
||||
var/digest_alert_prey = pick(digest_messages_prey)
|
||||
|
||||
//Replace placeholder vars
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
|
||||
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
|
||||
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
|
||||
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
|
||||
|
||||
//Send messages
|
||||
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
|
||||
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>")
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/living/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/living/H in hearing_mobs)
|
||||
if(!isbelly(H.loc))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_death)
|
||||
M.spill_organs(FALSE,TRUE,TRUE)
|
||||
M.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
digestion_death(M)
|
||||
owner.update_icons()
|
||||
continue
|
||||
|
||||
|
||||
// Deal digestion damage (and feed the pred)
|
||||
if(!(M.status_flags & GODMODE))
|
||||
M.adjustFireLoss(digest_burn)
|
||||
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)) //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/perfect_tele_beacon/digest_act(...)
|
||||
return FALSE //Sorta important to not digest your own beacons.
|
||||
/obj/item/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/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/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
|
||||
@@ -0,0 +1,411 @@
|
||||
///////////////////// Mob Living /////////////////////
|
||||
/mob/living
|
||||
var/digestable = FALSE // Can the mob be digested inside a belly?
|
||||
var/showvoreprefs = TRUE // Determines if the mechanical vore preferences button will be displayed on the mob or not.
|
||||
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 = FALSE // Is the vore panel open?
|
||||
var/absorbed = FALSE //are we absorbed?
|
||||
var/next_preyloop
|
||||
var/vore_init = FALSE //Has this mob's vore been initialized yet?
|
||||
var/vorepref_init = FALSE //Has this mob's voreprefs been initialized?
|
||||
|
||||
//
|
||||
// Hook for generic creation of stuff on new creatures
|
||||
//
|
||||
/hook/living_new/proc/vore_setup(mob/living/M)
|
||||
M.verbs += /mob/living/proc/preyloop_refresh
|
||||
M.verbs += /mob/living/proc/lick
|
||||
M.verbs += /mob/living/proc/escapeOOC
|
||||
|
||||
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 TRUE
|
||||
M.verbs += /mob/living/proc/insidePanel
|
||||
|
||||
//Tries to load prefs if a client is present otherwise gives freebie stomach
|
||||
spawn(10 SECONDS) // long delay because the server delays in its startup. just on the safe side.
|
||||
if(M)
|
||||
M.init_vore()
|
||||
|
||||
//return TRUE to hook-caller
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/init_vore()
|
||||
vore_init = TRUE
|
||||
//Something else made organs, meanwhile.
|
||||
if(LAZYLEN(vore_organs))
|
||||
return TRUE
|
||||
|
||||
//We'll load our client's organs if we have one
|
||||
if(client && client.prefs_vr)
|
||||
if(!copy_from_prefs_vr())
|
||||
to_chat(src,"<span class='warning'>ERROR: You seem to have saved vore prefs, but they couldn't be loaded.</span>")
|
||||
return FALSE
|
||||
if(LAZYLEN(vore_organs))
|
||||
vore_selected = vore_organs[1]
|
||||
return TRUE
|
||||
|
||||
//Or, we can create a basic one for them
|
||||
if(!LAZYLEN(vore_organs))
|
||||
LAZYINITLIST(vore_organs)
|
||||
var/obj/belly/B = new /obj/belly(src)
|
||||
vore_selected = B
|
||||
B.immutable = TRUE
|
||||
B.name = "Stomach"
|
||||
B.desc = "It appears to be rather warm and wet. Makes sense, considering it's inside [name]."
|
||||
B.can_taste = TRUE
|
||||
return TRUE
|
||||
|
||||
// Handle being clicked, perhaps with something to devour
|
||||
//
|
||||
|
||||
// Refactored to use centralized vore code system - Leshana
|
||||
|
||||
// Critical adjustments due to TG grab changes - Poojawa
|
||||
|
||||
/mob/living/proc/vore_attack(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
|
||||
if(!user || !prey || !pred)
|
||||
return
|
||||
|
||||
if(!isliving(pred)) //no badmin, you can't feed people to ghosts or objects.
|
||||
return
|
||||
|
||||
if(pred == prey) //you click your target
|
||||
if(!pred.feeding)
|
||||
to_chat(user, "<span class='notice'>They aren't able to be fed.</span>")
|
||||
to_chat(pred, "<span class='notice'>[user] tried to feed you themselves, but you aren't voracious enough to be fed.</span>")
|
||||
return
|
||||
if(!is_vore_predator(pred))
|
||||
to_chat(user, "<span class='notice'>They aren't voracious enough.</span>")
|
||||
return
|
||||
feed_self_to_grabbed(user, pred)
|
||||
|
||||
if(pred == user) //you click yourself
|
||||
if(!is_vore_predator(src))
|
||||
to_chat(user, "<span class='notice'>You aren't voracious enough.</span>")
|
||||
return
|
||||
feed_grabbed_to_self(user, prey)
|
||||
|
||||
else // click someone other than you/prey
|
||||
if(!pred.feeding)
|
||||
to_chat(user, "<span class='notice'>They aren't voracious enough to be fed.</span>")
|
||||
to_chat(pred, "<span class='notice'>[user] tried to feed you [prey], but you aren't voracious enough to be fed.</span>")
|
||||
return
|
||||
if(!prey.feeding)
|
||||
to_chat(user, "<span class='notice'>They aren't able to be fed to someone.</span>")
|
||||
to_chat(prey, "<span class='notice'>[user] tried to feed you to [pred], but you aren't able to be fed to them.</span>")
|
||||
return
|
||||
if(!is_vore_predator(pred))
|
||||
to_chat(user, "<span class='notice'>They aren't voracious enough.</span>")
|
||||
return
|
||||
feed_grabbed_to_other(user, prey, pred)
|
||||
//
|
||||
// Eating procs depending on who clicked what
|
||||
//
|
||||
/mob/living/proc/feed_grabbed_to_self(var/mob/living/user, var/mob/living/prey)
|
||||
var/belly = user.vore_selected
|
||||
return perform_the_nom(user, prey, user, belly)
|
||||
|
||||
/mob/living/proc/feed_self_to_grabbed(var/mob/living/user, var/mob/living/pred)
|
||||
var/belly = input("Choose Belly") in pred.vore_organs
|
||||
return perform_the_nom(user, user, pred, belly)
|
||||
|
||||
/mob/living/proc/feed_grabbed_to_other(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
|
||||
var/belly = input("Choose Belly") in pred.vore_organs
|
||||
return perform_the_nom(user, prey, pred, belly)
|
||||
|
||||
//
|
||||
// Master vore proc that actually does vore procedures
|
||||
//
|
||||
|
||||
/mob/living/proc/perform_the_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/obj/belly/belly, var/delay)
|
||||
//Sanity
|
||||
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 FALSE
|
||||
|
||||
if (!prey.devourable)
|
||||
to_chat(user, "This can't be eaten!")
|
||||
return FALSE
|
||||
|
||||
// The belly selected at the time of noms
|
||||
var/attempt_msg = "ERROR: Vore message couldn't be created. Notify a dev. (at)"
|
||||
var/success_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
|
||||
|
||||
// Prepare messages
|
||||
if(user == pred) //Feeding someone to yourself
|
||||
attempt_msg = text("<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.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))
|
||||
|
||||
if(!prey.Adjacent(user)) // let's not even bother attempting it yet if they aren't next to us.
|
||||
return FALSE
|
||||
|
||||
// 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(!prey.Adjacent(user)) //double check'd just in case they moved during the timer and the do_mob didn't fail for whatever reason
|
||||
return FALSE
|
||||
|
||||
// If we got this far, nom successful! Announce it!
|
||||
user.visible_message(success_msg)
|
||||
|
||||
// incredibly contentious eating noises time
|
||||
var/turf/source = get_turf(user)
|
||||
var/sound/eating = GLOB.vore_sounds[belly.vore_sound]
|
||||
for(var/mob/living/M in get_hearers_in_view(3, source))
|
||||
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
|
||||
SEND_SOUND(M, eating)
|
||||
|
||||
// Actually shove prey into the belly.
|
||||
belly.nom_mob(prey, user)
|
||||
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
|
||||
if(prey.ckey)
|
||||
prey_stat = prey.stat//only return this if they're not an unmonkey or whatever
|
||||
if(!prey.client)//if they disconnected, tell us
|
||||
prey_braindead = TRUE
|
||||
if (pred == user)
|
||||
message_admins("[ADMIN_LOOKUPFLW(pred)] ate [ADMIN_LOOKUPFLW(prey)][!prey_braindead ? "" : " (BRAINDEAD)"][prey_stat ? " (DEAD/UNCONSCIOUS)" : ""].")
|
||||
pred.log_message("[key_name(pred)] ate [key_name(prey)].", LOG_ATTACK)
|
||||
prey.log_message("[key_name(prey)] was eaten by [key_name(pred)].", LOG_ATTACK)
|
||||
else
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] forced [ADMIN_LOOKUPFLW(pred)] to eat [ADMIN_LOOKUPFLW(prey)].")
|
||||
user.log_message("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)].", LOG_ATTACK)
|
||||
pred.log_message("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)].", LOG_ATTACK)
|
||||
prey.log_message("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)].", LOG_ATTACK)
|
||||
return TRUE
|
||||
|
||||
//
|
||||
//End vore code.
|
||||
|
||||
|
||||
//
|
||||
// Our custom resist catches for /mob/living
|
||||
//
|
||||
/mob/living/proc/vore_process_resist()
|
||||
|
||||
//Are we resisting from inside a belly?
|
||||
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
|
||||
|
||||
// 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(isbelly(loc))
|
||||
src.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case
|
||||
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
|
||||
SEND_SOUND(src, preyloop)
|
||||
else
|
||||
to_chat(src, "<span class='alert'>You aren't inside anything, you clod.</span>")
|
||||
|
||||
// OOC Escape code for pref-breaking or AFK preds
|
||||
//
|
||||
/mob/living/proc/escapeOOC()
|
||||
set name = "OOC Escape"
|
||||
set category = "Vore"
|
||||
|
||||
//You're in a belly!
|
||||
if(isbelly(loc))
|
||||
var/obj/belly/B = loc
|
||||
var/confirm = alert(src, "You're in a mob. If you're otherwise unable to escape from a pred AFK for a long time, use this.", "Confirmation", "Okay", "Cancel")
|
||||
if(!confirm == "Okay" || loc != B)
|
||||
return
|
||||
//Actual escaping
|
||||
B.release_specific_contents(src,TRUE) //we might as well take advantage of that specific belly's handling. Else we stay blinded forever.
|
||||
src.stop_sound_channel(CHANNEL_PREYLOOP)
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey)
|
||||
for(var/mob/living/simple_animal/SA in range(10))
|
||||
SA.prey_excludes[src] = world.time
|
||||
|
||||
if(isanimal(B.owner))
|
||||
var/mob/living/simple_animal/SA = B.owner
|
||||
SA.update_icons()
|
||||
|
||||
//You're in a dogborg!
|
||||
else if(istype(loc, /obj/item/dogborg/sleeper))
|
||||
var/obj/item/dogborg/sleeper/belly = loc //The belly!
|
||||
|
||||
var/confirm = alert(src, "You're in a dogborg sleeper. This is for escaping from preference-breaking or if your predator disconnects/AFKs. You can also resist out naturally too.", "Confirmation", "Okay", "Cancel")
|
||||
if(!confirm == "Okay" || loc != belly)
|
||||
return
|
||||
//Actual escaping
|
||||
belly.go_out(src) //Just force-ejects from the borg as if they'd clicked the eject button.
|
||||
else
|
||||
to_chat(src,"<span class='alert'>You aren't inside anyone, though, is the thing.</span>")
|
||||
|
||||
//
|
||||
// Verb for saving vore preferences to save file
|
||||
//
|
||||
/mob/living/proc/save_vore_prefs()
|
||||
if(!client || !client.prefs_vr)
|
||||
return FALSE
|
||||
if(!copy_to_prefs_vr())
|
||||
return FALSE
|
||||
if(!client.prefs_vr.save_vore())
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/apply_vore_prefs()
|
||||
if(!client || !client.prefs_vr)
|
||||
return FALSE
|
||||
if(!client.prefs_vr.load_vore())
|
||||
return FALSE
|
||||
if(!copy_from_prefs_vr())
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/copy_to_prefs_vr()
|
||||
if(!client || !client.prefs_vr)
|
||||
to_chat(src,"<span class='warning'>You attempted to save your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev.</span>")
|
||||
return FALSE
|
||||
|
||||
var/datum/vore_preferences/P = client.prefs_vr
|
||||
|
||||
P.digestable = src.digestable
|
||||
P.devourable = src.devourable
|
||||
P.feeding = src.feeding
|
||||
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
|
||||
|
||||
//
|
||||
// Proc for applying vore preferences, given bellies
|
||||
//
|
||||
/mob/living/proc/copy_from_prefs_vr()
|
||||
if(!client || !client.prefs_vr)
|
||||
to_chat(src,"<span class='warning'>You attempted to apply your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev.</span>")
|
||||
return FALSE
|
||||
vorepref_init = TRUE
|
||||
|
||||
var/datum/vore_preferences/P = client.prefs_vr
|
||||
|
||||
digestable = P.digestable
|
||||
devourable = P.devourable
|
||||
feeding = P.feeding
|
||||
vore_taste = P.vore_taste
|
||||
|
||||
release_vore_contents(silent = TRUE)
|
||||
vore_organs.Cut()
|
||||
for(var/entry in P.belly_prefs)
|
||||
list_to_object(entry,src)
|
||||
|
||||
return TRUE
|
||||
|
||||
//
|
||||
// Release everything in every vore organ
|
||||
//
|
||||
/mob/living/proc/release_vore_contents(var/include_absorbed = TRUE, var/silent = FALSE)
|
||||
for(var/belly in vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
B.release_all_contents(include_absorbed, silent)
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
/mob/living/proc/lick(var/mob/living/tasted in oview(1))
|
||||
set name = "Lick Someone"
|
||||
set category = "Vore"
|
||||
set desc = "Lick someone nearby!"
|
||||
|
||||
if(!istype(tasted))
|
||||
return
|
||||
|
||||
if(src == stat)
|
||||
return
|
||||
|
||||
src.setClickCooldown(100)
|
||||
|
||||
src.visible_message("<span class='warning'>[src] licks [tasted]!</span>","<span class='notice'>You lick [tasted]. They taste rather like [tasted.get_taste_message()].</span>","<b>Slurp!</b>")
|
||||
|
||||
|
||||
/mob/living/proc/get_taste_message(allow_generic = TRUE, datum/species/mrace)
|
||||
if(!vore_taste && !allow_generic)
|
||||
return FALSE
|
||||
|
||||
var/taste_message = ""
|
||||
if(vore_taste && (vore_taste != ""))
|
||||
taste_message += "[vore_taste]"
|
||||
else
|
||||
if(ishuman(src))
|
||||
taste_message += "they haven't bothered to set their flavor text"
|
||||
else
|
||||
taste_message += "a plain old normal [src]"
|
||||
|
||||
/* if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(H.touching.reagent_list.len) //Just the first one otherwise I'll go insane.
|
||||
var/datum/reagent/R = H.touching.reagent_list[1]
|
||||
taste_message += " You also get the flavor of [R.taste_description] from something on them"*/
|
||||
return taste_message
|
||||
@@ -0,0 +1,169 @@
|
||||
|
||||
/*
|
||||
VVVVVVVV VVVVVVVV OOOOOOOOO RRRRRRRRRRRRRRRRR EEEEEEEEEEEEEEEEEEEEEE
|
||||
V::::::V V::::::V OO:::::::::OO R::::::::::::::::R E::::::::::::::::::::E
|
||||
V::::::V V::::::V OO:::::::::::::OO R::::::RRRRRR:::::R E::::::::::::::::::::E
|
||||
V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEEEEE::::E
|
||||
V:::::V V:::::V O::::::O O::::::O R::::R R:::::R E:::::E EEEEEE
|
||||
V:::::V V:::::V O:::::O O:::::O R::::R R:::::R E:::::E
|
||||
V:::::V V:::::V O:::::O O:::::O R::::RRRRRR:::::R E::::::EEEEEEEEEE
|
||||
V:::::V V:::::V O:::::O O:::::O R:::::::::::::RR E:::::::::::::::E
|
||||
V:::::V V:::::V O:::::O O:::::O R::::RRRRRR:::::R E:::::::::::::::E
|
||||
V:::::V V:::::V O:::::O O:::::O R::::R R:::::R E::::::EEEEEEEEEE
|
||||
V:::::V:::::V O:::::O O:::::O R::::R R:::::R E:::::E
|
||||
V:::::::::V O::::::O O::::::O R::::R R:::::R E:::::E EEEEEE
|
||||
V:::::::V O:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEEEE:::::E
|
||||
V:::::V OO:::::::::::::OO R::::::R R:::::RE::::::::::::::::::::E
|
||||
V:::V OO:::::::::OO R::::::R R:::::RE::::::::::::::::::::E
|
||||
VVV OOOOOOOOO RRRRRRRR RRRRRRREEEEEEEEEEEEEEEEEEEEEE
|
||||
|
||||
-Aro <3 */
|
||||
|
||||
//
|
||||
// Overrides/additions to stock defines go here, as well as hooks. Sort them by
|
||||
// the object they are overriding. So all /mob/living together, etc.
|
||||
//
|
||||
|
||||
//
|
||||
// The datum type bolted onto normal preferences datums for storing Vore stuff
|
||||
//
|
||||
|
||||
#define VORE_VERSION 4
|
||||
|
||||
GLOBAL_LIST_EMPTY(vore_preferences_datums)
|
||||
|
||||
/client
|
||||
var/datum/vore_preferences/prefs_vr
|
||||
|
||||
/datum/vore_preferences
|
||||
//Actual preferences
|
||||
var/digestable = FALSE
|
||||
var/devourable = FALSE
|
||||
var/feeding = FALSE
|
||||
// var/allowmobvore = TRUE
|
||||
var/list/belly_prefs = list()
|
||||
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
|
||||
|
||||
/datum/vore_preferences/New(client/C)
|
||||
if(istype(C))
|
||||
client = C
|
||||
client_ckey = C.ckey
|
||||
load_vore()
|
||||
|
||||
//
|
||||
// Check if an object is capable of eating things, based on vore_organs
|
||||
//
|
||||
/proc/is_vore_predator(var/mob/living/O)
|
||||
if(istype(O,/mob/living))
|
||||
if(O.vore_organs.len > 0)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
//
|
||||
// Belly searching for simplifying other procs
|
||||
// Mostly redundant now with belly-objects and isbelly(loc)
|
||||
//
|
||||
/proc/check_belly(atom/movable/A)
|
||||
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.prefs || !client.prefs.default_slot)
|
||||
return FALSE //Need to know what character to load!
|
||||
|
||||
slot = client.prefs.default_slot
|
||||
|
||||
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/list/json_from_file = json_decode(file2text(path))
|
||||
if(!json_from_file)
|
||||
return FALSE //My concern grows
|
||||
|
||||
var/version = json_from_file["version"]
|
||||
json_from_file = patch_version(json_from_file,version)
|
||||
|
||||
digestable = json_from_file["digestable"]
|
||||
devourable = json_from_file["devourable"]
|
||||
feeding = json_from_file["feeding"]
|
||||
vore_taste = json_from_file["vore_taste"]
|
||||
belly_prefs = json_from_file["belly_prefs"]
|
||||
|
||||
//Quick sanitize
|
||||
if(isnull(digestable))
|
||||
digestable = FALSE
|
||||
if(isnull(devourable))
|
||||
devourable = FALSE
|
||||
if(isnull(feeding))
|
||||
feeding = FALSE
|
||||
if(isnull(belly_prefs))
|
||||
belly_prefs = list()
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/vore_preferences/proc/save_vore()
|
||||
if(!path)
|
||||
return FALSE
|
||||
|
||||
var/version = VORE_VERSION //For "good times" use in the future
|
||||
var/list/settings_list = list(
|
||||
"version" = version,
|
||||
"digestable" = digestable,
|
||||
"devourable" = devourable,
|
||||
"feeding" = feeding,
|
||||
"vore_taste" = vore_taste,
|
||||
"belly_prefs" = belly_prefs,
|
||||
)
|
||||
|
||||
//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
|
||||
//#ifdef RUST_G
|
||||
// call(RUST_G, "file_write")(json_to_file, path)
|
||||
//#else
|
||||
// Fall back to using old format if we are not using rust-g
|
||||
if(fexists(path))
|
||||
fdel(path) //Byond only supports APPENDING to files, not replacing.
|
||||
text2file(json_to_file, path)
|
||||
//#endif
|
||||
if(!fexists(path))
|
||||
testing("Saving: [path] failed file write")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/* commented out list things
|
||||
"allowmobvore" = allowmobvore,
|
||||
"can_be_drop_prey" = can_be_drop_prey,
|
||||
"can_be_drop_pred" = can_be_drop_pred, */
|
||||
|
||||
//Can do conversions here
|
||||
datum/vore_preferences/proc/patch_version(var/list/json_from_file,var/version)
|
||||
return json_from_file
|
||||
|
||||
#undef VORE_VERSION
|
||||
@@ -0,0 +1,62 @@
|
||||
// -------------- Sickshot -------------
|
||||
/obj/item/gun/energy/sickshot
|
||||
name = "\improper MPA6 \'Sickshot\'"
|
||||
desc = "A device that can trigger convusions in specific areas to eject foreign material from a host. Must be used very close to a target. Not for Combat usage."
|
||||
|
||||
icon_state = "dragnet"
|
||||
item_state = "dragnet"
|
||||
ammo_x_offset = 1
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/sickshot)
|
||||
|
||||
/obj/item/ammo_casing/energy/sickshot
|
||||
projectile_type = /obj/item/projectile/sickshot
|
||||
e_cost = 100
|
||||
|
||||
//Projectile
|
||||
/obj/item/projectile/sickshot
|
||||
name = "sickshot pulse"
|
||||
icon_state = "e_netting"
|
||||
damage = 0
|
||||
damage_type = STAMINA
|
||||
range = 2
|
||||
|
||||
/obj/item/projectile/sickshot/on_hit(var/atom/movable/target, var/blocked = 0)
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/H = target
|
||||
if(prob(5))
|
||||
for(var/X in H.vore_organs)
|
||||
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
|
||||
|
||||
|
||||
////////////////////////// Anti-Noms Drugs //////////////////////////
|
||||
/*
|
||||
/datum/reagent/medicine/ickypak
|
||||
name = "Ickypak"
|
||||
id = "ickypak"
|
||||
description = "A foul-smelling green liquid, for inducing muscle contractions to expel accidentally ingested things."
|
||||
reagent_state = LIQUID
|
||||
color = "#0E900E"
|
||||
metabolization_rate = 0.25 * REAGENTS_METABOLISM
|
||||
|
||||
/datum/reagent/medicine/ickypak/on_mob_life(var/mob/living/M, method=INGEST)
|
||||
if(prob(10))
|
||||
M.visible_message("<span class='danger'>[M] retches!</span>", \
|
||||
"<span class='userdanger'>You don't feel good...</span>")
|
||||
for(var/I in M.vore_organs)
|
||||
var/datum/belly/B = M.vore_organs[I]
|
||||
for(var/atom/movable/A in B.internal_contents)
|
||||
if(prob(55))
|
||||
playsound(M, 'sound/effects/splat.ogg', 50, 1)
|
||||
B.release_specific_contents(A)
|
||||
M.visible_message("<span class='danger'>[M] contracts strangely, spewing out something!</span>", \
|
||||
"<span class='userdanger'>You spew out something from inside you!</span>")
|
||||
return ..()
|
||||
|
||||
/datum/chemical_reaction/ickypak
|
||||
name = "Ickypak"
|
||||
id = "ickypak"
|
||||
results = list("ickypak" = 2)
|
||||
required_reagents = list("chlorine" = 2 , "oil" = 1) */
|
||||
@@ -0,0 +1,738 @@
|
||||
//
|
||||
// Vore management panel for players
|
||||
//
|
||||
|
||||
#define BELLIES_MAX 20
|
||||
#define BELLIES_NAME_MIN 2
|
||||
#define BELLIES_NAME_MAX 12
|
||||
#define BELLIES_DESC_MAX 1024
|
||||
#define FLAVOR_MAX 40
|
||||
|
||||
/mob/living/proc/insidePanel()
|
||||
set name = "Vore Panel"
|
||||
set category = "Vore"
|
||||
|
||||
var/datum/vore_look/picker_holder = new()
|
||||
picker_holder.loop = picker_holder
|
||||
picker_holder.selected = vore_selected
|
||||
|
||||
var/dat = picker_holder.gen_vui(src)
|
||||
|
||||
picker_holder.popup = new(src, "insidePanel","Vore Panel", 450, 700, picker_holder)
|
||||
picker_holder.popup.set_content(dat)
|
||||
picker_holder.popup.open()
|
||||
src.openpanel = TRUE
|
||||
|
||||
/mob/living/proc/updateVRPanel() //Panel popup update call from belly events.
|
||||
if(src.openpanel == TRUE)
|
||||
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", 450, 700, picker_holder)
|
||||
picker_holder.popup.set_content(dat)
|
||||
picker_holder.popup.open()
|
||||
|
||||
//
|
||||
// Callback Handler for the Inside form
|
||||
//
|
||||
/datum/vore_look
|
||||
var/obj/belly/selected
|
||||
var/show_interacts = FALSE
|
||||
var/datum/browser/popup
|
||||
var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action.
|
||||
|
||||
/datum/vore_look/Destroy()
|
||||
loop = null
|
||||
selected = null
|
||||
return QDEL_HINT_HARDDEL
|
||||
|
||||
/datum/vore_look/Topic(href,href_list[])
|
||||
if (vp_interact(href, href_list))
|
||||
popup.set_content(gen_vui(usr))
|
||||
usr << output(popup.get_content(), "insidePanel.browser")
|
||||
|
||||
/datum/vore_look/proc/gen_vui(var/mob/living/user)
|
||||
var/dat
|
||||
dat += "Remember to toggle the vore mode, it's to the left of your combat toggle. Open mouth means you're voracious!<br>"
|
||||
dat += "Remember that the prey is blind, use audible mode subtle messages to communicate to them with posts!<br>"
|
||||
dat += "<HR>"
|
||||
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 [user.absorbed ? "absorbed into " : "inside "]</font> <font color = 'yellow'>[eater]'s</font> <font color = 'red'>[inside_belly]</font>!<br><br>"
|
||||
|
||||
if(inside_belly.desc)
|
||||
dat += "[inside_belly.desc]<br><br>"
|
||||
|
||||
if (inside_belly.contents.len > 1)
|
||||
dat += "You can see the following around you:<br>"
|
||||
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>"
|
||||
|
||||
//Zero-width space, for wrapping
|
||||
dat += "​"
|
||||
else
|
||||
dat += "You aren't inside anyone."
|
||||
|
||||
dat += "<HR>"
|
||||
|
||||
dat += "<ol style='list-style: none; padding: 0; overflow: auto;'>"
|
||||
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
|
||||
dat += "<li style='float: left'><a href='?src=\ref[src];bellypick=\ref[B]'>[B.name]"
|
||||
var/spanstyle
|
||||
switch(B.digest_mode)
|
||||
if(DM_HOLD)
|
||||
spanstyle = ""
|
||||
if(DM_DIGEST)
|
||||
spanstyle = "color:red;"
|
||||
if(DM_HEAL)
|
||||
spanstyle = "color:darkgreen;"
|
||||
if(DM_NOISY)
|
||||
spanstyle = "color:purple;"
|
||||
if(DM_ABSORB)
|
||||
spanstyle = "color:purple;"
|
||||
if(DM_DRAGON)
|
||||
spanstyle = "color:blue;"
|
||||
|
||||
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>"
|
||||
dat += "</ol>"
|
||||
dat += "<HR>"
|
||||
|
||||
// Selected Belly (contents, configuration)
|
||||
if(!selected)
|
||||
dat += "No belly selected. Click one to select it."
|
||||
else
|
||||
if(selected.contents.len)
|
||||
dat += "<b>Contents:</b> "
|
||||
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.contents.len > 1)
|
||||
dat += "<a href='?src=\ref[src];insidepick=1;pickall=1'>\[All\]</a>"
|
||||
|
||||
dat += "<HR>"
|
||||
|
||||
//Belly Name Button
|
||||
dat += "<a href='?src=\ref[src];b_name=\ref[selected]'>Name:</a>"
|
||||
dat += " '[selected.name]'"
|
||||
|
||||
//Belly Type button
|
||||
dat += "<br><a href='?src=\ref[src];b_wetness=\ref[selected]'>Is Fleshy:</a>"
|
||||
dat += "[selected.is_wet ? "Yes" : "No"]"
|
||||
if(selected.is_wet)
|
||||
dat += "<br><a href='?src=\ref[src];b_wetloop=\ref[selected]'>Internal loop for prey?:</a>"
|
||||
dat += "[selected.wet_loop ? "Yes" : "No"]"
|
||||
|
||||
//Digest Mode Button
|
||||
dat += "<br><a href='?src=\ref[src];b_mode=\ref[selected]'>Belly Mode:</a>"
|
||||
dat += " [selected.digest_mode]"
|
||||
|
||||
//Belly verb
|
||||
dat += "<br><a href='?src=\ref[src];b_verb=\ref[selected]'>Vore Verb:</a>"
|
||||
dat += " '[selected.vore_verb]'"
|
||||
|
||||
//Inside flavortext
|
||||
dat += "<br><a href='?src=\ref[src];b_desc=\ref[selected]'>Flavor Text:</a>"
|
||||
dat += " '[selected.desc]'"
|
||||
|
||||
//Belly sound
|
||||
dat += "<br><a href='?src=\ref[src];b_sound=\ref[selected]'>Vore Sound: [selected.vore_sound]</a>"
|
||||
dat += "<a href='?src=\ref[src];b_soundtest=\ref[selected]'>Test</a>"
|
||||
|
||||
//Release sound
|
||||
dat += "<br><a href='?src=\ref[src];b_release=\ref[selected]'>Release Sound: [selected.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>"
|
||||
|
||||
//Can belly taste?
|
||||
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)
|
||||
dat += "<a href='?src=\ref[src];show_int=\ref[selected]'>[show_interacts ? "Hide" : "Show"]</a>"
|
||||
|
||||
if(show_interacts && selected.escapable)
|
||||
dat += "<HR>"
|
||||
dat += "Interaction Settings <a href='?src=\ref[src];int_help=\ref[selected]'>?</a>"
|
||||
dat += "<br><a href='?src=\ref[src];b_escapechance=\ref[selected]'>Set Belly Escape Chance</a>"
|
||||
dat += " [selected.escapechance]%"
|
||||
|
||||
dat += "<br><a href='?src=\ref[src];b_escapetime=\ref[selected]'>Set Belly Escape Time</a>"
|
||||
dat += " [selected.escapetime/10]s"
|
||||
|
||||
//Special <br> here to add a gap
|
||||
dat += "<br style='line-height:5px;'>"
|
||||
dat += "<br><a href='?src=\ref[src];b_transferchance=\ref[selected]'>Set Belly Transfer Chance</a>"
|
||||
dat += " [selected.transferchance]%"
|
||||
|
||||
dat += "<br><a href='?src=\ref[src];b_transferlocation=\ref[selected]'>Set Belly Transfer Location</a>"
|
||||
dat += " [selected.transferlocation ? selected.transferlocation : "Disabled"]"
|
||||
|
||||
//Special <br> here to add a gap
|
||||
dat += "<br style='line-height:5px;'>"
|
||||
dat += "<br><a href='?src=\ref[src];b_absorbchance=\ref[selected]'>Set Belly Absorb Chance</a>"
|
||||
dat += " [selected.absorbchance]%"
|
||||
|
||||
dat += "<br><a href='?src=\ref[src];b_digestchance=\ref[selected]'>Set Belly Digest Chance</a>"
|
||||
dat += " [selected.digestchance]%"
|
||||
dat += "<HR>"
|
||||
|
||||
//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 += "<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];applyprefs=1'>Reload Slot Prefs</a>"
|
||||
|
||||
dat += "<HR>"
|
||||
switch(user.digestable)
|
||||
if(TRUE)
|
||||
dat += "<br><a style='background:#173d15;' href='?src=\ref[src];toggledg=1'>Toggle Digestable (Currently: ON)</a>"
|
||||
if(FALSE)
|
||||
dat += "<br><a style='background:#990000;' href='?src=\ref[src];toggledg=1'>Toggle Digestable (Currently: OFF)</a>"
|
||||
switch(user.devourable)
|
||||
if(TRUE)
|
||||
dat += "<br><a style='background:#173d15;' href='?src=\ref[src];toggledvor=1'>Toggle Devourable (Currently: ON)</a>"
|
||||
if(FALSE)
|
||||
dat += "<br><a style='background:#990000;' href='?src=\ref[src];toggledvor=1'>Toggle Devourable (Currently: OFF)</a>"
|
||||
switch(user.feeding)
|
||||
if(TRUE)
|
||||
dat += "<br><a style='background:#173d15;' href='?src=\ref[src];toggledfeed=1'>Toggle Feeding (Currently: ON)</a>"
|
||||
if(FALSE)
|
||||
dat += "<br><a style='background:#990000;' href='?src=\ref[src];toggledfeed=1'>Toggle Feeding (Currently: OFF)</a>"
|
||||
|
||||
//Returns the dat html to the vore_look
|
||||
return dat
|
||||
|
||||
/datum/vore_look/proc/vp_interact(href, href_list)
|
||||
var/mob/living/user = usr
|
||||
for(var/H in href_list)
|
||||
|
||||
if(href_list["close"])
|
||||
qdel(src) // Cleanup
|
||||
user.openpanel = FALSE
|
||||
return
|
||||
|
||||
if(href_list["show_int"])
|
||||
show_interacts = !show_interacts
|
||||
return TRUE //Force update
|
||||
|
||||
if(href_list["int_help"])
|
||||
alert("These control how your belly responds to someone using 'resist' while inside you. The percent chance to trigger each is listed below, \
|
||||
and you can change them to whatever you see fit. Setting them to 0% will disable the possibility of that interaction. \
|
||||
These only function as long as interactions are turned on in general. Keep in mind, the 'belly mode' interactions (digest/absorb) \
|
||||
will affect all prey in that belly, if one resists and triggers digestion/absorption. If multiple trigger at the same time, \
|
||||
only the first in the order of 'Escape > Transfer > Absorb > Digest' will occur.","Interactions Help")
|
||||
return FALSE //Force update
|
||||
|
||||
if(href_list["outsidepick"])
|
||||
var/atom/movable/tgt = locate(href_list["outsidepick"])
|
||||
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"
|
||||
|
||||
if(istype(tgt,/mob/living))
|
||||
var/mob/living/M = tgt
|
||||
intent = alert("What do you want to do to them?","Query","Examine","Help Out","Devour")
|
||||
switch(intent)
|
||||
if("Examine") //Examine a mob inside another mob
|
||||
M.examine(user)
|
||||
|
||||
if("Help Out") //Help the inside-mob out
|
||||
if(user.stat || user.absorbed || M.absorbed)
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return TRUE
|
||||
|
||||
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>")
|
||||
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>")
|
||||
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 TRUE
|
||||
|
||||
if(!user.vore_selected)
|
||||
to_chat(user,"<span class='warning'>Pick a belly on yourself first!</span>")
|
||||
return TRUE
|
||||
|
||||
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) //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)
|
||||
|
||||
else if(istype(tgt,/obj/item))
|
||||
var/obj/item/T = tgt
|
||||
if(!(tgt in OB))
|
||||
//Doesn't exist anymore, update.
|
||||
return TRUE
|
||||
intent = alert("What do you want to do to that?","Query","Examine","Use Hand")
|
||||
switch(intent)
|
||||
if("Examine")
|
||||
T.examine(user)
|
||||
|
||||
if("Use Hand")
|
||||
if(user.stat)
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return TRUE
|
||||
|
||||
user.ClickOn(T)
|
||||
sleep(5) //Seems to exit too fast for the panel to update
|
||||
|
||||
if(href_list["insidepick"])
|
||||
var/intent
|
||||
|
||||
//Handle the [All] choice. Ugh inelegant. Someone make this pretty.
|
||||
if(href_list["pickall"])
|
||||
intent = alert("Eject all, Move all?","Query","Eject all","Cancel","Move all")
|
||||
switch(intent)
|
||||
if("Cancel")
|
||||
return FALSE
|
||||
|
||||
if("Eject all")
|
||||
if(user.stat)
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return FALSE
|
||||
|
||||
selected.release_all_contents()
|
||||
|
||||
if("Move all")
|
||||
if(user.stat)
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return FALSE
|
||||
|
||||
var/obj/belly/choice = input("Move all where?","Select Belly") as null|anything in user.vore_organs
|
||||
if(!choice)
|
||||
return FALSE
|
||||
|
||||
for(var/atom/movable/tgt in selected)
|
||||
to_chat(tgt,"<span class='warning'>You're squished from [user]'s [lowertext(selected)] to their [lowertext(choice.name)]!</span>")
|
||||
selected.transfer_contents(tgt, choice, 1)
|
||||
|
||||
var/atom/movable/tgt = locate(href_list["insidepick"])
|
||||
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")
|
||||
switch(intent)
|
||||
if("Examine")
|
||||
tgt.examine(user)
|
||||
|
||||
if("Eject")
|
||||
if(user.stat)
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return FALSE
|
||||
|
||||
selected.release_specific_contents(tgt)
|
||||
|
||||
if("Move")
|
||||
if(user.stat)
|
||||
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
|
||||
return FALSE
|
||||
|
||||
var/obj/belly/choice = input("Move [tgt] where?","Select Belly") as null|anything in user.vore_organs
|
||||
if(!choice || !(tgt in selected))
|
||||
return FALSE
|
||||
|
||||
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)
|
||||
|
||||
if(href_list["newbelly"])
|
||||
if(user.vore_organs.len >= BELLIES_MAX)
|
||||
return FALSE
|
||||
|
||||
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)
|
||||
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 FALSE
|
||||
|
||||
var/obj/belly/NB = new(user)
|
||||
NB.name = new_name
|
||||
selected = NB
|
||||
|
||||
if(href_list["bellypick"])
|
||||
selected = locate(href_list["bellypick"])
|
||||
user.vore_selected = selected
|
||||
|
||||
////
|
||||
//Please keep these the same order they are on the panel UI for ease of coding
|
||||
////
|
||||
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)
|
||||
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 FALSE
|
||||
|
||||
selected.name = new_name
|
||||
|
||||
if(href_list["b_wetness"])
|
||||
selected.is_wet = !selected.is_wet
|
||||
|
||||
if(href_list["b_wetloop"])
|
||||
selected.wet_loop = !selected.wet_loop
|
||||
|
||||
if(href_list["b_mode"])
|
||||
var/list/menu_list = selected.digest_modes
|
||||
|
||||
var/new_mode = input("Choose Mode (currently [selected.digest_mode])") as null|anything in menu_list
|
||||
if(!new_mode)
|
||||
return FALSE
|
||||
selected.digest_mode = new_mode
|
||||
|
||||
if(href_list["b_desc"])
|
||||
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)
|
||||
alert("Entered belly desc too long. [BELLIES_DESC_MAX] character limit.","Error")
|
||||
return FALSE
|
||||
selected.desc = new_desc
|
||||
else //Returned null
|
||||
return FALSE
|
||||
|
||||
if(href_list["b_msgs"])
|
||||
var/list/messages = list(
|
||||
"Digest Message (to prey)",
|
||||
"Digest Message (to you)",
|
||||
"Struggle Message (outside)",
|
||||
"Struggle Message (inside)",
|
||||
"Examine Message (when full)",
|
||||
"Reset All To Default"
|
||||
)
|
||||
|
||||
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") 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)
|
||||
if("Digest Message (to prey)")
|
||||
var/new_message = input(user,"These are sent to prey when they expire. Write them in 2nd person ('you feel X'). Avoid using %prey in this type."+help,"Digest Message (to prey)",selected.get_messages("dmp")) as message
|
||||
if(new_message)
|
||||
selected.set_messages(new_message,"dmp")
|
||||
|
||||
if("Digest Message (to you)")
|
||||
var/new_message = input(user,"These are sent to you when prey expires in you. Write them in 2nd person ('you feel X'). Avoid using %pred in this type."+help,"Digest Message (to you)",selected.get_messages("dmo")) as message
|
||||
if(new_message)
|
||||
selected.set_messages(new_message,"dmo")
|
||||
|
||||
if("Struggle Message (outside)")
|
||||
var/new_message = input(user,"These are sent to those nearby when prey struggles. Write them in 3rd person ('X's Y bulges')."+help,"Struggle Message (outside)",selected.get_messages("smo")) as message
|
||||
if(new_message)
|
||||
selected.set_messages(new_message,"smo")
|
||||
|
||||
if("Struggle Message (inside)")
|
||||
var/new_message = input(user,"These are sent to prey when they struggle. Write them in 2nd person ('you feel X'). Avoid using %prey in this type."+help,"Struggle Message (inside)",selected.get_messages("smi")) as message
|
||||
if(new_message)
|
||||
selected.set_messages(new_message,"smi")
|
||||
|
||||
if("Examine Message (when full)")
|
||||
var/new_message = input(user,"These are sent to people who examine you when this belly has contents. Write them in 3rd person ('Their %belly is bulging')."+help,"Examine Message (when full)",selected.get_messages("em")) as message
|
||||
if(new_message)
|
||||
selected.set_messages(new_message,"em")
|
||||
|
||||
if("Reset All To Default")
|
||||
var/confirm = alert(user,"This will delete any custom messages. Are you sure?","Confirmation","DELETE","Cancel")
|
||||
if(confirm == "DELETE")
|
||||
selected.digest_messages_prey = initial(selected.digest_messages_prey)
|
||||
selected.digest_messages_owner = initial(selected.digest_messages_owner)
|
||||
selected.struggle_messages_outside = initial(selected.struggle_messages_outside)
|
||||
selected.struggle_messages_inside = initial(selected.struggle_messages_inside)
|
||||
|
||||
if(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)
|
||||
alert("Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).","Error")
|
||||
return FALSE
|
||||
|
||||
selected.vore_verb = new_verb
|
||||
|
||||
if(href_list["b_release"])
|
||||
var/choice = input(user,"Currently set to [selected.release_sound]","Select Sound") as null|anything in GLOB.release_sounds
|
||||
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
selected.release_sound = choice
|
||||
|
||||
if(href_list["b_releasesoundtest"])
|
||||
var/sound/releasetest = GLOB.release_sounds[selected.release_sound]
|
||||
if(releasetest)
|
||||
SEND_SOUND(user, releasetest)
|
||||
|
||||
if(href_list["b_sound"])
|
||||
var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in GLOB.vore_sounds
|
||||
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
selected.vore_sound = choice
|
||||
|
||||
if(href_list["b_soundtest"])
|
||||
var/sound/voretest = GLOB.vore_sounds[selected.vore_sound]
|
||||
if(voretest)
|
||||
SEND_SOUND(user, voretest)
|
||||
|
||||
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
|
||||
to_chat(usr,"<span class='warning'>Prey now have special interactions with your [lowertext(selected.name)] depending on your settings.</span>")
|
||||
else if(selected.escapable == TRUE) //Never escapable.
|
||||
selected.escapable = FALSE
|
||||
to_chat(usr,"<span class='warning'>Prey will not be able to have special interactions with your [lowertext(selected.name)].</span>")
|
||||
show_interacts = FALSE //Force the hiding of the panel
|
||||
else
|
||||
alert("Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.","Error") //If they somehow have a varable that's not 0 or 1
|
||||
selected.escapable = FALSE
|
||||
show_interacts = FALSE //Force the hiding of the panel
|
||||
|
||||
if(href_list["b_escapechance"])
|
||||
var/escape_chance_input = input(user, "Set prey escape chance on resist (as %)", "Prey Escape Chance") as num|null
|
||||
if(!isnull(escape_chance_input)) //These have to be 'null' because both cancel and 0 are valid, separate options
|
||||
selected.escapechance = sanitize_integer(escape_chance_input, 0, 100, initial(selected.escapechance))
|
||||
|
||||
if(href_list["b_escapetime"])
|
||||
var/escape_time_input = input(user, "Set number of seconds for prey to escape on resist (1-60)", "Prey Escape Time") as num|null
|
||||
if(!isnull(escape_time_input))
|
||||
selected.escapetime = sanitize_integer(escape_time_input*10, 10, 600, initial(selected.escapetime))
|
||||
|
||||
if(href_list["b_transferchance"])
|
||||
var/transfer_chance_input = input(user, "Set belly transfer chance on resist (as %). You must also set the location for this to have any effect.", "Prey Escape Time") as num|null
|
||||
if(!isnull(transfer_chance_input))
|
||||
selected.transferchance = sanitize_integer(transfer_chance_input, 0, 100, initial(selected.transferchance))
|
||||
|
||||
if(href_list["b_transferlocation"])
|
||||
var/obj/belly/choice = input("Where do you want your [lowertext(selected.name)] to lead if prey resists?","Select Belly") as null|anything in (user.vore_organs + "None - Remove" - selected)
|
||||
|
||||
if(!choice) //They cancelled, no changes
|
||||
return FALSE
|
||||
else if(choice == "None - Remove")
|
||||
selected.transferlocation = null
|
||||
else
|
||||
selected.transferlocation = choice.name
|
||||
|
||||
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_del"])
|
||||
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(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='warning'>Belly Preferences not saved!</span>")
|
||||
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Belly Preferences were saved!</span>")
|
||||
log_admin("Could not save vore prefs on USER: [user].")
|
||||
|
||||
if(href_list["applyprefs"])
|
||||
var/alert = alert("Are you sure you want to reload character slot preferences? This will remove your current vore organs and eject their contents.","Confirmation","Reload","Cancel")
|
||||
if(!alert == "Reload")
|
||||
return FALSE
|
||||
if(!user.apply_vore_prefs())
|
||||
alert("ERROR: Vore preferences failed to apply!","Error")
|
||||
else
|
||||
to_chat(user,"<span class='notice'>Vore preferences applied from active slot!</span>")
|
||||
|
||||
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 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 FALSE
|
||||
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")
|
||||
switch(choice)
|
||||
if("Cancel")
|
||||
return FALSE
|
||||
if("Allow Digestion")
|
||||
user.digestable = TRUE
|
||||
if("Prevent Digestion")
|
||||
user.digestable = FALSE
|
||||
|
||||
if(user.client.prefs_vr)
|
||||
user.client.prefs_vr.digestable = user.digestable
|
||||
|
||||
if(href_list["toggledvor"])
|
||||
var/choice = alert(user, "This button is for those who don't like vore at all. Devouring you is currently: [user.devourable ? "Allowed" : "Prevented"]", "", "Allow Devourment", "Cancel", "Prevent Devourment")
|
||||
switch(choice)
|
||||
if("Cancel")
|
||||
return FALSE
|
||||
if("Allow Devourment")
|
||||
user.devourable = TRUE
|
||||
if("Prevent Devourment")
|
||||
user.devourable = FALSE
|
||||
|
||||
if(user.client.prefs_vr)
|
||||
user.client.prefs_vr.devourable = user.devourable
|
||||
|
||||
if(href_list["toggledfeed"])
|
||||
var/choice = alert(user, "This button is to toggle your ability to be fed to others. Feeding predators is currently: [user.feeding ? "Allowed" : "Prevented"]", "", "Allow Feeding", "Cancel", "Prevent Feeding")
|
||||
switch(choice)
|
||||
if("Cancel")
|
||||
return FALSE
|
||||
if("Allow Feeding")
|
||||
user.feeding = TRUE
|
||||
if("Prevent Feeding")
|
||||
user.feeding = FALSE
|
||||
|
||||
if(user.client.prefs_vr)
|
||||
user.client.prefs_vr.feeding = user.feeding
|
||||
|
||||
//Refresh when interacted with, returning 1 makes vore_look.Topic update
|
||||
return TRUE
|
||||
@@ -0,0 +1,37 @@
|
||||
//The base hooks themselves
|
||||
|
||||
//New() hooks
|
||||
/hook/client_new
|
||||
|
||||
/hook/mob_new
|
||||
|
||||
/hook/living_new
|
||||
|
||||
/hook/carbon_new
|
||||
|
||||
/hook/human_new
|
||||
|
||||
/hook/simple_animal_new
|
||||
|
||||
//Hooks for interactions
|
||||
/hook/living_attackby
|
||||
|
||||
//
|
||||
//Hook helpers to expand hooks to others
|
||||
//
|
||||
/hook/mob_new/proc/chain_hooks(mob/M)
|
||||
var/result = 1
|
||||
if(isliving(M))
|
||||
if(!hook_vr("living_new",args))
|
||||
result = 0
|
||||
|
||||
if(iscarbon(M))
|
||||
if(!hook_vr("carbon_new",args))
|
||||
result = 0
|
||||
|
||||
if(ishuman(M))
|
||||
if(!hook_vr("human_new",args))
|
||||
result = 0
|
||||
|
||||
//Return 1 to superhook
|
||||
return result
|
||||
@@ -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
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Gravity Pull effect which draws in movable objects to its center.
|
||||
// In this case, "number" refers to the range. directions is ignored.
|
||||
//
|
||||
/datum/effect/effect/system/grav_pull
|
||||
var/pull_radius = 3
|
||||
var/pull_anchored = 0
|
||||
var/break_windows = 0
|
||||
|
||||
/datum/effect/effect/system/grav_pull/set_up(range, num, loca)
|
||||
pull_radius = range
|
||||
number = num
|
||||
if(istype(loca, /turf/))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
|
||||
/datum/effect/effect/system/grav_pull/start()
|
||||
spawn(0)
|
||||
if(holder)
|
||||
src.location = get_turf(holder)
|
||||
for(var/i=0, i < number, i++)
|
||||
do_pull()
|
||||
sleep(25)
|
||||
|
||||
/datum/effect/effect/system/grav_pull/proc/do_pull()
|
||||
//following is adapted from supermatter and singulo code
|
||||
if(defer_powernet_rebuild != 2)
|
||||
defer_powernet_rebuild = 1
|
||||
|
||||
// Let's just make this one loop.
|
||||
for(var/atom/X in orange(pull_radius, location))
|
||||
// Movable atoms only
|
||||
if(istype(X, /atom/movable))
|
||||
if(istype(X, /obj/effect/overlay)) continue
|
||||
if(X && !istype(X, /mob/living/carbon/human))
|
||||
if(break_windows && istype(X, /obj/structure/window)) //shatter windows
|
||||
var/obj/structure/window/W = X
|
||||
W.ex_act(2.0)
|
||||
|
||||
if(istype(X, /obj))
|
||||
var/obj/O = X
|
||||
if(O.anchored)
|
||||
if (!pull_anchored) continue // Don't pull anchored stuff unless configured
|
||||
step_towards(X, location) // step just once if anchored
|
||||
continue
|
||||
|
||||
step_towards(X, location) // Step twice
|
||||
step_towards(X, location)
|
||||
|
||||
else if(istype(X,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = X
|
||||
if(istype(H.shoes,/obj/item/clothing/shoes/magboots))
|
||||
var/obj/item/clothing/shoes/magboots/M = H.shoes
|
||||
if(M.magpulse)
|
||||
step_towards(H, location) //step just once with magboots
|
||||
continue
|
||||
step_towards(H, location) //step twice
|
||||
step_towards(H, location)
|
||||
|
||||
if(defer_powernet_rebuild != 2)
|
||||
defer_powernet_rebuild = 0
|
||||
return
|
||||
@@ -0,0 +1,33 @@
|
||||
// Micro Holders - Extends /obj/item/holder
|
||||
|
||||
/obj/item/holder/micro
|
||||
name = "micro"
|
||||
desc = "Another crewmember, small enough to fit in your hand."
|
||||
icon_state = "micro"
|
||||
slot_flags = SLOT_FEET | SLOT_HEAD | SLOT_ID
|
||||
w_class = 2
|
||||
item_icons = null // Override value from parent. We don't have magic sprites.
|
||||
pixel_y = 0 // Override value from parent.
|
||||
|
||||
/obj/item/holder/micro/examine(var/mob/user)
|
||||
for(var/mob/living/M in contents)
|
||||
M.examine(user)
|
||||
|
||||
/obj/item/holder/MouseDrop(mob/M as mob)
|
||||
..()
|
||||
if(M != usr) return
|
||||
if(usr == src) return
|
||||
if(!Adjacent(usr)) return
|
||||
if(istype(M,/mob/living/silicon/ai)) return
|
||||
for(var/mob/living/carbon/human/O in contents)
|
||||
O.show_inv(usr)
|
||||
|
||||
/obj/item/holder/micro/attack_self(var/mob/living/user)
|
||||
for(var/mob/living/carbon/human/M in contents)
|
||||
M.help_shake_act(user)
|
||||
|
||||
/obj/item/holder/micro/update_state()
|
||||
// If any items have been dropped by contained mob, drop them to floor.
|
||||
for(var/obj/O in contents)
|
||||
O.forceMove(get_turf(src))
|
||||
..()
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
//these aren't defines so they can stay in this file
|
||||
GLOBAL_VAR_CONST(SIZESCALE_HUGE, 2)
|
||||
GLOBAL_VAR_CONST(SIZESCALE_BIG, 1.5)
|
||||
GLOBAL_VAR_CONST(SIZESCALE_NORMAL, 1)
|
||||
GLOBAL_VAR_CONST(SIZESCALE_SMALL, 0.85)
|
||||
GLOBAL_VAR_CONST(SIZESCALE_TINY, 0.60)
|
||||
|
||||
GLOBAL_VAR_CONST(SIZESCALE_A_HUGEBIG, (GLOB.SIZESCALE_HUGE + GLOB.SIZESCALE_BIG) / 2)
|
||||
GLOBAL_VAR_CONST(SIZESCALE_A_BIGNORMAL, (GLOB.SIZESCALE_BIG + GLOB.SIZESCALE_NORMAL) / 2)
|
||||
GLOBAL_VAR_CONST(SIZESCALE_A_NORMALSMALL,(GLOB.SIZESCALE_NORMAL + GLOB.SIZESCALE_SMALL) / 2)
|
||||
GLOBAL_VAR_CONST(SIZESCALE_A_SMALLTINY,(GLOB.SIZESCALE_SMALL + GLOB.SIZESCALE_TINY) / 2)
|
||||
*/
|
||||
// Adding needed defines to /mob/living
|
||||
// Note: Polaris had this on /mob/living/carbon/human We need it higher up for animals and stuff.
|
||||
/mob/living
|
||||
var/size_multiplier = 1 //multiplier for the mob's icon size
|
||||
|
||||
// Define holder_type on types we want to be scoop-able
|
||||
//mob/living/carbon/human
|
||||
// holder_type = /obj/item/holder/micro
|
||||
|
||||
/**
|
||||
* Scale up the size of a mob's icon by the size_multiplier.
|
||||
* NOTE: mob/living/carbon/human/update_transform() has a more complicated system and
|
||||
* is already applying this transform. BUT, it does not call ..()
|
||||
* as long as that is true, we should be fine. If that changes we need to
|
||||
* re-evaluate.
|
||||
*/
|
||||
/mob/living/update_transform()
|
||||
ASSERT(!iscarbon(src))
|
||||
var/matrix/M = matrix()
|
||||
M.Scale(size_multiplier)
|
||||
M.Translate(0, 16*(size_multiplier-1))
|
||||
src.transform = M
|
||||
|
||||
/**
|
||||
* Get the effective size of a mob.
|
||||
* Currently this is based only on size_multiplier for micro/macro stuff,
|
||||
* but in the future we may also incorporate the "mob_size", so that
|
||||
* a macro mouse is still only effectively "normal" or a micro dragon is still large etc.
|
||||
*/
|
||||
/mob/living/proc/get_effective_size()
|
||||
return src.size_multiplier
|
||||
|
||||
/**
|
||||
* Resizes the mob immediately to the desired mod, animating it growing/shrinking.
|
||||
* It can be used by anything that calls it.
|
||||
*/
|
||||
/mob/living/proc/sizescale(var/new_size)
|
||||
var/matrix/sizescale = matrix() // Defines the matrix to change the player's size
|
||||
sizescale.Scale(new_size) //Change the size of the matrix
|
||||
|
||||
if(new_size >= SIZESCALE_NORMAL)
|
||||
sizescale.Translate(0, -1 * (1 - new_size) * 16) //Move the player up in the tile so their feet align with the bottom
|
||||
|
||||
animate(src, transform = sizescale, time = 5) //Animate the player resizing
|
||||
size_multiplier = new_size //Change size_multiplier so that other items can interact with them
|
||||
|
||||
/*
|
||||
* Verb proc for a command that lets players change their size OOCly.
|
||||
* Ace was here! Redid this a little so we'd use math for shrinking characters. This is the old code.
|
||||
|
||||
/mob/living/proc/set_size()
|
||||
set name = "Set Character Size"
|
||||
set category = "Vore"
|
||||
var/nagmessage = "DO NOT ABUSE THESE COMMANDS. They are not here for you to play with. \
|
||||
We were originally going to remove them but kept them for popular demand. \
|
||||
Do not abuse their existence outside of ERP scenes where they apply, \
|
||||
or reverting OOCly unwanted changes like someone lolshooting the crew with a shrink ray. -Ace"
|
||||
|
||||
var/size_name = input(nagmessage, "Pick a Size") in player_sizes_list
|
||||
if (size_name && player_sizes_list[size_name])
|
||||
src.sizescale(player_sizes_list[size_name])
|
||||
message_admins("[key_name(src)] used the sizescale command in-game to be [size_name]. \
|
||||
([src ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>" : "null"])")
|
||||
|
||||
/** Add the set_size() proc to usable verbs. */
|
||||
/hook/living_new/proc/sizescale_setup(mob/living/M)
|
||||
M.verbs += /mob/living/proc/set_size
|
||||
return 1
|
||||
|
||||
|
||||
* Attempt to scoop up this mob up into M's hands, if the size difference is large enough.
|
||||
* @return false if normal code should continue, 1 to prevent normal code.
|
||||
|
||||
/mob/living/proc/attempt_to_scoop(var/mob/living/carbon/human/M)
|
||||
if(!istype(M))
|
||||
return 0;
|
||||
if(M.buckled)
|
||||
usr << "<span class='notice'>You have to unbuckle \the [M] before you pick them up.</span>"
|
||||
return 0
|
||||
if(M.get_effective_size() - src.get_effective_size() >= 0.75)
|
||||
var/obj/item/holder/m_holder = get_scooped(M)
|
||||
if (m_holder)
|
||||
return 1
|
||||
else
|
||||
return 0; // Unable to scoop, let other code run
|
||||
*/
|
||||
/*
|
||||
* Handle bumping into someone with helping intent.
|
||||
* Called from /mob/living/Bump() in the 'brohugs all around' section.
|
||||
* @return false if normal code should continue, 1 to prevent normal code.
|
||||
* // TODO - can the now_pushing = 0 be moved up? What does it do anyway?
|
||||
*/
|
||||
/mob/living/proc/handle_micro_bump_helping(var/mob/living/tmob)
|
||||
if(src.get_effective_size() <= SIZESCALE_A_SMALLTINY && tmob.get_effective_size() <= SIZESCALE_A_SMALLTINY)
|
||||
// Both small! Go ahead and
|
||||
now_pushing = 0
|
||||
src.forceMove(tmob.loc)
|
||||
return 1
|
||||
if(abs(src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
|
||||
now_pushing = 0
|
||||
src.forceMove(tmob.loc)
|
||||
|
||||
if(src.get_effective_size() > tmob.get_effective_size())
|
||||
/* var/mob/living/carbon/human/tmob = src
|
||||
if(istype(tmob) && istype(tmob.tail_style, /datum/sprite_accessory/tail/taur/naga))
|
||||
src << "You carefully slither around [tmob]."
|
||||
M << "[src]'s huge tail slithers past beside you!"
|
||||
else
|
||||
*/
|
||||
src.forceMove(tmob.loc)
|
||||
src << "You carefully step over [tmob]."
|
||||
tmob << "[src] steps over you carefully!"
|
||||
if(tmob.get_effective_size() > src.get_effective_size())
|
||||
/* var/mob/living/carbon/human/M = M
|
||||
if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
|
||||
src << "You jump over [M]'s thick tail."
|
||||
M << "[src] bounds over your tail."
|
||||
else
|
||||
*/
|
||||
src.forceMove(tmob.loc)
|
||||
src << "You run between [tmob]'s legs."
|
||||
tmob << "[src] runs between your legs."
|
||||
return 1
|
||||
|
||||
/**
|
||||
* Handle bumping into someone without mutual help intent.
|
||||
* Called from /mob/living/Bump()
|
||||
* NW was here, adding even more options for stomping!
|
||||
*
|
||||
* @return false if normal code should continue, 1 to prevent normal code.
|
||||
*/
|
||||
/mob/living/proc/handle_micro_bump_other(var/mob/living/tmob)
|
||||
ASSERT(isliving(tmob)) // Baby don't hurt me
|
||||
|
||||
if(src.a_intent == "disarm" && src.canmove && !src.buckled)
|
||||
// If bigger than them by at least 0.75, move onto them and print message.
|
||||
if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
|
||||
now_pushing = 0
|
||||
src.forceMove(tmob.loc)
|
||||
tmob.Stun(4)
|
||||
/*
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(istype(H) && istype(H.tail_style, /datum/sprite_accessory/tail/taur/naga))
|
||||
src << "You carefully squish [tmob] under your tail!"
|
||||
tmob << "[src] pins you under their tail!"
|
||||
else
|
||||
*/
|
||||
src << "You pin [tmob] beneath your foot!"
|
||||
tmob << "[src] pins you beneath their foot!"
|
||||
return 1
|
||||
|
||||
if(src.a_intent == "harm" && src.canmove && !src.buckled)
|
||||
if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
|
||||
now_pushing = 0
|
||||
src.forceMove(tmob.loc)
|
||||
tmob.adjustStaminaLoss(35)
|
||||
tmob.adjustBruteLoss(5)
|
||||
/* var/mob/living/carbon/human/M = src
|
||||
if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
|
||||
src << "You steamroller over [tmob] with your heavy tail!"
|
||||
tmob << "[src] ploughs you down mercilessly with their heavy tail!"
|
||||
else
|
||||
*/
|
||||
src << "You bring your foot down heavily upon [tmob]!"
|
||||
tmob << "[src] steps carelessly on your body!"
|
||||
return 1
|
||||
|
||||
// until I figure out grabbing micros with the godawful pull code...
|
||||
if(src.a_intent == "grab" && src.canmove && !src.buckled)
|
||||
if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
|
||||
now_pushing = 0
|
||||
tmob.adjustStaminaLoss(15)
|
||||
src.forceMove(tmob.loc)
|
||||
src << "You press [tmob] beneath your foot!"
|
||||
tmob << "[src] presses you beneath their foot!"
|
||||
/*
|
||||
var/mob/living/carbon/human/M = src
|
||||
if(istype(M) && !M.shoes)
|
||||
// User is a human (capable of scooping) and not wearing shoes! Scoop into foot slot!
|
||||
equip_to_slot_if_possible(tmob.get_scooped(M), slot_shoes, 0, 1)
|
||||
if(istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
|
||||
src << "You wrap up [tmob] with your powerful tail!"
|
||||
tmob << "[src] binds you with their powerful tail!"
|
||||
else
|
||||
src << "You clench your toes around [tmob]'s body!"
|
||||
tmob << "[src] grabs your body with their toes!"
|
||||
else if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
|
||||
src << "You carefully squish [tmob] under your tail!"
|
||||
tmob << "[src] pins you under their tail!"
|
||||
else
|
||||
src << "You pin [tmob] beneath your foot!"
|
||||
tmob << "[src] pins you beneath their foot!"
|
||||
return 1
|
||||
*/
|
||||
@@ -0,0 +1,115 @@
|
||||
|
||||
////////////////////////////
|
||||
/// shrinking serum ///
|
||||
////////////////////////////
|
||||
|
||||
/datum/reagent/medicine/macrocillin
|
||||
name = "Macrocillin"
|
||||
id = "macrocillin"
|
||||
description = "Glowing yellow liquid."
|
||||
reagent_state = LIQUID
|
||||
color = "#FFFF00" // rgb: 255, 255, 0
|
||||
overdose_threshold = 20
|
||||
|
||||
/datum/reagent/medicine/macrocillin/on_mob_life(mob/living/M, method=INGEST)
|
||||
for(var/size in list(SIZESCALE_SMALL, SIZESCALE_NORMAL, SIZESCALE_BIG, SIZESCALE_HUGE))
|
||||
if(M.size_multiplier < size)
|
||||
M.sizescale(size)
|
||||
M << "<font color='green'>You grow!</font>"
|
||||
break
|
||||
if(M.reagents.has_reagent("macrocillin"))
|
||||
M.reagents.remove_reagent("macrocillin", 20)
|
||||
..()
|
||||
|
||||
/datum/reagent/medicine/microcillin
|
||||
name = "Microcillin"
|
||||
id = "microcillin"
|
||||
description = "Murky purple liquid."
|
||||
reagent_state = LIQUID
|
||||
color = "#800080"
|
||||
overdose_threshold = 20
|
||||
|
||||
/datum/reagent/microcillin/on_mob_life(mob/living/M, method=INGEST)
|
||||
for(var/size in list(SIZESCALE_BIG, SIZESCALE_NORMAL, SIZESCALE_SMALL, SIZESCALE_TINY))
|
||||
if(M.size_multiplier > size)
|
||||
M.sizescale(size)
|
||||
M << "<span class='alert'>You shrink!</span>"
|
||||
break;
|
||||
if(M.reagents.has_reagent("microcillin"))
|
||||
M.reagents.remove_reagent("microcillin", 20)
|
||||
|
||||
..()
|
||||
|
||||
/datum/reagent/medicine/normalcillin
|
||||
name = "Normalcillin"
|
||||
id = "normalcillin"
|
||||
description = "Translucent cyan liquid."
|
||||
reagent_state = LIQUID
|
||||
color = "#00FFFF"
|
||||
overdose_threshold = 20
|
||||
|
||||
/datum/reagent/medicine/normalcillin/on_mob_life(mob/living/M, method=INGEST)
|
||||
if(M.size_multiplier > SIZESCALE_BIG)
|
||||
M.sizescale(SIZESCALE_BIG)
|
||||
M << "<span class='alert'>You shrink!</span>"
|
||||
else if(M.size_multiplier > SIZESCALE_NORMAL)
|
||||
M.sizescale(SIZESCALE_NORMAL)
|
||||
M << "<span class='alert'>You shrink!</span>"
|
||||
else if(M.size_multiplier < SIZESCALE_NORMAL)
|
||||
M.sizescale(SIZESCALE_NORMAL)
|
||||
M << "<font color='green'>You grow!</font>"
|
||||
else if(M.size_multiplier < SIZESCALE_SMALL)
|
||||
M.sizescale(SIZESCALE_SMALL)
|
||||
M << "<font color='green'>You grow!</font>"
|
||||
|
||||
if(M.reagents.has_reagent("normalcillin"))
|
||||
M.reagents.remove_reagent("normalcillin", 20)
|
||||
..()
|
||||
|
||||
|
||||
/datum/reagent/medicine/sizeoxadone
|
||||
name = "Sizeoxadone"
|
||||
id = "sizeoxadone"
|
||||
description = "A volatile liquid used as a precursor to size-altering chemicals. Causes dizziness if taken unprocessed."
|
||||
reagent_state = LIQUID
|
||||
color = "#1E90FF"
|
||||
overdose_threshold = 30
|
||||
metabolization_rate = 0.8 * REAGENTS_METABOLISM
|
||||
|
||||
/datum/reagent/sizeoxadone/on_mob_life(var/mob/living/carbon/M, var/removed)
|
||||
if(M.hallucination < volume && prob(20))
|
||||
M.hallucination += 5
|
||||
if(!M.confused) M.confused = 1
|
||||
M.confused = max(M.confused, 20)
|
||||
return
|
||||
|
||||
/datum/reagent/medicine/sizeoxadone/overdose_process(mob/living/M)
|
||||
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1)
|
||||
M.adjustToxLoss(1)
|
||||
..()
|
||||
. = 1
|
||||
|
||||
////////////////////////// Anti-Noms Drugs //////////////////////////
|
||||
|
||||
/datum/reagent/medicine/ickypak
|
||||
name = "Ickypak"
|
||||
id = "ickypak"
|
||||
description = "A foul-smelling green liquid, for inducing muscle contractions to expel accidentally ingested things."
|
||||
reagent_state = LIQUID
|
||||
color = "#0E900E"
|
||||
metabolization_rate = 0.25 * REAGENTS_METABOLISM
|
||||
|
||||
/datum/reagent/medicine/ickypak/on_mob_life(var/mob/living/M, method=INGEST)
|
||||
..()
|
||||
if(M.hallucination < volume && prob(20))
|
||||
M.hallucination += 5
|
||||
M.adjustToxLoss(-5)
|
||||
|
||||
for(var/I in M.vore_organs)
|
||||
var/datum/belly/B = M.vore_organs[I]
|
||||
for(var/atom/movable/A in B.internal_contents)
|
||||
if(prob(55))
|
||||
playsound(M, 'sound/effects/splat.ogg', 50, 1)
|
||||
B.release_vore_contents(A)
|
||||
..()
|
||||
. = 1
|
||||
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// Size Gun
|
||||
//
|
||||
/*
|
||||
/obj/item/gun/energy/sizegun
|
||||
name = "shrink ray"
|
||||
desc = "A highly advanced ray gun with two settings: Shrink and Grow. Warning: Do not insert into mouth."
|
||||
icon = 'icons/obj/gun_vr.dmi'
|
||||
icon_state = "sizegun-shrink100" // Someone can probably do better. -Ace
|
||||
item_state = null //so the human update icon uses the icon_state instead
|
||||
fire_sound = 'sound/weapons/wave.ogg'
|
||||
charge_cost = 100
|
||||
projectile_type = /obj/item/projectile/beam/shrinklaser
|
||||
modifystate = "sizegun-shrink"
|
||||
selfcharge = EGUN_SELFCHARGE
|
||||
firemodes = list(
|
||||
list(mode_name = "grow",
|
||||
projectile_type = /obj/item/projectile/beam/growlaser,
|
||||
modifystate = "sizegun-grow",
|
||||
fire_sound = 'sound/weapons/pulse3.ogg'
|
||||
),
|
||||
list(mode_name = "shrink",
|
||||
projectile_type = /obj/item/projectile/beam/shrinklaser,
|
||||
modifystate = "sizegun-shrink",
|
||||
fire_sound = 'sound/weapons/wave.ogg'
|
||||
))
|
||||
|
||||
//
|
||||
// Beams for size gun
|
||||
//
|
||||
// tracers TBD
|
||||
|
||||
/obj/item/projectile/beam/shrinklaser
|
||||
name = "shrink beam"
|
||||
icon_state = "xray"
|
||||
nodamage = 1
|
||||
damage = 0
|
||||
check_armour = "laser"
|
||||
|
||||
muzzle_type = /obj/effect/projectile/xray/muzzle
|
||||
tracer_type = /obj/effect/projectile/xray/tracer
|
||||
impact_type = /obj/effect/projectile/xray/impact
|
||||
|
||||
/obj/item/projectile/beam/shrinklaser/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living))
|
||||
var/mob/living/M = target
|
||||
switch(M.size_multiplier)
|
||||
if(SIZESCALE_HUGE to INFINITY)
|
||||
M.sizescale(SIZESCALE_BIG)
|
||||
if(SIZESCALE_BIG to SIZESCALE_HUGE)
|
||||
M.sizescale(SIZESCALE_NORMAL)
|
||||
if(SIZESCALE_NORMAL to SIZESCALE_BIG)
|
||||
M.sizescale(SIZESCALE_SMALL)
|
||||
if((0 - INFINITY) to SIZESCALE_NORMAL)
|
||||
M.sizescale(SIZESCALE_TINY)
|
||||
M.update_transform()
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/beam/growlaser
|
||||
name = "growth beam"
|
||||
icon_state = "bluelaser"
|
||||
nodamage = 1
|
||||
damage = 0
|
||||
check_armour = "laser"
|
||||
|
||||
muzzle_type = /obj/effect/projectile/laser_blue/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_blue/tracer
|
||||
impact_type = /obj/effect/projectile/laser_blue/impact
|
||||
|
||||
/obj/item/projectile/beam/growlaser/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living))
|
||||
var/mob/living/M = target
|
||||
switch(M.size_multiplier)
|
||||
if(SIZESCALE_BIG to SIZESCALE_HUGE)
|
||||
M.sizescale(SIZESCALE_HUGE)
|
||||
if(SIZESCALE_NORMAL to SIZESCALE_BIG)
|
||||
M.sizescale(SIZESCALE_BIG)
|
||||
if(SIZESCALE_SMALL to SIZESCALE_NORMAL)
|
||||
M.sizescale(SIZESCALE_NORMAL)
|
||||
if((0 - INFINITY) to SIZESCALE_TINY)
|
||||
M.sizescale(SIZESCALE_SMALL)
|
||||
M.update_transform()
|
||||
return 1
|
||||
*/
|
||||
|
||||
datum/design/sizeray
|
||||
name = "Size Ray"
|
||||
desc = "Abuse bluespace tech to alter living matter scale."
|
||||
id = "sizeray"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 1000, MAT_GLASS = 1000, MAT_DIAMOND = 2500, MAT_URANIUM = 2500, MAT_TITANIUM = 1000)
|
||||
build_path = /obj/item/gun/energy/laser/sizeray
|
||||
category = list("Weapons")
|
||||
|
||||
/obj/item/projectile/sizeray
|
||||
name = "sizeray beam"
|
||||
icon_state = "omnilaser"
|
||||
hitsound = null
|
||||
damage = 0
|
||||
damage_type = STAMINA
|
||||
flag = "laser"
|
||||
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
|
||||
|
||||
/obj/item/projectile/sizeray/shrinkray
|
||||
icon_state="bluelaser"
|
||||
|
||||
/obj/item/projectile/sizeray/growthray
|
||||
icon_state="laser"
|
||||
|
||||
/obj/item/projectile/sizeray/shrinkray/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living))
|
||||
var/mob/living/M = target
|
||||
switch(M.size_multiplier)
|
||||
if(SIZESCALE_HUGE to INFINITY)
|
||||
M.sizescale(SIZESCALE_BIG)
|
||||
if(SIZESCALE_BIG to SIZESCALE_HUGE)
|
||||
M.sizescale(SIZESCALE_NORMAL)
|
||||
if(SIZESCALE_NORMAL to SIZESCALE_BIG)
|
||||
M.sizescale(SIZESCALE_SMALL)
|
||||
if((0 - INFINITY) to SIZESCALE_NORMAL)
|
||||
M.sizescale(SIZESCALE_TINY)
|
||||
M.update_transform()
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/sizeray/growthray/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living))
|
||||
var/mob/living/M = target
|
||||
switch(M.size_multiplier)
|
||||
if(SIZESCALE_BIG to SIZESCALE_HUGE)
|
||||
M.sizescale(SIZESCALE_HUGE)
|
||||
if(SIZESCALE_NORMAL to SIZESCALE_BIG)
|
||||
M.sizescale(SIZESCALE_BIG)
|
||||
if(SIZESCALE_SMALL to SIZESCALE_NORMAL)
|
||||
M.sizescale(SIZESCALE_NORMAL)
|
||||
if((0 - INFINITY) to SIZESCALE_TINY)
|
||||
M.sizescale(SIZESCALE_SMALL)
|
||||
M.update_transform()
|
||||
return 1
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/growthray
|
||||
projectile_type = /obj/item/projectile/sizeray/growthray
|
||||
select_name = "Growth"
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/shrinkray
|
||||
projectile_type = /obj/item/projectile/sizeray/shrinkray
|
||||
select_name = "Shrink"
|
||||
|
||||
|
||||
//Gun here
|
||||
/obj/item/gun/energy/laser/sizeray
|
||||
name = "size ray"
|
||||
icon_state = "bluetag"
|
||||
desc = "Size manipulator using bluespace breakthroughs."
|
||||
item_state = null //so the human update icon uses the icon_state instead.
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray, /obj/item/ammo_casing/energy/laser/growthray)
|
||||
selfcharge = EGUN_SELFCHARGE
|
||||
charge_delay = 5
|
||||
ammo_x_offset = 2
|
||||
clumsy_check = 1
|
||||
|
||||
attackby(obj/item/W, mob/user)
|
||||
if(W==src)
|
||||
if(icon_state=="bluetag")
|
||||
icon_state="redtag"
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/laser/growthray)
|
||||
else
|
||||
icon_state="bluetag"
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray)
|
||||
return ..()
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
This file is for jamming single-line procs into Polaris procs.
|
||||
It will prevent runtimes and allow their code to run if these fail.
|
||||
It will also log when we mess up our code rather than making it vague.
|
||||
|
||||
Call it at the top of a stock proc with...
|
||||
|
||||
if(attempt_vr(object,proc to call,args)) return
|
||||
|
||||
...if you are replacing an entire proc.
|
||||
|
||||
The proc you're attemping should return nonzero values on success.
|
||||
*/
|
||||
|
||||
/proc/attempt_vr(callon, procname, list/args=null)
|
||||
try
|
||||
if(!callon || !procname)
|
||||
CRASH("attempt_vr: Invalid obj/proc: [callon]/[procname]")
|
||||
return 0
|
||||
|
||||
var/result = call(callon,procname)(arglist(args))
|
||||
|
||||
return result
|
||||
|
||||
catch(var/exception/e)
|
||||
CRASH("attempt_vr runtimed when calling [procname] on [callon].")
|
||||
CRASH("attempt_vr catch: [e] on [e.file]:[e.line]")
|
||||
return 0
|
||||
|
||||
/*
|
||||
This is the _vr version of calling hooks.
|
||||
It's meant to have different messages, and also the try/catch block.
|
||||
For when you want hooks and want to know when you ruin everything,
|
||||
vs when Polaris ruins everything.
|
||||
|
||||
Call it at the top of a stock proc with...
|
||||
|
||||
if(hook_vr(proc,args)) return
|
||||
|
||||
...if you are replacing an entire proc.
|
||||
|
||||
The hooks you're calling should return nonzero values on success.
|
||||
*/
|
||||
/proc/hook_vr(hook, list/args=null)
|
||||
try
|
||||
var/hook_path = text2path("/hook/[hook]")
|
||||
if(!hook_path)
|
||||
CRASH("hook_vr: Invalid hook '/hook/[hook]' called.")
|
||||
return 0
|
||||
|
||||
var/caller = new hook_path
|
||||
var/status = 1
|
||||
for(var/P in typesof("[hook_path]/proc"))
|
||||
if(!call(caller, P)(arglist(args)))
|
||||
CRASH("hook_vr: Hook '[P]' failed or runtimed.")
|
||||
status = 0
|
||||
|
||||
return status
|
||||
|
||||
catch(var/exception/e)
|
||||
CRASH("hook_vr itself failed or runtimed. Exception below.")
|
||||
CRASH("hook_vr catch: [e] on [e.file]:[e.line]")
|
||||
Reference in New Issue
Block a user