diff --git a/baystation12.dme b/baystation12.dme
index cd9c14c5606e0..c677e42a2e340 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -187,6 +187,7 @@
#include "code\bos\game\objects\items\shooting_range.dm"
#include "code\bos\game\objects\items\toys.dm"
#include "code\bos\game\objects\items\wallet.dm"
+#include "code\bos\game\objects\items\devices\holopad_hand.dm"
#include "code\bos\game\objects\items\devices\radio.dm"
#include "code\bos\game\objects\items\devices\spy_sensor.dm"
#include "code\bos\game\objects\items\devices\syndietele.dm"
@@ -199,6 +200,7 @@
#include "code\bos\game\objects\items\weapons\implants\implants\fake_death.dm"
#include "code\bos\game\objects\items\weapons\implants\implants\spying.dm"
#include "code\bos\game\objects\items\weapons\storage\boxes.dm"
+#include "code\bos\game\objects\items\weapons\storage\cigarettes.dm"
#include "code\bos\game\objects\items\weapons\storage\mgsbox.dm"
#include "code\bos\game\objects\items\weapons\storage\snb.dm"
#include "code\bos\game\objects\items\weapons\storage\uplink_kits.dm"
@@ -242,6 +244,7 @@
#include "code\bos\modules\clothing\hats\kgb_hat.dm"
#include "code\bos\modules\clothing\hats\sombrero.dm"
#include "code\bos\modules\clothing\mask\booker_face.dm"
+#include "code\bos\modules\clothing\mask\smokable.dm"
#include "code\bos\modules\clothing\suit\blazer.dm"
#include "code\bos\modules\clothing\suit\booker.dm"
#include "code\bos\modules\clothing\suit\cyberpunk_overcoat.dm"
@@ -355,6 +358,7 @@
#include "code\bos\modules\projectiles\projectile\special.dm"
#include "code\bos\modules\reagents\Chemistry-Reagents-Recipes.dm"
#include "code\bos\modules\reagents\kvasok.dm"
+#include "code\bos\modules\reagents\tobacco.dm"
#include "code\bos\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Food-Drinks.dm"
#include "code\bos\modules\species\mantid\mantid.dm"
#include "code\bos\modules\species\station\prometheans.dm"
diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm
index 013911a1cde55..78e22ec1b6820 100644
--- a/code/_helpers/icons.dm
+++ b/code/_helpers/icons.dm
@@ -924,3 +924,19 @@ lighting determines lighting capturing (optional), suppress_errors suppreses err
cap.Blend(img, blendMode2iconMode(A.blend_mode), A.pixel_x + xoff, A.pixel_y + yoff)
return cap
+
+
+/proc/build_composite_icon_omnidir(atom/A)
+ var/icon/composite = icon('icons/effects/effects.dmi', "icon_state"="nothing")
+ for(var/O in A.underlays)
+ var/image/I = O
+ composite.Blend(new /icon(I.icon, I.icon_state), ICON_OVERLAY)
+ var/icon/ico_omnidir = new(A.icon)
+ if(A.icon_state in ico_omnidir.IconStates())
+ composite.Blend(new /icon(ico_omnidir, A.icon_state), ICON_OVERLAY)
+ else
+ composite.Blend(new /icon(ico_omnidir, null), ICON_OVERLAY)
+ for(var/O in A.overlays)
+ var/image/I = O
+ composite.Blend(new /icon(I.icon, I.icon_state), ICON_OVERLAY)
+ return composite
diff --git a/code/bos/game/objects/items/devices/holopad_hand.dm b/code/bos/game/objects/items/devices/holopad_hand.dm
new file mode 100644
index 0000000000000..58c8f406d6e9b
--- /dev/null
+++ b/code/bos/game/objects/items/devices/holopad_hand.dm
@@ -0,0 +1,205 @@
+#define CALL_NONE 0
+#define CALL_CALLING 1
+#define CALL_RINGING 2
+#define CALL_IN_CALL 3
+
+/obj/item/device/holopad
+ name = "Holopad"
+ desc = "Small handheld disk with controls."
+ icon = 'icons/bos/obj/holopad.dmi'
+ icon_state = "holopad"
+ item_state = "card-id"
+ w_class = ITEM_SIZE_TINY
+ var/voice
+ var/id
+ var/uniq_id
+ var/obj/item/device/holopad/abonent = null
+ var/call_state = CALL_NONE
+ var/obj/effect/hologram = null
+ var/updatingPos = 0
+ origin_tech = list(TECH_DATA = 4, TECH_BLUESPACE = 2, TECH_MAGNET = 4)
+
+/obj/item/device/holopad/Initialize()
+ uniq_id = random_id("holopad_device", 00000, 99999)
+ id = rand(1000, 9999)
+ name = "[initial(name)] [id] #[uniq_id]"
+ voice = "Holopad [id]"
+ GLOB.listening_objects += src
+ . = ..()
+
+/obj/item/device/holopad/Destroy()
+ GLOB.listening_objects -= src
+ abonent = null
+ . = ..()
+
+
+/obj/item/device/holopad/verb/setID()
+ set name="Set ID"
+ set category = "Object"
+ set src in usr
+ var/newid = sanitize(input(usr, "What would be new ID?") as null|text, MAX_NAME_LEN)
+ if(newid && CanPhysicallyInteract(usr))
+ id = newid
+ name = "[initial(name)] [id] #[uniq_id]"
+
+/obj/item/device/holopad/proc/getName(override_busy = 0)
+ if(call_state!=CALL_NONE && !override_busy)
+ return "Holopad [id] #[uniq_id] - busy"
+ else
+ return "Holopad [id] #[uniq_id]"
+
+/obj/item/device/holopad/proc/incall(obj/item/device/holopad/caller)
+ if(call_state != CALL_NONE)
+ return FALSE
+ abonent = caller
+ call_state = CALL_RINGING
+ icon_state = "holopad_ringing"
+ desc = "[initial(desc)] Incoming call from [caller.getName()]."
+ INVOKE_ASYNC(src, .proc/ring)
+ return TRUE
+
+/obj/item/device/holopad/proc/ring()
+ if(call_state != CALL_RINGING)
+ return
+ audible_message(SPAN_WARNING("Something vibrates.."), hearing_distance = 4)
+ addtimer(CALLBACK(src, .proc/ring), 50)
+
+/obj/item/device/holopad/proc/placeCall(mob/user)
+ var/list/Targets = list()
+ for(var/obj/item/device/holopad/H in GLOB.listening_objects)
+ if(H == src)
+ continue
+ Targets[H.getName()] = H
+ var/selection = input("Who do you want to call?") as null|anything in Targets
+ if(!selection)
+ return
+ var/obj/item/device/holopad/target = Targets[selection]
+ if(!target)
+ return
+ if(target.incall(src))
+ call_state = CALL_CALLING
+ abonent = target
+ icon_state = "holopad_calling"
+ to_chat(user, SPAN_NOTICE("Calling [sanitize(abonent.getName(1))]"))
+ else
+ to_chat(user, SPAN_WARNING("Remote device is busy"))
+
+/obj/item/device/holopad/proc/acceptCall()
+ if(call_state == CALL_RINGING)
+ if(abonent && abonent.call_state == CALL_CALLING)
+ abonent.acceptCall()
+ call_state = CALL_IN_CALL
+ icon_state = "holopad_in_call"
+ addtimer(CALLBACK(src, .proc/update_holo), 1)
+
+ audible_message("[voice] transmits, \"Connection established\"", hearing_distance = 1)
+ else
+ call_state = CALL_NONE
+ icon_state = initial(icon_state)
+ desc = initial(desc)
+ abonent = null
+
+ else if(call_state == CALL_CALLING)
+ call_state = CALL_IN_CALL
+ icon_state = "holopad_in_call"
+ addtimer(CALLBACK(src, .proc/update_holo), 1)
+
+ audible_message("[voice] transmits, \"Connection established\"", hearing_distance = 1)
+
+/obj/item/device/holopad/proc/hangUp(remote = 0)
+ if(!remote && abonent)
+ abonent.hangUp(1)
+
+ if(call_state==CALL_NONE)
+ return
+
+ audible_message(SPAN_WARNING("Connection closed"), hearing_distance = 4)
+ call_state = CALL_NONE
+ icon_state = initial(icon_state)
+ desc = initial(desc)
+ abonent = null
+ qdel(hologram)
+
+/obj/item/device/holopad/dropped()
+ update_holo()
+
+/obj/item/device/holopad/proc/update_holo()
+ if(call_state == CALL_IN_CALL)
+ if(!abonent)
+ return
+ if(!abonent.hologram)
+ abonent.hologram = new()
+ abonent.hologram.name = "Hologram [sanitize(id)]"
+ abonent.hologram.layer = 5
+ if(isliving(loc))
+ abonent.hologram.icon = getHologramIcon(build_composite_icon_omnidir(loc))
+ else
+ abonent.hologram.icon = icon('icons/effects/effects.dmi', "icon_state"="nothing")
+ if(!abonent.updatingPos)
+ abonent.update_holo_pos()
+
+/obj/item/device/holopad/proc/update_holo_pos()
+ if(call_state != CALL_IN_CALL)
+ updatingPos = 0
+ return
+ updatingPos = 1
+ if(isliving(loc))
+ var/mob/living/L = loc
+ hologram.dir = turn(L.dir,180)
+ hologram.loc = L.loc
+ hologram.pixel_x = ((L.dir&4)?32:((L.dir&8)?-32:0))
+ hologram.pixel_y = ((L.dir&1)?32:((L.dir&2)?-32:0))
+ else if(isturf(loc))
+ hologram.dir = 2
+ hologram.loc = loc
+ hologram.pixel_x = 0
+ hologram.pixel_y = 0
+ else
+ hangUp()
+ addtimer(CALLBACK(src, .proc/update_holo_pos), 2)
+
+
+/obj/item/device/holopad/attack_self(mob/user)
+ switch(call_state)
+ if(CALL_NONE)
+ placeCall()
+ if(CALL_CALLING)
+ hangUp()
+ if(CALL_RINGING)
+ acceptCall()
+ if(CALL_IN_CALL)
+ hangUp()
+
+/obj/item/device/holopad/hear_talk(mob/user, datum/language/speaking)
+ if(call_state == CALL_IN_CALL)
+ abonent.receive(speaking, user == loc)
+
+/obj/item/device/holopad/proc/receive(speaking, mob/user)
+ var/list/listening = get_mobs_or_objects_in_view(3, src)
+
+ for(var/mob/observer/ghost/G in GLOB.ghost_mob_list)
+ if(get_dist(src, G) > world.view && G.get_preference_value(/datum/client_preference/ghost_ears) != GLOB.PREF_ALL_SPEECH)
+ continue
+ listening |= G
+
+ if(!user)
+ voice = "Holopad Background Voice"
+ for(var/mob/M in listening)
+ to_chat(M, "[voice] transmits, \"[speaking]\" ")
+
+
+/*
+/obj/item/device/holopad/cheap
+ name = "Holopda"
+ desc = "New brand pda now with holo-link and built-in clock."
+ icon = 'icons/bos/obj/holopda.dmi'
+ w_class = ITEM_SIZE_SMALL
+
+/obj/item/device/holopad/cheap/examine(mob/user)
+ . = ..()
+ to_chat(user, "\the [src] displays [stationtime2text()].")
+*/
+#undef CALL_NONE
+#undef CALL_CALLING
+#undef CALL_RINGING
+#undef CALL_IN_CALL
diff --git a/code/bos/game/objects/items/weapons/storage/cigarettes.dm b/code/bos/game/objects/items/weapons/storage/cigarettes.dm
new file mode 100644
index 0000000000000..95e6a267a5301
--- /dev/null
+++ b/code/bos/game/objects/items/weapons/storage/cigarettes.dm
@@ -0,0 +1,35 @@
+/obj/item/storage/fancy/cigarettes/bos/elpedros
+ name = "pack of El Pedro's"
+ desc = "One of the most popular brands of women's cigarettes in Lordania. \
+ Every smoking girl is ready to give a lot of money for blocks of such cigarettes."
+ icon_state = "ppacket"
+ icon = 'icons/bos/obj/cigarettes.dmi'
+ startswith = list(/obj/item/clothing/mask/smokable/cigarette/elpedros = 4)
+
+/obj/item/storage/fancy/cigarettes/bos/nirvana
+ name = "pack of Nirvana Honeys"
+ desc = "The Manufacturer promises that these honey cigarettes will take you directly to Nirvana. \
+ In fact, this is just a crappy brand of cigarettes. But with honey flavor!"
+ icon_state = "npacket"
+ startswith = list(/obj/item/clothing/mask/smokable/cigarette/nirvana = 6)
+
+/obj/item/storage/fancy/cigarettes/bos/mars
+ name = "pack of Marsian Coffee"
+ desc = "Popular coffee cigarettes produced by Marsian branch of SyndiBust. \
+ Originally named «Gideon's Coffee», the name was changed due to a lawsuit filed by relatives of Jimmy Gideon."
+ icon_state = "mpacket"
+ startswith = list(/obj/item/clothing/mask/smokable/cigarette/mars = 6)
+
+/obj/item/storage/fancy/cigarettes/bos/pear
+ name = "pack of Green Pear"
+ desc = "Selenian brand of cigarettes with specific flavor and smiling pear on it's cover. \
+ Sometimes it seems that time flies like a clock while smoking them."
+ icon_state = "pepacket"
+ startswith = list(/obj/item/clothing/mask/smokable/cigarette/pear = 6)
+
+/obj/item/storage/fancy/cigarettes/bos/chinese
+ name = "pack of Yao Yan"
+ desc = "Special brand of medical cigarettes produced in collaboration between Me-Vir and Euclidian government. \
+ Shoddy taste, but less harmful than other cigarettes."
+ icon_state = "cpacket"
+ startswith = list(/obj/item/clothing/mask/smokable/cigarette/chinese = 6)
diff --git a/code/bos/modules/clothing/mask/smokable.dm b/code/bos/modules/clothing/mask/smokable.dm
new file mode 100644
index 0000000000000..8cdba4bc40e70
--- /dev/null
+++ b/code/bos/modules/clothing/mask/smokable.dm
@@ -0,0 +1,30 @@
+/obj/item/clothing/mask/smokable/cigarette/elpedros
+ name = "thin cigarette"
+ brand = "\improper El Pedro's"
+ icon_state = "cigpro"
+ type_butt = /obj/item/trash/cigbutt/professionals
+ filling = list(/datum/reagent/tobacco/female = 1)
+
+/obj/item/clothing/mask/smokable/cigarette/nirvana
+ name = "cigarette"
+ brand = "\improper Nirvana Honeys"
+ icon_state = "cigoff"
+ filling = list(/datum/reagent/tobacco/honey = 1)
+
+/obj/item/clothing/mask/smokable/cigarette/mars
+ name = "cigarette"
+ brand = "\improper Marsian Coffee"
+ icon_state = "cigjer"
+ filling = list(/datum/reagent/tobacco/coffee = 1)
+
+/obj/item/clothing/mask/smokable/cigarette/pear
+ name = "cigarette"
+ brand = "\improper Green Pear"
+ icon_state = "cigoff"
+ filling = list(/datum/reagent/tobacco/perception = 1)
+
+/obj/item/clothing/mask/smokable/cigarette/chinese
+ name = "cigarette"
+ brand = "\improper Yao Yan"
+ icon_state = "cigoff"
+ filling = list(/datum/reagent/tobacco/medical = 1)
diff --git a/code/bos/modules/reagents/tobacco.dm b/code/bos/modules/reagents/tobacco.dm
new file mode 100644
index 0000000000000..1bdfd133b2fbb
--- /dev/null
+++ b/code/bos/modules/reagents/tobacco.dm
@@ -0,0 +1,158 @@
+/datum/reagent/bicaridine/tobacco
+ taste_description = "speeding up time?"
+
+/datum/reagent/tobacco/perception
+ name = "Herbal drugs and tobacco"
+ description = "Cut and process tobacco leaves along with herbal preparations."
+ taste_description = "tobacco"
+ scent = "cigarette smoke and herbal drug?"
+ scent_range = 6
+
+/datum/reagent/tobacco/perception/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ ..()
+ M.add_chemical_effect(CE_SLOWDOWN, 1)
+
+/datum/reagent/tobacco/medical
+ name = "Medical tobacco"
+ description = "medicinal tobacco used for relaxation and concentration."
+ taste_description = "relax, concetration and tobacco"
+ scent = "tobacco"
+ scent_range = 2
+
+/datum/reagent/tobacco/strong
+ name = "Strong tobacco"
+ description = "Strong tobacco for strong men... or women, i don't know."
+ taste_description = "strong tobacco that hits the throat hard"
+ scent = "strong tobacco"
+ scent_range = 10
+
+/datum/reagent/tobacco/strong/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ ..()
+ M.reagents.add_reagent(/datum/reagent/nicotine, 10)
+
+/datum/reagent/tobacco/female
+ name = "female tobacco"
+ description = "female tobacco for good ladies."
+ taste_description = "weak tobacco that gently caresses the throat."
+ scent = "weak tobacco"
+
+/datum/reagent/tobacco/honey
+ name = "tobacco with honey"
+ description = "tobacco that has been processed in honey."
+ taste_description = "the sweetness of honey and the strength of tobacco."
+ scent = "sweet tobacco"
+
+/datum/reagent/tobacco/coffee
+ name = "tobacco with coffee"
+ description = "tobacco leaves that have been mixed with coffee powder."
+ taste_description = "sweet tobacco and energetic coffee."
+ scent = "sweet tobacco and energy tobacco"
+ scent_descriptor = "sweet tobacco"
+
+
+
+//packet
+
+/obj/item/tobacco
+ name = "Peace of tobacco"
+ desc = "Tobacco who used in hookah's for make smoke."
+ w_class = ITEM_SIZE_TINY
+
+ icon = 'icons/obj/hydroponics_products.dmi'
+ icon_state = "tobacco-product"
+ item_state = "tobacco-product"
+ var/volume = 5
+ var/list/filling = list(/datum/reagent/tobacco = 1)
+
+
+/obj/item/tobacco/New()
+ ..()
+ create_reagents(volume)
+ for(var/R in filling)
+ reagents.add_reagent(R, filling[R])
+
+/obj/item/tobacco/perception
+ name = "perception tobacco"
+ desc = "Cut and process tobacco leaves along with herbal preparations."
+
+ filling = list(/datum/reagent/tobacco/perception = 1, /datum/reagent/bicaridine/tobacco = 1)
+
+/obj/item/tobacco/medical
+ name = "medical tobacco"
+ desc = "Medicinal tobacco used for relaxation and concentration."
+
+ filling = list(/datum/reagent/tobacco/medical = 1, /datum/reagent/paroxetine = 0.7)
+
+/obj/item/tobacco/strong
+ name = "strong tobacco"
+ desc = "Strong tobacco for strong men... or women, perhaps."
+
+ filling = list(/datum/reagent/tobacco/strong = 1)
+
+/obj/item/tobacco/female
+ name = "female tobacco"
+ desc = "Female tobacco for good ladies."
+
+ filling = list(/datum/reagent/tobacco/female = 1)
+
+/obj/item/tobacco/honey
+ name = "tobacco with honey"
+ desc = "Tobacco that has been processed in honey."
+
+ filling = list(/datum/reagent/tobacco/honey = 1)
+
+/obj/item/tobacco/coffee
+ name = "tobacco with coffee"
+ desc = "Tobacco leaves that have been mixed with coffee powder."
+
+ filling = list(/datum/reagent/tobacco/coffee = 1)
+
+/obj/item/tobacco/attackby(obj/item/I, mob/user)
+ if(is_type_in_list(I, list(/obj/item/paper/cig/, /obj/item/paper/, /obj/item/teleportation_scroll)))
+ if(user.unEquip(I))
+ var/obj/item/clothing/mask/smokable/cigarette/rolled/R = new(get_turf(src))
+ R.chem_volume = reagents.total_volume
+ R.brand = "[src] handrolled in \the [I]."
+ reagents.trans_to_holder(R.reagents, R.chem_volume)
+ to_chat(user, "You roll \the [src] into \the [I]")
+ user.put_in_active_hand(R)
+ qdel(I)
+ qdel(src)
+ return
+ ..()
+
+/obj/item/storage/chewables/rollable/perception
+ name = "bag of perception tobacco"
+ desc = "Cut and process tobacco leaves along with herbal preparations."
+ startswith = list(/obj/item/tobacco/perception = 8)
+ icon_state = "rollfine"
+
+/obj/item/storage/chewables/rollable/medical
+ name = "bag of medical tobacco"
+ desc = "Medicinal tobacco used for relaxation and concentration."
+ startswith = list(/obj/item/tobacco/medical = 8)
+ icon_state = "rollfine"
+
+/obj/item/storage/chewables/rollable/strong
+ name = "bag of strong tobacco"
+ desc = "Strong tobacco for strong men... or women, perhaps."
+ startswith = list(/obj/item/tobacco/strong = 8)
+ icon_state = "rollfine"
+
+/obj/item/storage/chewables/rollable/female
+ name = "bag of female tobacco"
+ desc = "Female tobacco for good ladies."
+ startswith = list(/obj/item/tobacco/female = 8)
+ icon_state = "rollfine"
+
+/obj/item/storage/chewables/rollable/honey
+ name = "bag of honey tobacco"
+ desc = "Tobacco that has been processed in honey."
+ startswith = list(/obj/item/tobacco/honey = 8)
+ icon_state = "rollfine"
+
+/obj/item/storage/chewables/rollable/coffee
+ name = "bag of coffee tobacco"
+ desc = "Tobacco leaves that have been mixed with coffee powder."
+ startswith = list(/obj/item/tobacco/coffee = 8)
+ icon_state = "rollfine"
diff --git a/code/modules/client/preference_setup/loadout/lists/misc.dm b/code/modules/client/preference_setup/loadout/lists/misc.dm
index 321857e6dedb2..46fba0d2ced02 100644
--- a/code/modules/client/preference_setup/loadout/lists/misc.dm
+++ b/code/modules/client/preference_setup/loadout/lists/misc.dm
@@ -310,3 +310,8 @@
cointype["coin, phoron"] = /obj/item/material/coin/phoron
cointype["coin, platinum"] = /obj/item/material/coin/platinum
gear_tweaks += new/datum/gear_tweak/path(cointype)
+
+/datum/gear/device/holopad/cheap
+ display_name = "holopda"
+ path = /obj/item/device/holopad/cheap
+ cost = 3
diff --git a/icons/bos/obj/cigarettes.dmi b/icons/bos/obj/cigarettes.dmi
new file mode 100644
index 0000000000000..ed8fad0c3db1f
Binary files /dev/null and b/icons/bos/obj/cigarettes.dmi differ
diff --git a/icons/bos/obj/holopad.dmi b/icons/bos/obj/holopad.dmi
new file mode 100644
index 0000000000000..b83c53ea7a874
Binary files /dev/null and b/icons/bos/obj/holopad.dmi differ
diff --git a/icons/bos/obj/holopda.dmi b/icons/bos/obj/holopda.dmi
new file mode 100644
index 0000000000000..4bb6e0349acaa
Binary files /dev/null and b/icons/bos/obj/holopda.dmi differ