diff --git a/__DEFINES/setup.dm b/__DEFINES/setup.dm
index 4e8dc010cf2..d404cb5dd38 100644
--- a/__DEFINES/setup.dm
+++ b/__DEFINES/setup.dm
@@ -418,7 +418,8 @@ var/global/list/BODY_COVER_VALUE_LIST=list("[HEAD]" = COVER_PROTECTION_HEAD,"[EY
// MUTATIONS
///////////////////////////////////////
-
+#define M_CHECK_ALL 1
+#define M_CHECK_JOB 2
// Generic mutations:
#define M_TK 1
diff --git a/code/datums/body_archive.dm b/code/datums/body_archive.dm
index 25fd8038948..ef679119ada 100644
--- a/code/datums/body_archive.dm
+++ b/code/datums/body_archive.dm
@@ -157,7 +157,7 @@ var/list/body_archives = list()
H.dna.species = R.dna.species
if(H.dna.species != "Human")
H.set_species(H.dna.species, TRUE)
- H.check_mutations = TRUE
+ H.check_mutations = M_CHECK_ALL
H.updatehealth()
if (our_mind)
has_been_shade -= our_mind
diff --git a/code/datums/outfit/civilian.dm b/code/datums/outfit/civilian.dm
index a34f2b1d461..84a5352a36a 100644
--- a/code/datums/outfit/civilian.dm
+++ b/code/datums/outfit/civilian.dm
@@ -119,7 +119,7 @@
..()
H.put_in_hands(new /obj/item/weapon/storage/bag/plasticbag(H))
H.dna.SetSEState(SOBERBLOCK,1)
- genemutcheck(H, SOBERBLOCK)
+ H.check_mutations = M_CHECK_JOB
/datum/outfit/bartender/pre_equip_priority(var/mob/living/carbon/human/H, var/species)
items_to_collect[/obj/item/weapon/circuitboard/chem_dispenser/soda_dispenser] = SURVIVAL_BOX
@@ -581,7 +581,7 @@
/obj/item/weapon/palette = null,
)
)
-
+
pda_type = /obj/item/device/pda/librarian
pda_slot = slot_belt
diff --git a/code/datums/outfit/security.dm b/code/datums/outfit/security.dm
index d0f1b19d375..e332e2c46fc 100644
--- a/code/datums/outfit/security.dm
+++ b/code/datums/outfit/security.dm
@@ -269,8 +269,7 @@
H.dna.SetSEState(SOBERBLOCK,1)
if (H.mind.role_alt_title == "Gumshoe" || H.mind.role_alt_title == "Private Eye")
H.dna.SetSEState(NOIRBLOCK,1)
- genemutcheck(H, NOIRBLOCK)
- genemutcheck(H, SOBERBLOCK)
+ H.check_mutations = M_CHECK_JOB
/datum/outfit/detective/post_equip_priority(var/mob/living/carbon/human/H)
equip_accessory(H, /obj/item/clothing/accessory/holster/knife/boot/preloaded/tactical, /obj/item/clothing/shoes, 5)
diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm
index a5f5193d26f..00a6ec76e3c 100644
--- a/code/game/jobs/job/civilian.dm
+++ b/code/game/jobs/job/civilian.dm
@@ -10,6 +10,10 @@
access = list(access_hydroponics, access_bar, access_kitchen, access_morgue, access_weapons)
minimal_access = list(access_bar,access_weapons)
outfit_datum = /datum/outfit/bartender
+ additional_information = "You can juggle most bottles and empty glasses by picking them up while on GRAB intent, so long as you remain unusually sober."
+
+/datum/job/bartender/post_init(var/mob/living/carbon/human/H)
+ genemutcheck(H, SOBERBLOCK)
/datum/job/chef
title = "Chef"
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index bef26b1f6f1..7655ebd2461 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -61,6 +61,8 @@
var/outfit_datum = null
+ var/additional_information = ""
+
/datum/job/proc/is_disabled()
return FALSE
@@ -122,6 +124,9 @@
to_chat(M, "You are the [job_title].")
to_chat(M, "As the [job_title] you answer directly to [src.supervisors]. Special circumstances may change this.")
+ if (additional_information)
+ to_chat(M, "[additional_information]")
+
if(src.req_admin_notify)
to_chat(M, "You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.")
@@ -132,3 +137,6 @@
/datum/job/proc/get_wage()
return wage_payout
+
+/datum/job/proc/post_init(var/mob/living/carbon/human/H)
+ return
diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm
index 6087323faf4..8a62c705285 100644
--- a/code/game/jobs/job/security.dm
+++ b/code/game/jobs/job/security.dm
@@ -54,6 +54,11 @@
outfit_datum = /datum/outfit/detective
minimal_player_age = 7
+/datum/job/detective/post_init(var/mob/living/carbon/human/H)
+ genemutcheck(H, SOBERBLOCK)
+ if (H.mind.role_alt_title == "Gumshoe" || H.mind.role_alt_title == "Private Eye")
+ genemutcheck(H, NOIRBLOCK)
+
/datum/job/officer
title = "Security Officer"
faction = "Station"
diff --git a/code/game/objects/structures/dorfpod.dm b/code/game/objects/structures/dorfpod.dm
index 5aa1496e73a..d1ee1c9b4d0 100644
--- a/code/game/objects/structures/dorfpod.dm
+++ b/code/game/objects/structures/dorfpod.dm
@@ -153,7 +153,7 @@ var/obj/structure/dorfpod/center/dorfpod
H.adjustCloneLoss(rand(50,60))
H.adjustBrainLoss(rand(20,30))
- H.check_mutations = TRUE
+ H.check_mutations = M_CHECK_ALL
H.Paralyse(4)
H.stat = H.status_flags & BUDDHAMODE ? CONSCIOUS : UNCONSCIOUS
H.updatehealth()
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 6522349a6dd..64cae9e0817 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -145,11 +145,15 @@ var/global/list/organ_damage_overlays = list(
var/obj/location_as_object = loc
location_as_object.handle_internal_lifeform(src, 0)
last_processed = "Interacted with our container"
- if(check_mutations)
-// testing("Updating [src.real_name]'s mutations: "+english_list(mutations))
- domutcheck(src,null,MUTCHK_FORCED)
- update_mutations()
- check_mutations = 0
+ switch(check_mutations)
+ if (M_CHECK_ALL)
+ domutcheck(src,null,MUTCHK_FORCED)
+ update_mutations()
+ check_mutations = 0
+ if (M_CHECK_JOB)
+ var/datum/job/J = job_master.GetJob(job)
+ J.post_init(src)
+ check_mutations = 0
//Updates the number of stored chemicals for powers
//handle_changeling()
//Mutations and radiation
diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm
index 2b62778fc9c..df445bf8669 100644
--- a/code/modules/reagents/reagent_containers/food/drinks.dm
+++ b/code/modules/reagents/reagent_containers/food/drinks.dm
@@ -1,3 +1,7 @@
+#define FLIPPING_DURATION 7
+#define FLIPPING_ROTATION 360
+#define FLIPPING_INCREMENT FLIPPING_ROTATION / 8
+
////////////////////////////////////////////////////////////////////////////////
/// Drinks.
////////////////////////////////////////////////////////////////////////////////
@@ -28,6 +32,11 @@
var/flammin_color = null
var/base_icon_state = "glassbottle"
+ //bottle flipping
+ var/can_flip = FALSE
+ var/last_flipping = 0
+ var/atom/movable/overlay/flipping = null
+
/obj/item/weapon/reagent_containers/food/drinks/on_reagent_change()
if(gulp_size < 5)
gulp_size = 5
@@ -62,7 +71,7 @@
..()
cant_drop = 0
-/obj/item/weapon/reagent_containers/food/drinks/pickup(mob/user as mob)
+/obj/item/weapon/reagent_containers/food/drinks/pickup(var/mob/user)
..()
if(ishuman(user) && arcanetampered) // wizards turn it into SCP-198
var/mob/living/carbon/human/H = user
@@ -70,6 +79,86 @@
H.audible_scream()
H.adjustHalLoss(50)
H.vessel.trans_to(reagents,reagents.maximum_volume)
+ if (can_flip && (M_SOBER in user.mutations) && (user.a_intent == I_GRAB))
+ if (flipping && (M_CLUMSY in user.mutations) && prob(20))
+ to_chat(user, "Your clumsy fingers fail to catch back \the [src].")
+ user.drop_item(src, user.loc, 1)
+ throw_impact(user.loc,1,user)
+ else
+ bottleflip(user)
+
+/obj/item/weapon/reagent_containers/food/drinks/dropped(var/mob/user)
+ ..()
+ if(flipping)
+ QDEL_NULL(flipping)
+ last_flipping = world.time
+ item_state = initial(item_state)
+ playsound(loc,'sound/effects/slap2.ogg', 5, 1, -2)
+
+/obj/item/weapon/reagent_containers/food/drinks/proc/bottleflip(var/mob/user)
+ playsound(loc,'sound/effects/woosh.ogg', 10, 1, -2)
+ last_flipping = world.time
+ var/this_flipping = last_flipping
+ item_state = "invisible"
+ user.update_inv_hands()
+ if (flipping)
+ qdel(flipping)
+ var/pixOffX = 0
+ var/list/offsets = user.get_item_offset_by_index(user.active_hand)
+ var/pixOffY = offsets["y"]
+ var/fliplay = user.layer + 1
+ var/rotate = 1
+ var/anim_icon_state = initial(item_state)
+ if (!anim_icon_state)
+ anim_icon_state = initial(icon_state)
+ switch (user.get_direction_by_index(user.active_hand))
+ if ("right_hand")
+ switch(user.dir)
+ if (NORTH)
+ pixOffX = 3
+ fliplay = user.layer - 1
+ rotate = -1
+ if (SOUTH)
+ pixOffX = -4
+ if (WEST)
+ pixOffX = -7
+ if (EAST)
+ pixOffX = 2
+ rotate = -1
+ if ("left_hand")
+ switch(user.dir)
+ if (NORTH)
+ pixOffX = -4
+ fliplay = user.layer - 1
+ if (SOUTH)
+ pixOffX = 3
+ rotate = -1
+ if (WEST)
+ pixOffX = -2
+ if (EAST)
+ pixOffX = 7
+ rotate = -1
+ flipping = anim(target = user, a_icon = 'icons/obj/bottleflip.dmi', a_icon_state = anim_icon_state, sleeptime = FLIPPING_DURATION, offX = pixOffX, lay = fliplay, offY = pixOffY)
+ animate(flipping, pixel_y = pixOffY + 12, transform = turn(matrix(), rotate*FLIPPING_INCREMENT), time = FLIPPING_DURATION/8, easing = LINEAR_EASING)
+ animate(pixel_y = pixOffY + 18, transform = turn(matrix(), rotate*2*FLIPPING_INCREMENT), time = FLIPPING_DURATION/8, easing = LINEAR_EASING)
+ animate(pixel_y = pixOffY + 21, transform = turn(matrix(), rotate*3*FLIPPING_INCREMENT), time = FLIPPING_DURATION/8, easing = LINEAR_EASING)
+ animate(pixel_y = pixOffY + 24, transform = turn(matrix(), rotate*4*FLIPPING_INCREMENT), time = FLIPPING_DURATION/8, easing = LINEAR_EASING)
+ animate(pixel_y = pixOffY + 21, transform = turn(matrix(), rotate*5*FLIPPING_INCREMENT), time = FLIPPING_DURATION/8, easing = LINEAR_EASING)
+ animate(pixel_y = pixOffY + 18, transform = turn(matrix(), rotate*6*FLIPPING_INCREMENT), time = FLIPPING_DURATION/8, easing = LINEAR_EASING)
+ animate(pixel_y = pixOffY + 12, transform = turn(matrix(), rotate*7*FLIPPING_INCREMENT), time = FLIPPING_DURATION/8, easing = LINEAR_EASING)
+ animate(pixel_y = pixOffY + 0, transform = turn(matrix(), rotate*8*FLIPPING_INCREMENT), time = FLIPPING_DURATION/8, easing = LINEAR_EASING)
+ spawn (FLIPPING_DURATION)
+ if ((loc == user) && (this_flipping == last_flipping))//only the last flipping action will reset the bottle's vars
+ QDEL_NULL(flipping)
+ last_flipping = world.time
+ item_state = initial(item_state)
+ if ((M_CLUMSY in user.mutations) && prob(20))
+ to_chat(user, "Your clumsy fingers fail to catch back \the [src].")
+ user.drop_item(src, user.loc, 1)
+ throw_impact(user.loc,1,user)
+ else
+ user.update_inv_hands()
+ playsound(loc,'sound/effects/slap2.ogg', 10, 1, -2)
/obj/item/weapon/reagent_containers/food/drinks/attack(mob/living/M as mob, mob/user as mob, def_zone)
var/datum/reagents/R = src.reagents
@@ -281,10 +370,6 @@
flags = FPRINT | OPENCONTAINER
siemens_coefficient = 1
-/obj/item/weapon/reagent_containers/food/drinks/golden_cup/tournament_26_06_2011
- desc = "A golden cup. It will be presented to a winner of tournament 26 June, and name of the winner will be engraved on it."
-
-
///////////////////////////////////////////////Drinks
//Notes by Darem: Drinks are simply containers that start preloaded. Unlike condiments, the contents can be ingested directly
// rather then having to add it to something else first. They should only contain liquids. They have a default container size of 50.
@@ -296,6 +381,7 @@
icon = 'icons/obj/food_condiment.dmi'
icon_state = "milk"
vending_cat = "dairy products"
+ can_flip = TRUE
/obj/item/weapon/reagent_containers/food/drinks/milk/New()
..()
reagents.add_reagent(MILK, 50)
@@ -319,6 +405,7 @@
icon = 'icons/obj/food_condiment.dmi'
icon_state = "soymilk"
vending_cat = "dairy products"//it's not a dairy product but oh come on who cares
+ can_flip = TRUE
/obj/item/weapon/reagent_containers/food/drinks/soymilk/New()
..()
reagents.add_reagent(SOYMILK, 50)
@@ -673,6 +760,8 @@
vending_cat = "fermented"
molotov = -1 //can become a molotov
isGlass = 1
+ can_flip = TRUE
+
/obj/item/weapon/reagent_containers/food/drinks/beer/New()
..()
reagents.add_reagent(BEER, 30)
@@ -686,6 +775,8 @@
vending_cat = "fermented"
molotov = -1 //can become a molotov
isGlass = 1
+ can_flip = TRUE
+
/obj/item/weapon/reagent_containers/food/drinks/ale/New()
..()
reagents.add_reagent(ALE, 30)
@@ -1204,6 +1295,7 @@
amount_per_transfer_from_this = 10
volume = 100
flags = FPRINT | OPENCONTAINER | NOREACT | SILENTCONTAINER
+ can_flip = TRUE
var/shaking = FALSE
var/obj/item/weapon/reagent_containers/food/drinks/shaker/reaction/reaction = null
@@ -1222,6 +1314,11 @@
to_chat(user, "You won't shake an empty shaker now, will you?")
return
if (!shaking)
+ if(flipping)
+ QDEL_NULL(flipping)
+ last_flipping = world.time
+ item_state = initial(item_state)
+ playsound(loc,'sound/effects/slap2.ogg', 10, 1, -2)
shaking = TRUE
var/adjective = pick("furiously","passionately","with vigor","with determination","like a devil","with care and love","like there is no tomorrow")
user.visible_message("\The [user] shakes \the [src] [adjective]!","You shake \the [src] [adjective]!")
@@ -1314,6 +1411,7 @@
icon_state = "flask"
origin_tech = Tc_MATERIALS + "=1"
volume = 60
+ can_flip = TRUE
/obj/item/weapon/reagent_containers/food/drinks/flask/detflask
name = "\improper Detective's flask"
@@ -1463,6 +1561,7 @@
bottleheight = 31
melt_temperature = MELTPOINT_GLASS
w_type=RECYK_GLASS
+ can_flip = TRUE
//Keeping this here for now, I'll ask if I should keep it here.
/obj/item/weapon/broken_bottle
@@ -1911,6 +2010,7 @@
molotov = 1
isGlass = 1
icon_state = "vodkabottle" //not strictly necessary for the "abstract" molotov type that the molotov-making-process copies variables from, but is used for pre-spawned molotovs
+ can_flip = TRUE
/obj/item/weapon/reagent_containers/food/drinks/molotov/New()
..()
@@ -2038,3 +2138,7 @@
forceMove(over_location, glide_size_override = DELAY2GLIDESIZE(0.4 SECONDS))
return
return ..()
+
+#undef FLIPPING_DURATION
+#undef FLIPPING_ROTATION
+#undef FLIPPING_INCREMENT
diff --git a/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm b/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm
index 9bdaa842a45..3f629bed0af 100644
--- a/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm
+++ b/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm
@@ -17,8 +17,11 @@
var/current_path = null
var/counter = 1
+ can_flip = TRUE
+
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/on_reagent_change()
..()
+ can_flip = FALSE
overlays.Cut()
flammable = 0
if(!molotov)
@@ -68,6 +71,7 @@
item_state = "glass_empty"
name = "drinking glass"
desc = "Your standard drinking glass."
+ can_flip = TRUE
if(iscarbon(loc))
var/mob/living/carbon/M = loc
diff --git a/icons/mob/in-hand/left/drinkingglass.dmi b/icons/mob/in-hand/left/drinkingglass.dmi
index 32c010ff44d..b15573a11f2 100644
Binary files a/icons/mob/in-hand/left/drinkingglass.dmi and b/icons/mob/in-hand/left/drinkingglass.dmi differ
diff --git a/icons/mob/in-hand/right/drinkingglass.dmi b/icons/mob/in-hand/right/drinkingglass.dmi
index 71d2d05c827..add119bac76 100644
Binary files a/icons/mob/in-hand/right/drinkingglass.dmi and b/icons/mob/in-hand/right/drinkingglass.dmi differ
diff --git a/icons/obj/bottleflip.dmi b/icons/obj/bottleflip.dmi
new file mode 100644
index 00000000000..27473000ee6
Binary files /dev/null and b/icons/obj/bottleflip.dmi differ
diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi
index 710526a6551..ee4e326bff9 100644
Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ
diff --git a/sound/effects/woosh.ogg b/sound/effects/woosh.ogg
new file mode 100644
index 00000000000..7f3688b818a
Binary files /dev/null and b/sound/effects/woosh.ogg differ
diff --git a/sound/effects/woosh.wav b/sound/effects/woosh.wav
new file mode 100644
index 00000000000..adca6e2a60d
Binary files /dev/null and b/sound/effects/woosh.wav differ