Files
goonstation-2016/code/mob/melee_attack_procs.dm
2016-03-06 20:52:14 +01:00

923 lines
31 KiB
Plaintext

// Contains:
// - Help procs
// - Grab procs
// - Disarm procs
// - Harm procs
// - Helper procs:
// -- attackResult datum [This is where the magic happens.]
// -- Targeting checks
// -- Calculate damage
// -- Target damage modifiers
// -- After attack
///////////////////////////////////////////////// Help intent //////////////////////////////////////////////
/mob/proc/do_help(var/mob/living/M)
if (!istype(M))
return
if (M.health <= 0 && src.health >= -75.0)
if (src == M && src.is_bleeding())
src.staunch_bleeding(M) // if they've got SOMETHING to do let's not just harass them for trying to do CPR on themselves
else
src.administer_CPR(M)
else if (src.is_bleeding())
src.staunch_bleeding(M)
else if (src.health > 0)
src.shake_awake(M)
/mob/proc/shake_awake(var/mob/living/target)
if (!src || !target)
return 0
if (istype(target,/mob/living/carbon/human/))
var/mob/living/carbon/human/H = target
if (H)
H.add_fingerprint(src) // Just put 'em on the mob itself, like pulling does. Simplifies forensic analysis a bit (Convair880).
target.asleep = 0
target.sleeping = 0
target.resting = 0
target.paralysis = max(0,target.paralysis - 3)
target.paralysis = max(0,target.stunned - 3)
target.paralysis = max(0,target.weakened - 3)
playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
src.visible_message("<span style=\"color:blue\">[src] shakes [target], trying to wake them up!</span>")
target.hit_twitch()
/mob/proc/administer_CPR(var/mob/living/carbon/human/target)
boutput(src, "<span style=\"color:red\">You have no idea how to perform CPR.</span>")
return
/mob/living/carbon/human/administer_CPR(var/mob/living/carbon/human/target)
if (!src || !target)
return 0
if (src == target) // :I
boutput(src, "<span style=\"color:red\">You desperately try to think of a way to do CPR on yourself, but it's just not logically possible!</span>")
return
if (target.head && (target.head.c_flags & 4))
boutput(src, "<span style=\"color:blue\">You need to take off their headgear before you can give CPR!</span>")
return
if (target.wear_mask && !(target.wear_mask.c_flags & 32))
boutput(src, "<span style=\"color:blue\">You need to take off their facemask before you can give CPR!</span>")
return
if (src.head && (src.head.c_flags & 4))
boutput(src, "<span style=\"color:blue\">You need to take off your headgear before you can give CPR!</span>")
return
if (src.wear_mask && !(src.wear_mask.c_flags & 32))
boutput(src, "<span style=\"color:blue\">You need to take off your facemask before you can give CPR!</span>")
return
if (target.cpr_time >= world.time + 3)
return
src.visible_message("<span style=\"color:red\"><B>[src] is trying to perform CPR on [target]!</B></span>")
if (do_mob(src, target, 40))
if (target.cpr_time >= world.time + 30)
return
if (target.health < 0)
target.cpr_time = world.time
target.take_oxygen_deprivation(-15)
target.losebreath = 0
target.paralysis--
/*if(prob(50)) // this doesn't work yet
for(var/datum/ailment/disability/D in src.target.ailments)
if(istype(D,/datum/ailment/disease/heartfailure))
src.target.resistances += D.type
src.target.ailments -= D
boutput(world, "<span style=\"color:red\">CURED [D] in [src.target]</span>")
if(istype(D,/datum/ailment/disease/flatline))
src.target.resistances += D.type
src.target.ailments -= D
boutput(world, "<span style=\"color:red\">CURED [D] in [src.target]</span>")*/
src.updatehealth()
if (src)
src.visible_message("<span style=\"color:red\">[src] performs CPR on [target]!</span>")
///////////////////////////////////////////// Grab intent //////////////////////////////////////////////////////////
/mob/living/carbon/proc/grab_self()
if (!src)
return
if(istype(src.wear_mask,/obj/item/clothing/mask/moustache))
src.visible_message("<span style=\"color:red\"><B>[src] twirls [his_or_her(src)] moustache and laughs [pick_string("tweak_yo_self.txt", "moustache")]!</B></span>")
else
src.visible_message("<span style=\"color:red\"><B>[src] tweaks [his_or_her(src)] own nipples! That's [pick_string("tweak_yo_self.txt", "tweakadj")] [pick_string("tweak_yo_self.txt", "tweak")]!</B></span>")
/mob/living/proc/grab_other(var/mob/living/carbon/human/target, var/suppress_final_message = 0)
if(!src || !target)
return 0
var/mob/living/carbon/human/H = src
if (istype(H))
if (H.sims)
var/mult = H.sims.getMoodActionMultiplier()
if (mult < 0.5)
if (prob((0.5 - mult) * 200))
boutput(src, pick("<span style=\"color:red\">You're not in the mood to grab that.</span>", "<span style=\"color:red\">You don't feel like doing that.</span>"))
return
logTheThing("combat", src, target, "grabs %target% at [log_loc(src)].")
if (target)
target.add_fingerprint(src) // Just put 'em on the mob itself, like pulling does. Simplifies forensic analysis a bit (Convair880).
if (check_target_immunity(target) == 1)
playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
target.visible_message("<span style=\"color:red\"><B>[src] tries to grab [target], but can't get a good grip!</B></span>")
return
if (istype(H))
if(H.traitHolder && !H.traitHolder.hasTrait("glasscannon"))
H.process_stamina(STAMINA_GRAB_COST)
if (!target.stat && !target.weakened && !target.stunned && !target.paralysis && target.a_intent == "disarm" && target.stamina > STAMINA_DEFAULT_BLOCK_COST && prob(STAMINA_GRAB_BLOCK_CHANCE) && !target.equipped())
src.visible_message("<span style=\"color:red\"><B>[target] blocks [src]'s attempt to grab [him_or_her(target)]!</span>")
playsound(target.loc, 'sound/weapons/punchmiss.ogg', 25, 1, 1)
target.remove_stamina(STAMINA_DEFAULT_BLOCK_COST)
target.stamina_stun()
return
if (istype(H))
for (var/uid in H.pathogens)
var/datum/pathogen/P = H.pathogens[uid]
P.ongrab(target)
var/obj/item/grab/G = new /obj/item/grab(src)
G.assailant = src
src.put_in_hand(G, src.hand)
G.affecting = target
target.grabbed_by += G
playsound(target.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if (suppress_final_message != 1) // Melee-focused roles (resp. their limb datums) grab the target aggressively (Convair880).
target.visible_message("<span style=\"color:red\">[src] grabs hold of [target]!</span>")
///////////////////////////////////////////////////// Disarm intent ////////////////////////////////////////////////
/mob/proc/disarm(var/mob/living/target, var/extra_damage = 0, var/suppress_flags = 0, var/damtype = DAMAGE_BLUNT)
if (!src || !ismob(src) || !target || !ismob(target))
return
if (!isnum(extra_damage))
extra_damage = 0
if (target.melee_attack_test(src, null, null, 1) != 1)
return
var/obj/item/affecting = target.get_affecting(src)
var/datum/attackResults/disarm/msgs = calculate_disarm_attack(target, affecting, 0, 0, extra_damage)
msgs.damage_type = damtype
msgs.flush(suppress_flags)
return
// I needed a harm intent-like attack datum for some limbs (Convair880).
/mob/proc/calculate_disarm_attack(var/mob/target, var/obj/item/affecting, var/base_damage_low = 0, var/base_damage_high = 0, var/extra_damage = 0)
var/datum/attackResults/disarm/msgs = new(src)
msgs.clear(target)
msgs.valid = 1
msgs.disarm = 1
var/def_zone = null
if (istype(affecting, /obj/item/organ))
var/obj/item/organ/O = affecting
def_zone = O.organ_name
msgs.affecting = affecting
else if (istype(affecting, /obj/item/parts))
var/obj/item/parts/P = affecting
def_zone = P.slot
msgs.affecting = affecting
else if (zone_sel)
def_zone = zone_sel.selecting
msgs.affecting = def_zone
else
def_zone = "All"
msgs.affecting = def_zone
var/damage = rand(base_damage_low, base_damage_high) * extra_damage
var/mult = 1
if (damage > 0)
def_zone = target.check_target_zone(def_zone)
var/armor_mod = 0
if (def_zone == "head")
armor_mod = target.get_head_armor_modifier()
else if (def_zone == "chest")
armor_mod = target.get_chest_armor_modifier()
damage -= armor_mod
msgs.stamina_target -= max((STAMINA_DISARM_COST * 2.5) - armor_mod, 0)
var/attack_resistance = target.check_attack_resistance()
if (attack_resistance)
damage = 0
if (istext(attack_resistance))
msgs.show_message_target(attack_resistance)
msgs.damage = max(damage, 0)
if (ishuman(target))
var/mob/living/carbon/human/HT = target
if (ishuman(src))
var/mob/living/carbon/human/H = src
if (H.sims)
mult = H.sims.getMoodActionMultiplier()
var/stampart = round( ((STAMINA_MAX - HT.stamina) / 3) )
if (prob((stampart + 10) * mult))
for (var/uid in H.pathogens)
var/datum/pathogen/P = H.pathogens[uid]
var/ret = P.ondisarm(target, 1)
if (!ret)
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] shoves [target]!</B></span>"
return msgs
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] shoves [target] to the ground!</B></span>"
msgs.played_sound = 'sound/weapons/thudswoosh.ogg'
msgs.disarm_RNG_result = "shoved_down"
return msgs
var/obj/item/I = target.equipped()
if (I)
if (I.cant_other_remove)
msgs.played_sound = 'sound/weapons/punchmiss.ogg'
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] vainly tries to knock [I] out of [target]'s hand!</B></span>"
msgs.show_self.Add("<span style=\"color:red\">Something is binding [I] to [target]. You won't be able to disarm [him_or_her(target)].</span>")
msgs.show_target.Add("<span style=\"color:red\">Something is binding [I] to you. It cannot be knocked out of your hands.</span>")
else if (prob(30 * mult))
if (ishuman(src))
var/mob/living/carbon/human/H2 = src
for (var/uid in H2.pathogens)
var/datum/pathogen/P = H2.pathogens[uid]
var/ret = P.ondisarm(target, 1)
if (!ret)
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] tries to knock [I] out of [target]'s hand!</B></span>"
return msgs
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] knocks [I] out of [target]'s hand!</B></span>"
msgs.played_sound = 'sound/weapons/thudswoosh.ogg'
msgs.disarm_RNG_result = "drop_item"
else
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] tries to knock [I] out of [target]'s hand!</B></span>"
msgs.played_sound = 'sound/weapons/punchmiss.ogg'
else
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] shoves [target]!</B></span>"
msgs.played_sound = 'sound/weapons/thudswoosh.ogg'
return msgs
/mob/proc/check_block()
if (!stat && !weakened && !stunned && !paralysis && a_intent == "disarm" && prob(STAMINA_BLOCK_CHANCE) && !equipped())
return 1
return 0
/mob/living/carbon/human/check_block()
if (!stat && !weakened && !stunned && !paralysis && a_intent == "disarm" && stamina > STAMINA_DEFAULT_BLOCK_COST && prob(STAMINA_BLOCK_CHANCE) && !equipped())
return 1
return 0
/mob/proc/do_block(var/mob/attacker)
if (check_block())
visible_message("<span style=\"color:red\"><B>[src] blocks [attacker]'s attack!</span>")
playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, 1)
remove_stamina(STAMINA_DEFAULT_BLOCK_COST)
stamina_stun()
return 1
return 0
/////////////////////////////////////////////////// Harm intent ////////////////////////////////////////////////////////
/mob/living/carbon/human/proc/stun_glove_attack(var/mob/living/target)
if (!src || !target || !src.gloves)
return 0
if (src.gloves.uses > 0)
src.lastattacked = target
target.lastattacker = src
target.lastattackertime = world.time
logTheThing("combat", src, target, "touches %target% with stun gloves at [log_loc(src)].")
target.add_fingerprint(src) // Some as the other 'empty hand' melee attacks (Convair880).
src.unlock_medal("High Five!", 1)
var/datum/effects/system/spark_spread/s = unpool(/datum/effects/system/spark_spread)
s.set_up(5, 1, target.loc)
s.start()
src.gloves.uses = max(0, src.gloves.uses - 1)
if (src.gloves.uses < 1)
src.gloves.icon_state = "yellow"
src.gloves.item_state = "ygloves"
src.update_clothing() // Was missing (Convair880).
if (src.gloves.uses <= 0)
src.show_text("The gloves are no longer electrically charged.", "red")
else
src.show_text("The gloves have [src.gloves.uses]/[src.gloves.max_uses] charges left!", "red")
target.visible_message("<span style=\"color:red\"><B>[src] touches [target] with the stun gloves!</B></span>")
if (check_target_immunity(target) == 1)
target.visible_message("<span style=\"color:red\"><B>...but it has no effect whatsoever!</B></span>")
return
target.weakened = max(target.weakened,3)
target.stuttering = max(target.stuttering,5)
target.stunned = max(target.stunned,3)
else
boutput(src, "<span style=\"color:red\">The stun gloves don't have enough charge!</span>")
return
/mob/living/carbon/human/proc/melee_attack(var/mob/living/carbon/human/target)
var/datum/limb/L = equipped_limb()
if (!L)
return
L.harm(target, src) // Calls melee_attack_normal if limb datum doesn't override anything.
/mob/proc/melee_attack_normal(var/mob/living/carbon/human/target, var/extra_damage = 0, var/suppress_flags = 0, var/damtype = DAMAGE_BLUNT)
if(!src || !target)
return 0
if(!isnum(extra_damage))
extra_damage = 0
if (!target.melee_attack_test(src))
return
var/obj/item/affecting = target.get_affecting(src)
var/datum/attackResults/msgs = calculate_melee_attack(target, affecting, 2, 9, extra_damage)
msgs.damage_type = damtype
attack_effects(target, affecting)
msgs.flush(suppress_flags)
/mob/proc/calculate_melee_attack(var/mob/target, var/obj/item/affecting, var/base_damage_low = 2, var/base_damage_high = 9, var/extra_damage = 0)
var/datum/attackResults/msgs = new(src)
msgs.clear(target)
msgs.valid = 1
var/def_zone = null
if (istype(affecting, /obj/item/organ))
var/obj/item/organ/O = affecting
def_zone = O.organ_name
msgs.affecting = affecting
else if (istype(affecting, /obj/item/parts))
var/obj/item/parts/P = affecting
def_zone = P.slot
msgs.affecting = affecting
else if (zone_sel)
def_zone = zone_sel.selecting
msgs.affecting = def_zone
else
def_zone = "All"
msgs.affecting = def_zone
var/punchmult = get_base_damage_multiplier(def_zone)
var/punchedmult = target.get_taken_base_damage_multiplier(src, def_zone)
if (!punchedmult)
if (narrator_mode)
msgs.played_sound = 'sound/vox/hit.ogg'
else
msgs.played_sound = 'sound/weapons/punch1.ogg'
msgs.visible_message_self("<span style=\"color:red\"><B>[src] [src.punchMessage] [target], but it does absolutely nothing!</B></span>")
return
if (!punchmult)
msgs.played_sound = 'sound/effects/snap.ogg'
msgs.visible_message_self("<span style=\"color:red\"><B>[src] hits [target] with a ridiculously feeble attack!</B></span>")
return
var/damage = rand(base_damage_low, base_damage_high) * punchedmult * punchmult + extra_damage + calculate_bonus_damage(msgs)
if (!target.canmove && target.lying)
msgs.played_sound = 'sound/weapons/genhit1.ogg'
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] [src.kickMessage] [target]!</B></span>"
msgs.logs = list("[src.kickMessage] %target%")
if(STAMINA_LOW_COST_KICK)
msgs.stamina_self += STAMINA_HTH_COST / 3
else
msgs.base_attack_message = "<span style=\"color:red\"><B>[src] [src.punchMessage] [target]!</B></span>"
msgs.played_sound = "punch"
if (src != target && iswrestler(src) && prob(66))
msgs.base_attack_message = "<span style=\"color:red\"><B>[src]</b> winds up and delivers a backfist to [target], sending them flying!</span>"
damage += 4
msgs.after_effects += /proc/wrestler_backfist
def_zone = target.check_target_zone(def_zone)
var/armor_mod = 0
if (def_zone == "head")
armor_mod = target.get_head_armor_modifier()
else if (def_zone == "chest")
armor_mod = target.get_chest_armor_modifier()
damage -= armor_mod
msgs.stamina_target -= max(STAMINA_HTH_DMG - armor_mod, 0)
if (prob(STAMINA_CRIT_CHANCE))
msgs.stamina_crit = 1
msgs.played_sound = "sound/misc/critpunch.ogg"
msgs.visible_message_target("<span style=\"color:red\"><B><I>... and lands a devastating hit!</B></I></span>")
var/attack_resistance = target.check_attack_resistance()
if (attack_resistance)
damage = 0
if (istext(attack_resistance))
msgs.show_message_target(attack_resistance)
msgs.damage = max(damage, 0)
return msgs
// This is used by certain limb datums (werewolf, shambling abomination) (Convair880).
/proc/special_attack_silicon(var/mob/target, var/mob/living/user)
if (!target || !issilicon(target) || !user || !isliving(user))
return
if (check_target_immunity(target) == 1)
playsound(user.loc, "punch", 50, 1, 1)
user.visible_message("<span style=\"color:red\"><B>[user]'s attack bounces off [target] uselessly!</B></span>")
return
var/damage = 0
var/send_flying = 0 // 1: a little bit | 2: across the room
if (isrobot(target))
var/mob/living/silicon/robot/BORG = target
if (!BORG.part_head)
user.visible_message("<span style=\"color:red\"><B>[user] smashes [BORG.name] to pieces!</B></span>")
playsound(user.loc, "sound/effects/wbreak.wav", 70, 1)
BORG.gib()
else
if (BORG.part_head.ropart_get_damage_percentage() >= 85)
user.visible_message("<span style=\"color:red\"><B>[user] grabs [BORG.name]'s head and wrenches it right off!</B></span>")
playsound(user.loc, "sound/effects/wbreak.wav", 70, 1)
BORG.compborg_lose_limb(BORG.part_head)
else
user.visible_message("<span style=\"color:red\"><B>[user] pounds on [BORG.name]'s head furiously!</B></span>")
playsound(user.loc, "sound/effects/metal_bang.ogg", 50, 1)
BORG.part_head.ropart_take_damage(rand(20,40),0)
if (!BORG.anchored && prob(30))
user.visible_message("<span style=\"color:red\"><B>...and sends them flying!</B></span>")
send_flying = 2
else if (isAI(target))
user.visible_message("<span style=\"color:red\"><B>[user] [pick("wails", "pounds", "slams")] on [target]'s terminal furiously!</B></span>")
playsound(user.loc, "sound/effects/metal_bang.ogg", 50, 1)
damage = 10
else
user.visible_message("<span style=\"color:red\"><B>[user] smashes [target] furiously!</B></span>")
playsound(user.loc, "sound/effects/metal_bang.ogg", 50, 1)
damage = 10
if (!target.anchored && prob(30))
user.visible_message("<span style=\"color:red\"><B>...and sends them flying!</B></span>")
send_flying = 2
if (send_flying == 2)
wrestler_backfist(user, target)
else if (send_flying == 1)
wrestler_knockdown(user, target)
if (damage > 0)
random_brute_damage(target, damage)
target.updatehealth()
target.UpdateDamageIcon()
logTheThing("combat", user, target, "punches %target% at [log_loc(user)].")
return
/////////////////////////////////////////////////////// attackResult datum ////////////////////////////////////////
/datum/attackResults
var/mob/owner
var/mob/target
var/list/visible_self = list()
var/list/visible_target = list()
var/list/show_self = list()
var/list/show_target = list()
var/list/logs = list("punches %target%")
var/list/after_effects = list()
// the message to play to the target
var/base_attack_message = null
// a sound to play when this attack is flushed
var/played_sound = null
var/stamina_self = 0
var/stamina_target = 0
var/stamina_crit = 0
var/damage = 0
var/damage_type = DAMAGE_BLUNT
var/obj/item/affecting = null
var/valid = 0
var/disarm = 0 // Is this a disarm as opposed to harm attack?
var/disarm_RNG_result = null // Blocked, shoved down etc.
New(var/mob/M)
owner = M
proc/clear(var/mob/M)
target = M
visible_self = list()
visible_target = list()
show_self = list()
show_target = list()
if (istype(src, /datum/attackResults/disarm))
logs = list("disarms %target%")
else
logs = list("punches %target%")
played_sound = null
base_attack_message = null
stamina_self = 0
stamina_target = 0
stamina_crit = 0
damage = 0
damage_type = DAMAGE_BLUNT
affecting = null
valid = 0
disarm = 0
disarm_RNG_result = null
after_effects = list()
proc/show_message_self(var/message)
show_self += message
proc/show_message_target(var/message)
show_target += message
proc/visible_message_self(var/message)
visible_self += message
proc/visible_message_target(var/message)
visible_target += message
proc/logc(var/message)
logs += message
// I worked disarm into this because I needed a more detailed disarm proc and didn't want to reinvent the wheel or repeat a bunch of code (Convair880).
proc/flush(var/suppress = 0)
if (!target)
clear(null)
logTheThing("debug", owner, null, "<b>Marquesas/Melee Attack Refactor:</b> NO TARGET FLUSH! EMERGENCY!")
return
if (!affecting)
clear(null)
logTheThing("debug", owner, null, "<b>Marquesas/Melee Attack Refactor:</b> NO AFFECTING FLUSH! WARNING!")
return
if (!(suppress & SUPPRESS_SOUND) && played_sound)
playsound(owner.loc, played_sound, 50, 1, -1)
if (!(suppress & SUPPRESS_BASE_MESSAGE) && base_attack_message)
owner.visible_message(base_attack_message)
if (!(suppress & SUPPRESS_SHOWN_MESSAGES))
for (var/message in show_self)
owner.show_message(message)
for (var/message in visible_self)
owner.visible_message(message)
if (!(suppress & SUPPRESS_SHOWN_MESSAGES))
for (var/message in visible_target)
target.visible_message(message)
for (var/message in show_target)
target.show_message(message)
if (!(suppress & SUPPRESS_LOGS))
for (var/message in logs)
logTheThing("combat", owner, target, "[message] at [log_loc(owner)].")
if (stamina_self)
if (stamina_self > 0)
owner.add_stamina(stamina_self)
else
owner.remove_stamina(-stamina_self)
if (src.disarm == 1)
target.add_fingerprint(owner)
if (owner.traitHolder && !owner.traitHolder.hasTrait("glasscannon"))
owner.process_stamina(STAMINA_DISARM_COST)
if (!isnull(src.disarm_RNG_result))
switch (src.disarm_RNG_result)
if ("drop_item")
target.deliver_move_trigger("bump")
target.drop_item()
if ("shoved_down")
target.deliver_move_trigger("pushdown")
target.drop_item()
target.weakened = 2
else
target.deliver_move_trigger("bump")
else
if (owner.traitHolder && !owner.traitHolder.hasTrait("glasscannon"))
owner.process_stamina(STAMINA_HTH_COST)
#ifdef DATALOGGER
game_stats.Increment("violence")
#endif
owner.lastattacked = target
target.lastattacker = owner
target.lastattackertime = world.time
target.add_fingerprint(owner)
if (damage > 0 || src.disarm == 1)
if (src.disarm == 1 && damage <= 0)
goto process_stamina
// important
target.abuse_clown()
if (damage_type == DAMAGE_BLUNT && prob(25 + (damage * 2)) && damage >= 8)
damage_type = DAMAGE_CRUSH
if (damage_type == DAMAGE_BURN)
if (istype(affecting))
affecting.take_damage(0, damage, 0, damage_type)
else if (affecting)
target.TakeDamage(affecting, 0, damage, 0, damage_type)
else
target.TakeDamage("chest", 0, damage, 0, damage_type)
else
if (istype(affecting))
affecting.take_damage(damage, 0, 0, damage_type)
else if (affecting)
target.TakeDamage(affecting, damage, 0, 0, damage_type)
else
target.TakeDamage("chest", damage, 0, 0, damage_type)
if (damage_type & (DAMAGE_CUT | DAMAGE_STAB))
take_bleeding_damage(target, owner, damage, damage_type)
target.spread_blood_clothes(target)
owner.spread_blood_hands(target)
if (prob(15))
owner.spread_blood_clothes(target)
for (var/P in after_effects)
call(P)(owner, target)
process_stamina
if (stamina_target)
if (stamina_target > 0)
target.add_stamina(stamina_target)
else
var/prev_stam = target.get_stamina()
target.remove_stamina(-stamina_target)
target.stamina_stun()
if(prev_stam > 0 && target.get_stamina() <= 0) //We were just knocked out.
target.set_clothing_icon_dirty()
target.lastgasp()
if (istype(ticker.mode, /datum/game_mode/revolution))
var/datum/game_mode/revolution/R = ticker.mode
R.remove_revolutionary(target.mind)
if (stamina_crit)
target.handle_stamina_crit()
if (src.disarm != 1)
owner.attack_finished(target)
target.attackby_finished(owner)
target.UpdateDamageIcon()
target.updatehealth()
clear(null)
/datum/attackResults/disarm
logs = list("disarms %target%")
////////////////////////////////////////////////////////// Targeting checks ////////////////////////////////////
/mob/proc/melee_attack_test(var/mob/attacker, var/obj/item/I, var/def_zone, var/disarm_check = 0)
if (check_target_immunity(src) == 1)
playsound(loc, "punch", 50, 1, 1)
src.visible_message("<span style=\"color:red\"><B>[attacker]'s attack bounces off [src] uselessly!</B></span>")
return 0
if (disarm_check == 1 && (ishuman(src) && src.lying == 1))
src.visible_message("<span style=\"color:red\"><B>[attacker]</B> makes a threatening gesture at [src]!</span>")
return 0
return 1
/mob/living/silicon/robot/melee_attack_test(var/mob/attacker, var/obj/item/I, var/def_zone, var/disarm_check = 0)
if (!..())
return 0
if (I)
var/hit_chance = 50
if (def_zone == "chest")
hit_chance = 90
else if (def_zone == "head")
hit_chance = 70
if(!client || stat || paralysis || stunned || weakened)
hit_chance = 100
if (!prob(hit_chance))
playsound(loc, "sound/weapons/punchmiss.ogg", 50, 1, 1)
src.visible_message("<span style=\"color:red\"><b>[attacker] swings at [src] with [I], but misses!</b></span>")
return 0
return 1
/mob/living/carbon/human/melee_attack_test(var/mob/attacker, var/obj/item/I, var/def_zone, var/disarm_check = 0)
if (!..())
return 0
if (src.do_block(attacker))
return 0
return 1
/mob/proc/get_affecting(mob/attacker, def_zone = null)
if (def_zone)
return def_zone
var/t = pick("head", "chest")
if(attacker.zone_sel)
t = attacker.zone_sel.selecting
return t
/mob/living/carbon/human/get_affecting(mob/attacker, def_zone = null)
var/t = pick("head", "chest")
if(def_zone)
t = def_zone
else if(attacker.zone_sel)
t = attacker.zone_sel.selecting
var/r_zone = ran_zone(t)
var/obj/item/affecting = organs["chest"]
if (organs[text("[]", r_zone)])
affecting = organs[text("[]", r_zone)]
return affecting
/mob/proc/check_target_zone(var/def_zone)
return def_zone
/mob/living/carbon/human/check_target_zone(var/def_zone)
if (limbs && !limbs.l_arm && def_zone == "l_arm")
return "chest"
if (limbs && !limbs.r_arm && def_zone == "r_arm")
return "chest"
return def_zone
////////////////////////////////////////////////////// Calculate damage //////////////////////////////////////////
/mob/proc/get_base_damage_multiplier()
return 1
/mob/living/carbon/human/get_base_damage_multiplier(var/def_zone)
var/punchmult = 1
for (var/uid in src.pathogens)
var/datum/pathogen/P = src.pathogens[uid]
punchmult *= P.onpunch(target, def_zone)
if (sims)
punchmult *= sims.getMoodActionMultiplier()
return punchmult
/mob/proc/get_taken_base_damage_multiplier()
return 1
/mob/living/carbon/human/get_taken_base_damage_multiplier(var/mob/attacker, var/def_zone)
var/punchedmult = 1
for (var/uid in src.pathogens)
var/datum/pathogen/P = src.pathogens[uid]
punchedmult *= P.onpunched(attacker, def_zone)
return punchedmult
/mob/proc/calculate_bonus_damage(var/datum/attackResults/msgs)
return 0
/mob/living/carbon/human/calculate_bonus_damage(var/datum/attackResults/msgs)
var/damage = 0
if (src.gloves)
damage += src.gloves.damage_bonus()
if (src.reagents && (src.reagents.get_reagent_amount("ethanol") >= 100) && prob(40))
damage += rand(3,5)
if (msgs)
msgs.show_message_self("<span style=\"color:red\">You drunkenly throw a brutal punch!</span>")
if (src.bioHolder.HasEffect("hulk"))
damage += 5
return damage
/////////////////////////////////////////////////////// Target damage modifiers //////////////////////////////////
/mob/proc/check_attack_resistance(var/obj/item/I)
return null
/mob/living/silicon/robot/check_attack_resistance(var/obj/item/I)
if (!I)
return "<span style=\"color:red\">Sensors indicate no damage from external impact.</span>"
return null
/mob/living/carbon/human/check_attack_resistance(var/obj/item/I)
if (reagents.get_reagent_amount("ethanol") >= 100 && prob(40) && (!I || I.force <= 15))
return "<span style=\"color:red\">You drunkenly shrug off the blow!</span>"
return null
/mob/proc/get_head_armor_modifier()
return 0
/mob/living/carbon/human/get_head_armor_modifier()
if (client && client.hellbanned)
return 0
if ((head && head.body_parts_covered & HEAD) || (wear_mask && wear_mask.body_parts_covered & HEAD))
if (head && !wear_mask)
return max(0, head.armor_value_melee)
else if (!head && wear_mask)
return max(0, wear_mask.armor_value_melee)
else if (head && wear_mask)
return max(0, max(head.armor_value_melee, wear_mask.armor_value_melee))
return 0
/mob/proc/get_chest_armor_modifier()
return 0
/mob/living/carbon/human/get_chest_armor_modifier()
if (client && client.hellbanned)
return 0
if ((wear_suit && wear_suit.body_parts_covered & TORSO) || (w_uniform && w_uniform.body_parts_covered & TORSO))
if (wear_suit && !w_uniform)
return max(0, wear_suit.armor_value_melee)
else if (!wear_suit && w_uniform)
return max(0, w_uniform.armor_value_melee)
else if (wear_suit && w_uniform)
return max(0, max(w_uniform.armor_value_melee, wear_suit.armor_value_melee))
return 0
/////////////////////////////////////////////////////////// After attack ////////////////////////////////////////////
/mob/proc/attack_effects(var/target, var/obj/item/affecting)
return
/mob/living/carbon/human/attack_effects(var/mob/target, var/obj/item/affecting)
if (src.bioHolder.HasEffect("hulk"))
spawn(0)
target.stunned += 1
step_away(target,src,15)
sleep(3)
step_away(target,src,15)
if (src.bioHolder.HasEffect("revenant"))
var/datum/bioEffect/hidden/revenant/R = src.bioHolder.GetEffect("revenant")
if (R.ghoulTouchActive)
R.ghoulTouch(target, affecting)
/proc/wrestler_knockdown(var/mob/H, var/mob/T)
if (!H || !ismob(H) || !T || !ismob(T))
return
T.weakened += rand(2,3)
spawn(0)
step_away(T, H, 15)
return
/proc/wrestler_backfist(var/mob/H, var/mob/T)
if (!H || !ismob(H) || !T || !ismob(T))
return
T.weakened += rand(5,6)
var/turf/throwpoint = get_edge_target_turf(H, get_dir(H, T))
if (throwpoint && isturf(throwpoint))
spawn(0)
T.throw_at(throwpoint, 10, 2)
return
/mob/proc/attack_finished(var/mob/target)
return
/mob/living/carbon/human/attack_finished(var/mob/target)
if (sims)
sims.affectMotive("fun", 5)
/mob/proc/attackby_finished(var/mob/attacker)
return
/mob/living/carbon/human/attackby_finished(var/mob/attacker)
if (sims)
if (istype(gloves, /obj/item/clothing/gloves/boxing))
sims.affectMotive("fun", 2.5)