diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm
index 97cea621dae..cc2d7069348 100644
--- a/code/__DEFINES/mob.dm
+++ b/code/__DEFINES/mob.dm
@@ -67,6 +67,12 @@
// Factor of how fast mob nutrition decreases
#define HUNGER_FACTOR 0.1
+// Taste sensitivity - the more the more reagents you'll taste
+#define TASTE_SENSITIVITY_NORMAL 1
+#define TASTE_SENSITIVITY_SHARP 3
+#define TASTE_SENSITIVITY_DULL 0.75
+#define TASTE_SENSITIVITY_NO_TASTE 0
+
// Reagent type flags, defines the types of mobs this reagent will affect
#define ORGANIC 1
#define SYNTHETIC 2
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 5911c04f563..193ac27e310 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1015,6 +1015,7 @@ so that different stomachs can handle things in different ways VB*/
if(toEat.consume_sound)
playsound(loc, toEat.consume_sound, rand(10,50), 1)
if(toEat.reagents.total_volume)
+ taste_reagents(toEat.reagents)
var/fraction = min(this_bite/toEat.reagents.total_volume, 1)
toEat.reagents.reaction(src, toEat.apply_type, fraction)
toEat.reagents.trans_to(src, this_bite*toEat.transfer_efficiency)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 1c012655cdc..735e897c1c1 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -2160,3 +2160,9 @@
update_icons()
..()
+
+mob/living/carbon/human/get_taste_sensitivity()
+ if(species)
+ return species.taste_sensitivity
+ else
+ return 1
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index d2d44757705..cc01bdf65d6 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -45,6 +45,7 @@
var/reagent_tag //Used for metabolizing reagents.
var/hunger_drain = HUNGER_FACTOR
var/digestion_ratio = 1 //How quickly the species digests/absorbs reagents.
+ var/taste_sensitivity = TASTE_SENSITIVITY_NORMAL //factor of how much of a reagent is needed for a human to taste it
var/siemens_coeff = 1 //base electrocution coefficient
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 525559e8e6c..4d145a19e7c 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -851,3 +851,39 @@
to_chat(src, "You don't have the dexterity to do this!")
return 0
return 1
+
+/mob/living/proc/get_taste_sensitivity()
+ return 1
+
+/mob/living/proc/taste_reagents(datum/reagents/tastes)
+ if(!get_taste_sensitivity())//this also works for IPCs and stuff that returns 0 here
+ return
+
+ var/do_not_taste_at_all = 1//so we don't spam with recent tastes
+
+ var/taste_sum = 0
+ var/list/taste_list = list()//associative list so we can stack stuff that tastes the same
+ var/list/final_taste_list = list()//final list of taste strings
+
+ for(var/datum/reagent/R in tastes.reagent_list)
+ taste_sum += R.volume * R.taste_strength
+ taste_list[R.taste_message] += R.volume * R.taste_strength
+
+ for(var/R in taste_list)
+ if(recent_tastes[R] && (world.time - recent_tastes[R] < 12 SECONDS))
+ continue
+
+ do_not_taste_at_all = 0//something was fresh enough to taste; could still be bland enough to be unrecognizable
+
+ if(taste_list[R] / taste_sum >= 0.15 / get_taste_sensitivity())//we return earlier if the proc returns a 0; won't break the universe
+ final_taste_list += R
+ recent_tastes[R] = world.time
+
+ if(do_not_taste_at_all)
+ return //no message spam
+
+ if(final_taste_list.len == 0)//too many reagents - none meet their thresholds
+ to_chat(src, "You you can't really make out what you're tasting...")
+ return
+
+ to_chat(src, "You can taste [english_list(final_taste_list)].")
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 397ce90af6c..52a0f2f74ad 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -59,3 +59,5 @@
var/tesla_ignore = FALSE
var/list/say_log = list() //a log of what we've said, plain text, no spans or junk, essentially just each individual "message"
+
+ var/list/recent_tastes = list()
diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm
index cdc214c3089..054be7442e6 100644
--- a/code/modules/reagents/chemistry/reagents.dm
+++ b/code/modules/reagents/chemistry/reagents.dm
@@ -29,6 +29,8 @@
var/drink_icon = null
var/drink_name = "Glass of ..what?"
var/drink_desc = "You can't really tell what this is."
+ var/taste_strength = 1 //how easy it is to taste - the more the easier
+ var/taste_message = "bitterness" //life's bitter by default. Cool points for using a span class for when you're tasting LIQUID FUCKING DEATH
/datum/reagent/Destroy()
. = ..()
@@ -148,4 +150,4 @@
if(prob(5))
to_chat(M, "You feel like you can't live without [name]!")
if(prob(5))
- to_chat(M, "You would DIE for some [name] right now!")
\ No newline at end of file
+ to_chat(M, "You would DIE for some [name] right now!")
diff --git a/code/modules/reagents/chemistry/reagents/admin.dm b/code/modules/reagents/chemistry/reagents/admin.dm
index b94998221ef..eadcb57cc91 100644
--- a/code/modules/reagents/chemistry/reagents/admin.dm
+++ b/code/modules/reagents/chemistry/reagents/admin.dm
@@ -7,6 +7,7 @@
process_flags = ORGANIC | SYNTHETIC //Adminbuse knows no bounds!
admin_only = 1
can_synth = 0
+ taste_message = "admin abuse"
/datum/reagent/medicine/adminordrazine/on_mob_life(mob/living/carbon/M)
M.setCloneLoss(0)
@@ -58,4 +59,5 @@
/datum/reagent/medicine/adminordrazine/nanites
name = "Nanites"
id = "nanites"
- description = "Nanomachines that aid in rapid cellular regeneration."
\ No newline at end of file
+ description = "Nanomachines that aid in rapid cellular regeneration."
+ taste_message = "nanomachines, son"