diff --git a/code/__DEFINES/melee.dm b/code/__DEFINES/melee.dm
index cb4a433211..b166b9d21a 100644
--- a/code/__DEFINES/melee.dm
+++ b/code/__DEFINES/melee.dm
@@ -7,4 +7,5 @@
#define MARTIALART_MUSHPUNCH "mushroom punch"
#define MARTIALART_KRAVMAGA "krav maga"
#define MARTIALART_CQC "CQC"
-#define MARTIALART_PLASMAFIST "plasma fist"
\ No newline at end of file
+#define MARTIALART_PLASMAFIST "plasma fist"
+#define MARTIALART_RISINGBASS "rising bass"
\ No newline at end of file
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 428d569531..439b3d1493 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -226,6 +226,7 @@
#define NINJA_SUIT_TRAIT "ninja-suit"
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
#define SLEEPING_CARP_TRAIT "sleeping_carp"
+#define RISING_BASS_TRAIT "rising_bass"
#define ABDUCTOR_ANTAGONIST "abductor-antagonist"
#define MADE_UNCLONEABLE "made-uncloneable"
#define NUKEOP_TRAIT "nuke-op"
diff --git a/code/datums/martial.dm b/code/datums/martial.dm
index 32850c69df..c8caa853c3 100644
--- a/code/datums/martial.dm
+++ b/code/datums/martial.dm
@@ -8,6 +8,8 @@
var/deflection_chance = 0 //Chance to deflect projectiles
var/reroute_deflection = FALSE //Delete the bullet, or actually deflect it in some direction?
var/block_chance = 0 //Chance to block melee attacks using items while on throw mode.
+ var/dodge_chance = 0
+ 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
var/pacifism_check = TRUE //are the martial arts combos/attacks unable to be used by pacifist.
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm
index 09a493a670..4ec16ac18c 100644
--- a/code/datums/martial/cqc.dm
+++ b/code/datums/martial/cqc.dm
@@ -10,7 +10,6 @@
help_verb = /mob/living/carbon/human/proc/CQC_help
block_chance = 75
var/old_grab_state = null
- var/restraining = FALSE
/datum/martial_art/cqc/reset_streak(mob/living/carbon/human/new_target)
. = ..()
diff --git a/code/datums/martial/rising_bass.dm b/code/datums/martial/rising_bass.dm
new file mode 100644
index 0000000000..a3b71c6784
--- /dev/null
+++ b/code/datums/martial/rising_bass.dm
@@ -0,0 +1,156 @@
+#define SIDE_KICK_COMBO "DH"
+#define SHOULDER_FLIP_COMBO "GHDGHH"
+#define REPULSE_PUNCH_COMBO "GHGH"
+#define FOOT_SMASH_COMBO "HH"
+#define DEFT_SWITCH_COMBO "GDD"
+
+/datum/martial_art/the_rising_bass
+ name = "The Rising Bass"
+ id = MARTIALART_RISINGBASS
+ dodge_chance = 100
+ allow_temp_override = FALSE
+ help_verb = /mob/living/carbon/human/proc/rising_bass_help
+
+/datum/martial_art/the_rising_bass/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ if(findtext(streak,SIDE_KICK_COMBO))
+ streak = ""
+ sideKick(A,D)
+ return 1
+ if(findtext(streak,SHOULDER_FLIP_COMBO))
+ streak = ""
+ shoulderFlip(A,D)
+ return 1
+ if(findtext(streak,REPULSE_PUNCH_COMBO))
+ streak = ""
+ repulsePunch(A,D)
+ return 1
+ if(findtext(streak,FOOT_SMASH_COMBO))
+ streak = ""
+ footSmash(A,D)
+ return 1
+ if(findtext(streak,DEFT_SWITCH_COMBO))
+ streak = ""
+ deftSwitch(A,D)
+ return 1
+ return 0
+
+
+/datum/martial_art/the_rising_bass/proc/sideKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ if(!D.IsKnockdown() || D.lying == 0)
+ var/turf/H = get_step(D, A.dir & (NORTH | SOUTH) ? pick(EAST, WEST) : pick(NORTH, SOUTH))
+ A.do_attack_animation(D, ATTACK_EFFECT_KICK)
+ D.visible_message("[A] kicks [D] in the side, sliding them over!", \
+ "[A] kicks you in the side, forcing you to step away!")
+ playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ D.apply_damage(5, BRUTE, BODY_ZONE_CHEST)
+ D.Knockdown(60)
+ var/L = H
+ for(var/obj/i in H.contents)
+ if(!istype(i,/mob) && i.density == 1)
+ L = D.loc
+ D.forceMove(L)
+ log_combat(A, D, "side kicked (Rising Bass)")
+ return 1
+ return basic_hit(A,D)
+
+/datum/martial_art/the_rising_bass/proc/shoulderFlip(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ if(!D.IsKnockdown() || !D.lying)
+ var/turf/H = get_step(A, get_dir(D,A))
+ var/L = H
+ for(var/obj/i in H.contents)
+ if(!istype(i,/mob) && i.density == 1)//(i.anchored == 1 && i.density == 1) || istype(i,/obj/structure) || istype(i,/turf/closed)
+ L = A.loc
+ A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
+ D.visible_message("[A] flips [D] over their shoulder, slamming them into the ground!", \
+ "[A] flips you over their shoulder, slamming you into the ground!")
+ playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ D.emote("scream")
+ D.apply_damage(10, BRUTE, BODY_ZONE_CHEST)
+ D.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
+ D.Sleeping(60)
+ D.Knockdown(300)
+ D.forceMove(L)
+ log_combat(A, D, "shoulder flipped (Rising Bass)")
+ return 1
+ return basic_hit(A,D)
+
+/datum/martial_art/the_rising_bass/proc/repulsePunch(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ if(!D.IsKnockdown() || !D.lying)
+ A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
+ D.visible_message("[A] smashes [D] in the chest, throwing them away!", \
+ "[A] smashes you in the chest, repelling you away!")
+ playsound(get_turf(A), 'sound/weapons/punch1.ogg', 50, 1, -1)
+ var/atom/F = get_edge_target_turf(D, get_dir(A, get_step_away(D, A)))
+ D.throw_at(F, 10, 1)
+ D.apply_damage(10, BRUTE, BODY_ZONE_CHEST)
+ D.Knockdown(90)
+ log_combat(A, D, "repulse punched (Rising Bass)")
+ return 1
+ return basic_hit(A,D)
+
+/datum/martial_art/the_rising_bass/proc/footSmash(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ if(!D.IsKnockdown() || !D.lying)
+ A.do_attack_animation(D, ATTACK_EFFECT_KICK)
+ D.visible_message("[A] smashes their foot down on [D]'s foot!", \
+ "[A] smashes your foot!")
+ playsound(get_turf(A), 'sound/weapons/punch1.ogg', 50, 1, -1)
+ D.apply_damage(5, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
+ D.dropItemToGround(D.get_active_held_item())
+ log_combat(A, D, "foot smashed (Rising Bass)")
+ return 1
+ return basic_hit(A,D)
+
+/datum/martial_art/the_rising_bass/proc/deftSwitch(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ if(!D.IsKnockdown() || !D.lying)
+ if (D.get_active_held_item())
+ var/obj/item/G = D.get_active_held_item()
+ if (G && !(G.item_flags & (ABSTRACT|DROPDEL)) && D.temporarilyRemoveItemFromInventory(G))
+ A.put_in_hands(G)
+ D.visible_message("[A] slaps [D]'s hands, taking [G] from them!", \
+ "[A] slaps you, taking [G] from you!")
+ log_combat(A, D, "deft switched (Rising Bass)")
+ return 1
+ else
+ to_chat(A, "[G] can't be taken out of [D]'s hands!")
+ return 0
+
+/datum/martial_art/the_rising_bass/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ add_to_streak("D",D)
+ if(check_streak(A,D))
+ return 1
+ return ..()
+
+/datum/martial_art/the_rising_bass/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ add_to_streak("H",D)
+ if(check_streak(A,D))
+ return 1
+ return ..()
+
+/datum/martial_art/the_rising_bass/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
+ add_to_streak("G",D)
+ if(check_streak(A,D))
+ return 1
+ return ..()
+
+/mob/living/carbon/human/proc/rising_bass_help()
+ set name = "Recall Teachings"
+ set desc = "Remember the martial techniques of the Rising Bass clan."
+ set category = "Rising Bass"
+
+ to_chat(usr, "You retreat inward and recall the teachings of the Rising Bass...")
+
+ to_chat(usr, "Side Kick: Disarm Harm. Forces opponent to step to the side.")
+ to_chat(usr, "Shoulder Flip: Grab Harm Disarm Grab Harm Harm. Flips opponent over your shoulder and stuns.")
+ to_chat(usr, "Repulse Punch: Grab Harm Grab Harm. Slams the opponent far away from you.")
+ to_chat(usr, "Foot Smash: Harm Harm. Stuns opponent, minor damage.")
+ to_chat(usr, "Deft Switch: Grab Disarm Disarm. Switches the opponent's held item for your own. Most useful with nothing in your hand.")
+
+/datum/martial_art/the_rising_bass/teach(mob/living/carbon/human/H, make_temporary = FALSE)
+ . = ..()
+ if(!.)
+ return
+ ADD_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
+
+/datum/martial_art/the_rising_bass/on_remove(mob/living/carbon/human/H)
+ . = ..()
+ REMOVE_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
\ No newline at end of file
diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm
index 62a7742628..70cd503ef4 100644
--- a/code/game/objects/items/granters.dm
+++ b/code/game/objects/items/granters.dm
@@ -414,6 +414,23 @@
name = "empty scroll"
icon_state = "blankscroll"
+/obj/item/book/granter/martial/bass
+ martial = /datum/martial_art/the_rising_bass
+ name = "shifting scroll"
+ martialname = "rising bass"
+ desc = "A paper scroll that seems to move even as you read it, the letters never seem to stay still."
+ greet = "You have learned the ancient martial art of the Rising Bass. Your skill at running away has increased quite a bit. Use the combos to get away from opponents quickly. Along with this, you now dodge all projectiles and catch anything thrown at you."
+ icon = 'icons/obj/wizard.dmi'
+ icon_state = "scroll2"
+ remarks = list("The trick is to disarm them...","Running away helps in many situations...","Never stay still...","Fighting won't help unless you're forced to...", "Crush their limbs to incapacitate them...", "Stay as far away as possible...")
+
+/obj/item/book/granter/martial/bass/onlearned(mob/living/carbon/user)
+ ..()
+ if(oneuse == TRUE)
+ desc = "It's completely blank."
+ name = "empty scroll"
+ icon_state = "blankscroll"
+
/obj/item/book/granter/martial/plasma_fist
martial = /datum/martial_art/plasma_fist
name = "frayed scroll"
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index f0d81e0a4d..06575aa802 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -50,6 +50,9 @@
/mob/living/carbon/proc/can_catch_item(skip_throw_mode_check)
. = FALSE
+ if(mind)
+ if(mind.martial_art && mind.martial_art.dodge_chance == 100)
+ return TRUE
if(!skip_throw_mode_check && !in_throw_mode)
return
if(get_active_held_item())
@@ -63,6 +66,13 @@
if(can_catch_item())
if(istype(AM, /obj/item))
var/obj/item/I = AM
+ if (mind)
+ if (mind.martial_art && mind.martial_art.dodge_chance == 100) //autocatch for rising bass
+ if (get_active_held_item())
+ visible_message("[I] falls to the ground as [src] chops it out of the air!")
+ return 1
+ if(!in_throw_mode)
+ throw_mode_on()
if(isturf(I.loc))
I.attack_hand(src)
if(get_active_held_item() == I) //if our attack_hand() picks up the item...
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 042b4af4fe..93f33c3a3d 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -46,6 +46,12 @@
return spec_return
if(mind)
+ if (mind.martial_art && mind.martial_art.dodge_chance)
+ if(!lying && dna && !dna.check_mutation(HULK))
+ if(prob(mind.martial_art.dodge_chance))
+ var/dodgemessage = pick("dodges under the projectile!","dodges to the right of the projectile!","jumps over the projectile!")
+ visible_message("[src] [dodgemessage]", "You dodge the projectile!")
+ return -1
if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
if(prob(mind.martial_art.deflection_chance))
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
@@ -145,7 +151,7 @@
skipcatch = TRUE
blocked = TRUE
else if(I)
- if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD)
+ if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && !(mind.martial_art && mind.martial_art.dodge_chance == 100))
if(can_embed(I))
if(prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE))
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
@@ -158,7 +164,9 @@
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
hitpush = FALSE
skipcatch = TRUE //can't catch the now embedded item
-
+ if (mind)
+ if (mind.martial_art && mind.martial_art.dodge_chance == 100)
+ skipcatch = FALSE
return ..()
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 2de04cf0df..6feb465c12 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -641,7 +641,7 @@
cost = 2
/datum/uplink_item/stealthy_weapons/martialarts
- name = "Martial Arts Scroll"
+ name = "Sleeping Carp Scroll"
desc = "This scroll contains the secrets of an ancient martial arts technique. You will master unarmed combat, \
deflecting all ranged weapon fire, but you also refuse to use dishonorable ranged weaponry."
item = /obj/item/book/granter/martial/carp
@@ -649,6 +649,15 @@
surplus = 0
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+/datum/uplink_item/stealthy_weapons/martialartstwo
+ name = "Rising Bass Scroll"
+ desc = "This scroll contains the secrets of an ancient martial arts technique. You will become proficient in fleeing situations, \
+ and dodging all ranged weapon fire, but you will refuse to use dishonorable ranged weaponry."
+ item = /obj/item/book/granter/martial/bass
+ cost = 18
+ surplus = 0
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+
/datum/uplink_item/stealthy_weapons/crossbow
name = "Miniature Energy Crossbow"
desc = "A short bow mounted across a tiller in miniature. Small enough to \
diff --git a/tgstation.dme b/tgstation.dme
index 20cbea540c..7a1b6cb890 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -483,6 +483,7 @@
#include "code\datums\martial\mushpunch.dm"
#include "code\datums\martial\plasma_fist.dm"
#include "code\datums\martial\psychotic_brawl.dm"
+#include "code\datums\martial\rising_bass.dm"
#include "code\datums\martial\sleeping_carp.dm"
#include "code\datums\martial\wrestling.dm"
#include "code\datums\mood_events\beauty_events.dm"