Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A comprehensive refactor / cleanup of bullet_hit and on_hit to cut out a single bad species / mob proc #167

Merged
merged 1 commit into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
///from base of atom/fire_act(): (exposed_temperature, exposed_volume)
#define COMSIG_ATOM_FIRE_ACT "atom_fire_act"
///from base of atom/bullet_act(): (/obj/projectile, def_zone)
#define COMSIG_ATOM_PRE_BULLET_ACT "pre_atom_bullet_act"
/// All this does is prevent default bullet on_hit from being called, [BULLET_ACT_HIT] being return is implied
#define COMPONENT_BULLET_ACTED (1<<0)
/// Forces bullet act to return [BULLET_ACT_BLOCK], takes priority over above
#define COMPONENT_BULLET_BLOCKED (1<<1)
/// Forces bullet act to return [BULLET_ACT_FORCE_PIERCE], takes priority over above
#define COMPONENT_BULLET_PIERCED (1<<2)
///from base of atom/bullet_act(): (/obj/projectile, def_zone)
#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act"
///from base of atom/CheckParts(): (list/parts_list, datum/crafting_recipe/R)
#define COMSIG_ATOM_CHECKPARTS "atom_checkparts"
Expand Down
5 changes: 3 additions & 2 deletions code/datums/components/singularity.dm
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
)
AddComponent(/datum/component/connect_loc_behalf, parent, loc_connections)

RegisterSignal(parent, COMSIG_ATOM_BULLET_ACT, PROC_REF(consume_bullets))
RegisterSignal(parent, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(consume_bullets))

if (notify_admins)
admin_investigate_setup()
Expand All @@ -127,7 +127,7 @@
COMSIG_ATOM_ATTACK_PAW,
COMSIG_ATOM_BLOB_ACT,
COMSIG_ATOM_BSA_BEAM,
COMSIG_ATOM_BULLET_ACT,
COMSIG_ATOM_PRE_BULLET_ACT,
COMSIG_ATOM_BUMPED,
COMSIG_MOVABLE_PRE_MOVE,
COMSIG_ATOM_ATTACKBY,
Expand Down Expand Up @@ -180,6 +180,7 @@
SIGNAL_HANDLER

qdel(projectile)
return COMPONENT_BULLET_BLOCKED

/// Calls singularity_act on the thing passed, usually destroying the object
/datum/component/singularity/proc/default_singularity_act(atom/thing)
Expand Down
4 changes: 0 additions & 4 deletions code/datums/martial/_martial.dm
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,3 @@
if(help_verb)
remove_verb(holder_living, help_verb)
return

///Gets called when a projectile hits the owner. Returning anything other than BULLET_ACT_HIT will stop the projectile from hitting the mob.
/datum/martial_art/proc/on_projectile_hit(mob/living/attacker, obj/projectile/P, def_zone)
return BULLET_ACT_HIT
27 changes: 17 additions & 10 deletions code/datums/martial/sleeping_carp.dm
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
return
target.add_traits(list(TRAIT_NOGUNS, TRAIT_HARDLY_WOUNDED, TRAIT_NODISMEMBER), SLEEPING_CARP_TRAIT)
RegisterSignal(target, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
RegisterSignal(target, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile))
target.faction |= FACTION_CARP //:D

/datum/martial_art/the_sleeping_carp/on_remove(mob/living/target)
target.remove_traits(list(TRAIT_NOGUNS, TRAIT_HARDLY_WOUNDED, TRAIT_NODISMEMBER), SLEEPING_CARP_TRAIT)
UnregisterSignal(target, COMSIG_ATOM_ATTACKBY)
UnregisterSignal(target, COMSIG_ATOM_PRE_BULLET_ACT)
target.faction -= FACTION_CARP //:(
. = ..()

Expand Down Expand Up @@ -113,6 +115,8 @@
return ..()

/datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user)
if(!can_use(carp_user) || !carp_user.throw_mode)
return FALSE
if(carp_user.incapacitated(IGNORE_GRAB)) //NO STUN
return FALSE
if(!(carp_user.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE
Expand All @@ -124,17 +128,20 @@
return FALSE
return TRUE

/datum/martial_art/the_sleeping_carp/on_projectile_hit(mob/living/carp_user, obj/projectile/P, def_zone)
. = ..()
/datum/martial_art/the_sleeping_carp/proc/hit_by_projectile(mob/living/carp_user, obj/projectile/hitting_projectile, def_zone)
SIGNAL_HANDLER

if(!can_deflect(carp_user))
return BULLET_ACT_HIT
if(carp_user.throw_mode)
carp_user.visible_message(span_danger("[carp_user] effortlessly swats the projectile aside! They can block bullets with their bare hands!"), span_userdanger("You deflect the projectile!"))
playsound(get_turf(carp_user), pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
P.firer = carp_user
P.set_angle(rand(0, 360))//SHING
return BULLET_ACT_FORCE_PIERCE
return BULLET_ACT_HIT
return NONE

carp_user.visible_message(
span_danger("[carp_user] effortlessly swats [hitting_projectile] aside! [carp_user.p_They()] can block bullets with [carp_user.p_their()] bare hands!"),
span_userdanger("You deflect [hitting_projectile]!"),
)
playsound(carp_user, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
hitting_projectile.firer = carp_user
hitting_projectile.set_angle(rand(0, 360))//SHING
return COMPONENT_BULLET_PIERCED

///Signal from getting attacked with an item, for a special interaction with touch spells
/datum/martial_art/the_sleeping_carp/proc/on_attackby(mob/living/carp_user, obj/item/attack_weapon, mob/attacker, params)
Expand Down
2 changes: 2 additions & 0 deletions code/game/atom_defense.dm
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,6 @@

/// A cut-out proc for [/atom/proc/bullet_act] so living mobs can have their own armor behavior checks without causing issues with needing their own on_hit call
/atom/proc/check_projectile_armor(def_zone, obj/projectile/impacting_projectile, is_silent)
if(uses_integrity)
return clamp(PENETRATE_ARMOUR(get_armor_rating(impacting_projectile.armor_flag), impacting_projectile.armour_penetration), 0, 100)
return 0
32 changes: 23 additions & 9 deletions code/game/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -586,19 +586,33 @@
/**
* React to a hit by a projectile object
*
* Default behaviour is to send the [COMSIG_ATOM_BULLET_ACT] and then call [on_hit][/obj/projectile/proc/on_hit] on the projectile.
*
* @params
* hitting_projectile - projectile
* def_zone - zone hit
* piercing_hit - is this hit piercing or normal?
* * hitting_projectile - projectile
* * def_zone - zone hit
* * piercing_hit - is this hit piercing or normal?
*/
/atom/proc/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit = FALSE)
SHOULD_CALL_PARENT(TRUE)

var/sigreturn = SEND_SIGNAL(src, COMSIG_ATOM_PRE_BULLET_ACT, hitting_projectile, def_zone)
if(sigreturn & COMPONENT_BULLET_PIERCED)
return BULLET_ACT_FORCE_PIERCE
if(sigreturn & COMPONENT_BULLET_BLOCKED)
return BULLET_ACT_BLOCK
if(sigreturn & COMPONENT_BULLET_ACTED)
return BULLET_ACT_HIT

SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, hitting_projectile, def_zone)
// This armor check only matters for the visuals and messages in on_hit(), it's not actually used to reduce damage since
// only living mobs use armor to reduce damage, but on_hit() is going to need the value no matter what is shot.
var/visual_armor_check = check_projectile_armor(def_zone, hitting_projectile)
. = hitting_projectile.on_hit(src, visual_armor_check, def_zone, piercing_hit)
if(QDELETED(hitting_projectile)) // Signal deleted it?
return BULLET_ACT_BLOCK

return hitting_projectile.on_hit(
target = src,
// This armor check only matters for the visuals and messages in on_hit(), it's not actually used to reduce damage since
// only living mobs use armor to reduce damage, but on_hit() is going to need the value no matter what is shot.
blocked = check_projectile_armor(def_zone, hitting_projectile),
pierce_hit = piercing_hit,
)

///Return true if we're inside the passed in atom
/atom/proc/in_contents_of(container)//can take class or object instance as argument
Expand Down
3 changes: 2 additions & 1 deletion code/game/objects/effects/phased_mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@
/obj/effect/dummy/phased_mob/ex_act()
return FALSE

/obj/effect/dummy/phased_mob/bullet_act(blah)
/obj/effect/dummy/phased_mob/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit = FALSE)
SHOULD_CALL_PARENT(FALSE)
return BULLET_ACT_FORCE_PIERCE

/obj/effect/dummy/phased_mob/relaymove(mob/living/user, direction)
Expand Down
41 changes: 15 additions & 26 deletions code/game/objects/items/cardboard_cutouts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
icon_state = "cutout_basic"
w_class = WEIGHT_CLASS_BULKY
resistance_flags = FLAMMABLE
obj_flags = CAN_BE_HIT
item_flags = NO_PIXEL_RANDOM_DROP
/// If the cutout is pushed over and has to be righted
var/pushed_over = FALSE
Expand Down Expand Up @@ -35,7 +36,7 @@

//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/cardboard_cutout/attack_hand(mob/living/user, list/modifiers)
if(!user.combat_mode || pushed_over)
if(!user.combat_mode || pushed_over || !isturf(loc))
return ..()
user.visible_message(span_warning("[user] pushes over [src]!"), span_danger("You push over [src]!"))
playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE)
Expand All @@ -60,32 +61,20 @@
/obj/item/cardboard_cutout/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/toy/crayon))
change_appearance(I, user)
return
// Why yes, this does closely resemble mob and object attack code.
if(I.item_flags & NOBLUDGEON)
return
if(!I.force)
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), TRUE, -1)
else if(I.hitsound)
playsound(loc, I.hitsound, get_clamped_volume(), TRUE, -1)

