diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index aa4e2cf9d06..e3c4bdd8f77 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1041,6 +1041,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_SETTLER "settler" #define TRAIT_STRONG_STOMACH "strong_stomach" #define TRAIT_VEGETARIAN "trait_vegetarian" +#define TRAIT_KEEN_NOSE "keen_nose" /// This mob always lands on their feet when they fall, for better or for worse. #define TRAIT_CATLIKE_GRACE "catlike_grace" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 813d7d13e9e..92010822738 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -365,6 +365,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_IN_CALL" = TRAIT_IN_CALL, "TRAIT_IS_WET" = TRAIT_IS_WET, "TRAIT_IWASBATONED" = TRAIT_IWASBATONED, + "TRAIT_KEEN_NOSE" = TRAIT_KEEN_NOSE, "TRAIT_KISS_OF_DEATH" = TRAIT_KISS_OF_DEATH, "TRAIT_SEE_BLESSED_TILES" = TRAIT_SEE_BLESSED_TILES, "TRAIT_SYNDIE_KISS" = TRAIT_SYNDIE_KISS, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 0b1e2f2ba84..3e9622b79d0 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -160,6 +160,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_INTROVERT" = TRAIT_INTROVERT, "TRAIT_INVISIBLE_MAN" = TRAIT_INVISIBLE_MAN, "TRAIT_IWASBATONED" = TRAIT_IWASBATONED, + "TRAIT_KEEN_NOSE" = TRAIT_KEEN_NOSE, "TRAIT_KISS_OF_DEATH" = TRAIT_KISS_OF_DEATH, "TRAIT_KNOCKEDOUT" = TRAIT_KNOCKEDOUT, "TRAIT_KNOW_ENGI_WIRES" = TRAIT_KNOW_ENGI_WIRES, diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index 5c4239962b2..9bc33a49573 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -26,6 +26,7 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list( list(/datum/quirk/settler, /datum/quirk/freerunning), list(/datum/quirk/numb, /datum/quirk/selfaware), list(/datum/quirk/empath, /datum/quirk/evil), + list(/datum/quirk/keen_nose, /datum/quirk/item_quirk/anosmia), )) GLOBAL_LIST_INIT(quirk_string_blacklist, generate_quirk_string_blacklist()) diff --git a/code/datums/quirks/positive_quirks/keen_nose.dm b/code/datums/quirks/positive_quirks/keen_nose.dm new file mode 100644 index 00000000000..2681d34b86d --- /dev/null +++ b/code/datums/quirks/positive_quirks/keen_nose.dm @@ -0,0 +1,9 @@ +/datum/quirk/keen_nose + name = "Keen Nose" + desc = "You have a very sensitive nose. You can smell the contents of any open containers you are holding simply by examining them." + icon = FA_ICON_FLASK + value = 3 + mob_trait = TRAIT_KEEN_NOSE + gain_text = span_notice("You can smell everything around you much more clearly.") + lose_text = span_danger("Your sense of smell returns to normal.") + medical_record_text = "Patient has an unusually sensitive olfactory system." diff --git a/code/game/atom/atom_examine.dm b/code/game/atom/atom_examine.dm index 02e66ab749e..d2dc54d5d50 100644 --- a/code/game/atom/atom_examine.dm +++ b/code/game/atom/atom_examine.dm @@ -44,7 +44,6 @@ if(reagents.is_reacting) . += span_warning("It is currently reacting!") . += span_notice("The solution's pH is [round(reagents.ph, 0.01)] and has a temperature of [reagents.chem_temp]K.") - else . += "It contains:
Nothing." else if(reagents.flags & AMOUNT_VISIBLE) @@ -53,8 +52,29 @@ else . += span_danger("It's empty.") + if(HAS_TRAIT(user, TRAIT_KEEN_NOSE)) + var/sniff_text = get_sniff_examine(user) + if(sniff_text) + . += sniff_text + SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE, user, .) +/// Returns an examine string describing what the contents of this atom smell like +/atom/proc/get_sniff_examine(mob/living/carbon/sniffer) + if(!istype(sniffer) || HAS_TRAIT(sniffer, TRAIT_ANOSMIA)) + return + if(!is_open_container() || !reagents?.total_volume) + return + if(!sniffer.is_holding(src)) + return + if(!sniffer.get_bodypart(BODY_ZONE_HEAD)) // Need a nose to smell + return + if(sniffer.is_mouth_covered()) + return span_warning("You can't get a whiff of [src] with your face covered.") + + var/smell_message = generate_reagents_taste_message(reagents.reagent_list, sniffer, 10) + return span_notice("You catch a whiff of [src]. It smells like [smell_message].") + /** * A list of "tags" displayed after atom's description in examine. * This should return an assoc list of tags -> tooltips for them. If item is null, then no tooltip is assigned. diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 38be6d99f23..b10f040c8f0 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -473,6 +473,8 @@ victim.Knockdown(3 SECONDS) victim.add_movespeed_modifier(/datum/movespeed_modifier/reagent/pepperspray) addtimer(CALLBACK(victim, TYPE_PROC_REF(/mob, remove_movespeed_modifier), /datum/movespeed_modifier/reagent/pepperspray), 10 SECONDS) + ADD_TRAIT(victim, TRAIT_ANOSMIA, type) + addtimer(TRAIT_CALLBACK_REMOVE(victim, TRAIT_ANOSMIA, type), 30 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE) victim.update_damage_hud() if(methods & INGEST) if(!holder.has_reagent(/datum/reagent/consumable/milk)) diff --git a/code/modules/reagents/chemistry/taste.dm b/code/modules/reagents/chemistry/taste.dm index 06cee0bba2d..d81a0ef1851 100644 --- a/code/modules/reagents/chemistry/taste.dm +++ b/code/modules/reagents/chemistry/taste.dm @@ -1,41 +1,45 @@ #define TEXT_NO_TASTE "something indescribable" -//================================TASTE=================================================== +//=============================== TASTE GRAPH ==================================== +// // +// Flavor Intensity Thresholds (Relative to Detection Threshold % 'DT'): // +// 0% 1x DT 2x DT 4x DT 100% // +// |----------------|------------------|------------------|-----------------| // +// | Undetected | Weak | Mild | Strong | // +// |----------------|------------------|------------------|-----------------| // +// // +//==============================================================================// + /** - * Returns what this reagents in our given list taste like + * Returns what the reagents in our given list taste like * * Arguments: * * list/reagent_list - List of reagents to taste. * * mob/living/taster - Who is doing the tasting. Some mobs can pick up specific flavours. - * * minimum_percent - The lower the minimum percent, the more sensitive the message is. - * * weight_modifier - Value to multiply each reagent's taste weight with. + * * detection_threshold_percent - The minimum relative percentage a flavor must reach to be tasted. */ -/proc/generate_reagents_taste_message(list/reagent_list, mob/living/taster, minimum_percent) +/proc/generate_reagents_taste_message(list/reagent_list, mob/living/taster, detection_threshold_percent) // We can't taste anything - if(minimum_percent > 100) + if(detection_threshold_percent > 100) return TEXT_NO_TASTE - // Associative list of our tastes, descriptor - strength + // Associative list of our tastes - list("taste description" = strength) var/list/tastes = list() - // Total of our taste strengths so far - var/total_taste = 0 + var/total_taste_strength = 0 for(var/datum/reagent/reagent as anything in reagent_list) if(!reagent.taste_mult) continue var/list/taste_data = reagent.get_taste_description(taster) - for(var/taste in taste_data) - var/taste_strength = taste_data[taste] * reagent.volume * reagent.taste_mult - if(taste in tastes) - tastes[taste] += taste_strength - else - tastes[taste] = taste_strength - total_taste += taste_strength + for(var/taste_desc in taste_data) + var/taste_strength = taste_data[taste_desc] * reagent.volume * reagent.taste_mult + tastes[taste_desc] += taste_strength + total_taste_strength += taste_strength // None of our reagents had any flavour - if(total_taste <= 0) + if(total_taste_strength <= 0) return TEXT_NO_TASTE // If we have exactly one taste, don't bother with relative strengths @@ -46,32 +50,33 @@ sortTim(tastes, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE) // Lazylists for different taste strength categories, no need to initialize if we don't have such flavors - var/list/strong - var/list/mild - var/list/hint + var/list/strong_tastes + var/list/mild_tastes + var/list/weak_tastes for(var/taste_desc in tastes) - var/percent = tastes[taste_desc]/total_taste * 100 - if(percent < minimum_percent) - continue + var/relative_taste_percent = (tastes[taste_desc] / total_taste_strength) * 100 - if(percent <= minimum_percent * 2) - LAZYADD(hint, taste_desc) - else if(percent > minimum_percent * 4) - LAZYADD(strong, taste_desc) + // From weakest to strongest + if(relative_taste_percent < detection_threshold_percent) + continue // too weak to detect + else if(relative_taste_percent <= detection_threshold_percent * 2) + LAZYADD(weak_tastes, taste_desc) + else if(relative_taste_percent <= detection_threshold_percent * 4) + LAZYADD(mild_tastes, taste_desc) else - LAZYADD(mild, taste_desc) + LAZYADD(strong_tastes, taste_desc) - var/list/out = list() + var/list/taste_messages = list() - if(LAZYLEN(strong)) - out += "the strong flavor of [english_list(strong, TEXT_NO_TASTE)]" - if(LAZYLEN(mild)) + if(LAZYLEN(strong_tastes)) + taste_messages += "the strong flavor of [english_list(strong_tastes, TEXT_NO_TASTE)]" + if(LAZYLEN(mild_tastes)) // Prefix "some " if there are strong flavors to avoid seeming like a strong flavor - out += "[LAZYLEN(strong) ? "some " : ""][english_list(mild, TEXT_NO_TASTE)]" - if(LAZYLEN(hint)) - out += "a hint of [english_list(hint, TEXT_NO_TASTE)]" + taste_messages += "[LAZYLEN(strong_tastes) ? "some " : ""][english_list(mild_tastes, TEXT_NO_TASTE)]" + if(LAZYLEN(weak_tastes)) + taste_messages += "a hint of [english_list(weak_tastes, TEXT_NO_TASTE)]" - return english_list(out, TEXT_NO_TASTE) + return english_list(taste_messages, TEXT_NO_TASTE) #undef TEXT_NO_TASTE diff --git a/tgstation.dme b/tgstation.dme index 717fc41a448..8d6ff832949 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1981,6 +1981,7 @@ #include "code\datums\quirks\positive_quirks\freerunning.dm" #include "code\datums\quirks\positive_quirks\friendly.dm" #include "code\datums\quirks\positive_quirks\jolly.dm" +#include "code\datums\quirks\positive_quirks\keen_nose.dm" #include "code\datums\quirks\positive_quirks\light_step.dm" #include "code\datums\quirks\positive_quirks\mime_fan.dm" #include "code\datums\quirks\positive_quirks\musician.dm"