diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 093975051b..94f9b7774d 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -3,6 +3,10 @@
/obj/item/proc/attack_self(mob/user)
return
+/obj/item/proc/resolve_attackby(atom/A, mob/source)
+ add_fingerprint(source)
+ return A.attackby(src,source)
+
// No comment
/atom/proc/attackby(obj/item/W, mob/user)
return
@@ -12,29 +16,23 @@
visible_message("[src] has been hit by [user] with [W].")
/mob/living/attackby(obj/item/I, mob/user)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
- if(istype(I) && ismob(user))
- I.attack(src, user)
-
+ if(!ismob(user))
+ return 0
+ if(can_operate(src) && do_surgery(src,user,I)) //Surgery
+ return 1
+ if(istype(I))
+ return I.attack(src, user, user.zone_sel.selecting)
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
// Click parameters is the params string from byond Click() code, see that documentation.
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
return
-//TODO: refactor mob attack code.
-/*
-Busy writing something else that I don't want to get mixed up in a general attack code, and I don't want to forget this so leaving a note here.
-leave attackby() as handling the general case of "using an item on a mob"
-attackby() will decide to call attacked_by() or not.
-attacked_by() will be made a living level proc and handle the specific case of "attacking with an item to cause harm"
-attacked_by() will then call attack() so that stunbatons and other weapons that have special attack effects can do their thing.
-attacked_by() will handle hitting/missing/logging as it does now, and will call attack() to apply the attack effects (damage) instead of the other way around (as it is now).
-*/
-
-/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
-
- if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0
+/obj/item/proc/attack(mob/living/M, mob/living/user, def_zone)
+ if(!istype(M))
+ return 0
+ if(!force || (flags & NOBLUDGEON))
+ return 0
/////////////////////////
user.lastattacked = M
@@ -46,50 +44,19 @@ attacked_by() will handle hitting/missing/logging as it does now, and will call
msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
/////////////////////////
- // Attacking someone with a weapon while they are neck-grabbed
- if(user.a_intent == I_HURT)
- for(var/obj/item/weapon/grab/G in M.grabbed_by)
- if(G.assailant == user && G.state >= GRAB_NECK)
- M.attack_throat(src, G, user)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.do_attack_animation(M)
+ M.attacked_with_item(src, user, def_zone)
+ return 1
+
+//Called when a weapon is used to make a successful melee attack on a mob.
+/obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
+ if(hitsound)
+ playsound(loc, hitsound, 50, 1, -1)
+
var/power = force
if(HULK in user.mutations)
power *= 2
+ return target.hit_with_weapon(src, user, power, hit_zone)
- // TODO: needs to be refactored into a mob/living level attacked_by() proc. ~Z
- user.do_attack_animation(M)
- user.break_cloak()
- if(istype(M, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = M
-
- // Handle striking to cripple.
- var/dislocation_str
- if(user.a_intent == I_DISARM)
- dislocation_str = H.attack_joint(src, user, def_zone)
- if(H.attacked_by(src, user, def_zone) && hitsound)
- playsound(loc, hitsound, 50, 1, -1)
- spawn(1) //ugh I hate this but I don't want to root through human attack procs to print it after this call resolves.
- if(dislocation_str) user.visible_message("[dislocation_str]")
- return 1
- return 0
- else
- if(attack_verb.len)
- user.visible_message("[M] has been [pick(attack_verb)] with [src] by [user]!")
- else
- user.visible_message("[M] has been attacked with [src] by [user]!")
-
- if (hitsound)
- playsound(loc, hitsound, 50, 1, -1)
- switch(damtype)
- if("brute")
- M.take_organ_damage(power)
- if(prob(33)) // Added blood for whacking non-humans too
- var/turf/simulated/location = get_turf(M)
- if(istype(location)) location.add_blood_floor(M)
- if("fire")
- if (!(COLD_RESISTANCE in M.mutations))
- M.take_organ_damage(0, power)
- M << "Aargh it burns!"
- M.updatehealth()
- add_fingerprint(user)
- return 1
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 2493e29609..9b40cf4e8c 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -633,6 +633,3 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
/obj/item/proc/pwr_drain()
return 0 // Process Kill
-/obj/item/proc/resolve_attackby(atom/A, mob/source)
- return A.attackby(src,source)
-
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 7c17c58467..8528033f52 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -242,40 +242,23 @@
if(user.a_intent == I_HURT)
- // This is being copypasted here because reagent_containers (WHY DOES FOOD DESCEND FROM THAT) overrides it completely.
- // TODO: refactor all food paths to be less horrible and difficult to work with in this respect. ~Z
- if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0
+ if(!istype(M))
+ return 0
+ if(!force || (flags & NOBLUDGEON))
+ return 0
+ /////////////////////////
user.lastattacked = M
M.lastattacker = user
- user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])"
- M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])"
- msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
- if(istype(M, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = M
- var/hit = H.attacked_by(src, user, def_zone)
- if(hit && hitsound)
- playsound(loc, hitsound, 50, 1, -1)
- return hit
- else
- if(attack_verb.len)
- user.visible_message("[M] has been [pick(attack_verb)] with [src] by [user]!")
- else
- user.visible_message("[M] has been attacked with [src] by [user]!")
+ if(!no_attack_log)
+ user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])"
+ M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])"
+ msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
+ /////////////////////////
- if (hitsound)
- playsound(loc, hitsound, 50, 1, -1)
- switch(damtype)
- if("brute")
- M.take_organ_damage(force)
- if(prob(33))
- var/turf/simulated/location = get_turf(M)
- if(istype(location)) location.add_blood_floor(M)
- if("fire")
- if (!(COLD_RESISTANCE in M.mutations))
- M.take_organ_damage(0, force)
- M.updatehealth()
+ user.do_attack_animation(M)
+ M.attacked_with_item(src, user, def_zone)
if(seed && seed.get_trait(TRAIT_STINGS))
if(!reagents || reagents.total_volume <= 0)
diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm
index 5679cc1a46..5eceb7c7ba 100644
--- a/code/modules/mob/living/bot/bot.dm
+++ b/code/modules/mob/living/bot/bot.dm
@@ -337,3 +337,4 @@
//if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID)
else return !D.check_access(ID) // it's a real, air blocking door
return 0
+
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
new file mode 100644
index 0000000000..933ec801ca
--- /dev/null
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -0,0 +1,98 @@
+
+//Called when the mob is hit with an item in combat.
+/mob/living/carbon/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone)
+ if(check_attack_throat(I, user))
+ return
+ ..()
+
+/mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone)
+ if(!effective_force || blocked >= 2)
+ return 0
+
+ //Hulk modifier
+ if(HULK in user.mutations)
+ effective_force *= 2
+
+ //Apply weapon damage
+ var/weapon_sharp = is_sharp(I)
+ var/weapon_edge = has_edge(I)
+ if(prob(getarmor(hit_zone, "melee"))) //melee armour provides a chance to turn sharp/edge weapon attacks into blunt ones
+ weapon_sharp = 0
+ weapon_edge = 0
+
+ apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I)
+
+ //Melee weapon embedded object code.
+ if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I))
+ var/damage = effective_force
+ if (blocked)
+ damage /= blocked+1
+
+ //blunt objects should really not be embedding in things unless a huge amount of force is involved
+ var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3)
+ var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class
+
+ //Sharp objects will always embed if they do enough damage.
+ if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance)))
+ src.embed(I, hit_zone)
+
+ return 1
+
+// Attacking someone with a weapon while they are neck-grabbed
+/mob/living/carbon/proc/check_attack_throat(obj/item/W, mob/user)
+ if(user.a_intent == I_HURT)
+ for(var/obj/item/weapon/grab/G in src.grabbed_by)
+ if(G.assailant == user && G.state >= GRAB_NECK)
+ if(attack_throat(W, G, user))
+ return 1
+ return 0
+
+// Knifing
+/mob/living/carbon/proc/attack_throat(obj/item/W, obj/item/weapon/grab/G, mob/user)
+
+ if(!W.edge || !W.force || W.damtype != BRUTE)
+ return 0 //unsuitable weapon
+
+ user.visible_message("\The [user] begins to slit [src]'s throat with \the [W]!")
+
+ user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly
+ if(!do_after(user, 20))
+ return 0
+ if(!(G && G.assailant == user && G.affecting == src)) //check that we still have a grab
+ return 0
+
+ var/damage_mod = 1
+ //presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well
+ var/obj/item/clothing/head/helmet = get_equipped_item(slot_head)
+ if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.flags & STOPPRESSUREDAMAGE))
+ //we don't do an armor_check here because this is not an impact effect like a weapon swung with momentum, that either penetrates or glances off.
+ damage_mod = 1.0 - (helmet.armor["melee"]/100)
+
+ var/total_damage = 0
+ for(var/i in 1 to 3)
+ var/damage = min(W.force*1.5, 20)*damage_mod
+ apply_damage(damage, W.damtype, "head", 0, sharp=W.sharp, edge=W.edge)
+ total_damage += damage
+
+ var/oxyloss = total_damage
+ if(total_damage >= 40) //threshold to make someone pass out
+ oxyloss = 60 // Brain lacks oxygen immediately, pass out
+
+ adjustOxyLoss(min(oxyloss, 100 - getOxyLoss())) //don't put them over 100 oxyloss
+
+ if(total_damage)
+ if(oxyloss >= 40)
+ user.visible_message("\The [user] slit [src]'s throat open with \the [W]!")
+ else
+ user.visible_message("\The [user] cut [src]'s neck with \the [W]!")
+
+ if(W.hitsound)
+ playsound(loc, W.hitsound, 50, 1, -1)
+
+ G.last_action = world.time
+ flick(G.hud.icon_state, G.hud)
+
+ user.attack_log += "\[[time_stamp()]\] Knifed [name] ([ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])"
+ src.attack_log += "\[[time_stamp()]\] Got knifed by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])"
+ msg_admin_attack("[key_name(user)] knifed [key_name(src)] with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" )
+ return 1
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm
index a38e516acf..1d61cd6d0e 100644
--- a/code/modules/mob/living/carbon/human/human_attackhand.dm
+++ b/code/modules/mob/living/carbon/human/human_attackhand.dm
@@ -310,23 +310,6 @@
updatehealth()
return 1
-/mob/living/carbon/human/proc/attack_joint(var/obj/item/W, var/mob/living/user, var/def_zone)
- if(!def_zone) def_zone = user.zone_sel.selecting
- var/target_zone = get_zone_with_miss_chance(check_zone(def_zone), src)
-
- if(user == src) // Attacking yourself can't miss
- target_zone = user.zone_sel.selecting
- if(!target_zone)
- return null
- var/obj/item/organ/external/organ = get_organ(check_zone(target_zone))
- if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1))
- return null
- var/dislocation_str
- if(prob(W.force))
- dislocation_str = "[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!"
- organ.dislocate(1)
- return dislocation_str
-
//Used to attack a joint through grabbing
/mob/living/carbon/human/proc/grab_joint(var/mob/living/user, var/def_zone)
var/has_grab = 0
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 105d7be9bd..accfed5513 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -139,67 +139,75 @@ emp_act
if(.) return
return 0
-//Returns 1 if the attack hit, 0 if it missed.
-/mob/living/carbon/human/proc/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone)
- if(!I || !user) return 0
+/mob/living/carbon/human/emp_act(severity)
+ for(var/obj/O in src)
+ if(!O) continue
+ O.emp_act(severity)
+ ..()
- var/target_zone = def_zone? check_zone(def_zone) : get_zone_with_miss_chance(user.zone_sel.selecting, src)
+/mob/living/carbon/human/attacked_with_item(obj/item/I, mob/living/user, var/target_zone)
+ if(!I || !user)
+ return
- if(user == src) // Attacking yourself can't miss
- target_zone = user.zone_sel.selecting
- if(!target_zone)
- visible_message("[user] misses [src] with \the [I]!")
- return 0
+ if(check_attack_throat(I, user))
+ return
- var/obj/item/organ/external/affecting = get_organ(target_zone)
+ var/hit_zone = target_zone
+ if(user != src) // Attacking yourself can't miss
+ hit_zone = get_zone_with_miss_chance(target_zone, src)
+ if(!hit_zone)
+ visible_message("\The [user] misses [src] with \the [I]!")
+ return
+
+ if(check_shields(I.force, I, user, target_zone, "the [I.name]"))
+ return
+
+ var/obj/item/organ/external/affecting = get_organ(hit_zone)
if (!affecting || affecting.is_stump())
user << "They are missing that limb!"
return 0
- var/effective_force = I.force
- if(user.a_intent == "disarm") effective_force = round(I.force/2)
- var/hit_area = affecting.name
+ I.apply_hit_effect(src, user, target_zone)
- if((user != src) && check_shields(effective_force, I, user, target_zone, "the [I.name]"))
+/mob/living/carbon/human/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone)
+ var/obj/item/organ/external/affecting = get_organ(hit_zone)
+ if(!affecting)
+ return //should be prevented by attacked_with_item() but for sanity.
+
+ visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] in the [affecting.name] with [I.name] by [user]!")
+
+ var/blocked = run_armor_check(hit_zone, "melee", I.armor_penetration, "Your armor has protected your [affecting.name].", "Your armor has softened the blow to your [affecting.name].")
+ standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone)
+
+ return 1
+
+/mob/living/carbon/human/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone)
+ var/obj/item/organ/external/affecting = get_organ(hit_zone)
+ if(!affecting)
return 0
- if(istype(I,/obj/item/weapon/card/emag))
- if(!(affecting.status & ORGAN_ROBOT))
- user << "\red That limb isn't robotic."
- return
- if(affecting.sabotaged)
- user << "\red [src]'s [affecting.name] is already sabotaged!"
+ // Handle striking to cripple.
+ if(user.a_intent == I_DISARM)
+ effective_force /= 2
+ if(..(I, user effective_force, blocked, hit_zone))
+ attack_joint(affecting, I, blocked)
else
- user << "\red You sneakily slide [I] into the dataport on [src]'s [affecting.name] and short out the safeties."
- var/obj/item/weapon/card/emag/emag = I
- emag.uses--
- affecting.sabotaged = 1
- return 1
+ return 0
+ else if(!..())
+ return 0
- if(I.attack_verb.len)
- visible_message("\red [src] has been [pick(I.attack_verb)] in the [hit_area] with [I.name] by [user]!")
- else
- visible_message("\red [src] has been attacked in the [hit_area] with [I.name] by [user]!")
+ if(effective_force > 10 || effective_force >= 5 && prob(33))
+ forcesay(hit_appends) //forcesay checks stat already
- var/armor = run_armor_check(affecting, "melee", I.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].")
- var/weapon_sharp = is_sharp(I)
- var/weapon_edge = has_edge(I)
- if ((weapon_sharp || weapon_edge) && prob(getarmor(target_zone, "melee")))
- weapon_sharp = 0
- weapon_edge = 0
+ if(prob(25 + (effective_force * 2)))
+ if(!((I.damtype == BRUTE) || (I.damtype == HALLOSS)))
+ return
- if(armor >= 100) return 0
- if(!effective_force) return 0
- var/Iforce = effective_force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
+ if(!(I.flags & NOBLOODY))
+ I.add_blood(src)
- apply_damage(effective_force, I.damtype, affecting, armor, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I)
-
- var/bloody = 0
- if(((I.damtype == BRUTE) || (I.damtype == HALLOSS)) && prob(25 + (effective_force * 2)))
- I.add_blood(src) //Make the weapon bloody, not the person.
-// if(user.hand) user.update_inv_l_hand() //updates the attacker's overlay for the (now bloodied) weapon
-// else user.update_inv_r_hand() //removed because weapons don't have on-mob blood overlays
+ var/bloody = 0
if(prob(33))
bloody = 1
var/turf/location = loc
@@ -212,51 +220,56 @@ emp_act
H.bloody_hands(src)
if(!stat)
- if(headcheck(hit_area))
- //Harder to score a stun but if you do it lasts a bit longer
- if(prob(effective_force))
- apply_effect(20, PARALYZE, armor)
- visible_message("[src] [species.get_knockout_message(src)]")
- else
- //Easier to score a stun but lasts less time
- if(prob(effective_force + 10))
- apply_effect(6, WEAKEN, armor)
- visible_message("[src] has been knocked down!")
+ switch(hit_zone)
+ if("head")//Harder to score a stun but if you do it lasts a bit longer
+ if(prob(effective_force))
+ apply_effect(20, PARALYZE, blocked)
+ visible_message("\The [src] has been knocked unconscious!")
+ if(bloody)//Apply blood
+ if(wear_mask)
+ wear_mask.add_blood(src)
+ update_inv_wear_mask(0)
+ if(head)
+ head.add_blood(src)
+ update_inv_head(0)
+ if(glasses && prob(33))
+ glasses.add_blood(src)
+ update_inv_glasses(0)
+ if("chest")//Easier to score a stun but lasts less time
+ if(prob(effective_force + 10))
+ apply_effect(6, WEAKEN, blocked)
+ visible_message("\The [src] has been knocked down!")
+ if(bloody)
+ bloody_body(src)
- //Apply blood
- if(bloody)
- switch(hit_area)
- if(BP_HEAD)
- if(wear_mask)
- wear_mask.add_blood(src)
- update_inv_wear_mask(0)
- if(head)
- head.add_blood(src)
- update_inv_head(0)
- if(glasses && prob(33))
- glasses.add_blood(src)
- update_inv_glasses(0)
- if(BP_TORSO)
- bloody_body(src)
-
- if(Iforce > 10 || Iforce >= 5 && prob(33))
- forcesay(hit_appends) //forcesay checks stat already
-
- //Melee weapon embedded object code.
- if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I))
- var/damage = effective_force
- if (armor)
- damage /= armor+1
-
- //blunt objects should really not be embedding in things unless a huge amount of force is involved
- var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3)
- var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class
-
- //Sharp objects will always embed if they do enough damage.
- if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance)))
- affecting.embed(I)
return 1
+/mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/blocked)
+ if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 2)
+ return 0
+ if(prob(W.force / (blocked+1)))
+ visible_message("[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!")
+ organ.dislocate(1)
+ return 1
+ return 0
+
+//*** TODO
+
+/* TODO Reimplement pending cleanup
+if(istype(I,/obj/item/weapon/card/emag))
+ if(!(affecting.status & ORGAN_ROBOT))
+ user << "\red That limb isn't robotic."
+ return
+ if(affecting.sabotaged)
+ user << "\red [src]'s [affecting.name] is already sabotaged!"
+ else
+ user << "\red You sneakily slide [I] into the dataport on [src]'s [affecting.name] and short out the safeties."
+ var/obj/item/weapon/card/emag/emag = I
+ emag.uses--
+ affecting.sabotaged = 1
+ return 1
+*/
+
//this proc handles being hit by a thrown atom
/mob/living/carbon/human/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)
if(istype(AM,/obj/))
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 3966f60a20..5f96e48b8d 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -144,6 +144,41 @@
O.emp_act(severity)
..()
+//Whereas attackby() handles the general case of using items on mobs, this handles the specific case of attacking a mob with an item as a weapon.
+/mob/living/proc/attacked_with_item(obj/item/I, mob/living/user, var/target_zone)
+ I.apply_hit_effect(src, user, target_zone)
+
+//Called when the mob is hit with an item in combat.
+/mob/living/proc/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone)
+ visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] with [I.name] by [user]!")
+
+ var/blocked = run_armor_check(hit_zone, "melee")
+ standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone)
+
+ if(I.damtype == BRUTE && prob(33)) // Added blood for whacking non-humans too
+ var/turf/simulated/location = get_turf(src)
+ if(istype(location)) location.add_blood_floor(src)
+
+//returns 0 if the effects failed to apply for some reason, 1 otherwise.
+/mob/living/proc/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone)
+ if(!effective_force || blocked >= 2)
+ return 0
+
+ //Hulk modifier
+ if(HULK in user.mutations)
+ effective_force *= 2
+
+ //Apply weapon damage
+ var/weapon_sharp = is_sharp(I)
+ var/weapon_edge = has_edge(I)
+ if(prob(max(getarmor(hit_zone, "melee") - I.armor_penetration, 0))) //melee armour provides a chance to turn sharp/edge weapon attacks into blunt ones
+ weapon_sharp = 0
+ weapon_edge = 0
+
+ apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I)
+
+ return 1
+
//this proc handles being hit by a thrown atom
/mob/living/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve
if(istype(AM,/obj/))
@@ -370,54 +405,3 @@
hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number+1)
//hud_used.SetButtonCoords(hud_used.hide_actions_toggle,button_number+1)
client.screen += hud_used.hide_actions_toggle
-
-
-//If simple_animals are ever moved under carbon, then this can probably be moved to carbon as well
-/mob/living/proc/attack_throat(obj/item/W, obj/item/weapon/grab/G, mob/user)
-
- // Knifing
- if(!W.edge || !W.force || W.damtype != BRUTE) return //unsuitable weapon
-
- user.visible_message("\The [user] begins to slit [src]'s throat with \the [W]!")
-
- user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly
- if(!do_after(user, 20))
- return
- if(!(G && G.assailant == user && G.affecting == src)) //check that we still have a grab
- return
-
- var/damage_mod = 1
- //presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well
- var/obj/item/clothing/head/helmet = get_equipped_item(slot_head)
- if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.item_flags & STOPPRESSUREDAMAGE))
- //we don't do an armor_check here because this is not an impact effect like a weapon swung with momentum, that either penetrates or glances off.
- damage_mod = 1.0 - (helmet.armor["melee"]/100)
-
- var/total_damage = 0
- for(var/i in 1 to 3)
- var/damage = min(W.force*1.5, 20)*damage_mod
- apply_damage(damage, W.damtype, BP_HEAD, 0, sharp=W.sharp, edge=W.edge)
- total_damage += damage
-
- var/oxyloss = total_damage
- if(total_damage >= 40) //threshold to make someone pass out
- oxyloss = 60 // Brain lacks oxygen immediately, pass out
-
- adjustOxyLoss(min(oxyloss, 100 - getOxyLoss())) //don't put them over 100 oxyloss
-
- if(total_damage)
- if(oxyloss >= 40)
- user.visible_message("\The [user] slit [src]'s throat open with \the [W]!")
- else
- user.visible_message("\The [user] cut [src]'s neck with \the [W]!")
-
- if(W.hitsound)
- playsound(loc, W.hitsound, 50, 1, -1)
-
- G.last_action = world.time
- flick(G.hud.icon_state, G.hud)
-
- user.attack_log += "\[[time_stamp()]\] Knifed [name] ([ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])"
- src.attack_log += "\[[time_stamp()]\] Got knifed by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])"
- msg_admin_attack("[key_name(user)] knifed [key_name(src)] with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" )
- return
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 0d0a83b7d1..d670e17ee3 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -132,9 +132,6 @@
updatehealth()
return 1*/
-/mob/living/silicon/attack_throat()
- return
-
/proc/islinked(var/mob/living/silicon/robot/bot, var/mob/living/silicon/ai/ai)
if(!istype(bot) || !istype(ai))
return 0
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 2fbad9deee..d0a7ba2ba3 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -287,11 +287,9 @@
if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch))
harvest(user)
else
- attacked_with_item(O, user)
+ attacked_with_item(O, user, user.zone_sel.selecting)
-//TODO: refactor mob attackby(), attacked_by(), and friends.
-/mob/living/simple_animal/proc/attacked_with_item(var/obj/item/O, var/mob/user)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+/mob/living/simple_animal/attacked_with_item(obj/item/O, mob/living/user, var/target_zone)
if(!O.force)
visible_message("[user] gently taps [src] with \the [O].")
return
diff --git a/polaris.dme b/polaris.dme
index 82459576ff..ab2cacb4f0 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -1305,6 +1305,7 @@
#include "code\modules\mob\living\bot\secbot.dm"
#include "code\modules\mob\living\carbon\breathe.dm"
#include "code\modules\mob\living\carbon\carbon.dm"
+#include "code\modules\mob\living\carbon\carbon_defense.dm"
#include "code\modules\mob\living\carbon\carbon_defines.dm"
#include "code\modules\mob\living\carbon\carbon_powers.dm"
#include "code\modules\mob\living\carbon\give.dm"