user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(src)

if(I.force)
user.visible_message(span_danger("[user] hits [src] with [I]!"), \
span_danger("You hit [src] with [I]!"))
if(prob(I.force))
push_over()

/obj/item/cardboard_cutout/bullet_act(obj/projectile/P, def_zone, piercing_hit = FALSE)
if(istype(P, /obj/projectile/bullet))
P.on_hit(src, 0, piercing_hit)
visible_message(span_danger("[src] is hit by [P]!"))
playsound(src, 'sound/weapons/slice.ogg', 50, TRUE)
if(prob(P.damage))
return TRUE

return ..()

/obj/item/cardboard_cutout/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration)
. = ..()
var/damage_sustained = . || 0
if((damage_flag == BULLET || damage_flag == MELEE) && (damage_type == BRUTE) && prob(damage_sustained))
push_over()
return BULLET_ACT_HIT

/obj/item/cardboard_cutout/deconstruct(disassembled)
if(!(flags_1 & (HOLOGRAM_1|NODECONSTRUCT_1)))
new /obj/item/stack/sheet/cardboard(loc, 1)
return ..()

/proc/get_cardboard_cutout_instance(datum/cardboard_cutout/cardboard_cutout)
ASSERT(ispath(cardboard_cutout), "[cardboard_cutout] is not a path of /datum/cardboard_cutout")
Expand Down
3 changes: 2 additions & 1 deletion code/game/objects/items/crayons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,8 @@
carbon_target.set_eye_blur_if_lower(6 SECONDS)
carbon_target.adjust_temp_blindness(2 SECONDS)
if(carbon_target.get_eye_protection() <= 0) // no eye protection? ARGH IT BURNS. Warning: don't add a stun here. It's a roundstart item with some quirks.
carbon_target.apply_effects(eyeblur = 5, jitter = 10)
carbon_target.adjust_jitter(1 SECONDS)
carbon_target.adjust_eye_blur(0.5 SECONDS)
flash_color(carbon_target, flash_color=paint_color, flash_time=40)
if(ishuman(carbon_target) && actually_paints)
var/mob/living/carbon/human/human_target = carbon_target
Expand Down
16 changes: 11 additions & 5 deletions code/game/objects/items/melee/misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@
shard.countdown = null
START_PROCESSING(SSobj, src)
visible_message(span_warning("[src] appears, balanced ever so perfectly on its hilt. This isn't ominous at all."))
RegisterSignal(src, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(eat_bullets))

