diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 46a7ba2e0fa..36a38cc5189 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -107,8 +107,9 @@ * * silent: Not actually necessary I don't think, was originally used for demoting wounds so they wouldn't make new messages, but I believe old_wound took over that, I may remove this shortly * * old_wound: If our new wound is a replacement for one of the same time (promotion or demotion), we can reference the old one just before it's removed to copy over necessary vars * * smited- If this is a smite, we don't care about this wound for stat tracking purposes (not yet implemented) + * * attack_direction: For bloodsplatters, if relevant */ -/datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE) +/datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null) if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || !L.is_organic_limb() || HAS_TRAIT(L.owner, TRAIT_NEVER_WOUNDED)) qdel(src) return @@ -158,7 +159,7 @@ playsound(L.owner, sound_effect, 70 + 20 * severity, TRUE) if(!demoted) - wound_injury(old_wound) + wound_injury(old_wound, attack_direction = attack_direction) second_wind() /datum/wound/proc/null_victim() @@ -207,16 +208,16 @@ * * new_type- The TYPE PATH of the wound you want to replace this, like /datum/wound/slash/severe * * smited- If this is a smite, we don't care about this wound for stat tracking purposes (not yet implemented) */ -/datum/wound/proc/replace_wound(new_type, smited = FALSE) +/datum/wound/proc/replace_wound(new_type, smited = FALSE, attack_direction = attack_direction) var/datum/wound/new_wound = new new_type already_scarred = TRUE remove_wound(replaced=TRUE) - new_wound.apply_wound(limb, old_wound = src, smited = smited) + new_wound.apply_wound(limb, old_wound = src, smited = smited, attack_direction = attack_direction) . = new_wound qdel(src) /// The immediate negative effects faced as a result of the wound -/datum/wound/proc/wound_injury(datum/wound/old_wound = null) +/datum/wound/proc/wound_injury(datum/wound/old_wound = null, attack_direction = null) return @@ -346,7 +347,7 @@ return (!QDELETED(src) && limb) /// When our parent bodypart is hurt -/datum/wound/proc/receive_damage(wounding_type, wounding_dmg, wound_bonus) +/datum/wound/proc/receive_damage(wounding_type, wounding_dmg, wound_bonus, attack_direction) return /// Called from cryoxadone and pyroxadone when they're proc'ing. Wounds will slowly be fixed separately from other methods when these are in effect. crappy name but eh diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index bb9a3d51b22..4ad7de9c70a 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -34,7 +34,7 @@ /* Overwriting of base procs */ -/datum/wound/blunt/wound_injury(datum/wound/old_wound = null) +/datum/wound/blunt/wound_injury(datum/wound/old_wound = null, attack_direction = null) // hook into gaining/losing gauze so crit bone wounds can re-enable/disable depending if they're slung or not RegisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED), .proc/update_inefficiencies) @@ -225,7 +225,7 @@ UnregisterSignal(victim, COMSIG_LIVING_DOORCRUSHED) return ..() -/datum/wound/blunt/moderate/wound_injury(datum/wound/old_wound) +/datum/wound/blunt/moderate/wound_injury(datum/wound/old_wound, attack_direction = null) . = ..() RegisterSignal(victim, COMSIG_LIVING_DOORCRUSHED, .proc/door_crush) @@ -363,7 +363,7 @@ regen_ticks_needed = 240 // ticks every 2 seconds, 480 seconds, so roughly 8 minutes default // doesn't make much sense for "a" bone to stick out of your head -/datum/wound/blunt/critical/apply_wound(obj/item/bodypart/L, silent, datum/wound/old_wound, smited) +/datum/wound/blunt/critical/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null) if(L.body_zone == BODY_ZONE_HEAD) occur_text = "splits open, exposing a bare, cracked skull through the flesh and blood" examine_desc = "has an unsettling indent, with bits of skull poking out" diff --git a/code/datums/wounds/loss.dm b/code/datums/wounds/loss.dm index b11280a3a13..9a97ae7c4b6 100644 --- a/code/datums/wounds/loss.dm +++ b/code/datums/wounds/loss.dm @@ -12,7 +12,7 @@ already_scarred = TRUE // We manually assign scars for dismembers through endround missing limbs and aheals /// Our special proc for our special dismembering, the wounding type only matters for what text we have -/datum/wound/loss/proc/apply_dismember(obj/item/bodypart/dismembered_part, wounding_type=WOUND_SLASH, outright = FALSE) +/datum/wound/loss/proc/apply_dismember(obj/item/bodypart/dismembered_part, wounding_type=WOUND_SLASH, outright = FALSE, attack_direction) if(!istype(dismembered_part) || !dismembered_part.owner || !(dismembered_part.body_zone in viable_zones) || isalien(dismembered_part.owner) || !dismembered_part.can_dismember()) qdel(src) return @@ -51,6 +51,8 @@ set_limb(dismembered_part) second_wind() log_wound(victim, src) + if(wounding_type != WOUND_BURN && victim.blood_volume) + victim.spray_blood(attack_direction, severity) dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE) qdel(src) return TRUE diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index 4b1a2defd04..d36292ac7a3 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -25,8 +25,11 @@ /// If we let off blood when hit, the max blood lost is this * the incoming damage var/internal_bleeding_coefficient -/datum/wound/pierce/wound_injury(datum/wound/old_wound) +/datum/wound/pierce/wound_injury(datum/wound/old_wound = null, attack_direction = null) blood_flow = initial_flow + if(attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) + victim.spray_blood(attack_direction, severity) + /datum/wound/pierce/receive_damage(wounding_type, wounding_dmg, wound_bonus) if(victim.stat == DEAD || wounding_dmg < 5) diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index 697c1ccaaeb..90a5aa3fcad 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -32,13 +32,15 @@ /// A bad system I'm using to track the worst scar we earned (since we can demote, we want the biggest our wound has been, not what it was when it was cured (probably moderate)) var/datum/scar/highest_scar -/datum/wound/slash/wound_injury(datum/wound/slash/old_wound = null) +/datum/wound/slash/wound_injury(datum/wound/slash/old_wound = null, attack_direction = null) blood_flow = initial_flow if(old_wound) blood_flow = max(old_wound.blood_flow, initial_flow) if(old_wound.severity > severity && old_wound.highest_scar) set_highest_scar(old_wound.highest_scar) old_wound.clear_highest_scar() + else if(attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY) + victim.spray_blood(attack_direction, severity) if(!highest_scar) var/datum/scar/new_scar = new diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index bb9ed3ec5b7..5f9bd002f96 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -69,6 +69,12 @@ icon_state = "gibbl1" random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5") +/obj/effect/decal/cleanable/blood/splatter/over_window // special layer/plane set to appear on windows + layer = ABOVE_WINDOW_LAYER + plane = GAME_PLANE + turf_loc_check = FALSE + alpha = 180 + /obj/effect/decal/cleanable/blood/tracks icon_state = "tracks" desc = "They look like tracks left by wheels." @@ -296,3 +302,97 @@ if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY)) return TRUE return FALSE + +/obj/effect/decal/cleanable/blood/hitsplatter + name = "blood splatter" + pass_flags = PASSTABLE | PASSGRILLE + icon_state = "hitsplatter1" + random_icon_states = list("hitsplatter1", "hitsplatter2", "hitsplatter3") + /// The turf we just came from, so we can back up when we hit a wall + var/turf/prev_loc + /// The cached info about the blood + var/list/blood_dna_info + /// Skip making the final blood splatter when we're done, like if we're not in a turf + var/skip = FALSE + /// How many tiles/items/people we can paint red + var/splatter_strength = 3 + /// Insurance so that we don't keep moving once we hit a stoppoint + var/hit_endpoint = FALSE + +/obj/effect/decal/cleanable/blood/hitsplatter/Initialize(mapload, splatter_strength) + . = ..() + prev_loc = loc //Just so we are sure prev_loc exists + if(splatter_strength) + src.splatter_strength = splatter_strength + +/obj/effect/decal/cleanable/blood/hitsplatter/Destroy() + if(isturf(loc) && !skip) + playsound(src, 'sound/effects/wounds/splatter.ogg', 60, TRUE, -1) + if(blood_dna_info) + loc.add_blood_DNA(blood_dna_info) + return ..() + +/// Set the splatter up to fly through the air until it rounds out of steam or hits something. Contains sleep() pending imminent moveloop rework, don't call without async'ing it +/obj/effect/decal/cleanable/blood/hitsplatter/proc/fly_towards(turf/target_turf, range) + for(var/i in 1 to range) + step_towards(src,target_turf) + sleep(2) // Will be resolved pending Potato's moveloop rework + prev_loc = loc + for(var/atom/iter_atom in get_turf(src)) + if(hit_endpoint) + return + if(splatter_strength <= 0) + break + + if(isitem(iter_atom)) + iter_atom.add_blood_DNA(blood_dna_info) + splatter_strength-- + else if(ishuman(iter_atom)) + var/mob/living/carbon/human/splashed_human = iter_atom + if(splashed_human.wear_suit) + splashed_human.wear_suit.add_blood_DNA(blood_dna_info) + splashed_human.update_inv_wear_suit() //updates mob overlays to show the new blood (no refresh) + if(splashed_human.w_uniform) + splashed_human.w_uniform.add_blood_DNA(blood_dna_info) + splashed_human.update_inv_w_uniform() //updates mob overlays to show the new blood (no refresh) + splatter_strength-- + if(splatter_strength <= 0) // we used all the puff so we delete it. + qdel(src) + return + qdel(src) + +/obj/effect/decal/cleanable/blood/hitsplatter/Bump(atom/bumped_atom) + if(!iswallturf(bumped_atom) && !istype(bumped_atom, /obj/structure/window)) + qdel(src) + return + + if(istype(bumped_atom, /obj/structure/window)) + var/obj/structure/window/bumped_window = bumped_atom + if(!bumped_window.fulltile) + qdel(src) + return + + hit_endpoint = TRUE + if(isturf(prev_loc)) + abstract_move(bumped_atom) + skip = TRUE + //Adjust pixel offset to make splatters appear on the wall + if(istype(bumped_atom, /obj/structure/window)) + land_on_window(bumped_atom) + else + var/obj/effect/decal/cleanable/blood/splatter/over_window/final_splatter = new(prev_loc) + final_splatter.pixel_x = (dir == EAST ? 32 : (dir == WEST ? -32 : 0)) + final_splatter.pixel_y = (dir == NORTH ? 32 : (dir == SOUTH ? -32 : 0)) + else // This will only happen if prev_loc is not even a turf, which is highly unlikely. + abstract_move(bumped_atom) + qdel(src) + +/// A special case for hitsplatters hitting windows, since those can actually be moved around, store it in the window and slap it in the vis_contents +/obj/effect/decal/cleanable/blood/hitsplatter/proc/land_on_window(obj/structure/window/the_window) + if(!the_window.fulltile) + return + var/obj/effect/decal/cleanable/blood/splatter/over_window/final_splatter = new + final_splatter.forceMove(the_window) + the_window.vis_contents += final_splatter + the_window.bloodied = TRUE + qdel(src) diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm index 7bdac4fde8b..c5a5decb738 100644 --- a/code/game/objects/items/clown_items.dm +++ b/code/game/objects/items/clown_items.dm @@ -148,6 +148,12 @@ to_chat(user, span_notice("You clean \the [target.name].")) target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) target.set_opacity(initial(target.opacity)) + var/obj/structure/window/our_window = target + if(our_window.bloodied) + for(var/obj/effect/decal/cleanable/blood/iter_blood in our_window) + our_window.vis_contents -= iter_blood + qdel(iter_blood) + our_window.bloodied = FALSE user.mind?.adjust_experience(/datum/skill/cleaning, CLEAN_SKILL_GENERIC_WASH_XP) decreaseUses(user) else diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 374dab70c9a..21b4acf23df 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -15,6 +15,8 @@ rad_insulation = RAD_VERY_LIGHT_INSULATION pass_flags_self = PASSGLASS set_dir_on_move = FALSE + flags_ricochet = RICOCHET_HARD + receive_ricochet_chance_mod = 0.5 var/state = WINDOW_OUT_OF_FRAME var/reinf = FALSE var/heat_resistance = 800 @@ -29,8 +31,8 @@ var/knock_sound = 'sound/effects/glassknock.ogg' var/bash_sound = 'sound/effects/glassbash.ogg' var/hit_sound = 'sound/effects/glasshit.ogg' - flags_ricochet = RICOCHET_HARD - receive_ricochet_chance_mod = 0.5 + /// If some inconsiderate jerk has had their blood spilled on this window, thus making it cleanable + var/bloodied = FALSE /obj/structure/window/examine(mob/user) . = ..() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 66fb50083a7..566da32b00a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1374,7 +1374,6 @@ log_combat(src, target, "shoved", "into [name]") return COMSIG_CARBON_SHOVE_HANDLED - // Checks to see how many hands this person has to sign with. /mob/living/carbon/proc/check_signables_state() var/obj/item/bodypart/left_arm = get_bodypart(BODY_ZONE_L_ARM) @@ -1392,3 +1391,21 @@ return SIGN_CUFFED if(length(empty_indexes) == 1 || exit_left || exit_right) // One arm gone return SIGN_ONE_HAND + +/** + * This proc is a helper for spraying blood for things like slashing/piercing wounds and dismemberment. + * + * The strength of the splatter in the second argument determines how much it can dirty and how far it can go + * + * Arguments: + * * splatter_direction: Which direction the blood is flying + * * splatter_strength: How many tiles it can go, and how many items it can pass over and dirty + */ +/mob/living/carbon/proc/spray_blood(splatter_direction, splatter_strength = 3) + if(!isturf(loc)) + return + var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc) + our_splatter.add_blood_DNA(return_blood_DNA()) + our_splatter.blood_dna_info = get_blood_dna_list() + var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength) + INVOKE_ASYNC(our_splatter, /obj/effect/decal/cleanable/blood/hitsplatter/.proc/fly_towards, targ, splatter_strength) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 814ceaf12e4..e96bbc74e0d 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -86,7 +86,8 @@ SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting) send_item_attack_message(I, user, affecting.name, affecting) if(I.force) - apply_damage(I.force, I.damtype, affecting, wound_bonus = I.wound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness()) + var/attack_direction = get_dir(user, src) + apply_damage(I.force, I.damtype, affecting, wound_bonus = I.wound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness(), attack_direction = attack_direction) if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC) if(prob(33)) I.add_mob_blood(src) diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm index c06ae421220..65d410c314c 100644 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -1,6 +1,6 @@ -/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE) +/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null) SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone) var/hit_percent = (100-blocked)/100 if(!damage || (!forced && hit_percent <= 0)) @@ -21,13 +21,13 @@ switch(damagetype) if(BRUTE) if(BP) - if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness)) + if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction)) update_damage_overlays() else //no bodypart, we deal damage with a more general method. adjustBruteLoss(damage_amount, forced = forced) if(BURN) if(BP) - if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness)) + if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction)) update_damage_overlays() else adjustFireLoss(damage_amount, forced = forced) diff --git a/code/modules/mob/living/carbon/human/damage_procs.dm b/code/modules/mob/living/carbon/human/damage_procs.dm index d932f7a8b87..a3d47d496ad 100644 --- a/code/modules/mob/living/carbon/human/damage_procs.dm +++ b/code/modules/mob/living/carbon/human/damage_procs.dm @@ -1,4 +1,4 @@ /// depending on the species, it will run the corresponding apply_damage code there -/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE) - return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, forced, spread_damage, wound_bonus, bare_wound_bonus, sharpness) +/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null) + return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, forced, spread_damage, wound_bonus, bare_wound_bonus, sharpness, attack_direction) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index f84fd8af767..2d327991054 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -353,7 +353,8 @@ if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) var/armor = run_armor_check(affecting, MELEE, armour_penetration = user.armour_penetration) - apply_damage(damage, user.melee_damage_type, affecting, armor, wound_bonus = user.wound_bonus, bare_wound_bonus = user.bare_wound_bonus, sharpness = user.sharpness) + var/attack_direction = get_dir(user, src) + apply_damage(damage, user.melee_damage_type, affecting, armor, wound_bonus = user.wound_bonus, bare_wound_bonus = user.bare_wound_bonus, sharpness = user.sharpness, attack_direction = attack_direction) /mob/living/carbon/human/attack_animal(mob/living/simple_animal/user, list/modifiers) @@ -370,7 +371,8 @@ if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) var/armor = run_armor_check(affecting, MELEE, armour_penetration = user.armour_penetration) - apply_damage(damage, user.melee_damage_type, affecting, armor, wound_bonus = user.wound_bonus, bare_wound_bonus = user.bare_wound_bonus, sharpness = user.sharpness) + var/attack_direction = get_dir(user, src) + apply_damage(damage, user.melee_damage_type, affecting, armor, wound_bonus = user.wound_bonus, bare_wound_bonus = user.bare_wound_bonus, sharpness = user.sharpness, attack_direction = attack_direction) /mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index c92798710b3..62b0db0a246 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1439,12 +1439,13 @@ GLOBAL_LIST_EMPTY(features_by_species) if(user.limb_destroyer) target.dismembering_strike(user, affecting.body_zone) + var/attack_direction = get_dir(user, target) if(atk_effect == ATTACK_EFFECT_KICK)//kicks deal 1.5x raw damage - target.apply_damage(damage*1.5, user.dna.species.attack_type, affecting, armor_block) + target.apply_damage(damage*1.5, user.dna.species.attack_type, affecting, armor_block, attack_direction = attack_direction) target.apply_damage(damage*PUNCH_STAMINA_MULTIPLIER, STAMINA, affecting, armor_block) //SKYRAT EDIT ADDITION log_combat(user, target, "kicked") else//other attacks deal full raw damage + 1.5x in stamina damage - target.apply_damage(damage, user.dna.species.attack_type, affecting, armor_block) + target.apply_damage(damage, user.dna.species.attack_type, affecting, armor_block, attack_direction = attack_direction) target.apply_damage(damage*PUNCH_STAMINA_MULTIPLIER, STAMINA, affecting, armor_block) //SKYRAT EDIT CHANGE: target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) log_combat(user, target, "punched") @@ -1539,7 +1540,9 @@ GLOBAL_LIST_EMPTY(features_by_species) H.send_item_attack_message(I, user, hit_area, affecting) - apply_damage(I.force * weakness, I.damtype, def_zone, armor_block, H, wound_bonus = Iwound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness()) + + var/attack_direction = get_dir(user, H) + apply_damage(I.force * weakness, I.damtype, def_zone, armor_block, H, wound_bonus = Iwound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness(), attack_direction = attack_direction) if(!I.force) return FALSE //item force is zero @@ -1604,8 +1607,8 @@ GLOBAL_LIST_EMPTY(features_by_species) return TRUE -/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE) - SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness) // make sure putting wound_bonus here doesn't screw up other signals or uses for this signal +/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null) + SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness, attack_direction) var/hit_percent = (100-(blocked+armor))/100 hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100 if(!damage || (!forced && hit_percent <= 0)) @@ -1627,7 +1630,7 @@ GLOBAL_LIST_EMPTY(features_by_species) H.damageoverlaytemp = 20 var/damage_amount = forced ? damage : damage * hit_percent * brutemod * H.physiology.brute_mod if(BP) - if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness)) + if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction)) H.update_damage_overlays() else//no bodypart, we deal damage with a more general method. H.adjustBruteLoss(damage_amount) @@ -1635,7 +1638,7 @@ GLOBAL_LIST_EMPTY(features_by_species) H.damageoverlaytemp = 20 var/damage_amount = forced ? damage : damage * hit_percent * burnmod * H.physiology.burn_mod if(BP) - if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness)) + if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness, attack_direction = attack_direction)) H.update_damage_overlays() else H.adjustFireLoss(damage_amount) diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 7f0c0a11a7b..9b4127d6d21 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -65,7 +65,7 @@ /datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount) . = min(20, amount) -/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, spread_damage = FALSE, forced = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE) +/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, spread_damage = FALSE, forced = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null) . = ..() if(.) COOLDOWN_START(src, regen_cooldown, REGENERATION_DELAY) diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 119691708f8..dced134476c 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -14,7 +14,7 @@ * * Returns TRUE if damage applied */ -/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE) +/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null) SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone) var/hit_percent = (100-blocked)/100 if(!damage || (!forced && hit_percent <= 0)) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index aebd1fe71cd..cde492d2278 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -55,7 +55,8 @@ var/armor = run_armor_check(def_zone, P.flag, "","",P.armour_penetration, "", FALSE, P.weak_against_armour) var/on_hit_state = P.on_hit(src, armor, piercing_hit) if(!P.nodamage && on_hit_state != BULLET_ACT_BLOCK) - apply_damage(P.damage, P.damage_type, def_zone, armor, wound_bonus=P.wound_bonus, bare_wound_bonus=P.bare_wound_bonus, sharpness = P.sharpness) + var/attack_direction = get_dir(P.starting, src) + apply_damage(P.damage, P.damage_type, def_zone, armor, wound_bonus=P.wound_bonus, bare_wound_bonus=P.bare_wound_bonus, sharpness = P.sharpness, attack_direction = attack_direction) apply_effects(P.stun, P.knockdown, P.unconscious, P.slur, P.stutter, P.eyeblur, P.drowsy, armor, P.stamina, P.jitter, P.paralyze, P.immobilize) if(P.dismemberment) check_projectile_dismemberment(P, def_zone) diff --git a/code/modules/mob/living/silicon/damage_procs.dm b/code/modules/mob/living/silicon/damage_procs.dm index ced34124179..4433b3e4255 100644 --- a/code/modules/mob/living/silicon/damage_procs.dm +++ b/code/modules/mob/living/silicon/damage_procs.dm @@ -1,5 +1,5 @@ -/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE) +/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null) var/hit_percent = (100-blocked)/100 if((!damage || (!forced && hit_percent <= 0))) return 0 diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index a1ec7bf5946..084b0ccf742 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -247,7 +247,7 @@ //Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all. //Damage will not exceed max_damage using this proc //Cannot apply negative damage -/obj/item/bodypart/proc/receive_damage(brute = 0, burn = 0, stamina = 0, blocked = 0, updating_health = TRUE, required_status = null, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE) // maybe separate BRUTE_SHARP and BRUTE_OTHER eventually somehow hmm +/obj/item/bodypart/proc/receive_damage(brute = 0, burn = 0, stamina = 0, blocked = 0, updating_health = TRUE, required_status = null, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null) var/hit_percent = (100-blocked)/100 if((!brute && !burn && !stamina) || hit_percent <= 0) return FALSE @@ -331,17 +331,17 @@ //This makes it so the more damaged bodyparts are, the more likely they are to get wounds //However, this bonus isn't applied when the object doesn't pass the initial wound threshold, nor is it when it already has enough wounding dmg if(wounding_dmg < DAMAGED_BODYPART_BONUS_WOUNDING_BONUS) - var/damaged_percent = (brute_dam + burn_dam)/max_damage + var/damaged_percent = (brute_dam + burn_dam) / max_damage if(damaged_percent > DAMAGED_BODYPART_BONUS_WOUNDING_THRESHOLD) damaged_percent = DAMAGED_BODYPART_BONUS_WOUNDING_THRESHOLD - wounding_dmg = min(DAMAGED_BODYPART_BONUS_WOUNDING_BONUS, wounding_dmg+(damaged_percent*DAMAGED_BODYPART_BONUS_WOUNDING_COEFF)) + wounding_dmg = min(DAMAGED_BODYPART_BONUS_WOUNDING_BONUS, wounding_dmg + (damaged_percent * DAMAGED_BODYPART_BONUS_WOUNDING_COEFF)) if(current_gauze) current_gauze.take_damage() if(current_splint) current_splint.take_damage() - //SKYRAT EDIT ADDITION - MEDICAL - check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus) + //SKYRAT EDIT ADDITION END - MEDICAL + check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus, attack_direction) for(var/datum/wound/iter_wound as anything in wounds) iter_wound.receive_damage(wounding_type, wounding_dmg, wound_bonus) @@ -435,7 +435,7 @@ * * wound_bonus- The wound_bonus of an attack * * bare_wound_bonus- The bare_wound_bonus of an attack */ -/obj/item/bodypart/proc/check_wounding(woundtype, damage, wound_bonus, bare_wound_bonus) +/obj/item/bodypart/proc/check_wounding(woundtype, damage, wound_bonus, bare_wound_bonus, attack_direction) if(HAS_TRAIT(owner, TRAIT_NEVER_WOUNDED)) return @@ -458,7 +458,7 @@ if(injury_roll > WOUND_DISMEMBER_OUTRIGHT_THRESH && prob(get_damage() / max_damage * 100)) var/datum/wound/loss/dismembering = new - dismembering.apply_dismember(src, woundtype, outright=TRUE) + dismembering.apply_dismember(src, woundtype, outright = TRUE, attack_direction = attack_direction) return // quick re-check to see if bare_wound_bonus applies, for the benefit of log_wound(), see about getting the check from check_woundings_mods() somehow @@ -484,10 +484,10 @@ if(initial(possible_wound.threshold_minimum) < injury_roll) var/datum/wound/new_wound if(replaced_wound) - new_wound = replaced_wound.replace_wound(possible_wound) + new_wound = replaced_wound.replace_wound(possible_wound, attack_direction = attack_direction) else new_wound = new possible_wound - new_wound.apply_wound(src) + new_wound.apply_wound(src, attack_direction = attack_direction) log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned return new_wound diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi index bee16d4d908..7fc5ec23514 100644 Binary files a/icons/effects/blood.dmi and b/icons/effects/blood.dmi differ diff --git a/modular_skyrat/modules/medical/code/wounds/bones.dm b/modular_skyrat/modules/medical/code/wounds/bones.dm index a1efcf0dff5..2e745f60a8f 100644 --- a/modular_skyrat/modules/medical/code/wounds/bones.dm +++ b/modular_skyrat/modules/medical/code/wounds/bones.dm @@ -32,7 +32,7 @@ /* Overwriting of base procs */ -/datum/wound/blunt/wound_injury(datum/wound/old_wound = null) +/datum/wound/blunt/wound_injury(datum/wound/old_wound = null, attack_direction) // hook into gaining/losing gauze so crit bone wounds can re-enable/disable depending if they're slung or not RegisterSignal(limb, list(COMSIG_BODYPART_SPLINTED, COMSIG_BODYPART_SPLINT_DESTROYED), .proc/update_inefficiencies) @@ -217,7 +217,7 @@ UnregisterSignal(victim, COMSIG_LIVING_DOORCRUSHED) return ..() -/datum/wound/blunt/moderate/wound_injury(datum/wound/old_wound) +/datum/wound/blunt/moderate/wound_injury(datum/wound/old_wound, attack_direction) . = ..() RegisterSignal(victim, COMSIG_LIVING_DOORCRUSHED, .proc/door_crush) @@ -353,7 +353,7 @@ regen_ticks_needed = 240 // ticks every 2 seconds, 480 seconds, so roughly 8 minutes default // doesn't make much sense for "a" bone to stick out of your head -/datum/wound/blunt/critical/apply_wound(obj/item/bodypart/L, silent, datum/wound/old_wound, smited) +/datum/wound/blunt/critical/apply_wound(obj/item/bodypart/L, silent, datum/wound/old_wound, smited, attack_direction) if(L.body_zone == BODY_ZONE_HEAD) occur_text = "splits open, exposing a bare, cracked skull through the flesh and blood" examine_desc = "has an unsettling indent, with bits of skull poking out" diff --git a/modular_skyrat/modules/medical/code/wounds/muscle.dm b/modular_skyrat/modules/medical/code/wounds/muscle.dm index 362d52d902e..1849391028d 100644 --- a/modular_skyrat/modules/medical/code/wounds/muscle.dm +++ b/modular_skyrat/modules/medical/code/wounds/muscle.dm @@ -18,7 +18,7 @@ /* Overwriting of base procs */ -/datum/wound/muscle/wound_injury(datum/wound/old_wound = null) +/datum/wound/muscle/wound_injury(datum/wound/old_wound = null, attack_direction) // hook into gaining/losing gauze so crit muscle wounds can re-enable/disable depending if they're slung or not RegisterSignal(limb, list(COMSIG_BODYPART_SPLINTED, COMSIG_BODYPART_SPLINT_DESTROYED), .proc/update_inefficiencies) diff --git a/modular_skyrat/modules/medical/code/wounds/pierce.dm b/modular_skyrat/modules/medical/code/wounds/pierce.dm index c189988af7c..fee2d96aabd 100644 --- a/modular_skyrat/modules/medical/code/wounds/pierce.dm +++ b/modular_skyrat/modules/medical/code/wounds/pierce.dm @@ -33,7 +33,7 @@ return victim.self_grasp_bleeding_limb(limb) -/datum/wound/pierce/wound_injury(datum/wound/old_wound) +/datum/wound/pierce/wound_injury(datum/wound/old_wound, attack_direction) blood_flow = initial_flow /datum/wound/pierce/receive_damage(wounding_type, wounding_dmg, wound_bonus) diff --git a/modular_skyrat/modules/medical/code/wounds/slash.dm b/modular_skyrat/modules/medical/code/wounds/slash.dm index fd2fc453049..81fef9084a5 100644 --- a/modular_skyrat/modules/medical/code/wounds/slash.dm +++ b/modular_skyrat/modules/medical/code/wounds/slash.dm @@ -40,7 +40,7 @@ return victim.self_grasp_bleeding_limb(limb) -/datum/wound/slash/wound_injury(datum/wound/slash/old_wound = null) +/datum/wound/slash/wound_injury(datum/wound/slash/old_wound = null, attack_direction) blood_flow = initial_flow if(old_wound) blood_flow = max(old_wound.blood_flow, initial_flow) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/arousal_system.dm b/modular_skyrat/modules/modular_items/lewd_items/code/arousal_system.dm index 24a898b2ad4..255c6db43b7 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/arousal_system.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/arousal_system.dm @@ -316,7 +316,7 @@ pleasure = min(max(pleasure,0),100) // get damage for pain system -/datum/species/apply_damage(damage, damagetype, def_zone, blocked, mob/living/carbon/human/H, forced, spread_damage, wound_bonus, bare_wound_bonus, sharpness) +/datum/species/apply_damage(damage, damagetype, def_zone, blocked, mob/living/carbon/human/H, forced, spread_damage, wound_bonus, bare_wound_bonus, sharpness, attack_direction) . = ..() if(!.) return diff --git a/sound/attributions.txt b/sound/attributions.txt index 4dc823b9a76..a405da1862d 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -21,4 +21,6 @@ kiss sound: https://freesound.org/people/stereostereo/sounds/117355/ champagne_pop.ogg is credited to ultradust on freesound https://freesound.org/people/ultradust/sounds/166923/ can_open.ogg adapted from https://freesound.org/people/MaxDemianAGL/sounds/130031/ -can_shake.ogg adapted from https://freesound.org/people/mcmast/sounds/456703/ \ No newline at end of file +can_shake.ogg adapted from https://freesound.org/people/mcmast/sounds/456703/ + +splatter.ogg adapted from https://freesound.org/people/Rocktopus/sounds/233418/ diff --git a/sound/effects/wounds/splatter.ogg b/sound/effects/wounds/splatter.ogg new file mode 100644 index 00000000000..1c678cfe126 Binary files /dev/null and b/sound/effects/wounds/splatter.ogg differ