diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index c3ca91192c98b..333473ed9770c 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -994,3 +994,36 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
/obj/item/proc/should_stack_with(obj/item/other)
return type == other.type && name == other.name
+
+/**
+ * Handles the bulk of cigarette lighting interactions. You must call `light()` to actually light the cigarette.
+ *
+ * Returns: the target's cigarette (or the cigarette itself if attacked directly) if all checks are passed.
+ * If the cigarette is already lit, or is a fancy smokable being lit by anything other than a zippo or match, will return `FALSE`.
+ * Otherwise it will return `null`.
+ * Arguments:
+ * * user - The mob trying to light the cigarette.
+ * * target - The mob with the cigarette.
+ * * direct_attackby_item - Used if the cigarette item is clicked on directly with a lighter instead of a mob wearing a cigarette.
+ */
+/obj/item/proc/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ if(!user || !target)
+ return null
+
+ var/obj/item/clothing/mask/cigarette/cig = direct_attackby_item ? direct_attackby_item : target.wear_mask
+ if(!istype(cig))
+ return null
+
+ if(user.zone_selected != "mouth" || !user.a_intent == INTENT_HELP)
+ return null
+
+ if(cig.lit)
+ to_chat(user, "[cig] is already lit!")
+ return FALSE
+
+ // Only matches and cigars can light fancy smokables.
+ if(cig.fancy && !istype(src, /obj/item/match) && !istype(src, /obj/item/lighter/zippo))
+ to_chat(user, "[cig] straight out REFUSES to be lit by such uncivilized means!")
+ return FALSE
+
+ return cig
diff --git a/code/game/objects/items/robot/cyborg_gripper.dm b/code/game/objects/items/robot/cyborg_gripper.dm
index fed267133598e..ac58fc2fe3ce9 100644
--- a/code/game/objects/items/robot/cyborg_gripper.dm
+++ b/code/game/objects/items/robot/cyborg_gripper.dm
@@ -324,7 +324,8 @@
/obj/item/coin,
/obj/item/paper,
/obj/item/photo,
- /obj/item/toy/plushie
+ /obj/item/toy/plushie,
+ /obj/item/clothing/mask/cigarette
)
// Mining Gripper
diff --git a/code/game/objects/items/tools/welder.dm b/code/game/objects/items/tools/welder.dm
index 891223a9efe81..40edd403aafff 100644
--- a/code/game/objects/items/tools/welder.dm
+++ b/code/game/objects/items/tools/welder.dm
@@ -153,19 +153,31 @@
return
remove_fuel(0.5)
-/obj/item/weldingtool/attack(mob/living/carbon/M, mob/living/carbon/user)
- // For lighting other people's cigarettes.
- var/obj/item/clothing/mask/cigarette/cig = M?.wear_mask
- if(!istype(cig) || user.zone_selected != "mouth" || !tool_enabled)
+/obj/item/weldingtool/attack(mob/living/target, mob/living/user)
+ if(!cigarette_lighter_act(user, target))
return ..()
- if(M == user)
- cig.attackby(src, user)
- return
+/obj/item/weldingtool/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!tool_enabled)
+ to_chat(user, "You need to activate [src] before you can light anything with it!")
+ return TRUE
- cig.light("[user] holds out [src] out for [M], and casually lights [cig]. What a badass.")
- playsound(src, 'sound/items/lighter/light.ogg', 25, TRUE)
- M.update_inv_wear_mask()
+ if(target == user)
+ user.visible_message(
+ "[user] casually lights [cig] with [src], what a badass.",
+ "You light [cig] with [src]."
+ )
+ else
+ user.visible_message(
+ "[user] holds out [src] out for [target], and casually lights [cig]. What a badass.",
+ "You light [cig] for [target] with [src]."
+ )
+ cig.light(user, target)
+ return TRUE
/obj/item/weldingtool/use_tool(atom/target, user, delay, amount, volume, datum/callback/extra_checks)
target.add_overlay(GLOB.welding_sparks)
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index fcf93613fe061..b50ff4b90e8b6 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -211,7 +211,7 @@
..()
if(istype(W, /obj/item/toy/sword))
if(W == src)
- to_chat(user, "You try to attach the end of the plastic sword to... itself. You're not very smart, are you?")
+ to_chat(user, "You try to attach the end of the plastic sword to... Itself. You're not very smart, are you?")
if(ishuman(user))
user.adjustBrainLoss(10)
else if((W.flags & NODROP) || (flags & NODROP))
@@ -229,10 +229,64 @@
/// Sets to TRUE once the character using it hits something and realises it's not a real energy sword
var/pranked = FALSE
+/obj/item/toy/sword/attack(mob/target, mob/living/user)
+ if(!cigarette_lighter_act(user, target))
+ return ..()
+
+/obj/item/toy/sword/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!active)
+ to_chat(user, "You must activate [src] before you can light [cig] with it!")
+ return TRUE
+
+ user.do_attack_animation(target)
+
+ // 1% chance to light the cig. Somehow...
+ if(prob(1))
+ if(target == user)
+ user.visible_message(
+ "[user] makes a violent slashing motion, barely missing [user.p_their()] nose as light flashes! \
+ [user.p_they(TRUE)] light[user.p_s()] [user.p_their()] [cig] with [src] in the process. Somehow...",
+ "You casually slash [src] at [cig], lighting it with the blade. Somehow...",
+ "You hear an energy blade slashing something!"
+ )
+ else
+ user.visible_message(
+ "[user] makes a violent slashing motion, barely missing the nose of [target] as light flashes! \
+ [user.p_they(TRUE)] light[user.p_s()] [cig] in the mouth of [target] with [src] in the process. Somehow...",
+ "You casually slash [src] at [cig] in the mouth of [target], lighting it with the blade. Somehow...",
+ "You hear an energy blade slashing something!"
+ )
+ playsound(user.loc, 'sound/weapons/blade1.ogg', 50, TRUE)
+ cig.light(user, target)
+ return TRUE
+
+ // Else, bat it out of the target's mouth.
+ if(target == user)
+ user.visible_message(
+ "[user] makes a violent slashing motion, barely missing [user.p_their()] nose as light flashes! \
+ [user.p_they(TRUE)] instead hit [cig], knocking it out of [user.p_their()] mouth and dropping it to the floor.",
+ "You casually slash [src] at [cig], swatting it out of your mouth.",
+ "You hear a gentle tapping."
+ )
+ else
+ user.visible_message(
+ "[user] makes a violent slashing motion, barely missing the nose of [target] as light flashes! \
+ [user] does hit [cig], knocking it out of the mouth of [target] and dropping it to the floor. Wow, rude!",
+ "You casually slash [src] at [cig] in the mouth of [target], swatting it to the floor!",
+ "You hear a gentle tapping."
+ )
+ playsound(loc, 'sound/weapons/tap.ogg', vary = TRUE)
+ target.unEquip(cig, TRUE)
+ return TRUE
+
/obj/item/toy/sword/chaosprank/afterattack(mob/living/target, mob/living/user, proximity)
..()
if(!pranked)
- to_chat(user, "Oh... it's a fake.")
+ to_chat(user, "Oh... It's a fake.")
name = "toy sword"
pranked = TRUE
@@ -241,7 +295,7 @@
*/
/obj/item/dualsaber/toy
name = "double-bladed toy sword"
- desc = "A cheap, plastic replica of TWO energy swords. Double the fun!"
+ desc = "A cheap, plastic replica of TWO energy swords. Double the fun!"
force = 0
throwforce = 0
throw_speed = 3
@@ -280,7 +334,10 @@
hitsound = 'sound/weapons/bladeslice.ogg'
/obj/item/toy/katana/suicide_act(mob/user)
- var/dmsg = pick("[user] tries to stab \the [src] into [user.p_their()] abdomen, but it shatters! [user.p_they(TRUE)] look[user.p_s()] as if [user.p_they()] might die from the shame.","[user] tries to stab \the [src] into [user.p_their()] abdomen, but \the [src] bends and breaks in half! [user.p_they(TRUE)] look[user.p_s()] as if [user.p_they()] might die from the shame.","[user] tries to slice [user.p_their()] own throat, but the plastic blade has no sharpness, causing [user.p_them()] to lose [user.p_their()] balance, slip over, and break [user.p_their()] neck with a loud snap!")
+ var/dmsg = pick(
+ "[user] tries to stab [src] into [user.p_their()] abdomen, but it shatters! [user.p_they(TRUE)] look[user.p_s()] as if [user.p_they()] might die from the shame.",
+ "[user] tries to stab [src] into [user.p_their()] abdomen, but [src] bends and breaks in half! [user.p_they(TRUE)] look[user.p_s()] as if [user.p_they()] might die from the shame.",
+ "[user] tries to slice [user.p_their()] own throat, but the plastic blade has no sharpness, causing [user.p_them()] to lose [user.p_their()] balance, slip over, and break [user.p_their()] neck with a loud snap!")
user.visible_message("[dmsg] It looks like [user.p_theyre()] trying to commit suicide!")
return BRUTELOSS
diff --git a/code/game/objects/items/weapons/cigs.dm b/code/game/objects/items/weapons/cigs.dm
index 085c66cbab3a7..5680009ec55ac 100644
--- a/code/game/objects/items/weapons/cigs.dm
+++ b/code/game/objects/items/weapons/cigs.dm
@@ -1,11 +1,12 @@
#define REAGENT_TIME_RATIO 2.5
/*
-CONTAINS:
-CIGARETTES
-CIGARS
-SMOKING PIPES
-HOLO-CIGAR
+CONTENTS:
+1. CIGARETTES
+2. CIGARS
+3. HOLO-CIGAR
+4. PIPES
+5. ROLLING
CIGARETTE PACKETS ARE IN FANCY.DM
LIGHTERS ARE IN LIGHTERS.DM
@@ -19,22 +20,31 @@ LIGHTERS ARE IN LIGHTERS.DM
name = "cigarette"
desc = "A roll of tobacco and nicotine."
icon_state = "cigoff"
- throw_speed = 0.5
item_state = "cigoff"
+ throw_speed = 0.5
slot_flags = SLOT_FLAG_MASK
w_class = WEIGHT_CLASS_TINY
body_parts_covered = null
attack_verb = null
container_type = INJECTABLE
+ /// Is the cigarette lit?
var/lit = FALSE
+ /// Lit cigarette sprite.
var/icon_on = "cigon" //Note - these are in masks.dmi not in cigarette.dmi
+ /// Unlit cigarette sprite.
var/icon_off = "cigoff"
+ /// Are we an extra-classy smokable?
+ var/fancy = FALSE
+ /// What trash item the cigarette makes when it burns out.
var/type_butt = /obj/item/cigbutt
- var/lastHolder = null
- var/smoketime = 150
+ /// How long does the cigarette last before going out? Decrements by 1 every cycle.
+ var/smoketime = 150 // 300 seconds.
+ /// The cigarette's total reagent capacity.
var/chem_volume = 60
+ /// A list of the types and amounts of reagents in the cigarette.
var/list/list_reagents = list("nicotine" = 40)
- var/first_puff = TRUE // the first puff is a bit more reagents ingested
+ /// Has anyone taken any reagents from the cigarette? The first tick gives a bigger dose.
+ var/first_puff = TRUE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/mask.dmi',
"Unathi" = 'icons/mob/clothing/species/unathi/mask.dmi',
@@ -42,14 +52,6 @@ LIGHTERS ARE IN LIGHTERS.DM
"Vulpkanin" = 'icons/mob/clothing/species/vulpkanin/mask.dmi',
"Grey" = 'icons/mob/clothing/species/grey/mask.dmi')
- var/static/things_that_light = typecacheof(list(
- /obj/item/lighter,
- /obj/item/match,
- /obj/item/melee/energy/sword/saber,
- /obj/item/assembly/igniter,
- /obj/item/gun/magic/wand/fireball))
-
-
/obj/item/clothing/mask/cigarette/Initialize(mapload)
. = ..()
create_reagents(chem_volume) // making the cigarrete a chemical holder with a maximum volume of 30
@@ -57,19 +59,12 @@ LIGHTERS ARE IN LIGHTERS.DM
if(list_reagents)
reagents.add_reagent_list(list_reagents)
smoketime = reagents.total_volume * 2.5
- RegisterSignal(src, COMSIG_ITEM_BEING_ATTACKED, PROC_REF(try_light))
/obj/item/clothing/mask/cigarette/Destroy()
QDEL_NULL(reagents)
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/item/clothing/mask/cigarette/proc/try_light(obj/item/cigarette, obj/item/lighting_item)
- SIGNAL_HANDLER
- if(lighting_item.get_heat())
- light()
- return COMPONENT_CANCEL_ATTACK_CHAIN
-
/obj/item/clothing/mask/cigarette/decompile_act(obj/item/matter_decompiler/C, mob/user)
if(isdrone(user))
C.stored_comms["wood"] += 1
@@ -81,17 +76,74 @@ LIGHTERS ARE IN LIGHTERS.DM
if(istype(M) && M.on_fire)
user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(M)
- light("[user] coldly lights [src] with the burning body of [M]. Clearly, [user.p_they()] offer[user.p_s()] the warmest of regards...")
+ if(M != user)
+ user.visible_message(
+ "[user] coldly lights [src] with the burning body of [M]. Clearly, [user.p_they()] offer[user.p_s()] the warmest of regards...",
+ "You coldly light [src] with the burning body of [M]."
+ )
+ else
+ // The fire will light it in your hands by itself, but if you whip out the cig and click yourself fast enough, this will happen. TRULY you have your priorities stright.
+ user.visible_message(
+ "[user] quickly whips out [src] and nonchalantly lights it with [user.p_their()] own burning body. Clearly, [user.p_they()] [user.p_have()] [user.p_their()] priorities straight.",
+ "You quickly whip out [src] and nonchalantly light it with your own burning body. Clearly, you have your priorities straight."
+ )
+ light(user, user)
return TRUE
- else
- return ..()
+
+/obj/item/clothing/mask/cigarette/afterattack(atom/target, mob/living/user, proximity)
+ if(!proximity)
+ return
+
+ if(ismob(target))
+ // If the target has no cig, try to give them the cig.
+ var/mob/living/carbon/M = target
+ if(istype(M) && user.zone_selected == "mouth" && !M.wear_mask && user.a_intent == INTENT_HELP)
+ user.unEquip(src, TRUE)
+ M.equip_to_slot_if_possible(src, SLOT_HUD_WEAR_MASK)
+ if(target != user)
+ user.visible_message(
+ "[user] slips \a [name] into the mouth of [M].",
+ "You slip [src] into the mouth of [M]."
+ )
+ else
+ to_chat(user, "You put [src] into your mouth.")
+ return TRUE
+
+ // If they DO have a cig, try to light it with your own cig.
+ if(!cigarette_lighter_act(user, M))
+ return ..()
+
+ // You can dip cigarettes into beakers.
+ if(istype(target, /obj/item/reagent_containers/glass))
+ var/obj/item/reagent_containers/glass/glass = target
+ var/transfered = glass.reagents.trans_to(src, chem_volume)
+ if(transfered)
+ to_chat(user, "You dip [src] into [glass].")
+ return
+
+ // Either the beaker was empty, or the cigarette was full
+ if(!glass.reagents.total_volume)
+ to_chat(user, "[glass] is empty.")
+ else
+ to_chat(user, "[src] is full.")
+
+ return ..()
+
+/obj/item/clothing/mask/cigarette/attack_self(mob/user)
+ if(lit)
+ user.visible_message(
+ "[user] calmly drops and treads on [src], putting it out instantly.",
+ "You calmly drop and tread on [src], putting it out instantly.",
+ "You hear a foot being brought down on something, and the tiny fizzling of an ember going out."
+ )
+ die()
+ return ..()
/obj/item/clothing/mask/cigarette/can_enter_storage(obj/item/storage/S, mob/user)
if(lit)
- to_chat(user, "[S] can't hold [initial(name)] while it's lit!") // initial(name) so it doesn't say "lit" twice in a row
+ to_chat(user, "[S] can't hold \the [initial(name)] while it's lit!") // initial(name) so it doesn't say "lit" twice in a row
return FALSE
- else
- return TRUE
+ return TRUE
/obj/item/clothing/mask/cigarette/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
..()
@@ -101,116 +153,95 @@ LIGHTERS ARE IN LIGHTERS.DM
if(!lit)
light("[src] is lit by the flames!")
-/obj/item/clothing/mask/cigarette/welder_act(mob/user, obj/item/I)
- . = TRUE
- if(I.tool_use_check(user, 0)) //Don't need to flash eyes because you are a badass
- light("[user] casually lights [src] with [I], what a badass.")
+/obj/item/clothing/mask/cigarette/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
-/obj/item/clothing/mask/cigarette/attackby(obj/item/I, mob/user, params)
- ..()
- if(istype(I, /obj/item/lighter/zippo))
- var/obj/item/lighter/zippo/Z = I
- if(Z.lit)
- light("With a single flick of [user.p_their()] wrist, [user] smoothly lights [user.p_their()] [name] with [user.p_their()] [Z]. Damn [user.p_theyre()] cool.")
-
- else if(istype(I, /obj/item/lighter))
- var/obj/item/lighter/L = I
- if(L.lit)
- light("After some fiddling, [user] manages to light [user.p_their()] [name] with [L].")
-
- else if(istype(I, /obj/item/match/unathi))
- var/obj/item/match/unathi/U = I
- if(U.lit)
- playsound(user.loc, 'sound/effects/unathiignite.ogg', 40, FALSE)
- light("[user] spits fire at [user.p_their()] [name], igniting it.")
- U.matchburnout()
-
- else if(istype(I, /obj/item/match))
- var/obj/item/match/M = I
- if(M.lit)
- light("[user] lights [user.p_their()] [name] with [user.p_their()] [M].")
-
- else if(istype(I, /obj/item/melee/energy/sword/saber))
- var/obj/item/melee/energy/sword/saber/S = I
- if(HAS_TRAIT(S, TRAIT_ITEM_ACTIVE))
- light("[user] makes a violent slashing motion, barely missing [user.p_their()] nose as light flashes. [user.p_they(TRUE)] light[user.p_s()] [user.p_their()] [name] with [S] in the process.")
-
- else if(istype(I, /obj/item/assembly/igniter))
- light("[user] fiddles with [I], and manages to light [user.p_their()] [name].")
-
- else if(istype(I, /obj/item/gun/magic/wand/fireball))
- var/obj/item/gun/magic/wand/fireball/F = I
- if(F.charges)
- if(prob(50) || user.mind.assigned_role == "Wizard")
- light("Holy shit, did [user] just manage to light [user.p_their()] [name] with [F], with only moderate eyebrow singing?")
- else
- to_chat(user, "Unsure which end of the wand is which, [user] fails to light [name] with [F].")
- explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2)
- F.charges--
+ if(!lit)
+ to_chat(user, "You cannot light [cig] with [src] because you need a lighter to light [src] before you can use [src] as a lighter to light [cig]... This seems a little convoluted.")
+ return TRUE
- //can't think of any other way to update the overlays :<
- user.update_inv_wear_mask()
- user.update_inv_l_hand()
- user.update_inv_r_hand()
+ if(target == user)
+ user.visible_message(
+ "[user] presses [src] against [cig] until it lights. Seems oddly recursive...",
+ "You press [src] against [cig] until it lights. Seems oddly recursive..."
+ )
+ else
+ user.visible_message(
+ "[user] presses [src] until it lights. Sharing is caring!",
+ "You press [src] against [cig] until it lights. Sharing is caring!"
+ )
+ cig.light(user, target)
+ return TRUE
+
+/obj/item/clothing/mask/cigarette/attackby(obj/item/I, mob/living/user, params)
+ if(I.cigarette_lighter_act(user, user, src))
+ return
+ // Catch any item that has no cigarette_lighter_act but logically should be able to work as a lighter due to being hot.
+ if(I.get_heat())
+ //Give a generic light message.
+ user.visible_message(
+ "[user] lights [src] with [I]",
+ "You light [src] with [I]."
+ )
+ light(user)
-/obj/item/clothing/mask/cigarette/afterattack(obj/item/reagent_containers/glass/glass, mob/user, proximity)
- ..()
- if(!proximity)
+/obj/item/clothing/mask/cigarette/proc/light(mob/living/user, mob/living/target)
+ if(lit)
return
- if(istype(glass)) //you can dip cigarettes into beakers
- var/transfered = glass.reagents.trans_to(src, chem_volume)
- if(transfered) //if reagents were transfered, show the message
- smoketime = reagents.total_volume * 2.5
- to_chat(user, "You dip \the [src] into \the [glass].")
- else //if not, either the beaker was empty, or the cigarette was full
- if(!glass.reagents.total_volume)
- to_chat(user, "[glass] is empty.")
- else
- to_chat(user, "[src] is full.")
+ lit = TRUE
+ name = "lit [name]"
+ attack_verb = list("burnt", "singed")
+ hitsound = 'sound/items/welder.ogg'
+ damtype = BURN
+ force = 4
+ var/mob/M = loc
+
+ // Plasma explodes when exposed to fire.
+ if(reagents.get_reagent_amount("plasma"))
+ var/datum/effect_system/reagents_explosion/e = new()
+ e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0)
+ e.start()
+ if(ismob(M))
+ M.unEquip(src, TRUE)
+ qdel(src)
+ return
-/obj/item/clothing/mask/cigarette/proc/light(flavor_text = null)
- if(!lit)
- lit = TRUE
- name = "lit [name]"
- attack_verb = list("burnt", "singed")
- hitsound = 'sound/items/welder.ogg'
- damtype = "fire"
- force = 4
- if(reagents.get_reagent_amount("plasma")) // the plasma explodes when exposed to fire
- var/datum/effect_system/reagents_explosion/e = new()
- e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0)
- e.start()
- if(ismob(loc))
- var/mob/M = loc
- M.unEquip(src, 1)
- qdel(src)
- return
- if(reagents.get_reagent_amount("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("fuel") / 5, 1), get_turf(src), 0, 0)
- e.start()
- if(ismob(loc))
- var/mob/M = loc
- M.unEquip(src, 1)
- qdel(src)
- return
- reagents.set_reacting(TRUE)
- reagents.handle_reactions()
- icon_state = icon_on
- item_state = icon_on
- if(flavor_text)
- var/turf/T = get_turf(src)
- T.visible_message(flavor_text)
- if(iscarbon(loc))
- var/mob/living/carbon/C = loc
- if(C.wear_mask == src) // Don't update if it's just in their hand
- C.wear_mask_update(src)
- set_light(2, 0.25, "#E38F46")
- START_PROCESSING(SSobj, src)
- playsound(src, 'sound/items/lighter/light.ogg', 25, TRUE)
+ // Fuel explodes, too, but much less violently.
+ if(reagents.get_reagent_amount("fuel"))
+ var/datum/effect_system/reagents_explosion/e = new()
+ e.set_up(round(reagents.get_reagent_amount("fuel") / 5, 1), get_turf(src), 0, 0)
+ e.start()
+ if(ismob(M))
+ M.unEquip(src, TRUE)
+ qdel(src)
+ return
+
+ // If there is no target, the user is probably lighting their own cig.
+ if(isnull(target))
+ target = user
+ // If there is also no user, the cig is being lit by atmos or something.
+ if(target)
+ target.update_inv_wear_mask()
+ target.update_inv_l_hand()
+ target.update_inv_r_hand()
+
+ reagents.set_reacting(TRUE)
+ reagents.handle_reactions()
+ icon_state = icon_on
+ item_state = icon_on
+ if(iscarbon(loc))
+ var/mob/living/carbon/C = loc
+ if(C.wear_mask == src) // Don't update if it's just in their hand
+ C.wear_mask_update(src)
+ set_light(2, 0.25, "#E38F46")
+ START_PROCESSING(SSobj, src)
+ playsound(src, 'sound/items/lighter/light.ogg', 25, TRUE)
+ return TRUE
/obj/item/clothing/mask/cigarette/process()
var/mob/living/M = loc
@@ -222,18 +253,11 @@ LIGHTERS ARE IN LIGHTERS.DM
return
smoke()
-
/obj/item/clothing/mask/cigarette/extinguish_light(force)
if(!force)
return
die()
-/obj/item/clothing/mask/cigarette/attack_self(mob/user)
- if(lit)
- user.visible_message("[user] calmly drops and treads on [src], putting it out instantly.")
- die()
- return ..()
-
/obj/item/clothing/mask/cigarette/proc/smoke()
var/turf/location = get_turf(src)
var/is_being_smoked = FALSE
@@ -264,16 +288,16 @@ LIGHTERS ARE IN LIGHTERS.DM
if(ismob(loc))
var/mob/living/M = loc
to_chat(M, "Your [name] goes out.")
- M.unEquip(src, 1) //Force the un-equip so the overlays update
+ M.unEquip(src, TRUE) //Force the un-equip so the overlays update
STOP_PROCESSING(SSobj, src)
qdel(src)
/obj/item/clothing/mask/cigarette/get_heat()
return lit * 1000
-/obj/item/clothing/mask/cigarette/proc/can_light_fancy(obj/item/lighting_item)
- return (istype(lighting_item, /obj/item/match) || istype(lighting_item, /obj/item/lighter/zippo))
-
+//////////////////////////////
+// MARK: CIGARETTES
+//////////////////////////////
/obj/item/clothing/mask/cigarette/menthol
list_reagents = list("nicotine" = 40, "menthol" = 20)
@@ -314,6 +338,26 @@ LIGHTERS ARE IN LIGHTERS.DM
/obj/item/clothing/mask/cigarette/rollie/custom
list_reagents = list()
+/obj/item/cigbutt
+ name = "cigarette butt"
+ desc = "A manky old cigarette butt."
+ icon = 'icons/obj/clothing/masks.dmi'
+ icon_state = "cigbutt"
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 1
+
+/obj/item/cigbutt/Initialize(mapload)
+ . = ..()
+ pixel_x = rand(-10, 10)
+ pixel_y = rand(-10, 10)
+ transform = turn(transform, rand(0, 360))
+
+/obj/item/cigbutt/decompile_act(obj/item/matter_decompiler/C, mob/user)
+ if(isdrone(user))
+ C.stored_comms["wood"] += 1
+ qdel(src)
+ return TRUE
+ return ..()
/obj/item/cigbutt/roach
name = "roach"
@@ -325,27 +369,59 @@ LIGHTERS ARE IN LIGHTERS.DM
pixel_x = rand(-5, 5)
pixel_y = rand(-5, 5)
-////////////
-// CIGARS //
-////////////
+//////////////////////////////
+// MARK: 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/afterattack(atom/target, mob/user, proximity)
+ if(!proximity)
+ return
+
+ if(!istype(target, /obj/item/food/grown))
+ return ..()
+
+ var/obj/item/food/grown/plant = target
+ if(!plant.dry)
+ to_chat(user, "You need to dry this first!")
+ return
+ user.unEquip(plant, TRUE)
+ user.unEquip(src, TRUE)
+ var/obj/item/clothing/mask/cigarette/rollie/custom/custom_rollie = new (get_turf(user))
+ custom_rollie.reagents.maximum_volume = plant.reagents.total_volume
+ plant.reagents.trans_to(custom_rollie, plant.reagents.total_volume)
+ custom_rollie.smoketime = custom_rollie.reagents.total_volume * 2.5
+
+ user.put_in_active_hand(custom_rollie)
+ to_chat(user, "You roll the [plant.name] into a rolling paper.")
+ custom_rollie.desc = "Dried [plant.name] rolled up in a thin piece of paper."
+
+ qdel(plant)
+ qdel(src)
+
+//////////////////////////////
+// MARK: CIGARS
+//////////////////////////////
/obj/item/clothing/mask/cigarette/cigar
name = "\improper Premium Cigar"
desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!"
icon_state = "cigaroff"
+ item_state = "cigaroff"
icon_on = "cigaron"
icon_off = "cigaroff"
- type_butt = /obj/item/cigbutt/cigarbutt
throw_speed = 0.5
- item_state = "cigaroff"
+ fancy = TRUE
+ type_butt = /obj/item/cigbutt/cigarbutt
smoketime = 300
chem_volume = 120
list_reagents = list("nicotine" = 120)
-/obj/item/clothing/mask/cigarette/cigar/try_light(obj/item/cigar, obj/item/lighting_item)
- if(can_light_fancy(lighting_item))
- return ..()
-
/obj/item/clothing/mask/cigarette/cigar/cohiba
name = "\improper Cohiba Robusto Cigar"
desc = "There's little more you could want from a cigar."
@@ -363,45 +439,19 @@ LIGHTERS ARE IN LIGHTERS.DM
chem_volume = 180
list_reagents = list("nicotine" = 180)
-/obj/item/cigbutt
- name = "cigarette butt"
- desc = "A manky old cigarette butt."
- icon = 'icons/obj/clothing/masks.dmi'
- icon_state = "cigbutt"
- w_class = WEIGHT_CLASS_TINY
- throwforce = 1
-
-/obj/item/cigbutt/Initialize(mapload)
- . = ..()
- pixel_x = rand(-10,10)
- pixel_y = rand(-10,10)
- transform = turn(transform,rand(0,360))
-
-/obj/item/cigbutt/decompile_act(obj/item/matter_decompiler/C, mob/user)
- if(isdrone(user))
- C.stored_comms["wood"] += 1
- qdel(src)
- return TRUE
- return ..()
-
/obj/item/cigbutt/cigarbutt
name = "cigar butt"
desc = "A manky old cigar butt."
icon_state = "cigarbutt"
-
-/obj/item/clothing/mask/cigarette/cigar/attackby(obj/item/I, mob/user, params)
- if(!is_type_in_typecache(I, things_that_light))
- return
- if(can_light_fancy(I))
- ..()
- else
- to_chat(user, "[src] straight out REFUSES to be lit by such uncivilized means.")
-
+//////////////////////////////
+// MARK: HOLO-CIGAR
+//////////////////////////////
/obj/item/clothing/mask/holo_cigar
name = "Holo-Cigar"
desc = "A sleek electronic cigar imported straight from Sol. You feel badass merely glimpsing it..."
icon_state = "holocigaroff"
+ /// Is the holo-cigar lit?
var/enabled = FALSE
/// Tracks if this is the first cycle smoking the cigar.
var/has_smoked = FALSE
@@ -462,10 +512,9 @@ LIGHTERS ARE IN LIGHTERS.DM
update_appearance(UPDATE_ICON_STATE)
-/////////////////
-//SMOKING PIPES//
-/////////////////
-
+//////////////////////////////
+// MARK: PIPES
+//////////////////////////////
/obj/item/clothing/mask/cigarette/pipe
name = "smoking pipe"
desc = "A pipe, for smoking. Probably made of meershaum or something."
@@ -473,6 +522,7 @@ LIGHTERS ARE IN LIGHTERS.DM
item_state = "pipeoff"
icon_on = "pipeon" //Note - these are in masks.dmi
icon_off = "pipeoff"
+ fancy = TRUE
smoketime = 500
chem_volume = 200
list_reagents = list("nicotine" = 200)
@@ -480,15 +530,12 @@ LIGHTERS ARE IN LIGHTERS.DM
/obj/item/clothing/mask/cigarette/pipe/die()
return
-/obj/item/clothing/mask/cigarette/pipe/light(flavor_text = null)
+/obj/item/clothing/mask/cigarette/pipe/light()
if(!lit)
lit = TRUE
damtype = "fire"
icon_state = icon_on
item_state = icon_on
- if(flavor_text)
- var/turf/T = get_turf(src)
- T.visible_message(flavor_text)
START_PROCESSING(SSobj, src)
/obj/item/clothing/mask/cigarette/pipe/process()
@@ -509,18 +556,18 @@ LIGHTERS ARE IN LIGHTERS.DM
/obj/item/clothing/mask/cigarette/pipe/attack_self(mob/user) // Extinguishes the pipe.
if(lit)
- user.visible_message("[user] puts out [src].")
+ user.visible_message(
+ "[user] puts out [src].",
+ "You put out [src]."
+ )
lit = FALSE
+ first_puff = TRUE
icon_state = icon_off
item_state = icon_off
STOP_PROCESSING(SSobj, src)
return
-/obj/item/clothing/mask/cigarette/pipe/try_light(obj/item/cigar, obj/item/lighting_item)
- if(can_light_fancy(lighting_item))
- return ..()
-
-// Refill or light the pipe
+// Refill the pipe
/obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/food/grown))
var/obj/item/food/grown/O = I
@@ -534,14 +581,6 @@ LIGHTERS ARE IN LIGHTERS.DM
qdel(O)
else
to_chat(user, "You need to dry this first!")
- return
-
- if(!is_type_in_typecache(I, things_that_light))
- return
- if(can_light_fancy(I))
- ..()
- else
- to_chat(user, "[src] straight out REFUSES to be lit by such means.")
/obj/item/clothing/mask/cigarette/pipe/cobpipe
name = "corn cob pipe"
@@ -554,40 +593,4 @@ LIGHTERS ARE IN LIGHTERS.DM
chem_volume = 160
list_reagents = list()
-///////////
-//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/afterattack(atom/target, mob/user, proximity)
- if(!proximity)
- return
- if(!istype(target, /obj/item/food/grown))
- return ..()
-
- var/obj/item/food/grown/plant = target
- if(!plant.dry)
- to_chat(user, "You need to dry this first!")
- return
-
- user.unEquip(plant, TRUE)
- user.unEquip(src, TRUE)
- var/obj/item/clothing/mask/cigarette/rollie/custom/custom_rollie = new (get_turf(user))
- custom_rollie.reagents.maximum_volume = plant.reagents.total_volume
- plant.reagents.trans_to(custom_rollie, plant.reagents.total_volume)
- custom_rollie.smoketime = custom_rollie.reagents.total_volume * 2.5
-
- user.put_in_active_hand(custom_rollie)
- to_chat(user, "You roll the [plant.name] into a rolling paper.")
- custom_rollie.desc = "Dried [plant.name] rolled up in a thin piece of paper."
-
- qdel(plant)
- qdel(src)
-
#undef REAGENT_TIME_RATIO
diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm
index 7940fb082c23a..f496e5fdb3d71 100644
--- a/code/game/objects/items/weapons/flamethrower.dm
+++ b/code/game/objects/items/weapons/flamethrower.dm
@@ -74,6 +74,53 @@
else
return TRUE
+/obj/item/flamethrower/attack(mob/living/target, mob/living/user)
+ if(!cigarette_lighter_act(user, target))
+ return ..()
+
+/obj/item/flamethrower/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!lit)
+ to_chat(user, "You need to ignite [src] before you can use it as a lighter!")
+ return TRUE
+
+ // Pulling this off 'safely' requires years of experience, a true badass, or blind luck!
+ if(HAS_TRAIT(user, TRAIT_BADASS) || (user.mind.assigned_role in list("Station Engineer", "Chief Engineer", "Life Support Specialist")) || prob(50))
+ if(user == target)
+ user.visible_message(
+ "[user] confidently lifts up [src] and releases a big puff of flame at [user.p_their()] [cig] to light it, like some kind of psychopath!",
+ "You lift up [src] and lightly pull the trigger, lighting [cig].",
+ "You hear a brief burst of flame!"
+ )
+ else
+ user.visible_message(
+ "[user] confidently lifts up [src] and releases a big puff of flame at [target], lighting [target.p_their()] [cig.name], like some kind of psychopath!",
+ "You lift up [src] and point it at [target], lightly pullling the trigger to light [target.p_their()] [cig.name] with a big puff of flame.",
+ "You hear a brief burst of flame!"
+ )
+ else
+ // You set them on fire, but at least the cigarette got lit...
+ if(target == user)
+ user.visible_message(
+ "[user] carelessly lifts up [src] and releases a large burst of flame at [user.p_their()] [cig] to light it, accidentally setting [user.p_themselves()] ablaze in the process!",
+ "You lift up [src] and squeeze the trigger to light [cig]. Unfortunately, you squeeze a little too hard and release a large burst of flame that sets you ablaze!",
+ "You hear a plume of fire and something igniting!"
+ )
+ else
+ user.visible_message(
+ "[user] carelessly lifts up [src] and releases a large burst of flame at [target] to light [target.p_their()] [cig.name], accidentally setting [target.p_them()] ablaze!",
+ "You lift up [src] up and point it at [target], squeezing the trigger to light [target.p_their()] [cig.name]. \
+ Unfortunately, your squeeze a little too hard and release large burst of flame that sets [target.p_them()] ablaze!",
+ "You hear a plume of fire and something igniting!"
+ )
+ target.adjust_fire_stacks(2)
+ target.IgniteMob()
+ cig.light(user, target)
+ return TRUE
+
/obj/item/flamethrower/afterattack(atom/target, mob/user, flag)
. = ..()
if(flag)
diff --git a/code/game/objects/items/weapons/lighters.dm b/code/game/objects/items/weapons/lighters.dm
index 9002eeac82ed1..2992f2473a88b 100644
--- a/code/game/objects/items/weapons/lighters.dm
+++ b/code/game/objects/items/weapons/lighters.dm
@@ -1,7 +1,7 @@
-// Basic lighters
+// MARK: LIGHTERS
/obj/item/lighter
name = "cheap lighter"
- desc = "A cheap-as-free lighter."
+ desc = "A cheap cigarette lighter. It gets the job done, barely."
icon = 'icons/obj/lighter.dmi'
lefthand_file = 'icons/mob/inhands/lighter_lefthand.dmi'
righthand_file = 'icons/mob/inhands/lighter_righthand.dmi'
@@ -20,6 +20,7 @@
var/next_off_message
/// Our lighter color suffix. => [base_icon_state]-[lightercolor] => lighter-r
var/lighter_color
+ var/is_a_zippo = FALSE
/obj/item/lighter/random
base_icon_state = "lighter"
@@ -95,26 +96,41 @@
playsound(src, 'sound/items/lighter/plastic_close.ogg', 25, TRUE)
next_off_message = world.time + 5 SECONDS
-/obj/item/lighter/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
- if(!isliving(M))
- return
- M.IgniteMob()
- if(!ismob(M))
+/obj/item/lighter/attack(mob/living/target, mob/living/user)
+ if(cigarette_lighter_act(user, target))
return
- if(istype(M.wear_mask, /obj/item/clothing/mask/cigarette) && user.zone_selected == "mouth" && lit)
- var/obj/item/clothing/mask/cigarette/cig = M.wear_mask
- if(M == user)
- cig.attackby(src, user)
- else
- if(istype(src, /obj/item/lighter/zippo))
- cig.light("[user] whips [src] out and holds it for [M]. [user.p_their(TRUE)] arm is as steady as the unflickering flame [user.p_they()] light[user.p_s()] \the [cig] with.")
- else
- cig.light("[user] holds [src] out for [M], and lights [cig].")
- playsound(src, 'sound/items/lighter/light.ogg', 25, TRUE)
- M.update_inv_wear_mask()
+ if(lit && target.IgniteMob())
+ message_admins("[key_name_admin(user)] set [key_name_admin(target)] on fire")
+ log_game("[key_name(user)] set [key_name(target)] on fire")
+
+ return ..()
+
+/obj/item/lighter/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ // Otherwise the later parts of this proc can be passed to the zippo and cause a runtime.
+ if(is_a_zippo)
+ return cig
+
+ if(!cig)
+ return !isnull(cig)
+
+ if(!lit)
+ to_chat(user, "You need to light [src] before it can be used to light anything!")
+ return TRUE
+
+ if(target == user)
+ user.visible_message(
+ "After some fiddling, [user] manages to light [user.p_their()] [cig] with [src].",
+ "After some fiddling, you manage to light [cig] with [src].,"
+ )
else
- ..()
+ user.visible_message(
+ "After some fiddling, [user] manages to light [cig] for [target] with [src].",
+ "After some fiddling, you manage to light [cig] for [target] with [src]."
+ )
+ cig.light(user, target)
+ return TRUE
/obj/item/lighter/process()
var/turf/location = get_turf(src)
@@ -131,18 +147,24 @@
/obj/item/lighter/get_heat()
return lit * 1500
-// Zippo lighters
+// ZIPPO LIGHTERS
+
/obj/item/lighter/zippo
name = "zippo lighter"
- desc = "The zippo."
+ desc = "A premium cigarette lighter, for cool and distinguished individuals."
icon_state = "zippo"
item_state = "zippo"
+ is_a_zippo = TRUE
/obj/item/lighter/zippo/turn_on_lighter(mob/living/user)
. = ..()
if(world.time > next_on_message)
- user.visible_message("Without even breaking stride, [user] flips open and lights [src] in one smooth movement.")
- playsound(src.loc, 'sound/items/zippolight.ogg', 25, 1)
+ user.visible_message(
+ "Without even breaking stride, [user] flips open and lights [src] in one smooth movement.",
+ "Without breaking your stride, you flip open and light [src] in one smooth movement.",
+ "You hear a zippo being lit."
+ )
+ playsound(src.loc, 'sound/items/zippolight.ogg', 25, TRUE)
next_on_message = world.time + 5 SECONDS
else
to_chat(user, "You light [src].")
@@ -153,11 +175,37 @@
return
if(world.time > next_off_message)
- user.visible_message("You hear a quiet click, as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow.")
- playsound(src.loc, 'sound/items/zippoclose.ogg', 25, 1)
+ user.visible_message(
+ "You hear a quiet click as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow.",
+ "You shut off [src] without even looking at what you're doing.",
+ "You hear a quiet click as a zippo lighter is shut off. Wow."
+ )
+ playsound(loc, 'sound/items/zippoclose.ogg', 25, TRUE)
next_off_message = world.time + 5 SECONDS
else
- to_chat(user, "You shut off [src].")
+ to_chat(user, "You shut off [src].")
+
+/obj/item/lighter/zippo/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!lit)
+ to_chat(user, "You need to light [src] before it can be used to light anything!")
+ return TRUE
+
+ if(target == user)
+ user.visible_message(
+ "With a single flick of [user.p_their()] wrist, [user] smoothly lights [user.p_their()] [cig.name] with [src]. Damn [user.p_theyre()] cool.",
+ "With a single flick of your wrist, you smoothly light [cig] with [src]."
+ )
+ else
+ user.visible_message(
+ "[user] whips [src] out and holds it for [target]. [user.p_their(TRUE)] arm is as steady as the unflickering flame [user.p_they()] light [cig] with. Damn [user.p_theyre()] cool.",
+ "You whip [src] out and hold it for [target]. Your arm is as steady as the unflickering flame you light [cig] with."
+ )
+ cig.light(user, target)
+ return TRUE
/obj/item/lighter/zippo/show_off_message(mob/living/user)
return
@@ -165,10 +213,9 @@
/obj/item/lighter/zippo/attempt_light(mob/living/user)
return
-//EXTRA LIGHTERS
/obj/item/lighter/zippo/nt_rep
name = "gold engraved zippo"
- desc = "An engraved golden Zippo lighter with the letters NT on it."
+ desc = "An engraved golden Zippo lighter with the letters \"NT\" engraved on the sides."
icon_state = "zippo-nt"
item_state = "zippo-gold"
@@ -195,9 +242,8 @@
icon_state = "zippo-gonzo"
item_state = "zippo-red"
-///////////
-//MATCHES//
-///////////
+// MARK: MATCHES
+
/obj/item/match
name = "match"
desc = "A simple match stick, used for lighting fine smokables."
@@ -209,6 +255,7 @@
w_class = WEIGHT_CLASS_TINY
origin_tech = "materials=1"
attack_verb = null
+ var/is_unathi_fire = FALSE
/obj/item/match/process()
var/turf/location = get_turf(src)
@@ -268,35 +315,43 @@
else
return TRUE
-/obj/item/match/attack(mob/living/carbon/M, mob/living/carbon/user)
- if(!isliving(M))
- return ..()
- if(lit && M.IgniteMob())
- message_admins("[key_name_admin(user)] set [key_name_admin(M)] on fire")
- log_game("[key_name(user)] set [key_name(M)] on fire")
- var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
- if(lit && cig && user.a_intent == INTENT_HELP)
- if(cig.lit)
- to_chat(user, "[cig] is already lit.")
- if(M == user)
- cig.attackby(src, user)
- else
- if(istype(src, /obj/item/match/unathi))
- if(prob(50))
- cig.light("[user] spits fire at [M], lighting [cig] and nearly burning [user.p_their()] face!")
- matchburnout()
- else
- cig.light("[user] spits fire at [M], burning [user.p_their()] face and lighting [cig] in the process.")
- var/obj/item/organ/external/head/affecting = M.get_organ("head")
- affecting.receive_damage(0, 5)
- M.UpdateDamageIcon()
- playsound(user.loc, 'sound/effects/unathiignite.ogg', 40, FALSE)
-
- else
- cig.light("[user] holds [src] out for [M], and lights [cig].")
- playsound(src, 'sound/items/lighter/light.ogg', 25, TRUE)
+/obj/item/match/attack(mob/living/target, mob/living/user)
+ if(cigarette_lighter_act(user, target))
+ return
+
+ if(lit && target.IgniteMob())
+ message_admins("[key_name_admin(user)] set [key_name_admin(target)] on fire")
+ log_game("[key_name(user)] set [key_name(target)] on fire")
+
+ return ..()
+
+/obj/item/match/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+
+ // Otherwise the later parts of this proc can be passed to the unathi's blaze and cause a runtime.
+ if(is_unathi_fire)
+ return cig
+
+ if(!cig)
+ return !isnull(cig)
+
+ if(!lit)
+ to_chat(user, "You need to light [src] before it can be used to light anything!")
+ return TRUE
+
+ if(target == user)
+ user.visible_message(
+ "[user] lights [user.p_their()] [cig] with [src].",
+ "You light [cig] with [src]."
+ )
else
- ..()
+ user.visible_message(
+ "[user] holds [src] out for [target], and lights [cig].",
+ "You hold [src] out for [target], and light [user.p_their()] [cig]."
+ )
+ cig.light(user, target)
+ matchburnout()
+ return TRUE
/obj/item/match/decompile_act(obj/item/matter_decompiler/C, mob/user)
if(isdrone(user) && burnt)
@@ -305,11 +360,6 @@
return TRUE
return ..()
-/obj/item/proc/help_light_cig(mob/living/M)
- var/mask_item = M.get_item_by_slot(SLOT_HUD_WEAR_MASK)
- if(istype(mask_item, /obj/item/clothing/mask/cigarette))
- return mask_item
-
/obj/item/match/get_heat()
return lit * 1000
@@ -332,6 +382,43 @@
origin_tech = null
lit = TRUE
w_class = WEIGHT_CLASS_BULKY //to prevent it going to pockets
+ is_unathi_fire = TRUE
+
+/obj/item/match/unathi/cigarette_lighter_act(mob/living/target, mob/living/user, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!lit)
+ to_chat(user, "If you can see this message, please make an issue report to GitHub, something bad has happened.")
+ return TRUE
+
+ if(target == user)
+ user.visible_message(
+ "[user] spits fire at [user.p_their()] [cig.name], igniting it.",
+ "You spit fire at [cig], igniting it.",
+ "You hear a brief burst of flame!"
+ )
+ else
+ if(prob(50))
+ user.visible_message(
+ "[user] spits fire at [target], lighting [cig] in [target.p_their()] mouth and nearly burning [target.p_their()] face!",
+ "You spit fire at [target], lighting [cig] in [target.p_their()] mouth and nearly burning [target.p_their()] face!",
+ "You hear a brief burst of flame!"
+ )
+ else
+ user.visible_message(
+ "[user] spits fire at [target], burning [target.p_their()] face and lighting [cig] in the process!",
+ "You spit fire at [target], burning [target.p_their()] face and lighting [cig] in the process!",
+ "You hear a brief burst of flame!"
+ )
+ var/obj/item/organ/external/head/affecting = target.get_organ("head")
+ affecting.receive_damage(0, 5)
+ target.UpdateDamageIcon()
+ cig.light(user, target)
+ playsound(user.loc, 'sound/effects/unathiignite.ogg', 40, FALSE)
+ matchburnout()
+ return TRUE
/obj/item/match/unathi/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/items/weapons/melee/energy_melee_weapons.dm b/code/game/objects/items/weapons/melee/energy_melee_weapons.dm
index 3e9422d4bfeb1..5fef9bf2214e7 100644
--- a/code/game/objects/items/weapons/melee/energy_melee_weapons.dm
+++ b/code/game/objects/items/weapons/melee/energy_melee_weapons.dm
@@ -44,6 +44,8 @@
light_power = 2
var/brightness_on = 2
var/colormap = list(red=LIGHT_COLOR_RED, blue=LIGHT_COLOR_LIGHTBLUE, green=LIGHT_COLOR_GREEN, purple=LIGHT_COLOR_PURPLE, rainbow=LIGHT_COLOR_WHITE)
+ /// Used to mark the item as a cleaving saw so that cigarette_lighter_act() will perform an early return.
+ var/is_a_cleaving_saw = FALSE
/obj/item/melee/energy/Initialize(mapload)
. = ..()
@@ -55,7 +57,10 @@
UnregisterSignal(src, COMSIG_ITEM_SHARPEN_ACT)
return ..()
-/obj/item/melee/energy/attack(mob/living/target, mob/living/carbon/human/user)
+/obj/item/melee/energy/attack(mob/living/target, mob/living/user)
+ if(cigarette_lighter_act(user, target))
+ return
+
var/nemesis_faction = FALSE
if(LAZYLEN(nemesis_factions))
for(var/F in target.faction)
@@ -68,6 +73,37 @@
if(nemesis_faction)
force -= faction_bonus_force
+/obj/item/melee/energy/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ if(is_a_cleaving_saw)
+ return FALSE
+
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!HAS_TRAIT(src, TRAIT_ITEM_ACTIVE))
+ to_chat(user, "You must activate [src] before you can light [cig] with it!")
+ return TRUE
+
+ if(target == user)
+ user.visible_message(
+ "[user] makes a violent slashing motion, barely missing [user.p_their()] nose as light flashes! \
+ [user.p_they(TRUE)] light[user.p_s()] [user.p_their()] [cig] with [src] in the process.",
+ "You casually slash [src] at [cig], lighting it with the blade.",
+ "You hear an energy blade slashing something!"
+ )
+ else
+ user.visible_message(
+ "[user] makes a violent slashing motion, barely missing the nose of [target] as light flashes! \
+ [user.p_they(TRUE)] light[user.p_s()] [cig] in the mouth of [target] with [src] in the process.",
+ "You casually slash [src] at [cig] in the mouth of [target], lighting it with the blade.",
+ "You hear an energy blade slashing something!"
+ )
+ user.do_attack_animation(target)
+ playsound(user.loc, hitsound, 50, TRUE)
+ cig.light(user, target)
+ return TRUE
+
/obj/item/melee/energy/suicide_act(mob/user)
user.visible_message(pick("[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku!", \
"[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -365,6 +401,7 @@
icon_state = "cleaving_saw"
icon_state_on = "cleaving_saw_open"
slot_flags = SLOT_FLAG_BELT
+ is_a_cleaving_saw = TRUE
var/attack_verb_off = list("attacked", "sawed", "sliced", "torn", "ripped", "diced", "cut")
attack_verb_on = list("cleaved", "swiped", "slashed", "chopped")
hitsound = 'sound/weapons/bladeslice.ogg'
diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm
index d44683a5b9974..49f940b183501 100644
--- a/code/game/objects/items/weapons/storage/fancy.dm
+++ b/code/game/objects/items/weapons/storage/fancy.dm
@@ -235,39 +235,45 @@
/obj/item/storage/fancy/cigarettes/update_icon_state()
icon_state = "[initial(icon_state)][length(contents)]"
-/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
+/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M, mob/living/user)
if(!ismob(M))
return
- if(istype(M) && M == user && user.zone_selected == "mouth" && length(contents) > 0 && !user.wear_mask)
- var/got_cig = 0
- for(var/num=1, num <= length(contents), num++)
+ if(istype(M) && user.zone_selected == "mouth" && length(contents) > 0 && !M.wear_mask)
+ var/got_cig = FALSE
+ for(var/num in 1 to length(contents))
var/obj/item/I = contents[num]
if(istype(I, /obj/item/clothing/mask/cigarette))
var/obj/item/clothing/mask/cigarette/C = I
- user.equip_to_slot_if_possible(C, SLOT_HUD_WEAR_MASK)
- to_chat(user, "You take \a [C.name] out of the pack.")
+ M.equip_to_slot_if_possible(C, SLOT_HUD_WEAR_MASK)
+ if(M != user)
+ user.visible_message(
+ "[user] takes \a [C.name] out of [src] and gives it to [M].",
+ "You take \a [C.name] out of [src] and give it to [M]."
+ )
+ else
+ to_chat(user, "You take \a [C.name] out of the pack.")
update_icon()
- got_cig = 1
+ got_cig = TRUE
break
if(!got_cig)
to_chat(user, "There are no smokables in the pack!")
else
..()
-/obj/item/storage/fancy/cigarettes/can_be_inserted(obj/item/W as obj, stop_messages = 0)
+/obj/item/storage/fancy/cigarettes/can_be_inserted(obj/item/W, stop_messages = FALSE)
if(istype(W, /obj/item/match))
var/obj/item/match/M = W
if(M.lit)
if(!stop_messages)
to_chat(usr, "Putting a lit [W] in [src] probably isn't a good idea.")
- return 0
+ return FALSE
if(istype(W, /obj/item/lighter))
var/obj/item/lighter/L = W
if(L.lit)
if(!stop_messages)
to_chat(usr, "Putting [W] in [src] while lit probably isn't a good idea.")
- return 0
+ return FALSE
//if we get this far, handle the insertion checks as normal
. = ..()
diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm
index 4d3204ce5d766..49f7873925520 100644
--- a/code/game/objects/items/weapons/twohanded.dm
+++ b/code/game/objects/items/weapons/twohanded.dm
@@ -140,6 +140,9 @@
set_light(0)
/obj/item/dualsaber/attack(mob/target, mob/living/user)
+ if(cigarette_lighter_act(user, target))
+ return
+
if(HAS_TRAIT(user, TRAIT_HULK))
to_chat(user, "You grip the blade too hard and accidentally drop it!")
if(HAS_TRAIT(src, TRAIT_WIELDED))
@@ -153,6 +156,33 @@
if((HAS_TRAIT(src, TRAIT_WIELDED)) && prob(50))
INVOKE_ASYNC(src, PROC_REF(jedi_spin), user)
+/obj/item/dualsaber/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!HAS_TRAIT(src, TRAIT_WIELDED))
+ to_chat(user, "You need to activate [src] before you can light anything with it!")
+ return TRUE
+
+ if(target == user)
+ user.visible_message(
+ "[user] flips through the air and spins [src] wildly! It brushes against [user.p_their()] [cig] and sets it alight!",
+ "You flip through the air and twist [src] so it brushes against [cig], lighting it with the blade.",
+ "You hear an energy blade slashing something!"
+ )
+ else
+ user.visible_message(
+ "[user] flips through the air and slashes at [user] with [src]! The blade barely misses, brushing against [user.p_their()] [cig] and setting it alight!",
+ "You flip through the air and slash [src] at [cig], lighting it for [target].",
+ "You hear an energy blade slashing something!"
+ )
+ user.do_attack_animation(target)
+ playsound(user.loc, hitsound, 50, TRUE)
+ cig.light(user, target)
+ INVOKE_ASYNC(src, PROC_REF(jedi_spin), user)
+ return TRUE
+
/obj/item/dualsaber/proc/jedi_spin(mob/living/user)
for(var/i in list(NORTH, SOUTH, EAST, WEST, EAST, SOUTH, NORTH, SOUTH, EAST, WEST, EAST, SOUTH))
user.setDir(i)
diff --git a/code/modules/assembly/igniter.dm b/code/modules/assembly/igniter.dm
index dd9c6f9ec053d..0f09929b83a1f 100644
--- a/code/modules/assembly/igniter.dm
+++ b/code/modules/assembly/igniter.dm
@@ -28,7 +28,10 @@
var/turf/location = get_turf(loc)
if(location)
location.hotspot_expose(1000, 1000)
-
+ visible_message(
+ "Sparks shoot out of [src].",
+ "You hear a shower of sparks shooting out from something!"
+ )
sparks.start()
if(istype(loc, /obj/item/assembly_holder))
@@ -54,6 +57,30 @@
return TRUE
+/obj/item/assembly/igniter/attack(mob/living/target, mob/living/user)
+ if(!cigarette_lighter_act(user, target))
+ return ..()
+
+/obj/item/assembly/igniter/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(target == user)
+ user.visible_message(
+ "[user] presses [src] against [cig] and activates it, lighting [cig] in a shower of sparks!",
+ "You press [src] against [cig] and activates it, lighting [cig] in a shower of sparks!",
+ "You hear a shower of sparks shooting out from something!"
+ )
+ else
+ user.visible_message(
+ "[user] presses [src] against [cig] and activates it, lighting [cig] for [target] in a shower of sparks!",
+ "You press [src] against [cig] and activate it, lighting [cig] in a shower of sparks!",
+ "You hear a shower of sparks shooting out from something!"
+ )
+ sparks.start() // Make sparks fly!
+ cig.light(user, target)
+ return TRUE
/obj/item/assembly/igniter/attack_self(mob/user)
if(!istype(loc, /obj/item/assembly_holder))
diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
index 7c82ec854ab6a..31f42bc2ef8b2 100644
--- a/code/modules/mining/lavaland/loot/ashdragon_loot.dm
+++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
@@ -273,6 +273,28 @@
. = ..()
banned_turfs = typecacheof(list(/turf/space/transit, /turf/simulated/wall, /turf/simulated/mineral))
+/obj/item/lava_staff/attack(mob/target, mob/living/user)
+ if(!cigarette_lighter_act(user, target))
+ return ..()
+
+/obj/item/lava_staff/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(target == user)
+ user.visible_message(
+ "[user] holds the tip of [src] near [user.p_their()] [cig.name] until it is suddenly set alight.",
+ "You hold the tip of [src] near [cig] until it is suddenly set alight.",
+ )
+ else
+ user.visible_message(
+ "[user] points [src] at [target] until [target.p_their()] [cig.name] is suddenly set alight.",
+ "You point [src] at [target] until [target.p_their()] [cig] is suddenly set alight.",
+ )
+ cig.light(user, target)
+ return TRUE
+
/obj/item/lava_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
..()
if(timer > world.time)
diff --git a/code/modules/mining/lavaland/loot/legion_loot.dm b/code/modules/mining/lavaland/loot/legion_loot.dm
index 2aff38595d9e6..40c1e51167a32 100644
--- a/code/modules/mining/lavaland/loot/legion_loot.dm
+++ b/code/modules/mining/lavaland/loot/legion_loot.dm
@@ -30,6 +30,38 @@
. += "Use it on targets to summon thunderbolts from the sky."
. += "The thunderbolts are boosted if in an area with weather effects."
+/obj/item/storm_staff/attack(mob/living/target, mob/living/user)
+ if(cigarette_lighter_act(user, target))
+ return TRUE
+
+ return ..()
+
+/obj/item/storm_staff/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!thunder_charges)
+ to_chat(user, "[src] needs to recharge!")
+ return TRUE
+
+ if(target == user)
+ user.visible_message(
+ "[user] holds [src] up to [user.p_their()] [cig.name] and shoots a tiny bolt of lightning that sets it alight!",
+ "You hold [src] up to [cig] and shoot a tiny bolt of lightning that sets it alight!",
+ "A thundercrack fills the air!"
+ )
+ else
+ user.visible_message(
+ "[user] points [src] at [target] and shoots a tiny bolt of lightning that sets [target.p_their()] [cig.name] alight!",
+ "You point [src] at [target] and shoot a tiny bolt of lightning that sets [target.p_their()] [cig.name] alight!",
+ "A thundercrack fills the air!"
+ )
+ cig.light(user, target)
+ playsound(target, 'sound/magic/lightningbolt.ogg', 50, TRUE)
+ thunder_charges--
+ return TRUE
+
/obj/item/storm_staff/attack_self(mob/user)
var/area/user_area = get_area(user)
var/turf/user_turf = get_turf(user)
@@ -48,9 +80,11 @@
if(A.stage == WEATHER_WIND_DOWN_STAGE)
to_chat(user, "The storm is already ending! It would be a waste to use the staff now.")
return
- user.visible_message("[user] holds [src] skywards as an orange beam travels into the sky!", \
- "You hold [src] skyward, dispelling the storm!")
- playsound(user, 'sound/magic/staff_change.ogg', 200, 0)
+ user.visible_message(
+ "[user] holds [src] skywards as an orange beam travels into the sky!",
+ "You hold [src] skyward, dispelling the storm!"
+ )
+ playsound(user, 'sound/magic/staff_change.ogg', 200, FALSE)
A.wind_down()
var/old_color = user.color
user.color = list(340/255, 240/255, 0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
@@ -59,6 +93,13 @@
animate(user, color = old_color, transform = old_transform, time = 1 SECONDS)
/obj/item/storm_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+ // This early return stops the staff from shooting lightning at someone when being used as a lighter.
+ if(iscarbon(target))
+ var/mob/living/carbon/cig_haver = target
+ var/mask_item = cig_haver.get_item_by_slot(SLOT_HUD_WEAR_MASK)
+ if(istype(mask_item, /obj/item/clothing/mask/cigarette) && user.zone_selected == "mouth" && user.a_intent == INTENT_HELP)
+ return
+
. = ..()
if(!thunder_charges)
to_chat(user, "The staff needs to recharge.")
@@ -120,7 +161,10 @@
for(var/obj/hit_thing in T)
hit_thing.take_damage(20, BURN, ENERGY, FALSE)
playsound(target, 'sound/magic/lightningbolt.ogg', 100, TRUE)
- target.visible_message("A thunderbolt strikes [target]!")
+ target.visible_message(
+ "A thunderbolt strikes [target]!",
+ "A thundercrack fills the air!"
+ )
explosion(target, -1, -1, light_impact_range = (boosted ? 1 : 0), flame_range = (boosted ? 2 : 1), silent = TRUE)
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 0ca56f85cb197..ebe264a447179 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -1,14 +1,14 @@
/* Pens!
- * Contains:
- * Pens
- * Sleepy Pens
- * Edaggers
+ * CONTENTS:
+ * 1. PENS
+ * 2. SLEEPYPENS
+ * 3. E-DAGGERS
+ 4. POISON PEN
*/
-/*
- * Pens
- */
+// PENS
+
/obj/item/pen
desc = "It's a normal black ink pen."
name = "pen"
@@ -139,15 +139,13 @@
desc = "An expensive-looking pen only issued to heads of cargo."
icon_state = "pen_qm"
-/*
- * Sleepypens
- */
+// SLEEPYPEN
+
/obj/item/pen/sleepy
container_type = OPENCONTAINER
origin_tech = "engineering=4;syndicate=2"
var/transfer_amount = 50
-
/obj/item/pen/sleepy/attack(mob/living/M, mob/user)
if(!istype(M))
return
@@ -169,7 +167,6 @@
add_attack_logs(user, M, "Stabbed with (sleepy) [src]. [transfered]u of reagents transfered from pen containing [english_list(contained)].")
return TRUE
-
/obj/item/pen/sleepy/Initialize(mapload)
. = ..()
create_reagents(100)
@@ -201,12 +198,11 @@
desc = "Used to stealthily inject targets. Comes loaded with ketamine but can be refilled with other chemicals. This one isn't disguised."
icon_state = "pen_syndie"
-/*
- * (Alan) Edaggers
- */
+// E-DAGGER
+
/obj/item/pen/edagger
origin_tech = "combat=3;syndicate=1"
- var/on = FALSE
+ var/active = FALSE
var/brightness_on = 2
light_color = LIGHT_COLOR_RED
var/backstab_sound = 'sound/items/unsheath.ogg'
@@ -215,14 +211,20 @@
throw_speed = 4
/obj/item/pen/edagger/attack(mob/living/M, mob/living/user, def_zone)
+ if(cigarette_lighter_act(user, M))
+ return
+
var/extra_force_applied = FALSE
- if(on && user.dir == M.dir && !HAS_TRAIT(M, TRAIT_FLOORED) && user != M)
+ if(active && user.dir == M.dir && !HAS_TRAIT(M, TRAIT_FLOORED) && user != M)
force += backstab_damage
extra_force_applied = TRUE
add_attack_logs(user, M, "Backstabbed with [src]", ATKLOG_ALL)
M.apply_damage(40, STAMINA) //Just enough to slow
M.KnockDown(2 SECONDS)
- M.visible_message("[user] stabs [M] in the back!", "[user] stabs you in the back! The energy blade makes you collapse in pain!")
+ M.visible_message(
+ "[user] stabs [M] in the back!",
+ "[user] stabs you in the back! The energy blade makes you collapse in pain!"
+ )
playsound(loc, backstab_sound, 5, TRUE, ignore_walls = FALSE, falloff_distance = 0)
else
@@ -231,13 +233,40 @@
if(extra_force_applied)
force -= backstab_damage
-/obj/item/pen/edagger/get_clamped_volume() //So the parent proc of attack isn't the loudest sound known to man
- return 0
+/obj/item/pen/edagger/cigarette_lighter_act(mob/living/user, mob/living/carbon/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!active)
+ to_chat(user, "You need to activate [src] before you can light anything with it!")
+ return TRUE
+
+ if(target == user)
+ user.visible_message(
+ "[user] makes a violent slashing motion, barely missing [user.p_their()] nose as light flashes! \
+ [user.p_they(TRUE)] light[user.p_s()] [user.p_their()] [cig] with [src] in the process.",
+ "You casually slash [src] at [cig], lighting it with the blade.",
+ "You hear an energy blade slashing something!"
+ )
+ else
+ user.visible_message(
+ "[user] makes a violent slashing motion, barely missing the nose of [target] as light flashes! \
+ [user.p_they(TRUE)] light[user.p_s()] [cig] in the mouth of [target] with [src] in the process.",
+ "You casually slash [src] at [cig] in the mouth of [target], lighting it with the blade.",
+ "You hear an energy blade slashing something!"
+ )
+ user.do_attack_animation(target)
+ playsound(user.loc, hitsound, 5, TRUE, ignore_walls = FALSE, falloff_distance = 0)
+ cig.light(user, target)
+ return TRUE
+/obj/item/pen/edagger/get_clamped_volume() //So the parent proc of attack isn't the loudest sound known to man
+ return FALSE
/obj/item/pen/edagger/attack_self(mob/living/user)
- if(on)
- on = FALSE
+ if(active)
+ active = FALSE
force = initial(force)
w_class = initial(w_class)
name = initial(name)
@@ -249,7 +278,7 @@
to_chat(user, "[src] can now be concealed.")
set_light(0)
else
- on = TRUE
+ active = TRUE
force = 18
w_class = WEIGHT_CLASS_NORMAL
name = "energy dagger"
@@ -257,14 +286,14 @@
hitsound = 'sound/weapons/blade1.ogg'
embed_chance = 100 //rule of cool
throwforce = 35
- playsound(user, 'sound/weapons/saberon.ogg', 2, 1)
+ playsound(user, 'sound/weapons/saberon.ogg', 2, TRUE)
to_chat(user, "[src] is now active.")
set_light(brightness_on, 1)
- set_sharpness(on)
+ set_sharpness(active)
update_icon()
/obj/item/pen/edagger/update_icon_state()
- if(on)
+ if(active)
icon_state = "edagger"
item_state = "edagger"
else
@@ -274,6 +303,8 @@
/obj/item/proc/on_write(obj/item/paper/P, mob/user)
return
+// POISON PEN
+
/obj/item/pen/multi/poison
var/current_poison = null
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index d2819aeba821c..2eb257881e09c 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -1,3 +1,16 @@
+/*
+CONTENTS:
+1. Wand of Nothing
+2. Wand of Death
+3. Wand of Healing
+4. Wand of Polymorph
+5. Wand of Teleportation
+6. Wand of Door Creation
+7. Wand of Fireball
+8. Wand of Slipping
+9. Wand of Chaos
+*/
+
/obj/item/gun/magic/wand
name = "wand of nothing"
desc = "It's not just a stick, it's a MAGIC stick!"
@@ -59,9 +72,8 @@
user.create_attack_log("[key_name(user)] zapped [user.p_themselves()] with a [src]")
add_attack_logs(user, user, "zapped [user.p_themselves()] with a [src]", ATKLOG_ALL)
-/////////////////////////////////////
-//WAND OF DEATH
-/////////////////////////////////////
+// WAND OF DEATH
+
/obj/item/gun/magic/wand/death
name = "wand of death"
@@ -85,9 +97,7 @@
user.adjustFireLoss(6969)
user.death(FALSE)
-/////////////////////////////////////
-//WAND OF HEALING
-/////////////////////////////////////
+// WAND OF HEALING
/obj/item/gun/magic/wand/resurrection
name = "wand of resurrection"
@@ -109,9 +119,8 @@
user.revive()
to_chat(user, "You feel great!")
-/////////////////////////////////////
-//WAND OF POLYMORPH
-/////////////////////////////////////
+// WAND OF POLYMORPH
+
/obj/item/gun/magic/wand/polymorph
name = "wand of polymorph"
@@ -127,9 +136,8 @@
wabbajack(user)
charges--
-/////////////////////////////////////
-//WAND OF TELEPORTATION
-/////////////////////////////////////
+// WAND OF TELEPORTATION
+
/obj/item/gun/magic/wand/teleport
name = "wand of teleportation"
@@ -149,9 +157,8 @@
charges--
..()
-/////////////////////////////////////
-//WAND OF DOOR CREATION
-/////////////////////////////////////
+// WAND OF DOOR CREATION
+
/obj/item/gun/magic/wand/door
name = "wand of door creation"
@@ -168,9 +175,8 @@
charges--
..()
-/////////////////////////////////////
-//WAND OF FIREBALL
-/////////////////////////////////////
+// WAND OF FIREBALL
+
/obj/item/gun/magic/wand/fireball
name = "wand of fireball"
@@ -186,9 +192,61 @@
charges--
..()
-/////////////////////////////////////
-//WAND OF SLIPPING
-/////////////////////////////////////
+/obj/item/gun/magic/wand/fireball/attack(atom/target, mob/living/user)
+ if(!iscarbon(target))
+ return ..()
+
+ var/mob/living/M = target
+ if(cigarette_lighter_act(user, M))
+ return
+
+ if(M != user) // Do not blow yourself up!
+ return ..() // Blow everyone else up!
+
+/obj/item/gun/magic/wand/fireball/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(!charges)
+ to_chat(user, "[src] is out of charge!")
+ return TRUE
+
+ if(prob(50) || user.mind.assigned_role == "Wizard")
+ if(target == user)
+ user.visible_message(
+ "Holy shit! Did [user] just manage to light [user.p_their()] [cig.name] with [src], with only moderate eyebrow singing!?",
+ "You swish and flick [src], lighting [cig] with a plume of flame, whilst only moderately eyebrow singing your eyebrows.",
+ "You hear a brief burst of flame!"
+ )
+ else
+ user.visible_message(
+ "Holy shit! Did [user] just manage to light [cig] for [target] with [src], only moderately singing [target.p_their()] eyebrows!?",
+ "You swish and flick [src] at [target], lighting [user.p_their()] [cig.name] with a plume of flame, whilst only moderately singing [target.p_their()] eyebrows.",
+ "You hear a brief burst of flame!"
+ )
+ cig.light(user, target)
+ return TRUE
+
+ // Oops...
+ user.visible_message(
+ "Unsure which end of [src] is which, [user] zaps [user.p_themselves()] with a fireball!",
+ "Unsure which end of [src] is which, you accidentally zap yourself with a fireball!",
+ "You hear a firey explosion!"
+ )
+ explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2)
+ charges--
+ return TRUE
+
+// This is needed to you don't try to perform an execution/suicide when lighting a cigarette.
+/obj/item/gun/magic/wand/fireball/handle_suicide(mob/user, mob/living/carbon/human/target, params)
+ var/mask_item = target.get_item_by_slot(SLOT_HUD_WEAR_MASK)
+ if(istype(mask_item, /obj/item/clothing/mask/cigarette) && user.zone_selected == "mouth" && user.a_intent == INTENT_HELP)
+ return
+ . = ..()
+
+// WAND OF SLIPPING
+
/obj/item/gun/magic/wand/slipping
name = "wand of slipping"
desc = "This wand shoots... banana peels?"
@@ -202,9 +260,8 @@
charges--
..()
-/////////////////////////////////////
-//WAND OF CHAOS - Only spawned by the Staff of Chaos as a rare random effect
-/////////////////////////////////////
+// WAND OF CHAOS - Only spawned by the Staff of Chaos as a rare random effect
+
/obj/item/gun/magic/wand/chaos
name = "wand of chaos"
desc = "Payback time!"
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index 1a012ae609c24..ca7740d1a3094 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -56,6 +56,28 @@
attack_verb = list("burnt")
tool_behaviour = TOOL_CAUTERY
+/obj/item/cautery/attack(mob/living/target, mob/living/user)
+ if(!cigarette_lighter_act(user, target))
+ return ..()
+
+/obj/item/cautery/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(target == user)
+ user.visible_message(
+ "[user] presses [src] against [cig], heating it until it lights.",
+ "You press [src] against [cig], heating it until it lights."
+ )
+ else
+ user.visible_message(
+ "[user] presses [src] against [cig] for [target], heating it until it lights.",
+ "You press [src] against [cig] for [target], heating it until it lights."
+ )
+ cig.light(user, target)
+ return TRUE
+
/obj/item/cautery/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_SURGICAL, ROUNDSTART_TRAIT)
@@ -146,6 +168,28 @@
damtype = "fire"
hitsound = 'sound/weapons/sear.ogg'
+/obj/item/scalpel/laser/attack(mob/living/carbon/target, mob/living/user)
+ if(!cigarette_lighter_act(user, target))
+ return ..()
+
+/obj/item/scalpel/laser/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
+ var/obj/item/clothing/mask/cigarette/cig = ..()
+ if(!cig)
+ return !isnull(cig)
+
+ if(target == user)
+ user.visible_message(
+ "[user] presses [src] against [cig], heating it until it lights.",
+ "You press [src] against [cig], heating it until it lights."
+ )
+ else
+ user.visible_message(
+ "[user] presses [src] against [cig] for [target], heating it until it lights.",
+ "You press [src] against [cig] for [target], heating it until it lights."
+ )
+ cig.light(user, target)
+ return TRUE
+
/// lasers also count as catuarys
/obj/item/scalpel/laser/laser1
name = "laser scalpel"
diff --git a/strings/sillytips.txt b/strings/sillytips.txt
index c5bc6f25ab3bb..2d118c7a5b942 100644
--- a/strings/sillytips.txt
+++ b/strings/sillytips.txt
@@ -32,3 +32,4 @@ HONK.
Solars probably give radiation poisoning or something, considering the other power sources are deadly in their own ways.
Nanotrasen would like to remind you that the popular "Deathsquad" show is completely fictional. The Deathsquad is not real. Making any suggestion to the contrary is grounds for immediate termination.
It's rumored that you can recolor the fur on station pets in washing machines by also throwing in a crayon.
+Smoking is cool, but you have to light that cigarette before you can use it! How many ways to light a cigarette can you name?
diff --git a/strings/tips.txt b/strings/tips.txt
index 4fab8345756fd..9aa338604e80d 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -187,6 +187,7 @@ As a Terror Spider, sometimes quickly pulling an enemy into a web can ensure vic
Remote signalers are extremely versatile. They can be used in bombs, hacking, counteracting anomalies, and much more. Get creative!
Need to perform surgery? No surgery kit? No worries! You can use a wide variety of improvised tools to perform ghetto surgery! For example, using a wrench as a stand-in for a bone setter, or a cigarette as a cautery. You can even use alcohol as a makeshift painkiller. Just be aware that these tools may not work as well as proper ones.
If you examine something twice in quick succession, you will perform an extended examination. Many items have extended descriptions that give you more information about the world.
+You can dip cigarettes into beakers or inject reagents into them. This can be used to infuse cigarettes with powerful medications or poisons which will slowly release over time. Welding fuel and plasma make them explode when lit!
You can swap floor tiles by holding a crowbar in one hand and a stack of tiles in the other.
When hacking doors, cutting and mending a "test light wire" will restore power to the door.
When crafting most items, you can either manually combine parts or use the crafting menu.