[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>
This commit is contained in:
SkyratBot
2020-12-17 08:05:01 +01:00
committed by GitHub
co-authored by silicons
parent 08cb863bd1
commit 1459ec2edc
4 changed files with 41 additions and 31 deletions
@@ -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
+1 -1
View File
@@ -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))
@@ -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()
+29 -20
View File
@@ -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