diff --git a/code/datums/proximity_monitor/fields/gravity.dm b/code/datums/proximity_monitor/fields/gravity.dm index 745072d69e1..51a73978886 100644 --- a/code/datums/proximity_monitor/fields/gravity.dm +++ b/code/datums/proximity_monitor/fields/gravity.dm @@ -80,6 +80,7 @@ alpha = 200 /// our emissive appearance var/mutable_appearance/emissive + var/particles/particle_type /obj/gravity_fluff_field/Initialize(mapload, strength) . = ..() @@ -89,20 +90,22 @@ QUEUE_SMOOTH_NEIGHBORS(src) switch(strength) if(2 to INFINITY) - particles = new /particles/grav_field_down/strong() + particle_type = /particles/grav_field_down/strong if(1 to 2) - particles = new /particles/grav_field_down() + particle_type = /particles/grav_field_down if(0 to 1) - particles = new /particles/grav_field_float() + particle_type = /particles/grav_field_float if(-INFINITY to -1) - particles = new /particles/grav_field_up() - color = particles.color + particle_type = /particles/grav_field_up + if (particle_type) + add_shared_particles(/particles/grav_field_down/strong) + color = particle_type::color RegisterSignal(src, COMSIG_ATOM_SMOOTHED_ICON, PROC_REF(smoothed)) /obj/gravity_fluff_field/Destroy(force) - . = ..() - QDEL_NULL(particles) + remove_shared_particles(particle_type) emissive = null + return ..() /obj/gravity_fluff_field/proc/smoothed(datum/source) SIGNAL_HANDLER diff --git a/code/game/objects/effects/shared_particle_holder.dm b/code/game/objects/effects/shared_particle_holder.dm index 2d5bbbb8c3a..2fe0c976479 100644 --- a/code/game/objects/effects/shared_particle_holder.dm +++ b/code/game/objects/effects/shared_particle_holder.dm @@ -42,16 +42,19 @@ GLOBAL_LIST_EMPTY(shared_particles) vis_contents += GLOB.shared_particles[particle_key][SHARED_PARTICLE_HOLDER_INDEX][1] return GLOB.shared_particles[particle_key][SHARED_PARTICLE_HOLDER_INDEX][1] - if (length(GLOB.shared_particles[particle_key][SHARED_PARTICLE_HOLDER_INDEX]) < pool_size) + var/list/type_holders = GLOB.shared_particles[particle_key][SHARED_PARTICLE_HOLDER_INDEX] + for (var/obj/effect/abstract/shared_particle_holder/particle_holder as anything in type_holders) + if (particle_holder in vis_contents) + return particle_holder + + if (length(type_holders) < pool_size) var/obj/effect/abstract/shared_particle_holder/new_holder = new(null, particle_type, particle_flags) - GLOB.shared_particles[particle_key][SHARED_PARTICLE_HOLDER_INDEX] += new_holder + type_holders += new_holder vis_contents += new_holder GLOB.shared_particles[particle_key][SHARED_PARTICLE_USER_NUM_INDEX] += 1 return new_holder - var/obj/effect/abstract/shared_particle_holder/particle_holder = pick(GLOB.shared_particles[particle_key][SHARED_PARTICLE_HOLDER_INDEX]) - if (particle_holder in vis_contents) - return particle_holder + var/obj/effect/abstract/shared_particle_holder/particle_holder = pick(type_holders) vis_contents += particle_holder GLOB.shared_particles[particle_key][SHARED_PARTICLE_USER_NUM_INDEX] += 1 return particle_holder diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index 6da965e4757..379169e6f73 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -195,7 +195,12 @@ . = ..() RegisterSignal(src, COMSIG_ITEM_GRILL_PROCESS, PROC_REF(OnGrill)) if(stink_particles) - particles = new stink_particles + add_shared_particles(stink_particles) + +/obj/item/food/badrecipe/Destroy(force) + if (stink_particles) + remove_shared_particles(stink_particles) + return ..() // We override the parent procs here to prevent burned messes from cooking into burned messes. /obj/item/food/badrecipe/make_grillable() diff --git a/code/game/objects/structures/fireplace.dm b/code/game/objects/structures/fireplace.dm index 4e568a56f48..7e94805045f 100644 --- a/code/game/objects/structures/fireplace.dm +++ b/code/game/objects/structures/fireplace.dm @@ -166,7 +166,7 @@ fuel_added = 0 update_appearance() adjust_light() - particles = new /particles/smoke/burning() + add_shared_particles(/particles/smoke/burning) switch(dir) if(SOUTH) @@ -185,7 +185,7 @@ update_appearance() adjust_light() desc = initial(desc) - QDEL_NULL(particles) + remove_shared_particles(/particles/smoke/burning) #undef LOG_BURN_TIMER #undef PAPER_BURN_TIMER diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm index 1eaff6e93dc..d53935bda29 100644 --- a/code/game/objects/structures/lavaland/ore_vent.dm +++ b/code/game/objects/structures/lavaland/ore_vent.dm @@ -224,7 +224,7 @@ addtimer(CALLBACK(node, TYPE_PROC_REF(/atom, update_appearance)), wave_timer * 0.25) addtimer(CALLBACK(node, TYPE_PROC_REF(/atom, update_appearance)), wave_timer * 0.5) addtimer(CALLBACK(node, TYPE_PROC_REF(/atom, update_appearance)), wave_timer * 0.75) - particles = new /particles/smoke/ash() + add_shared_particles(/particles/smoke/ash) for(var/i in 1 to 5) // Clears the surroundings of the ore vent before starting wave defense. for(var/turf/closed/mineral/rock in oview(i)) if(istype(rock, /turf/open/misc/asteroid) && prob(35)) // so it's too common @@ -272,7 +272,7 @@ SEND_SIGNAL(src, COMSIG_VENT_WAVE_CONCLUDED) COOLDOWN_RESET(src, wave_cooldown) - particles = null + remove_shared_particles(/particles/smoke/ash) if(force) initiate_wave_win() diff --git a/code/modules/clothing/head/mind_monkey_helmet.dm b/code/modules/clothing/head/mind_monkey_helmet.dm index e9ff9978239..602f64eefb2 100644 --- a/code/modules/clothing/head/mind_monkey_helmet.dm +++ b/code/modules/clothing/head/mind_monkey_helmet.dm @@ -12,8 +12,8 @@ var/light_colors = 1 ///which icon state color this is (red, blue, yellow) /// This chance is increased by 7 every time the helmet fails to get a host, to dissuade spam. starts negative to add 1 safe reuse var/rage_chance = -7 - /// Holds the steam effect at dangerous rage chance levels. - var/obj/effect/abstract/particle_holder/particle_effect + /// Currently used particle type + var/particle_path /obj/item/clothing/head/helmet/monkey_sentience/Initialize(mapload) . = ..() @@ -60,7 +60,8 @@ UnregisterSignal(magnification, COMSIG_SPECIES_LOSS) magnification = null visible_message(span_notice("[src] falls silent and drops on the floor. Maybe you should try again later?")) - var/particle_path + if (particle_path) + remove_shared_particles(particle_path) switch(rage_chance) if(-7 to 0) user.visible_message(span_notice("[src] falls silent and drops on the floor. Try again later?")) @@ -83,11 +84,10 @@ playsound(src, 'sound/machines/buzz/buzz-two.ogg', 30, TRUE) particle_path = /particles/smoke/steam rage_chance += 7 - - QDEL_NULL(particle_effect) if(particle_path) - particle_effect = new(src, particle_path) - QDEL_IN(particle_effect, 2 MINUTES) + add_shared_particles(particle_path) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/movable, remove_shared_particles), particle_path), 2 MINUTES) + addtimer(VARSET_CALLBACK(src, particle_path, null), 2 MINUTES) if((rage_chance > 0) && prob(rage_chance)) // too much spam means agnry gorilla running at you malfunction(user) diff --git a/code/modules/food_and_drinks/machinery/coffeemaker.dm b/code/modules/food_and_drinks/machinery/coffeemaker.dm index bb532b31624..3a9e7a1af9f 100644 --- a/code/modules/food_and_drinks/machinery/coffeemaker.dm +++ b/code/modules/food_and_drinks/machinery/coffeemaker.dm @@ -52,6 +52,7 @@ /obj/machinery/coffeemaker/Destroy() QDEL_NULL(coffeepot) QDEL_NULL(cartridge) + remove_shared_particles(/particles/smoke) return ..() /obj/machinery/coffeemaker/Exited(atom/movable/gone, direction) @@ -391,10 +392,8 @@ ///Updates the smoke state to something else, setting particles if relevant /obj/machinery/coffeemaker/proc/toggle_steam() - QDEL_NULL(particles) - if(brewing) - particles = new /particles/smoke/steam/mild() - particles.position = list(-6, 0, 0) + var/obj/effect/abstract/shared_particle_holder/smoke_particles = add_shared_particles(/particles/smoke/steam/mild, "smoke_coffeemaker") + smoke_particles.particles.position = list(-6, 0, 0) /obj/machinery/coffeemaker/proc/operate_for(time, silent = FALSE) brewing = TRUE @@ -705,10 +704,8 @@ update_appearance(UPDATE_OVERLAYS) /obj/machinery/coffeemaker/impressa/toggle_steam() - QDEL_NULL(particles) - if(brewing) - particles = new /particles/smoke/steam/mild() - particles.position = list(-2, 1, 0) + var/obj/effect/abstract/shared_particle_holder/smoke_particles = add_shared_particles(/particles/smoke/steam/mild, "smoke_impressa") + smoke_particles.particles.position = list(-2, 1, 0) /obj/machinery/coffeemaker/impressa/brew() power_change() diff --git a/code/modules/food_and_drinks/machinery/microwave.dm b/code/modules/food_and_drinks/machinery/microwave.dm index ae6e3945c94..53725dad385 100644 --- a/code/modules/food_and_drinks/machinery/microwave.dm +++ b/code/modules/food_and_drinks/machinery/microwave.dm @@ -113,7 +113,7 @@ /obj/machinery/microwave/Destroy() QDEL_LIST(ingredients) QDEL_NULL(soundloop) - QDEL_NULL(particles) + remove_shared_particles(/particles/smoke) if(!isnull(cell)) QDEL_NULL(cell) return ..() @@ -707,17 +707,14 @@ if(HAS_TRAIT(smeller, TRAIT_ANOSMIA)) cant_smell += smeller visible_message(span_danger("You smell a burnt smell coming from [src]!"), ignored_mobs = cant_smell) - particles = new /particles/smoke() - addtimer(CALLBACK(src, PROC_REF(remove_smoke)), 10 SECONDS) + add_shared_particles(/particles/smoke) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/movable, remove_shared_particles), /particles/smoke), 10 SECONDS) Shake(duration = 1 SECONDS) cycles-- use_energy(active_power_usage) addtimer(CALLBACK(src, PROC_REF(cook_loop), type, cycles, wait, cooker), wait) -/obj/machinery/microwave/proc/remove_smoke() - QDEL_NULL(particles) - /obj/machinery/microwave/power_change() . = ..() if(cell_powered) diff --git a/code/modules/food_and_drinks/machinery/oven.dm b/code/modules/food_and_drinks/machinery/oven.dm index c997f349241..e9af9338000 100644 --- a/code/modules/food_and_drinks/machinery/oven.dm +++ b/code/modules/food_and_drinks/machinery/oven.dm @@ -31,6 +31,8 @@ var/datum/looping_sound/oven/oven_loop ///Current state of smoke coming from the oven var/smoke_state = OVEN_SMOKE_STATE_NONE + ///Currently used particle type, if any + var/particle_type /obj/machinery/oven/Initialize(mapload) . = ..() @@ -40,7 +42,8 @@ /obj/machinery/oven/Destroy() QDEL_NULL(oven_loop) - QDEL_NULL(particles) + if (particle_type) + remove_shared_particles(particle_type) return ..() /// Used to determine if the oven appears active and cooking, or offline. @@ -210,16 +213,22 @@ /obj/machinery/oven/proc/set_smoke_state(new_state) if(new_state == smoke_state) return - smoke_state = new_state - QDEL_NULL(particles) + smoke_state = new_state + if (particle_type) + remove_shared_particles(particle_type) + particle_type = null + switch(smoke_state) if(OVEN_SMOKE_STATE_BAD) - particles = new /particles/smoke() + particle_type = /particles/smoke if(OVEN_SMOKE_STATE_NEUTRAL) - particles = new /particles/smoke/steam() + particle_type = /particles/smoke/steam if(OVEN_SMOKE_STATE_GOOD) - particles = new /particles/smoke/steam/mild() + particle_type = /particles/smoke/steam/mild + + if (particle_type) + add_shared_particles(particle_type) /obj/machinery/oven/crowbar_act(mob/living/user, obj/item/tool) return default_deconstruction_crowbar(tool, ignore_panel = TRUE) diff --git a/code/modules/food_and_drinks/machinery/stove_component.dm b/code/modules/food_and_drinks/machinery/stove_component.dm index 76f52345c8c..8db59dc2739 100644 --- a/code/modules/food_and_drinks/machinery/stove_component.dm +++ b/code/modules/food_and_drinks/machinery/stove_component.dm @@ -11,8 +11,6 @@ VAR_FINAL/on = FALSE /// A reference to the current soup pot overtop VAR_FINAL/obj/item/container - /// A particle holder for the smoke that comes out of the soup while a container is cooking. - VAR_FINAL/obj/effect/abstract/particle_holder/soup_smoke /// Typepath of particles to use for the particle holder. VAR_FINAL/particle_type = /particles/smoke/steam/mild /// Ref to our looping sound played when cooking @@ -60,11 +58,12 @@ real_parent.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1 /datum/component/stove/UnregisterFromParent() + var/obj/machinery/real_parent = parent if(!QDELING(parent)) - var/obj/machinery/real_parent = parent container.forceMove(real_parent.drop_location()) - QDEL_NULL(soup_smoke) + if (particle_type) + real_parent.remove_shared_particles("[particle_type]_stove_[container_x]") UnregisterSignal(parent, list( COMSIG_ATOM_ATTACK_HAND_SECONDARY, @@ -248,6 +247,7 @@ SIGNAL_HANDLER var/existing_temp = container?.reagents.chem_temp || 0 + var/old_type = particle_type if(existing_temp >= SOUP_BURN_TEMP) particle_type = /particles/smoke/steam/bad else if(existing_temp >= WATER_BOILING_POINT) @@ -255,20 +255,23 @@ else particle_type = null - update_smoke() + update_smoke(old_type) -/datum/component/stove/proc/update_smoke() - if(on && container?.reagents.total_volume > 0) - soup_sound.start() - // Don't override existing particles, wasteful - if(isnull(soup_smoke) || soup_smoke.particles.type != particle_type) - QDEL_NULL(soup_smoke) - if(isnull(particle_type)) - return - // this gets badly murdered by sidemap - soup_smoke = new(parent, particle_type) - soup_smoke.set_particle_position(container_x, round(ICON_SIZE_Y * 0.66), 0) +/datum/component/stove/proc/update_smoke(old_type = null) + var/obj/obj_parent = parent + + if (old_type) + obj_parent.remove_shared_particles("[old_type]_stove_[container_x]") + + if(!on || !container?.reagents.total_volume) + soup_sound?.stop() + if (!isnull(particle_type)) + obj_parent.remove_shared_particles("[particle_type]_stove_[container_x]") return - QDEL_NULL(soup_smoke) - soup_sound?.stop() + soup_sound.start() + if(isnull(particle_type)) + return + var/obj/effect/abstract/shared_particle_holder/soup_smoke = obj_parent.add_shared_particles(particle_type, "[particle_type]_stove_[container_x]") + soup_smoke.particles.position = list(container_x, round(ICON_SIZE_Y * 0.66), 0) + diff --git a/code/modules/hydroponics/beekeeping/bee_smoker.dm b/code/modules/hydroponics/beekeeping/bee_smoker.dm index 3daa75f89e6..d04c72adfd6 100644 --- a/code/modules/hydroponics/beekeeping/bee_smoker.dm +++ b/code/modules/hydroponics/beekeeping/bee_smoker.dm @@ -25,6 +25,10 @@ . = ..() beesmoke_loop = new(src) +/obj/item/bee_smoker/Destroy(force) + remove_shared_particles(/particles/smoke/bee_smoke) + return ..() + /obj/item/bee_smoker/attack_self(mob/user) . = ..() if(.) @@ -100,13 +104,13 @@ if(!activated) beesmoke_loop.stop() - QDEL_NULL(particles) + remove_shared_particles(/particles/smoke/bee_smoke) STOP_PROCESSING(SSobj, src) return beesmoke_loop.start() START_PROCESSING(SSobj, src) - particles = new /particles/smoke/bee_smoke + add_shared_particles(/particles/smoke/bee_smoke) /particles/smoke/bee_smoke lifespan = 0.4 SECONDS diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 53ffae4aca0..e6eb41c42e6 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -202,6 +202,7 @@ /obj/machinery/hydroponics/Destroy() if(myseed) QDEL_NULL(myseed) + remove_shared_particles(/particles/pollen) return ..() /obj/machinery/hydroponics/Exited(atom/movable/gone) @@ -536,7 +537,7 @@ age = 0 update_appearance() if(isnull(myseed)) - particles = null + remove_shared_particles(/particles/pollen) /* * Setter proc to set a tray to a new self_sustaining state and update all values associated with it. @@ -798,12 +799,11 @@ T.myseed.set_instability(round((T.myseed.instability+(1/10)*(myseed.instability-T.myseed.instability)))) T.myseed.set_yield(round((T.myseed.yield+(1/2)*(myseed.yield-T.myseed.yield)))) any_adjacent = TRUE - if(isnull(particles)) - particles = new /particles/pollen() + add_shared_particles(/particles/pollen) if(myseed.instability >= 20 && prob(70) && length(T.myseed.reagents_add)) myseed.perform_reagent_pollination(T.myseed) if(!any_adjacent) - particles = null + remove_shared_particles(/particles/pollen) /** * Bee pollinate proc. diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index cfcffa6fea1..b50c966d230 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -817,7 +817,11 @@ /obj/item/drake_remains/Initialize(mapload) . = ..() - particles = new /particles/bonfire() + add_shared_particles(/particles/bonfire) + +/obj/item/drake_remains/Destroy(force) + remove_shared_particles(/particles/bonfire) + return ..() /obj/item/clothing/glasses/godeye name = "eye of god" diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 88876e0233e..67a61c4b832 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -134,6 +134,12 @@ QDEL_LIST(upgrades) QDEL_NULL(cell) QDEL_NULL(robot_suit) + + if (smoke_particles) + remove_shared_particles(smoke_particles) + if (spark_particles) + remove_shared_particles(spark_particles) + return ..() /mob/living/silicon/robot/Topic(href, href_list) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 323420cb8ae..8e222dd54c7 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -193,41 +193,34 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real var/brute_percent = bruteloss / maxHealth var/burn_percent = fireloss / maxHealth + var/old_smoke = smoke_particles if (brute_percent > MODERATE_DAMAGE_UPPER_BOUND) - if(!smoke_particles) - smoke_particles = new(src, /particles/smoke/cyborg/heavy_damage, PARTICLE_ATTACH_MOB) - else if(!istype(smoke_particles.particles, /particles/smoke/cyborg/heavy_damage)) //TODO: needs to be darker - QDEL_NULL(smoke_particles) - smoke_particles = new(src, /particles/smoke/cyborg/heavy_damage, PARTICLE_ATTACH_MOB) - + smoke_particles = /particles/smoke/cyborg/heavy_damage else if (brute_percent > LOW_DAMAGE_UPPER_BOUND) - if(!smoke_particles) - smoke_particles = new(src, /particles/smoke/cyborg, PARTICLE_ATTACH_MOB) - else if(!istype(smoke_particles.particles, /particles/smoke/cyborg)) - QDEL_NULL(smoke_particles) - smoke_particles = new(src, /particles/smoke/cyborg, PARTICLE_ATTACH_MOB) - + smoke_particles = /particles/smoke/cyborg else - if(smoke_particles) - QDEL_NULL(smoke_particles) + smoke_particles = null + if (old_smoke != smoke_particles) + if (old_smoke) + remove_shared_particles(old_smoke) + if (smoke_particles) + add_shared_particles(smoke_particles) + + var/old_sparks = spark_particles if (burn_percent > MODERATE_DAMAGE_UPPER_BOUND) - if(!spark_particles) - spark_particles = new(src, /particles/embers/spark/severe, PARTICLE_ATTACH_MOB) - else if(!istype(spark_particles.particles, /particles/embers/spark/severe)) //TODO: needs to be more dramatic - QDEL_NULL(spark_particles) - spark_particles = new(src, /particles/embers/spark/severe, PARTICLE_ATTACH_MOB) - + spark_particles = /particles/embers/spark/severe else if (burn_percent > LOW_DAMAGE_UPPER_BOUND) - if(!spark_particles) - spark_particles = new(src, /particles/embers/spark, PARTICLE_ATTACH_MOB) - else if(!istype(spark_particles.particles, /particles/embers/spark)) - QDEL_NULL(spark_particles) - spark_particles = new(src, /particles/embers/spark, PARTICLE_ATTACH_MOB) - + spark_particles = /particles/embers/spark else - if(spark_particles) - QDEL_NULL(spark_particles) + spark_particles = null + + if (old_sparks != spark_particles) + if (old_sparks) + remove_shared_particles(old_sparks) + if (spark_particles) + add_shared_particles(spark_particles) + #undef LOW_DAMAGE_UPPER_BOUND #undef MODERATE_DAMAGE_UPPER_BOUND diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index dd4ba8b6bd4..7e2d8de2469 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -118,10 +118,10 @@ var/low_power_mode = FALSE ///So they can initialize sparks whenever/N var/datum/effect_system/spark_spread/spark_system - ///Smoke particle holder for brute damage - var/obj/effect/abstract/particle_holder/smoke_particles = null - ///Spark particle holder for burn damage - var/obj/effect/abstract/particle_holder/spark_particles = null + ///Smoke particle type for brute damage + var/smoke_particles + ///Spark particle type for burn damage + var/spark_particles ///Jetpack-like effect. var/ionpulse = FALSE