diff --git a/GainStation13/code/datums/mutations/fatfang.dm b/GainStation13/code/datums/mutations/fatfang.dm
index 16eba2b3..0303b090 100644
--- a/GainStation13/code/datums/mutations/fatfang.dm
+++ b/GainStation13/code/datums/mutations/fatfang.dm
@@ -8,6 +8,7 @@
power = /obj/effect/proc_holder/spell/targeted/touch/fatfang
instability = 10
energy_coeff = 1
+ power_coeff = 1
/obj/effect/proc_holder/spell/targeted/touch/fatfang
name = "The Nibble"
@@ -28,7 +29,8 @@
icon_state = "power_feed"
///How much weight is added?
var/chem_to_add = 5
- ///What verb is used for the spell?
+
+ var/starttime = 0
/obj/item/melee/touch_attack/fatfang/afterattack(atom/target, mob/living/carbon/user, proximity)
if(!proximity || !iscarbon(target) || target == user)
@@ -36,10 +38,18 @@
if(!target || !chem_to_add)
return FALSE
-
- target.reagents.add_reagent(/datum/reagent/consumable/lipoifier, chem_to_add)
-
target.visible_message("[user] nibbles [target]!","[user] nibbles you!")
+ if(target == user.pulling && ishuman(user.pulling))
+ starttime = world.time
+ user.dna.get_mutation(FATFANG).power.charge_max = 600 * GET_MUTATION_ENERGY(user.dna.get_mutation(FATFANG))
+ while(starttime + 300 > world.time && in_range(user, target))
+ if(do_mob(user, target, 10, 0, 1))
+ target.reagents.add_reagent(/datum/reagent/consumable/lipoifier, (chem_to_add * GET_MUTATION_POWER(user.dna.get_mutation(FATFANG))/2))
+ target.visible_message("[user] pumps some venom in [target]!","[user] pumps some venom in you!")
+ else
+ user.dna.get_mutation(FATFANG).power.charge_max = 50 * GET_MUTATION_ENERGY(user.dna.get_mutation(FATFANG))
+ target.reagents.add_reagent(/datum/reagent/consumable/lipoifier, chem_to_add * GET_MUTATION_POWER(user.dna.get_mutation(FATFANG)))
+
return ..()
/obj/item/dnainjector/antifang
diff --git a/GainStation13/code/mechanics/web_weaving.dm b/GainStation13/code/mechanics/web_weaving.dm
index e6c6904a..ef2b768c 100644
--- a/GainStation13/code/mechanics/web_weaving.dm
+++ b/GainStation13/code/mechanics/web_weaving.dm
@@ -5,15 +5,20 @@
gain_text = "You find yourself able to weave webs."
lose_text = "You are no longer able to weave webs."
category = CATEGORY_SEXUAL
+ mob_trait = TRAIT_WEB_WEAVER
///What action is linked with this quirk?
- var/datum/action/innate/wrap_target/linked_action
+ var/datum/action/innate/wrap_target/linked_action1
+ var/datum/action/innate/make_web/linked_action2
/datum/quirk/web_weaving/post_add()
- linked_action = new
- linked_action.Grant(quirk_holder)
+ linked_action1 = new
+ linked_action1.Grant(quirk_holder)
+ linked_action2 = new
+ linked_action2.Grant(quirk_holder)
/datum/quirk/web_weaving/remove()
- linked_action.Remove(quirk_holder)
+ linked_action1.Remove(quirk_holder)
+ linked_action2.Remove(quirk_holder)
return ..()
/datum/action/innate/wrap_target
@@ -83,3 +88,20 @@
/obj/structure/spider/cocoon/quirk
max_integrity = 20
+
+/datum/action/innate/make_web
+ name = "weave"
+ desc = "spins a sticky web."
+ icon_icon = 'icons/effects/effects.dmi'
+ button_icon_state = "stickyweb1"
+ background_icon_state = "bg_alien"
+
+/datum/action/innate/make_web/Activate()
+ var/turf/T = get_turf(owner)
+ owner.visible_message("[owner] begins spinning a web!", "You begin spinning a web.")
+ if(!do_after(owner, 10 SECONDS, 1, null, 1))
+ owner.visible_message("[owner] fails to spin a web!", "You fail to spin web.")
+ return FALSE
+ T.ChangeTurf(/obj/structure/spider/stickyweb)
+ owner.visible_message("[owner] spin a sticky web!", "You spin a sticky web.")
+ return TRUE
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 2b3f5934..1778d470 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -203,6 +203,7 @@
#define TRAIT_LIPOLICIDE_TOLERANCE "lipolicide_tolerance"
#define TRAIT_WEAKLEGS "weak_legs"
#define TRAIT_STRONGLEGS "strong_legs"
+#define TRAIT_WEB_WEAVER "web_weaving"
//Hyper
#define TRAIT_MACROPHILE "macrophile" //likes the big
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index b20cc07d..c94989ca 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -55,7 +55,7 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
GLOB.breasts_size_list = list ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
- GLOB.genital_fluids_list = list ("Milk", "Water", "Semen", "Femcum", "Honey", "Strawberry Milk")
+ GLOB.genital_fluids_list = list ("Milk", "Water", "Semen", "Femcum", "Honey", "Strawberry Milk", "Nutriment")
GLOB.gentlemans_organ_names = list("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ", "cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret", "baloney pony", "schlanger")
for(var/K in GLOB.breasts_shapes_list)
var/datum/sprite_accessory/breasts/value = GLOB.breasts_shapes_list[K]
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index d53e7250..737247ac 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -36,7 +36,7 @@
. = ..()
/obj/structure/spider/stickyweb/CanPass(atom/movable/mover, turf/target)
- if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider))
+ if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider) || HAS_TRAIT(mover, TRAIT_WEB_WEAVER))
return TRUE
else if(isliving(mover))
if(istype(mover.pulledby, /mob/living/simple_animal/hostile/poison/giant_spider))
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 8a06e02b..8702b594 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -893,6 +893,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Femcum"
if(/datum/reagent/consumable/alienhoney)
dat += "Honey"
+ if(/datum/reagent/consumable/nutriment)
+ dat += "Nutriment"
else
dat += "Nothing?"
//This else is a safeguard for errors, and if it happened, they wouldn't be able to change this pref,
@@ -940,6 +942,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Honey"
if(/datum/reagent/consumable/pinkmilk)
dat += "Strawberry Milk"
+ if(/datum/reagent/consumable/nutriment)
+ dat += "Nutriment"
else
dat += "Nothing?"
//This else is a safeguard for errors, and if it happened, they wouldn't be able to change this pref,
@@ -2381,6 +2385,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["balls_fluid"] = /datum/reagent/consumable/alienhoney
if("Strawberry Milk")
features["balls_fluid"] = /datum/reagent/consumable/pinkmilk
+ if("Nutriment")
+ features["balls_fluid"] = /datum/reagent/consumable/nutriment
if("egg_size")
var/new_size
@@ -2426,6 +2432,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["breasts_fluid"] = /datum/reagent/consumable/alienhoney
if("Strawberry Milk")
features["breasts_fluid"] = /datum/reagent/consumable/pinkmilk
+ if("Nutriment")
+ features["breasts_fluid"] = /datum/reagent/consumable/nutriment
if("breasts_color")
var/new_breasts_color = input(user, "Breast Color:", "Character Preference", "#"+features["breasts_color"]) as color|null
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index de4a4b68..3c506574 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -222,6 +222,7 @@
glass_desc = "White and nutritious goodness!"
pH = 6.5
hydration = 3
+ nutriment_factor = 15 * REAGENTS_METABOLISM
/datum/reagent/consumable/milk/on_mob_life(mob/living/carbon/M)
if(HAS_TRAIT(M, TRAIT_CALCIUM_HEALER))
diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm
index 6d0c0131..5f43568b 100644
--- a/hyperstation/code/modules/arousal/arousalhud.dm
+++ b/hyperstation/code/modules/arousal/arousalhud.dm
@@ -34,9 +34,19 @@
if(user.pulling)
dat += "Kiss [user.pulling]"
dat += "(Kiss a partner, or object.)
"
+ dat += "Feed [user.pulling]"
+ dat += "(Feed a partner.)
"
+ dat += "Feed from [user.pulling]"
+ dat += "(Feed a partner.)
"
else
dat += "Kiss"
dat += "(Requires a partner)
"
+ dat += "Feed others"
+ dat += "(Requires a partner)
"
+ dat += "Feed from others"
+ dat += "(Requires a partner)
"
+ dat += "Feed yourself"
+ dat += "(Feed yourself with your own genitals)
"
var/obj/item/organ/genital/belly/Belly = user.getorganslot("belly")
if(Belly)
@@ -202,6 +212,24 @@
to_chat(usr, "You cannot do this alone!")
return
+ if(href_list["feed"])
+ if(usr.pulling)
+ feed()
+ else
+ to_chat(usr, "You cannot do this alone!")
+ return
+
+ if(href_list["feedfrom"])
+ if(usr.pulling)
+ feedfrom()
+ else
+ to_chat(usr, "You cannot do this alone!")
+ return
+
+ if(href_list["feedyourself"])
+ feedyourself()
+ return
+
if(href_list["shrink_belly"])
var/obj/item/organ/genital/belly/E = usr.getorganslot("belly")
if(E.size > 0)
@@ -282,6 +310,30 @@ obj/screen/arousal/proc/kiss()
if (H)
H.kisstarget(H.pulling)
+obj/screen/arousal/proc/feed()
+ if(usr.restrained(TRUE))
+ to_chat(usr, "You can't do that while restrained!")
+ return
+ var/mob/living/carbon/human/H = usr
+ if (H)
+ H.genitalfeed(H.pulling)
+
+obj/screen/arousal/proc/feedfrom()
+ if(usr.restrained(TRUE))
+ to_chat(usr, "You can't do that while restrained!")
+ return
+ var/mob/living/carbon/human/H = usr
+ if (H)
+ H.genitalfeedfrom(H.pulling)
+
+obj/screen/arousal/proc/feedyourself()
+ if(usr.restrained(TRUE))
+ to_chat(usr, "You can't do that while restrained!")
+ return
+ var/mob/living/carbon/human/H = usr
+ if (H)
+ H.genitalfeedyourself()
+
/mob/living/carbon/human/proc/menuremovecondom()
@@ -517,3 +569,136 @@ obj/screen/arousal/proc/kiss()
if(cum_splatter_icon)
cut_overlay(cum_splatter_icon)
return TRUE
+
+/mob/living/carbon/human/proc/genitalfeed(mob/living/L, mb_time = 30)
+ if(isliving(L)) //is your target living? Living people can resist your advances if they want to via moving.
+ if(iscarbon(L))
+ var/obj/item/organ/genital/picked_organ
+ var/total_fluids = 0
+ var/datum/reagents/fluid_source = null
+ src << browse(null, "window=arousal")
+ picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids.
+ if(picked_organ)
+ //Good, got an organ, time to pick a container
+ if(picked_organ.name == "penis")//if the select organ is a penis
+ var/obj/item/organ/genital/penis/P = src.getorganslot("penis")
+ if(P.condom) //if the penis is condomed
+ to_chat(src, "You cannot feed someone when there is a condom over your [picked_organ.name].")
+ return
+ if(P.sounding) //if the penis is sounded
+ to_chat(src, "You cannot feed someone when there is a rod inside your [picked_organ.name].")
+ return
+ if(picked_organ.producing) //Can it produce its own fluids, such as breasts?
+ fluid_source = picked_organ.reagents
+ else
+ if(!picked_organ.linked_organ)
+ to_chat(src, "Your [picked_organ.name] is unable to produce it's own fluids, it's missing the organs for it.")
+ return
+ fluid_source = picked_organ.linked_organ.reagents
+ total_fluids = fluid_source.total_volume
+
+ src.visible_message("[src] starts to feed [L.name] with their [picked_organ.name].", \
+ "You feed [L.name] with your [picked_organ.name].")
+ if(do_after(src, mb_time, target = src) && in_range(src, L))
+ fluid_source.trans_to(L, total_fluids)
+ src.visible_message("[src] uses [p_their()] [picked_organ.name] to feed [L.name]!", \
+ "You used your [picked_organ.name] to feed [L.name] a total of [total_fluids]u's.")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
+ if(picked_organ.can_climax)
+ setArousalLoss(min_arousal)
+
+ else //They either lack organs that can climax, or they didn't pick one.
+ to_chat(src, "You cannot fill anything without choosing exposed genitals.")
+ return
+
+/mob/living/carbon/human/proc/genitalfeedfrom(mob/living/target, mb_time = 30)
+ var/mob/living/carbon/human/L = target
+ var/obj/item/organ/genital/picked_organ
+ var/total_fluids = 0
+ var/datum/reagents/fluid_source = null
+ src << browse(null, "window=arousal")
+
+ var/list/genitals_list = list()
+ var/list/worn_stuff = L.get_equipped_items()
+
+ for(var/obj/item/organ/genital/G in L.internal_organs)
+ if(G.can_climax) //filter out what you can't masturbate with
+ if(G.is_exposed(worn_stuff)) //Nude or through_clothing
+ if(!G.dontlist)
+ genitals_list += G
+ if(genitals_list.len)
+ picked_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list
+ else
+ return
+
+ if(picked_organ)
+ //Good, got an organ, time to pick a container
+ if(picked_organ.name == "penis")//if the select organ is a penis
+ var/obj/item/organ/genital/penis/P = L.getorganslot("penis")
+ if(P.condom) //if the penis is condomed
+ to_chat(src, "You cannot feed from [picked_organ.name] when there is a condom over it.")
+ return
+ if(P.sounding) //if the penis is sounded
+ to_chat(src, "You cannot feed from [picked_organ.name] when there is a rod inside it.")
+ return
+ if(picked_organ.producing) //Can it produce its own fluids, such as breasts?
+ fluid_source = picked_organ.reagents
+ else
+ if(!picked_organ.linked_organ)
+ to_chat(src, "The [picked_organ.name] is unable to produce it's own fluids, it's missing the organs for it.")
+ return
+ fluid_source = picked_organ.linked_organ.reagents
+ total_fluids = fluid_source.total_volume
+
+ src.visible_message("[src] starts to feed from [L.name]'s [picked_organ.name].", \
+ "You feed from [L.name]'s '[picked_organ.name].")
+ if(do_after(src, mb_time, target = src) && in_range(src, L))
+ fluid_source.trans_to(src, total_fluids)
+ src.visible_message("[src] feeds from [L.name]'s [picked_organ.name]!", \
+ "You used [L.name]'s [picked_organ.name] to feed with a total of [total_fluids]u's.")
+ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
+ if(picked_organ.can_climax)
+ L.setArousalLoss(min_arousal)
+
+ else //They either lack organs that can climax, or they didn't pick one.
+ to_chat(src, "You cannot fill anything without choosing exposed genitals.")
+ return
+
+/mob/living/carbon/human/proc/genitalfeedyourself(mb_time = 30)
+ var/obj/item/organ/genital/picked_organ
+ var/total_fluids = 0
+ var/datum/reagents/fluid_source = null
+ src << browse(null, "window=arousal")
+ picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids.
+ if(picked_organ)
+ //Good, got an organ, time to pick a container
+ if(picked_organ.name == "penis")//if the select organ is a penis
+ var/obj/item/organ/genital/penis/P = src.getorganslot("penis")
+ if(P.condom) //if the penis is condomed
+ to_chat(src, "You cannot feed yourself when there is a condom over your [picked_organ.name].")
+ return
+ if(P.sounding) //if the penis is sounded
+ to_chat(src, "You cannot feed yourself when there is a rod inside your [picked_organ.name].")
+ return
+ if(picked_organ.producing) //Can it produce its own fluids, such as breasts?
+ fluid_source = picked_organ.reagents
+ else
+ if(!picked_organ.linked_organ)
+ to_chat(src, "Your [picked_organ.name] is unable to produce it's own fluids, it's missing the organs for it.")
+ return
+ fluid_source = picked_organ.linked_organ.reagents
+ total_fluids = fluid_source.total_volume
+
+ src.visible_message("[src] starts to feed themselves with their [picked_organ.name].", \
+ "You feed yourself with your [picked_organ.name].")
+ if(do_after(src, mb_time))
+ fluid_source.trans_to(src, total_fluids)
+ src.visible_message("[src] uses [p_their()] [picked_organ.name] to feed themselves!", \
+ "You used your [picked_organ.name] to feed yourself a total of [total_fluids]u's.")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
+ if(picked_organ.can_climax)
+ setArousalLoss(min_arousal)
+
+ else //They either lack organs that can climax, or they didn't pick one.
+ to_chat(src, "You cannot fill anything without choosing exposed genitals.")
+ return