diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index ddc990dc182..9aefeff9f84 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -173,3 +173,9 @@
//We will round to this value in damage calculations.
#define DAMAGE_PRECISION 0.1
+
+//bullet_act() return values
+#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
+#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
+#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
+#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index 77ea2a3e98e..d2e462bbaea 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -1,157 +1,158 @@
-/*
- These defines are specific to the atom/flags_1 bitmask
-*/
-#define ALL (~0) //For convenience.
-#define NONE 0
-
-//for convenience
-#define ENABLE_BITFIELD(variable, flag) (variable |= (flag))
-#define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag))
-#define TOGGLE_BITFIELD(variable, flag) (variable ^= (flag))
-#define CHECK_BITFIELD(variable, flag) (variable & flag)
-
-//check if all bitflags specified are present
-#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) ((flagvar & (flags)) == flags)
-
-GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
-
-// for /datum/var/datum_flags
-#define DF_USE_TAG (1<<0)
-#define DF_VAR_EDITED (1<<1)
-#define DF_ISPROCESSING (1<<2)
-
-//FLAGS BITMASK
-
-#define HEAR_1 (1<<3) // This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
-#define CHECK_RICOCHET_1 (1<<4) // Projectiels will check ricochet on things impacted that have this.
-#define CONDUCT_1 (1<<5) // conducts electricity (metal etc.)
-#define NODECONSTRUCT_1 (1<<7) // For machines and structures that should not break into parts, eg, holodeck stuff
-#define OVERLAY_QUEUED_1 (1<<8) // atom queued to SSoverlay
-#define ON_BORDER_1 (1<<9) // item has priority to check when entering or leaving
-#define PREVENT_CLICK_UNDER_1 (1<<11) //Prevent clicking things below it on the same turf eg. doors/ fulltile windows
-#define HOLOGRAM_1 (1<<12)
-#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity
-#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object
-#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff.
-
-//turf-only flags
-#define NOJAUNT_1 (1<<0)
-#define UNUSED_RESERVATION_TURF_1 (1<<1)
-#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas.
-#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf
-#define NO_RUINS_1 (1<<10) //Blocks ruins spawning on the turf
-
-/*
- These defines are used specifically with the atom/pass_flags bitmask
- the atom/checkpass() proc uses them (tables will call movable atom checkpass(PASSTABLE) for example)
-*/
-//flags for pass_flags
-#define PASSTABLE (1<<0)
-#define PASSGLASS (1<<1)
-#define PASSGRILLE (1<<2)
-#define PASSBLOB (1<<3)
-#define PASSMOB (1<<4)
-#define PASSCLOSEDTURF (1<<5)
-#define LETPASSTHROW (1<<6)
-
-//Movement Types
-#define GROUND (1<<0)
-#define FLYING (1<<1)
-#define VENTCRAWLING (1<<2)
-#define FLOATING (1<<3)
-#define UNSTOPPABLE (1<<4) //When moving, will Bump()/Cross()/Uncross() everything, but won't be stopped.
-
-//Fire and Acid stuff, for resistance_flags
-#define LAVA_PROOF (1<<0)
-#define FIRE_PROOF (1<<1) //100% immune to fire damage (but not necessarily to lava or heat)
-#define FLAMMABLE (1<<2)
-#define ON_FIRE (1<<3)
-#define UNACIDABLE (1<<4) //acid can't even appear on it, let alone melt it.
-#define ACID_PROOF (1<<5) //acid stuck on it doesn't melt it.
-#define INDESTRUCTIBLE (1<<6) //doesn't take damage
-#define FREEZE_PROOF (1<<7) //can't be frozen
-
-/obj/item/proc/clothing_resistance_flag_examine_message(mob/user)
- if(resistance_flags & INDESTRUCTIBLE)
- to_chat(user, "[src] seems extremely robust! It'll probably withstand anything that could happen to it!")
- return
- if(resistance_flags & LAVA_PROOF)
- to_chat(user, "[src] is made of an extremely heat-resistant material, it'd probably be able to withstand lava!")
- if(resistance_flags & (ACID_PROOF | UNACIDABLE))
- to_chat(user, "[src] looks pretty robust! It'd probably be able to withstand acid!")
- if(resistance_flags & FREEZE_PROOF)
- to_chat(user, "[src] is made of cold-resistant materials.")
- if(resistance_flags & FIRE_PROOF)
- to_chat(user, "[src] is made of fire-retardant materials.")
- return TRUE
-
-/obj/item/clothing/clothing_resistance_flag_examine_message(mob/user)
- . = ..()
- if(.)
- return
- if(max_heat_protection_temperature == FIRE_IMMUNITY_MAX_TEMP_PROTECT)
- to_chat(user, "[src] is made of fire-retardant materials.")
- return TRUE
-
-/obj/item/clothing/head/clothing_resistance_flag_examine_message(mob/user)
- . = ..()
- if(.)
- return
- if(max_heat_protection_temperature == (HELMET_MAX_TEMP_PROTECT || SPACE_HELM_MAX_TEMP_PROTECT || FIRE_HELM_MAX_TEMP_PROTECT))
- to_chat(user, "[src] is made of thermally insulated materials and offers some protection to fire.")
- return TRUE
-
-/obj/item/clothing/gloves/clothing_resistance_flag_examine_message(mob/user)
- . = ..()
- if(.)
- return
- if(max_heat_protection_temperature == GLOVES_MAX_TEMP_PROTECT)
- to_chat(user, "[src] is made of thermally insulated materials and offers some protection to fire.")
- return TRUE
-
-/obj/item/clothing/shoes/clothing_resistance_flag_examine_message(mob/user)
- . = ..()
- if(.)
- return
- if(max_heat_protection_temperature == SHOES_MAX_TEMP_PROTECT)
- to_chat(user, "[src] is made of thermally insulated materials and offers some protection to fire.")
- return TRUE
-
-/obj/item/clothing/suit/clothing_resistance_flag_examine_message(mob/user)
- . = ..()
- if(.)
- return
- if(max_heat_protection_temperature == SPACE_SUIT_MAX_TEMP_PROTECT)
- to_chat(user, "[src] is made of thermally insulated materials and offers some protection to fire.")
- return TRUE
-
-//tesla_zap
-#define TESLA_MACHINE_EXPLOSIVE (1<<0)
-#define TESLA_ALLOW_DUPLICATES (1<<1)
-#define TESLA_OBJ_DAMAGE (1<<2)
-#define TESLA_MOB_DAMAGE (1<<3)
-#define TESLA_MOB_STUN (1<<4)
-
-#define TESLA_DEFAULT_FLAGS ALL
-#define TESLA_FUSION_FLAGS TESLA_OBJ_DAMAGE | TESLA_MOB_DAMAGE | TESLA_MOB_STUN
-
-//EMP protection
-#define EMP_PROTECT_SELF (1<<0)
-#define EMP_PROTECT_CONTENTS (1<<1)
-#define EMP_PROTECT_WIRES (1<<2)
-
-//Mob mobility var flags
-#define MOBILITY_MOVE (1<<0) //can move
-#define MOBILITY_STAND (1<<1) //can, and is, standing up
-#define MOBILITY_PICKUP (1<<2) //can pickup items
-#define MOBILITY_USE (1<<3) //can hold and use items
-#define MOBILITY_UI (1<<4) //can use interfaces like machinery
-#define MOBILITY_STORAGE (1<<5) //can use storage item
-#define MOBILITY_PULL (1<<6) //can pull things
-
-#define MOBILITY_FLAGS_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_PICKUP | MOBILITY_USE | MOBILITY_UI | MOBILITY_STORAGE | MOBILITY_PULL)
-#define MOBILITY_FLAGS_INTERACTION (MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_UI | MOBILITY_STORAGE)
-
-// radiation
-#define RAD_PROTECT_CONTENTS (1<<0)
-#define RAD_NO_CONTAMINATE (1<<1)
+/*
+ These defines are specific to the atom/flags_1 bitmask
+*/
+#define ALL (~0) //For convenience.
+#define NONE 0
+
+//for convenience
+#define ENABLE_BITFIELD(variable, flag) (variable |= (flag))
+#define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag))
+#define CHECK_BITFIELD(variable, flag) (variable & (flag))
+#define TOGGLE_BITFIELD(variable, flag) (variable ^= (flag))
+
+
+//check if all bitflags specified are present
+#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) ((flagvar & (flags)) == flags)
+
+GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
+
+// for /datum/var/datum_flags
+#define DF_USE_TAG (1<<0)
+#define DF_VAR_EDITED (1<<1)
+#define DF_ISPROCESSING (1<<2)
+
+//FLAGS BITMASK
+
+#define HEAR_1 (1<<3) // This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
+#define CHECK_RICOCHET_1 (1<<4) // Projectiels will check ricochet on things impacted that have this.
+#define CONDUCT_1 (1<<5) // conducts electricity (metal etc.)
+#define NODECONSTRUCT_1 (1<<7) // For machines and structures that should not break into parts, eg, holodeck stuff
+#define OVERLAY_QUEUED_1 (1<<8) // atom queued to SSoverlay
+#define ON_BORDER_1 (1<<9) // item has priority to check when entering or leaving
+#define PREVENT_CLICK_UNDER_1 (1<<11) //Prevent clicking things below it on the same turf eg. doors/ fulltile windows
+#define HOLOGRAM_1 (1<<12)
+#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity
+#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object
+#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff.
+
+//turf-only flags
+#define NOJAUNT_1 (1<<0)
+#define UNUSED_RESERVATION_TURF_1 (1<<1)
+#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas.
+#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf
+#define NO_RUINS_1 (1<<10) //Blocks ruins spawning on the turf
+
+/*
+ These defines are used specifically with the atom/pass_flags bitmask
+ the atom/checkpass() proc uses them (tables will call movable atom checkpass(PASSTABLE) for example)
+*/
+//flags for pass_flags
+#define PASSTABLE (1<<0)
+#define PASSGLASS (1<<1)
+#define PASSGRILLE (1<<2)
+#define PASSBLOB (1<<3)
+#define PASSMOB (1<<4)
+#define PASSCLOSEDTURF (1<<5)
+#define LETPASSTHROW (1<<6)
+
+//Movement Types
+#define GROUND (1<<0)
+#define FLYING (1<<1)
+#define VENTCRAWLING (1<<2)
+#define FLOATING (1<<3)
+#define UNSTOPPABLE (1<<4) //When moving, will Bump()/Cross()/Uncross() everything, but won't be stopped.
+
+//Fire and Acid stuff, for resistance_flags
+#define LAVA_PROOF (1<<0)
+#define FIRE_PROOF (1<<1) //100% immune to fire damage (but not necessarily to lava or heat)
+#define FLAMMABLE (1<<2)
+#define ON_FIRE (1<<3)
+#define UNACIDABLE (1<<4) //acid can't even appear on it, let alone melt it.
+#define ACID_PROOF (1<<5) //acid stuck on it doesn't melt it.
+#define INDESTRUCTIBLE (1<<6) //doesn't take damage
+#define FREEZE_PROOF (1<<7) //can't be frozen
+
+/obj/item/proc/clothing_resistance_flag_examine_message(mob/user)
+ if(resistance_flags & INDESTRUCTIBLE)
+ to_chat(user, "[src] seems extremely robust! It'll probably withstand anything that could happen to it!")
+ return
+ if(resistance_flags & LAVA_PROOF)
+ to_chat(user, "[src] is made of an extremely heat-resistant material, it'd probably be able to withstand lava!")
+ if(resistance_flags & (ACID_PROOF | UNACIDABLE))
+ to_chat(user, "[src] looks pretty robust! It'd probably be able to withstand acid!")
+ if(resistance_flags & FREEZE_PROOF)
+ to_chat(user, "[src] is made of cold-resistant materials.")
+ if(resistance_flags & FIRE_PROOF)
+ to_chat(user, "[src] is made of fire-retardant materials.")
+ return TRUE
+
+/obj/item/clothing/clothing_resistance_flag_examine_message(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(max_heat_protection_temperature == FIRE_IMMUNITY_MAX_TEMP_PROTECT)
+ to_chat(user, "[src] is made of fire-retardant materials.")
+ return TRUE
+
+/obj/item/clothing/head/clothing_resistance_flag_examine_message(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(max_heat_protection_temperature == (HELMET_MAX_TEMP_PROTECT || SPACE_HELM_MAX_TEMP_PROTECT || FIRE_HELM_MAX_TEMP_PROTECT))
+ to_chat(user, "[src] is made of thermally insulated materials and offers some protection to fire.")
+ return TRUE
+
+/obj/item/clothing/gloves/clothing_resistance_flag_examine_message(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(max_heat_protection_temperature == GLOVES_MAX_TEMP_PROTECT)
+ to_chat(user, "[src] is made of thermally insulated materials and offers some protection to fire.")
+ return TRUE
+
+/obj/item/clothing/shoes/clothing_resistance_flag_examine_message(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(max_heat_protection_temperature == SHOES_MAX_TEMP_PROTECT)
+ to_chat(user, "[src] is made of thermally insulated materials and offers some protection to fire.")
+ return TRUE
+
+/obj/item/clothing/suit/clothing_resistance_flag_examine_message(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(max_heat_protection_temperature == SPACE_SUIT_MAX_TEMP_PROTECT)
+ to_chat(user, "[src] is made of thermally insulated materials and offers some protection to fire.")
+ return TRUE
+
+//tesla_zap
+#define TESLA_MACHINE_EXPLOSIVE (1<<0)
+#define TESLA_ALLOW_DUPLICATES (1<<1)
+#define TESLA_OBJ_DAMAGE (1<<2)
+#define TESLA_MOB_DAMAGE (1<<3)
+#define TESLA_MOB_STUN (1<<4)
+
+#define TESLA_DEFAULT_FLAGS ALL
+#define TESLA_FUSION_FLAGS TESLA_OBJ_DAMAGE | TESLA_MOB_DAMAGE | TESLA_MOB_STUN
+
+//EMP protection
+#define EMP_PROTECT_SELF (1<<0)
+#define EMP_PROTECT_CONTENTS (1<<1)
+#define EMP_PROTECT_WIRES (1<<2)
+
+//Mob mobility var flags
+#define MOBILITY_MOVE (1<<0) //can move
+#define MOBILITY_STAND (1<<1) //can, and is, standing up
+#define MOBILITY_PICKUP (1<<2) //can pickup items
+#define MOBILITY_USE (1<<3) //can hold and use items
+#define MOBILITY_UI (1<<4) //can use interfaces like machinery
+#define MOBILITY_STORAGE (1<<5) //can use storage item
+#define MOBILITY_PULL (1<<6) //can pull things
+
+#define MOBILITY_FLAGS_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_PICKUP | MOBILITY_USE | MOBILITY_UI | MOBILITY_STORAGE | MOBILITY_PULL)
+#define MOBILITY_FLAGS_INTERACTION (MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_UI | MOBILITY_STORAGE)
+
+// radiation
+#define RAD_PROTECT_CONTENTS (1<<0)
+#define RAD_NO_CONTAMINATE (1<<1)
diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm
index 109078f804b..fe51b0fc0ad 100644
--- a/code/game/objects/items/cardboard_cutouts.dm
+++ b/code/game/objects/items/cardboard_cutouts.dm
@@ -74,6 +74,7 @@
playsound(src, 'sound/weapons/slice.ogg', 50, 1)
if(prob(P.damage))
push_over()
+ return BULLET_ACT_HIT
/obj/item/cardboard_cutout/proc/change_appearance(obj/item/toy/crayon/crayon, mob/living/user)
if(!crayon || !user)
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 0595463d9fa..ba4e365e982 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -245,7 +245,7 @@
if(Pgun && istype(Pgun))
Pgun.field_connect(src)
else
- return 0
+ return BULLET_ACT_HIT
/obj/structure/chrono_field/assume_air()
return 0
diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index 25d3d63b942..1e9b4959f76 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -146,7 +146,7 @@
master.disrupt()
/obj/effect/dummy/chameleon/bullet_act()
- ..()
+ . = ..()
master.disrupt()
/obj/effect/dummy/chameleon/relaymove(mob/user, direction)
diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm
index d6142ea2750..eb8359fc358 100644
--- a/code/game/objects/items/latexballoon.dm
+++ b/code/game/objects/items/latexballoon.dm
@@ -40,8 +40,10 @@
if (prob(50))
qdel(src)
-/obj/item/latexballon/bullet_act()
- burst()
+/obj/item/latexballon/bullet_act(obj/item/projectile/P)
+ if(!P.nodamage)
+ burst()
+ return ..()
/obj/item/latexballon/temperature_expose(datum/gas_mixture/air, temperature, volume)
if(temperature > T0C+100)
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index e20ed59697d..50de4a8ec1f 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -310,7 +310,8 @@
/obj/item/melee/supermatter_sword/bullet_act(obj/item/projectile/P)
visible_message("[P] smacks into [src] and rapidly flashes to ash.",\
"You hear a loud crack as you are washed with a wave of heat.")
- consume_everything()
+ consume_everything(P)
+ return BULLET_ACT_HIT
/obj/item/melee/supermatter_sword/suicide_act(mob/user)
user.visible_message("[user] touches [src]'s blade. It looks like [user.p_theyre()] tired of waiting for the radiation to kill [user.p_them()]!")
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 9087d0acc54..3e8ca31f77d 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -60,7 +60,7 @@
#define DECALTYPE_BULLET 2
/obj/item/target/clown/bullet_act(obj/item/projectile/P)
- ..()
+ . = ..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
/obj/item/target/bullet_act(obj/item/projectile/P)
@@ -89,8 +89,8 @@
else
bullet_hole.icon_state = "dent"
add_overlay(bullet_hole)
- return
- return -1
+ return BULLET_ACT_HIT
+ return BULLET_ACT_FORCE_PIERCE
#undef DECALTYPE_SCORCH
#undef DECALTYPE_BULLET
diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm
index 3c649f15492..5c48f762501 100644
--- a/code/game/objects/structures/holosign.dm
+++ b/code/game/objects/structures/holosign.dm
@@ -106,6 +106,7 @@
take_damage(10, BRUTE, "melee", 1) //Tasers aren't harmful.
if(istype(P, /obj/item/projectile/beam/disabler))
take_damage(5, BRUTE, "melee", 1) //Disablers aren't harmful.
+ return BULLET_ACT_HIT
/obj/structure/holosign/barrier/medical
name = "\improper PENLITE holobarrier"
@@ -151,6 +152,7 @@
/obj/structure/holosign/barrier/cyborg/hacked/bullet_act(obj/item/projectile/P)
take_damage(P.damage, BRUTE, "melee", 1) //Yeah no this doesn't get projectile resistance.
+ return BULLET_ACT_HIT
/obj/structure/holosign/barrier/cyborg/hacked/proc/cooldown()
shockcd = FALSE
diff --git a/code/game/objects/structures/reflector.dm b/code/game/objects/structures/reflector.dm
index 11bc62a2a66..c03c0022559 100644
--- a/code/game/objects/structures/reflector.dm
+++ b/code/game/objects/structures/reflector.dm
@@ -67,13 +67,13 @@
return ..()
if(auto_reflect(P, pdir, ploc, pangle) != -1)
return ..()
- return -1
+ return BULLET_ACT_FORCE_PIERCE
/obj/structure/reflector/proc/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
P.ignore_source_check = TRUE
P.range = P.decayedRange
P.decayedRange = max(P.decayedRange--, 0)
- return -1
+ return BULLET_ACT_FORCE_PIERCE
/obj/structure/reflector/attackby(obj/item/W, mob/user, params)
if(admin)
diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm
index b25c1c555d6..8160bbddf51 100644
--- a/code/game/objects/structures/statues.dm
+++ b/code/game/objects/structures/statues.dm
@@ -124,7 +124,7 @@
message_admins("Plasma statue ignited by [Proj]. No known firer, in [ADMIN_VERBOSEJMP(T)]")
log_game("Plasma statue ignited by [Proj] in [AREACOORD(T)]. No known firer.")
PlasmaBurn(2500)
- ..()
+ . = ..()
/obj/structure/statue/plasma/attackby(obj/item/W, mob/user, params)
if(W.is_hot() > 300 && !QDELETED(src))//If the temperature of the object is over 300, then ignite
diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm
index b1ad847cc8c..8ce0ffc91c9 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -73,4 +73,4 @@
if(pinned_target)
pinned_target.bullet_act(P)
else
- ..()
+ . = ..()
diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm
index f9abcc7345f..333146a5462 100644
--- a/code/game/turfs/simulated/wall/mineral_walls.dm
+++ b/code/game/turfs/simulated/wall/mineral_walls.dm
@@ -115,13 +115,12 @@
if(exposed_temperature > 300)
PlasmaBurn(exposed_temperature)
-/turf/closed/wall/mineral/plasma/bullet_act(var/obj/item/projectile/Proj)
+/turf/closed/wall/mineral/plasma/bullet_act(obj/item/projectile/Proj)
if(istype(Proj, /obj/item/projectile/beam))
PlasmaBurn(2500)
else if(istype(Proj, /obj/item/projectile/ion))
PlasmaBurn(500)
- ..()
-
+ . = ..()
/turf/closed/wall/mineral/wood
name = "wooden wall"
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 58a95655bfc..571501c8d01 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -204,41 +204,44 @@
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 ..()
// Byond's default turf/Enter() doesn't have the behaviour we want with Bump()
// By default byond will call Bump() on the first dense object in contents
// Here's hoping it doesn't stay like this for years before we finish conversion to step_
var/atom/firstbump
- if(!CanPass(mover, src))
- firstbump = src
- else
+ var/canPassSelf = CanPass(mover, src)
+ if(canPassSelf || CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
for(var/i in contents)
+ if(QDELETED(mover))
+ return FALSE //We were deleted, do not attempt to proceed with movement.
if(i == mover || i == mover.loc) // Multi tile objects and moving out of other objects
continue
- if(QDELETED(mover))
- break
var/atom/movable/thing = i
if(!thing.Cross(mover))
+ if(QDELETED(mover)) //Mover deleted from Cross/CanPass, do not proceed.
+ return FALSE
if(CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
mover.Bump(thing)
continue
else
if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_1 & ON_BORDER_1) && !(firstbump.flags_1 & ON_BORDER_1)))
firstbump = thing
+ if(QDELETED(mover)) //Mover deleted from Cross/CanPass/Bump, do not proceed.
+ return FALSE
+ if(!canPassSelf) //Even if mover is unstoppable they need to bump us.
+ firstbump = src
if(firstbump)
- if(!QDELETED(mover))
- mover.Bump(firstbump)
+ mover.Bump(firstbump)
return CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)
return TRUE
/turf/Exit(atom/movable/mover, atom/newloc)
. = ..()
- if(!.)
+ if(!. || QDELETED(mover))
return FALSE
for(var/i in contents)
- if(QDELETED(mover))
- break
if(i == mover)
continue
var/atom/movable/thing = i
@@ -247,6 +250,8 @@
mover.Bump(thing)
if(!CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
return FALSE
+ if(QDELETED(mover))
+ return FALSE //We were deleted.
/turf/Entered(atom/movable/AM)
..()
@@ -549,3 +554,7 @@
//Should return new turf
/turf/proc/Melt()
return ScrapeAway()
+
+/turf/bullet_act(obj/item/projectile/P)
+ . = ..()
+ return BULLET_ACT_TURF
diff --git a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
index 42ca9e07e2c..3360b0ef5a4 100644
--- a/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
+++ b/code/modules/antagonists/clockcult/clock_mobs/clockwork_marauder.dm
@@ -82,7 +82,7 @@
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/P)
if(deflect_projectile(P))
- return
+ return BULLET_ACT_BLOCK
return ..()
/mob/living/simple_animal/hostile/clockwork/marauder/proc/deflect_projectile(obj/item/projectile/P)
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index ad1900a8e1a..8cabbb322c4 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -244,13 +244,11 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
/obj/item/twohanded/required/gibtonite/bullet_act(obj/item/projectile/P)
GibtoniteReaction(P.firer)
- ..()
+ . = ..()
/obj/item/twohanded/required/gibtonite/ex_act()
GibtoniteReaction(null, 1)
-
-
/obj/item/twohanded/required/gibtonite/proc/GibtoniteReaction(mob/user, triggered_by = 0)
if(!primed)
primed = TRUE
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
index 0139059878a..fd60061284d 100644
--- a/code/modules/mob/living/bloodcrawl.dm
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -13,8 +13,9 @@
/obj/effect/dummy/phased_mob/slaughter/ex_act()
return
+
/obj/effect/dummy/phased_mob/slaughter/bullet_act()
- return
+ return BULLET_ACT_FORCE_PIERCE
/obj/effect/dummy/phased_mob/slaughter/singularity_act()
return
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 8b297333419..c2c69456785 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -80,9 +80,9 @@
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
P.on_hit(src, 100, def_zone)
- return 2
+ return BULLET_ACT_HIT
- return (..(P , def_zone))
+ return ..(P, def_zone)
/mob/living/carbon/human/proc/check_reflect(def_zone) //Reflection checks for anything in your l_hand, r_hand, or wear_suit based on the reflection chance of the object
if(wear_suit)
diff --git a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm
index 22f2083807b..01ee56d94e4 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -399,7 +399,7 @@
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && isliving(Proj.firer))
retaliate(Proj.firer)
- ..()
+ . = ..()
/mob/living/carbon/monkey/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(istype(AM, /obj/item))
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index f4f6fc15596..b548d3c7d72 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -48,7 +48,7 @@
apply_damage(P.damage, P.damage_type, def_zone, armor)
if(P.dismemberment)
check_projectile_dismemberment(P, def_zone)
- return P.on_hit(src, armor)
+ return P.on_hit(src, armor)? BULLET_ACT_HIT : BULLET_ACT_BLOCK
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
return 0
diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm
index 4cf5fd27496..44cdade59f9 100644
--- a/code/modules/mob/living/living_movement.dm
+++ b/code/modules/mob/living/living_movement.dm
@@ -2,6 +2,23 @@
. = ..()
update_turf_movespeed(loc)
+/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
+ if(P.can_hit_target(src, P.permutated, src == P.original, TRUE))
+ P.Bump(src)
+ return TRUE
+ if(mover.throwing)
+ return (!density || !(mobility_flags & MOBILITY_STAND))
+ if(buckled == mover)
+ return TRUE
+ if(ismob(mover))
+ if(mover in buckled_mobs)
+ return TRUE
+ return (!mover.density || !density || !(mobility_flags & MOBILITY_STAND))
+
/mob/living/toggle_move_intent()
. = ..()
update_move_intent_slowdown()
diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm
index 7c59c2b791b..eff8c3f0a5f 100644
--- a/code/modules/mob/living/silicon/ai/ai_defense.dm
+++ b/code/modules/mob/living/silicon/ai/ai_defense.dm
@@ -48,9 +48,8 @@
/mob/living/silicon/ai/bullet_act(obj/item/projectile/Proj)
- ..(Proj)
+ . = ..(Proj)
updatehealth()
- return 2
/mob/living/silicon/ai/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
return // no eyes, no flashing
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 3c798588e50..f342c90db70 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -178,8 +178,7 @@
adjustBruteLoss(30)
/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj, def_zone)
- ..()
+ . = ..()
updatehealth()
if(prob(75) && Proj.damage > 0)
spark_system.start()
- return 2
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 7320e457f12..243f9e78eaf 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -124,7 +124,7 @@
unbuckle_mob(M)
M.visible_message("[M] is knocked off of [src] by the [Proj]!")
Proj.on_hit(src)
- return 2
+ return BULLET_ACT_HIT
/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/static)
if(affect_silicon)
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index a00373c7d78..b31f082f856 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -105,11 +105,9 @@
return TRUE
/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj)
- if(!Proj)
- return
apply_damage(Proj.damage, Proj.damage_type)
Proj.on_hit(src)
- return 0
+ return BULLET_ACT_HIT
/mob/living/simple_animal/ex_act(severity, target, origin)
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
index 0378b0b9ee9..5dea3f0c63e 100644
--- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
+++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
@@ -21,7 +21,7 @@
/mob/living/simple_animal/bot/secbot/grievous/bullet_act(obj/item/projectile/P)
visible_message("[src] deflects [P] with its energy swords!")
playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE)
- return FALSE
+ return BULLET_ACT_BLOCK
/mob/living/simple_animal/bot/secbot/grievous/Crossed(atom/movable/AM)
..()
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index e74b7cfa12c..007b705585d 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -210,7 +210,7 @@ Auto Patrol[]"},
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
retaliate(Proj.firer)
- ..()
+ return ..()
/mob/living/simple_animal/bot/ed209/handle_automated_action()
if(!..())
@@ -510,11 +510,11 @@ Auto Patrol[]"},
spawn(100)
disabled = 0
icon_state = "[lasercolor]ed2091"
- return 1
+ return BULLET_ACT_HIT
else
- ..(Proj)
+ . = ..()
else
- ..(Proj)
+ . = ..()
/mob/living/simple_animal/bot/ed209/bluetag
lasercolor = "b"
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index 3e00590c4e2..c3d7eeb87a3 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -138,7 +138,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
/mob/living/simple_animal/bot/honkbot/bullet_act(obj/item/projectile/Proj)
if((istype(Proj,/obj/item/projectile/beam)) || (istype(Proj,/obj/item/projectile/bullet) && (Proj.damage_type == BURN))||(Proj.damage_type == BRUTE) && (!Proj.nodamage && Proj.damage < health && ishuman(Proj.firer)))
retaliate(Proj.firer)
- ..()
+ return ..()
/mob/living/simple_animal/bot/honkbot/UnarmedAttack(atom/A)
if(!on)
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 7fe2fc97f63..1cc39ca5835 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -149,7 +149,8 @@
return
/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
- if(..())
+ . = ..()
+ if(.)
if(prob(50) && !isnull(load))
unload(0)
if(prob(25))
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index 487d5f84df6..980d3e75774 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -204,8 +204,7 @@ Auto Patrol: []"},
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
retaliate(Proj.firer)
- ..()
-
+ return ..()
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
if(!on)
@@ -219,7 +218,6 @@ Auto Patrol: []"},
else
..()
-
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(istype(AM, /obj/item))
var/obj/item/I = AM
@@ -228,7 +226,6 @@ Auto Patrol: []"},
retaliate(H)
..()
-
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 2ebe0896f85..86c50ec7356 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -173,9 +173,7 @@
return -1 // complete projectile permutation
- return (..(P))
-
-
+ return ..()
////////////////////////Wraith/////////////////////////////////////////////
/mob/living/simple_animal/hostile/construct/wraith
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 2eb3c05eaec..d9c182b3686 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -117,7 +117,7 @@ Difficulty: Very Hard
var/random_y = rand(0, 72)
AT.pixel_y += random_y
- ..()
+ return ..()
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
if(ishuman(L))
@@ -395,7 +395,7 @@ Difficulty: Very Hard
..()
/obj/machinery/anomalous_crystal/bullet_act(obj/item/projectile/P, def_zone)
- ..()
+ . = ..()
if(istype(P, /obj/item/projectile/magic))
ActivationReaction(P.firer, ACTIVATE_MAGIC, P.damage_type)
return
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
index 2041f64154c..d1cbeb2539e 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
@@ -74,7 +74,7 @@
/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(obj/item/projectile/P)
visible_message("The [P.name] was repelled by [name]'s girth!")
- return
+ return BULLET_ACT_BLOCK
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
vision_range = 9
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index 51913e49b05..9cdeaa2f629 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -177,9 +177,10 @@
if(T.throwforce)
Bruise()
-/mob/living/simple_animal/hostile/mushroom/bullet_act()
- ..()
- Bruise()
+/mob/living/simple_animal/hostile/mushroom/bullet_act(obj/item/projectile/P)
+ . = ..()
+ if(P.nodamage)
+ Bruise()
/mob/living/simple_animal/hostile/mushroom/harvest()
var/counter
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 2c45743c55c..26bb9b0c13e 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -84,6 +84,7 @@
attacktext = "slashes"
attack_sound = 'sound/weapons/bladeslice.ogg'
status_flags = 0
+ var/projectile_deflect_chance = 50
/mob/living/simple_animal/hostile/syndicate/melee/space
icon_state = "syndicate_space_knife"
@@ -128,13 +129,11 @@
return ..()
/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(obj/item/projectile/Proj)
- if(!Proj)
- return
- if(prob(50))
+ if(prob(projectile_deflect_chance))
return ..()
else
visible_message("[src] blocks [Proj] with its shield!")
- return 0
+ return BULLET_ACT_BLOCK
/mob/living/simple_animal/hostile/syndicate/melee/sword/space
icon_state = "syndicate_space_sword"
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 6f2120fcb64..11c35a9e4be 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -337,7 +337,7 @@
//Bullets
/mob/living/simple_animal/parrot/bullet_act(obj/item/projectile/Proj)
- ..()
+ . = ..()
if(!stat && !client)
if(parrot_state == PARROT_PERCH)
parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
@@ -347,8 +347,6 @@
//parrot_been_shot += 5
icon_state = icon_living
drop_held_item(0)
- return
-
/*
* AI - Not really intelligent, but I'm calling it AI anyway.
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 1b0d7effc46..ac25431ae2e 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -219,15 +219,13 @@
return ..() //Heals them
/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj)
- if(!Proj)
- return
attacked += 10
if((Proj.damage_type == BURN))
adjustBruteLoss(-abs(Proj.damage)) //fire projectiles heals slimes.
Proj.on_hit(src)
else
- ..(Proj)
- return 0
+ . = ..(Proj)
+ . = . || BULLET_ACT_BLOCK
/mob/living/simple_animal/slime/emp_act(severity)
. = ..()
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 50228c8310b..be049bbed77 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -1,18 +1,6 @@
/mob/CanPass(atom/movable/mover, turf/target)
return TRUE //There's almost no cases where non /living mobs should be used in game as actual mobs, other than ghosts.
-/mob/living/CanPass(atom/movable/mover, turf/target)
- if((mover.pass_flags & PASSMOB))
- return TRUE
- if(istype(mover, /obj/item/projectile) || mover.throwing)
- return (!density || !(mobility_flags & MOBILITY_STAND))
- if(buckled == mover)
- return TRUE
- if(ismob(mover))
- if (mover in buckled_mobs)
- return TRUE
- return (!mover.density || !density || !(mobility_flags & MOBILITY_STAND))
-
//DO NOT USE THIS UNLESS YOU ABSOLUTELY HAVE TO. THIS IS BEING PHASED OUT FOR THE MOVESPEED MODIFICATION SYSTEM.
//See mob_movespeed.dm
/mob/proc/movement_delay() //update /living/movement_delay() if you change this
diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm
index a6808736421..f9e02fd9097 100644
--- a/code/modules/power/rtg.dm
+++ b/code/modules/power/rtg.dm
@@ -79,7 +79,7 @@
addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, get_turf(src), 2, 3, 4, 8), 100) // Not a normal explosion.
/obj/machinery/power/rtg/abductor/bullet_act(obj/item/projectile/Proj)
- ..()
+ . = ..()
if(!going_kaboom && istype(Proj) && !Proj.nodamage && ((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE)))
log_bomber(Proj.firer, "triggered a", src, "explosion via projectile")
overload()
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index 34346a1629b..e94f35f0f11 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -161,7 +161,7 @@ field_generator power level display
if(Proj.flag != "bullet")
power = min(power + Proj.damage, field_generator_max_power)
check_power_level()
- ..()
+ . = ..()
/obj/machinery/field/generator/Destroy()
@@ -336,7 +336,7 @@ field_generator power level display
message_admins("A singulo exists and a containment field has failed at [ADMIN_VERBOSEJMP(T)].")
investigate_log("has failed whilst a singulo exists at [AREACOORD(T)].", INVESTIGATE_SINGULO)
O.last_warning = world.time
-
+
move_resist = initial(move_resist)
/obj/machinery/field/generator/shock(mob/living/user)
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index f06f4ed816c..751ee7a8a52 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -113,7 +113,8 @@
/obj/singularity/bullet_act(obj/item/projectile/P)
- return 0 //Will there be an impact? Who knows. Will we see it? No.
+ qdel(P)
+ return BULLET_ACT_HIT //Will there be an impact? Who knows. Will we see it? No.
/obj/singularity/Bump(atom/A)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 6cae62e2408..92e7c7e6b5d 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -489,7 +489,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
has_been_powered = TRUE
else if(takes_damage)
damage += Proj.damage * config_bullet_energy
- return FALSE
+ return BULLET_ACT_HIT
/obj/machinery/power/supermatter_crystal/singularity_act()
var/gain = 100
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 680982effc2..06e0d2f4119 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -219,6 +219,7 @@
/obj/item/projectile/Bump(atom/A)
var/datum/point/pcache = trajectory.copy_to()
+ var/turf/T = get_turf(A)
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
ricochets++
if(A.handle_ricochet(src))
@@ -233,11 +234,11 @@
var/mob/checking = firer
if((A == firer) || (((A in firer.buckled_mobs) || (istype(checking) && (A == checking.buckled))) && (A != original)) || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
trajectory_ignore_forcemove = TRUE
- forceMove(get_turf(A))
+ forceMove(T)
trajectory_ignore_forcemove = FALSE
return FALSE
- var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
+ var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
if(isturf(A) && hitsound_wall)
@@ -246,50 +247,66 @@
volume = 5
playsound(loc, hitsound_wall, volume, 1, -1)
- if(!prehit(A))
- return FALSE
+ return process_hit(T, select_target(T, A))
- var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
- if(permutation == -1) // the bullet passes through a dense object!
+#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 && !CHECK_BITFIELD(movement_type, UNSTOPPABLE)))
+ 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(!CHECK_BITFIELD(movement_type, UNSTOPPABLE))
temporary_unstoppable_movement = TRUE
ENABLE_BITFIELD(movement_type, UNSTOPPABLE)
- if(A)
- permutated.Add(A)
- return FALSE
- else
- var/atom/alt = select_target(A)
- if(alt)
- if(!prehit(alt))
- return FALSE
- alt.bullet_act(src, def_zone)
- if(!CHECK_BITFIELD(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 && !CHECK_BITFIELD(movement_type, UNSTOPPABLE)))
qdel(src)
- return TRUE
+ return hit_something
-/obj/item/projectile/Move()
- . = ..()
- if(temporary_unstoppable_movement)
- DISABLE_BITFIELD(movement_type, UNSTOPPABLE)
+#undef QDEL_SELF
+#undef DO_NOT_QDEL
+#undef FORCE_QDEL
-/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
- if(!A || !A.density || (A.flags_1 & ON_BORDER_1) || ismob(A) || A == original) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs or machines/structures on that tile.
- return
- var/turf/T = get_turf(A)
- if(original in T)
+/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))
return original
- var/list/mob/living/possible_mobs = typecache_filter_list(T, GLOB.typecache_mob) - A
+ 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(!(M.mobility_flags & MOBILITY_STAND))
+ if(!can_hit_target(M, permutated, M == original, TRUE))
continue
mobs += M
var/mob/M = safepick(mobs)
if(M)
return M.lowest_buckled_mob()
- var/obj/O = safepick(typecache_filter_list(T, GLOB.typecache_machine_or_structure) - A)
+ 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))
+ continue
+ objs += O
+ var/obj/O = safepick(objs)
if(O)
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))
+ return T
+ //Returns null if nothing at all was found.
/obj/item/projectile/proc/check_ricochet()
if(prob(ricochet_chance))
@@ -480,8 +497,6 @@
else if(T != loc)
step_towards(src, T)
hitscan_last = loc
- if(can_hit_target(original, permutated))
- Bump(original)
if(!hitscanning && !forcemoved)
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move
@@ -510,8 +525,25 @@
homing_offset_y = -homing_offset_y
//Returns true if the target atom is on our current turf and above the right layer
-/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
- return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
+//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_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)
+ if(!CHECK_BITFIELD(L.mobility_flags, MOBILITY_USE | MOBILITY_STAND | MOBILITY_MOVE) || !(L.stat == CONSCIOUS)) //If they're able to 1. stand or 2. use items or 3. move, AND they are not softcrit, they are not stunned enough to dodge projectiles passing over.
+ return FALSE
+ return TRUE
//Spread is FORCED!
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
@@ -576,13 +608,17 @@
. = ..()
if(isliving(AM) && !(pass_flags & PASSMOB))
var/mob/living/L = AM
- if(AM == original) //specific aiming for
- Bump(AM)
- if(AM.density) //blocks projectiles
- Bump(AM)
- if((L.mobility_flags & MOBILITY_USE|MOBILITY_STAND|MOBILITY_MOVE) & (MOBILITY_USE|MOBILITY_MOVE)) //If they're either able to move or use items, while crawling, they're not stunned enough to avoid projectiles.
+ if(can_hit_target(L, permutated, (AM == original)))
Bump(AM)
+/obj/item/projectile/Move(atom/newloc, dir = NONE)
+ . = ..()
+ if(.)
+ if(temporary_unstoppable_movement)
+ DISABLE_BITFIELD(movement_type, UNSTOPPABLE)
+ if(fired && can_hit_target(original, permutated, TRUE))
+ Bump(original)
+
/obj/item/projectile/Destroy()
if(hitscan)
finalize_hitscan_and_generate_tracers()
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index 0870c1dbbbe..e5559cace6f 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -81,7 +81,7 @@
boom()
/obj/structure/reagent_dispensers/fueltank/bullet_act(obj/item/projectile/P)
- ..()
+ . = ..()
if(!QDELETED(src)) //wasn't deleted by the projectile's effects.
if(!P.nodamage && ((P.damage_type == BURN) || (P.damage_type == BRUTE)))
log_bomber(P.firer, "detonated a", src, "via projectile")
diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm
index 7d2c7a8e0ec..32aa247a23f 100644
--- a/code/modules/spells/spell_types/ethereal_jaunt.dm
+++ b/code/modules/spells/spell_types/ethereal_jaunt.dm
@@ -99,5 +99,6 @@
/obj/effect/dummy/phased_mob/spell_jaunt/ex_act(blah)
return
+
/obj/effect/dummy/phased_mob/spell_jaunt/bullet_act(blah)
- return
+ return BULLET_ACT_FORCE_PIERCE
diff --git a/code/modules/spells/spell_types/shadow_walk.dm b/code/modules/spells/spell_types/shadow_walk.dm
index f80c74fec71..a3afdba9ecd 100644
--- a/code/modules/spells/spell_types/shadow_walk.dm
+++ b/code/modules/spells/spell_types/shadow_walk.dm
@@ -91,7 +91,7 @@
return
/obj/effect/dummy/phased_mob/shadow/bullet_act()
- return
+ return BULLET_ACT_FORCE_PIERCE
/obj/effect/dummy/phased_mob/shadow/singularity_act()
return