diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/venom_milker.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/venom_milker.dm index 9624d9f11b3..fbd063c779c 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/venom_milker.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/venom_milker.dm @@ -14,7 +14,7 @@ /obj/item/reagent_containers/venom_milker/Initialize(mapload) . = ..() - var/filter_immune_string = /datum/preference/choiced/venomous_bite_venom::filter_immune_string + var/filter_immune_string = /datum/preference/choiced/aphrodisiacal_bite_venom::filter_immune_string if (length(filter_immune_string)) desc += span_notice("\nThe following reagents cannot be filtered by the neutralizer: [filter_immune_string]") @@ -52,7 +52,7 @@ * * silent = FALSE: If TRUE, will not give user any feedback. */ /obj/item/reagent_containers/venom_milker/proc/can_milk(mob/living/target, mob/living/user, silent = FALSE) - var/datum/action/cooldown/mob_cooldown/venomous_bite/bite = locate() in target.actions + var/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/bite = locate() in target.actions if (isnull(bite)) if (!silent) user?.balloon_alert(user, "no fangs!") @@ -87,7 +87,7 @@ /obj/item/reagent_containers/venom_milker/proc/siphon(mob/living/target, mob/living/user) if (!can_milk(target, user)) return FALSE - var/datum/action/cooldown/mob_cooldown/venomous_bite/bite = locate(/datum/action/cooldown/mob_cooldown/venomous_bite) in target.actions + var/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/bite = locate() in target.actions if (isnull(bite)) return FALSE @@ -106,7 +106,7 @@ return TRUE /** - * If a reagent milked from someone with the venom quirk is NOT in /datum/preference/choiced/venomous_bite_venom::milkable_venoms, it will be transformed into this + * If a reagent milked from someone with the venom quirk is NOT in /datum/preference/choiced/aphrodisiacal_bite_venom::milkable_venoms, it will be transformed into this * generic chem that has no effects. */ /datum/reagent/generic_milked_venom diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/aphrodisiacal_bite/aphrodisiacal_bite.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/aphrodisiacal_bite/aphrodisiacal_bite.dm new file mode 100644 index 00000000000..34c710f432a --- /dev/null +++ b/modular_zubbers/code/datums/quirks/neutral_quirks/aphrodisiacal_bite/aphrodisiacal_bite.dm @@ -0,0 +1,106 @@ +/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite + name = "Inject Aphrodisiac" + desc = "Sink your fangs into another and inject them with your aphrodisiac." + + button_icon = 'modular_zubbers/icons/mob/actions/quirks/aphrodisiacal_bite.dmi' + button_icon_state = "aphrodisiac" + + ranged_mousepointer = 'icons/effects/mouse_pointers/supplypod_pickturf.dmi' + + check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED // can use it if cuffed, enjoy + + shared_cooldown = NONE + + /// The reagent we will inject. + var/datum/reagent/reagent_typepath + /// How much of [reagent_typepath] we will inject. + var/to_inject = 0 + +/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/New(Target, original, datum/reagent/our_reagent, quantity_override = null) + . = ..() + set_reagent(our_reagent, quantity_override) + +/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/proc/set_reagent(datum/reagent/new_reagent, quantity_override = null, cooldown_override = null) + reagent_typepath = new_reagent + var/list/reagent_spec = /datum/preference/choiced/aphrodisiacal_bite_venom::aphrodisiacal_bite_choice_specs[new_reagent] + to_inject = quantity_override || reagent_spec[1] + cooldown_time = cooldown_override || reagent_spec[2] + +/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/set_click_ability(mob/on_who) + . = ..() + if (!.) + return + owner.visible_message(span_warning("[owner] bares [owner.p_their()] fangs..."), span_notice("You bare your fangs...")) + +/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/Activate(atom/target_atom) + if (!isliving(target_atom)) + return FALSE + + if (astype(owner, /mob/living/carbon)?.is_mouth_covered()) + owner.balloon_alert(owner, "mouth covered!") + return FALSE + + if (!owner.Adjacent(target_atom)) + owner.balloon_alert(owner, "too far!") + return FALSE + + if (target_atom == owner) + owner.balloon_alert(owner, "can't bite yourself!") + return FALSE + + if(!iscarbon(target_atom)) + owner.balloon_alert(owner, "not carbon!") + return FALSE + + if(!astype(target_atom, /mob/living/carbon).client?.prefs.read_preference(/datum/preference/toggle/erp/aphro)) + owner.balloon_alert(owner, "not interested!") + log_game("[key_name(owner)] tried to bite [key_name(astype(target_atom, /mob/living/carbon))] but [key_name(astype(target_atom, /mob/living/carbon))] had aphrodisiacs disabled") + return FALSE + + log_combat(owner, target_atom, "started to bite", null, "with venom: [reagent_typepath::name]") + owner.visible_message(span_warning("[owner] starts to bite [target_atom]!"), span_warning("You start to bite [target_atom]!"), ignored_mobs = target_atom) + to_chat(target_atom, span_userdanger("[owner] starts to bite you!")) + owner.balloon_alert_to_viewers("biting...") + if (!do_after(owner, 0.5 SECONDS, target_atom, IGNORE_HELD_ITEM)) + return FALSE + + . = ..() + + if (try_bite(target_atom)) + inject(target_atom) + return TRUE + +/// Does NOT inject reagents; represents the initial bite. +/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/proc/try_bite(mob/living/target) + PRIVATE_PROC(TRUE) + var/target_zone = check_zone(owner.zone_selected) + + var/text = "[owner] sinks [owner.p_their()] teeth into [target]'s [target.parse_zone_with_bodypart(target_zone)]!" + var/self_message = "You sink your teeth into [target]'s [target.parse_zone_with_bodypart(target_zone)]!" + var/victim_message = "[owner] sinks [owner.p_their()] teeth into your [target.parse_zone_with_bodypart(target_zone)]!" + + owner.visible_message(span_warning(text), span_warning(self_message), ignored_mobs = list(target)) + to_chat(target, span_userdanger(victim_message)) + + owner.do_attack_animation(target, ATTACK_EFFECT_BITE) + playsound(owner, 'sound/items/weapons/bite.ogg', 60, TRUE) + log_combat(owner, target, "successfully bit", null, "with venom: [reagent_typepath::name]") + return TRUE + +/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/proc/inject(mob/living/target) + if (!target.try_inject(owner, check_zone(owner.zone_selected))) + return FALSE + + add_reagents(target.reagents) + return TRUE + +/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/proc/add_reagents(datum/reagents/target, harvesting = FALSE) + var/temp = astype(owner, /mob/living/carbon/human)?.coretemperature + var/datum/reagent/local_typepath = reagent_typepath + if (harvesting) + var/list/spec = /datum/preference/choiced/aphrodisiacal_bite_venom::aphrodisiacal_bite_choice_specs[local_typepath] + if (!spec[3]) + local_typepath = /datum/reagent/generic_milked_venom + + target.add_reagent(local_typepath, to_inject, reagtemp = temp) + return TRUE diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/aphrodisiacal_bite/aphrodisiacal_bite_quirk.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/aphrodisiacal_bite/aphrodisiacal_bite_quirk.dm new file mode 100644 index 00000000000..ded2f3f1841 --- /dev/null +++ b/modular_zubbers/code/datums/quirks/neutral_quirks/aphrodisiacal_bite/aphrodisiacal_bite_quirk.dm @@ -0,0 +1,111 @@ +/datum/quirk/aphrodisiacal_bite + name = "Aphrodisiacal Bite" + desc = "You have a aphrodisiacal gland, and can bite people to inject them with an aphrodisiac of your choosing." + icon = FA_ICON_ICICLES + value = 0 + gain_text = span_notice("You feel a aphrodisiacal gland in the back of your throat.") + lose_text = span_warning("Your aphrodisiacal gland vanishes.") + medical_record_text = "Patient possesses an aphrodisiacal gland." + +/datum/quirk/aphrodisiacal_bite/add(client/client_source) + var/datum/reagent/reagent = text2path(client_source?.prefs?.read_preference(/datum/preference/choiced/aphrodisiacal_bite_venom)) + + var/mob/living/carbon/human/human_holder = quirk_holder + var/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/action = new /datum/action/cooldown/mob_cooldown/aphrodisiacal_bite(human_holder, our_reagent = reagent) + action.Grant(human_holder) + +/datum/quirk/aphrodisiacal_bite/remove() + if(QDELETED(quirk_holder)) + return ..() + var/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite/action = locate(/datum/action/cooldown/mob_cooldown/aphrodisiacal_bite) in quirk_holder.actions + action.Remove() + + return ..() + +/datum/quirk_constant_data/aphrodisiacal_bite + associated_typepath = /datum/quirk/aphrodisiacal_bite + customization_options = list(/datum/preference/choiced/aphrodisiacal_bite_venom) + +/datum/preference/choiced/aphrodisiacal_bite_venom + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "aphrodisiacal_bite_venom" + savefile_identifier = PREFERENCE_CHARACTER + /// Format: (reagent typepath -> list(amount to inject per bite, cooldown, can be milked (venom_milker.dm))) + var/static/list/aphrodisiacal_bite_choice_specs = list( + /datum/reagent/drug/aphrodisiac/crocin = list(5, 2 SECONDS, TRUE), + /datum/reagent/drug/aphrodisiac/crocin/hexacrocin = list(5, 5 SECONDS, TRUE), + /datum/reagent/drug/aphrodisiac/succubus_milk = list(5, 2 SECONDS, TRUE), + /datum/reagent/drug/aphrodisiac/incubus_draft = list(5, 2 SECONDS, TRUE), +) + var/static/list/milkable_venoms = generate_milkable_venom_list() + var/static/filter_immune_string = generate_filter_immune_string() + +/** + * Generates a static list of /datum/reagent that will not be transformed into [/datum/reagent/generic_milked_venom] upon being milked by a venom milker. + * + * Ran once, then never again. + */ +/proc/generate_milkable_venom_list() + RETURN_TYPE(/list) + + var/list/milkable = list() + + for (var/datum/reagent/typepath as anything in /datum/preference/choiced/aphrodisiacal_bite_venom::aphrodisiacal_bite_choice_specs) + var/list/spec = /datum/preference/choiced/aphrodisiacal_bite_venom::aphrodisiacal_bite_choice_specs[typepath] + + if (spec[3]) + milkable += typepath + + return milkable + +/** + * Generates a static string appended to the venom milker's description, detailing which reagents available to the venom quirk will not be transformed into [/datum/reagent/generic_milked_venom]. + * + * Ran once, then never again. + */ +/proc/generate_filter_immune_string() + var/filter_immune_string = "" + for (var/datum/reagent/typepath as anything in /datum/preference/choiced/aphrodisiacal_bite_venom::milkable_venoms) + if (length(filter_immune_string)) + filter_immune_string += ", " + filter_immune_string += typepath::name + return filter_immune_string + +/datum/preference/choiced/aphrodisiacal_bite_venom/init_possible_values() + var/list/choices = list() + for (var/entry in aphrodisiacal_bite_choice_specs) + choices += "[entry]" + + return choices + +/datum/preference/choiced/aphrodisiacal_bite_venom/create_default_value() + return "/datum/reagent/drug/aphrodisiac/crocin" + +/datum/preference/choiced/aphrodisiacal_bite_venom/compile_constant_data() + var/list/data = ..() + + var/list/titles = list() + + for (var/datum/reagent/entry as anything in aphrodisiacal_bite_choice_specs) + var/list/specs = aphrodisiacal_bite_choice_specs[entry] + + var/inject = specs[1] + var/cooldown = specs[2] + + var/name = entry::name + + titles["[entry]"] = "[name] ([inject]u, [cooldown / 10] second cooldown)" + + data[CHOICED_PREFERENCE_DISPLAY_NAMES] = titles + + return data + +/datum/preference/choiced/aphrodisiacal_bite_venom/is_accessible(datum/preferences/preferences) + . = ..() + if (!.) + return FALSE + + return "Aphrodisiacal Bite" in preferences.all_quirks + +/datum/preference/choiced/aphrodisiacal_bite_venom/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm b/modular_zubbers/code/datums/quirks/positive_quirks/venomous_bite/venomous_bite.dm similarity index 95% rename from modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm rename to modular_zubbers/code/datums/quirks/positive_quirks/venomous_bite/venomous_bite.dm index c5b38ca6749..a700816dc29 100644 --- a/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm +++ b/modular_zubbers/code/datums/quirks/positive_quirks/venomous_bite/venomous_bite.dm @@ -116,13 +116,9 @@ add_reagents(target.reagents) return TRUE -/datum/action/cooldown/mob_cooldown/venomous_bite/proc/add_reagents(datum/reagents/target, harvesting = FALSE) +/datum/action/cooldown/mob_cooldown/venomous_bite/proc/add_reagents(datum/reagents/target) var/temp = astype(owner, /mob/living/carbon/human)?.coretemperature var/datum/reagent/local_typepath = reagent_typepath - if (harvesting) - var/list/spec = /datum/preference/choiced/venomous_bite_venom::venomous_bite_choice_specs[local_typepath] - if (!spec[3]) - local_typepath = /datum/reagent/generic_milked_venom target.add_reagent(local_typepath, to_inject, reagtemp = temp) return TRUE diff --git a/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm b/modular_zubbers/code/datums/quirks/positive_quirks/venomous_bite/venomous_bite_quirk.dm similarity index 56% rename from modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm rename to modular_zubbers/code/datums/quirks/positive_quirks/venomous_bite/venomous_bite_quirk.dm index 55e3995df41..b6de10c8d71 100644 --- a/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm +++ b/modular_zubbers/code/datums/quirks/positive_quirks/venomous_bite/venomous_bite_quirk.dm @@ -30,53 +30,15 @@ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED savefile_key = "venomous_bite_venom" savefile_identifier = PREFERENCE_CHARACTER - /// Format: (reagent typepath -> list(amount to inject per bite, cooldown, can be milked (venom_milker.dm))) + /// Format: (reagent typepath -> list(amount to inject per bite, cooldown)) var/static/list/venomous_bite_choice_specs = list( - /datum/reagent/toxin = list(5, 80 SECONDS, FALSE), - /datum/reagent/toxin/venom = list(5, 180 SECONDS, FALSE), - /datum/reagent/toxin/carpotoxin = list(5, 60 SECONDS, FALSE), // less powerful than toxin + /datum/reagent/toxin = list(5, 80 SECONDS), + /datum/reagent/toxin/venom = list(5, 180 SECONDS), + /datum/reagent/toxin/carpotoxin = list(5, 60 SECONDS), // less powerful than toxin // drugs - /datum/reagent/drug/space_drugs = list(5, 60 SECONDS, TRUE), - /datum/reagent/toxin/mindbreaker = list(5, 60 SECONDS, FALSE), - // erp stuff - /datum/reagent/drug/aphrodisiac/crocin = list(5, 2 SECONDS, TRUE), - /datum/reagent/drug/aphrodisiac/crocin/hexacrocin = list(5, 5 SECONDS, TRUE), - /datum/reagent/drug/aphrodisiac/succubus_milk = list(5, 2 SECONDS, TRUE), - /datum/reagent/drug/aphrodisiac/incubus_draft = list(5, 2 SECONDS, TRUE), + /datum/reagent/drug/space_drugs = list(5, 60 SECONDS), + /datum/reagent/toxin/mindbreaker = list(5, 60 SECONDS), ) - var/static/list/milkable_venoms = generate_milkable_venom_list() - var/static/filter_immune_string = generate_filter_immune_string() - -/** - * Generates a static list of /datum/reagent that will not be transformed into [/datum/reagent/generic_milked_venom] upon being milked by a venom milker. - * - * Ran once, then never again. - */ -/proc/generate_milkable_venom_list() - RETURN_TYPE(/list) - - var/list/milkable = list() - - for (var/datum/reagent/typepath as anything in /datum/preference/choiced/venomous_bite_venom::venomous_bite_choice_specs) - var/list/spec = /datum/preference/choiced/venomous_bite_venom::venomous_bite_choice_specs[typepath] - - if (spec[3]) - milkable += typepath - - return milkable - -/** - * Generates a static string appended to the venom milker's description, detailing which reagents available to the venom quirk will not be transformed into [/datum/reagent/generic_milked_venom]. - * - * Ran once, then never again. - */ -/proc/generate_filter_immune_string() - var/filter_immune_string = "" - for (var/datum/reagent/typepath as anything in /datum/preference/choiced/venomous_bite_venom::milkable_venoms) - if (length(filter_immune_string)) - filter_immune_string += ", " - filter_immune_string += typepath::name - return filter_immune_string /datum/preference/choiced/venomous_bite_venom/init_possible_values() var/list/choices = list() diff --git a/modular_zubbers/icons/mob/actions/quirks/aphrodisiacal_bite.dmi b/modular_zubbers/icons/mob/actions/quirks/aphrodisiacal_bite.dmi new file mode 100644 index 00000000000..2a446e1e5fe Binary files /dev/null and b/modular_zubbers/icons/mob/actions/quirks/aphrodisiacal_bite.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 62fb5625a4a..9fc1564ad5f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -8943,6 +8943,8 @@ #include "modular_zubbers\code\datums\quirks\neutral_quirks\seamless_clothes.dm" #include "modular_zubbers\code\datums\quirks\neutral_quirks\unblinking.dm" #include "modular_zubbers\code\datums\quirks\neutral_quirks\waddle.dm" +#include "modular_zubbers\code\datums\quirks\neutral_quirks\aphrodisiacal_bite\aphrodisiacal_bite.dm" +#include "modular_zubbers\code\datums\quirks\neutral_quirks\aphrodisiacal_bite\aphrodisiacal_bite_quirk.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\apathetic_override.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\bilingual_override.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\chip_connector_override.dm" @@ -8960,8 +8962,8 @@ #include "modular_zubbers\code\datums\quirks\positive_quirks\spacer_override.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\strong_stomach_override.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\tagger_override.dm" -#include "modular_zubbers\code\datums\quirks\positive_quirks\venemous_bite\venomous_bite.dm" -#include "modular_zubbers\code\datums\quirks\positive_quirks\venemous_bite\venomous_bite_quirk.dm" +#include "modular_zubbers\code\datums\quirks\positive_quirks\venomous_bite\venomous_bite.dm" +#include "modular_zubbers\code\datums\quirks\positive_quirks\venomous_bite\venomous_bite_quirk.dm" #include "modular_zubbers\code\datums\shuttle\arena.dm" #include "modular_zubbers\code\datums\shuttles\emergency.dm" #include "modular_zubbers\code\datums\station_traits\disabled_traits.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/aphrodisiacal_bite.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/aphrodisiacal_bite.tsx new file mode 100644 index 00000000000..ee97563b8e1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/aphrodisiacal_bite.tsx @@ -0,0 +1,7 @@ +import type { FeatureChoiced } from '../../base'; +import { FeatureDropdownInput } from '../../dropdowns'; + +export const aphrodisiacal_bite_venom: FeatureChoiced = { + name: 'Aphrodisiac Type', + component: FeatureDropdownInput, +};