From 4ab7f126ed38bdee349320afe623777c8fca7982 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Tue, 19 Sep 2017 14:03:13 -0500 Subject: [PATCH] Vore system updates (#2864) * Tasting, digest/transfer chance, improvements * more vague for defaults * Actually let's hold off on silenced mode 'cuz broke * make sure it's all commented out * reverts vorepanel updater, buggy af. Adds mob vore Ian can eat you now. \o/ --- .../mob/living/simple_animal/simple_animal.dm | 3 + .../living/simple_animal/simple_animal_vr.dm | 68 +++++ code/modules/vore/eating/belly_vr.dm | 82 +++++- code/modules/vore/eating/bellymodes_vr.dm | 6 +- code/modules/vore/eating/living_vr.dm | 53 +++- code/modules/vore/eating/simple_animal_vr.dm | 37 +-- code/modules/vore/eating/vore_vr.dm | 3 + code/modules/vore/eating/vorepanel_vr.dm | 233 +++++++++++++++--- tgstation.dme | 2 +- 9 files changed, 414 insertions(+), 73 deletions(-) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index aa95d182cb..1a14a9cd36 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -95,6 +95,9 @@ real_name = name if(!loc) stack_trace("Simple animal being instantiated in nullspace") + if(vore_active) + init_belly() + verbs |= /mob/living/proc/animal_nom /mob/living/simple_animal/Login() diff --git a/code/modules/mob/living/simple_animal/simple_animal_vr.dm b/code/modules/mob/living/simple_animal/simple_animal_vr.dm index 45320ecc3e..1ba77aa67f 100644 --- a/code/modules/mob/living/simple_animal/simple_animal_vr.dm +++ b/code/modules/mob/living/simple_animal/simple_animal_vr.dm @@ -2,3 +2,71 @@ // List of targets excluded (for now) from being eaten by this mob. var/list/prey_exclusions = list() devourable = FALSE //insurance because who knows. + var/vore_active = FALSE // If vore behavior is enabled for this mob + + var/vore_capacity = 1 // The capacity (in people) this person can hold + var/vore_default_mode = DM_DIGEST // Default bellymode (DM_DIGEST, DM_HOLD, DM_ABSORB) + var/vore_digest_chance = 25 // Chance to switch to digest mode if resisted + var/vore_absorb_chance = 0 // Chance to switch to absorb mode if resisted + var/vore_escape_chance = 25 // Chance of resisting out of mob + + var/vore_stomach_name // The name for the first belly if not "stomach" + var/vore_stomach_flavor // The flavortext for the first belly if not the default + + +// Release belly contents beforey being gc'd! +/mob/living/simple_animal/Destroy() + for(var/I in vore_organs) + var/datum/belly/B = vore_organs[I] + B.release_all_contents() // When your stomach is empty + prey_excludes.Cut() + . = ..() + +/mob/living/simple_animal/death() + for(var/I in vore_organs) + var/datum/belly/B = vore_organs[I] + B.release_all_contents() // When your stomach is empty + ..() // then you have my permission to die. + +// Simple animals have only one belly. This creates it (if it isn't already set up) +/mob/living/simple_animal/proc/init_belly() + if(vore_organs.len) + return + if(no_vore) //If it can't vore, let's not give it a stomach. + return + + var/datum/belly/B = new /datum/belly(src) + B.immutable = TRUE + B.name = vore_stomach_name ? vore_stomach_name : "stomach" + B.inside_flavor = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]." + B.digest_mode = vore_default_mode + B.escapable = vore_escape_chance > 0 + B.escapechance = vore_escape_chance + B.digestchance = vore_digest_chance + B.human_prey_swallow_time = swallowTime + B.nonhuman_prey_swallow_time = swallowTime + B.vore_verb = "swallow" + // TODO - Customizable per mob + B.emote_lists[DM_HOLD] = list( // We need more that aren't repetitive. I suck at endo. -Ace + "The insides knead at you gently for a moment.", + "The guts glorp wetly around you as some air shifts.", + "The predator takes a deep breath and sighs, shifting you somewhat.", + "The stomach squeezes you tight for a moment, then relaxes harmlessly.", + "The predator's calm breathing and thumping heartbeat pulses around you.", + "The warm walls kneads harmlessly against you.", + "The liquids churn around you, though there doesn't seem to be much effect.", + "The sound of bodily movements drown out everything for a moment.", + "The predator's movements gently force you into a different position.") + B.emote_lists[DM_DIGEST] = list( + "The burning acids eat away at your form.", + "The muscular stomach flesh grinds harshly against you.", + "The caustic air stings your chest when you try to breathe.", + "The slimy guts squeeze inward to help the digestive juices soften you up.", + "The onslaught against your body doesn't seem to be letting up; you're food now.", + "The predator's body ripples and crushes against you as digestive enzymes pull you apart.", + "The juices pooling beneath you sizzle against your sore skin.", + "The churning walls slowly pulverize you into meaty nutrients.", + "The stomach glorps and gurgles as it tries to work you into slop.") + src.vore_organs[B.name] = B + src.vore_selected = B.name + diff --git a/code/modules/vore/eating/belly_vr.dm b/code/modules/vore/eating/belly_vr.dm index f1e4274ce9..1a181efa58 100644 --- a/code/modules/vore/eating/belly_vr.dm +++ b/code/modules/vore/eating/belly_vr.dm @@ -13,16 +13,21 @@ var/inside_flavor // Flavor text description of inside sight/sound/smells/feels. var/vore_sound = 'sound/vore/pred/swallow_01.ogg' // Sound when ingesting someone var/vore_verb = "ingest" // Verb for eating with this in messages - var/human_prey_swallow_time = 100 // Time in deciseconds to swallow /mob/living/carbon/human - var/nonhuman_prey_swallow_time = 60 // Time in deciseconds to swallow anything else + var/human_prey_swallow_time = 10 SECONDS // Time in deciseconds to swallow /mob/living/carbon/human + var/nonhuman_prey_swallow_time = 5 SECONDS // Time in deciseconds to swallow anything else var/emoteTime = 300 // How long between stomach emotes at prey var/digest_brute = 0 // Brute damage per tick in digestion mode var/digest_burn = 1 // Burn damage per tick in digestion mode var/digest_tickrate = 9 // Modulus this of air controller tick number to iterate gurgles on var/immutable = FALSE // Prevents this belly from being deleted - var/escapable = 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/escapable = FALSE // Belly can be resisted out of at any time + var/escapetime = 60 SECONDS // Deciseconds, how long to escape this belly + var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles +// var/silenced = FALSE // Will the heartbeat/fleshy internal loop play? + var/escapechance = 0 // % Chance of prey beginning to escape if prey struggles. + var/transferchance = 0 // % Chance of prey being + var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone. + var/datum/belly/transferlocation = null // Location that the prey is released if they struggle and get dropped off. var/tmp/digest_mode = DM_HOLD // Whether or not to digest. Default to not digest. var/tmp/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY) // Possible digest modes var/tmp/mob/living/owner // The mob whose belly this is. @@ -125,7 +130,7 @@ M.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner. M << sound(null, repeat = 0, wait = 0, volume = 80, channel = CHANNEL_PREYLOOP) - src.internal_contents.Add(M) // Remove from the belly contents + src.internal_contents.Remove(M) // Remove from the belly contents var/datum/belly/B = check_belly(owner) if(B) B.internal_contents.Add(M) @@ -143,10 +148,13 @@ prey.forceMove(owner) internal_contents.Add(prey) + +// var/datum/belly/B = check_belly(owner) +// if(B.silenced == FALSE) //this needs more testing later prey << sound('sound/vore/prey/loop.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_PREYLOOP) if(inside_flavor) - prey << "[inside_flavor]" + to_chat(prey, "[src.inside_flavor]") // 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, @@ -158,6 +166,8 @@ var/raw_message = pick(examine_messages) formatted_message = replacetext(raw_message,"%belly",lowertext(name)) + formatted_message = replacetext(formatted_message,"%pred",owner) + formatted_message = replacetext(formatted_message,"%prey",english_list(internal_contents)) return("[formatted_message]
") @@ -226,8 +236,8 @@ internal_contents.Remove(M) M << sound(null, repeat = 0, wait = 0, volume = 80, channel = CHANNEL_PREYLOOP) // If digested prey is also a pred... anyone inside their bellies gets moved up. - if (is_vore_predator(M)) - for (var/bellytype in M.vore_organs) + 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 @@ -237,7 +247,7 @@ internal_contents.Add(subprey) to_chat(subprey, "As [M] melts away around you, you find yourself in [owner]'s [name]") - //Drop all items into the belly. + //Drop all items into the belly/floor. for(var/obj/item/W in M) if(!M.dropItemToGround(W)) qdel(W) @@ -312,12 +322,57 @@ to_chat(owner, "The attempt to escape from your [name] has failed!/span>") return + else if(prob(transferchance) && istype(transferlocation)) //Next, let's have it see if they end up getting into an even bigger mess then when they started. + var/location_found = FALSE + var/name_found = FALSE + for(var/I in owner.vore_organs) + var/datum/belly/B = owner.vore_organs[I] + if(B == transferlocation) + location_found = TRUE + break + + if(!location_found) + for(var/I in owner.vore_organs) + var/datum/belly/B = owner.vore_organs[I] + if(B.name == transferlocation.name) + name_found = TRUE + transferlocation = B + break + + if(!location_found && !name_found) + to_chat(owner, "Something went wrong with your belly transfer settings.") + transferlocation = null + return + + to_chat(R, "Your attempt to escape [name] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!") + to_chat(owner, "Someone slid into your [transferlocation] due to their struggling inside your [name]!") + transfer_contents(R, transferlocation) + return + + else if(prob(digestchance)) //Finally, let's see if it should run the digest chance.) + to_chat(R, "In response to your struggling, \the [name] begins to get more active...") + to_chat(owner, "You feel your [name] beginning to become active!") + digest_mode = DM_DIGEST + return else //Nothing interesting happened. to_chat(R, "But make no progress in escaping [owner]'s [name].") to_chat(owner, "But appears to be unable to make any progress in escaping your [name].") return - else +//Transfers contents from one belly to another +/datum/belly/proc/transfer_contents(var/atom/movable/content, var/datum/belly/target, silent = 0) + if(!(content in internal_contents)) return + internal_contents.Remove(content) + target.internal_contents.Add(content) + if(isliving(content)) + var/mob/living/M = content + if(target.inside_flavor) + to_chat(M, "[target.inside_flavor]") + if(target.can_taste && M.get_taste_message(0)) + to_chat(owner, "[M] tastes of [M.get_taste_message(0)].") + if(!silent) + for(var/mob/hearer in range(1,owner)) + hearer << sound(target.vore_sound,volume=80) // Belly copies and then returns the copy // Needs to be updated for any var changes @@ -336,8 +391,13 @@ dupe.digest_burn = digest_burn dupe.digest_tickrate = digest_tickrate dupe.immutable = immutable + dupe.can_taste = can_taste dupe.escapable = escapable dupe.escapetime = escapetime + dupe.digestchance = digestchance + dupe.escapechance = escapechance + dupe.transferchance = transferchance + dupe.transferlocation = transferlocation //// Object-holding variables //struggle_messages_outside - strings diff --git a/code/modules/vore/eating/bellymodes_vr.dm b/code/modules/vore/eating/bellymodes_vr.dm index 19d07e6fb6..901c1ca56f 100644 --- a/code/modules/vore/eating/bellymodes_vr.dm +++ b/code/modules/vore/eating/bellymodes_vr.dm @@ -21,7 +21,7 @@ //////////////////////////// DM_DIGEST //////////////////////////// if(digest_mode == DM_DIGEST) for (var/mob/living/M in internal_contents) - if(prob(15)) + if(prob(25)) M.stop_sound_channel(CHANNEL_PRED) playsound(get_turf(owner),"digest_pred",50,0,-6,0,channel=CHANNEL_PRED) M.stop_sound_channel(CHANNEL_PRED) @@ -62,14 +62,14 @@ // Deal digestion damage (and feed the pred) if(!(M.status_flags & GODMODE)) - M.adjustFireLoss(1) + M.adjustFireLoss(digest_burn) owner.nutrition += 1 return ///////////////////////////// DM_HEAL ///////////////////////////// if(digest_mode == DM_HEAL) for (var/mob/living/M in internal_contents) - if(prob(15)) + if(prob(25)) M.stop_sound_channel(CHANNEL_PRED) playsound(get_turf(owner),"digest_pred",35,0,-6,0,channel=CHANNEL_PRED) M.stop_sound_channel(CHANNEL_PRED) diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 98db33a763..60206a43f1 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -5,14 +5,20 @@ var/list/vore_organs = list() // List of vore containers inside a mob var/devourable = FALSE // Can the mob be vored at all? // var/feeding = FALSE // Are we going to feed someone else? - + var/vore_taste = null // What the character tastes like + var/no_vore = FALSE // If the character/mob can vore. + var/openpanel = 0 // Is the vore panel open? // // 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 + M.verbs += /mob/living/proc/lick + if(M.no_vore) //If the mob isn's supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach. + M << "The creature that you are can not eat others." + return TRUE + M.verbs += /mob/living/proc/insidePanel //Tries to load prefs if a client is present otherwise gives freebie stomach if(!M.vore_organs || !M.vore_organs.len) @@ -32,7 +38,8 @@ 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]." + B.inside_flavor = "It appears to be rather warm and wet. Makes sense, considering it's inside \the [M.name]" + B.can_taste = TRUE M.vore_organs[B.name] = B M.vore_selected = B.name @@ -302,6 +309,7 @@ P.digestable = src.digestable P.devourable = src.devourable P.belly_prefs = src.vore_organs + P.vore_taste = src.vore_taste return TRUE @@ -318,9 +326,48 @@ src.digestable = P.digestable src.devourable = P.devourable src.vore_organs = list() + src.vore_taste = P.vore_taste for(var/I in P.belly_prefs) var/datum/belly/Bp = P.belly_prefs[I] src.vore_organs[Bp.name] = Bp.copy(src) return TRUE +// +// Clearly super important. Obviously. +// +/mob/living/proc/lick(var/mob/living/tasted in oview(1)) + set name = "Lick Someone" + set category = "Vore" + set desc = "Lick someone nearby!" + + if(!istype(tasted)) + return + + if(src == stat) + return + + src.setClickCooldown(50) + + src.visible_message("[src] licks [tasted]!","You lick [tasted]. They taste rather like [tasted.get_taste_message()].","Slurp!") + + +/mob/living/proc/get_taste_message(allow_generic = TRUE, datum/species/mrace) + if(!vore_taste && !allow_generic) + return FALSE + + var/taste_message = "" + if(vore_taste && (vore_taste != "")) + taste_message += "[vore_taste]" + else + if(ishuman(src)) + taste_message += "normal, like a critter should" + else + taste_message += "a plain old normal [src]" + +/* if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(H.touching.reagent_list.len) //Just the first one otherwise I'll go insane. + var/datum/reagent/R = H.touching.reagent_list[1] + taste_message += " You also get the flavor of [R.taste_description] from something on them"*/ + return taste_message \ No newline at end of file diff --git a/code/modules/vore/eating/simple_animal_vr.dm b/code/modules/vore/eating/simple_animal_vr.dm index 33417331f5..f8e30b6353 100644 --- a/code/modules/vore/eating/simple_animal_vr.dm +++ b/code/modules/vore/eating/simple_animal_vr.dm @@ -1,19 +1,9 @@ ///////////////////// 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/isPredator = FALSE //Are they capable of performing and pre-defined vore actions for their species? + var/swallowTime = 5 SECONDS //How long it takes to eat its prey in 1/10 of a second. The default is 5 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 // @@ -25,15 +15,30 @@ var/datum/belly/B = vore_organs[vore_selected] if(faction != usr.faction) - usr << "This predator isn't friendly, and doesn't give a shit about your opinions of it digesting you." + to_chat(usr,"This predator isn't friendly, and doesn't give a shit about your opinions of it digesting you.") 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" + sleep(20 MINUTES) //12000=20 minutes + 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" \ No newline at end of file + B.digest_mode = "Hold" + +// +// 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!" + + if (stat != CONSCIOUS) + return + if (T.devourable == FALSE) + to_chat(usr, "You can't eat this!") + return + return feed_grabbed_to_self(src,T) \ No newline at end of file diff --git a/code/modules/vore/eating/vore_vr.dm b/code/modules/vore/eating/vore_vr.dm index 7589997594..f6d886e93f 100644 --- a/code/modules/vore/eating/vore_vr.dm +++ b/code/modules/vore/eating/vore_vr.dm @@ -41,6 +41,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE var/digestable = TRUE var/devourable = FALSE var/list/belly_prefs = list() + var/vore_taste //Mechanically required var/path @@ -101,6 +102,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE S["digestable"] >> digestable S["devourable"] >> devourable S["belly_prefs"] >> belly_prefs + S["vore_taste"] >> vore_taste if(isnull(digestable)) digestable = TRUE @@ -121,6 +123,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE WRITE_FILE(S["digestable"], digestable) WRITE_FILE(S["devourable"], devourable) WRITE_FILE(S["belly_prefs"], belly_prefs) + WRITE_FILE(S["vore_taste"], vore_taste) return TRUE diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 4afb33b2ac..ebbc2f371c 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -2,6 +2,12 @@ // Vore management panel for players // +#define BELLIES_MAX 20 +#define BELLIES_NAME_MIN 2 +#define BELLIES_NAME_MAX 12 +#define BELLIES_DESC_MAX 1024 +#define FLAVOR_MAX 40 + /mob/living/proc/insidePanel() set name = "Vore Panel" set category = "Vore" @@ -21,9 +27,15 @@ // /datum/vore_look var/datum/belly/selected + var/show_interacts = FALSE var/datum/browser/popup var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action. +/datum/vore_look/Destroy() + loop = null + selected = null + return QDEL_HINT_HARDDEL + /datum/vore_look/Topic(href,href_list[]) if (vp_interact(href, href_list)) popup.set_content(gen_vui(usr)) @@ -55,6 +67,8 @@ continue //Anything else dat += "[O]" + //Zero-width space, for wrapping + dat += "​" else dat += "You aren't inside anyone." @@ -79,7 +93,7 @@ dat += " ([B.internal_contents.len])" - if(user.vore_organs.len < 10) + if(user.vore_organs.len < BELLIES_MAX) dat += "
  • New+
  • " dat += "" dat += "
    " @@ -93,6 +107,8 @@ for(var/O in selected.internal_contents) dat += "[O]" + //Zero-width space, for wrapping + dat += "​" //If there's more than one thing, add an [All] button if(selected.internal_contents.len > 1) dat += "\[All\]" @@ -119,9 +135,44 @@ dat += "
    Set Vore Sound" dat += "Test" + // //Belly silence + // dat += "
    Belly Silence ([selected.silenced ? "Silenced" : "Noisy"])" + //Belly messages dat += "
    Belly Messages" + //Can belly taste? + dat += "
    Can Taste:" + dat += " [selected.can_taste ? "Yes" : "No"]" + + //Belly escapability + dat += "
    Belly Interactions ([selected.escapable ? "On" : "Off"])" + if(selected.escapable) + dat += "[show_interacts ? "Hide" : "Show"]" + + if(show_interacts && selected.escapable) + dat += "
    " + dat += "Interaction Settings ?" + dat += "
    Set Belly Escape Chance" + dat += " [selected.escapechance]%" + + dat += "
    Set Belly Escape Time" + dat += " [selected.escapetime/10]s" + + //Special
    here to add a gap + dat += "
    " + dat += "
    Set Belly Transfer Chance" + dat += " [selected.transferchance]%" + + dat += "
    Set Belly Transfer Location" + dat += " [selected.transferlocation ? selected.transferlocation : "Disabled"]" + + //Special
    here to add a gap + dat += "
    " + dat += "
    Set Belly Digest Chance" + dat += " [selected.digestchance]%" + dat += "
    " + //Delete button dat += "
    Delete Belly" @@ -130,7 +181,9 @@ //Under the last HR, save and stuff. dat += "Save Prefs" dat += "Refresh" + dat += "Set Flavor" + dat += "
    " switch(user.digestable) if(TRUE) dat += "Toggle Digestable (Currently: ON)" @@ -151,12 +204,26 @@ for(var/H in href_list) if(href_list["close"]) - del(src) // Cleanup + qdel(src) // Cleanup return + if(href_list["show_int"]) + show_interacts = !show_interacts + return TRUE //Force update + + if(href_list["int_help"]) + to_chat(usr,"These control how your belly responds to someone using 'resist' while inside you. The percent chance to trigger each is listed below, \ + and you can change them to whatever you see fit. Setting them to 0% will disable the possibility of that interaction. \ + These only function as long as interactions are turned on in general. Keep in mind, the 'belly mode' interactions (digest) \ + will affect all prey in that belly, if one resists and triggers digestion. If multiple trigger at the same time, \ + only the first in the order of 'Escape > Transfer > Digest' will occur.") + return TRUE //Force update + if(href_list["outsidepick"]) - var/tgt = locate(href_list["outsidepick"]) + var/atom/movable/tgt = locate(href_list["outsidepick"]) var/datum/belly/OB = locate(href_list["outsidebelly"]) + if(!(tgt in OB.internal_contents)) //Aren't here anymore, need to update menu. + return TRUE var/intent = "Examine" if(istype(tgt,/mob/living)) @@ -184,7 +251,7 @@ if("Devour") //Eat the inside mob if(!user.vore_selected) to_chat(user, "Pick a belly on yourself first!") - return TRUE + return var/datum/belly/TB = user.vore_organs[user.vore_selected] to_chat(user, "You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!") @@ -202,6 +269,9 @@ else if(istype(tgt,/obj/item)) var/obj/item/T = tgt + if(!(tgt in OB.internal_contents)) + //Doesn't exist anymore, update. + return TRUE intent = alert("What do you want to do to that?","Query","Examine","Use Hand") switch(intent) if("Examine") @@ -210,7 +280,7 @@ if("Use Hand") if(user.stat) to_chat(user, "You can't do that in your state!") - return TRUE + return user.ClickOn(T) sleep(5) //Seems to exit too fast for the panel to update @@ -223,40 +293,38 @@ intent = alert("Eject all, Move all?","Query","Eject all","Cancel","Move all") switch(intent) if("Cancel") - return 1 + return if("Eject all") if(user.stat) to_chat(user, "You can't do that in your state!") - return TRUE + return selected.release_all_contents() - playsound(user, 'sound/vore/pred/escape.ogg', volume=80) - user.loc << "Everything is released from [user]!" + playsound(user, 'sound/vore/pred/escape.ogg', vol=80) + to_chat(user.loc,"Everything is released from [user]!") if("Move all") if(user.stat) to_chat(user, "You can't do that in your state!") - return TRUE + return var/choice = input("Move all where?","Select Belly") in user.vore_organs + "Cancel - Don't Move" if(choice == "Cancel - Don't Move") - return TRUE + return 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 - to_chat(tgt, "You're squished from [user]'s [selected] to their [B]!") + selected.transfer_contents(tgt, B, 1) for(var/mob/hearer in range(1,user)) hearer << sound('sound/vore/pred/stomachmove.ogg',volume=80) - return TRUE - var/atom/movable/tgt = locate(href_list["insidepick"]) + if(!(tgt in selected.internal_contents)) //Old menu, needs updating because they aren't really there. + return TRUE//Forces update intent = "Examine" intent = alert("Examine, Eject, Move? Examine if you want to leave this box.","Query","Examine","Eject","Move") switch(intent) @@ -266,7 +334,7 @@ if("Eject") if(user.stat) to_chat(user, "You can't do that in your state!") - return TRUE + return FALSE selected.release_specific_contents(tgt) playsound(user, 'sound/effects/splat.ogg', 50, 1) @@ -275,28 +343,28 @@ if("Move") if(user.stat) to_chat(user, "You can't do that in your state!") - return TRUE + return FALSE var/choice = input("Move [tgt] where?","Select Belly") in user.vore_organs + "Cancel - Don't Move" if(choice == "Cancel - Don't Move") - return TRUE + return else var/datum/belly/B = user.vore_organs[choice] - selected.internal_contents -= tgt - B.internal_contents += tgt - - to_chat(tgt, "You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(B.name)]!") + if (!(tgt in selected.internal_contents)) + return FALSE + to_chat(tgt, "You're moved from [user]'s [lowertext(selected.name)] to their [lowertext(B.name)]!") for(var/mob/hearer in range(1,user)) hearer << sound('sound/vore/pred/stomachmove.ogg',volume=80) + selected.transfer_contents(tgt, B) if(href_list["newbelly"]) - if(user.vore_organs.len >= 10) + if(user.vore_organs.len >= BELLIES_MAX) return TRUE 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) + if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN) to_chat(usr, "Entered belly name is too long.") return FALSE if(new_name in user.vore_organs) @@ -313,10 +381,13 @@ selected = locate(href_list["bellypick"]) user.vore_selected = selected.name + //// + //Please keep these the same order they are on the panel UI for ease of coding + //// if(href_list["b_name"]) var/new_name = html_encode(input(usr,"Belly's new name:","New Name") as text|null) - if(length(new_name) > 12 || length(new_name) < 2) + if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN) to_chat(usr, "Entered belly name length invalid (must be longer than 2, shorter than 12).") return FALSE if(new_name in user.vore_organs) @@ -344,14 +415,16 @@ 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(new_desc) + new_desc = readd_quotes(new_desc) + if(length(new_desc) > BELLIES_DESC_MAX) + to_chat(usr, "Entered belly desc too long. [BELLIES_DESC_MAX] character limit.") + return FALSE - if(length(new_desc) > 1024) - to_chat(usr, "Entered belly desc too long. 1024 character limit.") + selected.inside_flavor = new_desc + else //Returned null return FALSE - selected.inside_flavor = new_desc - if(href_list["b_msgs"]) var/list/messages = list( "Digest Message (to prey)", @@ -389,7 +462,7 @@ selected.set_messages(new_message,"smi") if("Examine Message (when full)") - var/new_message = input(user,"These are sent to people who examine you when this belly has contents. Write them in 3rd person ('Their %belly is bulging'). Do not use %pred or %prey in this type."+help,"Examine Message (when full)",selected.get_messages("em")) as message + var/new_message = input(user,"These are sent to people who examine you when this belly has contents. Write them in 3rd person ('Their %belly is bulging'). "+help,"Examine Message (when full)",selected.get_messages("em")) as message if(new_message) selected.set_messages(new_message,"em") @@ -402,13 +475,13 @@ selected.struggle_messages_inside = initial(selected.struggle_messages_inside) if("Cancel - No Changes") - return TRUE + return if(href_list["b_verb"]) var/new_verb = html_encode(input(usr,"New verb when eating (infinitive tense, e.g. nom or swallow):","New Verb") as text|null) - if(length(new_verb) > 12 || length(new_verb) < 2) - to_chat(usr, "Entered verb length invalid (must be longer than 2, shorter than 12).") + if(length(new_verb) > BELLIES_NAME_MAX || length(new_verb) < BELLIES_NAME_MIN) + to_chat(usr, "Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).") return FALSE selected.vore_verb = new_verb @@ -417,20 +490,90 @@ var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") in GLOB.pred_vore_sounds + "Cancel - No Changes" if(choice == "Cancel") - return 1 + return selected.vore_sound = GLOB.pred_vore_sounds[choice] if(href_list["b_soundtest"]) user << selected.vore_sound +/* + if(href_list["silenced"]) + if(selected.silenced == FALSE) + selected.silenced = TRUE + to_chat(usr,"The [selected.name] is now silenced, it will not play the internal loop to prey within it.") + else if(selected.silenced == TRUE) + selected.silenced = FALSE + to_chat(usr,"The [selected.name] will play the internal loop to prey within it.") +*/ + if(href_list["b_tastes"]) + selected.can_taste = !selected.can_taste + + if(href_list["b_escapable"]) + if(selected.escapable == FALSE) //Possibly escapable and special interactions. + selected.escapable = TRUE + to_chat(usr,"Prey now have special interactions with your [selected.name] depending on your settings.") + else if(selected.escapable == TRUE) //Never escapable. + selected.escapable = FALSE + to_chat(usr,"Prey will not be able to have special interactions with your [selected.name].") + show_interacts = FALSE //Force the hiding of the panel + else + to_chat(usr,"Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.") //If they somehow have a varable that's not 0 or 1 + selected.escapable = FALSE + show_interacts = FALSE //Force the hiding of the panel + + if(href_list["b_escapechance"]) + var/escape_chance_input = input(user, "Set prey escape chance on resist (as %)", "Prey Escape Chance") as num|null + if(!isnull(escape_chance_input)) //These have to be 'null' because both cancel and 0 are valid, separate options + selected.escapechance = sanitize_integer(escape_chance_input, 0, 100, initial(selected.escapechance)) + + if(href_list["b_escapetime"]) + var/escape_time_input = input(user, "Set number of seconds for prey to escape on resist (1-60)", "Prey Escape Time") as num|null + if(!isnull(escape_time_input)) + selected.escapetime = sanitize_integer(escape_time_input*10, 10, 600, initial(selected.escapetime)) + + if(href_list["b_transferchance"]) + var/transfer_chance_input = input(user, "Set belly transfer chance on resist (as %). You must also set the location for this to have any effect.", "Prey Escape Time") as num|null + if(!isnull(transfer_chance_input)) + selected.transferchance = sanitize_integer(transfer_chance_input, 0, 100, initial(selected.transferchance)) + + if(href_list["b_transferlocation"]) + var/choice = input("Where do you want your [selected.name] to lead if prey resists?","Select Belly") as null|anything in (user.vore_organs + "None - Remove" - selected.name) + + if(!choice) //They cancelled, no changes + return + else if(choice == "None - Remove") + selected.transferlocation = null + else + selected.transferlocation = user.vore_organs[choice] + + if(href_list["b_digestchance"]) + var/digest_chance_input = input(user, "Set belly digest mode chance on resist (as %)", "Prey Digest Chance") as num|null + if(!isnull(digest_chance_input)) + selected.digestchance = sanitize_integer(digest_chance_input, 0, 100, initial(selected.digestchance)) if(href_list["b_del"]) + var/dest_for = FALSE //Check to see if it's the destination of another vore organ. + for(var/I in user.vore_organs) + var/datum/belly/B = user.vore_organs[I] + if(B.transferlocation == selected) + dest_for = B.name + break + + if(dest_for) + alert("This is the destiantion for at least '[dest_for]' belly transfers. Remove it as the destination from any bellies before deleting it.","Error") + return TRUE + else if(selected.internal_contents.len) + alert("Can't delete bellies with contents!","Error") + return TRUE if(selected.internal_contents.len) to_chat(usr, "Can't delete bellies with contents!") + return else if(selected.immutable) to_chat(usr, "This belly is marked as undeletable.") + return else if(user.vore_organs.len == 1) to_chat(usr, "You must have at least one belly.") + return else var/alert = alert("Are you sure you want to delete [selected]?","Confirmation","Delete","Cancel") if(alert == "Delete" && !selected.internal_contents.len) @@ -438,6 +581,7 @@ user.vore_organs.Remove(selected) selected = user.vore_organs[1] user.vore_selected = user.vore_organs[1] + to_chat(usr,"Note: If you had this organ selected as a transfer location, please remove the transfer location by selecting Cancel - None - Remove on this stomach.") if(href_list["saveprefs"]) if(user.save_vore_prefs()) @@ -447,12 +591,23 @@ to_chat(user, "ERROR: Belly Preferences were not saved!") log_admin("Could not save vore prefs on USER: [user].") + if(href_list["setflavor"]) + var/new_flavor = html_encode(input(usr,"What your character tastes like (40ch limit). This text will be printed to the pred after 'X tastes of...' so just put something like 'strawberries and cream':","Character Flavor",user.vore_taste) as text|null) + + if(new_flavor) + new_flavor = readd_quotes(new_flavor) + if(length(new_flavor) > FLAVOR_MAX) + alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error") + return FALSE + user.vore_taste = new_flavor + else //Returned null + return FALSE 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 + return if("Allow Digestion") user.digestable = TRUE if("Prevent Digestion") @@ -465,7 +620,7 @@ 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 + return if("Allow Devourment") user.devourable = TRUE if("Prevent Devourment") @@ -475,4 +630,4 @@ user.client.prefs_vr.devourable = user.devourable //Refresh when interacted with, returning 1 makes vore_look.Topic update - return 1 + return TRUE diff --git a/tgstation.dme b/tgstation.dme index eed2515ce3..b1fd32e5c7 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -412,7 +412,6 @@ #include "code\game\gamemodes\objective.dm" #include "code\game\gamemodes\objective_items.dm" #include "code\game\gamemodes\objective_team.dm" -#include "code\game\gamemodes\brother\traitor_bro.dm" #include "code\game\gamemodes\blob\blob.dm" #include "code\game\gamemodes\blob\blob_finish.dm" #include "code\game\gamemodes\blob\blob_report.dm" @@ -425,6 +424,7 @@ #include "code\game\gamemodes\blob\blobs\node.dm" #include "code\game\gamemodes\blob\blobs\resource.dm" #include "code\game\gamemodes\blob\blobs\shield.dm" +#include "code\game\gamemodes\brother\traitor_bro.dm" #include "code\game\gamemodes\changeling\cellular_emporium.dm" #include "code\game\gamemodes\changeling\changeling.dm" #include "code\game\gamemodes\changeling\changeling_power.dm"