/obj/item/melee/supermatter_sword/process()
if(balanced || throwing || ismob(src.loc) || isnull(src.loc))
Expand Down Expand Up @@ -283,11 +284,16 @@
consume_everything()
return TRUE

/obj/item/melee/supermatter_sword/bullet_act(obj/projectile/projectile)
visible_message(span_danger("[projectile] smacks into [src] and rapidly flashes to ash."),\
span_hear("You hear a loud crack as you are washed with a wave of heat."))
consume_everything(projectile)
return BULLET_ACT_HIT
/obj/item/melee/supermatter_sword/proc/eat_bullets(datum/source, obj/projectile/hitting_projectile)
SIGNAL_HANDLER

visible_message(
span_danger("[hitting_projectile] smacks into [source] and rapidly flashes to ash."),
null,
span_hear("You hear a loud crack as you are washed with a wave of heat."),
)
consume_everything(hitting_projectile)
return COMPONENT_BULLET_BLOCKED

/obj/item/melee/supermatter_sword/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] touches [src]'s blade. It looks like [user.p_theyre()] tired of waiting for the radiation to kill [user.p_them()]!"))
Expand Down
107 changes: 59 additions & 48 deletions code/game/objects/items/shooting_range.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,84 @@
icon = 'icons/obj/structures.dmi'
icon_state = "target_h"
density = FALSE
var/hp = 1800
max_integrity = 1800
item_flags = CAN_BE_HIT
/// Lazylist to keep track of bullet-hole overlays.
var/list/bullethole_overlays

/obj/item/target/welder_act(mob/living/user, obj/item/I)
..()
if(I.use_tool(src, user, 0, volume=40))
for (var/bullethole in bullethole_overlays)
cut_overlay(bullethole)
bullethole_overlays = null
to_chat(user, span_notice("You slice off [src]'s uneven chunks of aluminium and scorch marks."))
/obj/item/target/welder_act(mob/living/user, obj/item/tool)
if(tool.use_tool(src, user, 0 SECONDS, volume = 40))
LAZYNULL(bullethole_overlays)
balloon_alert(user, "target repaired")
update_appearance(UPDATE_OVERLAYS)
return TRUE

/obj/item/target/update_overlays()
. = ..()
. |= bullethole_overlays

/obj/item/target/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit = FALSE)
if(prob(25))
return ..() // RNG change to just not leave a mark, like walls
if(length(overlays) > 35)
return ..() // Too many bullets, we're done here

// Projectiles which do not deal damage will not leave dent / scorch mark graphics.
// However we snowflake some projectiles to leave them anyway, because they're appropriate.
var/static/list/always_leave_marks
if(isnull(always_leave_marks))
always_leave_marks = typecacheof(list(
/obj/projectile/beam/practice,
/obj/projectile/beam/laser/carbine/practice,
))

var/is_invalid_damage = hitting_projectile.damage_type != BRUTE && hitting_projectile.damage_type != BURN
var/is_safe = !hitting_projectile.is_hostile_projectile()
var/is_generic_projectile = !is_type_in_typecache(hitting_projectile, always_leave_marks)
if(is_generic_projectile && (is_invalid_damage || is_safe))
return ..() // Don't bother unless it's real shit

