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