diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index 979c43e8e13e..dd674fdd2fa3 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -33,6 +33,8 @@ ..() /datum/brain_trauma/severe/aphasia/on_lose() + if(QDELETED(owner)) + return ..() owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_APHASIA) owner.remove_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA) ..() diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm index d18bdc7d8cbc..4e75843262af 100644 --- a/code/datums/components/pellet_cloud.dm +++ b/code/datums/components/pellet_cloud.dm @@ -83,21 +83,23 @@ UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_PELLET_CLOUD_INIT, COMSIG_GRENADE_PRIME, COMSIG_GRENADE_ARMED, COMSIG_MOVABLE_MOVED, COMSIG_MINE_TRIGGERED, COMSIG_ITEM_DROPPED)) -//create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance) -// -//Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing()] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes. -//The arguments really don't matter, this proc is triggered by COMSIG_PELLET_CLOUD_INIT which is only for this really, it's just a big mess of the state vars we need for doing the stuff over here. - +/** + * create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance) + * + * Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes. + * The arguments really don't matter, while this proc is triggered by COMSIG_FIRE_CASING, it's just a big mess of the state vars we need for doing the stuff over here. + */ +/datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro, obj/projectile/proj) + SIGNAL_HANDLER -/datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro) - if(user) - shooter = user - else - shooter = fired_from - var/targloc = get_turf(target) + shooter = user + var/turf/target_loc = get_turf(target) if(!zone_override) zone_override = shooter.zone_selected + // things like mouth executions and gunpoints can multiply the damage of projectiles, so this makes sure those effects are applied to each pellet instead of just one + var/original_damage = shell.BB.damage + for(var/i in 1 to num_pellets) shell.ready_proj(target, user, SUPPRESSED_VERY, zone_override, fired_from) if(distro) @@ -107,14 +109,14 @@ spread = round((i / num_pellets - 0.5) * distro) RegisterSignal(shell.BB, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(pellet_hit)) - RegisterSignal(shell.BB, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), PROC_REF(pellet_range)) + RegisterSignals(shell.BB, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), PROC_REF(pellet_range)) + shell.BB.damage = original_damage pellets += shell.BB - if(user) - if(!shell.throw_proj(target, targloc, shooter, params, spread)) - return - else - if(!shell.throw_proj(target, targloc, null, params, spread, shooter)) - return + var/turf/current_loc = get_turf(fired_from) + if (!istype(target_loc) || !istype(current_loc) || !(shell.BB)) + return + INVOKE_ASYNC(shell, TYPE_PROC_REF(/obj/item/ammo_casing, throw_proj), target, target_loc, shooter, params, spread, fired_from) + if(i != num_pellets) shell.newshot() @@ -208,6 +210,8 @@ ///One of our pellets hit something, record what it was and check if we're done (terminated == num_pellets) /datum/component/pellet_cloud/proc/pellet_hit(obj/projectile/P, atom/movable/firer, atom/target, Angle) + SIGNAL_HANDLER + pellets -= P terminated++ hits++ @@ -220,6 +224,8 @@ ///One of our pellets disappeared due to hitting their max range (or just somehow got qdel'd), remove it from our list and check if we're done (terminated == num_pellets) /datum/component/pellet_cloud/proc/pellet_range(obj/projectile/P) + SIGNAL_HANDLER + pellets -= P terminated++ UnregisterSignal(P, list(COMSIG_PARENT_QDELETING, COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT)) @@ -271,6 +277,8 @@ /// Look alive, we're armed! Now we start watching to see if anyone's covering us /datum/component/pellet_cloud/proc/grenade_armed(obj/item/nade) + SIGNAL_HANDLER + if(ismob(nade.loc)) shooter = nade.loc LAZYINITLIST(bodies) @@ -283,11 +291,15 @@ /// Someone dropped the grenade, so set them to the shooter in case they're on top of it when it goes off /datum/component/pellet_cloud/proc/grenade_dropped(obj/item/nade, mob/living/slick_willy) + SIGNAL_HANDLER + shooter = slick_willy grenade_moved() /// Our grenade has moved, reset var/list/bodies so we're "on top" of any mobs currently on the tile /datum/component/pellet_cloud/proc/grenade_moved() + SIGNAL_HANDLER + LAZYCLEARLIST(bodies) for(var/mob/living/new_mob in get_turf(parent)) RegisterSignal(new_mob, COMSIG_PARENT_QDELETING, PROC_REF(on_target_qdel), override=TRUE) @@ -295,10 +307,14 @@ /// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it /datum/component/pellet_cloud/proc/grenade_uncrossed(datum/source, atom/movable/AM, direction) + SIGNAL_HANDLER + LAZYREMOVE(bodies, AM) /// Our grenade or landmine or caseless shell or whatever tried deleting itself, so we intervene and nullspace it until we're done here /datum/component/pellet_cloud/proc/nullspace_parent() + SIGNAL_HANDLER + var/atom/movable/AM = parent AM.moveToNullspace() queued_delete = TRUE diff --git a/code/game/objects/effects/anomalies/anomalies_gravity.dm b/code/game/objects/effects/anomalies/anomalies_gravity.dm index 20cc30dcc74d..550c4414d408 100644 --- a/code/game/objects/effects/anomalies/anomalies_gravity.dm +++ b/code/game/objects/effects/anomalies/anomalies_gravity.dm @@ -87,9 +87,6 @@ /obj/effect/anomaly/grav/high/Initialize(mapload, new_lifespan) . = ..() - INVOKE_ASYNC(src, PROC_REF(setup_grav_field)) - -/obj/effect/anomaly/grav/high/proc/setup_grav_field() grav_field = new(src, effectrange, TRUE, 2) /obj/effect/anomaly/grav/high/Destroy() diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm index 0d2282eeb873..505221b2b013 100644 --- a/code/game/objects/effects/decals/decal.dm +++ b/code/game/objects/effects/decals/decal.dm @@ -61,5 +61,5 @@ /obj/effect/turf_decal/Destroy(force) SHOULD_CALL_PARENT(FALSE) - moveToNullspace() + loc = null return QDEL_HINT_QUEUE diff --git a/code/game/objects/effects/effect_system/effect_system.dm b/code/game/objects/effects/effect_system/effect_system.dm index 8e2db3706ca3..3ad3bd1e26ab 100644 --- a/code/game/objects/effects/effect_system/effect_system.dm +++ b/code/game/objects/effects/effect_system/effect_system.dm @@ -56,7 +56,7 @@ would spawn and follow the beaker, even if it is carried or thrown. for(var/i in 1 to number) if(total_effects > 20) return - INVOKE_ASYNC(src, PROC_REF(generate_effect)) + generate_effect() /datum/effect_system/proc/generate_effect() if(holder) @@ -68,11 +68,21 @@ would spawn and follow the beaker, even if it is carried or thrown. direction = pick(GLOB.cardinals) else direction = pick(GLOB.alldirs) - var/steps_amt = pick(1,2,3) - for(var/j in 1 to steps_amt) - sleep(5) - step(E,direction) - if(!QDELETED(src)) + var/steps_amt = rand(1, 3) + addtimer(CALLBACK(src, PROC_REF(scoot), direction, E, steps_amt), 5) + +/datum/effect_system/proc/scoot(direction, obj/effect/ref, steps) + if(QDELETED(src)) + return + var/step = get_step(ref, direction) + if(isnull(step)) + return + + ref.forceMove(step) + + if(steps) + addtimer(CALLBACK(src, PROC_REF(scoot), direction, ref, steps - 1), 5) + else addtimer(CALLBACK(src, PROC_REF(decrement_total_effect)), 20) /datum/effect_system/proc/decrement_total_effect() diff --git a/code/game/objects/items/devices/mines.dm b/code/game/objects/items/devices/mines.dm index 4e1ec520e55c..28c30aa09019 100644 --- a/code/game/objects/items/devices/mines.dm +++ b/code/game/objects/items/devices/mines.dm @@ -131,6 +131,8 @@ ///NOW we actually blow up /obj/item/mine/proc/blast_now(atom/movable/triggerer) + if(QDELETED(src)) + return var/datum/effect_system/spark_spread/sporks = new /datum/effect_system/spark_spread sporks.set_up(3, 1, src) sporks.start() diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 9903beaf6ad8..61abe8410e14 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -368,6 +368,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated." radio.talk_into(src, speaking, common_channel, language = get_selected_language()) for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10) + if(QDELETED(src)) + return if(damage < explosion_point) // Cutting it a bit close there engineers radio.talk_into(src, "[safe_alert] Failsafe has been disengaged.", common_channel) final_countdown = FALSE @@ -970,17 +972,18 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) continue //You can't pull someone nailed to the deck step_towards(P,center) -/obj/machinery/power/supermatter_crystal/proc/supermatter_anomaly_gen(turf/anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5) - var/turf/L = pick(orange(anomalyrange, anomalycenter)) - if(L) - switch(type) - if(FLUX_ANOMALY) - var/obj/effect/anomaly/flux/A = new(L, 300) - A.explosive = FALSE - if(GRAVITATIONAL_ANOMALY) - new /obj/effect/anomaly/grav(L, 250) - if(PYRO_ANOMALY) - new /obj/effect/anomaly/pyro(L, 200) +/obj/machinery/power/supermatter_crystal/proc/supermatter_anomaly_gen(anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5) + var/turf/spawn_turf = pick(orange(anomalyrange, anomalycenter)) + if(!istype(spawn_turf)) + return + switch(type) + if(FLUX_ANOMALY) + var/obj/effect/anomaly/flux/A = new(spawn_turf, 300) + A.explosive = FALSE + if(GRAVITATIONAL_ANOMALY) + new /obj/effect/anomaly/grav(spawn_turf, 250) + if(PYRO_ANOMALY) + new /obj/effect/anomaly/pyro(spawn_turf, 200) /obj/machinery/power/supermatter_crystal/proc/supermatter_zap(atom/zapstart = src, range = 5, zap_str = 4000, zap_flags = ZAP_SUPERMATTER_FLAGS, list/targets_hit = list()) if(QDELETED(zapstart)) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index c4eaf50e45d0..f996f8ddb539 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -611,7 +611,7 @@ mix_message = "The mixture rapidly condenses and darkens in color..." /datum/chemical_reaction/cellulose_carbonization/ash // Sub for cellulose - required_reagents = list(/datum/reagent/ash_fibers) + required_reagents = list(/datum/reagent/ash_fibers = 1) /datum/chemical_reaction/fervor results = list(/datum/reagent/consumable/fervor = 10) diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 96c2a85c280c..11e9cab7212f 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -6,7 +6,7 @@ explode(holder, created_volume) /datum/chemical_reaction/reagent_explosion/proc/explode(datum/reagents/holder, created_volume) - if(QDELING(holder.my_atom)) + if(QDELETED(holder.my_atom)) return var/power = modifier + round(created_volume/strengthdiv, 1) if(power > 0) diff --git a/code/modules/unit_tests/create_and_destroy.dm b/code/modules/unit_tests/create_and_destroy.dm index ed3d9c6ed0a7..0e1d850a696f 100644 --- a/code/modules/unit_tests/create_and_destroy.dm +++ b/code/modules/unit_tests/create_and_destroy.dm @@ -174,11 +174,12 @@ oldest_packet_creation = min(qdeld_at, oldest_packet_creation) //If we've found a packet that got del'd later then we finished, then all our shit has been processed - if(oldest_packet_creation > start_time) + //That said, if there are any pending hard deletes you may NOT sleep, we gotta handle that shit + if(oldest_packet_creation > start_time && !length(SSgarbage.queues[GC_QUEUE_HARDDELETE])) garbage_queue_processed = TRUE break - if(REALTIMEOFDAY > real_start_time + time_needed + 30 MINUTES) //If this gets us gitbanned I'm going to laugh so hard + if(REALTIMEOFDAY > real_start_time + time_needed + 50 MINUTES) //If this gets us gitbanned I'm going to laugh so hard TEST_FAIL("Something has gone horribly wrong, the garbage queue has been processing for well over 30 minutes. What the hell did you do") break @@ -207,7 +208,7 @@ if(fails & BAD_INIT_NO_HINT) TEST_FAIL("[path] didn't return an Initialize hint") if(fails & BAD_INIT_QDEL_BEFORE) - TEST_FAIL("[path] qdel'd in New()") + TEST_FAIL("[path] qdel'd before we could call Initialize()") if(fails & BAD_INIT_SLEPT) TEST_FAIL("[path] slept during Initialize()")