diff --git a/code/__DEFINES/martial_arts.dm b/code/__DEFINES/martial_arts.dm
new file mode 100644
index 00000000000..4eb139cc44a
--- /dev/null
+++ b/code/__DEFINES/martial_arts.dm
@@ -0,0 +1,16 @@
+#define MARTIAL_COMBO_FAIL 0 // If the combo failed
+#define MARTIAL_COMBO_CONTINUE 1 // If the combo should continue
+#define MARTIAL_COMBO_DONE 2 // If the combo is successful and done
+#define MARTIAL_COMBO_DONE_NO_CLEAR 3 // If the combo is successful and done but the others should have a chance to finish
+#define MARTIAL_COMBO_DONE_BASIC_HIT 4 // If the combo should do a basic hit after it's done
+#define MARTIAL_COMBO_DONE_CLEAR_COMBOS 5 // If the combo should do a basic hit after it's done
+
+#define MARTIAL_ARTS_CANNOT_USE -1
+
+#define MARTIAL_COMBO_STEP_HARM "Harm"
+#define MARTIAL_COMBO_STEP_DISARM "Disarm"
+#define MARTIAL_COMBO_STEP_GRAB "Grab"
+#define MARTIAL_COMBO_STEP_HELP "Help"
+
+// A check used for all act types. Such as disarm_act
+#define MARTIAL_ARTS_ACT_CHECK if((. = ..()) != FALSE) return .
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 148d8e8276f..53230d1f83d 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -35,6 +35,7 @@
var/list/restricted_roles = list()
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
+ var/datum/martial_art/martial_art
var/role_alt_title
diff --git a/code/game/objects/items/weapons/highlander_swords.dm b/code/game/objects/items/weapons/highlander_swords.dm
index 330da6beba0..568b023d051 100644
--- a/code/game/objects/items/weapons/highlander_swords.dm
+++ b/code/game/objects/items/weapons/highlander_swords.dm
@@ -25,14 +25,14 @@
return ..()
/obj/item/claymore/highlander/equipped(mob/user, slot)
- if(!ishuman(user))
+ if(!ishuman(user) || !user.mind)
return
var/mob/living/carbon/human/H = user
if(slot == slot_r_hand || slot == slot_l_hand)
- if(H.martial_art && H.martial_art != style)
- style.teach(H, 1)
+ if(H.mind.martial_art && H.mind.martial_art != style)
+ style.teach(H, TRUE)
to_chat(H, "THERE CAN ONLY BE ONE!")
- else if(H.martial_art && H.martial_art == style)
+ else if(H.mind.martial_art && H.mind.martial_art == style)
style.remove(H)
var/obj/item/claymore/highlander/sword = H.is_in_hands(/obj/item/claymore/highlander)
if(sword)
diff --git a/code/game/objects/items/weapons/implants/implant_krav_maga.dm b/code/game/objects/items/weapons/implants/implant_krav_maga.dm
index 3c2666f3d66..9c33f43950a 100644
--- a/code/game/objects/items/weapons/implants/implant_krav_maga.dm
+++ b/code/game/objects/items/weapons/implants/implant_krav_maga.dm
@@ -17,12 +17,12 @@
/obj/item/implant/krav_maga/activate()
var/mob/living/carbon/human/H = imp_in
- if(!ishuman(H))
+ if(!ishuman(H) || !H.mind)
return
- if(istype(H.martial_art, /datum/martial_art/krav_maga))
+ if(istype(H.mind.martial_art, /datum/martial_art/krav_maga))
style.remove(H)
else
- style.teach(H,1)
+ style.teach(H, TRUE)
/obj/item/implanter/krav_maga
name = "implanter (krav maga)"
diff --git a/code/modules/martial_arts/adminfu.dm b/code/modules/martial_arts/adminfu.dm
index 12436061e20..20f3c95f7b6 100644
--- a/code/modules/martial_arts/adminfu.dm
+++ b/code/modules/martial_arts/adminfu.dm
@@ -1,93 +1,37 @@
-///Adminfu
-//Help act:Heal/revie GP //p is for help
-//Disarm:Stun
-//Grab:Neck
-//Harm:Gib
-#define HEAL_COMBO "GP"
-
/datum/martial_art/adminfu
name = "Way of the Dancing Admin"
- help_verb = /mob/living/carbon/human/proc/adminfu_help
-
-/datum/martial_art/adminfu/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(findtext(streak,HEAL_COMBO))
- streak = ""
- healPalm(A,D)
- return 1
- return 0
+ has_explaination_verb = TRUE
+ combos = list(/datum/martial_combo/adminfu/healing_palm)
/datum/martial_art/adminfu/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
-
+ MARTIAL_ARTS_ACT_CHECK
if(!D.stat)//do not kill what is dead...
A.do_attack_animation(D)
D.visible_message("[A] manifests a large glowing toolbox and shoves it in [D]'s chest!", \
"[A] shoves a mystical toolbox in your chest!")
D.death()
- return 1
+ return TRUE
/datum/martial_art/adminfu/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
+ MARTIAL_ARTS_ACT_CHECK
A.do_attack_animation(D)
D.Weaken(25)
D.Stun(25)
- return 1
+ return TRUE
/datum/martial_art/adminfu/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("G",D)
- if(check_streak(A,D))
- return 1
+ MARTIAL_ARTS_ACT_CHECK
var/obj/item/grab/G = D.grabbedby(A,1)
if(G)
G.state = GRAB_NECK
+ return TRUE
-/datum/martial_art/adminfu/help_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("P",D)
- if(check_streak(A,D))
- return 1
-
-/datum/martial_art/adminfu/proc/healPalm(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- A.do_attack_animation(D)
- D.visible_message("[A] smacks [D] in the forehead!")
-
- //its the staff of healing code..hush
- if(istype(D,/mob))
- var/old_stat = D.stat
- if(isanimal(D) && D.stat == DEAD)
- var/mob/living/simple_animal/O = D
- var/mob/living/simple_animal/P = new O.type(O.loc)
- P.real_name = O.real_name
- P.name = O.name
- if(O.mind)
- O.mind.transfer_to(P)
- else
- P.key = O.key
- qdel(O)
- D = P
- else
- D.revive()
- D.suiciding = 0
- if(!D.ckey)
- for(var/mob/dead/observer/ghost in GLOB.player_list)
- if(D.real_name == ghost.real_name)
- ghost.reenter_corpse()
- break
- if(old_stat != DEAD)
- to_chat(D, "You feel great!")
- else
- to_chat(D, "You rise with a start, you're alive!!!")
- return 1
-
-/mob/living/carbon/human/proc/adminfu_help()
- set name = "Recall Teachings"
- set desc = "Remember the way of the dancing admin."
- set category = "Adminfu"
-
- to_chat(usr, "Grab: Automatic Neck Grab.")
- to_chat(usr, "Disarm: Stun/weaken")
- to_chat(usr, "Harm: Death.")
- to_chat(usr, "Healing Palm::Combo:Grab,Help intent. Heals or revives a crature.")
-
+/datum/martial_art/adminfu/explaination_header(user)
+ to_chat(user, "Grab: Automatic Neck Grab.")
+ to_chat(user, "Disarm: Stun/weaken")
+ to_chat(user, "Harm: Death.")
/obj/item/adminfu_scroll
name = "frayed scroll"
diff --git a/code/modules/martial_arts/combos/adminfu/healing_palm.dm b/code/modules/martial_arts/combos/adminfu/healing_palm.dm
new file mode 100644
index 00000000000..c5bd34f1886
--- /dev/null
+++ b/code/modules/martial_arts/combos/adminfu/healing_palm.dm
@@ -0,0 +1,38 @@
+/datum/martial_combo/adminfu/healing_palm
+ name = "Healing Palm"
+ steps = list(MARTIAL_COMBO_STEP_GRAB, MARTIAL_COMBO_STEP_HELP)
+ explaination_text = "Heals or revives a creature."
+ combo_text_override = "Grab, switch hands, Help"
+
+/datum/martial_combo/adminfu/healing_palm/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ user.do_attack_animation(target)
+ target.visible_message("[user] smacks [target] in the forehead!")
+
+ //its the staff of healing code..hush
+ if(istype(target,/mob))
+ var/old_stat = target.stat
+ if(isanimal(target) && target.stat == DEAD)
+ var/mob/living/simple_animal/O = target
+ var/mob/living/simple_animal/P = new O.type(O.loc)
+ P.real_name = O.real_name
+ P.name = O.name
+ if(O.mind)
+ O.mind.transfer_to(P)
+ else
+ P.key = O.key
+ qdel(O)
+ target = P
+ else
+ target.revive()
+ target.suiciding = 0
+ if(!target.ckey)
+ for(var/mob/dead/observer/ghost in GLOB.player_list)
+ if(target.real_name == ghost.real_name)
+ ghost.reenter_corpse()
+ break
+ if(old_stat != DEAD)
+ to_chat(target, "You feel great!")
+ else
+ to_chat(target, "You rise with a start, you're alive!!!")
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_FAIL
diff --git a/code/modules/martial_arts/combos/cqc/consecutive.dm b/code/modules/martial_arts/combos/cqc/consecutive.dm
new file mode 100644
index 00000000000..b513c8191e4
--- /dev/null
+++ b/code/modules/martial_arts/combos/cqc/consecutive.dm
@@ -0,0 +1,18 @@
+/datum/martial_combo/cqc/consecutive
+ name = "Consecutive CQC"
+ steps = list(MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_HARM)
+ explaination_text = "Mainly offensive move, huge damage and decent stamina damage."
+
+/datum/martial_combo/cqc/consecutive/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(!target.stat)
+ target.visible_message("[user] strikes [target]'s abdomen, neck and back consecutively", \
+ "[user] strikes your abdomen, neck and back consecutively!")
+ playsound(get_turf(target), 'sound/weapons/cqchit2.ogg', 50, 1, -1)
+ var/obj/item/I = target.get_active_hand()
+ if(I && target.drop_item())
+ user.put_in_hands(I)
+ target.adjustStaminaLoss(50)
+ target.apply_damage(25, BRUTE)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Consecutive", ATKLOG_ALL)
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_FAIL
diff --git a/code/modules/martial_arts/combos/cqc/kick.dm b/code/modules/martial_arts/combos/cqc/kick.dm
new file mode 100644
index 00000000000..887a51b049d
--- /dev/null
+++ b/code/modules/martial_arts/combos/cqc/kick.dm
@@ -0,0 +1,24 @@
+/datum/martial_combo/cqc/kick
+ name = "CQC Kick"
+ steps = list(MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_HARM)
+ explaination_text = "Knocks opponent away. Knocks out stunned or knocked down opponents."
+
+/datum/martial_combo/cqc/kick/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ . = MARTIAL_COMBO_FAIL
+ if(!target.stat || !target.IsWeakened())
+ target.visible_message("[user] kicks [target] back!", \
+ "[user] kicks you back!")
+ playsound(get_turf(user), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
+ var/atom/throw_target = get_edge_target_turf(target, user.dir)
+ target.throw_at(throw_target, 1, 14, user)
+ target.apply_damage(10, BRUTE)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Kick", ATKLOG_ALL)
+ . = MARTIAL_COMBO_DONE
+ if(target.IsWeakened() && !target.stat)
+ target.visible_message("[user] kicks [target]'s head, knocking [target.p_them()] out!", \
+ "[user] kicks your head, knocking you out!")
+ playsound(get_turf(user), 'sound/weapons/genhit1.ogg', 50, 1, -1)
+ target.SetSleeping(15)
+ target.adjustBrainLoss(15)
+ add_attack_logs(user, target, "Knocked out with martial-art [src] : Kick", ATKLOG_ALL)
+ . = MARTIAL_COMBO_DONE
diff --git a/code/modules/martial_arts/combos/cqc/pressure.dm b/code/modules/martial_arts/combos/cqc/pressure.dm
new file mode 100644
index 00000000000..b19bfb6ddf7
--- /dev/null
+++ b/code/modules/martial_arts/combos/cqc/pressure.dm
@@ -0,0 +1,11 @@
+/datum/martial_combo/cqc/pressure
+ name = "Pressure"
+ steps = list(MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_GRAB)
+ explaination_text = "Decent stamina damage."
+
+/datum/martial_combo/cqc/pressure/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ target.visible_message("[user] forces their arm on [target]'s neck!")
+ target.adjustStaminaLoss(60)
+ playsound(get_turf(user), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Pressure", ATKLOG_ALL)
+ return MARTIAL_COMBO_DONE
diff --git a/code/modules/martial_arts/combos/cqc/restrain.dm b/code/modules/martial_arts/combos/cqc/restrain.dm
new file mode 100644
index 00000000000..e9495c61dba
--- /dev/null
+++ b/code/modules/martial_arts/combos/cqc/restrain.dm
@@ -0,0 +1,22 @@
+/datum/martial_combo/cqc/restrain
+ name = "Restrain"
+ steps = list(MARTIAL_COMBO_STEP_GRAB, MARTIAL_COMBO_STEP_GRAB)
+ explaination_text = "Locks opponents into a restraining position, disarm to knock them out with a choke hold."
+ combo_text_override = "Grab, switch hands, Grab"
+
+/datum/martial_combo/cqc/restrain/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ var/datum/martial_art/cqc/CQC = MA
+ if(!istype(CQC))
+ return MARTIAL_COMBO_FAIL
+ if(CQC.restraining)
+ return MARTIAL_COMBO_FAIL
+ if(!target.stat)
+ target.visible_message("[user] locks [target] into a restraining position!", \
+ "[user] locks you into a restraining position!")
+ target.adjustStaminaLoss(20)
+ target.Stun(5)
+ CQC.restraining = TRUE
+ addtimer(CALLBACK(CQC, /datum/martial_art/cqc/.proc/drop_restraining), 50, TIMER_UNIQUE)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Restrain", ATKLOG_ALL)
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_FAIL
diff --git a/code/modules/martial_arts/combos/cqc/slam.dm b/code/modules/martial_arts/combos/cqc/slam.dm
new file mode 100644
index 00000000000..8c1a84d7817
--- /dev/null
+++ b/code/modules/martial_arts/combos/cqc/slam.dm
@@ -0,0 +1,16 @@
+/datum/martial_combo/cqc/slam
+ name = "Slam"
+ steps = list(MARTIAL_COMBO_STEP_GRAB, MARTIAL_COMBO_STEP_HARM)
+ explaination_text = "Slam opponent into the ground, knocking them down."
+ combo_text_override = "Grab, switch hands, Harm"
+
+/datum/martial_combo/cqc/slam/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(!target.IsWeakened() && !target.resting && !target.lying)
+ target.visible_message("[user] slams [target] into the ground!", \
+ "[user] slams you into the ground!")
+ playsound(get_turf(user), 'sound/weapons/slam.ogg', 50, 1, -1)
+ target.apply_damage(10, BRUTE)
+ target.Weaken(6)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Slam", ATKLOG_ALL)
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_FAIL
diff --git a/code/modules/martial_arts/combos/krav_maga/leg_sweep.dm b/code/modules/martial_arts/combos/krav_maga/leg_sweep.dm
new file mode 100644
index 00000000000..0defb3e9eff
--- /dev/null
+++ b/code/modules/martial_arts/combos/krav_maga/leg_sweep.dm
@@ -0,0 +1,14 @@
+/datum/martial_combo/krav_maga/leg_sweep
+ name = "Leg Sweep"
+ explaination_text = "Trips the victim, rendering them prone and unable to move for a short time."
+
+/datum/martial_combo/krav_maga/leg_sweep/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(target.stat || target.IsWeakened())
+ return FALSE
+ target.visible_message("[user] leg sweeps [target]!", \
+ "[user] leg sweeps you!")
+ playsound(get_turf(user), 'sound/effects/hit_kick.ogg', 50, 1, -1)
+ target.apply_damage(5, BRUTE)
+ target.Weaken(2)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Leg Sweep", ATKLOG_ALL)
+ return MARTIAL_COMBO_DONE_CLEAR_COMBOS
diff --git a/code/modules/martial_arts/combos/krav_maga/lung_punch.dm b/code/modules/martial_arts/combos/krav_maga/lung_punch.dm
new file mode 100644
index 00000000000..e71289f9174
--- /dev/null
+++ b/code/modules/martial_arts/combos/krav_maga/lung_punch.dm
@@ -0,0 +1,12 @@
+/datum/martial_combo/krav_maga/lung_punch
+ name = "Lung Punch"
+ explaination_text = "Delivers a strong punch just above the victim's abdomen, constraining the lungs. The victim will be unable to breathe for a short time."
+
+/datum/martial_combo/krav_maga/lung_punch/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ target.visible_message("[user] pounds [target] on the chest!", \
+ "[user] slams your chest! You can't breathe!")
+ playsound(get_turf(user), 'sound/effects/hit_punch.ogg', 50, 1, -1)
+ target.AdjustLoseBreath(5)
+ target.adjustOxyLoss(10)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Lung Punch", ATKLOG_ALL)
+ return MARTIAL_COMBO_DONE_CLEAR_COMBOS
diff --git a/code/modules/martial_arts/combos/krav_maga/neck_chop.dm b/code/modules/martial_arts/combos/krav_maga/neck_chop.dm
new file mode 100644
index 00000000000..c0e2f71b6a5
--- /dev/null
+++ b/code/modules/martial_arts/combos/krav_maga/neck_chop.dm
@@ -0,0 +1,12 @@
+/datum/martial_combo/krav_maga/neck_chop
+ name = "Neck Chop"
+ explaination_text = "Injures the neck, stopping the victim from speaking for a while."
+
+/datum/martial_combo/krav_maga/neck_chop/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ target.visible_message("[user] karate chops [target]'s neck!", \
+ "[user] karate chops your neck, rendering you unable to speak for a short time!")
+ playsound(get_turf(user), 'sound/effects/hit_punch.ogg', 50, 1, -1)
+ target.apply_damage(5, BRUTE)
+ target.AdjustSilence(10)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Neck Chop", ATKLOG_ALL)
+ return MARTIAL_COMBO_DONE_CLEAR_COMBOS
diff --git a/code/modules/martial_arts/combos/martial_combo.dm b/code/modules/martial_arts/combos/martial_combo.dm
new file mode 100644
index 00000000000..6b4eedb97dc
--- /dev/null
+++ b/code/modules/martial_arts/combos/martial_combo.dm
@@ -0,0 +1,36 @@
+/datum/martial_combo
+ /// Name used to explain the combo
+ var/name = "Code Fu"
+ /// Which steps need to be performed
+ var/list/steps
+ /// What index to check
+ var/current_step_index = 1
+ /// Who is the target the combo is being executed on
+ var/current_combo_target = null
+ /// If you require to do the combo's on the same target
+ var/combos_require_same_target = TRUE
+ /// What does it do
+ var/explaination_text = "Ability to break shit"
+ /// How to do the combo. If null it'll auto generate it from the steps
+ var/combo_text_override
+
+/datum/martial_combo/proc/check_combo(step, mob/living/target)
+ if(!combos_require_same_target || current_combo_target == null || current_combo_target == target)
+ if(!length(steps) || step == steps[current_step_index])
+ return TRUE
+ return FALSE
+
+/datum/martial_combo/proc/progress_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ current_combo_target = target
+ if(current_step_index++ >= LAZYLEN(steps))
+ return perform_combo(user, target, MA)
+ return MARTIAL_COMBO_CONTINUE
+
+/datum/martial_combo/proc/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ return MARTIAL_COMBO_FAIL // Override this
+
+/datum/martial_combo/proc/give_explaination(user)
+ var/final_combo_text = combo_text_override
+ if(!final_combo_text)
+ final_combo_text = english_list(steps, and_text = " ", comma_text = " ")
+ to_chat(user, "[name]: [final_combo_text]. [explaination_text]")
diff --git a/code/modules/martial_arts/combos/mimejutsu/mimechucks.dm b/code/modules/martial_arts/combos/mimejutsu/mimechucks.dm
new file mode 100644
index 00000000000..b7f2d247b4b
--- /dev/null
+++ b/code/modules/martial_arts/combos/mimejutsu/mimechucks.dm
@@ -0,0 +1,26 @@
+/datum/martial_combo/mimejutsu/mimechucks
+ name = "Mimechucks"
+ steps = list(MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_HARM)
+ explaination_text = "Hits the opponent with invisible nunchucks."
+
+/datum/martial_combo/mimejutsu/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(!target.stat && !target.stunned && !target.IsWeakened())
+ var/damage = rand(5, 8) + user.dna.species.punchdamagelow
+ if(!damage)
+ playsound(target.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ target.visible_message("[user] swings invisible nunchcuks at [target]..and misses?")
+ return MARTIAL_COMBO_DONE
+
+
+ var/obj/item/organ/external/affecting = target.get_organ(ran_zone(user.zone_selected))
+ var/armor_block = target.run_armor_check(affecting, "melee")
+
+ target.visible_message("[user] has hit [target] with invisible nunchucks!", \
+ "[user] has hit [target] with a with invisible nunchuck!")
+ playsound(get_turf(user), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+
+ target.apply_damage(damage, STAMINA, affecting, armor_block)
+ add_attack_logs(user, target, "Melee attacked with [src] (mimechuck)")
+
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_DONE_BASIC_HIT
diff --git a/code/modules/martial_arts/combos/mimejutsu/silent_palm.dm b/code/modules/martial_arts/combos/mimejutsu/silent_palm.dm
new file mode 100644
index 00000000000..eb8df68fac4
--- /dev/null
+++ b/code/modules/martial_arts/combos/mimejutsu/silent_palm.dm
@@ -0,0 +1,13 @@
+/datum/martial_combo/mimejutsu/silent_palm
+ name = "Silent Palm"
+ steps = list(MARTIAL_COMBO_STEP_GRAB, MARTIAL_COMBO_STEP_DISARM)
+ explaination_text = "Use mime energy to throw someone back."
+
+/datum/martial_combo/mimejutsu/silent_palm/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(!target.stat && !target.stunned && !target.IsWeakened())
+ target.visible_message("[user] has barely touched [target] with [user.p_their()] palm!", \
+ "[user] hovers [user.p_their()] palm over your face!")
+
+ var/atom/throw_target = get_edge_target_turf(target, get_dir(target, get_step_away(target, user)))
+ target.throw_at(throw_target, 200, 4, user)
+ return MARTIAL_COMBO_DONE_BASIC_HIT
diff --git a/code/modules/martial_arts/combos/mimejutsu/smokebomb.dm b/code/modules/martial_arts/combos/mimejutsu/smokebomb.dm
new file mode 100644
index 00000000000..23277fa5f0d
--- /dev/null
+++ b/code/modules/martial_arts/combos/mimejutsu/smokebomb.dm
@@ -0,0 +1,13 @@
+/datum/martial_combo/mimejutsu/smokebomb
+ name = "Smokebomb"
+ steps = list(MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_DISARM)
+ explaination_text = "Drops a mime smokebomb."
+
+/datum/martial_combo/mimejutsu/smokebomb/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ target.visible_message("[user] throws an invisible smoke bomb!!")
+
+ var/datum/effect_system/smoke_spread/bad/smoke = new
+ smoke.set_up(5, 0, target.loc)
+ smoke.start()
+
+ return MARTIAL_COMBO_DONE_BASIC_HIT
diff --git a/code/modules/martial_arts/combos/plasma_fist/plasma_fist.dm b/code/modules/martial_arts/combos/plasma_fist/plasma_fist.dm
new file mode 100644
index 00000000000..93c3e3ef480
--- /dev/null
+++ b/code/modules/martial_arts/combos/plasma_fist/plasma_fist.dm
@@ -0,0 +1,13 @@
+/datum/martial_combo/plasma_fist/plasma_fist
+ name = "The Plasma Fist"
+ steps = list(MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_HARM)
+ explaination_text = "Knocks the brain out of the opponent and gibs their body."
+
+/datum/martial_combo/plasma_fist/plasma_fist/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ user.do_attack_animation(target, ATTACK_EFFECT_PUNCH)
+ playsound(target.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
+ user.say("PLASMA FIST!")
+ target.visible_message("[user] has hit [target] with THE PLASMA FIST TECHNIQUE!", \
+ "[user] has hit [target] with THE PLASMA FIST TECHNIQUE!")
+ target.gib()
+ return MARTIAL_COMBO_DONE
diff --git a/code/modules/martial_arts/combos/plasma_fist/throwback.dm b/code/modules/martial_arts/combos/plasma_fist/throwback.dm
new file mode 100644
index 00000000000..7057452a913
--- /dev/null
+++ b/code/modules/martial_arts/combos/plasma_fist/throwback.dm
@@ -0,0 +1,13 @@
+/datum/martial_combo/plasma_fist/throwback
+ name = "Throwback"
+ steps = list(MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_DISARM)
+ explaination_text = "Throws the target and an item at them."
+
+/datum/martial_combo/plasma_fist/throwback/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ target.visible_message("[user] has hit [target] with Plasma Punch!", \
+ "[user] has hit [target] with Plasma Punch!")
+ playsound(target.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
+ var/atom/throw_target = get_edge_target_turf(target, get_dir(target, get_step_away(target, user)))
+ target.throw_at(throw_target, 200, 4, user)
+ user.say("HYAH!")
+ return MARTIAL_COMBO_DONE
diff --git a/code/modules/martial_arts/combos/plasma_fist/tornado_sweep.dm b/code/modules/martial_arts/combos/plasma_fist/tornado_sweep.dm
new file mode 100644
index 00000000000..41a7bd676d3
--- /dev/null
+++ b/code/modules/martial_arts/combos/plasma_fist/tornado_sweep.dm
@@ -0,0 +1,20 @@
+/datum/martial_combo/plasma_fist/tornado_sweep
+ name = "Tornado Sweep"
+ steps = list(MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_DISARM)
+ explaination_text = "Repulses target and everyone back."
+
+/datum/martial_combo/plasma_fist/tornado_sweep/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ user.say("TORNADO SWEEP!")
+ INVOKE_ASYNC(src, .proc/do_tornado_effect, user)
+ var/obj/effect/proc_holder/spell/aoe_turf/repulse/R = new(null)
+ var/list/turfs = list()
+ for(var/turf/T in range(1,user))
+ turfs.Add(T)
+ R.cast(turfs)
+ return MARTIAL_COMBO_DONE
+
+/datum/martial_combo/plasma_fist/tornado_sweep/proc/do_tornado_effect(mob/living/carbon/human/user)
+ for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH))
+ user.dir = i
+ playsound(user.loc, 'sound/weapons/punch1.ogg', 15, 1, -1)
+ sleep(1)
diff --git a/code/modules/martial_arts/combos/sleeping_carp/back_kick.dm b/code/modules/martial_arts/combos/sleeping_carp/back_kick.dm
new file mode 100644
index 00000000000..3ebaa191e23
--- /dev/null
+++ b/code/modules/martial_arts/combos/sleeping_carp/back_kick.dm
@@ -0,0 +1,18 @@
+/datum/martial_combo/sleeping_carp/back_kick
+ name = "Back Kick"
+ steps = list(MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_GRAB)
+ explaination_text = "Opponent must be facing away. Knocks down."
+
+/datum/martial_combo/sleeping_carp/back_kick/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(user.dir == target.dir && !target.stat && !target.IsWeakened())
+ user.do_attack_animation(target, ATTACK_EFFECT_KICK)
+ target.visible_message("[user] kicks [target] in the back!", \
+ "[user] kicks you in the back, making you stumble and fall!")
+ step_to(target,get_step(target,target.dir),1)
+ target.Weaken(4)
+ playsound(get_turf(target), 'sound/weapons/punch1.ogg', 50, 1, -1)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Back Kick", ATKLOG_ALL)
+ if(prob(80))
+ user.say(pick("SURRPRIZU!","BACK STRIKE!","WOPAH!", "WATAAH", "ZOTA!", "Never turn your back to the enemy!"))
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_DONE_BASIC_HIT
diff --git a/code/modules/martial_arts/combos/sleeping_carp/elbow_drop.dm b/code/modules/martial_arts/combos/sleeping_carp/elbow_drop.dm
new file mode 100644
index 00000000000..0269c9bed4d
--- /dev/null
+++ b/code/modules/martial_arts/combos/sleeping_carp/elbow_drop.dm
@@ -0,0 +1,18 @@
+/datum/martial_combo/sleeping_carp/elbow_drop
+ name = "Elbow Drop"
+ steps = list(MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_HARM)
+ explaination_text = "Opponent must be on the ground. Deals huge damage, instantly kills anyone in critical condition."
+
+/datum/martial_combo/sleeping_carp/elbow_drop/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(target.IsWeakened() || target.resting || target.stat)
+ user.do_attack_animation(target, ATTACK_EFFECT_PUNCH)
+ target.visible_message("[user] elbow drops [target]!", \
+ "[user] piledrives you with [user.p_their()] elbow!")
+ target.death() //FINISH HIM!
+ target.apply_damage(50, BRUTE, "chest")
+ playsound(get_turf(target), 'sound/weapons/punch1.ogg', 75, 1, -1)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Elbow Drop", ATKLOG_ALL)
+ if(prob(80))
+ user.say(pick("BANZAIII!", "KIYAAAA!", "OMAE WA MOU SHINDEIRU!", "YOU CAN'T SEE ME!", "MY TIME IS NOW!", "COWABUNGA"))
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_DONE_BASIC_HIT
diff --git a/code/modules/martial_arts/combos/sleeping_carp/head_kick.dm b/code/modules/martial_arts/combos/sleeping_carp/head_kick.dm
new file mode 100644
index 00000000000..b45e10e73ce
--- /dev/null
+++ b/code/modules/martial_arts/combos/sleeping_carp/head_kick.dm
@@ -0,0 +1,19 @@
+/datum/martial_combo/sleeping_carp/head_kick
+ name = "Head Kick"
+ steps = list(MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_HARM, MARTIAL_COMBO_STEP_HARM)
+ explaination_text = "Decent damage, forces opponent to drop item in hand."
+
+/datum/martial_combo/sleeping_carp/head_kick/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(!target.stat && !target.IsWeakened())
+ user.do_attack_animation(target, ATTACK_EFFECT_KICK)
+ target.visible_message("[user] kicks [target] in the head!", \
+ "[user] kicks you in the jaw!")
+ target.apply_damage(20, BRUTE, "head")
+ target.drop_item()
+ playsound(get_turf(target), 'sound/weapons/punch1.ogg', 50, 1, -1)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Head Kick", ATKLOG_ALL)
+ if(prob(60))
+ user.say(pick("OOHYOO!", "OOPYAH!", "HYOOAA!", "WOOAAA!", "SHURYUKICK!", "HIYAH!"))
+ target.Stun(4)
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_DONE_BASIC_HIT
diff --git a/code/modules/martial_arts/combos/sleeping_carp/stomach_knee.dm b/code/modules/martial_arts/combos/sleeping_carp/stomach_knee.dm
new file mode 100644
index 00000000000..312e575003d
--- /dev/null
+++ b/code/modules/martial_arts/combos/sleeping_carp/stomach_knee.dm
@@ -0,0 +1,20 @@
+/datum/martial_combo/sleeping_carp/stomach_knee
+ name = "Stomach Knee"
+ steps = list(MARTIAL_COMBO_STEP_GRAB, MARTIAL_COMBO_STEP_HARM)
+ explaination_text = "Knocks the wind out of opponent and stuns."
+ combo_text_override = "Grab, switch hands, Harm"
+
+/datum/martial_combo/sleeping_carp/stomach_knee/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(!target.stat && !target.IsWeakened())
+ user.do_attack_animation(target, ATTACK_EFFECT_KICK)
+ target.visible_message("[user] knees [target] in the stomach!", \
+ "[user] winds you with a knee in the stomach!")
+ target.audible_message("[target] gags!")
+ target.AdjustLoseBreath(3)
+ target.Stun(2)
+ playsound(get_turf(target), 'sound/weapons/punch1.ogg', 50, 1, -1)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Stomach Knee", ATKLOG_ALL)
+ if(prob(80))
+ user.say(pick("HWOP!", "KUH!", "YAKUUH!", "KYUH!", "KNEESTRIKE!"))
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_DONE_BASIC_HIT
diff --git a/code/modules/martial_arts/combos/sleeping_carp/wrist_wrench.dm b/code/modules/martial_arts/combos/sleeping_carp/wrist_wrench.dm
new file mode 100644
index 00000000000..38c21e7309e
--- /dev/null
+++ b/code/modules/martial_arts/combos/sleeping_carp/wrist_wrench.dm
@@ -0,0 +1,20 @@
+/datum/martial_combo/sleeping_carp/wrist_wrench
+ name = "Wrist Wrench"
+ steps = list(MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_DISARM)
+ explaination_text = "Forces opponent to drop item in hand."
+
+/datum/martial_combo/sleeping_carp/wrist_wrench/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
+ if(!target.stat && !target.stunned && !target.IsWeakened())
+ user.do_attack_animation(target, ATTACK_EFFECT_PUNCH)
+ target.visible_message("[user] grabs [target]'s wrist and wrenches it sideways!", \
+ "[user] grabs your wrist and violently wrenches it to the side!")
+ playsound(get_turf(user), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ add_attack_logs(user, target, "Melee attacked with martial-art [src] : Wrist Wrench", ATKLOG_ALL)
+ if(prob(60))
+ user.say(pick("WRISTY TWIRLY!", "WE FIGHT LIKE MEN!", "YOU DISHONOR YOURSELF!", "POHYAH!", "WHERE IS YOUR BATON NOW?", "SAY UNCLE!"))
+ target.emote("scream")
+ target.drop_item()
+ target.apply_damage(5, BRUTE, pick("l_arm", "r_arm"))
+ target.Stun(3)
+ return MARTIAL_COMBO_DONE
+ return MARTIAL_COMBO_DONE_BASIC_HIT
diff --git a/code/modules/martial_arts/cqc.dm b/code/modules/martial_arts/cqc.dm
index f0b5c016c5b..49a08c1bd3c 100644
--- a/code/modules/martial_arts/cqc.dm
+++ b/code/modules/martial_arts/cqc.dm
@@ -1,152 +1,27 @@
-#define SLAM_COMBO "GH"
-#define KICK_COMBO "HH"
-#define RESTRAIN_COMBO "GG"
-#define PRESSURE_COMBO "DG"
-#define CONSECUTIVE_COMBO "DDH"
-
/datum/martial_art/cqc
name = "CQC"
- help_verb = /mob/living/carbon/human/proc/CQC_help
block_chance = 75
- var/just_a_cook = FALSE
+ has_explaination_verb = TRUE
+ combos = list(/datum/martial_combo/cqc/slam, /datum/martial_combo/cqc/kick, /datum/martial_combo/cqc/restrain, /datum/martial_combo/cqc/pressure, /datum/martial_combo/cqc/consecutive)
+ var/restraining = FALSE //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not
var/static/list/areas_under_siege = typecacheof(list(/area/crew_quarters/kitchen,
/area/crew_quarters/cafeteria,
/area/crew_quarters/bar))
/datum/martial_art/cqc/under_siege
name = "Close Quarters Cooking"
- just_a_cook = TRUE
+
+/datum/martial_art/cqc/under_siege/can_use(mob/living/carbon/human/H)
+ var/area/A = get_area(H)
+ if(!(is_type_in_typecache(A, areas_under_siege)))
+ return FALSE
+ return ..()
/datum/martial_art/cqc/proc/drop_restraining()
restraining = FALSE
-/datum/martial_art/cqc/can_use(mob/living/carbon/human/H)
- var/area/A = get_area(H)
- if(just_a_cook && !(is_type_in_typecache(A, areas_under_siege)))
- return FALSE
- return ..()
-
-/datum/martial_art/cqc/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(!can_use(A))
- return FALSE
- if(findtext(streak, SLAM_COMBO))
- streak = ""
- Slam(A, D)
- return TRUE
- if(findtext(streak, KICK_COMBO))
- streak = ""
- Kick(A, D)
- return TRUE
- if(findtext(streak, RESTRAIN_COMBO))
- streak = ""
- Restrain(A, D)
- return TRUE
- if(findtext(streak, PRESSURE_COMBO))
- streak = ""
- Pressure(A, D)
- return TRUE
- if(findtext(streak, CONSECUTIVE_COMBO))
- streak = ""
- Consecutive(A, D)
- return FALSE
-
-/datum/martial_art/cqc/proc/Slam(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(!can_use(A))
- return FALSE
- if(!D.IsWeakened() && !D.resting && !D.lying)
- D.visible_message("[A] slams [D] into the ground!", \
- "[A] slams you into the ground!")
- playsound(get_turf(A), 'sound/weapons/slam.ogg', 50, 1, -1)
- D.apply_damage(10, BRUTE)
- D.Weaken(6)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Slam", ATKLOG_ALL)
- return TRUE
- streak = ""
- harm_act(A, D)
- streak = ""
- return TRUE
-
-/datum/martial_art/cqc/proc/Kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(!can_use(A))
- return FALSE
- var/success = FALSE
- if(!D.stat || !D.IsWeakened())
- D.visible_message("[A] kicks [D] back!", \
- "[A] kicks you back!")
- playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
- var/atom/throw_target = get_edge_target_turf(D, A.dir)
- D.throw_at(throw_target, 1, 14, A)
- D.apply_damage(10, BRUTE)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Kick", ATKLOG_ALL)
- success = TRUE
- if(D.IsWeakened() && !D.stat)
- D.visible_message("[A] kicks [D]'s head, knocking [D.p_them()] out!", \
- "[A] kicks your head, knocking you out!")
- playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1)
- D.SetSleeping(15)
- D.adjustBrainLoss(15)
- add_attack_logs(A, D, "Knocked out with martial-art [src] : Kick", ATKLOG_ALL)
- success = TRUE
- if(success)
- return TRUE
- streak = ""
- harm_act(A, D)
- streak = ""
- return TRUE
-
-/datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(!can_use(A))
- return FALSE
- D.visible_message("[A] forces their arm on [D]'s neck!")
- D.adjustStaminaLoss(60)
- playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Pressure", ATKLOG_ALL)
- return TRUE
-
-/datum/martial_art/cqc/proc/Restrain(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(restraining)
- return
- if(!can_use(A))
- return FALSE
- if(!D.stat)
- D.visible_message("[A] locks [D] into a restraining position!", \
- "[A] locks you into a restraining position!")
- D.adjustStaminaLoss(20)
- D.Stun(5)
- restraining = TRUE
- addtimer(CALLBACK(src, .proc/drop_restraining), 50, TIMER_UNIQUE)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Restrain", ATKLOG_ALL)
- return TRUE
- streak = ""
- harm_act(A, D)
- streak = ""
- return TRUE
-
-/datum/martial_art/cqc/proc/Consecutive(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(!can_use(A))
- return FALSE
- if(!D.stat)
- D.visible_message("[A] strikes [D]'s abdomen, neck and back consecutively", \
- "[A] strikes your abdomen, neck and back consecutively!")
- playsound(get_turf(D), 'sound/weapons/cqchit2.ogg', 50, 1, -1)
- var/obj/item/I = D.get_active_hand()
- if(I && D.drop_item())
- A.put_in_hands(I)
- D.adjustStaminaLoss(50)
- D.apply_damage(25, BRUTE)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Consecutive", ATKLOG_ALL)
- return TRUE
- streak = ""
- harm_act(A, D)
- streak = ""
- return TRUE
-
/datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(!can_use(A))
- return FALSE
- add_to_streak("G", D)
- if(check_streak(A, D))
- return TRUE
+ MARTIAL_ARTS_ACT_CHECK
var/obj/item/grab/G = D.grabbedby(A, 1)
if(G)
G.state = GRAB_AGGRESSIVE //Instant aggressive grab
@@ -155,11 +30,7 @@
return TRUE
/datum/martial_art/cqc/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(!can_use(A))
- return FALSE
- add_to_streak("H", D)
- if(check_streak(A, D))
- return TRUE
+ MARTIAL_ARTS_ACT_CHECK
add_attack_logs(A, D, "Melee attacked with martial-art [src]", ATKLOG_ALL)
A.do_attack_animation(D)
var/picked_hit_type = pick("CQC'd", "neck chopped", "gut punched", "Big Bossed")
@@ -185,12 +56,7 @@
return TRUE
/datum/martial_art/cqc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
- if(!can_use(A))
- return FALSE
- add_to_streak("D", D)
- var/obj/item/I = null
- if(check_streak(A, D))
- return TRUE
+ MARTIAL_ARTS_ACT_CHECK
var/obj/item/grab/G = A.get_inactive_hand()
if(restraining && istype(G) && G.affecting == D)
D.visible_message("[A] puts [D] into a chokehold!", \
@@ -203,6 +69,8 @@
else
restraining = FALSE
+ var/obj/item/I = null
+
if(prob(65))
if(!D.stat || !D.IsWeakened() || !restraining)
I = D.get_active_hand()
@@ -220,16 +88,8 @@
add_attack_logs(A, D, "Melee attacked with martial-art [src] : Disarmed [I ? " grabbing \the [I]" : ""]", ATKLOG_ALL)
return TRUE
-/mob/living/carbon/human/proc/CQC_help()
- set name = "Remember The Basics"
- set desc = "You try to remember some of the basics of CQC."
- set category = "CQC"
- to_chat(usr, "You try to remember some of the basics of CQC.")
+/datum/martial_art/cqc/explaination_header(user)
+ to_chat(user, "You try to remember some of the basics of CQC.")
- to_chat(usr, "Slam: Grab, switch hands, Harm. Slam opponent into the ground, knocking them down.")
- to_chat(usr, "CQC Kick: Harm Harm. Knocks opponent away. Knocks out stunned or knocked down opponents.")
- to_chat(usr, "Restrain: Grab, switch hands, Grab. Locks opponents into a restraining position, disarm to knock them out with a choke hold.")
- to_chat(usr, "Pressure: Disarm Grab. Decent stamina damage.")
- to_chat(usr, "Consecutive CQC: Disarm Disarm Harm. Mainly offensive move, huge damage and decent stamina damage.")
-
- to_chat(usr, "In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter attacks done to you.")
+/datum/martial_art/cqc/explaination_footer(user)
+ to_chat(user, "In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter attacks done to you.")
diff --git a/code/modules/martial_arts/krav_maga.dm b/code/modules/martial_arts/krav_maga.dm
index d348b3765fb..cd3a6214e83 100644
--- a/code/modules/martial_arts/krav_maga.dm
+++ b/code/modules/martial_arts/krav_maga.dm
@@ -15,7 +15,9 @@
to_chat(owner, "Your next attack will be a Neck Chop.")
owner.visible_message("[owner] assumes the Neck Chop stance!")
var/mob/living/carbon/human/H = owner
- H.martial_art.streak = "neck_chop"
+ H.mind.martial_art.combos.Cut()
+ H.mind.martial_art.combos.Add(/datum/martial_combo/krav_maga/neck_chop)
+ H.mind.martial_art.reset_combos()
/datum/action/leg_sweep
name = "Leg Sweep - Trips the victim, rendering them prone and unable to move for a short time."
@@ -28,7 +30,9 @@
to_chat(owner, "Your next attack will be a Leg Sweep.")
owner.visible_message("[owner] assumes the Leg Sweep stance!")
var/mob/living/carbon/human/H = owner
- H.martial_art.streak = "leg_sweep"
+ H.mind.martial_art.combos.Cut()
+ H.mind.martial_art.combos.Add(/datum/martial_combo/krav_maga/leg_sweep)
+ H.mind.martial_art.reset_combos()
/datum/action/lung_punch//referred to internally as 'quick choke'
name = "Lung Punch - Delivers a strong punch just above the victim's abdomen, constraining the lungs. The victim will be unable to breathe for a short time."
@@ -41,7 +45,9 @@
to_chat(owner, "Your next attack will be a Lung Punch.")
owner.visible_message("[owner] assumes the Lung Punch stance!")
var/mob/living/carbon/human/H = owner
- H.martial_art.streak = "quick_choke"//internal name for lung punch
+ H.mind.martial_art.combos.Cut()
+ H.mind.martial_art.combos.Add(/datum/martial_combo/krav_maga/lung_punch)
+ H.mind.martial_art.reset_combos()
/datum/martial_art/krav_maga/teach(var/mob/living/carbon/human/H,var/make_temporary=0)
..()
@@ -58,59 +64,8 @@
legsweep.Remove(H)
lungpunch.Remove(H)
-/datum/martial_art/krav_maga/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- switch(streak)
- if("neck_chop")
- streak = ""
- neck_chop(A,D)
- return 1
- if("leg_sweep")
- streak = ""
- leg_sweep(A,D)
- return 1
- if("quick_choke")//is actually lung punch
- streak = ""
- quick_choke(A,D)
- return 1
- return 0
-
-/datum/martial_art/krav_maga/proc/leg_sweep(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(D.stat || D.IsWeakened())
- return 0
- D.visible_message("[A] leg sweeps [D]!", \
- "[A] leg sweeps you!")
- playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
- D.apply_damage(5, BRUTE)
- D.Weaken(2)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Leg Sweep", ATKLOG_ALL)
- return 1
-
-/datum/martial_art/krav_maga/proc/quick_choke(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)//is actually lung punch
- D.visible_message("[A] pounds [D] on the chest!", \
- "[A] slams your chest! You can't breathe!")
- playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
- D.AdjustLoseBreath(5)
- D.adjustOxyLoss(10)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Lung Punch", ATKLOG_ALL)
- return 1
-
-/datum/martial_art/krav_maga/proc/neck_chop(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- D.visible_message("[A] karate chops [D]'s neck!", \
- "[A] karate chops your neck, rendering you unable to speak for a short time!")
- playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
- D.apply_damage(5, BRUTE)
- D.AdjustSilence(10)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Neck Chop", ATKLOG_ALL)
- return 1
-
-/datum/martial_art/krav_maga/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(check_streak(A,D))
- return 1
- ..()
-
/datum/martial_art/krav_maga/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(check_streak(A,D))
- return 1
+ MARTIAL_ARTS_ACT_CHECK
add_attack_logs(A, D, "Melee attacked with [src]")
var/picked_hit_type = pick("punches", "kicks")
var/bonus_damage = 10
@@ -126,11 +81,10 @@
playsound(get_turf(D), 'sound/effects/hit_punch.ogg', 50, 1, -1)
D.visible_message("[A] [picked_hit_type] [D]!", \
"[A] [picked_hit_type] you!")
- return 1
+ return TRUE
/datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(check_streak(A,D))
- return 1
+ MARTIAL_ARTS_ACT_CHECK
if(prob(60))
if(D.hand)
if(istype(D.l_hand, /obj/item))
@@ -149,7 +103,7 @@
D.visible_message("[A] attempted to disarm [D]!", \
"[A] attempted to disarm [D]!")
playsound(D, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- return 1
+ return TRUE
//Krav Maga Gloves
diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm
index 8969463be1d..50ca634a22f 100644
--- a/code/modules/martial_arts/martial.dm
+++ b/code/modules/martial_arts/martial.dm
@@ -1,42 +1,87 @@
+#define HAS_COMBOS LAZYLEN(combos)
+#define COMBO_ALIVE_TIME 5 SECONDS // How long the combo stays alive when no new attack is done
+
/datum/martial_art
var/name = "Martial Art"
var/streak = ""
var/max_streak_length = 6
- var/current_target = null
- var/temporary = 0
+ var/temporary = FALSE
var/datum/martial_art/base = null // The permanent style
var/deflection_chance = 0 //Chance to deflect projectiles
var/block_chance = 0 //Chance to block melee attacks using items while on throw mode.
- var/restraining = 0 //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not
var/help_verb = null
var/no_guns = FALSE //set to TRUE to prevent users of this style from using guns (sleeping carp, highlander). They can still pick them up, but not fire them.
var/no_guns_message = "" //message to tell the style user if they try and use a gun while no_guns = TRUE (DISHONORABRU!)
-/datum/martial_art/proc/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- return 0
+ var/has_explaination_verb = FALSE // If the martial art has it's own explaination verb
-/datum/martial_art/proc/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- return 0
+ var/list/combos = list() // What combos can the user do? List of combo types
+ var/list/datum/martial_art/current_combos = list() // What combos are currently (possibly) being performed
+ var/last_hit = 0 // When the last hit happened
-/datum/martial_art/proc/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- return 0
+/datum/martial_art/New()
+ . = ..()
+ reset_combos()
-/datum/martial_art/proc/help_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- return 0
+/datum/martial_art/proc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ return act(MARTIAL_COMBO_STEP_DISARM, A, D)
+
+/datum/martial_art/proc/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ return act(MARTIAL_COMBO_STEP_HARM, A, D)
+
+/datum/martial_art/proc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ return act(MARTIAL_COMBO_STEP_GRAB, A, D)
+
+/datum/martial_art/proc/help_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ return act(MARTIAL_COMBO_STEP_HELP, A, D)
/datum/martial_art/proc/can_use(mob/living/carbon/human/H)
return TRUE
-/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/act(step, mob/living/carbon/human/user, mob/living/carbon/human/target)
+ if(!can_use(user))
+ return MARTIAL_ARTS_CANNOT_USE
+ if(last_hit + COMBO_ALIVE_TIME < world.time)
+ reset_combos()
+ last_hit = world.time
-/datum/martial_art/proc/basic_hit(var/mob/living/carbon/human/A,var/mob/living/carbon/human/D)
+ if(HAS_COMBOS)
+ return check_combos(step, user, target)
+ return FALSE
+
+/datum/martial_art/proc/reset_combos()
+ current_combos.Cut()
+ for(var/combo_type in combos)
+ current_combos.Add(new combo_type())
+
+/datum/martial_art/proc/check_combos(step, mob/living/carbon/human/user, mob/living/carbon/human/target)
+ . = FALSE
+ for(var/thing in current_combos)
+ var/datum/martial_combo/MC = thing
+ if(!MC.check_combo(step, target))
+ current_combos -= MC // It failed so remove it
+ else
+ switch(MC.progress_combo(user, target, src))
+ if(MARTIAL_COMBO_FAIL)
+ current_combos -= MC
+ if(MARTIAL_COMBO_DONE_NO_CLEAR)
+ . = TRUE
+ current_combos -= MC
+ if(MARTIAL_COMBO_DONE)
+ reset_combos()
+ return TRUE
+ if(MARTIAL_COMBO_DONE_BASIC_HIT)
+ basic_hit(user, target)
+ reset_combos()
+ return TRUE
+ if(MARTIAL_COMBO_DONE_CLEAR_COMBOS)
+ combos.Cut()
+ reset_combos()
+ return TRUE
+ if(!LAZYLEN(current_combos))
+ reset_combos()
+
+/datum/martial_art/proc/basic_hit(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
var/datum/unarmed_attack/attack = A.dna.species.unarmed
@@ -54,7 +99,7 @@
if(!damage)
playsound(D.loc, attack.miss_sound, 25, 1, -1)
D.visible_message("[A] has attempted to [atk_verb] [D]!")
- return 0
+ return FALSE
var/obj/item/organ/external/affecting = D.get_organ(ran_zone(A.zone_selected))
var/armor_block = D.run_armor_check(affecting, "melee")
@@ -74,26 +119,60 @@
D.forcesay(GLOB.hit_appends)
else if(D.lying)
D.forcesay(GLOB.hit_appends)
- return 1
+ return TRUE
-/datum/martial_art/proc/teach(var/mob/living/carbon/human/H,var/make_temporary=0)
- if(help_verb)
- H.verbs += help_verb
+/datum/martial_art/proc/teach(mob/living/carbon/human/H, make_temporary = FALSE)
+ if(!H.mind)
+ return
+ if(has_explaination_verb)
+ H.verbs |= /mob/living/carbon/human/proc/martial_arts_help
if(make_temporary)
- temporary = 1
+ temporary = TRUE
if(temporary)
- if(H.martial_art)
- base = H.martial_art.base
+ if(H.mind.martial_art)
+ base = H.mind.martial_art.base
else
base = src
- H.martial_art = src
+ H.mind.martial_art = src
/datum/martial_art/proc/remove(var/mob/living/carbon/human/H)
- if(H.martial_art != src)
+ if(!H.mind)
return
- H.martial_art = base
- if(help_verb)
- H.verbs -= help_verb
+ if(H.mind.martial_art != src)
+ return
+ H.mind.martial_art = base
+ if(has_explaination_verb && !(base && base.has_explaination_verb))
+ H.verbs -= /mob/living/carbon/human/proc/martial_arts_help
+
+/mob/living/carbon/human/proc/martial_arts_help()
+ set name = "Show Info"
+ set desc = "Gives information about the martial arts you know."
+ set category = "Martial Arts"
+ var/mob/living/carbon/human/H = usr
+ if(!istype(H))
+ to_chat(usr, "You shouldn't have access to this verb. Report this as a bug to the github please.")
+ return
+ H.mind.martial_art.give_explaination(H)
+
+/datum/martial_art/proc/give_explaination(user = usr)
+ explaination_header(user)
+ explaination_combos(user)
+ explaination_footer(user)
+
+// Put after the header and before the footer in the explaination text
+/datum/martial_art/proc/explaination_combos(user)
+ if(HAS_COMBOS)
+ for(var/combo_type in combos)
+ var/datum/martial_combo/MC = new combo_type()
+ MC.give_explaination(user)
+
+// Put on top of the explaination text
+/datum/martial_art/proc/explaination_header(user)
+ return
+
+// Put below the combos in the explaination text
+/datum/martial_art/proc/explaination_footer(user)
+ return
//ITEMS
@@ -283,3 +362,6 @@
if(wielded)
return ..()
return 0
+
+#undef HAS_COMBOS
+#undef COMBO_ALIVE_TIME
diff --git a/code/modules/martial_arts/mimejutsu.dm b/code/modules/martial_arts/mimejutsu.dm
index 38904d407de..d57df486638 100644
--- a/code/modules/martial_arts/mimejutsu.dm
+++ b/code/modules/martial_arts/mimejutsu.dm
@@ -1,90 +1,16 @@
-#define MIMECHUCKS_COMBO "DH"
-#define MIMESMOKE_COMBO "DD"
-#define MIMEPALM_COMBO "GD"
-
/datum/martial_art/mimejutsu
name = "Mimejutsu"
- help_verb = /mob/living/carbon/human/proc/mimejutsu_help
-
-/datum/martial_art/mimejutsu/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(findtext(streak,MIMECHUCKS_COMBO))
- streak = ""
- mimeChuck(A,D)
- return 1
- if(findtext(streak,MIMESMOKE_COMBO))
- streak = ""
- mimeSmoke(A,D)
- return 1
- if(findtext(streak,MIMEPALM_COMBO))
- streak = ""
- mimePalm(A,D)
- return 1
- return 0
-
-/datum/martial_art/mimejutsu/proc/mimeChuck(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(!D.stat && !D.stunned && !D.IsWeakened())
- var/damage = rand(5, 8) + A.dna.species.punchdamagelow
- if(!damage)
- playsound(D.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- D.visible_message("[A] swings invisible nunchcuks at [D]..and misses?")
- return 0
-
-
- var/obj/item/organ/external/affecting = D.get_organ(ran_zone(A.zone_selected))
- var/armor_block = D.run_armor_check(affecting, "melee")
-
- D.visible_message("[A] has hit [D] with invisible nunchucks!", \
- "[A] has hit [D] with a with invisible nunchuck!")
- playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
- D.apply_damage(damage, STAMINA, affecting, armor_block)
- add_attack_logs(A, D, "Melee attacked with [src] (mimechuck)")
-
- return 1
- return basic_hit(A,D)
-
-/datum/martial_art/mimejutsu/proc/mimeSmoke(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
-
- D.visible_message("[A] throws an invisible smoke bomb!!")
-
- var/datum/effect_system/smoke_spread/bad/smoke = new
- smoke.set_up(5, 0, D.loc)
- smoke.start()
-
- return basic_hit(A,D)
-
-/datum/martial_art/mimejutsu/proc/mimePalm(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(!D.stat && !D.stunned && !D.IsWeakened())
- D.visible_message("[A] has barely touched [D] with [A.p_their()] palm!", \
- "[A] hovers [A.p_their()] palm over your face!")
-
- 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)
- return basic_hit(A,D)
-
-
-/datum/martial_art/mimejutsu/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("D",D)
- if(check_streak(A,D))
- return 1
-
- return ..()
+ has_explaination_verb = TRUE
+ combos = list(/datum/martial_combo/mimejutsu/mimechucks, /datum/martial_combo/mimejutsu/smokebomb, /datum/martial_combo/mimejutsu/silent_palm)
/datum/martial_art/mimejutsu/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("G",D)
- if(check_streak(A,D))
- return 1
-
- return 1
+ MARTIAL_ARTS_ACT_CHECK
+ return TRUE
/datum/martial_art/mimejutsu/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("H",D)
- if(check_streak(A,D))
- return 1
-
+ MARTIAL_ARTS_ACT_CHECK
A.do_attack_animation(D)
-
- return 1
+ return TRUE
/obj/item/mimejutsu_scroll
name = "Mimejutsu 'scroll'"
@@ -106,13 +32,5 @@
name = "beret with staple"
icon_state = "beret"
-/mob/living/carbon/human/proc/mimejutsu_help()
- set name = "Recall Ancient Mimeing"
- set desc = "Remember the martial techniques of Mimejutsu."
- set category = "Mimejutsu"
-
- to_chat(usr, "You make a invisible box around yourself and recall the teachings of Mimejutsu...")
-
- to_chat(usr, "Mimechucks: Disarm Harm. Hits the opponent with invisible nunchucks.")
- to_chat(usr, "Smokebomb: Disarm Disarm. Drops a mime smokebomb.")
- to_chat(usr, "Silent Palm: Grab Disarm. Using mime energy throw someone back.")
+/datum/martial_art/mimejutsu/explaination_header(user)
+ to_chat(user, "You make a invisible box around yourself and recall the teachings of Mimejutsu...")
diff --git a/code/modules/martial_arts/plasma_fist.dm b/code/modules/martial_arts/plasma_fist.dm
index ea5aef5ea74..a216a5d730f 100644
--- a/code/modules/martial_arts/plasma_fist.dm
+++ b/code/modules/martial_arts/plasma_fist.dm
@@ -1,86 +1,22 @@
-#define TORNADO_COMBO "HHD"
-#define THROWBACK_COMBO "DHD"
-#define PLASMA_COMBO "HDDDH"
-
/datum/martial_art/plasma_fist
name = "Plasma Fist"
- help_verb = /mob/living/carbon/human/proc/plasma_fist_help
-
-
-/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/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)
- 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, ATTACK_EFFECT_PUNCH)
- 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
+ combos = list(/datum/martial_combo/plasma_fist/tornado_sweep, /datum/martial_combo/plasma_fist/throwback, /datum/martial_combo/plasma_fist/plasma_fist)
+ has_explaination_verb = TRUE
/datum/martial_art/plasma_fist/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("H",D)
- if(check_streak(A,D))
- return 1
+ MARTIAL_ARTS_ACT_CHECK
basic_hit(A,D)
- return 1
+ return TRUE
/datum/martial_art/plasma_fist/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("D",D)
- if(check_streak(A,D))
- return 1
+ MARTIAL_ARTS_ACT_CHECK
basic_hit(A,D)
- return 1
+ return TRUE
/datum/martial_art/plasma_fist/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("G",D)
- if(check_streak(A,D))
- return 1
+ MARTIAL_ARTS_ACT_CHECK
basic_hit(A,D)
- return 1
+ return TRUE
-/mob/living/carbon/human/proc/plasma_fist_help()
- set name = "Recall Teachings"
- set desc = "Remember the martial techniques of the Plasma Fist."
- set category = "Plasma Fist"
-
- to_chat(usr, "You clench your fists and have a flashback of knowledge...")
- to_chat(usr, "Tornado Sweep: Harm Harm Disarm. Repulses target and everyone back.")
- to_chat(usr, "Throwback: Disarm Harm Disarm. Throws the target and an item at them.")
- to_chat(usr, "The Plasma Fist: Harm Disarm Disarm Disarm Harm. Knocks the brain out of the opponent and gibs their body.")
+/datum/martial_art/plasma_fist/explaination_header(user)
+ to_chat(user, "You clench your fists and have a flashback of knowledge...")
diff --git a/code/modules/martial_arts/sleeping_carp.dm b/code/modules/martial_arts/sleeping_carp.dm
index 472fb6ca506..9ca070f8bfd 100644
--- a/code/modules/martial_arts/sleeping_carp.dm
+++ b/code/modules/martial_arts/sleeping_carp.dm
@@ -1,126 +1,21 @@
//Used by the gang of the same name. Uses combos. Basic attacks bypass armor and never miss
-#define WRIST_WRENCH_COMBO "DD"
-#define BACK_KICK_COMBO "HG"
-#define STOMACH_KNEE_COMBO "GH"
-#define HEAD_KICK_COMBO "DHH"
-#define ELBOW_DROP_COMBO "HDHDH"
/datum/martial_art/the_sleeping_carp
name = "The Sleeping Carp"
deflection_chance = 100
- help_verb = /mob/living/carbon/human/proc/sleeping_carp_help
no_guns = TRUE
no_guns_message = "Use of ranged weaponry would bring dishonor to the clan."
-
-/datum/martial_art/the_sleeping_carp/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(findtext(streak,WRIST_WRENCH_COMBO))
- streak = ""
- wristWrench(A,D)
- return 1
- if(findtext(streak,BACK_KICK_COMBO))
- streak = ""
- backKick(A,D)
- return 1
- if(findtext(streak,STOMACH_KNEE_COMBO))
- streak = ""
- kneeStomach(A,D)
- return 1
- if(findtext(streak,HEAD_KICK_COMBO))
- streak = ""
- headKick(A,D)
- return 1
- if(findtext(streak,ELBOW_DROP_COMBO))
- streak = ""
- elbowDrop(A,D)
- return 1
- return 0
-
-/datum/martial_art/the_sleeping_carp/proc/wristWrench(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(!D.stat && !D.stunned && !D.IsWeakened())
- A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
- D.visible_message("[A] grabs [D]'s wrist and wrenches it sideways!", \
- "[A] grabs your wrist and violently wrenches it to the side!")
- playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Wrist Wrench", ATKLOG_ALL)
- if(prob(60))
- A.say(pick("WRISTY TWIRLY!", "WE FIGHT LIKE MEN!", "YOU DISHONOR YOURSELF!", "POHYAH!", "WHERE IS YOUR BATON NOW?", "SAY UNCLE!"))
- D.emote("scream")
- D.drop_item()
- D.apply_damage(5, BRUTE, pick("l_arm", "r_arm"))
- D.Stun(3)
- return 1
- return basic_hit(A,D)
-
-/datum/martial_art/the_sleeping_carp/proc/backKick(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(A.dir == D.dir && !D.stat && !D.IsWeakened())
- A.do_attack_animation(D, ATTACK_EFFECT_KICK)
- D.visible_message("[A] kicks [D] in the back!", \
- "[A] kicks you in the back, making you stumble and fall!")
- step_to(D,get_step(D,D.dir),1)
- D.Weaken(4)
- playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Back Kick", ATKLOG_ALL)
- if(prob(80))
- A.say(pick("SURRPRIZU!","BACK STRIKE!","WOPAH!", "WATAAH", "ZOTA!", "Never turn your back to the enemy!"))
- return 1
- return basic_hit(A,D)
-
-/datum/martial_art/the_sleeping_carp/proc/kneeStomach(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(!D.stat && !D.IsWeakened())
- A.do_attack_animation(D, ATTACK_EFFECT_KICK)
- D.visible_message("[A] knees [D] in the stomach!", \
- "[A] winds you with a knee in the stomach!")
- D.audible_message("[D] gags!")
- D.AdjustLoseBreath(3)
- D.Stun(2)
- playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Stomach Knee", ATKLOG_ALL)
- if(prob(80))
- A.say(pick("HWOP!", "KUH!", "YAKUUH!", "KYUH!", "KNEESTRIKE!"))
- return 1
- return basic_hit(A,D)
-
-/datum/martial_art/the_sleeping_carp/proc/headKick(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(!D.stat && !D.IsWeakened())
- A.do_attack_animation(D, ATTACK_EFFECT_KICK)
- D.visible_message("[A] kicks [D] in the head!", \
- "[A] kicks you in the jaw!")
- D.apply_damage(20, BRUTE, "head")
- D.drop_item()
- playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Head Kick", ATKLOG_ALL)
- if(prob(60))
- A.say(pick("OOHYOO!", "OOPYAH!", "HYOOAA!", "WOOAAA!", "SHURYUKICK!", "HIYAH!"))
- D.Stun(4)
- return 1
- return basic_hit(A,D)
-
-/datum/martial_art/the_sleeping_carp/proc/elbowDrop(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- if(D.IsWeakened() || D.resting || D.stat)
- A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
- D.visible_message("[A] elbow drops [D]!", \
- "[A] piledrives you with [A.p_their()] elbow!")
- if(D.stat)
- D.death() //FINISH HIM!
- D.apply_damage(50, BRUTE, "chest")
- playsound(get_turf(D), 'sound/weapons/punch1.ogg', 75, 1, -1)
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Elbow Drop", ATKLOG_ALL)
- if(prob(80))
- A.say(pick("BANZAIII!", "KIYAAAA!", "OMAE WA MOU SHINDEIRU!", "YOU CAN'T SEE ME!", "MY TIME IS NOW!", "COWABUNGA"))
- return 1
- return basic_hit(A,D)
+ has_explaination_verb = TRUE
+ combos = list(/datum/martial_combo/sleeping_carp/wrist_wrench, /datum/martial_combo/sleeping_carp/back_kick, /datum/martial_combo/sleeping_carp/stomach_knee, /datum/martial_combo/sleeping_carp/head_kick, /datum/martial_combo/sleeping_carp/elbow_drop)
/datum/martial_art/the_sleeping_carp/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("G",D)
- if(check_streak(A,D))
- return 1
+ MARTIAL_ARTS_ACT_CHECK
var/obj/item/grab/G = D.grabbedby(A,1)
if(G)
G.state = GRAB_AGGRESSIVE //Instant aggressive grab
+ return TRUE
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
- add_to_streak("H",D)
- if(check_streak(A,D))
- return 1
+ MARTIAL_ARTS_ACT_CHECK
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
var/atk_verb = pick("punches", "kicks", "chops", "hits", "slams")
D.visible_message("[A] [atk_verb] [D]!", \
@@ -132,24 +27,7 @@
if(prob(D.getBruteLoss()) && !D.lying)
D.visible_message("[D] stumbles and falls!", "The blow sends you to the ground!")
D.Weaken(4)
- return 1
-
-
-/datum/martial_art/the_sleeping_carp/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
- add_to_streak("D",D)
- if(check_streak(A,D))
- return 1
- return ..()
-
-/mob/living/carbon/human/proc/sleeping_carp_help()
- set name = "Recall Teachings"
- set desc = "Remember the martial techniques of the Sleeping Carp clan."
- set category = "Sleeping Carp"
+ return TRUE
+/datum/martial_art/the_sleeping_carp/explaination_header(user)
to_chat(usr, "You retreat inward and recall the teachings of the Sleeping Carp...")
-
- to_chat(usr, "Wrist Wrench: Disarm Disarm. Forces opponent to drop item in hand.")
- to_chat(usr, "Back Kick: Harm Grab. Opponent must be facing away. Knocks down.")
- to_chat(usr, "Stomach Knee: Grab Harm. Knocks the wind out of opponent and stuns.")
- to_chat(usr, "Head Kick: Disarm Harm Harm. Decent damage, forces opponent to drop item in hand.")
- to_chat(usr, "Elbow Drop: Harm Disarm Harm Disarm Harm. Opponent must be on the ground. Deals huge damage, instantly kills anyone in critical condition.")
diff --git a/code/modules/martial_arts/wrestleing.dm b/code/modules/martial_arts/wrestling.dm
similarity index 100%
rename from code/modules/martial_arts/wrestleing.dm
rename to code/modules/martial_arts/wrestling.dm
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index d495ca3d2f4..4cb846139f7 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -29,8 +29,6 @@
create_reagents(330)
- martial_art = GLOB.default_martial_art
-
handcrafting = new()
// Set up DNA.
@@ -298,8 +296,8 @@
apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee"))
/mob/living/carbon/human/bullet_act()
- if(martial_art && martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
- if(!prob(martial_art.deflection_chance))
+ if(mind && mind.martial_art && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
+ if(!prob(mind.martial_art.deflection_chance))
return ..()
if(!src.lying && !(HULK in mutations)) //But only if they're not lying down, and hulks can't do it
visible_message("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!", "You deflect the projectile!")
@@ -1731,16 +1729,14 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
if(HULK in mutations)
to_chat(src, "Your meaty finger is much too large for the trigger guard!")
- return 0
+ return FALSE
if(NOGUNS in dna.species.species_traits)
to_chat(src, "Your fingers don't fit in the trigger guard!")
- return 0
+ return FALSE
- if(martial_art && martial_art.no_guns) //great dishonor to famiry
- to_chat(src, "[martial_art.no_guns_message]")
- return 0
-
- return .
+ if(mind && mind.martial_art && mind.martial_art.no_guns) //great dishonor to famiry
+ to_chat(src, "[mind.martial_art.no_guns_message]")
+ return FALSE
/mob/living/carbon/human/proc/change_icobase(var/new_icobase, var/new_deform, var/owner_sensitive)
for(var/obj/item/organ/external/O in bodyparts)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 958afaaef94..cf61162733e 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -214,7 +214,7 @@ emp_act
return 0
/mob/living/carbon/human/proc/check_block()
- if(martial_art && prob(martial_art.block_chance) && martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE))
+ if(mind && mind.martial_art && prob(mind.martial_art.block_chance) && mind.martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE))
return TRUE
/mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit) //todo: update this to utilize check_obscured_slots() //and make sure it's check_obscured_slots(TRUE) to stop aciding through visors etc
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 3d365afa940..bc5c85e2929 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -1,4 +1,3 @@
-GLOBAL_DATUM_INIT(default_martial_art, /datum/martial_art, new())
/mob/living/carbon/human
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPMINDSHIELD_HUD,IMPCHEM_HUD,IMPTRACK_HUD,SPECIALROLE_HUD,GLAND_HUD)
@@ -42,8 +41,6 @@ GLOBAL_DATUM_INIT(default_martial_art, /datum/martial_art, new())
var/datum/personal_crafting/handcrafting
- var/datum/martial_art/martial_art = null
-
var/special_voice = "" // For changing our voice. Used by a symptom.
var/hand_blood_color
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index a1be84f8163..c9cd99ad2d0 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -696,13 +696,14 @@
if(alcohol_strength >= slur_start) //slurring
Slur(drunk)
- if(alcohol_strength >= brawl_start) //the drunken martial art
- if(!istype(martial_art, /datum/martial_art/drunk_brawling))
- var/datum/martial_art/drunk_brawling/F = new
- F.teach(src, 1)
- if(alcohol_strength < brawl_start) //removing the art
- if(istype(martial_art, /datum/martial_art/drunk_brawling))
- martial_art.remove(src)
+ if(mind)
+ if(alcohol_strength >= brawl_start) //the drunken martial art
+ if(!istype(mind.martial_art, /datum/martial_art/drunk_brawling))
+ var/datum/martial_art/drunk_brawling/F = new
+ F.teach(src, TRUE)
+ else if(alcohol_strength < brawl_start) //removing the art
+ if(istype(mind.martial_art, /datum/martial_art/drunk_brawling))
+ mind.martial_art.remove(src)
if(alcohol_strength >= confused_start && prob(33)) //confused walking
if(!confused)
Confused(1)
diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm
index a8e1eee5f52..1ba796c0435 100644
--- a/code/modules/mob/living/carbon/human/species/_species.dm
+++ b/code/modules/mob/living/carbon/human/species/_species.dm
@@ -516,7 +516,7 @@
playsound(target.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
target.visible_message("[user] attempted to disarm [target]!")
-/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style = M.martial_art) //Handles any species-specific attackhand events.
+/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style) //Handles any species-specific attackhand events.
if(!istype(M))
return
@@ -528,6 +528,9 @@
to_chat(M, "You can't use your hand.")
return
+ if(M.mind)
+ attacker_style = M.mind.martial_art
+
if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
add_attack_logs(M, H, "Melee attacked with fists (miss/block)")
H.visible_message("[M] attempted to touch [H]!")
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 2f97001d3ae..dd0316f4177 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -122,8 +122,8 @@ Difficulty: Very Hard
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
if(ishuman(L))
var/mob/living/carbon/human/H = L
- if(H.martial_art && prob(H.martial_art.deflection_chance))
- . = TRUE
+ if(H.mind && H.mind.martial_art && prob(H.mind.martial_art.deflection_chance))
+ return TRUE
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
ranged_cooldown = world.time + 40
diff --git a/paradise.dme b/paradise.dme
index 5ed4f7e3bc5..7fe2674b7d8 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -50,6 +50,7 @@
#include "code\__DEFINES\lighting.dm"
#include "code\__DEFINES\logs.dm"
#include "code\__DEFINES\machines.dm"
+#include "code\__DEFINES\martial_arts.dm"
#include "code\__DEFINES\math.dm"
#include "code\__DEFINES\MC.dm"
#include "code\__DEFINES\mecha.dm"
@@ -1664,7 +1665,28 @@
#include "code\modules\martial_arts\mimejutsu.dm"
#include "code\modules\martial_arts\plasma_fist.dm"
#include "code\modules\martial_arts\sleeping_carp.dm"
-#include "code\modules\martial_arts\wrestleing.dm"
+#include "code\modules\martial_arts\wrestling.dm"
+#include "code\modules\martial_arts\combos\martial_combo.dm"
+#include "code\modules\martial_arts\combos\adminfu\healing_palm.dm"
+#include "code\modules\martial_arts\combos\cqc\consecutive.dm"
+#include "code\modules\martial_arts\combos\cqc\kick.dm"
+#include "code\modules\martial_arts\combos\cqc\pressure.dm"
+#include "code\modules\martial_arts\combos\cqc\restrain.dm"
+#include "code\modules\martial_arts\combos\cqc\slam.dm"
+#include "code\modules\martial_arts\combos\krav_maga\leg_sweep.dm"
+#include "code\modules\martial_arts\combos\krav_maga\lung_punch.dm"
+#include "code\modules\martial_arts\combos\krav_maga\neck_chop.dm"
+#include "code\modules\martial_arts\combos\mimejutsu\mimechucks.dm"
+#include "code\modules\martial_arts\combos\mimejutsu\silent_palm.dm"
+#include "code\modules\martial_arts\combos\mimejutsu\smokebomb.dm"
+#include "code\modules\martial_arts\combos\plasma_fist\plasma_fist.dm"
+#include "code\modules\martial_arts\combos\plasma_fist\throwback.dm"
+#include "code\modules\martial_arts\combos\plasma_fist\tornado_sweep.dm"
+#include "code\modules\martial_arts\combos\sleeping_carp\back_kick.dm"
+#include "code\modules\martial_arts\combos\sleeping_carp\elbow_drop.dm"
+#include "code\modules\martial_arts\combos\sleeping_carp\head_kick.dm"
+#include "code\modules\martial_arts\combos\sleeping_carp\stomach_knee.dm"
+#include "code\modules\martial_arts\combos\sleeping_carp\wrist_wrench.dm"
#include "code\modules\mining\abandonedcrates.dm"
#include "code\modules\mining\fulton.dm"
#include "code\modules\mining\machine_processing.dm"