From f13fda0afb043f37daa5b1df286656c11d1f6bb4 Mon Sep 17 00:00:00 2001 From: ShadowLarkens Date: Sat, 8 Aug 2020 09:41:59 -0700 Subject: [PATCH 1/3] TGUI Vore Panel --- code/modules/vore/eating/living_vr.dm | 2 +- code/modules/vore/eating/vorepanel_vr.dm | 1759 +++++++++----------- tgui/packages/tgui/interfaces/VorePanel.js | 600 +++++++ 3 files changed, 1396 insertions(+), 965 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/VorePanel.js diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 76f11b8768..0570744028 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -43,7 +43,7 @@ M.verbs += /mob/living/proc/switch_scaling if(M.no_vore) //If the mob isn't supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach. return TRUE - M.vorePanel = new + M.vorePanel = new(M) M.verbs += /mob/living/proc/insidePanel //Tries to load prefs if a client is present otherwise gives freebie stomach diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 709138c47e..f125cb52ad 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -17,1026 +17,857 @@ if(!vorePanel) log_debug("[src] ([type], \ref[src]) didn't have a vorePanel and tried to use the verb.") - vorePanel = new + vorePanel = new(src) - vorePanel.selected = vore_selected - vorePanel.show(src) + vorePanel.tgui_interact(src) /mob/living/proc/updateVRPanel() //Panel popup update call from belly events. - if(!vorePanel) - log_debug("[src] ([type], \ref[src]) didn't have a vorePanel and something tried to update it.") - vorePanel = new - - if(vorePanel.open) - vorePanel.selected = vore_selected - vorePanel.show(src) + SStgui.update_uis(vorePanel) // // Callback Handler for the Inside form // /datum/vore_look - var/datum/browser/popup - var/obj/belly/selected - var/show_interacts = 0 - var/open = FALSE + var/mob/living/host // Note, we do this in case we ever want to allow people to view others vore panels -/datum/vore_look/Destroy() - selected = null - QDEL_NULL(popup) +/datum/vore_look/New(mob/living/new_host) + if(istype(new_host)) + host = new_host . = ..() -/datum/vore_look/Topic(href,href_list[]) - if(vp_interact(href, href_list) && popup) - popup.set_content(gen_ui(usr)) - usr << output(popup.get_content(), "insidePanel.browser") +/datum/vore_look/Destroy() + host = null + . = ..() -/datum/vore_look/proc/show(mob/living/user) - if(popup) - QDEL_NULL(popup) - popup = new(user, "insidePanel", "Inside!", 450, 700, src) - popup.set_content(gen_ui(user)) - popup.open() - open = TRUE +/datum/vore_look/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "VorePanel", "Inside!") + ui.open() -/datum/vore_look/proc/gen_ui(var/mob/living/user) - var/list/dat = list() +// This looks weird, but all tgui_host is used for is state checking +// So this allows us to use the self_state just fine. +/datum/vore_look/tgui_host(mob/user) + return host - var/atom/userloc = user.loc - if(isbelly(userloc)) - var/obj/belly/inside_belly = userloc - var/mob/living/eater = inside_belly.owner +// Note, in order to allow others to look at others vore panels, this state would need +// to be changed to tgui_always_state, and a custom tgui_status() implemented for true "rights" management. +/datum/vore_look/tgui_state(mob/user) + return GLOB.tgui_self_state - dat += "You are currently [user.absorbed ? "absorbed into " : "inside "] [eater]'s [inside_belly.name]!

" +/datum/vore_look/var/static/list/nom_icons +/datum/vore_look/proc/cached_nom_icon(atom/target) + LAZYINITLIST(nom_icons) - if(inside_belly.desc) - dat += "[inside_belly.desc]

" //Extra br - - if(inside_belly.contents.len > 1) - dat += "You can see the following around you:
" - var/list/belly_contents = list() - for (var/atom/movable/O in inside_belly) - if(istype(O,/mob/living)) - var/mob/living/M = O - //That's just you - if(M == user) - continue - - //That's an absorbed person you're checking - if(M.absorbed) - if(user.absorbed) - belly_contents += "[O]" - continue - else - continue - - //Anything else - dat += "[O]​" - - //Zero-width space, for wrapping - dat += "​" - - dat += jointext(belly_contents, null) //Add in belly contents to main running list + var/key = "" + if(isobj(target)) + key = "[target.type]" + else if(ismob(target)) + var/mob/M = target + key = "\ref[target][M.real_name]" + if(nom_icons[key]) + . = nom_icons[key] else - dat += "You aren't inside anyone." + . = icon2base64(getFlatIcon(target,defdir=SOUTH,no_anim=TRUE)) + nom_icons[key] = . - var/list/belly_list = list("
    ") - for(var/belly in user.vore_organs) - var/obj/belly/B = belly - if(B == selected) - belly_list += "
  1. [B.name]" - else - belly_list += "
  2. [B.name]" - var/spanstyle - switch(B.digest_mode) - if(DM_HOLD) - spanstyle = "" - if(DM_DIGEST) - spanstyle = "color:red;" - if(DM_ABSORB) - spanstyle = "color:purple;" - if(DM_DRAIN) - spanstyle = "color:purple;" - if(DM_HEAL) - spanstyle = "color:green;" - if(DM_SHRINK) - spanstyle = "color:purple;" - if(DM_GROW) - spanstyle = "color:purple;" - if(DM_SIZE_STEAL) - spanstyle = "color:purple;" - if(DM_TRANSFORM_MALE) - spanstyle = "color:purple;" - if(DM_TRANSFORM_HAIR_AND_EYES) - spanstyle = "color:purple;" - if(DM_TRANSFORM_FEMALE) - spanstyle = "color:purple;" - if(DM_TRANSFORM_KEEP_GENDER) - spanstyle = "color:purple;" - if(DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR) - spanstyle = "color:purple;" - if(DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG) - spanstyle = "color:purple;" - if(DM_TRANSFORM_REPLICA) - spanstyle = "color:purple;" - if(DM_TRANSFORM_REPLICA_EGG) - spanstyle = "color:purple;" - if(DM_TRANSFORM_KEEP_GENDER_EGG) - spanstyle = "color:purple;" - if(DM_TRANSFORM_MALE_EGG) - spanstyle = "color:purple;" - if(DM_TRANSFORM_FEMALE_EGG) - spanstyle = "color:purple;" - if(DM_EGG) - spanstyle = "color:purple;" +/datum/vore_look/tgui_data(mob/user) + var/list/data = list() - belly_list += " ([B.contents.len])
  3. " + if(!host) + return data - if(user.vore_organs.len < BELLIES_MAX) - belly_list += "
  4. New+
  5. " - belly_list += "

