From 23754f11751ff3fc9d772420a8b3a5a4b1fd2e1b Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sat, 18 Nov 2023 08:19:31 +0100 Subject: [PATCH] [MIRROR] Mob `attackedby` / `check_block` refactor, plus some minor cleanup of `attack_x` procs [MDB IGNORE] (#25079) * Mob `attackedby` / `check_block` refactor, plus some minor cleanup of `attack_x` procs * Fix the race condition * Modular * Ooops --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/combat.dm | 11 +- .../signals/signals_mob/signals_mob_carbon.dm | 3 - .../signals/signals_mob/signals_mob_living.dm | 4 + code/_onclick/item_attack.dm | 166 +++++++++++++++--- code/_onclick/other_mobs.dm | 3 + code/datums/actions/mobs/charge.dm | 2 +- code/datums/elements/damage_threshold.dm | 51 ++++++ code/datums/martial/_martial.dm | 1 - code/datums/martial/cqc.dm | 31 +++- code/game/objects/items/melee/baton.dm | 9 +- code/game/objects/items/melee/misc.dm | 9 +- .../game/objects/items/robot/items/generic.dm | 2 +- .../heretic/knowledge/blade_lore.dm | 4 +- .../heretic/status_effects/buffs.dm | 8 +- code/modules/mob/living/basic/basic.dm | 2 - .../modules/mob/living/basic/basic_defense.dm | 104 ++++++----- .../living/basic/blob_minions/blobbernaut.dm | 2 +- code/modules/mob/living/basic/clown/clown.dm | 3 +- .../basic/cult/constructs/juggernaut.dm | 5 +- .../basic/guardian/guardian_types/charger.dm | 2 +- .../living/basic/ruin_defender/skeleton.dm | 2 +- .../mob/living/carbon/alien/adult/adult.dm | 5 +- .../living/carbon/alien/adult/caste/hunter.dm | 2 +- .../mob/living/carbon/alien/alien_defense.dm | 19 -- .../mob/living/carbon/carbon_defense.dm | 65 +++---- .../mob/living/carbon/human/_species.dm | 126 +------------ .../mob/living/carbon/human/human_defense.dm | 118 +++---------- code/modules/mob/living/living_defense.dm | 165 ++++++++++++----- .../mob/living/silicon/ai/ai_defense.dm | 9 +- .../mob/living/silicon/robot/robot_defense.dm | 2 - .../mob/living/silicon/silicon_defense.dm | 34 ++-- .../living/simple_animal/animal_defense.dm | 40 +---- .../mob/living/simple_animal/bot/bot.dm | 10 +- .../mob/living/simple_animal/bot/secbot.dm | 2 +- .../mob/living/simple_animal/parrot.dm | 6 +- .../mob/living/simple_animal/simple_animal.dm | 2 - .../mob/living/simple_animal/slime/slime.dm | 1 - code/modules/mod/modules/modules_antag.dm | 6 +- code/modules/mod/modules/modules_security.dm | 6 +- .../organs/internal/cyberimp/augments_arms.dm | 2 +- .../modules/client/augment/organs.dm | 4 +- .../mob/living/carbon/human/species/ghoul.dm | 108 ++++++------ .../game/objects/items/gladiator_items.dm | 6 +- .../modules/moretraitoritems/code/pirate.dm | 4 +- .../xenos_skyrat_redo/code/human_defense.dm | 2 +- tgstation.dme | 1 + 46 files changed, 584 insertions(+), 585 deletions(-) create mode 100644 code/datums/elements/damage_threshold.dm diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 116b933c6ae..d619da64d48 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -132,13 +132,22 @@ DEFINE_BITFIELD(status_flags, list( //slowdown when crawling #define CRAWLING_ADD_SLOWDOWN 4 -//Attack types for checking shields/hit reactions +//Attack types for checking block reactions +/// Attack was made with a melee weapon #define MELEE_ATTACK 1 +/// Attack is a punch or kick. +/// Mob attacks are not classified as unarmed (currently). #define UNARMED_ATTACK 2 +/// A projectile is hitting us. #define PROJECTILE_ATTACK 3 +/// A thrown item is hitting us. #define THROWN_PROJECTILE_ATTACK 4 +/// We're being tackled or leaped at. #define LEAP_ATTACK 5 +/// Used in check block to get what mob is attacking the blocker. +#define GET_ASSAILANT(weapon) (get(weapon, /mob/living)) + //attack visual effects #define ATTACK_EFFECT_PUNCH "punch" #define ATTACK_EFFECT_KICK "kick" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index e86ed58269e..f3c3d5d71cc 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -133,9 +133,6 @@ #define COMSIG_HUMAN_CORETEMP_CHANGE "human_coretemp_change" ///from /datum/species/handle_fire. Called when the human is set on fire and burning clothes and stuff #define COMSIG_HUMAN_BURNING "human_burning" -///from /mob/living/carbon/human/proc/check_shields(): (atom/hit_by, damage, attack_text, attack_type, armour_penetration, damage_type) -#define COMSIG_HUMAN_CHECK_SHIELDS "human_check_shields" - #define SHIELD_BLOCK (1<<0) ///from /mob/living/carbon/human/proc/force_say(): () #define COMSIG_HUMAN_FORCESAY "human_forcesay" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index b919f94a1c1..c2c28f31257 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -222,6 +222,10 @@ /// From /datum/ai/behavior/climb_tree/perform() : (mob/living/basic/living_pawn) #define COMSIG_LIVING_CLIMB_TREE "living_climb_tree" +///from /mob/living/proc/check_block(): (atom/hit_by, damage, attack_text, attack_type, armour_penetration, damage_type) +#define COMSIG_LIVING_CHECK_BLOCK "living_check_block" + #define SUCCESSFUL_BLOCK (1<<0) + /// Sent on a mob from /datum/component/mob_chain when component is attached with it as the "front" : (mob/living/basic/tail) #define COMSIG_MOB_GAINED_CHAIN_TAIL "living_gained_chain_tail" /// Sent on a mob from /datum/component/mob_chain when component is detached from it as the "front" : (mob/living/basic/tail) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index b3d15e0c476..213e3dae195 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -257,32 +257,154 @@ CRASH("areas are NOT supposed to have attacked_by() called on them!") /mob/living/attacked_by(obj/item/attacking_item, mob/living/user) - send_item_attack_message(attacking_item, user) - if(!attacking_item.force) - return FALSE + + var/targeting = check_zone(user.zone_selected) + if(user != src) + var/zone_hit_chance = 80 + if(body_position == LYING_DOWN) + zone_hit_chance += 10 + targeting = get_random_valid_zone(targeting, zone_hit_chance) + var/targeting_human_readable = parse_zone(targeting) + + send_item_attack_message(attacking_item, user, targeting_human_readable, targeting) + + var/armor_block = min(run_armor_check( + def_zone = targeting, + attack_flag = MELEE, + absorb_text = span_notice("Your armor has protected your [targeting_human_readable]!"), + soften_text = span_warning("Your armor has softened a hit to your [targeting_human_readable]!"), + armour_penetration = attacking_item.armour_penetration, + weak_against_armour = attacking_item.weak_against_armour, + ), ARMOR_MAX_BLOCK) + var/damage = attacking_item.force if(mob_biotypes & MOB_ROBOTIC) damage *= attacking_item.demolition_mod - apply_damage(damage, attacking_item.damtype, attacking_item = attacking_item) - if(attacking_item.damtype == BRUTE && prob(33)) + + var/wounding = attacking_item.wound_bonus + if((attacking_item.item_flags & SURGICAL_TOOL) && !user.combat_mode && body_position == LYING_DOWN && (LAZYLEN(surgeries) > 0)) + wounding = CANT_WOUND + + if(user != src) + // This doesn't factor in armor, or most damage modifiers (physiology). Your mileage may vary + if(check_block(attacking_item, damage, "the [attacking_item.name]", MELEE_ATTACK, attacking_item.armour_penetration, attacking_item.damtype)) + return FALSE + + SEND_SIGNAL(attacking_item, COMSIG_ITEM_ATTACK_ZONE, src, user, targeting) + + if(damage <= 0) + return FALSE + + if(ishuman(src) || client) // istype(src) is kinda bad, but it's to avoid spamming the blackbox + SSblackbox.record_feedback("nested tally", "item_used_for_combat", 1, list("[attacking_item.force]", "[attacking_item.type]")) + SSblackbox.record_feedback("tally", "zone_targeted", 1, targeting_human_readable) + + var/damage_done = apply_damage( + damage = damage, + damagetype = attacking_item.damtype, + def_zone = targeting, + blocked = armor_block, + wound_bonus = wounding, + bare_wound_bonus = attacking_item.bare_wound_bonus, + sharpness = attacking_item.get_sharpness(), + attack_direction = get_dir(user, src), + attacking_item = attacking_item, + ) + + attack_effects(damage_done, targeting, armor_block, attacking_item, user) + + return TRUE + +/** + * Called when we take damage, used to cause effects such as a blood splatter. + * + * Return TRUE if an effect was done, FALSE otherwise. + */ +/mob/living/proc/attack_effects(damage_done, hit_zone, armor_block, obj/item/attacking_item, mob/living/attacker) + if(damage_done > 0 && attacking_item.damtype == BRUTE && prob(25 + damage_done * 2)) attacking_item.add_mob_blood(src) - var/turf/location = get_turf(src) - add_splatter_floor(location) - if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood - user.add_mob_blood(src) - return TRUE //successful attack - -/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user) - if(!attack_threshold_check(I.force, I.damtype, MELEE, FALSE)) - playsound(loc, 'sound/weapons/tap.ogg', I.get_clamped_volume(), TRUE, -1) - else - return ..() + add_splatter_floor(get_turf(src)) + if(get_dist(attacker, src) <= 1) + attacker.add_mob_blood(src) + return TRUE -/mob/living/basic/attacked_by(obj/item/I, mob/living/user) - if(!attack_threshold_check(I.force, I.damtype, MELEE, FALSE)) - playsound(loc, 'sound/weapons/tap.ogg', I.get_clamped_volume(), TRUE, -1) - else - return ..() + return FALSE + +/mob/living/silicon/robot/attack_effects(damage_done, hit_zone, armor_block, obj/item/attacking_item, mob/living/attacker) + if(damage_done > 0 && attacking_item.damtype != STAMINA && stat != DEAD) + spark_system.start() + . = TRUE + return ..() || . + +/mob/living/silicon/ai/attack_effects(damage_done, hit_zone, armor_block, obj/item/attacking_item, mob/living/attacker) + if(damage_done > 0 && attacking_item.damtype != STAMINA && stat != DEAD) + spark_system.start() + . = TRUE + return ..() || . + +/mob/living/carbon/attack_effects(damage_done, hit_zone, armor_block, obj/item/attacking_item, mob/living/attacker) + var/obj/item/bodypart/hit_bodypart = get_bodypart(hit_zone) || bodyparts[1] + if(!hit_bodypart.can_bleed()) + return FALSE + + return ..() + +/mob/living/carbon/human/attack_effects(damage_done, hit_zone, armor_block, obj/item/attacking_item, mob/living/attacker) + . = ..() + switch(hit_zone) + if(BODY_ZONE_HEAD) + if(.) + if(wear_mask) + wear_mask.add_mob_blood(src) + update_worn_mask() + if(head) + head.add_mob_blood(src) + update_worn_head() + if(glasses && prob(33)) + glasses.add_mob_blood(src) + update_worn_glasses() + + if(!attacking_item.get_sharpness() && armor_block < 50) + if(prob(damage_done)) + adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) + if(stat == CONSCIOUS) + visible_message( + span_danger("[src] is knocked senseless!"), + span_userdanger("You're knocked senseless!"), + ) + set_confusion_if_lower(20 SECONDS) + adjust_eye_blur(20 SECONDS) + if(prob(10)) + gain_trauma(/datum/brain_trauma/mild/concussion) + else + adjustOrganLoss(ORGAN_SLOT_BRAIN, damage_done * 0.2) + + // rev deconversion through blunt trauma. + // this can be signalized to the rev datum + if(mind && stat == CONSCIOUS && src != attacker && prob(damage_done + ((maxHealth - health) * 0.5))) // SKYRAT EDIT CHANGE - ORIGINAL : if(mind && stat == CONSCIOUS && src != attacker && prob(damage_done + ((100 - health) * 0.5))) + var/datum/antagonist/rev/rev = mind.has_antag_datum(/datum/antagonist/rev) + rev?.remove_revolutionary(attacker) + + if(BODY_ZONE_CHEST) + if(.) + if(wear_suit) + wear_suit.add_mob_blood(src) + update_worn_oversuit() + if(w_uniform) + w_uniform.add_mob_blood(src) + update_worn_undersuit() + + if(stat == CONSCIOUS && !attacking_item.get_sharpness() && armor_block < 50) + if(prob(damage_done)) + visible_message( + span_danger("[src] is knocked down!"), + span_userdanger("You're knocked down!"), + ) + apply_effect(6 SECONDS, EFFECT_KNOCKDOWN, armor_block) + + // Triggers force say events + if(damage_done > 10 || (damage_done >= 5 && prob(33))) + force_say() /** * Last proc in the [/obj/item/proc/melee_attack_chain]. @@ -335,7 +457,7 @@ else return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100 -/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, obj/item/bodypart/hit_bodypart) +/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area, def_zone) if(!I.force && !length(I.attack_verb_simple) && !length(I.attack_verb_continuous)) return var/message_verb_continuous = length(I.attack_verb_continuous) ? "[pick(I.attack_verb_continuous)]" : "attacks" diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 46ca2f53904..f398a5c0343 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -169,6 +169,9 @@ /mob/living/proc/resolve_right_click_attack(atom/target, list/modifiers) return target.attack_animal_secondary(src, modifiers) +/** + * Called when a simple animal is unarmed attacking / clicking on this atom. + */ /atom/proc/attack_animal(mob/user, list/modifiers) SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_ANIMAL, user) diff --git a/code/datums/actions/mobs/charge.dm b/code/datums/actions/mobs/charge.dm index 0c73145770e..d235b4d50ab 100644 --- a/code/datums/actions/mobs/charge.dm +++ b/code/datums/actions/mobs/charge.dm @@ -213,7 +213,7 @@ var/mob/living/living_target = target if(ishuman(living_target)) var/mob/living/carbon/human/human_target = living_target - if(human_target.check_shields(source, 0, "the [source.name]", attack_type = LEAP_ATTACK) && living_source) + if(human_target.check_block(source, 0, "the [source.name]", attack_type = LEAP_ATTACK) && living_source) living_source.Stun(recoil_duration, ignore_canstun = TRUE) return diff --git a/code/datums/elements/damage_threshold.dm b/code/datums/elements/damage_threshold.dm new file mode 100644 index 00000000000..918c984b066 --- /dev/null +++ b/code/datums/elements/damage_threshold.dm @@ -0,0 +1,51 @@ +/// Applied to living mobs. +/// Adds a force threshold for which attacks will be blocked entirely. +/// IE, if they are hit with an attack that deals less than X damage, the attack does nothing. +/datum/element/damage_threshold + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// Incoming attacks beneath this threshold, inclusive, will be blocked entirely + var/force_threshold = -1 + +/datum/element/damage_threshold/Attach(datum/target, threshold) + . = ..() + if(!isliving(target)) + return ELEMENT_INCOMPATIBLE + if(!isnum(threshold) || threshold <= 0) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block)) + force_threshold = threshold + +/datum/element/damage_threshold/Detach(datum/source, ...) + . = ..() + UnregisterSignal(source, COMSIG_LIVING_CHECK_BLOCK) + +/datum/element/damage_threshold/proc/check_block( + mob/living/source, + atom/hitby, + damage, + attack_text, + attack_type, + armour_penetration, + damage_type, + attack_flag, +) + SIGNAL_HANDLER + + if(damage <= 0) // Already handled + return NONE + + if(damage <= force_threshold) + var/obj/item/item_hitting = hitby + var/tap_vol = istype(item_hitting) ? item_hitting.get_clamped_volume() : 50 + source.visible_message( + span_warning("[src] looks unharmed!"), + span_warning("[attack_text] deals no damage to you!"), + span_hear("You hear a thud."), + COMBAT_MESSAGE_RANGE, + ) + playsound(source, 'sound/weapons/tap.ogg', tap_vol, TRUE, -1) + return SUCCESSFUL_BLOCK + + return NONE diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm index c91ae511788..2af604cd8fe 100644 --- a/code/datums/martial/_martial.dm +++ b/code/datums/martial/_martial.dm @@ -5,7 +5,6 @@ var/max_streak_length = 6 var/current_target var/datum/martial_art/base // The permanent style. This will be null unless the martial art is temporary - var/block_chance = 0 //Chance to block melee attacks using items while on throw mode. var/help_verb var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts var/smashes_tables = FALSE //If the martial art smashes tables when performing table slams and head smashes diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index cae4cdf14b2..a8cae64cd0d 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -8,18 +8,20 @@ name = "CQC" id = MARTIALART_CQC help_verb = /mob/living/proc/CQC_help - block_chance = 75 smashes_tables = TRUE display_combos = TRUE var/old_grab_state = null var/mob/restraining_mob + /// Probability of successfully blocking attacks while on throw mode + var/block_chance = 75 /datum/martial_art/cqc/teach(mob/living/cqc_user, make_temporary) . = ..() RegisterSignal(cqc_user, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) + RegisterSignal(cqc_user, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block)) /datum/martial_art/cqc/on_remove(mob/living/cqc_user) - UnregisterSignal(cqc_user, COMSIG_ATOM_ATTACKBY) + UnregisterSignal(cqc_user, list(COMSIG_ATOM_ATTACKBY, COMSIG_LIVING_CHECK_BLOCK)) . = ..() ///Signal from getting attacked with an item, for a special interaction with touch spells @@ -41,6 +43,31 @@ INVOKE_ASYNC(touch_spell, TYPE_PROC_REF(/datum/action/cooldown/spell/touch, do_hand_hit), touch_weapon, attacker, attacker) return COMPONENT_NO_AFTERATTACK +/datum/martial_art/cqc/proc/check_block(mob/living/cqc_user, atom/movable/hitby, damage, attack_text, attack_type, ...) + SIGNAL_HANDLER + + if(!can_use(cqc_user) || !cqc_user.throw_mode || cqc_user.incapacitated(IGNORE_GRAB)) + return NONE + if(attack_type == PROJECTILE_ATTACK) + return NONE + if(!prob(block_chance)) + return NONE + + var/mob/living/attacker = GET_ASSAILANT(hitby) + if(istype(attacker) && cqc_user.Adjacent(attacker)) + cqc_user.visible_message( + span_danger("[cqc_user] blocks [attack_text] and twists [attacker]'s arm behind [attacker.p_their()] back!"), + span_userdanger("You block [attack_text]!"), + ) + attacker.Stun(4 SECONDS) + else + cqc_user.visible_message( + span_danger("[cqc_user] blocks [attack_text]!"), + span_userdanger("You block [attack_text]!"), + ) + return SUCCESSFUL_BLOCK + + /datum/martial_art/cqc/reset_streak(mob/living/new_target) if(new_target && new_target != restraining_mob) restraining_mob = null diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index 9dd35dfb25f..01f66c0e4dd 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -175,13 +175,10 @@ target.visible_message(desc["visible"], desc["local"]) /obj/item/melee/baton/proc/check_parried(mob/living/carbon/human/human_target, mob/living/user) - if(!ishuman(human_target)) - return - if (human_target.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) + if (human_target.check_block(src, 0, "[user]'s [name]", MELEE_ATTACK)) playsound(human_target, 'sound/weapons/genhit.ogg', 50, TRUE) return TRUE - if(check_martial_counter(human_target, user)) - return TRUE + return FALSE /obj/item/melee/baton/proc/finalize_baton_attack(mob/living/target, mob/living/user, modifiers, in_attack_chain = TRUE) if(!in_attack_chain && HAS_TRAIT_FROM(target, TRAIT_IWASBATONED, REF(user))) @@ -632,7 +629,7 @@ /obj/item/melee/baton/security/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) . = ..() - if(active && prob(throw_stun_chance) && isliving(hit_atom)) + if(!. && active && prob(throw_stun_chance) && isliving(hit_atom)) finalize_baton_attack(hit_atom, thrownby?.resolve(), in_attack_chain = FALSE) /obj/item/melee/baton/security/emp_act(severity) diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 77f002c3f1e..2b15d9ddef2 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -1,14 +1,7 @@ +// Deprecated, you do not need to use this type for melee weapons. /obj/item/melee item_flags = NEEDS_PERMIT -/obj/item/melee/proc/check_martial_counter(mob/living/carbon/human/target, mob/living/carbon/human/user) - if(target.check_block()) - target.visible_message(span_danger("[target.name] blocks [src] and twists [user]'s arm behind [user.p_their()] back!"), - span_userdanger("You block the attack!")) - user.Stun(40) - return TRUE - - /obj/item/melee/chainofcommand name = "chain of command" desc = "A tool used by great men to placate the frothing masses." diff --git a/code/game/objects/items/robot/items/generic.dm b/code/game/objects/items/robot/items/generic.dm index 4db09ab3804..b8492b7ba30 100644 --- a/code/game/objects/items/robot/items/generic.dm +++ b/code/game/objects/items/robot/items/generic.dm @@ -28,7 +28,7 @@ return if(ishuman(attacked_mob)) var/mob/living/carbon/human/human = attacked_mob - if(human.check_shields(src, 0, "[attacked_mob]'s [name]", MELEE_ATTACK)) + if(human.check_block(src, 0, "[attacked_mob]'s [name]", MELEE_ATTACK)) playsound(attacked_mob, 'sound/weapons/genhit.ogg', 50, TRUE) return FALSE if(iscyborg(user)) diff --git a/code/modules/antagonists/heretic/knowledge/blade_lore.dm b/code/modules/antagonists/heretic/knowledge/blade_lore.dm index e3117045f74..e28721d055d 100644 --- a/code/modules/antagonists/heretic/knowledge/blade_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/blade_lore.dm @@ -117,10 +117,10 @@ var/riposte_ready = TRUE /datum/heretic_knowledge/blade_dance/on_gain(mob/user, datum/antagonist/heretic/our_heretic) - RegisterSignal(user, COMSIG_HUMAN_CHECK_SHIELDS, PROC_REF(on_shield_reaction)) + RegisterSignal(user, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(on_shield_reaction)) /datum/heretic_knowledge/blade_dance/on_lose(mob/user, datum/antagonist/heretic/our_heretic) - UnregisterSignal(user, COMSIG_HUMAN_CHECK_SHIELDS) + UnregisterSignal(user, COMSIG_LIVING_CHECK_BLOCK) /datum/heretic_knowledge/blade_dance/proc/on_shield_reaction( mob/living/carbon/human/source, diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm index 5798d273de9..4a5941fe55c 100644 --- a/code/modules/antagonists/heretic/status_effects/buffs.dm +++ b/code/modules/antagonists/heretic/status_effects/buffs.dm @@ -133,7 +133,7 @@ return ..() /datum/status_effect/protective_blades/on_apply() - RegisterSignal(owner, COMSIG_HUMAN_CHECK_SHIELDS, PROC_REF(on_shield_reaction)) + RegisterSignal(owner, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(on_shield_reaction)) for(var/blade_num in 1 to max_num_blades) var/time_until_created = (blade_num - 1) * time_between_initial_blades if(time_until_created <= 0) @@ -144,7 +144,7 @@ return TRUE /datum/status_effect/protective_blades/on_remove() - UnregisterSignal(owner, COMSIG_HUMAN_CHECK_SHIELDS) + UnregisterSignal(owner, COMSIG_LIVING_CHECK_BLOCK) QDEL_LIST(blades) return ..() @@ -160,7 +160,7 @@ RegisterSignal(blade, COMSIG_QDELETING, PROC_REF(remove_blade)) playsound(get_turf(owner), 'sound/items/unsheath.ogg', 33, TRUE) -/// Signal proc for [COMSIG_HUMAN_CHECK_SHIELDS]. +/// Signal proc for [COMSIG_LIVING_CHECK_BLOCK]. /// If we have a blade in our list, consume it and block the incoming attack (shield it) /datum/status_effect/protective_blades/proc/on_shield_reaction( mob/living/carbon/human/source, @@ -194,7 +194,7 @@ addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_BEING_BLADE_SHIELDED, type), 1) - return SHIELD_BLOCK + return SUCCESSFUL_BLOCK /// Remove deleted blades from our blades list properly. /datum/status_effect/protective_blades/proc/remove_blade(obj/effect/floating_blade/to_remove) diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index 585c8b6b97b..b61cc70fd93 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -43,8 +43,6 @@ /// 1 for full damage, 0 for none, -1 for 1:1 heal from that source. var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) - ///Minimum force required to deal any damage. - var/force_threshold = 0 ///Verbs used for speaking e.g. "Says" or "Chitters". This can be elementized var/list/speak_emote = list() diff --git a/code/modules/mob/living/basic/basic_defense.dm b/code/modules/mob/living/basic/basic_defense.dm index a1093f914d8..03f684b7d87 100644 --- a/code/modules/mob/living/basic/basic_defense.dm +++ b/code/modules/mob/living/basic/basic_defense.dm @@ -11,40 +11,58 @@ var/shove_dir = get_dir(user, src) if(!Move(get_step(src, shove_dir), shove_dir)) log_combat(user, src, "shoved", "failing to move it") - user.visible_message(span_danger("[user.name] [response_disarm_continuous] [src]!"), - span_danger("You [response_disarm_simple] [src]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src)) + user.visible_message( + span_danger("[user.name] [response_disarm_continuous] [src]!"), + span_danger("You [response_disarm_simple] [src]!"), + span_hear("You hear aggressive shuffling!"), + COMBAT_MESSAGE_RANGE, + list(src), + ) to_chat(src, span_userdanger("You're shoved by [user.name]!")) return TRUE log_combat(user, src, "shoved", "pushing it") - user.visible_message(span_danger("[user.name] [response_disarm_continuous] [src], pushing [p_them()]!"), - span_danger("You [response_disarm_simple] [src], pushing [p_them()]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src)) + user.visible_message( + span_danger("[user.name] [response_disarm_continuous] [src], pushing [p_them()]!"), + span_danger("You [response_disarm_simple] [src], pushing [p_them()]!"), + span_hear("You hear aggressive shuffling!"), + COMBAT_MESSAGE_RANGE, + list(src), + ) to_chat(src, span_userdanger("You're pushed by [user.name]!")) return TRUE if(!user.combat_mode) - if (stat == DEAD) - return - visible_message(span_notice("[user] [response_help_continuous] [src]."), \ - span_notice("[user] [response_help_continuous] you."), null, null, user) - to_chat(user, span_notice("You [response_help_simple] [src].")) - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) - else - if(HAS_TRAIT(user, TRAIT_PACIFISM)) - to_chat(user, span_warning("You don't want to hurt [src]!")) - return - user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) - visible_message(span_danger("[user] [response_harm_continuous] [src]!"),\ - span_userdanger("[user] [response_harm_continuous] you!"), null, COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You [response_harm_simple] [src]!")) - playsound(loc, attacked_sound, 25, TRUE, -1) - var/obj/item/bodypart/arm/active_arm = user.get_active_hand() - var/damage = (basic_mob_flags & IMMUNE_TO_FISTS) ? 0 : rand(active_arm.unarmed_damage_low, active_arm.unarmed_damage_high) - - attack_threshold_check(damage) - log_combat(user, src, "attacked") - updatehealth() + if (stat != DEAD) + visible_message( + span_notice("[user] [response_help_continuous] [src]."), + span_notice("[user] [response_help_continuous] you."), + ignored_mobs = user, + ) + to_chat(user, span_notice("You [response_help_simple] [src].")) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) return TRUE + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + to_chat(user, span_warning("You don't want to hurt [src]!")) + return TRUE + var/obj/item/bodypart/arm/active_arm = user.get_active_hand() + var/damage = (basic_mob_flags & IMMUNE_TO_FISTS) ? 0 : rand(active_arm.unarmed_damage_low, active_arm.unarmed_damage_high) + if(check_block(user, damage, "[user]'s punch", UNARMED_ATTACK, 0, BRUTE)) + return + user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) + visible_message( + span_danger("[user] [response_harm_continuous] [src]!"), + span_userdanger("[user] [response_harm_continuous] you!"), + vision_distance = COMBAT_MESSAGE_RANGE, + ignored_mobs = user, + ) + to_chat(user, span_danger("You [response_harm_simple] [src]!")) + playsound(loc, attacked_sound, 25, TRUE, -1) + apply_damage(damage) + log_combat(user, src, "attacked") + updatehealth() + return TRUE + /mob/living/basic/attack_hulk(mob/living/carbon/human/user) . = ..() if(!.) @@ -58,9 +76,8 @@ /mob/living/basic/attack_paw(mob/living/carbon/human/user, list/modifiers) if(..()) //successful monkey bite. if(stat != DEAD) - var/damage = rand(1, 3) - attack_threshold_check(damage) - return 1 + return apply_damage(rand(1, 3)) + if (!user.combat_mode) if (health > 0) visible_message(span_notice("[user.name] [response_help_continuous] [src]."), \ @@ -85,29 +102,22 @@ span_userdanger("You're slashed at by [user]!"), null, COMBAT_MESSAGE_RANGE, user) to_chat(user, span_danger("You slash at [src]!")) playsound(loc, 'sound/weapons/slice.ogg', 25, TRUE, -1) - attack_threshold_check(damage) + apply_damage(damage) log_combat(user, src, "attacked") /mob/living/basic/attack_larva(mob/living/carbon/alien/larva/attacking_larva, list/modifiers) . = ..() if(. && stat != DEAD) //successful larva bite - var/damage = rand(attacking_larva.melee_damage_lower, attacking_larva.melee_damage_upper) - . = attack_threshold_check(damage) - if(.) - attacking_larva.amount_grown = min(attacking_larva.amount_grown + damage, attacking_larva.max_grown) - -/mob/living/basic/attack_animal(mob/living/simple_animal/user, list/modifiers) - . = ..() - if(.) - var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - return attack_threshold_check(damage, user.melee_damage_type) + var/damage_done = apply_damage(rand(attacking_larva.melee_damage_lower, attacking_larva.melee_damage_upper), BRUTE) + if(damage_done > 0) + attacking_larva.amount_grown = min(attacking_larva.amount_grown + damage_done, attacking_larva.max_grown) /mob/living/basic/attack_slime(mob/living/simple_animal/slime/M, list/modifiers) if(..()) //successful slime attack var/damage = rand(15, 25) if(M.is_adult) damage = rand(20, 35) - return attack_threshold_check(damage) + return apply_damage(damage, M.melee_damage_type) /mob/living/basic/attack_drone(mob/living/basic/drone/attacking_drone) if(attacking_drone.combat_mode) //No kicking dogs even as a rogue drone. Use a weapon. @@ -119,20 +129,6 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN return ..() -/mob/living/basic/proc/attack_threshold_check(damage, damagetype = BRUTE, armorcheck = MELEE, actuallydamage = TRUE) - var/temp_damage = damage - if(!damage_coeff[damagetype]) - temp_damage = 0 - else - temp_damage *= damage_coeff[damagetype] - if(temp_damage >= 0 && temp_damage <= force_threshold) - visible_message(span_warning("[src] looks unharmed!")) - return FALSE - else - if(actuallydamage) - apply_damage(damage, damagetype, blocked = getarmor(null, armorcheck)) - return TRUE - /mob/living/basic/check_projectile_armor(def_zone, obj/projectile/impacting_projectile, is_silent) return 0 diff --git a/code/modules/mob/living/basic/blob_minions/blobbernaut.dm b/code/modules/mob/living/basic/blob_minions/blobbernaut.dm index b483641993a..d12febb748e 100644 --- a/code/modules/mob/living/basic/blob_minions/blobbernaut.dm +++ b/code/modules/mob/living/basic/blob_minions/blobbernaut.dm @@ -22,7 +22,6 @@ verb_ask = "demands" verb_exclaim = "roars" verb_yell = "bellows" - force_threshold = 10 pressure_resistance = 50 mob_size = MOB_SIZE_LARGE hud_type = /datum/hud/living/blobbernaut @@ -32,6 +31,7 @@ /mob/living/basic/blob_minion/blobbernaut/Initialize(mapload) . = ..() AddElement(/datum/element/swabable, CELL_LINE_TABLE_BLOBBERNAUT, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) + AddElement(/datum/element/damage_threshold, 10) /mob/living/basic/blob_minion/blobbernaut/death(gibbed) flick("blobbernaut_death", src) diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index e55b91bade2..fdd42cab098 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -370,7 +370,6 @@ speed = 1 melee_damage_lower = 10 melee_damage_upper = 15 - force_threshold = 10 //lots of fat to cushion blows. damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 2, STAMINA = 0, OXY = 1) attack_verb_continuous = "slams" attack_verb_simple = "slam" @@ -395,7 +394,7 @@ AddElement(/datum/element/swabable, CELL_LINE_TABLE_GLUTTON, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/cheesiehonkers, /obj/item/food/cornchips), tame_chance = 30, bonus_tame_chance = 0, after_tame = CALLBACK(src, PROC_REF(tamed))) - + AddElement(/datum/element/damage_threshold, 10) //lots of fat to cushion blows. /mob/living/basic/clown/mutant/glutton/attacked_by(obj/item/item, mob/living/user) if(!check_edible(item)) diff --git a/code/modules/mob/living/basic/cult/constructs/juggernaut.dm b/code/modules/mob/living/basic/cult/constructs/juggernaut.dm index 6beee5554a3..ef972d2b916 100644 --- a/code/modules/mob/living/basic/cult/constructs/juggernaut.dm +++ b/code/modules/mob/living/basic/cult/constructs/juggernaut.dm @@ -17,7 +17,6 @@ attack_sound = 'sound/weapons/punch3.ogg' status_flags = NONE mob_size = MOB_SIZE_LARGE - force_threshold = 10 construct_spells = list( /datum/action/cooldown/spell/basic_projectile/juggernaut, /datum/action/cooldown/spell/forcewall/cult, @@ -27,6 +26,10 @@ smashes_walls = TRUE +/mob/living/basic/construct/juggernaut/Initialize(mapload) + . = ..() + AddElement(/datum/element/damage_threshold, 10) + /// Hostile NPC version. Pretty dumb, just attacks whoever is near. /mob/living/basic/construct/juggernaut/hostile ai_controller = /datum/ai_controller/basic_controller/juggernaut diff --git a/code/modules/mob/living/basic/guardian/guardian_types/charger.dm b/code/modules/mob/living/basic/guardian/guardian_types/charger.dm index 02f839c6a41..93b82b7b0a9 100644 --- a/code/modules/mob/living/basic/guardian/guardian_types/charger.dm +++ b/code/modules/mob/living/basic/guardian/guardian_types/charger.dm @@ -62,7 +62,7 @@ /datum/action/cooldown/mob_cooldown/charge/basic_charge/guardian/hit_target(atom/movable/source, mob/living/target, damage_dealt) if(ishuman(target)) var/mob/living/carbon/human/hit_human = target - if(hit_human.check_shields(src, charge_damage, name, attack_type = LEAP_ATTACK)) + if(hit_human.check_block(src, charge_damage, name, attack_type = LEAP_ATTACK)) return . = ..() var/mob/living/hit_mob = target diff --git a/code/modules/mob/living/basic/ruin_defender/skeleton.dm b/code/modules/mob/living/basic/ruin_defender/skeleton.dm index 17262f6495d..aa41a399b7f 100644 --- a/code/modules/mob/living/basic/ruin_defender/skeleton.dm +++ b/code/modules/mob/living/basic/ruin_defender/skeleton.dm @@ -86,7 +86,7 @@ maxHealth = 150 health = 150 speed = 2 - force_threshold = 10 //trying to simulate actually having armor + damage_coeff = list(BRUTE = 0.5, BURN = 0.5, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //trying to simulate actually having armor obj_damage = 50 melee_damage_lower = 25 melee_damage_upper = 30 diff --git a/code/modules/mob/living/carbon/alien/adult/adult.dm b/code/modules/mob/living/carbon/alien/adult/adult.dm index ad8ef8ca877..92f3febef2c 100644 --- a/code/modules/mob/living/carbon/alien/adult/adult.dm +++ b/code/modules/mob/living/carbon/alien/adult/adult.dm @@ -75,10 +75,7 @@ GLOBAL_LIST_INIT(strippable_alien_humanoid_items, create_strippable_list(list( real_name = name /mob/living/carbon/alien/adult/proc/grab(mob/living/carbon/human/target) - if(target.check_block()) - target.visible_message(span_warning("[target] blocks [src]'s grab!"), \ - span_userdanger("You block [src]'s grab!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, src) - to_chat(src, span_warning("Your grab at [target] was blocked!")) + if(target.check_block(src, 0, "[target]'s grab")) return FALSE target.grabbedby(src) return TRUE diff --git a/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm b/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm index 3a346bf8255..ed39fda2108 100644 --- a/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm @@ -74,7 +74,7 @@ var/blocked = FALSE if(ishuman(hit_atom)) var/mob/living/carbon/human/H = hit_atom - if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK)) + if(H.check_block(src, 0, "the [name]", attack_type = LEAP_ATTACK)) blocked = TRUE if(!blocked) L.visible_message(span_danger("[src] pounces on [L]!"), span_userdanger("[src] pounces on you!")) diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index 63ef8830435..4ea7e98b05f 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -67,25 +67,6 @@ In all, this is a lot like the monkey code. /N var/obj/item/bodypart/affecting = get_bodypart(get_random_valid_zone(user.zone_selected)) apply_damage(rand(1, 3), BRUTE, affecting) - -/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/user, list/modifiers) - . = ..() - if(.) - var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - switch(user.melee_damage_type) - if(BRUTE) - adjustBruteLoss(damage) - if(BURN) - adjustFireLoss(damage) - if(TOX) - adjustToxLoss(damage) - if(OXY) - adjustOxyLoss(damage) - if(CLONE) - adjustCloneLoss(damage) - if(STAMINA) - adjustStaminaLoss(damage) - /mob/living/carbon/alien/attack_slime(mob/living/simple_animal/slime/M, list/modifiers) if(..()) //successful slime attack var/damage = rand(5, 35) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index ab94a5a0b38..2032eb511ff 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -92,46 +92,13 @@ return TRUE return ..() - -/mob/living/carbon/attacked_by(obj/item/I, mob/living/user) - var/obj/item/bodypart/affecting - if(user == src) - affecting = get_bodypart(check_zone(user.zone_selected)) //we're self-mutilating! yay! - else - var/zone_hit_chance = 80 - if(body_position == LYING_DOWN) // half as likely to hit a different zone if they're on the ground - zone_hit_chance += 10 - affecting = get_bodypart(get_random_valid_zone(user.zone_selected, zone_hit_chance)) - if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest) - affecting = bodyparts[1] - SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting) - send_item_attack_message(I, user, affecting.plaintext_zone, affecting) - if(I.force) - 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, attacking_item = I) - if(I.damtype == BRUTE && affecting.can_bleed()) - if(prob(33)) - I.add_mob_blood(src) - var/turf/location = get_turf(src) - add_splatter_floor(location) - if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood - user.add_mob_blood(src) - if(affecting.body_zone == BODY_ZONE_HEAD) - if(wear_mask) - wear_mask.add_mob_blood(src) - update_worn_mask() - if(wear_neck) - wear_neck.add_mob_blood(src) - update_worn_neck() - if(head) - head.add_mob_blood(src) - update_worn_head() - - return TRUE //successful attack - -/mob/living/carbon/send_item_attack_message(obj/item/I, mob/living/user, hit_area, obj/item/bodypart/hit_bodypart) +/mob/living/carbon/send_item_attack_message(obj/item/I, mob/living/user, hit_area, def_zone) if(!I.force && !length(I.attack_verb_simple) && !length(I.attack_verb_continuous)) return + var/obj/item/bodypart/hit_bodypart = get_bodypart(def_zone) + if(isnull(hit_bodypart)) // ?? + return ..() + var/message_verb_continuous = length(I.attack_verb_continuous) ? "[pick(I.attack_verb_continuous)]" : "attacks" var/message_verb_simple = length(I.attack_verb_simple) ? "[pick(I.attack_verb_simple)]" : "attack" //SKYRAT EDIT ADDITION BEGIN @@ -270,7 +237,18 @@ updatehealth() return 1 -/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone) +/** + * Really weird proc that attempts to dismebmer the passed zone if it is at max damage + * Unless the attacker is an NPC, in which case it disregards the zone and picks a random one + * + * Cannot dismember heads + * + * Returns a falsy value (null) on success, and a truthy value (the hit zone) on failure + */ +/mob/living/proc/dismembering_strike(mob/living/attacker, dam_zone) + return dam_zone + +/mob/living/carbon/dismembering_strike(mob/living/attacker, dam_zone) if(!attacker.limb_destroyer) return dam_zone var/obj/item/bodypart/affecting @@ -278,18 +256,17 @@ affecting = get_bodypart(get_random_valid_zone(dam_zone)) else var/list/things_to_ruin = shuffle(bodyparts.Copy()) - for(var/B in things_to_ruin) - var/obj/item/bodypart/bodypart = B + for(var/obj/item/bodypart/bodypart as anything in things_to_ruin) if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST) continue if(!affecting || ((affecting.get_damage() / affecting.max_damage) < (bodypart.get_damage() / bodypart.max_damage))) affecting = bodypart + if(affecting) dam_zone = affecting.body_zone - if(affecting.get_damage() >= affecting.max_damage) - affecting.dismember() + if(affecting.get_damage() >= affecting.max_damage && affecting.dismember()) return null - return affecting.body_zone + return dam_zone /** diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index ba2a82a034b..b4e56f2bfb4 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1138,11 +1138,6 @@ GLOBAL_LIST_EMPTY(features_by_species) user.do_cpr(target) /datum/species/proc/grab(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) - if(target.check_block()) - target.visible_message(span_warning("[target] blocks [user]'s grab!"), \ - span_userdanger("You block [user]'s grab!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_warning("Your grab at [target] was blocked!")) - return FALSE if(attacker_style?.grab_act(user, target) == MARTIAL_ATTACK_SUCCESS) return TRUE target.grabbedby(user) @@ -1153,11 +1148,6 @@ GLOBAL_LIST_EMPTY(features_by_species) if(HAS_TRAIT(user, TRAIT_PACIFISM) && !attacker_style?.pacifist_style) to_chat(user, span_warning("You don't want to harm [target]!")) return FALSE - if(target.check_block()) - target.visible_message(span_warning("[target] blocks [user]'s attack!"), \ - span_userdanger("You block [user]'s attack!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_warning("Your attack at [target] was blocked!")) - return FALSE if(attacker_style?.harm_act(user,target) == MARTIAL_ATTACK_SUCCESS) return TRUE else @@ -1252,11 +1242,6 @@ GLOBAL_LIST_EMPTY(features_by_species) log_combat(user, target, "got a stun punch with their previous punch") /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) - if(target.check_block()) - target.visible_message(span_warning("[user]'s shove is blocked by [target]!"), \ - span_danger("You block [user]'s shove!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_warning("Your shove at [target] was blocked!")) - return FALSE if(attacker_style?.disarm_act(user,target) == MARTIAL_ATTACK_SUCCESS) return TRUE if(user.body_position != STANDING_UP) @@ -1277,7 +1262,7 @@ GLOBAL_LIST_EMPTY(features_by_species) return if(owner.mind) attacker_style = owner.mind.martial_art - if((owner != target) && target.check_shields(owner, 0, owner.name, attack_type = UNARMED_ATTACK)) + if((owner != target) && target.check_block(owner, 0, owner.name, attack_type = UNARMED_ATTACK)) log_combat(owner, target, "attempted to touch") target.visible_message(span_warning("[owner] attempts to touch [target]!"), \ span_danger("[owner] attempts to touch you!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, owner) @@ -1294,115 +1279,6 @@ GLOBAL_LIST_EMPTY(features_by_species) else help(owner, target, attacker_style) -/datum/species/proc/spec_attacked_by(obj/item/weapon, mob/living/user, obj/item/bodypart/affecting, mob/living/carbon/human/human) - // Allows you to put in item-specific reactions based on species - if(user != human) - if(human.check_shields(weapon, weapon.force, "the [weapon.name]", MELEE_ATTACK, weapon.armour_penetration, weapon.damtype)) - return FALSE - if(human.check_block()) - human.visible_message(span_warning("[human] blocks [weapon]!"), \ - span_userdanger("You block [weapon]!")) - return FALSE - - affecting ||= human.bodyparts[1] //Something went wrong. Maybe the limb is missing? - var/hit_area = affecting.plaintext_zone - var/armor_block = min(human.run_armor_check( - def_zone = affecting, - attack_flag = MELEE, - absorb_text = span_notice("Your armor has protected your [hit_area]!"), - soften_text = span_warning("Your armor has softened a hit to your [hit_area]!"), - armour_penetration = weapon.armour_penetration, - weak_against_armour = weapon.weak_against_armour, - ), ARMOR_MAX_BLOCK) //cap damage reduction at 90% - - var/modified_wound_bonus = weapon.wound_bonus - // this way, you can't wound with a surgical tool on help intent if they have a surgery active and are lying down, so a misclick with a circular saw on the wrong limb doesn't bleed them dry (they still get hit tho) - if((weapon.item_flags & SURGICAL_TOOL) && !user.combat_mode && human.body_position == LYING_DOWN && (LAZYLEN(human.surgeries) > 0)) - modified_wound_bonus = CANT_WOUND - - human.send_item_attack_message(weapon, user, hit_area, affecting) - var/damage_dealt = human.apply_damage( - damage = weapon.force, - damagetype = weapon.damtype, - def_zone = affecting, - blocked = armor_block, - wound_bonus = modified_wound_bonus, - bare_wound_bonus = weapon.bare_wound_bonus, - sharpness = weapon.get_sharpness(), - attack_direction = get_dir(user, human), - attacking_item = weapon, - ) - - if(damage_dealt <= 0) - return FALSE //item force is zero - var/bloody = FALSE - if(weapon.damtype != BRUTE) - return TRUE - if(!(prob(25 + (weapon.force * 2)))) - return TRUE - - if(affecting.can_bleed()) - weapon.add_mob_blood(human) //Make the weapon bloody, not the person. - if(prob(weapon.force * 2)) //blood spatter! - bloody = TRUE - var/turf/location = human.loc - if(istype(location)) - human.add_splatter_floor(location) - if(get_dist(user, human) <= 1) //people with TK won't get smeared with blood - user.add_mob_blood(human) - - switch(hit_area) - if(BODY_ZONE_HEAD) - if(!weapon.get_sharpness() && armor_block < 50) - if(prob(weapon.force)) - human.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) - if(human.stat == CONSCIOUS) - human.visible_message(span_danger("[human] is knocked senseless!"), \ - span_userdanger("You're knocked senseless!")) - human.set_confusion_if_lower(20 SECONDS) - human.adjust_eye_blur(20 SECONDS) - if(prob(10)) - human.gain_trauma(/datum/brain_trauma/mild/concussion) - else - human.adjustOrganLoss(ORGAN_SLOT_BRAIN, weapon.force * 0.2) - - if(human.mind && human.stat == CONSCIOUS && human != user && prob(weapon.force + ((human.maxHealth - human.health) * 0.5))) // rev deconversion through blunt trauma. // SKYRAT EDIT CHANGE - var/datum/antagonist/rev/rev = human.mind.has_antag_datum(/datum/antagonist/rev) - if(rev) - rev.remove_revolutionary(user) - - if(bloody) //Apply blood - if(human.wear_mask) - human.wear_mask.add_mob_blood(human) - human.update_worn_mask() - if(human.head) - human.head.add_mob_blood(human) - human.update_worn_head() - if(human.glasses && prob(33)) - human.glasses.add_mob_blood(human) - human.update_worn_glasses() - - if(BODY_ZONE_CHEST) - if(human.stat == CONSCIOUS && !weapon.get_sharpness() && armor_block < 50) - if(prob(weapon.force)) - human.visible_message(span_danger("[human] is knocked down!"), \ - span_userdanger("You're knocked down!")) - human.apply_effect(60, EFFECT_KNOCKDOWN, armor_block) - - if(bloody) - if(human.wear_suit) - human.wear_suit.add_mob_blood(human) - human.update_worn_oversuit() - if(human.w_uniform) - human.w_uniform.add_mob_blood(human) - human.update_worn_undersuit() - - /// Triggers force say events - if(weapon.force > 10 || (weapon.force >= 5 && prob(33))) - human.force_say(user) - - return TRUE - ////////////////////////// // ENVIRONMENT HANDLERS // ////////////////////////// diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index da1a9332ab8..825e2b6a56b 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -68,7 +68,7 @@ return BULLET_ACT_FORCE_PIERCE // complete projectile permutation - if(check_shields(bullet, bullet.damage, "the [bullet.name]", PROJECTILE_ATTACK, bullet.armour_penetration, bullet.damage_type)) + if(check_block(bullet, bullet.damage, "the [bullet.name]", PROJECTILE_ATTACK, bullet.armour_penetration, bullet.damage_type)) bullet.on_hit(src, 100, def_zone, piercing_hit) return BULLET_ACT_HIT @@ -87,94 +87,39 @@ return TRUE return FALSE -/mob/living/carbon/human/proc/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0, damage_type = BRUTE) +/mob/living/carbon/human/check_block(atom/hit_by, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0, damage_type = BRUTE) + . = ..() + if(.) + return TRUE + var/block_chance_modifier = round(damage / -3) + for(var/obj/item/worn_thing in get_equipped_items(include_pockets = FALSE) + held_items) + // Things that are supposed to be worn, being held = cannot block + if(isclothing(worn_thing)) + if(worn_thing in held_items) + continue + // Things that are supposed to be held, being worn = cannot block + else + if(!(worn_thing in held_items)) + continue - for(var/obj/item/I in held_items) - if(!isclothing(I)) - var/final_block_chance = I.block_chance - (clamp((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example - if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type, damage_type)) - return TRUE - if(wear_suit) - var/final_block_chance = wear_suit.block_chance - (clamp((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier - if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type, damage_type)) - return TRUE - if(w_uniform) - var/final_block_chance = w_uniform.block_chance - (clamp((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier - if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type, damage_type)) - return TRUE - if(wear_neck) - var/final_block_chance = wear_neck.block_chance - (clamp((armour_penetration-wear_neck.armour_penetration)/2,0,100)) + block_chance_modifier - if(wear_neck.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type, damage_type)) + var/final_block_chance = worn_thing.block_chance - (clamp((armour_penetration - worn_thing.armour_penetration) / 2, 0, 100)) + block_chance_modifier + if(worn_thing.hit_reaction(src, hit_by, attack_text, final_block_chance, damage, attack_type, damage_type)) return TRUE - if(head) - var/final_block_chance = head.block_chance - (clamp((armour_penetration-head.armour_penetration)/2,0,100)) + block_chance_modifier - if(head.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type, damage_type)) - return TRUE - if(SEND_SIGNAL(src, COMSIG_HUMAN_CHECK_SHIELDS, AM, damage, attack_text, attack_type, armour_penetration, damage_type) & SHIELD_BLOCK) - return TRUE - return FALSE -/mob/living/carbon/human/proc/check_block() - if(mind) - if(mind.martial_art && prob(mind.martial_art.block_chance) && mind.martial_art.can_use(src) && throw_mode && !incapacitated(IGNORE_GRAB)) - return TRUE return FALSE -/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) - var/obj/item/I - var/damage_type = BRUTE - var/throwpower = 30 - if(isitem(AM)) - I = AM - if(I.thrownby == WEAKREF(src)) //No throwing stuff at yourself to trigger hit reactions - return ..() - throwpower = I.throwforce - damage_type = I.damtype - if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK, 0, damage_type)) - hitpush = FALSE - skipcatch = TRUE - blocked = TRUE - - return ..() - /mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE) if(w_uniform) w_uniform.add_fingerprint(user) ..() - -/mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user) - if(!I || !user) - return FALSE - - var/obj/item/bodypart/affecting - if(user == src) - affecting = get_bodypart(check_zone(user.zone_selected)) //stabbing yourself always hits the right target - else - var/zone_hit_chance = 80 - if(body_position == LYING_DOWN) // half as likely to hit a different zone if they're on the ground - zone_hit_chance += 10 - affecting = get_bodypart(get_random_valid_zone(user.zone_selected, zone_hit_chance)) - var/target_area = parse_zone(check_zone(user.zone_selected)) //our intended target - - SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting) - - SSblackbox.record_feedback("nested tally", "item_used_for_combat", 1, list("[I.force]", "[I.type]")) - SSblackbox.record_feedback("tally", "zone_targeted", 1, target_area) - - // the attacked_by code varies among species - return dna.species.spec_attacked_by(I, user, affecting, src) - - /mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user) . = ..() if(!.) return var/hulk_verb = pick("smash","pummel") - if(check_shields(user, 15, "the [hulk_verb]ing", attack_type = UNARMED_ATTACK)) - return - if(check_block()) //everybody is kung fu fighting + if(check_block(user, 15, "the [hulk_verb]ing", attack_type = UNARMED_ATTACK)) return var/obj/item/bodypart/arm/active_arm = user.get_active_hand() playsound(loc, active_arm.unarmed_attack_sound, 25, TRUE, -1) @@ -234,7 +179,7 @@ var/damage = HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) ? monkey_mouth.unarmed_damage_high : rand(monkey_mouth.unarmed_damage_low, monkey_mouth.unarmed_damage_high) if(!damage) return FALSE - if(check_shields(user, damage, "the [user.name]")) + if(check_block(user, damage, "the [user.name]")) return FALSE apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, MELEE)) return TRUE @@ -242,11 +187,6 @@ //SKYRAT EDIT REMOVAL BEGIN - SKYRAT_XENO_REDO - Moved to: modular_skyrat\modules\xenos_skyrat_redo\code\human_defense.dm /* /mob/living/carbon/human/attack_alien(mob/living/carbon/alien/adult/user, list/modifiers) - if(check_shields(user, 0, "the [user.name]")) - visible_message(span_danger("[user] attempts to touch [src]!"), \ - span_danger("[user] attempts to touch you!"), span_hear("You hear a swoosh!"), null, user) - to_chat(user, span_warning("You attempt to touch [src]!")) - return FALSE . = ..() if(!.) return @@ -308,7 +248,7 @@ var/damage = rand(L.melee_damage_lower, L.melee_damage_upper) if(!damage) return - if(check_shields(L, damage, "the [L.name]")) + if(check_block(L, damage, "the [L.name]")) return FALSE if(stat != DEAD) L.amount_grown = min(L.amount_grown + damage, L.max_grown) @@ -316,22 +256,6 @@ var/armor_block = run_armor_check(affecting, MELEE) apply_damage(damage, BRUTE, affecting, armor_block) -/mob/living/carbon/human/attack_animal(mob/living/simple_animal/user, list/modifiers) - . = ..() - if(!.) - return - var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - if(check_shields(user, damage, "the [user.name]", MELEE_ATTACK, user.armour_penetration, user.melee_damage_type)) - return FALSE - var/dam_zone = dismembering_strike(user, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) - if(!dam_zone) //Dismemberment successful - return TRUE - var/obj/item/bodypart/affecting = get_bodypart(get_random_valid_zone(dam_zone)) - var/armor = run_armor_check(affecting, MELEE, armour_penetration = user.armour_penetration) - 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, list/modifiers) . = ..() if(!.) // slime attack failed @@ -344,7 +268,7 @@ damage += rand(5, 10) wound_mod = -90 // 35^1.4=145, 145-90=55 - if(check_shields(M, damage, "the [M.name]")) + if(check_block(M, damage, "the [M.name]")) return FALSE var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 3f5dd6f3340..60991f9e7a4 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -171,35 +171,49 @@ SEND_SOUND(src, sound('sound/misc/ui_toggleoffcombat.ogg', volume = 25)) //Slightly modified version of the above /mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) - if(isitem(AM)) - var/obj/item/thrown_item = AM - var/zone = get_random_valid_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest - var/nosell_hit = SEND_SIGNAL(thrown_item, COMSIG_MOVABLE_IMPACT_ZONE, src, zone, blocked, throwingdatum) // TODO: find a better way to handle hitpush and skipcatch for humans - if(nosell_hit) - skipcatch = TRUE + if(!isitem(AM)) + // Filled with made up numbers for non-items. + if(check_block(AM, 30, "\the [AM.name]", THROWN_PROJECTILE_ATTACK, 0, BRUTE)) hitpush = FALSE + skipcatch = TRUE + blocked = TRUE + else + playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1) //Item sounds are handled in the item itself + return ..() - if(blocked) - return TRUE - - var/mob/thrown_by = thrown_item.thrownby?.resolve() - if(thrown_by) - log_combat(thrown_by, src, "threw and hit", thrown_item) - if(nosell_hit) - return ..() - visible_message(span_danger("[src] is hit by [thrown_item]!"), \ - span_userdanger("You're hit by [thrown_item]!")) - if(!thrown_item.throwforce) - return - var/armor = run_armor_check(zone, MELEE, "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", thrown_item.armour_penetration, "", FALSE, thrown_item.weak_against_armour) - apply_damage(thrown_item.throwforce, thrown_item.damtype, zone, armor, sharpness = thrown_item.get_sharpness(), wound_bonus = (nosell_hit * CANT_WOUND)) - if(QDELETED(src)) //Damage can delete the mob. - return - if(body_position == LYING_DOWN) // physics says it's significantly harder to push someone by constantly chucking random furniture at them if they are down on the floor. - hitpush = FALSE + var/obj/item/thrown_item = AM + if(thrown_item.thrownby == WEAKREF(src)) //No throwing stuff at yourself to trigger hit reactions return ..() - playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1) //Item sounds are handled in the item itself + if(check_block(AM, thrown_item.throwforce, "\the [thrown_item.name]", THROWN_PROJECTILE_ATTACK, 0, thrown_item.damtype)) + hitpush = FALSE + skipcatch = TRUE + blocked = TRUE + + var/zone = get_random_valid_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest + var/nosell_hit = SEND_SIGNAL(thrown_item, COMSIG_MOVABLE_IMPACT_ZONE, src, zone, blocked, throwingdatum) // TODO: find a better way to handle hitpush and skipcatch for humans + if(nosell_hit) + skipcatch = TRUE + hitpush = FALSE + + if(blocked) + return TRUE + + var/mob/thrown_by = thrown_item.thrownby?.resolve() + if(thrown_by) + log_combat(thrown_by, src, "threw and hit", thrown_item) + if(nosell_hit) + return ..() + visible_message(span_danger("[src] is hit by [thrown_item]!"), \ + span_userdanger("You're hit by [thrown_item]!")) + if(!thrown_item.throwforce) + return + var/armor = run_armor_check(zone, MELEE, "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].", thrown_item.armour_penetration, "", FALSE, thrown_item.weak_against_armour) + apply_damage(thrown_item.throwforce, thrown_item.damtype, zone, armor, sharpness = thrown_item.get_sharpness(), wound_bonus = (nosell_hit * CANT_WOUND)) + if(QDELETED(src)) //Damage can delete the mob. + return + if(body_position == LYING_DOWN) // physics says it's significantly harder to push someone by constantly chucking random furniture at them if they are down on the floor. + hitpush = FALSE return ..() /mob/living/fire_act() @@ -284,10 +298,6 @@ /mob/living/attack_slime(mob/living/simple_animal/slime/M, list/modifiers) - if(!SSticker.HasRoundStarted()) - to_chat(M, "You cannot attack people before the game has started.") - return - if(M.buckled) if(M in buckled_mobs) M.Feedstop() @@ -297,6 +307,9 @@ to_chat(M, span_warning("You don't want to hurt anyone!")) return FALSE + if(check_block(src, M.melee_damage_upper, "[M]'s glomp", MELEE_ATTACK, M.armour_penetration, M.melee_damage_type)) + return FALSE + if (stat != DEAD) log_combat(M, src, "attacked") M.do_attack_animation(src) @@ -305,30 +318,68 @@ to_chat(M, span_danger("You glomp [src]!")) return TRUE + return FALSE + /mob/living/attack_animal(mob/living/simple_animal/user, list/modifiers) . = ..() - user.face_atom(src) + if(.) + return FALSE // looks wrong, but if the attack chain was cancelled we don't propogate it up to children calls. Yeah it's cringe. + if(user.melee_damage_upper == 0) if(user != src) - visible_message(span_notice("\The [user] [user.friendly_verb_continuous] [src]!"), \ - span_notice("\The [user] [user.friendly_verb_continuous] you!"), null, COMBAT_MESSAGE_RANGE, user) + visible_message( + span_notice("[user] [user.friendly_verb_continuous] [src]!"), + span_notice("[user] [user.friendly_verb_continuous] you!"), + vision_distance = COMBAT_MESSAGE_RANGE, + ignored_mobs = user, + ) to_chat(user, span_notice("You [user.friendly_verb_simple] [src]!")) return FALSE + if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, span_warning("You don't want to hurt anyone!")) return FALSE + var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) + if(check_block(user, damage, "[user]'s [user.attack_verb_simple]", MELEE_ATTACK/*or UNARMED_ATTACK?*/, user.armour_penetration, user.melee_damage_type)) + return FALSE + if(user.attack_sound) - playsound(loc, user.attack_sound, 50, TRUE, TRUE) + playsound(src, user.attack_sound, 50, TRUE, TRUE) + user.do_attack_animation(src) - visible_message(span_danger("\The [user] [user.attack_verb_continuous] [src]!"), \ - span_userdanger("\The [user] [user.attack_verb_continuous] you!"), null, COMBAT_MESSAGE_RANGE, user) + visible_message( + span_danger("[user] [user.attack_verb_continuous] [src]!"), + span_userdanger("[user] [user.attack_verb_continuous] you!"), + null, + COMBAT_MESSAGE_RANGE, + user, + ) + + var/dam_zone = dismembering_strike(user, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) + if(!dam_zone) //Dismemberment successful + return FALSE + + var/armor_block = run_armor_check(user.zone_selected, MELEE, armour_penetration = user.armour_penetration) + to_chat(user, span_danger("You [user.attack_verb_simple] [src]!")) log_combat(user, src, "attacked") - return TRUE + var/damage_done = apply_damage( + damage = damage, + damagetype = user.melee_damage_type, + def_zone = user.zone_selected, + blocked = armor_block, + wound_bonus = user.wound_bonus, + bare_wound_bonus = user.bare_wound_bonus, + sharpness = user.sharpness, + attack_direction = get_dir(user, src), + ) + return damage_done /mob/living/attack_hand(mob/living/carbon/human/user, list/modifiers) . = ..() + if(.) + return TRUE for(var/datum/surgery/operations as anything in surgeries) if(user.combat_mode) @@ -342,6 +393,8 @@ if (martial_result != MARTIAL_ATTACK_INVALID) return martial_result + return FALSE + /mob/living/attack_paw(mob/living/carbon/human/user, list/modifiers) var/martial_result = user.apply_martial_art(src, modifiers) if (martial_result != MARTIAL_ATTACK_INVALID) @@ -362,6 +415,10 @@ if(user.is_muzzled() || user.is_mouth_covered(ITEM_SLOT_MASK)) to_chat(user, span_warning("You can't bite with your mouth covered!")) return FALSE + + if(check_block(user, 1, "[user]'s bite", UNARMED_ATTACK, 0, BRUTE)) + return FALSE + user.do_attack_animation(src, ATTACK_EFFECT_BITE) if (HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) || prob(75)) log_combat(user, src, "attacked") @@ -381,7 +438,10 @@ if(L.combat_mode) if(HAS_TRAIT(L, TRAIT_PACIFISM)) to_chat(L, span_warning("You don't want to hurt anyone!")) - return + return FALSE + + if(check_block(L, 1, "[L]'s bite", UNARMED_ATTACK, 0, BRUTE)) + return FALSE L.do_attack_animation(src) if(prob(90)) @@ -395,29 +455,34 @@ visible_message(span_danger("[L.name]'s bite misses [src]!"), \ span_danger("You avoid [L.name]'s bite!"), span_hear("You hear the sound of jaws snapping shut!"), COMBAT_MESSAGE_RANGE, L) to_chat(L, span_warning("Your bite misses [src]!")) - else - visible_message(span_notice("[L.name] rubs its head against [src]."), \ - span_notice("[L.name] rubs its head against you."), null, null, L) - to_chat(L, span_notice("You rub your head against [src].")) - return FALSE + return FALSE + + visible_message(span_notice("[L.name] rubs its head against [src]."), \ + span_notice("[L.name] rubs its head against you."), null, null, L) + to_chat(L, span_notice("You rub your head against [src].")) return FALSE /mob/living/attack_alien(mob/living/carbon/alien/adult/user, list/modifiers) SEND_SIGNAL(src, COMSIG_MOB_ATTACK_ALIEN, user, modifiers) if(LAZYACCESS(modifiers, RIGHT_CLICK)) + if(check_block(user, 0, "[user]'s tackle", MELEE_ATTACK, 0, BRUTE)) + return FALSE user.do_attack_animation(src, ATTACK_EFFECT_DISARM) return TRUE + if(user.combat_mode) if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, span_warning("You don't want to hurt anyone!")) return FALSE + if(check_block(user, user.melee_damage_upper, "[user]'s slash", MELEE_ATTACK, 0, BRUTE)) + return FALSE user.do_attack_animation(src) return TRUE - else - visible_message(span_notice("[user] caresses [src] with its scythe-like arm."), \ - span_notice("[user] caresses you with its scythe-like arm."), null, null, user) - to_chat(user, span_notice("You caress [src] with your scythe-like arm.")) - return FALSE + + visible_message(span_notice("[user] caresses [src] with its scythe-like arm."), \ + span_notice("[user] caresses you with its scythe-like arm."), null, null, user) + to_chat(user, span_notice("You caress [src] with your scythe-like arm.")) + return FALSE /mob/living/attack_hulk(mob/living/carbon/human/user) ..() @@ -579,3 +644,9 @@ var/new_angle_s = SIMPLIFY_DEGREES(face_angle + GET_ANGLE_OF_INCIDENCE(face_angle, (ricocheting_projectile.Angle + 180))) ricocheting_projectile.set_angle(new_angle_s) return TRUE + +/mob/living/proc/check_block(atom/hit_by, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0, damage_type = BRUTE) + if(SEND_SIGNAL(src, COMSIG_LIVING_CHECK_BLOCK, hit_by, damage, attack_text, attack_type, armour_penetration, damage_type) & SUCCESSFUL_BLOCK) + return TRUE + + return FALSE diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm index ad9a965242e..853e6e9c8eb 100644 --- a/code/modules/mob/living/silicon/ai/ai_defense.dm +++ b/code/modules/mob/living/silicon/ai/ai_defense.dm @@ -7,15 +7,8 @@ return MOD.install(laws, user) //Proc includes a success mesage so we don't need another one return - if(W.force && W.damtype != STAMINA && stat != DEAD && !QDELETED(src)) //only sparks if real damage is dealt. - spark_system.start() - return ..() -/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/adult/user, list/modifiers) - if(!SSticker.HasRoundStarted()) - to_chat(user, "You cannot attack people before the game has started.") - return - ..() + return ..() /mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user, list/modifiers) return //immune to slimes diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index e5117317cbd..074f9d0049a 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -184,8 +184,6 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real modularInterface.inserted_disk = floppy return - if(W.force && W.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt. - spark_system.start() return ..() /mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/adult/user, list/modifiers) diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index 75cbd83f54f..4b870fdf474 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -27,20 +27,17 @@ /mob/living/silicon/attack_animal(mob/living/simple_animal/user, list/modifiers) . = ..() - if(.) - var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - if(prob(damage)) - for(var/mob/living/buckled in buckled_mobs) - buckled.Paralyze(20) - unbuckle_mob(buckled) - buckled.visible_message(span_danger("[buckled] is knocked off of [src] by [user]!"), \ - span_userdanger("You're knocked off of [src] by [user]!"), null, null, user) - to_chat(user, span_danger("You knock [buckled] off of [src]!")) - switch(user.melee_damage_type) - if(BRUTE) - adjustBruteLoss(damage) - if(BURN) - adjustFireLoss(damage) + var/damage_received = . + if(prob(damage_received)) + for(var/mob/living/buckled in buckled_mobs) + buckled.Paralyze(2 SECONDS) + unbuckle_mob(buckled) + buckled.visible_message( + span_danger("[buckled] is knocked off of [src] by [user]!"), + span_userdanger("You're knocked off of [src] by [user]!"), + ignored_mobs = user, + ) + to_chat(user, span_danger("You knock [buckled] off of [src]!")) /mob/living/silicon/attack_paw(mob/living/user, list/modifiers) return attack_hand(user, modifiers) @@ -79,6 +76,15 @@ to_chat(user, span_notice("You pet [src].")) user.add_mood_event("pet_borg", /datum/mood_event/pet_borg) +/mob/living/silicon/check_block(atom/hitby, damage, attack_text, attack_type, armour_penetration, damage_type, attack_flag) + . = ..() + if(.) + return TRUE + if(damage_type == BRUTE && attack_type == UNARMED_ATTACK && attack_flag == MELEE && damage <= 10) + playsound(src, 'sound/effects/bang.ogg', 10, TRUE) + visible_message(span_danger("[attack_text] doesn't leave a dent on [src]!"), vision_distance = COMBAT_MESSAGE_RANGE) + return TRUE + return FALSE /mob/living/silicon/attack_drone(mob/living/basic/drone/user) if(user.combat_mode) diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm index 103ea7aa147..01d144aea88 100644 --- a/code/modules/mob/living/simple_animal/animal_defense.dm +++ b/code/modules/mob/living/simple_animal/animal_defense.dm @@ -32,12 +32,14 @@ if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, span_warning("You don't want to hurt [src]!")) return + if(check_block(user, harm_intent_damage, "[user]'s punch", UNARMED_ATTACK, 0, BRUTE)) + return user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) visible_message(span_danger("[user] [response_harm_continuous] [src]!"),\ span_userdanger("[user] [response_harm_continuous] you!"), null, COMBAT_MESSAGE_RANGE, user) to_chat(user, span_danger("You [response_harm_simple] [src]!")) playsound(loc, attacked_sound, 25, TRUE, -1) - attack_threshold_check(harm_intent_damage) + apply_damage(harm_intent_damage) log_combat(user, src, "attacked") updatehealth() return TRUE @@ -55,9 +57,7 @@ /mob/living/simple_animal/attack_paw(mob/living/carbon/human/user, list/modifiers) if(..()) //successful monkey bite. if(stat != DEAD) - var/damage = rand(1, 3) - attack_threshold_check(damage) - return 1 + return apply_damage(rand(1, 3)) if (!user.combat_mode) if (health > 0) visible_message(span_notice("[user.name] [response_help_continuous] [src]."), \ @@ -80,30 +80,23 @@ span_userdanger("You're slashed at by [user]!"), null, COMBAT_MESSAGE_RANGE, user) to_chat(user, span_danger("You slash at [src]!")) playsound(loc, 'sound/weapons/slice.ogg', 25, TRUE, -1) - attack_threshold_check(damage) + apply_damage(damage) log_combat(user, src, "attacked") return 1 /mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L, list/modifiers) . = ..() if(. && stat != DEAD) //successful larva bite - var/damage = rand(5, 10) - . = attack_threshold_check(damage) - if(.) - L.amount_grown = min(L.amount_grown + damage, L.max_grown) - -/mob/living/simple_animal/attack_animal(mob/living/simple_animal/user, list/modifiers) - . = ..() - if(.) - var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - return attack_threshold_check(damage, user.melee_damage_type) + var/damage_done = apply_damage(rand(L.melee_damage_lower, L.melee_damage_upper), BRUTE) + if(damage_done > 0) + L.amount_grown = min(L.amount_grown + damage_done, L.max_grown) /mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/user, list/modifiers) if(..()) //successful slime attack var/damage = rand(15, 25) if(user.is_adult) damage = rand(20, 35) - return attack_threshold_check(damage) + return apply_damage(damage, user.melee_damage_type) /mob/living/simple_animal/attack_drone(mob/living/basic/drone/user) if(user.combat_mode) //No kicking dogs even as a rogue drone. Use a weapon. @@ -115,21 +108,6 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN return ..() -/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE, armorcheck = MELEE, actuallydamage = TRUE) - var/temp_damage = damage - if(!damage_coeff[damagetype]) - temp_damage = 0 - else - temp_damage *= damage_coeff[damagetype] - - if(temp_damage >= 0 && temp_damage <= force_threshold) - visible_message(span_warning("[src] looks unharmed!")) - return FALSE - else - if(actuallydamage) - apply_damage(damage, damagetype, null, getarmor(null, armorcheck)) - return TRUE - /mob/living/simple_animal/ex_act(severity, target, origin) . = ..() if(!. || QDELETED(src)) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index c369058a2a3..9eca91ab1e6 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -496,11 +496,11 @@ return return ..() -/mob/living/simple_animal/bot/attacked_by(obj/item/I, mob/living/user) - . = ..() - if (!.) - return - do_sparks(5, TRUE, src) +/mob/living/simple_animal/bot/attack_effects(damage_done, hit_zone, armor_block, obj/item/attacking_item, mob/living/attacker) + if(damage_done > 0 && attacking_item.damtype != STAMINA && stat != DEAD) + do_sparks(5, TRUE, src) + . = TRUE + return ..() || . /mob/living/simple_animal/bot/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit = FALSE) . = ..() diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 5b994b1fc0c..651384cb030 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -520,7 +520,7 @@ return ..() /mob/living/simple_animal/bot/secbot/attack_alien(mob/living/carbon/alien/user, list/modifiers) - ..() + . = ..() if(!isalien(target)) target = user mode = BOT_HUNT diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index f6c5e644b86..b02e8354da8 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -330,20 +330,16 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( /mob/living/simple_animal/parrot/attack_paw(mob/living/carbon/human/user, list/modifiers) return attack_hand(user, modifiers) -/mob/living/simple_animal/parrot/attack_alien(mob/living/carbon/alien/user, list/modifiers) - return attack_hand(user, modifiers) - //Simple animals /mob/living/simple_animal/parrot/attack_animal(mob/living/simple_animal/user, list/modifiers) . = ..() //goodbye immortal parrots - if(client) return if(parrot_state == PARROT_PERCH) parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - if(user.melee_damage_upper > 0 && !stat) + if(. > 0 && stat == CONSCIOUS) set_parrot_interest(user) parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless icon_state = icon_living diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index ed304e276b0..3c380465769 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -51,8 +51,6 @@ ///Harm-intent verb in present simple tense. var/response_harm_simple = "hit" var/harm_intent_damage = 3 - ///Minimum force required to deal any damage. - var/force_threshold = 0 ///Maximum amount of stamina damage the mob can be inflicted with total var/max_staminaloss = 200 ///How much stamina the mob recovers per second diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index cdae01abd8c..3e5d714746b 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -342,7 +342,6 @@ if(.) attacked += 10 - /mob/living/simple_animal/slime/attack_paw(mob/living/carbon/human/user, list/modifiers) if(..()) //successful monkey bite. attacked += 10 diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index 1cd70ef9f80..33aba248d9a 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -120,13 +120,13 @@ /obj/item/mod/module/energy_shield/on_suit_activation() mod.AddComponent(/datum/component/shielded, max_charges = max_charges, recharge_start_delay = recharge_start_delay, charge_increment_delay = charge_increment_delay, \ charge_recovery = charge_recovery, lose_multiple_charges = lose_multiple_charges, recharge_path = recharge_path, starting_charges = charges, shield_icon_file = shield_icon_file, shield_icon = shield_icon) - RegisterSignal(mod.wearer, COMSIG_HUMAN_CHECK_SHIELDS, PROC_REF(shield_reaction)) + RegisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(shield_reaction)) /obj/item/mod/module/energy_shield/on_suit_deactivation(deleting = FALSE) var/datum/component/shielded/shield = mod.GetComponent(/datum/component/shielded) charges = shield.current_charges qdel(shield) - UnregisterSignal(mod.wearer, COMSIG_HUMAN_CHECK_SHIELDS) + UnregisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK) /obj/item/mod/module/energy_shield/proc/shield_reaction(mob/living/carbon/human/owner, atom/movable/hitby, @@ -140,7 +140,7 @@ if(SEND_SIGNAL(mod, COMSIG_ITEM_HIT_REACT, owner, hitby, attack_text, 0, damage, attack_type, damage_type) & COMPONENT_HIT_REACTION_BLOCK) drain_power(use_power_cost) - return SHIELD_BLOCK + return SUCCESSFUL_BLOCK return NONE /obj/item/mod/module/energy_shield/wizard diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 3ac431034b5..a5128996b62 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -67,10 +67,10 @@ overlay_state_use = "module_pepper_used" /obj/item/mod/module/pepper_shoulders/on_suit_activation() - RegisterSignal(mod.wearer, COMSIG_HUMAN_CHECK_SHIELDS, PROC_REF(on_check_shields)) + RegisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(on_check_block)) /obj/item/mod/module/pepper_shoulders/on_suit_deactivation(deleting = FALSE) - UnregisterSignal(mod.wearer, COMSIG_HUMAN_CHECK_SHIELDS) + UnregisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK) /obj/item/mod/module/pepper_shoulders/on_use() . = ..() @@ -84,7 +84,7 @@ smoke.start(log = TRUE) QDEL_NULL(capsaicin_holder) // Reagents have a ref to their holder which has a ref to them. No leaks please. -/obj/item/mod/module/pepper_shoulders/proc/on_check_shields() +/obj/item/mod/module/pepper_shoulders/proc/on_check_block() SIGNAL_HANDLER if(!COOLDOWN_FINISHED(src, cooldown_timer)) diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm b/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm index 486284b8b6d..9e4c544d338 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm @@ -430,7 +430,7 @@ if(ishuman(target)) var/mob/living/carbon/human/human_target = target - if(human_target.check_shields(source, punch_damage, "[source]'s' [picked_hit_type]")) + if(human_target.check_block(source, punch_damage, "[source]'s' [picked_hit_type]")) source.do_attack_animation(target) playsound(living_target.loc, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1) log_combat(source, target, "attempted to [picked_hit_type]", "muscle implant") diff --git a/modular_skyrat/modules/customization/modules/client/augment/organs.dm b/modular_skyrat/modules/customization/modules/client/augment/organs.dm index 94d13ff9504..091b0414456 100644 --- a/modular_skyrat/modules/customization/modules/client/augment/organs.dm +++ b/modular_skyrat/modules/customization/modules/client/augment/organs.dm @@ -4,8 +4,10 @@ /datum/augment_item/organ/apply(mob/living/carbon/human/human_holder, character_setup = FALSE, datum/preferences/prefs) if(character_setup) return + + var/obj/item/organ/organ_path = path // cast this to an organ so we can get the slot from it using initial() var/obj/item/organ/new_organ = new path() - new_organ.copy_traits_from(human_holder.get_organ_slot(ORGAN_SLOT_TONGUE)) + new_organ.copy_traits_from(human_holder.get_organ_slot(initial(organ_path.slot))) new_organ.Insert(human_holder, special = TRUE, drop_if_replaced = FALSE) //HEARTS diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm index 0efe513cf26..0b615d6bfc1 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm @@ -41,32 +41,12 @@ if(inFeatures["ghoulcolor"] == null || inFeatures["ghoulcolor"] == "") inFeatures["ghoulcolor"] = GLOB.color_list_ghoul[pick(GLOB.color_list_ghoul)] -/datum/species/ghoul/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) - // Missing Defaults in DNA? Randomize! - proof_ghoul_features(C.dna.features) - - . = ..() - - if(ishuman(C)) - var/mob/living/carbon/human/H = C - - set_ghoul_color(H) - - // 2) BODYPARTS - C.part_default_head = /obj/item/bodypart/head/mutant/ghoul - C.part_default_chest = /obj/item/bodypart/chest/mutant/ghoul - C.part_default_l_arm = /obj/item/bodypart/arm/left/mutant/ghoul - C.part_default_r_arm = /obj/item/bodypart/arm/right/mutant/ghoul - C.part_default_l_leg = /obj/item/bodypart/leg/left/mutant/ghoul - C.part_default_r_leg = /obj/item/bodypart/leg/right/mutant/ghoul - C.ReassignForeignBodyparts() - -/datum/species/proc/set_ghoul_color(mob/living/carbon/human/H) +/datum/species/proc/set_ghoul_color(mob/living/carbon/human/human_ghoul) return // Do Nothing -/datum/species/ghoul/set_ghoul_color(mob/living/carbon/human/H) +/datum/species/ghoul/set_ghoul_color(mob/living/carbon/human/human_ghoul) // Called on Assign, or on Color Change (or any time proof_ghoul_features() is used) - fixed_mut_color = H.dna.features["ghoulcolor"] + fixed_mut_color = human_ghoul.dna.features["ghoulcolor"] /mob/living/carbon/proc/ReassignForeignBodyparts() var/obj/item/bodypart/head = get_bodypart(BODY_ZONE_HEAD) @@ -105,18 +85,39 @@ var/obj/item/bodypart/limb = new part_default_r_leg limb.replace_limb(src, TRUE) +/datum/species/ghoul/on_species_gain(mob/living/carbon/new_ghoul, datum/species/old_species, pref_load) + // Missing Defaults in DNA? Randomize! + proof_ghoul_features(new_ghoul.dna.features) + + . = ..() + + if(ishuman(new_ghoul)) + var/mob/living/carbon/human/human_ghoul = new_ghoul -/datum/species/ghoul/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) - ..() + set_ghoul_color(human_ghoul) + + // 2) BODYPARTS + RegisterSignal(src, COMSIG_ITEM_ATTACK, PROC_REF(attach_meat)) + human_ghoul.part_default_head = /obj/item/bodypart/head/mutant/ghoul + human_ghoul.part_default_chest = /obj/item/bodypart/chest/mutant/ghoul + human_ghoul.part_default_l_arm = /obj/item/bodypart/arm/left/mutant/ghoul + human_ghoul.part_default_r_arm = /obj/item/bodypart/arm/right/mutant/ghoul + human_ghoul.part_default_l_leg = /obj/item/bodypart/leg/left/mutant/ghoul + human_ghoul.part_default_r_leg = /obj/item/bodypart/leg/right/mutant/ghoul + human_ghoul.ReassignForeignBodyparts() + +/datum/species/ghoul/on_species_loss(mob/living/carbon/human/former_ghoul, datum/species/new_species, pref_load) + . = ..() // 2) BODYPARTS - C.part_default_head = /obj/item/bodypart/head - C.part_default_chest = /obj/item/bodypart/chest - C.part_default_l_arm = /obj/item/bodypart/arm/left - C.part_default_r_arm = /obj/item/bodypart/arm/right - C.part_default_l_leg = /obj/item/bodypart/leg/left - C.part_default_r_leg = /obj/item/bodypart/leg/right - C.ReassignForeignBodyparts() + UnregisterSignal(src, COMSIG_ITEM_ATTACK) + former_ghoul.part_default_head = /obj/item/bodypart/head + former_ghoul.part_default_chest = /obj/item/bodypart/chest + former_ghoul.part_default_l_arm = /obj/item/bodypart/arm/left + former_ghoul.part_default_r_arm = /obj/item/bodypart/arm/right + former_ghoul.part_default_l_leg = /obj/item/bodypart/leg/left + former_ghoul.part_default_r_leg = /obj/item/bodypart/leg/right + former_ghoul.ReassignForeignBodyparts() /* * ATTACK PROCS @@ -157,40 +158,43 @@ target.add_splatter_floor(target.loc) target.bleed(60) - return TRUE - return ..() + return COMPONENT_CANCEL_ATTACK_CHAIN -/datum/species/ghoul/proc/handle_limb_mashing() +/datum/species/ghoul/proc/attach_meat(obj/item/attacking_item, mob/living/carbon/human/target, mob/living/user, params) SIGNAL_HANDLER -/datum/species/ghoul/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, mob/living/carbon/human/H, modifiers) - handle_limb_mashing() - // MEAT LIMBS: If our limb is missing, and we're using meat, stick it in! - if(LAZYACCESS(modifiers, RIGHT_CLICK)) + if(!istype(target)) + return + + if(LAZYACCESS(params2list(params), RIGHT_CLICK)) return - if(H.stat < DEAD && !affecting && istype(I, /obj/item/food/meat/slab)) + + // MEAT LIMBS: If our limb is missing, and we're using meat, stick it in! + if(target.stat < DEAD && istype(attacking_item, /obj/item/food/meat/slab)) var/target_zone = user.zone_selected + + if(target.get_bodypart(target_zone)) // we already have a limb here + return + var/list/limbs = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) if((target_zone in limbs)) - if(user == H) - user.visible_message("[user] begins mashing [I] into [H]'s torso.", span_notice("You begin mashing [I] into your torso.")) + if(user == target) + user.visible_message("[user] begins mashing [attacking_item] into [target]'s torso.", span_notice("You begin mashing [attacking_item] into your torso.")) else - user.visible_message("[user] begins mashing [I] into [H]'s torso.", span_notice("You begin mashing [I] into [H]'s torso.")) + user.visible_message("[user] begins mashing [attacking_item] into [target]'s torso.", span_notice("You begin mashing [attacking_item] into [target]'s torso.")) // Leave Melee Chain (so deleting the meat doesn't throw an error) <--- aka, deleting the meat that called this very proc. spawn(1) - if(do_after(user, 3 SECONDS, H)) + if(do_after(user, 3 SECONDS, target)) // Attach the part! - var/obj/item/bodypart/newBP = H.newBodyPart(target_zone, FALSE) - H.visible_message("The meat sprouts digits and becomes [H]'s new [newBP.name]!", span_notice("The meat sprouts digits and becomes your new [newBP.name]!")) - newBP.try_attach_limb(H) - qdel(I) - playsound(get_turf(H), 'sound/effects/meatslap.ogg', 50, 1) - - return TRUE // True CANCELS the sequence. + var/obj/item/bodypart/newBP = target.newBodyPart(target_zone, FALSE) + target.visible_message("The meat sprouts digits and becomes [target]'s new [newBP.name]!", span_notice("The meat sprouts digits and becomes your new [newBP.name]!")) + newBP.try_attach_limb(target) + qdel(attacking_item) + playsound(get_turf(target), 'sound/effects/meatslap.ogg', 50, 1) - return ..() // TRUE FALSE + return COMPONENT_CANCEL_ATTACK_CHAIN /mob/living/carbon // Type References for Bodyparts diff --git a/modular_skyrat/modules/gladiator/code/game/objects/items/gladiator_items.dm b/modular_skyrat/modules/gladiator/code/game/objects/items/gladiator_items.dm index cf74a0d6dd2..91c4cd461b7 100644 --- a/modular_skyrat/modules/gladiator/code/game/objects/items/gladiator_items.dm +++ b/modular_skyrat/modules/gladiator/code/game/objects/items/gladiator_items.dm @@ -173,18 +173,18 @@ duration = 1 SECONDS // worth tweaking? /datum/status_effect/dodgeroll_iframes/on_apply() - RegisterSignal(owner, COMSIG_HUMAN_CHECK_SHIELDS, PROC_REF(whiff)) + RegisterSignal(owner, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(whiff)) return TRUE /datum/status_effect/dodgeroll_iframes/on_remove() - UnregisterSignal(owner, COMSIG_HUMAN_CHECK_SHIELDS) + UnregisterSignal(owner, COMSIG_LIVING_CHECK_BLOCK) return ..() /datum/status_effect/dodgeroll_iframes/proc/whiff() SIGNAL_HANDLER owner.balloon_alert_to_viewers("MISS!") playsound(src, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) - return SHIELD_BLOCK + return SUCCESSFUL_BLOCK /obj/item/claymore/dragonslayer/very_fucking_loud name = "\proper Tempered Dragonslayer" diff --git a/modular_skyrat/modules/moretraitoritems/code/pirate.dm b/modular_skyrat/modules/moretraitoritems/code/pirate.dm index c3f2f2ea006..b11db59ab8e 100644 --- a/modular_skyrat/modules/moretraitoritems/code/pirate.dm +++ b/modular_skyrat/modules/moretraitoritems/code/pirate.dm @@ -25,11 +25,11 @@ . = ..() if(!(slot & ITEM_SLOT_OCLOTHING)) return - RegisterSignal(user, COMSIG_HUMAN_CHECK_SHIELDS, PROC_REF(armor_reaction)) + RegisterSignal(user, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(armor_reaction)) /obj/item/clothing/suit/jacket/det_suit/noir/heister/proc/armor_reaction(mob/living/carbon/human/owner, atom/movable/hitby, damage = 0, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0) if(SEND_SIGNAL(src, COMSIG_ITEM_HIT_REACT, owner, hitby, attack_text, 0, damage, attack_type) & COMPONENT_HIT_REACTION_BLOCK) - return SHIELD_BLOCK + return SUCCESSFUL_BLOCK return NONE /obj/item/clothing/gloves/latex/nitrile/heister diff --git a/modular_skyrat/modules/xenos_skyrat_redo/code/human_defense.dm b/modular_skyrat/modules/xenos_skyrat_redo/code/human_defense.dm index 7c8394fc5f3..5f71d1710ab 100644 --- a/modular_skyrat/modules/xenos_skyrat_redo/code/human_defense.dm +++ b/modular_skyrat/modules/xenos_skyrat_redo/code/human_defense.dm @@ -11,7 +11,7 @@ if(mob_held_item) - if(check_shields(user, 0, "[user.name]")) + if(check_block(user, charge_damage = 0, name = "[user.name]")) playsound(loc, 'sound/weapons/parry.ogg', 25, TRUE, -1) //Audio feedback to the fact you just got blocked apply_damage(disarm_damage / 2, STAMINA) visible_message(span_danger("[user] attempts to touch [src]!"), \ diff --git a/tgstation.dme b/tgstation.dme index 321364fc955..e600dfaae77 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1445,6 +1445,7 @@ #include "code\datums\elements\cult_halo.dm" #include "code\datums\elements\curse_announcement.dm" #include "code\datums\elements\cursed.dm" +#include "code\datums\elements\damage_threshold.dm" #include "code\datums\elements\dangerous_surgical_removal.dm" #include "code\datums\elements\death_drops.dm" #include "code\datums\elements\death_explosion.dm"