mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 04:30:44 +01:00
Mob attackedby / check_block refactor, plus some minor cleanup of attack_x procs (#79563)
## About The Pull Request - Deletes `spec_attacked_by` - Elements simple/basic mob attack threshold - There was a skeleton mob that "mimics armor" but didn't use the actual mimicing armor thing we have, so I changed that. - Moves `check_shields` down to the living level, renames it to `check_block` - Martial art blocking is now signalized (only CQC uses it anyways) - Cleaned up a bit of `attack_x` procs, but not a lot. Should have an entire PR dedicated to this .... mess. - Deprecates `/obj/item/melee` ## Why It's Good For The Game Second verse, same as the first. - Less bad species related procs. - Largely brings a lot of code in line, making combat more consistent across types. - Makes it a lot easier to add new code relating to blocking or taking damage. ## Changelog 🆑 Melbert refactor: Refactored another large chuck of attack code, primarily involving melee item attacks and non-human mob attacks. Report if you see anything weird fix: Pacifists clicking on simple robots or silicons no longer causes sparks fix: Blocked thrown batons are now properly... blocked /🆑
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
+143
-21
@@ -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
|
||||
add_splatter_floor(get_turf(src))
|
||||
if(get_dist(attacker, src) <= 1)
|
||||
attacker.add_mob_blood(src)
|
||||
return TRUE
|
||||
|
||||
/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 ..()
|
||||
return FALSE
|
||||
|
||||
/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 ..()
|
||||
/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 + ((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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!"))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -90,46 +90,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"
|
||||
|
||||
@@ -257,7 +224,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
|
||||
@@ -265,18 +243,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
|
||||
|
||||
/**
|
||||
|
||||
@@ -1121,11 +1121,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)
|
||||
@@ -1136,11 +1131,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
|
||||
@@ -1231,11 +1221,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)
|
||||
@@ -1256,7 +1241,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)
|
||||
@@ -1273,115 +1258,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 + ((100 - human.health) * 0.5))) // rev deconversion through blunt trauma.
|
||||
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 //
|
||||
//////////////////////////
|
||||
|
||||
@@ -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)
|
||||
var/block_chance_modifier = round(damage / -3)
|
||||
|
||||
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))
|
||||
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)
|
||||
/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
|
||||
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))
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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,17 +179,12 @@
|
||||
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
|
||||
|
||||
/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
|
||||
@@ -306,7 +246,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)
|
||||
@@ -314,22 +254,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
|
||||
@@ -342,7 +266,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))
|
||||
|
||||
@@ -159,35 +159,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)
|
||||
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
|
||||
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
|
||||
blocked = TRUE
|
||||
else
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1) //Item sounds are handled in the item itself
|
||||
return ..()
|
||||
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1) //Item sounds are handled in the item itself
|
||||
var/obj/item/thrown_item = AM
|
||||
if(thrown_item.thrownby == WEAKREF(src)) //No throwing stuff at yourself to trigger hit reactions
|
||||
return ..()
|
||||
|
||||
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()
|
||||
@@ -272,10 +286,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()
|
||||
@@ -285,6 +295,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)
|
||||
@@ -293,30 +306,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)
|
||||
@@ -330,6 +381,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)
|
||||
@@ -350,6 +403,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")
|
||||
@@ -369,7 +426,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))
|
||||
@@ -383,29 +443,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)
|
||||
..()
|
||||
@@ -567,3 +632,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -326,20 +326,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -1347,6 +1347,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"
|
||||
|
||||
Reference in New Issue
Block a user