From 2fdb70b2b9f955ee8d5181b2d698fe5a8cabaf87 Mon Sep 17 00:00:00 2001 From: Solaris-Shade <73904284+Solaris-Shade@users.noreply.github.com> Date: Sun, 6 Mar 2022 15:20:23 -0500 Subject: [PATCH] [DNM][DNM][WIP] Projectile backend code port and update Ports#54924, #65061, #59804 from /tg. adds auxiliary code from /tg to make code work. --- code/__DEFINES/_flags/_flags.dm | 5 +- code/__DEFINES/projectiles.dm | 11 + code/_globalvars/bitfields.dm | 2 +- code/_onclick/adjacent.dm | 2 +- code/controllers/subsystem/throwing.dm | 2 +- code/datums/components/mirv.dm | 2 +- code/datums/components/pellet_cloud.dm | 2 +- code/game/atoms.dm | 34 +- code/game/atoms_movable.dm | 14 +- code/game/machinery/_machinery.dm | 1 + code/game/machinery/deployable.dm | 25 +- code/game/machinery/doors/door.dm | 6 +- code/game/machinery/doors/firedoor.dm | 14 +- code/game/machinery/doors/windowdoor.dm | 21 +- code/game/machinery/recycler.dm | 2 +- code/game/machinery/shieldgen.dm | 5 +- code/game/machinery/transformer.dm | 10 +- .../effects/effect_system/effects_foam.dm | 12 +- .../effects/effect_system/effects_smoke.dm | 10 +- code/game/objects/effects/spiders.dm | 4 +- code/game/objects/items/cardboard_cutouts.dm | 4 +- .../items/devices/forcefieldprojector.dm | 6 +- code/game/objects/objs.dm | 6 +- code/game/objects/structures.dm | 4 +- code/game/objects/structures/aliens.dm | 5 - .../structures/crates_lockers/closets.dm | 4 +- .../structures/crates_lockers/crates.dm | 8 +- code/game/objects/structures/girders.dm | 10 +- code/game/objects/structures/grille.dm | 13 +- code/game/objects/structures/holosign.dm | 44 +- code/game/objects/structures/mineral_doors.dm | 4 +- code/game/objects/structures/morgue.dm | 20 +- code/game/objects/structures/plasticflaps.dm | 5 +- code/game/objects/structures/railings.dm | 2 +- code/game/objects/structures/tables_racks.dm | 23 +- .../structures/transit_tubes/transit_tube.dm | 6 +- .../objects/structures/windoor_assembly.dm | 16 +- code/game/objects/structures/window.dm | 20 +- code/game/turfs/closed.dm | 6 +- code/game/turfs/simulated/chasm.dm | 3 - code/game/turfs/turf.dm | 23 +- .../antagonists/blob/blob/blobs/blob_mobs.dm | 6 +- code/modules/antagonists/blob/blob/theblob.dm | 12 +- code/modules/antagonists/swarmer/swarmer.dm | 11 +- code/modules/assembly/infrared.dm | 3 +- code/modules/awaymissions/away_props.dm | 5 +- code/modules/awaymissions/capture_the_flag.dm | 8 +- code/modules/events/spacevine.dm | 2 +- code/modules/fields/turf_objects.dm | 4 +- code/modules/flufftext/Hallucination.dm | 4 +- code/modules/holiday/halloween/halloween.dm | 5 +- code/modules/hydroponics/grown/towercap.dm | 8 +- code/modules/mining/minebot.dm | 4 +- code/modules/mob/dead/observer/observer.dm | 3 - .../mob/living/carbon/human/human_defense.dm | 4 +- code/modules/mob/living/living_defense.dm | 4 +- code/modules/mob/living/living_movement.dm | 12 +- .../mob/living/silicon/silicon_defense.dm | 4 +- .../living/simple_animal/animal_defense.dm | 4 +- .../simple_animal/hostile/jungle/mook.dm | 4 +- .../hostile/megafauna/bubblegum.dm | 12 +- .../hostile/megafauna/hierophant.dm | 4 +- .../simple_animal/hostile/megafauna/legion.dm | 2 +- .../hostile/mining_mobs/curse_blob.dm | 4 +- .../hostile/mining_mobs/elites/elite.dm | 5 +- .../mob/living/simple_animal/slime/slime.dm | 4 +- code/modules/mob/mob_defines.dm | 2 +- .../plumbing/plumbers/grinder_chemical.dm | 2 +- .../power/singularity/containment_field.dm | 4 +- .../guns/energy/kinetic_accelerator.dm | 4 +- .../projectiles/guns/misc/beam_rifle.dm | 76 ++-- .../projectiles/guns/misc/blastcannon.dm | 3 +- code/modules/projectiles/projectile.dm | 396 ++++++++++++------ code/modules/projectiles/projectile/beams.dm | 2 +- .../projectile/bullets/ferromagnetic.dm | 4 +- .../projectiles/projectile/bullets/sniper.dm | 3 +- .../projectiles/projectile/bullets/special.dm | 3 +- code/modules/projectiles/projectile/magic.dm | 13 +- .../projectiles/projectile/special/curse.dm | 11 +- .../ruins/objects_and_mobs/necropolis_gate.dm | 8 +- .../ruins/objects_and_mobs/sin_ruins.dm | 5 +- code/modules/shuttle/special.dm | 5 +- code/modules/spells/spell_types/forcewall.dm | 4 +- code/modules/vehicles/ridden.dm | 1 + 84 files changed, 597 insertions(+), 503 deletions(-) diff --git a/code/__DEFINES/_flags/_flags.dm b/code/__DEFINES/_flags/_flags.dm index 5f591b429b..99c9b293fb 100644 --- a/code/__DEFINES/_flags/_flags.dm +++ b/code/__DEFINES/_flags/_flags.dm @@ -104,6 +104,7 @@ GLOBAL_LIST_INIT(bitflags, list( #define PASSBLOB (1<<3) #define PASSMOB (1<<4) #define PASSCLOSEDTURF (1<<5) +/// Let thrown things past us. **ONLY MEANINGFUL ON pass_flags_self!** #define LETPASSTHROW (1<<6) //Movement Types @@ -111,8 +112,8 @@ GLOBAL_LIST_INIT(bitflags, list( #define FLYING (1<<1) #define VENTCRAWLING (1<<2) #define FLOATING (1<<3) -///When moving, will Bump()/Cross()/Uncross() everything, but won't be stopped. -#define UNSTOPPABLE (1<<4) +///When moving, will Bump()/Cross()/Uncross() everything, but won't stop or Bump() anything. +#define PHASING (1<<4) ///Applied if you're crawling around on the ground/resting. #define CRAWLING (1<<5) diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm index 1bd67fbe02..70a2d611ab 100644 --- a/code/__DEFINES/projectiles.dm +++ b/code/__DEFINES/projectiles.dm @@ -1,3 +1,14 @@ + +// check_pierce() return values +/// Default behavior: hit and delete self +#define PROJECTILE_PIERCE_NONE 0 +/// Hit the thing but go through without deleting. Causes on_hit to be called with pierced = TRUE +#define PROJECTILE_PIERCE_HIT 1 +/// Entirely phase through the thing without ever hitting. +#define PROJECTILE_PIERCE_PHASE 2 +// Delete self without hitting +#define PROJECTILE_DELETE_WITHOUT_HITTING 3 + /// This atom should be ricocheted off of from its inherent properties using standard % chance handling. #define PROJECTILE_RICOCHET_YES 1 /// This atom should not be ricocheted off of from its inherent properties. diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index df3b6e5334..e3675a53f5 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -130,7 +130,7 @@ GLOBAL_LIST_INIT(bitfields, list( "FLYING" = FLYING, "VENTCRAWLING" = VENTCRAWLING, "FLOATING" = FLOATING, - "UNSTOPPABLE" = UNSTOPPABLE + "PHASING" = PHASING ), "resistance_flags" = list( "LAVA_PROOF" = LAVA_PROOF, diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index 3f3eecb676..e629a6eb57 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -94,7 +94,7 @@ for(var/obj/O in src) if((mover && O.CanPass(mover,get_step(src,target_dir))) || (!mover && !O.density)) continue - if(O == target_atom || O == mover || (O.pass_flags & LETPASSTHROW)) //check if there's a dense object present on the turf + if(O == target_atom || O == mover || (O.pass_flags_self & LETPASSTHROW)) //check if there's a dense object present on the turf continue // LETPASSTHROW is used for anything you can click through (or the firedoor special case, see above) if( O.flags_1&ON_BORDER_1) // windows are on border, check them first diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index 0fa8035d72..2ff1e284d0 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -200,6 +200,6 @@ SUBSYSTEM_DEF(throwing) var/atom/movable/AM = thing if (AM == thrownthing || (AM == thrower && !ismob(thrownthing))) continue - if (AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags_1 & ON_BORDER_1)) + if (AM.density && !(AM.pass_flags_self & LETPASSTHROW) && !(AM.flags_1 & ON_BORDER_1)) finalize(hit=TRUE, target=AM) return TRUE diff --git a/code/datums/components/mirv.dm b/code/datums/components/mirv.dm index 2a1663776c..77c47bcb1d 100644 --- a/code/datums/components/mirv.dm +++ b/code/datums/components/mirv.dm @@ -38,5 +38,5 @@ P.range = override_projectile_range P.preparePixelProjectile(shootat_turf, target) P.firer = firer // don't hit ourself that would be really annoying - P.permutated += target // don't hit the target we hit already with the flak + P.impacted = list(target = TRUE) // don't hit the target we hit already with the flak P.fire() diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm index dcc806d991..a06242962f 100644 --- a/code/datums/components/pellet_cloud.dm +++ b/code/datums/components/pellet_cloud.dm @@ -242,7 +242,7 @@ P.original = target P.fired_from = parent P.firer = parent // don't hit ourself that would be really annoying - P.permutated += parent // don't hit the target we hit already with the flak + P.impacted = list(parent = TRUE) // don't hit the target we hit already with the flak P.suppressed = SUPPRESSED_VERY // set the projectiles to make no message so we can do our own aggregate message P.preparePixelProjectile(target, parent) RegisterSignal(P, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 40162a6c9b..e4b7507560 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -9,6 +9,9 @@ plane = GAME_PLANE appearance_flags = TILE_BOUND + /// pass_flags that we are. If any of this matches a pass_flag on a moving thing, by default, we let them through. + var/pass_flags_self = NONE + var/level = 2 ///If non-null, overrides a/an/some in all cases var/article @@ -269,12 +272,27 @@ return FALSE if((P.flag in list("bullet", "bomb")) && P.ricochet_incidence_leeway) if((a_incidence_s < 90 && a_incidence_s < 90 - P.ricochet_incidence_leeway) || (a_incidence_s > 270 && a_incidence_s -270 > P.ricochet_incidence_leeway)) - return + return FALSE var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s) P.setAngle(new_angle_s) return TRUE /atom/proc/CanPass(atom/movable/mover, turf/target) + SHOULD_CALL_PARENT(TRUE) + if(mover.movement_type & PHASING) + return TRUE + . = CanAllowThrough(mover, target) + // This is cheaper than calling the proc every time since most things dont override CanPassThrough + if(!mover.generic_canpass) + return mover.CanPassThrough(src, target, .) + +/// Returns true or false to allow the mover to move through src +/atom/proc/CanAllowThrough(atom/movable/mover, turf/target) + SHOULD_CALL_PARENT(TRUE) + if(mover.pass_flags & pass_flags_self) + return TRUE + if(mover.throwing && (pass_flags_self & LETPASSTHROW)) + return TRUE return !density /** @@ -445,9 +463,19 @@ wires.emp_pulse(severity) return protection // Pass the protection value collected here upwards -/atom/proc/bullet_act(obj/item/projectile/P, def_zone) +/** + * React to a hit by a projectile object + * + * Default behaviour is to send the [COMSIG_ATOM_BULLET_ACT] and then call [on_hit][/obj/item/projectile/proc/on_hit] on the projectile + * + * @params + * P - projectile + * def_zone - zone hit + * piercing_hit - is this hit piercing or normal? + */ +/atom/proc/bullet_act(obj/item/projectile/P, def_zone, piercing_hit = FALSE) SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, P, def_zone) - . = P.on_hit(src, 0, def_zone) + . = P.on_hit(src, 0, def_zone, piercing_hit) //used on altdisarm() for special interactions between the shoved victim (target) and the src, with user being the one shoving the target on it. // IMPORTANT: if you wish to add a new own shove_act() to a certain object, remember to add SHOVABLE_ONTO to its obj_flags bitfied var first. diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 5da389fbb8..56c668a24b 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -25,7 +25,10 @@ var/inertia_moving = 0 var/inertia_next_move = 0 var/inertia_move_delay = 5 - var/pass_flags = 0 + /// Things we can pass through while moving. If any of this matches the thing we're trying to pass's [pass_flags_self], then we can pass through. + var/pass_flags = NONE + /// If false makes CanPass call CanPassThrough on this type instead of using default behaviour + var/generic_canpass = TRUE var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move var/atom/movable/moving_from_pull //attempt to resume grab after moving instead of before. var/list/acted_explosions //for explosion dodging @@ -473,10 +476,15 @@ /atom/movable/proc/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) return FALSE -/atom/movable/CanPass(atom/movable/mover, turf/target) +/atom/movable/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(mover in buckled_mobs) return TRUE - return ..() + +/// Returns true or false to allow src to move through the blocker, mover has final say +/atom/movable/proc/CanPassThrough(atom/blocker, turf/target, blocker_opinion) + SHOULD_CALL_PARENT(TRUE) + return blocker_opinion /// called when this atom is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called. /atom/movable/proc/on_exit_storage(datum/component/storage/concrete/S) // rename S to master_storage diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index f40adcd00b..675d54ef22 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -90,6 +90,7 @@ Class Procs: verb_say = "beeps" verb_yell = "blares" pressure_resistance = 15 + pass_flags_self = PASSMACHINE max_integrity = 200 layer = BELOW_OBJ_LAYER //keeps shit coming out of the machine from ending up underneath it. flags_1 = DEFAULT_RICOCHET_1 diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index ca4b392efa..b720a92402 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -37,22 +37,19 @@ else return ..() -/obj/structure/barricade/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff. +/obj/structure/barricade/CanAllowThrough(atom/movable/mover, turf/target)//So bullets will fly over and stuff. + . = ..() if(locate(/obj/structure/barricade) in get_turf(mover)) - return 1 + return TRUE else if(istype(mover, /obj/item/projectile)) if(!anchored) - return 1 + return TRUE var/obj/item/projectile/proj = mover if(proj.firer && Adjacent(proj.firer)) - return 1 + return TRUE if(prob(proj_pass_rate)) - return 1 - return 0 - else - return !density - - + return TRUE + return FALSE /////BARRICADE TYPES/////// @@ -79,7 +76,6 @@ return return ..() - /obj/structure/barricade/wooden/crude name = "crude plank barricade" desc = "This space is blocked off by a crude assortment of planks." @@ -96,7 +92,6 @@ /obj/structure/barricade/wooden/make_debris() new /obj/item/stack/sheet/mineral/wood(get_turf(src), drop_amount) - /obj/structure/barricade/sandbags name = "sandbags" desc = "Bags of sand. Self explanatory." @@ -104,13 +99,12 @@ icon_state = "sandbags" max_integrity = 280 proj_pass_rate = 20 - pass_flags = LETPASSTHROW + pass_flags_self = LETPASSTHROW bar_material = SAND climbable = TRUE smooth = SMOOTH_TRUE canSmoothWith = list(/obj/structure/barricade/sandbags, /turf/closed/wall, /turf/closed/wall/r_wall, /obj/structure/falsewall, /obj/structure/falsewall/reinforced, /turf/closed/wall/rust, /turf/closed/wall/r_wall/rust, /obj/structure/barricade/security) - /obj/structure/barricade/security name = "security barrier" desc = "A deployable barrier. Provides good cover in fire fights." @@ -125,7 +119,6 @@ var/deploy_time = 40 var/deploy_message = TRUE - /obj/structure/barricade/security/Initialize() . = ..() addtimer(CALLBACK(src, .proc/deploy), deploy_time) @@ -137,7 +130,6 @@ if(deploy_message) visible_message("[src] deploys!") - /obj/item/grenade/barrier name = "barrier grenade" desc = "Instant cover." @@ -194,7 +186,6 @@ /obj/item/grenade/barrier/ui_action_click(mob/user) toggle_mode(user) - #undef SINGLE #undef VERTICAL #undef HORIZONTAL diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index d1781d9477..71df6affb7 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -127,10 +127,12 @@ . = ..() move_update_air(T) -/obj/machinery/door/CanPass(atom/movable/mover, turf/target) +/obj/machinery/door/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + + // Snowflake handling for PASSGLASS. if(istype(mover) && (mover.pass_flags & PASSGLASS)) return !opacity - return !density /obj/machinery/door/proc/bumpopen(mob/user) if(operating) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index d84b994b92..62eb08735f 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -347,21 +347,15 @@ return 0 // not big enough to matter return start_point.air.return_pressure() < 20 ? -1 : 1 -/obj/machinery/door/firedoor/border_only/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return TRUE - if(get_dir(loc, target) == dir) //Make sure looking at appropriate border - return !density - else +/obj/machinery/door/firedoor/border_only/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(!(get_dir(loc, target) == dir)) //Make sure looking at appropriate border return TRUE /obj/machinery/door/firedoor/border_only/CheckExit(atom/movable/mover as mob|obj, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return TRUE if(get_dir(loc, target) == dir) return !density - else - return TRUE + return TRUE /obj/machinery/door/firedoor/border_only/CanAtmosPass(turf/T) if(get_dir(loc, T) == dir) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index af7545d3c9..5027e46aa0 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -12,6 +12,7 @@ armor = list("melee" = 20, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 70, "acid" = 100) visible = FALSE flags_1 = ON_BORDER_1|DEFAULT_RICOCHET_1 + pass_flags_self = PASSGLASS opacity = 0 CanAtmosPass = ATMOS_PASS_PROC interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN @@ -103,11 +104,12 @@ do_animate("deny") return -/obj/machinery/door/window/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return 1 +/obj/machinery/door/window/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(.) + return if(get_dir(loc, target) == dir) //Make sure looking at appropriate border - return !density + return if(istype(mover, /obj/structure/window)) var/obj/structure/window/W = mover if(!valid_window_location(loc, W.ini_dir)) @@ -119,7 +121,7 @@ else if(istype(mover, /obj/machinery/door/window) && !valid_window_location(loc, mover.dir)) return FALSE else - return 1 + return TRUE /obj/machinery/door/window/CanAtmosPass(turf/T) if(get_dir(loc, T) == dir) @@ -131,13 +133,12 @@ /obj/machinery/door/window/CanAStarPass(obj/item/card/id/ID, to_dir) return !density || (dir != to_dir) || (check_access(ID) && hasPower()) -/obj/machinery/door/window/CheckExit(atom/movable/mover as mob|obj, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return 1 +/obj/machinery/door/window/CheckExit(atom/movable/mover, turf/target) + if((pass_flags_self & mover.pass_flags)) || ((pass_flags_self & LETPASSTHROW) && mover.throwing)) + return TRUE if(get_dir(loc, target) == dir) return !density - else - return 1 + return TRUE /obj/machinery/door/window/open(forced=0) if (src.operating == 1) //doors can still open when emag-disabled diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 21ef8e2dcf..7129b6fe57 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -87,7 +87,7 @@ is_powered = FALSE icon_state = icon_name + "[is_powered]" + "[(blood ? "bld" : "")]" // add the blood tag at the end -/obj/machinery/recycler/CanPass(atom/movable/AM) +/obj/machinery/recycler/CanAllowThrough(atom/movable/AM) . = ..() if(!anchored) return diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 2ebb137839..51f16c3425 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -454,11 +454,10 @@ if(gen_secondary) //using power may cause us to be destroyed gen_secondary.use_stored_power(drain_amount*0.5) -/obj/machinery/shieldwall/CanPass(atom/movable/mover, turf/target) +/obj/machinery/shieldwall/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(istype(mover) && (mover.pass_flags & PASSGLASS)) return prob(20) else if(istype(mover, /obj/item/projectile)) return prob(10) - else - return !density diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm index 8bca58a7de..afaf617cbc 100644 --- a/code/game/machinery/transformer.dm +++ b/code/game/machinery/transformer.dm @@ -57,14 +57,14 @@ AM.forceMove(drop_location()) do_transform(AM) -/obj/machinery/transformer/CanPass(atom/movable/mover, turf/target) +/obj/machinery/transformer/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() // Allows items to go through, // to stop them from blocking the conveyor belt. if(!ishuman(mover)) - var/dir = get_dir(src, mover) - if(dir == EAST) - return ..() - return 0 + if(get_dir(src, mover) == EAST) + return + return FALSE /obj/machinery/transformer/process() if(cooldown && (cooldown_timer <= world.time)) diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm index a0f53ceab7..d4a198a5b0 100644 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -291,9 +291,6 @@ to_chat(user, "You hit [src] but bounce off it!") playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) -/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target) - return !density - /obj/structure/foamedmetal/iron max_integrity = 50 icon_state = "ironfoam" @@ -306,6 +303,7 @@ icon_state = "atmos_resin" alpha = 120 max_integrity = 10 + pass_flags_self = PASSGLASS /obj/structure/foamedmetal/resin/Initialize() . = ..() @@ -336,14 +334,6 @@ for(var/obj/item/Item in O) Item.extinguish() -/obj/structure/foamedmetal/resin/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return TRUE - . = ..() - -/obj/structure/foamedmetal/resin/BlockThermalConductivity() - return TRUE - #undef ALUMINUM_FOAM #undef IRON_FOAM #undef RESIN_FOAM diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm index 3e80ade0ce..db1b9d5b2b 100644 --- a/code/game/objects/effects/effect_system/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/effects_smoke.dm @@ -133,13 +133,11 @@ M.emote("cough") return 1 -/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, turf/target) - if(istype(mover, /obj/item/projectile/beam)) - var/obj/item/projectile/beam/B = mover +/obj/effect/particle_effect/smoke/bad/Crossed(atom/movable/AM, oldloc) + . = ..() + if(istype(AM, /obj/projectile/beam)) + var/obj/projectile/beam/B = AM B.damage = (B.damage/2) - return 1 - - /datum/effect_system/smoke_spread/bad effect_type = /obj/effect/particle_effect/smoke/bad diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index 4b04606401..1c8df008fd 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -36,7 +36,8 @@ icon_state = "stickyweb2" . = ..() -/obj/structure/spider/stickyweb/CanPass(atom/movable/mover, turf/target) +/obj/structure/spider/stickyweb/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if (genetic) return if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider)) @@ -49,7 +50,6 @@ return FALSE else if(istype(mover, /obj/item/projectile)) return prob(30) - return TRUE /obj/structure/spider/stickyweb/genetic //for the spider genes in genetics genetic = TRUE diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index a8ff7b9004..4a59118c8a 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -92,9 +92,9 @@ if(prob(I.force)) push_over() -/obj/item/cardboard_cutout/bullet_act(obj/item/projectile/P) +/obj/item/cardboard_cutout/bullet_act(obj/item/projectile/P, def_zone, piercing_hit = FALSE) if(istype(P, /obj/item/projectile/bullet/reusable)) - P.on_hit(src, 0) + P.on_hit(src, 0, piercing_hit) visible_message("[src] has been hit by [P]!") playsound(src, 'sound/weapons/slice.ogg', 50, 1) if(prob(P.damage)) diff --git a/code/game/objects/items/devices/forcefieldprojector.dm b/code/game/objects/items/devices/forcefieldprojector.dm index 9ef9d73705..71f69a5c93 100644 --- a/code/game/objects/items/devices/forcefieldprojector.dm +++ b/code/game/objects/items/devices/forcefieldprojector.dm @@ -84,6 +84,7 @@ layer = ABOVE_ALL_MOB_LAYER anchored = TRUE density = TRUE + pass_flags_self = PASSGLASS mouse_opacity = MOUSE_OPACITY_OPAQUE resistance_flags = INDESTRUCTIBLE CanAtmosPass = ATMOS_PASS_DENSITY @@ -101,11 +102,6 @@ generator = null return ..() -/obj/structure/projected_forcefield/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return 1 - return !density - /obj/structure/projected_forcefield/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) playsound(loc, 'sound/weapons/egloves.ogg', 80, 1) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index e263678943..0651891421 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -238,7 +238,11 @@ /obj/get_dumping_location(datum/component/storage/source,mob/user) return get_turf(src) -/obj/proc/CanAStarPass() +/obj/proc/CanAStarPass(ID, dir, caller) + if(ismovable(caller)) + var/atom/movable/AM = caller + if(AM.pass_flags & pass_flags_self) + return TRUE . = !density /obj/proc/check_uplink_validity() diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 52036427c8..a8f0739bed 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -10,9 +10,11 @@ var/broken = 0 //similar to machinery's stat BROKEN layer = BELOW_OBJ_LAYER //ricochets on structures commented out for now because there's a lot of structures that /shouldnt/ be ricocheting and those need to be reviewed first + //With the addition of [pass_flags_self] the ricocheting of structures /shouldnt/ happen by default thus the existing code could be uncommented out - Solaris-Shade //flags_1 = DEFAULT_RICOCHET_1 //flags_ricochet = RICOCHET_HARD //ricochet_chance_mod = 0.5 + pass_flags_self = PASSSTRUCTURE /obj/structure/Initialize() if (!armor) @@ -114,4 +116,4 @@ return "It's falling apart!" /obj/structure/rust_heretic_act() - take_damage(500, BRUTE, "melee", 1) + take_damage(500, BRUTE, "melee", 1) diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index bc7ce8c36e..bd90db9c12 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -97,11 +97,6 @@ /obj/structure/alien/resin/attack_paw(mob/user) return attack_hand(user) - -/obj/structure/alien/resin/CanPass(atom/movable/mover, turf/target) - return !density - - /* * Weeds */ diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index af4d098157..b511ed7e2d 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -110,10 +110,10 @@ if(HAS_TRAIT(user, TRAIT_SKITTISH)) . += "If you bump into [p_them()] while running, you will jump inside." -/obj/structure/closet/CanPass(atom/movable/mover, turf/target) +/obj/structure/closet/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(wall_mounted) return TRUE - return !density /obj/structure/closet/proc/can_open(mob/living/user, force = FALSE) if(force) diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index f6153330e4..ec97dad72c 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -26,15 +26,15 @@ // AddElement(/datum/element/climbable, climb_time = crate_climb_time, climb_stun = 0) update_icon() -/obj/structure/closet/crate/CanPass(atom/movable/mover, turf/target) +/obj/structure/closet/crate/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(!istype(mover, /obj/structure/closet)) var/obj/structure/closet/crate/locatedcrate = locate(/obj/structure/closet/crate) in get_turf(mover) if(locatedcrate) //you can walk on it like tables, if you're not in an open crate trying to move to a closed crate if(opened) //if we're open, allow entering regardless of located crate openness - return 1 + return TRUE if(!locatedcrate.opened) //otherwise, if the located crate is closed, allow entering - return 1 - return !density + return TRUE /obj/structure/closet/crate/update_icon_state() icon_state = "[initial(icon_state)][opened ? "open" : ""]" diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 50240aabb3..3e6884613e 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -296,14 +296,10 @@ qdel(src) return TRUE -/obj/structure/girder/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGRILLE)) +/obj/structure/girder/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if((mover.pass_flags & PASSGRILLE) || istype(mover, /obj/projectile)) return prob(girderpasschance) - else - if(istype(mover, /obj/item/projectile)) - return prob(girderpasschance) - else - return 0 /obj/structure/girder/CanAStarPass(ID, dir, caller) . = !density diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 2ac85f79dc..54dce18d44 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -5,6 +5,7 @@ icon_state = "grille" density = TRUE anchored = TRUE + pass_flags_self = PASSGRILLE flags_1 = CONDUCT_1 pressure_resistance = 5*ONE_ATMOSPHERE layer = BELOW_OBJ_LAYER @@ -124,14 +125,10 @@ if(!shock(user, 70)) take_damage(20, BRUTE, "melee", 1) -/obj/structure/grille/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGRILLE)) - return TRUE - else - if(istype(mover, /obj/item/projectile) && density) - return prob(30) - else - return !density +/obj/structure/grille/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(!. && istype(mover, /obj/projectile)) + return prob(30) /obj/structure/grille/CanAStarPass(ID, dir, caller) . = !density diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm index cb9309c4c4..26dedf3b62 100644 --- a/code/game/objects/structures/holosign.dm +++ b/code/game/objects/structures/holosign.dm @@ -51,20 +51,19 @@ name = "holo barrier" desc = "A short holographic barrier which can only be passed by walking." icon_state = "holosign_sec" - pass_flags = LETPASSTHROW + pass_flags_self = PASSTABLE | PASSGRILLE | PASSGLASS | LETPASSTHROW density = TRUE max_integrity = 20 var/allow_walk = 1 //can we pass through it on walk intent -/obj/structure/holosign/barrier/CanPass(atom/movable/mover, turf/target) - if(!density) - return 1 - if(mover.pass_flags & (PASSGLASS|PASSTABLE|PASSGRILLE)) - return 1 +/obj/structure/holosign/barrier/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(.) + return if(iscarbon(mover)) var/mob/living/carbon/C = mover if(allow_walk && C.m_intent == MOVE_INTENT_WALK) - return 1 + return TRUE /obj/structure/holosign/barrier/engineering icon_state = "holosign_engi" @@ -149,22 +148,27 @@ . = ..() . += "The biometric scanners are [force_allaccess ? "off" : "on"]." -/obj/structure/holosign/barrier/medical/CanPass(atom/movable/mover, turf/target) - icon_state = "holo_medical" +/obj/structure/holosign/barrier/medical/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(force_allaccess) return TRUE if(ishuman(mover)) - var/mob/living/carbon/human/sickboi = mover - var/threat = sickboi.check_virus() - switch(threat) - if(DISEASE_SEVERITY_MINOR, DISEASE_SEVERITY_MEDIUM, DISEASE_SEVERITY_HARMFUL, DISEASE_SEVERITY_DANGEROUS, DISEASE_SEVERITY_BIOHAZARD) - if(buzzcd < world.time) - playsound(get_turf(src),'sound/machines/buzz-sigh.ogg',65,1,4) - buzzcd = (world.time + 60) - icon_state = "holo_medical-deny" - return FALSE - else - return TRUE //nice or benign diseases! + + return CheckHuman(mover) + +/obj/structure/holosign/barrier/medical/Bumped(atom/movable/AM) + . = ..() + icon_state = "holo_medical" + if(ishuman(AM) && !CheckHuman(AM)) + if(buzzcd < world.time) + playsound(get_turf(src),'sound/machines/buzz-sigh.ogg',65,TRUE,4) + buzzcd = (world.time + 60) + icon_state = "holo_medical-deny" + +/obj/structure/holosign/barrier/medical/proc/CheckHuman(mob/living/carbon/human/sickboi) + var/threat = sickboi.check_virus() + if(get_disease_severity_value(threat) > get_disease_severity_value(DISEASE_SEVERITY_MINOR)) + return FALSE return TRUE /obj/structure/holosign/barrier/medical/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags) diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index b2f1de8750..ecd7c1a03e 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -53,10 +53,10 @@ /obj/structure/mineral_door/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags) return TryToSwitchState(user) -/obj/structure/mineral_door/CanPass(atom/movable/mover, turf/target) +/obj/structure/mineral_door/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(istype(mover, /obj/effect/beam)) return !opacity - return !density /obj/structure/mineral_door/proc/TryToSwitchState(atom/user) if(isSwitchingStates) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 73268009ce..f98151e76a 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -306,7 +306,7 @@ GLOBAL_LIST_EMPTY(crematoriums) layer = TRAY_LAYER var/obj/structure/bodycontainer/connected = null anchored = TRUE - pass_flags = LETPASSTHROW + pass_flags_self = LETPASSTHROW max_integrity = 350 /obj/structure/tray/Destroy() @@ -362,17 +362,11 @@ GLOBAL_LIST_EMPTY(crematoriums) name = "morgue tray" desc = "Apply corpse before closing." icon_state = "morguet" + pass_flags_self = PASSTABLE -/obj/structure/tray/m_tray/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSTABLE)) - return 1 +/obj/structure/tray/m_tray/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(.) + return if(locate(/obj/structure/table) in get_turf(mover)) - return 1 - else - return 0 - -/obj/structure/tray/m_tray/CanAStarPass(ID, dir, caller) - . = !density - if(ismovable(caller)) - var/atom/movable/mover = caller - . = . || (mover.pass_flags & PASSTABLE) + return TRUE diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index ff8287d77b..4e916d57a6 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -69,7 +69,9 @@ return CanAStarPass(ID, to_dir, M.pulling) return 1 //diseases, stings, etc can pass -/obj/structure/plasticflaps/CanPass(atom/movable/A, turf/T) +/obj/structure/plasticflaps/CanAllowThrough(atom/movable/A, turf/T) + . = ..() + if(istype(A) && (A.pass_flags & PASSGLASS)) return prob(60) @@ -93,7 +95,6 @@ return 1 if(!M.lying && !(SEND_SIGNAL(M, COMSIG_CHECK_VENTCRAWL)) && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass. return 0 - return ..() /obj/structure/plasticflaps/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index 21cf97ba70..13bc676239 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -78,7 +78,7 @@ /obj/structure/railing/CheckExit(atom/movable/mover, turf/target) ..() if(get_dir(loc, target) & dir) - var/checking = UNSTOPPABLE | FLYING | FLOATING + var/checking = PHASING | FLYING | FLOATING return !density || mover.throwing || mover.movement_type & checking || mover.move_force >= MOVE_FORCE_EXTREMELY_STRONG return TRUE diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 065c0d2f28..2435e9a5f6 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -19,10 +19,10 @@ icon_state = "table" density = TRUE anchored = TRUE + pass_flags_self = PASSTABLE | LETPASSTHROW layer = TABLE_LAYER climbable = TRUE obj_flags = CAN_BE_HIT|SHOVABLE_ONTO - pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density.") attack_hand_speed = CLICK_CD_MELEE attack_hand_is_action = TRUE var/frame = /obj/structure/table_frame @@ -99,15 +99,14 @@ /obj/structure/table/attack_tk() return FALSE -/obj/structure/table/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSTABLE)) - return 1 +/obj/structure/table/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(.) + return if(mover.throwing) - return 1 + return TRUE if(locate(/obj/structure/table) in get_turf(mover)) - return 1 - else - return !density + return TRUE /obj/structure/table/CanAStarPass(ID, dir, caller) . = !density @@ -685,7 +684,7 @@ layer = TABLE_LAYER density = TRUE anchored = TRUE - pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density. + pass_flags_self = LETPASSTHROW //You can throw objects over this, despite it's density. max_integrity = 20 attack_hand_speed = CLICK_CD_MELEE attack_hand_is_action = TRUE @@ -702,12 +701,6 @@ else return 0 -/obj/structure/rack/CanAStarPass(ID, dir, caller) - . = !density - if(ismovable(caller)) - var/atom/movable/mover = caller - . = . || (mover.pass_flags & PASSTABLE) - /obj/structure/rack/MouseDrop_T(obj/O, mob/user) . = ..() if ((!( istype(O, /obj/item) ) || user.get_active_held_item() != O)) diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm index 7e3684ad32..c8341c8834 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube.dm @@ -8,17 +8,13 @@ layer = LOW_ITEM_LAYER anchored = TRUE climbable = 1 + pass_flags_self = PASSGLASS var/tube_construction = /obj/structure/c_transit_tube var/list/tube_dirs //list of directions this tube section can connect to. var/exit_delay = 1 var/enter_delay = 0 var/const/time_to_unwrench = 2 SECONDS -/obj/structure/transit_tube/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return 1 - return !density - /obj/structure/transit_tube/New(loc, newdirection) ..(loc) if(newdirection) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index ef1ca6720a..4f1de6432a 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -50,11 +50,10 @@ /obj/structure/windoor_assembly/update_icon_state() icon_state = "[facing]_[secure ? "secure_" : ""]windoor_assembly[state]" -/obj/structure/windoor_assembly/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return 1 +/obj/structure/windoor_assembly/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(get_dir(loc, target) == dir) //Make sure looking at appropriate border - return !density + return if(istype(mover, /obj/structure/window)) var/obj/structure/window/W = mover if(!valid_window_location(loc, W.ini_dir)) @@ -65,7 +64,6 @@ return FALSE else if(istype(mover, /obj/machinery/door/window) && !valid_window_location(loc, mover.dir)) return FALSE - return 1 /obj/structure/windoor_assembly/CanAtmosPass(turf/T) if(get_dir(loc, T) == dir) @@ -73,13 +71,13 @@ else return 1 -/obj/structure/windoor_assembly/CheckExit(atom/movable/mover as mob|obj, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return 1 +/obj/structure/windoor_assembly/CheckExit(atom/movable/mover, turf/target) + if(mover.pass_flags & pass_flags_self) + return TRUE if(get_dir(loc, target) == dir) return !density else - return 1 + return TRUE /obj/structure/windoor_assembly/attackby(obj/item/W, mob/user, params) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 4853d553dc..a73de2d367 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -18,6 +18,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) pressure_resistance = 4*ONE_ATMOSPHERE anchored = TRUE //initially is 0 for tile smoothing max_integrity = 25 + pass_flags_self = PASSGLASS var/ini_dir = null var/state = WINDOW_OUT_OF_FRAME var/reinf = FALSE @@ -90,13 +91,13 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) . = ..() if(direct) setDir(direct) - + if(extra_reinforced && anchored) state = PRWINDOW_SECURE else if(reinf && anchored) state = WINDOW_SCREWED_TO_FRAME - + if(mapload && electrochromatic_id && electrochromatic_id[1] == "!") electrochromatic_id = SSmapping.get_obfuscated_id(electrochromatic_id) @@ -159,13 +160,15 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) else ..(FULLTILE_WINDOW_DIR) -/obj/structure/window/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return 1 +/obj/structure/window/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(.) + return if(dir == FULLTILE_WINDOW_DIR) return 0 //full tile window, you can't move into it! - if(get_dir(loc, target) == dir) - return !density + var/attempted_dir = get_dir(loc, target) + if(attempted_dir == dir) + return if(istype(mover, /obj/structure/window)) var/obj/structure/window/W = mover if(!valid_window_location(loc, W.ini_dir)) @@ -176,7 +179,8 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) return FALSE else if(istype(mover, /obj/machinery/door/window) && !valid_window_location(loc, mover.dir)) return FALSE - return 1 + else if(attempted_dir != dir) + return TRUE /obj/structure/window/CheckExit(atom/movable/O, turf/target) if(istype(O) && (O.pass_flags & PASSGLASS)) diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index ccfb5dc238..3c2f38e872 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -6,6 +6,7 @@ blocks_air = 1 rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE rad_insulation = RAD_MEDIUM_INSULATION + pass_flags_self = PASSCLOSEDTURF wave_explosion_block = 10 wave_explosion_multiply = 0.75 /// How much we block yelling @@ -23,11 +24,6 @@ /turf/closed/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) return FALSE -/turf/closed/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSCLOSEDTURF)) - return TRUE - return ..() - /turf/closed/indestructible name = "wall" icon = 'icons/turf/walls.dmi' diff --git a/code/game/turfs/simulated/chasm.dm b/code/game/turfs/simulated/chasm.dm index 9490d728fe..40b96dbcc8 100644 --- a/code/game/turfs/simulated/chasm.dm +++ b/code/game/turfs/simulated/chasm.dm @@ -77,9 +77,6 @@ else to_chat(user, "The plating is going to need some support! Place metal rods first.") -/turf/open/chasm/CanPass(atom/movable/mover, turf/target) - return 1 - // Chasms for Lavaland, with planetary atmos and lava glow /turf/open/chasm/lavaland initial_gas_mix = LAVALAND_DEFAULT_ATMOS diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 85de964463..c87d386b5f 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -225,16 +225,6 @@ GLOBAL_LIST_EMPTY(station_turfs) return FALSE -/turf/CanPass(atom/movable/mover, turf/target) - if(!target) - return FALSE - - if(istype(mover)) // turf/Enter(...) will perform more advanced checks - return !density - - stack_trace("Non movable passed to turf CanPass : [mover]") - return FALSE - //There's a lot of QDELETED() calls here if someone can figure out how to optimize this but not runtime when something gets deleted by a Bump/CanPass/Cross call, lemme know or go ahead and fix this mess - kevinz000 /turf/Enter(atom/movable/mover, atom/oldloc) // Do not call ..() @@ -243,7 +233,7 @@ GLOBAL_LIST_EMPTY(station_turfs) // Here's hoping it doesn't stay like this for years before we finish conversion to step_ var/atom/firstbump var/canPassSelf = CanPass(mover, src) - if(canPassSelf || (mover.movement_type & UNSTOPPABLE)) + if(canPassSelf || (mover.movement_type & PHASING)) for(var/i in contents) if(QDELETED(mover)) return FALSE //We were deleted, do not attempt to proceed with movement. @@ -253,7 +243,7 @@ GLOBAL_LIST_EMPTY(station_turfs) if(!thing.Cross(mover)) if(QDELETED(mover)) //Mover deleted from Cross/CanPass, do not proceed. return FALSE - if((mover.movement_type & UNSTOPPABLE)) + if((mover.movement_type & PHASING)) mover.Bump(thing) continue else @@ -265,7 +255,7 @@ GLOBAL_LIST_EMPTY(station_turfs) firstbump = src if(firstbump) mover.Bump(firstbump) - return (mover.movement_type & UNSTOPPABLE) + return (mover.movement_type & PHASING) return TRUE /turf/Exit(atom/movable/mover, atom/newloc) @@ -279,7 +269,7 @@ GLOBAL_LIST_EMPTY(station_turfs) if(!thing.Uncross(mover, newloc)) if(thing.flags_1 & ON_BORDER_1) mover.Bump(thing) - if(!(mover.movement_type & UNSTOPPABLE)) + if(!(mover.movement_type & PHASING)) return FALSE if(QDELETED(mover)) return FALSE //We were deleted. @@ -621,11 +611,6 @@ GLOBAL_LIST_EMPTY(station_turfs) /turf/proc/Melt() return ScrapeAway(flags = CHANGETURF_INHERIT_AIR) -/turf/bullet_act(obj/item/projectile/P) - . = ..() - if(. != BULLET_ACT_FORCE_PIERCE) - . = BULLET_ACT_TURF - /turf/proc/get_yelling_resistance(power) . = 0 // don't bother checking fulltile, we don't need accuracy diff --git a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm index f9763b92fd..3caaff4a53 100644 --- a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm +++ b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm @@ -46,10 +46,10 @@ else adjustFireLoss(5) -/mob/living/simple_animal/hostile/blob/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/hostile/blob/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(istype(mover, /obj/structure/blob)) - return 1 - return ..() + return TRUE /mob/living/simple_animal/hostile/blob/Process_Spacemove(movement_dir = 0) for(var/obj/structure/blob/B in range(1, src)) diff --git a/code/modules/antagonists/blob/blob/theblob.dm b/code/modules/antagonists/blob/blob/theblob.dm index a95f73f90d..7651093ea1 100644 --- a/code/modules/antagonists/blob/blob/theblob.dm +++ b/code/modules/antagonists/blob/blob/theblob.dm @@ -8,6 +8,7 @@ opacity = 0 anchored = TRUE layer = BELOW_MOB_LAYER + pass_flags_self = PASSBLOB CanAtmosPass = ATMOS_PASS_PROC var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed. max_integrity = 30 @@ -67,20 +68,9 @@ /obj/structure/blob/BlockThermalConductivity() return atmosblock -/obj/structure/blob/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSBLOB)) - return 1 - return 0 - /obj/structure/blob/CanAtmosPass(turf/T) return !atmosblock -/obj/structure/blob/CanAStarPass(ID, dir, caller) - . = 0 - if(ismovable(caller)) - var/atom/movable/mover = caller - . = . || (mover.pass_flags & PASSBLOB) - /obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind. if(overmind) add_atom_colour(overmind.blobstrain.color, FIXED_COLOUR_PRIORITY) diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm index 2d4ac88656..a572238877 100644 --- a/code/modules/antagonists/swarmer/swarmer.dm +++ b/code/modules/antagonists/swarmer/swarmer.dm @@ -139,12 +139,12 @@ else death() -/mob/living/simple_animal/hostile/swarmer/CanPass(atom/movable/O) +/mob/living/simple_animal/hostile/swarmer/CanAllowThrough(atom/movable/O) + . = ..() if(istype(O, /obj/item/projectile/beam/disabler))//Allows for swarmers to fight as a group without wasting their shots hitting each other return 1 if(isswarmer(O)) return 1 - ..() ////CTRL CLICK FOR SWARMERS AND SWARMER_ACT()'S//// /mob/living/simple_animal/hostile/swarmer/AttackingTarget() @@ -698,11 +698,12 @@ light_range = MINIMUM_USEFUL_LIGHT_RANGE max_integrity = 50 -/obj/structure/swarmer/blockade/CanPass(atom/movable/O) +/obj/structure/swarmer/blockade/CanAllowThrough(atom/movable/O) + . = ..() if(isswarmer(O)) - return 1 + return TRUE if(istype(O, /obj/item/projectile/beam/disabler)) - return 1 + return TRUE /mob/living/simple_animal/hostile/swarmer/proc/CreateSwarmer() set name = "Replicate" diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index d0ed0f2436..94f7409cc9 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -220,7 +220,8 @@ icon_state = "ibeam" anchored = TRUE density = FALSE - pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW + pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE + pass_flags_self = LETPASSTHROW var/obj/item/assembly/infra/master /obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj) diff --git a/code/modules/awaymissions/away_props.dm b/code/modules/awaymissions/away_props.dm index 36ed9b6ba3..d5d94b2a92 100644 --- a/code/modules/awaymissions/away_props.dm +++ b/code/modules/awaymissions/away_props.dm @@ -6,10 +6,11 @@ invisibility = INVISIBILITY_MAXIMUM anchored = TRUE -/obj/effect/oneway/CanPass(atom/movable/mover, turf/target) +/obj/effect/oneway/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() var/turf/T = get_turf(src) var/turf/MT = get_turf(mover) - return ..() && (T == MT || get_dir(MT,T) == dir) + return . && (T == MT || get_dir(MT,T) == dir) /obj/effect/wind diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm index d32905e007..c6cd2e4d77 100644 --- a/code/modules/awaymissions/capture_the_flag.dm +++ b/code/modules/awaymissions/capture_the_flag.dm @@ -405,10 +405,10 @@ /obj/item/projectile/bullet/ctf damage = 0 -/obj/item/projectile/bullet/ctf/prehit(atom/target) +/obj/item/projectile/bullet/ctf/prehit_pierce(atom/target) if(is_ctf_target(target)) damage = 60 - return //PROJECTILE_PIERCE_NONE /// hey uhh don't hit anyone behind them + return PROJECTILE_PIERCE_NONE /// hey uhh don't hit anyone behind them . = ..() /obj/item/gun/ballistic/automatic/laser/ctf @@ -442,10 +442,10 @@ damage = 0 icon_state = "omnilaser" -/obj/item/projectile/beam/ctf/prehit(atom/target) +/obj/item/projectile/beam/ctf/prehit_pierce(atom/target) if(is_ctf_target(target)) damage = 150 - return //PROJECTILE_PIERCE_NONE /// hey uhhh don't hit anyone behind them + return PROJECTILE_PIERCE_NONE /// hey uhhh don't hit anyone behind them . = ..() /proc/is_ctf_target(atom/target) diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index ed6a087cd9..8cbe7f50e1 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -523,7 +523,7 @@ if(!override) qdel(src) -/obj/structure/spacevine/CanPass(atom/movable/mover, turf/target) +/obj/structure/spacevine/CanAllowThrough(atom/movable/mover, turf/target) . = ..() if(isvineimmune(mover)) return TRUE diff --git a/code/modules/fields/turf_objects.dm b/code/modules/fields/turf_objects.dm index 1af924294a..f8d139a45d 100644 --- a/code/modules/fields/turf_objects.dm +++ b/code/modules/fields/turf_objects.dm @@ -23,7 +23,7 @@ name = "energy field" desc = "Get off my turf!" -/obj/effect/abstract/proximity_checker/advanced/field_turf/CanPass(atom/movable/AM, turf/target) +/obj/effect/abstract/proximity_checker/advanced/field_turf/CanAllowThrough(atom/movable/AM, turf/target) . = ..() if(parent) return parent.field_turf_canpass(AM, src, target) @@ -48,7 +48,7 @@ name = "energy field edge" desc = "Edgy description here." -/obj/effect/abstract/proximity_checker/advanced/field_edge/CanPass(atom/movable/AM, turf/target) +/obj/effect/abstract/proximity_checker/advanced/field_edge/CanAllowThrough(atom/movable/AM, turf/target) . = ..() if(parent) return parent.field_edge_canpass(AM, src, target) diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index 5d84901e7f..a43bb0cff5 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -647,10 +647,10 @@ GLOBAL_LIST_INIT(hallucination_list, list( target.playsound_local(get_turf(airlock), 'sound/machines/boltsup.ogg',30,0,3) qdel(src) -/obj/effect/hallucination/fake_door_lock/CanPass(atom/movable/mover, turf/_target) +/obj/effect/hallucination/fake_door_lock/CanAllowThrough(atom/movable/mover, turf/_target) + . = ..() if(mover == target && airlock.density) return FALSE - return TRUE /datum/hallucination/chat diff --git a/code/modules/holiday/halloween/halloween.dm b/code/modules/holiday/halloween/halloween.dm index 0c9987fc00..1e5f4b4502 100644 --- a/code/modules/holiday/halloween/halloween.dm +++ b/code/modules/holiday/halloween/halloween.dm @@ -175,9 +175,6 @@ step(I,direction) return -/mob/living/simple_animal/hostile/construct/shade/howling_ghost/CanPass(atom/movable/mover, turf/target) - return 1 - /////////////////////////// //Spookoween Insane Clown// /////////////////////////// @@ -233,7 +230,7 @@ return /mob/living/simple_animal/hostile/retaliate/clown/insane/adjustHealth() - . = ..() + . = ..() if(prob(5)) playsound(loc, 'sound/spookoween/insane_low_laugh.ogg', 300, 1) diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 38e4fcc6ff..a314210570 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -151,6 +151,7 @@ density = FALSE anchored = TRUE buckle_lying = 0 + pass_flags_self = PASSTABLE | LETPASSTHROW var/burning = 0 var/burn_icon = "bonfire_on_fire" //for a softer more burning embers icon, use "bonfire_warm" var/grill = FALSE @@ -163,13 +164,6 @@ . = ..() StartBurning() -/obj/structure/bonfire/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSTABLE)) - return TRUE - if(mover.throwing) - return TRUE - return ..() - /obj/structure/bonfire/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/stack/rods) && !can_buckle && !grill) var/obj/item/stack/rods/R = W diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 8037a22a52..50c91378ec 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -131,7 +131,8 @@ to_chat(M, "[src] has been set to attack hostile wildlife.") return -/mob/living/simple_animal/hostile/mining_drone/CanPass(atom/movable/O) +/mob/living/simple_animal/hostile/mining_drone/CanAllowThrough(atom/movable/O) + . = ..() if(istype(O, /obj/item/projectile/kinetic)) var/obj/item/projectile/kinetic/K = O if(K.kinetic_gun) @@ -141,7 +142,6 @@ return TRUE if(istype(O, /obj/item/projectile/destabilizer)) return TRUE - return ..() /mob/living/simple_animal/hostile/mining_drone/proc/SetCollectBehavior() mode = MINEDRONE_COLLECT diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 624db8caf5..4b228e1eb3 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -166,9 +166,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) QDEL_NULL(spawners_menu) return ..() -/mob/dead/CanPass(atom/movable/mover, turf/target) - return 1 - /* * This proc will update the icon of the ghost itself, with hair overlays, as well as the ghost image. * Please call update_icon(icon_state) from now on when you want to update the icon_state of the ghost, diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 71573abc90..b65155f086 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -53,7 +53,7 @@ dna.species.on_hit(P, src) -/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone) +/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone, piercing_hit = FALSE) if(dna && dna.species) var/spec_return = dna.species.bullet_act(P, src) if(spec_return) @@ -61,7 +61,7 @@ if(mind) //martial art stuff if(mind.martial_art && mind.martial_art.can_use(src)) //Some martial arts users can deflect projectiles! - var/martial_art_result = mind.martial_art.on_projectile_hit(src, P, def_zone) + var/martial_art_result = mind.martial_art.on_projectile_hit(src, P, def_zone, piercing_hit) if(!(martial_art_result == BULLET_ACT_HIT)) return martial_art_result return ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 5ce80c5575..2aaedb22a5 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -68,7 +68,7 @@ else CRASH("Invalid rediretion mode [redirection_mode]") -/mob/living/bullet_act(obj/item/projectile/P, def_zone) +/mob/living/bullet_act(obj/item/projectile/P, def_zone, piercing_hit = FALSE) var/totaldamage = P.damage var/final_percent = 0 if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself @@ -81,7 +81,7 @@ if(returned & BLOCK_REDIRECTED) return BULLET_ACT_FORCE_PIERCE if(returned & BLOCK_SUCCESS) - P.on_hit(src, final_percent, def_zone) + P.on_hit(src, final_percent, def_zone, piercing_hit) return BULLET_ACT_BLOCK totaldamage = block_calculate_resultant_damage(totaldamage, returnlist) var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null) diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index a35558884b..fcab9344d9 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -20,12 +20,10 @@ /mob/living/proc/update_density() density = !lying && !HAS_TRAIT(src, TRAIT_LIVING_NO_DENSITY) -/mob/living/CanPass(atom/movable/mover, turf/target) - if((mover.pass_flags & PASSMOB)) - return TRUE - if(istype(mover, /obj/item/projectile)) - var/obj/item/projectile/P = mover - return !P.can_hit_target(src, P.permutated, src == P.original, TRUE) +/mob/living/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(.) + return if(mover.throwing) return (!density || lying) if(buckled == mover) @@ -41,7 +39,7 @@ var/mob/living/L = mover //typecast first, check isliving and only check this if living using short circuit if(isliving(L) && lying && L.lying) //if we're both lying down and aren't already being thrown/shipped around, don't pass return FALSE - return (!density || (isliving(mover)? L.can_move_under_living(src) : !mover.density)) + return (isliving(mover)? L.can_move_under_living(src) : !mover.density) /mob/living/toggle_move_intent() . = ..() diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index 55d0336671..a87c0a81ab 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -120,7 +120,7 @@ "You are thrown off of [src]!") flash_act(affect_silicon = 1) -/mob/living/silicon/bullet_act(obj/item/projectile/P, def_zone) +/mob/living/silicon/bullet_act(obj/item/projectile/P, def_zone, piercing_hit = FALSE) var/totaldamage = P.damage if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself var/list/returnlist = list() @@ -141,7 +141,7 @@ "You are knocked off of [src] by the [P]!") unbuckle_mob(M) M.DefaultCombatKnockdown(40) - P.on_hit(src, 0, def_zone) + P.on_hit(src, 0, def_zone, 0, piercing_hit) return BULLET_ACT_HIT /mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/tiled/flash/static) diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm index b003e066ef..df8ef44845 100644 --- a/code/modules/mob/living/simple_animal/animal_defense.dm +++ b/code/modules/mob/living/simple_animal/animal_defense.dm @@ -124,10 +124,10 @@ apply_damage(damage, damagetype, null, getarmor(null, armorcheck)) return TRUE -/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj) +/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj, def_zone, piercing_hit = FALSE) if(!Proj) return - apply_damage(Proj.damage, Proj.damage_type) + apply_damage(Proj.damage, Proj.damage_type, 0, piercing_hit) Proj.on_hit(src) return BULLET_ACT_HIT diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm index 2d964f5721..baa0fe4649 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm @@ -33,12 +33,12 @@ footstep_type = FOOTSTEP_MOB_BAREFOOT -/mob/living/simple_animal/hostile/jungle/mook/CanPass(atom/movable/O) +/mob/living/simple_animal/hostile/jungle/mook/CanAllowThrough(atom/movable/O) + . = ..() if(istype(O, /mob/living/simple_animal/hostile/jungle/mook)) var/mob/living/simple_animal/hostile/jungle/mook/M = O if(M.attack_state == MOOK_ATTACK_ACTIVE && M.throwing) return TRUE - return ..() /mob/living/simple_animal/hostile/jungle/mook/death() desc = "A deceased primitive. Upon closer inspection, it was suffering from severe cellular degeneration and its garments are machine made..."//Can you guess the twist diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index 9bcc21efa6..ab6c9fa301 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -160,10 +160,10 @@ Difficulty: Hard severity = EXPLODE_LIGHT // puny mortals return ..() -/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/hostile/megafauna/bubblegum/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination)) - return 1 - return ..() + return TRUE /mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance) if(!charging) @@ -466,10 +466,10 @@ Difficulty: Hard new /obj/effect/decal/cleanable/blood(get_turf(src)) . = ..() -/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) // hallucinations should not be stopping bubblegum or eachother - return 1 - return ..() + return TRUE /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life() return diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index c1aea8db9d..a4620cd781 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -490,7 +490,8 @@ Difficulty: Normal queue_smooth_neighbors(src) return ..() -/obj/effect/temp_visual/hierophant/wall/CanPass(atom/movable/mover, turf/target) +/obj/effect/temp_visual/hierophant/wall/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(QDELETED(caster)) return FALSE if(mover == caster.pulledby) @@ -501,7 +502,6 @@ Difficulty: Normal return TRUE if(mover == caster) return TRUE - return FALSE /obj/effect/temp_visual/hierophant/chaser //a hierophant's chaser. follows target around, moving and producing a blast every speed deciseconds. duration = 98 diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm index 15bfe2b7f7..f0f978c03f 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm @@ -394,7 +394,7 @@ SHITCODE AHEAD. BE ADVISED. Also comment extravaganza muzzle_type = /obj/effect/projectile/tracer/legion impact_type = /obj/effect/projectile/tracer/legion hitscan = TRUE - movement_type = UNSTOPPABLE + projectile_piercing = ALL ///Used for the legion turret tracer. /obj/effect/projectile/tracer/legion/tracer diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm index ed056c2ad9..04b003b315 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm @@ -72,14 +72,14 @@ return //if it's not our target, we ignore it -/mob/living/simple_animal/hostile/asteroid/curseblob/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/hostile/asteroid/curseblob/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(mover == set_target) return FALSE if(istype(mover, /obj/item/projectile)) var/obj/item/projectile/P = mover if(P.firer == set_target) return FALSE - return TRUE #define IGNORE_PROC_IF_NOT_TARGET(X) /mob/living/simple_animal/hostile/asteroid/curseblob/##X(AM) { if (AM == set_target) return ..(); } diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index be596b0292..b92f429c8c 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -383,8 +383,7 @@ While using this makes the system rely on OnFire, it still gives options for tim ourelite = null return ..() -/obj/effect/temp_visual/elite_tumor_wall/CanPass(atom/movable/mover, turf/target) +/obj/effect/temp_visual/elite_tumor_wall/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(mover == ourelite || mover == activator) return FALSE - else - return TRUE diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 38149494bc..9812307300 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -231,11 +231,11 @@ amount = -abs(amount) return ..() //Heals them -/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj) +/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj, def_zone, piercing_hit = FALSE) attacked += 10 if((Proj.damage_type == BURN)) adjustBruteLoss(-abs(Proj.damage)) //fire projectiles heals slimes. - Proj.on_hit(src) + Proj.on_hit(src, 0, piercing_hit) return BULLET_ACT_BLOCK return ..() diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 527b0c0917..138a3b9662 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -9,7 +9,7 @@ mouse_drag_pointer = MOUSE_ACTIVE_POINTER throwforce = 10 blocks_emissive = EMISSIVE_BLOCK_GENERIC - + pass_flags_self = PASSMOB vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace. attack_hand_is_action = TRUE diff --git a/code/modules/plumbing/plumbers/grinder_chemical.dm b/code/modules/plumbing/plumbers/grinder_chemical.dm index f39c79f906..1d216046e4 100644 --- a/code/modules/plumbing/plumbers/grinder_chemical.dm +++ b/code/modules/plumbing/plumbers/grinder_chemical.dm @@ -31,7 +31,7 @@ eat_dir = WEST return TRUE -/obj/machinery/plumbing/grinder_chemical/CanPass(atom/movable/AM) +/obj/machinery/plumbing/grinder_chemical/CanAllowThrough(atom/movable/AM) . = ..() if(!anchored) return diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index ff6cf99411..7c6b1cc922 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -100,10 +100,10 @@ return -/obj/machinery/field/CanPass(atom/movable/mover, turf/target) +/obj/machinery/field/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(hasShocked || isliving(mover) || ismachinery(mover) || isstructure(mover) || ismecha(mover)) return FALSE - return ..() /obj/machinery/field/proc/shock(mob/living/user) var/shock_damage = min(rand(30,40),rand(30,40)) diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 4d394401c4..7516092149 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -232,14 +232,14 @@ kinetic_gun = null return ..() -/obj/item/projectile/kinetic/prehit(atom/target) +/obj/item/projectile/kinetic/prehit_pierce(atom/target) . = ..() if(.) if(kinetic_gun) var/list/mods = kinetic_gun.get_modkits() for(var/obj/item/borg/upgrade/modkit/M in mods) M.projectile_prehit(src, target, kinetic_gun) - if(!lavaland_equipment_pressure_check(get_turf(target))) + if(!pressure_decrease_active && !lavaland_equipment_pressure_check(get_turf(target))) name = "weakened [name]" damage = damage * pressure_decrease pressure_decrease_active = TRUE diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm index 2ef974a450..ebc388a965 100644 --- a/code/modules/projectiles/guns/misc/beam_rifle.dm +++ b/code/modules/projectiles/guns/misc/beam_rifle.dm @@ -427,11 +427,9 @@ var/aoe_mob_damage = 30 var/impact_structure_damage = 0 var/impact_direct_damage = 0 - var/turf/cached var/list/pierced = list() /obj/item/projectile/beam/beam_rifle/proc/AOE(turf/epicenter) - set waitfor = FALSE if(!epicenter) return new /obj/effect/temp_visual/explosion/fast(epicenter) @@ -447,31 +445,22 @@ continue O.take_damage(aoe_structure_damage * get_damage_coeff(O), BURN, "laser", FALSE) -/obj/item/projectile/beam/beam_rifle/proc/check_pierce(atom/target) - if(!do_pierce) - return FALSE - if(pierced[target]) //we already pierced them go away - return TRUE - if(isclosedturf(target)) - if(wall_pierce++ < wall_pierce_amount) - if(prob(wall_devastate)) - if(iswallturf(target)) - var/turf/closed/wall/W = target - W.dismantle_wall(TRUE, TRUE) - else - target.ex_act(EXPLODE_HEAVY) - return TRUE - if(ismovable(target)) - var/atom/movable/AM = target - if(AM.density && !AM.CanPass(src, get_turf(target)) && !ismob(AM)) - if(structure_pierce < structure_pierce_amount) - if(isobj(AM)) - var/obj/O = AM - O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(AM), BURN, "energy", FALSE) - pierced[AM] = TRUE - structure_pierce++ - return TRUE - return FALSE +/obj/item/projectile/beam/beam_rifle/proc/check_pierce(atom/A) + if(isclosedturf(A) && (wall_pierce < wall_pierce_amount)) + if(prob(wall_devastate)) + if(iswallturf(A)) + var/turf/closed/wall/W = A + W.dismantle_wall(TRUE, TRUE) + else + target.ex_act(EXPLODE_HEAVY) + ++wall_pierce + return PROJECTILE_PIERCE_PHASE // yeah this gun is a snowflakey piece of garbage - Silly-Cons + if(isobj(A) && (structure_pierce < structure_pierce_amount)) + ++structure_pierce + var/obj/O = A + O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(A), BURN, ENERGY, FALSE) + return PROJECTILE_PIERCE_PHASE // ditto and this could be refactored to on_hit honestly - Silly-Cons + return ..() /obj/item/projectile/beam/beam_rifle/proc/get_damage_coeff(atom/target) if(istype(target, /obj/machinery/door)) @@ -491,32 +480,18 @@ L.adjustFireLoss(impact_direct_damage) L.emote("scream") -/obj/item/projectile/beam/beam_rifle/proc/handle_hit(atom/target) +/obj/item/projectile/beam/beam_rifle/proc/handle_hit(atom/target, piercing_hit = FALSE) set waitfor = FALSE - if(!cached && !QDELETED(target)) - cached = get_turf(target) if(nodamage) return FALSE - playsound(cached, 'sound/effects/explosion3.ogg', 100, 1) - AOE(cached) + playsound(src, 'sound/effects/explosion3.ogg', 100, TRUE) + if(!piercing_hit) + AOE(get_turf(target) || get_turf(src)) if(!QDELETED(target)) handle_impact(target) -/obj/item/projectile/beam/beam_rifle/Bump(atom/target) - if(check_pierce(target)) - permutated += target - trajectory_ignore_forcemove = TRUE - forceMove(target.loc) - trajectory_ignore_forcemove = FALSE - return FALSE - if(!QDELETED(target)) - cached = get_turf(target) - . = ..() - -/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE) - if(!QDELETED(target)) - cached = get_turf(target) - handle_hit(target) +/obj/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE, piercing_hit = FALSE) + handle_hit(target, piercing_hit) . = ..() /obj/item/projectile/beam/beam_rifle/hitscan @@ -547,6 +522,9 @@ hitscan_light_intensity = 0 hitscan_light_color_override = "#99ff99" -/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target) +/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit_pierce(atom/target) + return PROJECTILE_DELETE_WITHOUT_HITTING + +/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit() qdel(src) - return FALSE + return BULLET_ACT_BLOCK diff --git a/code/modules/projectiles/guns/misc/blastcannon.dm b/code/modules/projectiles/guns/misc/blastcannon.dm index 64cffe52e7..b28c06a2c2 100644 --- a/code/modules/projectiles/guns/misc/blastcannon.dm +++ b/code/modules/projectiles/guns/misc/blastcannon.dm @@ -114,7 +114,8 @@ icon_state = "blastwave" damage = 0 nodamage = FALSE - movement_type = FLYING | UNSTOPPABLE + movement_type = FLYING + projectile_phasing = ALL // just blows up the turfs lmao - Silly-Cons var/heavyr = 0 var/mediumr = 0 var/lightr = 0 diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index ca07bde239..3fd1bce1ca 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -13,9 +13,9 @@ density = FALSE anchored = TRUE item_flags = ABSTRACT - pass_flags = PASSTABLE mouse_opacity = MOUSE_OPACITY_TRANSPARENT movement_type = FLYING + generic_canpass = FALSE animate_movement = NO_STEPS hitsound = 'sound/weapons/pierce.ogg' appearance_flags = PIXEL_SCALE @@ -40,6 +40,35 @@ var/time_offset = 0 var/datum/point/vector/trajectory var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location! + /// We already impacted these things, do not impact them again. Used to make sure we can pierce things we want to pierce. Lazylist, typecache style (object = TRUE) for performance. + var/list/impacted + /// If TRUE, we can hit our firer. + var/ignore_source_check = FALSE + /// We are flagged PHASING temporarily to not stop moving when we Bump something but want to keep going anyways. + var/temporary_unstoppable_movement = FALSE + + /** PROJECTILE PIERCING + * WARNING: + * Projectile piercing MUST be done using these variables. + * Ordinary passflags will be **IGNORED**. + * 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. + * + * Also, projectiles sense hits using Bump(), and then pierce them if necessary. + * They simply do not follow conventional movement rules. + * NEVER flag a projectile as PHASING movement type. + * If you so badly need to make one go through *everything*, override check_pierce() for your projectile to always return PROJECTILE_PIERCE_PHASE/HIT. + */ + /// The "usual" flags of pass_flags is used in that can_hit_target ignores these unless they're specifically targeted/clicked on. This behavior entirely bypasses process_hit if triggered, rather than phasing which uses prehit_pierce() to check. + pass_flags = PASSTABLE + /// If FALSE, allow us to hit something directly targeted/clicked/whatnot even if we're able to phase through it + var/phasing_ignore_direct_target = FALSE + /// Bitflag for things the projectile should just phase through entirely - No hitting unless direct target and [phasing_ignore_direct_target] is FALSE. Uses pass_flags flags. + var/projectile_phasing = NONE + /// Bitflag for things the projectile should hit, but pierce through without deleting itself. Defers to projectile_phasing. Uses pass_flags flags. + var/projectile_piercing = NONE + /// number of times we've pierced something. Incremented BEFORE bullet_act and on_hit proc! + var/pierces = 0 /// "leftover" pixels for Range() calculation as pixel_move() was moved to simulated semi-pixel movement and Range() is in tiles. var/pixels_range_leftover = 0 /// "leftover" tick pixels and stuff yeah, so we don't round off things and introducing tracing inaccuracy. @@ -117,8 +146,6 @@ /// How many deciseconds are each hitscan movement considered. Used for homing and other things that use seconds for timing rather than ticks. var/hitscan_movement_decisecond_equivalency = 0.1 - var/ignore_source_check = FALSE - var/damage = 10 var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here var/nodamage = 0 //Determines if the projectile will skip any damage inflictions @@ -150,8 +177,6 @@ var/impact_effect_type //what type of impact effect to show when hitting something var/log_override = FALSE //is this type spammed enough to not log? (KAs) - var/temporary_unstoppable_movement = FALSE - ///If defined, on hit we create an item of this type then call hitby() on the hit target with this, mainly used for embedding items (bullets) in targets var/shrapnel_type ///If TRUE, hit mobs even if they're on the floor and not our target @@ -167,7 +192,6 @@ /obj/item/projectile/Initialize() . = ..() - permutated = list() decayedRange = range if(embedding) updateEmbedding() @@ -201,10 +225,7 @@ else //when a limb is missing the damage is actually passed to the chest return BODY_ZONE_CHEST -/obj/item/projectile/proc/prehit(atom/target) - return TRUE - -/obj/item/projectile/proc/on_hit(atom/target, blocked = FALSE) +/obj/item/projectile/proc/on_hit(atom/target, blocked = FALSE, pierce_hit) if(fired_from) SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle) @@ -238,6 +259,11 @@ if(!isliving(target)) if(impact_effect_type && !hitscan) new impact_effect_type(target_loca, hitx, hity) + if(isturf(target) && hitsound_wall) + var/volume = clamp(vol_by_damage() + 20, 0, 100) + if(suppressed) + volume = 5 + playsound(loc, hitsound_wall, volume, TRUE, -1) return BULLET_ACT_HIT var/mob/living/L = target @@ -278,7 +304,7 @@ else if(hitsound) var/volume = vol_by_damage() - playsound(loc, hitsound, volume, 1, -1) + playsound(src, hitsound, volume, 1, -1) L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \ "[L] is hit by \a [src][organ_hit_text]!", null, COMBAT_MESSAGE_RANGE) if(candink && def_zone == BODY_ZONE_HEAD) @@ -298,7 +324,7 @@ /obj/item/projectile/proc/vol_by_damage() if(src.damage) - return clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100 + return clamp((src.damage) * 0.67, 30, 100) // Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100 else return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume @@ -327,95 +353,267 @@ beam_segments[beam_index] = null /obj/item/projectile/Bump(atom/A) - if(!trajectory) + SEND_SIGNAL(src, COMSIG_MOVABLE_BUMP, A) + if(!can_hit_target(A, A == original, TRUE)) return + Impact(A) + +/** + * Called when the projectile hits something + * This can either be from it bumping something, + * or it passing over a turf/being crossed and scanning that there is infact + * a valid target it needs to hit. + * This target isn't however necessarily WHAT it hits + * that is determined by process_hit and select_target. + * + * Furthermore, this proc shouldn't check can_hit_target - this should only be called if can hit target is already checked. + * Also, we select_target to find what to process_hit first. + */ +/obj/projectile/proc/Impact(atom/A) + if(!trajectory) + qdel(src) + return FALSE + if(impacted[A]) // NEVER doublehit - Silly-Cons + return FALSE + var/datum/point/pcache = trajectory.copy_to() var/turf/T = get_turf(A) if(check_ricochet_flag(A) && check_ricochet(A)) //if you can ricochet, attempt to ricochet off the object ricochets++ if(A.handle_ricochet(src)) on_ricochet(A) //if allowed, use autoaim to ricochet into someone, otherwise default to ricocheting off the object from above - var/datum/point/pcache = trajectory.copy_to() - if(hitscan) - store_hitscan_collision(pcache) + impacted = list() // Shoot a x-ray laser at a pair of mirrors I dare you + ignore_source_check = TRUE // Firer is no longer immune decayedRange = max(0, decayedRange - reflect_range_decrease) ricochet_chance *= ricochet_decay_chance damage *= ricochet_decay_damage range = decayedRange + if(hitscan) + store_hitscan_collision(pcache) return TRUE 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. if(def_zone && check_zone(def_zone) != BODY_ZONE_CHEST) def_zone = ran_zone(def_zone, max(100-(7*distance), 5) * zone_accuracy_factor) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use. - if(isturf(A) && hitsound_wall) - var/volume = clamp(vol_by_damage() + 20, 0, 100) - if(suppressed) - volume = 5 - playsound(loc, hitsound_wall, volume, 1, -1) + return process_hit(T, select_target(T, A)) // SELECT TARGET FIRST! - return process_hit(T, select_target(T, A)) - -#define QDEL_SELF 1 //Delete if we're not UNSTOPPABLE flagged non-temporarily -#define DO_NOT_QDEL 2 //Pass through. -#define FORCE_QDEL 3 //Force deletion. - -/obj/item/projectile/proc/process_hit(turf/T, atom/target, qdel_self, hit_something = FALSE) //probably needs to be reworked entirely when pixel movement is done. - if(QDELETED(src) || !T || !target) //We're done, nothing's left. - if((qdel_self == FORCE_QDEL) || ((qdel_self == QDEL_SELF) && !temporary_unstoppable_movement && !(movement_type & UNSTOPPABLE))) - qdel(src) +/** + * The primary workhorse proc of projectile impacts. + * This is a RECURSIVE call - process_hit is called on the first selected target, and then repeatedly called if the projectile still hasn't been deleted. + * + * Order of operations: + * 1. Checks if we are deleted, or if we're somehow trying to hit a null, in which case, bail out + * 2. Adds the thing we're hitting to impacted so we can make sure we don't doublehit + * 3. Checks piercing - stores this. + * Afterwards: + * Hit and delete, hit without deleting and pass through, pass through without hitting, or delete without hitting depending on result + * If we're going through without hitting, find something else to hit if possible and recurse, set unstoppable movement to true + * If we're deleting without hitting, delete and return + * Otherwise, send signal of COMSIG_PROJECTILE_PREHIT to target + * Then, hit, deleting ourselves if necessary. + * @params + * T - Turf we're on/supposedly hitting + * target - target we're hitting + * hit_something - only should be set by recursive calling by this proc - tracks if we hit something already + * + * Returns if we hit something. + * - Silly-Cons + */ +/obj/item/projectile/proc/process_hit(turf/T, atom/target, hit_something = FALSE) + // 1. + if(QDELETED(src) || !T || !target) + return + // 2. + impacted[target] = TRUE //hash lookup > in for performance in hit-checking + // 3. + var/mode = prehit_pierce(target) + if(mode == PROJECTILE_DELETE_WITHOUT_HITTING) + qdel(src) return hit_something - permutated |= target //Make sure we're never hitting it again. If we ever run into weirdness with piercing projectiles needing to hit something multiple times.. well.. that's a to-do. - if(!prehit(target)) - return process_hit(T, select_target(T), qdel_self, hit_something) //Hit whatever else we can since that didn't work. - var/result = target.bullet_act(src, def_zone) - if(result == BULLET_ACT_FORCE_PIERCE) - if(!(movement_type & UNSTOPPABLE)) + else if(mode == PROJECTILE_PIERCE_PHASE) + if(!(movement_type & PHASING)) temporary_unstoppable_movement = TRUE - movement_type |= UNSTOPPABLE - return process_hit(T, select_target(T), qdel_self, TRUE) //Hit whatever else we can since we're piercing through but we're still on the same tile. - else if(result == BULLET_ACT_TURF) //We hit the turf but instead we're going to also hit something else on it. - return process_hit(T, select_target(T), QDEL_SELF, TRUE) - else //Whether it hit or blocked, we're done! - qdel_self = QDEL_SELF - hit_something = TRUE - if((qdel_self == FORCE_QDEL) || ((qdel_self == QDEL_SELF) && !temporary_unstoppable_movement && !(movement_type & UNSTOPPABLE))) + movement_type |= PHASING + return process_hit(T, select_target(T, target), 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) + if(mode == PROJECTILE_PIERCE_HIT) + ++pierces + hit_something = TRUE + var/result = target.bullet_act(src, def_zone, mode == PROJECTILE_PIERCE_HIT) + if((result == BULLET_ACT_FORCE_PIERCE) || (mode == PROJECTILE_PIERCE_HIT)) + if(!(movement_type & PHASING)) + temporary_unstoppable_movement = TRUE + movement_type |= PHASING + return process_hit(T, select_target(T, target), TRUE) qdel(src) return hit_something -#undef QDEL_SELF -#undef DO_NOT_QDEL -#undef FORCE_QDEL - -/obj/item/projectile/proc/select_target(turf/T, atom/target) //Select a target from a turf. - if((original in T) && can_hit_target(original, permutated, TRUE, TRUE)) +/** + * Selects a target to hit from a turf + * + * @params + * T - The turf + * target - The "preferred" atom to hit, usually what we Bumped() first. + * + * 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. + * Furthermore, can_hit_target is always checked. This (entire proc) is PERFORMANCE OVERHEAD!! But, it shouldn't be ""too"" bad and I frankly don't have a better *generic non snowflakey* way that I can think of right now at 3 AM. + * FURTHERMORE, mobs/objs have a density check from can_hit_target - to hit non dense objects over a turf, you must click on them, same for mobs that usually wouldn't get hit. + * 1. The thing originally aimed at/clicked on + * 2. Mobs - picks lowest buckled mob to prevent scarp piggybacking memes + * 3. Objs + * 4. Turf + * 5. Nothing + */ +/obj/projectile/proc/select_target(turf/T, atom/target) + // 1. original + if(can_hit_target(original, TRUE, FALSE)) return original - if(target && can_hit_target(target, permutated, target == original, TRUE)) - return target - var/list/mob/living/possible_mobs = typecache_filter_list(T, GLOB.typecache_mob) - var/list/mob/mobs = list() - for(var/mob/living/M in possible_mobs) - if(!can_hit_target(M, permutated, M == original, TRUE)) + 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)) continue - mobs += M - var/mob/M = safepick(mobs) - if(M) + considering += i + if(considering.len) + var/mob/living/M = pick(considering) return M.lowest_buckled_mob() - var/list/obj/possible_objs = typecache_filter_list(T, GLOB.typecache_machine_or_structure) - var/list/obj/objs = list() - for(var/obj/O in possible_objs) - if(!can_hit_target(O, permutated, O == original, TRUE)) + 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)) continue - objs += O - var/obj/O = safepick(objs) - if(O) - if(length(O.buckled_mobs)) - return pick(O.buckled_mobs) - return O - //Nothing else is here that we can hit, hit the turf if we haven't. - if(!(T in permutated) && can_hit_target(T, permutated, T == original, TRUE)) + considering += i + if(considering.len) + return pick(considering) + // 4. turf + if(can_hit_target(T, T == original, TRUE)) return T - //Returns null if nothing at all was found. + // 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) + 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 + 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. + return TRUE + if(!isliving(target)) + if(isturf(target)) // non dense turfs + return FALSE + if(target.layer < PROJECTILE_HIT_THRESHHOLD_LAYER) + return FALSE + else if(!direct_target) // non dense objects do not get hit unless specifically clicked + return FALSE + else + var/mob/living/L = target + 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))) + return FALSE + return TRUE + +/** + * Scan if we should hit something and hit it if we need to + * The difference between this and handling in Impact is + * In this we strictly check if we need to Impact() something in specific + * If we do, we do + * We don't even check if it got hit already - Impact() does that + * In impact there's more code for selecting WHAT to hit + * So this proc is more of checking if we should hit something at all BY having an atom cross us. + */ +/obj/projectile/proc/scan_crossed_hit(atom/movable/A) + if(can_hit_target(A, direct_target = (A == original))) + Impact(A) + +/** + * Scans if we should hit something on the turf we just moved to if we haven't already + * + * This proc is a little high in overhead but allows us to not snowflake CanPass in living and other things. + */ +/obj/projectile/proc/scan_moved_turf() + // Optimally, we scan: mobs --> objs --> turf for impact + // but, overhead is a thing and 2 for loops every time it moves is a no-go. + // realistically, since we already do select_target in impact, we can not do that + // and hope projectiles get refactored again in the future to have a less stupid impact detection system + // that hopefully won't also involve a ton of overhead + if(can_hit_target(original, TRUE, FALSE)) + Impact(original) // try to hit thing clicked on + // else, try to hit mobs + else // because if we impacted original and pierced we'll already have select target'd and hit everything else we should be hitting + for(var/mob/M in loc) // so I guess we're STILL doing a for loop of mobs because living movement would otherwise have snowflake code for projectile CanPass + // so the snowflake vs performance is pretty arguable here + if(can_hit_target(M, M == original, TRUE)) + Impact(M) + break + +/** + * Projectile crossed: When something enters a projectile's tile, make sure the projectile hits it if it should be hitting it. + */ +/obj/projectile/Crossed(atom/movable/AM) + . = ..() + scan_crossed_hit(AM) + +/** + * Projectile can pass through + * Used to not even attempt to Bump() or fail to Cross() anything we already hit. + */ +/obj/projectile/CanPassThrough(atom/blocker, turf/target, blocker_opinion) + return impacted[blocker]? TRUE : ..() + +/** + * Projectile moved: + * + * If not fired yet, do not do anything. Else, + * + * If temporary unstoppable movement used for piercing through things we already hit (impacted list) is set, unset it. + * Scan turf we're now in for anything we can/should hit. This is useful for hitting non dense objects the user + * directly clicks on, as well as for PHASING projectiles to be able to hit things at all as they don't ever Bump(). + */ +/obj/projectile/Moved(atom/OldLoc, Dir) + . = ..() + if(!fired) + return + if(temporary_unstoppable_movement) + temporary_unstoppable_movement = FALSE + movement_type &= ~PHASING + scan_moved_turf() //mostly used for making sure we can hit a non-dense object the user directly clicked on, and for penetrating projectiles that don't bump + +/** + * Checks if we should pierce something. + * + * NOT meant to be a pure proc, since this replaces prehit() which was used to do things. + * 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) + return PROJECTILE_PIERCE_PHASE + if(projectile_piercing & A.pass_flags_self) + return PROJECTILE_PIERCE_HIT + if(ismovable(A)) + var/atom/movable/AM = A + if(AM.throwing) + return (projectile_phasing & LETPASSTHROW)? PROJECTILE_PIERCE_PHASE : ((projectile_piercing & LETPASSTHROW)? PROJECTILE_PIERCE_HIT : PROJECTILE_PIERCE_NONE) + return PROJECTILE_PIERCE_NONE + +/**INeedAnAdult I am unsure what the fuck is going on in here and I'll have to get clairification on this shit. + */ /obj/item/projectile/proc/check_ricochet(atom/A) if(ricochets > ricochets_max) //safety thing, we don't care about what the other thing says about this. return FALSE @@ -484,11 +682,10 @@ AddElement(/datum/element/embed, projectile_payload = shrapnel_type) if(!log_override && firer && original) log_combat(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]") - if(direct_target) - if(prehit(direct_target)) - direct_target.bullet_act(src, def_zone) - qdel(src) - return + if(direct_target && (get_dist(direct_target, get_turf(src)) <= 1)) // point blank shots + process_hit(get_turf(direct_target), direct_target) + if(QDELETED(src)) + return if(isnum(angle)) setAngle(angle) if(spread) @@ -506,6 +703,7 @@ var/matrix/M = new M.Turn(Angle) transform = M + LAZYINITLIST(impacted) trajectory_ignore_forcemove = TRUE forceMove(starting) set_light(fired_light_range, fired_light_intensity, fired_light_color) @@ -544,6 +742,8 @@ if(zc) before_z_change(old, target) . = ..() + if(QDELETED(src)) // we coulda bumped something + return if(trajectory && !trajectory_ignore_forcemove && isturf(target)) if(hitscan) finalize_hitscan_and_generate_tracers(FALSE) @@ -678,30 +878,6 @@ if(prob(50)) homing_offset_y = -homing_offset_y -//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/item/projectile/proc/can_hit_target(atom/target, list/passthrough, direct_target = FALSE, ignore_loc = FALSE) - if(QDELETED(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))) - if(!ricochets) //if it has ricocheted, it can hit the firer. - return FALSE - if(!ignore_loc && (loc != target.loc)) - return FALSE - if(target in passthrough) - return FALSE - if(target.density) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc. - return TRUE - if(!isliving(target)) - if(target.layer < PROJECTILE_HIT_THRESHHOLD_LAYER) - return FALSE - else - var/mob/living/L = target - if(!direct_target && !L.density) - return FALSE - return TRUE //Spread is FORCED! /obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0) @@ -762,22 +938,6 @@ angle = arctan(y - oy, x - ox) return list(angle, p_x, p_y) -/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it. - . = ..() - if(isliving(AM) && !(pass_flags & PASSMOB)) - var/mob/living/L = AM - if(can_hit_target(L, permutated, (AM == original))) - Bump(AM) - -/obj/item/projectile/Move(atom/newloc, dir = NONE) - . = ..() - if(.) - if(temporary_unstoppable_movement) - temporary_unstoppable_movement = FALSE - movement_type &= ~(UNSTOPPABLE) - if(fired && can_hit_target(original, permutated, TRUE)) - Bump(original) - /obj/item/projectile/Destroy() STOP_PROCESSING(SSprojectiles, src) if(hitscan) diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 79e9ab8b4b..a74a71d141 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -166,7 +166,7 @@ /obj/item/projectile/beam/lasertag/mag //the projectile, compatible with regular laser tag armor icon_state = "magjectile-toy" name = "lasertag magbolt" - movement_type = FLYING | UNSTOPPABLE //for penetration memes + movement_type = FLYING | PHASING //for penetration memes range = 5 //so it isn't super annoying light_range = 2 light_color = LIGHT_COLOR_YELLOW diff --git a/code/modules/projectiles/projectile/bullets/ferromagnetic.dm b/code/modules/projectiles/projectile/bullets/ferromagnetic.dm index 03482e2a9d..1ba6ba7b79 100644 --- a/code/modules/projectiles/projectile/bullets/ferromagnetic.dm +++ b/code/modules/projectiles/projectile/bullets/ferromagnetic.dm @@ -28,7 +28,7 @@ damage = 10 armour_penetration = 20 stamina = 10 - movement_type = FLYING | UNSTOPPABLE + movement_type = FLYING | PHASING range = 6 fired_light_range = 1 fired_light_color = LIGHT_COLOR_RED @@ -37,7 +37,7 @@ icon_state = "magjectile-large" damage = 10 armour_penetration = 20 - movement_type = FLYING | UNSTOPPABLE + movement_type = FLYING | PHASING range = 20 pixels_per_second = TILES_TO_PIXELS(12.5) fired_light_range = 4 diff --git a/code/modules/projectiles/projectile/bullets/sniper.dm b/code/modules/projectiles/projectile/bullets/sniper.dm index f69b62a149..80edd716b5 100644 --- a/code/modules/projectiles/projectile/bullets/sniper.dm +++ b/code/modules/projectiles/projectile/bullets/sniper.dm @@ -35,7 +35,8 @@ icon_state = "gauss" name = "penetrator round" damage = 60 - movement_type = FLYING | UNSTOPPABLE + projectile_piercing = PASSMOB + projectile_phasing = (ALL & (~PASSMOB)) dismemberment = 0 //It goes through you cleanly. knockdown = 0 breakthings = FALSE diff --git a/code/modules/projectiles/projectile/bullets/special.dm b/code/modules/projectiles/projectile/bullets/special.dm index a0414d8a9c..76ba76fbfe 100644 --- a/code/modules/projectiles/projectile/bullets/special.dm +++ b/code/modules/projectiles/projectile/bullets/special.dm @@ -3,7 +3,8 @@ /obj/item/projectile/bullet/honker damage = 0 knockdown = 60 - movement_type = FLYING | UNSTOPPABLE + movement_type = FLYING + projectile_piercing = ALL nodamage = TRUE candink = FALSE hitsound = 'sound/items/bikehorn.ogg' diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 76cd1a6bc5..21af43478a 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -344,18 +344,17 @@ var/created = FALSE //prevents creation of more then one locker if it has multiple hits var/locker_suck = TRUE -/obj/item/projectile/magic/locker/prehit(atom/A) +/obj/item/projectile/magic/locker/prehit_pierce(atom/A) + . = ..() if(ismob(A) && locker_suck) var/mob/M = A - if(M.anti_magic_check()) + if(M.anti_magic_check()) // no this doesn't check if ..() returned to phase through do I care no it's magic ain't gotta explain shit - Silly-Cons M.visible_message("[src] vanishes on contact with [A]!") - qdel(src) - return + return PROJECTILE_DELETE_WITHOUT_HITTING if(M.anchored) - return ..() + return M.forceMove(src) - return FALSE - return ..() + return PROJECTILE_PIERCE_PHASE /obj/item/projectile/magic/locker/on_hit(target) if(created) diff --git a/code/modules/projectiles/projectile/special/curse.dm b/code/modules/projectiles/projectile/special/curse.dm index 6c682763ae..36c27ac0e1 100644 --- a/code/modules/projectiles/projectile/special/curse.dm +++ b/code/modules/projectiles/projectile/special/curse.dm @@ -12,7 +12,6 @@ knockdown = 20 pixels_per_second = TILES_TO_PIXELS(5) range = 16 - movement_type = FLYING | UNSTOPPABLE var/datum/beam/arm var/handedness = 0 @@ -29,18 +28,14 @@ arm = starting.Beam(src, icon_state = "curse[handedness]", time = INFINITY, maxdistance = INFINITY, beam_type=/obj/effect/ebeam/curse_arm) ..() -/obj/item/projectile/curse_hand/prehit(atom/target) - if(target == original) - movement_type &= ~(UNSTOPPABLE) - else if(!isturf(target)) - return FALSE - return ..() +/obj/projectile/curse_hand/prehit_pierce(atom/target) + return (target == original)? PROJECTILE_PIERCE_NONE : PROJECTILE_PIERCE_PHASE /obj/item/projectile/curse_hand/Destroy() if(arm) arm.End() arm = null - if((movement_type & UNSTOPPABLE)) + if((movement_type & PHASING)) playsound(src, 'sound/effects/curse3.ogg', 25, 1, -1) var/turf/T = get_step(src, dir) var/obj/effect/temp_visual/dir_setting/curse/hand/leftover = new(T, dir) diff --git a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm index d62b3c2611..54e07d24e5 100644 --- a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm @@ -59,10 +59,10 @@ /obj/structure/necropolis_gate/singularity_pull() return 0 -/obj/structure/necropolis_gate/CanPass(atom/movable/mover, turf/target) - if(get_dir(loc, target) == dir) - return !density - return 1 +/obj/structure/necropolis_gate/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(!(get_dir(loc, target) == dir)) + return TRUE /obj/structure/necropolis_gate/CheckExit(atom/movable/O, target) if(get_dir(O.loc, target) == dir) diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index 5e2fc3d7e4..da6179197c 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -80,7 +80,8 @@ icon = 'icons/mob/blob.dmi' color = rgb(145, 150, 0) -/obj/effect/gluttony/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff. +/obj/effect/gluttony/CanAllowThrough(atom/movable/mover, turf/target)//So bullets will fly over and stuff. + . = ..() if(ishuman(mover)) var/mob/living/carbon/human/H = mover if(H.nutrition >= NUTRITION_LEVEL_FAT) @@ -90,8 +91,6 @@ to_chat(H, "You're repulsed by even looking at [src]. Only a pig could force themselves to go through it.") if(istype(mover, /mob/living/simple_animal/hostile/morph)) return TRUE - else - return FALSE /obj/structure/mirror/magic/pride //Pride's mirror: Used in the Pride ruin. name = "pride's mirror" diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index 05450fd7c2..274efcda5a 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -212,15 +212,14 @@ var/static/list/check_times = list() -/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target) +/obj/effect/forcefield/luxury_shuttle/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(mover in approved_passengers) return TRUE if(!isliving(mover)) //No stowaways return FALSE - return FALSE - #define LUXURY_MESSAGE_COOLDOWN 100 /obj/effect/forcefield/luxury_shuttle/Bumped(atom/movable/AM) diff --git a/code/modules/spells/spell_types/forcewall.dm b/code/modules/spells/spell_types/forcewall.dm index e0c21066cf..be7bb4cbd3 100644 --- a/code/modules/spells/spell_types/forcewall.dm +++ b/code/modules/spells/spell_types/forcewall.dm @@ -30,11 +30,11 @@ . = ..() wizard = summoner -/obj/effect/forcefield/wizard/CanPass(atom/movable/mover, turf/target) +/obj/effect/forcefield/wizard/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() if(mover == wizard) return TRUE if(ismob(mover)) var/mob/M = mover if(M.anti_magic_check(chargecost = 0)) return TRUE - return FALSE diff --git a/code/modules/vehicles/ridden.dm b/code/modules/vehicles/ridden.dm index f71d9367d3..28b79a1599 100644 --- a/code/modules/vehicles/ridden.dm +++ b/code/modules/vehicles/ridden.dm @@ -4,6 +4,7 @@ max_buckled_mobs = 1 buckle_lying = FALSE default_driver_move = FALSE + pass_flags_self = PASSTABLE var/legs_required = 1 var/arms_required = 0 //why not?