diff --git a/code/datums/beam.dm b/code/datums/beam.dm index 7d57dd38e10..fdeedb47804 100644 --- a/code/datums/beam.dm +++ b/code/datums/beam.dm @@ -38,12 +38,15 @@ /datum/beam/proc/Start() recalculate() - recalculate_in(sleep_time) /datum/beam/proc/recalculate() + if(QDELETED(src)) + return + if(recalculating) recalculate_in(sleep_time) return + recalculating = TRUE timing_id = null var/turf/origin_turf = get_turf(origin) @@ -67,10 +70,12 @@ return /datum/beam/proc/recalculate_in(time) + if(QDELETED(src)) + return timing_id = addtimer(CALLBACK(src, PROC_REF(recalculate)), time, TIMER_STOPPABLE | TIMER_UNIQUE | TIMER_NO_HASH_WAIT | TIMER_OVERRIDE) /datum/beam/proc/after_calculate() - if((sleep_time == null) || finished) //Does not automatically recalculate. + if(QDELETED(src) || (sleep_time == null) || finished) //Does not automatically recalculate. return timing_id = addtimer(CALLBACK(src, PROC_REF(recalculate)), sleep_time, TIMER_STOPPABLE | TIMER_UNIQUE | TIMER_NO_HASH_WAIT) @@ -82,16 +87,17 @@ qdel(src) /datum/beam/proc/Reset() - for(var/obj/effect/ebeam/B in elements) - qdel(B) - elements.Cut() + QDEL_LIST(elements) /datum/beam/Destroy() if(timing_id) deltimer(timing_id) + timing_id = null Reset() target = null origin = null + target_oldloc = null + origin_oldloc = null return ..() /datum/beam/proc/Draw() diff --git a/code/modules/organs/internal/appendix.dm b/code/modules/organs/internal/appendix.dm index 62999b8f36e..b2114eaa2ee 100644 --- a/code/modules/organs/internal/appendix.dm +++ b/code/modules/organs/internal/appendix.dm @@ -65,8 +65,9 @@ owner.Weaken(10) var/obj/item/organ/external/E = owner.get_organ(parent_organ) - E.sever_artery() - E.germ_level = max(INFECTION_LEVEL_TWO, E.germ_level) + if(E) + E.sever_artery() + E.germ_level = max(INFECTION_LEVEL_TWO, E.germ_level) owner.adjustToxLoss(25) removed() qdel(src) diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index ffafa6d7c93..f50b7f27083 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -17,8 +17,14 @@ //Organ damage stats. var/damage = 0 // amount of damage to the organ - var/surge_damage = 0 // EMP damage counter. - var/surge_time = 0 + /// Total amount of EMP damage a mechanical organ has taken. Effectively equal to "number of seconds the organ EMP effect will last". + var/surge_damage = 0.0 + /** + * The amount of EMP damage a mechanical organ will recover per second. + * Fractional and floating points are allowed, but it shouldn't ever be negative. + */ + var/surge_recovery_per_second = 1.0 + var/min_broken_damage = 30 var/min_bruised_damage = 10 // Damage before considered bruised var/max_damage = 30 @@ -65,7 +71,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) LOG_DEBUG("[src] at [loc] spawned without a proper DNA.") var/mob/living/carbon/human/H = holder if(istype(H)) - if(internal) + if(internal && parent_organ) var/obj/item/organ/external/E = H.get_organ(parent_organ) if(E) if(E.internal_organs == null) @@ -158,52 +164,52 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) if(istype(loc,/obj/structure/closet/body_bag/cryobag) || istype(loc,/obj/structure/closet/crate/freezer) || istype(loc,/obj/item/storage/box/unique/freezer)) return //Process infections - if ((status & ORGAN_ROBOT) || (owner && owner.species && (owner.species.flags & IS_PLANT))) + var/is_immune = ((status & ORGAN_ROBOT) || robotic >= ROBOTIC_MECHANICAL || (owner && owner.species && (owner.species.flags & IS_PLANT))) + if (is_immune) germ_level = 0 - return - if(BP_IS_ROBOTIC(src) && surge_damage) - tick_surge_damage() + if((BP_IS_ROBOTIC(src) || robotic >= ROBOTIC_MECHANICAL) && surge_damage) + tick_surge_damage(seconds_per_tick) if(!owner) if (QDELETED(reagents)) LOG_DEBUG("Organ [DEBUG_REF(src)] had QDELETED reagents! Regenerating.") create_reagents(5) - if(REAGENT_VOLUME(reagents, /singleton/reagent/blood) && !(status & ORGAN_ROBOT) && prob(40)) + if(REAGENT_VOLUME(reagents, /singleton/reagent/blood) && !is_immune && prob(40)) reagents.remove_reagent(/singleton/reagent/blood,0.1) if (isturf(loc)) blood_splatter(src,src,TRUE) if(GLOB.config.organs_decay) damage += rand(1,3) if(damage >= max_damage) damage = max_damage - germ_level += rand(2,6) - if(germ_level >= INFECTION_LEVEL_TWO) + if(!is_immune) germ_level += rand(2,6) - if(germ_level >= INFECTION_LEVEL_THREE) - die() + if(germ_level >= INFECTION_LEVEL_TWO) + germ_level += rand(2,6) + if(germ_level >= INFECTION_LEVEL_THREE) + die() else if(owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs //** Handle antibiotics and curing infections handle_antibiotics() - handle_immunosuppressants() - handle_rejection() - handle_germ_effects() + if(!is_immune) + handle_immunosuppressants() + handle_rejection() + handle_germ_effects() //check if we've hit max_damage if(damage >= max_damage) die() -/obj/item/organ/proc/tick_surge_damage() - if(surge_damage) - do_surge_effects() - if(surge_time + 1 SECOND < world.time) - surge_damage = max(0, surge_damage - 10) - surge_time = world.time - if(!surge_damage) - surge_time = 0 - clear_surge_effects() +/obj/item/organ/proc/tick_surge_damage(seconds_per_tick) + if(!surge_damage) + clear_surge_effects() + return + + do_surge_effects() + surge_damage = max(0, surge_damage - (surge_recovery_per_second * seconds_per_tick)) /obj/item/organ/proc/do_surge_effects() return @@ -232,10 +238,10 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) if(antibiotics < 5 && prob(round(germ_level/7))) germ_level++ - if (germ_level >= INFECTION_LEVEL_TWO) + if (germ_level >= INFECTION_LEVEL_TWO && parent_organ) var/obj/item/organ/external/parent = owner.get_organ(parent_organ) //spread germs - if (antibiotics < 5 && parent.germ_level < germ_level && ( parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30) )) + if (parent && antibiotics < 5 && parent.germ_level < germ_level && ( parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30) )) parent.germ_level++ if (prob(3)) //about once every 30 seconds @@ -423,7 +429,6 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) return //We check earlier, but just to make sure. surge_damage = clamp(0, surge + surge_damage, MAXIMUM_SURGE_DAMAGE) //We want X seconds at most of hampered movement or what have you. - surge_time = world.time /** * Remove an organ @@ -443,7 +448,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) owner.internal_organs_by_name -= null owner.internal_organs -= src - if(detach) + if(detach && parent_organ) var/obj/item/organ/external/affected = owner.get_organ(parent_organ) if(affected) affected.internal_organs -= src diff --git a/code/modules/organs/pain.dm b/code/modules/organs/pain.dm index 84425782a51..e9171af43c5 100644 --- a/code/modules/organs/pain.dm +++ b/code/modules/organs/pain.dm @@ -86,8 +86,9 @@ // Damage to internal organs hurts a lot. for(var/obj/item/organ/internal/I in internal_organs) - if(prob(1) && !((I.status & ORGAN_DEAD) || BP_IS_ROBOTIC(I)) && I.damage > 5) + if(prob(1) && !((I.status & ORGAN_DEAD) || BP_IS_ROBOTIC(I)) && I.damage > 5 && I.parent_organ) var/obj/item/organ/external/parent = get_organ(I.parent_organ) + if (!parent) continue var/pain = 10 var/message = I.unknown_pain_location ? "You feel a dull pain in your [parent.name]..." : "You feel a dull pain radiating from your [I.name]..." if(I.is_bruised()) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 3928dcc9014..c72e142781d 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -519,7 +519,8 @@ ABSTRACT_TYPE(/obj/item/gun) P.suppressed = suppressed - P.preparePixelProjectile(target, get_turf(src)) + if(!P.preparePixelProjectile(target, get_turf(src))) + return FALSE P.fired_from = src P.fire() @@ -680,7 +681,8 @@ ABSTRACT_TYPE(/obj/item/gun) else if(mob.shock_stage > 70) added_spread = 15 - P.preparePixelProjectile(target, src, deviation = added_spread) + if(!P.preparePixelProjectile(target, src, params, added_spread)) + return FALSE P.firer = user P.fired_from = src P.def_zone = target_zone diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 62c7bbab89f..07fe18585a0 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -764,6 +764,8 @@ pixel_move(pixel_speed_multiplier, FALSE) /obj/projectile/proc/fire(angle, atom/direct_target) + if(QDELETED(src)) + return LAZYINITLIST(impacted) if(fired_from) SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original) @@ -984,8 +986,7 @@ */ /obj/projectile/proc/preparePixelProjectile(atom/target, atom/source, list/modifiers = null, deviation = 0) if(!(isnull(modifiers) || islist(modifiers))) - stack_trace("WARNING: Projectile [type] fired with non-list modifiers, likely was passed click params.") - modifiers = null + modifiers = params2list(modifiers) var/turf/source_loc = get_turf(source) var/turf/target_loc = get_turf(target) diff --git a/html/changelogs/hellfirejag-misc-guard-fixes.yml b/html/changelogs/hellfirejag-misc-guard-fixes.yml new file mode 100644 index 00000000000..46a7d7fb9a6 --- /dev/null +++ b/html/changelogs/hellfirejag-misc-guard-fixes.yml @@ -0,0 +1,7 @@ +author: Hellfirejag +delete-after: True +changes: + - bugfix: "Fixed mechanical organs and augments getting infections and never recovering correctly from EMP damage." + - bugfix: "Fixed some runtime errors with projectiles and firearms." + - bugfix: "Fixed some runtime errors with Beams." + - bugfix: "Fixed Mechanical Organs EMP effects being extremely underwhelming and short lived. An EMP grenade will disable mechanical organs for 30 seconds."