From 1459ec2edceb46784adf703ec7103efa6f12ecda Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Thu, 17 Dec 2020 08:05:01 +0100 Subject: [PATCH] [MIRROR] fixes the clusterfuck of projectile issues (#2199) * fixes the clusterfuck of projectile issues (#55495) * fixes the clusterfuck of projectile issues Co-authored-by: silicons <2003111+silicons@users.noreply.github.com> --- .../antagonists/blob/structures/_blob.dm | 2 +- code/modules/mob/living/living_movement.dm | 2 +- .../guns/energy/kinetic_accelerator.dm | 19 +++---- code/modules/projectiles/projectile.dm | 49 +++++++++++-------- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm index bee8f01595a..1d868f38cbe 100644 --- a/code/modules/antagonists/blob/structures/_blob.dm +++ b/code/modules/antagonists/blob/structures/_blob.dm @@ -4,7 +4,7 @@ icon = 'icons/mob/blob.dmi' light_range = 2 desc = "A thick wall of writhing tendrils." - density = FALSE //this being false causes two bugs, being able to attack blob tiles behind other blobs and being unable to move on blob tiles in no gravity, but turning it to 1 causes the blob mobs to be unable to path through blobs, which is probably worse. + density = TRUE opacity = FALSE anchored = TRUE layer = BELOW_MOB_LAYER diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 709550cbc56..629b3e5a6e1 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -8,7 +8,7 @@ if(.) return if(mover.throwing) - return (!density || body_position == LYING_DOWN || (mover.throwing.thrower == src && !ismob(mover))) + return (!density || (body_position == LYING_DOWN) || (mover.throwing.thrower == src && !ismob(mover))) if(buckled == mover) return TRUE if(ismob(mover) && (mover in buckled_mobs)) diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 4ba555769bc..4e8f3a35975 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -188,15 +188,16 @@ /obj/projectile/kinetic/prehit_pierce(atom/target) . = ..() - if(.) - if(kinetic_gun) - var/list/mods = kinetic_gun.modkits - for(var/obj/item/borg/upgrade/modkit/M in mods) - M.projectile_prehit(src, target, kinetic_gun) - if(!pressure_decrease_active && !lavaland_equipment_pressure_check(get_turf(target))) - name = "weakened [name]" - damage = damage * pressure_decrease - pressure_decrease_active = TRUE + if(. == PROJECTILE_PIERCE_PHASE) + return + if(kinetic_gun) + var/list/mods = kinetic_gun.modkits + for(var/obj/item/borg/upgrade/modkit/modkit in mods) + modkit.projectile_prehit(src, target, kinetic_gun) + if(!pressure_decrease_active && !lavaland_equipment_pressure_check(get_turf(target))) + name = "weakened [name]" + damage = damage * pressure_decrease + pressure_decrease_active = TRUE /obj/projectile/kinetic/on_range() strike_thing() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 2dbf436bdd3..b8050e04065 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -46,7 +46,7 @@ /** PROJECTILE PIERCING * WARNING: * Projectile piercing MUST be done using these variables. - * Ordinary passflags will be **IGNORED**. + * Ordinary passflags will result in can_hit_target being false unless directly clicked on - similar to projectile_phasing but without even going to process_hit. * The two flag variables below both use pass flags. * In the context of LETPASStHROW, it means the projectile will ignore things that are currently "in the air" from a throw. * @@ -324,7 +324,7 @@ /obj/projectile/Bump(atom/A) SEND_SIGNAL(src, COMSIG_MOVABLE_BUMP, A) - if(!can_hit_target(A, A == original, TRUE)) + if(!can_hit_target(A, A == original, TRUE, TRUE)) return Impact(A) @@ -364,7 +364,7 @@ var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations. def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use. - return process_hit(T, select_target(T, A)) // SELECT TARGET FIRST! + return process_hit(T, select_target(T, A, A), A) // SELECT TARGET FIRST! /** * The primary workhorse proc of projectile impacts. @@ -383,11 +383,13 @@ * @params * T - Turf we're on/supposedly hitting * target - target we're hitting + * bumped - target we originally bumped. it's here to ensure that if something blocks our projectile by means of Cross() failure, we hit it + * even if it is not dense. * hit_something - only should be set by recursive calling by this proc - tracks if we hit something already * * Returns if we hit something. */ -/obj/projectile/proc/process_hit(turf/T, atom/target, hit_something = FALSE) +/obj/projectile/proc/process_hit(turf/T, atom/target, atom/bumped, hit_something = FALSE) // 1. if(QDELETED(src) || !T || !target) return @@ -402,7 +404,7 @@ if(!(movement_type & PHASING)) temporary_unstoppable_movement = TRUE movement_type |= PHASING - return process_hit(T, select_target(T, target), hit_something) // try to hit something else + return process_hit(T, select_target(T, target, bumped), bumped, hit_something) // try to hit something else // at this point we are going to hit the thing // in which case send signal to it SEND_SIGNAL(target, COMSIG_PROJECTILE_PREHIT, args) @@ -414,7 +416,7 @@ if(!(movement_type & PHASING)) temporary_unstoppable_movement = TRUE movement_type |= PHASING - return process_hit(T, select_target(T, target), TRUE) + return process_hit(T, select_target(T, target, bumped), bumped, TRUE) qdel(src) return hit_something @@ -424,6 +426,8 @@ * @params * T - The turf * target - The "preferred" atom to hit, usually what we Bumped() first. + * bumped - used to track if something is the reason we impacted in the first place. + * If set, this atom is always treated as dense by can_hit_target. * * Priority: * 0. Anything that is already in impacted is ignored no matter what. Furthermore, in any bracket, if the target atom parameter is in it, that's hit first. @@ -435,51 +439,50 @@ * 4. Turf * 5. Nothing */ -/obj/projectile/proc/select_target(turf/T, atom/target) +/obj/projectile/proc/select_target(turf/T, atom/target, atom/bumped) // 1. original - if(can_hit_target(original, TRUE, FALSE)) + if(can_hit_target(original, TRUE, FALSE, original == bumped)) return original var/list/atom/possible = list() // let's define these ONCE var/list/atom/considering = list() // 2. mobs possible = typecache_filter_list(T, GLOB.typecache_living) // living only for(var/i in possible) - if(!can_hit_target(i, i == original, TRUE)) + if(!can_hit_target(i, i == original, TRUE, i == bumped)) continue considering += i if(considering.len) var/mob/living/M = pick(considering) return M.lowest_buckled_mob() considering.len = 0 - // 3. objs - possible = typecache_filter_list(T, GLOB.typecache_machine_or_structure) // because why are items ever dense? - for(var/i in possible) - if(!can_hit_target(i, i == original, TRUE)) + // 3. objs and other dense things + for(var/i in T.contents) + if(!can_hit_target(i, i == original, TRUE, i == bumped)) continue considering += i if(considering.len) return pick(considering) // 4. turf - if(can_hit_target(T, T == original, TRUE)) + if(can_hit_target(T, T == original, TRUE, T == bumped)) return T // 5. nothing // (returns null) //Returns true if the target atom is on our current turf and above the right layer //If direct target is true it's the originally clicked target. -/obj/projectile/proc/can_hit_target(atom/target, direct_target = FALSE, ignore_loc = FALSE) +/obj/projectile/proc/can_hit_target(atom/target, direct_target = FALSE, ignore_loc = FALSE, cross_failed = FALSE) if(QDELETED(target) || impacted[target]) return FALSE if(!ignore_loc && (loc != target.loc)) return FALSE - // if pass_flags match, pass through entirely - if(target.pass_flags_self & pass_flags) // phasing + // if pass_flags match, pass through entirely - unless direct target is set. + if((target.pass_flags_self & pass_flags) && !direct_target) return FALSE if(!ignore_source_check && firer) var/mob/M = firer if((target == firer) || ((target == firer.loc) && ismecha(firer.loc)) || (target in firer.buckled_mobs) || (istype(M) && (M.buckled == target))) return FALSE - if(target.density) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc. + if(target.density || cross_failed) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc. return TRUE if(!isliving(target)) if(isturf(target)) // non dense turfs @@ -493,8 +496,14 @@ if(direct_target) return TRUE // If target not able to use items, move and stand - or if they're just dead, pass over. - if(L.stat == DEAD || (!hit_stunned_targets && HAS_TRAIT(L, TRAIT_IMMOBILIZED) && HAS_TRAIT(L, TRAIT_FLOORED) && HAS_TRAIT(L, TRAIT_HANDS_BLOCKED))) + if(L.stat == DEAD) return FALSE + if(!L.density) + return FALSE + if(L.body_position != LYING_DOWN) + return TRUE + var/stunned = HAS_TRAIT(L, TRAIT_IMMOBILIZED) && HAS_TRAIT(L, TRAIT_FLOORED) && HAS_TRAIT(L, TRAIT_HANDS_BLOCKED) + return !stunned || hit_stunned_targets return TRUE /** @@ -570,7 +579,7 @@ * Return PROJECTILE_DELETE_WITHOUT_HITTING to delete projectile without hitting at all! */ /obj/projectile/proc/prehit_pierce(atom/A) - if(projectile_phasing & A.pass_flags_self) + if((projectile_phasing & A.pass_flags_self) && (!phasing_ignore_direct_target || original != A)) return PROJECTILE_PIERCE_PHASE if(projectile_piercing & A.pass_flags_self) return PROJECTILE_PIERCE_HIT