diff --git a/code/datums/martial.dm b/code/datums/martial.dm
new file mode 100644
index 00000000000..3f13b49b4b5
--- /dev/null
+++ b/code/datums/martial.dm
@@ -0,0 +1,306 @@
+/datum/martial_art
+ var/name = "Martial Art"
+ var/streak = ""
+ var/max_streak_length = 6
+ var/current_target = null
+ var/temporary = 0
+ var/datum/martial_art/base = null // The permanent style
+
+/datum/martial_art/proc/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ return 0
+
+/datum/martial_art/proc/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ return 0
+
+/datum/martial_art/proc/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ return 0
+
+/datum/martial_art/proc/add_to_streak(var/element,var/mob/living/carbon/human/D)
+ if(D != current_target)
+ current_target = D
+ streak = ""
+ streak = streak+element
+ if(length(streak) > max_streak_length)
+ streak = copytext(streak,2)
+ return
+
+/datum/martial_art/proc/basic_hit(var/mob/living/carbon/human/A,var/mob/living/carbon/human/D)
+ add_logs(A, D, "punched")
+ A.do_attack_animation(D)
+ var/damage = rand(0,9)
+
+ var/atk_verb = "punch"
+ if(D.lying)
+ atk_verb = "kick"
+
+ if(!damage)
+ playsound(D.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ D.visible_message("[A] has attempted to [atk_verb] [D]!")
+ return 0
+
+ var/obj/item/organ/external/affecting = D.get_organ(ran_zone(A.zone_sel.selecting))
+ var/armor_block = D.run_armor_check(affecting, "melee")
+
+ playsound(D.loc, 'sound/weapons/punch1.ogg', 25, 1, -1)
+
+ D.visible_message("[A] has [atk_verb]ed [D]!", \
+ "[A] has [atk_verb]ed [D]!")
+
+ D.apply_damage(damage, BRUTE, affecting, armor_block)
+ if((D.stat != DEAD) && damage >= 9)
+ D.visible_message("[A] has weakened [D]!!", \
+ "[A] has weakened [D]!")
+ D.apply_effect(4, WEAKEN, armor_block)
+ D.forcesay(hit_appends)
+ else if(D.lying)
+ D.forcesay(hit_appends)
+ return 1
+
+/datum/martial_art/proc/teach(var/mob/living/carbon/human/H,var/make_temporary=0)
+ if(make_temporary)
+ temporary = 1
+ if(H.martial_art && H.martial_art.temporary)
+ if(temporary)
+ base = H.martial_art.base
+ else
+ H.martial_art.base = src //temporary styles have priority
+ return
+ H.martial_art = src
+
+/datum/martial_art/proc/remove(var/mob/living/carbon/human/H)
+ if(H.martial_art != src)
+ return
+ H.martial_art = base
+
+
+/datum/martial_art/boxing
+ name = "Boxing"
+
+/datum/martial_art/boxing/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ A << " Can't disarm while boxing!"
+ return 1
+
+/datum/martial_art/boxing/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ A << " Can't grab while boxing!"
+ return 1
+
+/datum/martial_art/boxing/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ add_logs(A, D, "punched")
+ A.do_attack_animation(D)
+
+ var/atk_verb = pick("left hook","right hook","straight punch")
+
+ var/damage = rand(5,8)
+
+ if(!damage)
+ playsound(D.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ D.visible_message("[A] has attempted to hit [D] with a [atk_verb]!")
+ return 0
+
+
+ var/obj/item/organ/external/affecting = D.get_organ(ran_zone(A.zone_sel.selecting))
+ var/armor_block = D.run_armor_check(affecting, "melee")
+
+ playsound(D.loc, 'sound/weapons/punch1.ogg', 25, 1, -1)
+
+
+ D.visible_message("[A] has hit [D] with a [atk_verb]!", \
+ "[A] has hit [D] with a [atk_verb]!")
+
+ D.apply_damage(damage, STAMINA, affecting, armor_block)
+ if(D.getStaminaLoss() > 50)
+ var/knockout_prob = D.getStaminaLoss() + rand(-15,15)
+ if((D.stat != DEAD) && prob(knockout_prob))
+ D.visible_message("[A] has knocked [D] out with a haymaker!", \
+ "[A] has knocked [D] out with a haymaker!")
+ D.apply_effect(10,WEAKEN,armor_block)
+ D.SetSleeping(5)
+ D.forcesay(hit_appends)
+ else if(D.lying)
+ D.forcesay(hit_appends)
+ return 1
+
+/datum/martial_art/wrestling
+ name = "Wrestling"
+
+/datum/martial_art/wrestling/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ D.grabbedby(A,1)
+ var/obj/item/weapon/grab/G = A.get_active_hand()
+ if(G && prob(50))
+ G.state = GRAB_AGGRESSIVE
+ D.visible_message("[A] has [D] in a clinch!", \
+ "[A] has [D] in a clinch!")
+ else
+ D.visible_message("[A] fails to get [D] in a clinch!", \
+ "[A] fails to get [D] in a clinch!")
+ return 1
+
+
+/datum/martial_art/wrestling/proc/Suplex(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ add_logs(A, D, "suplexed")
+ D.visible_message("[A] suplexes [D]!", \
+ "[A] suplexes [D]!")
+ D.forceMove(A.loc)
+ var/armor_block = D.run_armor_check(null, "melee")
+ D.apply_damage(30, BRUTE, null, armor_block)
+ D.apply_effect(6, WEAKEN, armor_block)
+ A.SpinAnimation(10,1)
+
+ D.SpinAnimation(10,1)
+ spawn(3)
+ armor_block = A.run_armor_check(null, "melee")
+ A.apply_effect(4, WEAKEN, armor_block)
+ return
+
+/datum/martial_art/wrestling/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ if(istype(A.get_inactive_hand(),/obj/item/weapon/grab))
+ var/obj/item/weapon/grab/G = A.get_inactive_hand()
+ if(G.affecting == D)
+ Suplex(A,D)
+ return 1
+ harm_act(A,D)
+ return 1
+
+/datum/martial_art/wrestling/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ D.grabbedby(A,1)
+ D.visible_message("[A] holds [D] down!", \
+ "[A] holds [D] down!")
+ var/obj/item/organ/external/affecting = D.get_organ(ran_zone(A.zone_sel.selecting))
+ var/armor_block = D.run_armor_check(affecting, "melee")
+ D.apply_damage(10, STAMINA, affecting, armor_block)
+ return 1
+
+#define TORNADO_COMBO "HHD"
+#define THROWBACK_COMBO "DHD"
+#define PLASMA_COMBO "HDDDH"
+
+/datum/martial_art/plasma_fist
+ name = "Plasma Fist"
+
+/datum/martial_art/plasma_fist/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ if(findtext(streak,TORNADO_COMBO))
+ streak = ""
+ Tornado(A,D)
+ return 1
+ if(findtext(streak,THROWBACK_COMBO))
+ streak = ""
+ Throwback(A,D)
+ return 1
+ if(findtext(streak,PLASMA_COMBO))
+ streak = ""
+ Plasma(A,D)
+ return 1
+ return 0
+
+/datum/martial_art/plasma_fist/proc/Tornado(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ A.say("TORNADO SWEEP!")
+ spawn(0)
+ for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH))
+ A.dir = i
+ playsound(A.loc, 'sound/weapons/punch1.ogg', 15, 1, -1)
+ sleep(1)
+ var/obj/effect/proc_holder/spell/wizard/aoe_turf/repulse/R = new(null)
+ var/list/turfs = list()
+ for(var/turf/T in range(1,A))
+ turfs.Add(T)
+ R.cast(turfs)
+ return
+
+/datum/martial_art/plasma_fist/proc/Throwback(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ D.visible_message("[A] has hit [D] with Plasma Punch!", \
+ "[A] has hit [D] with Plasma Punch!")
+ playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
+ var/atom/throw_target = get_edge_target_turf(D, get_dir(D, get_step_away(D, A)))
+ D.throw_at(throw_target, 200, 4)
+ A.say("HYAH!")
+ return
+
+/datum/martial_art/plasma_fist/proc/Plasma(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ A.do_attack_animation(D)
+ playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
+ A.say("PLASMA FIST!")
+ D.visible_message("[A] has hit [D] with THE PLASMA FIST TECHNIQUE!", \
+ "[A] has hit [D] with THE PLASMA FIST TECHNIQUE!")
+ D.gib()
+ return
+
+/datum/martial_art/plasma_fist/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ add_to_streak("H")
+ if(check_streak(A,D))
+ return 1
+ basic_hit(A,D)
+ return 1
+
+/datum/martial_art/plasma_fist/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ add_to_streak("D")
+ if(check_streak(A,D))
+ return 1
+ basic_hit(A,D)
+ return 1
+
+/datum/martial_art/plasma_fist/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ add_to_streak("G")
+ if(check_streak(A,D))
+ return 1
+ basic_hit(A,D)
+ return 1
+
+
+//ITEMS
+
+/obj/item/clothing/gloves/boxing
+ var/datum/martial_art/boxing/style = new
+
+/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
+ if(!ishuman(user))
+ return
+ if(slot == slot_gloves)
+ var/mob/living/carbon/human/H = user
+ style.teach(H,1)
+ return
+
+/obj/item/clothing/gloves/boxing/dropped(mob/user)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
+ if(H.get_item_by_slot(slot_gloves) == src)
+ style.remove(H)
+ return
+
+/obj/item/weapon/storage/belt/champion/wrestling
+ name = "Wrestling Belt"
+ var/datum/martial_art/wrestling/style = new
+
+/obj/item/weapon/storage/belt/champion/wrestling/equipped(mob/user, slot)
+ if(!ishuman(user))
+ return
+ if(slot == slot_belt)
+ var/mob/living/carbon/human/H = user
+ style.teach(H,1)
+ return
+
+/obj/item/weapon/storage/belt/champion/wrestling/dropped(mob/user)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
+ if(H.get_item_by_slot(slot_belt) == src)
+ style.remove(H)
+ return
+
+/obj/item/weapon/plasma_fist_scroll
+ name = "Plasma Fist Scroll"
+ desc = "Teaches the traditional wizard martial art."
+ icon = 'icons/obj/wizard.dmi'
+ icon_state ="scroll2"
+ var/used = 0
+
+/obj/item/weapon/plasma_fist_scroll/attack_self(mob/user as mob)
+ if(!ishuman(user))
+ return
+ if(!used)
+ var/mob/living/carbon/human/H = user
+ var/datum/martial_art/plasma_fist/F = new/datum/martial_art/plasma_fist(null)
+ F.teach(H)
+ H << "You learn the PLASMA FIST style."
+ used = 1
+ desc += "It looks like it's magic was used up."
diff --git a/code/modules/mob/living/carbon/alien/alien_defenses.dm b/code/modules/mob/living/carbon/alien/alien_defenses.dm
index 9f57ad843ce..95ed75f18a0 100644
--- a/code/modules/mob/living/carbon/alien/alien_defenses.dm
+++ b/code/modules/mob/living/carbon/alien/alien_defenses.dm
@@ -1,6 +1,6 @@
/mob/living/carbon/alien/hitby(atom/movable/AM)
..(AM, 1)
-
+
/*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other.
As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble.
In all, this is a lot like the monkey code. /N
@@ -25,23 +25,8 @@ In all, this is a lot like the monkey code. /N
visible_message("[M.name] nuzzles [src] trying to wake it up!")
if ("grab")
- if (M == src || anchored)
- return
- if (!(status_flags & CANPUSH))
- return
-
- var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src )
-
- M.put_in_active_hand(G)
-
- grabbed_by += G
- G.synch()
-
- LAssailant = M
-
- for(var/mob/O in viewers(src, null))
- if ((O.client && !( O.blinded )))
- O.show_message(text("\red [] has grabbed [] passively!", M, src), 1)
+ src.grabbedby(M)
+ return 1
else
if (health > 0)
@@ -69,23 +54,7 @@ In all, this is a lot like the monkey code. /N
if("help")
help_shake_act(M)
if("grab")
- if (M == src || anchored)
- return
- if (!(status_flags & CANPUSH))
- return
-
- var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src )
-
- M.put_in_active_hand(G)
-
- grabbed_by += G
- G.synch()
-
- LAssailant = M
-
- for(var/mob/O in viewers(src, null))
- if ((O.client && !( O.blinded )))
- O.show_message(text("\red [] has grabbed [] passively!", M, src), 1)
+ src.grabbedby(M)
if ("harm", "disarm")
return 1
return 0
diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm
index 848d5f11b51..b2be2f8e29d 100644
--- a/code/modules/mob/living/carbon/human/human_attackhand.dm
+++ b/code/modules/mob/living/carbon/human/human_attackhand.dm
@@ -53,6 +53,8 @@
// log_debug("No gloves, [M] is truing to infect [src]")
M.spread_disease_to(src, "Contact")
+ var/datum/martial_art/attacker_style = M.martial_art
+
switch(M.a_intent)
if("help")
if(health >= config.health_threshold_crit)
@@ -81,149 +83,142 @@
return 1
if("grab")
- if(M == src || anchored)
- return 0
- if(w_uniform)
- w_uniform.add_fingerprint(M)
-
- var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src)
- if(buckled)
- M << "You cannot grab [src], \he is buckled in!"
- if(!G) //the grab will delete itself in New if affecting is anchored
- return
- M.put_in_active_hand(G)
- grabbed_by += G
- G.synch()
- LAssailant = M
-
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- visible_message("[M] has grabbed [src] passively!")
- add_logs(src, M, "grabbed", addition="passively")
- return 1
+ if(attacker_style && attacker_style.grab_act(H, src))
+ return 1
+ else
+ src.grabbedby(M)
+ return 1
if("harm")
- var/datum/unarmed_attack/attack = M.species.unarmed
- //Vampire code
- if(M.zone_sel && M.zone_sel.selecting == "head" && src != M)
- if(M.mind && M.mind.vampire && (M.mind in ticker.mode.vampires) && !M.mind.vampire.draining)
- if((head && (head.flags & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags & MASKCOVERSMOUTH)))
- M << "\red Remove their mask!"
- return 0
- if((M.head && (M.head.flags & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags & MASKCOVERSMOUTH)))
- M << "\red Remove your mask!"
- return 0
- if(mind && mind.vampire && (mind in ticker.mode.vampires))
- M << "\red Your fangs fail to pierce [src.name]'s cold flesh"
- return 0
- if(SKELETON in mutations)
- M << "\red There is no blood in a skeleton!"
- return 0
- //we're good to suck the blood, blaah
- M.handle_bloodsucking(src)
- add_logs(src, M, "vampirebit")
- message_admins("[M.name] ([M.ckey]) vampirebit [src.name] ([src.ckey])")
- return
- //end vampire codes
-
- M.do_attack_animation(src)
- add_logs(src, M, "[pick(attack.attack_verb)]ed")
-
- if(!iscarbon(M))
- LAssailant = null
+ if(attacker_style && attacker_style.harm_act(H, src))
+ return 1
else
- LAssailant = M
+ var/datum/unarmed_attack/attack = M.species.unarmed
- var/damage = rand(0, M.species.max_hurt_damage)//BS12 EDIT
- if(!damage)
- playsound(loc, attack.miss_sound, 25, 1, -1)
- visible_message("\red [M] tried to [pick(attack.attack_verb)] [src]!")
- return 0
+ //Vampire code
+ if(M.zone_sel && M.zone_sel.selecting == "head" && src != M)
+ if(M.mind && M.mind.vampire && (M.mind in ticker.mode.vampires) && !M.mind.vampire.draining)
+ if((head && (head.flags & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags & MASKCOVERSMOUTH)))
+ M << "\red Remove their mask!"
+ return 0
+ if((M.head && (M.head.flags & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags & MASKCOVERSMOUTH)))
+ M << "\red Remove your mask!"
+ return 0
+ if(mind && mind.vampire && (mind in ticker.mode.vampires))
+ M << "\red Your fangs fail to pierce [src.name]'s cold flesh"
+ return 0
+ if(SKELETON in mutations)
+ M << "\red There is no blood in a skeleton!"
+ return 0
+ //we're good to suck the blood, blaah
+ M.handle_bloodsucking(src)
+ add_logs(src, M, "vampirebit")
+ message_admins("[M.name] ([M.ckey]) vampirebit [src.name] ([src.ckey])")
+ return
+ //end vampire codes
+ M.do_attack_animation(src)
+ add_logs(src, M, "[pick(attack.attack_verb)]ed")
- var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
- var/armor_block = run_armor_check(affecting, "melee")
-
- if(HULK in M.mutations)
- damage += 5
- Weaken(4)
-
- playsound(loc, attack.attack_sound, 25, 1, -1)
-
- visible_message("\red [M] [pick(attack.attack_verb)]ed [src]!")
-
- damage += attack.damage
- apply_damage(damage, BRUTE, affecting, armor_block, sharp=attack.sharp, edge=attack.edge) //moving this back here means Armalis are going to knock you down 70% of the time, but they're pure adminbus anyway.
- if((stat != DEAD) && damage >= 9)
- visible_message("[M] has weakened [src]!", \
- "[M] has weakened [src]!")
- apply_effect(4, WEAKEN, armor_block)
- forcesay(hit_appends)
- else if(lying)
- forcesay(hit_appends)
-
-
- if("disarm")
- add_logs(src, M, "disarmed")
-
- if(w_uniform)
- w_uniform.add_fingerprint(M)
- var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
- var/randn = rand(1, 100)
- if (randn <= 25)
- apply_effect(2, WEAKEN, run_armor_check(affecting, "melee"))
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- visible_message("\red [M] has pushed [src]!")
- M.attack_log += text("\[[time_stamp()]\] Pushed [src.name] ([src.ckey])")
- src.attack_log += text("\[[time_stamp()]\] Has been pushed by [M.name] ([M.ckey])")
if(!iscarbon(M))
LAssailant = null
else
LAssailant = M
- log_attack("[M.name] ([M.ckey]) pushed [src.name] ([src.ckey])")
- return
+ var/damage = rand(0, M.species.max_hurt_damage)//BS12 EDIT
+ if(!damage)
+ playsound(loc, attack.miss_sound, 25, 1, -1)
+ visible_message("\red [M] tried to [pick(attack.attack_verb)] [src]!")
+ return 0
-/* if(randn <= 45 && !lying)
- if(head)
- var/obj/item/clothing/head/H = head
- if(!istype(H) || prob(H.loose))
- if(unEquip(H))
- if(prob(60))
- step_away(H,M)
- visible_message("[M] has knocked [src]'s [H] off!",
- "[M] knocked \the [H] clean off your head!") */
- var/talked = 0 // BubbleWrap
+ var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
+ var/armor_block = run_armor_check(affecting, "melee")
- if(randn <= 60)
- //BubbleWrap: Disarming breaks a pull
- if(pulling)
- visible_message("\red [M] has broken [src]'s grip on [pulling]!")
- talked = 1
- stop_pulling()
+ if(HULK in M.mutations)
+ damage += 5
+ Weaken(4)
- //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it?
- if(istype(l_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/lgrab = l_hand
- if(lgrab.affecting)
- visible_message("\red [M] has broken [src]'s grip on [lgrab.affecting]!")
+ playsound(loc, attack.attack_sound, 25, 1, -1)
+
+ visible_message("\red [M] [pick(attack.attack_verb)]ed [src]!")
+
+ damage += attack.damage
+ apply_damage(damage, BRUTE, affecting, armor_block, sharp=attack.sharp, edge=attack.edge) //moving this back here means Armalis are going to knock you down 70% of the time, but they're pure adminbus anyway.
+ if((stat != DEAD) && damage >= 9)
+ visible_message("[M] has weakened [src]!", \
+ "[M] has weakened [src]!")
+ apply_effect(4, WEAKEN, armor_block)
+ forcesay(hit_appends)
+ else if(lying)
+ forcesay(hit_appends)
+
+
+ if("disarm")
+ if(attacker_style && attacker_style.disarm_act(H, src))
+ return 1
+ else
+ add_logs(src, M, "disarmed")
+
+ if(w_uniform)
+ w_uniform.add_fingerprint(M)
+ var/obj/item/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
+ var/randn = rand(1, 100)
+ if (randn <= 25)
+ apply_effect(2, WEAKEN, run_armor_check(affecting, "melee"))
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ visible_message("\red [M] has pushed [src]!")
+ M.attack_log += text("\[[time_stamp()]\] Pushed [src.name] ([src.ckey])")
+ src.attack_log += text("\[[time_stamp()]\] Has been pushed by [M.name] ([M.ckey])")
+ if(!iscarbon(M))
+ LAssailant = null
+ else
+ LAssailant = M
+
+ log_attack("[M.name] ([M.ckey]) pushed [src.name] ([src.ckey])")
+ return
+
+ /* if(randn <= 45 && !lying)
+ if(head)
+ var/obj/item/clothing/head/H = head
+ if(!istype(H) || prob(H.loose))
+ if(unEquip(H))
+ if(prob(60))
+ step_away(H,M)
+ visible_message("[M] has knocked [src]'s [H] off!",
+ "[M] knocked \the [H] clean off your head!") */
+
+ var/talked = 0 // BubbleWrap
+
+ if(randn <= 60)
+ //BubbleWrap: Disarming breaks a pull
+ if(pulling)
+ visible_message("\red [M] has broken [src]'s grip on [pulling]!")
talked = 1
- spawn(1)
- del(lgrab)
- if(istype(r_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/rgrab = r_hand
- if(rgrab.affecting)
- visible_message("\red [M] has broken [src]'s grip on [rgrab.affecting]!")
- talked = 1
- spawn(1)
- del(rgrab)
- //End BubbleWrap
+ stop_pulling()
- if(!talked) //BubbleWrap
- if(drop_item())
- visible_message("\red [M] has disarmed [src]!")
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- return
+ //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it?
+ if(istype(l_hand, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/lgrab = l_hand
+ if(lgrab.affecting)
+ visible_message("\red [M] has broken [src]'s grip on [lgrab.affecting]!")
+ talked = 1
+ spawn(1)
+ del(lgrab)
+ if(istype(r_hand, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/rgrab = r_hand
+ if(rgrab.affecting)
+ visible_message("\red [M] has broken [src]'s grip on [rgrab.affecting]!")
+ talked = 1
+ spawn(1)
+ del(rgrab)
+ //End BubbleWrap
+
+ if(!talked) //BubbleWrap
+ if(drop_item())
+ visible_message("\red [M] has disarmed [src]!")
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ return
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 04189211f2f..b792385f581 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -55,6 +55,8 @@
var/speech_problem_flag = 0
+ var/datum/martial_art/martial_art = null
+
var/miming = null //Toggle for the mime's abilities.
var/special_voice = "" // For changing our voice. Used by a symptom.
var/said_last_words=0
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 5af3c8953c0..deb84cdf5e4 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -257,3 +257,24 @@
IgniteMob()
//Mobs on Fire end
+
+/mob/living/proc/grabbedby(mob/living/carbon/user,var/supress_message = 0)
+ if(user == src || anchored)
+ return 0
+ if(!(status_flags & CANPUSH))
+ return 0
+
+ add_logs(user, src, "grabbed", addition="passively")
+
+ var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(user, src)
+ if(buckled)
+ user << "You cannot grab [src], \he is buckled in!"
+ if(!G) //the grab will delete itself in New if src is anchored
+ return 0
+ user.put_in_active_hand(G)
+ G.synch()
+ LAssailant = user
+
+ playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ if(!supress_message)
+ visible_message("[user] has grabbed [src] passively!")
diff --git a/paradise.dme b/paradise.dme
index f4bdc02c04c..899cc7bde06 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -134,6 +134,7 @@
#include "code\datums\computerfiles.dm"
#include "code\datums\datacore.dm"
#include "code\datums\datumvars.dm"
+#include "code\datums\martial.dm"
#include "code\datums\medical_effects.dm"
#include "code\datums\mind.dm"
#include "code\datums\mixed.dm"