@@ -0,0 +1,66 @@
|
||||
// Overhauled vore system
|
||||
#define DM_HOLD "Hold"
|
||||
#define DM_DIGEST "Digest"
|
||||
#define DM_HEAL "Heal"
|
||||
#define DM_DIGESTF "Fast Digest"
|
||||
|
||||
#define VORE_STRUGGLE_EMOTE_CHANCE 40
|
||||
|
||||
// Stance for hostile mobs to be in while devouring someone.
|
||||
#define HOSTILE_STANCE_EATING 99
|
||||
|
||||
|
||||
var/global/list/player_sizes_list = list("Macro" = SIZESCALE_HUGE, "Big" = SIZESCALE_BIG, "Normal" = SIZESCALE_NORMAL, "Small" = SIZESCALE_SMALL, "Tiny" = SIZESCALE_TINY)
|
||||
/* // moved to sound.dm
|
||||
|
||||
var/global/list/digestion_sounds = list(
|
||||
'sound/vore/digest1.ogg',
|
||||
'sound/vore/digest2.ogg',
|
||||
'sound/vore/digest3.ogg',
|
||||
'sound/vore/digest4.ogg',
|
||||
'sound/vore/digest5.ogg',
|
||||
'sound/vore/digest6.ogg',
|
||||
'sound/vore/digest7.ogg',
|
||||
'sound/vore/digest8.ogg',
|
||||
'sound/vore/digest9.ogg',
|
||||
'sound/vore/digest10.ogg',
|
||||
'sound/vore/digest11.ogg',
|
||||
'sound/vore/digest12.ogg')
|
||||
|
||||
var/global/list/death_sounds = list(
|
||||
'sound/vore/death1.ogg',
|
||||
'sound/vore/death2.ogg',
|
||||
'sound/vore/death3.ogg',
|
||||
'sound/vore/death4.ogg',
|
||||
'sound/vore/death5.ogg',
|
||||
'sound/vore/death6.ogg',
|
||||
'sound/vore/death7.ogg',
|
||||
'sound/vore/death8.ogg',
|
||||
'sound/vore/death9.ogg',
|
||||
'sound/vore/death10.ogg') */
|
||||
|
||||
var/global/list/vore_sounds = list(
|
||||
"Gulp" = 'sound/vore/gulp.ogg',
|
||||
"Insert" = 'sound/vore/insert.ogg',
|
||||
"Insertion1" = 'sound/vore/insertion1.ogg',
|
||||
"Insertion2" = 'sound/vore/insertion2.ogg',
|
||||
"Insertion3" = 'sound/vore/insertion3.ogg',
|
||||
"Schlorp" = 'sound/vore/schlorp.ogg',
|
||||
"Squish1" = 'sound/vore/squish1.ogg',
|
||||
"Squish2" = 'sound/vore/squish2.ogg',
|
||||
"Squish3" = 'sound/vore/squish3.ogg',
|
||||
"Squish4" = 'sound/vore/squish4.ogg')
|
||||
/* also moved to sound.dmi
|
||||
var/global/list/struggle_sounds = list(
|
||||
"Squish1" = 'sound/vore/squish1.ogg',
|
||||
"Squish2" = 'sound/vore/squish2.ogg',
|
||||
"Squish3" = 'sound/vore/squish3.ogg',
|
||||
"Squish4" = 'sound/vore/squish4.ogg')
|
||||
|
||||
/proc/log_debug(text)
|
||||
if (config.log_debug)
|
||||
diary << "\[[time_stamp()]]DEBUG: [text][log_end]"
|
||||
|
||||
for(var/client/C in admins)
|
||||
if(C.prefs.toggles & CHAT_DEBUGLOGS)
|
||||
C << "DEBUG: [text]" */
|
||||
@@ -347,6 +347,8 @@ GLOBAL_LIST(external_rsc_urls)
|
||||
if(!tooltips)
|
||||
tooltips = new /datum/tooltip(src)
|
||||
|
||||
hook_vr("client_new",list(src))
|
||||
|
||||
//////////////
|
||||
//DISCONNECT//
|
||||
//////////////
|
||||
|
||||
@@ -1535,8 +1535,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if("load")
|
||||
load_preferences()
|
||||
load_character()
|
||||
attempt_vr(parent.prefs_vr,"load_vore","")
|
||||
|
||||
if("changeslot")
|
||||
attempt_vr(parent.prefs_vr,"load_vore","")
|
||||
if(!load_character(text2num(href_list["num"])))
|
||||
random_character()
|
||||
real_name = random_unique_name(gender)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
//File isn't currently being used.
|
||||
/datum/preferences
|
||||
var/biological_gender = MALE
|
||||
var/identifying_gender = MALE
|
||||
|
||||
/datum/preferences/proc/set_biological_gender(var/gender)
|
||||
biological_gender = gender
|
||||
identifying_gender = gender
|
||||
@@ -257,6 +257,9 @@
|
||||
msg += "[t_He] looks like a drunken mess.\n"
|
||||
if(91.01 to INFINITY)
|
||||
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
|
||||
for (var/I in src.vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
msg += B.get_examine_msg()
|
||||
|
||||
msg += "</span>"
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/mob/living/carbon/human/proc/examine_nutrition()
|
||||
var/message = ""
|
||||
var/nutrition_examine = round(nutrition)
|
||||
var/t_He = "It" //capitalised for use at the start of each line.
|
||||
var/t_His = "Its"
|
||||
var/t_his = "its"
|
||||
var/t_is = "is"
|
||||
var/t_has = "has"
|
||||
switch(gender)
|
||||
if(MALE)
|
||||
t_He = "He"
|
||||
t_his = "his"
|
||||
t_His = "His"
|
||||
if(FEMALE)
|
||||
t_He = "She"
|
||||
t_his = "her"
|
||||
t_His = "Her"
|
||||
if(PLURAL)
|
||||
t_He = "They"
|
||||
t_his = "their"
|
||||
t_His = "Their"
|
||||
t_is = "are"
|
||||
t_has = "have"
|
||||
if(NEUTER)
|
||||
t_He = "It"
|
||||
t_his = "its"
|
||||
t_His = "Its"
|
||||
switch(nutrition_examine)
|
||||
if(0 to 49)
|
||||
message = "<span class='warning'>[t_He] [t_is] starving! You can hear [t_his] stomach snarling from across the room!</span>\n"
|
||||
if(50 to 99)
|
||||
message = "<span class='warning'>[t_He] [t_is] extremely hungry. A deep growl occasionally rumbles from [t_his] empty stomach.</span>\n"
|
||||
if(100 to 499)
|
||||
return message //Well that's pretty normal, really.
|
||||
if(500 to 864) // Fat.
|
||||
message = "[t_He] [t_has] a stuffed belly, bloated fat and round from eating too much.\n"
|
||||
if(1200 to 1934) // One person fully digested.
|
||||
message = "<span class='warning'>[t_He] [t_is] sporting a large, round, sagging stomach. It's contains at least their body weight worth of glorping slush.</span>\n"
|
||||
if(1935 to 3004) // Two people.
|
||||
message = "<span class='warning'>[t_He] [t_is] engorged with a huge stomach that sags and wobbles as they move. [t_He] must have consumed at least twice their body weight. It looks incredibly soft.</span>\n"
|
||||
if(3005 to 4074) // Three people.
|
||||
message = "<span class='warning'>[t_His] stomach is firmly packed with digesting slop. [t_He] must have eaten at least a few times worth their body weight! It looks hard for them to stand, and [t_his] gut jiggles when they move.</span>\n"
|
||||
if(4075 to 10000) // Four or more people.
|
||||
message = "<span class='warning'>[t_He] [t_is] so absolutely stuffed that you aren't sure how it's possible to move. [t_He] can't seem to swell any bigger. The surface of [t_his] belly looks sorely strained!</span>\n"
|
||||
return message
|
||||
|
||||
/mob/living/carbon/human/proc/examine_bellies()
|
||||
var/message = ""
|
||||
|
||||
for (var/I in src.vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
message += B.get_examine_msg()
|
||||
|
||||
return message
|
||||
@@ -160,8 +160,8 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
|
||||
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (disabilities & FAT) && ismonkey(pulling))
|
||||
devour_mob(pulling)
|
||||
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
|
||||
vore_attack(user, pulling)
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
return
|
||||
if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
|
||||
return
|
||||
if(ismob(loc))
|
||||
return
|
||||
|
||||
|
||||
var/datum/gas_mixture/environment
|
||||
if(loc)
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
//stuff in the stomach
|
||||
handle_stomach()
|
||||
|
||||
// Vore code for belly processes
|
||||
handle_internal_contents()
|
||||
|
||||
update_gravity(mob_has_gravity())
|
||||
|
||||
if(machine)
|
||||
|
||||
@@ -550,6 +550,9 @@
|
||||
if(buckled && last_special <= world.time)
|
||||
resist_buckle()
|
||||
|
||||
// climbing out of a gut
|
||||
if(attempt_vr(src,"vore_process_resist",args)) return TRUE
|
||||
|
||||
//Breaking out of a container (Locker, sleeper, cryo...)
|
||||
else if(isobj(loc))
|
||||
var/obj/C = loc
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
|
||||
if("grab")
|
||||
grabbedby(M)
|
||||
if(grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
|
||||
vore_attack(M, pulling)
|
||||
else
|
||||
grabbedby(M)
|
||||
|
||||
if("harm", "disarm")
|
||||
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
GLOB.living_mob_list += src
|
||||
prepare_huds()
|
||||
can_ride_typecache = typecacheof(can_ride_typecache)
|
||||
hook_vr("mob_new",list(src))
|
||||
..()
|
||||
|
||||
/atom/proc/prepare_huds()
|
||||
@@ -110,7 +111,7 @@
|
||||
if(self_message)
|
||||
msg = self_message
|
||||
else
|
||||
if(M.see_invisible<invisibility || (T != loc && T != src))//if src is invisible to us or is inside something (and isn't a turf),
|
||||
if(M.see_invisible<invisibility)//if src is invisible
|
||||
if(blind_message) // then people see blind message if there is one, otherwise nothing.
|
||||
msg = blind_message
|
||||
else
|
||||
|
||||
@@ -0,0 +1,369 @@
|
||||
//
|
||||
// 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/gulp.ogg' // Sound when ingesting someone
|
||||
var/vore_verb = "ingest" // Verb for eating with this in messages
|
||||
var/human_prey_swallow_time = 100 // Time in deciseconds to swallow /mob/living/carbon/human
|
||||
var/nonhuman_prey_swallow_time = 60 // Time in deciseconds to swallow anything else
|
||||
var/emoteTime = 300 // How long between stomach emotes at prey
|
||||
var/digest_brute = 1 // Brute damage per tick in digestion mode
|
||||
var/digest_burn = 3 // 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 = TRUE // Belly can be resisted out of at any time
|
||||
var/escapetime = 200 // Deciseconds, how long to escape this belly
|
||||
var/escapechance = 45 // % Chance of prey beginning to escape if prey struggles.
|
||||
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_DIGESTF) // 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
|
||||
|
||||
// Don't forget to watch your commas at the end of each line if you change these.
|
||||
var/list/struggle_messages_outside = list(
|
||||
"%pred's %belly wobbles with a squirming meal.",
|
||||
"%pred's %belly jostles with movement.",
|
||||
"%pred's %belly briefly swells outward as someone pushes from inside.",
|
||||
"%pred's %belly fidgets with a trapped victim.",
|
||||
"%pred's %belly jiggles with motion from inside.",
|
||||
"%pred's %belly sloshes around.",
|
||||
"%pred's %belly gushes softly.",
|
||||
"%pred's %belly lets out a wet squelch.")
|
||||
|
||||
var/list/struggle_messages_inside = list(
|
||||
"Your useless squirming only causes %pred's slimy %belly to squelch over your body.",
|
||||
"Your struggles only cause %pred's %belly to gush softly around you.",
|
||||
"Your movement only causes %pred's %belly to slosh around you.",
|
||||
"Your motion causes %pred's %belly to jiggle.",
|
||||
"You fidget around inside of %pred's %belly.",
|
||||
"You shove against the walls of %pred's %belly, making it briefly swell outward.",
|
||||
"You jostle %pred's %belly with movement.",
|
||||
"You squirm inside of %pred's %belly, making it wobble around.")
|
||||
|
||||
var/list/digest_messages_owner = list(
|
||||
"You feel %prey's body succumb to your digestive system, which breaks it apart into soft slurry.",
|
||||
"You hear a lewd glorp as your %belly muscles grind %prey into a warm pulp.",
|
||||
"Your %belly lets out a rumble as it melts %prey into sludge.",
|
||||
"You feel a soft gurgle as %prey's body loses form in your %belly. They're nothing but a soft mass of churning slop now.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your thighs.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your rump.",
|
||||
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your belly.",
|
||||
"Your %belly groans as %prey falls apart into a thick soup. You can feel their remains soon flowing deeper into your body to be absorbed.",
|
||||
"Your %belly kneads on every fiber of %prey, softening them down into mush to fuel your next hunt.",
|
||||
"Your %belly churns %prey down into a hot slush. You can feel the nutrients coursing through your digestive track with a series of long, wet glorps.")
|
||||
|
||||
var/list/digest_messages_prey = list(
|
||||
"Your body succumbs to %pred's digestive system, which breaks you apart into soft slurry.",
|
||||
"%pred's %belly lets out a lewd glorp as their muscles grind you into a warm pulp.",
|
||||
"%pred's %belly lets out a rumble as it melts you into sludge.",
|
||||
"%pred feels a soft gurgle as your body loses form in their %belly. You're nothing but a soft mass of churning slop now.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's thighs.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's rump.",
|
||||
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's belly.",
|
||||
"%pred's %belly groans as you fall apart into a thick soup. Your remains soon flow deeper into %pred's body to be absorbed.",
|
||||
"%pred's %belly kneads on every fiber of your body, softening you down into mush to fuel their next hunt.",
|
||||
"%pred's %belly churns you down into a hot slush. Your nutrient-rich remains course through their digestive track with a series of long, wet glorps.")
|
||||
|
||||
var/list/examine_messages = list(
|
||||
"They have something solid in their %belly!",
|
||||
"It looks like they have something in their %belly!")
|
||||
|
||||
//Mostly for being overridden on precreated bellies on mobs. Could be VV'd into
|
||||
//a carbon's belly if someone really wanted. No UI for carbons to adjust this.
|
||||
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
|
||||
var/list/emote_lists = list()
|
||||
|
||||
// Constructor that sets the owning mob
|
||||
/datum/belly/New(var/mob/living/owning_mob)
|
||||
owner = owning_mob
|
||||
|
||||
// Toggle digestion on/off and notify user of the new setting.
|
||||
// If multiple digestion modes are avaliable (i.e. unbirth) then user should be prompted.
|
||||
/datum/belly/proc/toggle_digestion()
|
||||
return
|
||||
|
||||
// Checks if any mobs are present inside the belly
|
||||
// return True if the belly is empty.
|
||||
/datum/belly/proc/is_empty()
|
||||
return internal_contents.len == 0
|
||||
|
||||
// Release all contents of this belly into the owning mob's location.
|
||||
// If that location is another mob, contents are transferred into whichever of its bellies the owning mob is in.
|
||||
// Returns the number of mobs so released.
|
||||
/datum/belly/proc/release_all_contents()
|
||||
if (internal_contents.len == 0)
|
||||
return 0
|
||||
for (var/atom/movable/M in internal_contents)
|
||||
M.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner.
|
||||
internal_contents.Remove(M) // Remove from the belly contents
|
||||
|
||||
var/datum/belly/B = check_belly(owner) // This makes sure that the mob behaves properly if released into another mob
|
||||
if(B)
|
||||
B.internal_contents.Add(M)
|
||||
|
||||
owner.visible_message("<font color='green'><b>[owner] expels everything from their [lowertext(name)]!</b></font>")
|
||||
return TRUE
|
||||
|
||||
// Release a specific atom from the contents of this belly into the owning mob's location.
|
||||
// If that location is another mob, the atom is transferred into whichever of its bellies the owning mob is in.
|
||||
// Returns the number of atoms so released.
|
||||
/datum/belly/proc/release_specific_contents(var/atom/movable/M)
|
||||
if (!(M in internal_contents))
|
||||
return FALSE // They weren't in this belly anyway
|
||||
|
||||
M.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner.
|
||||
src.internal_contents.Add(M) // Remove from the belly contents
|
||||
var/datum/belly/B = check_belly(owner)
|
||||
if(B)
|
||||
B.internal_contents.Add(M)
|
||||
|
||||
owner.visible_message("<font color='green'><b>[owner] expels [M] from their [lowertext(name)]!</b></font>")
|
||||
// owner.regenerate_icons()
|
||||
return TRUE
|
||||
|
||||
// Actually perform the mechanics of devouring the tasty prey.
|
||||
// The purpose of this method is to avoid duplicate code, and ensure that all necessary
|
||||
// steps are taken.
|
||||
/datum/belly/proc/nom_mob(var/mob/prey, var/mob/user)
|
||||
// if (prey.buckled)
|
||||
// prey.buckled.unbuckle_mob()
|
||||
|
||||
prey.forceMove(owner)
|
||||
internal_contents.Add(prey)
|
||||
|
||||
if(inside_flavor)
|
||||
prey << "<span class='notice'><B>[inside_flavor]</B></span>"
|
||||
|
||||
// Get the line that should show up in Examine message if the owner of this belly
|
||||
// is examined. By making this a proc, we not only take advantage of polymorphism,
|
||||
// but can easily make the message vary based on how many people are inside, etc.
|
||||
// Returns a string which shoul be appended to the Examine output.
|
||||
/datum/belly/proc/get_examine_msg()
|
||||
if(internal_contents.len && examine_messages.len)
|
||||
var/formatted_message
|
||||
var/raw_message = pick(examine_messages)
|
||||
|
||||
formatted_message = replacetext(raw_message,"%belly",lowertext(name))
|
||||
|
||||
return("<span class='warning'>[formatted_message]</span><BR>")
|
||||
|
||||
// The next function gets the messages set on the belly, in human-readable format.
|
||||
// This is useful in customization boxes and such. The delimiter right now is \n\n so
|
||||
// in message boxes, this looks nice and is easily delimited.
|
||||
/datum/belly/proc/get_messages(var/type, var/delim = "\n\n")
|
||||
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
|
||||
var/list/raw_messages
|
||||
|
||||
switch(type)
|
||||
if("smo")
|
||||
raw_messages = struggle_messages_outside
|
||||
if("smi")
|
||||
raw_messages = struggle_messages_inside
|
||||
if("dmo")
|
||||
raw_messages = digest_messages_owner
|
||||
if("dmp")
|
||||
raw_messages = digest_messages_prey
|
||||
if("em")
|
||||
raw_messages = examine_messages
|
||||
|
||||
var/messages = list2text(raw_messages,delim)
|
||||
return messages
|
||||
|
||||
// The next function sets the messages on the belly, from human-readable var
|
||||
// replacement strings and linebreaks as delimiters (two \n\n by default).
|
||||
// They also sanitize the messages.
|
||||
/datum/belly/proc/set_messages(var/raw_text, var/type, var/delim = "\n\n")
|
||||
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
|
||||
|
||||
var/list/raw_list = text2list(html_encode(raw_text),delim)
|
||||
if(raw_list.len > 10)
|
||||
raw_list.Cut(11)
|
||||
|
||||
for(var/i = 1, i <= raw_list.len, i++)
|
||||
if(length(raw_list[i]) > 160 || length(raw_list[i]) < 10) //160 is fudged value due to htmlencoding increasing the size
|
||||
raw_list.Cut(i,i)
|
||||
else
|
||||
raw_list[i] = readd_quotes(raw_list[i])
|
||||
//Also fix % sign for var replacement
|
||||
raw_list[i] = replacetext(raw_list[i],"%","%")
|
||||
|
||||
ASSERT(raw_list.len <= 10) //Sanity
|
||||
|
||||
switch(type)
|
||||
if("smo")
|
||||
struggle_messages_outside = raw_list
|
||||
if("smi")
|
||||
struggle_messages_inside = raw_list
|
||||
if("dmo")
|
||||
digest_messages_owner = raw_list
|
||||
if("dmp")
|
||||
digest_messages_prey = raw_list
|
||||
if("em")
|
||||
examine_messages = raw_list
|
||||
|
||||
return
|
||||
|
||||
// Handle the death of a mob via digestion.
|
||||
// Called from the process_Life() methods of bellies that digest prey.
|
||||
// Default implementation calls M.death() and removes from internal contents.
|
||||
// Indigestable items are removed, and M is deleted.
|
||||
/datum/belly/proc/digestion_death(var/mob/living/M)
|
||||
is_full = TRUE
|
||||
internal_contents.Remove(M)
|
||||
|
||||
// If digested prey is also a pred... anyone inside their bellies gets moved up.
|
||||
if (is_vore_predator(M))
|
||||
for (var/bellytype in M.vore_organs)
|
||||
var/datum/belly/belly = M.vore_organs[bellytype]
|
||||
for (var/obj/thing in belly.internal_contents)
|
||||
thing.loc = owner
|
||||
internal_contents.Add(thing)
|
||||
for (var/mob/subprey in belly.internal_contents)
|
||||
subprey.loc = owner
|
||||
internal_contents.Add(subprey)
|
||||
subprey << "As [M] melts away around you, you find yourself in [owner]'s [name]"
|
||||
|
||||
//Drop all items into the belly.
|
||||
for(var/obj/item/W in M)
|
||||
if(!M.dropItemToGround(W))
|
||||
qdel(W)
|
||||
|
||||
message_admins("[key_name(owner)] digested [key_name(M)].")
|
||||
log_attack("[key_name(owner)] digested [key_name(M)].")
|
||||
|
||||
// Delete the digested mob
|
||||
qdel(M)
|
||||
|
||||
//Handle a mob struggling
|
||||
// Called from /mob/living/carbon/relaymove()
|
||||
/datum/belly/proc/relay_resist(var/mob/living/R)
|
||||
if (!(R in internal_contents))
|
||||
return // User is not in this belly, or struggle too soon.
|
||||
|
||||
R.setClickCooldown(50)
|
||||
|
||||
if(owner.stat) //If owner is stat (dead, KO) we can actually escape
|
||||
R << "<span class='warning'>You attempt to climb out of \the [name]. (This will take around [escapetime/10] seconds.)</span>"
|
||||
owner << "<span class='warning'>Someone is attempting to climb out of your [name]!</span>"
|
||||
|
||||
if(do_after(R, escapetime, owner))
|
||||
if((owner.stat || escapable) && (R in internal_contents)) //Can still escape?
|
||||
release_specific_contents(R)
|
||||
return
|
||||
else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
|
||||
return
|
||||
else //Belly became inescapable or mob revived
|
||||
R << "<span class='warning'>Your attempt to escape [name] has failed!</span>"
|
||||
owner << "<span class='notice'>The attempt to escape from your [name] has failed!</span>"
|
||||
return
|
||||
return
|
||||
var/struggle_outer_message = pick(struggle_messages_outside)
|
||||
var/struggle_user_message = pick(struggle_messages_inside)
|
||||
|
||||
struggle_outer_message = replacetext(struggle_outer_message,"%pred",owner)
|
||||
struggle_outer_message = replacetext(struggle_outer_message,"%prey",R)
|
||||
struggle_outer_message = replacetext(struggle_outer_message,"%belly",lowertext(name))
|
||||
|
||||
struggle_user_message = replacetext(struggle_user_message,"%pred",owner)
|
||||
struggle_user_message = replacetext(struggle_user_message,"%prey",R)
|
||||
struggle_user_message = replacetext(struggle_user_message,"%belly",lowertext(name))
|
||||
|
||||
struggle_outer_message = "<span class='alert'>" + struggle_outer_message + "</span>"
|
||||
struggle_user_message = "<span class='alert'>" + struggle_user_message + "</span>"
|
||||
|
||||
// for(var/mob/M in hearers(4, owner))
|
||||
// M.visible_message(struggle_outer_message) // hearable
|
||||
R.visible_message( "<span class='alert'>[struggle_outer_message]</span>", "<span class='alert'>[struggle_user_message]</span>")
|
||||
playsound(R.loc, "struggle_sounds", 50, 0, -5)
|
||||
|
||||
if(escapable && R.a_intent != "help") //If the stomach has escapable enabled and the person is actually trying to kick out
|
||||
R << "<span class='warning'>You attempt to climb out of \the [name].</span>"
|
||||
owner << "<span class='warning'>Someone is attempting to climb out of your [name]!</span>"
|
||||
if(prob(escapechance)) //Let's have it check to see if the prey escapes first.
|
||||
if(do_after(R, escapetime))
|
||||
if((escapable) && (R in internal_contents)) //Does the owner still have escapable enabled?
|
||||
release_specific_contents(R)
|
||||
R << "<span class='warning'>You climb out of \the [name].</span>"
|
||||
owner << "<span class='warning'>[R] climbs out of your [name]!</span>"
|
||||
for(var/mob/M in hearers(4, owner))
|
||||
M.visible_message("<span class='warning'>[R] climbs out of [owner]'s [name]!</span>", 2)
|
||||
return
|
||||
else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
|
||||
return
|
||||
else //Belly became inescapable.
|
||||
R << "<span class='warning'>Your attempt to escape [name] has failed!</span>"
|
||||
owner << "<span class='notice'>The attempt to escape from your [name] has failed!</span>"
|
||||
return
|
||||
|
||||
else //Nothing interesting happened.
|
||||
R << "<span class='warning'>But make no progress in escaping [owner]'s [name].</span>"
|
||||
owner << "<span class='warning'>But appears to be unable to make any progress in escaping your [name].</span>"
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
// Belly copies and then returns the copy
|
||||
// Needs to be updated for any var changes
|
||||
/datum/belly/proc/copy(mob/new_owner)
|
||||
var/datum/belly/dupe = new /datum/belly(new_owner)
|
||||
|
||||
//// Non-object variables
|
||||
dupe.name = name
|
||||
dupe.inside_flavor = inside_flavor
|
||||
dupe.vore_sound = vore_sound
|
||||
dupe.vore_verb = vore_verb
|
||||
dupe.human_prey_swallow_time = human_prey_swallow_time
|
||||
dupe.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
|
||||
dupe.emoteTime = emoteTime
|
||||
dupe.digest_brute = digest_brute
|
||||
dupe.digest_burn = digest_burn
|
||||
dupe.digest_tickrate = digest_tickrate
|
||||
dupe.immutable = immutable
|
||||
dupe.escapable = escapable
|
||||
dupe.escapetime = escapetime
|
||||
|
||||
//// 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,115 @@
|
||||
// Process the predator's effects upon the contents of its belly (i.e digestion/transformation etc)
|
||||
// Called from /mob/living/Life() proc.
|
||||
/datum/belly/proc/process_Life()
|
||||
|
||||
/////////////////////////// Auto-Emotes ///////////////////////////
|
||||
if((digest_mode in emote_lists) && !emotePend)
|
||||
emotePend = TRUE
|
||||
|
||||
spawn(emoteTime)
|
||||
var/list/EL = emote_lists[digest_mode]
|
||||
for(var/mob/living/M in internal_contents)
|
||||
M << "<span class='notice'>[pick(EL)]</span>"
|
||||
src.emotePend = FALSE
|
||||
|
||||
///////////////////////////// DM_HOLD /////////////////////////////
|
||||
if(digest_mode == DM_HOLD)
|
||||
return //Pretty boring, huh
|
||||
|
||||
//////////////////////////// DM_DIGEST ////////////////////////////
|
||||
if(digest_mode == DM_DIGEST)
|
||||
|
||||
if(prob(50))
|
||||
playsound(owner.loc, "digestion_sounds", 50, 0, -5)
|
||||
|
||||
for (var/mob/living/M in internal_contents)
|
||||
//Pref protection!
|
||||
if (!M.digestable)
|
||||
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
|
||||
owner << "<span class='warning'>" + digest_alert_owner + "</span>"
|
||||
M << "<span class='userdanger'>" + digest_alert_prey + "</span>"
|
||||
|
||||
owner.nutrition += 400 // so eating dead mobs gives you *something*.
|
||||
playsound(owner.loc, "death_gurgles", 50, 0, -5)
|
||||
digestion_death(M)
|
||||
owner.update_icons()
|
||||
continue
|
||||
|
||||
|
||||
// Deal digestion damage (and feed the pred)
|
||||
if(!(M.status_flags & GODMODE))
|
||||
M.adjustFireLoss(1)
|
||||
owner.nutrition += 1
|
||||
return
|
||||
|
||||
//////////////////////////// DM_DIGESTF ////////////////////////////
|
||||
if(digest_mode == DM_DIGESTF)
|
||||
|
||||
if(prob(50))
|
||||
playsound(owner.loc, "digestion_sounds", 55, 0, -3) //slightly louder 'cuz heavier gurgles
|
||||
|
||||
for (var/mob/living/M in internal_contents)
|
||||
//Pref protection!
|
||||
if (!M.digestable)
|
||||
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
|
||||
owner << "<span class='warning'>" + digest_alert_owner + "</span>"
|
||||
M << "<span class='userdanger'>" + digest_alert_prey + "</span>"
|
||||
M.visible_message("<span class='userdanger'>[digest_alert_owner]</span>", "<span class='warning'>[digest_alert_prey]</span>",
|
||||
"<span class='notice'>You watch as [owner]'s form lose its additions.</span>")
|
||||
owner.nutrition += 400 // so eating dead mobs gives you *something*.
|
||||
playsound(owner.loc, "death_gurgles", 50, 0, -5)
|
||||
digestion_death(M)
|
||||
owner.update_icons()
|
||||
continue
|
||||
|
||||
// Deal digestion damage (and feed the pred)
|
||||
if(!(M.status_flags & GODMODE))
|
||||
M.adjustBruteLoss(2)
|
||||
M.adjustFireLoss(3)
|
||||
owner.nutrition += 1
|
||||
return
|
||||
|
||||
///////////////////////////// DM_HEAL /////////////////////////////
|
||||
if(digest_mode == DM_HEAL)
|
||||
if(prob(50))
|
||||
playsound(owner.loc, "digestion_sounds", 45, 0, -6) //very quiet gurgles, supposedly.
|
||||
|
||||
for (var/mob/living/M in internal_contents)
|
||||
if(M.stat != DEAD)
|
||||
if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
|
||||
M.adjustBruteLoss(-1)
|
||||
M.adjustFireLoss(-1)
|
||||
owner.nutrition -= 10
|
||||
return
|
||||
@@ -0,0 +1,326 @@
|
||||
///////////////////// Mob Living /////////////////////
|
||||
/mob/living
|
||||
var/digestable = 1 // Can the mob be digested inside a belly?
|
||||
var/datum/belly/vore_selected // Default to no vore capability.
|
||||
var/list/vore_organs = list() // List of vore containers inside a mob
|
||||
var/devourable = 0 // Can the mob be vored at all?
|
||||
// var/feeding = 0 // Are we going to feed someone else?
|
||||
|
||||
|
||||
//
|
||||
// Hook for generic creation of stuff on new creatures
|
||||
//
|
||||
/hook/living_new/proc/vore_setup(mob/living/M)
|
||||
M.verbs += /mob/living/proc/insidePanel
|
||||
M.verbs += /mob/living/proc/escapeOOC
|
||||
|
||||
//Tries to load prefs if a client is present otherwise gives freebie stomach
|
||||
if(!M.vore_organs || !M.vore_organs.len)
|
||||
spawn(20) //Wait a couple of seconds to make sure copy_to or whatever has gone
|
||||
if(!M) return
|
||||
|
||||
if(M.client && M.client.prefs_vr)
|
||||
if(!M.copy_from_prefs_vr())
|
||||
M << "<span class='warning'>ERROR: You seem to have saved VOREStation prefs, but they couldn't be loaded.</span>"
|
||||
return FALSE
|
||||
if(M.vore_organs && M.vore_organs.len)
|
||||
M.vore_selected = M.vore_organs[1]
|
||||
|
||||
if(!M.vore_organs || !M.vore_organs.len)
|
||||
if(!M.vore_organs)
|
||||
M.vore_organs = list()
|
||||
var/datum/belly/B = new /datum/belly(M)
|
||||
B.immutable = TRUE
|
||||
B.name = "Stomach"
|
||||
B.inside_flavor = "It appears to be rather warm and wet. Makes sense, considering it's inside \the [M.name]."
|
||||
M.vore_organs[B.name] = B
|
||||
M.vore_selected = B.name
|
||||
|
||||
//Simple_animal gets emotes. move this to that hook instead?
|
||||
if(istype(src,/mob/living/simple_animal))
|
||||
B.emote_lists[DM_HOLD] = list(
|
||||
"The insides knead at you gently for a moment.",
|
||||
"The guts glorp wetly around you as some air shifts.",
|
||||
"Your predator takes a deep breath and sighs, shifting you somewhat.",
|
||||
"The stomach squeezes you tight for a moment, then relaxes.",
|
||||
"During a moment of quiet, breathing becomes the most audible thing.",
|
||||
"The warm slickness surrounds and kneads on you.")
|
||||
|
||||
B.emote_lists[DM_DIGEST] = list(
|
||||
"The caustic acids eat away at your form.",
|
||||
"The acrid air burns at your lungs.",
|
||||
"Without a thought for you, the stomach grinds inwards painfully.",
|
||||
"The guts treat you like food, squeezing to press more acids against you.",
|
||||
"The onslaught against your body doesn't seem to be letting up; you're food now.",
|
||||
"The insides work on you like they would any other food.")
|
||||
|
||||
//Return 1 to hook-caller
|
||||
return 1
|
||||
|
||||
//
|
||||
// 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)
|
||||
if(!user || !prey)
|
||||
return
|
||||
|
||||
if(prey == src && user.zone_selected == "mouth") //you click your target
|
||||
// if(!feeding(src))
|
||||
// return
|
||||
if(!is_vore_predator(prey))
|
||||
user << "<span class='notice'>They aren't voracious enough.</span>"
|
||||
return
|
||||
feed_self_to_grabbed(user, src)
|
||||
|
||||
if(user == src) //you click yourself
|
||||
if(!is_vore_predator(src))
|
||||
user << "<span class='notice'>You aren't voracious enough.</span>"
|
||||
return
|
||||
user.feed_grabbed_to_self(src, prey)
|
||||
|
||||
else // click someone other than you/prey
|
||||
// if(!feeding(src))
|
||||
// return
|
||||
if(!is_vore_predator(src))
|
||||
user << "<span class='notice'>They aren't voracious enough.</span>"
|
||||
return
|
||||
feed_grabbed_to_other(user, prey, src)
|
||||
//
|
||||
// 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/eat_held_mob(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
|
||||
var/belly
|
||||
if(user != pred)
|
||||
belly = input("Choose Belly") in pred.vore_organs
|
||||
else
|
||||
belly = pred.vore_selected
|
||||
return perform_the_nom(user, prey, pred, 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)
|
||||
return//disabled until I can make that toggle work
|
||||
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/belly, swallow_time = 100)
|
||||
//Sanity
|
||||
if(!user || !prey || !pred || !belly || !(belly in pred.vore_organs))
|
||||
return
|
||||
if (!prey.devourable)
|
||||
user << "This can't be eaten!"
|
||||
return
|
||||
// The belly selected at the time of noms
|
||||
var/datum/belly/belly_target = pred.vore_organs[belly]
|
||||
var/attempt_msg = "ERROR: Vore message couldn't be created. Notify a dev. (at)"
|
||||
var/success_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
|
||||
|
||||
// Prepare messages
|
||||
if(user == pred) //Feeding someone to yourself
|
||||
attempt_msg = text("<span class='warning'>[] is attemping to [] [] into their []!</span>",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
success_msg = text("<span class='warning'>[] manages to [] [] into their []!</span>",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
else //Feeding someone to another person
|
||||
attempt_msg = text("<span class='warning'>[] is attempting to make [] [] [] into their []!</span>",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
success_msg = text("<span class='warning'>[] manages to make [] [] [] into their []!</span>",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
|
||||
|
||||
// Announce that we start the attempt!
|
||||
user.visible_message(attempt_msg)
|
||||
|
||||
// Now give the prey time to escape... return if they did
|
||||
|
||||
if(!do_mob(src, user, swallow_time))
|
||||
return FALSE // Prey escaped (or user disabled) before timer expired.
|
||||
|
||||
// If we got this far, nom successful! Announce it!
|
||||
user.visible_message(success_msg)
|
||||
playsound(user, belly_target.vore_sound, 100, 1)
|
||||
|
||||
// Actually shove prey into the belly.
|
||||
belly_target.nom_mob(prey, user)
|
||||
// user.update_icons()
|
||||
stop_pulling()
|
||||
|
||||
// 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 = 1
|
||||
if (pred == user)
|
||||
message_admins("[ADMIN_LOOKUPFLW(pred)] ate [ADMIN_LOOKUPFLW(prey)][!prey_braindead ? "" : " (BRAINDEAD)"][prey_stat ? " (DEAD/UNCONSCIOUS)" : ""].")
|
||||
log_attack("[key_name(pred)] ate [key_name(prey)]")
|
||||
else
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] forced [ADMIN_LOOKUPFLW(pred)] to eat [ADMIN_LOOKUPFLW(prey)].")
|
||||
log_attack("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)].")
|
||||
return TRUE
|
||||
|
||||
//
|
||||
//End vore code.
|
||||
/*
|
||||
//Handle case: /obj/item/weapon/holder
|
||||
if(/obj/item/weapon/holder/micro)
|
||||
var/obj/item/weapon/holder/H = I
|
||||
|
||||
if(!isliving(user)) return 0 // Return 0 to continue upper procs
|
||||
var/mob/living/attacker = user // Typecast to living
|
||||
|
||||
if (is_vore_predator(src))
|
||||
for (var/mob/living/M in H.contents)
|
||||
attacker.eat_held_mob(attacker, M, src)
|
||||
return 1 //Return 1 to exit upper procs
|
||||
else
|
||||
log_attack("[attacker] attempted to feed [H.contents] to [src] ([src.type]) but it failed.")
|
||||
|
||||
// I just can't imagine this not being complained about
|
||||
//Handle case: /obj/item/device/radio/beacon
|
||||
if(/obj/item/device/radio/beacon)
|
||||
var/confirm = alert(user, "[src == user ? "Eat the beacon?" : "Feed the beacon to [src]?"]", "Confirmation", "Yes!", "Cancel")
|
||||
if(confirm == "Yes!")
|
||||
var/bellychoice = input("Which belly?","Select A Belly") in src.vore_organs
|
||||
var/datum/belly/B = src.vore_organs[bellychoice]
|
||||
src.visible_message("<span class='warning'>[user] is trying to stuff a beacon into [src]'s [bellychoice]!</span>","<span class='warning'>[user] is trying to stuff a beacon into you!</span>")
|
||||
if(do_after(user,30,src))
|
||||
user.drop_item()
|
||||
I.loc = src
|
||||
B.internal_contents += I
|
||||
src.visible_message("<span class='warning'>[src] is fed the beacon!</span>","You're fed the beacon!")
|
||||
playsound(src, B.vore_sound, 100, 1)
|
||||
return 1
|
||||
else
|
||||
return 1 //You don't get to hit someone 'later'
|
||||
|
||||
return 0
|
||||
*/
|
||||
//
|
||||
// Custom resist catches for /mob/living
|
||||
//
|
||||
/mob/living/proc/vore_process_resist()
|
||||
|
||||
//Are we resisting from inside a belly?
|
||||
var/datum/belly/B = check_belly(src)
|
||||
if(B)
|
||||
spawn() B.relay_resist(src)
|
||||
return TRUE //resist() on living does this TRUE thing.
|
||||
|
||||
//Other overridden resists go here
|
||||
|
||||
|
||||
return FALSE
|
||||
|
||||
//
|
||||
// Proc for updating vore organs and digestion/healing/absorbing
|
||||
//
|
||||
/mob/living/proc/handle_internal_contents()
|
||||
if(SSmobs.times_fired%6==1)
|
||||
return //The accursed timer
|
||||
|
||||
for (var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
if(B.internal_contents.len)
|
||||
B.process_Life() //AKA 'do bellymodes_vr.dm'
|
||||
|
||||
for (var/I in vore_organs)
|
||||
var/datum/belly/B = vore_organs[I]
|
||||
if(B.internal_contents.len)
|
||||
listclearnulls(B.internal_contents)
|
||||
for(var/atom/movable/M in B.internal_contents)
|
||||
if(M.loc != src)
|
||||
B.internal_contents.Remove(M)
|
||||
|
||||
// OOC Escape code for pref-breaking or AFK preds
|
||||
//
|
||||
/mob/living/proc/escapeOOC()
|
||||
set name = "Animal Escape"
|
||||
set category = "Vore"
|
||||
|
||||
//You're in an animal!
|
||||
if(istype(src.loc,/mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/pred = src.loc
|
||||
var/confirm = alert(src, "You're in a mob. Use this as a trick to get out of hostile animals. If you are in more than one pred, use this more than once.", "Confirmation", "Okay", "Cancel")
|
||||
if(confirm == "Okay")
|
||||
for(var/I in pred.vore_organs)
|
||||
var/datum/belly/B = pred.vore_organs[I]
|
||||
B.release_specific_contents(src)
|
||||
|
||||
for(var/mob/living/simple_animal/SA in range(10))
|
||||
SA.prey_excludes += src
|
||||
spawn(18000)
|
||||
if(src && SA)
|
||||
SA.prey_excludes -= src
|
||||
|
||||
pred.update_icons()
|
||||
|
||||
else
|
||||
src << "<span class='alert'>You aren't inside anything, you clod.</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)
|
||||
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.belly_prefs = src.vore_organs
|
||||
|
||||
return TRUE
|
||||
|
||||
//
|
||||
// Proc for applying vore preferences, given bellies
|
||||
//
|
||||
/mob/living/proc/copy_from_prefs_vr()
|
||||
if(!client || !client.prefs_vr)
|
||||
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
|
||||
|
||||
var/datum/vore_preferences/P = client.prefs_vr
|
||||
|
||||
src.digestable = P.digestable
|
||||
src.devourable = P.devourable
|
||||
src.vore_organs = list()
|
||||
|
||||
for(var/I in P.belly_prefs)
|
||||
var/datum/belly/Bp = P.belly_prefs[I]
|
||||
src.vore_organs[Bp.name] = Bp.copy(src)
|
||||
|
||||
return TRUE
|
||||
@@ -0,0 +1,39 @@
|
||||
///////////////////// Simple Animal /////////////////////
|
||||
/mob/living/simple_animal
|
||||
var/isPredator = 0 //Are they capable of performing and pre-defined vore actions for their species?
|
||||
var/swallowTime = 30 //How long it takes to eat its prey in 1/10 of a second. The default is 3 seconds.
|
||||
var/list/prey_excludes = list() //For excluding people from being eaten.
|
||||
|
||||
//
|
||||
// Simple nom proc for if you get ckey'd into a simple_animal mob! Avoids grabs.
|
||||
/*
|
||||
/mob/living/proc/animal_nom(var/mob/living/T in oview(1))
|
||||
set name = "Animal Nom"
|
||||
set category = "Vore"
|
||||
set desc = "Since you can't grab, you get a verb!"
|
||||
|
||||
feed_grabbed_to_self(src,T)
|
||||
*/
|
||||
//
|
||||
// Simple proc for animals to have their digestion toggled on/off externally
|
||||
//
|
||||
/mob/living/simple_animal/verb/toggle_digestion()
|
||||
set name = "Toggle Animal's Digestion"
|
||||
set desc = "Enables digestion on this mob for 20 minutes."
|
||||
set category = "Vore"
|
||||
set src in oview(1)
|
||||
|
||||
var/datum/belly/B = vore_organs[vore_selected]
|
||||
if(faction != usr.faction)
|
||||
usr << "<span class='warning'>This predator isn't friendly, and doesn't give a shit about your opinions of it digesting you.</span>"
|
||||
return
|
||||
if(B.digest_mode == "Hold")
|
||||
var/confirm = alert(usr, "Enabling digestion on [name] will cause it to digest all stomach contents. Using this to break OOC prefs is against the rules. Digestion will disable itself after 20 minutes.", "Enabling [name]'s Digestion", "Enable", "Cancel")
|
||||
if(confirm == "Enable")
|
||||
B.digest_mode = "Digest"
|
||||
spawn(12000) //12000=20 minutes
|
||||
if(src) B.digest_mode = "Hold"
|
||||
else
|
||||
var/confirm = alert(usr, "This mob is currently set to digest all stomach contents. Do you want to disable this?", "Disabling [name]'s Digestion", "Disable", "Cancel")
|
||||
if(confirm == "Disable")
|
||||
B.digest_mode = "Hold"
|
||||
@@ -0,0 +1,125 @@
|
||||
|
||||
/*
|
||||
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
|
||||
//
|
||||
/client
|
||||
var/datum/vore_preferences/prefs_vr
|
||||
|
||||
/hook/client_new/proc/add_prefs_vr(client/C)
|
||||
C.prefs_vr = new/datum/vore_preferences(C)
|
||||
if(C.prefs_vr)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/vore_preferences
|
||||
//Actual preferences
|
||||
var/digestable = 1
|
||||
var/devourable = 0
|
||||
var/list/belly_prefs = list()
|
||||
|
||||
//Mechanically required
|
||||
var/path
|
||||
var/slot
|
||||
var/client/client
|
||||
var/client_ckey
|
||||
var/client/parent
|
||||
|
||||
/datum/vore_preferences/New(client/C)
|
||||
if(istype(C))
|
||||
client = C
|
||||
client_ckey = C.ckey
|
||||
load_vore(C)
|
||||
|
||||
//
|
||||
// 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
|
||||
//
|
||||
/proc/check_belly(atom/movable/A)
|
||||
if(istype(A.loc,/mob/living))
|
||||
var/mob/living/M = A.loc
|
||||
for(var/I in M.vore_organs)
|
||||
var/datum/belly/B = M.vore_organs[I]
|
||||
if(A in B.internal_contents)
|
||||
return(B)
|
||||
|
||||
return FALSE
|
||||
|
||||
//
|
||||
// Save/Load Vore Preferences
|
||||
//
|
||||
/datum/vore_preferences/proc/load_vore()
|
||||
if(!client || !client_ckey) return 0 //No client, how can we save?
|
||||
|
||||
slot = client.prefs.default_slot
|
||||
|
||||
path = client.prefs.path
|
||||
|
||||
if(!path) return 0 //Path couldn't be set?
|
||||
if(!fexists(path)) //Never saved before
|
||||
save_vore() //Make the file first
|
||||
return TRUE
|
||||
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S) return 0 //Savefile object couldn't be created?
|
||||
|
||||
S.cd = "/character[slot]"
|
||||
|
||||
S["digestable"] >> digestable
|
||||
S["devourable"] >> devourable
|
||||
S["belly_prefs"] >> belly_prefs
|
||||
|
||||
if(isnull(digestable))
|
||||
digestable = 1
|
||||
if(isnull(devourable))
|
||||
devourable = 0
|
||||
if(isnull(belly_prefs))
|
||||
belly_prefs = list()
|
||||
|
||||
return 1
|
||||
|
||||
/datum/vore_preferences/proc/save_vore()
|
||||
if(!path) return 0
|
||||
if(!slot) return 0
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S) return 0
|
||||
S.cd = "/character[slot]"
|
||||
|
||||
S["digestable"] << digestable
|
||||
S["devourable"] << devourable
|
||||
S["belly_prefs"] << belly_prefs
|
||||
|
||||
return 1
|
||||
@@ -0,0 +1,480 @@
|
||||
//
|
||||
// Vore management panel for players
|
||||
//
|
||||
|
||||
/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_organs[vore_selected]
|
||||
|
||||
var/dat = picker_holder.gen_vui(src)
|
||||
|
||||
picker_holder.popup = new(src, "insidePanel","Vore Panel", 400, 600, picker_holder)
|
||||
picker_holder.popup.set_content(dat)
|
||||
picker_holder.popup.open()
|
||||
|
||||
//
|
||||
// Callback Handler for the Inside form
|
||||
//
|
||||
/datum/vore_look
|
||||
var/datum/belly/selected
|
||||
var/datum/browser/popup
|
||||
var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action.
|
||||
|
||||
/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
|
||||
|
||||
if (is_vore_predator(user.loc))
|
||||
var/mob/living/eater = user.loc
|
||||
var/datum/belly/inside_belly
|
||||
|
||||
//This big block here figures out where the prey is
|
||||
inside_belly = check_belly(user)
|
||||
|
||||
if(inside_belly)
|
||||
dat += "<font color = 'green'>You are currently inside</font> <font color = 'yellow'>[eater]'s</font> <font color = 'red'>[inside_belly]</font>!<br><br>"
|
||||
|
||||
if(inside_belly.inside_flavor)
|
||||
dat += "[inside_belly.inside_flavor]<br><br>"
|
||||
|
||||
if (inside_belly.internal_contents.len > 1)
|
||||
dat += "You can see the following around you:<br>"
|
||||
for (var/atom/movable/O in inside_belly.internal_contents)
|
||||
if(istype(O,/mob/living))
|
||||
var/mob/living/M = O
|
||||
//That's just you
|
||||
if(M == user)
|
||||
continue
|
||||
//Anything else
|
||||
dat += "<a href='?src=\ref[src];outsidepick=\ref[O];outsidebelly=\ref[inside_belly]'>[O]</a>"
|
||||
else
|
||||
dat += "You aren't inside anyone."
|
||||
|
||||
dat += "<HR>"
|
||||
|
||||
dat += "<ol style='list-style: none; padding: 0; overflow: auto;'>"
|
||||
for(var/K in user.vore_organs) //Fuggin can't iterate over values
|
||||
var/datum/belly/B = user.vore_organs[K]
|
||||
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_DIGESTF)
|
||||
spanstyle = "color:purple;"
|
||||
if(DM_HEAL)
|
||||
spanstyle = "color:green;"
|
||||
|
||||
dat += "<span style='[spanstyle]'> ([B.internal_contents.len])</span></a></li>"
|
||||
|
||||
if(user.vore_organs.len < 10)
|
||||
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.internal_contents.len > 0)
|
||||
dat += "<b>Contents:</b> "
|
||||
for(var/O in selected.internal_contents)
|
||||
dat += "<a href='?src=\ref[src];insidepick=\ref[O]'>[O]</a>"
|
||||
|
||||
//If there's more than one thing, add an [All] button
|
||||
if(selected.internal_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]'"
|
||||
|
||||
//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.inside_flavor]'"
|
||||
|
||||
//Belly sound
|
||||
dat += "<br><a href='?src=\ref[src];b_sound=\ref[selected]'>Set Vore Sound</a>"
|
||||
dat += "<a href='?src=\ref[src];b_soundtest=\ref[selected]'>Test</a>"
|
||||
|
||||
//Belly messages
|
||||
dat += "<br><a href='?src=\ref[src];b_msgs=\ref[selected]'>Belly Messages</a>"
|
||||
|
||||
//Delete button
|
||||
dat += "<br><a style='background:#990000;' href='?src=\ref[src];b_del=\ref[selected]'>Delete Belly</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>"
|
||||
|
||||
switch(user.digestable)
|
||||
if(1)
|
||||
dat += "<a href='?src=\ref[src];toggledg=1'>Toggle Digestable</a>"
|
||||
if(0)
|
||||
dat += "<a href='?src=\ref[src];toggledg=1'><span style='color:green;'>Toggle Digestable</span></a>"
|
||||
|
||||
switch(user.devourable)
|
||||
if(1)
|
||||
dat += "<a href='?src=\ref[src];toggledvor=1'>Toggle Devourable</a>"
|
||||
if(0)
|
||||
dat += "<a href='?src=\ref[src];toggledvor=1'><span style='color:green;'>Toggle Devourable</span></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"])
|
||||
del(src) // Cleanup
|
||||
return
|
||||
|
||||
if(href_list["outsidepick"])
|
||||
var/tgt = locate(href_list["outsidepick"])
|
||||
var/datum/belly/OB = locate(href_list["outsidebelly"])
|
||||
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
|
||||
user << "<font color='green'>You begin to push [M] to freedom!</font>"
|
||||
M << "[usr] begins to push you to freedom!"
|
||||
M.loc << "<span class='warning'>Someone is trying to escape from inside you!</span>"
|
||||
sleep(50)
|
||||
if(prob(33))
|
||||
OB.release_specific_contents(M)
|
||||
usr << "<font color='green'>You manage to help [M] to safety!</font>"
|
||||
M << "<font color='green'>[user] pushes you free!</font>"
|
||||
M.loc << "<span class='alert'>[M] forces free of the confines of your body!</span>"
|
||||
else
|
||||
user << "<span class='alert'>[M] slips back down inside despite your efforts.</span>"
|
||||
M << "<span class='alert'> Even with [user]'s help, you slip back inside again.</span>"
|
||||
M.loc << "<font color='green'>Your body efficiently shoves [M] back where they belong.</font>"
|
||||
|
||||
if("Devour") //Eat the inside mob
|
||||
if(!user.vore_selected)
|
||||
user << "<span class='warning'>Pick a belly on yourself first!</span>"
|
||||
return 1
|
||||
|
||||
var/datum/belly/TB = user.vore_organs[user.vore_selected]
|
||||
user << "<span class='warning'>You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!</span>"
|
||||
M << "<span class='warning'>[user] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!</span>"
|
||||
M.loc << "<span class='warning'>Someone inside you is eating someone else!</span>"
|
||||
|
||||
sleep(TB.nonhuman_prey_swallow_time)
|
||||
if((user in OB.internal_contents) && (M in OB.internal_contents))
|
||||
user << "<span class='warning'>You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!</span>"
|
||||
M << "<span class='warning'>[user] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!</span>"
|
||||
M.loc << "<span class='warning'>Someone inside you has eaten someone else!</span>"
|
||||
M.loc = user
|
||||
TB.nom_mob(M)
|
||||
OB.internal_contents -= M
|
||||
|
||||
else if(istype(tgt,/obj/item))
|
||||
var/obj/item/T = tgt
|
||||
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)
|
||||
user << "<span class='warning'>You can't do that in your state!</span>"
|
||||
return 1
|
||||
|
||||
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 1
|
||||
|
||||
if("Eject all")
|
||||
if(user.stat)
|
||||
user << "<span class='warning'>You can't do that in your state!</span>"
|
||||
return 1
|
||||
|
||||
selected.release_all_contents()
|
||||
playsound(user, 'sound/effects/splat.ogg', 50, 1)
|
||||
user.loc << "<span class='danger'>Everything is released from [user]!</span>"
|
||||
|
||||
if("Move all")
|
||||
if(user.stat)
|
||||
user << "<span class='warning'>You can't do that in your state!</span>"
|
||||
return 1
|
||||
|
||||
var/choice = input("Move all where?","Select Belly") in user.vore_organs + "Cancel - Don't Move"
|
||||
|
||||
if(choice == "Cancel - Don't Move")
|
||||
return 1
|
||||
else
|
||||
var/datum/belly/B = user.vore_organs[choice]
|
||||
for(var/atom/movable/tgt in selected.internal_contents)
|
||||
selected.internal_contents -= tgt
|
||||
B.internal_contents += tgt
|
||||
|
||||
tgt << "<span class='warning'>You're squished from [user]'s [selected] to their [B]!</span>"
|
||||
|
||||
for(var/mob/hearer in range(1,user))
|
||||
hearer << sound('sound/vore/squish2.ogg',volume=80)
|
||||
return 1
|
||||
|
||||
|
||||
var/atom/movable/tgt = locate(href_list["insidepick"])
|
||||
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)
|
||||
user << "<span class='warning'>You can't do that in your state!</span>"
|
||||
return 1
|
||||
|
||||
selected.release_specific_contents(tgt)
|
||||
playsound(user, 'sound/effects/splat.ogg', 50, 1)
|
||||
user.loc << "<span class='danger'>[tgt] is released from [user]!</span>"
|
||||
|
||||
if("Move")
|
||||
if(user.stat)
|
||||
user << "<span class='warning'>You can't do that in your state!</span>"
|
||||
return 1
|
||||
|
||||
var/choice = input("Move [tgt] where?","Select Belly") in user.vore_organs + "Cancel - Don't Move"
|
||||
|
||||
if(choice == "Cancel - Don't Move")
|
||||
return 1
|
||||
else
|
||||
var/datum/belly/B = user.vore_organs[choice]
|
||||
selected.internal_contents -= tgt
|
||||
B.internal_contents += tgt
|
||||
|
||||
tgt << "<span class='warning'>You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(B.name)]!</span>"
|
||||
for(var/mob/hearer in range(1,user))
|
||||
hearer << sound('sound/vore/squish2.ogg',volume=80)
|
||||
|
||||
if(href_list["newbelly"])
|
||||
if(user.vore_organs.len >= 10)
|
||||
return 1
|
||||
|
||||
var/new_name = html_encode(input(usr,"New belly's name:","New Belly") as text|null)
|
||||
|
||||
if(length(new_name) > 12 || length(new_name) < 2)
|
||||
usr << "<span class='warning'>Entered belly name is too long.</span>"
|
||||
return 0
|
||||
if(new_name in user.vore_organs)
|
||||
usr << "<span class='warning'>No duplicate belly names, please.</span>"
|
||||
return 0
|
||||
|
||||
var/datum/belly/NB = new(user)
|
||||
NB.name = new_name
|
||||
NB.owner = user //might be the thing we all needed.
|
||||
user.vore_organs[new_name] = NB
|
||||
selected = NB
|
||||
|
||||
if(href_list["bellypick"])
|
||||
selected = locate(href_list["bellypick"])
|
||||
user.vore_selected = selected.name
|
||||
|
||||
if(href_list["b_name"])
|
||||
var/new_name = html_encode(input(usr,"Belly's new name:","New Name") as text|null)
|
||||
|
||||
if(length(new_name) > 12 || length(new_name) < 2)
|
||||
usr << "<span class='warning'>Entered belly name length invalid (must be longer than 2, shorter than 12).</span>"
|
||||
return 0
|
||||
if(new_name in user.vore_organs)
|
||||
usr << "<span class='warning'>No duplicate belly names, please.</span>"
|
||||
return 0
|
||||
|
||||
user.vore_organs[new_name] = selected
|
||||
user.vore_organs -= selected.name
|
||||
selected.name = new_name
|
||||
|
||||
if(href_list["b_mode"])
|
||||
var/list/menu_list = selected.digest_modes
|
||||
|
||||
if(selected.digest_modes.len == 1) // Don't do anything
|
||||
return 1
|
||||
if(selected.digest_modes.len == 2) // Just toggle... there's probably a more elegant way to do this...
|
||||
var/index = selected.digest_modes.Find(selected.digest_mode)
|
||||
switch(index)
|
||||
if(1)
|
||||
selected.digest_mode = selected.digest_modes[2]
|
||||
if(2)
|
||||
selected.digest_mode = selected.digest_modes[1]
|
||||
else
|
||||
selected.digest_mode = input("Choose Mode (currently [selected.digest_mode])") in menu_list
|
||||
|
||||
if(href_list["b_desc"])
|
||||
var/new_desc = html_encode(input(usr,"Belly Description (1024 char limit):","New Description",selected.inside_flavor) as message|null)
|
||||
new_desc = readd_quotes(new_desc)
|
||||
|
||||
if(length(new_desc) > 1024)
|
||||
usr << "<span class='warning'>Entered belly desc too long. 1024 character limit.</span>"
|
||||
return FALSE
|
||||
|
||||
selected.inside_flavor = new_desc
|
||||
|
||||
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",
|
||||
"Cancel - No Changes"
|
||||
)
|
||||
|
||||
alert(user,"Setting abusive or deceptive messages will result in a ban. Consider this your warning. Max 150 characters per message, max 10 messages per topic.","Really, don't.")
|
||||
var/choice = input(user,"Select a type to modify. Messages from each topic are pulled at random when needed.","Pick Type") in messages
|
||||
var/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'). Do not use %pred or %prey in this type."+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("Cancel - No Changes")
|
||||
return 1
|
||||
|
||||
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) > 12 || length(new_verb) < 2)
|
||||
usr << "<span class='warning'>Entered verb length invalid (must be longer than 2, shorter than 12).</span>"
|
||||
return FALSE
|
||||
|
||||
selected.vore_verb = new_verb
|
||||
|
||||
if(href_list["b_sound"])
|
||||
var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") in vore_sounds + "Cancel - No Changes"
|
||||
|
||||
if(choice == "Cancel")
|
||||
return 1
|
||||
|
||||
selected.vore_sound = vore_sounds[choice]
|
||||
|
||||
if(href_list["b_soundtest"])
|
||||
user << selected.vore_sound
|
||||
|
||||
if(href_list["b_del"])
|
||||
if(selected.internal_contents.len)
|
||||
usr << "<span class='warning'>Can't delete bellies with contents!</span>"
|
||||
else if(selected.immutable)
|
||||
usr << "<span class='warning'>This belly is marked as undeletable.</span>"
|
||||
else if(user.vore_organs.len == 1)
|
||||
usr << "<span class='warning'>You must have at least one belly.</span>"
|
||||
else
|
||||
var/alert = alert("Are you sure you want to delete [selected]?","Confirmation","Delete","Cancel")
|
||||
if(alert == "Delete" && !selected.internal_contents.len)
|
||||
user.vore_organs -= selected.name
|
||||
user.vore_organs.Remove(selected)
|
||||
selected = user.vore_organs[1]
|
||||
user.vore_selected = user.vore_organs[1]
|
||||
|
||||
if(href_list["saveprefs"])
|
||||
if(user.save_vore_prefs())
|
||||
user << "<span class='notice'>Belly Preferences saved!</span>"
|
||||
|
||||
else
|
||||
user << "<span class='warning'>ERROR: Belly Preferences were not saved!</span>"
|
||||
log_admin("Could not save vore prefs on USER: [user].")
|
||||
|
||||
|
||||
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 1
|
||||
if("Allow Digestion")
|
||||
user.digestable = 1
|
||||
if("Prevent Digestion")
|
||||
user.digestable = 0
|
||||
|
||||
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 1
|
||||
if("Allow Devourment")
|
||||
user.devourable = 1
|
||||
if("Prevent Devourment")
|
||||
user.devourable = 0
|
||||
|
||||
if(user.client.prefs_vr)
|
||||
user.client.prefs_vr.devourable = user.devourable
|
||||
|
||||
//Refresh when interacted with, returning 1 makes vore_look.Topic update
|
||||
return 1
|
||||
@@ -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,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/weapon/holder
|
||||
|
||||
/obj/item/weapon/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/weapon/holder/micro/examine(var/mob/user)
|
||||
for(var/mob/living/M in contents)
|
||||
M.examine(user)
|
||||
|
||||
/obj/item/weapon/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/weapon/holder/micro/attack_self(var/mob/living/user)
|
||||
for(var/mob/living/carbon/human/M in contents)
|
||||
M.help_shake_act(user)
|
||||
|
||||
/obj/item/weapon/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,208 @@
|
||||
|
||||
//these aren't defines so they can stay in this file
|
||||
var/const/SIZESCALE_HUGE = 2
|
||||
var/const/SIZESCALE_BIG = 1.5
|
||||
var/const/SIZESCALE_NORMAL = 1
|
||||
var/const/SIZESCALE_SMALL = 0.85
|
||||
var/const/SIZESCALE_TINY = 0.60
|
||||
|
||||
//average
|
||||
var/const/SIZESCALE_A_HUGEBIG = (SIZESCALE_HUGE + SIZESCALE_BIG) / 2
|
||||
var/const/SIZESCALE_A_BIGNORMAL = (SIZESCALE_BIG + SIZESCALE_NORMAL) / 2
|
||||
var/const/SIZESCALE_A_NORMALSMALL = (SIZESCALE_NORMAL + SIZESCALE_SMALL) / 2
|
||||
var/const/SIZESCALE_A_SMALLTINY = (SIZESCALE_SMALL + 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/weapon/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/weapon/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.adjustBrainLoss(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_specific_contents(A)
|
||||
..()
|
||||
. = 1
|
||||
@@ -0,0 +1,172 @@
|
||||
//
|
||||
// Size Gun
|
||||
//
|
||||
/*
|
||||
/obj/item/weapon/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
|
||||
origin_tech = "redspace=1;bluespace=4"
|
||||
modifystate = "sizegun-shrink"
|
||||
selfcharge = 1
|
||||
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"
|
||||
req_tech = list("combat" = 5, "materials" = 4, "engineering" = 5, "bluespace" = 4)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 1000, MAT_GLASS = 1000, MAT_DIAMOND = 2500, MAT_URANIUM = 2500, MAT_TITANIUM = 1000)
|
||||
build_path = /obj/item/weapon/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/weapon/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)
|
||||
origin_tech = "combat=1;magnets=2"
|
||||
selfcharge = 1
|
||||
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 VOREStation's fails.
|
||||
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]")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+13
-1
@@ -14,7 +14,6 @@
|
||||
|
||||
// BEGIN_INCLUDE
|
||||
#include "_maps\basemap.dm"
|
||||
#include "_maps\loadallmaps.dm"
|
||||
#include "_maps\tgstation2.dm"
|
||||
#include "code\_compile_options.dm"
|
||||
#include "code\world.dm"
|
||||
@@ -67,6 +66,7 @@
|
||||
#include "code\__DEFINES\tgui.dm"
|
||||
#include "code\__DEFINES\tick.dm"
|
||||
#include "code\__DEFINES\typeids.dm"
|
||||
#include "code\__DEFINES\voreconstants.dm"
|
||||
#include "code\__DEFINES\vv.dm"
|
||||
#include "code\__DEFINES\wires.dm"
|
||||
#include "code\__HELPERS\_lists.dm"
|
||||
@@ -1148,6 +1148,7 @@
|
||||
#include "code\modules\client\preferences.dm"
|
||||
#include "code\modules\client\preferences_savefile.dm"
|
||||
#include "code\modules\client\preferences_toggles.dm"
|
||||
#include "code\modules\client\preferences_vr.dm"
|
||||
#include "code\modules\client\verbs\looc.dm"
|
||||
#include "code\modules\client\verbs\ooc.dm"
|
||||
#include "code\modules\client\verbs\ping.dm"
|
||||
@@ -1567,6 +1568,7 @@
|
||||
#include "code\modules\mob\living\carbon\human\death.dm"
|
||||
#include "code\modules\mob\living\carbon\human\emote.dm"
|
||||
#include "code\modules\mob\living\carbon\human\examine.dm"
|
||||
#include "code\modules\mob\living\carbon\human\examine_vr.dm"
|
||||
#include "code\modules\mob\living\carbon\human\human.dm"
|
||||
#include "code\modules\mob\living\carbon\human\human_defense.dm"
|
||||
#include "code\modules\mob\living\carbon\human\human_defines.dm"
|
||||
@@ -2130,6 +2132,16 @@
|
||||
#include "code\modules\vehicles\secway.dm"
|
||||
#include "code\modules\vehicles\speedbike.dm"
|
||||
#include "code\modules\vehicles\vehicle.dm"
|
||||
#include "code\modules\vore\hook-defs_vr.dm"
|
||||
#include "code\modules\vore\trycatch_vr.dm"
|
||||
#include "code\modules\vore\eating\belly_vr.dm"
|
||||
#include "code\modules\vore\eating\bellymodes_vr.dm"
|
||||
#include "code\modules\vore\eating\living_vr.dm"
|
||||
#include "code\modules\vore\eating\simple_animal_vr.dm"
|
||||
#include "code\modules\vore\eating\vore_vr.dm"
|
||||
#include "code\modules\vore\eating\vorepanel_vr.dm"
|
||||
#include "code\modules\vore\resizing\resize_vr.dm"
|
||||
#include "code\modules\vore\resizing\sizegun_vr.dm"
|
||||
#include "code\modules\VR\vr_human.dm"
|
||||
#include "code\modules\VR\vr_sleeper.dm"
|
||||
#include "code\modules\zombie\items.dm"
|
||||
|
||||
Reference in New Issue
Block a user