diff --git a/code/game/objects/effects/particle_holder.dm b/code/game/objects/effects/particle_holder.dm index c9d902ca07679b..9921e75ec8ab6e 100644 --- a/code/game/objects/effects/particle_holder.dm +++ b/code/game/objects/effects/particle_holder.dm @@ -55,7 +55,6 @@ var/mob/particle_mob = attached.loc particle_mob.vis_contents += src -/// Sets the particles position to the passed coordinate list (X, Y, Z) -/// See [https://www.byond.com/docs/ref/#/{notes}/particles] for position documentation -/obj/effect/abstract/particle_holder/proc/set_particle_position(list/pos) - particles.position = pos +/// Sets the particles position to the passed coordinates +/obj/effect/abstract/particle_holder/proc/set_particle_position(x = 0, y = 0, z = 0) + particles.position = list(x, y, z) diff --git a/code/game/objects/effects/particles/smoke.dm b/code/game/objects/effects/particles/smoke.dm index b41b4eb1d96c96..27249c65a683e2 100644 --- a/code/game/objects/effects/particles/smoke.dm +++ b/code/game/objects/effects/particles/smoke.dm @@ -37,6 +37,31 @@ spawning = 2 velocity = list(0, 0.25, 0) +/particles/smoke/cig + icon_state = list("steam_1" = 2, "steam_2" = 1, "steam_3" = 1) + count = 1 + spawning = 0.05 // used to pace it out roughly in time with breath ticks + position = list(-6, -2, 0) + gravity = list(0, 0.75, 0) + lifespan = 0.75 SECONDS + fade = 0.75 SECONDS + velocity = list(0, 0.2, 0) + scale = 0.5 + grow = 0.01 + friction = 0.5 + color = "#d0d0d09d" + +/particles/smoke/cig/big + icon_state = list("steam_1" = 1, "steam_2" = 2, "steam_3" = 2) + gravity = list(0, 0.5, 0) + velocity = list(0, 0.1, 0) + lifespan = 1 SECONDS + fade = 1 SECONDS + grow = 0.1 + scale = 0.75 + spawning = 1 + friction = 0.75 + /particles/smoke/ash icon_state = list("ash_1" = 2, "ash_2" = 2, "ash_3" = 1, "smoke_1" = 3, "smoke_2" = 2) count = 500 diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index e34d64559bb99e..19ec5c69eaed49 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -141,7 +141,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM supports_variations_flags = CLOTHING_SNOUTED_VARIATION throw_verb = "flick" /// Whether this cigarette has been lit. - var/lit = FALSE + VAR_FINAL/lit = FALSE /// Whether this cigarette should start lit. var/starts_lit = FALSE // Note - these are in masks.dmi not in cigarette.dmi @@ -175,6 +175,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/choke_time_max = 30 SECONDS // I am mean /// What type of pollution does this produce on smoking, changed to weed pollution sometimes var/pollution_type = /datum/pollutant/smoke + /// 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 /obj/item/clothing/mask/cigarette/Initialize(mapload) . = ..() @@ -190,23 +196,59 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/Destroy() STOP_PROCESSING(SSobj, src) + QDEL_NULL(mob_smoke) + QDEL_NULL(cig_smoke) return ..() /obj/item/clothing/mask/cigarette/equipped(mob/equipee, slot) . = ..() if(!(slot & ITEM_SLOT_MASK)) - UnregisterSignal(equipee, COMSIG_HUMAN_FORCESAY) + 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/clothing/mask/cigarette/dropped(mob/dropee) +/obj/item/clothing/mask/cigarette/dropped(mob/dropee, silent) . = ..() - UnregisterSignal(dropee, COMSIG_HUMAN_FORCESAY) + // 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/clothing/mask/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/clothing/mask/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/clothing/mask/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/clothing/mask/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) @@ -272,9 +314,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM return lit = TRUE - + make_cig_smoke() if(!(flags_1 & INITIALIZED_1)) - update_icon() + update_appearance(UPDATE_ICON) return attack_verb_continuous = string_list(list("burns", "singes")) @@ -302,17 +344,16 @@ CIGARETTE PACKETS ARE IN FANCY.DM // allowing reagents to react after being lit reagents.flags &= ~(NO_REACT) reagents.handle_reactions() - update_icon() + update_appearance(UPDATE_ICON) if(flavor_text) var/turf/T = get_turf(src) T.visible_message(flavor_text) START_PROCESSING(SSobj, src) - //can't think of any other way to update the overlays :< - if(ismob(loc)) - var/mob/M = loc - M.update_worn_mask() - M.update_held_items() + if(iscarbon(loc)) + var/mob/living/carbon/smoker = loc + if(src == smoker.wear_mask) + make_mob_smoke(smoker) /obj/item/clothing/mask/cigarette/extinguish() . = ..() @@ -326,16 +367,26 @@ CIGARETTE PACKETS ARE IN FANCY.DM STOP_PROCESSING(SSobj, src) reagents.flags |= NO_REACT lit = FALSE - update_icon() - + update_appearance(UPDATE_ICON) if(ismob(loc)) - var/mob/living/M = loc - to_chat(M, span_notice("Your [name] goes out.")) - M.update_worn_mask() - M.update_held_items() + to_chat(loc, span_notice("Your [name] goes out.")) + QDEL_NULL(cig_smoke) + QDEL_NULL(mob_smoke) + +/obj/item/clothing/mask/cigarette/proc/long_exhale(mob/living/carbon/smoker) + 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]."), + ) + 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) /// Handles processing the reagents in the cigarette. -/obj/item/clothing/mask/cigarette/proc/handle_reagents() +/obj/item/clothing/mask/cigarette/proc/handle_reagents(seconds_per_tick) if(!reagents.total_volume) return reagents.expose_temperature(heat, 0.05) @@ -362,6 +413,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM reagents.remove_any(to_smoke) return + how_long_have_we_been_smokin += seconds_per_tick * (1 SECONDS) reagents.expose(smoker, INGEST, min(to_smoke / reagents.total_volume, 1)) var/obj/item/organ/internal/lungs/lungs = smoker.get_organ_slot(ORGAN_SLOT_LUNGS) if(lungs && !(lungs.organ_flags & ORGAN_SYNTHETIC)) @@ -389,7 +441,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM open_flame(heat) if((reagents?.total_volume) && COOLDOWN_FINISHED(src, drag_cooldown)) COOLDOWN_START(src, drag_cooldown, dragtime) - handle_reagents() + handle_reagents(seconds_per_tick) /obj/item/clothing/mask/cigarette/attack_self(mob/user) if(lit) @@ -398,11 +450,17 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/proc/put_out(mob/user, done_early = FALSE) var/atom/location = drop_location() - if(done_early) - user.visible_message(span_notice("[user] calmly drops and treads on \the [src], putting it out instantly.")) - new /obj/effect/decal/cleanable/ash(location) - else if(user) - to_chat(user, span_notice("Your [name] goes out.")) + 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) @@ -429,6 +487,15 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/get_temperature() return lit * heat +/obj/item/clothing/mask/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/clothing/mask/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/clothing/mask/cigarette/space_cigarette @@ -647,7 +714,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM name = "smoking pipe" desc = "A pipe, for smoking. Probably made of meerschaum or something." icon_state = "pipeoff" - icon_on = "pipeon" //Note - these are in masks.dmi + icon_on = "pipeff" //Note - these are in masks.dmi icon_off = "pipeoff" inhand_icon_state = null inhand_icon_on = null @@ -663,7 +730,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/pipe/Initialize(mapload) . = ..() - update_name() + update_appearance(UPDATE_NAME) /obj/item/clothing/mask/cigarette/pipe/update_name() . = ..() @@ -678,11 +745,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(user) to_chat(user, span_notice("Your [name] goes out.")) packeditem = null - update_icon() - - inhand_icon_state = icon_off - user?.update_worn_mask() + update_appearance(UPDATE_ICON) STOP_PROCESSING(SSobj, src) + QDEL_NULL(cig_smoke) /obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/thing, mob/user, params) if(!istype(thing, /obj/item/food/grown)) @@ -721,7 +786,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM 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 = "cobpipeon" //Note - these are in masks.dmi + icon_on = "cobpipeff" //Note - these are in masks.dmi icon_off = "cobpipeoff" inhand_icon_on = null inhand_icon_off = null diff --git a/code/modules/food_and_drinks/machinery/stove_component.dm b/code/modules/food_and_drinks/machinery/stove_component.dm index 898cd7e3513c17..b1dab9cc248df0 100644 --- a/code/modules/food_and_drinks/machinery/stove_component.dm +++ b/code/modules/food_and_drinks/machinery/stove_component.dm @@ -238,7 +238,7 @@ return // this gets badly murdered by sidemap soup_smoke = new(parent, particle_type) - soup_smoke.set_particle_position(list(container_x, round(world.icon_size * 0.66), 0)) + soup_smoke.set_particle_position(container_x, round(world.icon_size * 0.66), 0) return QDEL_NULL(soup_smoke) diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index 1a1a1c78d59d8b..283c85274c06eb 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 5c003d0999ffec..86fdcf786e14d8 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