mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 16:47:13 +01:00
[READY] Wounds part 2: Piercing wounds, dismemberment changes, housekeeping (#51786)
* pierce the heavens * starts doing projs * continue pierce * before armor * before sharpness redefine * rename sharp defines, before further implementation * finishing undoing atk_type back to sharpness * neatens up sharpness defines, FALSE -> SHARP_NONE * more piercing, removes brute damage bleed, bubblegum no longer wound * starts letting embeds get in on the fun * half with embed * work on dismembering * continued embed work * more moving bandaging to limbs * more dismemberment work * removing embed pierce stuff * tweaking bullets * more docs and work on dismemberment * spans, piercing, guns * dismemberment and scar fixes * bee changes * bullets embedding * more bullet and dismember work * dismemberment, surgery, piercing, formaldehyde, * pleases travis * pierce smite * nicer on blood * Auto stash before rebase of "tgstation/master" * more neatening * wounds only consider up to 35 damage, wounds on l6 and 762 * updates hulk * balance * defines * lower slug to 50 brute to accommodate wounds * adds differentiation for having flesh/bones/both in mobs * moves scar descs to json, renames organic_state * excises removed healing skill * fixes logs, inconsistencies, some balance changes * untab * slight compress * a * kills pointed global list * dmdoc * halfway through roh * finishes roh review * okay NOW i finished roh's reviews * roh roh roh your boat * gently down the stream * global lists * list ops, fix scanner for bone gel improvised fix * travis moment * sounds added and moved * pellet clouds can join the fun fully, slight gun balancing for wounds * doc moment * unconflicts myself * update hulk * Update code/_onclick/item_attack.dm Co-authored-by: Rohesie <rohesie@gmail.com> * crying ascii face * final rohview * oops * final final Co-authored-by: Rohesie <rohesie@gmail.com>
This commit is contained in:
committed by
SkyratBot
co-authored by
Rohesie
parent
cf47c08045
commit
a97c51b30b
@@ -71,7 +71,7 @@
|
||||
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) // easy tiger, we'll get to that in a sec
|
||||
var/obj/item/bodypart/slit_throat = H.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(slit_throat)
|
||||
var/datum/wound/brute/cut/critical/screaming_through_a_slit_throat = new
|
||||
var/datum/wound/slash/critical/screaming_through_a_slit_throat = new
|
||||
screaming_through_a_slit_throat.apply_wound(slit_throat)
|
||||
H.apply_status_effect(/datum/status_effect/neck_slice)
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/datum/component/embedded
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/obj/item/bodypart/limb
|
||||
@@ -90,14 +89,18 @@
|
||||
RegisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/weaponDeleted)
|
||||
victim.visible_message("<span class='danger'>[weapon] [harmful ? "embeds" : "sticks"] itself [harmful ? "in" : "to"] [victim]'s [limb.name]!</span>", "<span class='userdanger'>[weapon] [harmful ? "embeds" : "sticks"] itself [harmful ? "in" : "to"] your [limb.name]!</span>")
|
||||
|
||||
var/damage = weapon.throwforce
|
||||
if(harmful)
|
||||
victim.throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
|
||||
playsound(victim,'sound/weapons/bladeslice.ogg', 40)
|
||||
weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody!
|
||||
var/damage = weapon.w_class * impact_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND)
|
||||
damage += weapon.w_class * impact_pain_mult
|
||||
SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||
|
||||
if(damage > 0)
|
||||
var/armor = victim.run_armor_check(limb.body_zone, "melee", "Your armor has protected your [limb.name].", "Your armor has softened a hit to your [limb.name].",I.armour_penetration)
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, blocked=armor, sharpness = I.get_sharpness())
|
||||
|
||||
/datum/component/embedded/Destroy()
|
||||
var/mob/living/carbon/victim = parent
|
||||
if(victim && !victim.has_embedded_objects())
|
||||
@@ -129,16 +132,22 @@
|
||||
return
|
||||
|
||||
var/damage = weapon.w_class * pain_mult
|
||||
var/chance = pain_chance
|
||||
var/pain_chance_current = pain_chance
|
||||
if(pain_stam_pct && victim.stam_paralyzed) //if it's a less-lethal embed, give them a break if they're already stamcritted
|
||||
chance *= 0.2
|
||||
pain_chance_current *= 0.2
|
||||
damage *= 0.5
|
||||
else if(victim.mobility_flags & ~MOBILITY_STAND)
|
||||
pain_chance_current *= 0.2
|
||||
|
||||
if(harmful && prob(chance))
|
||||
if(harmful && prob(pain_chance_current))
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE, wound_bonus = CANT_WOUND)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] hurts!</span>")
|
||||
|
||||
if(prob(fall_chance))
|
||||
var/fall_chance_current = fall_chance
|
||||
if(victim.mobility_flags & ~MOBILITY_STAND)
|
||||
fall_chance_current *= 0.2
|
||||
|
||||
if(prob(fall_chance_current))
|
||||
fallOut()
|
||||
|
||||
////////////////////////////////////////
|
||||
@@ -155,7 +164,7 @@
|
||||
|
||||
if(harmful && prob(chance))
|
||||
var/damage = weapon.w_class * jostle_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE, wound_bonus = CANT_WOUND)
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] jostles and stings!</span>")
|
||||
|
||||
|
||||
@@ -165,29 +174,27 @@
|
||||
|
||||
if(harmful)
|
||||
var/damage = weapon.w_class * remove_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE, wound_bonus = CANT_WOUND)
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=SHARP_EDGED) // can wound
|
||||
|
||||
victim.visible_message("<span class='danger'>[weapon] falls [harmful ? "out" : "off"] of [victim.name]'s [limb.name]!</span>", "<span class='userdanger'>[weapon] falls [harmful ? "out" : "off"] of your [limb.name]!</span>")
|
||||
safeRemove()
|
||||
|
||||
|
||||
/// Called when a carbon with an object embedded/stuck to them inspects themselves and clicks the appropriate link to begin ripping the item out. This handles the ripping attempt, descriptors, and dealing damage, then calls safe_remove()
|
||||
/datum/component/embedded/proc/ripOut(datum/source, obj/item/I, obj/item/bodypart/limb)
|
||||
if(I != weapon || src.limb != limb)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/victim = parent
|
||||
var/time_taken = rip_time * weapon.w_class
|
||||
victim.visible_message("<span class='warning'>[victim] attempts to remove [weapon] from [victim.p_their()] [limb.name].</span>","<span class='notice'>You attempt to remove [weapon] from your [limb.name]... (It will take [DisplayTimeText(time_taken)].)</span>")
|
||||
|
||||
if(!do_after(victim, time_taken, target = victim))
|
||||
return
|
||||
if(!weapon || !limb || weapon.loc != victim || !(weapon in limb.embedded_objects))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(harmful)
|
||||
var/damage = weapon.w_class * remove_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE) //It hurts to rip it out, get surgery you dingus.
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=SHARP_EDGED) //It hurts to rip it out, get surgery you dingus.
|
||||
victim.emote("scream")
|
||||
|
||||
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] [harmful ? "out" : "off"] of [victim.p_their()] [limb.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [limb.name].</span>")
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// the following defines are used for [/datum/component/pellet_cloud/var/list/wound_info_by_part] to store the damage, wound_bonus, and bw_bonus for each bodypart hit
|
||||
#define CLOUD_POSITION_DAMAGE 1
|
||||
#define CLOUD_POSITION_W_BONUS 2
|
||||
#define CLOUD_POSITION_BW_BONUS 3
|
||||
|
||||
/*
|
||||
* This component is used when you want to create a bunch of shrapnel or projectiles (say, shrapnel from a fragmentation grenade, or buckshot from a shotgun) from a central point,
|
||||
* without necessarily printing a separate message for every single impact. This component should be instantiated right when you need it (like the moment of firing), then activated
|
||||
@@ -29,9 +34,11 @@
|
||||
var/list/pellets = list()
|
||||
/// An associated list with the atom hit as the key and how many pellets they've eaten for the value, for printing aggregate messages
|
||||
var/list/targets_hit = list()
|
||||
/// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
/// Another associated list for hit bodyparts on carbons so we can track how much wounding potential we have for each bodypart
|
||||
var/list/wound_info_by_part = list()
|
||||
/// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs]
|
||||
var/list/bodies
|
||||
/// For grenades, tracking people who die covering a grenade for achievement purposes, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
/// For grenades, tracking people who die covering a grenade for achievement purposes, see [/datum/component/pellet_cloud/proc/handle_martyrs]
|
||||
var/list/purple_hearts
|
||||
|
||||
/// For grenades, tracking how many pellets are removed due to martyrs and how many pellets are added due to the last person to touch it being on top of it
|
||||
@@ -65,6 +72,7 @@
|
||||
purple_hearts = null
|
||||
pellets = null
|
||||
targets_hit = null
|
||||
wound_info_by_part = null
|
||||
bodies = null
|
||||
return ..()
|
||||
|
||||
@@ -86,7 +94,7 @@
|
||||
/**
|
||||
* create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance)
|
||||
*
|
||||
* Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing()] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes.
|
||||
* Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes.
|
||||
* The arguments really don't matter, this proc is triggered by COMSIG_PELLET_CLOUD_INIT which is only for this really, it's just a big mess of the state vars we need for doing the stuff over here.
|
||||
*/
|
||||
/datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro)
|
||||
@@ -114,7 +122,7 @@
|
||||
/**
|
||||
* create_blast_pellets() is for when we have a central point we want to shred the surroundings of with a ring of shrapnel, namely frag grenades and landmines.
|
||||
*
|
||||
* Note that grenades have extra handling for someone throwing themselves/being thrown on top of it, while landmines do not (obviously, it's a landmine!). See [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
* Note that grenades have extra handling for someone throwing themselves/being thrown on top of it, while landmines do not (obviously, it's a landmine!). See [/datum/component/pellet_cloud/proc/handle_martyrs]
|
||||
*/
|
||||
/datum/component/pellet_cloud/proc/create_blast_pellets(obj/O, mob/living/lanced_by)
|
||||
var/atom/A = parent
|
||||
@@ -189,10 +197,26 @@
|
||||
break
|
||||
|
||||
///One of our pellets hit something, record what it was and check if we're done (terminated == num_pellets)
|
||||
/datum/component/pellet_cloud/proc/pellet_hit(obj/projectile/P, atom/movable/firer, atom/target, Angle)
|
||||
/datum/component/pellet_cloud/proc/pellet_hit(obj/projectile/P, atom/movable/firer, atom/target, Angle, hit_zone)
|
||||
pellets -= P
|
||||
terminated++
|
||||
hits++
|
||||
var/obj/item/bodypart/hit_part
|
||||
if(iscarbon(target) && hit_zone)
|
||||
var/mob/living/carbon/hit_carbon = target
|
||||
hit_part = hit_carbon.get_bodypart(hit_zone)
|
||||
if(hit_part)
|
||||
target = hit_part
|
||||
if(P.wound_bonus != CANT_WOUND) // handle wounding
|
||||
// unfortunately, due to how pellet clouds handle finalizing only after every pellet is accounted for, that also means there might be a short delay in dealing wounds if one pellet goes wide
|
||||
// while buckshot may reach a target or miss it all in one tick, we also have to account for possible ricochets that may take a bit longer to hit the target
|
||||
if(isnull(wound_info_by_part[hit_part]))
|
||||
wound_info_by_part[hit_part] = list(0, 0, 0)
|
||||
wound_info_by_part[hit_part][CLOUD_POSITION_DAMAGE] += P.damage // these account for decay
|
||||
wound_info_by_part[hit_part][CLOUD_POSITION_W_BONUS] += P.wound_bonus
|
||||
wound_info_by_part[hit_part][CLOUD_POSITION_BW_BONUS] += P.bare_wound_bonus
|
||||
P.wound_bonus = CANT_WOUND // actual wounding will be handled aggregate
|
||||
|
||||
targets_hit[target]++
|
||||
if(targets_hit[target] == 1)
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
|
||||
@@ -233,12 +257,23 @@
|
||||
for(var/atom/target in targets_hit)
|
||||
var/num_hits = targets_hit[target]
|
||||
UnregisterSignal(target, COMSIG_PARENT_QDELETING)
|
||||
var/obj/item/bodypart/hit_part
|
||||
if(isbodypart(target))
|
||||
hit_part = target
|
||||
target = hit_part.owner
|
||||
var/damage_dealt = wound_info_by_part[hit_part][CLOUD_POSITION_DAMAGE]
|
||||
var/w_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_W_BONUS]
|
||||
var/bw_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_BW_BONUS]
|
||||
var/wound_type = (initial(P.damage_type) == BRUTE) ? WOUND_BLUNT : WOUND_BURN // sharpness is handled in the wound rolling
|
||||
wound_info_by_part[hit_part] = null
|
||||
hit_part.painless_wound_roll(wound_type, damage_dealt, w_bonus, bw_bonus, initial(P.sharpness))
|
||||
|
||||
if(num_hits > 1)
|
||||
target.visible_message("<span class='danger'>[target] is hit by [num_hits] [proj_name]s!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by [num_hits] [proj_name]s!</span>")
|
||||
target.visible_message("<span class='danger'>[target] is hit by [num_hits] [proj_name]s[hit_part ? " in the [hit_part.name]" : ""]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by [num_hits] [proj_name]s[hit_part ? " in the [hit_part.name]" : ""]!</span>")
|
||||
else
|
||||
target.visible_message("<span class='danger'>[target] is hit by a [proj_name]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by a [proj_name]!</span>")
|
||||
target.visible_message("<span class='danger'>[target] is hit by a [proj_name][hit_part ? " in the [hit_part.name]" : ""]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by a [proj_name][hit_part ? " in the [hit_part.name]" : ""]!</span>")
|
||||
|
||||
for(var/M in purple_hearts)
|
||||
var/mob/living/martyr = M
|
||||
@@ -287,3 +322,8 @@
|
||||
targets_hit -= target
|
||||
LAZYREMOVE(bodies, target)
|
||||
LAZYREMOVE(purple_hearts, target)
|
||||
|
||||
|
||||
#undef CLOUD_POSITION_DAMAGE
|
||||
#undef CLOUD_POSITION_W_BONUS
|
||||
#undef CLOUD_POSITION_BW_BONUS
|
||||
|
||||
@@ -366,7 +366,7 @@
|
||||
user.adjustBruteLoss(30)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 60, TRUE)
|
||||
playsound(user, 'sound/effects/splat.ogg', 70, TRUE)
|
||||
playsound(user, 'sound/effects/crack2.ogg', 70, TRUE)
|
||||
playsound(user, 'sound/effects/wounds/crack2.ogg', 70, TRUE)
|
||||
user.emote("scream")
|
||||
user.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic) // oopsie indeed!
|
||||
shake_camera(user, 7, 7)
|
||||
|
||||
Reference in New Issue
Block a user