Skip to content

Commit

Permalink
Adds defenestration and bullet penetrating glass (#573)
Browse files Browse the repository at this point in the history
* Adds defenestration and pullet penetrating glass

* Tackle Tweaks
  • Loading branch information
MrMelbert authored Sep 15, 2024
1 parent bc3ba1d commit 98c8b30
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 61 deletions.
2 changes: 1 addition & 1 deletion code/datums/components/caltrop.dm
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
if((flags & CALTROP_IGNORE_WALKERS) && digitigrade_fan.move_intent == MOVE_INTENT_WALK)
return

if(digitigrade_fan.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) //check if they are able to pass over us
if((digitigrade_fan.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || !QDELETED(digitigrade_fan.throwing)) //check if they are able to pass over us
//gravity checking only our parent would prevent us from triggering they're using magboots / other gravity assisting items that would cause them to still touch us.
return

Expand Down
41 changes: 2 additions & 39 deletions code/datums/components/tackle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -488,25 +488,13 @@
var/obj/machinery/vending/darth_vendor = hit
darth_vendor.tilt(user, 100)
return
else if(istype(hit, /obj/structure/window))
var/obj/structure/window/W = hit
splatWindow(user, W)
if(QDELETED(W))
return COMPONENT_MOVABLE_IMPACT_NEVERMIND
return

var/oopsie_mod = 0
var/danger_zone = (speed - 1) * 13 // for every extra speed we have over 1, take away 13 of the safest chance
danger_zone = max(min(danger_zone, 100), 1)

if(ishuman(user))
var/mob/living/carbon/human/S = user
var/head_slot = S.get_item_by_slot(ITEM_SLOT_HEAD)
var/suit_slot = S.get_item_by_slot(ITEM_SLOT_OCLOTHING)
if(head_slot && (istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/utility/hardhat)))
oopsie_mod -= 6
if(suit_slot && (istype(suit_slot,/obj/item/clothing/suit/armor/riot)))
oopsie_mod -= 6
oopsie_mod -= floor(user.getarmor(BODY_ZONE_HEAD, MELEE) * 0.18)
oopsie_mod -= floor(user.getarmor(BODY_ZONE_CHEST, MELEE) * 0.12)

if(HAS_TRAIT(user, TRAIT_CLUMSY))
oopsie_mod += 6 //honk!
Expand Down Expand Up @@ -597,31 +585,6 @@
QDEL_NULL(tackle_ref)
UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)

///A special case for splatting for handling windows
/datum/component/tackler/proc/splatWindow(mob/living/carbon/user, obj/structure/window/W)
playsound(user, 'sound/effects/Glasshit.ogg', 140, TRUE)

if(W.type in list(/obj/structure/window, /obj/structure/window/fulltile, /obj/structure/window/unanchored, /obj/structure/window/fulltile/unanchored)) // boring unreinforced windows
for(var/i in 1 to speed)
var/obj/item/shard/shard = new /obj/item/shard(get_turf(user))
shard.embedding = list(embed_chance = 100, ignore_throwspeed_threshold = TRUE, impact_pain_mult=3, pain_chance=5)
shard.updateEmbedding()
user.hitby(shard, skipcatch = TRUE, hitpush = FALSE)
shard.embedding = null
shard.updateEmbedding()
W.atom_destruction()
user.adjustStaminaLoss(10 * speed)
user.Paralyze(3 SECONDS)
user.visible_message(span_danger("[user] smacks into [W] and shatters it, shredding [user.p_them()]self with glass!"), span_userdanger("You smacks into [W] and shatter it, shredding yourself with glass!"))

else
user.visible_message(span_danger("[user] smacks into [W] like a bug!"), span_userdanger("You smacks into [W] like a bug!"))
user.Paralyze(1 SECONDS)
user.Knockdown(3 SECONDS)
W.take_damage(30 * speed)
user.adjustStaminaLoss(10 * speed, updating_stamina=FALSE)
user.adjustBruteLoss(5 * speed)

/datum/component/tackler/proc/delayedSmash(obj/structure/window/W)
if(W)
W.atom_destruction()
Expand Down
97 changes: 95 additions & 2 deletions code/game/objects/obj_defense.dm
Original file line number Diff line number Diff line change
@@ -1,7 +1,87 @@

/obj/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
..()
take_damage(AM.throwforce, BRUTE, MELEE, 1, get_dir(src, AM))
. = ..()
if(QDELETED(src))
return
hit_by_damage(AM, throwingdatum)

/obj/proc/hit_by_damage(atom/movable/hitting_us, datum/thrownthing/throwingdatum)
var/base_dam = hitting_us.throwforce
if(isliving(hitting_us))
var/mob/living/living_mob = hitting_us
var/speed_bonus = throwingdatum.speed - living_mob.throw_speed
if(speed_bonus > 0)
base_dam += (5 * speed_bonus)
base_dam += (5 * max(0, living_mob.mob_size - 1))
if(isitem(hitting_us))
var/obj/item/hit_item = hitting_us
base_dam += (5 * max(0, hit_item.w_class - 2))

// no armor penetration
take_damage(base_dam, BRUTE, MELEE, TRUE, get_dir(src, hitting_us), 0)

/obj/structure/window/Initialize(mapload, direct)
. = ..()
// glass will buckle before being pushed around
ADD_TRAIT(src, TRAIT_NO_THROW_HITPUSH, INNATE_TRAIT)

/obj/structure/window/Cross(atom/movable/crossed_atom)
. = ..()
if(.)
return .
if(!isliving(crossed_atom) || QDELETED(crossed_atom.throwing))
return .
if(anchored && get_integrity_percentage() > 0.5)
return .

var/turf/old_loc = loc

take_damage(INFINITY, BRUTE, MELEE, TRUE, get_dir(src, crossed_atom), 0)

