diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm
index fc62eea666f..1b1e0afac07 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/obj_flags.dm
@@ -45,8 +45,9 @@
#define SNUG_FIT (1<<9) //! prevents hat throwing from knocking this hat off
#define EFFECT_HAT (1<<10) //! For hats with an effect that shouldn't get knocked off ie finfoil
#define SCAN_REAGENTS (1<<11) //! Allows helmets and glasses to scan reagents.
-#define MASKEXTENDRANGE (1<<12) //! For masks, allows you to breathe from internals on adjecent tiles
-#define NOTCONSUMABLE (1<<13) //! Moths cannot eat clothing with that flag
+#define SCAN_BOOZEPOWER (1<<12) //! Allows helmets and glasses to scan reagents.
+#define MASKEXTENDRANGE (1<<13) //! For masks, allows you to breathe from internals on adjecent tiles
+#define NOTCONSUMABLE (1<<14) //! Moths cannot eat clothing with that flag
/// Flags for the organ_flags var on /obj/item/organ
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index c0aa63293c5..68f77e79efc 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -232,6 +232,19 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NONECRODISEASE "nonecrodisease"
#define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good....
#define TRAIT_ALWAYS_STUBS "always_stubs_toe" //you will always stub your toe on tables, even if you're wearing shoes
+<<<<<<< HEAD
+=======
+#define TRAIT_NAIVE "naive" //All dead people will appear as sleeping.
+#define TRAIT_DROPS_ITEMS_ON_DEATH "drops_items_on_death" //used for battle royale
+#define TRAIT_DRINKSBLOOD "drinks_blood"
+#define TRAIT_SOMMELIER "sommelier" // shows different booze power flavor texts
+#define TRAIT_BARMASTER "bar_master" // always can identify reagents
+
+// You can stare into the abyss, but it does not stare back.
+// You're immune to the hallucination effect of the supermatter, either
+// through force of will, or equipment.
+#define TRAIT_MADNESS_IMMUNE "supermatter_madness_immune"
+>>>>>>> cd0a8c0b5d... Beer goggles now can measure Booze power and expect tastes (#7320)
//non-mob traits
#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index da88c2d2179..c146dd970d7 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1593,3 +1593,77 @@ config_setting should be one of the following:
if(-INFINITY to 0, 11 to INFINITY)
CRASH("Can't turn invalid directions!")
return turn(input_dir, 180)
+
+/atom/proc/get_boozepower_text(booze_power, mob/living/L)
+ if(isnull(booze_power))
+ return
+
+ if(HAS_TRAIT(L, TRAIT_SOMMELIER)) // A trained sommelier will have different identifying flavour
+ // because of float values, you need to write like `0 to 10`, `10 to 20`
+ switch(booze_power)
+ if(-INFINITY to 1)
+ . = "For children"
+ if(300 to INFINITY)
+ . = pick("Shift wrecking hammering",
+ "Get new liver after consumption",
+ "Post-consumption support groups exist",
+ "Place in Molotov instead",
+ "To stumble and slur, the will of Bacchus")
+ if(100 to 100)
+ . = "For a real man"
+ // these values must be detected first.
+
+ if(100 to 300)
+ . = "Cheated the blessing"
+ if(90 to 100)
+ . = "Get to drunk tank"
+ if(80 to 90)
+ . = "Liver pickler"
+ if(70 to 80)
+ . = "Drunkard's Challenge"
+ if(60 to 70)
+ . = "Have Shotgun ready"
+ if(50 to 60)
+ . = "3 rounds till down"
+ if(40 to 50)
+ . = "Drunkard's fixers"
+ if(30 to 40)
+ . = "Stick arounds"
+ if(20 to 30)
+ . = "Flask fillers"
+ if(10 to 20)
+ . = "Tipsy stuff"
+ if(1 to 10)
+ . = "Lightweight's dream"
+ else
+ switch(booze_power)
+ if(-INFINITY to 1)
+ . = "Safe for work"
+ if(300 to INFINITY)
+ . = "Lethal"
+ if(100 to 300)
+ . = "Deadly"
+ if(90 to 100)
+ . = "Dangerous"
+ if(80 to 90)
+ . = "Extreme"
+ if(70 to 80)
+ . = "Challenging"
+ if(60 to 70)
+ . = "Stronger"
+ if(50 to 60)
+ . = "Strong"
+ if(40 to 50)
+ . = "Average"
+ if(30 to 40)
+ . = "Less than average"
+ if(20 to 30)
+ . = "Light"
+ if(10 to 20)
+ . = "Mild"
+ if(1 to 10)
+ . = "Delightfully mild"
+
+ if(!.)
+ . = "not measurable. Ask the space god for what's wrong with this drink."
+ CRASH("not valid booze power value is detected: [booze_power]")
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 64dfc941e4f..13bdf1c29f9 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -196,6 +196,7 @@ DEFINE_BITFIELD(clothing_flags, list(
"SNUG_FIT" = SNUG_FIT,
"EFFECT_HAT" = EFFECT_HAT,
"SCAN_REAGENTS" = SCAN_REAGENTS,
+ "SCAN_BOOZEPOWER" = SCAN_BOOZEPOWER,
))
DEFINE_BITFIELD(tesla_flags, list(
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 60f4626898c..2b1b1457c00 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -552,6 +552,7 @@
if(reagents.flags & TRANSPARENT)
. += "It contains:"
if(length(reagents.reagent_list))
+ //-------- Reagent checks ---------
if(user.can_see_reagents()) //Show each individual reagent
for(var/datum/reagent/R in reagents.reagent_list)
. += "[R.volume] units of [R.name]"
@@ -560,6 +561,25 @@
for(var/datum/reagent/R in reagents.reagent_list)
total_volume += R.volume
. += "[total_volume] units of various reagents"
+ //-------- Beer goggles ---------
+ if(user.can_see_boozepower())
+ var/total_boozepower = 0
+ var/list/taste_list = list()
+
+ // calculates the total booze power from all 'ethanol' reagents
+ for(var/datum/reagent/consumable/ethanol/B in reagents.reagent_list)
+ total_boozepower += B.volume * max(B.boozepwr, 0) // minus booze power is reversed to light drinkers, but is actually 0 to normal drinkers.
+
+ // gets taste results from all reagents
+ for(var/datum/reagent/R in reagents.reagent_list)
+ if(istype(R, /datum/reagent/consumable/ethanol/fruit_wine) && !(user.stat == DEAD) && !(HAS_TRAIT(src, TRAIT_BARMASTER)) ) // taste of fruit wine is mysterious, but can be known by ghosts/some special bar master trait holders
+ taste_list += "
- unexplored taste of the winery (from [R.name])"
+ else
+ taste_list += "
- [R.taste_description] (from [R.name])"
+ if(reagents.total_volume)
+ . += "Booze Power: total [total_boozepower], average [round(total_boozepower/reagents.total_volume, 0.1)] ([get_boozepower_text(total_boozepower/reagents.total_volume, user)])"
+ . += "It would taste like: [english_list(taste_list, comma_text="", and_text="")]."
+ //-------------------------------
else
. += "Nothing."
else if(reagents.flags & AMOUNT_VISIBLE)
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index 9a569fcadc7..ed5387747f4 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -411,6 +411,14 @@
glasses = /obj/item/clothing/glasses/sunglasses/advanced/reagent
id = /obj/item/card/id
+/datum/outfit/spacebartender/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+
+ if(visualsOnly)
+ return
+
+ ADD_TRAIT(H, TRAIT_SOMMELIER, ROUNDSTART_TRAIT)
+
/obj/effect/mob_spawn/human/beach
outfit = /datum/outfit/beachbum
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index 3d20806ad8d..df0eff3ee91 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -229,7 +229,7 @@
/obj/item/clothing/glasses/sunglasses/advanced/reagent
name = "beer goggles"
desc = "A pair of sunglasses outfitted with apparatus to scan reagents, as well as providing an innate understanding of liquid viscosity while in motion. Has enhanced shielding which blocks flashes."
- clothing_flags = SCAN_REAGENTS
+ clothing_flags = SCAN_REAGENTS | SCAN_BOOZEPOWER
/obj/item/clothing/glasses/sunglasses/advanced/reagent/equipped(mob/user, slot)
. = ..()
@@ -452,7 +452,7 @@
item_state = "godeye"
vision_flags = SEE_TURFS|SEE_MOBS|SEE_OBJS
darkness_view = 8
- clothing_flags = SCAN_REAGENTS
+ clothing_flags = SCAN_REAGENTS | SCAN_BOOZEPOWER
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
resistance_flags = LAVA_PROOF | FIRE_PROOF
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index f6e5194aacc..ca0b41c7908 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -299,7 +299,7 @@
darkness_view = 8
flash_protect = 2
vision_correction = 1
- clothing_flags = SCAN_REAGENTS
+ clothing_flags = SCAN_REAGENTS | SCAN_BOOZEPOWER
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
hud_type = list(DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED, DATA_HUD_SECURITY_ADVANCED)
resistance_flags = INDESTRUCTIBLE
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
index ab7c686a6d1..786ad59ec95 100644
--- a/code/modules/jobs/job_types/bartender.dm
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -37,3 +37,11 @@
backpack_contents = list(/obj/item/storage/box/beanbag=1)
shoes = /obj/item/clothing/shoes/laceup
+
+/datum/outfit/job/bartender/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+
+ if(visualsOnly)
+ return
+
+ ADD_TRAIT(H, TRAIT_SOMMELIER, ROUNDSTART_TRAIT)
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 5cd6a7a5798..cced9877502 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -191,3 +191,14 @@
return TRUE
if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
return TRUE
+
+/mob/living/carbon/human/can_see_boozepower()
+ . = ..()
+ if(.)
+ return
+ if(isclothing(glasses) && (glasses.clothing_flags & SCAN_BOOZEPOWER))
+ return TRUE
+ if(isclothing(head) && (head.clothing_flags & SCAN_BOOZEPOWER))
+ return TRUE
+ if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_BOOZEPOWER))
+ return TRUE
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 9565a685acb..d927b007309 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -613,4 +613,19 @@
//Can the mob see reagents inside of containers?
/mob/proc/can_see_reagents()
- return stat == DEAD || has_unlimited_silicon_privilege //Dead guys and silicons can always see reagents
+ . = FALSE
+ if(stat == DEAD) // Dead guys and silicons can always see reagents
+ return TRUE
+ else if(has_unlimited_silicon_privilege)
+ return TRUE
+ else if(HAS_TRAIT(src, TRAIT_BARMASTER)) // If they're a bar master, they know what reagents are at a glance
+ return TRUE
+
+/mob/proc/can_see_boozepower() // same rule above
+ . = FALSE
+ if(stat == DEAD)
+ return TRUE
+ else if(has_unlimited_silicon_privilege)
+ return TRUE
+ else if(HAS_TRAIT(src, TRAIT_BARMASTER))
+ return TRUE
diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm
index 09b27bb782b..51b3f83e93f 100644
--- a/code/modules/shuttle/special.dm
+++ b/code/modules/shuttle/special.dm
@@ -149,6 +149,9 @@
/mob/living/simple_animal/drone/snowflake/bardrone/Initialize()
. = ..()
access_card.access |= ACCESS_CENT_BAR
+ ADD_TRAIT(src, TRAIT_BARMASTER, ROUNDSTART_TRAIT)
+ ADD_TRAIT(src, TRAIT_SOMMELIER, ROUNDSTART_TRAIT)
+
/mob/living/simple_animal/hostile/alien/maid/barmaid
gold_core_spawnable = NO_SPAWN
@@ -168,6 +171,8 @@
access_card.access = C.get_access()
access_card.access |= ACCESS_CENT_BAR
ADD_TRAIT(access_card, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
+ ADD_TRAIT(src, TRAIT_BARMASTER, ROUNDSTART_TRAIT)
+ ADD_TRAIT(src, TRAIT_SOMMELIER, ROUNDSTART_TRAIT)
/mob/living/simple_animal/hostile/alien/maid/barmaid/Destroy()
qdel(access_card)