mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-28 18:11:16 +00:00
## About The Pull Request <img width="612" height="185" alt="dreamseeker_SNMvxqCRiR" src="https://github.com/user-attachments/assets/1d3103e9-edc1-4e50-8793-c8c2ace53aea" /> This is a small expansion to narcotics, their production, and presence in the game! For my esteemed Terry and Manuel/Sybil sector colleagues I've added: - 2 new solid drug items: **crystal meth and opium**! - A **precipitation reaction** for meth after it's been cooled, producing a solid crystal form, 2u sulfuric acid, 10u meth. **Above 90% purity, the meth will gain an increasingly blue tint!** - A production method for opium! Slice a well developed poppy pod with any sharp item, **before it's fully mature and flowered** to extract a small amount of opium to enjoy! It's a small container for morphine. Can be pressed together to combine the concentrations up to 10u, as each extraction contains trace amounts. Scales off poppy's potency. - Populated narcotics/contraband spawners with new items, and items that really should have been on there. - Added a brand new smoking apparatus, the glass pipe! Can be crafted. Fixed the transparent pixel. - **Fixed methsplosions so that now spacemen can finally smoke meth without exploding!!!** Omegaweed too. Normal methsplosions are untouched! - **Expanded the ability for players to insert all drug items into pipes**, so now players can smoke moon rocks, SaturnX, and my new items! Previously, only 'dried' items were. - Fentanyl patch box for narcotics spawner, also for a new ruin I've made. - **Expanded these changes to the black market uplink.** <img width="640" height="256" alt="demo" src="https://github.com/user-attachments/assets/c8a0eb2c-b0fa-4e70-b6c1-2e741cd170a2" /> Now, players can precipitate meth into a solid form, and produce opium. I added a lot of these substances and the ones that didn't exist into spawners that they were partially in, or could reasonably be in. The opium poppy extraction required a new variable that can be used for similar interactions too. Crystal sprites are transparent, smoked sprite has a nice little animation and glow. These items are now on the black market uplink, in both expensive dealer shipments of varying rarities for different narcotics, as well as personal use quantities on a different rotation, at a steeper price. Expanded randomized spawners to give the black market and ruins more teeth and edge, without adding another weapon. Credit to the moon rock guy, I'm just happy I made your stuff smokable!! <img width="219" height="201" alt="dreamseeker_N8x9bsN3kS" src="https://github.com/user-attachments/assets/64d23c27-92b9-423b-91ac-903b8476d0b4" /> tl;dr added opium and meth ## Why It's Good For The Game For **too long**, narcotics, chems and stims have been mere integers or buffs/debuffs in pills or syringes, so I introduced two new methods for making them and populated niche, criminal vectors with them. These are real items now, with more interactions. Allowing these to be smoked also allowed moon rocks and SaturnX to be smoked too, including them into this and enticing players to have another reason to make them as well. Buffs with drawbacks, addictions and problems are actually great. It's a new venue for flavor. I've put thought into the balance for addition and quantity. It'll add a criminal, or exotic tone to a round, provide new business opportunities, and new access to stims and chems without going over the top. Perhaps something peaceful antagonists can do. More proverbial floor pills give security or command something to selectively enforce, and absolutely provide novel opportunities for medical staff! Also, methsplosions now don't happen in cigarette items! You can smoke omegaweed without fucking dying! ## Changelog 🆑 add: Added meth, opium, and their production! Also added to black market uplink. add: Added a craftable glass pipe. add: Added to contraband spawners. qol: Can now insert any drug item into a pipe. fix: Spacemen can now smoke meth without exploding!! /🆑 --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: tattle <66640614+dragomagol@users.noreply.github.com>
1241 lines
38 KiB
Plaintext
1241 lines
38 KiB
Plaintext
//cleansed 9/15/2012 17:48
|
|
|
|
/*
|
|
CONTAINS:
|
|
MATCHES
|
|
CIGARETTES
|
|
CIGARS
|
|
SMOKING PIPES
|
|
|
|
CIGARETTE PACKETS ARE IN FANCY.DM
|
|
*/
|
|
|
|
///////////
|
|
//MATCHES//
|
|
///////////
|
|
/obj/item/match
|
|
name = "match"
|
|
desc = "A simple match stick, used for lighting fine smokables."
|
|
icon = 'icons/obj/cigarettes.dmi'
|
|
icon_state = "match_unlit"
|
|
inhand_icon_state = "cigoff"
|
|
base_icon_state = "match"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
heat = 1000
|
|
grind_results = list(/datum/reagent/phosphorus = 2)
|
|
/// Whether this match has been lit.
|
|
var/lit = FALSE
|
|
/// Whether this match has burnt out.
|
|
var/burnt = FALSE
|
|
/// How long the match lasts in seconds
|
|
var/smoketime = 10 SECONDS
|
|
/// If the match is broken
|
|
var/broken = FALSE
|
|
|
|
/obj/item/match/process(seconds_per_tick)
|
|
smoketime -= seconds_per_tick * (1 SECONDS)
|
|
if(smoketime <= 0)
|
|
matchburnout()
|
|
else
|
|
open_flame(heat)
|
|
|
|
/obj/item/match/fire_act(exposed_temperature, exposed_volume)
|
|
. = ..()
|
|
matchignite()
|
|
|
|
/obj/item/match/update_name(updates)
|
|
. = ..()
|
|
if(lit)
|
|
name = "lit [initial(name)]"
|
|
else if(burnt)
|
|
name = "burnt [initial(name)]"
|
|
else if(broken)
|
|
name = "broken [initial(name)]"
|
|
else
|
|
name = "[initial(name)]"
|
|
|
|
/obj/item/match/update_desc(updates)
|
|
. = ..()
|
|
if(lit)
|
|
desc = "[initial(desc)] This one is lit."
|
|
else if(burnt)
|
|
desc = "[initial(desc)] This one has seen better days."
|
|
else if(broken)
|
|
desc = "[initial(desc)] This one is broken."
|
|
else
|
|
desc = initial(desc)
|
|
|
|
/obj/item/match/update_icon_state()
|
|
. = ..()
|
|
inhand_icon_state = "cigoff"
|
|
if(lit)
|
|
icon_state = "[base_icon_state]_lit"
|
|
inhand_icon_state = "cigon"
|
|
else if(burnt)
|
|
icon_state = "[base_icon_state]_burnt"
|
|
else if(broken)
|
|
icon_state = "[base_icon_state]_broken"
|
|
else
|
|
icon_state = "[base_icon_state]_unlit"
|
|
|
|
/obj/item/match/proc/snap()
|
|
if(broken)
|
|
return
|
|
if(lit)
|
|
matchburnout()
|
|
|
|
playsound(src, 'sound/effects/snap.ogg', 15, TRUE)
|
|
broken = TRUE
|
|
attack_verb_continuous = string_list(list("flicks"))
|
|
attack_verb_simple = string_list(list("flick"))
|
|
STOP_PROCESSING(SSobj, src)
|
|
update_appearance()
|
|
|
|
/obj/item/match/proc/matchignite()
|
|
if(lit || burnt || broken)
|
|
return
|
|
|
|
playsound(src, 'sound/items/match_strike.ogg', 15, TRUE)
|
|
lit = TRUE
|
|
damtype = BURN
|
|
force = 3
|
|
hitsound = 'sound/items/tools/welder.ogg'
|
|
attack_verb_continuous = string_list(list("burns", "singes"))
|
|
attack_verb_simple = string_list(list("burn", "singe"))
|
|
if(isliving(loc))
|
|
var/mob/living/male_model = loc
|
|
if(male_model.fire_stacks && !(male_model.on_fire))
|
|
male_model.ignite_mob()
|
|
START_PROCESSING(SSobj, src)
|
|
update_appearance()
|
|
|
|
/obj/item/match/proc/matchburnout()
|
|
if(!lit)
|
|
return
|
|
|
|
lit = FALSE
|
|
burnt = TRUE
|
|
damtype = BRUTE
|
|
force = initial(force)
|
|
attack_verb_continuous = string_list(list("flicks"))
|
|
attack_verb_simple = string_list(list("flick"))
|
|
STOP_PROCESSING(SSobj, src)
|
|
update_appearance()
|
|
|
|
/obj/item/match/extinguish()
|
|
. = ..()
|
|
matchburnout()
|
|
|
|
/obj/item/match/dropped(mob/user)
|
|
matchburnout()
|
|
return ..()
|
|
|
|
/obj/item/match/attack(mob/living/carbon/M, mob/living/carbon/user)
|
|
if(!isliving(M))
|
|
return
|
|
|
|
if(lit && M.ignite_mob())
|
|
message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
|
|
user.log_message("set [key_name(M)] on fire with [src]", LOG_ATTACK)
|
|
|
|
var/obj/item/cigarette/cig = help_light_cig(M)
|
|
if(!lit || !cig || user.combat_mode)
|
|
..()
|
|
return
|
|
|
|
if(cig.lit)
|
|
to_chat(user, span_warning("[cig] is already lit!"))
|
|
if(M == user)
|
|
cig.attackby(src, user)
|
|
else
|
|
cig.light(span_notice("[user] holds [src] out for [M], and lights [cig]."))
|
|
|
|
/// Finds a cigarette on another mob to help light.
|
|
/obj/item/proc/help_light_cig(mob/living/M)
|
|
var/mask_item = M.get_item_by_slot(ITEM_SLOT_MASK)
|
|
if(istype(mask_item, /obj/item/cigarette))
|
|
return mask_item
|
|
|
|
/obj/item/match/get_temperature()
|
|
return lit * heat
|
|
|
|
/obj/item/match/firebrand
|
|
name = "firebrand"
|
|
desc = "An unlit firebrand. It makes you wonder why it's not just called a stick."
|
|
smoketime = 40 SECONDS
|
|
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT)
|
|
grind_results = list(/datum/reagent/carbon = 2)
|
|
|
|
/obj/item/match/firebrand/Initialize(mapload)
|
|
. = ..()
|
|
matchignite()
|
|
|
|
/obj/item/match/battery
|
|
name = "battery lighter"
|
|
desc = "A budget lighter done by using a battery and some aluminium. Hold tightly to ignite."
|
|
icon_state = "battery_unlit"
|
|
base_icon_state = "battery"
|
|
|
|
/obj/item/match/battery/attack_self(mob/living/user, modifiers)
|
|
. = ..()
|
|
if(!do_after(user, 4 SECONDS, src))
|
|
return
|
|
user.apply_damage(5, BURN, user.get_active_hand())
|
|
matchignite()
|
|
|
|
//////////////////
|
|
//FINE SMOKABLES//
|
|
//////////////////
|
|
|
|
/obj/item/cigarette
|
|
name = "cigarette"
|
|
desc = "A roll of tobacco and nicotine. It is not food."
|
|
icon = 'icons/obj/cigarettes.dmi'
|
|
worn_icon = 'icons/mob/clothing/mask.dmi'
|
|
icon_state = "cigoff"
|
|
inhand_icon_state = "cigon" //gets overriden during intialize(), just have it for unit test sanity.
|
|
throw_speed = 0.5
|
|
w_class = WEIGHT_CLASS_TINY
|
|
slot_flags = ITEM_SLOT_MASK
|
|
grind_results = list()
|
|
heat = 1000
|
|
light_range = 1
|
|
light_color = LIGHT_COLOR_FIRE
|
|
light_system = OVERLAY_LIGHT
|
|
light_on = FALSE
|
|
throw_verb = "flick"
|
|
/// Whether this cigarette has been lit.
|
|
VAR_FINAL/lit = FALSE
|
|
/// Whether this cigarette should start lit.
|
|
var/starts_lit = FALSE
|
|
// Note - these are in masks.dmi not in cigarette.dmi
|
|
/// The icon state used when this is lit.
|
|
var/icon_on = "cigon"
|
|
/// The icon state used when this is extinguished.
|
|
var/icon_off = "cigoff"
|
|
/// The inhand icon state used when this is lit.
|
|
var/inhand_icon_on = "cigon"
|
|
/// The inhand icon state used when this is extinguished.
|
|
var/inhand_icon_off = "cigoff"
|
|
/// How long the cigarette lasts in seconds
|
|
var/smoketime = 6 MINUTES
|
|
/// How much time between drags of the cigarette.
|
|
var/dragtime = 10 SECONDS
|
|
/// The cooldown that prevents just huffing the entire cigarette at once.
|
|
COOLDOWN_DECLARE(drag_cooldown)
|
|
/// The type of cigarette butt spawned when this burns out.
|
|
var/type_butt = /obj/item/cigbutt
|
|
/// The capacity for chems this cigarette has.
|
|
var/chem_volume = 30
|
|
/// The reagents that this cigarette starts with.
|
|
var/list/list_reagents = list(/datum/reagent/drug/nicotine = 15)
|
|
/// Should we smoke all of the chems in the cig before it runs out. Splits each puff to take a portion of the overall chems so by the end you'll always have consumed all of the chems inside.
|
|
var/smoke_all = FALSE
|
|
/// How much damage this deals to the lungs per drag.
|
|
var/lung_harm = 1
|
|
/// If, when glorf'd, we will choke on this cig forever
|
|
var/choke_forever = FALSE
|
|
/// When choking, what is the maximum amount of time we COULD choke for
|
|
var/choke_time_max = 30 SECONDS // I am mean
|
|
/// The particle effect of the smoke rising out of the cigarette when lit
|
|
VAR_PRIVATE/obj/effect/abstract/particle_holder/cig_smoke
|
|
/// The particle effect of the smoke rising out of the mob when...smoked
|
|
VAR_PRIVATE/obj/effect/abstract/particle_holder/mob_smoke
|
|
/// How long the current mob has been smoking this cigarette
|
|
VAR_FINAL/how_long_have_we_been_smokin = 0 SECONDS
|
|
/// Which people ate cigarettes and how many
|
|
var/static/list/cigarette_eaters = list()
|
|
|
|
/obj/item/cigarette/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/knockoff, 90, list(BODY_ZONE_PRECISE_MOUTH), slot_flags) //90% to knock off when wearing a mask
|
|
AddElement(/datum/element/update_icon_updates_onmob)
|
|
RegisterSignal(src, COMSIG_ATOM_TOUCHED_SPARKS, PROC_REF(sparks_touched))
|
|
icon_state = icon_off
|
|
inhand_icon_state = inhand_icon_off
|
|
|
|
// "It is called a cigarette"
|
|
AddComponentFrom(
|
|
SOURCE_EDIBLE_INNATE,\
|
|
/datum/component/edible,\
|
|
initial_reagents = list_reagents,\
|
|
food_flags = FOOD_NO_EXAMINE,\
|
|
foodtypes = JUNKFOOD,\
|
|
volume = chem_volume,\
|
|
eat_time = 0 SECONDS,\
|
|
tastes = list("a never before experienced flavour", "finally sitting down after standing your entire life"),\
|
|
eatverbs = list("taste"),\
|
|
bite_consumption = chem_volume,\
|
|
junkiness = 0,\
|
|
reagent_purity = null,\
|
|
on_consume = CALLBACK(src, PROC_REF(on_consume)),\
|
|
)
|
|
if(starts_lit)
|
|
light()
|
|
|
|
/obj/item/cigarette/Destroy()
|
|
STOP_PROCESSING(SSobj, src)
|
|
QDEL_NULL(mob_smoke)
|
|
QDEL_NULL(cig_smoke)
|
|
return ..()
|
|
|
|
/obj/item/cigarette/proc/on_consume(mob/living/eater, mob/living/feeder)
|
|
if(isnull(eater.client))
|
|
return
|
|
var/ckey = eater.client.ckey
|
|
// We must have more!
|
|
cigarette_eaters[ckey]++
|
|
if(cigarette_eaters[ckey] >= 500)
|
|
eater.client.give_award(/datum/award/achievement/misc/cigarettes)
|
|
|
|
/obj/item/cigarette/equipped(mob/equipee, slot)
|
|
. = ..()
|
|
if(!(slot & ITEM_SLOT_MASK))
|
|
UnregisterSignal(equipee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE))
|
|
return
|
|
RegisterSignal(equipee, COMSIG_HUMAN_FORCESAY, PROC_REF(on_forcesay))
|
|
RegisterSignal(equipee, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_mob_dir_change))
|
|
if(lit && iscarbon(loc))
|
|
make_mob_smoke(loc)
|
|
|
|
/obj/item/cigarette/dropped(mob/dropee)
|
|
. = ..()
|
|
// Moving the cigarette from mask to hands (or pocket I guess) will emit a larger puff of smoke
|
|
if(!QDELETED(src) && !QDELETED(dropee) && how_long_have_we_been_smokin >= 4 SECONDS && iscarbon(dropee) && iscarbon(loc))
|
|
var/mob/living/carbon/smoker = dropee
|
|
// This relies on the fact that dropped is called before slot is nulled
|
|
if(src == smoker.wear_mask && !smoker.incapacitated)
|
|
long_exhale(smoker)
|
|
|
|
UnregisterSignal(dropee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE))
|
|
QDEL_NULL(mob_smoke)
|
|
how_long_have_we_been_smokin = 0 SECONDS
|
|
|
|
/obj/item/cigarette/proc/on_forcesay(mob/living/source)
|
|
SIGNAL_HANDLER
|
|
source.apply_status_effect(/datum/status_effect/choke, src, lit, choke_forever ? -1 : rand(25 SECONDS, choke_time_max))
|
|
|
|
/obj/item/cigarette/proc/on_mob_dir_change(mob/living/source, old_dir, new_dir)
|
|
SIGNAL_HANDLER
|
|
if(isnull(mob_smoke))
|
|
return
|
|
update_particle_position(mob_smoke, new_dir)
|
|
|
|
/obj/item/cigarette/proc/update_particle_position(obj/effect/abstract/particle_holder/to_edit, new_dir = loc.dir)
|
|
var/new_x = 0
|
|
var/new_layer = initial(to_edit.layer)
|
|
if(new_dir & NORTH)
|
|
new_x = 4
|
|
new_layer = BELOW_MOB_LAYER
|
|
else if(new_dir & SOUTH)
|
|
new_x = -4
|
|
else if(new_dir & EAST)
|
|
new_x = 8
|
|
else if(new_dir & WEST)
|
|
new_x = -8
|
|
to_edit.set_particle_position(new_x, 8, 0)
|
|
to_edit.layer = new_layer
|
|
|
|
/obj/item/cigarette/suicide_act(mob/living/user)
|
|
user.visible_message(span_suicide("[user] is huffing [src] as quickly as [user.p_they()] can! It looks like [user.p_theyre()] trying to give [user.p_them()]self cancer."))
|
|
return (TOXLOSS|OXYLOSS)
|
|
|
|
/obj/item/cigarette/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers)
|
|
if(lit)
|
|
return ..()
|
|
|
|
var/lighting_text = W.ignition_effect(src, user)
|
|
if(!lighting_text)
|
|
return ..()
|
|
|
|
if(!check_oxygen(user)) //cigarettes need oxygen
|
|
balloon_alert(user, "no air!")
|
|
return ..()
|
|
|
|
if(smoketime > 0)
|
|
light(lighting_text)
|
|
else
|
|
to_chat(user, span_warning("There is nothing to smoke!"))
|
|
|
|
/// Checks that we have enough air to smoke
|
|
/obj/item/cigarette/proc/check_oxygen(mob/user)
|
|
if (reagents.has_reagent(/datum/reagent/oxygen))
|
|
return TRUE
|
|
var/datum/gas_mixture/air = return_air()
|
|
if (!isnull(air) && air.has_gas(/datum/gas/oxygen, 1))
|
|
return TRUE
|
|
if (!iscarbon(user))
|
|
return FALSE
|
|
var/mob/living/carbon/the_smoker = user
|
|
return the_smoker.can_breathe_helmet()
|
|
|
|
/obj/item/cigarette/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
|
|
if(lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead)
|
|
return NONE
|
|
var/obj/item/reagent_containers/cup/glass = interacting_with
|
|
if(!istype(glass)) //you can dip cigarettes into beakers
|
|
return NONE
|
|
if(istype(glass, /obj/item/reagent_containers/cup/mortar))
|
|
return NONE
|
|
if(glass.reagents.trans_to(src, chem_volume, transferred_by = user)) //if reagents were transferred, show the message
|
|
to_chat(user, span_notice("You dip \the [src] into \the [glass]."))
|
|
//if not, either the beaker was empty, or the cigarette was full
|
|
else if(!glass.reagents.total_volume)
|
|
to_chat(user, span_warning("[glass] is empty!"))
|
|
else
|
|
to_chat(user, span_warning("[src] is full!"))
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/obj/item/cigarette/update_icon_state()
|
|
. = ..()
|
|
if(lit)
|
|
icon_state = icon_on
|
|
inhand_icon_state = inhand_icon_on
|
|
else
|
|
icon_state = icon_off
|
|
inhand_icon_state = inhand_icon_off
|
|
|
|
|
|
/obj/item/cigarette/proc/sparks_touched(datum/source, obj/effect/particle_effect)
|
|
SIGNAL_HANDLER
|
|
|
|
if(lit)
|
|
return
|
|
light()
|
|
|
|
/// Lights the cigarette with given flavor text.
|
|
/obj/item/cigarette/proc/light(flavor_text = null)
|
|
if(lit)
|
|
return
|
|
|
|
lit = TRUE
|
|
playsound(src.loc, 'sound/items/lighter/cig_light.ogg', 100, 1)
|
|
make_cig_smoke()
|
|
set_light_on(TRUE)
|
|
if(!(flags_1 & INITIALIZED_1))
|
|
update_appearance(UPDATE_ICON)
|
|
return
|
|
|
|
attack_verb_continuous = string_list(list("burns", "singes"))
|
|
attack_verb_simple = string_list(list("burn", "singe"))
|
|
hitsound = 'sound/items/tools/welder.ogg'
|
|
damtype = BURN
|
|
force = 4
|
|
|
|
if(reagents && reagents.has_reagent(/datum/reagent/drug/methamphetamine))
|
|
reagents.flags |= NO_REACT
|
|
|
|
if(reagents.get_reagent_amount(/datum/reagent/toxin/plasma)) // the plasma explodes when exposed to fire
|
|
var/datum/effect_system/reagents_explosion/e = new()
|
|
e.set_up(round(reagents.get_reagent_amount(/datum/reagent/toxin/plasma) / 2.5, 1), get_turf(src), 0, 0)
|
|
e.start(src)
|
|
qdel(src)
|
|
return
|
|
if(reagents.get_reagent_amount(/datum/reagent/fuel)) // the fuel explodes, too, but much less violently
|
|
var/datum/effect_system/reagents_explosion/e = new()
|
|
e.set_up(round(reagents.get_reagent_amount(/datum/reagent/fuel) / 5, 1), get_turf(src), 0, 0)
|
|
e.start(src)
|
|
qdel(src)
|
|
return
|
|
// allowing reagents to react after being lit
|
|
update_appearance(UPDATE_ICON)
|
|
if(flavor_text)
|
|
var/turf/T = get_turf(src)
|
|
T.visible_message(flavor_text)
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
if(iscarbon(loc))
|
|
var/mob/living/carbon/smoker = loc
|
|
if(src == smoker.wear_mask)
|
|
make_mob_smoke(smoker)
|
|
|
|
/obj/item/cigarette/extinguish()
|
|
. = ..()
|
|
if(!lit)
|
|
return
|
|
attack_verb_continuous = null
|
|
attack_verb_simple = null
|
|
hitsound = null
|
|
damtype = BRUTE
|
|
force = 0
|
|
STOP_PROCESSING(SSobj, src)
|
|
reagents.flags |= NO_REACT
|
|
lit = FALSE
|
|
playsound(src.loc, 'sound/items/lighter/cig_snuff.ogg', 100, 1)
|
|
update_appearance(UPDATE_ICON)
|
|
set_light_on(FALSE)
|
|
if(ismob(loc))
|
|
to_chat(loc, span_notice("Your [name] goes out."))
|
|
QDEL_NULL(cig_smoke)
|
|
QDEL_NULL(mob_smoke)
|
|
|
|
/obj/item/cigarette/proc/long_exhale(mob/living/carbon/smoker)
|
|
// Find a mob to blow smoke at
|
|
var/mob/living/guy_infront
|
|
for(var/mob/living/guy in get_step(smoker, smoker.dir))
|
|
// one of you has to get on the other's level
|
|
if(guy.body_position != smoker.body_position)
|
|
continue
|
|
// ensures we're face to face
|
|
if(!(REVERSE_DIR(guy.dir) & smoker.dir))
|
|
continue
|
|
guy_infront = guy
|
|
// in case we get a living first, we wanna prioritize humans
|
|
if(ishuman(guy_infront))
|
|
break
|
|
|
|
if(isnull(guy_infront))
|
|
smoker.visible_message(
|
|
span_notice("[smoker] exhales a large cloud of smoke from [src]."),
|
|
span_notice("You exhale a large cloud of smoke from [src]."),
|
|
)
|
|
|
|
else if(ishuman(guy_infront) && guy_infront.get_bodypart(BODY_ZONE_HEAD) && !guy_infront.is_pepper_proof())
|
|
guy_infront.visible_message(
|
|
span_notice("[smoker] exhales a large cloud of smoke from [src] directly at [guy_infront]'s face!"),
|
|
span_notice("You exhale a large cloud of smoke from [src] directly at [guy_infront]'s face."),
|
|
ignored_mobs = guy_infront,
|
|
)
|
|
to_chat(guy_infront, span_warning("You get a face full of smoke from [smoker]'s [name]!"))
|
|
smoke_in_face(guy_infront)
|
|
|
|
else
|
|
guy_infront.visible_message(
|
|
span_notice("[smoker] exhales a large cloud of smoke from [src] at [guy_infront]."),
|
|
span_notice("You exhale a large cloud of smoke from [src] at [guy_infront]."),
|
|
)
|
|
|
|
if(!isturf(smoker.loc))
|
|
return
|
|
|
|
var/obj/effect/abstract/particle_holder/big_smoke = new(smoker.loc, /particles/smoke/cig/big)
|
|
update_particle_position(big_smoke, smoker.dir)
|
|
QDEL_IN(big_smoke, big_smoke.particles.lifespan)
|
|
|
|
/// Called when a mob gets smoke blown in their face.
|
|
/obj/item/cigarette/proc/smoke_in_face(mob/living/getting_smoked)
|
|
getting_smoked.add_mood_event("smoke_bm", /datum/mood_event/smoke_in_face)
|
|
if(prob(20) && !HAS_TRAIT(getting_smoked, TRAIT_SMOKER) && !HAS_TRAIT(getting_smoked, TRAIT_ANOSMIA))
|
|
getting_smoked.emote("cough")
|
|
|
|
/// Handles processing the reagents in the cigarette.
|
|
/obj/item/cigarette/proc/handle_reagents(seconds_per_tick)
|
|
if(!reagents.total_volume)
|
|
return
|
|
reagents.expose_temperature(heat, 0.05)
|
|
if(!reagents.total_volume) //may have reacted and gone to 0 after expose_temperature
|
|
return
|
|
var/to_smoke = smoke_all ? (reagents.total_volume * (dragtime / smoketime)) : REAGENTS_METABOLISM
|
|
var/mob/living/carbon/smoker = loc
|
|
// These checks are a bit messy but at least they're fairly readable
|
|
// Check if the smoker is a carbon mob, since it needs to have wear_mask
|
|
if(!istype(smoker))
|
|
// If not, check if it's a gas mask
|
|
if(!istype(smoker, /obj/item/clothing/mask/gas))
|
|
reagents.remove_all(to_smoke)
|
|
return
|
|
|
|
smoker = smoker.loc
|
|
|
|
// If it is, check if that mask is on a carbon mob
|
|
if(!istype(smoker) || smoker.get_item_by_slot(ITEM_SLOT_MASK) != loc)
|
|
reagents.remove_all(to_smoke)
|
|
return
|
|
else
|
|
if(src != smoker.wear_mask)
|
|
reagents.remove_all(to_smoke)
|
|
return
|
|
|
|
how_long_have_we_been_smokin += seconds_per_tick * (1 SECONDS)
|
|
reagents.expose(smoker, INHALE, min(to_smoke / reagents.total_volume, 1))
|
|
var/obj/item/organ/lungs/lungs = smoker.get_organ_slot(ORGAN_SLOT_LUNGS)
|
|
if(lungs && IS_ORGANIC_ORGAN(lungs))
|
|
var/smoker_resistance = HAS_TRAIT(smoker, TRAIT_SMOKER) ? 0.5 : 1
|
|
smoker.adjustOrganLoss(ORGAN_SLOT_LUNGS, lung_harm * smoker_resistance)
|
|
if(!reagents.trans_to(smoker, to_smoke, methods = INHALE, ignore_stomach = TRUE))
|
|
reagents.remove_all(to_smoke)
|
|
|
|
/obj/item/cigarette/process(seconds_per_tick)
|
|
var/mob/living/user = isliving(loc) ? loc : null
|
|
user?.ignite_mob()
|
|
|
|
if(!check_oxygen(user))
|
|
extinguish()
|
|
return
|
|
|
|
smoketime -= seconds_per_tick * (1 SECONDS)
|
|
if(smoketime <= 0)
|
|
put_out(user)
|
|
return
|
|
|
|
open_flame(heat)
|
|
if((reagents?.total_volume) && COOLDOWN_FINISHED(src, drag_cooldown))
|
|
COOLDOWN_START(src, drag_cooldown, dragtime)
|
|
handle_reagents(seconds_per_tick)
|
|
|
|
/obj/item/cigarette/attack_self(mob/user)
|
|
if(lit)
|
|
put_out(user, TRUE)
|
|
return ..()
|
|
|
|
/obj/item/cigarette/proc/put_out(mob/user, done_early = FALSE)
|
|
var/atom/location = drop_location()
|
|
if(!isnull(user))
|
|
if(done_early)
|
|
if(isfloorturf(location) && location.has_gravity())
|
|
user.visible_message(span_notice("[user] calmly drops and treads on [src], putting it out instantly."))
|
|
new /obj/effect/decal/cleanable/ash(location)
|
|
long_exhale(user)
|
|
else
|
|
user.visible_message(span_notice("[user] pinches out [src]."))
|
|
how_long_have_we_been_smokin = 0 SECONDS
|
|
else
|
|
to_chat(user, span_notice("Your [name] goes out."))
|
|
new type_butt(location)
|
|
qdel(src)
|
|
|
|
/obj/item/cigarette/attack(mob/living/carbon/M, mob/living/carbon/user)
|
|
if(!istype(M))
|
|
return ..()
|
|
if(M.on_fire && !lit)
|
|
light(span_notice("[user] lights [src] with [M]'s burning body. What a cold-blooded badass."))
|
|
return
|
|
var/obj/item/cigarette/cig = help_light_cig(M)
|
|
if(!lit || !cig || user.combat_mode)
|
|
return ..()
|
|
|
|
if(cig.lit)
|
|
to_chat(user, span_warning("\The [cig] is already lit!"))
|
|
if(M == user)
|
|
cig.attackby(src, user)
|
|
else
|
|
cig.light(span_notice("[user] holds \the [src] out for [M], and lights [M.p_their()] [cig.name]."))
|
|
|
|
/obj/item/cigarette/fire_act(exposed_temperature, exposed_volume)
|
|
light()
|
|
|
|
/obj/item/cigarette/get_temperature()
|
|
return lit * heat
|
|
|
|
/obj/item/cigarette/proc/make_mob_smoke(mob/living/smoker)
|
|
mob_smoke = new(smoker, /particles/smoke/cig)
|
|
update_particle_position(mob_smoke, smoker.dir)
|
|
return mob_smoke
|
|
|
|
/obj/item/cigarette/proc/make_cig_smoke()
|
|
cig_smoke = new(src, /particles/smoke/cig)
|
|
cig_smoke.particles?.scale *= 1.5
|
|
return cig_smoke
|
|
|
|
// Cigarette brands.
|
|
/obj/item/cigarette/space_cigarette
|
|
desc = "A Space brand cigarette that can be smoked anywhere."
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 9, /datum/reagent/oxygen = 9)
|
|
smoketime = 4 MINUTES // space cigs have a shorter burn time than normal cigs
|
|
smoke_all = TRUE // so that it doesn't runout of oxygen while being smoked in space
|
|
|
|
/obj/item/cigarette/dromedary
|
|
desc = "A DromedaryCo brand cigarette. Contrary to popular belief, does not contain Calomel, but is reported to have a watery taste."
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 13, /datum/reagent/water = 5) //camel has water
|
|
|
|
/obj/item/cigarette/uplift
|
|
desc = "An Uplift Smooth brand cigarette. Smells refreshing."
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 13, /datum/reagent/consumable/menthol = 5)
|
|
|
|
/obj/item/cigarette/robust
|
|
desc = "A Robust brand cigarette."
|
|
|
|
/obj/item/cigarette/greytide
|
|
name = "grey mainthol"
|
|
desc = "Made by hand, has a funky smell."
|
|
chem_volume = 60
|
|
lung_harm = 2.5
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/consumable/menthol = 6, /datum/reagent/medicine/oculine = 1)
|
|
/// Weighted list of random reagents to add
|
|
var/static/list/possible_reagents = list(
|
|
/datum/reagent/toxin/fentanyl = 2,
|
|
/datum/reagent/glitter/random = 2,
|
|
/datum/reagent/drug/aranesp = 2,
|
|
/datum/reagent/consumable/laughter = 2,
|
|
/datum/reagent/medicine/insulin = 2,
|
|
/datum/reagent/drug/maint/powder = 2,
|
|
/datum/reagent/drug/maint/sludge = 2,
|
|
/datum/reagent/toxin/staminatoxin = 2,
|
|
/datum/reagent/toxin/leadacetate = 2,
|
|
/datum/reagent/drug/space_drugs = 2,
|
|
/datum/reagent/drug/pumpup = 2,
|
|
/datum/reagent/drug/kronkaine = 2,
|
|
/datum/reagent/consumable/mintextract = 2,
|
|
/datum/reagent/pax = 1,
|
|
)
|
|
|
|
/obj/item/cigarette/greytide/Initialize(mapload)
|
|
. = ..()
|
|
if(prob(40))
|
|
reagents.add_reagent(pick_weight(possible_reagents), rand(10, 15))
|
|
|
|
/obj/item/cigarette/robustgold
|
|
desc = "A Robust Gold brand cigarette."
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/gold = 3) // Just enough to taste a hint of expensive metal.
|
|
|
|
/obj/item/cigarette/carp
|
|
desc = "A Carp Classic brand cigarette. A small label on its side indicates that it does NOT contain carpotoxin."
|
|
|
|
/obj/item/cigarette/carp/Initialize(mapload)
|
|
. = ..()
|
|
if(!prob(5))
|
|
return
|
|
reagents?.add_reagent(/datum/reagent/toxin/carpotoxin , 3) // They lied
|
|
|
|
/obj/item/cigarette/syndicate
|
|
desc = "An unknown brand cigarette."
|
|
chem_volume = 60
|
|
smoketime = 2 MINUTES
|
|
smoke_all = TRUE
|
|
lung_harm = 1.5
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 10, /datum/reagent/medicine/omnizine = 15)
|
|
|
|
/obj/item/cigarette/syndicate/smoke_in_face(mob/living/getting_smoked)
|
|
. = ..()
|
|
getting_smoked.adjust_eye_blur(6 SECONDS)
|
|
getting_smoked.adjust_temp_blindness(2 SECONDS)
|
|
|
|
/obj/item/cigarette/shadyjims
|
|
desc = "A Shady Jim's Super Slims cigarette."
|
|
lung_harm = 1.5
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/toxin/lipolicide = 4, /datum/reagent/ammonia = 2, /datum/reagent/toxin/plantbgone = 1, /datum/reagent/toxin = 1.5)
|
|
|
|
/obj/item/cigarette/xeno
|
|
desc = "A Xeno Filtered brand cigarette."
|
|
lung_harm = 2
|
|
list_reagents = list (/datum/reagent/drug/nicotine = 20, /datum/reagent/medicine/regen_jelly = 15, /datum/reagent/drug/krokodil = 4)
|
|
|
|
// Rollies.
|
|
|
|
/obj/item/cigarette/rollie
|
|
name = "rollie"
|
|
desc = "A roll of dried plant matter wrapped in thin paper."
|
|
icon_state = "spliffoff"
|
|
icon_on = "spliffon"
|
|
icon_off = "spliffoff"
|
|
type_butt = /obj/item/cigbutt/roach
|
|
throw_speed = 0.5
|
|
smoketime = 4 MINUTES
|
|
chem_volume = 50
|
|
list_reagents = null
|
|
choke_time_max = 40 SECONDS
|
|
|
|
/obj/item/cigarette/rollie/Initialize(mapload)
|
|
name = pick(list(
|
|
"bifta",
|
|
"bifter",
|
|
"bird",
|
|
"blunt",
|
|
"bloint",
|
|
"boof",
|
|
"boofer",
|
|
"bomber",
|
|
"bone",
|
|
"bun",
|
|
"doink",
|
|
"doob",
|
|
"doober",
|
|
"doobie",
|
|
"dutch",
|
|
"fatty",
|
|
"hogger",
|
|
"hooter",
|
|
"hootie",
|
|
"\improper J",
|
|
"jay",
|
|
"jimmy",
|
|
"joint",
|
|
"juju",
|
|
"jeebie weebie",
|
|
"number",
|
|
"owl",
|
|
"phattie",
|
|
"puffer",
|
|
"reef",
|
|
"reefer",
|
|
"rollie",
|
|
"scoobie",
|
|
"shorty",
|
|
"spiff",
|
|
"spliff",
|
|
"toke",
|
|
"torpedo",
|
|
"zoot",
|
|
"zooter"))
|
|
. = ..()
|
|
pixel_x = rand(-5, 5)
|
|
pixel_y = rand(-5, 5)
|
|
|
|
/obj/item/cigarette/rollie/nicotine
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 15)
|
|
|
|
/obj/item/cigarette/rollie/trippy
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/drug/mushroomhallucinogen = 35)
|
|
starts_lit = TRUE
|
|
|
|
/obj/item/cigarette/rollie/cannabis
|
|
list_reagents = list(/datum/reagent/drug/cannabis = 15)
|
|
|
|
/obj/item/cigarette/rollie/mindbreaker
|
|
list_reagents = list(/datum/reagent/toxin/mindbreaker = 35, /datum/reagent/toxin/lipolicide = 15)
|
|
|
|
/obj/item/cigarette/candy
|
|
name = "\improper Little Timmy's candy cigarette"
|
|
desc = "For all ages*! Doesn't contain any amount of nicotine. Health and safety risks can be read on the tip of the cigarette."
|
|
smoketime = 2 MINUTES
|
|
icon_state = "candyoff"
|
|
icon_on = "candyon"
|
|
icon_off = "candyoff" //make sure to add positional sprites in icons/obj/cigarettes.dmi if you add more.
|
|
inhand_icon_off = "candyoff"
|
|
type_butt = /obj/item/food/candy_trash
|
|
heat = 473.15 // Lowered so that the sugar can be carmalized, but not burnt.
|
|
lung_harm = 0.5
|
|
list_reagents = list(/datum/reagent/consumable/sugar = 20)
|
|
choke_time_max = 70 SECONDS // This shit really is deadly
|
|
|
|
/obj/item/cigarette/candy/nicotine
|
|
desc = "For all ages*! Doesn't contain any* amount of nicotine. Health and safety risks can be read on the tip of the cigarette."
|
|
type_butt = /obj/item/food/candy_trash/nicotine
|
|
list_reagents = list(/datum/reagent/consumable/sugar = 20, /datum/reagent/drug/nicotine = 20) //oh no!
|
|
smoke_all = TRUE //timmy's not getting out of this one
|
|
|
|
/obj/item/cigbutt/roach
|
|
name = "roach"
|
|
desc = "A manky old roach, or for non-stoners, a used rollup."
|
|
icon_state = "roach"
|
|
|
|
/obj/item/cigbutt/greycigbutt
|
|
name = "butt"
|
|
desc = "It's low tide, now."
|
|
icon_state = "cigbutt"
|
|
|
|
/obj/item/cigbutt/roach/Initialize(mapload)
|
|
. = ..()
|
|
pixel_x = rand(-5, 5)
|
|
pixel_y = rand(-5, 5)
|
|
|
|
|
|
/obj/item/cigarette/dart
|
|
name = "fat dart"
|
|
desc = "Chuff back this fat dart"
|
|
icon_state = "bigon"
|
|
icon_on = "bigon"
|
|
icon_off = "bigoff"
|
|
w_class = WEIGHT_CLASS_BULKY
|
|
smoketime = 18 MINUTES
|
|
chem_volume = 65
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 45)
|
|
choke_time_max = 40 SECONDS
|
|
lung_harm = 2
|
|
|
|
/obj/item/cigarette/dart/Initialize(mapload)
|
|
. = ..()
|
|
//the compiled icon state is how it appears when it's on.
|
|
//That's how we want it to show on orbies (little virtual PDA pets).
|
|
//However we should reset their appearance on runtime.
|
|
update_appearance(UPDATE_ICON_STATE)
|
|
|
|
|
|
////////////
|
|
// CIGARS //
|
|
////////////
|
|
/obj/item/cigarette/cigar
|
|
name = "cigar"
|
|
desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!"
|
|
icon_state = "cigaroff"
|
|
icon_on = "cigaron"
|
|
icon_off = "cigaroff" //make sure to add positional sprites in icons/obj/cigarettes.dmi if you add more.
|
|
inhand_icon_state = "cigaron" //gets overriden during intialize(), just have it for unit test sanity.
|
|
inhand_icon_on = "cigaron"
|
|
inhand_icon_off = "cigaroff"
|
|
type_butt = /obj/item/cigbutt/cigarbutt
|
|
throw_speed = 0.5
|
|
smoketime = 11 MINUTES
|
|
chem_volume = 40
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 25)
|
|
choke_time_max = 40 SECONDS
|
|
|
|
/obj/item/cigarette/cigar/premium
|
|
name = "premium cigar"
|
|
//this is the version that actually spawns in premium cigar cases, the distinction is made so that the smoker quirk can differentiate between the default cigar box and its subtypes
|
|
|
|
/obj/item/cigarette/cigar/cohiba
|
|
name = "\improper Cohiba Robusto cigar"
|
|
desc = "There's little more you could want from a cigar."
|
|
icon_state = "cigar2off"
|
|
icon_on = "cigar2on"
|
|
icon_off = "cigar2off"
|
|
smoketime = 20 MINUTES
|
|
chem_volume = 80
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 40)
|
|
|
|
/obj/item/cigarette/cigar/havana
|
|
name = "premium Havanian cigar"
|
|
desc = "A cigar fit for only the best of the best."
|
|
icon_state = "cigar2off"
|
|
icon_on = "cigar2on"
|
|
icon_off = "cigar2off"
|
|
smoketime = 30 MINUTES
|
|
chem_volume = 60
|
|
list_reagents = list(/datum/reagent/drug/nicotine = 45)
|
|
|
|
/obj/item/cigbutt
|
|
name = "cigarette butt"
|
|
desc = "A manky old cigarette butt."
|
|
icon = 'icons/obj/cigarettes.dmi'
|
|
icon_state = "cigbutt"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
throwforce = 0
|
|
grind_results = list(/datum/reagent/carbon = 2)
|
|
|
|
/obj/item/cigbutt/cigarbutt
|
|
name = "cigar butt"
|
|
desc = "A manky old cigar butt."
|
|
icon_state = "cigarbutt"
|
|
|
|
/////////////////
|
|
//SMOKING PIPES//
|
|
/////////////////
|
|
/obj/item/cigarette/pipe
|
|
name = "smoking pipe"
|
|
desc = "A pipe, for smoking. Probably made of meerschaum or something."
|
|
icon_state = "pipeoff"
|
|
icon_on = "pipeoff" //Note - these are in masks.dmi
|
|
icon_off = "pipeoff"
|
|
inhand_icon_state = null
|
|
inhand_icon_on = null
|
|
inhand_icon_off = null
|
|
smoketime = 0
|
|
chem_volume = 200 // So we can fit densified chemicals plants
|
|
list_reagents = null
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
choke_forever = TRUE
|
|
///name of the stuff packed inside this pipe
|
|
var/packeditem
|
|
|
|
/obj/item/cigarette/pipe/Initialize(mapload)
|
|
. = ..()
|
|
update_appearance(UPDATE_NAME)
|
|
|
|
/obj/item/cigarette/pipe/update_name()
|
|
. = ..()
|
|
name = packeditem ? "[packeditem]-packed [initial(name)]" : "empty [initial(name)]"
|
|
|
|
/obj/item/cigarette/pipe/put_out(mob/user, done_early = FALSE)
|
|
lit = FALSE
|
|
if(done_early)
|
|
user.visible_message(span_notice("[user] puts out [src]."), span_notice("You put out [src]."))
|
|
|
|
else
|
|
if(user)
|
|
to_chat(user, span_notice("Your [name] goes out."))
|
|
packeditem = null
|
|
update_appearance(UPDATE_ICON)
|
|
set_light_on(FALSE)
|
|
STOP_PROCESSING(SSobj, src)
|
|
QDEL_NULL(cig_smoke)
|
|
|
|
/obj/item/cigarette/pipe/attackby(obj/item/thing, mob/user, list/modifiers, list/attack_modifiers)
|
|
if(!(istype(thing, /obj/item/food/grown) || istype(thing, /obj/item/food/drug)))
|
|
return ..()
|
|
|
|
if(packeditem)
|
|
to_chat(user, span_warning("It is already packed!"))
|
|
return
|
|
|
|
var/obj/item/to_smoke = thing
|
|
if(istype(to_smoke, /obj/item/food/grown) && !HAS_TRAIT(to_smoke, TRAIT_DRIED))
|
|
to_chat(user, span_warning("It has to be dried first!"))
|
|
return
|
|
|
|
to_chat(user, span_notice("You stuff [to_smoke] into [src]."))
|
|
smoketime = 13 MINUTES
|
|
packeditem = to_smoke.name
|
|
update_name()
|
|
if(to_smoke.reagents)
|
|
to_smoke.reagents.trans_to(src, to_smoke.reagents.total_volume, transferred_by = user)
|
|
qdel(to_smoke)
|
|
|
|
|
|
/obj/item/cigarette/pipe/attack_self(mob/user)
|
|
var/atom/location = drop_location()
|
|
if(packeditem && !lit)
|
|
to_chat(user, span_notice("You empty [src] onto [location]."))
|
|
new /obj/effect/decal/cleanable/ash(location)
|
|
packeditem = null
|
|
smoketime = 0
|
|
reagents.clear_reagents()
|
|
update_name()
|
|
return
|
|
return ..()
|
|
|
|
/obj/item/cigarette/pipe/cobpipe
|
|
name = "corn cob pipe"
|
|
desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters. Can be loaded with objects."
|
|
icon_state = "cobpipeoff"
|
|
icon_on = "cobpipeoff" //Note - these are in masks.dmi
|
|
icon_off = "cobpipeoff"
|
|
inhand_icon_on = null
|
|
inhand_icon_off = null
|
|
|
|
/obj/item/cigarette/pipe/crackpipe
|
|
name = "glass pipe"
|
|
desc = "An ergonomic, low-key delivery method for the combusted. This apparatus taught the ancients much wisdom."
|
|
icon_state = "crackpipe"
|
|
icon_on = "crackpipeon"
|
|
icon_off = "crackpipe"
|
|
inhand_icon_on = null
|
|
inhand_icon_off = null
|
|
lung_harm = 2
|
|
custom_materials = list(/datum/material/glass = SHEET_MATERIAL_AMOUNT)
|
|
|
|
///////////
|
|
//ROLLING//
|
|
///////////
|
|
/obj/item/rollingpaper
|
|
name = "rolling paper"
|
|
desc = "A thin piece of paper used to make fine smokeables."
|
|
icon = 'icons/obj/cigarettes.dmi'
|
|
icon_state = "cig_paper"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
|
|
/obj/item/rollingpaper/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/ingredients_holder, /obj/item/cigarette/rollie, CUSTOM_INGREDIENT_ICON_NOCHANGE, ingredient_type=CUSTOM_INGREDIENT_TYPE_DRYABLE, max_ingredients=2)
|
|
|
|
|
|
///////////////
|
|
//VAPE NATION//
|
|
///////////////
|
|
/obj/item/vape
|
|
name = "\improper E-Cigarette"
|
|
desc = "A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\""//<<< i'd vape to that.
|
|
icon = 'icons/map_icons/items/_item.dmi'
|
|
icon_state = "/obj/item/vape"
|
|
post_init_icon_state = "vape"
|
|
worn_icon_state = "vape_worn"
|
|
greyscale_config = /datum/greyscale_config/vape
|
|
greyscale_config_worn = /datum/greyscale_config/vape/worn
|
|
greyscale_colors = "#2e2e2e"
|
|
inhand_icon_state = null
|
|
w_class = WEIGHT_CLASS_TINY
|
|
slot_flags = ITEM_SLOT_MASK
|
|
flags_1 = IS_PLAYER_COLORABLE_1
|
|
light_range = 1
|
|
light_color = LIGHT_COLOR_HALOGEN
|
|
light_system = OVERLAY_LIGHT
|
|
light_on = FALSE
|
|
|
|
/// The capacity of the vape.
|
|
var/chem_volume = 100
|
|
/// The amount of time between drags.
|
|
var/dragtime = 8 SECONDS
|
|
/// A cooldown to prevent huffing the vape all at once.
|
|
COOLDOWN_DECLARE(drag_cooldown)
|
|
/// Whether the resevoir is open and we can add reagents.
|
|
var/screw = FALSE
|
|
/// Whether the vape has been overloaded to spread smoke.
|
|
var/super = FALSE
|
|
|
|
/obj/item/vape/Initialize(mapload)
|
|
. = ..()
|
|
create_reagents(chem_volume, NO_REACT)
|
|
reagents.add_reagent(/datum/reagent/drug/nicotine, 50)
|
|
|
|
/obj/item/vape/suicide_act(mob/living/user)
|
|
user.visible_message(span_suicide("[user] is puffin hard on dat vape, [user.p_they()] trying to join the vape life on a whole notha plane!"))//it doesn't give you cancer, it is cancer
|
|
return (TOXLOSS|OXYLOSS)
|
|
|
|
/obj/item/vape/screwdriver_act(mob/living/user, obj/item/tool)
|
|
if(!screw)
|
|
screw = TRUE
|
|
to_chat(user, span_notice("You open the cap on [src]."))
|
|
reagents.flags |= OPENCONTAINER
|
|
if(obj_flags & EMAGGED)
|
|
icon_state = "vapeopen_high"
|
|
set_greyscale(new_config = /datum/greyscale_config/vape/open_high)
|
|
else if(super)
|
|
icon_state = "vapeopen_med"
|
|
set_greyscale(new_config = /datum/greyscale_config/vape/open_med)
|
|
else
|
|
icon_state = "vapeopen_low"
|
|
set_greyscale(new_config = /datum/greyscale_config/vape/open_low)
|
|
else
|
|
screw = FALSE
|
|
to_chat(user, span_notice("You close the cap on [src]."))
|
|
reagents.flags &= ~(OPENCONTAINER)
|
|
icon_state = initial(post_init_icon_state) || initial(icon_state)
|
|
set_greyscale(new_config = initial(greyscale_config))
|
|
|
|
/obj/item/vape/multitool_act(mob/living/user, obj/item/tool)
|
|
. = TRUE
|
|
if(screw && !(obj_flags & EMAGGED))//also kinky
|
|
if(!super)
|
|
super = TRUE
|
|
to_chat(user, span_notice("You increase the voltage of [src]."))
|
|
icon_state = "vapeopen_med"
|
|
set_greyscale(new_config = /datum/greyscale_config/vape/open_med)
|
|
else
|
|
super = FALSE
|
|
to_chat(user, span_notice("You decrease the voltage of [src]."))
|
|
icon_state = "vapeopen_low"
|
|
set_greyscale(new_config = /datum/greyscale_config/vape/open_low)
|
|
|
|
if(screw && (obj_flags & EMAGGED))
|
|
to_chat(user, span_warning("[src] can't be modified!"))
|
|
|
|
/obj/item/vape/emag_act(mob/user, obj/item/card/emag/emag_card) // I WON'T REGRET WRITTING THIS, SURLY.
|
|
|
|
if (!screw)
|
|
balloon_alert(user, "open the cap first!")
|
|
return FALSE
|
|
|
|
if (obj_flags & EMAGGED)
|
|
balloon_alert(user, "already emagged!")
|
|
return FALSE
|
|
|
|
obj_flags |= EMAGGED
|
|
super = FALSE
|
|
balloon_alert(user, "voltage maximized")
|
|
icon_state = "vapeopen_high"
|
|
set_greyscale(new_config = /datum/greyscale_config/vape/open_high)
|
|
var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect
|
|
sp.set_up(5, 1, src)
|
|
sp.start()
|
|
return TRUE
|
|
|
|
/obj/item/vape/attack_self(mob/user)
|
|
if(!screw)
|
|
balloon_alert(user, "open the cap first!")
|
|
return
|
|
if(reagents.total_volume > 0)
|
|
to_chat(user, span_notice("You empty [src] of all reagents."))
|
|
reagents.clear_reagents()
|
|
|
|
/obj/item/vape/equipped(mob/user, slot)
|
|
. = ..()
|
|
if(!(slot & ITEM_SLOT_MASK))
|
|
return
|
|
|
|
if(screw)
|
|
to_chat(user, span_warning("You need to close the cap first!"))
|
|
return
|
|
|
|
to_chat(user, span_notice("You start puffing on the vape."))
|
|
reagents.flags &= ~(NO_REACT)
|
|
START_PROCESSING(SSobj, src)
|
|
set_light_on(TRUE)
|
|
|
|
/obj/item/vape/dropped(mob/user)
|
|
. = ..()
|
|
if(user.get_item_by_slot(ITEM_SLOT_MASK) == src)
|
|
reagents.flags |= NO_REACT
|
|
STOP_PROCESSING(SSobj, src)
|
|
set_light_on(FALSE)
|
|
|
|
/obj/item/vape/proc/handle_reagents()
|
|
if(!reagents.total_volume)
|
|
return
|
|
|
|
var/mob/living/carbon/vaper = loc
|
|
if(!iscarbon(vaper) || src != vaper.wear_mask)
|
|
reagents.remove_all(REAGENTS_METABOLISM)
|
|
return
|
|
|
|
if(reagents.get_reagent_amount(/datum/reagent/fuel))
|
|
//HOT STUFF
|
|
vaper.adjust_fire_stacks(2)
|
|
vaper.ignite_mob()
|
|
|
|
if(reagents.get_reagent_amount(/datum/reagent/toxin/plasma)) // the plasma explodes when exposed to fire
|
|
var/datum/effect_system/reagents_explosion/e = new()
|
|
e.set_up(round(reagents.get_reagent_amount(/datum/reagent/toxin/plasma) / 2.5, 1), get_turf(src), 0, 0)
|
|
e.start(src)
|
|
qdel(src)
|
|
|
|
if(!reagents.trans_to(vaper, REAGENTS_METABOLISM, methods = INHALE, ignore_stomach = TRUE))
|
|
reagents.remove_all(REAGENTS_METABOLISM)
|
|
|
|
/obj/item/vape/process(seconds_per_tick)
|
|
var/mob/living/M = loc
|
|
|
|
if(isliving(loc))
|
|
M.ignite_mob()
|
|
|
|
if(!reagents.total_volume)
|
|
if(ismob(loc))
|
|
to_chat(M, span_warning("[src] is empty!"))
|
|
STOP_PROCESSING(SSobj, src)
|
|
//it's reusable so it won't unequip when empty
|
|
return
|
|
|
|
if(!COOLDOWN_FINISHED(src, drag_cooldown))
|
|
return
|
|
|
|
//Time to start puffing those fat vapes, yo.
|
|
COOLDOWN_START(src, drag_cooldown, dragtime)
|
|
if(obj_flags & EMAGGED)
|
|
var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new
|
|
puff.set_up(4, holder = src, location = loc, carry = reagents, efficiency = 24)
|
|
puff.start()
|
|
if(prob(5)) //small chance for the vape to break and deal damage if it's emagged
|
|
playsound(get_turf(src), 'sound/effects/pop_expl.ogg', 50, FALSE)
|
|
M.apply_damage(20, BURN, BODY_ZONE_HEAD)
|
|
M.Paralyze(300)
|
|
var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread
|
|
sp.set_up(5, 1, src)
|
|
sp.start()
|
|
to_chat(M, span_userdanger("[src] suddenly explodes in your mouth!"))
|
|
qdel(src)
|
|
return
|
|
else if(super)
|
|
var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new
|
|
puff.set_up(1, holder = src, location = loc, carry = reagents, efficiency = 24)
|
|
puff.start()
|
|
|
|
handle_reagents()
|
|
|
|
/obj/item/vape/red
|
|
icon_state = "/obj/item/vape/red"
|
|
greyscale_colors = "#A02525"
|
|
flags_1 = NONE
|
|
|
|
/obj/item/vape/blue
|
|
icon_state = "/obj/item/vape/blue"
|
|
greyscale_colors = "#294A98"
|
|
flags_1 = NONE
|
|
|
|
/obj/item/vape/purple
|
|
icon_state = "/obj/item/vape/purple"
|
|
greyscale_colors = "#9900CC"
|
|
flags_1 = NONE
|
|
|
|
/obj/item/vape/green
|
|
icon_state = "/obj/item/vape/green"
|
|
greyscale_colors = "#3D9829"
|
|
flags_1 = NONE
|
|
|
|
/obj/item/vape/yellow
|
|
icon_state = "/obj/item/vape/yellow"
|
|
greyscale_colors = "#DAC20E"
|
|
flags_1 = NONE
|
|
|
|
/obj/item/vape/orange
|
|
icon_state = "/obj/item/vape/orange"
|
|
greyscale_colors = "#da930e"
|
|
flags_1 = NONE
|
|
|
|
/obj/item/vape/black
|
|
greyscale_colors = "#2e2e2e"
|
|
flags_1 = NO_NEW_GAGS_PREVIEW_1 // same color as basetype
|
|
|
|
/obj/item/vape/white
|
|
icon_state = "/obj/item/vape/white"
|
|
greyscale_colors = "#DCDCDC"
|
|
flags_1 = NONE
|