Keen Nose Quirk - The Smell of Discovery (#95697)

## About The Pull Request
This adds a new positive quirk called "**Keen Nose**" that costs 3
points.

It lets you examine any open container with reagents to smell them. It
generates the smell based on the taste description. Also added an effect
to pepper spray, where it causes you to lose your sense of smell
temporarily.

This quirk is blacklisted against the Anosmia quirk, which is the
opposite. (no sense of smell)

## Why It's Good For The Game
Since there is a serious lack of positive quirks, I figured this one
might be useful as a utility quirk. It's a niche thing that could come
in handy. Keep in mind, there are several ways to identify chemicals,
like using the bartender's beer goggles, the science goggles, a chem
machine, or just eyeballing the color. Also, many chems have overlapping
taste descriptions (several different things taste like "death") so it's
not foolproof.
This commit is contained in:
Tim
2026-04-13 13:03:26 -05:00
committed by GitHub
parent fb7e230315
commit d2e5e35d68
9 changed files with 78 additions and 37 deletions
@@ -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))
+41 -36
View File
@@ -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