diff --git a/code/__SANDCODE/DEFINES/lewd.dm b/code/__SANDCODE/DEFINES/lewd.dm
index 789ab5599b..789c32cecf 100644
--- a/code/__SANDCODE/DEFINES/lewd.dm
+++ b/code/__SANDCODE/DEFINES/lewd.dm
@@ -31,7 +31,34 @@ GLOBAL_LIST_INIT(lewd_prefs_choices, list(
#define NORMAL_LUST 10
#define LOW_LUST 1
-#define REQUIRE_NONE 0
-#define REQUIRE_EXPOSED 1
-#define REQUIRE_UNEXPOSED 2
-#define REQUIRE_ANY 3
+/// Exposed states, your friendly non-carbon returns
+// TRUE
+#define HAS_EXPOSED_GENITAL 2
+#define HAS_UNEXPOSED_GENITAL 3
+
+/// Interaction requirements
+#define INTERACTION_REQUIRE_MOUTH (1<<0)
+#define INTERACTION_REQUIRE_HANDS (1<<1)
+#define INTERACTION_REQUIRE_TOPLESS (1<<2)
+#define INTERACTION_REQUIRE_BOTTOMLESS (1<<3)
+
+/// Interaction requirements -- Has require states
+#define INTERACTION_REQUIRE_PENIS (1<<0)
+#define INTERACTION_REQUIRE_ANUS (1<<1)
+#define INTERACTION_REQUIRE_VAGINA (1<<2)
+#define INTERACTION_REQUIRE_BREASTS (1<<3)
+#define INTERACTION_REQUIRE_FEET (1<<4)
+#define INTERACTION_REQUIRE_BALLS (1<<5)
+// Terrible stuff start here
+#define INTERACTION_REQUIRE_EARS (1<<6)
+#define INTERACTION_REQUIRE_EARSOCKETS (1<<7)
+#define INTERACTION_REQUIRE_EYES (1<<8)
+#define INTERACTION_REQUIRE_EYESOCKETS (1<<9)
+
+/// Interaction flags
+#define INTERACTION_FLAG_OOC_CONSENT (1<<0)
+#define INTERACTION_FLAG_ADJACENT (1<<1)
+#define INTERACTION_FLAG_USER_IS_TARGET (1<<2)
+#define INTERACTION_FLAG_USER_NOT_TIRED (1<<3)
+#define INTERACTION_FLAG_TARGET_NOT_TIRED (1<<4)
+#define INTERACTION_FLAG_EXTREME_CONTENT (1<<5)
diff --git a/modular_sand/code/_globalvars/bitfields.dm b/modular_sand/code/_globalvars/bitfields.dm
index 7a2bb8d87d..79da8cb6f6 100644
--- a/modular_sand/code/_globalvars/bitfields.dm
+++ b/modular_sand/code/_globalvars/bitfields.dm
@@ -24,6 +24,48 @@ DEFINE_BITFIELD(flags_inv, list(
"HIDEWRISTS" = HIDEWRISTS,
))
+DEFINE_BITFIELD(interaction_flags, list(
+ "INTERACTION_FLAG_OOC_CONSENT" = INTERACTION_FLAG_OOC_CONSENT,
+ "INTERACTION_FLAG_ADJACENT" = INTERACTION_FLAG_ADJACENT,
+ "INTERACTION_FLAG_USER_IS_TARGET" = INTERACTION_FLAG_USER_IS_TARGET,
+ "INTERACTION_FLAG_USER_NOT_TIRED" = INTERACTION_FLAG_USER_NOT_TIRED,
+ "INTERACTION_FLAG_TARGET_NOT_TIRED" = INTERACTION_FLAG_TARGET_NOT_TIRED,
+ "INTERACTION_FLAG_EXTREME_CONTENT" = INTERACTION_FLAG_EXTREME_CONTENT,
+))
+
+DEFINE_BITFIELD(required_from_user, list(
+ "INTERACTION_REQUIRE_MOUTH" = INTERACTION_REQUIRE_MOUTH,
+ "INTERACTION_REQUIRE_HANDS" = INTERACTION_REQUIRE_HANDS,
+ "INTERACTION_REQUIRE_TOPLESS" = INTERACTION_REQUIRE_TOPLESS,
+ "INTERACTION_REQUIRE_BOTTOMLESS" = INTERACTION_REQUIRE_BOTTOMLESS,
+))
+
+DEFINE_BITFIELD(required_from_user_exposed, list(
+ "INTERACTION_REQUIRE_PENIS" = INTERACTION_REQUIRE_PENIS,
+ "INTERACTION_REQUIRE_ANUS" = INTERACTION_REQUIRE_ANUS,
+ "INTERACTION_REQUIRE_VAGINA" = INTERACTION_REQUIRE_VAGINA,
+ "INTERACTION_REQUIRE_BREASTS" = INTERACTION_REQUIRE_BREASTS,
+ "INTERACTION_REQUIRE_FEET" = INTERACTION_REQUIRE_FEET,
+ "INTERACTION_REQUIRE_BALLS" = INTERACTION_REQUIRE_BALLS,
+ "INTERACTION_REQUIRE_EARS" = INTERACTION_REQUIRE_EARS,
+ "INTERACTION_REQUIRE_EARSOCKETS" = INTERACTION_REQUIRE_EARSOCKETS,
+ "INTERACTION_REQUIRE_EYES" = INTERACTION_REQUIRE_EYES,
+ "INTERACTION_REQUIRE_EYESOCKETS" = INTERACTION_REQUIRE_EYESOCKETS,
+))
+
+DEFINE_BITFIELD(required_from_user_unexposed, list(
+ "INTERACTION_REQUIRE_PENIS" = INTERACTION_REQUIRE_PENIS,
+ "INTERACTION_REQUIRE_ANUS" = INTERACTION_REQUIRE_ANUS,
+ "INTERACTION_REQUIRE_VAGINA" = INTERACTION_REQUIRE_VAGINA,
+ "INTERACTION_REQUIRE_BREASTS" = INTERACTION_REQUIRE_BREASTS,
+ "INTERACTION_REQUIRE_FEET" = INTERACTION_REQUIRE_FEET,
+ "INTERACTION_REQUIRE_BALLS" = INTERACTION_REQUIRE_BALLS,
+ "INTERACTION_REQUIRE_EARS" = INTERACTION_REQUIRE_EARS,
+ "INTERACTION_REQUIRE_EARSOCKETS" = INTERACTION_REQUIRE_EARSOCKETS,
+ "INTERACTION_REQUIRE_EYES" = INTERACTION_REQUIRE_EYES,
+ "INTERACTION_REQUIRE_EYESOCKETS" = INTERACTION_REQUIRE_EYESOCKETS,
+))
+
DEFINE_BITFIELD(slot_flags, list(
"ITEM_SLOT_ACCESSORY" = ITEM_SLOT_ACCESSORY,
"ITEM_SLOT_BACK" = ITEM_SLOT_BACK,
@@ -53,6 +95,39 @@ DEFINE_BITFIELD(slot_flags, list(
"ITEM_SLOT_WRISTS" = ITEM_SLOT_WRISTS,
))
+DEFINE_BITFIELD(required_from_target, list(
+ "INTERACTION_REQUIRE_MOUTH" = INTERACTION_REQUIRE_MOUTH,
+ "INTERACTION_REQUIRE_HANDS" = INTERACTION_REQUIRE_HANDS,
+ "INTERACTION_REQUIRE_TOPLESS" = INTERACTION_REQUIRE_TOPLESS,
+ "INTERACTION_REQUIRE_BOTTOMLESS" = INTERACTION_REQUIRE_BOTTOMLESS,
+))
+
+DEFINE_BITFIELD(required_from_target_exposed, list(
+ "INTERACTION_REQUIRE_PENIS" = INTERACTION_REQUIRE_PENIS,
+ "INTERACTION_REQUIRE_ANUS" = INTERACTION_REQUIRE_ANUS,
+ "INTERACTION_REQUIRE_VAGINA" = INTERACTION_REQUIRE_VAGINA,
+ "INTERACTION_REQUIRE_BREASTS" = INTERACTION_REQUIRE_BREASTS,
+ "INTERACTION_REQUIRE_FEET" = INTERACTION_REQUIRE_FEET,
+ "INTERACTION_REQUIRE_BALLS" = INTERACTION_REQUIRE_BALLS,
+ "INTERACTION_REQUIRE_EARS" = INTERACTION_REQUIRE_EARS,
+ "INTERACTION_REQUIRE_EARSOCKETS" = INTERACTION_REQUIRE_EARSOCKETS,
+ "INTERACTION_REQUIRE_EYES" = INTERACTION_REQUIRE_EYES,
+ "INTERACTION_REQUIRE_EYESOCKETS" = INTERACTION_REQUIRE_EYESOCKETS,
+))
+
+DEFINE_BITFIELD(required_from_target_unexposed, list(
+ "INTERACTION_REQUIRE_PENIS" = INTERACTION_REQUIRE_PENIS,
+ "INTERACTION_REQUIRE_ANUS" = INTERACTION_REQUIRE_ANUS,
+ "INTERACTION_REQUIRE_VAGINA" = INTERACTION_REQUIRE_VAGINA,
+ "INTERACTION_REQUIRE_BREASTS" = INTERACTION_REQUIRE_BREASTS,
+ "INTERACTION_REQUIRE_FEET" = INTERACTION_REQUIRE_FEET,
+ "INTERACTION_REQUIRE_BALLS" = INTERACTION_REQUIRE_BALLS,
+ "INTERACTION_REQUIRE_EARS" = INTERACTION_REQUIRE_EARS,
+ "INTERACTION_REQUIRE_EARSOCKETS" = INTERACTION_REQUIRE_EARSOCKETS,
+ "INTERACTION_REQUIRE_EYES" = INTERACTION_REQUIRE_EYES,
+ "INTERACTION_REQUIRE_EYESOCKETS" = INTERACTION_REQUIRE_EYESOCKETS,
+))
+
DEFINE_BITFIELD(vis_flags_inv, list(
"HIDEACCESSORY" = HIDEACCESSORY,
"HIDEEARS" = HIDEEARS,
diff --git a/modular_sand/code/datums/components/interaction_menu_granter.dm b/modular_sand/code/datums/components/interaction_menu_granter.dm
index a88f96f24a..a5545c0c14 100644
--- a/modular_sand/code/datums/components/interaction_menu_granter.dm
+++ b/modular_sand/code/datums/components/interaction_menu_granter.dm
@@ -41,6 +41,8 @@
/datum/component/interaction_menu_granter/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_MOB_CTRLSHIFTCLICKON)
+ if(target)
+ UnregisterSignal(target, COMSIG_PARENT_QDELETING)
. = ..()
/// The one interacting is clicker, the interacted is clicked.
@@ -51,10 +53,20 @@
// Don't cancel admin quick spawn
if(isobserver(clicked) && check_rights_for(clicker.client, R_SPAWN))
return FALSE
+ // Changing targets!!
+ if(target)
+ UnregisterSignal(target, COMSIG_PARENT_QDELETING)
target = clicked
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_deleted)
ui_interact(clicker)
return COMSIG_MOB_CANCEL_CLICKON
+/// Such a shame
+/datum/component/interaction_menu_granter/proc/on_target_deleted(datum/source, ...)
+ UnregisterSignal(target, COMSIG_PARENT_QDELETING)
+ target = null
+ SStgui.close_user_uis(parent, src)
+
/datum/component/interaction_menu_granter/ui_state(mob/user)
// Funny admin, don't you dare be the extra funny now.
if(user.client.holder && !user.client.holder.deadmined)
@@ -88,34 +100,224 @@
.["selfAttributes"] = self.list_interaction_attributes(self)
.["lust"] = self.get_lust()
.["maxLust"] = self.get_lust_tolerance() * 3
+
+ .["max_distance"] = 0
+ var/required_from_user = NONE
+ if(self.has_mouth())
+ required_from_user |= INTERACTION_REQUIRE_MOUTH
+ if(self.has_hands())
+ required_from_user |= INTERACTION_REQUIRE_HANDS
+ if(self.is_topless())
+ required_from_user |= INTERACTION_REQUIRE_TOPLESS
+ if(self.is_bottomless())
+ required_from_user |= INTERACTION_REQUIRE_BOTTOMLESS
+ .["required_from_user"] = required_from_user
+
+ var/required_from_user_exposed = NONE
+ var/required_from_user_unexposed = NONE
+
+ var/user_has_penis = self.has_penis()
+ switch(user_has_penis)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_user_exposed |= INTERACTION_REQUIRE_PENIS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_user_unexposed |= INTERACTION_REQUIRE_PENIS
+ if(1)
+ required_from_user_exposed |= INTERACTION_REQUIRE_PENIS
+ required_from_user_unexposed |= INTERACTION_REQUIRE_PENIS
+
+ var/user_has_anus = self.has_anus()
+ switch(user_has_anus)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_user_exposed |= INTERACTION_REQUIRE_ANUS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_user_unexposed |= INTERACTION_REQUIRE_ANUS
+ if(1)
+ required_from_user_exposed |= INTERACTION_REQUIRE_ANUS
+ required_from_user_unexposed |= INTERACTION_REQUIRE_ANUS
+
+ var/user_has_vagina = self.has_vagina()
+ switch(user_has_vagina)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_user_exposed |= INTERACTION_REQUIRE_VAGINA
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_user_unexposed |= INTERACTION_REQUIRE_VAGINA
+ if(1)
+ required_from_user_exposed |= INTERACTION_REQUIRE_VAGINA
+ required_from_user_unexposed |= INTERACTION_REQUIRE_VAGINA
+
+ var/user_has_breasts = self.has_breasts()
+ switch(user_has_breasts)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_user_exposed |= INTERACTION_REQUIRE_BREASTS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_user_unexposed |= INTERACTION_REQUIRE_BREASTS
+ if(1)
+ required_from_user_exposed |= INTERACTION_REQUIRE_BREASTS
+ required_from_user_unexposed |= INTERACTION_REQUIRE_BREASTS
+
+ var/user_has_feet = self.has_feet()
+ switch(user_has_feet)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_user_exposed |= INTERACTION_REQUIRE_FEET
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_user_unexposed |= INTERACTION_REQUIRE_FEET
+ if(1)
+ required_from_user_exposed |= INTERACTION_REQUIRE_FEET
+ required_from_user_unexposed |= INTERACTION_REQUIRE_FEET
+
+ var/user_has_balls = self.has_balls()
+ switch(user_has_balls)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_user_exposed |= INTERACTION_REQUIRE_BALLS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_user_unexposed |= INTERACTION_REQUIRE_BALLS
+ if(1)
+ required_from_user_exposed |= INTERACTION_REQUIRE_BALLS
+ required_from_user_unexposed |= INTERACTION_REQUIRE_BALLS
+
+ var/user_has_ears = self.has_ears()
+ switch(user_has_ears)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_user_exposed |= INTERACTION_REQUIRE_EARS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_user_unexposed |= INTERACTION_REQUIRE_EARS
+ if(FALSE)
+ required_from_user_exposed |= INTERACTION_REQUIRE_EARSOCKETS
+
+ var/user_has_eyes = self.has_eyes()
+ switch(user_has_eyes)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_user_exposed |= INTERACTION_REQUIRE_EYES
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_user_unexposed |= INTERACTION_REQUIRE_EYES
+ if(FALSE)
+ required_from_user_exposed |= INTERACTION_REQUIRE_EYESOCKETS
+
+ .["required_from_user_exposed"] = required_from_user_exposed
+ .["required_from_user_unexposed"] = required_from_user_unexposed
+ .["user_num_feet"] = self.get_num_feet()
+
+ // Let's clear it in case the user goes directly from interacting with someone to themself
+ .["theirAttributes"] = null
+ .["target_has_active_player"] = null
+ .["max_distance"] = null
+ .["required_from_target"] = null
+ .["required_from_target_exposed"] = null
+ .["required_from_target_unexposed"] = null
+ .["target_num_feet"] = null
+ .["theirPrefs"] = null
+ .["theirLust"] = null
+ .["theyAllowLewd"] = null
+ .["theyAllowExtreme"] = null
if(target != self)
.["theirAttributes"] = target.list_interaction_attributes(self)
+
+ // Always TRUE if has key, 2 if cliented, FALSE if nobody owns it
+ .["target_has_active_player"] = target.ckey ? (target.client ? 2 : TRUE) : FALSE
+ .["max_distance"] = get_dist(self, target)
+ var/required_from_target = NONE
+ if(target.has_mouth())
+ required_from_target |= INTERACTION_REQUIRE_MOUTH
+ if(target.has_hands())
+ required_from_target |= INTERACTION_REQUIRE_HANDS
+ if(target.is_topless())
+ required_from_target |= INTERACTION_REQUIRE_TOPLESS
+ if(target.is_bottomless())
+ required_from_target |= INTERACTION_REQUIRE_BOTTOMLESS
+ .["required_from_target"] = required_from_target
+
+ var/required_from_target_exposed = NONE
+ var/required_from_target_unexposed = NONE
+
+ var/target_has_penis = target.has_penis()
+ switch(target_has_penis)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_target_exposed |= INTERACTION_REQUIRE_PENIS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_target_unexposed |= INTERACTION_REQUIRE_PENIS
+ if(1)
+ required_from_target_exposed |= INTERACTION_REQUIRE_PENIS
+ required_from_target_unexposed |= INTERACTION_REQUIRE_PENIS
+
+ var/target_has_anus = target.has_anus()
+ switch(target_has_anus)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_target_exposed |= INTERACTION_REQUIRE_ANUS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_target_unexposed |= INTERACTION_REQUIRE_ANUS
+ if(1)
+ required_from_target_exposed |= INTERACTION_REQUIRE_ANUS
+ required_from_target_unexposed |= INTERACTION_REQUIRE_ANUS
+
+ var/target_has_vagina = target.has_vagina()
+ switch(target_has_vagina)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_target_exposed |= INTERACTION_REQUIRE_VAGINA
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_target_unexposed |= INTERACTION_REQUIRE_VAGINA
+ if(1)
+ required_from_target_exposed |= INTERACTION_REQUIRE_VAGINA
+ required_from_target_unexposed |= INTERACTION_REQUIRE_VAGINA
+
+ var/target_has_breasts = target.has_breasts()
+ switch(target_has_breasts)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_target_exposed |= INTERACTION_REQUIRE_BREASTS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_target_unexposed |= INTERACTION_REQUIRE_BREASTS
+ if(1)
+ required_from_target_exposed |= INTERACTION_REQUIRE_BREASTS
+ required_from_target_unexposed |= INTERACTION_REQUIRE_BREASTS
+
+ var/target_has_feet = target.has_feet()
+ switch(target_has_feet)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_target_exposed |= INTERACTION_REQUIRE_FEET
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_target_unexposed |= INTERACTION_REQUIRE_FEET
+ if(1)
+ required_from_target_exposed |= INTERACTION_REQUIRE_FEET
+ required_from_target_unexposed |= INTERACTION_REQUIRE_FEET
+
+ var/target_has_balls = target.has_balls()
+ switch(target_has_balls)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_target_exposed |= INTERACTION_REQUIRE_BALLS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_target_unexposed |= INTERACTION_REQUIRE_BALLS
+ if(1)
+ required_from_target_exposed |= INTERACTION_REQUIRE_BALLS
+ required_from_target_unexposed |= INTERACTION_REQUIRE_BALLS
+
+ var/target_has_eyes = target.has_eyes()
+ switch(target_has_eyes)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_target_exposed |= INTERACTION_REQUIRE_EYES
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_target_unexposed |= INTERACTION_REQUIRE_EYES
+ if(FALSE)
+ required_from_target_exposed |= INTERACTION_REQUIRE_EYESOCKETS
+
+ var/target_has_ears = target.has_ears()
+ switch(target_has_ears)
+ if(HAS_EXPOSED_GENITAL)
+ required_from_target_exposed |= INTERACTION_REQUIRE_EARS
+ if(HAS_UNEXPOSED_GENITAL)
+ required_from_target_unexposed |= INTERACTION_REQUIRE_EARS
+ if(FALSE)
+ required_from_target_exposed |= INTERACTION_REQUIRE_EARSOCKETS
+
+ .["required_from_target_exposed"] = required_from_target_exposed
+ .["required_from_target_unexposed"] = required_from_target_unexposed
+ .["target_num_feet"] = target.get_num_feet()
+ if(target?.client?.prefs)
+ .["theyAllowLewd"] = !!(target.client.prefs.toggles & VERB_CONSENT)
+ .["theyAllowExtreme"] = !!pref_to_num(target.client.prefs.extremepref)
if(HAS_TRAIT(user, TRAIT_ESTROUS_DETECT))
.["theirLust"] = target.get_lust()
.["theirMaxLust"] = target.get_lust_tolerance() * 3
- //Getting interactions
- var/list/sent_interactions = list()
- for(var/interaction_key in SSinteractions.interactions)
- var/datum/interaction/I = SSinteractions.interactions[interaction_key]
- if(I.evaluate_user(self, action_check = FALSE) && I.evaluate_target(self, target))
- if(I.user_is_target && target != self)
- continue
- var/list/interaction = list()
- interaction["key"] = I.type
- interaction["desc"] = I.description
- if(istype(I, /datum/interaction/lewd))
- var/datum/interaction/lewd/O = I
- if(O.extreme)
- interaction["type"] = INTERACTION_EXTREME
- else
- interaction["type"] = INTERACTION_LEWD
- else
- interaction["type"] = INTERACTION_NORMAL
- interaction["additionalDetails"] = I.additional_details
- sent_interactions += list(interaction)
- .["interactions"] = sent_interactions
-
//Get their genitals
var/list/genitals = list()
var/mob/living/carbon/get_genitals = self
@@ -193,6 +395,40 @@
.["no_ass_slap"] = !CHECK_BITFIELD(prefs.cit_toggles, NO_ASS_SLAP)
.["no_auto_wag"] = !CHECK_BITFIELD(prefs.cit_toggles, NO_AUTO_WAG)
+/datum/component/interaction_menu_granter/ui_static_data(mob/user)
+ . = ..()
+ //Getting interactions
+ var/list/sent_interactions = list()
+ for(var/interaction_key in SSinteractions.interactions)
+ var/datum/interaction/I = SSinteractions.interactions[interaction_key]
+ var/list/interaction = list()
+ interaction["key"] = I.type
+ interaction["desc"] = I.description
+ if(istype(I, /datum/interaction/lewd))
+ var/datum/interaction/lewd/O = I
+ if(O.interaction_flags & INTERACTION_FLAG_EXTREME_CONTENT)
+ interaction["type"] = INTERACTION_EXTREME
+ else
+ interaction["type"] = INTERACTION_LEWD
+ interaction["require_user_num_feet"] = O.require_user_num_feet
+ interaction["require_target_num_feet"] = O.require_target_num_feet
+ else
+ interaction["type"] = INTERACTION_NORMAL
+ interaction["maxDistance"] = I.max_distance
+
+ interaction["interactionFlags"] = I.interaction_flags
+
+ interaction["required_from_user"] = I.required_from_user
+ interaction["required_from_user_exposed"] = I.required_from_user_exposed
+ interaction["required_from_user_unexposed"] = I.required_from_user_unexposed
+
+ interaction["required_from_target"] = I.required_from_target
+ interaction["required_from_target_exposed"] = I.required_from_target_exposed
+ interaction["required_from_target_unexposed"] = I.required_from_target_unexposed
+ interaction["additionalDetails"] = I.additional_details
+ sent_interactions += list(interaction)
+ .["interactions"] = sent_interactions
+
/proc/num_to_pref(num)
switch(num)
if(1)
diff --git a/modular_sand/code/datums/interactions/_interaction.dm b/modular_sand/code/datums/interactions/_interaction.dm
index cf00b85774..fa91da6aeb 100644
--- a/modular_sand/code/datums/interactions/_interaction.dm
+++ b/modular_sand/code/datums/interactions/_interaction.dm
@@ -31,14 +31,16 @@
var/interaction_sound
var/max_distance = 1
- var/require_ooc_consent = FALSE
- var/require_user_mouth
- var/require_user_hands
- var/require_target_mouth
- var/require_target_hands
- var/needs_physical_contact
- var/user_is_target = FALSE //Boolean. Pretty self explanatory.
+ var/interaction_flags = INTERACTION_FLAG_ADJACENT
+
+ var/required_from_user = NONE
+ var/required_from_user_exposed = NONE
+ var/required_from_user_unexposed = NONE
+
+ var/required_from_target = NONE
+ var/required_from_target_exposed = NONE
+ var/required_from_target_unexposed = NONE
/// Refuses to accept more than one entry for some reason, fix sometime
var/list/additional_details
@@ -48,21 +50,22 @@
if(SSinteractions.is_blacklisted(user))
return FALSE
- if(require_user_mouth)
- if(!user.has_mouth() && !issilicon(user)) //Again, silicons do not have the required parts normally.
+ if(required_from_user & INTERACTION_REQUIRE_MOUTH)
+ if(!user.has_mouth())
if(!silent)
to_chat(user, span_warning("You don't have a mouth."))
return FALSE
- if(!user.mouth_is_free() && !issilicon(user)) //Borgs cannot wear mouthgear, bypassing the check.
+ if(!user.mouth_is_free())
if(!silent)
to_chat(user, span_warning("Your mouth is covered."))
return FALSE
- if(require_user_hands && !user.has_hands() && !issilicon(user)) //Edited to allow silicons to interact.
- if(!silent)
- to_chat(user, span_warning("You don't have hands."))
- return FALSE
+ if(required_from_user & INTERACTION_REQUIRE_HANDS)
+ if(!user.has_hands())
+ if(!silent)
+ to_chat(user, span_warning("You don't have hands."))
+ return FALSE
if(COOLDOWN_FINISHED(user, last_interaction_time))
return TRUE
@@ -77,40 +80,41 @@
if(SSinteractions.is_blacklisted(target))
return FALSE
- if(!user_is_target)
+ if(!(interaction_flags & INTERACTION_FLAG_USER_IS_TARGET))
if(user == target)
if(!silent)
- to_chat(user, "You can't do that to yourself.")
+ to_chat(user, span_warning("You can't do that to yourself."))
return FALSE
- if(require_target_mouth)
+ if(required_from_target & INTERACTION_REQUIRE_MOUTH)
if(!target.has_mouth())
if(!silent)
- to_chat(user, "They don't have a mouth.")
+ to_chat(user, span_warning("They don't have a mouth."))
return FALSE
- if(!target.mouth_is_free() && !issilicon(target))
+ if(!target.mouth_is_free())
if(!silent)
- to_chat(user, "Their mouth is covered.")
+ to_chat(user, span_warning("Their mouth is covered."))
return FALSE
- if(require_target_hands && !target.has_hands() && !issilicon(target))
- if(!silent)
- to_chat(user, "They don't have hands.")
- return FALSE
+ if(required_from_target & INTERACTION_REQUIRE_HANDS)
+ if(!target.has_hands())
+ if(!silent)
+ to_chat(user, span_warning("They don't have hands."))
+ return FALSE
return TRUE
/// Actually doing the action, has a few checks to see if it's valid, usually overwritten to be make things actually happen and what-not
/datum/interaction/proc/do_action(mob/living/user, mob/living/target)
- if(!user_is_target)
+ if(!(interaction_flags & INTERACTION_FLAG_USER_IS_TARGET))
if(user == target) //tactical href fix
to_chat(user, span_warning("You cannot target yourself."))
return
if(get_dist(user, target) > max_distance)
to_chat(user, span_warning("They are too far away."))
return
- if(needs_physical_contact && !(user.Adjacent(target) && target.Adjacent(user)))
+ if(interaction_flags & INTERACTION_FLAG_ADJACENT && !(user.Adjacent(target) && target.Adjacent(user)))
to_chat(user, span_warning("You cannot get to them."))
return
if(!evaluate_user(user, silent = FALSE))
diff --git a/modular_sand/code/datums/interactions/interaction_datums/interaction_definitions.dm b/modular_sand/code/datums/interactions/interaction_datums/interaction_definitions.dm
index 486c91e04d..ba618b8ced 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/interaction_definitions.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/interaction_definitions.dm
@@ -1,60 +1,58 @@
/datum/interaction/handshake
description = "Shake their hand."
simple_message = "USER shakes the hand of TARGET."
- require_user_hands = TRUE
- needs_physical_contact = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
/datum/interaction/pat
description = "Pat their shoulder."
simple_message = "USER pats TARGET's shoulder."
- require_user_hands = TRUE
- needs_physical_contact = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
/datum/interaction/cheer
description = "Cheer them on."
- require_user_mouth = TRUE
+ required_from_user = INTERACTION_REQUIRE_MOUTH
simple_message = "USER cheers TARGET on!"
+ interaction_flags = NONE
/datum/interaction/highfive
description = "Give them a high-five."
- require_user_mouth = TRUE
simple_message = "USER high fives TARGET!"
interaction_sound = 'modular_sand/sound/interactions/slap.ogg'
- needs_physical_contact = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_target = INTERACTION_REQUIRE_HANDS
/datum/interaction/headpat
description = "Pat their head. Aww..."
- require_user_hands = TRUE
simple_message = "USER headpats TARGET!"
- needs_physical_contact = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
/datum/interaction/salute
description = "Give them a firm salute!"
- require_user_hands = TRUE
simple_message = "USER salutes TARGET sharply!"
+ required_from_user = INTERACTION_REQUIRE_HANDS
max_distance = 25
+ interaction_flags = NONE
/datum/interaction/fistbump
description = "Bump it!"
- require_user_hands = TRUE
simple_message = "USER fistbumps TARGET! Yeah!"
- needs_physical_contact = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_target = INTERACTION_REQUIRE_HANDS
/datum/interaction/pinkypromise
description = "Make a pinky promise with them!"
- require_user_hands = TRUE
simple_message = "USER hooks their pinky with TARGET's! Pinky Promise!"
- needs_physical_contact = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
/datum/interaction/bird
description = "Flip them the bird!"
- require_user_hands = TRUE
simple_message = "USER gives TARGET the bird!"
+ required_from_user = INTERACTION_REQUIRE_HANDS
max_distance = 25
+ interaction_flags = NONE
/datum/interaction/holdhand
description = "Hold their hand."
- require_user_hands = TRUE
simple_message = "USER holds TARGET's hand."
- needs_physical_contact = TRUE
- max_distance = 25
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_target = INTERACTION_REQUIRE_HANDS
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/breasts.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/breasts.dm
index 9bcfddb45d..695f9389cd 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/breasts.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/breasts.dm
@@ -1,7 +1,7 @@
/datum/interaction/lewd/do_breastfeed
description = "Breastfeed them"
- require_user_breasts = REQUIRE_EXPOSED
- require_target_mouth = TRUE
+ required_from_user_exposed = INTERACTION_REQUIRE_BREASTS
+ required_from_target = INTERACTION_REQUIRE_MOUTH
max_distance = 1
write_log_user = "breastfed"
write_log_target = "was breastfed by"
@@ -49,8 +49,9 @@
/datum/interaction/lewd/titgrope
description = "Grope their breasts."
- require_user_hands = TRUE
- require_target_breasts = REQUIRE_ANY
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_target_exposed = INTERACTION_REQUIRE_BREASTS
+ required_from_target_unexposed = INTERACTION_REQUIRE_BREASTS
write_log_user = "groped"
write_log_target = "was groped by"
interaction_sound = null
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/cursed/earfuck.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/cursed/earfuck.dm
index 6c432ec2ce..3054d741fb 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/cursed/earfuck.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/cursed/earfuck.dm
@@ -1,17 +1,16 @@
/datum/interaction/lewd/earfuck
description = "Fuck their ear."
interaction_sound = null
- require_user_penis = REQUIRE_EXPOSED
- require_target_ears = REQUIRE_EXPOSED
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target_exposed = INTERACTION_REQUIRE_EARS
+ interaction_flags = INTERACTION_FLAG_ADJACENT | INTERACTION_FLAG_OOC_CONSENT | INTERACTION_FLAG_EXTREME_CONTENT
max_distance = 1
write_log_user = "earfucked"
write_log_target = "had their ear fucked by"
- extreme = TRUE
/datum/interaction/lewd/earfuck/earsocketfuck
description = "Fuck their earsocket."
- require_target_ears = null
- require_target_earsockets = REQUIRE_EXPOSED
+ required_from_target_exposed = INTERACTION_REQUIRE_EARSOCKETS
write_log_user = "earsocket fucked"
write_log_target = "had their earsocket fucked by"
@@ -41,6 +40,6 @@
playlewdinteractionsound(get_turf(user), pick('modular_sand/sound/interactions/champ1.ogg',
'modular_sand/sound/interactions/champ2.ogg'), 50, 1, -1)
- user.visible_message(message = span_lewd("\The [user] [message]"), ignored_mobs = user.get_unconsenting(TRUE))
+ user.visible_message(message = span_lewd("\The [user] [message]"), ignored_mobs = user.get_unconsenting(interaction_flags))
user.handle_post_sex(NORMAL_LUST, CUM_TARGET_EARS, partner)
partner.handle_post_sex(LOW_LUST, null, user)
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/cursed/eyefuck.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/cursed/eyefuck.dm
index f74673570c..038fb18256 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/cursed/eyefuck.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/cursed/eyefuck.dm
@@ -1,17 +1,16 @@
/datum/interaction/lewd/eyefuck
description = "Fuck their eye."
interaction_sound = null
- require_user_penis = REQUIRE_EXPOSED
- require_target_eyes = REQUIRE_EXPOSED
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target_exposed = INTERACTION_REQUIRE_EYES
+ interaction_flags = INTERACTION_FLAG_ADJACENT | INTERACTION_FLAG_OOC_CONSENT | INTERACTION_FLAG_EXTREME_CONTENT
max_distance = 1
write_log_user = "eyefucked"
write_log_target = "had their eye fucked by"
- extreme = TRUE
/datum/interaction/lewd/eyefuck/eyesocketfuck
description = "Fuck their eyesocket."
- require_target_eyes = null
- require_target_eyesockets = REQUIRE_EXPOSED
+ required_from_target_exposed = INTERACTION_REQUIRE_EYESOCKETS
write_log_user = "eyesocketfucked"
write_log_target = "had their eyesocket fucked by"
@@ -41,6 +40,6 @@
playlewdinteractionsound(get_turf(user), pick('modular_sand/sound/interactions/champ1.ogg',
'modular_sand/sound/interactions/champ2.ogg'), 50, 1, -1)
- user.visible_message(span_lewd("\The [user] [message]"), ignored_mobs = user.get_unconsenting(TRUE))
+ user.visible_message(span_lewd("\The [user] [message]"), ignored_mobs = user.get_unconsenting(interaction_flags))
user.handle_post_sex(NORMAL_LUST, CUM_TARGET_EYES, partner)
partner.handle_post_sex(LOW_LUST, null, user)
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/facefuck.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/facefuck.dm
index e775e95e96..3257b02301 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/facefuck.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/facefuck.dm
@@ -1,15 +1,14 @@
/datum/interaction/lewd/facefuck
description = "Fuck their mouth using your penis"
interaction_sound = null
- require_target_mouth = TRUE
- require_user_penis = REQUIRE_EXPOSED
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target = INTERACTION_REQUIRE_MOUTH
max_distance = 1
var/fucktarget = "penis"
/datum/interaction/lewd/facefuck/vag
description = "Fuck their mouth using your vagina"
- require_user_penis = null
- require_user_vagina = REQUIRE_EXPOSED
+ required_from_user_exposed = INTERACTION_REQUIRE_VAGINA
fucktarget = "vagina"
/datum/interaction/lewd/facefuck/display_interaction(mob/living/user, mob/living/partner)
@@ -111,8 +110,8 @@
/datum/interaction/lewd/throatfuck
description = "Fuck their throat. | Does oxy damage."
interaction_sound = null
- require_user_penis = REQUIRE_EXPOSED
- require_target_mouth = TRUE
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target = INTERACTION_REQUIRE_MOUTH
max_distance = 1
/datum/interaction/lewd/throatfuck/display_interaction(mob/living/user, mob/living/partner)
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/feet.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/feet.dm
index bdb3d9444b..050db1a745 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/feet.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/feet.dm
@@ -1,9 +1,10 @@
/datum/interaction/lewd/grindface
description = "Feet grind their face."
interaction_sound = null
- require_target_mouth = TRUE
+ required_from_user_exposed = INTERACTION_REQUIRE_FEET
+ required_from_user_unexposed = INTERACTION_REQUIRE_FEET
require_user_num_feet = 1
- require_user_feet = REQUIRE_ANY
+ required_from_target = INTERACTION_REQUIRE_MOUTH
max_distance = 1
/datum/interaction/lewd/grindface/display_interaction(mob/living/user, mob/living/partner)
@@ -56,9 +57,10 @@
/datum/interaction/lewd/grindmouth
description = "Feet grind their mouth."
interaction_sound = null
- require_target_mouth = TRUE
+ required_from_user_exposed = INTERACTION_REQUIRE_FEET
+ required_from_user_unexposed = INTERACTION_REQUIRE_FEET
require_user_num_feet = 1
- require_user_feet = REQUIRE_ANY
+ required_from_target = INTERACTION_REQUIRE_MOUTH
max_distance = 1
/datum/interaction/lewd/grindmouth/display_interaction(mob/living/user, mob/living/partner)
@@ -111,9 +113,10 @@
/datum/interaction/lewd/footjob
description = "Jerk them off with your foot."
interaction_sound = null
+ required_from_user_exposed = INTERACTION_REQUIRE_FEET
+ required_from_user_unexposed = INTERACTION_REQUIRE_FEET
require_user_num_feet = 1
- require_user_feet = REQUIRE_ANY
- require_target_penis = REQUIRE_EXPOSED
+ required_from_target_exposed = INTERACTION_REQUIRE_PENIS
max_distance = 1
/datum/interaction/lewd/footjob/display_interaction(mob/living/user, mob/living/partner)
@@ -169,8 +172,7 @@
/datum/interaction/lewd/footjob/vagina
description = "Rub their vagina with your foot."
- require_target_vagina = REQUIRE_EXPOSED
- require_target_penis = null
+ required_from_target_exposed = INTERACTION_REQUIRE_VAGINA
/datum/interaction/lewd/footjob/vagina/display_interaction(mob/living/user, mob/living/partner)
var/message
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/finger.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/finger.dm
index f17cd9b078..f4666896e9 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/finger.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/finger.dm
@@ -1,7 +1,7 @@
/datum/interaction/lewd/finger
description = "Finger their pussy."
- require_user_hands = TRUE
- require_target_vagina = REQUIRE_EXPOSED
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_target_exposed = INTERACTION_REQUIRE_VAGINA
interaction_sound = null
max_distance = 1
@@ -41,8 +41,8 @@
/datum/interaction/lewd/fingerass
description = "Finger their ass."
interaction_sound = null
- require_user_hands = TRUE
- require_target_anus = REQUIRE_EXPOSED
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_target_exposed = INTERACTION_REQUIRE_ANUS
max_distance = 1
/datum/interaction/lewd/fingerass/display_interaction(mob/living/user, mob/living/partner)
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/frotting.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/frotting.dm
index f91a041d47..990afe43c6 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/frotting.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/frotting.dm
@@ -1,8 +1,7 @@
/datum/interaction/lewd/frotting
description = "Rub your penis against theirs"
- require_user_penis = REQUIRE_EXPOSED
- require_target_penis = REQUIRE_EXPOSED
- max_distance = 1
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target_exposed = INTERACTION_REQUIRE_PENIS
write_log_user = "frotted"
write_log_target = "was frotted by"
interaction_sound = null
@@ -20,9 +19,8 @@
/datum/interaction/lewd/tribadism
description = "Grind your pussy against theirs."
interaction_sound = null
- require_target_vagina = REQUIRE_EXPOSED
- require_user_vagina = REQUIRE_EXPOSED
- max_distance = 1
+ required_from_user_exposed = INTERACTION_REQUIRE_VAGINA
+ required_from_target_exposed = INTERACTION_REQUIRE_VAGINA
/datum/interaction/lewd/tribadism/display_interaction(mob/living/user, mob/living/partner)
var/message
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/fuck.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/fuck.dm
index 4f168664f2..c7d3ca32e2 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/fuck.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/fuck.dm
@@ -1,11 +1,10 @@
/datum/interaction/lewd/fuck
description = "Fuck their pussy."
- require_user_penis = REQUIRE_EXPOSED
- require_target_vagina = REQUIRE_EXPOSED
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target_exposed = INTERACTION_REQUIRE_VAGINA
write_log_user = "fucked"
write_log_target = "was fucked by"
interaction_sound = null
- max_distance = 1
/datum/interaction/lewd/fuck/display_interaction(mob/living/user, mob/living/partner)
var/message
@@ -30,8 +29,7 @@
/datum/interaction/lewd/fuck/anal
description = "Fuck their ass."
- require_target_vagina = null
- require_target_anus = REQUIRE_EXPOSED
+ required_from_target_exposed = INTERACTION_REQUIRE_ANUS
/datum/interaction/lewd/fuck/anal/display_interaction(mob/living/user, mob/living/partner)
var/message
@@ -62,9 +60,8 @@
/datum/interaction/lewd/breastfuck
description = "Fuck their breasts."
interaction_sound = null
- require_user_penis = REQUIRE_EXPOSED
- require_target_breasts = REQUIRE_EXPOSED
- max_distance = 1
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target_exposed = INTERACTION_REQUIRE_BREASTS
/datum/interaction/lewd/breastfuck/display_interaction(mob/living/user, mob/living/partner)
var/message
@@ -90,9 +87,10 @@
/datum/interaction/lewd/footfuck
description = "Rub your cock on their foot."
interaction_sound = null
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target_exposed = INTERACTION_REQUIRE_FEET
+ required_from_target_unexposed = INTERACTION_REQUIRE_FEET
require_target_num_feet = 1
- require_target_feet = REQUIRE_ANY
- require_user_penis = REQUIRE_EXPOSED
max_distance = 1
/datum/interaction/lewd/footfuck/display_interaction(mob/living/user, mob/living/partner)
@@ -150,10 +148,8 @@
/datum/interaction/lewd/footfuck/vag
description = "Rub your vagina on their foot."
interaction_sound = null
+ required_from_user_exposed = INTERACTION_REQUIRE_VAGINA
require_target_num_feet = 1
- require_target_feet = REQUIRE_ANY
- require_user_vagina = REQUIRE_EXPOSED
- require_user_penis = REQUIRE_NONE
max_distance = 1
/datum/interaction/lewd/footfuck/vag/display_interaction(mob/living/user, mob/living/partner)
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/handjob.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/handjob.dm
index f9ef29c88a..e0e13443d2 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/handjob.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/handjob.dm
@@ -1,9 +1,8 @@
/datum/interaction/lewd/handjob
description = "Jerk them off."
interaction_sound = null
- require_user_hands = TRUE
- require_target_penis = REQUIRE_EXPOSED
- max_distance = 1
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_target_exposed = INTERACTION_REQUIRE_PENIS
additional_details = list(
list(
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/kiss.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/kiss.dm
index 8e196c8a19..4aded3a99e 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/kiss.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/kiss.dm
@@ -1,11 +1,10 @@
/datum/interaction/lewd/kiss
description = "Kiss them deeply."
- require_user_mouth = TRUE
- require_target_mouth = TRUE
+ required_from_user = INTERACTION_REQUIRE_MOUTH
+ required_from_target = INTERACTION_REQUIRE_MOUTH
write_log_user = "kissed"
write_log_target = "was kissed by"
interaction_sound = null
- max_distance = 1
/datum/interaction/lewd/kiss/post_interaction(mob/living/user, mob/living/partner)
. = ..()
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/lick.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/lick.dm
index 6798d07d62..f58f3dc22d 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/lick.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/lick.dm
@@ -1,9 +1,8 @@
/datum/interaction/lewd/rimjob
description = "Lick their ass."
interaction_sound = null
- require_user_mouth = TRUE
- require_target_anus = REQUIRE_EXPOSED
- max_distance = 1
+ required_from_user = INTERACTION_REQUIRE_MOUTH
+ required_from_target_exposed = INTERACTION_REQUIRE_ANUS
/datum/interaction/lewd/rimjob/display_interaction(mob/living/user, mob/living/partner)
user.visible_message(span_lewd("\The [user] licks \the [partner]'s asshole."), ignored_mobs = user.get_unconsenting())
@@ -13,10 +12,10 @@
/datum/interaction/lewd/lickfeet
description = "Lick their feet."
interaction_sound = null
- require_user_mouth = TRUE
- require_target_feet = REQUIRE_ANY
+ required_from_user = INTERACTION_REQUIRE_MOUTH
+ required_from_target_exposed = INTERACTION_REQUIRE_FEET
+ required_from_target_unexposed = INTERACTION_REQUIRE_FEET
require_target_num_feet = 1
- max_distance = 1
/datum/interaction/lewd/lickfeet/display_interaction(mob/living/user, mob/living/partner)
var/message
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/mount.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/mount.dm
index 6e7d5aedb2..2a56efcda3 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/mount.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/mount.dm
@@ -1,9 +1,8 @@
/datum/interaction/lewd/mount
description = "Mount with your pussy."
interaction_sound = null
- require_user_vagina = REQUIRE_EXPOSED
- require_target_penis = REQUIRE_EXPOSED
- max_distance = 1
+ required_from_user_exposed = INTERACTION_REQUIRE_VAGINA
+ required_from_target_exposed = INTERACTION_REQUIRE_PENIS
/datum/interaction/lewd/mount/display_interaction(mob/living/user, mob/living/partner)
var/message
@@ -26,9 +25,8 @@
/datum/interaction/lewd/mountass
description = "Mount with your ass."
interaction_sound = null
- require_user_anus = REQUIRE_EXPOSED
- require_target_penis = REQUIRE_EXPOSED
- max_distance = 1
+ required_from_user_exposed = INTERACTION_REQUIRE_ANUS
+ required_from_target_exposed = INTERACTION_REQUIRE_PENIS
/datum/interaction/lewd/mountass/display_interaction(mob/living/user, mob/living/partner)
var/message
@@ -51,9 +49,8 @@
/datum/interaction/lewd/mountface
description = "Ass to face."
interaction_sound = null
- require_target_mouth = TRUE
- require_user_anus = REQUIRE_EXPOSED
- max_distance = 1
+ required_from_user_exposed = INTERACTION_REQUIRE_ANUS
+ required_from_target = INTERACTION_REQUIRE_MOUTH
/datum/interaction/lewd/mountface/display_interaction(mob/living/user, mob/living/partner)
var/message
@@ -77,9 +74,8 @@
/datum/interaction/lewd/thighs
description = "Smother them using your penis."
- max_distance = 1
- require_user_penis = REQUIRE_EXPOSED
- require_target_mouth = TRUE
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ required_from_target = INTERACTION_REQUIRE_MOUTH
interaction_sound = null
write_log_user = "thigh-trapped (penis)"
write_log_target = "was smothered (penis) by"
@@ -87,8 +83,7 @@
/datum/interaction/lewd/thighs/vagina
description = "Smother them using your vagina."
- require_user_penis = REQUIRE_NONE
- require_user_vagina = REQUIRE_EXPOSED
+ required_from_user_exposed = INTERACTION_REQUIRE_VAGINA
write_log_user = "thigh-trapped (vagina)"
write_log_target = "was smothered (vagina) by"
fucktarget = "vagina"
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/nipsuck.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/nipsuck.dm
index e5a0b8911e..c1e2a07001 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/nipsuck.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/nipsuck.dm
@@ -1,11 +1,10 @@
/datum/interaction/lewd/nipsuck
description = "Suck their nipples."
- require_target_breasts = REQUIRE_EXPOSED
- require_user_mouth = TRUE
+ required_from_user = INTERACTION_REQUIRE_MOUTH
+ required_from_target_exposed = INTERACTION_REQUIRE_BREASTS
write_log_user = "sucked nipples"
write_log_target = "had their nipples sucked by"
interaction_sound = null
- max_distance = 1
/datum/interaction/lewd/nipsuck/display_interaction(mob/living/carbon/human/user, mob/living/carbon/human/target)
if((user.a_intent == INTENT_HELP) || (user.a_intent == INTENT_DISARM))
@@ -13,7 +12,8 @@
pick(span_lewd("\The [user] gently sucks on \the [target]'s [pick("nipple", "nipples")]."),
span_lewd("\The [user] gently nibs \the [target]'s [pick("nipple", "nipples")]."),
span_lewd("\The [user] licks \the [target]'s [pick("nipple", "nipples")].")))
- if(target.has_breasts(REQUIRE_EXPOSED))
+ var/has_breasts = target.has_breasts()
+ if(has_breasts == TRUE || has_breasts == HAS_EXPOSED_GENITAL)
var/modifier = 1
var/obj/item/organ/genital/breasts/B = target.getorganslot(ORGAN_SLOT_BREASTS)
switch(B.size)
@@ -33,7 +33,8 @@
user.visible_message(
pick(span_lewd("\The [user] bites \the [target]'s [pick("nipple", "nipples")]."),
span_lewd("\The [user] aggressively sucks \the [target]'s [pick("nipple", "nipples")].")))
- if(target.has_breasts(REQUIRE_EXPOSED))
+ var/has_breasts = target.has_breasts()
+ if(has_breasts == TRUE || has_breasts == HAS_EXPOSED_GENITAL)
var/modifier = 1
var/obj/item/organ/genital/breasts/B = target.getorganslot(ORGAN_SLOT_BREASTS)
switch(B.size)
@@ -54,7 +55,8 @@
pick(span_lewd("\The [user] sucks \the [target]'s [pick("nipple", "nipples")] intently."),
span_lewd("\The [user] feasts \the [target]'s [pick("nipple", "nipples")]."),
span_lewd("\The [user] glomps \the [target]'s [pick("nipple", "nipples")].")))
- if(target.has_breasts(REQUIRE_EXPOSED))
+ var/has_breasts = target.has_breasts()
+ if(has_breasts == TRUE || has_breasts == HAS_EXPOSED_GENITAL)
var/modifier = 1
var/obj/item/organ/genital/breasts/B = target.getorganslot(ORGAN_SLOT_BREASTS)
switch(B.size)
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/nuts.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/nuts.dm
index 3210d01ed3..b5fd82721a 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/nuts.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/nuts.dm
@@ -1,9 +1,8 @@
/datum/interaction/lewd/nuts
description = "Nuts to face."
interaction_sound = null
- require_user_balls = REQUIRE_EXPOSED
- require_target_mouth = TRUE
- max_distance = 1
+ required_from_user_exposed = INTERACTION_REQUIRE_BALLS
+ required_from_target = INTERACTION_REQUIRE_MOUTH
write_log_user = "make-them-suck-their-nuts"
write_log_target = "was made to suck nuts by"
@@ -36,8 +35,7 @@
description = "Smack their nuts."
interaction_sound = 'modular_sand/sound/interactions/slap.ogg'
simple_message = "USER slaps TARGET's nuts!"
- require_target_balls = REQUIRE_EXPOSED
- needs_physical_contact = TRUE
- max_distance = 1
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_target_exposed = INTERACTION_REQUIRE_BALLS
write_log_user = "slapped-nuts"
write_log_target = "had their nuts slapped by"
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/oral.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/oral.dm
index eaf4fef71d..22eedf9e84 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/oral.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/oral.dm
@@ -1,17 +1,15 @@
/datum/interaction/lewd/oral
description = "Go down on them."
- require_user_mouth = TRUE
- require_target_vagina = REQUIRE_EXPOSED
+ required_from_user = INTERACTION_REQUIRE_MOUTH
+ required_from_target_exposed = INTERACTION_REQUIRE_VAGINA
write_log_user = "gave head to"
write_log_target = "was given head by"
interaction_sound = null
- max_distance = 1
var/fucktarget = "vagina"
/datum/interaction/lewd/oral/blowjob
description = "Suck them off."
- require_target_vagina = null
- require_target_penis = REQUIRE_EXPOSED
+ required_from_target_exposed = INTERACTION_REQUIRE_PENIS
fucktarget = "penis"
/datum/interaction/lewd/oral/display_interaction(mob/living/user, mob/living/partner)
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/self/breasts.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/self/breasts.dm
index 40d3d160d8..5db5d28585 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/self/breasts.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/self/breasts.dm
@@ -1,8 +1,9 @@
/datum/interaction/lewd/titgrope_self
description = "Grope your own breasts."
- require_user_hands = TRUE
- require_user_breasts = REQUIRE_ANY
- user_is_target = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_user_exposed = INTERACTION_REQUIRE_BREASTS
+ required_from_user_unexposed = INTERACTION_REQUIRE_BREASTS
+ interaction_flags = INTERACTION_FLAG_OOC_CONSENT | INTERACTION_FLAG_USER_IS_TARGET
interaction_sound = null
max_distance = 0
write_log_user = "groped own breasts"
@@ -78,9 +79,9 @@
/datum/interaction/lewd/self_nipsuck
description = "Suck your own nips."
- require_user_breasts = REQUIRE_EXPOSED
- require_user_mouth = TRUE
- user_is_target = TRUE
+ required_from_user = INTERACTION_REQUIRE_MOUTH
+ required_from_user_exposed = INTERACTION_REQUIRE_BREASTS
+ interaction_flags = INTERACTION_FLAG_OOC_CONSENT | INTERACTION_FLAG_USER_IS_TARGET
interaction_sound = null
max_distance = 0
write_log_user = "sucked their own nips"
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/self/finger.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/self/finger.dm
index 09ea82cf94..b2d90be13b 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/self/finger.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/self/finger.dm
@@ -1,9 +1,9 @@
/datum/interaction/lewd/fingerass_self
description = "Finger yourself."
interaction_sound = null
- require_user_hands = TRUE
- require_user_anus = REQUIRE_EXPOSED
- user_is_target = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_user_exposed = INTERACTION_REQUIRE_ANUS
+ interaction_flags = INTERACTION_FLAG_OOC_CONSENT | INTERACTION_FLAG_USER_IS_TARGET
max_distance = 0
write_log_user = "fingered self"
write_log_target = null
@@ -21,10 +21,10 @@
/datum/interaction/lewd/finger_self
description = "Finger your own pussy."
- require_user_hands = TRUE
- require_user_vagina = REQUIRE_EXPOSED
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_user_exposed = INTERACTION_REQUIRE_VAGINA
interaction_sound = null
- user_is_target = TRUE
+ interaction_flags = INTERACTION_FLAG_OOC_CONSENT | INTERACTION_FLAG_USER_IS_TARGET
max_distance = 0
write_log_user = "fingered own pussy"
write_log_target = null
diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/self/jack.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/self/jack.dm
index 857f1d1029..c49675c4a2 100644
--- a/modular_sand/code/datums/interactions/interaction_datums/lewd/self/jack.dm
+++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/self/jack.dm
@@ -1,9 +1,9 @@
/datum/interaction/lewd/jack
description = "Jerk yourself off."
interaction_sound = null
- require_user_hands = TRUE
- require_user_penis = REQUIRE_EXPOSED
- user_is_target = TRUE
+ required_from_user = INTERACTION_REQUIRE_HANDS
+ required_from_user_exposed = INTERACTION_REQUIRE_PENIS
+ interaction_flags = INTERACTION_FLAG_OOC_CONSENT | INTERACTION_FLAG_USER_IS_TARGET
max_distance = 0
write_log_user = "jerked off"
write_log_target = null
diff --git a/modular_sand/code/datums/interactions/interaction_mob.dm b/modular_sand/code/datums/interactions/interaction_mob.dm
index 4fa398ea72..f6dc946f38 100644
--- a/modular_sand/code/datums/interactions/interaction_mob.dm
+++ b/modular_sand/code/datums/interactions/interaction_mob.dm
@@ -10,5 +10,11 @@
/mob/living/proc/foot_is_free()
return is_barefoot()
+/mob/living/silicon/robot/mouth_is_free()
+ return TRUE
+
/mob/living/carbon/human/has_mouth()
return get_bodypart(BODY_ZONE_HEAD)
+
+/mob/living/carbon/human/has_hands() // technically should be an and but i'll replicate original behavior
+ return get_bodypart(BODY_ZONE_L_ARM) || get_bodypart(BODY_ZONE_R_ARM)
diff --git a/modular_sand/code/datums/interactions/lewd_definitions.dm b/modular_sand/code/datums/interactions/lewd_definitions.dm
index 2491f6a0e6..101d8b1f3a 100644
--- a/modular_sand/code/datums/interactions/lewd_definitions.dm
+++ b/modular_sand/code/datums/interactions/lewd_definitions.dm
@@ -91,240 +91,132 @@
/mob/living/proc/toggle_anus_always_accessible(accessibility)
anus_always_accessible = isnull(accessibility) ? !anus_always_accessible : accessibility
-/mob/living/proc/has_genital(slot, visibility = REQUIRE_ANY)
+/mob/living/proc/has_genital(slot)
var/mob/living/carbon/C = src
if(istype(C))
var/obj/item/organ/genital/genital = C.getorganslot(slot)
if(genital)
- switch(visibility)
- if(REQUIRE_ANY)
- return TRUE
- if(REQUIRE_EXPOSED)
- return genital.is_exposed() || genital.always_accessible
- if(REQUIRE_UNEXPOSED)
- return !genital.is_exposed()
- else
- return TRUE
+ if(genital.is_exposed() || genital.always_accessible)
+ return HAS_EXPOSED_GENITAL
+ else
+ return HAS_UNEXPOSED_GENITAL
return FALSE
-/mob/living/proc/has_penis(visibility = REQUIRE_ANY)
+/mob/living/proc/has_penis()
var/mob/living/carbon/C = src
if(has_penis && !istype(C))
return TRUE
- return has_genital(ORGAN_SLOT_PENIS, visibility)
+ return has_genital(ORGAN_SLOT_PENIS)
-/mob/living/proc/has_balls(visibility = REQUIRE_ANY)
+/mob/living/proc/has_balls()
var/mob/living/carbon/C = src
if(has_balls && !istype(C))
return TRUE
- return has_genital(ORGAN_SLOT_TESTICLES, visibility)
+ return has_genital(ORGAN_SLOT_TESTICLES)
-/mob/living/proc/has_vagina(visibility = REQUIRE_ANY)
+/mob/living/proc/has_vagina()
var/mob/living/carbon/C = src
if(has_vagina && !istype(C))
return TRUE
- return has_genital(ORGAN_SLOT_VAGINA, visibility)
+ return has_genital(ORGAN_SLOT_VAGINA)
-/mob/living/proc/has_breasts(visibility = REQUIRE_ANY)
+/mob/living/proc/has_breasts()
var/mob/living/carbon/C = src
if(has_breasts && !istype(C))
return TRUE
- return has_genital(ORGAN_SLOT_BREASTS, visibility)
+ return has_genital(ORGAN_SLOT_BREASTS)
-/mob/living/proc/has_anus(visibility = REQUIRE_ANY)
+/mob/living/proc/has_butt()
+ var/mob/living/carbon/C = src
+ if(has_butt && !istype(C))
+ return TRUE
+ return has_genital(ORGAN_SLOT_BUTT)
+
+/mob/living/proc/has_anus()
if(has_anus && !iscarbon(src))
return TRUE
- switch(visibility)
- if(REQUIRE_ANY)
- return TRUE
- if(REQUIRE_EXPOSED)
- if (has_anus && anus_always_accessible)
- return TRUE
- switch(anus_exposed)
- if(-1)
- return FALSE
- if(1)
- return TRUE
- else
- if(is_bottomless())
- return TRUE
- else
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(anus_exposed == -1)
- if(!anus_exposed)
- if(!is_bottomless())
- return TRUE
- else
- return FALSE
- else
- return FALSE
- else
- return TRUE
+ if (has_anus && anus_always_accessible)
+ return HAS_EXPOSED_GENITAL
+ switch(anus_exposed)
+ if(-1)
+ return HAS_UNEXPOSED_GENITAL
+ if(1)
+ return HAS_EXPOSED_GENITAL
else
- return TRUE
+ if(is_bottomless())
+ return HAS_EXPOSED_GENITAL
+ else
+ return HAS_UNEXPOSED_GENITAL
-/mob/living/proc/has_hand(visibility = REQUIRE_ANY)
+/mob/living/proc/has_hand()
if(iscarbon(src))
var/mob/living/carbon/C = src
var/handcount = 0
var/covered = 0
- var/iscovered = FALSE
for(var/obj/item/bodypart/l_arm/L in C.bodyparts)
handcount++
for(var/obj/item/bodypart/r_arm/R in C.bodyparts)
handcount++
+ if(!handcount)
+ return FALSE
if(C.get_item_by_slot(ITEM_SLOT_HANDS))
var/obj/item/clothing/gloves/G = C.get_item_by_slot(ITEM_SLOT_HANDS)
covered = G.body_parts_covered
if(covered & HANDS)
- iscovered = TRUE
- switch(visibility)
- if(REQUIRE_ANY)
- return handcount
- if(REQUIRE_EXPOSED)
- if(iscovered)
- return FALSE
- else
- return handcount
- if(REQUIRE_UNEXPOSED)
- if(!iscovered)
- return FALSE
- else
- return handcount
- else
- return handcount
+ return HAS_UNEXPOSED_GENITAL
+ else
+ return HAS_EXPOSED_GENITAL
return FALSE
-/mob/living/proc/has_feet(visibility = REQUIRE_ANY)
+/mob/living/proc/has_feet()
if(iscarbon(src))
var/mob/living/carbon/C = src
var/feetcount = 0
var/covered = 0
- var/iscovered = FALSE
for(var/obj/item/bodypart/l_leg/L in C.bodyparts)
feetcount++
for(var/obj/item/bodypart/r_leg/R in C.bodyparts)
feetcount++
+ if(!feetcount)
+ return FALSE
if(!C.is_barefoot())
covered = TRUE
if(covered)
- iscovered = TRUE
- switch(visibility)
- if(REQUIRE_ANY)
- return feetcount
- if(REQUIRE_EXPOSED)
- if(iscovered)
- return FALSE
- else
- return feetcount
- if(REQUIRE_UNEXPOSED)
- if(!iscovered)
- return FALSE
- else
- return feetcount
- else
- return feetcount
+ return HAS_UNEXPOSED_GENITAL
+ else
+ return HAS_EXPOSED_GENITAL
return FALSE
/mob/living/proc/get_num_feet()
- return has_feet(REQUIRE_ANY)
+ return 0
+
+/mob/living/carbon/get_num_feet()
+ . = ..()
+ for(var/obj/item/bodypart/l_leg/L in bodyparts)
+ .++
+ for(var/obj/item/bodypart/r_leg/R in bodyparts)
+ .++
//weird procs go here
-/mob/living/proc/has_ears(visibility = REQUIRE_ANY)
+//please check for existance separately
+/mob/living/proc/has_ears()
var/mob/living/carbon/C = src
if(istype(C))
- var/obj/item/organ/peepee = C.getorganslot(ORGAN_SLOT_EARS)
- if(peepee)
- switch(visibility)
- if(REQUIRE_ANY)
- return TRUE
- if(REQUIRE_EXPOSED)
- if(C.get_item_by_slot(ITEM_SLOT_EARS_LEFT) || C.get_item_by_slot(ITEM_SLOT_EARS_RIGHT))
- return FALSE
- else
- return TRUE
- if(REQUIRE_UNEXPOSED)
- if(!C.get_item_by_slot(ITEM_SLOT_EARS_LEFT || C.get_item_by_slot(ITEM_SLOT_EARS_RIGHT)))
- return FALSE
- else
- return TRUE
- else
- return TRUE
+ if(C.get_item_by_slot(ITEM_SLOT_EARS_LEFT) || C.get_item_by_slot(ITEM_SLOT_EARS_RIGHT))
+ return HAS_UNEXPOSED_GENITAL
+ else
+ return HAS_EXPOSED_GENITAL
return FALSE
-/mob/living/proc/has_earsockets(visibility = REQUIRE_ANY)
+/mob/living/proc/has_eyes()
var/mob/living/carbon/C = src
if(istype(C))
- var/obj/item/organ/peepee = C.getorganslot(ORGAN_SLOT_EARS)
- if(!peepee)
- switch(visibility)
- if(REQUIRE_ANY)
- return TRUE
- if(REQUIRE_EXPOSED)
- if(C.get_item_by_slot(ITEM_SLOT_EARS_LEFT) || C.get_item_by_slot(ITEM_SLOT_EARS_RIGHT))
- return FALSE
- else
- return TRUE
- if(REQUIRE_UNEXPOSED)
- if(!C.get_item_by_slot(ITEM_SLOT_EARS_LEFT) || !C.get_item_by_slot(ITEM_SLOT_EARS_RIGHT))
- return FALSE
- else
- return TRUE
- else
- return TRUE
+ if(C.get_item_by_slot(ITEM_SLOT_EYES))
+ return HAS_UNEXPOSED_GENITAL
+ else
+ return HAS_EXPOSED_GENITAL
return FALSE
-/mob/living/proc/has_eyes(visibility = REQUIRE_ANY)
- var/mob/living/carbon/C = src
- if(istype(C))
- var/obj/item/organ/peepee = C.getorganslot(ORGAN_SLOT_EYES)
- if(peepee)
- switch(visibility)
- if(REQUIRE_ANY)
- return TRUE
- if(REQUIRE_EXPOSED)
- if(C.get_item_by_slot(ITEM_SLOT_EYES))
- return FALSE
- else
- return TRUE
- if(REQUIRE_UNEXPOSED)
- if(!C.get_item_by_slot(ITEM_SLOT_EYES))
- return FALSE
- else
- return TRUE
- else
- return TRUE
- return FALSE
-
-/mob/living/proc/has_eyesockets(visibility = REQUIRE_ANY)
- var/mob/living/carbon/C = src
- if(istype(C))
- var/obj/item/organ/peepee = C.getorganslot(ORGAN_SLOT_EYES)
- if(!peepee)
- switch(visibility)
- if(REQUIRE_ANY)
- return TRUE
- if(REQUIRE_EXPOSED)
- if(get_item_by_slot(ITEM_SLOT_EYES))
- return FALSE
- else
- return TRUE
- if(REQUIRE_UNEXPOSED)
- if(!get_item_by_slot(ITEM_SLOT_EYES))
- return FALSE
- else
- return TRUE
- else
- return TRUE
- return FALSE
-
-/mob/living/proc/has_butt(visibility = REQUIRE_ANY)
- var/mob/living/carbon/C = src
- if(has_butt && !istype(C))
- return TRUE
- return has_genital(ORGAN_SLOT_BUTT, visibility)
-
///Are we wearing something that covers our chest?
/mob/living/proc/is_topless()
for(var/slot in GLOB.slots)
@@ -422,7 +314,8 @@
else
message = "cums on \the [partner]'s face."
if(CUM_TARGET_VAGINA)
- if(partner.has_vagina(REQUIRE_EXPOSED))
+ var/has_vagina = partner.has_vagina()
+ if(has_vagina == TRUE || has_vagina == HAS_EXPOSED_GENITAL)
if(partner_carbon_check)
target_gen = c_partner.getorganslot(ORGAN_SLOT_VAGINA)
message = "cums in \the [partner]'s pussy."
@@ -430,18 +323,20 @@
else
message = "cums on \the [partner]'s belly."
if(CUM_TARGET_ANUS)
- if(partner.has_anus(REQUIRE_EXPOSED))
+ var/has_anus = partner.has_anus()
+ if(has_anus == TRUE || has_anus == HAS_EXPOSED_GENITAL)
message = "cums in \the [partner]'s asshole."
cumin = TRUE
else
message = "cums on \the [partner]'s backside."
if(CUM_TARGET_HAND)
- if(partner.has_hand(REQUIRE_ANY))
+ if(partner.has_hand())
message = "cums in \the [partner]'s hand."
else
message = "cums on \the [partner]."
if(CUM_TARGET_BREASTS)
- if(partner.has_breasts(REQUIRE_EXPOSED))
+ var/has_breasts = partner.has_breasts()
+ if(has_breasts == TRUE || has_breasts == HAS_EXPOSED_GENITAL)
message = "cums onto \the [partner]'s breasts."
else
message = "cums on \the [partner]'s chest and neck."
@@ -449,7 +344,8 @@
if(partner.has_mouth() && partner.mouth_is_free())
message = "vigorously ruts [u_His] nutsack into \the [partner]'s mouth before shooting [u_His] thick, sticky jizz all over [t_His] eyes and hair."
if(THIGH_SMOTHERING)
- if(has_penis(REQUIRE_EXPOSED)) //it already checks for the cock before, why the hell would you do this redundant shit
+ var/has_penis = has_penis()
+ if(has_penis == TRUE || has_penis == HAS_EXPOSED_GENITAL) //it already checks for the cock before, why the hell would you do this redundant shit
message = "keeps \the [partner] locked in [u_His] thighs as [u_His] cock throbs, dumping its heavy load all over [t_His] face."
else
message = "reaches [u_His] peak, locking [u_His] legs around \the [partner]'s head extra hard as [u_He] cum[u_S] straight onto the head stuck between [u_His] thighs"
@@ -462,7 +358,7 @@
message = "cums on the floor!"
else
if(partner.has_feet())
- message = "cums on \the [partner]'s [last_lewd_datum.require_target_feet == 1 ? pick("foot", "sole") : pick("feet", "soles")]."
+ message = "cums on \the [partner]'s [last_lewd_datum.require_target_num_feet == 1 ? pick("foot", "sole") : pick("feet", "soles")]."
else
message = "cums on the floor!"
//weird shit goes here
@@ -480,7 +376,8 @@
cumin = TRUE
//
if(CUM_TARGET_PENIS)
- if(partner.has_penis(REQUIRE_EXPOSED))
+ var/has_penis = partner.has_penis()
+ if(has_penis == TRUE || has_penis == HAS_EXPOSED_GENITAL)
message = "cums on \the [partner]."
else
message = "cums on the floor!"
@@ -504,24 +401,27 @@
else
message = "squirts on \the [partner]'s face."
if(CUM_TARGET_VAGINA)
- if(partner.has_vagina(REQUIRE_EXPOSED))
+ var/has_vagina = partner.has_vagina()
+ if(has_vagina == TRUE || has_vagina == HAS_EXPOSED_GENITAL)
message = "squirts on \the [partner]'s pussy."
cumin = TRUE
else
message = "squirts on \the [partner]'s belly."
if(CUM_TARGET_ANUS)
- if(partner.has_anus(REQUIRE_EXPOSED))
+ var/has_anus = partner.has_anus()
+ if(has_anus == TRUE || has_anus == HAS_EXPOSED_GENITAL)
message = "squirts on \the [partner]'s asshole."
cumin = TRUE
else
message = "squirts on \the [partner]'s backside."
if(CUM_TARGET_HAND)
- if(partner.has_hand(REQUIRE_ANY))
+ if(partner.has_hand())
message = "squirts on \the [partner]'s hand."
else
message = "squirts on \the [partner]."
if(CUM_TARGET_BREASTS)
- if(partner.has_breasts(REQUIRE_EXPOSED))
+ var/has_breasts = partner.has_breasts()
+ if(has_breasts == TRUE || has_breasts == HAS_EXPOSED_GENITAL)
message = "squirts onto \the [partner]'s breasts."
else
message = "squirts on \the [partner]'s chest and neck."
@@ -539,7 +439,7 @@
message = "squirts on the floor!"
else
if(partner.has_feet())
- message = "squirts on \the [partner]'s [last_lewd_datum.require_target_feet == 1 ? pick("foot", "sole") : pick("feet", "soles")]."
+ message = "squirts on \the [partner]'s [last_lewd_datum.require_target_num_feet == 1 ? pick("foot", "sole") : pick("feet", "soles")]."
else
message = "squirts on the floor!"
//weird shit goes here
@@ -557,7 +457,8 @@
cumin = TRUE
//
if(CUM_TARGET_PENIS)
- if(partner.has_penis(REQUIRE_EXPOSED))
+ var/has_penis = partner.has_penis()
+ if(has_penis == TRUE || has_penis == HAS_EXPOSED_GENITAL)
message = "squirts on \the [partner]'s penis"
else
message = "squirts on the floor!"
@@ -586,7 +487,8 @@
else
message = "cums on \the [partner]'s face."
if(CUM_TARGET_VAGINA)
- if(partner.has_vagina(REQUIRE_EXPOSED))
+ var/has_vagina = partner.has_vagina()
+ if(has_vagina == TRUE || has_vagina == HAS_EXPOSED_GENITAL)
if(partner_carbon_check)
target_gen = c_partner.getorganslot(ORGAN_SLOT_VAGINA)
message = "cums in \the [partner]'s pussy."
@@ -594,7 +496,8 @@
else
message = "cums on \the [partner]'s belly."
if(CUM_TARGET_ANUS)
- if(partner.has_anus(REQUIRE_EXPOSED))
+ var/has_anus = partner.has_anus()
+ if(has_anus == TRUE || has_anus == HAS_EXPOSED_GENITAL)
message = "cums in \the [partner]'s asshole."
cumin = TRUE
else
@@ -626,7 +529,7 @@
message = "cums on the floor!"
else
if(partner.has_feet())
- message = "cums on \the [partner]'s [last_lewd_datum.require_target_feet == 1 ? pick("foot", "sole") : pick("feet", "soles")]."
+ message = "cums on \the [partner]'s [last_lewd_datum.require_target_num_feet == 1 ? pick("foot", "sole") : pick("feet", "soles")]."
else
message = "cums on the floor!"
//weird shit goes here
@@ -644,7 +547,8 @@
cumin = TRUE
//
if(CUM_TARGET_PENIS)
- if(partner.has_penis(REQUIRE_EXPOSED))
+ var/has_penis = partner.has_penis()
+ if(has_penis == TRUE || has_penis == HAS_EXPOSED_GENITAL)
message = "cums on \the [partner]."
else
message = "cums on the floor!"
@@ -668,13 +572,15 @@
else
message = "squirts on \the [partner]'s face."
if(CUM_TARGET_VAGINA)
- if(partner.has_vagina(REQUIRE_EXPOSED))
+ var/has_vagina = partner.has_vagina()
+ if(has_vagina == TRUE || has_vagina == HAS_EXPOSED_GENITAL)
message = "squirts on \the [partner]'s pussy."
cumin = TRUE
else
message = "squirts on \the [partner]'s belly."
if(CUM_TARGET_ANUS)
- if(partner.has_anus(REQUIRE_EXPOSED))
+ var/has_anus = partner.has_anus()
+ if(has_anus == TRUE || has_anus == HAS_EXPOSED_GENITAL)
message = "squirts on \the [partner]'s asshole."
cumin = TRUE
else
@@ -685,7 +591,8 @@
else
message = "squirts on \the [partner]."
if(CUM_TARGET_BREASTS)
- if(partner.has_breasts(REQUIRE_EXPOSED))
+ var/has_breasts = partner.has_breasts()
+ if(has_breasts == TRUE || has_breasts == HAS_EXPOSED_GENITAL)
message = "squirts onto \the [partner]'s breasts."
else
message = "squirts on \the [partner]'s chest and neck."
@@ -704,7 +611,7 @@
message = "squirts on the floor!"
else
if(partner.has_feet())
- message = "squirts on \the [partner]'s [last_lewd_datum.require_target_feet == 1 ? pick("foot", "sole") : pick("feet", "soles")]."
+ message = "squirts on \the [partner]'s [last_lewd_datum.require_target_num_feet == 1 ? pick("foot", "sole") : pick("feet", "soles")]."
else
message = "squirts on the floor!"
//weird shit goes here
@@ -722,7 +629,8 @@
cumin = TRUE
//
if(CUM_TARGET_PENIS)
- if(partner.has_penis(REQUIRE_EXPOSED))
+ var/has_penis = partner.has_penis()
+ if(has_penis == TRUE || has_penis == HAS_EXPOSED_GENITAL)
message = "squirts on \the [partner]'s penis"
else
message = "squirts on the floor!"
@@ -828,7 +736,7 @@
return TRUE
return FALSE
-/mob/living/proc/get_unconsenting(extreme = FALSE, list/ignored_mobs)
+/mob/living/proc/get_unconsenting(interaction_flags, list/ignored_mobs)
var/list/nope = list()
nope += ignored_mobs
for(var/mob/M in range(7, src))
@@ -836,7 +744,7 @@
var/client/cli = M.client
if(!(cli.prefs.toggles & VERB_CONSENT)) //Note: This probably could do with a specific preference
nope += M
- else if(extreme && (cli.prefs.extremepref == "No"))
+ else if(interaction_flags & INTERACTION_FLAG_EXTREME_CONTENT && (cli.prefs.extremepref == "No"))
nope += M
else
nope += M
diff --git a/modular_sand/code/datums/interactions/lewd_interactions.dm b/modular_sand/code/datums/interactions/lewd_interactions.dm
index e443fd82b5..c934fac43a 100644
--- a/modular_sand/code/datums/interactions/lewd_interactions.dm
+++ b/modular_sand/code/datums/interactions/lewd_interactions.dm
@@ -4,66 +4,16 @@
simple_message = "USER slaps TARGET right on the ass!"
simple_style = "danger"
interaction_sound = 'sound/weapons/slap.ogg'
- needs_physical_contact = TRUE
- require_ooc_consent = TRUE
- max_distance = 1
+ interaction_flags = INTERACTION_FLAG_ADJACENT | INTERACTION_FLAG_OOC_CONSENT
write_log_user = "ass-slapped"
write_log_target = "was ass-slapped by"
- var/user_not_tired = FALSE
- var/target_not_tired = FALSE
- //Avoid using these!
- //Should only really use in case there are no related organs
- //but you want the target or user to be topless/bottomless.
- //Example: Nipple licking/sucking.
- //Otherwise, simply use the "require" vars, which
- //i have changed to actually check for the appropriate organs.
- //This is better because it means that exposing a genital while still
- //wearing something actually means you can do the s*x.
- var/require_user_topless
- var/require_target_topless
- var/require_user_bottomless
- var/require_target_bottomless
- //
-
- //REQUIRE_NONE for doesn't require.
- //REQUIRE_EXPOSED for requires exposed.
- //REQUIRE_ANY for both exposed and unexposed.
- //REQUIRE_UNEXPOSED for requires unexposed.
- var/require_user_penis
- var/require_user_anus
- var/require_user_vagina
- var/require_user_breasts
- var/require_user_feet
- var/require_user_balls
-
- //Different from the others above. Use the number of required feet.
+ /// Use the number of required feet.
var/require_user_num_feet
-
- //Same logic presented before
- var/require_target_penis
- var/require_target_anus
- var/require_target_vagina
- var/require_target_breasts
- var/require_target_feet
- var/require_target_balls
-
var/require_target_num_feet
- //"just fucking kill me" variables
- //also the same logic as before
- var/extreme = FALSE //Boolean. Used to hide extreme shit from those who do not want it.
- var/require_target_ears
- var/require_target_earsockets
- var/require_target_eyes
- var/require_target_eyesockets
- var/require_user_ears
- var/require_user_earsockets
- var/require_user_eyes
- var/require_user_eyesockets
- //
-
+ /// Time before actions can be done again
var/user_refractory_cost
var/target_refractory_cost
@@ -71,207 +21,218 @@
. = ..()
if(!.)
return FALSE
- if(user_not_tired && !COOLDOWN_FINISHED(user, refractory_period))
+ if((interaction_flags & INTERACTION_FLAG_USER_NOT_TIRED) && !COOLDOWN_FINISHED(user, refractory_period))
if(!silent) //bye spam
to_chat(user, span_warning("You're still exhausted from the last time. You need to wait [DisplayTimeText(COOLDOWN_TIMELEFT(user, refractory_period), 1)] until you can do that!"))
return FALSE
- if(require_user_bottomless && !user.is_bottomless())
+ if((required_from_user & INTERACTION_REQUIRE_BOTTOMLESS) && !user.is_bottomless())
if(!silent)
to_chat(user, span_warning("Your pants are in the way."))
return FALSE
- if(require_user_topless && !user.is_topless())
+ if((required_from_user & INTERACTION_REQUIRE_TOPLESS) && !user.is_topless())
if(!silent)
to_chat(user, span_warning("Your top is in the way."))
return FALSE
- if(require_user_penis)
- switch(require_user_penis)
- if(REQUIRE_EXPOSED)
- if(!user.has_penis(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your penis need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_penis(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You don't have a penis."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_penis(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your penis need to be unexposed."))
- return FALSE
+ var/user_require_penis_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_PENIS)
+ var/user_require_penis_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_PENIS)
+ if(user_require_penis_exposed || user_require_penis_unexposed)
+ var/has_penis = user.has_penis()
+ if(!has_penis)
+ if(!silent)
+ to_chat(user, span_warning("You don't have a penis."))
+ return FALSE
- if(require_user_balls)
- switch(require_user_balls)
- if(REQUIRE_EXPOSED)
- if(!user.has_balls(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your balls need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_balls(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You don't have balls."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_balls(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your balls need to be unexposed."))
- return FALSE
+ // Special behavior for things like non-humans and if both sides are allowed
+ if(!(has_penis == TRUE) || !(user_require_penis_exposed && user_require_penis_unexposed))
+ if((user_require_penis_exposed) && has_penis == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your penis need to be exposed."))
+ return FALSE
+ if((user_require_penis_unexposed) && has_penis == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your penis need to be unexposed."))
+ return FALSE
- if(require_user_anus)
- switch(require_user_anus)
- if(REQUIRE_EXPOSED)
- if(!user.has_anus(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your anus need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_anus(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You don't have an anus."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_anus(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your anus need to be unexposed."))
- return FALSE
+ var/user_require_balls_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_BALLS)
+ var/user_require_balls_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_BALLS)
+ if(user_require_balls_exposed || user_require_balls_unexposed)
+ var/has_balls = user.has_balls()
+ if(!has_balls)
+ if(!silent)
+ to_chat(user, span_warning("You don't have balls."))
+ return FALSE
- if(require_user_vagina)
- switch(require_user_vagina)
- if(REQUIRE_EXPOSED)
- if(!user.has_vagina(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your vagina need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_vagina(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You don't have a vagina."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_vagina(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your vagina need to be unexposed."))
- return FALSE
+ if(!(has_balls == TRUE) || !(user_require_balls_exposed && user_require_balls_unexposed))
+ if((user_require_balls_exposed) && has_balls == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your balls need to be exposed."))
+ return FALSE
+ if((user_require_balls_unexposed) && has_balls == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your balls need to be unexposed."))
+ return FALSE
- if(require_user_breasts)
- switch(require_user_breasts)
- if(REQUIRE_EXPOSED)
- if(!user.has_breasts(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your breasts need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_breasts(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You don't have breasts."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_breasts(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your breasts need to be unexposed."))
- return FALSE
+ var/user_require_anus_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_ANUS)
+ var/user_require_anus_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_ANUS)
+ if(user_require_anus_exposed || user_require_anus_unexposed)
+ var/has_anus = user.has_anus()
+ if(!has_anus)
+ if(!silent)
+ to_chat(user, span_warning("You don't have an anus."))
+ return FALSE
- if(require_user_feet)
- switch(require_user_feet)
- if(REQUIRE_EXPOSED)
- if(!user.has_feet(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your feet need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_feet(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You don't have enough feet."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_feet(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your feet need to be unexposed."))
- return FALSE
+ if(!(has_anus == TRUE) || !(user_require_anus_exposed && user_require_anus_unexposed))
+ if(user_require_anus_exposed && has_anus == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your anus needs to be exposed."))
+ return FALSE
+ if(user_require_anus_unexposed && has_anus == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your anus needs to be unexposed."))
+ return FALSE
+
+ var/user_require_vagina_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_VAGINA)
+ var/user_require_vagina_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_VAGINA)
+ if(user_require_vagina_exposed || user_require_vagina_unexposed)
+ var/has_vagina = user.has_vagina()
+ if(!has_vagina)
+ if(!silent)
+ to_chat(user, span_warning("You don't have a vagina."))
+ return FALSE
+
+ if(!(has_vagina == TRUE) || !(user_require_vagina_exposed && user_require_vagina_unexposed))
+ if(user_require_vagina_exposed && has_vagina == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your vagina needs to be exposed."))
+ return FALSE
+ if(user_require_vagina_unexposed && has_vagina == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your vagina needs to be unexposed."))
+ return FALSE
+
+ var/user_require_breasts_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_BREASTS)
+ var/user_require_breasts_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_BREASTS)
+ if(user_require_breasts_exposed || user_require_breasts_unexposed)
+ var/has_breasts = user.has_breasts()
+ if(!has_breasts)
+ if(!silent)
+ to_chat(user, span_warning("You don't have breasts."))
+ return FALSE
+
+ if(!(has_breasts == TRUE) || !(user_require_breasts_exposed && user_require_breasts_unexposed))
+ if(user_require_breasts_exposed && has_breasts == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your breasts need to be exposed."))
+ return FALSE
+ if(user_require_breasts_unexposed && has_breasts == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your breasts need to be unexposed."))
+ return FALSE
+
+ var/user_require_feet_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_FEET)
+ var/user_require_feet_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_FEET)
+ if(user_require_feet_exposed || user_require_feet_unexposed)
+ var/has_feet = user.has_feet()
+ if(!has_feet)
+ if(!silent)
+ to_chat(user, span_warning("You don't have feet."))
+ return FALSE
+
+ if(!(user_require_feet_exposed && user_require_feet_unexposed))
+ if(user_require_feet_exposed && has_feet == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your feet need to be exposed."))
+ return FALSE
+ if(user_require_feet_unexposed && has_feet == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your feet need to be unexposed."))
+ return FALSE
if(require_user_num_feet && (user.get_num_feet() < require_user_num_feet))
if(!silent)
to_chat(user, span_warning("You don't have enough feet."))
return FALSE
- if(require_user_eyes)
- switch(require_user_eyes)
- if(REQUIRE_EXPOSED)
- if(!user.has_eyes(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your eyes need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_eyes(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You don't have eyes."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_eyes(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your eyes need to be unexposed."))
- return FALSE
+ var/user_require_eyes_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_EYES)
+ var/user_require_eyes_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_EYES)
+ if(user_require_eyes_exposed || user_require_eyes_unexposed)
+ var/has_eyes = user.has_eyes()
+ if(!user.getorganslot(ORGAN_SLOT_EYES))
+ if(!silent)
+ to_chat(user, span_warning("You don't have eyes."))
+ return FALSE
- if(require_user_eyesockets)
- switch(require_user_eyesockets)
- if(REQUIRE_EXPOSED)
- if(!user.has_eyesockets(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your eyesockets need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_eyesockets(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You still have eyes."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_eyesockets(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your eyesockets need to be unexposed."))
- return FALSE
+ if(!(user_require_eyes_exposed && user_require_eyes_unexposed))
+ if(user_require_eyes_exposed && has_eyes == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your eyes need to be exposed."))
+ return FALSE
+ if(user_require_eyes_unexposed && has_eyes == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your eyes need to be unexposed."))
+ return FALSE
- if(require_user_ears)
- switch(require_user_ears)
- if(REQUIRE_EXPOSED)
- if(!user.has_ears(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your ears need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_ears(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You don't have ears."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_ears(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your ears need to be unexposed."))
- return FALSE
+ var/user_require_eyesockets_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_EYESOCKETS)
+ var/user_require_eyesockets_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_EYESOCKETS)
+ if(user_require_eyesockets_exposed || user_require_eyesockets_unexposed)
+ var/has_eyes = user.has_eyes()
+ if(user.getorganslot(ORGAN_SLOT_EYES))
+ if(!silent)
+ to_chat(user, span_warning("You have eyes!"))
+ return FALSE
- if(require_user_earsockets)
- switch(require_user_earsockets)
- if(REQUIRE_EXPOSED)
- if(!user.has_earsockets(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your earsockets need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!user.has_earsockets(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("You still have eyes."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!user.has_earsockets(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Your earsockets need to be unexposed."))
- return FALSE
+ if(!(user_require_eyesockets_exposed && user_require_eyesockets_unexposed))
+ if(user_require_eyesockets_exposed && has_eyes == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your eyesockets need to be exposed."))
+ return FALSE
+ if(user_require_eyesockets_unexposed && has_eyes == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your eyesockets need to be unexposed."))
+ return FALSE
- if(extreme)
+ var/user_require_ear_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_EARS)
+ var/user_require_ear_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_EARS)
+ if(user_require_ear_exposed || user_require_ear_unexposed)
+ var/has_ears = user.has_ears()
+ if(!user.getorganslot(ORGAN_SLOT_EARS))
+ if(!silent)
+ to_chat(user, span_warning("You don't have ears."))
+ return FALSE
+
+ if(!(user_require_ear_exposed && user_require_ear_unexposed))
+ if(user_require_ear_exposed && has_ears == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your ears need to be exposed."))
+ return FALSE
+ if(user_require_ear_unexposed && has_ears == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your ears need to be unexposed."))
+ return FALSE
+
+ var/user_require_earsockets_exposed = !!(required_from_user_exposed & INTERACTION_REQUIRE_EARSOCKETS)
+ var/user_require_earsockets_unexposed = !!(required_from_user_unexposed & INTERACTION_REQUIRE_EARSOCKETS)
+ if(user_require_earsockets_exposed || user_require_earsockets_unexposed)
+ var/has_ears = user.has_ears()
+ if(user.getorganslot(ORGAN_SLOT_EARS))
+ if(!silent)
+ to_chat(user, span_warning("You have ears!"))
+ return FALSE
+
+ if(!(user_require_earsockets_exposed && user_require_earsockets_unexposed))
+ if(user_require_earsockets_exposed && has_ears == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your earsockets need to be exposed."))
+ return FALSE
+ if(user_require_earsockets_unexposed && has_ears == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(user, span_warning("Your earsockets need to be unexposed."))
+ return FALSE
+
+ if(interaction_flags & INTERACTION_FLAG_EXTREME_CONTENT)
var/client/cli = user.client
if(cli)
if(cli.prefs.extremepref == "No")
@@ -279,7 +240,7 @@
to_chat(user, span_warning("That's way too much for you."))
return FALSE
- if(require_ooc_consent)
+ if(interaction_flags & INTERACTION_FLAG_OOC_CONSENT)
if((!user.ckey) || (user.client && user.client.prefs.toggles & VERB_CONSENT))
return TRUE
if(action_check)
@@ -290,207 +251,217 @@
. = ..()
if(!.)
return FALSE
- if(target_not_tired && !COOLDOWN_FINISHED(target, refractory_period))
+ if((required_from_target & INTERACTION_FLAG_TARGET_NOT_TIRED) && !COOLDOWN_FINISHED(target, refractory_period))
if(!silent) //same with this
to_chat(user, span_warning("They're still exhausted from the last time. They need to wait [DisplayTimeText(COOLDOWN_TIMELEFT(target, refractory_period), 1)] until you can do that!"))
return FALSE
- if(require_target_bottomless && !target.is_bottomless())
+ if((required_from_target & INTERACTION_REQUIRE_BOTTOMLESS) && !target.is_bottomless())
if(!silent)
to_chat(user, span_warning("Their pants are in the way."))
return FALSE
- if(require_target_topless && !target.is_topless())
+ if((required_from_target & INTERACTION_REQUIRE_TOPLESS) && !target.is_bottomless())
if(!silent)
to_chat(user, span_warning("Their clothes are in the way."))
return FALSE
- if(require_target_penis)
- switch(require_target_penis)
- if(REQUIRE_EXPOSED)
- if(!target.has_penis(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their penis needs to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_penis(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They don't have a penis."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_penis(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their penis needs to be unexposed."))
- return FALSE
+ var/target_require_penis_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_PENIS)
+ var/target_require_penis_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_PENIS)
+ if(target_require_penis_exposed || target_require_penis_unexposed)
+ var/has_penis = target.has_penis()
+ if(!has_penis)
+ if(!silent)
+ to_chat(target, span_warning("They don't have a penis."))
+ return FALSE
- if(require_target_balls)
- switch(require_target_balls)
- if(REQUIRE_EXPOSED)
- if(!target.has_balls(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their balls need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_balls(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They don't have balls."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_balls(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their balls need to be unexposed."))
- return FALSE
+ if(!(has_penis == TRUE) || !(target_require_penis_exposed && target_require_penis_unexposed))
+ if(target_require_penis_exposed && has_penis == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their penis needs to be exposed."))
+ return FALSE
+ if(target_require_penis_unexposed && has_penis == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their penis needs to be unexposed."))
+ return FALSE
- if(require_target_anus)
- switch(require_target_anus)
- if(REQUIRE_EXPOSED)
- if(!target.has_anus(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their anus needs to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_anus(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They don't have an anus."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_anus(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their anus needs to be unexposed."))
- return FALSE
+ var/target_require_balls_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_BALLS)
+ var/target_require_balls_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_BALLS)
+ if(target_require_balls_exposed || target_require_balls_unexposed)
+ var/has_balls = target.has_balls()
+ if(!has_balls)
+ if(!silent)
+ to_chat(target, span_warning("They don't have balls."))
+ return FALSE
- if(require_target_vagina)
- switch(require_target_vagina)
- if(REQUIRE_EXPOSED)
- if(!target.has_vagina(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their vagina needs to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_vagina(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They don't have a vagina."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_vagina(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their vagina needs to be unexposed."))
- return FALSE
+ if(!(has_balls == TRUE) || !(target_require_balls_exposed && target_require_balls_unexposed))
+ if(target_require_balls_exposed && has_balls == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their balls need to be exposed."))
+ return FALSE
+ if(target_require_balls_unexposed && has_balls == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their balls need to be unexposed."))
+ return FALSE
- if(require_target_breasts)
- switch(require_target_breasts)
- if(REQUIRE_EXPOSED)
- if(!target.has_breasts(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their breasts need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_breasts(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They don't have breasts."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_breasts(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their breasts need to be unexposed."))
- return FALSE
+ var/target_require_anus_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_ANUS)
+ var/target_require_anus_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_ANUS)
+ if(target_require_anus_exposed || target_require_anus_unexposed)
+ var/has_anus = target.has_anus()
+ if(!has_anus)
+ if(!silent)
+ to_chat(target, span_warning("They don't have an anus."))
+ return FALSE
- if(require_target_feet)
- switch(require_target_feet)
- if(REQUIRE_EXPOSED)
- if(!target.has_feet(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their feet need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_feet(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They don't have enough feet."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_feet(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their feet need to be unexposed."))
- return FALSE
+ if(!(has_anus == TRUE) || !(target_require_anus_exposed && target_require_anus_unexposed))
+ if(target_require_anus_exposed && has_anus == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their anus needs to be exposed."))
+ return FALSE
+ if(target_require_anus_unexposed && has_anus == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their anus needs to be unexposed."))
+ return FALSE
+
+ var/target_require_vagina_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_VAGINA)
+ var/target_require_vagina_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_VAGINA)
+ if(target_require_vagina_exposed || target_require_vagina_unexposed)
+ var/has_vagina = target.has_vagina()
+ if(!has_vagina)
+ if(!silent)
+ to_chat(target, span_warning("They don't have a vagina."))
+ return FALSE
+
+ if(!(has_vagina == TRUE) || !(target_require_vagina_exposed && target_require_vagina_unexposed))
+ if(target_require_vagina_exposed && has_vagina == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their vagina needs to be exposed."))
+ return FALSE
+ if(target_require_vagina_unexposed && has_vagina == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their vagina needs to be unexposed."))
+ return FALSE
+
+ var/target_require_breasts_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_BREASTS)
+ var/target_require_breasts_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_BREASTS)
+ if(target_require_breasts_exposed || target_require_breasts_unexposed)
+ var/has_breasts = target.has_breasts()
+ if(!has_breasts)
+ if(!silent)
+ to_chat(target, span_warning("They don't have breasts."))
+ return FALSE
+
+ if(!(has_breasts == TRUE) || !(target_require_breasts_exposed && target_require_breasts_unexposed))
+ if(target_require_breasts_exposed && has_breasts == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their breasts need to be exposed."))
+ return FALSE
+ if(target_require_breasts_unexposed && has_breasts == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their breasts need to be unexposed."))
+ return FALSE
+
+ var/target_require_feet_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_FEET)
+ var/target_require_feet_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_FEET)
+ if(target_require_feet_exposed || target_require_feet_unexposed)
+ var/has_feet = target.has_feet()
+ if(!has_feet)
+ if(!silent)
+ to_chat(target, span_warning("They don't have feet."))
+ return FALSE
+
+ if(!(target_require_feet_exposed && target_require_feet_unexposed))
+ if(target_require_feet_exposed && has_feet == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their feet need to be exposed."))
+ return FALSE
+ if(target_require_feet_unexposed && has_feet == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their feet need to be unexposed."))
+ return FALSE
if(require_target_num_feet && (target.get_num_feet() < require_target_num_feet))
if(!silent)
- to_chat(user, span_warning("They don't have enough feet."))
+ to_chat(target, span_warning("They don't have enough feet."))
return FALSE
- if(require_target_eyes)
- switch(require_target_eyes)
- if(REQUIRE_EXPOSED)
- if(!target.has_eyes(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their eyes need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_eyes(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They don't have eyes."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_eyes(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their eyes need to be unexposed."))
- return FALSE
+ var/target_require_eyes_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_EYES)
+ var/target_require_eyes_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_EYES)
+ if(target_require_eyes_exposed || target_require_eyes_unexposed)
+ var/has_eyes = target.has_eyes()
+ if(!target.getorganslot(ORGAN_SLOT_EYES))
+ if(!silent)
+ to_chat(target, span_warning("They don't have eyes."))
+ return FALSE
- if(require_target_eyesockets)
- switch(require_target_eyesockets)
- if(REQUIRE_EXPOSED)
- if(!target.has_eyesockets(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their eyesockets need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_eyesockets(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They still have eyes."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_eyesockets(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their eyesockets need to be unexposed."))
- return FALSE
+ if(!(target_require_eyes_exposed && target_require_eyes_unexposed))
+ if(target_require_eyes_exposed && has_eyes == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their eyes need to be exposed."))
+ return FALSE
+ if(target_require_eyes_unexposed && has_eyes == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their eyes need to be unexposed."))
+ return FALSE
- if(require_target_ears)
- switch(require_target_ears)
- if(REQUIRE_EXPOSED)
- if(!target.has_ears(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their ears need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_ears(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They don't have ears."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_ears(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their ears need to be unexposed."))
- return FALSE
+ var/target_require_eyesockets_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_EYESOCKETS)
+ var/target_require_eyesockets_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_EYESOCKETS)
+ if(target_require_eyesockets_exposed || target_require_eyesockets_unexposed)
+ var/has_eyes = target.has_eyes()
+ if(target.getorganslot(ORGAN_SLOT_EYES))
+ if(!silent)
+ to_chat(target, span_warning("They have eyes!"))
+ return FALSE
- if(require_target_earsockets)
- switch(require_target_earsockets)
- if(REQUIRE_EXPOSED)
- if(!target.has_earsockets(REQUIRE_EXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their earsockets need to be exposed."))
- return FALSE
- if(REQUIRE_ANY)
- if(!target.has_earsockets(REQUIRE_ANY))
- if(!silent)
- to_chat(user, span_warning("They still have eyes."))
- return FALSE
- if(REQUIRE_UNEXPOSED)
- if(!target.has_earsockets(REQUIRE_UNEXPOSED))
- if(!silent)
- to_chat(user, span_warning("Their earsockets need to be unexposed."))
- return FALSE
+ if(!(target_require_eyesockets_exposed && target_require_eyesockets_unexposed))
+ if(target_require_eyesockets_exposed && has_eyes == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their eyesockets need to be exposed."))
+ return FALSE
+ if(target_require_eyesockets_unexposed && has_eyes == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their eyesockets need to be unexposed."))
+ return FALSE
- if(extreme)
+ var/target_require_ears_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_EARS)
+ var/target_require_ears_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_EARS)
+ if(target_require_ears_exposed || target_require_ears_unexposed)
+ var/has_ears = target.has_ears()
+ if(!target.getorganslot(ORGAN_SLOT_EARS))
+ if(!silent)
+ to_chat(target, span_warning("They don't have ears."))
+ return FALSE
+
+ if(!(target_require_ears_exposed && target_require_ears_unexposed))
+ if(target_require_ears_exposed && has_ears == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their ears need to be exposed."))
+ return FALSE
+ if(target_require_ears_unexposed && has_ears == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their ears need to be unexposed."))
+ return FALSE
+
+ var/target_require_earsockets_exposed = !!(required_from_target_exposed & INTERACTION_REQUIRE_EARSOCKETS)
+ var/target_require_earsockets_unexposed = !!(required_from_target_unexposed & INTERACTION_REQUIRE_EARSOCKETS)
+ if(target_require_earsockets_exposed || target_require_earsockets_unexposed)
+ var/has_ears = target.has_ears()
+ if(target.getorganslot(ORGAN_SLOT_EARS))
+ if(!silent)
+ to_chat(target, span_warning("They have ears!"))
+ return FALSE
+
+ if(!(target_require_earsockets_exposed && target_require_earsockets_unexposed))
+ if(target_require_earsockets_exposed && has_ears == HAS_UNEXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their earsockets need to be exposed."))
+ return FALSE
+ if(target_require_earsockets_unexposed && has_ears == HAS_EXPOSED_GENITAL)
+ if(!silent)
+ to_chat(target, span_warning("Their earsockets need to be unexposed."))
+ return FALSE
+
+ if(interaction_flags & INTERACTION_FLAG_EXTREME_CONTENT)
var/client/cli = target.client
if(cli)
if(target.client.prefs.extremepref == "No")
@@ -498,7 +469,7 @@
to_chat(user, span_warning("For some reason, you don't want to do this to [target]."))
return FALSE
- if(require_ooc_consent)
+ if(interaction_flags & INTERACTION_FLAG_OOC_CONSENT)
if((!target.ckey) || (target.client && target.client.prefs.toggles & VERB_CONSENT))
return TRUE
return FALSE
@@ -558,18 +529,18 @@
. += "...are partially clothed."
else
. += "...are clothed."
- if(has_breasts(REQUIRE_EXPOSED))
+ if(has_breasts() == HAS_EXPOSED_GENITAL)
. += "...have breasts."
- if(has_penis(REQUIRE_EXPOSED))
+ if(has_penis() == HAS_EXPOSED_GENITAL)
. += "...have a penis."
- if(has_balls(REQUIRE_EXPOSED))
+ if(has_balls() == HAS_EXPOSED_GENITAL)
. += "...have a ballsack."
- if(has_vagina(REQUIRE_EXPOSED))
+ if(has_vagina() == HAS_EXPOSED_GENITAL)
. += "...have a vagina."
- if(has_anus(REQUIRE_EXPOSED))
+ if(has_anus() == HAS_EXPOSED_GENITAL)
. += "...have an anus."
- if(has_feet(REQUIRE_EXPOSED))
- switch(has_feet(REQUIRE_EXPOSED))
+ if(has_feet() == HAS_EXPOSED_GENITAL)
+ switch(get_num_feet())
if(2)
. += "...have a pair of feet."
if(1)
diff --git a/modular_sand/code/datums/interactions/lewd_objects.dm b/modular_sand/code/datums/interactions/lewd_objects.dm
index c2bb19045a..b002bd7bc3 100644
--- a/modular_sand/code/datums/interactions/lewd_objects.dm
+++ b/modular_sand/code/datums/interactions/lewd_objects.dm
@@ -11,11 +11,13 @@
if(BODY_ZONE_PRECISE_GROIN)
switch(hole)
if(CUM_TARGET_VAGINA)
- if(M.has_vagina(REQUIRE_EXPOSED))
+ var/has_vagina = M.has_vagina()
+ if(has_vagina == TRUE || has_vagina == HAS_EXPOSED_GENITAL)
message = (user == M) ? pick("fucks [possessive_verb] own pussy with \the [src]","shoves \the [src] into [possessive_verb] pussy", "jams \the [src] into [possessive_verb] pussy") : pick("fucks [M] right in the pussy with \the [src]", "jams \the [src] right into [M]'s pussy")
lust_amt = NORMAL_LUST
if(CUM_TARGET_ANUS)
- if(M.has_anus(REQUIRE_EXPOSED))
+ var/has_anus = M.has_anus()
+ if(has_anus == TRUE || has_anus == HAS_EXPOSED_GENITAL)
message = (user == M) ? pick("fucks [possessive_verb] own ass with \the [src]","shoves \the [src] into [possessive_verb] ass", "jams \the [src] into [possessive_verb] ass") : pick("fucks [M]'s asshole with \the [src]", "jams \the [src] into [M]'s ass")
lust_amt = NORMAL_LUST
if(BODY_ZONE_PRECISE_MOUTH)
diff --git a/modular_sand/code/game/objects/items/fleshlight.dm b/modular_sand/code/game/objects/items/fleshlight.dm
index 80bf2bca06..1741f7ff8d 100644
--- a/modular_sand/code/game/objects/items/fleshlight.dm
+++ b/modular_sand/code/game/objects/items/fleshlight.dm
@@ -56,7 +56,8 @@
if(ishuman(M) && (M?.client?.prefs?.toggles & VERB_CONSENT))
switch(user.zone_selected)
if(BODY_ZONE_PRECISE_GROIN)
- if(M.has_penis(REQUIRE_EXPOSED))
+ var/has_penis = M.has_penis()
+ if(has_penis == TRUE || has_penis == HAS_EXPOSED_GENITAL)
message = (user == M) ? pick("pumps [src] on [possessive_verb] penis") : pick("pumps \the [src] on [M]'s penis")
lust_amt = NORMAL_LUST
if(message)
@@ -110,7 +111,8 @@
if(ishuman(M) && (M?.client?.prefs?.toggles & VERB_CONSENT) && useable) // I promise all those checks are worth it!
switch(user.zone_selected)
if(BODY_ZONE_PRECISE_GROIN)
- if(M.has_penis(REQUIRE_EXPOSED))
+ var/has_penis = M.has_penis()
+ if(has_penis == TRUE || has_penis == HAS_EXPOSED_GENITAL)
message = (user == M) ? pick("fucks into [src]") : pick("forces [M] to fuck into [src]")
lust_amt = NORMAL_LUST
P = M.getorganslot(ORGAN_SLOT_PENIS)
@@ -122,7 +124,7 @@
arouse_only_target = TRUE
target = "mouth"
if(BODY_ZONE_R_ARM)
- if(M.has_hand(REQUIRE_ANY))
+ if(M.has_hand())
var/can_interact = FALSE
for(var/obj/item/bodypart/r_arm/R in M.bodyparts)
can_interact = TRUE
@@ -132,7 +134,7 @@
arouse_only_target = TRUE
target = "hand"
if(BODY_ZONE_L_ARM)
- if(M.has_hand(REQUIRE_ANY))
+ if(M.has_hand())
var/can_interact = FALSE
for(var/obj/item/bodypart/l_arm/L in M.bodyparts)
can_interact = TRUE
@@ -284,11 +286,13 @@
var/mob/living/carbon/human/human = M
switch(targetting)
if("vagina")
- if(!human.has_vagina(REQUIRE_EXPOSED))
+ var/has_vagina = !human.has_vagina()
+ if(has_vagina == TRUE || has_vagina == HAS_EXPOSED_GENITAL)
to_chat(human, span_warning("The vagina is covered or there is none!"))
return FALSE
if("anus")
- if(!human.has_anus(REQUIRE_EXPOSED))
+ var/has_anus = !human.has_anus()
+ if(has_anus == TRUE || has_anus == HAS_EXPOSED_GENITAL)
to_chat(human, span_warning("The anus is covered or there is none!"))
return FALSE
return TRUE
diff --git a/tgui/packages/tgui/interfaces/MobInteraction.tsx b/tgui/packages/tgui/interfaces/MobInteraction.tsx
index 2278a2d5bd..528441ce6a 100644
--- a/tgui/packages/tgui/interfaces/MobInteraction.tsx
+++ b/tgui/packages/tgui/interfaces/MobInteraction.tsx
@@ -74,6 +74,17 @@ type ContentPrefsInfo = {
no_auto_wag: boolean,
}
+const INTERACTION_NORMAL = 0;
+const INTERACTION_LEWD = 1;
+const INTERACTION_EXTREME = 2;
+
+const INTERACTION_FLAG_OOC_CONSENT = (1<<0);
+const INTERACTION_FLAG_ADJACENT = (1<<1);
+const INTERACTION_FLAG_USER_IS_TARGET = (1<<2);
+const INTERACTION_FLAG_USER_NOT_TIRED = (1<<3);
+const INTERACTION_FLAG_TARGET_NOT_TIRED = (1<<4);
+const INTERACTION_FLAG_EXTREME_CONTENT = (1<<5);
+
export const MobInteraction = (props, context) => {
const { act, data } = useBackend(context);
const {
@@ -129,15 +140,15 @@ export const MobInteraction = (props, context) => {
-
- {(!isTargetSelf && !isNaN(theirLust)) ? (
+ {(!isTargetSelf && (theirLust !== null) ? (
- ) : (null)}
+ ) : (null))}
@@ -191,7 +202,11 @@ const InteractionsTab = (props, context) => {
searchText,
setSearchText,
] = useLocalState(context, 'searchText', '');
- const interactions = sortInteractions(data.interactions, searchText) || [];
+ const interactions = sortInteractions(
+ data.interactions,
+ searchText,
+ data)
+ || [];
return (
@@ -202,7 +217,9 @@ const InteractionsTab = (props, context) => {