" + data["inside"] = list() + var/atom/hostloc = host.loc + if(isbelly(hostloc)) + var/obj/belly/inside_belly = hostloc + var/mob/living/pred = inside_belly.owner - dat += jointext(belly_list, null) //Add in belly list to main running list - - // Selected Belly (contents, configuration) - if(!selected) - dat += "No belly selected. Click one to select it." - else - var/list/belly_contents = list() - if(selected.contents.len) - belly_contents += "Contents: " - for(var/O in selected) - - //Mobs can be absorbed, so treat them separately from everything else - if(istype(O,/mob/living)) - var/mob/living/M = O - - //Absorbed gets special color OOoOOOOoooo - if(M.absorbed) - belly_contents += "[O]" - continue - - //Anything else - belly_contents += "[O]" - - //Zero-width space, for wrapping - belly_contents += "​" - - //If there's more than one thing, add an [All] button - if(selected.contents.len > 1) - belly_contents += "\[All\]" - - belly_contents += "
" - - if(belly_contents.len) - dat += jointext(belly_contents, null) - - //Belly Name Button - dat += "
Name: '[selected.name]'" - - //Belly Type button - dat += "
Is this belly fleshy: [selected.is_wet ? "Yes" : "No"]" - if(selected.is_wet) - dat += "
Internal loop for prey?: [selected.wet_loop ? "Yes" : "No"]" - - //Digest Mode Button - var/mode = selected.digest_mode - dat += "
Belly Mode: [mode]" - - //Mode addons button - var/list/flag_list = list() - for(var/flag_name in selected.mode_flag_list) - if(selected.mode_flags & selected.mode_flag_list[flag_name]) - flag_list += flag_name - if(flag_list.len) - dat += "
Mode Addons: [english_list(flag_list)]" - else - dat += "
Mode Addons: None" - - //Item Digest Mode Button - dat += "
Item Mode: [selected.item_digest_mode]" - - //Will it contaminate contents? - dat += "
Contaminates: [selected.contaminates ? "Yes" : "No"]" - - if(selected.contaminates) - //Contamination descriptors - dat += "
Contamination Flavor: [selected.contamination_flavor]" - //Contamination color - dat += "
Contamination Color: [selected.contamination_color]" - - //Belly verb - dat += "
Vore Verb: '[selected.vore_verb]'" - - //Inside flavortext - dat += "
Flavor Text: '[selected.desc]'" - - //Belly Sound Fanciness - dat += "
Use Fancy Sounds: [selected.fancy_vore ? "Yes" : "No"]" - - //Belly sound - dat += "
Vore Sound: [selected.vore_sound] Test" - - //Release sound - dat += "
Release Sound: [selected.release_sound] Test" - - //Belly messages - dat += "
Belly Messages" - - //Can belly taste? - dat += "
Can Taste: [selected.can_taste ? "Yes" : "No"]" - - //Nutritional percentage - dat += "
Nutritional Gain: [selected.nutrition_percent]%" - - //How much brute damage - dat += "
Digest Brute Damage: [selected.digest_brute]" - - //How much burn damage - dat += "
Digest Burn Damage: [selected.digest_burn]" - - //Minimum size prey must be to show up. - dat += "
Required examine size: [selected.bulge_size*100]%" - - //Size that prey will be grown/shrunk to. - dat += "
Shrink/Grow size: [selected.shrink_grow_size*100]%" - - //Belly escapability - dat += "
Belly Interactions ([selected.escapable ? "On" : "Off"])" - if(selected.escapable) - dat += "[show_interacts ? "Hide" : "Show"]" - - if(show_interacts && selected.escapable) - var/list/interacts = list() - interacts += "
" - interacts += "Interaction Settings ?" - interacts += "
Set Belly Escape Chance" - interacts += " [selected.escapechance]%" - - interacts += "
Set Belly Escape Time" - interacts += " [selected.escapetime/10]s" - - //Special
here to add a gap - interacts += "
" - interacts += "
Set Belly Transfer Chance" - interacts += " [selected.transferchance]%" - - interacts += "
Set Belly Transfer Location" - interacts += " [selected.transferlocation ? selected.transferlocation : "Disabled"]" - - //Special
here to add a gap - interacts += "
" - interacts += "
Set Belly Absorb Chance" - interacts += " [selected.absorbchance]%" - - interacts += "
Set Belly Digest Chance" - interacts += " [selected.digestchance]%" - interacts += "
" - dat += jointext(interacts, null) - - //Delete button - dat += "Delete Belly" - - dat += "
" - - var/list/nightmare_list = list() - switch(user.digestable) - if(TRUE) - nightmare_list += "Toggle Digestable (Currently: ON)" - if(FALSE) - nightmare_list += "Toggle Digestable (Currently: OFF)" - switch(user.devourable) - if(TRUE) - nightmare_list += "Toggle Devourable (Currently: ON)" - if(FALSE) - nightmare_list += "Toggle Devourable (Currently: OFF)" - switch(user.feeding) - if(TRUE) - nightmare_list += "
Toggle Feeding (Currently: ON)" - if(FALSE) - nightmare_list += "
Toggle Feeding (Currently: OFF)" - switch(user.absorbable) - if(TRUE) - nightmare_list += "Toggle Absorbtion Permission (Currently: ON)" - if(FALSE) - nightmare_list += "Toggle Absorbtion Permission (Currently: OFF)" - switch(user.digest_leave_remains) - if(TRUE) - nightmare_list += "Toggle Leaving Remains (Currently: ON)" - if(FALSE) - nightmare_list += "Toggle Leaving Remains (Currently: OFF)" - switch(user.allowmobvore) - if(TRUE) - nightmare_list += "
Toggle Mob Vore (Currently: ON)" - if(FALSE) - nightmare_list += "
Toggle Mob Vore (Currently: OFF)" - switch(user.permit_healbelly) - if(TRUE) - nightmare_list += "Toggle Healbelly Permission (Currently: ON)" - if(FALSE) - nightmare_list += "Toggle Healbelly Permission (Currently: OFF)" - - switch(user.can_be_drop_prey) - if(TRUE) - nightmare_list += "
Toggle Prey Spontaneous Vore (Currently: ON)" - if(FALSE) - nightmare_list += "
Toggle Prey Spontaneous Vore (Currently: OFF)" - - switch(user.can_be_drop_pred) - if(TRUE) - nightmare_list += "Toggle Pred Spontaneous Vore (Currently: ON)" - if(FALSE) - nightmare_list += "Toggle Pred Spontaneous Vore (Currently: OFF)" - - dat += jointext(nightmare_list, null) //AAAA - - dat += "
Set Your Taste" - dat += "
Set Your Smell" - dat += "
Toggle Hunger Noises" - - //Under the last HR, save and stuff. - dat += "
Save Prefs" - dat += "
Refresh" - dat += "
Reload Slot Prefs" - - //Returns the dat html to the vore_look - return jointext(dat, null) - -/datum/vore_look/proc/vp_interact(href, href_list) - var/mob/living/user = usr - if(href_list["close"]) - open = FALSE - QDEL_NULL(popup) - return - - if(href_list["show_int"]) - show_interacts = !show_interacts - return TRUE //Force update - - if(href_list["int_help"]) - alert("These control how your belly responds to someone using 'resist' while inside you. The percent chance to trigger each is listed below, \ - and you can change them to whatever you see fit. Setting them to 0% will disable the possibility of that interaction. \ - These only function as long as interactions are turned on in general. Keep in mind, the 'belly mode' interactions (digest/absorb) \ - will affect all prey in that belly, if one resists and triggers digestion/absorption. If multiple trigger at the same time, \ - only the first in the order of 'Escape > Transfer > Absorb > Digest' will occur.","Interactions Help") - return FALSE //Force update - - if(href_list["outsidepick"]) - var/atom/movable/tgt = locate(href_list["outsidepick"]) - var/obj/belly/OB = locate(href_list["outsidebelly"]) - if(!(tgt in OB)) //Aren't here anymore, need to update menu. - return TRUE - var/intent = "Examine" - - if(istype(tgt,/mob/living)) - var/mob/living/M = tgt - intent = alert("What do you want to do to them?","Query","Examine","Help Out","Devour") - switch(intent) - if("Examine") //Examine a mob inside another mob - var/list/results = M.examine(user) - if(!results || !results.len) - results = list("You were unable to examine that. Tell a developer!") - to_chat(user, jointext(results, "
")) - return FALSE - - if("Help Out") //Help the inside-mob out - if(user.stat || user.absorbed || M.absorbed) - to_chat(user,"You can't do that in your state!") - return TRUE - - to_chat(user,"You begin to push [M] to freedom!") - to_chat(M,"[usr] begins to push you to freedom!") - to_chat(M.loc,"Someone is trying to escape from inside you!") - sleep(50) - if(prob(33)) - OB.release_specific_contents(M) - to_chat(usr,"You manage to help [M] to safety!") - to_chat(M,"[user] pushes you free!") - to_chat(OB.owner,"[M] forces free of the confines of your body!") - else - to_chat(user,"[M] slips back down inside despite your efforts.") - to_chat(M," Even with [user]'s help, you slip back inside again.") - to_chat(OB.owner,"Your body efficiently shoves [M] back where they belong.") - - if("Devour") //Eat the inside mob - if(user.absorbed || user.stat) - to_chat(user,"You can't do that in your state!") - return TRUE - - if(!user.vore_selected) - to_chat(user,"Pick a belly on yourself first!") - return TRUE - - var/obj/belly/TB = user.vore_selected - to_chat(user,"You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!") - to_chat(M,"[user] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!") - to_chat(OB.owner,"Someone inside you is eating someone else!") - - sleep(TB.nonhuman_prey_swallow_time) //Can't do after, in a stomach, weird things abound. - if((user in OB) && (M in OB)) //Make sure they're still here. - to_chat(user,"You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!") - to_chat(M,"[user] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!") - to_chat(OB.owner,"Someone inside you has eaten someone else!") - TB.nom_mob(M) - - else if(istype(tgt,/obj/item)) - var/obj/item/T = tgt - if(!(tgt in OB)) - //Doesn't exist anymore, update. - return TRUE - intent = alert("What do you want to do to that?","Query","Examine","Use Hand") - switch(intent) - if("Examine") - var/list/results = T.examine(user) - if(!results || !results.len) - results = list("You were unable to examine that. Tell a developer!") - to_chat(user, jointext(results, "
")) - return FALSE - - if("Use Hand") - if(user.stat) - to_chat(user,"You can't do that in your state!") - return TRUE - - user.ClickOn(T) - sleep(5) //Seems to exit too fast for the panel to update - - if(href_list["insidepick"]) - var/intent - - //Handle the [All] choice. Ugh inelegant. Someone make this pretty. - if(href_list["pickall"]) - intent = alert("Eject all, Move all?","Query","Eject all","Cancel","Move all") - switch(intent) - if("Cancel") - return FALSE - - if("Eject all") - if(user.stat) - to_chat(user,"You can't do that in your state!") - return FALSE - - selected.release_all_contents() - - if("Move all") - if(user.stat) - to_chat(user,"You can't do that in your state!") - return FALSE - - var/obj/belly/choice = input("Move all where?","Select Belly") as null|anything in user.vore_organs - if(!choice) - return FALSE - - for(var/atom/movable/tgt in selected) - to_chat(tgt,"You're squished from [user]'s [lowertext(selected)] to their [lowertext(choice.name)]!") - selected.transfer_contents(tgt, choice, 1) - - var/atom/movable/tgt = locate(href_list["insidepick"]) - if(!(tgt in selected)) //Old menu, needs updating because they aren't really there. - return TRUE //Forces update - intent = "Examine" - intent = alert("Examine, Eject, Move? Examine if you want to leave this box.","Query","Examine","Eject","Move") - switch(intent) - if("Examine") - var/list/results = tgt.examine(user) - if(!results || !results.len) - results = list("You were unable to examine that. Tell a developer!") - to_chat(user, jointext(results, "
")) - return FALSE - - if("Eject") - if(user.stat) - to_chat(user,"You can't do that in your state!") - return FALSE - - selected.release_specific_contents(tgt) - - if("Move") - if(user.stat) - to_chat(user,"You can't do that in your state!") - return FALSE - - var/obj/belly/choice = input("Move [tgt] where?","Select Belly") as null|anything in user.vore_organs - if(!choice || !(tgt in selected)) - return FALSE - - to_chat(tgt,"You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(choice.name)]!") - selected.transfer_contents(tgt, choice) - - if(href_list["newbelly"]) - if(user.vore_organs.len >= BELLIES_MAX) - return FALSE - - var/new_name = html_encode(input(usr,"New belly's name:","New Belly") as text|null) - - var/failure_msg - if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN) - failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])." - // else if(whatever) //Next test here. - else - for(var/belly in user.vore_organs) - var/obj/belly/B = belly - if(lowertext(new_name) == lowertext(B.name)) - failure_msg = "No duplicate belly names, please." - break - - if(failure_msg) //Something went wrong. - alert(user,failure_msg,"Error!") - return FALSE - - var/obj/belly/NB = new(user) - NB.name = new_name - selected = NB - - if(href_list["bellypick"]) - selected = locate(href_list["bellypick"]) - user.vore_selected = selected - - //// - //Please keep these the same order they are on the panel UI for ease of coding - //// - if(href_list["b_name"]) - var/new_name = html_encode(input(usr,"Belly's new name:","New Name") as text|null) - - var/failure_msg - if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN) - failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])." - // else if(whatever) //Next test here. - else - for(var/belly in user.vore_organs) - var/obj/belly/B = belly - if(lowertext(new_name) == lowertext(B.name)) - failure_msg = "No duplicate belly names, please." - break - - if(failure_msg) //Something went wrong. - alert(user,failure_msg,"Error!") - return FALSE - - selected.name = new_name - - if(href_list["b_wetness"]) - selected.is_wet = !selected.is_wet - - if(href_list["b_wetloop"]) - selected.wet_loop = !selected.wet_loop - - if(href_list["b_mode"]) - var/list/menu_list = selected.digest_modes.Copy() - if(istype(usr,/mob/living/carbon/human)) - menu_list += DM_TRANSFORM - - var/new_mode = input("Choose Mode (currently [selected.digest_mode])") as null|anything in menu_list - if(!new_mode) - return FALSE - - if(new_mode == DM_TRANSFORM) //Snowflek submenu - var/list/tf_list = selected.transform_modes - var/new_tf_mode = input("Choose TF Mode (currently [selected.digest_mode])") as null|anything in tf_list - if(!new_tf_mode) - return FALSE - selected.digest_mode = new_tf_mode - return - - selected.digest_mode = new_mode - //selected.items_preserved.Cut() //Re-evaltuate all items in belly on belly-mode change //Handled with item modes now - - if(href_list["b_addons"]) - var/list/menu_list = selected.mode_flag_list.Copy() - var/toggle_addon = input("Toggle Addon") as null|anything in menu_list - if(!toggle_addon) - return FALSE - selected.mode_flags ^= selected.mode_flag_list[toggle_addon] - selected.items_preserved.Cut() //Re-evaltuate all items in belly on addon toggle - - if(href_list["b_item_mode"]) - var/list/menu_list = selected.item_digest_modes.Copy() - - var/new_mode = input("Choose Mode (currently [selected.item_digest_mode])") as null|anything in menu_list - if(!new_mode) - return FALSE - - selected.item_digest_mode = new_mode - selected.items_preserved.Cut() //Re-evaltuate all items in belly on belly-mode change - - if(href_list["b_contaminates"]) - selected.contaminates = !selected.contaminates - - if(href_list["b_contamination_flavor"]) - var/list/menu_list = contamination_flavors.Copy() - var/new_flavor = input("Choose Contamination Flavor Text Type (currently [selected.contamination_flavor])") as null|anything in menu_list - if(!new_flavor) - return FALSE - selected.contamination_flavor = new_flavor - - if(href_list["b_contamination_color"]) - var/list/menu_list = contamination_colors.Copy() - var/new_color = input("Choose Contamination Color (currently [selected.contamination_color])") as null|anything in menu_list - if(!new_color) - return FALSE - selected.contamination_color = new_color - selected.items_preserved.Cut() //To re-contaminate for new color - - if(href_list["b_desc"]) - var/new_desc = html_encode(input(usr,"Belly Description ([BELLIES_DESC_MAX] char limit):","New Description",selected.desc) as message|null) - - if(new_desc) - new_desc = readd_quotes(new_desc) - if(length(new_desc) > BELLIES_DESC_MAX) - alert("Entered belly desc too long. [BELLIES_DESC_MAX] character limit.","Error") - return FALSE - selected.desc = new_desc - else //Returned null - return FALSE - - if(href_list["b_msgs"]) - var/list/messages = list( - "Digest Message (to prey)", - "Digest Message (to you)", - "Struggle Message (outside)", - "Struggle Message (inside)", - "Examine Message (when full)", - "Reset All To Default" + data["inside"] = list( + "absorbed" = host.absorbed, + "belly_name" = inside_belly.name, + "belly_mode" = inside_belly.digest_mode, + "desc" = inside_belly.desc || "No description.", + "pred" = pred, + "ref" = "\ref[inside_belly]", ) - alert(user,"Setting abusive or deceptive messages will result in a ban. Consider this your warning. Max 150 characters per message, max 10 messages per topic.","Really, don't.") - var/choice = input(user,"Select a type to modify. Messages from each topic are pulled at random when needed.","Pick Type") as null|anything in messages - var/help = " Press enter twice to separate messages. '%pred' will be replaced with your name. '%prey' will be replaced with the prey's name. '%belly' will be replaced with your belly's name." + data["inside"]["contents"] = list() + for(var/atom/movable/O in inside_belly) + if(O == host) + continue - 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") + var/list/info = list( + "name" = "[O]", + "icon" = cached_nom_icon(O), + "absorbed" = FALSE, + "stat" = 0, + "ref" = "\ref[O]", + "outside" = FALSE, + ) + if(isliving(O)) + var/mob/living/M = O + info["stat"] = M.stat + if(M.absorbed) + info["absorbed"] = TRUE + data["inside"]["contents"].Add(list(info)) - 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") + data["our_bellies"] = list() + for(var/belly in host.vore_organs) + var/obj/belly/B = belly + data["our_bellies"].Add(list(list( + "selected" = (B == host.vore_selected), + "name" = B.name, + "ref" = "\ref[B]", + "digest_mode" = B.digest_mode, + "contents" = LAZYLEN(B.contents), + ))) - 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") + data["selected"] = null + if(host.vore_selected) + var/obj/belly/selected = host.vore_selected + data["selected"] = list( + "belly_name" = selected.name, + "is_wet" = selected.is_wet, + "wet_loop" = selected.wet_loop, + "mode" = selected.digest_mode, + "item_mode" = selected.item_digest_mode, + "verb" = selected.vore_verb, + "desc" = selected.desc, + "fancy" = selected.fancy_vore, + "sound" = selected.vore_sound, + "release_sound" = selected.release_sound, + // "messages" // TODO + "can_taste" = selected.can_taste, + "nutrition_percent" = selected.nutrition_percent, + "digest_brute" = selected.digest_brute, + "digest_burn" = selected.digest_burn, + "bulge_size" = selected.bulge_size, + "shrink_grow_size" = selected.shrink_grow_size, + ) - 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") + data["selected"]["addons"] = list() + for(var/flag_name in selected.mode_flag_list) + if(selected.mode_flags & selected.mode_flag_list[flag_name]) + data["selected"]["addons"].Add(flag_name) - if("Examine Message (when full)") - var/new_message = input(user,"These are sent to people who examine you when this belly has contents. Write them in 3rd person ('Their %belly is bulging')."+help,"Examine Message (when full)",selected.get_messages("em")) as message - if(new_message) - selected.set_messages(new_message,"em") + data["selected"]["contaminates"] = selected.contaminates + data["selected"]["contaminate_flavor"] = null + data["selected"]["contaminate_color"] = null + if(selected.contaminates) + data["selected"]["contaminate_flavor"] = selected.contamination_flavor + data["selected"]["contaminate_color"] = selected.contamination_color - 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) + data["selected"]["escapable"] = selected.escapable + data["selected"]["interacts"] = list() + if(selected.escapable) + data["selected"]["interacts"]["escapechance"] = selected.escapechance + data["selected"]["interacts"]["escapetime"] = selected.escapetime + data["selected"]["interacts"]["transferchance"] = selected.transferchance + data["selected"]["interacts"]["transferlocation"] = selected.transferlocation + data["selected"]["interacts"]["absorbchance"] = selected.absorbchance + data["selected"]["interacts"]["digestchance"] = selected.digestchance - 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) + data["selected"]["contents"] = list() + for(var/O in selected) + var/list/info = list( + "name" = "[O]", + "icon" = cached_nom_icon(O), + "absorbed" = FALSE, + "stat" = 0, + "ref" = "\ref[O]", + "outside" = TRUE, + ) + if(isliving(O)) + var/mob/living/M = O + info["stat"] = M.stat + if(M.absorbed) + info["absorbed"] = TRUE + data["selected"]["contents"].Add(list(info)) - if(length(new_verb) > BELLIES_NAME_MAX || length(new_verb) < BELLIES_NAME_MIN) - alert("Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).","Error") - return FALSE + data["prefs"] = list( + "digestable" = host.digestable, + "devourable" = host.devourable, + "feeding" = host.feeding, + "absorbable" = host.absorbable, + "digest_leave_remains" = host.digest_leave_remains, + "allowmobvore" = host.allowmobvore, + "permit_healbelly" = host.permit_healbelly, + "can_be_drop_prey" = host.can_be_drop_prey, + "can_be_drop_pred" = host.can_be_drop_pred, + "noisy" = host.noisy, + ) - selected.vore_verb = new_verb + return data - if(href_list["b_fancy_sound"]) - selected.fancy_vore = !selected.fancy_vore - selected.vore_sound = "Gulp" - selected.release_sound = "Splatter" - // defaults as to avoid potential bugs +/datum/vore_look/tgui_act(action, params) + if(..()) + return TRUE - if(href_list["b_release"]) - var/choice - if(selected.fancy_vore) - choice = input(user,"Currently set to [selected.release_sound]","Select Sound") as null|anything in fancy_release_sounds - else - choice = input(user,"Currently set to [selected.release_sound]","Select Sound") as null|anything in classic_release_sounds + switch(action) + if("int_help") + alert("These control how your belly responds to someone using 'resist' while inside you. The percent chance to trigger each is listed below, \ + and you can change them to whatever you see fit. Setting them to 0% will disable the possibility of that interaction. \ + These only function as long as interactions are turned on in general. Keep in mind, the 'belly mode' interactions (digest/absorb) \ + will affect all prey in that belly, if one resists and triggers digestion/absorption. If multiple trigger at the same time, \ + only the first in the order of 'Escape > Transfer > Absorb > Digest' will occur.","Interactions Help") + return TRUE - if(!choice) - return FALSE + // Host is inside someone else, and is trying to interact with something else inside that person. + if("pick_from_inside") + return pick_from_inside(usr, params) + + // Host is trying to interact with something in host's belly. + if("pick_from_outside") + return pick_from_outside(usr, params) - selected.release_sound = choice - - if(href_list["b_releasesoundtest"]) - var/sound/releasetest - if(selected.fancy_vore) - releasetest = fancy_release_sounds[selected.release_sound] - else - releasetest = classic_release_sounds[selected.release_sound] - - if(releasetest) - SEND_SOUND(user, releasetest) - - if(href_list["b_sound"]) - var/choice - if(selected.fancy_vore) - choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in fancy_vore_sounds - else - choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in classic_vore_sounds - - if(!choice) - return FALSE - - selected.vore_sound = choice - - if(href_list["b_soundtest"]) - var/sound/voretest - if(selected.fancy_vore) - voretest = fancy_vore_sounds[selected.vore_sound] - else - voretest = classic_vore_sounds[selected.vore_sound] - if(voretest) - SEND_SOUND(user, voretest) - - if(href_list["b_tastes"]) - selected.can_taste = !selected.can_taste - - if(href_list["b_bulge_size"]) - var/new_bulge = input(user, "Choose the required size prey must be to show up on examine, ranging from 25% to 200% Set this to 0 for no text on examine.", "Set Belly Examine Size.") as num|null - if(new_bulge == null) - return - if(new_bulge == 0) //Disable. - selected.bulge_size = 0 - to_chat(user,"Your stomach will not be seen on examine.") - else if (!ISINRANGE(new_bulge,25,200)) - selected.bulge_size = 0.25 //Set it to the default. - to_chat(user,"Invalid size.") - else if(new_bulge) - selected.bulge_size = (new_bulge/100) - - if(href_list["b_grow_shrink"]) - var/new_grow = input(user, "Choose the size that prey will be grown/shrunk to, ranging from 25% to 200%", "Set Growth Shrink Size.", selected.shrink_grow_size) as num|null - if (new_grow == null) - return - if (!ISINRANGE(new_grow,25,200)) - selected.shrink_grow_size = 1 //Set it to the default - to_chat(user,"Invalid size.") - else if(new_grow) - selected.shrink_grow_size = (new_grow*0.01) - - if(href_list["b_nutritionpercent"]) - var/new_damage = input(user, "Choose the nutrition gain percentage you will recieve per tick from prey. Ranges from 0.01 to 100.", "Set Nutrition Gain Percentage.", selected.digest_brute) as num|null - if(new_damage == null) - return - var/new_new_damage = CLAMP(new_damage, 0.01, 100) - selected.nutrition_percent = new_new_damage - - if(href_list["b_burn_dmg"]) - var/new_damage = input(user, "Choose the amount of burn damage prey will take per tick. Ranges from 0 to 6.", "Set Belly Burn Damage.", selected.digest_burn) as num|null - if(new_damage == null) - return - var/new_new_damage = CLAMP(new_damage, 0, 6) - selected.digest_burn = new_new_damage - - if(href_list["b_brute_dmg"]) - var/new_damage = input(user, "Choose the amount of brute damage prey will take per tick. Ranges from 0 to 6", "Set Belly Brute Damage.", selected.digest_brute) as num|null - if(new_damage == null) - return - var/new_new_damage = CLAMP(new_damage, 0, 6) - selected.digest_brute = new_new_damage - - if(href_list["b_escapable"]) - if(selected.escapable == 0) //Possibly escapable and special interactions. - selected.escapable = 1 - to_chat(usr,"Prey now have special interactions with your [lowertext(selected.name)] depending on your settings.") - else if(selected.escapable == 1) //Never escapable. - selected.escapable = 0 - to_chat(usr,"Prey will not be able to have special interactions with your [lowertext(selected.name)].") - show_interacts = 0 //Force the hiding of the panel - else - alert("Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.","Error") //If they somehow have a varable that's not 0 or 1 - selected.escapable = 0 - show_interacts = 0 //Force the hiding of the panel - - if(href_list["b_escapechance"]) - var/escape_chance_input = input(user, "Set prey escape chance on resist (as %)", "Prey Escape Chance") as num|null - if(!isnull(escape_chance_input)) //These have to be 'null' because both cancel and 0 are valid, separate options - selected.escapechance = sanitize_integer(escape_chance_input, 0, 100, initial(selected.escapechance)) - - if(href_list["b_escapetime"]) - var/escape_time_input = input(user, "Set number of seconds for prey to escape on resist (1-60)", "Prey Escape Time") as num|null - if(!isnull(escape_time_input)) - selected.escapetime = sanitize_integer(escape_time_input*10, 10, 600, initial(selected.escapetime)) - - if(href_list["b_transferchance"]) - var/transfer_chance_input = input(user, "Set belly transfer chance on resist (as %). You must also set the location for this to have any effect.", "Prey Escape Time") as num|null - if(!isnull(transfer_chance_input)) - selected.transferchance = sanitize_integer(transfer_chance_input, 0, 100, initial(selected.transferchance)) - - if(href_list["b_transferlocation"]) - var/obj/belly/choice = input("Where do you want your [lowertext(selected.name)] to lead if prey resists?","Select Belly") as null|anything in (user.vore_organs + "None - Remove" - selected) - - if(!choice) //They cancelled, no changes - return FALSE - else if(choice == "None - Remove") - selected.transferlocation = null - else - selected.transferlocation = choice.name - - if(href_list["b_absorbchance"]) - var/absorb_chance_input = input(user, "Set belly absorb mode chance on resist (as %)", "Prey Absorb Chance") as num|null - if(!isnull(absorb_chance_input)) - selected.absorbchance = sanitize_integer(absorb_chance_input, 0, 100, initial(selected.absorbchance)) - - if(href_list["b_digestchance"]) - var/digest_chance_input = input(user, "Set belly digest mode chance on resist (as %)", "Prey Digest Chance") as num|null - if(!isnull(digest_chance_input)) - selected.digestchance = sanitize_integer(digest_chance_input, 0, 100, initial(selected.digestchance)) - - if(href_list["b_del"]) - var/alert = alert("Are you sure you want to delete your [lowertext(selected.name)]?","Confirmation","Delete","Cancel") - if(!(alert == "Delete")) - return FALSE - - var/failure_msg = "" - - var/dest_for //Check to see if it's the destination of another vore organ. - for(var/belly in user.vore_organs) - var/obj/belly/B = belly - if(B.transferlocation == selected) - dest_for = B.name - failure_msg += "This is the destiantion for at least '[dest_for]' belly transfers. Remove it as the destination from any bellies before deleting it. " - break - - if(selected.contents.len) - failure_msg += "You cannot delete bellies with contents! " //These end with spaces, to be nice looking. Make sure you do the same. - if(selected.immutable) - failure_msg += "This belly is marked as undeletable. " - if(user.vore_organs.len == 1) - failure_msg += "You must have at least one belly. " - - if(failure_msg) - alert(user,failure_msg,"Error!") - return FALSE - - qdel(selected) - selected = user.vore_organs[1] - user.vore_selected = user.vore_organs[1] - - if(href_list["saveprefs"]) - if(!user.save_vore_prefs()) - alert("ERROR: Virgo-specific preferences failed to save!","Error") - else - to_chat(user,"Virgo-specific preferences saved!") - - if(href_list["applyprefs"]) - var/alert = alert("Are you sure you want to reload character slot preferences? This will remove your current vore organs and eject their contents.","Confirmation","Reload","Cancel") - if(alert != "Reload") - return FALSE - if(!user.apply_vore_prefs()) - alert("ERROR: Virgo-specific preferences failed to apply!","Error") - else - to_chat(user,"Virgo-specific preferences applied from active slot!") - - if(href_list["setflavor"]) - var/new_flavor = html_encode(input(usr,"What your character tastes like (40ch limit). This text will be printed to the pred after 'X tastes of...' so just put something like 'strawberries and cream':","Character Flavor",user.vore_taste) as text|null) - if(!new_flavor) - return FALSE - - new_flavor = readd_quotes(new_flavor) - if(length(new_flavor) > FLAVOR_MAX) - alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error!") - return FALSE - user.vore_taste = new_flavor - - if(href_list["setsmell"]) - var/new_smell = html_encode(input(usr,"What your character smells like (40ch limit). This text will be printed to the pred after 'X smells of...' so just put something like 'strawberries and cream':","Character Smell",user.vore_smell) as text|null) - if(!new_smell) - return FALSE - - new_smell = readd_quotes(new_smell) - if(length(new_smell) > FLAVOR_MAX) - alert("Entered perfume/smell text too long. [FLAVOR_MAX] character limit.","Error!") - return FALSE - user.vore_smell = new_smell - - if(href_list["toggle_dropnom_pred"]) - var/choice = alert(user, "This toggle is for spontaneous, environment related vore as a predator, including drop-noms, teleporters, etc. You are currently [user.can_be_drop_pred ? " able to eat prey that you encounter by environmental actions." : "avoiding eating prey encountered in the environment."]", "", "Be Pred", "Cancel", "Don't be Pred") - switch(choice) - if("Cancel") + if("newbelly") + if(host.vore_organs.len >= BELLIES_MAX) return FALSE - if("Be Pred") - user.can_be_drop_pred = TRUE - if("Don't be Pred") - user.can_be_drop_pred = FALSE - if(href_list["toggle_dropnom_prey"]) - var/choice = alert(user, "This toggle is for spontaneous, environment related vore as a prey, including drop-noms, teleporters, etc. You are currently [user.can_be_drop_prey ? "able to be eaten by environmental actions." : "not able to be eaten by environmental actions."]", "", "Be Prey", "Cancel", "Don't Be Prey") - switch(choice) - if("Cancel") + var/new_name = html_encode(input(usr,"New belly's name:","New Belly") as text|null) + + var/failure_msg + if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN) + failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])." + // else if(whatever) //Next test here. + else + for(var/belly in host.vore_organs) + var/obj/belly/B = belly + if(lowertext(new_name) == lowertext(B.name)) + failure_msg = "No duplicate belly names, please." + break + + if(failure_msg) //Something went wrong. + alert(usr, failure_msg, "Error!") + return TRUE + + var/obj/belly/NB = new(host) + NB.name = new_name + host.vore_selected = NB + return TRUE + + if("bellypick") + host.vore_selected = locate(params["bellypick"]) + return TRUE + + if("set_attribute") + return set_attr(usr, params) + + if("saveprefs") + if(!host.save_vore_prefs()) + alert("ERROR: Virgo-specific preferences failed to save!","Error") + else + to_chat(usr, "Virgo-specific preferences saved!") + return TRUE + if("reloadprefs") + var/alert = alert("Are you sure you want to reload character slot preferences? This will remove your current vore organs and eject their contents.","Confirmation","Reload","Cancel") + if(alert != "Reload") return FALSE - if("Be Prey") - user.can_be_drop_prey = TRUE - if("Don't Be Prey") - user.can_be_drop_prey = 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. Digesting you is currently: [user.digestable ? "Allowed" : "Prevented"]", "", "Allow Digestion", "Cancel", "Prevent Digestion") - switch(choice) - if("Cancel") + if(!host.apply_vore_prefs()) + alert("ERROR: Virgo-specific preferences failed to apply!","Error") + else + to_chat(usr,"Virgo-specific preferences applied from active slot!") + return TRUE + if("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",host.vore_taste) as text|null) + if(!new_flavor) return FALSE - if("Allow Digestion") - user.digestable = TRUE - if("Prevent Digestion") - user.digestable = FALSE - if(user.client.prefs_vr) - user.client.prefs_vr.digestable = user.digestable - - if(href_list["toggleddevour"]) - var/choice = alert(user, "This button is to toggle your ability to be devoured by others. Devouring is currently: [user.devourable ? "Allowed" : "Prevented"]", "", "Be Devourable", "Cancel", "Prevent being Devoured") - switch(choice) - if("Cancel") + 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 - if("Be Devourable") - user.devourable = TRUE - if("Prevent being Devoured") - user.devourable = FALSE - - if(user.client.prefs_vr) - user.client.prefs_vr.devourable = user.devourable - - if(href_list["toggledfeed"]) - var/choice = alert(user, "This button is to toggle your ability to be fed to or by others vorishly. Force Feeding is currently: [user.feeding ? "Allowed" : "Prevented"]", "", "Allow Feeding", "Cancel", "Prevent Feeding") - switch(choice) - if("Cancel") + host.vore_taste = new_flavor + return TRUE + if("setsmell") + var/new_smell = html_encode(input(usr,"What your character smells like (40ch limit). This text will be printed to the pred after 'X smells of...' so just put something like 'strawberries and cream':","Character Smell",host.vore_smell) as text|null) + if(!new_smell) return FALSE - if("Allow Feeding") - user.feeding = TRUE - if("Prevent Feeding") - user.feeding = FALSE - if(user.client.prefs_vr) - user.client.prefs_vr.feeding = user.feeding - - if(href_list["toggleabsorbable"]) - var/choice = alert(user, "This button allows preds to know whether you prefer or don't prefer to be absorbed. Currently you are [user.absorbable? "" : "not"] giving permission.", "", "Allow absorption", "Cancel", "Disallow absorption") - switch(choice) - if("Cancel") + new_smell = readd_quotes(new_smell) + if(length(new_smell) > FLAVOR_MAX) + alert("Entered perfume/smell text too long. [FLAVOR_MAX] character limit.","Error!") return FALSE - if("Allow absorption") - user.absorbable = TRUE - if("Disallow absorption") - user.absorbable = FALSE + host.vore_smell = new_smell + return TRUE + if("toggle_dropnom_pred") + var/choice = alert(usr, "This toggle is for spontaneous, environment related vore as a predator, including drop-noms, teleporters, etc. You are currently [host.can_be_drop_pred ? " able to eat prey that you encounter by environmental actions." : "avoiding eating prey encountered in the environment."]", "", "Be Pred", "Cancel", "Don't be Pred") + switch(choice) + if("Cancel") + return FALSE + if("Be Pred") + host.can_be_drop_pred = TRUE + if("Don't be Pred") + host.can_be_drop_pred = FALSE + return TRUE + if("toggle_dropnom_prey") + var/choice = alert(usr, "This toggle is for spontaneous, environment related vore as a prey, including drop-noms, teleporters, etc. You are currently [host.can_be_drop_prey ? "able to be eaten by environmental actions." : "not able to be eaten by environmental actions."]", "", "Be Prey", "Cancel", "Don't Be Prey") + switch(choice) + if("Cancel") + return FALSE + if("Be Prey") + host.can_be_drop_prey = TRUE + if("Don't Be Prey") + host.can_be_drop_prey = FALSE + return TRUE + if("toggle_digest") + var/choice = alert(usr, "This button is for those who don't like being digested. It can make you undigestable. Digesting you is currently: [host.digestable ? "Allowed" : "Prevented"]", "", "Allow Digestion", "Cancel", "Prevent Digestion") + switch(choice) + if("Cancel") + return FALSE + if("Allow Digestion") + host.digestable = TRUE + if("Prevent Digestion") + host.digestable = FALSE - if(user.client.prefs_vr) - user.client.prefs_vr.absorbable = user.absorbable + if(host.client.prefs_vr) + host.client.prefs_vr.digestable = host.digestable + return TRUE + if("toggle_devour") + var/choice = alert(usr, "This button is to toggle your ability to be devoured by others. Devouring is currently: [host.devourable ? "Allowed" : "Prevented"]", "", "Be Devourable", "Cancel", "Prevent being Devoured") + switch(choice) + if("Cancel") + return FALSE + if("Be Devourable") + host.devourable = TRUE + if("Prevent being Devoured") + host.devourable = FALSE - if(href_list["toggledlm"]) - var/choice = alert(user, "This button allows preds to have your remains be left in their belly after you are digested. This will only happen if pred sets their belly to do so. Remains consist of skeletal parts. Currently you are [user.digest_leave_remains? "" : "not"] leaving remains.", "", "Allow Post-digestion Remains", "Cancel", "Disallow Post-digestion Remains") - switch(choice) + if(host.client.prefs_vr) + host.client.prefs_vr.devourable = host.devourable + return TRUE + if("toggle_feed") + var/choice = alert(usr, "This button is to toggle your ability to be fed to or by others vorishly. Force Feeding is currently: [host.feeding ? "Allowed" : "Prevented"]", "", "Allow Feeding", "Cancel", "Prevent Feeding") + switch(choice) + if("Cancel") + return FALSE + if("Allow Feeding") + host.feeding = TRUE + if("Prevent Feeding") + host.feeding = FALSE + + if(host.client.prefs_vr) + host.client.prefs_vr.feeding = host.feeding + return TRUE + if("toggle_absorbable") + var/choice = alert(usr, "This button allows preds to know whether you prefer or don't prefer to be absorbed. Currently you are [host.absorbable? "" : "not"] giving permission.", "", "Allow absorption", "Cancel", "Disallow absorption") + switch(choice) + if("Cancel") + return FALSE + if("Allow absorption") + host.absorbable = TRUE + if("Disallow absorption") + host.absorbable = FALSE + + if(host.client.prefs_vr) + host.client.prefs_vr.absorbable = host.absorbable + return TRUE + if("toggle_leaveremains") + var/choice = alert(usr, "This button allows preds to have your remains be left in their belly after you are digested. This will only happen if pred sets their belly to do so. Remains consist of skeletal parts. Currently you are [host.digest_leave_remains? "" : "not"] leaving remains.", "", "Allow Post-digestion Remains", "Cancel", "Disallow Post-digestion Remains") + switch(choice) + if("Cancel") + return FALSE + if("Allow Post-digestion Remains") + host.digest_leave_remains = TRUE + if("Disallow Post-digestion Remains") + host.digest_leave_remains = FALSE + + if(host.client.prefs_vr) + host.client.prefs_vr.digest_leave_remains = host.digest_leave_remains + return TRUE + if("toggle_mobvore") + var/choice = alert(usr, "This button is for those who don't like being eaten by mobs. Mobs are currently: [host.allowmobvore ? "Allowed to eat" : "Prevented from eating"] you.", "", "Allow Mob Predation", "Cancel", "Prevent Mob Predation") + switch(choice) + if("Cancel") + return FALSE + if("Allow Mob Predation") + host.allowmobvore = TRUE + if("Prevent Mob Predation") + host.allowmobvore = FALSE + + if(host.client.prefs_vr) + host.client.prefs_vr.allowmobvore = host.allowmobvore + return TRUE + if("toggle_healbelly") + var/choice = alert(usr, "This button is for those who don't like healbelly used on them as a mechanic. It does not affect anything, but is displayed under mechanical prefs for ease of quick checks. You are currently: [host.allowmobvore ? "Okay" : "Not Okay"] with players using healbelly on you.", "", "Allow Healing Belly", "Cancel", "Disallow Healing Belly") + switch(choice) + if("Cancel") + return FALSE + if("Allow Healing Belly") + host.permit_healbelly = TRUE + if("Disallow Healing Belly") + host.permit_healbelly = FALSE + + if(host.client.prefs_vr) + host.client.prefs_vr.permit_healbelly = host.permit_healbelly + return TRUE + if("toggle_noisy") + var/choice = alert(usr, "Toggle audible hunger noises. Currently: [host.noisy ? "Enabled" : "Disabled"]", "", "Enable audible hunger", "Cancel", "Disable audible hunger") + switch(choice) + if("Cancel") + return FALSE + if("Enable audible hunger") + host.noisy = TRUE + if("Disable audible hunger") + host.noisy = FALSE + return TRUE + +/datum/vore_look/proc/pick_from_inside(mob/user, params) + var/atom/movable/target = locate(params["pick"]) + var/obj/belly/OB = locate(params["belly"]) + + if(!(target in OB)) + return TRUE // Aren't here anymore, need to update menu + + var/intent = "Examine" + if(isliving(target)) + intent = alert("What do you want to do to them?","Query","Examine","Help Out","Devour") + + else if(istype(target, /obj/item)) + intent = alert("What do you want to do to that?","Query","Examine","Use Hand") + + switch(intent) + if("Examine") //Examine a mob inside another mob + var/list/results = target.examine(host) + if(!results || !results.len) + results = list("You were unable to examine that. Tell a developer!") + to_chat(user, jointext(results, "
")) + return TRUE + + if("Use Hand") + if(host.stat) + to_chat(user, "You can't do that in your state!") + return TRUE + + host.ClickOn(target) + return TRUE + + if(!isliving(target)) + return + + var/mob/living/M = target + switch(intent) + if("Help Out") //Help the inside-mob out + if(host.stat || host.absorbed || M.absorbed) + to_chat(user, "You can't do that in your state!") + return TRUE + + to_chat(user,"You begin to push [M] to freedom!") + to_chat(M,"[host] begins to push you to freedom!") + to_chat(M.loc,"Someone is trying to escape from inside you!") + sleep(50) + if(prob(33)) + OB.release_specific_contents(M) + to_chat(user,"You manage to help [M] to safety!") + to_chat(M,"[host] pushes you free!") + to_chat(OB.owner,"[M] forces free of the confines of your body!") + else + to_chat(user,"[M] slips back down inside despite your efforts.") + to_chat(M," Even with [host]'s help, you slip back inside again.") + to_chat(OB.owner,"Your body efficiently shoves [M] back where they belong.") + return TRUE + + if("Devour") //Eat the inside mob + if(host.absorbed || host.stat) + to_chat(user,"You can't do that in your state!") + return TRUE + + if(!host.vore_selected) + to_chat(user,"Pick a belly on yourself first!") + return TRUE + + var/obj/belly/TB = host.vore_selected + to_chat(user,"You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!") + to_chat(M,"[host] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!") + to_chat(OB.owner,"Someone inside you is eating someone else!") + + sleep(TB.nonhuman_prey_swallow_time) //Can't do after, in a stomach, weird things abound. + if((host in OB) && (M in OB)) //Make sure they're still here. + to_chat(user,"You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!") + to_chat(M,"[host] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!") + to_chat(OB.owner,"Someone inside you has eaten someone else!") + TB.nom_mob(M) + +/datum/vore_look/proc/pick_from_outside(mob/user, params) + var/intent + + //Handle the [All] choice. Ugh inelegant. Someone make this pretty. + if(params["pickall"]) + intent = alert("Eject all, Move all?","Query","Eject all","Cancel","Move all") + switch(intent) if("Cancel") + return TRUE + + if("Eject all") + if(host.stat) + to_chat(user,"You can't do that in your state!") + return TRUE + + host.vore_selected.release_all_contents() + return TRUE + + if("Move all") + if(host.stat) + to_chat(user,"You can't do that in your state!") + return TRUE + + var/obj/belly/choice = input("Move all where?","Select Belly") as null|anything in host.vore_organs + if(!choice) + return FALSE + + for(var/atom/movable/target in host.vore_selected) + to_chat(target,"You're squished from [host]'s [lowertext(host.vore_selected)] to their [lowertext(choice.name)]!") + host.vore_selected.transfer_contents(target, choice, 1) + return TRUE + return + + var/atom/movable/target = locate(params["pick"]) + if(!(target in host.vore_selected)) + return TRUE // Not in our X anymore, update UI + intent = "Examine" + intent = alert("Examine, Eject, Move? Examine if you want to leave this box.","Query","Examine","Eject","Move") + switch(intent) + if("Examine") + var/list/results = target.examine(host) + if(!results || !results.len) + results = list("You were unable to examine that. Tell a developer!") + to_chat(user, jointext(results, "
")) + return TRUE + + if("Eject") + if(host.stat) + to_chat(user,"You can't do that in your state!") + return TRUE + + host.vore_selected.release_specific_contents(target) + + if("Move") + if(host.stat) + to_chat(user,"You can't do that in your state!") + return TRUE + + var/obj/belly/choice = input("Move [target] where?","Select Belly") as null|anything in host.vore_organs + if(!choice || !(target in host.vore_selected)) + return TRUE + + to_chat(target,"You're squished from [host]'s [lowertext(host.vore_selected.name)] to their [lowertext(choice.name)]!") + host.vore_selected.transfer_contents(target, choice) + +/datum/vore_look/proc/set_attr(mob/user, params) + if(!host.vore_selected) + alert("No belly selected to modify.") + return FALSE + + var/attr = params["attribute"] + switch(attr) + if("b_name") + var/new_name = html_encode(input(usr,"Belly's new name:","New Name") as text|null) + + var/failure_msg + if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN) + failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])." + // else if(whatever) //Next test here. + else + for(var/belly in host.vore_organs) + var/obj/belly/B = belly + if(lowertext(new_name) == lowertext(B.name)) + failure_msg = "No duplicate belly names, please." + break + + if(failure_msg) //Something went wrong. + alert(user,failure_msg,"Error!") return FALSE - if("Allow Post-digestion Remains") - user.digest_leave_remains = TRUE - if("Disallow Post-digestion Remains") - user.digest_leave_remains = FALSE - if(user.client.prefs_vr) - user.client.prefs_vr.digest_leave_remains = user.digest_leave_remains + host.vore_selected.name = new_name + return TRUE + if("b_wetness") + host.vore_selected.is_wet = !host.vore_selected.is_wet + return TRUE + if("b_wetloop") + host.vore_selected.wet_loop = !host.vore_selected.wet_loop + return TRUE + if("b_mode") + var/list/menu_list = host.vore_selected.digest_modes.Copy() + if(istype(usr,/mob/living/carbon/human)) + menu_list += DM_TRANSFORM - if(href_list["togglemv"]) - var/choice = alert(user, "This button is for those who don't like being eaten by mobs. Mobs are currently: [user.allowmobvore ? "Allowed to eat" : "Prevented from eating"] you.", "", "Allow Mob Predation", "Cancel", "Prevent Mob Predation") - switch(choice) - if("Cancel") + var/new_mode = input("Choose Mode (currently [host.vore_selected.digest_mode])") as null|anything in menu_list + if(!new_mode) return FALSE - if("Allow Mob Predation") - user.allowmobvore = TRUE - if("Prevent Mob Predation") - user.allowmobvore = FALSE - if(user.client.prefs_vr) - user.client.prefs_vr.allowmobvore = user.allowmobvore + if(new_mode == DM_TRANSFORM) //Snowflek submenu + var/list/tf_list = host.vore_selected.transform_modes + var/new_tf_mode = input("Choose TF Mode (currently [host.vore_selected.digest_mode])") as null|anything in tf_list + if(!new_tf_mode) + return FALSE + host.vore_selected.digest_mode = new_tf_mode + return - if(href_list["togglehealbelly"]) - var/choice = alert(user, "This button is for those who don't like healbelly used on them as a mechanic. It does not affect anything, but is displayed under mechanical prefs for ease of quick checks. You are currently: [user.allowmobvore ? "Okay" : "Not Okay"] with players using healbelly on you.", "", "Allow Healing Belly", "Cancel", "Disallow Healing Belly") - switch(choice) - if("Cancel") + host.vore_selected.digest_mode = new_mode + return TRUE + if("b_addons") + var/list/menu_list = host.vore_selected.mode_flag_list.Copy() + var/toggle_addon = input("Toggle Addon") as null|anything in menu_list + if(!toggle_addon) return FALSE - if("Allow Healing Belly") - user.permit_healbelly = TRUE - if("Disallow Healing Belly") - user.permit_healbelly = FALSE + host.vore_selected.mode_flags ^= host.vore_selected.mode_flag_list[toggle_addon] + host.vore_selected.items_preserved.Cut() //Re-evaltuate all items in belly on + return TRUE + if("b_item_mode") + var/list/menu_list = host.vore_selected.item_digest_modes.Copy() - if(user.client.prefs_vr) - user.client.prefs_vr.permit_healbelly = user.permit_healbelly - - if(href_list["togglenoisy"]) - var/choice = alert(user, "Toggle audible hunger noises. Currently: [user.noisy ? "Enabled" : "Disabled"]", "", "Enable audible hunger", "Cancel", "Disable audible hunger") - switch(choice) - if("Cancel") + var/new_mode = input("Choose Mode (currently [host.vore_selected.item_digest_mode])") as null|anything in menu_list + if(!new_mode) return FALSE - if("Enable audible hunger") - user.noisy = TRUE - if("Disable audible hunger") - user.noisy = FALSE - //Refresh when interacted with, returning 1 makes vore_look.Topic update - return TRUE + host.vore_selected.item_digest_mode = new_mode + host.vore_selected.items_preserved.Cut() //Re-evaltuate all items in belly on belly-mode change + return TRUE + if("b_contaminates") + host.vore_selected.contaminates = !host.vore_selected.contaminates + return TRUE + if("b_contamination_flavor") + var/list/menu_list = contamination_flavors.Copy() + var/new_flavor = input("Choose Contamination Flavor Text Type (currently [host.vore_selected.contamination_flavor])") as null|anything in menu_list + if(!new_flavor) + return FALSE + host.vore_selected.contamination_flavor = new_flavor + return TRUE + if("b_contamination_color") + var/list/menu_list = contamination_colors.Copy() + var/new_color = input("Choose Contamination Color (currently [host.vore_selected.contamination_color])") as null|anything in menu_list + if(!new_color) + return FALSE + host.vore_selected.contamination_color = new_color + host.vore_selected.items_preserved.Cut() //To re-contaminate for new color + return TRUE + if("b_desc") + var/new_desc = html_encode(input(usr,"Belly Description ([BELLIES_DESC_MAX] char limit):","New Description",host.vore_selected.desc) as message|null) + + if(new_desc) + new_desc = readd_quotes(new_desc) + if(length(new_desc) > BELLIES_DESC_MAX) + alert("Entered belly desc too long. [BELLIES_DESC_MAX] character limit.","Error") + return FALSE + host.vore_selected.desc = new_desc + return TRUE + if("b_msgs") + 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/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(params["msgtype"]) + if("dmp") + 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)",host.vore_selected.get_messages("dmp")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"dmp") + + if("dmo") + 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)",host.vore_selected.get_messages("dmo")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"dmo") + + if("smo") + 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)",host.vore_selected.get_messages("smo")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"smo") + + if("smi") + 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)",host.vore_selected.get_messages("smi")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"smi") + + if("em") + 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)",host.vore_selected.get_messages("em")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"em") + + if("reset") + var/confirm = alert(user,"This will delete any custom messages. Are you sure?","Confirmation","DELETE","Cancel") + if(confirm == "DELETE") + host.vore_selected.digest_messages_prey = initial(host.vore_selected.digest_messages_prey) + host.vore_selected.digest_messages_owner = initial(host.vore_selected.digest_messages_owner) + host.vore_selected.struggle_messages_outside = initial(host.vore_selected.struggle_messages_outside) + host.vore_selected.struggle_messages_inside = initial(host.vore_selected.struggle_messages_inside) + return TRUE + if("b_verb") + var/new_verb = html_encode(input(usr,"New verb when eating (infinitive tense, e.g. nom or swallow):","New Verb") as text|null) + + if(length(new_verb) > BELLIES_NAME_MAX || length(new_verb) < BELLIES_NAME_MIN) + alert("Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).","Error") + return FALSE + + host.vore_selected.vore_verb = new_verb + return TRUE + if("b_fancy_sound") + host.vore_selected.fancy_vore = !host.vore_selected.fancy_vore + host.vore_selected.vore_sound = "Gulp" + host.vore_selected.release_sound = "Splatter" + // defaults as to avoid potential bugs + return TRUE + if("b_release") + var/choice + if(host.vore_selected.fancy_vore) + choice = input(user,"Currently set to [host.vore_selected.release_sound]","Select Sound") as null|anything in fancy_release_sounds + else + choice = input(user,"Currently set to [host.vore_selected.release_sound]","Select Sound") as null|anything in classic_release_sounds + + if(!choice) + return FALSE + + host.vore_selected.release_sound = choice + return TRUE + if("b_releasesoundtest") + var/sound/releasetest + if(host.vore_selected.fancy_vore) + releasetest = fancy_release_sounds[host.vore_selected.release_sound] + else + releasetest = classic_release_sounds[host.vore_selected.release_sound] + + if(releasetest) + SEND_SOUND(user, releasetest) + return TRUE + if("b_sound") + var/choice + if(host.vore_selected.fancy_vore) + choice = input(user,"Currently set to [host.vore_selected.vore_sound]","Select Sound") as null|anything in fancy_vore_sounds + else + choice = input(user,"Currently set to [host.vore_selected.vore_sound]","Select Sound") as null|anything in classic_vore_sounds + + if(!choice) + return FALSE + + host.vore_selected.vore_sound = choice + return TRUE + if("b_soundtest") + var/sound/voretest + if(host.vore_selected.fancy_vore) + voretest = fancy_vore_sounds[host.vore_selected.vore_sound] + else + voretest = classic_vore_sounds[host.vore_selected.vore_sound] + if(voretest) + SEND_SOUND(user, voretest) + return TRUE + if("b_tastes") + host.vore_selected.can_taste = !host.vore_selected.can_taste + return TRUE + if("b_bulge_size") + var/new_bulge = input(user, "Choose the required size prey must be to show up on examine, ranging from 25% to 200% Set this to 0 for no text on examine.", "Set Belly Examine Size.") as num|null + if(new_bulge == null) + return FALSE + if(new_bulge == 0) //Disable. + host.vore_selected.bulge_size = 0 + to_chat(user,"Your stomach will not be seen on examine.") + else if (!ISINRANGE(new_bulge,25,200)) + host.vore_selected.bulge_size = 0.25 //Set it to the default. + to_chat(user,"Invalid size.") + else if(new_bulge) + host.vore_selected.bulge_size = (new_bulge/100) + return TRUE + if("b_grow_shrink") + var/new_grow = input(user, "Choose the size that prey will be grown/shrunk to, ranging from 25% to 200%", "Set Growth Shrink Size.", host.vore_selected.shrink_grow_size) as num|null + if (new_grow == null) + return FALSE + if (!ISINRANGE(new_grow,25,200)) + host.vore_selected.shrink_grow_size = 1 //Set it to the default + to_chat(user,"Invalid size.") + else if(new_grow) + host.vore_selected.shrink_grow_size = (new_grow*0.01) + return TRUE + if("b_nutritionpercent") + var/new_nutrition = input(user, "Choose the nutrition gain percentage you will recieve per tick from prey. Ranges from 0.01 to 100.", "Set Nutrition Gain Percentage.", host.vore_selected.nutrition_percent) as num|null + if(new_nutrition == null) + return FALSE + var/new_new_nutrition = CLAMP(new_nutrition, 0.01, 100) + host.vore_selected.nutrition_percent = new_new_nutrition + return TRUE + if("b_burn_dmg") + var/new_damage = input(user, "Choose the amount of burn damage prey will take per tick. Ranges from 0 to 6.", "Set Belly Burn Damage.", host.vore_selected.digest_burn) as num|null + if(new_damage == null) + return FALSE + var/new_new_damage = CLAMP(new_damage, 0, 6) + host.vore_selected.digest_burn = new_new_damage + return TRUE + if("b_brute_dmg") + var/new_damage = input(user, "Choose the amount of brute damage prey will take per tick. Ranges from 0 to 6", "Set Belly Brute Damage.", host.vore_selected.digest_brute) as num|null + if(new_damage == null) + return FALSE + var/new_new_damage = CLAMP(new_damage, 0, 6) + host.vore_selected.digest_brute = new_new_damage + return TRUE + if("b_escapable") + if(host.vore_selected.escapable == 0) //Possibly escapable and special interactions. + host.vore_selected.escapable = 1 + to_chat(usr,"Prey now have special interactions with your [lowertext(host.vore_selected.name)] depending on your settings.") + else if(host.vore_selected.escapable == 1) //Never escapable. + host.vore_selected.escapable = 0 + to_chat(usr,"Prey will not be able to have special interactions with your [lowertext(host.vore_selected.name)].") + else + alert("Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.","Error") //If they somehow have a varable that's not 0 or 1 + host.vore_selected.escapable = 0 + return TRUE + if("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 + host.vore_selected.escapechance = sanitize_integer(escape_chance_input, 0, 100, initial(host.vore_selected.escapechance)) + return TRUE + if("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)) + host.vore_selected.escapetime = sanitize_integer(escape_time_input*10, 10, 600, initial(host.vore_selected.escapetime)) + return TRUE + if("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)) + host.vore_selected.transferchance = sanitize_integer(transfer_chance_input, 0, 100, initial(host.vore_selected.transferchance)) + return TRUE + if("b_transferlocation") + var/obj/belly/choice = input("Where do you want your [lowertext(host.vore_selected.name)] to lead if prey resists?","Select Belly") as null|anything in (host.vore_organs + "None - Remove" - host.vore_selected) + + if(!choice) //They cancelled, no changes + return FALSE + else if(choice == "None - Remove") + host.vore_selected.transferlocation = null + else + host.vore_selected.transferlocation = choice.name + return TRUE + if("b_absorbchance") + var/absorb_chance_input = input(user, "Set belly absorb mode chance on resist (as %)", "Prey Absorb Chance") as num|null + if(!isnull(absorb_chance_input)) + host.vore_selected.absorbchance = sanitize_integer(absorb_chance_input, 0, 100, initial(host.vore_selected.absorbchance)) + return TRUE + if("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)) + host.vore_selected.digestchance = sanitize_integer(digest_chance_input, 0, 100, initial(host.vore_selected.digestchance)) + return TRUE + if("b_del") + var/alert = alert("Are you sure you want to delete your [lowertext(host.vore_selected.name)]?","Confirmation","Delete","Cancel") + if(!(alert == "Delete")) + return FALSE + + var/failure_msg = "" + + var/dest_for //Check to see if it's the destination of another vore organ. + for(var/belly in host.vore_organs) + var/obj/belly/B = belly + if(B.transferlocation == host.vore_selected) + dest_for = B.name + failure_msg += "This is the destiantion for at least '[dest_for]' belly transfers. Remove it as the destination from any bellies before deleting it. " + break + + if(host.vore_selected.contents.len) + failure_msg += "You cannot delete bellies with contents! " //These end with spaces, to be nice looking. Make sure you do the same. + if(host.vore_selected.immutable) + failure_msg += "This belly is marked as undeletable. " + if(host.vore_organs.len == 1) + failure_msg += "You must have at least one belly. " + + if(failure_msg) + alert(user,failure_msg,"Error!") + return FALSE + + qdel(host.vore_selected) + host.vore_selected = host.vore_organs[1] + return TRUE + return FALSE \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/VorePanel.js b/tgui/packages/tgui/interfaces/VorePanel.js new file mode 100644 index 0000000000..e995ba3bbf --- /dev/null +++ b/tgui/packages/tgui/interfaces/VorePanel.js @@ -0,0 +1,600 @@ +import { round } from 'common/math'; +import { capitalize } from 'common/string'; +import { Fragment } from 'inferno'; +import { useBackend, useLocalState } from "../backend"; +import { Box, Button, Flex, Collapsible, Icon, LabeledList, ProgressBar, Section, Tabs } from "../components"; +import { Window } from "../layouts"; + +const stats = [ + null, + 'average', + 'bad', +]; + +const digestModeToColor = { + "Hold": null, + "Digest": "red", + "Absorb": "purple", + "Unabsorb": "purple", + "Drain": "purple", + "Shrink": "purple", + "Grow": "purple", + "Size Steal": "purple", + "Heal": "purple", + "Encase In Egg": "purple", + "Transform": "purple", + "Transform (Hair and eyes)": "purple", + "Transform (Male)": "purple", + "Transform (Female)": "purple", + "Transform (Keep Gender)": "purple", + "Transform (Replica Of Self)": "purple", + "Transform (Change Species and Taur)": "purple", + "Transform (Change Species and Taur) (EGG)": "purple", + "Transform (Replica Of Self) (EGG)": "purple", + "Transform (Keep Gender) (EGG)": "purple", + "Transform (Male) (EGG)": "purple", + "Transform (Female) (EGG)": "purple", +}; + +const digestModeToPreyMode = { + "Hold": "being held.", + "Digest": "being digested.", + "Absorb": "being absorbed.", + "Unabsorb": "being unabsorbed.", + "Drain": "being drained.", + "Shrink": "being shrunken.", + "Grow": "being grown.", + "Size Steal": "having your size stolen.", + "Heal": "being healed.", + "Encase In Egg": "being encased in an egg.", + "Transform": "being transformed.", + "Transform (Hair and eyes)": "being transformed.", + "Transform (Male)": "being transformed.", + "Transform (Female)": "being transformed.", + "Transform (Keep Gender)": "being transformed.", + "Transform (Replica Of Self)": "being transformed.", + "Transform (Change Species and Taur)": "being transformed.", + "Transform (Change Species and Taur) (EGG)": "being transformed.", + "Transform (Replica Of Self) (EGG)": "being transformed.", + "Transform (Keep Gender) (EGG)": "being transformed.", + "Transform (Male) (EGG)": "being transformed.", + "Transform (Female) (EGG)": "being transformed.", +}; + +/** + * There are three main sections to this UI. + * - The Inside Panel, where all relevant data for interacting with a belly you're in is located. + * - The Belly Selection Panel, where you can select what belly people will go into and customize the active one. + * - User Preferences, where you can adjust all of your vore preferences on the fly. + */ +export const VorePanel = (props, context) => { + return ( + + + + + + + + ); +}; + +const VoreInsidePanel = (props, context) => { + const { act, data } = useBackend(context); + + const { + absorbed, + belly_name, + belly_mode, + desc, + pred, + contents, + ref, + } = data.inside; + + if (!belly_name) { + return ( +
+ You aren't inside anyone. +
+ ); + } + + return ( +
+ You are currently {absorbed ? "absorbed into" : "inside"}  + {pred}'s  + {belly_name}  + and you are  + {digestModeToPreyMode[belly_mode]}  + + {desc} + + {contents.length && ( + + + + ) || "There is nothing else around you."} +
+ ); +}; + +const VoreBellySelectionAndCustomization = (props, context) => { + const { act, data } = useBackend(context); + + const { + our_bellies, + selected, + } = data; + + return ( +
+ + {our_bellies.map(belly => ( + act("bellypick", { bellypick: belly.ref })}> + + {belly.name} ({belly.contents}) + + + ))} + act("newbelly")}> + New + + + + {selected && } +
+ ); +}; + +/** + * Subtemplate of VoreBellySelectionAndCustomization + */ +const VoreSelectedBelly = (props, context) => { + const { act } = useBackend(context); + + const { belly } = props; + const { + belly_name, + is_wet, + wet_loop, + mode, + item_mode, + verb, + desc, + fancy, + sound, + release_sound, + can_taste, + nutrition_percent, + digest_brute, + digest_burn, + bulge_size, + shrink_grow_size, + addons, + contaminates, + contaminate_flavor, + contaminate_color, + escapable, + interacts, + contents, + } = belly; + + const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0); + + return ( + + + setTabIndex(0)}> + Controls + + setTabIndex(1)}> + Options + + setTabIndex(2)}> + Contents ({contents.length}) + + setTabIndex(3)}> + Interactions + + + {tabIndex === 0 && ( + + + + {thing.name} + + ))} + + ); +}; + +const VoreUserPreferences = (props, context) => { + const { act, data } = useBackend(context); + + const { + digestable, + devourable, + feeding, + absorbable, + digest_leave_remains, + allowmobvore, + permit_healbelly, + can_be_drop_prey, + can_be_drop_pred, + noisy, + } = data.prefs; + + return ( +
+ + +
+ + ); +}; \ No newline at end of file From b1425af20f1d0654071eee4ec84b260e84a79319 Mon Sep 17 00:00:00 2001 From: ShadowLarkens Date: Sat, 8 Aug 2020 22:12:12 -0700 Subject: [PATCH 2/3] Make vore panel more consistent and add tooltips --- code/modules/vore/eating/vorepanel_vr.dm | 185 ++++++++------------- tgui/packages/tgui/interfaces/VorePanel.js | 134 ++++++++++----- 2 files changed, 161 insertions(+), 158 deletions(-) diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index f125cb52ad..de776e002b 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -29,6 +29,7 @@ // /datum/vore_look var/mob/living/host // Note, we do this in case we ever want to allow people to view others vore panels + var/unsaved_changes = FALSE /datum/vore_look/New(mob/living/new_host) if(istype(new_host)) @@ -78,6 +79,8 @@ if(!host) return data + data["unsaved_changes"] = unsaved_changes + data["inside"] = list() var/atom/hostloc = host.loc if(isbelly(hostloc)) @@ -246,6 +249,7 @@ var/obj/belly/NB = new(host) NB.name = new_name host.vore_selected = NB + unsaved_changes = TRUE return TRUE if("bellypick") @@ -260,6 +264,7 @@ alert("ERROR: Virgo-specific preferences failed to save!","Error") else to_chat(usr, "Virgo-specific preferences saved!") + unsaved_changes = FALSE return TRUE if("reloadprefs") var/alert = alert("Are you sure you want to reload character slot preferences? This will remove your current vore organs and eject their contents.","Confirmation","Reload","Cancel") @@ -269,6 +274,7 @@ alert("ERROR: Virgo-specific preferences failed to apply!","Error") else to_chat(usr,"Virgo-specific preferences applied from active slot!") + unsaved_changes = FALSE return TRUE if("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",host.vore_taste) as text|null) @@ -280,6 +286,7 @@ alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error!") return FALSE host.vore_taste = new_flavor + unsaved_changes = TRUE return TRUE if("setsmell") var/new_smell = html_encode(input(usr,"What your character smells like (40ch limit). This text will be printed to the pred after 'X smells of...' so just put something like 'strawberries and cream':","Character Smell",host.vore_smell) as text|null) @@ -291,127 +298,65 @@ alert("Entered perfume/smell text too long. [FLAVOR_MAX] character limit.","Error!") return FALSE host.vore_smell = new_smell + unsaved_changes = TRUE return TRUE if("toggle_dropnom_pred") - var/choice = alert(usr, "This toggle is for spontaneous, environment related vore as a predator, including drop-noms, teleporters, etc. You are currently [host.can_be_drop_pred ? " able to eat prey that you encounter by environmental actions." : "avoiding eating prey encountered in the environment."]", "", "Be Pred", "Cancel", "Don't be Pred") - switch(choice) - if("Cancel") - return FALSE - if("Be Pred") - host.can_be_drop_pred = TRUE - if("Don't be Pred") - host.can_be_drop_pred = FALSE + host.can_be_drop_pred = !host.can_be_drop_pred + if(host.client.prefs_vr) + host.client.prefs_vr.can_be_drop_pred = host.can_be_drop_pred + unsaved_changes = TRUE return TRUE if("toggle_dropnom_prey") - var/choice = alert(usr, "This toggle is for spontaneous, environment related vore as a prey, including drop-noms, teleporters, etc. You are currently [host.can_be_drop_prey ? "able to be eaten by environmental actions." : "not able to be eaten by environmental actions."]", "", "Be Prey", "Cancel", "Don't Be Prey") - switch(choice) - if("Cancel") - return FALSE - if("Be Prey") - host.can_be_drop_prey = TRUE - if("Don't Be Prey") - host.can_be_drop_prey = FALSE + host.can_be_drop_prey = !host.can_be_drop_prey + if(host.client.prefs_vr) + host.client.prefs_vr.can_be_drop_prey = host.can_be_drop_prey + unsaved_changes = TRUE return TRUE if("toggle_digest") - var/choice = alert(usr, "This button is for those who don't like being digested. It can make you undigestable. Digesting you is currently: [host.digestable ? "Allowed" : "Prevented"]", "", "Allow Digestion", "Cancel", "Prevent Digestion") - switch(choice) - if("Cancel") - return FALSE - if("Allow Digestion") - host.digestable = TRUE - if("Prevent Digestion") - host.digestable = FALSE - + host.digestable = !host.digestable if(host.client.prefs_vr) host.client.prefs_vr.digestable = host.digestable + unsaved_changes = TRUE return TRUE if("toggle_devour") - var/choice = alert(usr, "This button is to toggle your ability to be devoured by others. Devouring is currently: [host.devourable ? "Allowed" : "Prevented"]", "", "Be Devourable", "Cancel", "Prevent being Devoured") - switch(choice) - if("Cancel") - return FALSE - if("Be Devourable") - host.devourable = TRUE - if("Prevent being Devoured") - host.devourable = FALSE - + host.devourable = !host.devourable if(host.client.prefs_vr) host.client.prefs_vr.devourable = host.devourable + unsaved_changes = TRUE return TRUE if("toggle_feed") - var/choice = alert(usr, "This button is to toggle your ability to be fed to or by others vorishly. Force Feeding is currently: [host.feeding ? "Allowed" : "Prevented"]", "", "Allow Feeding", "Cancel", "Prevent Feeding") - switch(choice) - if("Cancel") - return FALSE - if("Allow Feeding") - host.feeding = TRUE - if("Prevent Feeding") - host.feeding = FALSE - + host.feeding = !host.feeding if(host.client.prefs_vr) host.client.prefs_vr.feeding = host.feeding + unsaved_changes = TRUE return TRUE if("toggle_absorbable") - var/choice = alert(usr, "This button allows preds to know whether you prefer or don't prefer to be absorbed. Currently you are [host.absorbable? "" : "not"] giving permission.", "", "Allow absorption", "Cancel", "Disallow absorption") - switch(choice) - if("Cancel") - return FALSE - if("Allow absorption") - host.absorbable = TRUE - if("Disallow absorption") - host.absorbable = FALSE - + host.absorbable = !host.absorbable if(host.client.prefs_vr) host.client.prefs_vr.absorbable = host.absorbable + unsaved_changes = TRUE return TRUE if("toggle_leaveremains") - var/choice = alert(usr, "This button allows preds to have your remains be left in their belly after you are digested. This will only happen if pred sets their belly to do so. Remains consist of skeletal parts. Currently you are [host.digest_leave_remains? "" : "not"] leaving remains.", "", "Allow Post-digestion Remains", "Cancel", "Disallow Post-digestion Remains") - switch(choice) - if("Cancel") - return FALSE - if("Allow Post-digestion Remains") - host.digest_leave_remains = TRUE - if("Disallow Post-digestion Remains") - host.digest_leave_remains = FALSE - + host.digest_leave_remains = !host.digest_leave_remains if(host.client.prefs_vr) host.client.prefs_vr.digest_leave_remains = host.digest_leave_remains + unsaved_changes = TRUE return TRUE if("toggle_mobvore") - var/choice = alert(usr, "This button is for those who don't like being eaten by mobs. Mobs are currently: [host.allowmobvore ? "Allowed to eat" : "Prevented from eating"] you.", "", "Allow Mob Predation", "Cancel", "Prevent Mob Predation") - switch(choice) - if("Cancel") - return FALSE - if("Allow Mob Predation") - host.allowmobvore = TRUE - if("Prevent Mob Predation") - host.allowmobvore = FALSE - + host.allowmobvore = !host.allowmobvore if(host.client.prefs_vr) host.client.prefs_vr.allowmobvore = host.allowmobvore + unsaved_changes = TRUE return TRUE if("toggle_healbelly") - var/choice = alert(usr, "This button is for those who don't like healbelly used on them as a mechanic. It does not affect anything, but is displayed under mechanical prefs for ease of quick checks. You are currently: [host.allowmobvore ? "Okay" : "Not Okay"] with players using healbelly on you.", "", "Allow Healing Belly", "Cancel", "Disallow Healing Belly") - switch(choice) - if("Cancel") - return FALSE - if("Allow Healing Belly") - host.permit_healbelly = TRUE - if("Disallow Healing Belly") - host.permit_healbelly = FALSE - + host.permit_healbelly = !host.permit_healbelly if(host.client.prefs_vr) host.client.prefs_vr.permit_healbelly = host.permit_healbelly + unsaved_changes = TRUE return TRUE if("toggle_noisy") - var/choice = alert(usr, "Toggle audible hunger noises. Currently: [host.noisy ? "Enabled" : "Disabled"]", "", "Enable audible hunger", "Cancel", "Disable audible hunger") - switch(choice) - if("Cancel") - return FALSE - if("Enable audible hunger") - host.noisy = TRUE - if("Disable audible hunger") - host.noisy = FALSE + host.noisy = !host.noisy + unsaved_changes = TRUE return TRUE /datum/vore_look/proc/pick_from_inside(mob/user, params) @@ -581,13 +526,13 @@ return FALSE host.vore_selected.name = new_name - return TRUE + . = TRUE if("b_wetness") host.vore_selected.is_wet = !host.vore_selected.is_wet - return TRUE + . = TRUE if("b_wetloop") host.vore_selected.wet_loop = !host.vore_selected.wet_loop - return TRUE + . = TRUE if("b_mode") var/list/menu_list = host.vore_selected.digest_modes.Copy() if(istype(usr,/mob/living/carbon/human)) @@ -606,7 +551,7 @@ return host.vore_selected.digest_mode = new_mode - return TRUE + . = TRUE if("b_addons") var/list/menu_list = host.vore_selected.mode_flag_list.Copy() var/toggle_addon = input("Toggle Addon") as null|anything in menu_list @@ -614,7 +559,7 @@ return FALSE host.vore_selected.mode_flags ^= host.vore_selected.mode_flag_list[toggle_addon] host.vore_selected.items_preserved.Cut() //Re-evaltuate all items in belly on - return TRUE + . = TRUE if("b_item_mode") var/list/menu_list = host.vore_selected.item_digest_modes.Copy() @@ -624,17 +569,17 @@ host.vore_selected.item_digest_mode = new_mode host.vore_selected.items_preserved.Cut() //Re-evaltuate all items in belly on belly-mode change - return TRUE + . = TRUE if("b_contaminates") host.vore_selected.contaminates = !host.vore_selected.contaminates - return TRUE + . = TRUE if("b_contamination_flavor") var/list/menu_list = contamination_flavors.Copy() var/new_flavor = input("Choose Contamination Flavor Text Type (currently [host.vore_selected.contamination_flavor])") as null|anything in menu_list if(!new_flavor) return FALSE host.vore_selected.contamination_flavor = new_flavor - return TRUE + . = TRUE if("b_contamination_color") var/list/menu_list = contamination_colors.Copy() var/new_color = input("Choose Contamination Color (currently [host.vore_selected.contamination_color])") as null|anything in menu_list @@ -642,7 +587,7 @@ return FALSE host.vore_selected.contamination_color = new_color host.vore_selected.items_preserved.Cut() //To re-contaminate for new color - return TRUE + . = TRUE if("b_desc") var/new_desc = html_encode(input(usr,"Belly Description ([BELLIES_DESC_MAX] char limit):","New Description",host.vore_selected.desc) as message|null) @@ -652,7 +597,7 @@ alert("Entered belly desc too long. [BELLIES_DESC_MAX] character limit.","Error") return FALSE host.vore_selected.desc = new_desc - return TRUE + . = TRUE if("b_msgs") 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/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." @@ -689,7 +634,7 @@ host.vore_selected.digest_messages_owner = initial(host.vore_selected.digest_messages_owner) host.vore_selected.struggle_messages_outside = initial(host.vore_selected.struggle_messages_outside) host.vore_selected.struggle_messages_inside = initial(host.vore_selected.struggle_messages_inside) - return TRUE + . = TRUE if("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) @@ -698,13 +643,13 @@ return FALSE host.vore_selected.vore_verb = new_verb - return TRUE + . = TRUE if("b_fancy_sound") host.vore_selected.fancy_vore = !host.vore_selected.fancy_vore host.vore_selected.vore_sound = "Gulp" host.vore_selected.release_sound = "Splatter" // defaults as to avoid potential bugs - return TRUE + . = TRUE if("b_release") var/choice if(host.vore_selected.fancy_vore) @@ -716,7 +661,7 @@ return FALSE host.vore_selected.release_sound = choice - return TRUE + . = TRUE if("b_releasesoundtest") var/sound/releasetest if(host.vore_selected.fancy_vore) @@ -726,7 +671,7 @@ if(releasetest) SEND_SOUND(user, releasetest) - return TRUE + . = TRUE if("b_sound") var/choice if(host.vore_selected.fancy_vore) @@ -738,7 +683,7 @@ return FALSE host.vore_selected.vore_sound = choice - return TRUE + . = TRUE if("b_soundtest") var/sound/voretest if(host.vore_selected.fancy_vore) @@ -747,10 +692,10 @@ voretest = classic_vore_sounds[host.vore_selected.vore_sound] if(voretest) SEND_SOUND(user, voretest) - return TRUE + . = TRUE if("b_tastes") host.vore_selected.can_taste = !host.vore_selected.can_taste - return TRUE + . = TRUE if("b_bulge_size") var/new_bulge = input(user, "Choose the required size prey must be to show up on examine, ranging from 25% to 200% Set this to 0 for no text on examine.", "Set Belly Examine Size.") as num|null if(new_bulge == null) @@ -763,7 +708,7 @@ to_chat(user,"Invalid size.") else if(new_bulge) host.vore_selected.bulge_size = (new_bulge/100) - return TRUE + . = TRUE if("b_grow_shrink") var/new_grow = input(user, "Choose the size that prey will be grown/shrunk to, ranging from 25% to 200%", "Set Growth Shrink Size.", host.vore_selected.shrink_grow_size) as num|null if (new_grow == null) @@ -773,28 +718,28 @@ to_chat(user,"Invalid size.") else if(new_grow) host.vore_selected.shrink_grow_size = (new_grow*0.01) - return TRUE + . = TRUE if("b_nutritionpercent") var/new_nutrition = input(user, "Choose the nutrition gain percentage you will recieve per tick from prey. Ranges from 0.01 to 100.", "Set Nutrition Gain Percentage.", host.vore_selected.nutrition_percent) as num|null if(new_nutrition == null) return FALSE var/new_new_nutrition = CLAMP(new_nutrition, 0.01, 100) host.vore_selected.nutrition_percent = new_new_nutrition - return TRUE + . = TRUE if("b_burn_dmg") var/new_damage = input(user, "Choose the amount of burn damage prey will take per tick. Ranges from 0 to 6.", "Set Belly Burn Damage.", host.vore_selected.digest_burn) as num|null if(new_damage == null) return FALSE var/new_new_damage = CLAMP(new_damage, 0, 6) host.vore_selected.digest_burn = new_new_damage - return TRUE + . = TRUE if("b_brute_dmg") var/new_damage = input(user, "Choose the amount of brute damage prey will take per tick. Ranges from 0 to 6", "Set Belly Brute Damage.", host.vore_selected.digest_brute) as num|null if(new_damage == null) return FALSE var/new_new_damage = CLAMP(new_damage, 0, 6) host.vore_selected.digest_brute = new_new_damage - return TRUE + . = TRUE if("b_escapable") if(host.vore_selected.escapable == 0) //Possibly escapable and special interactions. host.vore_selected.escapable = 1 @@ -805,22 +750,22 @@ else alert("Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.","Error") //If they somehow have a varable that's not 0 or 1 host.vore_selected.escapable = 0 - return TRUE + . = TRUE if("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 host.vore_selected.escapechance = sanitize_integer(escape_chance_input, 0, 100, initial(host.vore_selected.escapechance)) - return TRUE + . = TRUE if("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)) host.vore_selected.escapetime = sanitize_integer(escape_time_input*10, 10, 600, initial(host.vore_selected.escapetime)) - return TRUE + . = TRUE if("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)) host.vore_selected.transferchance = sanitize_integer(transfer_chance_input, 0, 100, initial(host.vore_selected.transferchance)) - return TRUE + . = TRUE if("b_transferlocation") var/obj/belly/choice = input("Where do you want your [lowertext(host.vore_selected.name)] to lead if prey resists?","Select Belly") as null|anything in (host.vore_organs + "None - Remove" - host.vore_selected) @@ -830,17 +775,17 @@ host.vore_selected.transferlocation = null else host.vore_selected.transferlocation = choice.name - return TRUE + . = TRUE if("b_absorbchance") var/absorb_chance_input = input(user, "Set belly absorb mode chance on resist (as %)", "Prey Absorb Chance") as num|null if(!isnull(absorb_chance_input)) host.vore_selected.absorbchance = sanitize_integer(absorb_chance_input, 0, 100, initial(host.vore_selected.absorbchance)) - return TRUE + . = TRUE if("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)) host.vore_selected.digestchance = sanitize_integer(digest_chance_input, 0, 100, initial(host.vore_selected.digestchance)) - return TRUE + . = TRUE if("b_del") var/alert = alert("Are you sure you want to delete your [lowertext(host.vore_selected.name)]?","Confirmation","Delete","Cancel") if(!(alert == "Delete")) @@ -869,5 +814,7 @@ qdel(host.vore_selected) host.vore_selected = host.vore_organs[1] - return TRUE - return FALSE \ No newline at end of file + . = TRUE + + if(.) + unsaved_changes = TRUE \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/VorePanel.js b/tgui/packages/tgui/interfaces/VorePanel.js index e995ba3bbf..7e3a178ec7 100644 --- a/tgui/packages/tgui/interfaces/VorePanel.js +++ b/tgui/packages/tgui/interfaces/VorePanel.js @@ -2,7 +2,7 @@ import { round } from 'common/math'; import { capitalize } from 'common/string'; import { Fragment } from 'inferno'; import { useBackend, useLocalState } from "../backend"; -import { Box, Button, Flex, Collapsible, Icon, LabeledList, ProgressBar, Section, Tabs } from "../components"; +import { Box, Button, Flex, Collapsible, Icon, LabeledList, NoticeBox, Section, Tabs } from "../components"; import { Window } from "../layouts"; const stats = [ @@ -68,9 +68,25 @@ const digestModeToPreyMode = { * - User Preferences, where you can adjust all of your vore preferences on the fly. */ export const VorePanel = (props, context) => { + const { act, data } = useBackend(context); return ( + {data.unsaved_changes && ( + + + + Warning: Unsaved Changes! + + +