if(!QDELETED(src))
return .

var/mob/living/defenestrated = crossed_atom
var/has_grille = locate(/obj/structure/grille) in old_loc
var/list/obj/item/shards = list()
for(var/obj/item/shard/shard in old_loc)
shards += shard

for(var/zone in shuffle(BODY_ZONES_ALL))
var/obj/item/bodypart/part = defenestrated.get_bodypart(zone)
if(!part)
continue
if(has_grille && prob(66))
continue

defenestrated.apply_damage(10, BRUTE, part, blocked = min(90, defenestrated.getarmor(part, MELEE)), sharpness = SHARP_POINTY, wound_bonus = 4, bare_wound_bonus = 8, attacking_item = (length(shards) ? shards[1] : "glass"))
if(prob(25 * length(shards)) && shards[1].tryEmbed(part, TRUE))
shards -= shards[1]

if(has_grille)
defenestrated.Paralyze(1 SECONDS)
defenestrated.Knockdown(2 SECONDS)
defenestrated.visible_message(
span_danger("[defenestrated] is thrown against [src], shattering it!"),
span_userdanger("You are thrown against [src], shattering it!"),
)

else
defenestrated.Paralyze(3 SECONDS)
defenestrated.Knockdown(6 SECONDS)
defenestrated.visible_message(
span_danger("[defenestrated] is thrown clean through [src]!"),
span_userdanger("You are thrown clean through [src]!"),
)

return TRUE

/obj/structure/window/hit_by_damage(atom/movable/hitting_us, datum/thrownthing/throwingdatum)
if(reinf || !isliving(hitting_us))
return ..()

// take a lot of damage from being hit with a mob - so we can defenestrate
take_damage(max_integrity * min(0.75, (get_armor_rating(MELEE) / 100)), BRUTE, MELEE, TRUE, get_dir(src, hitting_us), 0)

/obj/ex_act(severity, target)
if(resistance_flags & INDESTRUCTIBLE)
Expand Down Expand Up @@ -47,6 +127,19 @@

return damage_sustained > 0 ? BULLET_ACT_HIT : BULLET_ACT_BLOCK

/obj/structure/window/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
// don't smack the window and its grille same turf, ever
for(var/obj/structure/grille/grille in loc)
hitting_projectile.impacted[grille] = TRUE

. = ..()
if(QDELETED(hitting_projectile) || . != BULLET_ACT_HIT)
return .
if(QDELETED(src) && prob(80))
// right through the window!
return BULLET_ACT_FORCE_PIERCE
return .

/obj/attack_hulk(mob/living/carbon/human/user)
..()
if(density)
Expand Down
6 changes: 4 additions & 2 deletions code/modules/mob/living/carbon/carbon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@
take_bodypart_damage(5 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
else if(!iscarbon(hit_atom) && extra_speed)
take_bodypart_damage(5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
visible_message(span_danger("[src] crashes into [hit_atom][extra_speed ? " really hard" : ""]"),\
span_userdanger("You violently crash into [hit_atom][extra_speed ? " extra hard" : ""]!"))
visible_message(
span_danger("[src] crashes into [hit_atom][extra_speed ? " really hard" : ""]!"),
span_userdanger("You[extra_speed ? " violently" : ""] crash into [hit_atom][extra_speed ? " extra hard" : ""]!"),
)
log_combat(hit_atom, src, "crashes ")
oof_noise = TRUE

Expand Down
30 changes: 13 additions & 17 deletions code/modules/projectiles/projectile.dm
Original file line number Diff line number Diff line change
Expand Up @@ -293,23 +293,20 @@
hitx = target.pixel_x + rand(-8, 8)
hity = target.pixel_y + rand(-8, 8)

if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_turf) && prob(75))
var/turf/closed/wall/target_wall = target_turf
if(impact_effect_type && !hitscan)
new impact_effect_type(target_wall, hitx, hity)

target_wall.add_dent(WALL_DENT_SHOT, hitx, hity)

return BULLET_ACT_HIT
if((isturf(target) || (isobj(target) && target.density)) && hitsound_wall)
var/volume = clamp(vol_by_damage() + 20, 0, 100)
if(suppressed)
volume = 5
playsound(loc, hitsound_wall, volume, TRUE, -1)

if(!isliving(target))
if(impact_effect_type && !hitscan)
new impact_effect_type(target_turf, 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)

if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_turf) && prob(75))
var/turf/closed/wall/target_wall = target_turf
target_wall.add_dent(WALL_DENT_SHOT, hitx, hity)

return BULLET_ACT_HIT

var/mob/living/living_target = target
Expand Down Expand Up @@ -344,9 +341,7 @@
playsound(loc, hitsound, 5, TRUE, -1)
to_chat(living_target, span_userdanger("You're shot by \a [src][organ_hit_text]!"))
else
if(hitsound)
var/volume = vol_by_damage()
playsound(src, hitsound, volume, TRUE, -1)
playsound(loc, hitsound, vol_by_damage(), TRUE, -1)
living_target.visible_message(span_danger("[living_target] is hit by \a [src][organ_hit_text]!"), \
span_userdanger("You're hit by \a [src][organ_hit_text]!"), null, COMBAT_MESSAGE_RANGE)
if(living_target.is_blind())
Expand Down Expand Up @@ -596,7 +591,8 @@
var/mob/target_mob = target
if(faction_check(target_mob.faction, ignored_factions))
return FALSE
if(target.density || cross_failed) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc.
// melbert todo upstream this. stops grilles from being hit under windows
if((target.density && !target.IsObscured()) || cross_failed) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc.
return TRUE
if(!isliving(target))
if(isturf(target)) // non dense turfs
Expand Down

0 comments on commit 98c8b30

Please sign in to comment.