var/p_x = hitting_projectile.p_x + pick(0, 0, 0, 0, 0, -1, 1) // really ugly way of coding "sometimes offset p_x!"
var/p_y = hitting_projectile.p_y + pick(0, 0, 0, 0, 0, -1, 1)
var/icon/our_icon = icon(icon, icon_state)
if(!our_icon.GetPixel(p_x, p_y) || hitting_projectile.original != src)
return BULLET_ACT_FORCE_PIERCE // We, "missed", I guess?

. = ..()
if(. != BULLET_ACT_HIT)
return

var/image/bullet_hole = image('icons/effects/effects.dmi', "dent", OBJ_LAYER + 0.5)
bullet_hole.pixel_x = p_x - 1 //offset correction
bullet_hole.pixel_y = p_y - 1
if(hitting_projectile.damage_type != BRUTE)
bullet_hole.setDir(pick(GLOB.cardinals))// random scorch design
if(hitting_projectile.damage < 20 && is_generic_projectile)
bullet_hole.icon_state = "light_scorch"
else
bullet_hole.icon_state = "scorch"

LAZYADD(bullethole_overlays, bullet_hole)
update_appearance(UPDATE_OVERLAYS)

/obj/item/target/syndicate
icon_state = "target_s"
desc = "A shooting target that looks like syndicate scum."
hp = 2600
max_integrity = 2600

/obj/item/target/alien
icon_state = "target_q"
desc = "A shooting target that looks like a xenomorphic alien."
hp = 2350
max_integrity = 2350

/obj/item/target/alien/anchored
anchored = TRUE

/obj/item/target/clown
icon_state = "target_c"
desc = "A shooting target that looks like a useless clown."
hp = 2000

#define DECALTYPE_SCORCH 1
#define DECALTYPE_BULLET 2
max_integrity = 2000

/obj/item/target/clown/bullet_act(obj/projectile/P)
. = ..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, TRUE)

/obj/item/target/bullet_act(obj/projectile/P)
if(istype(P, /obj/projectile/bullet)) // If it's a foam dart, don't bother with any of this other shit
return P.on_hit(src, 0)
var/p_x = P.p_x + pick(0,0,0,0,0,-1,1) // really ugly way of coding "sometimes offset P.p_x!"
var/p_y = P.p_y + pick(0,0,0,0,0,-1,1)
var/decaltype = DECALTYPE_SCORCH
if(istype(P, /obj/projectile/bullet))
decaltype = DECALTYPE_BULLET
var/icon/C = icon(icon,icon_state)
if(C.GetPixel(p_x, p_y) && P.original == src && overlays.len <= 35) // if the located pixel isn't blank (null)
hp -= P.damage
if(hp <= 0)
visible_message(span_danger("[src] breaks into tiny pieces and collapses!"))
qdel(src)
var/image/bullet_hole = image('icons/effects/effects.dmi', "scorch", OBJ_LAYER + 0.5)
bullet_hole.pixel_x = p_x - 1 //offset correction
bullet_hole.pixel_y = p_y - 1
if(decaltype == DECALTYPE_SCORCH)
bullet_hole.setDir(pick(NORTH,SOUTH,EAST,WEST))// random scorch design
if(P.damage >= 20 || istype(P, /obj/projectile/beam/practice))
bullet_hole.setDir(pick(NORTH,SOUTH,EAST,WEST))
else
bullet_hole.icon_state = "light_scorch"
else
bullet_hole.icon_state = "dent"
LAZYADD(bullethole_overlays, bullet_hole)
add_overlay(bullet_hole)
return BULLET_ACT_HIT
return BULLET_ACT_FORCE_PIERCE

#undef DECALTYPE_SCORCH
#undef DECALTYPE_BULLET
playsound(src, 'sound/items/bikehorn.ogg', 50, TRUE)
Loading
Loading