vorepanel reloaded (#17723)

* vorepanel rework part 1

* finish first tab

* those should be fine

* .

* floating for the addons

* .

* tooltip prep and style

* while on it

* prep data compile for tab 2 rework

* message tab

* undef

* .

* some more components

* unify the mesage procs

* option tab preps

* tooltip prep

* small fixes

* sorting

* some more preps

* .

* move that

* move that

* finish options tab

* sound preps

* sound preps

* finish sound tab

* visual tab prep

* .

* visual tab prep2

* visual

* move that

* interaction tab prep

* interactions

* interaction tab

* more basic contents only for now

* defaulted

* .

* .

* clean up

* liquid tab

* wordng

* make it the same

* soulcatcher tab

* prefs

* crash save

* typing

* docs

* .

* sanitize corrupted save data

* use the right type
This commit is contained in:
Kashargul
2025-05-27 19:45:30 +02:00
committed by GitHub
parent d78157f9b0
commit faf52ecce2
98 changed files with 7624 additions and 5709 deletions
+33 -5
View File
@@ -1,5 +1,8 @@
// Vore belly options
// Descriptions
#define BELLY_DESCRIPTION_MESSAGE "b_desc"
#define BELLY_DESCRIPTION_MESSAGE_ABSROED "b_absorbed_desc"
// Vore belly options
#define STRUGGLE_OUTSIDE "smo"
#define STRUGGLE_INSIDE "smi"
@@ -27,8 +30,8 @@
#define ABSORBED_ESCAPE_PREY "aescp"
#define ABSORBED_ESCAPE_OUTSIDE "aescout"
#define FULL_ABSORBED_ESCAPE_OWNER "aescfo"
#define FULL_ABSORBED_ESCAPE_PREY "aescfp"
#define ABSORBED_ESCAPE_FAIL_OWNER "aescfo"
#define ABSORBED_ESCAPE_FAIL_PREY "aescfp"
#define PRIMARY_TRANSFER_OWNER "trnspo"
#define PRIMARY_TRANSFER_PREY "trnspp"
@@ -75,12 +78,37 @@
#define BELLY_TRASH_EATER_IN "te_in"
#define BELLY_TRASH_EATER_OUT "te_out"
#define BELLY_LIQUID_MESSAGE1 "full1"
#define BELLY_LIQUID_MESSAGE2 "full2"
#define BELLY_LIQUID_MESSAGE3 "full3"
#define BELLY_LIQUID_MESSAGE4 "full4"
#define BELLY_LIQUID_MESSAGE5 "full5"
#define VB_MESSAGE_SANITY(type) ASSERT(type == STRUGGLE_OUTSIDE || type == STRUGGLE_INSIDE || type == ABSORBED_STRUGGLE_OUSIDE || type == ABSORBED_STRUGGLE_INSIDE || type == ESCAPE_ATTEMPT_OWNER || type == ESCAPE_ATTEMPT_PREY ||\
type == ESCAPE_PREY || type == ESCAPE_OWNER || type == ESCAPE_OUTSIDE || type == ESCAPE_ITEM_PREY || type == ESCAPE_ITEM_OWNER || type == ESCAPE_ITEM_OUTSIDE || type == ESCAPE_FAIL_PREY ||\
type == ESCAPE_FAIL_OWNER || type == ABSORBED_ESCAPE_ATTEMPT_OWNER || type == ABSORBED_ESCAPE_ATTEMPT_PREY || type == ABSORBED_ESCAPE_PREY || type == ABSORBED_ESCAPE_OWNER ||\
type == ABSORBED_ESCAPE_OUTSIDE || type == FULL_ABSORBED_ESCAPE_PREY || type == FULL_ABSORBED_ESCAPE_OWNER || type == PRIMARY_TRANSFER_PREY || type == PRIMARY_TRANSFER_OWNER ||\
type == ABSORBED_ESCAPE_OUTSIDE || type == ABSORBED_ESCAPE_FAIL_PREY || type == ABSORBED_ESCAPE_FAIL_OWNER || type == PRIMARY_TRANSFER_PREY || type == PRIMARY_TRANSFER_OWNER ||\
type == SECONDARY_TRANSFER_PREY || type == SECONDARY_TRANSFER_OWNER || type == PRIMARY_AUTO_TRANSFER_PREY || type == PRIMARY_AUTO_TRANSFER_OWNER || type == SECONDARY_AUTO_TRANSFER_PREY ||\
type == SECONDARY_AUTO_TRANSFER_OWNER || type == DIGEST_CHANCE_PREY || type == DIGEST_CHANCE_OWNER || type == ABSORB_CHANCE_PREY || type == ABSORB_CHANCE_OWNER || type == DIGEST_OWNER ||\
type == DIGEST_PREY || type == ABSORB_OWNER || type == ABSORB_PREY || type == UNABSORBS_OWNER || type == UNABSORBS_PREY || type == EXAMINES || type == EXAMINES_ABSORBED ||\
type == BELLY_MODE_DIGEST || type == BELLY_MODE_HOLD || type == BELLY_MODE_HOLD_ABSORB || type == BELLY_MODE_ABSORB || type == BELLY_MODE_HEAL || type == BELLY_MODE_DRAIN ||\
type == BELLY_MODE_STEAL || type == BELLY_MODE_EGG || type == BELLY_MODE_SHRINK || type == BELLY_MODE_GROW || type == BELLY_MODE_UNABSORB || type == BELLY_TRASH_EATER_IN || type==BELLY_TRASH_EATER_OUT)
type == BELLY_MODE_STEAL || type == BELLY_MODE_EGG || type == BELLY_MODE_SHRINK || type == BELLY_MODE_GROW || type == BELLY_MODE_UNABSORB || type == BELLY_TRASH_EATER_IN || type==BELLY_TRASH_EATER_OUT ||\
type == BELLY_LIQUID_MESSAGE1 || type == BELLY_LIQUID_MESSAGE2 || type == BELLY_LIQUID_MESSAGE3 || type == BELLY_LIQUID_MESSAGE4 || type == BELLY_LIQUID_MESSAGE5)
// Soulcatcher Message Options
#define SC_INTERIOR_MESSAGE "sc_int"
#define SC_CAPTURE_MEESAGE "sc_cap"
#define SC_TRANSIT_MESSAGE "sc_transit"
#define SC_RELEASE_MESSAGE "sc_rel"
#define SC_TRANSFERE_MESSAGE "sc_transfer"
#define SC_DELETE_MESSAGE "sc_del"
// General Message Options
#define TASTE_FLAVOR "setflavor"
#define SMELL_FLAVOR "setsmell"
// General Examine Messages
#define GENERAL_EXAMINE_NUTRI "en"
#define GENERAL_EXAMINE_WEIGHT "ew"
#define VPPREF_MESSAGE_SANITY(type) ASSERT(type == GENERAL_EXAMINE_NUTRI || type == GENERAL_EXAMINE_WEIGHT)
+22 -1
View File
@@ -9,7 +9,28 @@
#define BELLIES_MAX 40
#define BELLIES_NAME_MIN 2
#define BELLIES_NAME_MAX 40
#define BELLIES_DESC_MAX 4096
#define BELLIES_DESC_MAX 8192
#define BELLIES_EXAMINE_MAX 2048
#define BELLIES_IDLE_MAX 2048
#define BELLIES_MESSAGE_MAX 1024
#define BELLIES_MESSAGE_COMBINED 1024 * 10 + 18
#define FLAVOR_MAX 400
#define VORE_SC_MAX 2048
#define VORE_SC_DESC_MAX 8192
#define VORE_VERSION 2 //This is a Define so you don't have to worry about magic numbers.
#define VPANEL_DESCRIPTION_TAB 0
#define VPANEL_EXAMINE_TAB 1
#define VPANEL_TRASH_EATER_TAB 2
#define VPANEL_STRUGGLE_TAB 3
#define VPANEL_ESCAPE_TAB 4
#define VPANEL_ESCAPE_ABSORBED_TAB 5
#define VPANEL_TRANSFER_TAB 6
#define VPANEL_INTERACTION_TAB 7
#define VPANEL_BELLYMODE_TAB 8
#define VPANEL_IDLE_TAB 9
#define VPANEL_LIQUIDS_TAB 10
#define VORE_RESIZE_COST 125
+118 -118
View File
@@ -156,274 +156,274 @@
new_belly.release_verb = new_release_verb
if(islist(belly_data["digest_messages_prey"]))
var/new_digest_messages_prey = sanitize(jointext(belly_data["digest_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_digest_messages_prey = sanitize(jointext(belly_data["digest_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_digest_messages_prey)
new_belly.set_messages(new_digest_messages_prey,DIGEST_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_digest_messages_prey,DIGEST_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["digest_messages_owner"]))
var/new_digest_messages_owner = sanitize(jointext(belly_data["digest_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_digest_messages_owner = sanitize(jointext(belly_data["digest_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_digest_messages_owner)
new_belly.set_messages(new_digest_messages_owner,DIGEST_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_digest_messages_owner,DIGEST_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["absorb_messages_prey"]))
var/new_absorb_messages_prey = sanitize(jointext(belly_data["absorb_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_absorb_messages_prey = sanitize(jointext(belly_data["absorb_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_absorb_messages_prey)
new_belly.set_messages(new_absorb_messages_prey,ABSORB_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_absorb_messages_prey,ABSORB_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["absorb_messages_owner"]))
var/new_absorb_messages_owner = sanitize(jointext(belly_data["absorb_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_absorb_messages_owner = sanitize(jointext(belly_data["absorb_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_absorb_messages_owner)
new_belly.set_messages(new_absorb_messages_owner,ABSORB_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_absorb_messages_owner,ABSORB_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["unabsorb_messages_prey"]))
var/new_unabsorb_messages_prey = sanitize(jointext(belly_data["unabsorb_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_unabsorb_messages_prey = sanitize(jointext(belly_data["unabsorb_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_unabsorb_messages_prey)
new_belly.set_messages(new_unabsorb_messages_prey,UNABSORBS_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_unabsorb_messages_prey,UNABSORBS_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["unabsorb_messages_owner"]))
var/new_unabsorb_messages_owner = sanitize(jointext(belly_data["unabsorb_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_unabsorb_messages_owner = sanitize(jointext(belly_data["unabsorb_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_unabsorb_messages_owner)
new_belly.set_messages(new_unabsorb_messages_owner,UNABSORBS_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_unabsorb_messages_owner,UNABSORBS_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["struggle_messages_outside"]))
var/new_struggle_messages_outside = sanitize(jointext(belly_data["struggle_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_struggle_messages_outside = sanitize(jointext(belly_data["struggle_messages_outside"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_struggle_messages_outside)
new_belly.set_messages(new_struggle_messages_outside,STRUGGLE_OUTSIDE, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_struggle_messages_outside,STRUGGLE_OUTSIDE, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["struggle_messages_inside"]))
var/new_struggle_messages_inside = sanitize(jointext(belly_data["struggle_messages_inside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_struggle_messages_inside = sanitize(jointext(belly_data["struggle_messages_inside"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_struggle_messages_inside)
new_belly.set_messages(new_struggle_messages_inside,STRUGGLE_INSIDE, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_struggle_messages_inside,STRUGGLE_INSIDE, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["absorbed_struggle_messages_outside"]))
var/new_absorbed_struggle_messages_outside = sanitize(jointext(belly_data["absorbed_struggle_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_absorbed_struggle_messages_outside = sanitize(jointext(belly_data["absorbed_struggle_messages_outside"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_absorbed_struggle_messages_outside)
new_belly.set_messages(new_absorbed_struggle_messages_outside,ABSORBED_STRUGGLE_OUSIDE, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_absorbed_struggle_messages_outside,ABSORBED_STRUGGLE_OUSIDE, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["absorbed_struggle_messages_inside"]))
var/new_absorbed_struggle_messages_inside = sanitize(jointext(belly_data["absorbed_struggle_messages_inside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_absorbed_struggle_messages_inside = sanitize(jointext(belly_data["absorbed_struggle_messages_inside"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_absorbed_struggle_messages_inside)
new_belly.set_messages(new_absorbed_struggle_messages_inside,ABSORBED_STRUGGLE_INSIDE, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_absorbed_struggle_messages_inside,ABSORBED_STRUGGLE_INSIDE, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_attempt_messages_prey"]))
var/new_escape_attempt_messages_prey = sanitize(jointext(belly_data["escape_attempt_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_attempt_messages_prey = sanitize(jointext(belly_data["escape_attempt_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_attempt_messages_prey)
new_belly.set_messages(new_escape_attempt_messages_prey,ESCAPE_ATTEMPT_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_attempt_messages_prey,ESCAPE_ATTEMPT_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_attempt_messages_owner"]))
var/new_escape_attempt_messages_owner = sanitize(jointext(belly_data["escape_attempt_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_attempt_messages_owner = sanitize(jointext(belly_data["escape_attempt_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_attempt_messages_owner)
new_belly.set_messages(new_escape_attempt_messages_owner,ESCAPE_ATTEMPT_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_attempt_messages_owner,ESCAPE_ATTEMPT_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_messages_prey"]))
var/new_escape_messages_prey = sanitize(jointext(belly_data["escape_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_messages_prey = sanitize(jointext(belly_data["escape_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_messages_prey)
new_belly.set_messages(new_escape_messages_prey,ESCAPE_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_messages_prey,ESCAPE_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_messages_owner"]))
var/new_escape_messages_owner = sanitize(jointext(belly_data["escape_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_messages_owner = sanitize(jointext(belly_data["escape_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_messages_owner)
new_belly.set_messages(new_escape_messages_owner,ESCAPE_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_messages_owner,ESCAPE_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_messages_outside"]))
var/new_escape_messages_outside = sanitize(jointext(belly_data["escape_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_messages_outside = sanitize(jointext(belly_data["escape_messages_outside"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_messages_outside)
new_belly.set_messages(new_escape_messages_outside,ESCAPE_OUTSIDE, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_messages_outside,ESCAPE_OUTSIDE, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_item_messages_prey"]))
var/new_escape_item_messages_prey = sanitize(jointext(belly_data["escape_item_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_item_messages_prey = sanitize(jointext(belly_data["escape_item_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_item_messages_prey)
new_belly.set_messages(new_escape_item_messages_prey,ESCAPE_ITEM_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_item_messages_prey,ESCAPE_ITEM_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_item_messages_owner"]))
var/new_escape_item_messages_owner = sanitize(jointext(belly_data["escape_item_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_item_messages_owner = sanitize(jointext(belly_data["escape_item_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_item_messages_owner)
new_belly.set_messages(new_escape_item_messages_owner,ESCAPE_ITEM_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_item_messages_owner,ESCAPE_ITEM_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_item_messages_outside"]))
var/new_escape_item_messages_outside = sanitize(jointext(belly_data["escape_item_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_item_messages_outside = sanitize(jointext(belly_data["escape_item_messages_outside"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_item_messages_outside)
new_belly.set_messages(new_escape_item_messages_outside,ESCAPE_ITEM_OUTSIDE, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_item_messages_outside,ESCAPE_ITEM_OUTSIDE, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_fail_messages_prey"]))
var/new_escape_fail_messages_prey = sanitize(jointext(belly_data["escape_fail_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_fail_messages_prey = sanitize(jointext(belly_data["escape_fail_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_fail_messages_prey)
new_belly.set_messages(new_escape_fail_messages_prey,ESCAPE_FAIL_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_fail_messages_prey,ESCAPE_FAIL_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_fail_messages_owner"]))
var/new_escape_fail_messages_owner = sanitize(jointext(belly_data["escape_fail_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_fail_messages_owner = sanitize(jointext(belly_data["escape_fail_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_fail_messages_owner)
new_belly.set_messages(new_escape_fail_messages_owner,ESCAPE_FAIL_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_fail_messages_owner,ESCAPE_FAIL_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_attempt_absorbed_messages_prey"]))
var/new_escape_attempt_absorbed_messages_prey = sanitize(jointext(belly_data["escape_attempt_absorbed_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_attempt_absorbed_messages_prey = sanitize(jointext(belly_data["escape_attempt_absorbed_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_attempt_absorbed_messages_prey)
new_belly.set_messages(new_escape_attempt_absorbed_messages_prey,ABSORBED_ESCAPE_ATTEMPT_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_attempt_absorbed_messages_prey,ABSORBED_ESCAPE_ATTEMPT_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_attempt_absorbed_messages_owner"]))
var/new_escape_attempt_absorbed_messages_owner = sanitize(jointext(belly_data["escape_attempt_absorbed_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_attempt_absorbed_messages_owner = sanitize(jointext(belly_data["escape_attempt_absorbed_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_attempt_absorbed_messages_owner)
new_belly.set_messages(new_escape_attempt_absorbed_messages_owner,ABSORBED_ESCAPE_ATTEMPT_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_attempt_absorbed_messages_owner,ABSORBED_ESCAPE_ATTEMPT_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_absorbed_messages_prey"]))
var/new_escape_absorbed_messages_prey = sanitize(jointext(belly_data["escape_absorbed_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_absorbed_messages_prey = sanitize(jointext(belly_data["escape_absorbed_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_absorbed_messages_prey)
new_belly.set_messages(new_escape_absorbed_messages_prey,ABSORBED_ESCAPE_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_absorbed_messages_prey,ABSORBED_ESCAPE_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_absorbed_messages_owner"]))
var/new_escape_absorbed_messages_owner = sanitize(jointext(belly_data["escape_absorbed_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_absorbed_messages_owner = sanitize(jointext(belly_data["escape_absorbed_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_absorbed_messages_owner)
new_belly.set_messages(new_escape_absorbed_messages_owner,ABSORBED_ESCAPE_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_absorbed_messages_owner,ABSORBED_ESCAPE_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_absorbed_messages_outside"]))
var/new_escape_absorbed_messages_outside = sanitize(jointext(belly_data["escape_absorbed_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_absorbed_messages_outside = sanitize(jointext(belly_data["escape_absorbed_messages_outside"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_absorbed_messages_outside)
new_belly.set_messages(new_escape_absorbed_messages_outside,ABSORBED_ESCAPE_OUTSIDE, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_absorbed_messages_outside,ABSORBED_ESCAPE_OUTSIDE, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_fail_absorbed_messages_prey"]))
var/new_escape_fail_absorbed_messages_prey = sanitize(jointext(belly_data["escape_fail_absorbed_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_fail_absorbed_messages_prey = sanitize(jointext(belly_data["escape_fail_absorbed_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_fail_absorbed_messages_prey)
new_belly.set_messages(new_escape_fail_absorbed_messages_prey,FULL_ABSORBED_ESCAPE_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_fail_absorbed_messages_prey,ABSORBED_ESCAPE_FAIL_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["escape_fail_absorbed_messages_owner"]))
var/new_escape_fail_absorbed_messages_owner = sanitize(jointext(belly_data["escape_fail_absorbed_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_escape_fail_absorbed_messages_owner = sanitize(jointext(belly_data["escape_fail_absorbed_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_escape_fail_absorbed_messages_owner)
new_belly.set_messages(new_escape_fail_absorbed_messages_owner,FULL_ABSORBED_ESCAPE_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_escape_fail_absorbed_messages_owner,ABSORBED_ESCAPE_FAIL_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["primary_transfer_messages_prey"]))
var/new_primary_transfer_messages_prey = sanitize(jointext(belly_data["primary_transfer_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_primary_transfer_messages_prey = sanitize(jointext(belly_data["primary_transfer_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_primary_transfer_messages_prey)
new_belly.set_messages(new_primary_transfer_messages_prey,PRIMARY_TRANSFER_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_primary_transfer_messages_prey,PRIMARY_TRANSFER_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["primary_transfer_messages_owner"]))
var/new_primary_transfer_messages_owner = sanitize(jointext(belly_data["primary_transfer_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_primary_transfer_messages_owner = sanitize(jointext(belly_data["primary_transfer_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_primary_transfer_messages_owner)
new_belly.set_messages(new_primary_transfer_messages_owner,PRIMARY_TRANSFER_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_primary_transfer_messages_owner,PRIMARY_TRANSFER_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["secondary_transfer_messages_prey"]))
var/new_secondary_transfer_messages_prey = sanitize(jointext(belly_data["secondary_transfer_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_secondary_transfer_messages_prey = sanitize(jointext(belly_data["secondary_transfer_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_secondary_transfer_messages_prey)
new_belly.set_messages(new_secondary_transfer_messages_prey,SECONDARY_TRANSFER_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_secondary_transfer_messages_prey,SECONDARY_TRANSFER_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["secondary_transfer_messages_owner"]))
var/new_secondary_transfer_messages_owner = sanitize(jointext(belly_data["secondary_transfer_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_secondary_transfer_messages_owner = sanitize(jointext(belly_data["secondary_transfer_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_secondary_transfer_messages_owner)
new_belly.set_messages(new_secondary_transfer_messages_owner,SECONDARY_TRANSFER_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_secondary_transfer_messages_owner,SECONDARY_TRANSFER_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["primary_autotransfer_messages_prey"]))
var/new_primary_autotransfer_messages_prey = sanitize(jointext(belly_data["primary_autotransfer_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_primary_autotransfer_messages_prey = sanitize(jointext(belly_data["primary_autotransfer_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_primary_autotransfer_messages_prey)
new_belly.set_messages(new_primary_autotransfer_messages_prey,PRIMARY_AUTO_TRANSFER_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_primary_autotransfer_messages_prey,PRIMARY_AUTO_TRANSFER_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["primary_autotransfer_messages_owner"]))
var/new_primary_autotransfer_messages_owner = sanitize(jointext(belly_data["primary_autotransfer_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_primary_autotransfer_messages_owner = sanitize(jointext(belly_data["primary_autotransfer_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_primary_autotransfer_messages_owner)
new_belly.set_messages(new_primary_autotransfer_messages_owner,PRIMARY_AUTO_TRANSFER_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_primary_autotransfer_messages_owner,PRIMARY_AUTO_TRANSFER_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["secondary_autotransfer_messages_prey"]))
var/new_secondary_autotransfer_messages_prey = sanitize(jointext(belly_data["secondary_autotransfer_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_secondary_autotransfer_messages_prey = sanitize(jointext(belly_data["secondary_autotransfer_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_secondary_autotransfer_messages_prey)
new_belly.set_messages(new_secondary_autotransfer_messages_prey,SECONDARY_AUTO_TRANSFER_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_secondary_autotransfer_messages_prey,SECONDARY_AUTO_TRANSFER_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["secondary_autotransfer_messages_owner"]))
var/new_secondary_autotransfer_messages_owner = sanitize(jointext(belly_data["secondary_autotransfer_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_secondary_autotransfer_messages_owner = sanitize(jointext(belly_data["secondary_autotransfer_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_secondary_autotransfer_messages_owner)
new_belly.set_messages(new_secondary_autotransfer_messages_owner,SECONDARY_AUTO_TRANSFER_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_secondary_autotransfer_messages_owner,SECONDARY_AUTO_TRANSFER_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["digest_chance_messages_prey"]))
var/new_digest_chance_messages_prey = sanitize(jointext(belly_data["digest_chance_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_digest_chance_messages_prey = sanitize(jointext(belly_data["digest_chance_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_digest_chance_messages_prey)
new_belly.set_messages(new_digest_chance_messages_prey,DIGEST_CHANCE_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_digest_chance_messages_prey,DIGEST_CHANCE_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["digest_chance_messages_owner"]))
var/new_digest_chance_messages_owner = sanitize(jointext(belly_data["digest_chance_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_digest_chance_messages_owner = sanitize(jointext(belly_data["digest_chance_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_digest_chance_messages_owner)
new_belly.set_messages(new_digest_chance_messages_owner,DIGEST_CHANCE_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_digest_chance_messages_owner,DIGEST_CHANCE_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["absorb_chance_messages_prey"]))
var/new_absorb_chance_messages_prey = sanitize(jointext(belly_data["absorb_chance_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_absorb_chance_messages_prey = sanitize(jointext(belly_data["absorb_chance_messages_prey"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_absorb_chance_messages_prey)
new_belly.set_messages(new_absorb_chance_messages_prey,ABSORB_CHANCE_PREY, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_absorb_chance_messages_prey,ABSORB_CHANCE_PREY, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["absorb_chance_messages_owner"]))
var/new_absorb_chance_messages_owner = sanitize(jointext(belly_data["absorb_chance_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_absorb_chance_messages_owner = sanitize(jointext(belly_data["absorb_chance_messages_owner"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_absorb_chance_messages_owner)
new_belly.set_messages(new_absorb_chance_messages_owner,ABSORB_CHANCE_OWNER, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_absorb_chance_messages_owner,ABSORB_CHANCE_OWNER, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["examine_messages"]))
var/new_examine_messages = sanitize(jointext(belly_data["examine_messages"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_examine_messages = sanitize(jointext(belly_data["examine_messages"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_examine_messages)
new_belly.set_messages(new_examine_messages,EXAMINES, limit = MAX_MESSAGE_LEN / 2)
new_belly.set_messages(new_examine_messages,EXAMINES, limit = BELLIES_EXAMINE_MAX)
if(islist(belly_data["examine_messages_absorbed"]))
var/new_examine_messages_absorbed = sanitize(jointext(belly_data["examine_messages_absorbed"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_examine_messages_absorbed = sanitize(jointext(belly_data["examine_messages_absorbed"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_examine_messages_absorbed)
new_belly.set_messages(new_examine_messages_absorbed,EXAMINES_ABSORBED, limit = MAX_MESSAGE_LEN / 2)
new_belly.set_messages(new_examine_messages_absorbed,EXAMINES_ABSORBED, limit = BELLIES_EXAMINE_MAX)
if(islist(belly_data["emotes_digest"]))
var/new_emotes_digest = sanitize(jointext(belly_data["emotes_digest"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_digest = sanitize(jointext(belly_data["emotes_digest"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_digest)
new_belly.set_messages(new_emotes_digest,BELLY_MODE_DIGEST, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_digest,BELLY_MODE_DIGEST, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["trash_eater_in"]))
var/new_trash_eater_in = sanitize(jointext(belly_data["trash_eater_in"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_trash_eater_in = sanitize(jointext(belly_data["trash_eater_in"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_trash_eater_in)
new_belly.set_messages(new_trash_eater_in ,BELLY_TRASH_EATER_IN, limit = MAX_MESSAGE_LEN / 2)
new_belly.set_messages(new_trash_eater_in ,BELLY_TRASH_EATER_IN, limit = BELLIES_EXAMINE_MAX)
if(islist(belly_data["trash_eater_out"]))
var/new_trash_eater_out = sanitize(jointext(belly_data["trash_eater_out"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_trash_eater_out = sanitize(jointext(belly_data["trash_eater_out"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_trash_eater_out)
new_belly.set_messages(new_trash_eater_out,BELLY_TRASH_EATER_OUT, limit = MAX_MESSAGE_LEN / 2)
new_belly.set_messages(new_trash_eater_out,BELLY_TRASH_EATER_OUT, limit = BELLIES_EXAMINE_MAX)
if(islist(belly_data["emotes_hold"]))
var/new_emotes_hold = sanitize(jointext(belly_data["emotes_hold"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_hold = sanitize(jointext(belly_data["emotes_hold"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_hold)
new_belly.set_messages(new_emotes_hold,BELLY_MODE_HOLD, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_hold,BELLY_MODE_HOLD, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_holdabsorbed"]))
var/new_emotes_holdabsorbed = sanitize(jointext(belly_data["emotes_holdabsorbed"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_holdabsorbed = sanitize(jointext(belly_data["emotes_holdabsorbed"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_holdabsorbed)
new_belly.set_messages(new_emotes_holdabsorbed,BELLY_MODE_HOLD_ABSORB, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_holdabsorbed,BELLY_MODE_HOLD_ABSORB, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_absorb"]))
var/new_emotes_absorb = sanitize(jointext(belly_data["emotes_absorb"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_absorb = sanitize(jointext(belly_data["emotes_absorb"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_absorb)
new_belly.set_messages(new_emotes_absorb,BELLY_MODE_ABSORB, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_absorb,BELLY_MODE_ABSORB, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_heal"]))
var/new_emotes_heal = sanitize(jointext(belly_data["emotes_heal"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_heal = sanitize(jointext(belly_data["emotes_heal"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_heal)
new_belly.set_messages(new_emotes_heal,BELLY_MODE_HEAL, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_heal,BELLY_MODE_HEAL, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_drain"]))
var/new_emotes_drain = sanitize(jointext(belly_data["emotes_drain"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_drain = sanitize(jointext(belly_data["emotes_drain"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_drain)
new_belly.set_messages(new_emotes_drain,BELLY_MODE_DRAIN, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_drain,BELLY_MODE_DRAIN, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_steal"]))
var/new_emotes_steal = sanitize(jointext(belly_data["emotes_steal"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_steal = sanitize(jointext(belly_data["emotes_steal"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_steal)
new_belly.set_messages(new_emotes_steal,BELLY_MODE_STEAL, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_steal,BELLY_MODE_STEAL, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_egg"]))
var/new_emotes_egg = sanitize(jointext(belly_data["emotes_egg"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_egg = sanitize(jointext(belly_data["emotes_egg"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_egg)
new_belly.set_messages(new_emotes_egg,BELLY_MODE_EGG, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_egg,BELLY_MODE_EGG, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_shrink"]))
var/new_emotes_shrink = sanitize(jointext(belly_data["emotes_shrink"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_shrink = sanitize(jointext(belly_data["emotes_shrink"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_shrink)
new_belly.set_messages(new_emotes_shrink,BELLY_MODE_SHRINK, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_shrink,BELLY_MODE_SHRINK, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_grow"]))
var/new_emotes_grow = sanitize(jointext(belly_data["emotes_grow"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_grow = sanitize(jointext(belly_data["emotes_grow"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_grow)
new_belly.set_messages(new_emotes_grow,BELLY_MODE_GROW, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_grow,BELLY_MODE_GROW, limit = BELLIES_IDLE_MAX)
if(islist(belly_data["emotes_unabsorb"]))
var/new_emotes_unabsorb = sanitize(jointext(belly_data["emotes_unabsorb"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0)
var/new_emotes_unabsorb = sanitize(jointext(belly_data["emotes_unabsorb"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_emotes_unabsorb)
new_belly.set_messages(new_emotes_unabsorb,BELLY_MODE_UNABSORB, limit = MAX_MESSAGE_LEN / 4)
new_belly.set_messages(new_emotes_unabsorb,BELLY_MODE_UNABSORB, limit = BELLIES_IDLE_MAX)
// Options
if(isnum(belly_data["can_taste"]))
@@ -1154,29 +1154,29 @@
new_belly.liquid_fullness5_messages = TRUE
if(islist(belly_data["fullness1_messages"]))
var/new_fullness1_messages = sanitize(jointext(belly_data["fullness1_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0)
var/new_fullness1_messages = sanitize(jointext(belly_data["fullness1_messages"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_fullness1_messages)
new_belly.set_reagent_messages(new_fullness1_messages,"full1")
new_belly.set_messages(new_fullness1_messages,BELLY_LIQUID_MESSAGE1, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["fullness2_messages"]))
var/new_fullness2_messages = sanitize(jointext(belly_data["fullness2_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0)
var/new_fullness2_messages = sanitize(jointext(belly_data["fullness2_messages"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_fullness2_messages)
new_belly.set_reagent_messages(new_fullness2_messages,"full2")
new_belly.set_messages(new_fullness2_messages,BELLY_LIQUID_MESSAGE2, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["fullness3_messages"]))
var/new_fullness3_messages = sanitize(jointext(belly_data["fullness3_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0)
var/new_fullness3_messages = sanitize(jointext(belly_data["fullness3_messages"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_fullness3_messages)
new_belly.set_reagent_messages(new_fullness3_messages,"full3")
new_belly.set_messages(new_fullness3_messages,BELLY_LIQUID_MESSAGE3, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["fullness4_messages"]))
var/new_fullness4_messages = sanitize(jointext(belly_data["fullness4_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0)
var/new_fullness4_messages = sanitize(jointext(belly_data["fullness4_messages"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_fullness4_messages)
new_belly.set_reagent_messages(new_fullness4_messages,"full4")
new_belly.set_messages(new_fullness4_messages,BELLY_LIQUID_MESSAGE4, limit = BELLIES_MESSAGE_MAX)
if(islist(belly_data["fullness5_messages"]))
var/new_fullness5_messages = sanitize(jointext(belly_data["fullness5_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0)
var/new_fullness5_messages = sanitize(jointext(belly_data["fullness5_messages"],"\n\n"),BELLIES_MESSAGE_COMBINED,0,0,0)
if(new_fullness5_messages)
new_belly.set_reagent_messages(new_fullness5_messages,"full5")
new_belly.set_messages(new_fullness5_messages,BELLY_LIQUID_MESSAGE5, limit = BELLIES_MESSAGE_MAX)
// After import updates
new_belly.items_preserved.Cut()
+30 -6
View File
@@ -326,9 +326,9 @@ GLOBAL_LIST_INIT(vore_words_snake, list("snake","serpent","reptilian","noodle","
raw_messages = escape_absorbed_messages_prey
if(ABSORBED_ESCAPE_OUTSIDE)
raw_messages = escape_absorbed_messages_outside
if(FULL_ABSORBED_ESCAPE_OWNER)
if(ABSORBED_ESCAPE_FAIL_OWNER)
raw_messages = escape_fail_absorbed_messages_owner
if(FULL_ABSORBED_ESCAPE_PREY)
if(ABSORBED_ESCAPE_FAIL_PREY)
raw_messages = escape_fail_absorbed_messages_prey
if(PRIMARY_TRANSFER_OWNER)
raw_messages = primary_transfer_messages_owner
@@ -396,6 +396,16 @@ GLOBAL_LIST_INIT(vore_words_snake, list("snake","serpent","reptilian","noodle","
raw_messages = trash_eater_in
if(BELLY_TRASH_EATER_OUT)
raw_messages = trash_eater_out
if(BELLY_LIQUID_MESSAGE1)
raw_messages = fullness1_messages
if(BELLY_LIQUID_MESSAGE2)
raw_messages = fullness2_messages
if(BELLY_LIQUID_MESSAGE3)
raw_messages = fullness3_messages
if(BELLY_LIQUID_MESSAGE4)
raw_messages = fullness4_messages
if(BELLY_LIQUID_MESSAGE5)
raw_messages = fullness5_messages
var/messages = null
if(raw_messages)
@@ -413,11 +423,15 @@ GLOBAL_LIST_INIT(vore_words_snake, list("snake","serpent","reptilian","noodle","
var/list/raw_list
if(findtext(raw_text, delim))
raw_list = splittext(html_encode(raw_text), delim)
if(islist(raw_text))
raw_list = raw_text
else if(findtext(raw_text, delim))
raw_list = splittext(raw_text, delim)
else
raw_list = list(raw_text)
for(var/i = 1, i <= raw_list.len, i++)
raw_list[i] = html_encode(raw_list[i])
if(!length(raw_list[i]))
raw_list.Cut(i, i + 1)
i--
@@ -480,9 +494,9 @@ GLOBAL_LIST_INIT(vore_words_snake, list("snake","serpent","reptilian","noodle","
escape_absorbed_messages_prey = raw_list
if(ABSORBED_ESCAPE_OUTSIDE)
escape_absorbed_messages_outside = raw_list
if(FULL_ABSORBED_ESCAPE_OWNER)
if(ABSORBED_ESCAPE_FAIL_OWNER)
escape_fail_absorbed_messages_owner = raw_list
if(FULL_ABSORBED_ESCAPE_PREY)
if(ABSORBED_ESCAPE_FAIL_PREY)
escape_fail_absorbed_messages_prey = raw_list
if(PRIMARY_TRANSFER_OWNER)
primary_transfer_messages_owner = raw_list
@@ -550,3 +564,13 @@ GLOBAL_LIST_INIT(vore_words_snake, list("snake","serpent","reptilian","noodle","
trash_eater_in = raw_list
if(BELLY_TRASH_EATER_OUT)
trash_eater_out = raw_list
if(BELLY_LIQUID_MESSAGE1)
fullness1_messages = raw_list
if(BELLY_LIQUID_MESSAGE2)
fullness2_messages = raw_list
if(BELLY_LIQUID_MESSAGE3)
fullness3_messages = raw_list
if(BELLY_LIQUID_MESSAGE4)
fullness4_messages = raw_list
if(BELLY_LIQUID_MESSAGE5)
fullness5_messages = raw_list
@@ -263,65 +263,6 @@
return(span_red("[formatted_message]<BR>"))
// The next function gets the messages set on the belly, in human-readable format.
// This is useful in customization boxes and such. The delimiter right now is \n\n so
// in message boxes, this looks nice and is easily delimited.
/obj/belly/proc/get_reagent_messages(var/type, var/delim = "\n\n")
ASSERT(type == "full1" || type == "full2" || type == "full3" || type == "full4" || type == "full5")
var/list/raw_messages
switch(type)
if("full1")
raw_messages = fullness1_messages
if("full2")
raw_messages = fullness2_messages
if("full3")
raw_messages = fullness3_messages
if("full4")
raw_messages = fullness4_messages
if("full5")
raw_messages = fullness5_messages
var/messages = raw_messages.Join(delim)
return messages
// The next function sets the messages on the belly, from human-readable var
// replacement strings and linebreaks as delimiters (two \n\n by default).
// They also sanitize the messages.
/obj/belly/proc/set_reagent_messages(var/raw_text, var/type, var/delim = "\n\n")
ASSERT(type == "full1" || type == "full2" || type == "full3" || type == "full4" || type == "full5")
var/list/raw_list = splittext(html_encode(raw_text),delim)
if(raw_list.len > 10)
raw_list.Cut(11)
log_debug("[owner] tried to set [lowertext(name)] with 11+ messages")
for(var/i = 1, i <= raw_list.len, i++)
if(length(raw_list[i]) > 160 || length(raw_list[i]) < 10) //160 is fudged value due to htmlencoding increasing the size
raw_list.Cut(i,i)
log_debug("[owner] tried to set [lowertext(name)] with >121 or <10 char message")
else
raw_list[i] = readd_quotes(raw_list[i])
//Also fix % sign for var replacement
raw_list[i] = replacetext(raw_list[i],"&#37;","%")
ASSERT(raw_list.len <= 10) //Sanity
switch(type)
if("full1")
fullness1_messages = raw_list
if("full2")
fullness2_messages = raw_list
if("full3")
fullness3_messages = raw_list
if("full4")
fullness4_messages = raw_list
if("full5")
fullness5_messages = raw_list
return
/////////////////////////// Process Cycle Lite /////////////////////////// CHOMP PCL
/obj/belly/proc/quick_cycle() //For manual belly cycling without straining the bellies subsystem.
HandleBellyReagents() //reagent belly stuff.
+1 -1
View File
@@ -129,7 +129,7 @@
S.use(1)
digest_stage = w_class
else
if(istype(src, /obj/item/reagent_containers/food))
if(istype(B) && istype(src, /obj/item/reagent_containers/food))
if(ishuman(B.owner) && reagents)
var/mob/living/carbon/human/H = B.owner
reagents.trans_to_holder(H.ingested, (reagents.total_volume), B.nutrition_percent / 100, 0)
-1
View File
@@ -25,7 +25,6 @@
var/allow_spontaneous_tf = FALSE // Obviously.
var/show_vore_fx = TRUE // Show belly fullscreens
var/selective_preference = DM_DEFAULT // Preference for selective bellymode
var/text_warnings = TRUE // Allows us to dismiss the text limit warning messages after viewing it once per round
var/eating_privacy_global = FALSE // Makes eating attempt/success messages only reach for subtle range if true, overwritten by belly-specific var
var/allow_mimicry = TRUE // Allows mimicking their character
var/allow_mind_transfer = FALSE //Allows ones mind to be taken over or swapped
@@ -0,0 +1,111 @@
/datum/vore_look/proc/get_preference_data(mob/owner)
return list(
"digestable" = owner.digestable,
"devourable" = owner.devourable,
"resizable" = owner.resizable,
"feeding" = owner.feeding,
"absorbable" = owner.absorbable,
"digest_leave_remains" = owner.digest_leave_remains,
"allowmobvore" = owner.allowmobvore,
"permit_healbelly" = owner.permit_healbelly,
"show_vore_fx" = owner.show_vore_fx,
"can_be_drop_prey" = owner.can_be_drop_prey,
"can_be_drop_pred" = owner.can_be_drop_pred,
"latejoin_vore" = owner.latejoin_vore,
"latejoin_prey" = owner.latejoin_prey,
"no_spawnpred_warning" = owner.no_latejoin_vore_warning,
"no_spawnprey_warning" = owner.no_latejoin_prey_warning,
"no_spawnpred_warning_time" = owner.no_latejoin_vore_warning_time,
"no_spawnprey_warning_time" = owner.no_latejoin_prey_warning_time,
"no_spawnpred_warning_save" = owner.no_latejoin_vore_warning_persists,
"no_spawnprey_warning_save" = owner.no_latejoin_prey_warning_persists,
"allow_spontaneous_tf" = owner.allow_spontaneous_tf,
"step_mechanics_active" = owner.step_mechanics_pref,
"pickup_mechanics_active" = owner.pickup_pref,
"strip_mechanics_active" = owner.strip_pref,
"noisy" = owner.noisy,
//liquid belly prefs
"liq_rec" = owner.receive_reagents,
"liq_giv" = owner.give_reagents,
"liq_apply" = owner.apply_reagents,
"autotransferable" = owner.autotransferable,
"noisy_full" = owner.noisy_full, //Belching while full
"selective_active" = owner.selective_preference, //Reveal active selective mode in prefs
"allow_mind_transfer" = owner.allow_mind_transfer,
"drop_vore" = owner.drop_vore,
"slip_vore" = owner.slip_vore,
"stumble_vore" = owner.stumble_vore,
"throw_vore" = owner.throw_vore,
"phase_vore" = owner.phase_vore,
"food_vore" = owner.food_vore,
"consume_liquid_belly" = owner.consume_liquid_belly,
"digest_pain" = owner.digest_pain,
"eating_privacy_global" = owner.eating_privacy_global,
"allow_mimicry" = owner.allow_mimicry,
//Soulcatcher
"soulcatcher_allow_capture" = owner.soulcatcher_pref_flags & SOULCATCHER_ALLOW_CAPTURE,
"soulcatcher_allow_transfer" = owner.soulcatcher_pref_flags & SOULCATCHER_ALLOW_TRANSFER,
"soulcatcher_allow_takeover" = owner.soulcatcher_pref_flags & SOULCATCHER_ALLOW_TAKEOVER,
"soulcatcher_allow_deletion" = (global_flag_check(owner.soulcatcher_pref_flags, SOULCATCHER_ALLOW_DELETION) + global_flag_check(owner.soulcatcher_pref_flags, SOULCATCHER_ALLOW_DELETION_INSTANT))
)
#define SET_TASTE "Set Taste"
#define SET_SMELL "Set Smell"
#define SET_NUTRITION_EX "Set Nutrition Examine"
#define SET_WEIGHT_EX "Set Weight Examine"
/datum/vore_look/proc/get_general_data(mob/owner)
return list(
"active_belly" = owner.vore_selected?.name,
"belly_rub_target" = owner.belly_rub_target,
// start, vore sprites
"aestethic_messages" = compile_aesthetic_messages(owner),
"vore_sprite_color" = owner.vore_sprite_color,
"vore_sprite_multiply" = owner.vore_sprite_multiply,
"vore_icon_options" = owner.vore_icon_bellies
)
/datum/vore_look/proc/compile_aesthetic_messages(mob/owner)
if(!aset_message_subtab)
aset_message_subtab = SET_TASTE
var/list/tab_data = list(
"possible_messages" = list(SET_TASTE, SET_SMELL, SET_NUTRITION_EX, SET_WEIGHT_EX),
"aest_subtab" = aset_message_subtab
)
if(aset_message_subtab == SET_TASTE)
tab_data["max_length"] = FLAVOR_MAX
tab_data["active_message"] = owner.vore_taste
tab_data["set_action"] = TASTE_FLAVOR
tab_data["tooltip"] = "What your character tastes like. This text will be printed to the pred after 'X tastes of...' so just put something like 'strawberries and cream'"
if(aset_message_subtab == SET_SMELL)
tab_data["max_length"] = FLAVOR_MAX
tab_data["active_message"] = owner.vore_smell
tab_data["set_action"] = SMELL_FLAVOR
tab_data["tooltip"] = "What your character smells like. This text will be printed to the pred after 'X smells of...' so just put something like 'strawberries and cream'"
if(aset_message_subtab == SET_NUTRITION_EX)
tab_data["max_length"] = BELLIES_EXAMINE_MAX
tab_data["active_message"] = owner.nutrition_messages
tab_data["set_action"] = "set_attribute"
tab_data["sub_action"] = GENERAL_EXAMINE_NUTRI
tab_data["tooltip"] = "Change the nutrition display messages on examine."
tab_data["button_label"] = "Display Nutrition Examine"
tab_data["button_action"] = "toggle_nutrition_ex"
tab_data["button_data"] = owner.nutrition_message_visible
tab_data["button_tooltip"] = "the nutition messages on examine." // those will automatically be preceeded by Enables / Disables!
if(aset_message_subtab == SET_WEIGHT_EX)
tab_data["max_length"] = BELLIES_EXAMINE_MAX
tab_data["active_message"] = owner.weight_messages
tab_data["set_action"] = "set_attribute"
tab_data["sub_action"] = GENERAL_EXAMINE_WEIGHT
tab_data["tooltip"] = "Change the weight display messages on examine."
tab_data["button_label"] = "Display Weight Examine"
tab_data["button_action"] = "toggle_weight_ex"
tab_data["button_data"] = owner.weight_message_visible
tab_data["button_tooltip"] = "the weight messages on examine." // those will automatically be preceeded by Enables / Disables!
return tab_data
#undef SET_TASTE
#undef SET_SMELL
#undef SET_NUTRITION_EX
#undef SET_WEIGHT_EX
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,215 @@
// liquid belly procs
/datum/vore_look/proc/liq_set_attr(mob/user, params)
if(!host.vore_selected)
tgui_alert(user, "No belly selected to modify.")
return FALSE
var/attr = params["attribute"]
switch(attr)
if("b_show_liq")
if(!host.vore_selected.show_liquids)
host.vore_selected.show_liquids = 1
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] now has liquid options."))
else
host.vore_selected.show_liquids = 0
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] no longer has liquid options."))
. = TRUE
if("b_liq_reagent_gen")
if(!host.vore_selected.reagentbellymode) //liquid container adjustments and interactions.
host.vore_selected.reagentbellymode = 1
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] now has interactions which can produce liquids."))
else //Doesnt produce liquids
host.vore_selected.reagentbellymode = 0
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] wont produce liquids, liquids already in your [lowertext(host.vore_selected.name)] must be emptied out or removed with purge."))
. = TRUE
if("b_liq_reagent_type")
var/new_reagent = params["val"]
if(!(new_reagent in host.vore_selected.reagent_choices))
return FALSE
host.vore_selected.reagent_chosen = new_reagent
host.vore_selected.ReagentSwitch() // For changing variables when a new reagent is chosen
. = TRUE
if("b_liq_reagent_name")
var/new_name = params["val"]
if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN)
tgui_alert(user, "Entered name length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).","Error")
return FALSE
host.vore_selected.reagent_name = new_name
. = TRUE
if("b_liq_reagent_transfer_verb")
var/new_verb = params["val"]
if(length(new_verb) > BELLIES_NAME_MAX || length(new_verb) < BELLIES_NAME_MIN)
tgui_alert(user, "Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).","Error")
return FALSE
host.vore_selected.reagent_transfer_verb = new_verb
. = TRUE
if("b_liq_reagent_nutri_rate")
host.vore_selected.gen_time_display = params["val"]
switch(host.vore_selected.gen_time_display)
if("10 minutes")
host.vore_selected.gen_time = 0
if("30 minutes")
host.vore_selected.gen_time = 2
if("1 hour")
host.vore_selected.gen_time = 5
if("3 hours")
host.vore_selected.gen_time = 17
if("6 hours")
host.vore_selected.gen_time = 35
if("12 hours")
host.vore_selected.gen_time = 71
if("24 hours")
host.vore_selected.gen_time = 143
. = TRUE
if("b_liq_reagent_capacity")
var/new_custom_vol = text2num(params["val"])
if(!isnum(new_custom_vol))
return FALSE
host.vore_selected.custom_max_volume = CLAMP(new_custom_vol, 10, 300)
. = TRUE
if("b_liq_sloshing")
if(!host.vore_selected.vorefootsteps_sounds)
host.vore_selected.vorefootsteps_sounds = 1
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] can now make sounds when you walk around depending on how full you are."))
else
host.vore_selected.vorefootsteps_sounds = 0
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] wont make any liquid sounds no matter how full it is."))
. = TRUE
if("b_liq_reagent_addons")
var/reagent_toggle_addon = params["val"]
if(!reagent_toggle_addon)
return FALSE
host.vore_selected.reagent_mode_flags ^= host.vore_selected.reagent_mode_flag_list[reagent_toggle_addon]
. = TRUE
if("b_liquid_overlay")
if(!host.vore_selected.liquid_overlay)
host.vore_selected.liquid_overlay = 1
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] now has liquid overlay enabled."))
else
host.vore_selected.liquid_overlay = 0
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] no longer has liquid overlay enabled."))
. = TRUE
if("b_max_liquid_level")
var/new_max_liquid_level = params["val"]
if(!isnum(new_max_liquid_level))
return FALSE
host.vore_selected.max_liquid_level = CLAMP(new_max_liquid_level, 0, 100)
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_custom_reagentcolor")
var/newcolor = tgui_color_picker(user, "Choose custom color for liquid overlay. Cancel for normal reagent color.", "", host.vore_selected.custom_reagentcolor)
if(newcolor)
host.vore_selected.custom_reagentcolor = newcolor
else
host.vore_selected.custom_reagentcolor = null
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_custom_reagentalpha")
var/newalpha = text2num(params["val"])
if(!isnum(newalpha))
return FALSE
if(newalpha)
host.vore_selected.custom_reagentalpha = CLAMP(newalpha, 0, 255)
else
host.vore_selected.custom_reagentalpha = null
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_reagent_touches")
if(!host.vore_selected.reagent_touches)
host.vore_selected.reagent_touches = 1
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] will now apply reagents to creatures when digesting."))
else
host.vore_selected.reagent_touches = 0
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] will no longer apply reagents to creatures when digesting."))
. = TRUE
if("b_mush_overlay")
if(!host.vore_selected.mush_overlay)
host.vore_selected.mush_overlay = 1
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] now has fullness overlay enabled."))
else
host.vore_selected.mush_overlay = 0
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] no longer has fullness overlay enabled."))
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_mush_color")
var/newcolor = tgui_color_picker(user, "Choose custom color for mush overlay.", "", host.vore_selected.mush_color)
if(newcolor)
host.vore_selected.mush_color = newcolor
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_mush_alpha")
var/newalpha = text2num(params["val"])
if(!isnum(newalpha))
return FALSE
host.vore_selected.mush_alpha = CLAMP(newalpha, 0, 255)
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_max_mush")
var/new_max_mush = text2num(params["val"])
if(!isnum(new_max_mush))
return FALSE
host.vore_selected.max_mush = CLAMP(new_max_mush, 0, 6000)
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_min_mush")
var/new_min_mush = text2num(params["val"])
if(!isnum(new_min_mush))
return FALSE
host.vore_selected.min_mush = CLAMP(new_min_mush, 0, 100)
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_item_mush_val")
var/new_item_mush_val = text2num(params["val"])
if(!isnum(new_item_mush_val))
return FALSE
host.vore_selected.item_mush_val = CLAMP(new_item_mush_val, 0, 1000)
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_metabolism_overlay")
if(!host.vore_selected.metabolism_overlay)
host.vore_selected.metabolism_overlay = 1
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] now has ingested metabolism overlay enabled."))
else
host.vore_selected.metabolism_overlay = 0
to_chat(user,span_warning("Your [lowertext(host.vore_selected.name)] no longer has ingested metabolism overlay enabled."))
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_metabolism_mush_ratio")
var/new_metabolism_mush_ratio = text2num(params["val"])
if(!isnum(new_metabolism_mush_ratio))
return FALSE
host.vore_selected.metabolism_mush_ratio = CLAMP(new_metabolism_mush_ratio, 0, 500)
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_max_ingested")
var/new_max_ingested = text2num(params["val"])
if(!isnum(new_max_ingested))
return FALSE
host.vore_selected.max_ingested = CLAMP(new_max_ingested, 0, 6000)
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_custom_ingested_color")
var/newcolor = tgui_color_picker(user, "Choose custom color for ingested metabolism overlay. Cancel for reagent-based dynamic blend.", "", host.vore_selected.custom_ingested_color)
if(newcolor)
host.vore_selected.custom_ingested_color = newcolor
else
host.vore_selected.custom_ingested_color = null
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_custom_ingested_alpha")
var/newalpha = text2num(params["val"])
if(!isnum(newalpha))
return FALSE
host.vore_selected.custom_ingested_alpha = newalpha
host.vore_selected.update_internal_overlay()
. = TRUE
if("b_liq_purge")
host.vore_selected.reagents.clear_reagents()
. = TRUE
if(.)
unsaved_changes = TRUE
@@ -0,0 +1,99 @@
#define INTERIOR_DESIGN "Interior Design"
#define CAPTURE_MESSAGE "Capture Message"
#define TRANSIT_MESSAGE "Transit Message"
#define TRANSFER_MESSAGE "Transfer Message"
#define RELEASE_MESSAGE "Release Message"
#define DELETE_MESSAGE "Delete Message"
/datum/vore_look/proc/get_soulcatcher_data(mob/owner)
if(!owner.soulgem)
return null
var/list/stored_souls = list()
for(var/soul in owner.soulgem.brainmobs)
var/list/info = list("displayText" = "[soul]", "value" = "\ref[soul]")
stored_souls.Add(list(info))
var/list/soulcatcher_data = list(
"active" = owner.soulgem.flag_check(SOULGEM_ACTIVE),
"name" = owner.soulgem.name,
"caught_souls" = stored_souls,
"selected_soul" = owner.soulgem.selected_soul,
"selected_sfx" = owner.soulgem.linked_belly,
"sc_message_data" = compile_soulcatcher_message_data(owner.soulgem),
"taken_over" = owner.soulgem.is_taken_over(),
"catch_self" = owner.soulgem.flag_check(NIF_SC_CATCHING_ME),
"catch_prey" = owner.soulgem.flag_check(NIF_SC_CATCHING_OTHERS),
"catch_drain" = owner.soulgem.flag_check(SOULGEM_CATCHING_DRAIN),
"catch_ghost" = owner.soulgem.flag_check(SOULGEM_CATCHING_GHOSTS),
"ext_hearing" = owner.soulgem.flag_check(NIF_SC_ALLOW_EARS),
"ext_vision" = owner.soulgem.flag_check(NIF_SC_ALLOW_EYES),
"mind_backups" = owner.soulgem.flag_check(NIF_SC_BACKUPS),
"sr_projecting" = owner.soulgem.flag_check(NIF_SC_PROJECTING),
"show_vore_sfx" = owner.soulgem.flag_check(SOULGEM_SHOW_VORE_SFX),
"see_sr_projecting" = owner.soulgem.flag_check(SOULGEM_SEE_SR_SOULS),
)
return soulcatcher_data
/datum/vore_look/proc/compile_soulcatcher_message_data(obj/soulgem/gem)
if(!sc_message_subtab)
sc_message_subtab = INTERIOR_DESIGN
var/list/tab_data = list(
"possible_messages" = list(INTERIOR_DESIGN, CAPTURE_MESSAGE, TRANSIT_MESSAGE, TRANSFER_MESSAGE, RELEASE_MESSAGE, DELETE_MESSAGE),
"sc_subtab" = sc_message_subtab
)
if(sc_message_subtab == INTERIOR_DESIGN)
tab_data["max_length"] = VORE_SC_DESC_MAX
tab_data["active_message"] = gem.inside_flavor
tab_data["set_action"] = SC_INTERIOR_MESSAGE
tab_data["tooltip"] = "Displayed to prey after being 'caught' by the soulcatcher. This will be displayed after an intro set in the capture message. If you already have prey and change the interior, this will be displayed after the transit message."
if(sc_message_subtab == CAPTURE_MESSAGE)
tab_data["max_length"] = VORE_SC_MAX
tab_data["active_message"] = gem.capture_message
tab_data["set_action"] = SC_CAPTURE_MEESAGE
tab_data["tooltip"] = "Change what the prey sees while being 'caught'. This will be printed before the iterior design to the prey."
if(sc_message_subtab == TRANSIT_MESSAGE)
tab_data["max_length"] = VORE_SC_MAX
tab_data["active_message"] = gem.transit_message
tab_data["set_action"] = SC_TRANSIT_MESSAGE
tab_data["tooltip"] = "Change what the prey sees when you change the interior with them already captured."
if(sc_message_subtab == TRANSFER_MESSAGE)
tab_data["max_length"] = VORE_SC_MAX
tab_data["active_message"] = gem.transfer_message
tab_data["set_action"] = SC_TRANSFERE_MESSAGE
tab_data["tooltip"] = "Change what the prey sees when they are transfered."
if(sc_message_subtab == RELEASE_MESSAGE)
tab_data["max_length"] = VORE_SC_MAX
tab_data["active_message"] = gem.release_message
tab_data["set_action"] = SC_RELEASE_MESSAGE
tab_data["tooltip"] = "Change what the prey sees when they are released."
if(sc_message_subtab == DELETE_MESSAGE)
tab_data["max_length"] = VORE_SC_MAX
tab_data["active_message"] = gem.delete_message
tab_data["set_action"] = SC_DELETE_MESSAGE
tab_data["tooltip"] = "Change what the prey sees when they are deleted."
return tab_data
/datum/vore_look/proc/get_ability_data(mob/owner)
var/list/abilities = list()
var/nutri_value = 0
if(isliving(owner))
var/mob/living/H = owner
nutri_value = H.nutrition
abilities["nutrition"] = nutri_value
abilities["size_change"] = list (
"current_size" = owner.size_multiplier,
"minimum_size" = owner.has_large_resize_bounds() ? RESIZE_MINIMUM_DORMS : RESIZE_MINIMUM,
"maximum_size" = owner.has_large_resize_bounds() ? RESIZE_MAXIMUM_DORMS : RESIZE_MAXIMUM,
"resize_cost" = VORE_RESIZE_COST
)
return abilities
#undef INTERIOR_DESIGN
#undef CAPTURE_MESSAGE
#undef TRANSIT_MESSAGE
#undef TRANSFER_MESSAGE
#undef RELEASE_MESSAGE
#undef DELETE_MESSAGE
@@ -0,0 +1,328 @@
#define CONTROL_TAB 0
#define DESCRIPTIONS_TAB 1
#define OPTIONS_TAB 2
#define SOUNDS_TAB 3
#define VISUALS_TAB 4
#define INTERACTIONS_TAB 5
#define CONTENTS_TAB 6
#define LIQUID_OPTIONS_TAB 7
/datum/vore_look/proc/get_vorebellies(mob/owner, full_data = TRUE)
var/list/our_bellies = list()
for(var/obj/belly/B as anything in owner.vore_organs)
var/list/belly_data = list()
belly_data += list(
"name" = B.name,
"ref" = "\ref[B]"
)
if(full_data)
belly_data += list(
"selected" = (B == owner.vore_selected),
"digest_mode" = B.digest_mode,
"contents" = LAZYLEN(B.contents),
"prevent_saving" = B.prevent_saving
)
UNTYPED_LIST_ADD(our_bellies, belly_data)
return our_bellies
/datum/vore_look/proc/get_inside_data(mob/owner)
var/atom/hostloc = owner.loc
//Allow VorePanel to show pred belly details even while indirectly inside
if(isliving(owner))
var/mob/living/H = owner
hostloc = H.surrounding_belly()
//End of indirect vorefx additions
var/list/inside = list()
if(isbelly(hostloc))
var/obj/belly/inside_belly = hostloc
var/mob/living/pred = inside_belly.owner
var/inside_desc = "No description."
if(owner.absorbed && inside_belly.absorbed_desc)
inside_desc = inside_belly.absorbed_desc
else if(inside_belly.desc)
inside_desc = inside_belly.desc
if(inside_desc != "No description.")
inside_desc = inside_belly.belly_format_string(inside_desc, owner, use_first_only = TRUE)
inside = list(
"absorbed" = owner.absorbed,
"belly_name" = inside_belly.name,
"belly_mode" = inside_belly.digest_mode,
"desc" = inside_desc,
"pred" = pred,
"ref" = "\ref[inside_belly]",
"liq_lvl" = inside_belly.reagents.total_volume,
"liq_reagent_type" = inside_belly.reagent_chosen,
"liuq_name" = inside_belly.reagent_name,
)
var/list/inside_contents = list()
for(var/atom/movable/O in inside_belly)
if(O == owner)
continue
var/list/info = list(
"name" = "[O]",
"absorbed" = FALSE,
"stat" = 0,
"ref" = "\ref[O]",
"outside" = FALSE,
)
if(show_pictures) //disables icon mode
if(inside_belly.contents.len <= max_icon_content)
icon_overflow = FALSE
info["icon"] = cached_nom_icon(O)
else
icon_overflow = TRUE
if(isliving(O))
var/mob/living/M = O
info["stat"] = M.stat
if(M.absorbed)
info["absorbed"] = TRUE
UNTYPED_LIST_ADD(inside_contents, info)
inside["contents"] = inside_contents
return inside
/datum/vore_look/proc/get_host_mobtype(mob/owner)
var/list/host_mobtype = list("is_cyborg" = FALSE, "is_vore_simple_mob" = FALSE)
if(isrobot(owner))
host_mobtype["is_cyborg"] = TRUE
else if(istype(owner, /mob/living/simple_mob/vore)) //So far, this does nothing. But, creating this for future belly work
host_mobtype["is_vore_simple_mob"] = TRUE
return host_mobtype
/datum/vore_look/proc/get_selected_data(mob/owner)
var/list/selected_list = null
if(owner.vore_selected)
var/obj/belly/selected = owner.vore_selected
selected_list = list("belly_name" = selected.name)
if(active_vore_tab == CONTROL_TAB)
var/list/addons = list()
for(var/flag_name in selected.mode_flag_list)
UNTYPED_LIST_ADD(addons, list("label" = flag_name, "selection" = selected.mode_flags & selected.mode_flag_list[flag_name]))
var/list/belly_mode_data = list(
"mode" = selected.digest_mode,
"item_mode" = selected.item_digest_mode,
"addons" = addons,
"name_length" = BELLIES_NAME_MAX,
"name_min" = BELLIES_NAME_MIN,
"mode_options" = host.vore_selected.digest_modes,
"item_mode_options" = host.vore_selected.item_digest_modes,
)
selected_list["belly_mode_data"] = belly_mode_data
if(active_vore_tab == DESCRIPTIONS_TAB)
// Compile our displayed options
var/list/displayed_options = list(
VPANEL_DESCRIPTION_TAB,
VPANEL_EXAMINE_TAB,
VPANEL_TRASH_EATER_TAB
)
if(selected.message_mode || selected.escapable)
displayed_options += VPANEL_STRUGGLE_TAB
displayed_options += VPANEL_ESCAPE_TAB
displayed_options += VPANEL_ESCAPE_ABSORBED_TAB
if(selected.message_mode || (selected.escapable && (selected.transferlocation || selected.transferlocation_secondary)) || selected.autotransfer_enabled && (selected.autotransferlocation || selected.autotransferlocation_secondary))
displayed_options += VPANEL_TRANSFER_TAB
if(selected.message_mode || selected.escapable && (selected.digestchance || selected.absorbchance))
displayed_options += VPANEL_INTERACTION_TAB
if(selected.message_mode || selected.digest_mode == DM_DIGEST || selected.digest_mode == DM_SELECT || selected.digest_mode == DM_ABSORB || selected.digest_mode == DM_UNABSORB)
displayed_options += VPANEL_BELLYMODE_TAB
if(selected.message_mode || selected.emote_active)
displayed_options += VPANEL_IDLE_TAB
if(selected.message_mode || selected.show_fullness_messages)
displayed_options += VPANEL_LIQUIDS_TAB
var/list/belly_description_data = list(
"displayed_message_types" = compile_message_data(selected),
"verb" = selected.vore_verb,
"release_verb" = selected.release_verb,
"message_mode" = selected.message_mode,
"displayed_options" = displayed_options,
"message_option" = message_option,
"message_subtab" = message_subtab,
"selected_message" = selected_message,
"show_liq_fullness" = selected.show_fullness_messages,
"emote_time" = selected.emote_time,
"emote_active" = selected.emote_active,
"entrance_logs" = selected.entrance_logs,
"item_digest_logs" = selected.item_digest_logs,
"name_min" = BELLIES_NAME_MIN,
"name_length" = BELLIES_NAME_MAX,
)
selected_list["belly_description_data"] = belly_description_data
if(active_vore_tab == OPTIONS_TAB)
var/list/silicon_control = list(
"silicon_belly_overlay_preference" = selected.silicon_belly_overlay_preference,
"belly_sprite_option_shown" = LAZYLEN(owner.vore_icon_bellies) >= 1 ? TRUE : FALSE,
"belly_sprite_to_affect" = selected.belly_sprite_to_affect
)
var/list/belly_option_data = list(
"can_taste" = selected.can_taste,
"is_feedable" = selected.is_feedable,
"nutrition_percent" = selected.nutrition_percent,
"digest_brute" = selected.digest_brute,
"digest_burn" = selected.digest_burn,
"digest_oxy" = selected.digest_oxy,
"digest_tox" = selected.digest_tox,
"digest_clone" = selected.digest_clone,
"digest_max" = selected.digest_max,
"digest_free" = selected.get_unused_digestion_damage(),
"bulge_size" = selected.bulge_size,
"shrink_grow_size" = selected.shrink_grow_size,
"contaminates" = selected.contaminates,
"egg_type" = selected.egg_type,
"egg_types" = GLOB.global_vore_egg_types,
"egg_name" = selected.egg_name,
"egg_size" = selected.egg_size,
"recycling" = selected.recycling,
"storing_nutrition" = selected.storing_nutrition,
"selective_preference" = selected.selective_preference,
"save_digest_mode" = selected.save_digest_mode,
"eating_privacy_local" = selected.eating_privacy_local,
"vorespawn_blacklist" = selected.vorespawn_blacklist,
"vorespawn_whitelist" = selected.vorespawn_whitelist,
"vorespawn_absorbed" = (global_flag_check(selected.vorespawn_absorbed, VS_FLAG_ABSORB_YES) + global_flag_check(selected.vorespawn_absorbed, VS_FLAG_ABSORB_PREY)),
"private_struggle" = selected.private_struggle,
"drainmode" = selected.drainmode,
"drainmode_options" = selected.drainmodes,
"mob_belly_controls" = silicon_control
)
if(selected.contaminates)
belly_option_data += list(
"contaminate_flavor" = selected.contamination_flavor,
"contaminate_options" = GLOB.contamination_flavors,
"contaminate_color" = selected.contamination_color,
"contaminate_colors" = GLOB.contamination_colors
)
selected_list["belly_option_data"] = belly_option_data
if(active_vore_tab == SOUNDS_TAB)
var/list/belly_sound_data = list(
"is_wet" = selected.is_wet,
"wet_loop" = selected.wet_loop,
"fancy" = selected.fancy_vore,
"sound" = selected.vore_sound,
"release_sound" = selected.release_sound,
"sound_volume" = selected.sound_volume,
"noise_freq" = selected.noise_freq,
"min_voice_freq" = MIN_VOICE_FREQ,
"max_voice_freq" = MAX_VOICE_FREQ,
"vore_sound_list" = (selected.fancy_vore ? GLOB.fancy_vore_sounds : GLOB.classic_vore_sounds),
"release_sound_list" = (selected.fancy_vore ? GLOB.fancy_release_sounds : GLOB.classic_release_sounds)
)
selected_list["belly_sound_data"] = belly_sound_data
if(active_vore_tab == VISUALS_TAB)
var/list/belly_fullscreens
if(selected.colorization_enabled)
belly_fullscreens = icon_states('icons/mob/screen_full_vore_list.dmi') //Makes any icons inside of here selectable.
else
belly_fullscreens = icon_states('icons/mob/screen_full_vore.dmi') //Non colorable
var/list/vs_flags = list()
for(var/flag_name in selected.vore_sprite_flag_list)
UNTYPED_LIST_ADD(vs_flags, list("label" = flag_name, "selection" = selected.vore_sprite_flags & selected.vore_sprite_flag_list[flag_name]))
var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[host.vore_selected.undergarment_chosen]
var/list/undergarments
if(UWC)
undergarments = UWC.items
var/list/belly_visual_data = list(
"belly_fullscreen" = selected.belly_fullscreen,
"colorization_enabled" = selected.colorization_enabled,
"belly_fullscreen_color" = selected.belly_fullscreen_color,
"belly_fullscreen_color2" = selected.belly_fullscreen_color2,
"belly_fullscreen_color3" = selected.belly_fullscreen_color3,
"belly_fullscreen_color4" = selected.belly_fullscreen_color4,
"belly_fullscreen_alpha" = selected.belly_fullscreen_alpha,
"possible_fullscreens" = belly_fullscreens,
"disable_hud" = selected.disable_hud,
"vore_sprite_flags" = vs_flags,
"affects_voresprite" = selected.affects_vore_sprites,
"absorbed_voresprite" = selected.count_absorbed_prey_for_sprite,
"absorbed_multiplier" = selected.absorbed_multiplier,
"liquid_voresprite" = selected.count_liquid_for_sprite,
"liquid_multiplier" = selected.liquid_multiplier,
"item_voresprite" = selected.count_items_for_sprite,
"item_multiplier" = selected.item_multiplier,
"health_voresprite" = selected.health_impacts_size,
"resist_animation" = selected.resist_triggers_animation,
"voresprite_size_factor" = selected.size_factor_for_sprite,
"belly_sprite_to_affect" = selected.belly_sprite_to_affect,
"belly_sprite_options" = host.vore_icon_bellies,
"undergarment_chosen" = selected.undergarment_chosen,
"undergarment_if_none" = selected.undergarment_if_none || "None",
"undergarment_options" = global_underwear.categories,
"undergarment_options_if_none" = undergarments,
"undergarment_color" = selected.undergarment_color,
"tail_option_shown" = ishuman(owner),
"tail_to_change_to" = selected.tail_to_change_to,
"tail_sprite_options" = global.tail_styles_list
)
selected_list["belly_visual_data"] = belly_visual_data
if(active_vore_tab == INTERACTIONS_TAB)
var/list/belly_interaction_data = list(
"escapable" = selected.escapable,
"interacts" = compile_interact_data(selected),
"autotransfer_enabled" = selected.autotransfer_enabled,
"autotransfer" = compile_autotransfer_data(selected)
)
selected_list["belly_interaction_data"] = belly_interaction_data
var/list/selected_contents
var/total_content_count = 0
for(var/O in selected)
total_content_count++
if(active_vore_tab == CONTENTS_TAB)
var/list/info = list(
"name" = "[O]",
"absorbed" = FALSE,
"stat" = 0,
"ref" = "\ref[O]",
"outside" = TRUE,
)
if(show_pictures) //disables icon mode
if(selected.contents.len <= max_icon_content)
icon_overflow = FALSE
info["icon"] = cached_nom_icon(O)
else
icon_overflow = TRUE
if(isliving(O))
var/mob/living/M = O
info["stat"] = M.stat
if(M.absorbed)
info["absorbed"] = TRUE
LAZYADD(selected_contents, list(info))
if(active_vore_tab == CONTENTS_TAB)
selected_list["contents"] = selected_contents
selected_list["content_length"] = total_content_count
if(active_vore_tab == LIQUID_OPTIONS_TAB)
// liquid belly options
var/list/belly_liquid_data = list(
"show_liq" = selected.show_liquids,
"liq_interacts" = compile_liquid_interact_data(selected)
)
selected_list["belly_liquid_data"] = belly_liquid_data
return selected_list
#undef CONTROL_TAB
#undef DESCRIPTIONS_TAB
#undef OPTIONS_TAB
#undef SOUNDS_TAB
#undef VISUALS_TAB
#undef INTERACTIONS_TAB
#undef CONTENTS_TAB
#undef LIQUID_OPTIONS_TAB
@@ -0,0 +1,759 @@
#define DEFAULT_MESSAGE "Default"
#define ABSORBED_MESSAGE "Absorbed"
#define WITH_PREY "With Prey"
#define WITH_ABSORBED_PREY "With Absorbed Prey"
#define TRASH_EAT "Eat"
#define TRASH_EXPEL "Expel"
#define OUTSIDE_MESSAGE "Outside"
#define INSIDE_MESSAGE "Inside"
#define TO_YOU "To You"
#define TO_PREY "To Prey"
#define ATTEMPT_MESSAGE "Attempt"
#define SUCCESS_MESSAGE "Success"
#define ITEM_MESSAGE "Item"
#define FAIL_MESSAGE "Fail"
#define PRIMARY_MESSAGE "Primary"
#define SECONARY_MESSAGE "Secondary"
#define PRIMARY_AUTO_MESSAGE "Primary (Auto)"
#define SECONARY_AUTO_MESSAGE "Secondary (Auto)"
#define DIGEST_MESSAGE "Digest"
#define HOLD_MESSAGE "Hold"
#define HOLDABSORBED_MESSAGE "Hold (Absorbed)"
#define ABSORB_MESSAGE "Absorb"
#define HEAL_MESSAGE "Heal"
#define DRAIN_MESSAGE "Drain"
#define STEAL_MESSAGE "Steal"
#define EGG_MESSAGE "Egg"
#define SHRINK_MESSAGE "Shrink"
#define GROW_MESSAGE "Grow"
#define UNABSORB_MESSAGE "Unabsorb"
#define LIQUID0 "Liquid 0-20%"
#define LIQUID20 "Liquid 20-40%"
#define LIQUID40 "Liquid 40-60%"
#define LIQUID60 "Liquid 60-80%"
#define LIQUID80 "Liquid 80-100%"
/datum/vore_look/proc/compile_message_data(obj/belly/selected)
if(message_option == VPANEL_DESCRIPTION_TAB)
var/list/tab_data = list(
"possible_messages" = list(DEFAULT_MESSAGE, ABSORBED_MESSAGE)
)
if(!selected_message)
selected_message = DEFAULT_MESSAGE
if(selected_message == DEFAULT_MESSAGE)
tab_data["max_length"] = BELLIES_DESC_MAX
tab_data["active_message"] = selected.desc
tab_data["set_action"] = BELLY_DESCRIPTION_MESSAGE
tab_data["tooltip"] = "Displayed to prey upon consumption."
return tab_data
if(selected_message == ABSORBED_MESSAGE)
tab_data["max_length"] = BELLIES_DESC_MAX
tab_data["active_message"] = selected.absorbed_desc
tab_data["set_action"] = BELLY_DESCRIPTION_MESSAGE_ABSROED
tab_data["tooltip"] = "Displayed to prey after absorption."
return tab_data
if(message_option == VPANEL_EXAMINE_TAB)
var/list/tab_data = list(
"possible_messages" = list(WITH_PREY, WITH_ABSORBED_PREY)
)
if(!selected_message)
selected_message = WITH_PREY
if(selected_message == WITH_PREY)
tab_data["max_length"] = BELLIES_EXAMINE_MAX
tab_data["active_message"] = selected.examine_messages
tab_data["set_action"] = EXAMINES
tab_data["tooltip"] = "Displayed to nearby players during examination when the vorgan is full."
return tab_data
if(selected_message == WITH_ABSORBED_PREY)
tab_data["max_length"] = BELLIES_EXAMINE_MAX
tab_data["active_message"] = selected.examine_messages_absorbed
tab_data["set_action"] = EXAMINES_ABSORBED
tab_data["tooltip"] = "Displayed to nearby players during examination when the vorgan contains absorbed prey."
tab_data["button_label"] = "Display Absorbed Examine"
tab_data["button_action"] = "b_display_absorbed_examine"
tab_data["button_data"] = selected.display_absorbed_examine
tab_data["button_tooltip"] = "the absorbed description on examine." // those will automatically be preceeded by Enables / Disables!
return tab_data
if(message_option == VPANEL_TRASH_EATER_TAB)
var/list/tab_data = list(
"possible_messages" = list(TRASH_EAT, TRASH_EXPEL)
)
if(!selected_message)
selected_message = TRASH_EAT
if(selected_message == TRASH_EAT)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.trash_eater_in
tab_data["set_action"] = BELLY_TRASH_EATER_IN
tab_data["tooltip"] = "Displayed to nearby players when you ingest trash items."
return tab_data
if(selected_message == TRASH_EXPEL)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.trash_eater_out
tab_data["set_action"] = BELLY_TRASH_EATER_OUT
tab_data["tooltip"] = "Displayed to nearby players when you expel trash items."
return tab_data
if(message_option == VPANEL_STRUGGLE_TAB)
var/list/tab_data = list(
"subtypes" = list(DEFAULT_MESSAGE, ABSORBED_MESSAGE)
)
if(!message_subtab)
message_subtab = DEFAULT_MESSAGE
if(message_subtab == DEFAULT_MESSAGE)
tab_data["possible_messages"] = list(OUTSIDE_MESSAGE, INSIDE_MESSAGE)
if(!selected_message)
selected_message = OUTSIDE_MESSAGE
if(selected_message == OUTSIDE_MESSAGE)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.struggle_messages_outside
tab_data["set_action"] = STRUGGLE_OUTSIDE
tab_data["tooltip"] = "Displayed to nearby players when your prey resists."
return tab_data
if(selected_message == INSIDE_MESSAGE)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.struggle_messages_inside
tab_data["set_action"] = STRUGGLE_INSIDE
tab_data["tooltip"] = "Displayed to your prey when they resists."
return tab_data
if(message_subtab == ABSORBED_MESSAGE)
tab_data["possible_messages"] = list(OUTSIDE_MESSAGE, INSIDE_MESSAGE)
if(!selected_message)
selected_message = OUTSIDE_MESSAGE
if(selected_message == OUTSIDE_MESSAGE)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.absorbed_struggle_messages_outside
tab_data["set_action"] = ABSORBED_STRUGGLE_OUSIDE
tab_data["tooltip"] = "Displayed to nearby players when your absorb prey resists."
return tab_data
if(selected_message == INSIDE_MESSAGE)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.absorbed_struggle_messages_inside
tab_data["set_action"] = ABSORBED_STRUGGLE_INSIDE
tab_data["tooltip"] = "Displayed to your prey when absorbed prey resists."
return tab_data
if(message_option == VPANEL_ESCAPE_TAB)
var/list/tab_data = list(
"subtypes" = list(ITEM_MESSAGE, ATTEMPT_MESSAGE, FAIL_MESSAGE)
)
if(selected.message_mode || selected.escapechance)
tab_data["subtypes"] += SUCCESS_MESSAGE
if(!message_subtab)
message_subtab = ATTEMPT_MESSAGE
if(message_subtab == ATTEMPT_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_attempt_messages_prey
tab_data["set_action"] = ESCAPE_ATTEMPT_PREY
tab_data["tooltip"] = "Displayed to your prey when they trigger an escape attempt."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_attempt_messages_owner
tab_data["set_action"] = ESCAPE_ATTEMPT_OWNER
tab_data["tooltip"] = "Displayed to you when your prey triggers an escape attempt."
return tab_data
if(message_subtab == SUCCESS_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU, OUTSIDE_MESSAGE)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_messages_prey
tab_data["set_action"] = ESCAPE_PREY
tab_data["tooltip"] = "Displayed to your prey when they succeed an escape attempt."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_messages_owner
tab_data["set_action"] = ESCAPE_OWNER
tab_data["tooltip"] = "Displayed to you when your prey succeeds an escape attempt."
return tab_data
if(selected_message == OUTSIDE_MESSAGE)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_messages_outside
tab_data["set_action"] = ESCAPE_OUTSIDE
tab_data["tooltip"] = "Displayed to nearby players when your prey succeeds an escape attempt."
return tab_data
if(message_subtab == ITEM_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU, OUTSIDE_MESSAGE)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_item_messages_prey
tab_data["set_action"] = ESCAPE_ITEM_PREY
tab_data["tooltip"] = "Displayed to your prey when they manage to push an item out of your belly."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_item_messages_owner
tab_data["set_action"] = ESCAPE_ITEM_OWNER
tab_data["tooltip"] = "Displayed to you when your prey manages to push an item out of your belly."
return tab_data
if(selected_message == OUTSIDE_MESSAGE)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_item_messages_outside
tab_data["set_action"] = ESCAPE_ITEM_OUTSIDE
tab_data["tooltip"] = "Displayed to nearby players when your prey manages to push an item out of your belly."
return tab_data
if(message_subtab == FAIL_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_fail_messages_prey
tab_data["set_action"] = ESCAPE_FAIL_PREY
tab_data["tooltip"] = "Displayed to your prey when they fail an escape attempt."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_fail_messages_owner
tab_data["set_action"] = ESCAPE_FAIL_OWNER
tab_data["tooltip"] = "Displayed to you when your prey fails an escape attempt."
return tab_data
if(message_option == VPANEL_ESCAPE_ABSORBED_TAB)
var/list/tab_data = list(
"subtypes" = list(ATTEMPT_MESSAGE, FAIL_MESSAGE)
)
if(selected.message_mode || selected.escapechance_absorbed)
tab_data["subtypes"] += SUCCESS_MESSAGE
if(!message_subtab)
message_subtab = ATTEMPT_MESSAGE
if(message_subtab == ATTEMPT_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_attempt_absorbed_messages_prey
tab_data["set_action"] = ABSORBED_ESCAPE_ATTEMPT_PREY
tab_data["tooltip"] = "Displayed to your prey when they trigger an escape attempt."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_attempt_absorbed_messages_owner
tab_data["set_action"] = ABSORBED_ESCAPE_ATTEMPT_OWNER
tab_data["tooltip"] = "Displayed to you when your prey triggers an escape attempt."
return tab_data
if(message_subtab == SUCCESS_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU, OUTSIDE_MESSAGE)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_absorbed_messages_prey
tab_data["set_action"] = ABSORBED_ESCAPE_PREY
tab_data["tooltip"] = "Displayed to your absorbed prey when they succeed an escape attempt."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_absorbed_messages_owner
tab_data["set_action"] = ABSORBED_ESCAPE_OWNER
tab_data["tooltip"] = "Displayed to you when your absorbed prey succeeds an escape attempt."
return tab_data
if(selected_message == OUTSIDE_MESSAGE)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_absorbed_messages_outside
tab_data["set_action"] = ABSORBED_ESCAPE_OUTSIDE
tab_data["tooltip"] = "Displayed to nearby players when your absorbed prey succeeds an escape attempt."
return tab_data
if(message_subtab == FAIL_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_fail_absorbed_messages_prey
tab_data["set_action"] = ABSORBED_ESCAPE_FAIL_PREY
tab_data["tooltip"] = "Displayed to your absorbed prey when they fail an escape attempt."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.escape_fail_absorbed_messages_owner
tab_data["set_action"] = ABSORBED_ESCAPE_FAIL_OWNER
tab_data["tooltip"] = "Displayed to you when your absorbed prey fails an escape attempt."
return tab_data
if(message_option == VPANEL_TRANSFER_TAB)
var/list/tab_data = list(
"subtypes" = list()
)
if(selected.message_mode || selected.transferlocation)
tab_data["subtypes"] += PRIMARY_MESSAGE
if(selected.message_mode || selected.transferlocation_secondary)
tab_data["subtypes"] += SECONARY_MESSAGE
if(selected.message_mode || selected.autotransferlocation)
tab_data["subtypes"] += PRIMARY_AUTO_MESSAGE
if(selected.message_mode || selected.autotransferlocation_secondary)
tab_data["subtypes"] += SECONARY_AUTO_MESSAGE
if(!message_subtab)
message_subtab = PRIMARY_MESSAGE
if(message_subtab == PRIMARY_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.primary_transfer_messages_prey
tab_data["set_action"] = PRIMARY_TRANSFER_PREY
tab_data["tooltip"] = "Displayed to your prey when they get transfered to the primary transfer location."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.primary_transfer_messages_owner
tab_data["set_action"] = PRIMARY_TRANSFER_OWNER
tab_data["tooltip"] = "Displayed to you when your prey gets transfered to the primary transfer location."
return tab_data
if(message_subtab == SECONARY_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.secondary_transfer_messages_prey
tab_data["set_action"] = SECONDARY_TRANSFER_PREY
tab_data["tooltip"] = "Displayed to your prey when they get transfered to the secondary transfer location."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.secondary_transfer_messages_owner
tab_data["set_action"] = SECONDARY_TRANSFER_OWNER
tab_data["tooltip"] = "Displayed to you when your prey gets transfered to the secondary transfer location."
return tab_data
if(message_subtab == PRIMARY_AUTO_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.primary_autotransfer_messages_prey
tab_data["set_action"] = PRIMARY_AUTO_TRANSFER_PREY
tab_data["tooltip"] = "Displayed to your prey when they get transfered to the primary auto transfer location."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.primary_autotransfer_messages_owner
tab_data["set_action"] = PRIMARY_AUTO_TRANSFER_OWNER
tab_data["tooltip"] = "Displayed to you when your prey gets transfered to the primary auto transfer location."
return tab_data
if(message_subtab == SECONARY_AUTO_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.secondary_autotransfer_messages_prey
tab_data["set_action"] = SECONDARY_AUTO_TRANSFER_PREY
tab_data["tooltip"] = "Displayed to your prey when they get transfered to the secondary auto transfer location."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.secondary_autotransfer_messages_owner
tab_data["set_action"] = SECONDARY_AUTO_TRANSFER_OWNER
tab_data["tooltip"] = "Displayed to you when your prey gets transfered to the secondary auto transfer location."
return tab_data
if(message_option == VPANEL_INTERACTION_TAB)
var/list/tab_data = list(
"subtypes" = list()
)
if(selected.message_mode || selected.digestchance)
tab_data["subtypes"] += DIGEST_MESSAGE
if(selected.message_mode || selected.absorbchance)
tab_data["subtypes"] += ABSORB_MESSAGE
if(!message_subtab)
message_subtab = DIGEST_MESSAGE
if(message_subtab == DIGEST_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.digest_chance_messages_prey
tab_data["set_action"] = DIGEST_CHANCE_PREY
tab_data["tooltip"] = "Displayed to your prey when their struggles trigger digest mode."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.digest_chance_messages_owner
tab_data["set_action"] = DIGEST_CHANCE_OWNER
tab_data["tooltip"] = "Displayed to you when your prey's struggles trigger digest mode."
return tab_data
if(message_subtab == ABSORB_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.absorb_chance_messages_prey
tab_data["set_action"] = ABSORB_CHANCE_PREY
tab_data["tooltip"] = "Displayed to your prey when their struggles trigger absorb mode."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.absorb_chance_messages_owner
tab_data["set_action"] = ABSORB_CHANCE_OWNER
tab_data["tooltip"] = "Displayed to you when your prey's struggles trigger absorb mode."
return tab_data
if(message_option == VPANEL_BELLYMODE_TAB)
var/list/tab_data = list(
"subtypes" = list()
)
if(selected.message_mode || selected.digest_mode == DM_DIGEST || DM_SELECT)
tab_data["subtypes"] += DIGEST_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_ABSORB || DM_SELECT)
tab_data["subtypes"] += ABSORB_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_UNABSORB)
tab_data["subtypes"] += UNABSORB_MESSAGE
if(!message_subtab)
message_subtab = DIGEST_MESSAGE
if(message_subtab == DIGEST_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.digest_messages_prey
tab_data["set_action"] = DIGEST_PREY
tab_data["tooltip"] = "Displayed to your prey when they get digested."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.digest_messages_owner
tab_data["set_action"] = DIGEST_OWNER
tab_data["tooltip"] = "Displayed to you when your prey gets digested."
return tab_data
if(message_subtab == ABSORBED_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.absorb_messages_prey
tab_data["set_action"] = ABSORB_PREY
tab_data["tooltip"] = "Displayed to your prey when they get absorbed."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.absorb_messages_owner
tab_data["set_action"] = ABSORB_OWNER
tab_data["tooltip"] = "Displayed to you when your prey gets absorbed."
if(message_subtab == UNABSORB_MESSAGE)
tab_data["possible_messages"] = list(TO_PREY, TO_YOU)
if(!selected_message)
selected_message = TO_PREY
if(selected_message == TO_PREY)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.unabsorb_messages_prey
tab_data["set_action"] = UNABSORBS_PREY
tab_data["tooltip"] = "Displayed to your prey when they get unabsorbed."
return tab_data
if(selected_message == TO_YOU)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = selected.unabsorb_messages_owner
tab_data["set_action"] = UNABSORBS_OWNER
tab_data["tooltip"] = "Displayed to you when your prey gets unabsorbed."
return tab_data
if(message_option == VPANEL_IDLE_TAB)
var/list/tab_data = list(
"possible_messages" = list()
)
if(selected.message_mode || selected.digest_mode == DM_DIGEST || selected.digest_mode == DM_SELECT)
tab_data["possible_messages"] += DIGEST_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_HOLD || selected.digest_mode == DM_SELECT)
tab_data["possible_messages"] += HOLD_MESSAGE
tab_data["possible_messages"] += HOLDABSORBED_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_ABSORB || selected.digest_mode == DM_SELECT)
tab_data["possible_messages"] += ABSORB_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_HEAL)
tab_data["possible_messages"] += HEAL_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_DRAIN || selected.digest_mode == DM_SELECT)
tab_data["possible_messages"] += DRAIN_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_SIZE_STEAL)
tab_data["possible_messages"] += STEAL_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_EGG)
tab_data["possible_messages"] += EGG_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_SHRINK)
tab_data["possible_messages"] += SHRINK_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_GROW)
tab_data["possible_messages"] += GROW_MESSAGE
if(selected.message_mode || selected.digest_mode == DM_UNABSORB)
tab_data["possible_messages"] += UNABSORB_MESSAGE
if(!selected_message)
selected_message = DIGEST_MESSAGE
if(selected_message == DIGEST_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_DIGEST])
tab_data["set_action"] = BELLY_MODE_DIGEST
tab_data["tooltip"] = "Cyclic idle messages while your prey is getting digested."
return tab_data
if(selected_message == HOLD_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_HOLD])
tab_data["set_action"] = BELLY_MODE_HOLD
tab_data["tooltip"] = "Cyclic idle messages while your prey is being held."
return tab_data
if(selected_message == HOLDABSORBED_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_HOLD_ABSORBED])
tab_data["set_action"] = BELLY_MODE_HOLD_ABSORB
tab_data["tooltip"] = "Cyclic idle messages while your absorbed prey is being held."
return tab_data
if(selected_message == ABSORB_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_ABSORB])
tab_data["set_action"] = BELLY_MODE_ABSORB
tab_data["tooltip"] = "Cyclic idle messages while your prey is getting absorbed."
return tab_data
if(selected_message == HEAL_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_HEAL])
tab_data["set_action"] = BELLY_MODE_HEAL
tab_data["tooltip"] = "Cyclic idle messages while your prey is getting healed."
return tab_data
if(selected_message == DRAIN_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_DRAIN])
tab_data["set_action"] = BELLY_MODE_DRAIN
tab_data["tooltip"] = "Cyclic idle messages while your prey is getting drained."
return tab_data
if(selected_message == STEAL_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_SIZE_STEAL])
tab_data["set_action"] = BELLY_MODE_STEAL
tab_data["tooltip"] = "Cyclic idle messages while your prey's size is stolen."
return tab_data
if(selected_message == EGG_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_EGG])
tab_data["set_action"] = BELLY_MODE_EGG
tab_data["tooltip"] = "Cyclic idle messages while your prey is getting getting encased in an egg."
return tab_data
if(selected_message == SHRINK_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_SHRINK])
tab_data["set_action"] = BELLY_MODE_SHRINK
tab_data["tooltip"] = "Cyclic idle messages while your prey is getting shrunk."
return tab_data
if(selected_message == GROW_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_GROW])
tab_data["set_action"] = BELLY_MODE_GROW
tab_data["tooltip"] = "Cyclic idle messages while your prey is getting grown."
return tab_data
if(selected_message == UNABSORB_MESSAGE)
tab_data["max_length"] = BELLIES_IDLE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.emote_lists[DM_UNABSORB])
tab_data["set_action"] = BELLY_MODE_UNABSORB
tab_data["tooltip"] = "Cyclic idle messages while your prey is getting unabsorbed."
return tab_data
if(message_option == VPANEL_LIQUIDS_TAB)
var/list/tab_data = list(
"possible_messages" = list(LIQUID0, LIQUID20, LIQUID40, LIQUID60, LIQUID80)
)
if(!selected_message)
selected_message = LIQUID0
if(selected_message == LIQUID0)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.fullness1_messages)
tab_data["set_action"] = BELLY_LIQUID_MESSAGE1
tab_data["tooltip"] = "Displayed on examine when the belly contains 0 to 20% of liquids."
tab_data["button_label"] = "Display Fullness 0-20%"
tab_data["button_action"] = "b_liq_msg_toggle1"
tab_data["button_data"] = selected.liquid_fullness1_messages
tab_data["button_tooltip"] = "the 0-20% examine description." // those will automatically be preceeded by Enables / Disables!
return tab_data
if(selected_message == LIQUID20)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.fullness2_messages)
tab_data["set_action"] = BELLY_LIQUID_MESSAGE2
tab_data["tooltip"] = "Displayed on examine when the belly contains 20 to 40% of liquids."
tab_data["button_label"] = "Display Fullness 20-40%"
tab_data["button_action"] = "b_liq_msg_toggle2"
tab_data["button_data"] = selected.liquid_fullness2_messages
tab_data["button_tooltip"] = "the 20-40% examine description." // those will automatically be preceeded by Enables / Disables!
return tab_data
if(selected_message == LIQUID40)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.fullness3_messages)
tab_data["set_action"] = BELLY_LIQUID_MESSAGE3
tab_data["tooltip"] = "Displayed on examine when the belly contains 40 to 60% of liquids."
tab_data["button_label"] = "Display Fullness 40-60%"
tab_data["button_action"] = "b_liq_msg_toggle3"
tab_data["button_data"] = selected.liquid_fullness3_messages
tab_data["button_tooltip"] = "the 40-60% examine description." // those will automatically be preceeded by Enables / Disables!
return tab_data
if(selected_message == LIQUID60)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.fullness4_messages)
tab_data["set_action"] = BELLY_LIQUID_MESSAGE4
tab_data["tooltip"] = "Displayed on examine when the belly contains 60 to 80% of liquids."
tab_data["button_label"] = "Display Fullness 60-80%"
tab_data["button_action"] = "b_liq_msg_toggle4"
tab_data["button_data"] = selected.liquid_fullness4_messages
tab_data["button_tooltip"] = "the 60-80% examine description." // those will automatically be preceeded by Enables / Disables!
return tab_data
if(selected_message == LIQUID80)
tab_data["max_length"] = BELLIES_MESSAGE_MAX
tab_data["active_message"] = SANITIZE_LIST(selected.fullness5_messages)
tab_data["set_action"] = BELLY_LIQUID_MESSAGE5
tab_data["tooltip"] = "Displayed on examine when the belly contains 80 to 100% of liquids."
tab_data["button_label"] = "Display Fullness 80-100%"
tab_data["button_action"] = "b_liq_msg_toggle5"
tab_data["button_data"] = selected.liquid_fullness5_messages
tab_data["button_tooltip"] = "the 80-100% examine description." // those will automatically be preceeded by Enables / Disables!
return tab_data
/datum/vore_look/proc/compile_interact_data(obj/belly/selected)
var/list/interact_data = list()
if(selected.escapable)
interact_data += list(
"escapechance" = selected.escapechance,
"escapechance_absorbed" = selected.escapechance_absorbed,
"escapetime" = selected.escapetime,
"transferchance" = selected.transferchance,
"transferlocation" = selected.transferlocation,
"transferchance_secondary" = selected.transferchance_secondary,
"transferlocation_secondary" = selected.transferlocation_secondary,
"absorbchance" = selected.absorbchance,
"digestchance" = selected.digestchance,
"belchchance" = selected.belchchance
)
return interact_data
/datum/vore_look/proc/compile_autotransfer_data(obj/belly/selected)
var/list/autotransfer_data = list()
if(selected.autotransfer_enabled)
//auto-transfer flags
var/list/at_whitelist = list()
var/list/at_secondary_whitelist = list()
var/list/at_blacklist = list()
var/list/at_secondary_blacklist = list()
for(var/flag_name in selected.autotransfer_flags_list)
UNTYPED_LIST_ADD(at_whitelist, list("label" = flag_name, "selection" = selected.autotransfer_whitelist & selected.autotransfer_flags_list[flag_name]))
UNTYPED_LIST_ADD(at_blacklist, list("label" = flag_name, "selection" = selected.autotransfer_blacklist & selected.autotransfer_flags_list[flag_name]))
UNTYPED_LIST_ADD(at_secondary_whitelist, list("label" = flag_name, "selection" = selected.autotransfer_secondary_whitelist & selected.autotransfer_flags_list[flag_name]))
UNTYPED_LIST_ADD(at_secondary_blacklist, list("label" = flag_name, "selection" = selected.autotransfer_secondary_blacklist & selected.autotransfer_flags_list[flag_name]))
var/list/at_whitelist_items = list()
var/list/at_blacklist_items = list()
var/list/at_secondary_whitelist_items = list()
var/list/at_secondary_blacklist_items = list()
for(var/flag_name in selected.autotransfer_flags_list_items)
UNTYPED_LIST_ADD(at_whitelist_items, list("label" = flag_name, "selection" = selected.autotransfer_whitelist_items & selected.autotransfer_flags_list_items[flag_name]))
UNTYPED_LIST_ADD(at_blacklist_items, list("label" = flag_name, "selection" = selected.autotransfer_blacklist_items & selected.autotransfer_flags_list_items[flag_name]))
UNTYPED_LIST_ADD(at_secondary_whitelist_items, list("label" = flag_name, "selection" = selected.autotransfer_secondary_whitelist_items & selected.autotransfer_flags_list_items[flag_name]))
UNTYPED_LIST_ADD(at_secondary_blacklist_items, list("label" = flag_name, "selection" = selected.autotransfer_secondary_blacklist_items & selected.autotransfer_flags_list_items[flag_name]))
var/list/primary_transfer = list(
"autotransferchance" = selected.autotransferchance,
"autotransferlocation" = selected.autotransferlocation,
"autotransferextralocation" = selected.autotransferextralocation,
"autotransfer_whitelist" = at_whitelist,
"autotransfer_blacklist" = at_blacklist,
"autotransfer_whitelist_items" = at_whitelist_items,
"autotransfer_blacklist_items" = at_blacklist_items
)
var/list/secondary_transfer = list(
"autotransferchance" = selected.autotransferchance_secondary,
"autotransferlocation" = selected.autotransferlocation_secondary,
"autotransferextralocation" = selected.autotransferextralocation_secondary,
"autotransfer_whitelist" = at_secondary_whitelist,
"autotransfer_blacklist" = at_secondary_blacklist,
"autotransfer_whitelist_items" = at_secondary_whitelist_items,
"autotransfer_blacklist_items" = at_secondary_blacklist_items
)
autotransfer_data += list(
"autotransferwait" = selected.autotransferwait,
"autotransfer_min_amount" = selected.autotransfer_min_amount,
"autotransfer_max_amount" = selected.autotransfer_max_amount,
"primary_transfer" = primary_transfer,
"secondary_transfer" = secondary_transfer
)
return autotransfer_data
/datum/vore_look/proc/compile_liquid_interact_data(obj/belly/selected)
var/list/liq_interacts = list()
if(selected.show_liquids)
var/list/liquid_addon_list = list()
for(var/flag_name in selected.reagent_mode_flag_list)
UNTYPED_LIST_ADD(liquid_addon_list, list("label" = flag_name, "selection" = selected.reagent_mode_flags & selected.reagent_mode_flag_list[flag_name]))
liq_interacts += list(
"liq_reagent_gen" = selected.reagentbellymode,
"liq_reagent_type" = selected.reagent_chosen,
"liq_reagent_types" = selected.reagent_choices,
"liq_reagent_name" = selected.reagent_name,
"liq_custom_name_max" = BELLIES_NAME_MAX,
"liq_custom_name_min" = BELLIES_NAME_MIN,
"liq_reagent_transfer_verb" = selected.reagent_transfer_verb,
"liq_reagent_nutri_rate" = selected.gen_time,
"liq_reagent_capacity" = selected.custom_max_volume,
"liq_sloshing" = selected.vorefootsteps_sounds,
"liq_reagent_addons" = liquid_addon_list,
"custom_reagentcolor" = (selected.custom_reagentcolor ? selected.custom_reagentcolor : selected.reagentcolor),
"custom_reagentalpha" = selected.custom_reagentalpha,
"liquid_overlay" = selected.liquid_overlay,
"max_liquid_level" = selected.max_liquid_level,
"reagent_touches" = selected.reagent_touches,
"mush_overlay" = selected.mush_overlay,
"mush_color" = selected.mush_color,
"mush_alpha" = selected.mush_alpha,
"max_mush" = selected.max_mush,
"min_mush" = selected.min_mush,
"item_mush_val" = selected.item_mush_val,
"metabolism_overlay" = selected.metabolism_overlay,
"metabolism_mush_ratio" = selected.metabolism_mush_ratio,
"max_ingested" = selected.max_ingested,
"custom_ingested_color" = (selected.custom_ingested_color ? selected.custom_ingested_color : "#3f6088"),
"custom_ingested_alpha" = selected.custom_ingested_alpha
)
return liq_interacts
#undef DEFAULT_MESSAGE
#undef ABSORBED_MESSAGE
#undef WITH_PREY
#undef WITH_ABSORBED_PREY
#undef TRASH_EAT
#undef TRASH_EXPEL
#undef OUTSIDE_MESSAGE
#undef INSIDE_MESSAGE
#undef TO_YOU
#undef TO_PREY
#undef ATTEMPT_MESSAGE
#undef SUCCESS_MESSAGE
#undef ITEM_MESSAGE
#undef FAIL_MESSAGE
#undef PRIMARY_MESSAGE
#undef SECONARY_MESSAGE
#undef PRIMARY_AUTO_MESSAGE
#undef SECONARY_AUTO_MESSAGE
#undef DIGEST_MESSAGE
#undef HOLD_MESSAGE
#undef HOLDABSORBED_MESSAGE
#undef ABSORB_MESSAGE
#undef HEAL_MESSAGE
#undef DRAIN_MESSAGE
#undef STEAL_MESSAGE
#undef EGG_MESSAGE
#undef SHRINK_MESSAGE
#undef GROW_MESSAGE
#undef UNABSORB_MESSAGE
#undef LIQUID0
#undef LIQUID20
#undef LIQUID40
#undef LIQUID60
#undef LIQUID80
+10 -9
View File
@@ -198,7 +198,7 @@
// Allows to adjust the interior of the soulcatcher
/obj/soulgem/proc/adjust_interior(var/new_flavor)
new_flavor = sanitize(new_flavor, MAX_MESSAGE_LEN * 2)
new_flavor = sanitize(new_flavor, VORE_SC_DESC_MAX, FALSE, TRUE, FALSE)
inside_flavor = new_flavor
notify_holder("Updating environment...")
for(var/mob/living/carbon/brain/caught_soul/vore/CS as anything in brainmobs)
@@ -225,26 +225,27 @@
// Sets the custom messages depending on the input
/obj/soulgem/proc/set_custom_message(var/message, var/target)
message = sanitize(message, MAX_MESSAGE_LEN / 4)
message = sanitize(message, VORE_SC_MAX, FALSE, TRUE, FALSE)
switch(target)
if("capture")
if(SC_CAPTURE_MEESAGE)
capture_message = message
if("transit")
if(SC_TRANSIT_MESSAGE)
transit_message = message
if("release")
if(SC_RELEASE_MESSAGE)
release_message = message
if("transfer")
if(SC_TRANSFERE_MESSAGE)
transfer_message = message
if("delete")
if(SC_DELETE_MESSAGE)
delete_message = message
// Allows to rename the soulgem
/obj/soulgem/proc/rename(var/new_name)
if(length(new_name) < 3 || length(new_name) > 60)
to_chat(owner, span_warning("Your soulcatcher's name needs to be between 3 and 60 characters long!"))
return
new_name = sanitize(new_name, 60)
return FALSE
new_name = sanitize(new_name, 60, FALSE, TRUE, FALSE)
name = new_name
return TRUE
// Toggles the given flag
/obj/soulgem/proc/toggle_setting(var/flag)
File diff suppressed because it is too large Load Diff
-1
View File
@@ -154,7 +154,6 @@
new_mob.ooc_notes_dislikes = ooc_notes_dislikes
new_mob.appendage_color = appendage_color
new_mob.appendage_alt_setting = appendage_alt_setting
new_mob.text_warnings = text_warnings
VORE_PREF_TRANSFER(new_mob, src)
+1 -1
View File
@@ -11,7 +11,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
"tgui-core": "^3.2.0"
"tgui-core": "^4.0.1"
},
"devDependencies": {
"@types/react": "^19.1.0",
+1 -1
View File
@@ -8,7 +8,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
"tgui-core": "^3.2.0",
"tgui-core": "^4.0.1",
"tgui-dev-server": "workspace:*"
},
"devDependencies": {
+1 -1
View File
@@ -7,7 +7,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
"tgui-core": "^3.2.0"
"tgui-core": "^4.0.1"
},
"devDependencies": {
"@types/react": "^19.1.0",
+1 -1
View File
@@ -102,7 +102,7 @@ export function AlertModal(props) {
<Window.Content onKeyDown={keyDownHandler}>
<Section fill>
<Stack fill vertical>
<Stack.Item m={1}>
<Stack.Item m={1} grow>
<Box color="label" overflow="hidden">
{message}
</Box>
+1 -1
View File
@@ -52,7 +52,7 @@ export const AlgaeFarm = (props) => {
<Stack fill vertical>
{errorText && (
<Stack.Item>
<NoticeBox warning>
<NoticeBox>
<Box inline verticalAlign="middle">
{errorText}
</Box>
@@ -50,7 +50,7 @@ export const BotanyEditor = (props) => {
Eject Loaded Disk
</Button>
</Box>
)) || <NoticeBox warning>No disk loaded.</NoticeBox>}
)) || <NoticeBox>No disk loaded.</NoticeBox>}
</Section>
<Section title="Loaded Material">
{(loaded && (
@@ -65,7 +65,7 @@ export const BotanyEditor = (props) => {
Eject Target
</Button>
</Box>
)) || <NoticeBox warning>No target seed packet loaded.</NoticeBox>}
)) || <NoticeBox>No target seed packet loaded.</NoticeBox>}
</Section>
</Window.Content>
</Window>
@@ -77,24 +77,16 @@ export const BotanyIsolator = (props) => {
Clear Genetic Buffer
</Button>
</Box>
)) || (
<NoticeBox mt={1} warning>
No disk inserted.
</NoticeBox>
)}
)) || <NoticeBox mt={1}>No disk inserted.</NoticeBox>}
</Box>
)) || (
<Box>
<NoticeBox warning>No Data Buffered.</NoticeBox>
<NoticeBox>No Data Buffered.</NoticeBox>
{(disk && (
<Button icon="eject" onClick={() => act('eject_disk')}>
Eject Loaded Disk
</Button>
)) || (
<NoticeBox mt={1} warning>
No disk inserted.
</NoticeBox>
)}
)) || <NoticeBox mt={1}>No disk inserted.</NoticeBox>}
</Box>
)}
</Section>
@@ -113,7 +105,7 @@ export const BotanyIsolator = (props) => {
Eject Packet
</Button>
</Box>
)) || <NoticeBox warning>No packet loaded.</NoticeBox>}
)) || <NoticeBox>No packet loaded.</NoticeBox>}
</Section>
</Window.Content>
</Window>
@@ -125,7 +125,7 @@ const Evacuation = (props: { evac: Evac }) => {
return null;
case Evac.CrewTransfer:
return (
<NoticeBox warning>
<NoticeBox>
The vessel is currently undergoing crew transfer procedures.
</NoticeBox>
);
@@ -17,7 +17,7 @@ export const ModifyRobotNoModule = (props: { target: Target }) => {
return (
<>
<NoticeBox warning>
<NoticeBox>
Target has no active module. Limited options available.
</NoticeBox>
<Divider />
@@ -4,7 +4,7 @@ export const NoSpriteWarning = (props: { name: string }) => {
const { name } = props;
return (
<NoticeBox warning>
<NoticeBox>
Warning, {name} has not yet chosen a sprite. Functionality might be
limited.
</NoticeBox>
@@ -127,7 +127,7 @@ export const PathogenicIsolator = (props) => {
<ComplexModal maxHeight="100%" maxWidth="95%" />
<Window.Content scrollable>
{(isolating && (
<NoticeBox warning>The Isolator is currently isolating...</NoticeBox>
<NoticeBox>The Isolator is currently isolating...</NoticeBox>
)) ||
''}
<Tabs>
@@ -46,7 +46,7 @@ export function WikiDonationBanner(props: {
if (progress < 0.66) {
return (
<NoticeBox warning>
<NoticeBox>
<WikiDonationContent
donated={donated}
goal={goal}
@@ -167,7 +167,7 @@ export const PublicLibraryWiki = (props) => {
<Stack vertical fill>
{!!errorText && (
<Stack.Item>
<NoticeBox warning>
<NoticeBox>
<Box textAlign="center">{errorText}</Box>
</NoticeBox>
</Stack.Item>
@@ -62,7 +62,7 @@ export const TelecommsLogBrowser = (props) => {
</NoticeBox>
)) ||
(temp && temp.color !== 'bad' && (
<NoticeBox warning>
<NoticeBox>
<Box inline verticalAlign="middle">
{temp.text}
</Box>
@@ -50,7 +50,7 @@ export const TelecommsMachineBrowser = (props) => {
</NoticeBox>
)) ||
(temp && temp.color !== 'bad' && (
<NoticeBox warning>
<NoticeBox>
<Box inline verticalAlign="middle">
{temp.text}
</Box>
@@ -1,40 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Box, Button, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
export const FeatureColorInput = (props: {
action_name: string;
value_of: BooleanLike | string;
back_color: string;
name_of: string;
}) => {
const { act } = useBackend();
const { action_name, value_of, back_color, name_of } = props;
return (
<>
<Stack.Item shrink>
<Box
backgroundColor={
back_color.startsWith('#') ? back_color : `#${back_color}`
}
style={{
border: '2px solid white',
}}
width="20px"
height="20px"
/>
</Stack.Item>
<Stack.Item grow>
<Button
fluid
icon="eye-dropper"
onClick={() => {
act('set_attribute', { attribute: action_name, val: value_of });
}}
>
Change {name_of}
</Button>
</Stack.Item>
</>
);
};
@@ -1,37 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Box, Button, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
export const LiquidColorInput = (props: {
action_name: string;
value_of: BooleanLike | string;
back_color: string;
name_of: string;
}) => {
const { act } = useBackend();
const { action_name, value_of, back_color, name_of } = props;
return (
<Button
onClick={() => {
act('liq_set_attribute', { liq_attribute: action_name, val: value_of });
}}
>
<Stack align="center" fill>
<Stack.Item>
<Box
style={{
background: back_color.startsWith('#')
? back_color
: `#${back_color}`,
border: '2px solid white',
boxSizing: 'content-box',
height: '11px',
width: '11px',
}}
/>
</Stack.Item>
<Stack.Item>Change {name_of}</Stack.Item>
</Stack>
</Button>
);
};
@@ -1,57 +0,0 @@
import { useBackend } from 'tgui/backend';
import { LabeledList, Section, Slider, Stack } from 'tgui-core/components';
import { toFixed } from 'tgui-core/math';
import type { abilities } from './types';
export const VoreAbilities = (props: { abilities: abilities }) => {
const { act } = useBackend();
const { abilities } = props;
const { nutrition, current_size, minimum_size, maximum_size, resize_cost } =
abilities;
function is_enabled(nutri: number, cost: number): boolean {
return nutri >= cost;
}
return (
<Section title="Abilities" buttons={'Nutrition: ' + toFixed(nutrition, 1)}>
<LabeledList>
<LabeledList.Item label="Resize">
<Stack align="baseline">
<Stack.Item>
<Slider
disabled={!is_enabled(nutrition, resize_cost)}
width="250px"
ranges={
is_enabled(nutrition, resize_cost)
? {
bad: [1, 25],
average: [25, 50],
green: [50, 150],
yellow: [150, 200],
red: [200, 600],
}
: { black: [0, 600] }
}
format={(value: number) => toFixed(value, 2) + '%'}
value={current_size * 100}
minValue={minimum_size * 100}
maxValue={maximum_size * 100}
onChange={(e, value: number) =>
act('adjust_own_size', {
new_mob_size: value / 100,
})
}
/>
</Stack.Item>
<Stack.Item color="label">&nbsp;&nbsp;Cost:&nbsp;</Stack.Item>
<Stack.Item>{resize_cost}</Stack.Item>
</Stack>
</LabeledList.Item>
</LabeledList>
</Section>
);
};
@@ -1,101 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Button, Image, LabeledList, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { stats } from './constants';
import type { contentData } from './types';
export const VoreContentsPanel = (props: {
contents: contentData[];
belly?: string;
outside?: BooleanLike;
show_pictures: BooleanLike;
icon_overflow: BooleanLike;
}) => {
const { act } = useBackend();
const {
contents,
belly,
outside = false,
show_pictures,
icon_overflow,
} = props;
return (
<>
{outside ? (
<Button
textAlign="center"
fluid
mb={1}
onClick={() => act('pick_from_outside', { pickall: true })}
>
All
</Button>
) : (
''
)}
{(show_pictures && !icon_overflow && (
<Stack wrap="wrap" justify="center" align="center">
{contents.map((thing) => (
<Stack.Item key={thing.name} basis="32%">
<Button
width="64px"
color={thing.absorbed ? 'purple' : stats[thing.stat]}
style={{
verticalAlign: 'middle',
marginRight: '5px',
borderRadius: '20px',
}}
onClick={() =>
act(
thing.outside ? 'pick_from_outside' : 'pick_from_inside',
{
pick: thing.ref,
belly: belly,
},
)
}
>
<Image
src={'data:image/jpeg;base64, ' + thing.icon}
width="64px"
height="64px"
style={{
marginLeft: '-5px',
}}
/>
</Button>
{thing.name}
</Stack.Item>
))}
</Stack>
)) || (
<LabeledList>
{contents.map((thing, i) => (
<LabeledList.Item key={i} label={thing.name}>
<Button
fluid
mt={-1}
mb={-1}
color={thing.absorbed ? 'purple' : stats[thing.stat]}
onClick={() =>
act(
thing.outside ? 'pick_from_outside' : 'pick_from_inside',
{
pick: thing.ref,
belly: belly,
},
)
}
>
Interact
</Button>
</LabeledList.Item>
))}
</LabeledList>
)}
</>
);
};
@@ -0,0 +1,49 @@
import { Box, Button } from 'tgui-core/components';
export const VorePanelColorBox = (props: {
back_color: string;
pixelSize?: number;
alpha?: number;
}) => {
const { back_color, pixelSize = 20, alpha = 255 } = props;
const parentSize = pixelSize + 'px';
const childSize = pixelSize - 4 + 'px';
return (
<Box
style={{
border: '2px solid white',
}}
width={parentSize}
height={parentSize}
>
<Box
backgroundColor={
back_color.startsWith('#') ? back_color : `#${back_color}`
}
style={{
opacity: alpha / 255,
}}
width={childSize}
height={childSize}
/>
</Box>
);
};
export const VorePanelEditToggle = (props: {
editMode: boolean;
toggleEditMode: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const { editMode, toggleEditMode } = props;
return (
<Button
icon="pencil"
color={editMode ? 'green' : undefined}
tooltip={(editMode ? 'Dis' : 'En') + 'able edit mode'}
onClick={() => toggleEditMode(!editMode)}
/>
);
};
@@ -0,0 +1,86 @@
import type { ComponentProps } from 'react';
import { useBackend } from 'tgui/backend';
import { Box, Button, Floating, Stack, Tooltip } from 'tgui-core/components';
import type { checkBoxEntry } from '../types';
export const VorePanelEditCheckboxes = (props: {
/** Switch between Element editing and display */
editMode: boolean;
/** Our option entry checboxes with labels and actiondata */
options: checkBoxEntry[];
/** Our backend action on text area blur */
action: string;
/** Our secondary backend action on text area blur */
subAction?: string;
/** Our tooltips associated to the checkbox actions as Record mapping our options to a tooltip */
tooltipList?: Record<string, string>;
/** Our displayed tooltip behind the input element */
tooltip?: string;
/** The position of the tooltip if static */
tooltipPosition?: ComponentProps<typeof Floating>['placement'];
}) => {
const { act } = useBackend();
const {
editMode,
options,
action,
subAction = '',
tooltipList,
tooltip,
tooltipPosition,
} = props;
return (
<Stack align="center">
{editMode && (
<>
<Stack.Item>
<Floating
placement="bottom-end"
contentClasses="VorePanel__fLoating"
content={
<Stack vertical fill>
{options.map((value) => (
<Stack.Item key={value.label}>
<Button.Checkbox
tooltip={tooltipList && tooltipList[value.label]}
checked={value.selection}
onClick={() =>
act(action, {
attribute: subAction,
val: value.ref ? value.ref : value.label,
})
}
>
{value.label}
</Button.Checkbox>
</Stack.Item>
))}
</Stack>
}
>
<Box className="VorePanel__floatingButton">+/-</Box>
</Floating>
</Stack.Item>
<Stack.Item>
<Tooltip content={tooltip} position={tooltipPosition}>
<Box className="VorePanel__floatingButton">?</Box>
</Tooltip>
</Stack.Item>
</>
)}
<Stack.Item grow>
<Box>
{(options.length &&
options
.filter((option) => option.selection)
.map((value) => value.label)
.join(', ')) ||
'None'}
</Box>
</Stack.Item>
</Stack>
);
};
@@ -0,0 +1,83 @@
import type { ComponentProps } from 'react';
import { useBackend } from 'tgui/backend';
import { Box, Button, type Floating, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { VorePanelColorBox } from './VorePanelCommonElements';
import { VorePanelEditNumber } from './VorePanelEditNumber';
export const VorePanelEditColor = (props: {
/** Switch between Element editing and display */
editMode: boolean;
/** Our backend action on text area blur */
action: string;
/** Our secondary backend action on text area blur */
subAction?: string;
/** Our color value sent to byond */
value_of: BooleanLike | string;
/** The displayed color of the color box */
back_color: string;
/** A number representing the alpha value for alpha inouts */
alpha?: number;
/** Optional label to show before the color box */
name_of?: string;
/** Our displayed tooltip behind the input element */
tooltip?: string;
/** The position of the tooltip if static */
tooltipPosition?: ComponentProps<typeof Floating>['placement'];
/** Removes the spacing behind the color box */
removePlaceholder?: boolean;
}) => {
const { act } = useBackend();
const {
editMode,
action,
subAction = '',
value_of,
back_color,
alpha,
name_of,
tooltip,
tooltipPosition,
removePlaceholder,
} = props;
return (
<>
{!!name_of && (
<Stack.Item>
<Box color="label">{name_of}</Box>
</Stack.Item>
)}
<Stack.Item shrink>
<VorePanelColorBox back_color={back_color} alpha={alpha} />
</Stack.Item>
{editMode && (
<Stack.Item basis={alpha !== undefined ? '65px' : undefined}>
{alpha !== undefined ? (
<VorePanelEditNumber
action={action}
subAction={subAction}
editMode={editMode}
value={alpha}
minValue={0}
maxValue={255}
tooltip={tooltip}
/>
) : (
<Button
fluid
icon="eye-dropper"
onClick={() => {
act(action, { attribute: subAction, val: value_of });
}}
tooltip={tooltip}
tooltipPosition={tooltipPosition}
/>
)}
</Stack.Item>
)}
{!removePlaceholder && <Stack.Item grow />}
</>
);
};
@@ -0,0 +1,72 @@
import type { ComponentProps } from 'react';
import { useBackend } from 'tgui/backend';
import {
Box,
Dropdown,
type Floating,
Stack,
Tooltip,
} from 'tgui-core/components';
import { capitalize } from 'tgui-core/string';
import type { DropdownEntry } from '../types';
export const VorePanelEditDropdown = (props: {
/** Switch between Element editing and display */
editMode: boolean;
/** Our backend action on text area blur */
action: string;
/** Our secondary backend action on text area blur */
subAction?: string;
/** Our dropdown inouts and actions */
options: (string | DropdownEntry)[];
/** The currently shown selection */
entry: string;
/** Color of the dropdown and text */
color?: string;
/** Icon of the dropdown */
icon?: string;
/** Our displayed tooltip behind the input element */
tooltip?: string;
/** The position of the tooltip if static */
tooltipPosition?: ComponentProps<typeof Floating>['placement'];
}) => {
const { act } = useBackend();
const {
entry,
editMode,
options,
action,
subAction = '',
color,
icon,
tooltip,
tooltipPosition,
} = props;
return editMode ? (
<Stack>
<Stack.Item>
<Dropdown
color={color}
onSelected={(value) =>
act(action, { attribute: subAction, val: value })
}
options={options}
selected={entry}
icon={icon}
/>
</Stack.Item>
{tooltip && (
<Stack.Item>
<Tooltip content={tooltip} position={tooltipPosition}>
<Box className="VorePanel__floatingButton">?</Box>
</Tooltip>
</Stack.Item>
)}
</Stack>
) : (
<Box textColor={color}>{capitalize(entry)}</Box>
);
};
@@ -0,0 +1,91 @@
import type { ComponentProps } from 'react';
import { useBackend } from 'tgui/backend';
import {
Box,
type Floating,
NumberInput,
Stack,
Tooltip,
} from 'tgui-core/components';
import { round, toFixed } from 'tgui-core/math';
export const VorePanelEditNumber = (props: {
/** Switch between Element editing and display */
editMode: boolean;
/** Our backend action on text area blur */
action: string;
/** Our secondary backend action on text area blur */
subAction?: string;
/** The current displayed number */
value: number;
/** The minimum number allowed */
minValue: number;
/** The maximum number allowed */
maxValue: number;
/** The steps of the input */
step?: number;
/** The pixels required for each step */
stepPixel?: number;
/** The unit shown behind the number */
unit?: string;
/** The color of the displayed text */
color?: string;
/** Our displayed tooltip behind the input element */
tooltip?: string;
/** The position of the tooltip if static */
tooltipPosition?: ComponentProps<typeof Floating>['placement'];
/** The amount of fractional digits shown */
digits?: number;
}) => {
const { act } = useBackend();
const {
action,
subAction = '',
value,
maxValue,
minValue,
step = 1,
stepPixel = 1,
editMode,
unit,
color,
tooltip,
tooltipPosition,
digits = 0,
} = props;
return editMode ? (
<Stack>
<Stack.Item>
<NumberInput
onChange={(value) =>
act(action, {
attribute: subAction,
val: round(value, digits),
})
}
stepPixelSize={stepPixel}
value={value}
maxValue={maxValue}
minValue={minValue}
step={step}
unit={unit}
format={(val) => toFixed(val, digits)}
/>
</Stack.Item>
{tooltip && (
<Stack.Item>
<Tooltip content={tooltip} position={tooltipPosition}>
<Box className="VorePanel__floatingButton">?</Box>
</Tooltip>
</Stack.Item>
)}
</Stack>
) : (
<Box textColor={color}>
{value}
{!!unit && ' ' + unit}
</Box>
);
};
@@ -0,0 +1,68 @@
import type { ComponentProps } from 'react';
import { useBackend } from 'tgui/backend';
import { Box, Button, type Floating } from 'tgui-core/components';
export const VorePanelEditSwitch = (props: {
/** Switch between Element editing and display */
editMode: boolean;
/** Our backend action on text area blur */
action: string;
/** Our secondary backend action on text area blur */
subAction?: string;
/** Is the button currently active / selected */
active?: boolean;
/** Displayed text content */
content?: string;
/** Our displayed tooltip on button hover */
tooltip?: string;
/** The position of the tooltip if static */
tooltipPosition?: ComponentProps<typeof Floating>['placement'];
/** Color of the button and displayed text */
color?: string;
/** Hides the button icon */
hideIcon?: boolean;
/** Allows to pass custom icon options */
customIcon?: string;
}) => {
const { act } = useBackend();
const {
action,
subAction = '',
active,
editMode,
content,
tooltip,
tooltipPosition,
color,
hideIcon,
customIcon,
} = props;
const currentIcon = customIcon
? customIcon
: active
? 'toggle-on'
: 'toggle-off';
return editMode ? (
<Button
tooltip={tooltip}
tooltipPosition={tooltipPosition}
onClick={() =>
act(action, {
attribute: subAction || '',
})
}
icon={!hideIcon && currentIcon}
selected={active}
color={color}
>
{content ? content : active ? 'Enabled' : 'Disabled'}
</Button>
) : (
<Box textColor={color ? color : active ? 'green' : 'red'}>
{content ? content : active ? 'Enabled' : 'Disabled'}
</Box>
);
};
@@ -0,0 +1,72 @@
import type { ComponentProps } from 'react';
import { useBackend } from 'tgui/backend';
import {
Box,
type Floating,
Input,
Stack,
Tooltip,
} from 'tgui-core/components';
export const VorePanelEditText = (props: {
/** Switch between Element editing and display */
editMode: boolean;
/** Our backend action on text area blur */
action: string;
/** Our secondary backend action on text area blur */
subAction?: string;
/** The maximum length of each message */
limit: number;
/** Minimum required text to trigger an change action to byond */
min?: number;
/** The current displayed message */
entry: string;
/** The color of the displayed text */
color?: string;
/** Our displayed tooltip displayed the text */
tooltip?: string;
/** The position of the tooltip if static */
tooltipPosition?: ComponentProps<typeof Floating>['placement'];
}) => {
const { act } = useBackend();
const {
entry,
min,
editMode,
limit,
action,
subAction = '',
color,
tooltip,
tooltipPosition,
} = props;
function doAct(value: string) {
if (entry === value) return;
if (min && value.length < min) return;
act(action, { attribute: subAction, val: value });
}
return editMode ? (
<Stack>
<Stack.Item>
<Input
fluid
maxLength={limit}
value={entry}
onBlur={(value) => doAct(value)}
/>
</Stack.Item>
{tooltip && (
<Stack.Item>
<Tooltip content={tooltip} position={tooltipPosition}>
<Box className="VorePanel__floatingButton">?</Box>
</Tooltip>
</Stack.Item>
)}
</Stack>
) : (
<Box textColor={color}>{entry}</Box>
);
};
@@ -0,0 +1,247 @@
import { type ReactNode, useEffect, useRef, useState } from 'react';
import { useBackend } from 'tgui/backend';
import {
Box,
Divider,
Floating,
Icon,
Stack,
TextArea,
} from 'tgui-core/components';
import { SYNTAX_COLOR, SYNTAX_REGEX } from '../constants';
import { calcLineHeight } from '../functions';
const DescriptionSyntaxHighlighting = (props: { desc: string }) => {
const { desc } = props;
const [htmlDesc, setHtmlDesc] = useState<ReactNode[]>([]);
useEffect(() => {
if (!desc || desc.length === 0) {
setHtmlDesc([]);
return;
}
const elements: ReactNode[] = [];
const regexCopy = new RegExp(SYNTAX_REGEX);
let lastIndex = 0;
let result;
while ((result = regexCopy.exec(desc)) !== null) {
elements.push(<>{desc.substring(lastIndex, result.index)}</>);
elements.push(
<Box inline color={SYNTAX_COLOR[result[0]] || 'purple'}>
{result[0]}
</Box>,
);
lastIndex = result.index + result[0].length;
}
elements.push(<>{desc.substring(lastIndex)}</>);
setHtmlDesc(elements);
}, [desc]);
return <Box preserveWhitespace>{htmlDesc}</Box>;
};
const CountedTextElement = (props: {
limit: number;
entry: string;
action: Function;
index?: number;
}) => {
const { entry, limit, action, index } = props;
const ref = useRef<HTMLTextAreaElement | null>(null);
const currentCount = ref.current?.value.length || 0;
return (
<>
<Stack.Item grow>
<TextArea
height="100%"
minHeight={calcLineHeight(limit, 16)}
fluid
ref={ref}
maxLength={limit}
value={entry}
onBlur={(value) => {
if (value !== entry) {
action(value, index);
}
}}
/>
</Stack.Item>
<Stack.Item>
<Stack>
<Stack.Item grow />
<Stack.Item>
<Box color="label">{currentCount + ' / ' + limit}</Box>
</Stack.Item>
<Stack.Item grow />
</Stack>
</Stack.Item>
</>
);
};
const AreaMapper = (props: {
limit: number;
entry: string[];
action: Function;
exactLength: boolean;
maxEntries: number;
}) => {
const { entry, limit, action, exactLength, maxEntries } = props;
const filledArray = [
...entry,
...new Array(maxEntries - entry.length).fill(''),
];
function performAction(value: string, index: number) {
const newEntry = [...filledArray];
newEntry[index] = value;
if (exactLength) {
action(newEntry);
return;
}
const filtered = newEntry.filter(Boolean);
action(filtered);
}
return filledArray.map((singleEntry, index) => (
<CountedTextElement
key={index}
limit={limit}
entry={singleEntry}
action={performAction}
index={index}
/>
));
};
export const VorePanelEditTextArea = (props: {
/** Switch between Element editing and display */
editMode: boolean;
/** Our backend action on text area blur */
action: string;
/** Our secondary backend action on text area blur */
subAction?: string;
/** Our secondary backend action if we used a list as input on text area blur */
listAction?: string;
/** Our displayed tooltip displayed above all texts */
tooltip?: string;
/** The maximum length of each message */
limit: number;
/** The current displayed message or message array */
entry: string | string[];
/** Do we force the input to always send the maxEntries as list length to byond */
exactLength?: boolean;
/** The amount of possible list entries. By default 10 */
maxEntries?: number;
/** Should we disbale the copy paste legacy field for text to list inputs */
disableLegacyInput?: boolean;
/** Disable our special highlighting used on belly messages */
noHighlight?: boolean;
}) => {
const { act } = useBackend();
const {
entry,
editMode,
tooltip,
limit,
action,
exactLength = false,
listAction,
subAction = '',
maxEntries = 10,
disableLegacyInput = false,
noHighlight,
} = props;
function doAct(value: string | string[]) {
if (Array.isArray(value)) {
act(action, { attribute: listAction, msgtype: subAction, val: value });
return;
}
act(action, { attribute: subAction, val: value });
}
function applyPaste(value: string) {
Array.isArray(entry) ? doAct(value.split('\n\n')) : doAct(value);
}
return editMode ? (
<Stack fill vertical>
{!!tooltip && (
<Stack.Item>
<Box color="label">{tooltip}</Box>
</Stack.Item>
)}
{!disableLegacyInput && Array.isArray(entry) && (
<Stack.Item>
<Floating
placement="bottom-start"
contentClasses="VorePanel__pasteArea"
content={
<Stack fill vertical>
<Stack.Item>
<Box color="label">
Copy paste the fields as legacy block text. Use enter to
apply. Shift + Enter for new lines.
</Box>
</Stack.Item>
<Stack.Item grow>
<TextArea
height="100%"
fluid
value={Array.isArray(entry) ? entry.join('\n\n') : entry}
onEnter={(value) => applyPaste(value)}
/>
</Stack.Item>
</Stack>
}
>
<Box className="VorePanel__floatingButton">
<Icon name="paste" />
</Box>
</Floating>
</Stack.Item>
)}
<Stack.Item>
{Array.isArray(entry) ? (
<AreaMapper
limit={limit}
entry={entry}
exactLength={exactLength}
action={doAct}
maxEntries={maxEntries}
/>
) : (
<CountedTextElement limit={limit} entry={entry} action={doAct} />
)}
</Stack.Item>
</Stack>
) : Array.isArray(entry) ? (
<Stack vertical g={1}>
{entry.map((singleEntry, index) => (
<Stack.Item key={index}>
<Divider />
{noHighlight ? (
<Box preserveWhitespace>{singleEntry}</Box>
) : (
<DescriptionSyntaxHighlighting desc={singleEntry} />
)}
</Stack.Item>
))}
</Stack>
) : !noHighlight ? (
<Box preserveWhitespace>{entry}</Box>
) : (
<DescriptionSyntaxHighlighting desc={entry} />
);
};
@@ -0,0 +1,125 @@
import { useBackend } from 'tgui/backend';
import { LabeledList, Stack, Tabs } from 'tgui-core/components';
import { VorePanelEditSwitch } from './VorePanelEditSwitch';
import { VorePanelEditTextArea } from './VorePanelTextArea';
export const VorePanelEditTextTabs = (props: {
/** Switch between Element editing and display */
editMode: boolean;
/** The tab options to switch through */
messsageOptions: string[];
/** The current active tab */
activeTab: string;
/** The backend action to perform on tab selection */
tabAction: string;
/** Our displayed tooltip displayed above all texts */
tooltip: string;
/** The maximum length of each message */
maxLength: number;
/** The current displayed message or message array */
activeMessage: string | string[] | null;
/** Do we force the input to always send the maxEntries as list length to byond */
exactLength?: boolean;
/** Our backend action on text area blur */
action: string;
/** Our secondary backend action on text area blur */
subAction?: string;
/** Our secondary backend action if we used a list as input on text area blur */
listAction?: string;
/** The amount of possible list entries. By default 10 */
maxEntries?: number;
/** Should we disbale the copy paste legacy field for text to list inputs */
disableLegacyInput?: boolean;
/** The action of a possibly supplied button shown above all inputs */
button_action?: string;
/** The action of a possibly supplied button shown above all inputs */
button_label?: string;
/** The data of the button to show its possible selected state */
button_data?: boolean;
/** The tooltip to display on button hover */
button_tooltip?: string;
/** The icon of each tab as record, mapping the messageOptions to icons */
tabsToIcons?: Record<string, string>;
/** Disable our special highlighting used on belly messages */
noHighlight?: boolean;
}) => {
const { act } = useBackend();
const {
editMode,
messsageOptions,
activeTab,
tabAction,
tooltip,
maxLength,
activeMessage,
action,
exactLength,
subAction,
listAction,
maxEntries = 10,
disableLegacyInput,
button_action,
button_label,
button_data,
button_tooltip,
tabsToIcons,
noHighlight,
} = props;
return (
<Stack vertical fill>
<Stack.Item>
<Tabs>
{messsageOptions.map((value) => (
<Tabs.Tab
key={value}
selected={value === activeTab}
onClick={() => {
if (value !== activeTab) {
act(tabAction, { tab: value });
}
}}
icon={tabsToIcons && tabsToIcons[value]}
>
{value}
</Tabs.Tab>
))}
</Tabs>
</Stack.Item>
{!!button_action && (
<Stack.Item>
<LabeledList>
<LabeledList.Item label={button_label}>
<VorePanelEditSwitch
action="set_attribute"
subAction={button_action}
editMode={editMode}
active={!!button_data}
tooltip={
(button_data ? 'Dis' : 'En') + 'ables ' + button_tooltip
}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
)}
<Stack.Item grow>
<VorePanelEditTextArea
noHighlight={noHighlight}
editMode={editMode}
tooltip={tooltip}
limit={maxLength}
entry={activeMessage || ''}
action={action}
exactLength={exactLength}
subAction={subAction}
listAction={listAction}
maxEntries={maxEntries}
disableLegacyInput={disableLegacyInput}
/>
</Stack.Item>
</Stack>
);
};
@@ -1,7 +1,7 @@
import { useBackend } from 'tgui/backend';
import { Button } from 'tgui-core/components';
import type { preferenceData } from './types';
import type { preferenceData } from '../types';
export const VoreUserPreferenceItem = (props: {
spec: preferenceData;
@@ -0,0 +1,66 @@
import { useBackend } from 'tgui/backend';
import { LabeledList, Section, Slider, Stack } from 'tgui-core/components';
import { toFixed } from 'tgui-core/math';
import { abilitiy_usable } from '../functions';
import type { abilities, abilitySizeChange } from '../types';
export const VoreAbilities = (props: { abilities: abilities }) => {
const { abilities } = props;
const { nutrition, size_change } = abilities;
return (
<Section title="Abilities" buttons={'Nutrition: ' + toFixed(nutrition, 1)}>
<LabeledList>
<SizeChange nutrition={nutrition} sizeChange={size_change} />
</LabeledList>
</Section>
);
};
const SizeChange = (props: {
nutrition: number;
sizeChange: abilitySizeChange;
}) => {
const { act } = useBackend();
const { nutrition, sizeChange } = props;
const { resize_cost, current_size, minimum_size, maximum_size } = sizeChange;
return (
<LabeledList.Item label="Resize">
<Stack align="baseline">
<Stack.Item>
<Slider
disabled={!abilitiy_usable(nutrition, resize_cost)}
width="250px"
ranges={
abilitiy_usable(nutrition, resize_cost)
? {
bad: [1, 25],
average: [25, 50],
green: [50, 150],
yellow: [150, 200],
red: [200, 600],
}
: { black: [0, 600] }
}
format={(value: number) => toFixed(value, 2) + '%'}
value={Math.round(current_size * 10000) / 100}
minValue={minimum_size * 100}
maxValue={maximum_size * 100}
onChange={(e, value: number) =>
act('adjust_own_size', {
new_mob_size: value / 100,
})
}
/>
</Stack.Item>
<Stack.Item color="label">&nbsp;&nbsp;Cost:&nbsp;</Stack.Item>
<Stack.Item>{resize_cost}</Stack.Item>
</Stack>
</LabeledList.Item>
);
};
@@ -1,41 +1,77 @@
import { useState } from 'react';
import { useBackend } from 'tgui/backend';
import {
Button,
Divider,
Icon,
Input,
Section,
Stack,
Tabs,
Tooltip,
} from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { createSearch } from 'tgui-core/string';
import { digestModeToColor } from './constants';
import type { bellyData, hostMob, selectedData } from './types';
import { digestModeToColor } from '../constants';
import type { bellyData, hostMob, selectedData } from '../types';
import { VorePanelEditToggle } from '../VorePanelElements/VorePanelCommonElements';
import { VoreSelectedBelly } from './VoreSelectedBelly';
export const VoreBellySelectionAndCustomization = (props: {
activeVoreTab?: number;
our_bellies: bellyData[];
selected: selectedData | null;
show_pictures: BooleanLike;
host_mobtype: hostMob;
icon_overflow: BooleanLike;
vore_words: Record<string, string[]>;
toggleEditMode: React.Dispatch<React.SetStateAction<boolean>>;
editMode: boolean;
}) => {
const { act } = useBackend();
const {
activeVoreTab = 0,
our_bellies,
selected,
show_pictures,
host_mobtype,
icon_overflow,
vore_words,
toggleEditMode,
editMode,
} = props;
const [showSearch, setShowSearch] = useState(false);
const [searchedBellies, setSearchedBellies] = useState('');
const bellySearch = createSearch(
searchedBellies,
(belly: bellyData) => belly.name,
);
const belliesToDisplay = our_bellies.filter(bellySearch);
const bellyDropdownNames = our_bellies.map((belly) => {
return { displayText: belly.name, value: belly.ref };
});
return (
<Stack fill>
<Stack.Item shrink basis="20%">
<Section title="My Bellies" scrollable fill>
<Section
title="My Bellies"
scrollable
fill
buttons={
<Button
icon="magnifying-glass"
selected={showSearch}
onClick={() => setShowSearch(!showSearch)}
/>
}
>
<Tabs vertical>
<Tabs.Tab onClick={() => act('newbelly')}>
New
@@ -50,18 +86,28 @@ export const VoreBellySelectionAndCustomization = (props: {
<Icon name="file-import" ml={0.5} />
</Tabs.Tab>
<Divider />
{our_bellies.map((belly) => (
{showSearch && (
<>
<Input
fluid
placeholder="Search for bellies..."
onChange={(value) => setSearchedBellies(value)}
/>
<Divider />
</>
)}
{belliesToDisplay.map((belly) => (
<Tabs.Tab
key={belly.name}
selected={!!belly.selected}
textColor={digestModeToColor[belly.digest_mode]}
textColor={digestModeToColor[belly.digest_mode!]}
onClick={() => act('bellypick', { bellypick: belly.ref })}
backgroundColor={belly.prevent_saving ? '#180000' : undefined}
>
<Stack
fill
textColor={
(belly.selected && digestModeToColor[belly.digest_mode]) ||
(belly.selected && digestModeToColor[belly.digest_mode!]) ||
null
}
>
@@ -87,13 +133,26 @@ export const VoreBellySelectionAndCustomization = (props: {
</Stack.Item>
<Stack.Item grow>
{selected && (
<Section title={selected.belly_name} fill scrollable>
<Section
title={selected.belly_name}
buttons={
<VorePanelEditToggle
editMode={editMode}
toggleEditMode={toggleEditMode}
/>
}
fill
scrollable
>
<VoreSelectedBelly
bellyDropdownNames={bellyDropdownNames}
activeVoreTab={activeVoreTab}
vore_words={vore_words}
belly={selected}
show_pictures={show_pictures}
host_mobtype={host_mobtype}
icon_overflow={icon_overflow}
editMode={editMode}
/>
</Section>
)}
@@ -1,10 +1,10 @@
import { Box, Collapsible, Section } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { digestModeToPreyMode, reagentToColor } from './constants';
import { digestModeToColor } from './constants';
import type { insideData } from './types';
import { VoreContentsPanel } from './VoreContentsPanel';
import { digestModeToPreyMode, reagentToColor } from '../constants';
import { digestModeToColor } from '../constants';
import type { insideData } from '../types';
import { VoreContentsPanel } from '../VoreSelectedBellyTabs/VoreContentsPanel';
export const VoreInsidePanel = (props: {
inside: insideData;
@@ -43,7 +43,7 @@ export const VoreInsidePanel = (props: {
<Box color="red" inline>
{belly_name}
</Box>
{liq_lvl! > 0 ? (
{!!liq_lvl && liq_lvl > 0 && (
<>
,&nbsp;
<Box color="yellow" inline>
@@ -54,8 +54,6 @@ export const VoreInsidePanel = (props: {
{liuq_name}
</Box>
</>
) : (
''
)}
&nbsp;
<Box color="yellow" inline>
@@ -67,17 +65,18 @@ export const VoreInsidePanel = (props: {
</Box>
&nbsp;
<Box color="label">{desc}</Box>
{(contents!.length && (
{contents && contents.length ? (
<Collapsible title="Belly Contents">
<VoreContentsPanel
contents={contents!}
contents={contents}
belly={ref}
show_pictures={show_pictures}
icon_overflow={icon_overflow}
/>
</Collapsible>
)) ||
'There is nothing else around you.'}
) : (
'There is nothing else around you.'
)}
</Section>
);
};
@@ -0,0 +1,135 @@
import { useState } from 'react';
import { useBackend } from 'tgui/backend';
import { Stack, Tabs } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { tabToNames } from '../constants';
import type { DropdownEntry, hostMob, selectedData } from '../types';
import { VoreContentsPanel } from '../VoreSelectedBellyTabs/VoreContentsPanel';
import { VoreSelectedBellyControls } from '../VoreSelectedBellyTabs/VoreSelectedBellyControls';
import { VoreSelectedBellyDescriptions } from '../VoreSelectedBellyTabs/VoreSelectedBellyDescriptions';
import { VoreSelectedBellyInteractions } from '../VoreSelectedBellyTabs/VoreSelectedBellyInteractions';
import { VoreSelectedBellyLiquidOptions } from '../VoreSelectedBellyTabs/VoreSelectedBellyLiquidOptions';
import { VoreSelectedBellyOptions } from '../VoreSelectedBellyTabs/VoreSelectedBellyOptions';
import { VoreSelectedBellySounds } from '../VoreSelectedBellyTabs/VoreSelectedBellySounds';
import { VoreSelectedBellyVisuals } from '../VoreSelectedBellyTabs/VoreSelectedBellyVisuals';
/**
* Subtemplate of VoreBellySelectionAndCustomization
*/
export const VoreSelectedBelly = (props: {
bellyDropdownNames: DropdownEntry[];
activeVoreTab: number;
belly: selectedData;
show_pictures: BooleanLike;
host_mobtype: hostMob;
icon_overflow: BooleanLike;
vore_words: Record<string, string[]>;
editMode: boolean;
}) => {
const { act } = useBackend();
const {
bellyDropdownNames,
activeVoreTab,
belly,
show_pictures,
host_mobtype,
icon_overflow,
vore_words,
editMode,
} = props;
const {
belly_name,
belly_mode_data,
belly_description_data,
belly_option_data,
belly_sound_data,
belly_visual_data,
belly_interaction_data,
belly_liquid_data,
contents,
content_length,
} = belly;
const [targetBelly, setTargetBelly] = useState('');
const tabs: (React.JSX.Element | undefined)[] = [];
tabs[0] = belly_mode_data && (
<VoreSelectedBellyControls
editMode={editMode}
bellyDropdownNames={bellyDropdownNames}
belly_name={belly_name}
bellyModeData={belly_mode_data}
/>
);
tabs[1] = belly_description_data && (
<VoreSelectedBellyDescriptions
editMode={editMode}
bellyDescriptionData={belly_description_data}
vore_words={vore_words}
/>
);
tabs[2] = belly_option_data && (
<VoreSelectedBellyOptions
editMode={editMode}
bellyOptionData={belly_option_data}
host_mobtype={host_mobtype}
/>
);
tabs[3] = belly_sound_data && (
<VoreSelectedBellySounds
editMode={editMode}
bellySoundData={belly_sound_data}
/>
);
tabs[4] = belly_visual_data && (
<VoreSelectedBellyVisuals
editMode={editMode}
bellyVisualData={belly_visual_data}
/>
);
tabs[5] = belly_interaction_data && (
<VoreSelectedBellyInteractions
editMode={editMode}
bellyDropdownNames={bellyDropdownNames}
bellyInteractData={belly_interaction_data}
/>
);
tabs[6] = (
<VoreContentsPanel
outside
targetBelly={targetBelly}
onTargetBely={setTargetBelly}
bellyDropdownNames={bellyDropdownNames}
contents={contents}
show_pictures={show_pictures}
icon_overflow={icon_overflow}
/>
);
tabs[7] = belly_liquid_data && (
<VoreSelectedBellyLiquidOptions
editMode={editMode}
bellyLiquidData={belly_liquid_data}
/>
);
return (
<Stack vertical fill>
<Stack.Item>
<Tabs>
{tabToNames.map((name, index) => (
<Tabs.Tab
key={name}
selected={activeVoreTab === index}
onClick={() => act('change_vore_tab', { tab: index })}
>
{tabToNames[index]}
{!!(index === 6) && '(' + content_length + ')'}
</Tabs.Tab>
))}
</Tabs>
</Stack.Item>
<Stack.Item grow>{tabs[activeVoreTab] || 'Error'}</Stack.Item>
</Stack>
);
};
@@ -0,0 +1,209 @@
import { useBackend } from 'tgui/backend';
import {
Box,
Dropdown,
LabeledList,
Section,
Stack,
} from 'tgui-core/components';
import { noSelectionName } from '../constants';
import type { abilities, DropdownEntry, soulcatcherData } from '../types';
import { VorePanelEditToggle } from '../VorePanelElements/VorePanelCommonElements';
import { VorePanelEditTextTabs } from '../VorePanelElements/VorePaneldEditTextTabs';
import { VorePanelEditDropdown } from '../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditSwitch } from '../VorePanelElements/VorePanelEditSwitch';
import { VorePanelEditText } from '../VorePanelElements/VorePanelEditText';
import { CatchSettings } from '../VoreSoulcatcherSettings/CatchSettings';
import { GlobalOptions } from '../VoreSoulcatcherSettings/GlobalOptions';
import { GlobalSettings } from '../VoreSoulcatcherSettings/GlobalSettings';
import { SoulOptions } from '../VoreSoulcatcherSettings/SoulOptions';
import { VoreAbilities } from './VoreAbilities';
export const VoreSoulcatcher = (props: {
soulcatcher: soulcatcherData | null;
our_bellies: Required<{ name: string; ref: string }[]> & {
map(
arg0: (belly: { name: string; ref: string }) => DropdownEntry,
): DropdownEntry[];
};
abilities: abilities;
toggleEditMode: React.Dispatch<React.SetStateAction<boolean>>;
editMode: boolean;
}) => {
const { soulcatcher, our_bellies, abilities, toggleEditMode, editMode } =
props;
const getBellies = our_bellies.map((belly) => {
return { displayText: belly.name, value: belly.ref };
});
const locationNames = [...getBellies, noSelectionName];
return (
<Section scrollable fill>
<Stack vertical fill>
{soulcatcher && (
<Stack.Item>
<VoreSoulcatcherSection
soulcatcher={soulcatcher}
overlayBellies={locationNames}
toggleEditMode={toggleEditMode}
editMode={editMode}
/>
</Stack.Item>
)}
<Stack.Item>
<VoreAbilities abilities={abilities} />
</Stack.Item>
</Stack>
</Section>
);
};
const VoreSoulcatcherSection = (props: {
soulcatcher: soulcatcherData;
overlayBellies: DropdownEntry[];
toggleEditMode: React.Dispatch<React.SetStateAction<boolean>>;
editMode: boolean;
}) => {
const { act } = useBackend();
const { soulcatcher, overlayBellies, toggleEditMode, editMode } = props;
const {
active,
name,
caught_souls,
selected_soul,
catch_self,
catch_prey,
catch_drain,
catch_ghost,
ext_hearing,
ext_vision,
mind_backups,
sr_projecting,
see_sr_projecting,
selected_sfx,
show_vore_sfx,
taken_over,
sc_message_data,
} = soulcatcher;
return (
<Section
title={'Soulcatcher (' + name + ')'}
fill
buttons={
<Stack>
<Stack.Item>
<VorePanelEditSwitch
action="soulcatcher_toggle"
editMode={editMode}
active={!!active}
tooltipPosition="top"
tooltip={
(active ? 'Disables' : 'Enables') +
' the ability to capture souls upon vore death.'
}
/>
</Stack.Item>
<Stack.Item>
<VorePanelEditToggle
editMode={editMode}
toggleEditMode={toggleEditMode}
/>
</Stack.Item>
</Stack>
}
>
{!!active && (
<Stack vertical>
<Stack.Item>
<LabeledList>
<LabeledList.Item label="Captured Souls">
<Stack align="center">
<Stack.Item>
<Dropdown
width="200px"
selected={selected_soul}
options={caught_souls}
onSelected={(value) =>
act('soulcatcher_select', {
selected_soul: value,
})
}
/>
</Stack.Item>
<Stack.Item>
<Box>{caught_souls.length}</Box>
</Stack.Item>
</Stack>
</LabeledList.Item>
{!!selected_soul && <SoulOptions taken_over={taken_over} />}
{!!caught_souls.length && (
<GlobalOptions taken_over={taken_over} />
)}
<CatchSettings
editMode={editMode}
catch_self={catch_self}
catch_prey={catch_prey}
catch_drain={catch_drain}
catch_ghost={catch_ghost}
/>
<GlobalSettings
editMode={editMode}
ext_hearing={ext_hearing}
ext_vision={ext_vision}
mind_backups={mind_backups}
sr_projecting={sr_projecting}
see_sr_projecting={see_sr_projecting}
show_vore_sfx={show_vore_sfx}
/>
<LabeledList.Item label="Interior SFX">
<VorePanelEditDropdown
action="soulcatcher_sfx"
editMode={editMode}
options={overlayBellies}
color={!editMode && !selected_sfx ? 'red' : undefined}
entry={selected_sfx || 'Disabled'}
tooltip="Allows you to link a belly FX to display to captured souls."
/>
</LabeledList.Item>
{editMode && (
<LabeledList.Item label="Edit Name">
<VorePanelEditText
action="soulcatcher_rename"
editMode={editMode}
tooltipPosition="top"
limit={60}
min={3}
entry={name}
tooltip={
'Adjust the name of your soulcatcher. [3-60 characters].'
}
/>
</LabeledList.Item>
)}
</LabeledList>
</Stack.Item>
<Stack.Divider />
<Stack.Item>
<VorePanelEditTextTabs
noHighlight
editMode={editMode}
messsageOptions={sc_message_data.possible_messages}
activeTab={sc_message_data.sc_subtab}
tabAction="change_sc_message_option"
tooltip={sc_message_data.tooltip}
maxLength={sc_message_data.max_length}
activeMessage={sc_message_data.active_message}
action={sc_message_data.set_action}
/>
</Stack.Item>
</Stack>
)}
</Section>
);
};
@@ -0,0 +1,56 @@
import { useBackend } from 'tgui/backend';
import { Button, Section, Stack } from 'tgui-core/components';
import type { bellyData, generalPrefData } from '../types';
import { VoreUserPreferencesAesthetic } from '../VoreUserPreferencesTabs/VoreUserPreferencesAesthetic';
/**
* Subtemplate of VoreBellySelectionAndCustomization
*/
export const VoreUserGeneral = (props: {
general_pref_data?: generalPrefData;
editMode: boolean;
our_bellies: bellyData[];
toggleEditMode: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const { act } = useBackend();
const { general_pref_data, editMode, our_bellies, toggleEditMode } = props;
return (
<Section fill>
<Stack vertical fill>
{!!general_pref_data && (
<Stack.Item grow>
<VoreUserPreferencesAesthetic
editMode={editMode}
toggleEditMode={toggleEditMode}
active_belly={general_pref_data.active_belly}
belly_rub_target={general_pref_data.belly_rub_target}
aestethicMessages={general_pref_data.aestethic_messages}
our_bellies={our_bellies}
vore_sprite_color={general_pref_data.vore_sprite_color}
vore_sprite_multiply={general_pref_data.vore_sprite_multiply}
vore_icon_options={general_pref_data.vore_icon_options}
/>
</Stack.Item>
)}
<Stack.Divider />
<Stack.Item>
<Section>
<Stack>
<Stack.Item basis="49%">
<Button fluid icon="save" onClick={() => act('saveprefs')}>
Save Prefs
</Button>
</Stack.Item>
<Stack.Item basis="49%" grow>
<Button fluid icon="undo" onClick={() => act('reloadprefs')}>
Reload Prefs
</Button>
</Stack.Item>
</Stack>
</Section>
</Stack.Item>
</Stack>
</Section>
);
};
@@ -1,25 +1,20 @@
import { useBackend } from 'tgui/backend';
import { Button, Divider, Section, Stack } from 'tgui-core/components';
import { Section } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { digestModeToColor } from './constants';
import type { localPrefs, prefData, selectedData } from './types';
import { VoreUserPreferencesAesthetic } from './VoreUserPreferencesTabs/VoreUserPreferencesAesthetic';
import { VoreUserPreferencesDevouring } from './VoreUserPreferencesTabs/VoreUserPreferencesDevouring';
import { VoreUserPreferencesMechanical } from './VoreUserPreferencesTabs/VoreUserPreferencesMechanical';
import { VoreUserPreferencesSoulcatcher } from './VoreUserPreferencesTabs/VoreUserPreferencesSoulcatcher';
import { VoreUserPreferencesSpawn } from './VoreUserPreferencesTabs/VoreUserPreferencesSpawn';
import { VoreUserPreferencesSpontaneous } from './VoreUserPreferencesTabs/VoreUserPreferencesSpontaneous';
import { digestModeToColor } from '../constants';
import type { localPrefs, prefData } from '../types';
import { VoreUserPreferencesDevouring } from '../VoreUserPreferencesTabs/VoreUserPreferencesDevouring';
import { VoreUserPreferencesMechanical } from '../VoreUserPreferencesTabs/VoreUserPreferencesMechanical';
import { VoreUserPreferencesSoulcatcher } from '../VoreUserPreferencesTabs/VoreUserPreferencesSoulcatcher';
import { VoreUserPreferencesSpawn } from '../VoreUserPreferencesTabs/VoreUserPreferencesSpawn';
import { VoreUserPreferencesSpontaneous } from '../VoreUserPreferencesTabs/VoreUserPreferencesSpontaneous';
export const VoreUserPreferences = (props: {
prefs: prefData;
selected: selectedData | null;
show_pictures: BooleanLike;
icon_overflow: BooleanLike;
}) => {
const { act } = useBackend();
const { prefs, selected, show_pictures, icon_overflow } = props;
const { prefs, show_pictures, icon_overflow } = props;
const {
digestable,
absorbable,
@@ -61,10 +56,7 @@ export const VoreUserPreferences = (props: {
no_spawnprey_warning_time,
no_spawnpred_warning_save,
no_spawnprey_warning_save,
nutrition_message_visible,
weight_message_visible,
selective_active,
belly_rub_target,
soulcatcher_allow_capture,
soulcatcher_allow_transfer,
soulcatcher_allow_deletion,
@@ -466,32 +458,6 @@ export const VoreUserPreferences = (props: {
disabled: 'Mind Transfer Disabled',
},
},
examine_nutrition: {
action: 'toggle_nutrition_ex',
test: nutrition_message_visible,
tooltip: {
main: '',
enable: 'Click here to enable nutrition messages.',
disable: 'Click here to disable nutrition messages.',
},
content: {
enabled: 'Examine Nutrition Messages Active',
disabled: 'Examine Nutrition Messages Inactive',
},
},
examine_weight: {
action: 'toggle_weight_ex',
test: weight_message_visible,
tooltip: {
main: '',
enable: 'Click here to enable weight messages.',
disable: 'Click here to disable weight messages.',
},
content: {
enabled: 'Examine Weight Messages Active',
disabled: 'Examine Weight Messages Inactive',
},
},
strippref: {
action: 'toggle_strippref',
test: strip_mechanics_active,
@@ -748,26 +714,6 @@ export const VoreUserPreferences = (props: {
no_spawnprey_warning_time={no_spawnprey_warning_time}
no_spawnprey_warning_save={no_spawnprey_warning_save}
/>
<VoreUserPreferencesAesthetic
preferences={preferences}
belly_rub_target={belly_rub_target}
selected={selected}
/>
<Divider />
<Section>
<Stack>
<Stack.Item basis="49%">
<Button fluid icon="save" onClick={() => act('saveprefs')}>
Save Prefs
</Button>
</Stack.Item>
<Stack.Item basis="49%" grow>
<Button fluid icon="undo" onClick={() => act('reloadprefs')}>
Reload Prefs
</Button>
</Stack.Item>
</Stack>
</Section>
</Section>
);
};
@@ -1,88 +0,0 @@
import { useState } from 'react';
import { Tabs } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import type { hostMob, selectedData } from './types';
import { VoreContentsPanel } from './VoreContentsPanel';
import { VoreSelectedBellyControls } from './VoreSelectedBellyTabs/VoreSelectedBellyControls';
import { VoreSelectedBellyDescriptions } from './VoreSelectedBellyTabs/VoreSelectedBellyDescriptions';
import { VoreSelectedBellyInteractions } from './VoreSelectedBellyTabs/VoreSelectedBellyInteractions';
import { VoreSelectedBellyLiquidMessages } from './VoreSelectedBellyTabs/VoreSelectedBellyLiquidMessages';
import { VoreSelectedBellyLiquidOptions } from './VoreSelectedBellyTabs/VoreSelectedBellyLiquidOptions';
import { VoreSelectedBellyOptions } from './VoreSelectedBellyTabs/VoreSelectedBellyOptions';
import { VoreSelectedBellySounds } from './VoreSelectedBellyTabs/VoreSelectedBellySounds';
import { VoreSelectedBellyVisuals } from './VoreSelectedBellyTabs/VoreSelectedBellyVisuals';
/**
* Subtemplate of VoreBellySelectionAndCustomization
*/
export const VoreSelectedBelly = (props: {
belly: selectedData;
show_pictures: BooleanLike;
host_mobtype: hostMob;
icon_overflow: BooleanLike;
vore_words: Record<string, string[]>;
}) => {
const { belly, show_pictures, host_mobtype, icon_overflow, vore_words } =
props;
const { contents } = belly;
const [tabIndex, setTabIndex] = useState(0);
const tabs: React.JSX.Element[] = [];
tabs[0] = <VoreSelectedBellyControls belly={belly} />;
tabs[1] = (
<VoreSelectedBellyDescriptions belly={belly} vore_words={vore_words} />
);
tabs[2] = (
<VoreSelectedBellyOptions belly={belly} host_mobtype={host_mobtype} />
);
tabs[3] = <VoreSelectedBellySounds belly={belly} />;
tabs[4] = <VoreSelectedBellyVisuals belly={belly} />;
tabs[5] = <VoreSelectedBellyInteractions belly={belly} />;
tabs[6] = (
<VoreContentsPanel
outside
contents={contents}
show_pictures={show_pictures}
icon_overflow={icon_overflow}
/>
);
tabs[7] = <VoreSelectedBellyLiquidOptions belly={belly} />;
tabs[8] = <VoreSelectedBellyLiquidMessages belly={belly} />;
return (
<>
<Tabs>
<Tabs.Tab selected={tabIndex === 0} onClick={() => setTabIndex(0)}>
Controls
</Tabs.Tab>
<Tabs.Tab selected={tabIndex === 1} onClick={() => setTabIndex(1)}>
Descriptions
</Tabs.Tab>
<Tabs.Tab selected={tabIndex === 2} onClick={() => setTabIndex(2)}>
Options
</Tabs.Tab>
<Tabs.Tab selected={tabIndex === 3} onClick={() => setTabIndex(3)}>
Sounds
</Tabs.Tab>
<Tabs.Tab selected={tabIndex === 4} onClick={() => setTabIndex(4)}>
Visuals
</Tabs.Tab>
<Tabs.Tab selected={tabIndex === 5} onClick={() => setTabIndex(5)}>
Interactions
</Tabs.Tab>
<Tabs.Tab selected={tabIndex === 6} onClick={() => setTabIndex(6)}>
Contents ({contents.length})
</Tabs.Tab>
<Tabs.Tab selected={tabIndex === 7} onClick={() => setTabIndex(7)}>
Liquid Options
</Tabs.Tab>
<Tabs.Tab selected={tabIndex === 8} onClick={() => setTabIndex(8)}>
Liquid Messages
</Tabs.Tab>
</Tabs>
{tabs[tabIndex] || 'Error'}
</>
);
};
@@ -1,83 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
export const VoreSelectedBellyDescriptionsBellymode = (props: {
message_mode: BooleanLike;
mode: string;
}) => {
const { act } = useBackend();
const { message_mode, mode } = props;
return (
<LabeledList.Item label="Bellymode Messages">
{(message_mode || mode === 'Digest' || mode === 'Selective') && (
<Stack wrap>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'dmp' })
}
>
Digest Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'dmo' })
}
>
Digest Message (to you)
</Button>
</Stack.Item>
</Stack>
)}
{(message_mode || mode === 'Absorb' || mode === 'Selective') && (
<Stack>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'amp' })
}
>
Absorb Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'amo' })
}
>
Absorb Message (to you)
</Button>
</Stack.Item>
</Stack>
)}
{(message_mode || mode === 'Unabsorb') && (
<Stack>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'uamp' })
}
>
Unabsorb Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'uamo' })
}
>
Unabsorb Message (to you)
</Button>
</Stack.Item>
</Stack>
)}
</LabeledList.Item>
);
};
@@ -1,203 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import type { interactData } from '../types';
export const VoreSelectedBellyDescriptionsEscape = (props: {
message_mode: BooleanLike;
interacts: interactData;
}) => {
const { act } = useBackend();
const { message_mode, interacts } = props;
return (
<LabeledList.Item label="Escape Messages">
<Stack wrap>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'escap' })
}
>
Escape Attempt Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'escao' })
}
>
Escape Attempt Message (to you)
</Button>
</Stack.Item>
{(message_mode || interacts.escapechance > 0) && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'escp',
})
}
>
Escape Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'esco',
})
}
>
Escape Message (to you)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'escout',
})
}
>
Escape Message (outside)
</Button>
</Stack.Item>
</>
)}
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'escip' })
}
>
Escape Item Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'escio' })
}
>
Escape Item Message (to you)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'esciout',
})
}
>
Escape Item Message (outside)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'escfp' })
}
>
Escape Fail Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'escfo' })
}
>
Escape Fail Message (to you)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescap' })
}
>
Absorbed Escape Attempt Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescao' })
}
>
Absorbed Escape Attempt Message (to you)
</Button>
</Stack.Item>
{(message_mode || interacts.escapechance_absorbed > 0) && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'aescp',
})
}
>
Absorbed Escape Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'aesco',
})
}
>
Absorbed Escape Message (to you)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'aescout',
})
}
>
Absorbed Escape Message (outside)
</Button>
</Stack.Item>
</>
)}
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescfp' })
}
>
Absorbed Escape Fail Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'aescfo' })
}
>
Absorbed Escape Fail Message (to you)
</Button>
</Stack.Item>
</Stack>
</LabeledList.Item>
);
};
@@ -1,170 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
export const VoreSelectedBellyDescriptionsIdle = (props: {
message_mode: BooleanLike;
mode: string;
}) => {
const { act } = useBackend();
const { message_mode, mode } = props;
return (
<LabeledList.Item label="Idle Messages">
<Stack wrap>
{(message_mode || mode === 'Hold' || mode === 'Selective') && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_hold',
})
}
>
Idle Messages (Hold)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_holdabsorbed',
})
}
>
Idle Messages (Hold Absorbed)
</Button>
</Stack.Item>
</>
)}
{(message_mode || mode === 'Digest' || mode === 'Selective') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_digest',
})
}
>
Idle Messages (Digest)
</Button>
</Stack.Item>
)}
{(message_mode || mode === 'Absorb' || mode === 'Selective') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_absorb',
})
}
>
Idle Messages (Absorb)
</Button>
</Stack.Item>
)}
{(message_mode || mode === 'Unabsorb') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_unabsorb',
})
}
>
Idle Messages (Unabsorb)
</Button>
</Stack.Item>
)}
{(message_mode || mode === 'Drain' || mode === 'Selective') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_drain',
})
}
>
Idle Messages (Drain)
</Button>
</Stack.Item>
)}
{(message_mode || mode === 'Heal') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_heal',
})
}
>
Idle Messages (Heal)
</Button>
</Stack.Item>
)}
{(message_mode || mode === 'Size Steal') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_steal',
})
}
>
Idle Messages (Size Steal)
</Button>
</Stack.Item>
)}
{(message_mode || mode === 'Shrink') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_shrink',
})
}
>
Idle Messages (Shrink)
</Button>
</Stack.Item>
)}
{(message_mode || mode === 'Grow') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'im_grow',
})
}
>
Idle Messages (Grow)
</Button>
</Stack.Item>
)}
{(message_mode || mode === 'Encase In Egg') && (
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'im_egg' })
}
>
Idle Messages (Encase In Egg)
</Button>
</Stack.Item>
)}
</Stack>
</LabeledList.Item>
);
};
@@ -1,77 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import type { interactData } from '../types';
export const VoreSelectedBellyDescriptionsInteractionChance = (props: {
message_mode: BooleanLike;
interacts: interactData;
}) => {
const { act } = useBackend();
const { message_mode, interacts } = props;
return (
<LabeledList.Item label="Interaction Chance Messages">
<Stack wrap>
{(message_mode || interacts.digestchance > 0) && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'stmodp',
})
}
>
Interaction Chance Digest Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'stmodo',
})
}
>
Interaction Chance Digest Message (to you)
</Button>
</Stack.Item>
</>
)}
{(message_mode || interacts.absorbchance > 0) && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'stmoap',
})
}
>
Interaction Chance Absorb Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'stmoao',
})
}
>
Interaction Chance Absorb Message (to you)
</Button>
</Stack.Item>
</>
)}
</Stack>
</LabeledList.Item>
);
};
@@ -1,49 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
export const VoreSelectedBellyDescriptionsStruggle = (props) => {
const { act } = useBackend();
return (
<LabeledList.Item label="Struggle Messages">
<Stack wrap>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'smo' })
}
>
Struggle Message (outside)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'smi' })
}
>
Struggle Message (inside)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'asmo' })
}
>
Absorbed Struggle Message (outside)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'asmi' })
}
>
Absorbed Struggle Message (inside)
</Button>
</Stack.Item>
</Stack>
</LabeledList.Item>
);
};
@@ -1,134 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import type { autotransferData, interactData } from '../types';
export const VoreSelectedBellyDescriptionsTransfer = (props: {
message_mode: BooleanLike;
interacts: interactData;
autotransfer: autotransferData;
}) => {
const { act } = useBackend();
const { message_mode, interacts, autotransfer } = props;
return (
<LabeledList.Item label="Transfer Messages">
<Stack wrap>
{(message_mode || !!interacts.transferlocation) && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'trnspp',
})
}
>
Primary Transfer Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'trnspo',
})
}
>
Primary Transfer Message (to you)
</Button>
</Stack.Item>
</>
)}
{(message_mode || !!interacts.transferlocation_secondary) && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'trnssp',
})
}
>
Secondary Transfer Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'trnsso',
})
}
>
Secondary Transfer Message (to you)
</Button>
</Stack.Item>
</>
)}
{(message_mode || !!autotransfer.autotransferlocation) && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'atrnspp',
})
}
>
Primary Auto-Transfer Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'atrnspo',
})
}
>
Primary Auto-Transfer Message (to you)
</Button>
</Stack.Item>
</>
)}
{(message_mode || !!autotransfer.autotransferlocation_secondary) && (
<>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'atrnssp',
})
}
>
Secondary Auto-Transfer Message (to prey)
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'atrnsso',
})
}
>
Secondary Auto-Transfer Message (to you)
</Button>
</Stack.Item>
</>
)}
</Stack>
</LabeledList.Item>
);
};
@@ -0,0 +1,205 @@
import { useBackend } from 'tgui/backend';
import {
Button,
LabeledList,
Section,
Stack,
Tabs,
} from 'tgui-core/components';
import { type BooleanLike } from 'tgui-core/react';
import { messageTabLabel } from '../../constants';
import type { bellyDescriptionData } from '../../types';
import { VorePanelEditSwitch } from '../../VorePanelElements/VorePanelEditSwitch';
import { VorePanelEditTextArea } from '../../VorePanelElements/VorePanelTextArea';
export const VoreSelectedBellyDescriptionMatrix = (props: {
showAll: BooleanLike;
showFormatHelp: boolean;
onShowFormatHelp: React.Dispatch<React.SetStateAction<boolean>>;
editMode: boolean;
bellyDescriptionData: bellyDescriptionData;
}) => {
const { act } = useBackend();
const {
showAll,
showFormatHelp,
onShowFormatHelp,
editMode,
bellyDescriptionData,
} = props;
const {
displayed_options,
message_option,
message_subtab,
displayed_message_types,
selected_message,
} = bellyDescriptionData;
return (
<Section
title="Messages"
fill
buttons={
<Stack>
{editMode && (
<Stack.Item>
<Button
color="red"
onClick={() =>
act('set_attribute', {
attribute: 'b_msgs',
msgtype: 'reset',
})
}
>
Reset Messages
</Button>
</Stack.Item>
)}
<Stack.Item>
<Button
tooltip={
(showAll ? 'Hides' : 'Shows') + ' all possible belly messages.'
}
onClick={() =>
act('set_attribute', {
attribute: 'b_message_mode',
})
}
icon={'eye'}
selected={showAll}
/>
</Stack.Item>
<Stack.Item>
<Button
icon="question"
tooltip="Formatting help"
onClick={() => onShowFormatHelp(!showFormatHelp)}
selected={showFormatHelp}
/>
</Stack.Item>
</Stack>
}
>
<Stack fill>
<Stack.Item basis="16%">
<Stack vertical>
<Stack.Item basis="1.667rem" />
<Stack.Item>
<Tabs vertical>
{displayed_options.map((index) => (
<Tabs.Tab
key={index}
selected={index === message_option}
onClick={() => {
if (index !== message_option) {
act('change_message_option', { tab: index });
}
}}
>
{messageTabLabel[index]}
</Tabs.Tab>
))}
</Tabs>
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item grow>
<Stack fill vertical ml="5px">
<Stack.Item>
<Stack>
<Stack.Item>
{!!displayed_message_types &&
!!displayed_message_types.subtypes && (
<Tabs>
{displayed_message_types.subtypes.map((subtype) => (
<Tabs.Tab
key={subtype}
selected={subtype === message_subtab}
onClick={() => {
if (subtype !== message_subtab) {
act('change_message_type', { tab: subtype });
}
}}
>
{subtype}
</Tabs.Tab>
))}
</Tabs>
)}
</Stack.Item>
<Stack.Item grow />
<Stack.Item>
{!!displayed_message_types &&
!!displayed_message_types.possible_messages && (
<Tabs>
{displayed_message_types.possible_messages.map(
(message_tyxpe) => (
<Tabs.Tab
key={message_tyxpe}
selected={message_tyxpe === selected_message}
onClick={() => {
if (message_tyxpe !== selected_message) {
act('set_current_message', {
tab: message_tyxpe,
});
}
}}
>
{message_tyxpe}
</Tabs.Tab>
),
)}
</Tabs>
)}
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item grow>
{!!selected_message && !!displayed_message_types && (
<Stack vertical fill>
{!!displayed_message_types.button_action && (
<Stack.Item>
<LabeledList>
<LabeledList.Item
label={displayed_message_types.button_label}
>
<VorePanelEditSwitch
action="set_attribute"
subAction={displayed_message_types.button_action}
editMode={editMode}
active={!!displayed_message_types.button_data}
tooltip={
(displayed_message_types.button_data
? 'Dis'
: 'En') +
'ables ' +
displayed_message_types.button_tooltip
}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
)}
<Stack.Item grow>
<VorePanelEditTextArea
editMode={editMode}
tooltip={displayed_message_types.tooltip}
limit={displayed_message_types.max_length}
entry={displayed_message_types.active_message || ''}
action={'set_attribute'}
listAction={'b_msgs'}
subAction={displayed_message_types.set_action}
/>
</Stack.Item>
</Stack>
)}
</Stack.Item>
</Stack>
</Stack.Item>
</Stack>
</Section>
);
};
@@ -0,0 +1,151 @@
import { LabeledList, Section, Stack } from 'tgui-core/components';
import { capitalize } from 'tgui-core/string';
import type { autoTransferOption, DropdownEntry } from '../../types';
import { VorePanelEditCheckboxes } from '../../VorePanelElements/VorePanelEditCheckboxes';
import { VorePanelEditDropdown } from '../../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditNumber } from '../../VorePanelElements/VorePanelEditNumber';
export const AutoTransferOptions = (props: {
editMode: boolean;
title: string;
bellyDropdownNames: DropdownEntry[];
locationNames: DropdownEntry[];
autotransferData: autoTransferOption;
}) => {
const {
editMode,
title,
bellyDropdownNames,
locationNames,
autotransferData,
} = props;
const {
autotransferchance,
autotransferlocation,
autotransferextralocation,
autotransfer_whitelist,
autotransfer_blacklist,
autotransfer_whitelist_items,
autotransfer_blacklist_items,
} = autotransferData;
const transferCheckboxes = bellyDropdownNames.map((entry) => {
return {
label: entry.displayText,
ref: entry.value,
selection: autotransferextralocation.includes(entry.displayText),
};
});
return (
<Section title={capitalize(title) + ' Auto-Transfer'}>
<Stack vertical fill>
<Stack.Item>
<Stack>
<Stack.Item basis="49%" grow>
<LabeledList.Item label="Auto-Transfer Chance">
<VorePanelEditNumber
action="set_attribute"
subAction={'b_autotransferchance_' + title}
editMode={editMode}
value={autotransferchance}
unit="%"
minValue={0}
maxValue={100}
tooltip={
'Set ' +
title +
' belly auto-transfer chance. You must also set the location for this to have any effect.'
}
/>
</LabeledList.Item>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList.Item label="Auto-Transfer Location">
<VorePanelEditDropdown
action="set_attribute"
subAction={'b_autotransferlocation_' + title}
editMode={editMode}
options={locationNames}
color={!editMode && !autotransferlocation ? 'red' : undefined}
entry={
autotransferlocation ? autotransferlocation : 'Disabled'
}
tooltip={
'Target location of the ' + title + ' auto-transfer.'
}
/>
</LabeledList.Item>
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item>
<LabeledList>
<LabeledList.Item label="Auto-Transfer Extra Location">
<VorePanelEditCheckboxes
editMode={editMode}
options={transferCheckboxes}
action="set_attribute"
subAction={'b_autotransferextralocation_' + title}
tooltip={'Set additional ' + title + ' transfer locations.'}
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Whitelist (Mobs)">
<VorePanelEditCheckboxes
editMode={editMode}
options={autotransfer_whitelist}
action="set_attribute"
subAction={'b_autotransfer_whitelist_' + title}
tooltip={
'Whitelist mob types for your ' +
title +
' transfer location.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Whitelist (Items)">
<VorePanelEditCheckboxes
editMode={editMode}
options={autotransfer_whitelist_items}
action="set_attribute"
subAction={'b_autotransfer_whitelist_items_' + title}
tooltip={
'Whitelist item types for your ' +
title +
' transfer location.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Primary Blacklist (Mobs)">
<VorePanelEditCheckboxes
editMode={editMode}
options={autotransfer_blacklist}
action="set_attribute"
subAction={'b_autotransfer_blacklist_' + title}
tooltip={
'Blacklist mob types for your ' +
title +
' transfer location.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Primary Blacklist (Items)">
<VorePanelEditCheckboxes
editMode={editMode}
options={autotransfer_blacklist_items}
action="set_attribute"
subAction={'b_autotransfer_blacklist_items_' + title}
tooltip={
'Blacklist item types for your ' +
title +
' transfer location.'
}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
</Stack>
</Section>
);
};
@@ -0,0 +1,220 @@
import { Box, LabeledList, Stack } from 'tgui-core/components';
import { reagentToColor } from '../../constants';
import type { liqInteractData } from '../../types';
import { VorePanelEditColor } from '../../VorePanelElements/VorePanelEditColor';
import { VorePanelEditDropdown } from '../../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditNumber } from '../../VorePanelElements/VorePanelEditNumber';
import { VorePanelEditSwitch } from '../../VorePanelElements/VorePanelEditSwitch';
import { VorePanelEditText } from '../../VorePanelElements/VorePanelEditText';
export const LiquidOptionsLeft = (props: {
editMode: boolean;
liquidInteract: liqInteractData;
}) => {
const { editMode, liquidInteract } = props;
const {
liq_reagent_gen,
liq_reagent_type,
liq_reagent_types,
liq_custom_name_max,
liq_custom_name_min,
liq_reagent_name,
liq_sloshing,
custom_reagentcolor,
custom_reagentalpha,
liquid_overlay,
mush_overlay,
mush_color,
mush_alpha,
min_mush,
metabolism_overlay,
metabolism_mush_ratio,
custom_ingested_color,
custom_ingested_alpha,
} = liquidInteract;
return (
<LabeledList>
<LabeledList.Item label="Generate Liquids">
<VorePanelEditSwitch
action="liq_set_attribute"
subAction="b_liq_reagent_gen"
editMode={editMode}
active={!!liq_reagent_gen}
content={liq_reagent_gen ? 'On' : 'Off'}
tooltip={
(liq_reagent_gen ? 'Dis' : 'En') +
'ables reagent creation for this belly.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Liquid Type">
<VorePanelEditDropdown
action="liq_set_attribute"
subAction="b_liq_reagent_type"
color={reagentToColor[liq_reagent_type]}
editMode={editMode}
options={liq_reagent_types}
entry={liq_reagent_type}
tooltip="Select the reagent to produce."
/>
</LabeledList.Item>
<LabeledList.Item label="Liquid Name">
<VorePanelEditText
action="liq_set_attribute"
subAction="b_liq_reagent_name"
editMode={editMode}
limit={liq_custom_name_max}
min={liq_custom_name_min}
entry={liq_reagent_name}
tooltip={
"New name for liquid shown when transfering and dumping on floor (The actual liquid's name is still the same) [" +
liq_custom_name_min +
'-' +
liq_custom_name_max +
' characters].'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Slosh Sounds">
<VorePanelEditSwitch
action="liq_set_attribute"
subAction="b_liq_sloshing"
editMode={editMode}
active={!!liq_sloshing}
content={liq_sloshing ? 'On' : 'Off'}
tooltip="Should this belly be considered for sloshing sounds when full?."
/>
</LabeledList.Item>
<LabeledList.Item label="Liquid Overlay">
<Stack align="center">
<Stack.Item>
<VorePanelEditSwitch
action="liq_set_attribute"
subAction="b_liquid_overlay"
editMode={editMode}
active={!!liquid_overlay}
content={liquid_overlay ? 'On' : 'Off'}
tooltip="Should this belly display liquid overlays to prey?."
/>
</Stack.Item>
<VorePanelEditColor
removePlaceholder
editMode={editMode}
action="liq_set_attribute"
subAction="b_custom_reagentcolor"
value_of={null}
back_color={custom_reagentcolor}
tooltip="Select your reagent overlay color."
/>
<VorePanelEditColor
removePlaceholder
editMode={editMode}
action="liq_set_attribute"
subAction="b_custom_reagentalpha"
value_of={null}
back_color="#FFFFFF"
alpha={custom_reagentalpha || 0}
tooltip="Set your reagent overlay transparency. 0 to use the Default."
/>
{!custom_reagentalpha && (
<Stack.Item>
<Box color="label">(Default)</Box>
</Stack.Item>
)}
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Fullness Overlay">
<Stack align="center">
<Stack.Item>
<VorePanelEditSwitch
action="liq_set_attribute"
subAction="b_mush_overlay"
editMode={editMode}
active={!!mush_overlay}
content={mush_overlay ? 'On' : 'Off'}
tooltip="Should this belly display mush overlays to prey?."
/>
</Stack.Item>
<VorePanelEditColor
removePlaceholder
editMode={editMode}
action="liq_set_attribute"
subAction="b_mush_color"
value_of={null}
back_color={mush_color}
tooltip="Select your mush overlay color."
/>
<VorePanelEditColor
removePlaceholder
editMode={editMode}
action="liq_set_attribute"
subAction="b_mush_alpha"
value_of={null}
back_color="#FFFFFF"
alpha={mush_alpha}
tooltip="Set your mush overlay transparency."
/>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Minimum Mush Level">
<VorePanelEditNumber
action="liq_set_attribute"
subAction="b_min_mush"
editMode={editMode}
value={min_mush}
unit="%"
minValue={0}
maxValue={100}
tooltip="Set custom minimum mush level."
/>
</LabeledList.Item>
<LabeledList.Item label="Metabolism Overlay">
<Stack align="center">
<Stack.Item>
<VorePanelEditSwitch
action="liq_set_attribute"
subAction="b_metabolism_overlay"
editMode={editMode}
active={!!metabolism_overlay}
content={metabolism_overlay ? 'On' : 'Off'}
tooltip="Should this belly display metabolism overlays to prey?."
/>
</Stack.Item>
<VorePanelEditColor
removePlaceholder
editMode={editMode}
action="liq_set_attribute"
subAction="b_custom_ingested_color"
value_of={null}
back_color={custom_ingested_color}
tooltip="Select your metabolism overlay color."
/>
<VorePanelEditColor
removePlaceholder
editMode={editMode}
action="liq_set_attribute"
subAction="b_custom_ingested_alpha"
value_of={null}
back_color="#FFFFFF"
alpha={custom_ingested_alpha}
tooltip="Set your metabolism overlay transparency."
/>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Metabolism Mush Ratio">
<VorePanelEditNumber
action="liq_set_attribute"
subAction="b_metabolism_mush_ratio"
editMode={editMode}
value={metabolism_mush_ratio}
unit="fullness per u"
minValue={0}
maxValue={500}
tooltip="How much should ingested reagents affect fullness overlay compared to nutrition? Nutrition units per reagent unit. Default 15."
/>
</LabeledList.Item>
</LabeledList>
);
};
@@ -0,0 +1,129 @@
import { LabeledList } from 'tgui-core/components';
import { nutriTimeToText } from '../../constants';
import type { liqInteractData } from '../../types';
import { VorePanelEditDropdown } from '../../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditNumber } from '../../VorePanelElements/VorePanelEditNumber';
import { VorePanelEditSwitch } from '../../VorePanelElements/VorePanelEditSwitch';
import { VorePanelEditText } from '../../VorePanelElements/VorePanelEditText';
export const LiquidOptionsRight = (props: {
editMode: boolean;
liquidInteract: liqInteractData;
}) => {
const { editMode, liquidInteract } = props;
const {
liq_reagent_transfer_verb,
liq_reagent_nutri_rate,
liq_reagent_capacity,
liq_custom_name_max,
liq_custom_name_min,
max_liquid_level,
reagent_touches,
max_mush,
item_mush_val,
max_ingested,
} = liquidInteract;
return (
<LabeledList>
<LabeledList.Item label="Liquid Capacity">
<VorePanelEditNumber
action="liq_set_attribute"
subAction="b_liq_reagent_capacity"
editMode={editMode}
value={liq_reagent_capacity}
minValue={10}
maxValue={300}
unit="u"
tooltip="Choose the amount of liquid the belly can contain at most. Ranges from 10 to 300."
/>
</LabeledList.Item>
<LabeledList.Item label="Generation Time">
<VorePanelEditDropdown
action="liq_set_attribute"
subAction="b_liq_reagent_nutri_rate"
editMode={editMode}
options={Object.values(nutriTimeToText)}
entry={nutriTimeToText[liq_reagent_nutri_rate]}
tooltip="Choose the time it takes to fill the belly from empty state using nutrition."
/>
</LabeledList.Item>
<LabeledList.Item label="Transfer Verb">
<VorePanelEditText
action="liq_set_attribute"
subAction="b_liq_reagent_transfer_verb"
editMode={editMode}
limit={liq_custom_name_max}
min={liq_custom_name_min}
entry={liq_reagent_transfer_verb}
tooltip={
'Adjust vore liquid verb. [' +
liq_custom_name_min +
'-' +
liq_reagent_transfer_verb +
' characters].'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Liquid Application to Prey">
<VorePanelEditSwitch
action="liq_set_attribute"
subAction="b_reagent_touches"
editMode={editMode}
active={!!reagent_touches}
content={reagent_touches ? 'On' : 'Off'}
tooltip="Should liquids be applied to the prey during digestion?."
/>
</LabeledList.Item>
<LabeledList.Item label="Max Liquid Level">
<VorePanelEditNumber
action="liq_set_attribute"
subAction="b_max_liquid_level"
editMode={editMode}
value={max_liquid_level}
unit="%"
minValue={0}
maxValue={100}
tooltip="The overlay coverage of the screen."
/>
</LabeledList.Item>
<LabeledList.Item label="Mush Overlay Scaling">
<VorePanelEditNumber
action="liq_set_attribute"
subAction="b_max_mush"
editMode={editMode}
value={max_mush}
unit="nutrition"
minValue={0}
maxValue={6000}
tooltip="Choose the amount of nutrition required for full mush overlay. Ranges from 0 to 6000. Default 500."
/>
</LabeledList.Item>
<LabeledList.Item label="Item Mush Value">
<VorePanelEditNumber
action="liq_set_attribute"
subAction="b_item_mush_val"
editMode={editMode}
value={item_mush_val}
unit="fullness per item"
minValue={0}
maxValue={1000}
tooltip="Set how much solid belly contents affect mush level per item."
/>
</LabeledList.Item>
<LabeledList.Item label="Metabolism Overlay Scaling">
<VorePanelEditNumber
action="liq_set_attribute"
subAction="b_max_ingested"
editMode={editMode}
value={max_ingested}
unit="u"
minValue={0}
maxValue={6000}
tooltip="Choose the amount of reagents within ingested metabolism required for full mush overlay when not using mush overlay option. Ranges from 0 to 6000. Default 500."
/>
</LabeledList.Item>
</LabeledList>
);
};
@@ -0,0 +1,195 @@
import { LabeledList, Stack } from 'tgui-core/components';
import { eatingMessagePrivacy } from '../../constants';
import { sanitize_color } from '../../functions';
import type { bellyOptionData, hostMob } from '../../types';
import { VorePanelColorBox } from '../../VorePanelElements/VorePanelCommonElements';
import { VorePanelEditDropdown } from '../../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditNumber } from '../../VorePanelElements/VorePanelEditNumber';
import { VorePanelEditSwitch } from '../../VorePanelElements/VorePanelEditSwitch';
import { VoreSelectedWhitelist } from '../VisualTab/VoreSelecetedWhitelist';
import { VoreSelectedMobTypeBellyButtons } from '../VisualTab/VoreSelectedMobTypeBellyButtons';
export const BellyOptionsLeft = (props: {
editMode: boolean;
bellyOptionData: bellyOptionData;
host_mobtype: hostMob;
}) => {
const { editMode, bellyOptionData, host_mobtype } = props;
const {
can_taste,
is_feedable,
nutrition_percent,
bulge_size,
contaminates,
contaminate_flavor,
contaminate_color,
contaminate_options,
contaminate_colors,
save_digest_mode,
eating_privacy_local,
private_struggle,
mob_belly_controls,
vorespawn_blacklist,
vorespawn_whitelist,
vorespawn_absorbed,
} = bellyOptionData;
return (
<>
<LabeledList>
<LabeledList.Item label="Can Taste">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_tastes"
editMode={editMode}
active={!!can_taste}
content={can_taste ? 'Yes' : 'No'}
tooltip={
(can_taste ? 'Dis' : 'En') +
'ables the ability for this belly to taste prey.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Feedable">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_feedable"
editMode={editMode}
active={!!is_feedable}
content={is_feedable ? 'Yes' : 'No'}
tooltip={
(is_feedable ? 'Dis' : 'En') +
'ables the ability for this belly to have prey fed to.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Contaminates">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_contaminates"
editMode={editMode}
active={!!contaminates}
content={contaminates ? 'Yes' : 'No'}
tooltip={
(contaminates ? 'Dis' : 'En') +
'ables the ability for this belly to contaminate items, requiring them to be washed clean.'
}
/>
</LabeledList.Item>
{!!contaminates && (
<>
<LabeledList.Item label="Contamination Flavor">
<VorePanelEditDropdown
editMode={editMode}
options={
contaminate_options ? Object.keys(contaminate_options) : []
}
entry={contaminate_flavor ? contaminate_flavor : ''}
action="set_attribute"
subAction="b_contamination_flavor"
tooltip="The flavour of your item contamination."
/>
</LabeledList.Item>
<LabeledList.Item label="Contamination Color">
<Stack>
<Stack.Item>
<VorePanelEditDropdown
editMode={editMode}
options={contaminate_colors ? contaminate_colors : []}
entry={contaminate_color ? contaminate_color : ''}
action="set_attribute"
subAction="b_contamination_color"
tooltip="The color overlay of your item contamination."
/>
</Stack.Item>
{!editMode && (
<Stack.Item>
<VorePanelColorBox
pixelSize={15}
back_color={sanitize_color(contaminate_color) || 'white'}
/>
</Stack.Item>
)}
</Stack>
</LabeledList.Item>
</>
)}
<LabeledList.Item label="Nutritional Gain">
<VorePanelEditNumber
action="set_attribute"
subAction="b_nutritionpercent"
editMode={editMode}
value={nutrition_percent}
minValue={0.01}
maxValue={100}
step={0.01}
stepPixel={0.1}
digits={2}
unit="%"
tooltip="The multiplier for nutrition you'll fain from prey."
/>
</LabeledList.Item>
<LabeledList.Item label="Required Examine Size">
<VorePanelEditNumber
action="set_attribute"
subAction="b_bulge_size"
editMode={editMode}
value={bulge_size * 100}
minValue={0}
maxValue={200}
unit="%"
tooltip="The minimum size for prey to show in examine. Type 0 to disable."
/>
</LabeledList.Item>
<LabeledList.Item label="Toggle Vore Privacy">
<VorePanelEditDropdown
editMode={editMode}
options={Object.keys(eatingMessagePrivacy)}
entry={eating_privacy_local}
action="set_attribute"
subAction="b_eating_privacy"
color={eatingMessagePrivacy[eating_privacy_local]}
tooltip="Allows to override the global audible range of your attempt and success messages for this belly."
/>
</LabeledList.Item>
<LabeledList.Item label="Toggle Struggle Privacy">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_private_struggle"
editMode={editMode}
active={!!private_struggle}
content={private_struggle ? 'Private' : 'Loud'}
tooltip={
(private_struggle ? 'Dis' : 'En') +
'ables subtle struggle messages.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Save Digest Mode">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_save_digest_mode"
editMode={editMode}
active={!!save_digest_mode}
tooltip={
(save_digest_mode ? 'Dis' : 'En') +
'ables persistent digest mode.'
}
/>
</LabeledList.Item>
</LabeledList>
<VoreSelectedMobTypeBellyButtons
editMode={editMode}
bellyControl={mob_belly_controls}
host_mobtype={host_mobtype}
/>
<VoreSelectedWhitelist
editMode={editMode}
vorespawnBlacklist={vorespawn_blacklist}
vorespawnWhitelist={vorespawn_whitelist}
vorespawnAbsorbed={vorespawn_absorbed}
/>
</>
);
};
@@ -0,0 +1,236 @@
import { LabeledList } from 'tgui-core/components';
import { digestModeToColor, selectiveBellyOptions } from '../../constants';
import type { bellyOptionData } from '../../types';
import { VorePanelEditDropdown } from '../../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditNumber } from '../../VorePanelElements/VorePanelEditNumber';
import { VorePanelEditSwitch } from '../../VorePanelElements/VorePanelEditSwitch';
import { VorePanelEditText } from '../../VorePanelElements/VorePanelEditText';
export const BellyOptionsRight = (props: {
editMode: boolean;
bellyOptionData: bellyOptionData;
}) => {
const { editMode, bellyOptionData } = props;
const {
digest_brute,
digest_burn,
digest_oxy,
digest_tox,
digest_clone,
digest_max,
digest_free,
shrink_grow_size,
egg_type,
egg_types,
egg_name,
egg_size,
recycling,
storing_nutrition,
selective_preference,
drainmode_options,
drainmode,
} = bellyOptionData;
return (
<LabeledList>
<LabeledList.Item label="Digest Brute Damage">
<VorePanelEditNumber
tooltip={
'Choose the amount of brute damage prey will take per tick. Max of ' +
digest_max +
' across all damage types. ' +
digest_free +
' remaining.'
}
action="set_attribute"
subAction="b_brute_dmg"
editMode={editMode}
value={digest_brute}
minValue={0}
step={0.001}
stepPixel={0.1}
digits={3}
maxValue={digest_free + digest_brute}
color="red"
/>
</LabeledList.Item>
<LabeledList.Item label="Digest Burn Damage">
<VorePanelEditNumber
tooltip={
'Choose the amount of burn damage prey will take per tick. Max of ' +
digest_max +
' across all damage types. ' +
digest_free +
' remaining.'
}
action="set_attribute"
subAction="b_burn_dmg"
editMode={editMode}
value={digest_burn}
minValue={0}
step={0.001}
stepPixel={0.1}
digits={3}
maxValue={digest_free + digest_burn}
color="orange"
/>
</LabeledList.Item>
<LabeledList.Item label="Digest Suffocation Damage">
<VorePanelEditNumber
tooltip={
'Choose the amount of oxygen damage prey will take per tick. Max of ' +
digest_max +
' across all damage types. ' +
digest_free +
' remaining.'
}
action="set_attribute"
subAction="b_oxy_dmg"
editMode={editMode}
value={digest_oxy}
minValue={0}
step={0.001}
stepPixel={0.1}
digits={3}
maxValue={digest_free + digest_oxy}
color="blue"
/>
</LabeledList.Item>
<LabeledList.Item label="Digest Toxins Damage">
<VorePanelEditNumber
tooltip={
'Choose the amount of toxin damage prey will take per tick. Max of ' +
digest_max +
' across all damage types. ' +
digest_free +
' remaining.'
}
action="set_attribute"
subAction="b_tox_dmg"
editMode={editMode}
value={digest_tox}
minValue={0}
step={0.001}
stepPixel={0.1}
digits={3}
maxValue={digest_free + digest_tox}
color="green"
/>
</LabeledList.Item>
<LabeledList.Item label="Digest Clone Damage">
<VorePanelEditNumber
tooltip={
'Choose the amount of genetic (clone) damage prey will take per tick. Max of ' +
digest_max +
' across all damage types. ' +
digest_free +
' remaining.'
}
action="set_attribute"
subAction="b_clone_dmg"
editMode={editMode}
value={digest_clone}
minValue={0}
step={0.001}
stepPixel={0.1}
digits={3}
maxValue={digest_free + digest_clone}
color="purple"
/>
</LabeledList.Item>
<LabeledList.Item label="Drain Finishing Mode">
<VorePanelEditDropdown
action="set_attribute"
subAction="b_drainmode"
editMode={editMode}
options={drainmode_options}
entry={drainmode}
tooltip="Event trigger once prey is fully drained of nutrition."
/>
</LabeledList.Item>
<LabeledList.Item label="Shrink/Grow Size">
<VorePanelEditNumber
tooltip="Choose the size that prey will be grown/shrunk to, ranging from 25% to 200%"
action="set_attribute"
subAction="b_grow_shrink"
editMode={editMode}
value={shrink_grow_size * 100}
minValue={25}
maxValue={200}
unit="%"
/>
</LabeledList.Item>
<LabeledList.Item label="Egg Type">
<VorePanelEditDropdown
tooltip="Select the displayed egg type when you encase prey in one."
action="set_attribute"
subAction="b_egg_type"
editMode={editMode}
options={egg_types}
entry={egg_type}
/>
</LabeledList.Item>
<LabeledList.Item label="Custom Egg Name">
<VorePanelEditText
action="set_attribute"
subAction="b_egg_name"
editMode={editMode}
limit={0}
entry={editMode ? egg_name : egg_name ? egg_name : 'Default'}
/>
</LabeledList.Item>
<LabeledList.Item label="Custom Egg Size">
{!egg_size && !editMode ? (
'Automatic'
) : (
<VorePanelEditNumber
tooltip="Custom Egg Size 25% to 200% (0 for automatic item depending egg size from 25% to 200%)"
action="set_attribute"
subAction="b_egg_size"
editMode={editMode}
value={egg_size * 100}
minValue={0}
maxValue={200}
unit="%"
/>
)}
</LabeledList.Item>
<LabeledList.Item label="Recycling">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_recycling"
editMode={editMode}
tooltip="Allows you to recycle items into small amounts of resources during digestion."
active={!!recycling}
/>
</LabeledList.Item>
<LabeledList.Item label="Storing Nutrition">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_storing_nutrition"
editMode={editMode}
content={storing_nutrition ? 'Storing' : 'Absorbing'}
active={!!storing_nutrition}
tooltip={
'Toggle nutirion ' +
(storing_nutrition ? 'storing' : 'absorbing') +
'. Currently nutrition will be ' +
(storing_nutrition ? 'stored as items' : 'absorbed') +
'.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Selective Mode Preference">
<VorePanelEditDropdown
action="set_attribute"
subAction="b_selective_mode_pref_toggle"
editMode={editMode}
options={selectiveBellyOptions}
entry={selective_preference}
color={digestModeToColor[selective_preference]}
/>
</LabeledList.Item>
</LabeledList>
);
};
@@ -0,0 +1,78 @@
import { useBackend } from 'tgui/backend';
import { Box, Button, Section, Stack } from 'tgui-core/components';
import { type BooleanLike, classes } from 'tgui-core/react';
export const BellyFullscreenSelection = (props: {
editMode: boolean;
belly_fullscreen: string;
colorization_enabled: BooleanLike;
possible_fullscreens: string[];
}) => {
const { act } = useBackend();
const {
editMode,
belly_fullscreen,
colorization_enabled,
possible_fullscreens,
} = props;
return editMode ? (
<Section title="Belly Fullscreens Styles">
<Stack wrap="wrap" justify="center">
<Stack.Item basis="100%">
<Button
fluid
selected={belly_fullscreen === '' || belly_fullscreen === null}
onClick={() =>
act('set_attribute', { attribute: 'b_fullscreen', val: null })
}
>
Disabled
</Button>
</Stack.Item>
{Object.keys(possible_fullscreens).map((key, index) => (
<Stack.Item key={index} basis="32%">
<Button
width="256px"
height="256px"
selected={key === belly_fullscreen}
onClick={() =>
act('set_attribute', { attribute: 'b_fullscreen', val: key })
}
>
<Box
className={classes([
colorization_enabled ? 'vore240x240' : 'fixedvore240x240',
key,
])}
style={{
transform: 'translate(0%, 4%)',
}}
/>
</Button>
</Stack.Item>
))}
</Stack>
</Section>
) : (
<Section fill title="Belly Fullscreen">
<Stack align="center">
<Stack.Item grow />
<Stack.Item>
{belly_fullscreen ? (
<Box
className={classes([
colorization_enabled ? 'vore240x240' : 'fixedvore240x240',
belly_fullscreen,
])}
/>
) : (
<Box>No overlay selected.</Box>
)}
</Stack.Item>
<Stack.Item grow />
</Stack>
</Section>
);
};
@@ -0,0 +1,74 @@
import { Divider, LabeledList, Section } from 'tgui-core/components';
import { type BooleanLike } from 'tgui-core/react';
import { vorespawnAbsorbedColor, vorespawnAbsorbedText } from '../../constants';
import { VorePanelEditDropdown } from '../../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditSwitch } from '../../VorePanelElements/VorePanelEditSwitch';
import { VorePanelEditTextArea } from '../../VorePanelElements/VorePanelTextArea';
export const VoreSelectedWhitelist = (props: {
editMode: boolean;
vorespawnBlacklist: BooleanLike;
vorespawnWhitelist: string[];
vorespawnAbsorbed: number;
}) => {
const {
editMode,
vorespawnBlacklist,
vorespawnWhitelist,
vorespawnAbsorbed,
} = props;
const ourEntry = editMode
? (vorespawnWhitelist.length && vorespawnWhitelist.join(', ')) || ''
: vorespawnWhitelist.length
? vorespawnWhitelist.join(', ')
: 'Anyone!';
return (
<Section
title="Vore Spawn"
buttons={
<VorePanelEditSwitch
action="set_attribute"
subAction="b_vorespawn_blacklist"
editMode={editMode}
active={!vorespawnBlacklist}
content={vorespawnBlacklist ? 'Hide' : 'Show'}
tooltip={
(vorespawnBlacklist ? 'Hide' : 'Show') +
" this belly from potential prey's spawn selection list."
}
/>
}
width={'80%'}
>
{!vorespawnBlacklist && (
<>
<LabeledList>
<LabeledList.Item label="Vore Spawn Absorbed">
<VorePanelEditDropdown
action="set_attribute"
subAction="b_vorespawn_absorbed"
editMode={editMode}
color={vorespawnAbsorbedColor[vorespawnAbsorbed]}
options={vorespawnAbsorbedText}
entry={vorespawnAbsorbedText[vorespawnAbsorbed]}
/>
</LabeledList.Item>
</LabeledList>
<Divider />
<VorePanelEditTextArea
disableLegacyInput
tooltip="Input vore spawn allowed ckeys. Empty means anyone can spawn."
editMode={editMode}
limit={4096}
entry={ourEntry}
action="set_attribute"
subAction="b_vorespawn_whitelist"
/>
</>
)}
</Section>
);
};
@@ -1,20 +1,20 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Section } from 'tgui-core/components';
import { capitalize } from 'tgui-core/string';
import { Box, LabeledList, Section } from 'tgui-core/components';
import type { hostMob, selectedData } from '../types';
import { robotBellyOptions } from '../../constants';
import type { hostMob, siliconeBellyControls } from '../../types';
import { VorePanelEditDropdown } from '../../VorePanelElements/VorePanelEditDropdown';
export const VoreSelectedMobTypeBellyButtons = (props: {
belly: selectedData;
editMode: boolean;
bellyControl: siliconeBellyControls;
host_mobtype: hostMob;
}) => {
const { act } = useBackend();
const { belly, host_mobtype } = props;
const { editMode, bellyControl, host_mobtype } = props;
const {
silicon_belly_overlay_preference,
belly_sprite_option_shown,
belly_sprite_to_affect,
} = belly;
} = bellyControl;
const { is_cyborg, is_vore_simple_mob } = host_mobtype;
@@ -24,13 +24,14 @@ export const VoreSelectedMobTypeBellyButtons = (props: {
<Section title={'Cyborg Controls'} width={'80%'}>
<LabeledList>
<LabeledList.Item label="Toggle Belly Overlay Mode">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_silicon_belly' })
}
>
{capitalize(silicon_belly_overlay_preference)}
</Button>
<VorePanelEditDropdown
tooltip="Choose whether you'd like your belly overlay to show from sleepers, normal vore bellies, or an average of the two. NOTE: This ONLY applies to silicons, not human mobs!"
action="set_attribute"
subAction="b_silicon_belly"
editMode={editMode}
options={robotBellyOptions}
entry={silicon_belly_overlay_preference}
/>
</LabeledList.Item>
</LabeledList>
</Section>
@@ -38,11 +39,11 @@ export const VoreSelectedMobTypeBellyButtons = (props: {
} else {
return (
<Section title={'Cyborg Controls'} width={'80%'}>
<span style={{ color: 'red' }}>
<Box color="red">
Your module does either not support vore sprites or you&apos;ve
selected a belly sprite other than the sleeper within the Visuals
section.
</span>
</Box>
</Section>
);
}
@@ -0,0 +1,247 @@
import { Box, LabeledList, Stack } from 'tgui-core/components';
import { spriteToTooltip } from '../../constants';
import type { bellyVisualData } from '../../types';
import { VorePanelEditCheckboxes } from '../../VorePanelElements/VorePanelEditCheckboxes';
import { VorePanelEditColor } from '../../VorePanelElements/VorePanelEditColor';
import { VorePanelEditDropdown } from '../../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditNumber } from '../../VorePanelElements/VorePanelEditNumber';
import { VorePanelEditSwitch } from '../../VorePanelElements/VorePanelEditSwitch';
export const VoreSpriteAffects = (props: {
editMode: boolean;
bellyVisualData: bellyVisualData;
}) => {
const { editMode, bellyVisualData } = props;
const {
vore_sprite_flags,
absorbed_voresprite,
absorbed_multiplier,
liquid_voresprite,
liquid_multiplier,
item_voresprite,
item_multiplier,
health_voresprite,
resist_animation,
voresprite_size_factor,
belly_sprite_to_affect,
belly_sprite_options,
undergarment_chosen,
undergarment_if_none,
undergarment_options,
undergarment_options_if_none,
undergarment_color,
tail_option_shown,
tail_to_change_to,
tail_sprite_options,
} = bellyVisualData;
return (
<Stack vertical>
<Stack.Item>
<LabeledList>
<LabeledList.Item label="Vore Sprite Mode">
<VorePanelEditCheckboxes
editMode={editMode}
options={vore_sprite_flags}
action="set_attribute"
subAction="b_vore_sprite_flags"
tooltipList={spriteToTooltip}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
<Stack.Item>
<Stack>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Count Absorbed prey for vore sprites">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_count_absorbed_prey_for_sprites"
editMode={editMode}
tooltip="Allows you to toggle if absorbed prey accounts for the vore sprite size."
content={absorbed_voresprite ? 'Yes' : 'No'}
active={!!absorbed_voresprite}
/>
</LabeledList.Item>
<LabeledList.Item label="Count liquid reagents for vore sprites">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_count_liquid_for_sprites"
editMode={editMode}
tooltip="Allows you to toggle if belly liquids account for the vore sprite size."
content={liquid_voresprite ? 'Yes' : 'No'}
active={!!liquid_voresprite}
/>
</LabeledList.Item>
<LabeledList.Item label="Count items for vore sprites">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_count_items_for_sprites"
editMode={editMode}
tooltip="Allows you to toggle if ingested items account for the vore sprite size."
content={item_voresprite ? 'Yes' : 'No'}
active={!!item_voresprite}
/>
</LabeledList.Item>
<LabeledList.Item label="Prey health affects vore sprites">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_health_impacts_size"
editMode={editMode}
tooltip="Allows you to toggle if your prey's health is accounted for the vore sprite size. The lower the health, the less a prey will contribute."
content={health_voresprite ? 'Yes' : 'No'}
active={!!health_voresprite}
/>
</LabeledList.Item>
{belly_sprite_options?.length ? (
<LabeledList.Item label="Belly Sprite to affect">
<VorePanelEditDropdown
action="set_attribute"
subAction="b_belly_sprite_to_affect"
editMode={editMode}
options={belly_sprite_options}
entry={belly_sprite_to_affect}
tooltip="Set the belly sprite to effect."
/>
</LabeledList.Item>
) : (
<LabeledList.Item label="Belly Sprite to affect">
<Box textColor="red">You do not have any bellysprites.</Box>
</LabeledList.Item>
)}
{!!tail_option_shown &&
vore_sprite_flags
.map((flag) => flag.label)
.includes('Undergarment addition') && (
<>
<LabeledList.Item label="Undergarment type to affect">
<VorePanelEditDropdown
action="set_attribute"
subAction="b_undergarment_choice"
editMode={editMode}
options={undergarment_options}
entry={undergarment_chosen}
tooltip="Set the undergarment sprite to effect."
/>
</LabeledList.Item>
<LabeledList.Item label="Undergarment if none equipped">
<Stack align="center">
<Stack.Item>
<VorePanelEditDropdown
action="set_attribute"
subAction="b_undergarment_if_none"
editMode={editMode}
options={undergarment_options_if_none}
entry={undergarment_if_none}
tooltip="If no undergarment is equipped, which undergarment style do you want to use?"
/>
</Stack.Item>
<VorePanelEditColor
editMode={editMode}
action="liq_set_attribute"
subAction="b_undergarment_color"
value_of={null}
back_color={undergarment_color}
tooltip="Select your undergarment color."
/>
</Stack>
</LabeledList.Item>
</>
)}
{!!tail_option_shown &&
vore_sprite_flags
.map((flag) => flag.label)
.includes('Tail adjustment') && (
<LabeledList.Item label="Tail to change to">
<VorePanelEditDropdown
action="set_attribute"
subAction="b_tail_to_change_to"
editMode={editMode}
options={tail_sprite_options}
entry={
typeof tail_to_change_to === 'string'
? tail_to_change_to
: 'None'
}
tooltip="Set the tail sprite to effect."
/>
</LabeledList.Item>
)}
</LabeledList>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Absorbed Multiplier">
<VorePanelEditNumber
action="set_attribute"
subAction="b_absorbed_multiplier"
editMode={editMode}
value={absorbed_multiplier}
minValue={0.1}
maxValue={3}
step={0.1}
unit="x"
digits={1}
tooltip="Set the impact absorbed prey's size have on your vore sprite. 1 means no scaling, 0.5 means absorbed prey count half as much, 2 means absorbed prey count double. (Range from 0.1 - 3)"
/>
</LabeledList.Item>
<LabeledList.Item label="Liquid Multiplier">
<VorePanelEditNumber
action="set_attribute"
subAction="b_liquid_multiplier"
editMode={editMode}
value={liquid_multiplier}
minValue={0.1}
maxValue={10}
step={0.1}
unit="x"
digits={1}
tooltip="Set the impact amount of liquid reagents will have on your vore sprite. 1 means a belly with 100 reagents of fluid will count as 1 normal sized prey-thing's worth, 0.5 means liquid counts half as much, 2 means liquid counts double. (Range from 0.1 - 10)"
/>
</LabeledList.Item>
<LabeledList.Item label="Items Multiplier">
<VorePanelEditNumber
action="set_attribute"
subAction="b_item_multiplier"
editMode={editMode}
value={item_multiplier}
minValue={0.1}
maxValue={10}
step={0.1}
unit="x"
digits={1}
tooltip="Set the impact items will have on your vore sprite. 1 means a belly with 8 normal-sized items will count as 1 normal sized prey-thing's worth, 0.5 means items count half as much, 2 means items count double. (Range from 0.1 - 10)"
/>
</LabeledList.Item>
<LabeledList.Item label="Vore Sprite Size Factor">
<VorePanelEditNumber
action="set_attribute"
subAction="b_size_factor_sprites"
editMode={editMode}
value={voresprite_size_factor}
minValue={0.1}
maxValue={3}
step={0.1}
unit="x"
digits={1}
tooltip="Set the impact all belly content's collective size has on your vore sprite. 1 means no scaling, 0.5 means content counts half as much, 2 means contents count double. (Range from 0.1 - 3)"
/>
</LabeledList.Item>
<LabeledList.Item label="Animation when prey resist">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_resist_animation"
editMode={editMode}
tooltip="Allows you to toggle if prey resists trigger struggle animations if the sprite supports it."
active={!!resist_animation}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
</Stack>
</Stack.Item>
</Stack>
);
};
@@ -0,0 +1,158 @@
import { useBackend } from 'tgui/backend';
import {
Button,
Dropdown,
Image,
LabeledList,
Stack,
} from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { stats } from '../constants';
import type { contentData, DropdownEntry } from '../types';
export const VoreContentsPanel = (props: {
contents?: contentData[] | null;
targetBelly?: string;
onTargetBely?: React.Dispatch<React.SetStateAction<string>>;
bellyDropdownNames?: DropdownEntry[];
belly?: string;
outside?: BooleanLike;
show_pictures: BooleanLike;
icon_overflow: BooleanLike;
}) => {
const { act } = useBackend();
const {
contents = [],
targetBelly = '',
onTargetBely,
bellyDropdownNames,
belly,
outside = false,
show_pictures,
icon_overflow,
} = props;
function bellyValueToName(value: string) {
const bellyName = bellyDropdownNames
?.map((entry) => {
if (entry.value === value) {
return entry.displayText;
}
})
.filter((value) => value !== undefined);
if (Array.isArray(bellyName) && bellyName.length) {
return bellyName[0];
}
return '';
}
return (
<>
{!!outside && (
<Stack>
<Stack.Item grow>
<Button.Confirm
textAlign="center"
confirmContent="Confirm Eject All?"
fluid
mb={1}
onClick={() =>
act('pick_from_outside', { pickall: true, intent: 'eject_all' })
}
>
Eject All
</Button.Confirm>
</Stack.Item>
<Stack.Item grow>
<Button.Confirm
textAlign="center"
confirmContent="Confirm Move All?"
fluid
mb={1}
onClick={() =>
act('pick_from_outside', {
pickall: true,
intent: 'move_all',
val: targetBelly,
})
}
>
Move All
</Button.Confirm>
</Stack.Item>
{!!bellyDropdownNames && !!onTargetBely && (
<Stack.Item>
<Dropdown
onSelected={(value) => onTargetBely(value)}
options={bellyDropdownNames!}
selected={bellyValueToName(targetBelly)}
/>
</Stack.Item>
)}
</Stack>
)}
{(show_pictures && !icon_overflow && (
<Stack wrap="wrap" justify="center" align="center">
{contents?.map((thing) => (
<Stack.Item key={thing.ref} basis="32%">
<Button
width="64px"
color={thing.absorbed ? 'purple' : stats[thing.stat]}
style={{
verticalAlign: 'middle',
marginRight: '5px',
borderRadius: '20px',
}}
onClick={() =>
act(
thing.outside ? 'pick_from_outside' : 'pick_from_inside',
{
pick: thing.ref,
belly: belly,
},
)
}
>
<Image
src={'data:image/jpeg;base64, ' + thing.icon}
width="64px"
height="64px"
style={{
marginLeft: '-5px',
}}
/>
</Button>
{thing.name}
</Stack.Item>
))}
</Stack>
)) || (
<LabeledList>
{contents?.map((thing) => (
<LabeledList.Item key={thing.ref} label={thing.name}>
<Button
fluid
mt={-1}
mb={-1}
color={thing.absorbed ? 'purple' : stats[thing.stat]}
onClick={() =>
act(
thing.outside ? 'pick_from_outside' : 'pick_from_inside',
{
pick: thing.ref,
belly: belly,
},
)
}
>
Interact
</Button>
</LabeledList.Item>
))}
</LabeledList>
)}
</>
);
};
@@ -1,79 +1,133 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
import { digestModeToColor } from '../constants';
import type { selectedData } from '../types';
import { digestModeToColor, modeToTooltip } from '../constants';
import type { bellyModeData, DropdownEntry } from '../types';
import { VorePanelEditCheckboxes } from '../VorePanelElements/VorePanelEditCheckboxes';
import { VorePanelEditDropdown } from '../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditText } from '../VorePanelElements/VorePanelEditText';
export const VoreSelectedBellyControls = (props: { belly: selectedData }) => {
export const VoreSelectedBellyControls = (props: {
bellyDropdownNames: DropdownEntry[];
editMode: boolean;
belly_name: string;
bellyModeData: bellyModeData;
}) => {
const { act } = useBackend();
const { belly } = props;
const { belly_name, mode, item_mode, addons } = belly;
const { bellyDropdownNames, belly_name, bellyModeData, editMode } = props;
const {
mode,
item_mode,
addons,
name_length,
name_min,
mode_options,
item_mode_options,
} = bellyModeData;
const bellyNames = bellyDropdownNames.map((belly) => {
return belly.displayText;
});
return (
<LabeledList>
<LabeledList.Item
label="Name"
buttons={
<Stack>
<Stack.Item>
<Button
icon="arrow-up"
tooltipPosition="left"
tooltip="Move this belly tab up."
onClick={() => act('move_belly', { dir: -1 })}
/>
</Stack.Item>
<Stack.Item>
<Button
icon="arrow-down"
tooltipPosition="left"
tooltip="Move this belly tab down."
onClick={() => act('move_belly', { dir: 1 })}
/>
</Stack.Item>
</Stack>
}
>
<Button onClick={() => act('set_attribute', { attribute: 'b_name' })}>
{belly_name}
</Button>
{editMode && (
<LabeledList.Item
buttons={
<Stack>
{bellyNames.indexOf(belly_name) !== 0 && (
<Stack.Item
mr={
bellyNames.indexOf(belly_name) === bellyNames.length - 1
? '28px'
: undefined
}
>
<Button
icon="arrow-up"
tooltipPosition="left"
tooltip="Move this belly tab up."
onClick={() => act('move_belly', { dir: -1 })}
/>
</Stack.Item>
)}
{bellyNames.indexOf(belly_name) !== bellyNames.length - 1 && (
<Stack.Item>
<Button
icon="arrow-down"
tooltipPosition="left"
tooltip="Move this belly tab down."
onClick={() => act('move_belly', { dir: 1 })}
/>
</Stack.Item>
)}
</Stack>
}
/>
)}
<LabeledList.Item label="Name">
<VorePanelEditText
editMode={editMode}
limit={name_length}
min={name_min}
entry={belly_name}
action={'set_attribute'}
subAction={'b_name'}
tooltip={
'Adjust the name of your belly. [' +
name_min +
'-' +
name_length +
' characters].'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Mode">
<Button
<VorePanelEditDropdown
editMode={editMode}
options={mode_options}
entry={mode}
action={'set_attribute'}
subAction={'b_mode'}
color={digestModeToColor[mode]}
onClick={() => act('set_attribute', { attribute: 'b_mode' })}
>
{mode}
</Button>
tooltip="The digest mode which will be applied for prey."
/>
</LabeledList.Item>
<LabeledList.Item label="Mode Addons">
{(addons.length && addons.join(', ')) || 'None'}
<Button
onClick={() => act('set_attribute', { attribute: 'b_addons' })}
ml={1}
icon="plus"
<VorePanelEditCheckboxes
editMode={editMode}
options={addons}
action={'set_attribute'}
subAction={'b_addons'}
tooltipList={modeToTooltip}
/>
</LabeledList.Item>
<LabeledList.Item label="Item Mode">
<Button
onClick={() => act('set_attribute', { attribute: 'b_item_mode' })}
>
{item_mode}
</Button>
</LabeledList.Item>
<LabeledList.Item>
<Button.Confirm
fluid
icon="exclamation-triangle"
confirmIcon="trash"
color="red"
confirmContent="This is irreversable!"
onClick={() => act('set_attribute', { attribute: 'b_del' })}
>
Delete Belly
</Button.Confirm>
<VorePanelEditDropdown
editMode={editMode}
options={item_mode_options}
entry={item_mode}
action={'set_attribute'}
subAction={'b_item_mode'}
color={digestModeToColor[item_mode]}
tooltip="The digest mode which will be applied for items."
/>
</LabeledList.Item>
{editMode && (
<LabeledList.Item>
<Button.Confirm
fluid
icon="exclamation-triangle"
confirmIcon="trash"
color="red"
confirmContent="This is irreversable!"
onClick={() => act('set_attribute', { attribute: 'b_del' })}
>
Delete Belly
</Button.Confirm>
</LabeledList.Item>
)}
</LabeledList>
);
};
@@ -1,7 +1,5 @@
import { type ReactNode, useEffect, useState } from 'react';
import { useBackend } from 'tgui/backend';
import { useState } from 'react';
import {
Box,
Button,
Dimmer,
LabeledList,
@@ -9,73 +7,35 @@ import {
Stack,
} from 'tgui-core/components';
import { SYNTAX_COLOR, SYNTAX_REGEX } from '../constants';
import type { selectedData } from '../types';
import { VoreSelectedBellyDescriptionsBellymode } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsBellymode';
import { VoreSelectedBellyDescriptionsEscape } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsEscape';
import { VoreSelectedBellyDescriptionsIdle } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsIdle';
import { VoreSelectedBellyDescriptionsInteractionChance } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsInteractionChance';
import { VoreSelectedBellyDescriptionsStruggle } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsStruggle';
import { VoreSelectedBellyDescriptionsTransfer } from '../VoreSelectedBellyDescriptionTexts/VoreSelectedBellyDescriptionsTransfer';
const DescriptionSyntaxHighlighting = (props: { desc: string }) => {
const { desc } = props;
const [htmlDesc, setHtmlDesc] = useState<ReactNode[]>([]);
useEffect(() => {
if (!desc || desc.length === 0) {
setHtmlDesc([]);
return;
}
const elements: ReactNode[] = [];
const regexCopy = new RegExp(SYNTAX_REGEX);
let lastIndex = 0;
let result;
while ((result = regexCopy.exec(desc)) !== null) {
elements.push(<>{desc.substring(lastIndex, result.index)}</>);
elements.push(
<Box inline color={SYNTAX_COLOR[result[0]] || 'purple'}>
{result[0]}
</Box>,
);
lastIndex = result.index + result[0].length;
}
elements.push(<>{desc.substring(lastIndex)}</>);
setHtmlDesc(elements);
}, [desc]);
return <Box preserveWhitespace>{htmlDesc}</Box>;
};
import type { bellyDescriptionData } from '../types';
import { VorePanelEditNumber } from '../VorePanelElements/VorePanelEditNumber';
import { VorePanelEditSwitch } from '../VorePanelElements/VorePanelEditSwitch';
import { VorePanelEditText } from '../VorePanelElements/VorePanelEditText';
import { VoreSelectedBellyDescriptionMatrix } from './DescriptionTab/VoreSelectedBellyDescriptionMatrix';
export const VoreSelectedBellyDescriptions = (props: {
belly: selectedData;
editMode: boolean;
bellyDescriptionData: bellyDescriptionData;
vore_words: Record<string, string[]>;
}) => {
const { act } = useBackend();
const [showFormatHelp, setShowFormatHelp] = useState(false);
const { belly, vore_words } = props;
const { editMode, bellyDescriptionData, vore_words } = props;
const {
verb,
release_verb,
desc,
absorbed_desc,
mode,
message_mode,
escapable,
interacts,
autotransfer_enabled,
autotransfer,
emote_active,
} = belly;
emote_time,
show_liq_fullness,
entrance_logs,
item_digest_logs,
name_length,
name_min,
} = bellyDescriptionData;
return (
<Box>
<>
{showFormatHelp && (
<Dimmer>
<Section
@@ -131,169 +91,129 @@ export const VoreSelectedBellyDescriptions = (props: {
</Section>
</Dimmer>
)}
<Stack>
<Stack fill vertical>
<Stack.Item>
<Box color="label" mt={1} mb={1}>
Description:
</Box>
<LabeledList>
<LabeledList.Item label="Vore Verb">
<VorePanelEditText
editMode={editMode}
limit={name_length}
min={name_min}
entry={verb}
action={'set_attribute'}
subAction={'b_verb'}
tooltip={
'Adjust vore verb. [' +
name_min +
'-' +
name_length +
' characters].'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Release Verb">
<VorePanelEditText
editMode={editMode}
limit={name_length}
min={name_min}
entry={release_verb}
action={'set_attribute'}
subAction={'b_release_verb'}
tooltip={
'Adjust release verb. [' +
name_min +
'-' +
name_length +
' characters].'
}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
<Stack.Divider />
<Stack.Item>
<Button
icon="pencil"
onClick={() => act('set_attribute', { attribute: 'b_desc' })}
>
Edit
</Button>
<Stack fill>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Idle Emotes">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_emoteactive"
editMode={editMode}
active={!!emote_active}
content={emote_active ? 'Active' : 'Inactive'}
tooltip={
(emote_active ? 'Dis' : 'En') + 'ables idle emotes.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Idle Emote Delay">
<VorePanelEditNumber
action="set_attribute"
subAction="b_emotetime"
editMode={editMode}
value={emote_time}
unit="seconds"
tooltip="Choose the period it takes for idle belly emotes to be shown to prey."
maxValue={600}
minValue={60}
/>
</LabeledList.Item>
<LabeledList.Item label="Liquid Fullness Examines">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_show_liq_fullness"
editMode={editMode}
active={!!show_liq_fullness}
content={show_liq_fullness ? 'Active' : 'Inactive'}
tooltip={
(show_liq_fullness ? 'Dis' : 'En') +
'ables liquid fullness examine messages.'
}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Entrance Logs">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_entrance_logs"
editMode={editMode}
active={!!entrance_logs}
tooltip={
(entrance_logs ? 'Dis' : 'En') +
'ables auto transfer messages and spawn messages being shown to yourself.'
}
/>
</LabeledList.Item>
<LabeledList.Item label="Item Digestion Logs">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_item_digest_logs"
editMode={editMode}
active={!!item_digest_logs}
tooltip={
(item_digest_logs ? 'Dis' : 'En') +
'ables item digest messages being shown to yourself.'
}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item>
<Button
icon="question"
tooltip="Formatting help"
onClick={() => setShowFormatHelp(!showFormatHelp)}
selected={showFormatHelp}
<Stack.Item grow>
<VoreSelectedBellyDescriptionMatrix
showAll={message_mode}
editMode={editMode}
bellyDescriptionData={bellyDescriptionData}
showFormatHelp={showFormatHelp}
onShowFormatHelp={setShowFormatHelp}
/>
</Stack.Item>
</Stack>
<DescriptionSyntaxHighlighting desc={desc} />
<Box color="label" mt={2} mb={1}>
Description (Absorbed):{' '}
<Button
icon="pencil"
onClick={() => act('set_attribute', { attribute: 'b_absorbed_desc' })}
>
Edit
</Button>
</Box>
<DescriptionSyntaxHighlighting desc={absorbed_desc} />
<Box mb={2} />
<LabeledList>
<LabeledList.Item label="Vore Verb">
<Button onClick={() => act('set_attribute', { attribute: 'b_verb' })}>
{verb}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Release Verb">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_release_verb' })
}
>
{release_verb}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Show All Messages">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_message_mode',
})
}
icon={message_mode ? 'toggle-on' : 'toggle-off'}
selected={message_mode}
>
{message_mode ? 'True' : 'False'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Examine Messages">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'em' })
}
>
Examine Message (when full)
</Button>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'ema' })
}
>
Examine Message (with absorbed victims)
</Button>
</LabeledList.Item>
<LabeledList.Item label="Trash Eater Messages">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_trasheater', msgtype: 'in' })
}
>
Item Eat Message
</Button>
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_trasheater',
msgtype: 'out',
})
}
>
Item Expel Message
</Button>
</LabeledList.Item>
{message_mode || escapable ? (
<>
<VoreSelectedBellyDescriptionsStruggle />
<VoreSelectedBellyDescriptionsEscape
message_mode={message_mode}
interacts={interacts}
/>
</>
) : (
''
)}
{message_mode ||
(escapable &&
(!!interacts.transferlocation ||
!!interacts.transferlocation_secondary)) ||
(autotransfer_enabled &&
(!!autotransfer.autotransferlocation ||
!!autotransfer.autotransferlocation_secondary)) ? (
<VoreSelectedBellyDescriptionsTransfer
message_mode={message_mode}
interacts={interacts}
autotransfer={autotransfer}
/>
) : (
''
)}
{message_mode ||
(escapable &&
(interacts.digestchance > 0 || interacts.absorbchance > 0)) ? (
<VoreSelectedBellyDescriptionsInteractionChance
message_mode={message_mode}
interacts={interacts}
/>
) : (
''
)}
{(message_mode ||
mode === 'Digest' ||
mode === 'Selective' ||
mode === 'Absorb' ||
mode === 'Unabsorb') && (
<VoreSelectedBellyDescriptionsBellymode
message_mode={message_mode}
mode={mode}
/>
)}
{emote_active ? (
<VoreSelectedBellyDescriptionsIdle
message_mode={message_mode}
mode={mode}
/>
) : (
''
)}
<LabeledList.Item label="Reset Messages">
<Button
color="red"
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'reset' })
}
>
Reset Messages
</Button>
</LabeledList.Item>
</LabeledList>
</Box>
</>
);
};
@@ -1,381 +1,277 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Section } from 'tgui-core/components';
import { LabeledList, Section, Stack } from 'tgui-core/components';
import type { selectedData } from '../types';
import { noSelectionName } from '../constants';
import type { bellyInteractionData, DropdownEntry } from '../types';
import { VorePanelEditDropdown } from '../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditNumber } from '../VorePanelElements/VorePanelEditNumber';
import { VorePanelEditSwitch } from '../VorePanelElements/VorePanelEditSwitch';
import { AutoTransferOptions } from './InteractionTab/AutoTransferOptions';
export const VoreSelectedBellyInteractions = (props: {
belly: selectedData;
editMode: boolean;
bellyDropdownNames: DropdownEntry[];
bellyInteractData: bellyInteractionData;
}) => {
const { act } = useBackend();
const { editMode, bellyDropdownNames, bellyInteractData } = props;
const { escapable, interacts, autotransfer_enabled, autotransfer } =
bellyInteractData;
const { belly } = props;
const { escapable, interacts, autotransfer_enabled, autotransfer } = belly;
const escapeTimeSeconds = interacts.escapetime / 10;
const autoTransferTimeSeconds = autotransfer.autotransferwait / 10;
const locationNames = [...bellyDropdownNames, noSelectionName];
return (
<Section
title="Belly Interactions"
buttons={
<Button
onClick={() => act('set_attribute', { attribute: 'b_escapable' })}
icon={escapable ? 'toggle-on' : 'toggle-off'}
selected={escapable}
<Stack fill vertical>
<Stack.Item>
<Section
title="Belly Interactions"
buttons={
<VorePanelEditSwitch
action="set_attribute"
subAction="b_escapable"
editMode={editMode}
active={!!escapable}
tooltip={
"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."
}
/>
}
>
{escapable ? 'Interactions On' : 'Interactions Off'}
</Button>
}
>
{escapable ? (
<LabeledList>
<LabeledList.Item label="Escape Chance">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_escapechance' })
<Stack fill>
{!!escapable && (
<>
<Stack.Item basis="49%" grow>
<LabeledList.Item label="Escape Chance">
<VorePanelEditNumber
action="set_attribute"
subAction="b_escapechance"
editMode={editMode}
value={interacts.escapechance}
minValue={0}
maxValue={100}
unit="%"
tooltip="Set prey escape chance on resist."
/>
</LabeledList.Item>
<LabeledList.Item label="Escape Time">
<VorePanelEditNumber
action="set_attribute"
subAction="b_escapetime"
editMode={editMode}
value={escapeTimeSeconds}
minValue={1}
maxValue={60}
unit={escapeTimeSeconds === 1 ? 'second' : 'seconds'}
tooltip="Set number of seconds for prey to escape on resist."
/>
</LabeledList.Item>
<LabeledList.Item label="Digest Chance">
<VorePanelEditNumber
action="set_attribute"
subAction="b_digestchance"
editMode={editMode}
value={interacts.escapechance}
minValue={0}
maxValue={100}
unit="%"
tooltip="Set belly digest mode chance on resist."
/>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Primary Transfer Chance">
<VorePanelEditNumber
action="set_attribute"
subAction="b_transferchance"
editMode={editMode}
value={interacts.transferchance}
minValue={0}
maxValue={100}
unit="%"
tooltip="Set the primary belly transfer chance on resist. You must also set the location for this to have any effect."
/>
</LabeledList.Item>
<LabeledList.Item label="Secondary Transfer Chance">
<VorePanelEditNumber
action="set_attribute"
subAction="b_transferchance_secondary"
editMode={editMode}
value={interacts.transferchance_secondary}
minValue={0}
maxValue={100}
unit="%"
tooltip="Set the secondary belly transfer chance on resist. You must also set the secondary location for this to have any effect."
/>
</LabeledList.Item>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList.Item label="Absorbed Escape Chance">
<VorePanelEditNumber
action="set_attribute"
subAction="b_escapechance_absorbed"
editMode={editMode}
value={interacts.escapechance_absorbed}
minValue={0}
maxValue={100}
unit="%"
tooltip="Set absorbed prey escape chance on resist."
/>
</LabeledList.Item>
<LabeledList.Item label="Belch Chance">
<VorePanelEditNumber
action="set_attribute"
subAction="b_belchchance"
editMode={editMode}
value={interacts.belchchance}
minValue={0}
maxValue={100}
unit="%"
tooltip="Set chance for belch emote on prey resist."
/>
</LabeledList.Item>
<LabeledList.Item label="Absorb Chance">
<VorePanelEditNumber
action="set_attribute"
subAction="b_absorbchance"
editMode={editMode}
value={interacts.absorbchance}
minValue={0}
maxValue={100}
unit="%"
tooltip="Set belly absorb mode chance on resist."
/>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Primary Transfer Location">
<VorePanelEditDropdown
action="set_attribute"
subAction="b_transferlocation"
editMode={editMode}
options={locationNames}
color={
!editMode && !interacts.transferlocation
? 'red'
: undefined
}
entry={
interacts.transferlocation
? interacts.transferlocation
: 'Disabled'
}
tooltip="Target location of the primary transfer trigger on resist."
/>
</LabeledList.Item>
<LabeledList.Item label="Secondary Transfer Location">
<VorePanelEditDropdown
action="set_attribute"
subAction="b_transferlocation_secondary"
editMode={editMode}
options={locationNames}
color={
!editMode && !interacts.transferlocation
? 'red'
: undefined
}
entry={
interacts.transferlocation_secondary
? interacts.transferlocation_secondary
: 'Disabled'
}
tooltip="Target location of the secondary transfer trigger on resist."
/>
</LabeledList.Item>
</Stack.Item>
</>
)}
<Stack.Divider />
</Stack>
</Section>
</Stack.Item>
<Stack.Item mt="5px">
<Section
title="Auto-Transfer Options"
buttons={
<VorePanelEditSwitch
action="set_attribute"
subAction="b_autotransfer_enabled"
editMode={editMode}
active={!!escapable}
tooltip={
'Allows you to setup auto transfer options for this belly. So that prey is automatically moved depending on a timer or content count.'
}
>
{interacts.escapechance + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Absorbed Escape Chance">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_escapechance_absorbed' })
}
>
{interacts.escapechance_absorbed + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Escape Time">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_escapetime' })
}
>
{interacts.escapetime / 10 + 's'}
</Button>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Transfer Chance">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_transferchance' })
}
>
{interacts.transferchance + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Transfer Location">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_transferlocation' })
}
>
{interacts.transferlocation
? interacts.transferlocation
: 'Disabled'}
</Button>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Secondary Transfer Chance">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_transferchance_secondary',
})
}
>
{interacts.transferchance_secondary + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Secondary Transfer Location">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_transferlocation_secondary',
})
}
>
{interacts.transferlocation_secondary
? interacts.transferlocation_secondary
: 'Disabled'}
</Button>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Absorb Chance">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_absorbchance' })
}
>
{interacts.absorbchance + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Digest Chance">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_digestchance' })
}
>
{interacts.digestchance + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Belch Chance">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_belchchance' })
}
>
{interacts.belchchance + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Divider />
</LabeledList>
) : (
'These options only display while interactions are turned on.'
)}
<Section
title="Auto-Transfer Options"
buttons={
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_autotransfer_enabled' })
}
icon={autotransfer_enabled ? 'toggle-on' : 'toggle-off'}
selected={autotransfer_enabled}
>
{autotransfer_enabled
? 'Auto-Transfer Enabled'
: 'Auto-Transfer Disabled'}
</Button>
}
>
{autotransfer_enabled ? (
<LabeledList>
<LabeledList.Item label="Auto-Transfer Time">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_autotransferwait' })
}
>
{autotransfer.autotransferwait / 10 + 's'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Min Amount">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_min_amount',
})
}
>
{autotransfer.autotransfer_min_amount}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Max Amount">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_max_amount',
})
}
>
{autotransfer.autotransfer_max_amount}
</Button>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Auto-Transfer Primary Chance">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_autotransferchance' })
}
>
{autotransfer.autotransferchance + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Primary Location">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_autotransferlocation' })
}
>
{autotransfer.autotransferlocation
? autotransfer.autotransferlocation
: 'Disabled'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Primary Location Extras">
{(autotransfer.autotransferextralocation &&
autotransfer.autotransferextralocation.join(', ')) ||
''}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransferextralocation',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Primary Whitelist (Mobs)">
{(autotransfer.autotransfer_whitelist.length &&
autotransfer.autotransfer_whitelist.join(', ')) ||
'Everything'}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_whitelist',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Primary Whitelist (Items)">
{(autotransfer.autotransfer_whitelist_items.length &&
autotransfer.autotransfer_whitelist_items.join(', ')) ||
'Everything'}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_whitelist_items',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Primary Blacklist (Mobs)">
{(autotransfer.autotransfer_blacklist.length &&
autotransfer.autotransfer_blacklist.join(', ')) ||
'Nothing'}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_blacklist',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Primary Blacklist (Items)">
{(autotransfer.autotransfer_blacklist_items.length &&
autotransfer.autotransfer_blacklist_items.join(', ')) ||
'Nothing'}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_blacklist_items',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item label="Auto-Transfer Secondary Chance">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransferchance_secondary',
})
}
>
{autotransfer.autotransferchance_secondary + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Secondary Location">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransferlocation_secondary',
})
}
>
{autotransfer.autotransferlocation_secondary
? autotransfer.autotransferlocation_secondary
: 'Disabled'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Secondary Location Extras">
{(autotransfer.autotransferextralocation_secondary &&
autotransfer.autotransferextralocation_secondary.join(', ')) ||
''}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransferextralocation_secondary',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Secondary Whitelist (Mobs)">
{(autotransfer.autotransfer_secondary_whitelist.length &&
autotransfer.autotransfer_secondary_whitelist.join(', ')) ||
'Everything'}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_secondary_whitelist',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Secondary Whitelist (Items)">
{(autotransfer.autotransfer_secondary_whitelist_items.length &&
autotransfer.autotransfer_secondary_whitelist_items.join(
', ',
)) ||
'Everything'}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_secondary_whitelist_items',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Secondary Blacklist (Mobs)">
{(autotransfer.autotransfer_secondary_blacklist.length &&
autotransfer.autotransfer_secondary_blacklist.join(', ')) ||
'Nothing'}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_secondary_blacklist',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Secondary Blacklist (Items)">
{(autotransfer.autotransfer_secondary_blacklist_items.length &&
autotransfer.autotransfer_secondary_blacklist_items.join(
', ',
)) ||
'Nothing'}
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_autotransfer_secondary_blacklist_items',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
</LabeledList>
) : (
'These options only display while Auto-Transfer is enabled.'
)}
</Section>
</Section>
/>
}
>
{!!autotransfer_enabled && (
<Stack vertical fill>
<Stack.Item>
<Stack>
<Stack.Item basis="49%" grow>
<LabeledList.Item label="Auto-Transfer Min Amount">
<VorePanelEditNumber
action="set_attribute"
subAction="b_autotransfer_min_amount"
editMode={editMode}
value={autotransfer.autotransfer_min_amount}
minValue={0}
maxValue={100}
tooltip="Set the minimum amount of items your belly can belly auto-transfer at once. Set to 0 for no limit."
/>
</LabeledList.Item>
<LabeledList.Item label="Auto-Transfer Max Amount">
<VorePanelEditNumber
action="set_attribute"
subAction="b_autotransfer_max_amount"
editMode={editMode}
value={autotransfer.autotransfer_max_amount}
minValue={0}
maxValue={100}
tooltip="Set the minimum amount of items your belly can belly auto-transfer at once. Set to 0 for no limit."
/>
</LabeledList.Item>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList.Item label="Auto-Transfer Time">
<VorePanelEditNumber
action="set_attribute"
subAction="b_autotransferwait"
editMode={editMode}
value={autoTransferTimeSeconds}
unit={
autoTransferTimeSeconds === 1 ? 'second' : 'seconds'
}
minValue={1}
maxValue={1800}
tooltip="Set minimum number of seconds for auto-transfer wait delay."
/>
</LabeledList.Item>
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item>
<AutoTransferOptions
editMode={editMode}
title={'primary'}
bellyDropdownNames={bellyDropdownNames}
locationNames={locationNames}
autotransferData={autotransfer.primary_transfer}
/>
</Stack.Item>
<Stack.Item>
<AutoTransferOptions
editMode={editMode}
title={'secondary'}
bellyDropdownNames={bellyDropdownNames}
locationNames={locationNames}
autotransferData={autotransfer.secondary_transfer}
/>
</Stack.Item>
</Stack>
)}
</Section>
</Stack.Item>
</Stack>
);
};
@@ -1,181 +0,0 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Section, Stack } from 'tgui-core/components';
import type { selectedData } from '../types';
export const VoreSelectedBellyLiquidMessages = (props: {
belly: selectedData;
}) => {
const { act } = useBackend();
const { belly } = props;
const { show_liq_fullness, liq_messages } = belly;
return (
<Section
title="Liquid Messages"
buttons={
<Button
onClick={() =>
act('liq_set_messages', { liq_messages: 'b_show_liq_fullness' })
}
icon={show_liq_fullness ? 'toggle-on' : 'toggle-off'}
selected={show_liq_fullness}
tooltipPosition="left"
tooltip={
'These are the settings for belly visibility when involving liquids fullness.'
}
>
{show_liq_fullness ? 'Messages On' : 'Messages Off'}
</Button>
}
>
{show_liq_fullness ? (
<LabeledList>
<LabeledList.Item label="0 to 20%">
<Stack>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', {
liq_messages: 'b_liq_msg_toggle1',
})
}
icon={
liq_messages.liq_msg_toggle1 ? 'toggle-on' : 'toggle-off'
}
selected={liq_messages.liq_msg_toggle1}
>
{liq_messages.liq_msg_toggle1 ? 'On' : 'Off'}
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', { liq_messages: 'b_liq_msg1' })
}
>
Examine Message (0 to 20%)
</Button>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="20 to 40%">
<Stack>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', {
liq_messages: 'b_liq_msg_toggle2',
})
}
icon={
liq_messages.liq_msg_toggle2 ? 'toggle-on' : 'toggle-off'
}
selected={liq_messages.liq_msg_toggle2}
>
{liq_messages.liq_msg_toggle2 ? 'On' : 'Off'}
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', { liq_messages: 'b_liq_msg2' })
}
>
Examine Message (20 to 40%)
</Button>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="40 to 60%">
<Stack>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', {
liq_messages: 'b_liq_msg_toggle3',
})
}
icon={
liq_messages.liq_msg_toggle3 ? 'toggle-on' : 'toggle-off'
}
selected={liq_messages.liq_msg_toggle3}
>
{liq_messages.liq_msg_toggle3 ? 'On' : 'Off'}
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', { liq_messages: 'b_liq_msg3' })
}
>
Examine Message (40 to 60%)
</Button>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="60 to 80%">
<Stack>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', {
liq_messages: 'b_liq_msg_toggle4',
})
}
icon={
liq_messages.liq_msg_toggle4 ? 'toggle-on' : 'toggle-off'
}
selected={liq_messages.liq_msg_toggle4}
>
{liq_messages.liq_msg_toggle4 ? 'On' : 'Off'}
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', { liq_messages: 'b_liq_msg4' })
}
>
Examine Message (60 to 80%)
</Button>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="80 to 100%">
<Stack>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', {
liq_messages: 'b_liq_msg_toggle5',
})
}
icon={
liq_messages.liq_msg_toggle5 ? 'toggle-on' : 'toggle-off'
}
selected={liq_messages.liq_msg_toggle5}
>
{liq_messages.liq_msg_toggle5 ? 'On' : 'Off'}
</Button>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('liq_set_messages', { liq_messages: 'b_liq_msg5' })
}
>
Examine Message (80 to 100%)
</Button>
</Stack.Item>
</Stack>
</LabeledList.Item>
</LabeledList>
) : (
'These options only display while liquid examination settings are turned on.'
)}
</Section>
);
};
@@ -1,329 +1,87 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Section } from 'tgui-core/components';
import { Button, LabeledList, Section, Stack } from 'tgui-core/components';
import { reagentToColor } from '../constants';
import { LiquidColorInput } from '../LiquidColorInput';
import type { selectedData } from '../types';
import { liquidToTooltip } from '../constants';
import type { bellyLiquidData } from '../types';
import { VorePanelEditCheckboxes } from '../VorePanelElements/VorePanelEditCheckboxes';
import { VorePanelEditSwitch } from '../VorePanelElements/VorePanelEditSwitch';
import { LiquidOptionsLeft } from './LiquidTab/LiquidOptionsLeft';
import { LiquidOptionsRight } from './LiquidTab/LiquidOptionsRight';
export const VoreSelectedBellyLiquidOptions = (props: {
belly: selectedData;
editMode: boolean;
bellyLiquidData: bellyLiquidData;
}) => {
const { act } = useBackend();
const { belly } = props;
const { show_liq, liq_interacts } = belly;
const generationTime = (liq_interacts.liq_reagent_nutri_rate + 1) * 10;
const generationMinutes = generationTime % 60;
const generationHours = Math.floor(generationTime / 60);
const { editMode, bellyLiquidData } = props;
const { show_liq, liq_interacts } = bellyLiquidData;
return (
<Section
title="Liquid Options"
fill
buttons={
<Button
onClick={() =>
act('liq_set_attribute', { liq_attribute: 'b_show_liq' })
}
icon={show_liq ? 'toggle-on' : 'toggle-off'}
selected={show_liq}
tooltipPosition="left"
tooltip={
'These are the settings for liquid bellies, every belly has a liquid storage.'
}
>
{show_liq ? 'Liquids On' : 'Liquids Off'}
</Button>
}
>
{show_liq ? (
<LabeledList>
<LabeledList.Item label="Generate Liquids">
<Button
onClick={() =>
act('liq_set_attribute', { liq_attribute: 'b_liq_reagent_gen' })
}
icon={liq_interacts.liq_reagent_gen ? 'toggle-on' : 'toggle-off'}
selected={liq_interacts.liq_reagent_gen}
>
{liq_interacts.liq_reagent_gen ? 'On' : 'Off'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Liquid Type">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_liq_reagent_type',
})
}
icon="pen"
color={reagentToColor[liq_interacts.liq_reagent_type]}
>
{liq_interacts.liq_reagent_type}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Liquid Name">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_liq_reagent_name',
})
}
>
{liq_interacts.liq_reagent_name}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Transfer Verb">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_liq_reagent_transfer_verb',
})
}
>
{liq_interacts.liq_reagent_transfer_verb}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Generation Time">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_liq_reagent_nutri_rate',
})
}
icon="clock"
>
{(generationHours < 10
? '0' + generationHours
: generationHours) +
':' +
(generationMinutes < 10
? '0' + generationMinutes
: generationMinutes) +
' hh:mm'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Liquid Capacity">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_liq_reagent_capacity',
})
}
>
{liq_interacts.liq_reagent_capacity}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Slosh Sounds">
<Button
onClick={() =>
act('liq_set_attribute', { liq_attribute: 'b_liq_sloshing' })
}
icon={liq_interacts.liq_sloshing ? 'toggle-on' : 'toggle-off'}
selected={liq_interacts.liq_sloshing}
>
{liq_interacts.liq_sloshing ? 'On' : 'Off'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Liquid Addons">
{(liq_interacts.liq_reagent_addons.length &&
liq_interacts.liq_reagent_addons.join(', ')) ||
'None'}
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_liq_reagent_addons',
})
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Liquid Application to Prey">
<Button
onClick={() =>
act('liq_set_attribute', { liq_attribute: 'b_reagent_touches' })
}
icon={liq_interacts.reagent_touches ? 'toggle-on' : 'toggle-off'}
selected={liq_interacts.reagent_touches}
>
{liq_interacts.reagent_touches ? 'On' : 'Off'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Custom Liquid Color">
<LiquidColorInput
action_name="b_custom_reagentcolor"
value_of={null}
back_color={liq_interacts.custom_reagentcolor}
name_of="Custom Liquid Color"
/>
</LabeledList.Item>
<LabeledList.Item label="Liquid Overlay">
<Button
onClick={() =>
act('liq_set_attribute', { liq_attribute: 'b_liquid_overlay' })
}
icon={liq_interacts.liquid_overlay ? 'toggle-on' : 'toggle-off'}
selected={liq_interacts.liquid_overlay}
>
{liq_interacts.liquid_overlay ? 'On' : 'Off'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Max Liquid Level">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_max_liquid_level',
})
}
>
{liq_interacts.max_liquid_level + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Custom Liquid Alpha">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_custom_reagentalpha',
})
}
>
{liq_interacts.custom_reagentalpha}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Fullness Overlay">
<Button
onClick={() =>
act('liq_set_attribute', { liq_attribute: 'b_mush_overlay' })
}
icon={liq_interacts.mush_overlay ? 'toggle-on' : 'toggle-off'}
selected={liq_interacts.mush_overlay}
>
{liq_interacts.mush_overlay ? 'On' : 'Off'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Mush Overlay Color">
<LiquidColorInput
action_name="b_mush_color"
value_of={null}
back_color={liq_interacts.mush_color}
name_of="Custom Mush Color"
/>
</LabeledList.Item>
<LabeledList.Item label="Mush Overlay Alpha">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_mush_alpha',
})
}
>
{liq_interacts.mush_alpha}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Mush Overlay Scaling">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_max_mush',
})
}
>
{liq_interacts.max_mush}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Minimum Mush Level">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_min_mush',
})
}
>
{liq_interacts.min_mush + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Item Mush Value">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_item_mush_val',
})
}
>
{liq_interacts.item_mush_val + ' fullness per item'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Metabolism Overlay">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_metabolism_overlay',
})
}
icon={
liq_interacts.metabolism_overlay ? 'toggle-on' : 'toggle-off'
}
selected={liq_interacts.metabolism_overlay}
>
{liq_interacts.metabolism_overlay ? 'On' : 'Off'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Metabolism Mush Ratio">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_metabolism_mush_ratio',
})
}
>
{liq_interacts.metabolism_mush_ratio +
' fullness per reagent unit'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Metabolism Overlay Scaling">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_max_ingested',
})
}
>
{liq_interacts.max_ingested}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Custom Metabolism Color">
<LiquidColorInput
action_name="b_custom_ingested_color"
value_of={null}
back_color={liq_interacts.custom_ingested_color}
name_of="Custom Metabolism Color"
/>
</LabeledList.Item>
<LabeledList.Item label="Metabolism Overlay Alpha">
<Button
onClick={() =>
act('liq_set_attribute', {
liq_attribute: 'b_custom_ingested_alpha',
})
}
>
{liq_interacts.custom_ingested_alpha}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Purge Liquids">
<Button
<Stack align="center">
<Stack.Item>
<Button.Confirm
color="red"
tooltip="Clear this belly's liquids."
confirmContent="Confirm Purge?"
onClick={() =>
act('liq_set_attribute', { liq_attribute: 'b_liq_purge' })
}
>
Purge Liquids
</Button>
</LabeledList.Item>
</LabeledList>
) : (
'These options only display while liquid settings are turned on.'
</Button.Confirm>
</Stack.Item>
<Stack.Item>
<VorePanelEditSwitch
action="liq_set_attribute"
subAction="b_show_liq"
editMode={editMode}
active={!!show_liq}
tooltip={
'These are the settings for liquid bellies, every belly has a liquid storage.'
}
/>
</Stack.Item>
</Stack>
}
>
{!!show_liq && (
<Stack fill vertical>
<Stack.Item>
<LabeledList>
<LabeledList.Item label="Liquid Addons">
<VorePanelEditCheckboxes
editMode={editMode}
options={liq_interacts.liq_reagent_addons}
action="liq_set_attribute"
subAction="b_liq_reagent_addons"
tooltipList={liquidToTooltip}
tooltip='Liquid production modes to apply as soon as "Produce Liquids" is turned on.'
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
<Stack.Item mt="5px">
<Stack fill>
<Stack.Item basis="49%" grow>
<LiquidOptionsLeft
editMode={editMode}
liquidInteract={liq_interacts}
/>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LiquidOptionsRight
editMode={editMode}
liquidInteract={liq_interacts}
/>
</Stack.Item>
</Stack>
</Stack.Item>
</Stack>
)}
</Section>
);
@@ -1,370 +1,30 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
import { capitalize } from 'tgui-core/string';
import { Stack } from 'tgui-core/components';
import { vorespawnAbsorbedColor, vorespawnAbsorbedText } from '../constants';
import type { hostMob, selectedData } from '../types';
import { VoreSelectedMobTypeBellyButtons } from './VoreSelectedMobTypeBellyButtons';
import type { bellyOptionData, hostMob } from '../types';
import { BellyOptionsLeft } from './OptionTab/BellyOptionsLeft';
import { BellyOptionsRight } from './OptionTab/BellyOptionsRight';
export const VoreSelectedBellyOptions = (props: {
belly: selectedData;
editMode: boolean;
bellyOptionData: bellyOptionData;
host_mobtype: hostMob;
}) => {
const { act } = useBackend();
const { belly, host_mobtype } = props;
const {
can_taste,
is_feedable,
nutrition_percent,
digest_brute,
digest_burn,
digest_oxy,
digest_tox,
digest_clone,
bulge_size,
display_absorbed_examine,
shrink_grow_size,
emote_time,
emote_active,
contaminates,
contaminate_flavor,
contaminate_color,
egg_type,
egg_name,
egg_size,
recycling,
storing_nutrition,
entrance_logs,
item_digest_logs,
selective_preference,
save_digest_mode,
eating_privacy_local,
vorespawn_blacklist,
vorespawn_whitelist,
vorespawn_absorbed,
private_struggle,
drainmode,
} = belly;
const { editMode, bellyOptionData, host_mobtype } = props;
return (
<Stack wrap="wrap">
<Stack fill>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Can Taste">
<Button
onClick={() => act('set_attribute', { attribute: 'b_tastes' })}
icon={can_taste ? 'toggle-on' : 'toggle-off'}
selected={can_taste}
>
{can_taste ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Feedable">
<Button
onClick={() => act('set_attribute', { attribute: 'b_feedable' })}
icon={is_feedable ? 'toggle-on' : 'toggle-off'}
selected={is_feedable}
>
{is_feedable ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Contaminates">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_contaminates' })
}
icon={contaminates ? 'toggle-on' : 'toggle-off'}
selected={contaminates}
>
{contaminates ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
{contaminates ? (
<>
<LabeledList.Item label="Contamination Flavor">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_contamination_flavor',
})
}
icon="pen"
>
{contaminate_flavor}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Contamination Color">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_contamination_color' })
}
icon="pen"
>
{!!contaminate_color && capitalize(contaminate_color)}
</Button>
</LabeledList.Item>
</>
) : (
''
)}
<LabeledList.Item label="Nutritional Gain">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_nutritionpercent' })
}
>
{nutrition_percent + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Required Examine Size">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_bulge_size' })
}
>
{bulge_size * 100 + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Display Absorbed Examines">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_display_absorbed_examine',
})
}
icon={display_absorbed_examine ? 'toggle-on' : 'toggle-off'}
selected={display_absorbed_examine}
>
{display_absorbed_examine ? 'True' : 'False'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Toggle Vore Privacy">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_eating_privacy' })
}
>
{capitalize(eating_privacy_local)}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Toggle Struggle Privacy">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_private_struggle' })
}
icon={private_struggle ? 'toggle-on' : 'toggle-off'}
selected={private_struggle}
>
{private_struggle ? 'Private' : 'Loud'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Save Digest Mode">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_save_digest_mode' })
}
icon={save_digest_mode ? 'toggle-on' : 'toggle-off'}
selected={save_digest_mode}
>
{save_digest_mode ? 'True' : 'False'}
</Button>
</LabeledList.Item>
</LabeledList>
<VoreSelectedMobTypeBellyButtons
belly={belly}
<BellyOptionsLeft
editMode={editMode}
bellyOptionData={bellyOptionData}
host_mobtype={host_mobtype}
/>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Idle Emotes">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_emoteactive' })
}
icon={emote_active ? 'toggle-on' : 'toggle-off'}
selected={emote_active}
>
{emote_active ? 'Active' : 'Inactive'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Idle Emote Delay">
<Button
onClick={() => act('set_attribute', { attribute: 'b_emotetime' })}
>
{emote_time + ' seconds'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Digest Brute Damage">
<Button
onClick={() => act('set_attribute', { attribute: 'b_brute_dmg' })}
>
{digest_brute}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Digest Burn Damage">
<Button
onClick={() => act('set_attribute', { attribute: 'b_burn_dmg' })}
>
{digest_burn}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Digest Suffocation Damage">
<Button
onClick={() => act('set_attribute', { attribute: 'b_oxy_dmg' })}
>
{digest_oxy}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Digest Toxins Damage">
<Button
onClick={() => act('set_attribute', { attribute: 'b_tox_dmg' })}
>
{digest_tox}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Digest Clone Damage">
<Button
onClick={() => act('set_attribute', { attribute: 'b_clone_dmg' })}
>
{digest_clone}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Drain Finishing Mode">
<Button
onClick={() => act('set_attribute', { attribute: 'b_drainmode' })}
>
{drainmode}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Shrink/Grow Size">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_grow_shrink' })
}
>
{shrink_grow_size * 100 + '%'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Vore Spawn Blacklist">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_vorespawn_blacklist' })
}
icon={vorespawn_blacklist ? 'toggle-on' : 'toggle-off'}
selected={vorespawn_blacklist}
>
{vorespawn_blacklist ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
{vorespawn_blacklist ? (
''
) : (
<>
<LabeledList.Item label="Vore Spawn Whitelist">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_vorespawn_whitelist' })
}
icon="pen"
>
{vorespawn_whitelist.length
? vorespawn_whitelist.join(', ')
: 'Anyone!'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Vore Spawn Absorbed">
<Button
color={vorespawnAbsorbedColor[vorespawn_absorbed]}
tooltip="Click to toggle between No, Yes and Prey's Choice."
onClick={() =>
act('set_attribute', { attribute: 'b_vorespawn_absorbed' })
}
>
{vorespawnAbsorbedText[vorespawn_absorbed]}
</Button>
</LabeledList.Item>
</>
)}
<LabeledList.Item label="Egg Type">
<Button
onClick={() => act('set_attribute', { attribute: 'b_egg_type' })}
icon="pen"
>
{capitalize(egg_type)}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Custom Egg Name">
<Button
onClick={() => act('set_attribute', { attribute: 'b_egg_name' })}
icon="pen"
>
{egg_name ? egg_name : 'Default'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Custom Egg Size">
<Button
onClick={() => act('set_attribute', { attribute: 'b_egg_size' })}
>
{egg_size ? egg_size * 100 + '%' : 'Automatic'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Recycling">
<Button
onClick={() => act('set_attribute', { attribute: 'b_recycling' })}
icon={recycling ? 'toggle-on' : 'toggle-off'}
selected={recycling}
>
{recycling ? 'Enabled' : 'Disabled'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Storing Nutrition">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_storing_nutrition' })
}
icon={storing_nutrition ? 'toggle-on' : 'toggle-off'}
selected={storing_nutrition}
>
{storing_nutrition ? 'Storing' : 'Absorbing'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Entrance Logs">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_entrance_logs' })
}
icon={entrance_logs ? 'toggle-on' : 'toggle-off'}
selected={entrance_logs}
>
{entrance_logs ? 'Enabled' : 'Disabled'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Item Digestion Logs">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_item_digest_logs' })
}
icon={item_digest_logs ? 'toggle-on' : 'toggle-off'}
selected={item_digest_logs}
>
{item_digest_logs ? 'Enabled' : 'Disabled'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Selective Mode Preference">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_selective_mode_pref_toggle',
})
}
>
{capitalize(selective_preference)}
</Button>
</LabeledList.Item>
</LabeledList>
<BellyOptionsRight
editMode={editMode}
bellyOptionData={bellyOptionData}
/>
</Stack.Item>
</Stack>
);
@@ -1,12 +1,18 @@
import { useBackend } from 'tgui/backend';
import { Button, LabeledList, Stack } from 'tgui-core/components';
import type { selectedData } from '../types';
import { useBackend } from '../../../backend';
import type { bellySoundData, DropdownEntry } from '../types';
import { VorePanelEditDropdown } from '../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditNumber } from '../VorePanelElements/VorePanelEditNumber';
import { VorePanelEditSwitch } from '../VorePanelElements/VorePanelEditSwitch';
export const VoreSelectedBellySounds = (props: { belly: selectedData }) => {
export const VoreSelectedBellySounds = (props: {
editMode: boolean;
bellySoundData: bellySoundData;
}) => {
const { act } = useBackend();
const { belly } = props;
const { editMode, bellySoundData } = props;
const {
is_wet,
wet_loop,
@@ -15,82 +21,148 @@ export const VoreSelectedBellySounds = (props: { belly: selectedData }) => {
release_sound,
sound_volume,
noise_freq,
} = belly;
min_voice_freq,
max_voice_freq,
vore_sound_list,
release_sound_list,
} = bellySoundData;
const ourPresets: DropdownEntry[] = [
{ displayText: 'high', value: max_voice_freq.toString() },
{ displayText: 'middle-high', value: '56250' },
{ displayText: 'middle', value: '42500' },
{ displayText: 'middle-low', value: '28750' },
{ displayText: 'low', value: min_voice_freq.toString() },
{ displayText: 'random', value: '0' },
];
function getDropdownDisplay(currentFeq: number) {
const ourEntry = ourPresets.find(
(preset) => preset.value === currentFeq.toString(),
);
if (!ourEntry) {
return 'custom';
}
return ourEntry.displayText;
}
return (
<Stack wrap="wrap">
<Stack>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Fleshy Belly">
<Button
onClick={() => act('set_attribute', { attribute: 'b_wetness' })}
icon={is_wet ? 'toggle-on' : 'toggle-off'}
selected={is_wet}
>
{is_wet ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Internal Loop">
<Button
onClick={() => act('set_attribute', { attribute: 'b_wetloop' })}
icon={wet_loop ? 'toggle-on' : 'toggle-off'}
selected={wet_loop}
>
{wet_loop ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Use Fancy Sounds">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_fancy_sound' })
}
icon={fancy ? 'toggle-on' : 'toggle-off'}
selected={fancy}
>
{fancy ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Vore Sound">
<Button
onClick={() => act('set_attribute', { attribute: 'b_sound' })}
>
{sound}
</Button>
<Button
onClick={() => act('set_attribute', { attribute: 'b_soundtest' })}
icon="volume-up"
<VorePanelEditSwitch
action="set_attribute"
subAction="b_wetness"
editMode={editMode}
content={is_wet ? 'Yes' : 'No'}
active={!!is_wet}
tooltip="When enabled, noises are more fleshy and less rustly."
/>
</LabeledList.Item>
<LabeledList.Item label="Release Sound">
<Button
onClick={() => act('set_attribute', { attribute: 'b_release' })}
>
{release_sound}
</Button>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_releasesoundtest' })
}
icon="volume-up"
<LabeledList.Item label="Internal Loop">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_wetloop"
editMode={editMode}
content={wet_loop ? 'Yes' : 'No'}
active={!!wet_loop}
tooltip="Loops belly sounds."
/>
</LabeledList.Item>
<LabeledList.Item label="Use Fancy Sounds">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_fancy_sound"
editMode={editMode}
content={fancy ? 'Yes' : 'No'}
active={!!fancy}
tooltip="Switch between the fancy and classic sound set."
/>
</LabeledList.Item>
<LabeledList.Item label="Sound Volume">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_sound_volume' })
}
>
{sound_volume + '%'}
</Button>
<VorePanelEditNumber
action="set_attribute"
subAction="b_sound_volume"
editMode={editMode}
value={sound_volume}
minValue={0}
maxValue={100}
unit="%"
tooltip="Adjust the volume of your vore sounds."
/>
</LabeledList.Item>
<LabeledList.Item label="Noise Frequency">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_noise_freq' })
}
>
{noise_freq}
</Button>
<Stack>
<Stack.Item>
<VorePanelEditNumber
action="set_attribute"
subAction="b_noise_freq"
editMode={editMode}
value={noise_freq}
minValue={min_voice_freq}
maxValue={max_voice_freq}
/>
</Stack.Item>
<Stack.Item>
<VorePanelEditDropdown
action="set_attribute"
subAction="b_noise_freq"
editMode={editMode}
options={ourPresets}
entry={getDropdownDisplay(noise_freq)}
tooltip="Adjust the frequency of your vore sounds. The dropdown contains presets."
/>
</Stack.Item>
</Stack>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Vore Sound">
<Stack>
<Stack.Item>
<VorePanelEditDropdown
action="set_attribute"
subAction="b_sound"
editMode={editMode}
options={Object.keys(vore_sound_list)}
entry={sound}
/>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_soundtest' })
}
icon="volume-up"
tooltip="Test your selected belly sound. Usually played to prey inside your belly."
/>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Release Sound">
<Stack>
<Stack.Item>
<VorePanelEditDropdown
action="set_attribute"
subAction="b_release"
editMode={editMode}
options={Object.keys(release_sound_list)}
entry={release_sound}
/>
</Stack.Item>
<Stack.Item>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_releasesoundtest' })
}
icon="volume-up"
tooltip="Test your selected release sound. Usually played once prey is released."
/>
</Stack.Item>
</Stack>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
@@ -1,368 +1,173 @@
import { useBackend } from 'tgui/backend';
import { Box, Button, LabeledList, Section, Stack } from 'tgui-core/components';
import { classes } from 'tgui-core/react';
import { Button, LabeledList, Section, Stack } from 'tgui-core/components';
import { FeatureColorInput } from '../FeatureColorInput';
import type { selectedData } from '../types';
import type { bellyVisualData } from '../types';
import { VorePanelEditColor } from '../VorePanelElements/VorePanelEditColor';
import { VorePanelEditSwitch } from '../VorePanelElements/VorePanelEditSwitch';
import { BellyFullscreenSelection } from './VisualTab/BellyFullscreenSelection';
import { VoreSpriteAffects } from './VisualTab/VoreSpriteAffect';
export const VoreSelectedBellyVisuals = (props: { belly: selectedData }) => {
export const VoreSelectedBellyVisuals = (props: {
editMode: boolean;
bellyVisualData: bellyVisualData;
}) => {
const { act } = useBackend();
const { belly } = props;
const { editMode, bellyVisualData } = props;
const {
belly_fullscreen,
colorization_enabled,
belly_fullscreen_color,
belly_fullscreen_color2,
belly_fullscreen_color3,
belly_fullscreen_color4,
colorization_enabled,
belly_fullscreen_alpha,
possible_fullscreens,
disable_hud,
vore_sprite_flags,
affects_voresprite,
absorbed_voresprite,
absorbed_multiplier,
liquid_voresprite,
liquid_multiplier,
item_voresprite,
item_multiplier,
health_voresprite,
resist_animation,
voresprite_size_factor,
belly_sprite_option_shown,
belly_sprite_to_affect,
undergarment_chosen,
undergarment_if_none,
undergarment_color,
tail_option_shown,
tail_to_change_to,
} = belly;
} = bellyVisualData;
return (
<>
<Section title="Vore Sprites">
<Stack direction="row">
<LabeledList>
<LabeledList.Item label="Affect Vore Sprites">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_affects_vore_sprites' })
}
icon={affects_voresprite ? 'toggle-on' : 'toggle-off'}
selected={affects_voresprite}
>
{affects_voresprite ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
{affects_voresprite ? (
<>
<LabeledList.Item label="Vore Sprite Mode">
{(vore_sprite_flags.length && vore_sprite_flags.join(', ')) ||
'None'}
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_vore_sprite_flags' })
}
ml={1}
icon="plus"
/>
</LabeledList.Item>
<LabeledList.Item label="Count Absorbed prey for vore sprites">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_count_absorbed_prey_for_sprites',
})
}
icon={absorbed_voresprite ? 'toggle-on' : 'toggle-off'}
selected={absorbed_voresprite}
>
{absorbed_voresprite ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Absorbed Multiplier">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_absorbed_multiplier',
})
}
>
{absorbed_multiplier}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Count liquid reagents for vore sprites">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_count_liquid_for_sprites',
})
}
icon={liquid_voresprite ? 'toggle-on' : 'toggle-off'}
selected={liquid_voresprite}
>
{liquid_voresprite ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Liquid Multiplier">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_liquid_multiplier' })
}
>
{liquid_multiplier}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Count items for vore sprites">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_count_items_for_sprites',
})
}
icon={item_voresprite ? 'toggle-on' : 'toggle-off'}
selected={item_voresprite}
>
{item_voresprite ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Items Multiplier">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_item_multiplier' })
}
>
{item_multiplier}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Prey health affects vore sprites">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_health_impacts_size',
})
}
icon={health_voresprite ? 'toggle-on' : 'toggle-off'}
selected={health_voresprite}
>
{health_voresprite ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Animation when prey resist">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_resist_animation' })
}
icon={resist_animation ? 'toggle-on' : 'toggle-off'}
selected={resist_animation}
>
{resist_animation ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Vore Sprite Size Factor">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_size_factor_sprites',
})
}
>
{voresprite_size_factor}
</Button>
</LabeledList.Item>
{belly_sprite_option_shown ? (
<LabeledList.Item label="Belly Sprite to affect">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_belly_sprite_to_affect',
})
}
>
{belly_sprite_to_affect}
</Button>
</LabeledList.Item>
) : (
<LabeledList.Item label="Belly Sprite to affect">
<Box textColor="red">You do not have any bellysprites.</Box>
</LabeledList.Item>
)}
{tail_option_shown &&
vore_sprite_flags.includes('Undergarment addition') ? (
<>
<LabeledList.Item label="Undergarment type to affect">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_undergarment_choice',
})
}
>
{undergarment_chosen}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Undergarment if none equipped">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_undergarment_if_none',
})
}
>
{undergarment_if_none}
</Button>
</LabeledList.Item>
<FeatureColorInput
action_name="b_undergarment_color"
value_of={null}
back_color={undergarment_color}
name_of="Undergarment Color if none"
/>
</>
) : (
''
)}
{tail_option_shown &&
vore_sprite_flags.includes('Tail adjustment') ? (
<LabeledList.Item label="Tail to change to">
<Button
onClick={() =>
act('set_attribute', {
attribute: 'b_tail_to_change_to',
})
}
>
{tail_to_change_to}
</Button>
</LabeledList.Item>
) : (
''
)}
</>
) : (
''
)}
</LabeledList>
</Stack>
</Section>
<Section title="Belly Fullscreens Preview and Coloring">
<Stack align="center">
<FeatureColorInput
action_name="b_fullscreen_color"
value_of={null}
back_color={belly_fullscreen_color}
name_of="1"
/>
<FeatureColorInput
action_name="b_fullscreen_color2"
value_of={null}
back_color={belly_fullscreen_color2}
name_of="2"
/>
<FeatureColorInput
action_name="b_fullscreen_color3"
value_of={null}
back_color={belly_fullscreen_color3}
name_of="3"
/>
<FeatureColorInput
action_name="b_fullscreen_color4"
value_of={null}
back_color={belly_fullscreen_color4}
name_of="4"
/>
<FeatureColorInput
action_name="b_fullscreen_alpha"
value_of={null}
back_color="#FFFFFF"
name_of="Alpha"
/>
</Stack>
<Box mt={1}>
<LabeledList>
<LabeledList.Item label="Enable Coloration">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_colorization_enabled' })
}
icon={colorization_enabled ? 'toggle-on' : 'toggle-off'}
selected={colorization_enabled}
>
{colorization_enabled ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Preview Belly">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_preview_belly' })
}
>
Preview
</Button>
</LabeledList.Item>
<LabeledList.Item label="Clear Preview">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_clear_preview' })
}
>
Clear
</Button>
</LabeledList.Item>
</LabeledList>
</Box>
</Section>
<Section>
<Stack vertical fill>
<Stack.Item>
<Section
title="Affect Vore Sprites"
buttons={
<VorePanelEditSwitch
action="set_attribute"
subAction="b_affects_vore_sprites"
editMode={editMode}
tooltip="Allows you to toggle if this belly should effect voresprites"
active={!!affects_voresprite}
/>
}
>
{!!affects_voresprite && (
<VoreSpriteAffects
editMode={editMode}
bellyVisualData={bellyVisualData}
/>
)}
</Section>
</Stack.Item>
<Stack.Item>
<Section title="Vore FX">
<LabeledList>
<LabeledList.Item label="Disable Prey HUD">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_disable_hud' })
}
icon={disable_hud ? 'toggle-on' : 'toggle-off'}
selected={disable_hud}
>
{disable_hud ? 'Yes' : 'No'}
</Button>
</LabeledList.Item>
</LabeledList>
<Stack vertical fill>
<Stack.Item>
<Stack>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Enable Coloration">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_colorization_enabled"
editMode={editMode}
active={!!colorization_enabled}
tooltip="Switches between the legacy pre-colored icon set and the modern colorable one."
/>
</LabeledList.Item>
<LabeledList.Item label="Hide Prey HUD">
<VorePanelEditSwitch
action="set_attribute"
subAction="b_disable_hud"
editMode={editMode}
active={!!disable_hud}
tooltip="Allows you to hide your prey's game UI."
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Preview Belly">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_preview_belly' })
}
>
Preview
</Button>
</LabeledList.Item>
<LabeledList.Item label="Clear Preview">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_clear_preview' })
}
>
Clear
</Button>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
</Stack>
</Stack.Item>
{!!colorization_enabled && (
<>
<Stack.Divider />
<Stack.Item>
<Stack align="center">
<VorePanelEditColor
editMode={editMode}
action="set_attribute"
subAction="b_fullscreen_color"
value_of={null}
back_color={belly_fullscreen_color}
name_of="Color 1:"
tooltip="Set the Vore FX overlay's first color."
/>
<VorePanelEditColor
editMode={editMode}
action="set_attribute"
subAction="b_fullscreen_color2"
value_of={null}
back_color={belly_fullscreen_color2}
name_of="Color 2:"
tooltip="Set the Vore FX overlay's second color."
/>
<VorePanelEditColor
editMode={editMode}
action="set_attribute"
subAction="b_fullscreen_color3"
value_of={null}
back_color={belly_fullscreen_color3}
name_of="Color 3:"
tooltip="Set the Vore FX overlay's third color."
/>
<VorePanelEditColor
editMode={editMode}
action="set_attribute"
subAction="b_fullscreen_color4"
value_of={null}
back_color={belly_fullscreen_color4}
name_of="Color 4:"
tooltip="Set the Vore FX overlay's fourth color."
/>
<VorePanelEditColor
removePlaceholder
editMode={editMode}
action="set_attribute"
subAction="b_fullscreen_alpha"
value_of={null}
back_color="#FFFFFF"
alpha={belly_fullscreen_alpha}
name_of="Alpha:"
tooltip="Set the Vore FX overlay's transparency."
/>
</Stack>
</Stack.Item>
</>
)}
</Stack>
</Section>
<Section title="Belly Fullscreens Styles" width="800px">
Belly styles:
<Button
fluid
selected={belly_fullscreen === '' || belly_fullscreen === null}
onClick={() =>
act('set_attribute', { attribute: 'b_fullscreen', val: null })
}
>
Disabled
</Button>
{Object.keys(possible_fullscreens).map((key, index) => (
<span key={index} style={{ width: '256px' }}>
<Button
width="256px"
height="256px"
selected={key === belly_fullscreen}
onClick={() =>
act('set_attribute', { attribute: 'b_fullscreen', val: key })
}
>
<Box
className={classes([
colorization_enabled ? 'vore240x240' : 'fixedvore240x240',
key,
])}
style={{
transform: 'translate(0%, 4%)',
}}
/>
</Button>
</span>
))}
</Section>
</Section>
</>
</Stack.Item>
<Stack.Item grow>
<BellyFullscreenSelection
editMode={editMode}
belly_fullscreen={belly_fullscreen}
colorization_enabled={colorization_enabled}
possible_fullscreens={possible_fullscreens}
/>
</Stack.Item>
</Stack>
);
};
@@ -1,198 +0,0 @@
import { useBackend } from 'tgui/backend';
import {
Box,
Button,
Dropdown,
LabeledList,
Section,
Stack,
} from 'tgui-core/components';
import type {
abilities,
bellyData,
DropdownEntry,
soulcatcherData,
} from './types';
import { VoreAbilities } from './VoreAbilities';
import { CatchSettings } from './VoreSoulcatcherSettings/CatchSettings';
import { GlobalOptions } from './VoreSoulcatcherSettings/GlobalOptions';
import { GlobalSettings } from './VoreSoulcatcherSettings/GlobalSettings';
import { SoulOptions } from './VoreSoulcatcherSettings/SoulOptions';
export const VoreSoulcatcher = (props: {
soulcatcher: soulcatcherData | null;
our_bellies: Required<bellyData[]> & {
map(arg0: (belly: bellyData) => DropdownEntry): DropdownEntry[];
};
abilities: abilities;
}) => {
const { soulcatcher, our_bellies, abilities } = props;
const getBellies = our_bellies.map((belly) => {
return { ...belly, displayText: belly.name, value: belly.ref };
});
return (
<Section scrollable fill>
{soulcatcher && (
<VoreSoulcatcherSection
soulcatcher={soulcatcher}
overlayBellies={getBellies}
/>
)}
<VoreAbilities abilities={abilities} />
</Section>
);
};
const VoreSoulcatcherSection = (props: {
soulcatcher: soulcatcherData;
overlayBellies: DropdownEntry[];
}) => {
const { act } = useBackend();
const { soulcatcher, overlayBellies } = props;
const {
active,
name,
caught_souls,
selected_soul,
interior_design,
catch_self,
catch_prey,
catch_drain,
catch_ghost,
ext_hearing,
ext_vision,
mind_backups,
sr_projecting,
see_sr_projecting,
selected_sfx,
show_vore_sfx,
taken_over,
} = soulcatcher;
return (
<Section
title={'Soulcatcher (' + name + ')'}
buttons={
<Stack>
<Stack.Item>
<Button
onClick={() => act('soulcatcher_rename')}
icon="pen"
tooltip="Click here to rename your soulcatcher."
/>
</Stack.Item>
<Stack.Item>
<Button
onClick={() => act('soulcatcher_toggle')}
icon={active ? 'toggle-on' : 'toggle-off'}
tooltip={
(active ? 'Disables' : 'Enables') +
' the ability to capture souls upon vore death.'
}
tooltipPosition="top"
selected={active}
>
{active ? 'Soulcatcher On' : 'Soulcatcher Off'}
</Button>
</Stack.Item>
</Stack>
}
>
{active ? (
<LabeledList>
<LabeledList.Item label="Captured Souls">
<Stack inline align="center">
<Stack.Item>
<Dropdown
width="200px"
selected={selected_soul}
options={caught_souls}
onSelected={(value) =>
act('soulcatcher_select', {
selected_soul: value,
})
}
/>
</Stack.Item>
<Stack.Item>
<Box>{caught_souls.length}</Box>
</Stack.Item>
</Stack>
</LabeledList.Item>
{selected_soul ? <SoulOptions taken_over={taken_over} /> : ''}
{caught_souls.length ? <GlobalOptions taken_over={taken_over} /> : ''}
<CatchSettings
catch_self={catch_self}
catch_prey={catch_prey}
catch_drain={catch_drain}
catch_ghost={catch_ghost}
/>
<GlobalSettings
ext_hearing={ext_hearing}
ext_vision={ext_vision}
mind_backups={mind_backups}
sr_projecting={sr_projecting}
see_sr_projecting={see_sr_projecting}
show_vore_sfx={show_vore_sfx}
/>
<LabeledList.Item
label="Interior Design"
buttons={
<Button
icon="wand-magic-sparkles"
tooltip="Customize your soulcatcher flavour text."
tooltipPosition="left"
onClick={() => act('soulcatcher_interior_design')}
/>
}
>
{interior_design}
</LabeledList.Item>
<LabeledList.Item label="Interior SFX">
<Dropdown
width="200px"
selected={selected_sfx}
options={overlayBellies}
onSelected={(value) =>
act('soulcatcher_sfx', {
selected_belly: value,
})
}
/>
</LabeledList.Item>
<LabeledList.Item label="Custom Messages">
<Stack>
<Stack.Item>
<Button onClick={() => act('soulcatcher_capture_message')}>
Capture Message
</Button>
</Stack.Item>
<Stack.Item>
<Button onClick={() => act('soulcatcher_transit_message')}>
Transit Message
</Button>
</Stack.Item>
<Stack.Item>
<Button onClick={() => act('soulcatcher_release_message')}>
Release Message
</Button>
</Stack.Item>
<Stack.Item>
<Button onClick={() => act('soulcatcher_delete_message')}>
Delete Message
</Button>
</Stack.Item>
</Stack>
</LabeledList.Item>
</LabeledList>
) : (
'Soulcatching disabled.'
)}
</Section>
);
};
@@ -3,6 +3,7 @@ import { Button, LabeledList, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
export const CatchSettings = (props: {
editMode: boolean;
catch_self: BooleanLike;
catch_prey: BooleanLike;
catch_drain: BooleanLike;
@@ -10,13 +11,14 @@ export const CatchSettings = (props: {
}) => {
const { act } = useBackend();
const { catch_self, catch_prey, catch_drain, catch_ghost } = props;
const { editMode, catch_self, catch_prey, catch_drain, catch_ghost } = props;
return (
<LabeledList.Item label="Catch Settings">
<Stack>
<Stack.Item>
<Button
disabled={!editMode}
icon="circle-user"
tooltip={
(catch_self ? 'Allow' : 'Disallow') +
@@ -31,6 +33,7 @@ export const CatchSettings = (props: {
</Stack.Item>
<Stack.Item>
<Button
disabled={!editMode}
icon="person"
tooltip={
(catch_prey ? 'Allow' : 'Disallow') +
@@ -45,6 +48,7 @@ export const CatchSettings = (props: {
</Stack.Item>
<Stack.Item>
<Button
disabled={!editMode}
icon="person-falling-burst"
tooltip={
(catch_drain ? 'Allow' : 'Disallow') +
@@ -59,6 +63,7 @@ export const CatchSettings = (props: {
</Stack.Item>
<Stack.Item>
<Button
disabled={!editMode}
icon="ghost"
tooltip={
(catch_ghost ? 'Allow' : 'Disallow') +
@@ -3,6 +3,7 @@ import { Button, LabeledList, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
export const GlobalSettings = (props: {
editMode: boolean;
ext_hearing: BooleanLike;
ext_vision: BooleanLike;
mind_backups: BooleanLike;
@@ -13,6 +14,7 @@ export const GlobalSettings = (props: {
const { act } = useBackend();
const {
editMode,
ext_hearing,
ext_vision,
mind_backups,
@@ -26,6 +28,7 @@ export const GlobalSettings = (props: {
<Stack>
<Stack.Item>
<Button
disabled={!editMode}
icon={ext_hearing ? 'ear-listen' : 'ear-deaf'}
tooltip={
(ext_hearing ? 'Allow' : 'Disallow') +
@@ -40,6 +43,7 @@ export const GlobalSettings = (props: {
</Stack.Item>
<Stack.Item>
<Button
disabled={!editMode}
icon={ext_vision ? 'eye' : 'eye-slash'}
tooltip={
(ext_vision ? 'Allow' : 'Disallow') +
@@ -54,6 +58,7 @@ export const GlobalSettings = (props: {
</Stack.Item>
<Stack.Item>
<Button
disabled={!editMode}
icon="database"
tooltip={
(mind_backups ? 'Allow' : 'Disallow') +
@@ -68,6 +73,7 @@ export const GlobalSettings = (props: {
</Stack.Item>
<Stack.Item>
<Button
disabled={!editMode}
icon="street-view"
tooltip={
(sr_projecting ? 'Allow' : 'Disallow') +
@@ -82,6 +88,7 @@ export const GlobalSettings = (props: {
</Stack.Item>
<Stack.Item>
<Button
disabled={!editMode}
icon="eye-low-vision"
tooltip={
(see_sr_projecting ? 'Enable' : 'Disable') +
@@ -98,6 +105,7 @@ export const GlobalSettings = (props: {
</Stack.Item>
<Stack.Item>
<Button
disabled={!editMode}
icon={show_vore_sfx ? 'circle-play' : 'circle-pause'}
tooltip={
(show_vore_sfx ? 'Show' : 'Hide') +
@@ -10,7 +10,7 @@ export const SoulOptions = (props: { taken_over: BooleanLike }) => {
return (
<LabeledList.Item label="Soul Options">
<Stack>
{!taken_over ? (
{!taken_over && (
<>
<Stack.Item>
<Button
@@ -46,8 +46,6 @@ export const SoulOptions = (props: { taken_over: BooleanLike }) => {
</Button.Confirm>
</Stack.Item>
</>
) : (
''
)}
<Stack.Item>
<Button
@@ -1,70 +1,156 @@
import { useBackend } from 'tgui/backend';
import { Button, Section, Stack } from 'tgui-core/components';
import { LabeledList, NoticeBox, Section, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { capitalize } from 'tgui-core/string';
import type { localPrefs, selectedData } from '../types';
import { VoreUserPreferenceItem } from '../VoreUserPreferenceItem';
import { aestehticTabsToIcons } from '../constants';
import { fixCorruptedData } from '../functions';
import type { aestMessageData, bellyData } from '../types';
import { VorePanelEditToggle } from '../VorePanelElements/VorePanelCommonElements';
import { VorePanelEditTextTabs } from '../VorePanelElements/VorePaneldEditTextTabs';
import { VorePanelEditColor } from '../VorePanelElements/VorePanelEditColor';
import { VorePanelEditDropdown } from '../VorePanelElements/VorePanelEditDropdown';
import { VorePanelEditSwitch } from '../VorePanelElements/VorePanelEditSwitch';
export const VoreUserPreferencesAesthetic = (props: {
editMode: boolean;
toggleEditMode: React.Dispatch<React.SetStateAction<boolean>>;
active_belly: string | null;
our_bellies: bellyData[];
belly_rub_target: string | null;
selected: selectedData | null;
preferences: localPrefs;
vore_sprite_color: Record<string, string>;
vore_sprite_multiply: Record<string, BooleanLike>;
vore_icon_options: string[];
aestethicMessages: aestMessageData;
}) => {
const { act } = useBackend();
const { belly_rub_target, selected, preferences } = props;
const {
editMode,
toggleEditMode,
active_belly,
belly_rub_target,
our_bellies,
vore_sprite_color,
vore_sprite_multiply,
vore_icon_options,
aestethicMessages,
} = props;
const sanitizeCorruption = fixCorruptedData(aestethicMessages.active_message);
const getBellies = our_bellies.map((belly) => {
return belly.name;
});
const locationNames = [...getBellies, 'Current Selected'];
const capitalizedName = active_belly && capitalize(active_belly);
return (
<Section title="Aesthetic Preferences">
<Stack wrap="wrap" justify="center">
<Stack.Item basis="49%" grow>
<Button fluid icon="grin-tongue" onClick={() => act('setflavor')}>
Set Taste
</Button>
<Section
fill
title="Aesthetic Preferences"
scrollable
buttons={
<VorePanelEditToggle
editMode={editMode}
toggleEditMode={toggleEditMode}
/>
}
>
<Stack vertical fill>
<Stack.Item>
<Stack>
<Stack.Item basis="49%" grow>
<LabeledList>
{vore_icon_options.map((entry) => (
<LabeledList.Item key={entry} label={capitalize(entry)}>
<Stack align="center">
<VorePanelEditColor
name_of="sprite color"
removePlaceholder
editMode={editMode}
action="set_vs_color"
subAction={entry}
back_color={vore_sprite_color[entry]}
tooltip={
"Modify the sprite color of your '" +
entry +
"' sprite."
}
value_of={undefined}
/>
<Stack.Item>
<VorePanelEditSwitch
hideIcon
editMode={editMode}
action="toggle_vs_multiply"
subAction={entry}
active={!!vore_sprite_multiply[entry]}
tooltip={
"Switch between color multiply and add mode for your '" +
entry +
"' sprite."
}
color={!editMode ? 'white' : undefined}
content={
vore_sprite_multiply[entry] ? 'Multiply' : 'Add'
}
/>
</Stack.Item>
</Stack>
</LabeledList.Item>
))}
</LabeledList>
</Stack.Item>
<Stack.Item basis="49%" grow>
<LabeledList>
<LabeledList.Item label="Belly Rub Target">
<VorePanelEditDropdown
action={'set_belly_rub'}
icon="crosshairs"
editMode={editMode}
options={locationNames}
entry={
belly_rub_target
? belly_rub_target
: 'Current Selected (' + capitalizedName + ')'
}
/>
</LabeledList.Item>
</LabeledList>
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item basis="49%">
<Button fluid icon="wind" onClick={() => act('setsmell')}>
Set Smell
</Button>
</Stack.Item>
<Stack.Item basis="49%" grow>
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'en' })
}
icon="flask"
fluid
>
Set Nutrition Examine Message
</Button>
</Stack.Item>
<Stack.Item basis="49%">
<Button
onClick={() =>
act('set_attribute', { attribute: 'b_msgs', msgtype: 'ew' })
}
icon="weight-hanging"
fluid
>
Set Weight Examine Message
</Button>
</Stack.Item>
<Stack.Item basis="49%" grow>
<VoreUserPreferenceItem spec={preferences.examine_nutrition} />
</Stack.Item>
<Stack.Item basis="49%">
<VoreUserPreferenceItem spec={preferences.examine_weight} />
</Stack.Item>
<Stack.Item basis="49%" grow>
<Button fluid onClick={() => act('set_vs_color')} icon="palette">
Vore Sprite Color
</Button>
</Stack.Item>
<Stack.Item basis="49%">
<Button fluid onClick={() => act('set_belly_rub')} icon="crosshairs">
{'Belly Rub Target: ' +
(belly_rub_target
? belly_rub_target
: 'Current Active (' + (selected && selected.belly_name) + ')')}
</Button>
<Stack.Divider />
<Stack.Item grow>
<Section fill>
{!!sanitizeCorruption.corrupted && (
<Stack.Item>
<NoticeBox danger>
Your {'>' + aestethicMessages.aest_subtab + '<'} messages are
corrupted, please edit and save them!
</NoticeBox>
</Stack.Item>
)}
<VorePanelEditTextTabs
exactLength
editMode={editMode}
messsageOptions={aestethicMessages.possible_messages}
activeTab={aestethicMessages.aest_subtab}
tabAction="change_aset_message_option"
tabsToIcons={aestehticTabsToIcons}
tooltip={aestethicMessages.tooltip}
maxLength={aestethicMessages.max_length}
activeMessage={sanitizeCorruption.data}
action={aestethicMessages.set_action}
listAction="b_msgs"
disableLegacyInput={!Array.isArray(sanitizeCorruption)}
subAction={aestethicMessages.sub_action}
button_action={aestethicMessages.button_action}
button_label={aestethicMessages.button_label}
button_data={!!aestethicMessages.button_data}
button_tooltip={aestethicMessages.button_tooltip}
/>
</Section>
</Stack.Item>
</Stack>
</Section>
@@ -4,7 +4,7 @@ import type { BooleanLike } from 'tgui-core/react';
import { capitalize } from 'tgui-core/string';
import type { localPrefs } from '../types';
import { VoreUserPreferenceItem } from '../VoreUserPreferenceItem';
import { VoreUserPreferenceItem } from '../VorePanelElements/VoreUserPreferenceItem';
export const VoreUserPreferencesDevouring = (props: {
devourable: BooleanLike;
@@ -3,7 +3,7 @@ import { Button, Section, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import type { localPrefs } from '../types';
import { VoreUserPreferenceItem } from '../VoreUserPreferenceItem';
import { VoreUserPreferenceItem } from '../VorePanelElements/VoreUserPreferenceItem';
export const VoreUserPreferencesMechanical = (props: {
show_pictures: BooleanLike;
@@ -2,7 +2,7 @@ import { Section, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import type { localPrefs } from '../types';
import { VoreUserPreferenceItem } from '../VoreUserPreferenceItem';
import { VoreUserPreferenceItem } from '../VorePanelElements/VoreUserPreferenceItem';
export const VoreUserPreferencesSoulcatcher = (props: {
soulcatcher_allow_capture: BooleanLike;
@@ -3,7 +3,7 @@ import { Button, NumberInput, Section, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import type { localPrefs } from '../types';
import { VoreUserPreferenceItem } from '../VoreUserPreferenceItem';
import { VoreUserPreferenceItem } from '../VorePanelElements/VoreUserPreferenceItem';
export const VoreUserPreferencesSpawn = (props: {
latejoin_vore: BooleanLike;
@@ -2,7 +2,7 @@ import { Section, Stack } from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import type { localPrefs } from '../types';
import { VoreUserPreferenceItem } from '../VoreUserPreferenceItem';
import { VoreUserPreferenceItem } from '../VorePanelElements/VoreUserPreferenceItem';
export const VoreUserPreferencesSpontaneous = (props: {
can_be_drop_prey: BooleanLike;
@@ -1,11 +1,15 @@
export const stats: (string | undefined)[] = [undefined, 'average', 'bad'];
export const vorespawnAbsorbedText: string[] = ['No', 'Yes', 'Prey Choice'];
export const vorespawnAbsorbedColor: (string | undefined)[] = [
undefined,
'green',
'orange',
];
export const selectiveBellyOptions = ['Digest', 'Absorb'];
export const digestModeToColor = {
Default: undefined,
Hold: undefined,
@@ -19,6 +23,8 @@ export const digestModeToColor = {
'Size Steal': 'teal',
Heal: 'green',
'Encase In Egg': 'blue',
'Digest (Food Only)': 'red',
'Digest (Dispersed Damage)': 'red',
};
export const reagentToColor = {
@@ -57,3 +63,86 @@ export const SYNTAX_COLOR = {
'%pred': 'bad',
'%prey': 'good',
};
export const tabToNames = [
'Controls',
'Descriptions',
'Options',
'Sounds',
'Visuals',
'Interactions',
'Contents',
'Liquid Options',
];
export const modeToTooltip = {
Numbing: 'Prey will recieve no pain from vorgan damage.',
Stripping: 'Strips prey of all equipped items.',
'Leave Remains': 'Prey might leave remains like bones.',
Muffles: 'Causes all prey messages to become subtles.',
'Affect Worn Items': 'Allows vorgan to coat and digest equipped items.',
'Jams Sensors': 'Blocks medical sensors, but not GPS.',
'Complete Absorb': 'Limits conversation to direct pred / prey.',
'Spare Prosthetics': 'Applies no damage to synthetic limbs. ',
'Slow Body Digestion': 'Continues to digest a body after the prey has died.',
'Muffle Items': ' Muffles noise from items inside the vorgan.',
'TURBO MODE': 'Heavily increases tick speed of the vorgan (6x).',
};
export const spriteToTooltip = {
'Normal Belly Sprite':
"This belly will effect the mob's belly sprite if available.",
'Undergarment addition':
"This belly will effect the mob's undergarment sprite if available.",
};
export const liquidToTooltip = {
'Produce Liquids': 'Enables automatic belly liquid porduction.',
'Digestion Liquids':
'Enables belly liquid production while prey is being diegested.',
'Absorption Liquids':
'Enables belly liquid production while prey is being absorbed.',
'Draining Liquids':
'Enables belly liquid production while prey is being drained.',
};
export const messageTabLabel = [
'Description',
'Examine',
'Trash Eater',
'Struggle',
'Escape',
'Escape (Absorbed)',
'Transfer',
'Interaction Chance',
'Bellymode',
'Idle',
'Liquid Fullness',
];
export const eatingMessagePrivacy = {
default: undefined,
subtle: 'green',
loud: 'red',
};
export const robotBellyOptions = ['Sleeper', 'Vorebelly', 'Both'];
export const noSelectionName = { displayText: 'None - Remove', value: '' };
export const nutriTimeToText = {
0: '10 minutes',
2: '30 minutes',
5: '1 hour',
17: '3 hours',
35: '6 hours',
71: '12 hours',
143: '24 hours',
};
export const aestehticTabsToIcons = {
'Set Taste': 'grin-tongue',
'Set Smell': 'wind',
'Set Nutrition Examine': 'flask',
'Set Weight Examine': 'weight-hanging',
};
@@ -0,0 +1,67 @@
export function abilitiy_usable(nutri: number, cost: number): boolean {
return nutri >= cost;
}
export function sanitize_color(color?: string | null, mirrorBlack?: boolean) {
if (!color) {
return undefined;
}
if (mirrorBlack && color === 'black') {
return 'white';
}
const ctx = document.createElement('canvas').getContext('2d');
if (!ctx) {
return undefined;
}
ctx.fillStyle = color;
return ctx.fillStyle;
}
export function calcLineHeight(lim: number, height: number) {
return (Math.ceil(lim / 25 / height + 0.5) * height).toFixed() + 'px';
}
export function fixCorruptedData(
toSanitize:
| string
| string[]
| null
| Record<string | number, string | number>,
) {
if (toSanitize === null) {
return { data: '' };
}
if (typeof toSanitize === 'string') {
return { data: toSanitize };
}
if (Array.isArray(toSanitize)) {
return { data: toSanitize };
}
const clearedData = Object.entries(toSanitize).map((entry) => {
if (typeof entry[0] === 'string') {
return entry[0];
} else if (typeof entry[1] === 'string') {
return entry[1];
} else {
return '';
}
});
return { corrupted: true, data: clearedData || [] };
}
// Those can't be used currently, due to byond limitations
export async function copy_to_clipboard(value: string | string[]) {
let data = value;
if (Array.isArray(data)) {
data = data.join('\n\n');
}
await navigator.clipboard.writeText(data);
}
export async function paste_from_clipboard(asArray = false) {
const ourText = await navigator.clipboard.readText();
if (asArray) {
return ourText.split('\n\n');
}
return ourText;
}
@@ -4,10 +4,11 @@ import { Window } from 'tgui/layouts';
import { Button, Icon, NoticeBox, Stack, Tabs } from 'tgui-core/components';
import type { Data } from './types';
import { VoreBellySelectionAndCustomization } from './VoreBellySelectionAndCustomization';
import { VoreInsidePanel } from './VoreInsidePanel';
import { VoreSoulcatcher } from './VoreSoulcatcher';
import { VoreUserPreferences } from './VoreUserPreferences';
import { VoreBellySelectionAndCustomization } from './VorePanelMainTabs/VoreBellySelectionAndCustomization';
import { VoreInsidePanel } from './VorePanelMainTabs/VoreInsidePanel';
import { VoreSoulcatcher } from './VorePanelMainTabs/VoreSoulcatcher';
import { VoreUserGeneral } from './VorePanelMainTabs/VoreUserGeneral';
import { VoreUserPreferences } from './VorePanelMainTabs/VoreUserPreferences';
/**
* There are three main sections to this UI.
@@ -153,6 +154,8 @@ export const VorePanel = () => {
const { act, data } = useBackend<Data>();
const {
active_tab,
active_vore_tab,
inside,
our_bellies,
selected,
@@ -164,40 +167,53 @@ export const VorePanel = () => {
host_mobtype,
unsaved_changes,
vore_words,
general_pref_data,
} = data;
const [tabIndex, setTabIndex] = useState(0);
const [editMode, setEditMode] = useState(false);
const tabs: React.JSX.Element[] = [];
const tabs: (React.JSX.Element | null | undefined)[] = [];
tabs[0] = (
tabs[0] = our_bellies && selected && host_mobtype && (
<VoreBellySelectionAndCustomization
activeVoreTab={active_vore_tab}
our_bellies={our_bellies}
selected={selected}
show_pictures={show_pictures}
host_mobtype={host_mobtype}
icon_overflow={icon_overflow}
vore_words={vore_words}
toggleEditMode={setEditMode}
editMode={editMode}
/>
);
tabs[1] = (
tabs[1] = our_bellies && soulcatcher && abilities && (
<VoreSoulcatcher
our_bellies={our_bellies}
soulcatcher={soulcatcher}
abilities={abilities}
toggleEditMode={setEditMode}
editMode={editMode}
/>
);
tabs[2] = (
tabs[2] = general_pref_data && our_bellies && (
<VoreUserGeneral
general_pref_data={general_pref_data}
our_bellies={our_bellies}
editMode={editMode}
toggleEditMode={setEditMode}
/>
);
tabs[3] = prefs && (
<VoreUserPreferences
prefs={prefs}
selected={selected}
show_pictures={show_pictures}
icon_overflow={icon_overflow}
/>
);
return (
<Window width={1000} height={660} theme="abstract">
<Window width={1030} height={760} theme="abstract">
<Window.Content>
<Stack fill vertical>
<Stack.Item>
@@ -236,29 +252,36 @@ export const VorePanel = () => {
<Stack.Item>
<Tabs>
<Tabs.Tab
selected={tabIndex === 0}
onClick={() => setTabIndex(0)}
selected={active_tab === 0}
onClick={() => act('change_tab', { tab: 0 })}
>
Bellies
<Icon name="list" ml={0.5} />
</Tabs.Tab>
<Tabs.Tab
selected={tabIndex === 1}
onClick={() => setTabIndex(1)}
selected={active_tab === 1}
onClick={() => act('change_tab', { tab: 1 })}
>
Soulcatcher
<Icon name="ghost" ml={0.5} />
</Tabs.Tab>
<Tabs.Tab
selected={tabIndex === 2}
onClick={() => setTabIndex(2)}
selected={active_tab === 2}
onClick={() => act('change_tab', { tab: 2 })}
>
General
<Icon name="user-circle" ml={0.5} />
</Tabs.Tab>
<Tabs.Tab
selected={active_tab === 3}
onClick={() => act('change_tab', { tab: 3 })}
>
Preferences
<Icon name="user-cog" ml={0.5} />
</Tabs.Tab>
</Tabs>
</Stack.Item>
<Stack.Item grow>{tabs[tabIndex] || 'Error'}</Stack.Item>
<Stack.Item grow>{tabs[active_tab] || 'Error'}</Stack.Item>
</Stack>
</Window.Content>
</Window>
+197 -127
View File
@@ -1,21 +1,28 @@
import type { BooleanLike } from 'tgui-core/react';
export type Data = {
vore_words: Record<string, string[]>;
unsaved_changes: BooleanLike;
inside: insideData;
show_pictures: BooleanLike;
icon_overflow: BooleanLike;
inside: insideData;
host_mobtype: hostMob;
our_bellies: bellyData[];
selected: selectedData | null;
prefs: prefData;
soulcatcher: soulcatcherData | null;
abilities: abilities;
vore_words: Record<string, string[]>;
active_tab: number;
host_mobtype: hostMob | null;
our_bellies?: bellyData[] | null;
selected?: selectedData | null;
prefs?: prefData | null;
soulcatcher?: soulcatcherData | null;
abilities?: abilities | null;
active_vore_tab?: number;
general_pref_data?: generalPrefData | null;
};
export type abilities = {
nutrition: number;
size_change: abilitySizeChange;
};
export type abilitySizeChange = {
current_size: number;
minimum_size: number;
maximum_size: number;
@@ -40,94 +47,115 @@ export type insideData = {
contents?: contentData[];
};
export type contentData = {
name: string;
absorbed: BooleanLike;
stat: number;
ref: string;
outside: BooleanLike;
icon: string;
};
export type bellyData = {
selected: BooleanLike;
name: string;
ref: string;
digest_mode: string;
contents: number;
prevent_saving: BooleanLike;
selected?: BooleanLike;
digest_mode?: string;
contents?: number;
prevent_saving?: BooleanLike;
};
export type selectedData = {
belly_name: string;
message_mode: BooleanLike;
is_wet: BooleanLike;
wet_loop: BooleanLike;
export type bellyModeData = {
mode: string;
item_mode: string;
addons: checkBoxEntry[];
name_length: number;
name_min: number;
mode_options: string[];
item_mode_options: string[];
};
export type bellyDescriptionData = {
verb: string;
release_verb: string;
desc: string;
absorbed_desc: string;
fancy: BooleanLike;
sound: string;
release_sound: string;
message_mode: BooleanLike;
displayed_options: number[];
message_option: number;
message_subtab: string;
selected_message: string;
emote_time: number;
emote_active: BooleanLike;
show_liq_fullness: BooleanLike;
entrance_logs: BooleanLike;
item_digest_logs: BooleanLike;
name_length: number;
name_min: number;
displayed_message_types: {
subtypes?: string[];
possible_messages?: string[] | null;
max_length: number;
set_action: string;
tooltip: string;
active_message: string | string[] | null;
button_action?: string;
button_data?: BooleanLike;
button_label?: string;
button_tooltip?: string;
} | null;
};
export type bellyOptionData = {
can_taste: BooleanLike;
is_feedable: BooleanLike;
egg_type: string;
egg_name: string;
egg_size: number;
recycling: BooleanLike;
storing_nutrition: BooleanLike;
entrance_logs: BooleanLike;
nutrition_percent: number;
digest_brute: number;
digest_burn: number;
digest_oxy: number;
digest_tox: number;
digest_clone: number;
digest_max: number;
digest_free: number;
bulge_size: number;
save_digest_mode: BooleanLike;
display_absorbed_examine: BooleanLike;
shrink_grow_size: number;
emote_time: number;
emote_active: BooleanLike;
contaminates: BooleanLike;
contaminate_flavor: string | null;
contaminate_color: string | null;
contaminate_options: Record<string, string>[] | null;
contaminate_colors: string[] | null;
egg_type: string;
egg_types: string[];
egg_name: string;
egg_size: number;
recycling: BooleanLike;
storing_nutrition: BooleanLike;
selective_preference: string;
nutrition_ex: BooleanLike;
weight_ex: BooleanLike;
belly_fullscreen: string;
save_digest_mode: BooleanLike;
eating_privacy_local: string;
silicon_belly_overlay_preference: string;
belly_mob_mult: number;
belly_item_mult: number;
belly_overall_mult: number;
vorespawn_blacklist: BooleanLike;
vorespawn_whitelist: string[];
vorespawn_absorbed: number;
private_struggle: BooleanLike;
drainmode_options: string[];
drainmode: string;
mob_belly_controls: siliconeBellyControls;
};
export type bellySoundData = {
is_wet: BooleanLike;
wet_loop: BooleanLike;
fancy: BooleanLike;
sound: string;
release_sound: string;
sound_volume: number;
noise_freq: number;
min_voice_freq: number;
max_voice_freq: number;
vore_sound_list: Record<string, string>;
release_sound_list: Record<string, string>;
};
export type bellyVisualData = {
belly_fullscreen: string;
colorization_enabled: BooleanLike;
belly_fullscreen_color: string;
belly_fullscreen_color2: string;
belly_fullscreen_color3: string;
belly_fullscreen_color4: string;
belly_fullscreen_alpha: number;
colorization_enabled: BooleanLike;
custom_reagentcolor: string;
custom_reagentalpha: number;
liquid_overlay: BooleanLike;
max_liquid_level: number;
reagent_touches: BooleanLike;
mush_overlay: BooleanLike;
mush_color: string;
mush_alpha: number;
max_mush: number;
min_mush: number;
item_mush_val: number;
metabolism_overlay: BooleanLike;
metabolism_mush_ratio: number;
max_ingested: number;
custom_ingested_color: string;
custom_ingested_alpha: number;
vorespawn_blacklist: BooleanLike;
vorespawn_whitelist: string[];
vorespawn_absorbed: number;
sound_volume: number;
possible_fullscreens: string[];
disable_hud: BooleanLike;
vore_sprite_flags: checkBoxEntry[];
affects_voresprite: BooleanLike;
absorbed_voresprite: BooleanLike;
absorbed_multiplier: number;
@@ -139,34 +167,55 @@ export type selectedData = {
resist_animation: BooleanLike;
voresprite_size_factor: number;
belly_sprite_to_affect: string;
belly_sprite_options: string[] | null;
undergarment_chosen: string;
undergarment_if_none: string;
undergarment_options: string[];
undergarment_options_if_none: string[];
undergarment_color: string;
belly_sprite_option_shown: BooleanLike;
tail_option_shown: BooleanLike;
tail_to_change_to: BooleanLike | string;
tail_colouration: BooleanLike;
tail_extra_overlay: BooleanLike;
tail_extra_overlay2: BooleanLike;
noise_freq: number;
item_digest_logs: BooleanLike;
private_struggle: BooleanLike;
addons: string[];
vore_sprite_flags: string[];
contaminates: BooleanLike;
contaminate_flavor: string | null;
contaminate_color: string | null;
tail_sprite_options: string[];
};
export type bellyInteractionData = {
escapable: BooleanLike;
interacts: interactData;
autotransfer_enabled: BooleanLike;
autotransfer: autotransferData;
disable_hud: BooleanLike;
possible_fullscreens: string[];
contents: contentData[];
};
export type contentData = {
name: string;
absorbed: BooleanLike;
stat: number;
ref: string;
outside: BooleanLike;
icon: string;
};
export type bellyLiquidData = {
show_liq: BooleanLike;
liq_interacts: liqInteractData;
show_liq_fullness: BooleanLike;
liq_messages: liqMessageData;
};
export type siliconeBellyControls = {
silicon_belly_overlay_preference: string;
belly_sprite_option_shown: BooleanLike;
belly_sprite_to_affect: string;
};
export type selectedData = {
belly_name: string;
belly_mode_data?: bellyModeData;
belly_description_data?: bellyDescriptionData;
belly_option_data?: bellyOptionData;
belly_sound_data?: bellySoundData;
belly_visual_data?: bellyVisualData;
belly_interaction_data?: bellyInteractionData;
contents?: contentData[] | null;
content_length: number;
belly_liquid_data?: bellyLiquidData;
};
export type interactData = {
@@ -183,36 +232,37 @@ export type interactData = {
};
export type autotransferData = {
autotransferchance: number;
autotransferwait: number;
autotransferlocation: string;
autotransferextralocation: string[];
autotransferchance_secondary: number;
autotransferlocation_secondary: string;
autotransferextralocation_secondary: string[];
autotransfer_min_amount: number;
autotransfer_max_amount: number;
autotransfer_whitelist: string[];
autotransfer_blacklist: string[];
autotransfer_whitelist_items: string[];
autotransfer_blacklist_items: string[];
autotransfer_secondary_whitelist: string[];
autotransfer_secondary_blacklist: string[];
autotransfer_secondary_whitelist_items: string[];
autotransfer_secondary_blacklist_items: string[];
primary_transfer: autoTransferOption;
secondary_transfer: autoTransferOption;
};
type liqInteractData = {
export type autoTransferOption = {
autotransferchance: number;
autotransferlocation: string | null;
autotransferextralocation: string[];
autotransfer_whitelist: checkBoxEntry[];
autotransfer_blacklist: checkBoxEntry[];
autotransfer_whitelist_items: checkBoxEntry[];
autotransfer_blacklist_items: checkBoxEntry[];
};
export type liqInteractData = {
liq_reagent_gen: BooleanLike;
liq_reagent_type: string;
liq_reagent_types: string[];
liq_reagent_name: string;
liq_custom_name_max: number;
liq_custom_name_min: number;
liq_reagent_transfer_verb: string;
liq_reagent_nutri_rate: number;
liq_reagent_capacity: number;
liq_sloshing: BooleanLike;
liq_reagent_addons: string[];
liq_reagent_addons: checkBoxEntry[];
custom_reagentcolor: string;
custom_reagentalpha: number | string;
custom_reagentalpha: number | null;
liquid_overlay: BooleanLike;
max_liquid_level: number;
reagent_touches: BooleanLike;
@@ -229,19 +279,6 @@ type liqInteractData = {
custom_ingested_alpha: number;
};
type liqMessageData = {
liq_msg_toggle1: BooleanLike;
liq_msg_toggle2: BooleanLike;
liq_msg_toggle3: BooleanLike;
liq_msg_toggle4: BooleanLike;
liq_msg_toggle5: BooleanLike;
liq_msg1: BooleanLike;
liq_msg2: BooleanLike;
liq_msg3: BooleanLike;
liq_msg4: BooleanLike;
liq_msg5: BooleanLike;
};
export type prefData = {
digestable: BooleanLike;
devourable: BooleanLike;
@@ -282,28 +319,30 @@ export type prefData = {
phase_vore: BooleanLike;
food_vore: BooleanLike;
digest_pain: BooleanLike;
nutrition_message_visible: BooleanLike;
nutrition_messages: string[];
weight_message_visible: BooleanLike;
weight_messages: string[];
eating_privacy_global: BooleanLike;
allow_mimicry: BooleanLike;
belly_rub_target: string | null;
vore_sprite_color: { stomach: string; 'taur belly': string };
vore_sprite_multiply: { stomach: BooleanLike; 'taur belly': BooleanLike };
soulcatcher_allow_capture: BooleanLike;
soulcatcher_allow_transfer: BooleanLike;
soulcatcher_allow_deletion: BooleanLike;
soulcatcher_allow_takeover: BooleanLike;
};
export type scMessageData = {
sc_subtab: string;
possible_messages: string[];
max_length: number;
active_message: string;
set_action: string;
tooltip: string;
};
export type soulcatcherData = {
active: BooleanLike;
name: string;
caught_souls: DropdownEntry[];
selected_sfx: string;
selected_sfx: string | null;
selected_soul: string;
interior_design: string;
sc_message_data: scMessageData;
catch_self: BooleanLike;
taken_over: BooleanLike;
catch_prey: BooleanLike;
@@ -322,6 +361,39 @@ export type DropdownEntry = {
value: string;
};
export type checkBoxEntry = {
label: string;
selection: BooleanLike;
ref?: string;
};
export type generalPrefData = {
active_belly: string | null;
belly_rub_target: string | null;
aestethic_messages: aestMessageData;
vore_sprite_color: Record<string, string>;
vore_sprite_multiply: Record<string, BooleanLike>;
vore_icon_options: string[];
};
export type aestMessageData = {
possible_messages: string[];
aest_subtab: string;
max_length: number;
active_message:
| string
| string[]
| null
| Record<string | number, string | number>; // The record is an ancient data corruption, it's not valid!
set_action: string;
tooltip: string;
sub_action?: string;
button_action?: string;
button_data?: BooleanLike;
button_label?: string;
button_tooltip?: string;
};
export type localPrefs = {
digestion: preferenceData;
absorbable: preferenceData;
@@ -349,8 +421,6 @@ export type localPrefs = {
pickuppref: preferenceData;
spontaneous_tf: preferenceData;
mind_transfer: preferenceData;
examine_nutrition: preferenceData;
examine_weight: preferenceData;
strippref: preferenceData;
eating_privacy_global: preferenceData;
allow_mimicry: preferenceData;
@@ -1,8 +1,6 @@
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import { Button, Section } from 'tgui-core/components';
import type { Data } from './types';
import { downloadPrefs } from './VorePanelExportDownload';
export const VorePanelExport = () => {
@@ -16,10 +14,6 @@ export const VorePanelExport = () => {
};
const VorePanelExportContent = (props) => {
const { act, data } = useBackend<Data>();
const { bellies } = data;
return (
<Section title="Vore Export Panel">
<Section title="Export">
+1 -1
View File
@@ -14,7 +14,7 @@
"marked": "^4.3.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui-core": "^3.2.0",
"tgui-core": "^4.0.1",
"tgui-dev-server": "workspace:*"
},
"devDependencies": {
@@ -0,0 +1,41 @@
.VorePanel__fLoating {
height: 200px;
background-color: var(--color-section);
backdrop-filter: var(--blur-medium);
border: var(--border-thickness-tiny) solid var(--color-border);
border-radius: var(--border-radius-medium);
box-shadow: var(--shadow-glow-medium) hsla(0, 0%, 0%, 0.5);
margin: var(--space-m);
color: var(--color-text);
overflow-y: scroll;
overflow-x: hidden;
padding: var(--space-m);
}
.VorePanel__floatingButton {
cursor: var(--cursor-pointer);
display: inline-block;
line-height: 1.667em;
padding: 0 var(--space-m);
outline: 0;
border-radius: var(--button-border-radius);
transition-property: background-color, color, opacity;
transition-duration: var(--button-transition);
transition-timing-function: var(--button-transition-timing);
user-select: none;
background-color: var(--button-background-default);
}
.VorePanel__pasteArea {
height: 200px;
width: 600px;
background-color: var(--color-section);
backdrop-filter: var(--blur-medium);
border: var(--border-thickness-tiny) solid var(--color-border);
border-radius: var(--border-radius-medium);
box-shadow: var(--shadow-glow-medium) hsla(0, 0%, 0%, 0.5);
margin: var(--space-m);
color: var(--color-text);
overflow: hidden;
padding: var(--space-m);
}
+1
View File
@@ -52,6 +52,7 @@
@include meta.load-css('./interfaces/IDCard.scss');
@include meta.load-css('./interfaces/TinderMessaging.scss');
@include meta.load-css('./interfaces/Turbolift.scss');
@include meta.load-css('./interfaces/VorePanel.scss');
@include meta.load-css('./interfaces/Wires.scss');
// Layouts
+8 -8
View File
@@ -19925,20 +19925,20 @@ __metadata:
react: "npm:^19.1.0"
react-dom: "npm:^19.1.0"
tgui: "workspace:*"
tgui-core: "npm:^3.2.0"
tgui-core: "npm:^4.0.1"
languageName: unknown
linkType: soft
"tgui-core@npm:^3.2.0":
version: 3.2.0
resolution: "tgui-core@npm:3.2.0"
"tgui-core@npm:^4.0.1":
version: 4.0.1
resolution: "tgui-core@npm:4.0.1"
dependencies:
"@floating-ui/react": "npm:^0.27.8"
"@nozbe/microfuzz": "npm:^1.0.0"
peerDependencies:
react: ^19.1.0
react-dom: ^19.1.0
checksum: 10c0/86afb01b278b850aaf226c26889674e6c4933c9366e1c2a0d50a4a4452ed67edd96c10f34cbcbec25aec50cb7baaa2498fd13fff2d2f90f42e77fe20f892f440
checksum: 10c0/dc15e1f615395fb62dc7445a68b5bb5b1a102993f5fbf2efe38c190e2608c13da7e78246e328bd5461059f554471ecd08e72719c7d409e5a79f8e2e96ddb81b3
languageName: node
linkType: hard
@@ -19966,7 +19966,7 @@ __metadata:
react: "npm:^19.1.0"
react-dom: "npm:^19.1.0"
tgui: "workspace:*"
tgui-core: "npm:^3.2.0"
tgui-core: "npm:^4.0.1"
tgui-dev-server: "workspace:*"
languageName: unknown
linkType: soft
@@ -19981,7 +19981,7 @@ __metadata:
react: "npm:^19.1.0"
react-dom: "npm:^19.1.0"
tgui: "workspace:*"
tgui-core: "npm:^3.2.0"
tgui-core: "npm:^4.0.1"
vitest: "npm:^3.1.1"
languageName: unknown
linkType: soft
@@ -20043,7 +20043,7 @@ __metadata:
marked: "npm:^4.3.0"
react: "npm:^19.1.0"
react-dom: "npm:^19.1.0"
tgui-core: "npm:^3.2.0"
tgui-core: "npm:^4.0.1"
tgui-dev-server: "workspace:*"
vitest: "npm:^3.1.1"
languageName: unknown
+6
View File
@@ -4420,6 +4420,12 @@
#include "code\modules\vore\eating\vertical_nom_vr.dm"
#include "code\modules\vore\eating\vore_vr.dm"
#include "code\modules\vore\eating\vorepanel_vr.dm"
#include "code\modules\vore\eating\panel_databackend\vorepanel_pref_data.dm"
#include "code\modules\vore\eating\panel_databackend\vorepanel_set_attribute.dm"
#include "code\modules\vore\eating\panel_databackend\vorepanel_set_liqattribute.dm"
#include "code\modules\vore\eating\panel_databackend\vorepanel_soulcatcher_data.dm"
#include "code\modules\vore\eating\panel_databackend\vorepanel_vore_data.dm"
#include "code\modules\vore\eating\panel_databackend\vorepanel_vore_subdata.dm"
#include "code\modules\vore\fluffstuff\custom_boxes_vr.dm"
#include "code\modules\vore\fluffstuff\custom_clothes_vr.dm"
#include "code\modules\vore\fluffstuff\custom_implants_vr.dm"