mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 21:48:39 +01:00
Kicks Martial Arts out of the attack chain (yippee), makes it use signals, plus a large clean up of existing martial arts (#81097)
## About The Pull Request - Kicks Martial Arts out of the attack chain. - All Martial Arts attacks are now handled via unarmed attack or grab signals - This means all martial arts are now technically on the living level, allowing any mob that can unarmed attack to martial arts. Sort of. YMMV. - All martial arts block checking is now handled by the arts themselves, meaning you can selectively decide for a martial arts strike to not be blocked. Maybe good for the future. - A comprehensive cleanup of all existing martial arts. Improving var names, code, adding some missing animation calls, etc. Fixes #74829 ## Why It's Good For The Game Untangles the mess that is martial arts, making it a lot easier to work with the attack chain and making it overall a ton more consistent. ## Changelog 🆑 Melbert refactor: Big martial arts refactor, they should now overall act a ton more consistent. Also technically any mob can do martial arts. Let me know if something is funky. /🆑 --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
@@ -338,13 +338,13 @@ GLOBAL_LIST_INIT(arm_zones, list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
|
||||
#define COMPONENT_AUTOFIRE_SHOT_SUCCESS (1<<0)
|
||||
|
||||
/// Martial arts attack requested but is not available, allow a check for a regular attack.
|
||||
#define MARTIAL_ATTACK_INVALID -1
|
||||
#define MARTIAL_ATTACK_INVALID NONE
|
||||
|
||||
/// Martial arts attack happened but failed, do not allow a check for a regular attack.
|
||||
#define MARTIAL_ATTACK_FAIL FALSE
|
||||
#define MARTIAL_ATTACK_FAIL COMPONENT_SKIP_ATTACK
|
||||
|
||||
/// Martial arts attack happened and succeeded, do not allow a check for a regular attack.
|
||||
#define MARTIAL_ATTACK_SUCCESS TRUE
|
||||
#define MARTIAL_ATTACK_SUCCESS COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/// IF an object is weak against armor, this is the value that any present armor is multiplied by
|
||||
#define ARMOR_WEAKENED_MULTIPLIER 2
|
||||
|
||||
@@ -249,5 +249,9 @@
|
||||
|
||||
/// Sent from a mob to their loc when starting to remove cuffs on itself
|
||||
#define COMSIG_MOB_REMOVING_CUFFS "living_removing_cuffs"
|
||||
/// Sent as a reply to above from any atom that wishs to stop self-cuff removal
|
||||
#define COMSIG_MOB_BLOCK_CUFF_REMOVAL (1<<0)
|
||||
/// Sent as a reply to above from any atom that wishs to stop self-cuff removal
|
||||
#define COMSIG_MOB_BLOCK_CUFF_REMOVAL (1<<0)
|
||||
|
||||
/// Sent to a mob grabbing another mob: (mob/living/grabbing)
|
||||
#define COMSIG_LIVING_GRAB "living_grab"
|
||||
// Return COMPONENT_CANCEL_ATTACK_CHAIN / COMPONENT_SKIP_ATTACK_CHAIN to stop the grab
|
||||
|
||||
@@ -70,6 +70,8 @@
|
||||
|
||||
///from mind/transfer_to. Sent to the receiving mob.
|
||||
#define COMSIG_MOB_MIND_TRANSFERRED_INTO "mob_mind_transferred_into"
|
||||
///from mind/transfer_from. Sent to the mob the mind is being transferred out of.
|
||||
#define COMSIG_MOB_MIND_TRANSFERRED_OUT_OF "mob_mind_transferred_out_of"
|
||||
/// From /mob/proc/ghostize() Called when a mob sucessfully ghosts
|
||||
#define COMSIG_MOB_GHOSTIZED "mob_ghostized"
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#define MARTIALART_BOXING "boxing"
|
||||
#define MARTIALART_CQC "CQC"
|
||||
#define MARTIALART_HUGS_OF_THE_GONDOLA "hugs of the gondola"
|
||||
#define MARTIALART_KRAVMAGA "krav maga"
|
||||
#define MARTIALART_MUSHPUNCH "mushroom punch"
|
||||
#define MARTIALART_PLASMAFIST "plasma fist"
|
||||
|
||||
+4
-24
@@ -358,46 +358,26 @@
|
||||
/atom/proc/CtrlClick(mob/user)
|
||||
SEND_SIGNAL(src, COMSIG_CLICK_CTRL, user)
|
||||
SEND_SIGNAL(user, COMSIG_MOB_CTRL_CLICKED, src)
|
||||
|
||||
var/mob/living/ML = user
|
||||
if(istype(ML))
|
||||
ML.pulled(src)
|
||||
if(!can_interact(user))
|
||||
return FALSE
|
||||
|
||||
/mob/living/CtrlClick(mob/user)
|
||||
/mob/living/CtrlClick(mob/living/user)
|
||||
if(!isliving(user) || !user.CanReach(src) || user.incapacitated())
|
||||
return ..()
|
||||
|
||||
if(world.time < user.next_move)
|
||||
return FALSE
|
||||
|
||||
var/mob/living/user_living = user
|
||||
if(user_living.apply_martial_art(src, null, is_grab=TRUE) == MARTIAL_ATTACK_SUCCESS)
|
||||
user_living.changeNext_move(CLICK_CD_MELEE)
|
||||
if(user.grab(src))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
return TRUE
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/carbon/human/CtrlClick(mob/user)
|
||||
if(!iscarbon(user) || !user.CanReach(src) || user.incapacitated())
|
||||
return ..()
|
||||
|
||||
if(world.time < user.next_move)
|
||||
return FALSE
|
||||
|
||||
if (ishuman(user))
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
if(human_user.dna.species.grab(human_user, src, human_user.mind.martial_art))
|
||||
human_user.changeNext_move(CLICK_CD_MELEE)
|
||||
return TRUE
|
||||
else if(isalien(user))
|
||||
var/mob/living/carbon/alien/adult/alien_boy = user
|
||||
if(alien_boy.grab(src))
|
||||
alien_boy.changeNext_move(CLICK_CD_MELEE)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/proc/CtrlMiddleClickOn(atom/A)
|
||||
if(check_rights_for(client, R_ADMIN))
|
||||
client.toggle_tag_datum(A)
|
||||
|
||||
@@ -245,14 +245,15 @@
|
||||
|
||||
/datum/brain_trauma/special/psychotic_brawling/on_gain()
|
||||
..()
|
||||
psychotic_brawling = new(null)
|
||||
psychotic_brawling = new()
|
||||
psychotic_brawling.allow_temp_override = FALSE
|
||||
if(!psychotic_brawling.teach(owner, TRUE))
|
||||
to_chat(owner, span_notice("But your martial knowledge keeps you grounded."))
|
||||
qdel(src)
|
||||
|
||||
/datum/brain_trauma/special/psychotic_brawling/on_lose()
|
||||
..()
|
||||
psychotic_brawling.remove(owner)
|
||||
psychotic_brawling.fully_remove(owner)
|
||||
QDEL_NULL(psychotic_brawling)
|
||||
|
||||
/datum/brain_trauma/special/psychotic_brawling/bath_salts
|
||||
|
||||
@@ -234,7 +234,7 @@
|
||||
target.Knockdown(3 SECONDS)
|
||||
target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS)
|
||||
if(ishuman(target) && ishuman(user))
|
||||
INVOKE_ASYNC(human_sacker.dna.species, TYPE_PROC_REF(/datum/species, grab), human_sacker, human_target)
|
||||
INVOKE_ASYNC(human_sacker, TYPE_PROC_REF(/mob/living, grab), human_sacker, human_target)
|
||||
human_sacker.setGrabState(GRAB_PASSIVE)
|
||||
|
||||
if(50 to INFINITY) // absolutely BODIED
|
||||
@@ -260,7 +260,7 @@
|
||||
target.Knockdown(3 SECONDS)
|
||||
target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 3, 10 SECONDS)
|
||||
if(ishuman(target) && ishuman(user))
|
||||
INVOKE_ASYNC(human_sacker.dna.species, TYPE_PROC_REF(/datum/species, grab), human_sacker, human_target)
|
||||
INVOKE_ASYNC(human_sacker, TYPE_PROC_REF(/mob/living, grab), human_sacker, human_target)
|
||||
human_sacker.setGrabState(GRAB_AGGRESSIVE)
|
||||
|
||||
/**
|
||||
|
||||
+312
-52
@@ -1,20 +1,41 @@
|
||||
/datum/martial_art
|
||||
/// Player readable name of the martial art
|
||||
var/name = "Martial Art"
|
||||
var/id = "" //ID, used by mind/has_martialart
|
||||
/// ID of the martial art
|
||||
var/id = ""
|
||||
/// The streak of attacks the user has performed
|
||||
var/streak = ""
|
||||
/// The maximum length of streaks allowed
|
||||
var/max_streak_length = 6
|
||||
var/current_target
|
||||
var/datum/martial_art/base // The permanent style. This will be null unless the martial art is temporary
|
||||
|
||||
/// The current mob associated with this martial art datum. Do not set directly.
|
||||
VAR_PRIVATE/mob/living/holder
|
||||
/// Weakref to the last mob we attacked, for determining when to reset streaks
|
||||
VAR_PRIVATE/datum/weakref/current_target
|
||||
/// Used for temporary martial arts.
|
||||
/// This is a reference to the last martial art that was replaced by this one.
|
||||
VAR_PRIVATE/datum/martial_art/base
|
||||
|
||||
/// Path to verb to display help text for this martial art.
|
||||
var/help_verb
|
||||
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
|
||||
var/smashes_tables = FALSE //If the martial art smashes tables when performing table slams and head smashes
|
||||
var/datum/weakref/holder //owner of the martial art
|
||||
var/display_combos = FALSE //shows combo meter if true
|
||||
var/combo_timer = 6 SECONDS // period of time after which the combo streak is reset.
|
||||
/// If TRUE, this martial art can be overridden and stored (via base) by other martial arts if deemed "temporary" via teach().
|
||||
var/allow_temp_override = TRUE
|
||||
/// If TRUE, this martial art smashes tables when performing table slams and head smashes
|
||||
var/smashes_tables = FALSE
|
||||
/// If TRUE, a combo meter will be displayed on the HUD for the current streak
|
||||
var/display_combos = FALSE
|
||||
/// The length of time until streaks are auto-reset.
|
||||
var/combo_timer = 6 SECONDS
|
||||
/// Timer ID for the combo reset timer.
|
||||
var/timerid
|
||||
/// If set to true this style allows you to punch people despite being a pacifist (for instance Boxing, which does no damage)
|
||||
/// If TRUE, this style allows you to punch people despite being a pacifist (IE: Boxing, which does no damage)
|
||||
var/pacifist_style = FALSE
|
||||
|
||||
/datum/martial_art/Destroy()
|
||||
if(!isnull(holder))
|
||||
remove(holder)
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/serialize_list(list/options, list/semvers)
|
||||
. = ..()
|
||||
|
||||
@@ -25,78 +46,317 @@
|
||||
SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
|
||||
return .
|
||||
|
||||
/// Signal proc for [COMSIG_LIVING_UNARMED_ATTACK] to hook into the appropriate proc
|
||||
/datum/martial_art/proc/unarmed_strike(mob/living/source, atom/attack_target, proximity, modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!proximity || !isliving(attack_target))
|
||||
return NONE
|
||||
|
||||
if(HAS_TRAIT(attack_target, TRAIT_MARTIAL_ARTS_IMMUNE))
|
||||
return NONE
|
||||
|
||||
if(!can_use(source))
|
||||
return NONE
|
||||
|
||||
if(LAZYACCESS(modifiers, RIGHT_CLICK))
|
||||
return disarm_act(source, attack_target)
|
||||
|
||||
if(source.combat_mode)
|
||||
if(HAS_TRAIT(source, TRAIT_PACIFISM) && !pacifist_style)
|
||||
return NONE
|
||||
|
||||
return harm_act(source, attack_target)
|
||||
|
||||
return help_act(source, attack_target)
|
||||
|
||||
/// Signal proc for [COMSIG_LIVING_GRAB] to hook into the grab
|
||||
/datum/martial_art/proc/attempt_grab(mob/living/source, mob/living/grabbing)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(HAS_TRAIT(grabbing, TRAIT_MARTIAL_ARTS_IMMUNE))
|
||||
return NONE
|
||||
|
||||
if(!source.can_unarmed_attack()) // For parity with unarmed attacks
|
||||
return NONE
|
||||
|
||||
if(!can_use(source))
|
||||
return NONE
|
||||
|
||||
return grab_act(source, grabbing)
|
||||
|
||||
/**
|
||||
* Called when help-intenting on someone
|
||||
*
|
||||
* What is checked going into this:
|
||||
* Adjacency, [TRAIT_MARTIAL_ARTS_IMMUNE], attacker incapacitated, can_unarmed_attack, can_use
|
||||
*
|
||||
* What is NOT:
|
||||
* check_block
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/attacker - The mob attacking
|
||||
* * mob/living/defender - The mob being attacked
|
||||
*
|
||||
* Returns
|
||||
* * MARTIAL_ATTACK_INVALID - The attack is not valid, do normal unarmed attack
|
||||
* * MARTIAL_ATTACK_FAIL - The attack is valid, but failed. No followup attack is made.
|
||||
* * MARTIAL_ATTACK_SUCCESS - The attack is valid, and succeeded. No followup attack is made.
|
||||
*/
|
||||
/datum/martial_art/proc/help_act(mob/living/attacker, mob/living/defender)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
PROTECTED_PROC(TRUE)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
/**
|
||||
* Called when disarm-intenting on someone
|
||||
*
|
||||
* What is checked going into this:
|
||||
* Adjacency, [TRAIT_MARTIAL_ARTS_IMMUNE], attacker incapacitated, can_unarmed_attack, can_use
|
||||
*
|
||||
* What is NOT:
|
||||
* check_block
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/attacker - The mob attacking
|
||||
* * mob/living/defender - The mob being attacked
|
||||
*
|
||||
* Returns
|
||||
* * MARTIAL_ATTACK_INVALID - The attack is not valid, do normal unarmed attack
|
||||
* * MARTIAL_ATTACK_FAIL - The attack is valid, but failed. No followup attack is made.
|
||||
* * MARTIAL_ATTACK_SUCCESS - The attack is valid, and succeeded. No followup attack is made.
|
||||
*/
|
||||
/datum/martial_art/proc/disarm_act(mob/living/attacker, mob/living/defender)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
PROTECTED_PROC(TRUE)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
/**
|
||||
* Called when harm-intenting on someone
|
||||
*
|
||||
* What is checked going into this:
|
||||
* Adjacency, [TRAIT_MARTIAL_ARTS_IMMUNE], attacker incapacitated, can_unarmed_attack, can_use
|
||||
*
|
||||
* What is NOT:
|
||||
* check_block
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/attacker - The mob attacking
|
||||
* * mob/living/defender - The mob being attacked
|
||||
*
|
||||
* Returns
|
||||
* * MARTIAL_ATTACK_INVALID - The attack is not valid, do normal unarmed attack
|
||||
* * MARTIAL_ATTACK_FAIL - The attack is valid, but failed. No followup attack is made.
|
||||
* * MARTIAL_ATTACK_SUCCESS - The attack is valid, and succeeded. No followup attack is made.
|
||||
*/
|
||||
/datum/martial_art/proc/harm_act(mob/living/attacker, mob/living/defender)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
PROTECTED_PROC(TRUE)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
/**
|
||||
* Called when grabbing someone
|
||||
*
|
||||
* What is checked going into this:
|
||||
* Adjacency, [TRAIT_MARTIAL_ARTS_IMMUNE], attacker incapacitated, can_unarmed_attack, can_use
|
||||
*
|
||||
* What is NOT:
|
||||
* check_block
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/attacker - The mob attacking
|
||||
* * mob/living/defender - The mob being attacked
|
||||
*
|
||||
* Returns
|
||||
* * MARTIAL_ATTACK_INVALID - The attack is not valid, do normal unarmed attack
|
||||
* * MARTIAL_ATTACK_FAIL - The attack is valid, but failed. No followup attack is made.
|
||||
* * MARTIAL_ATTACK_SUCCESS - The attack is valid, and succeeded. No followup attack is made.
|
||||
*/
|
||||
/datum/martial_art/proc/grab_act(mob/living/attacker, mob/living/defender)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
PROTECTED_PROC(TRUE)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
/datum/martial_art/proc/can_use(mob/living/L)
|
||||
/**
|
||||
* Checks if the passed mob can use this martial art.
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/martial_artist - The mob to check
|
||||
*
|
||||
* Returns
|
||||
* * TRUE - The mob can use this martial art
|
||||
* * FALSE - The mob cannot use this martial art
|
||||
*/
|
||||
/datum/martial_art/proc/can_use(mob/living/martial_artist)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Adds the passed element to the current streak, resetting it if the target is not the same as the last target.
|
||||
*
|
||||
* Arguments
|
||||
* * element - The element to add to the streak. This is some one letter string.
|
||||
* * mob/living/defender - The mob being attacked
|
||||
*/
|
||||
/datum/martial_art/proc/add_to_streak(element, mob/living/defender)
|
||||
if(defender != current_target)
|
||||
if(!IS_WEAKREF_OF(defender, current_target))
|
||||
reset_streak(defender)
|
||||
streak = streak+element
|
||||
streak += element
|
||||
if(length(streak) > max_streak_length)
|
||||
streak = copytext(streak, 1 + length(streak[1]))
|
||||
if (display_combos)
|
||||
var/mob/living/holder_living = holder.resolve()
|
||||
if(display_combos)
|
||||
timerid = addtimer(CALLBACK(src, PROC_REF(reset_streak), null, FALSE), combo_timer, TIMER_UNIQUE | TIMER_STOPPABLE)
|
||||
holder_living?.hud_used?.combo_display.update_icon_state(streak, combo_timer - 2 SECONDS)
|
||||
holder.hud_used?.combo_display.update_icon_state(streak, combo_timer - 2 SECONDS)
|
||||
|
||||
/**
|
||||
* Resets the current streak.
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/new_target - (Optional) The mob being attacked while the reset is occuring.
|
||||
* * update_icon - If TRUE, the combo display will be updated.
|
||||
*/
|
||||
/datum/martial_art/proc/reset_streak(mob/living/new_target, update_icon = TRUE)
|
||||
if(timerid)
|
||||
deltimer(timerid)
|
||||
current_target = new_target
|
||||
current_target = WEAKREF(new_target)
|
||||
streak = ""
|
||||
if(update_icon)
|
||||
var/mob/living/holder_living = holder?.resolve()
|
||||
holder_living?.hud_used?.combo_display.update_icon_state(streak)
|
||||
if(display_combos && update_icon)
|
||||
holder.hud_used?.combo_display.update_icon_state(streak)
|
||||
|
||||
/datum/martial_art/proc/teach(mob/living/holder_living, make_temporary=FALSE)
|
||||
if(!istype(holder_living) || !holder_living.mind)
|
||||
/**
|
||||
* Teaches the passed mob this martial art.
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/new_holder - The mob to teach this martial art to.
|
||||
* * make_temporary - If FALSE, this martial art will completely replace any existing martial arts.
|
||||
* If TRUE, any existing martial art will be stored in the base variable, and will be restored when this martial art is removed.
|
||||
* This can only occur if allow_temp_override is TRUE.
|
||||
*
|
||||
* Returns
|
||||
* * TRUE - The martial art was successfully taught.
|
||||
* * FALSE - The mob failed to learn the martial art, for whatever reason.
|
||||
*/
|
||||
/datum/martial_art/proc/teach(mob/living/new_holder, make_temporary = FALSE)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
|
||||
if(!istype(new_holder) || isnull(new_holder.mind))
|
||||
return FALSE
|
||||
if(holder_living.mind.martial_art)
|
||||
if(make_temporary)
|
||||
if(!holder_living.mind.martial_art.allow_temp_override)
|
||||
return FALSE
|
||||
store(holder_living.mind.martial_art, holder_living)
|
||||
else
|
||||
holder_living.mind.martial_art.on_remove(holder_living)
|
||||
else if(make_temporary)
|
||||
base = holder_living.mind.default_martial_art
|
||||
if(help_verb)
|
||||
add_verb(holder_living, help_verb)
|
||||
holder_living.mind.martial_art = src
|
||||
holder = WEAKREF(holder_living)
|
||||
|
||||
var/datum/martial_art/existing_martial = new_holder.mind.martial_art
|
||||
if(!isnull(existing_martial))
|
||||
if(make_temporary && !existing_martial.allow_temp_override)
|
||||
return FALSE
|
||||
|
||||
if(!isnull(existing_martial.base))
|
||||
store_martial_art(existing_martial.base)
|
||||
existing_martial.unstore_martial_art()
|
||||
else if(make_temporary)
|
||||
store_martial_art(existing_martial)
|
||||
|
||||
// Nulls out any existing martial art, it'll get GC'd if nothing owns it
|
||||
existing_martial.remove(new_holder)
|
||||
|
||||
new_holder.mind.martial_art = src
|
||||
holder = new_holder
|
||||
on_teach(new_holder)
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/proc/store(datum/martial_art/old, mob/living/holder_living)
|
||||
old.on_remove(holder_living)
|
||||
if (old.base) //Checks if old is temporary, if so it will not be stored.
|
||||
base = old.base
|
||||
else //Otherwise, old is stored.
|
||||
base = old
|
||||
/// Stores the passed martial art in the base var.
|
||||
/datum/martial_art/proc/store_martial_art(datum/martial_art/martial)
|
||||
if(!isnull(base))
|
||||
UnregisterSignal(base, COMSIG_QDELETING)
|
||||
|
||||
/datum/martial_art/proc/remove(mob/living/holder_living)
|
||||
if(!istype(holder_living) || !holder_living.mind || holder_living.mind.martial_art != src)
|
||||
return
|
||||
on_remove(holder_living)
|
||||
if(base)
|
||||
base.teach(holder_living)
|
||||
else
|
||||
var/datum/martial_art/default = holder_living.mind.default_martial_art
|
||||
default.teach(holder_living)
|
||||
base = martial
|
||||
RegisterSignal(base, COMSIG_QDELETING, PROC_REF(base_deleted))
|
||||
|
||||
/// Unstores the base var.
|
||||
/datum/martial_art/proc/unstore_martial_art()
|
||||
UnregisterSignal(base, COMSIG_QDELETING)
|
||||
base = null
|
||||
|
||||
/datum/martial_art/proc/base_deleted(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
base = null
|
||||
|
||||
/**
|
||||
* Removes this martial art from the passed mob AND their mind.
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/old_holder - The mob to remove this martial art from.
|
||||
*/
|
||||
/datum/martial_art/proc/remove(mob/living/old_holder)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
|
||||
ASSERT(old_holder == holder)
|
||||
ASSERT(old_holder.mind.martial_art == src)
|
||||
|
||||
on_remove(old_holder)
|
||||
old_holder.mind.martial_art = null
|
||||
if(!isnull(base))
|
||||
base.teach(old_holder)
|
||||
unstore_martial_art()
|
||||
holder = null
|
||||
|
||||
/datum/martial_art/proc/on_remove(mob/living/holder_living)
|
||||
/**
|
||||
* A helper proc to remove the martial art from the passed mob fully, e
|
||||
* ven if stored in another martial art's base.
|
||||
*
|
||||
* Arguments
|
||||
* * mob/living/maybe_holder - The mob to check.
|
||||
*
|
||||
* Returns
|
||||
* * TRUE - If the martial art was removed in some way
|
||||
* * FALSE - If nothing happened
|
||||
*/
|
||||
/datum/martial_art/proc/fully_remove(mob/living/maybe_holder)
|
||||
var/datum/martial_art/holder_art = maybe_holder.mind?.martial_art
|
||||
if(isnull(holder_art))
|
||||
return FALSE
|
||||
|
||||
if(holder_art == src)
|
||||
remove(maybe_holder)
|
||||
return TRUE
|
||||
|
||||
if(holder_art.base == src)
|
||||
holder_art.unstore_martial_art()
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Called when this martial art is added to a mob.
|
||||
*/
|
||||
/datum/martial_art/proc/on_teach(mob/living/new_holder)
|
||||
if(help_verb)
|
||||
remove_verb(holder_living, help_verb)
|
||||
return
|
||||
add_verb(new_holder, help_verb)
|
||||
RegisterSignal(new_holder, COMSIG_QDELETING, PROC_REF(holder_deleted))
|
||||
RegisterSignal(new_holder, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(unarmed_strike))
|
||||
RegisterSignal(new_holder, COMSIG_LIVING_GRAB, PROC_REF(attempt_grab))
|
||||
RegisterSignal(new_holder, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, PROC_REF(transfer_martial_arts))
|
||||
|
||||
/**
|
||||
* Called when this martial art is removed from a mob.
|
||||
*/
|
||||
/datum/martial_art/proc/on_remove(mob/living/remove_from)
|
||||
if(help_verb)
|
||||
remove_verb(remove_from, help_verb)
|
||||
UnregisterSignal(remove_from, list(COMSIG_QDELETING, COMSIG_LIVING_UNARMED_ATTACK, COMSIG_LIVING_GRAB, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF))
|
||||
|
||||
/datum/martial_art/proc/holder_deleted(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
holder = null
|
||||
|
||||
/// Signal proc for [COMSIG_MOB_MIND_TRANSFERRED_OUT_OF] to pass martial arts between bodies on mind transfer
|
||||
/// By this point the martial art's holder is the old body, but the mind that owns it is in the new body
|
||||
/datum/martial_art/proc/transfer_martial_arts(mob/living/old_body, mob/living/new_body)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
// This has some notable issues in that martial arts granted by items like Krav Maga
|
||||
// will follow the body swap, the easiest fix would be to move martial arts off of the mind
|
||||
|
||||
if(!isnull(base)) // If we're home to a temporary one just don't touch it, give the base to the new body and leave it at that
|
||||
base.teach(new_body)
|
||||
unstore_martial_art()
|
||||
return
|
||||
|
||||
on_remove(old_body) // on_remove rather than remove, because by this point the mind is already in the new body, which remove handles.
|
||||
teach(new_body)
|
||||
|
||||
@@ -3,62 +3,78 @@
|
||||
id = MARTIALART_BOXING
|
||||
pacifist_style = TRUE
|
||||
|
||||
/datum/martial_art/boxing/disarm_act(mob/living/attacker, mob/living/defender)
|
||||
to_chat(attacker, span_warning("Can't disarm while boxing!"))
|
||||
return TRUE
|
||||
/datum/martial_art/boxing/teach(mob/living/new_holder, make_temporary)
|
||||
if(!ishuman(new_holder))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/boxing/grab_act(mob/living/attacker, mob/living/defender)
|
||||
to_chat(attacker, span_warning("Can't grab while boxing!"))
|
||||
return TRUE
|
||||
/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/attacker, mob/living/defender)
|
||||
attacker.balloon_alert(attacker, "can't disarm while boxing!")
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
/datum/martial_art/boxing/harm_act(mob/living/attacker, mob/living/defender)
|
||||
|
||||
var/mob/living/carbon/human/attacker_human = attacker
|
||||
var/obj/item/bodypart/arm/active_arm = attacker_human.get_active_hand()
|
||||
/datum/martial_art/boxing/grab_act(mob/living/carbon/human/attacker, mob/living/defender)
|
||||
attacker.balloon_alert(attacker, "can't grab while boxing!")
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
/datum/martial_art/boxing/harm_act(mob/living/carbon/human/attacker, mob/living/defender)
|
||||
var/obj/item/bodypart/arm/active_arm = attacker.get_active_hand()
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
|
||||
var/atk_verb = pick("left hook","right hook","straight punch")
|
||||
|
||||
var/damage = rand(5, 8) + active_arm.unarmed_damage_low
|
||||
if(!damage)
|
||||
playsound(defender.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1)
|
||||
defender.visible_message(span_warning("[attacker]'s [atk_verb] misses [defender]!"), \
|
||||
span_danger("You avoid [attacker]'s [atk_verb]!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
var/atk_verb = pick("left hook", "right hook", "straight punch")
|
||||
if(damage <= 0)
|
||||
playsound(defender, active_arm.unarmed_miss_sound, 25, TRUE, -1)
|
||||
defender.visible_message(
|
||||
span_warning("[attacker]'s [atk_verb] misses [defender]!"),
|
||||
span_danger("You avoid [attacker]'s [atk_verb]!"),
|
||||
span_hear("You hear a swoosh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_warning("Your [atk_verb] misses [defender]!"))
|
||||
log_combat(attacker, defender, "attempted to hit", atk_verb)
|
||||
return FALSE
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
if(defender.check_block(attacker, damage, "[attacker]'s [atk_verb]", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
|
||||
var/armor_block = defender.run_armor_check(affecting, MELEE)
|
||||
|
||||
playsound(defender.loc, active_arm.unarmed_attack_sound, 25, TRUE, -1)
|
||||
|
||||
defender.visible_message(span_danger("[attacker] [atk_verb]ed [defender]!"), \
|
||||
span_userdanger("You're [atk_verb]ed by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
playsound(defender, active_arm.unarmed_attack_sound, 25, TRUE, -1)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] [atk_verb]ed [defender]!"),
|
||||
span_userdanger("You're [atk_verb]ed by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You [atk_verb]ed [defender]!"))
|
||||
|
||||
defender.apply_damage(damage, STAMINA, affecting, armor_block)
|
||||
log_combat(attacker, defender, "punched (boxing) ")
|
||||
if(defender.getStaminaLoss() > 50 && istype(defender.mind?.martial_art, /datum/martial_art/boxing))
|
||||
var/knockout_prob = defender.getStaminaLoss() + rand(-15,15)
|
||||
if((defender.stat != DEAD) && prob(knockout_prob))
|
||||
defender.visible_message(span_danger("[attacker] knocks [defender] out with a haymaker!"), \
|
||||
span_userdanger("You're knocked unconscious by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
var/knockout_prob = defender.getStaminaLoss() + rand(-15, 15)
|
||||
if(defender.stat != DEAD && prob(knockout_prob))
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] knocks [defender] out with a haymaker!"),
|
||||
span_userdanger("You're knocked unconscious by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You knock [defender] out with a haymaker!"))
|
||||
defender.apply_effect(20 SECONDS,EFFECT_KNOCKDOWN, armor_block)
|
||||
defender.apply_effect(20 SECONDS, EFFECT_KNOCKDOWN, armor_block)
|
||||
defender.SetSleeping(10 SECONDS)
|
||||
log_combat(attacker, defender, "knocked out (boxing) ")
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/boxing/can_use(mob/living/owner)
|
||||
if(!ishuman(owner))
|
||||
/datum/martial_art/boxing/can_use(mob/living/martial_artist)
|
||||
if(!ishuman(martial_artist))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/gloves/boxing
|
||||
var/datum/martial_art/boxing/style = new
|
||||
var/datum/martial_art/boxing/style
|
||||
|
||||
/obj/item/clothing/gloves/boxing/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -69,18 +85,18 @@
|
||||
slapcraft_recipes = slapcraft_recipe_list,\
|
||||
)
|
||||
|
||||
style = new()
|
||||
style.allow_temp_override = FALSE
|
||||
|
||||
/obj/item/clothing/gloves/boxing/Destroy()
|
||||
QDEL_NULL(style)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
|
||||
..()
|
||||
// boxing requires human
|
||||
if(!ishuman(user))
|
||||
return
|
||||
. = ..()
|
||||
if(slot & ITEM_SLOT_GLOVES)
|
||||
var/mob/living/student = user
|
||||
style.teach(student, 1)
|
||||
style.teach(user, TRUE)
|
||||
|
||||
/obj/item/clothing/gloves/boxing/dropped(mob/user)
|
||||
..()
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/owner = user
|
||||
style.remove(owner)
|
||||
. = ..()
|
||||
style.fully_remove(user)
|
||||
|
||||
+200
-128
@@ -10,19 +10,19 @@
|
||||
help_verb = /mob/living/proc/CQC_help
|
||||
smashes_tables = TRUE
|
||||
display_combos = TRUE
|
||||
var/old_grab_state = null
|
||||
var/mob/restraining_mob
|
||||
/// Weakref to a mob we're currently restraining (with grab-grab combo)
|
||||
VAR_PRIVATE/datum/weakref/restraining_mob
|
||||
/// Probability of successfully blocking attacks while on throw mode
|
||||
var/block_chance = 75
|
||||
|
||||
/datum/martial_art/cqc/teach(mob/living/cqc_user, make_temporary)
|
||||
/datum/martial_art/cqc/on_teach(mob/living/new_holder)
|
||||
. = ..()
|
||||
RegisterSignal(cqc_user, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
|
||||
RegisterSignal(cqc_user, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block))
|
||||
RegisterSignal(new_holder, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
|
||||
RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block))
|
||||
|
||||
/datum/martial_art/cqc/on_remove(mob/living/cqc_user)
|
||||
UnregisterSignal(cqc_user, list(COMSIG_ATOM_ATTACKBY, COMSIG_LIVING_CHECK_BLOCK))
|
||||
. = ..()
|
||||
/datum/martial_art/cqc/on_remove(mob/living/remove_from)
|
||||
UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_LIVING_CHECK_BLOCK))
|
||||
return ..()
|
||||
|
||||
///Signal from getting attacked with an item, for a special interaction with touch spells
|
||||
/datum/martial_art/cqc/proc/on_attackby(mob/living/cqc_user, obj/item/attack_weapon, mob/attacker, params)
|
||||
@@ -69,13 +69,11 @@
|
||||
|
||||
|
||||
/datum/martial_art/cqc/reset_streak(mob/living/new_target)
|
||||
if(new_target && new_target != restraining_mob)
|
||||
if(!IS_WEAKREF_OF(new_target, restraining_mob))
|
||||
restraining_mob = null
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/cqc/proc/check_streak(mob/living/attacker, mob/living/defender)
|
||||
if(!can_use(attacker))
|
||||
return FALSE
|
||||
if(findtext(streak, SLAM_COMBO))
|
||||
reset_streak()
|
||||
return Slam(attacker, defender)
|
||||
@@ -94,122 +92,152 @@
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/cqc/proc/Slam(mob/living/attacker, mob/living/defender)
|
||||
if(!can_use(attacker))
|
||||
if(defender.body_position != STANDING_UP)
|
||||
return FALSE
|
||||
if(defender.body_position == STANDING_UP)
|
||||
defender.visible_message(span_danger("[attacker] slams [defender] into the ground!"), \
|
||||
span_userdanger("You're slammed into the ground by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, attacker)
|
||||
to_chat(attacker, span_danger("You slam [defender] into the ground!"))
|
||||
playsound(get_turf(attacker), 'sound/weapons/slam.ogg', 50, TRUE, -1)
|
||||
defender.apply_damage(10, BRUTE)
|
||||
defender.Paralyze(12 SECONDS)
|
||||
log_combat(attacker, defender, "slammed (CQC)")
|
||||
return TRUE
|
||||
|
||||
attacker.do_attack_animation(defender)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] slams [defender] into the ground!"),
|
||||
span_userdanger("You're slammed into the ground by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You slam [defender] into the ground!"))
|
||||
playsound(attacker, 'sound/weapons/slam.ogg', 50, TRUE, -1)
|
||||
defender.apply_damage(10, BRUTE)
|
||||
defender.Paralyze(12 SECONDS)
|
||||
log_combat(attacker, defender, "slammed (CQC)")
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/cqc/proc/Kick(mob/living/attacker, mob/living/defender)
|
||||
if(!can_use(attacker) || defender.stat != CONSCIOUS)
|
||||
if(defender.stat != CONSCIOUS)
|
||||
return FALSE
|
||||
|
||||
attacker.do_attack_animation(defender)
|
||||
if(defender.body_position == LYING_DOWN && !defender.IsUnconscious() && defender.getStaminaLoss() >= 100)
|
||||
log_combat(attacker, defender, "knocked out (Head kick)(CQC)")
|
||||
defender.visible_message(span_danger("[attacker] kicks [defender]'s head, knocking [defender.p_them()] out!"), \
|
||||
span_userdanger("You're knocked unconscious by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, attacker)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] kicks [defender]'s head, knocking [defender.p_them()] out!"),
|
||||
span_userdanger("You're knocked unconscious by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You kick [defender]'s head, knocking [defender.p_them()] out!"))
|
||||
playsound(get_turf(attacker), 'sound/weapons/genhit1.ogg', 50, TRUE, -1)
|
||||
playsound(attacker, 'sound/weapons/genhit1.ogg', 50, TRUE, -1)
|
||||
|
||||
var/helmet_protection = defender.run_armor_check(BODY_ZONE_HEAD, MELEE)
|
||||
defender.apply_effect(20 SECONDS, EFFECT_KNOCKDOWN, helmet_protection)
|
||||
defender.apply_effect(10 SECONDS, EFFECT_UNCONSCIOUS, helmet_protection)
|
||||
defender.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 150)
|
||||
|
||||
else
|
||||
defender.visible_message(span_danger("[attacker] kicks [defender] back!"), \
|
||||
span_userdanger("You're kicked back by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] kicks [defender] back!"),
|
||||
span_userdanger("You're kicked back by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You kick [defender] back!"))
|
||||
playsound(get_turf(attacker), 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
|
||||
playsound(attacker, 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
|
||||
var/atom/throw_target = get_edge_target_turf(defender, attacker.dir)
|
||||
defender.throw_at(throw_target, 1, 14, attacker)
|
||||
defender.apply_damage(10, attacker.get_attack_type())
|
||||
if(defender.body_position == LYING_DOWN && !defender.IsUnconscious())
|
||||
defender.adjustStaminaLoss(45)
|
||||
log_combat(attacker, defender, "kicked (CQC)")
|
||||
. = TRUE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/cqc/proc/Pressure(mob/living/attacker, mob/living/defender)
|
||||
if(!can_use(attacker))
|
||||
return FALSE
|
||||
attacker.do_attack_animation(defender)
|
||||
log_combat(attacker, defender, "pressured (CQC)")
|
||||
defender.visible_message(span_danger("[attacker] punches [defender]'s neck!"), \
|
||||
span_userdanger("Your neck is punched by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] punches [defender]'s neck!"),
|
||||
span_userdanger("Your neck is punched by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You punch [defender]'s neck!"))
|
||||
defender.adjustStaminaLoss(60)
|
||||
playsound(get_turf(attacker), 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
|
||||
playsound(attacker, 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/cqc/proc/Restrain(mob/living/attacker, mob/living/defender)
|
||||
if(restraining_mob)
|
||||
return
|
||||
if(!can_use(attacker))
|
||||
if(restraining_mob?.resolve())
|
||||
return FALSE
|
||||
if(!defender.stat)
|
||||
log_combat(attacker, defender, "restrained (CQC)")
|
||||
defender.visible_message(span_warning("[attacker] locks [defender] into a restraining position!"), \
|
||||
span_userdanger("You're locked into a restraining position by [attacker]!"), span_hear("You hear shuffling and a muffled groan!"), null, attacker)
|
||||
to_chat(attacker, span_danger("You lock [defender] into a restraining position!"))
|
||||
defender.adjustStaminaLoss(20)
|
||||
defender.Stun(10 SECONDS)
|
||||
restraining_mob = defender
|
||||
addtimer(VARSET_CALLBACK(src, restraining_mob, null), 50, TIMER_UNIQUE)
|
||||
return TRUE
|
||||
if(defender.stat != CONSCIOUS)
|
||||
return FALSE
|
||||
|
||||
log_combat(attacker, defender, "restrained (CQC)")
|
||||
defender.visible_message(
|
||||
span_warning("[attacker] locks [defender] into a restraining position!"),
|
||||
span_userdanger("You're locked into a restraining position by [attacker]!"),
|
||||
span_hear("You hear shuffling and a muffled groan!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You lock [defender] into a restraining position!"))
|
||||
defender.adjustStaminaLoss(20)
|
||||
defender.Stun(10 SECONDS)
|
||||
restraining_mob = WEAKREF(defender)
|
||||
addtimer(VARSET_CALLBACK(src, restraining_mob, null), 5 SECONDS, TIMER_UNIQUE)
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/cqc/proc/Consecutive(mob/living/attacker, mob/living/defender)
|
||||
if(!can_use(attacker))
|
||||
if(defender.stat != CONSCIOUS)
|
||||
return FALSE
|
||||
if(!defender.stat)
|
||||
log_combat(attacker, defender, "consecutive CQC'd (CQC)")
|
||||
defender.visible_message(span_danger("[attacker] strikes [defender]'s abdomen, neck and back consecutively"), \
|
||||
span_userdanger("Your abdomen, neck and back are struck consecutively by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
to_chat(attacker, span_danger("You strike [defender]'s abdomen, neck and back consecutively!"))
|
||||
playsound(get_turf(defender), 'sound/weapons/cqchit2.ogg', 50, TRUE, -1)
|
||||
var/obj/item/held_item = defender.get_active_held_item()
|
||||
if(held_item && defender.temporarilyRemoveItemFromInventory(held_item))
|
||||
attacker.put_in_hands(held_item)
|
||||
defender.adjustStaminaLoss(50)
|
||||
defender.apply_damage(25, attacker.get_attack_type())
|
||||
return TRUE
|
||||
|
||||
attacker.do_attack_animation(defender)
|
||||
log_combat(attacker, defender, "consecutive CQC'd (CQC)")
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] strikes [defender]'s abdomen, neck and back consecutively"), \
|
||||
span_userdanger("Your abdomen, neck and back are struck consecutively by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You strike [defender]'s abdomen, neck and back consecutively!"))
|
||||
playsound(defender, 'sound/weapons/cqchit2.ogg', 50, TRUE, -1)
|
||||
var/obj/item/held_item = defender.get_active_held_item()
|
||||
if(held_item && defender.temporarilyRemoveItemFromInventory(held_item))
|
||||
attacker.put_in_hands(held_item)
|
||||
defender.adjustStaminaLoss(50)
|
||||
defender.apply_damage(25, attacker.get_attack_type())
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/cqc/grab_act(mob/living/attacker, mob/living/defender)
|
||||
if(attacker != defender && can_use(attacker)) // attacker != defender prevents grabbing yourself
|
||||
add_to_streak("G", defender)
|
||||
if(check_streak(attacker, defender)) //if a combo is made no grab upgrade is done
|
||||
return TRUE
|
||||
old_grab_state = attacker.grab_state
|
||||
defender.grabbedby(attacker, 1)
|
||||
if(old_grab_state == GRAB_PASSIVE)
|
||||
defender.drop_all_held_items()
|
||||
attacker.setGrabState(GRAB_AGGRESSIVE) //Instant aggressive grab if on grab intent
|
||||
log_combat(attacker, defender, "grabbed", addition="aggressively")
|
||||
defender.visible_message(span_warning("[attacker] violently grabs [defender]!"), \
|
||||
span_userdanger("You're grabbed violently by [attacker]!"), span_hear("You hear sounds of aggressive fondling!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
to_chat(attacker, span_danger("You violently grab [defender]!"))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/cqc/harm_act(mob/living/attacker, mob/living/defender)
|
||||
if(!can_use(attacker))
|
||||
if(attacker == defender)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
if(attacker.resting && defender.stat != DEAD && defender.body_position == STANDING_UP)
|
||||
defender.visible_message(span_danger("[attacker] leg sweeps [defender]!"), \
|
||||
span_userdanger("Your legs are sweeped by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, attacker)
|
||||
to_chat(attacker, span_danger("You leg sweep [defender]!"))
|
||||
playsound(get_turf(attacker), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
attacker.do_attack_animation(defender)
|
||||
defender.apply_damage(10, BRUTE)
|
||||
defender.Knockdown(5 SECONDS)
|
||||
log_combat(attacker, defender, "sweeped (CQC)")
|
||||
reset_streak()
|
||||
add_to_streak("G", defender)
|
||||
if(check_streak(attacker, defender)) //if a combo is made no grab upgrade is done
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
if(attacker.body_position == LYING_DOWN)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
var/old_grab_state = attacker.grab_state
|
||||
defender.grabbedby(attacker, TRUE)
|
||||
if(old_grab_state == GRAB_PASSIVE)
|
||||
defender.drop_all_held_items()
|
||||
attacker.setGrabState(GRAB_AGGRESSIVE) //Instant aggressive grab if on grab intent
|
||||
log_combat(attacker, defender, "grabbed", addition="aggressively")
|
||||
defender.visible_message(
|
||||
span_warning("[attacker] violently grabs [defender]!"),
|
||||
span_userdanger("You're grabbed violently by [attacker]!"),
|
||||
span_hear("You hear sounds of aggressive fondling!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You violently grab [defender]!"))
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/cqc/harm_act(mob/living/attacker, mob/living/defender)
|
||||
if(attacker.grab_state == GRAB_KILL \
|
||||
&& attacker.zone_selected == BODY_ZONE_HEAD \
|
||||
&& attacker.pulling == defender \
|
||||
@@ -232,63 +260,107 @@
|
||||
defender.investigate_log("has had [defender.p_their()] neck snapped by [attacker].", INVESTIGATE_DEATHS)
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
if(defender.check_block(attacker, 10, attacker.name, UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
if(attacker.resting && defender.stat != DEAD && defender.body_position == STANDING_UP)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] leg sweeps [defender]!"),
|
||||
span_userdanger("Your legs are sweeped by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You leg sweep [defender]!"))
|
||||
playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
attacker.do_attack_animation(defender)
|
||||
defender.apply_damage(10, BRUTE)
|
||||
defender.Knockdown(5 SECONDS)
|
||||
log_combat(attacker, defender, "sweeped (CQC)")
|
||||
reset_streak()
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
add_to_streak("H", defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
log_combat(attacker, defender, "attacked (CQC)")
|
||||
attacker.do_attack_animation(defender)
|
||||
var/picked_hit_type = pick("CQC", "Big Boss")
|
||||
var/bonus_damage = 13
|
||||
if(defender.body_position == LYING_DOWN)
|
||||
bonus_damage += 5
|
||||
picked_hit_type = "stomp"
|
||||
picked_hit_type = pick("kick", "stomp")
|
||||
defender.apply_damage(bonus_damage, BRUTE)
|
||||
if(picked_hit_type == "kick" || picked_hit_type == "stomp")
|
||||
playsound(get_turf(defender), 'sound/weapons/cqchit2.ogg', 50, TRUE, -1)
|
||||
else
|
||||
playsound(get_turf(defender), 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
|
||||
defender.visible_message(span_danger("[attacker] [picked_hit_type]ed [defender]!"), \
|
||||
span_userdanger("You're [picked_hit_type]ed by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
to_chat(attacker, span_danger("You [picked_hit_type] [defender]!"))
|
||||
log_combat(attacker, defender, "[picked_hit_type]s (CQC)")
|
||||
|
||||
playsound(defender, (picked_hit_type == "kick" || picked_hit_type == "stomp") ? 'sound/weapons/cqchit2.ogg' : 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
|
||||
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] [picked_hit_type]ed [defender]!"),
|
||||
span_userdanger("You're [picked_hit_type]ed by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You [picked_hit_type] [defender]!"))
|
||||
log_combat(attacker, defender, "attacked ([picked_hit_type]'d)(CQC)")
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/cqc/disarm_act(mob/living/attacker, mob/living/defender)
|
||||
if(!can_use(attacker))
|
||||
return FALSE
|
||||
if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
add_to_streak("D", defender)
|
||||
var/obj/item/held_item = null
|
||||
if(check_streak(attacker, defender))
|
||||
return TRUE
|
||||
log_combat(attacker, defender, "disarmed (CQC)", "[held_item ? " grabbing \the [held_item]" : ""]")
|
||||
if(restraining_mob && attacker.pulling == restraining_mob)
|
||||
log_combat(attacker, defender, "knocked out (Chokehold)(CQC)")
|
||||
defender.visible_message(span_danger("[attacker] puts [defender] into a chokehold!"), \
|
||||
span_userdanger("You're put into a chokehold by [attacker]!"), span_hear("You hear shuffling and a muffled groan!"), null, attacker)
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
if(IS_WEAKREF_OF(attacker.pulling, restraining_mob))
|
||||
log_combat(attacker, defender, "disarmed (CQC)", addition = "knocked out (CQC Chokehold)")
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] puts [defender] into a chokehold!"),
|
||||
span_userdanger("You're put into a chokehold by [attacker]!"),
|
||||
span_hear("You hear shuffling and a muffled groan!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You put [defender] into a chokehold!"))
|
||||
defender.SetSleeping(40 SECONDS)
|
||||
restraining_mob = null
|
||||
if(attacker.grab_state < GRAB_NECK && !HAS_TRAIT(attacker, TRAIT_PACIFISM))
|
||||
attacker.setGrabState(GRAB_NECK)
|
||||
return TRUE
|
||||
if(prob(65))
|
||||
if(!defender.stat || !defender.IsParalyzed() || !restraining_mob)
|
||||
held_item = defender.get_active_held_item()
|
||||
defender.visible_message(span_danger("[attacker] strikes [defender]'s jaw with their hand!"), \
|
||||
span_userdanger("Your jaw is struck by [attacker], you feel disoriented!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
to_chat(attacker, span_danger("You strike [defender]'s jaw, leaving [defender.p_them()] disoriented!"))
|
||||
playsound(get_turf(defender), 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
|
||||
if(held_item && defender.temporarilyRemoveItemFromInventory(held_item))
|
||||
attacker.put_in_hands(held_item)
|
||||
defender.set_jitter_if_lower(4 SECONDS)
|
||||
defender.apply_damage(5, attacker.get_attack_type())
|
||||
else
|
||||
defender.visible_message(span_danger("[attacker] fails to disarm [defender]!"), \
|
||||
span_userdanger("You're nearly disarmed by [attacker]!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
to_chat(attacker, span_warning("You fail to disarm [defender]!"))
|
||||
playsound(defender, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1)
|
||||
return FALSE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_DISARM)
|
||||
if(prob(65) && (defender.stat == CONSCIOUS || !defender.IsParalyzed() || !restraining_mob?.resolve()))
|
||||
var/obj/item/disarmed_item = defender.get_active_held_item()
|
||||
if(disarmed_item && defender.temporarilyRemoveItemFromInventory(disarmed_item))
|
||||
attacker.put_in_hands(disarmed_item)
|
||||
else
|
||||
disarmed_item = null
|
||||
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] strikes [defender]'s jaw with their hand[disarmed_item ? ", disarming [defender.p_them()] of [disarmed_item]" : ""]!"),
|
||||
span_userdanger("[attacker] strikes your jaw,[disarmed_item ? " disarming you of [disarmed_item] and" : ""] leaving you disoriented!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You strike [defender]'s jaw,[disarmed_item ? " disarming [defender.p_them()] of [disarmed_item] and" : ""] leaving [defender.p_them()] disoriented!"))
|
||||
playsound(defender, 'sound/weapons/cqchit1.ogg', 50, TRUE, -1)
|
||||
defender.set_jitter_if_lower(4 SECONDS)
|
||||
defender.apply_damage(5, attacker.get_attack_type())
|
||||
log_combat(attacker, defender, "disarmed (CQC)", addition = disarmed_item ? "(disarmed of [disarmed_item])" : null)
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] fails to disarm [defender]!"), \
|
||||
span_userdanger("You're nearly disarmed by [attacker]!"),
|
||||
span_hear("You hear a swoosh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_warning("You fail to disarm [defender]!"))
|
||||
playsound(defender, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1)
|
||||
log_combat(attacker, defender, "failed to disarm (CQC)")
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
|
||||
/mob/living/proc/CQC_help()
|
||||
@@ -330,8 +402,8 @@
|
||||
kitchen_areas |= path
|
||||
|
||||
/// Limits where the chef's CQC can be used to only whitelisted areas.
|
||||
/datum/martial_art/cqc/under_siege/can_use(mob/living/owner)
|
||||
if(!is_type_in_list(get_area(owner), kitchen_areas))
|
||||
/datum/martial_art/cqc/under_siege/can_use(mob/living/martial_artist)
|
||||
if(!is_type_in_list(get_area(martial_artist), kitchen_areas))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/// Gondola love, makes hugs inject pax if the arms are exposed
|
||||
/datum/martial_art/hugs_of_the_gondola
|
||||
name = "Hugs of the Gondola"
|
||||
id = MARTIALART_HUGS_OF_THE_GONDOLA
|
||||
|
||||
/datum/martial_art/hugs_of_the_gondola/help_act(mob/living/attacker, mob/living/defender)
|
||||
if(ishuman(defender) && ishuman(attacker))
|
||||
var/mob/living/carbon/human/human_attacker = attacker
|
||||
var/mob/living/carbon/human/human_defender = defender
|
||||
var/list/covered_body_zones = human_attacker.get_covered_body_zones()
|
||||
var/pax_injected = 4
|
||||
if(BODY_ZONE_L_ARM in covered_body_zones)
|
||||
pax_injected -= 2
|
||||
if(BODY_ZONE_R_ARM in covered_body_zones)
|
||||
pax_injected -= 2
|
||||
if(pax_injected)
|
||||
human_defender.reagents.add_reagent(/datum/reagent/pax, pax_injected)
|
||||
to_chat(defender, span_warning("You feel a tiny prick!"))
|
||||
//this is so it hugs/shakes up as usual
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
@@ -1,18 +1,31 @@
|
||||
/datum/martial_art/krav_maga
|
||||
name = "Krav Maga"
|
||||
id = MARTIALART_KRAVMAGA
|
||||
var/datum/action/neck_chop/neckchop = new/datum/action/neck_chop()
|
||||
var/datum/action/leg_sweep/legsweep = new/datum/action/leg_sweep()
|
||||
var/datum/action/lung_punch/lungpunch = new/datum/action/lung_punch()
|
||||
VAR_PRIVATE/datum/action/neck_chop/neckchop
|
||||
VAR_PRIVATE/datum/action/leg_sweep/legsweep
|
||||
VAR_PRIVATE/datum/action/lung_punch/lungpunch
|
||||
|
||||
/datum/martial_art/krav_maga/New()
|
||||
. = ..()
|
||||
neckchop = new(src)
|
||||
legsweep = new(src)
|
||||
lungpunch = new(src)
|
||||
|
||||
/datum/martial_art/krav_maga/Destroy()
|
||||
neckchop = null
|
||||
legsweep = null
|
||||
lungpunch = null
|
||||
return ..()
|
||||
|
||||
/datum/action/neck_chop
|
||||
name = "Neck Chop - Injures the neck, stopping the victim from speaking for a while."
|
||||
button_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "neckchop"
|
||||
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_HANDS_BLOCKED|AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/neck_chop/Trigger(trigger_flags)
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, span_warning("You can't use [name] while you're incapacitated."))
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if (owner.mind.martial_art.streak == "neck_chop")
|
||||
owner.visible_message(span_danger("[owner] assumes a neutral stance."), "<b><i>Your next attack is cleared.</i></b>")
|
||||
@@ -25,10 +38,11 @@
|
||||
name = "Leg Sweep - Trips the victim, knocking them down for a brief moment."
|
||||
button_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "legsweep"
|
||||
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_HANDS_BLOCKED|AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/leg_sweep/Trigger(trigger_flags)
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, span_warning("You can't use [name] while you're incapacitated."))
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if (owner.mind.martial_art.streak == "leg_sweep")
|
||||
owner.visible_message(span_danger("[owner] assumes a neutral stance."), "<b><i>Your next attack is cleared.</i></b>")
|
||||
@@ -41,10 +55,11 @@
|
||||
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."
|
||||
button_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "lungpunch"
|
||||
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_HANDS_BLOCKED|AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/lung_punch/Trigger(trigger_flags)
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, span_warning("You can't use [name] while you're incapacitated."))
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if (owner.mind.martial_art.streak == "quick_choke")
|
||||
owner.visible_message(span_danger("[owner] assumes a neutral stance."), "<b><i>Your next attack is cleared.</i></b>")
|
||||
@@ -53,19 +68,20 @@
|
||||
owner.visible_message(span_danger("[owner] assumes the Lung Punch stance!"), "<b><i>Your next attack will be a Lung Punch.</i></b>")
|
||||
owner.mind.martial_art.streak = "quick_choke"//internal name for lung punch
|
||||
|
||||
/datum/martial_art/krav_maga/teach(mob/living/owner, make_temporary=FALSE)
|
||||
if(..())
|
||||
to_chat(owner, span_userdanger("You know the arts of [name]!"))
|
||||
to_chat(owner, span_danger("Place your cursor over a move at the top of the screen to see what it does."))
|
||||
neckchop.Grant(owner)
|
||||
legsweep.Grant(owner)
|
||||
lungpunch.Grant(owner)
|
||||
/datum/martial_art/krav_maga/on_teach(mob/living/new_holder)
|
||||
. = ..()
|
||||
to_chat(new_holder, span_userdanger("You know the arts of [name]!"))
|
||||
to_chat(new_holder, span_danger("Place your cursor over a move at the top of the screen to see what it does."))
|
||||
neckchop.Grant(new_holder)
|
||||
legsweep.Grant(new_holder)
|
||||
lungpunch.Grant(new_holder)
|
||||
|
||||
/datum/martial_art/krav_maga/on_remove(mob/living/owner)
|
||||
to_chat(owner, span_userdanger("You suddenly forget the arts of [name]..."))
|
||||
neckchop.Remove(owner)
|
||||
legsweep.Remove(owner)
|
||||
lungpunch.Remove(owner)
|
||||
/datum/martial_art/krav_maga/on_remove(mob/living/remove_from)
|
||||
to_chat(remove_from, span_userdanger("You suddenly forget the arts of [name]..."))
|
||||
neckchop?.Remove(remove_from)
|
||||
legsweep?.Remove(remove_from)
|
||||
lungpunch?.Remove(remove_from)
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/krav_maga/proc/check_streak(mob/living/attacker, mob/living/defender)
|
||||
switch(streak)
|
||||
@@ -84,81 +100,134 @@
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/krav_maga/proc/leg_sweep(mob/living/attacker, mob/living/defender)
|
||||
if(defender.stat || defender.IsParalyzed())
|
||||
return FALSE
|
||||
defender.visible_message(span_warning("[attacker] leg sweeps [defender]!"), \
|
||||
span_userdanger("Your legs are sweeped by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, attacker)
|
||||
if(defender.stat != CONSCIOUS || defender.IsParalyzed())
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
defender.visible_message(
|
||||
span_warning("[attacker] leg sweeps [defender]!"),
|
||||
span_userdanger("Your legs are sweeped by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You leg sweep [defender]!"))
|
||||
playsound(get_turf(attacker), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
defender.apply_damage(5, BRUTE, BODY_ZONE_CHEST)
|
||||
defender.Knockdown(6 SECONDS)
|
||||
log_combat(attacker, defender, "leg sweeped")
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/krav_maga/proc/quick_choke(mob/living/attacker, mob/living/defender)//is actually lung punch
|
||||
defender.visible_message(span_warning("[attacker] pounds [defender] on the chest!"), \
|
||||
span_userdanger("Your chest is slammed by [attacker]! You can't breathe!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
attacker.do_attack_animation(defender)
|
||||
defender.visible_message(
|
||||
span_warning("[attacker] pounds [defender] on the chest!"),
|
||||
span_userdanger("Your chest is slammed by [attacker]! You can't breathe!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You pound [defender] on the chest!"))
|
||||
playsound(get_turf(attacker), 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
playsound(attacker, 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
if(defender.losebreath <= 10)
|
||||
defender.losebreath = clamp(defender.losebreath + 5, 0, 10)
|
||||
defender.adjustOxyLoss(10)
|
||||
log_combat(attacker, defender, "quickchoked")
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/krav_maga/proc/neck_chop(mob/living/attacker, mob/living/defender)
|
||||
defender.visible_message(span_warning("[attacker] karate chops [defender]'s neck!"), \
|
||||
span_userdanger("Your neck is karate chopped by [attacker], rendering you unable to speak!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
attacker.do_attack_animation(defender)
|
||||
defender.visible_message(
|
||||
span_warning("[attacker] karate chops [defender]'s neck!"),
|
||||
span_userdanger("Your neck is karate chopped by [attacker], rendering you unable to speak!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You karate chop [defender]'s neck, rendering [defender.p_them()] unable to speak!"))
|
||||
playsound(get_turf(attacker), 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
playsound(attacker, 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
defender.apply_damage(10, attacker.get_attack_type(), BODY_ZONE_HEAD)
|
||||
defender.adjust_silence_up_to(20 SECONDS, 20 SECONDS)
|
||||
log_combat(attacker, defender, "neck chopped")
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/krav_maga/harm_act(mob/living/attacker, mob/living/defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return TRUE
|
||||
log_combat(attacker, defender, "punched")
|
||||
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
|
||||
var/picked_hit_type = pick("punch", "kick")
|
||||
var/bonus_damage = 0
|
||||
if(defender.body_position == LYING_DOWN)
|
||||
bonus_damage += 5
|
||||
picked_hit_type = "stomp"
|
||||
|
||||
if(defender.check_block(attacker, 10 + bonus_damage, "[attacker]'s [picked_hit_type]", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
if(check_streak(attacker, defender))
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
log_combat(attacker, defender, "[picked_hit_type]ed")
|
||||
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
|
||||
defender.apply_damage(10 + bonus_damage, attacker.get_attack_type(), affecting)
|
||||
if(picked_hit_type == "kick" || picked_hit_type == "stomp")
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK)
|
||||
playsound(get_turf(defender), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
playsound(defender, 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
else
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
playsound(get_turf(defender), 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
defender.visible_message(span_danger("[attacker] [picked_hit_type]s [defender]!"), \
|
||||
span_userdanger("You're [picked_hit_type]ed by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
playsound(defender, 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] [picked_hit_type]s [defender]!"),
|
||||
span_userdanger("You're [picked_hit_type]ed by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You [picked_hit_type] [defender]!"))
|
||||
log_combat(attacker, defender, "[picked_hit_type] with [name]")
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/krav_maga/disarm_act(mob/living/attacker, mob/living/defender)
|
||||
if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
if(check_streak(attacker, defender))
|
||||
return TRUE
|
||||
var/obj/item/stuff_in_hand = null
|
||||
stuff_in_hand = defender.get_active_held_item()
|
||||
if(prob(60) && stuff_in_hand)
|
||||
if(defender.temporarilyRemoveItemFromInventory(stuff_in_hand))
|
||||
attacker.put_in_hands(stuff_in_hand)
|
||||
defender.visible_message("<span class='danger'>[attacker] disarms [defender]!</span>", \
|
||||
"<span class='userdanger'>You're disarmed by [attacker]!</span>", "<span class='hear'>You hear aggressive shuffling!</span>", COMBAT_MESSAGE_RANGE, attacker)
|
||||
to_chat(attacker, "<span class='danger'>You disarm [defender]!</span>")
|
||||
playsound(defender, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
|
||||
log_combat(attacker, defender, "shoved (Krav Maga)", "[stuff_in_hand ? " removing \the [stuff_in_hand]" : ""]")
|
||||
return FALSE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_DISARM)
|
||||
var/obj/item/stuff_in_hand = defender.get_active_held_item()
|
||||
if(prob(60) && stuff_in_hand && defender.temporarilyRemoveItemFromInventory(stuff_in_hand))
|
||||
attacker.put_in_hands(stuff_in_hand)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] disarms [defender]!"),
|
||||
span_userdanger("You're disarmed by [attacker]!"),
|
||||
span_hear("You hear aggressive shuffling!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You disarm [defender]!"))
|
||||
playsound(defender, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
|
||||
log_combat(attacker, defender, "disarmed (Krav Maga)", addition = "(disarmed of [stuff_in_hand])")
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] fails to disarm [defender]!"), \
|
||||
span_userdanger("You're nearly disarmed by [attacker]!"),
|
||||
span_hear("You hear a swoosh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_warning("You fail to disarm [defender]!"))
|
||||
playsound(defender, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1)
|
||||
log_combat(attacker, defender, "failed to disarm (Krav Maga)")
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
//Krav Maga Gloves
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga
|
||||
var/datum/martial_art/krav_maga/style = new
|
||||
clothing_traits = list(TRAIT_FAST_CUFFING)
|
||||
var/datum/martial_art/krav_maga/style
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/Initialize(mapload)
|
||||
. = ..()
|
||||
style = new()
|
||||
style.allow_temp_override = FALSE
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/Destroy()
|
||||
QDEL_NULL(style)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
@@ -167,8 +236,7 @@
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/dropped(mob/user)
|
||||
. = ..()
|
||||
if(user.get_item_by_slot(ITEM_SLOT_GLOVES) == src)
|
||||
style.remove(user)
|
||||
style.fully_remove(user)
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/sec//more obviously named, given to sec
|
||||
name = "krav maga gloves"
|
||||
|
||||
@@ -2,39 +2,56 @@
|
||||
name = "Mushroom Punch"
|
||||
id = MARTIALART_MUSHPUNCH
|
||||
|
||||
/datum/martial_art/mushpunch/harm_act(mob/living/A, mob/living/D)
|
||||
var/atk_verb
|
||||
to_chat(A, span_spiderbroodmother("You begin to wind up an attack..."))
|
||||
if(!do_after(A, 2.5 SECONDS, target = D))
|
||||
to_chat(A, span_spiderbroodmother("<b>Your attack was interrupted!</b>"))
|
||||
return TRUE //martial art code was a mistake
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
atk_verb = pick("punch", "smash", "crack")
|
||||
D.visible_message(span_danger("[A] [atk_verb]ed [D] with such inhuman strength that it sends [D.p_them()] flying backwards!"), \
|
||||
span_userdanger("You're [atk_verb]ed by [A] with such inhuman strength that it sends you flying backwards!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, A)
|
||||
to_chat(A, span_danger("You [atk_verb] [D] with such inhuman strength that it sends [D.p_them()] flying backwards!"))
|
||||
D.apply_damage(rand(15,30), A.get_attack_type())
|
||||
playsound(D, 'sound/effects/meteorimpact.ogg', 25, TRUE, -1)
|
||||
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
|
||||
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.
|
||||
D.Paralyze(2 SECONDS)
|
||||
if(atk_verb)
|
||||
log_combat(A, D, "[atk_verb] (Mushroom Punch)")
|
||||
return TRUE
|
||||
/datum/martial_art/mushpunch/harm_act(mob/living/attacker, mob/living/defender)
|
||||
INVOKE_ASYNC(src, PROC_REF(charge_up_attack), attacker, defender)
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/mushpunch/proc/charge_up_attack(mob/living/attacker, mob/living/defender)
|
||||
|
||||
to_chat(attacker, span_spiderbroodmother("You begin to wind up an attack..."))
|
||||
if(!do_after(attacker, 2.5 SECONDS, defender))
|
||||
to_chat(attacker, span_spiderbroodmother("<b>Your attack was interrupted!</b>"))
|
||||
return
|
||||
|
||||
var/final_damage = rand(15, 30)
|
||||
var/atk_verb = pick("punch", "smash", "crack")
|
||||
if(defender.check_block(attacker, final_damage, "[attacker]'s [atk_verb]", UNARMED_ATTACK))
|
||||
return
|
||||
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] [atk_verb]ed [defender] with such inhuman strength that it sends [defender.p_them()] flying backwards!"), \
|
||||
span_userdanger("You're [atk_verb]ed by [attacker] with such inhuman strength that it sends you flying backwards!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You [atk_verb] [defender] with such inhuman strength that it sends [defender.p_them()] flying backwards!"))
|
||||
defender.apply_damage(final_damage, attacker.get_attack_type())
|
||||
playsound(defender, 'sound/effects/meteorimpact.ogg', 25, TRUE, -1)
|
||||
var/throwtarget = get_edge_target_turf(attacker, get_dir(attacker, get_step_away(defender, attacker)))
|
||||
defender.throw_at(throwtarget, 4, 2, attacker)//So stuff gets tossed around at the same time.
|
||||
defender.Paralyze(2 SECONDS)
|
||||
log_combat(attacker, defender, "[atk_verb] (Mushroom Punch)")
|
||||
|
||||
/obj/item/mushpunch
|
||||
name = "odd mushroom"
|
||||
desc = "<I>Sapienza Ophioglossoides</I>:An odd mushroom from the flesh of a mushroom person. It has apparently retained some innate power of its owner, as it quivers with barely-contained POWER!"
|
||||
desc = "<I>Sapienza Ophioglossoides</I>:An odd mushroom from the flesh of a mushroom person. \
|
||||
It has apparently retained some innate power of its owner, as it quivers with barely-contained POWER!"
|
||||
icon = 'icons/obj/service/hydroponics/seeds.dmi'
|
||||
icon_state = "mycelium-angel"
|
||||
|
||||
/obj/item/mushpunch/attack_self(mob/living/user)
|
||||
if(!istype(user) || !user)
|
||||
if(!istype(user))
|
||||
return
|
||||
var/message = span_spiderbroodmother("You devour [src], and a confluence of skill and power from the mushroom enhances your punches! You do need a short moment to charge these powerful punches.")
|
||||
to_chat(user, message)
|
||||
var/datum/martial_art/mushpunch/mush = new(null)
|
||||
to_chat(user, span_spiderbroodmother("You devour [src], \
|
||||
and a confluence of skill and power from the mushroom enhances your punches! \
|
||||
You do need a short moment to charge these powerful punches."))
|
||||
var/datum/martial_art/mushpunch/mush = new()
|
||||
mush.teach(user)
|
||||
visible_message(
|
||||
span_warning("[user] devours [src]."),
|
||||
span_notice("You devour [src]."),
|
||||
)
|
||||
|
||||
qdel(src)
|
||||
visible_message(span_warning("[user] devours [src]."), \
|
||||
span_notice("You devour [src]."))
|
||||
|
||||
@@ -10,60 +10,71 @@
|
||||
var/plasma_power = 1 //starts at a 1, 2, 4 explosion.
|
||||
var/plasma_increment = 1 //how much explosion power gets added per kill (1 = 1, 2, 4. 2 = 2, 4, 8 and so on)
|
||||
var/plasma_cap = 12 //max size explosion level
|
||||
var/datum/action/cooldown/spell/aoe/repulse/tornado_spell
|
||||
display_combos = TRUE
|
||||
|
||||
/datum/martial_art/plasma_fist/New()
|
||||
. = ..()
|
||||
tornado_spell = new(src)
|
||||
|
||||
/datum/martial_art/plasma_fist/Destroy()
|
||||
tornado_spell = null
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/check_streak(mob/living/attacker, mob/living/defender)
|
||||
if(findtext(streak,TORNADO_COMBO))
|
||||
if(attacker == defender)//helps using apotheosis
|
||||
return FALSE
|
||||
reset_streak()
|
||||
Tornado(attacker, defender)
|
||||
return TRUE
|
||||
return Tornado(attacker, defender)
|
||||
if(findtext(streak,THROWBACK_COMBO))
|
||||
if(attacker == defender)//helps using apotheosis
|
||||
return FALSE
|
||||
reset_streak()
|
||||
Throwback(attacker, defender)
|
||||
return TRUE
|
||||
return Throwback(attacker, defender)
|
||||
if(findtext(streak,PLASMA_COMBO))
|
||||
reset_streak()
|
||||
if(attacker == defender && !nobomb)
|
||||
Apotheosis(attacker, defender)
|
||||
else
|
||||
Plasma(attacker, defender)
|
||||
return TRUE
|
||||
return Apotheosis(attacker, defender)
|
||||
return Plasma(attacker, defender)
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Tornado(mob/living/attacker, mob/living/defender)
|
||||
attacker.say("TORNADO SWEEP!", forced="plasma fist")
|
||||
dance_rotate(attacker, CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), attacker.loc, 'sound/weapons/punch1.ogg', 15, TRUE, -1))
|
||||
|
||||
var/datum/action/cooldown/spell/aoe/repulse/tornado_spell = new(src)
|
||||
dance_rotate(attacker, CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), attacker, 'sound/weapons/punch1.ogg', 15, TRUE, -1))
|
||||
tornado_spell.cast(attacker)
|
||||
qdel(tornado_spell)
|
||||
|
||||
log_combat(attacker, defender, "tornado sweeped(Plasma Fist)")
|
||||
return
|
||||
log_combat(attacker, defender, "tornado sweeped (Plasma Fist)")
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Throwback(mob/living/attacker, mob/living/defender)
|
||||
defender.visible_message(span_danger("[attacker] hits [defender] with Plasma Punch!"), \
|
||||
span_userdanger("You're hit with a Plasma Punch by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, attacker)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] hits [defender] with Plasma Punch!"),
|
||||
span_userdanger("You're hit with a Plasma Punch by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You hit [defender] with Plasma Punch!"))
|
||||
playsound(defender.loc, 'sound/weapons/punch1.ogg', 50, TRUE, -1)
|
||||
playsound(defender, 'sound/weapons/punch1.ogg', 50, TRUE, -1)
|
||||
var/atom/throw_target = get_edge_target_turf(defender, get_dir(defender, get_step_away(defender, attacker)))
|
||||
defender.throw_at(throw_target, 200, 4,attacker)
|
||||
attacker.say("HYAH!", forced="plasma fist")
|
||||
log_combat(attacker, defender, "threw back (Plasma Fist)")
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Plasma(mob/living/attacker, mob/living/defender)
|
||||
var/hasclient = defender.client ? TRUE : FALSE
|
||||
var/hasclient = !!defender.client
|
||||
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
playsound(defender.loc, 'sound/weapons/punch1.ogg', 50, TRUE, -1)
|
||||
playsound(defender, 'sound/weapons/punch1.ogg', 50, TRUE, -1)
|
||||
attacker.say("PLASMA FIST!", forced="plasma fist")
|
||||
defender.visible_message(span_danger("[attacker] hits [defender] with THE PLASMA FIST TECHNIQUE!"), \
|
||||
span_userdanger("You're suddenly hit with THE PLASMA FIST TECHNIQUE by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, attacker)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] hits [defender] with THE PLASMA FIST TECHNIQUE!"),
|
||||
span_userdanger("You're suddenly hit with THE PLASMA FIST TECHNIQUE by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You hit [defender] with THE PLASMA FIST TECHNIQUE!"))
|
||||
log_combat(attacker, defender, "gibbed (Plasma Fist)")
|
||||
var/turf/Dturf = get_turf(defender)
|
||||
@@ -71,13 +82,15 @@
|
||||
defender.gib(DROP_ALL_REMAINS)
|
||||
if(nobomb)
|
||||
return
|
||||
|
||||
if(!hasclient)
|
||||
to_chat(attacker, span_warning("Taking this plasma energy for your </span>[span_notice("Apotheosis")]<span class='warning'> would bring dishonor to the clan!"))
|
||||
new /obj/effect/temp_visual/plasma_soul(Dturf)//doesn't beam to you, so it just hangs around and poofs.
|
||||
return
|
||||
|
||||
else if(plasma_power >= plasma_cap)
|
||||
to_chat(attacker, span_warning("You cannot power up your </span>[span_notice("Apotheosis")]<span class='warning'> any more!"))
|
||||
new /obj/effect/temp_visual/plasma_soul(Dturf)//doesn't beam to you, so it just hangs around and poofs.
|
||||
|
||||
else
|
||||
plasma_power += plasma_increment
|
||||
to_chat(attacker, span_nicegreen("Power increasing! Your </span>[span_notice("Apotheosis")]<span class='nicegreen'> is now at power level [plasma_power]!"))
|
||||
@@ -87,6 +100,7 @@
|
||||
flash_color(attacker, flash_color = "#9C00FF", flash_time = 3 SECONDS)
|
||||
animate(attacker, color = oldcolor, time = 3 SECONDS)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Apotheosis(mob/living/user, mob/living/target)
|
||||
user.say("APOTHEOSIS!!", forced="plasma fist")
|
||||
@@ -108,12 +122,13 @@
|
||||
to_chat(user, span_userdanger("The explosion knocks your soul out of your body!"))
|
||||
user.ghostize(FALSE) //prevents... horrible memes just believe me
|
||||
|
||||
user.apply_damage(rand(50,70), BRUTE)
|
||||
user.apply_damage(rand(50, 70), BRUTE, wound_bonus = CANT_WOUND)
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(Apotheosis_end), user), 6 SECONDS)
|
||||
playsound(boomspot, 'sound/weapons/punch1.ogg', 50, TRUE, -1)
|
||||
explosion(user, devastation_range = plasma_power, heavy_impact_range = plasma_power*2, light_impact_range = plasma_power*4, ignorecap = TRUE, explosion_cause = src)
|
||||
plasma_power = 1 //just in case there is any clever way to cause it to happen again
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Apotheosis_end(mob/living/dying)
|
||||
dying.remove_traits(list(TRAIT_FORCED_STANDING, TRAIT_BOMBIMMUNE), type)
|
||||
@@ -123,24 +138,29 @@
|
||||
dying.death()
|
||||
|
||||
/datum/martial_art/plasma_fist/harm_act(mob/living/attacker, mob/living/defender)
|
||||
if(defender.check_block(attacker, 10, attacker.name, UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
add_to_streak("H", defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return TRUE
|
||||
return FALSE
|
||||
return check_streak(attacker, defender) ? MARTIAL_ATTACK_SUCCESS : MARTIAL_ATTACK_INVALID
|
||||
|
||||
/datum/martial_art/plasma_fist/disarm_act(mob/living/attacker, mob/living/defender)
|
||||
if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
add_to_streak("D", defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
if(attacker == defender)//there is no disarming yourself, so we need to let plasma fist user know
|
||||
to_chat(attacker, span_notice("You have added a disarm to your streak."))
|
||||
return FALSE
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
/datum/martial_art/plasma_fist/grab_act(mob/living/attacker, mob/living/defender)
|
||||
if(defender.check_block(attacker, 0, "[attacker]'s grab", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
add_to_streak("G", defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return TRUE
|
||||
return FALSE
|
||||
return check_streak(attacker, defender) ? MARTIAL_ATTACK_SUCCESS : MARTIAL_ATTACK_INVALID
|
||||
|
||||
/mob/living/proc/plasma_fist_help()
|
||||
set name = "Recall Teachings"
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
attacker.Stun(2 SECONDS)
|
||||
atk_verb = "cried looking at"
|
||||
if(3)
|
||||
if(defender.check_block(attacker, 0, "[attacker]'s grab", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
if(attacker.body_position == LYING_DOWN)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
if(attacker.grab_state >= GRAB_AGGRESSIVE)
|
||||
defender.grabbedby(attacker, 1)
|
||||
else
|
||||
@@ -33,22 +38,37 @@
|
||||
defender.stop_pulling()
|
||||
if(grab_attack)
|
||||
log_combat(attacker, defender, "grabbed", addition="aggressively")
|
||||
defender.visible_message(span_warning("[attacker] violently grabs [defender]!"), \
|
||||
span_userdanger("You're violently grabbed by [attacker]!"), span_hear("You hear sounds of aggressive fondling!"), null, attacker)
|
||||
defender.visible_message(
|
||||
span_warning("[attacker] violently grabs [defender]!"),
|
||||
span_userdanger("You're violently grabbed by [attacker]!"),
|
||||
span_hear("You hear sounds of aggressive fondling!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You violently grab [defender]!"))
|
||||
attacker.setGrabState(GRAB_AGGRESSIVE) //Instant aggressive grab
|
||||
else
|
||||
log_combat(attacker, defender, "grabbed", addition="passively")
|
||||
attacker.setGrabState(GRAB_PASSIVE)
|
||||
if(4)
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
atk_verb = "headbutt"
|
||||
defender.visible_message(span_danger("[attacker] [atk_verb]s [defender]!"), \
|
||||
span_userdanger("You're [atk_verb]ed by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, attacker)
|
||||
var/defender_damage = rand(5, 10)
|
||||
if(defender.check_block(attacker, defender_damage, "[attacker]'s [atk_verb]", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
attacker.emote("flip")
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] [atk_verb]s [defender]!"),
|
||||
span_userdanger("You're [atk_verb]ed by [attacker]!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You [atk_verb] [defender]!"))
|
||||
playsound(get_turf(defender), 'sound/weapons/punch1.ogg', 40, TRUE, -1)
|
||||
defender.apply_damage(rand(5,10), attacker.get_attack_type(), BODY_ZONE_HEAD)
|
||||
attacker.apply_damage(rand(5,10), attacker.get_attack_type(), BODY_ZONE_HEAD)
|
||||
playsound(defender, 'sound/weapons/punch1.ogg', 40, TRUE, -1)
|
||||
defender.apply_damage(defender_damage, attacker.get_attack_type(), BODY_ZONE_HEAD)
|
||||
attacker.apply_damage(rand(5, 10), attacker.get_attack_type(), BODY_ZONE_HEAD)
|
||||
if(iscarbon(defender))
|
||||
var/mob/living/carbon/carbon_defender = defender
|
||||
if(!istype(carbon_defender.head, /obj/item/clothing/head/helmet/) && !istype(carbon_defender.head, /obj/item/clothing/head/utility/hardhat))
|
||||
@@ -56,19 +76,29 @@
|
||||
attacker.Stun(rand(1 SECONDS, 4.5 SECONDS))
|
||||
defender.Stun(rand(0.5 SECONDS, 3 SECONDS))
|
||||
if(5,6)
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
atk_verb = pick("kick", "hit", "slam")
|
||||
defender.visible_message(span_danger("[attacker] [atk_verb]s [defender] with such inhuman strength that it sends [defender.p_them()] flying backwards!"), \
|
||||
span_userdanger("You're [atk_verb]ed by [attacker] with such inhuman strength that it sends you flying backwards!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, attacker)
|
||||
if(defender.check_block(attacker, 0, "[attacker]'s [atk_verb]", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] [atk_verb]s [defender] with such inhuman strength that it sends [defender.p_them()] flying backwards!"),
|
||||
span_userdanger("You're [atk_verb]ed by [attacker] with such inhuman strength that it sends you flying backwards!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You [atk_verb] [defender] with such inhuman strength that it sends [defender.p_them()] flying backwards!"))
|
||||
defender.apply_damage(rand(15,30), attacker.get_attack_type())
|
||||
playsound(get_turf(defender), 'sound/effects/meteorimpact.ogg', 25, TRUE, -1)
|
||||
defender.apply_damage(rand(15, 30), attacker.get_attack_type())
|
||||
playsound(defender, 'sound/effects/meteorimpact.ogg', 25, TRUE, -1)
|
||||
var/throwtarget = get_edge_target_turf(attacker, get_dir(attacker, get_step_away(defender, attacker)))
|
||||
defender.throw_at(throwtarget, 4, 2, attacker)//So stuff gets tossed around at the same time.
|
||||
defender.Paralyze(6 SECONDS)
|
||||
if(7,8)
|
||||
return FALSE //Resume default behaviour
|
||||
return MARTIAL_ATTACK_INVALID //Resume default behaviour
|
||||
|
||||
if(atk_verb)
|
||||
log_combat(attacker, defender, "[atk_verb] (Psychotic Brawling)")
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
@@ -8,69 +8,77 @@
|
||||
allow_temp_override = FALSE
|
||||
help_verb = /mob/living/proc/sleeping_carp_help
|
||||
display_combos = TRUE
|
||||
/// List of traits applied to users of this martial art.
|
||||
var/list/scarp_traits = list(TRAIT_NOGUNS, TRAIT_HARDLY_WOUNDED, TRAIT_NODISMEMBER, TRAIT_HEAVY_SLEEPER)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/teach(mob/living/target, make_temporary = FALSE)
|
||||
/datum/martial_art/the_sleeping_carp/on_teach(mob/living/new_holder)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
target.add_traits(scarp_traits, SLEEPING_CARP_TRAIT)
|
||||
RegisterSignal(target, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
|
||||
RegisterSignal(target, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile))
|
||||
target.faction |= FACTION_CARP //:D
|
||||
new_holder.add_traits(scarp_traits, SLEEPING_CARP_TRAIT)
|
||||
RegisterSignal(new_holder, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
|
||||
RegisterSignal(new_holder, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile))
|
||||
new_holder.faction |= FACTION_CARP //:D
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/on_remove(mob/living/target)
|
||||
target.remove_traits(scarp_traits, SLEEPING_CARP_TRAIT)
|
||||
UnregisterSignal(target, COMSIG_ATOM_ATTACKBY)
|
||||
UnregisterSignal(target, COMSIG_ATOM_PRE_BULLET_ACT)
|
||||
target.faction -= FACTION_CARP //:(
|
||||
. = ..()
|
||||
/datum/martial_art/the_sleeping_carp/on_remove(mob/living/remove_from)
|
||||
remove_from.remove_traits(scarp_traits, SLEEPING_CARP_TRAIT)
|
||||
UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_PRE_BULLET_ACT))
|
||||
remove_from.faction -= FACTION_CARP //:(
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/check_streak(mob/living/attacker, mob/living/defender)
|
||||
if(findtext(streak,STRONG_PUNCH_COMBO))
|
||||
reset_streak()
|
||||
strongPunch(attacker, defender)
|
||||
return TRUE
|
||||
return strongPunch(attacker, defender)
|
||||
|
||||
if(findtext(streak,LAUNCH_KICK_COMBO))
|
||||
reset_streak()
|
||||
launchKick(attacker, defender)
|
||||
return TRUE
|
||||
return launchKick(attacker, defender)
|
||||
|
||||
if(findtext(streak,DROP_KICK_COMBO))
|
||||
reset_streak()
|
||||
dropKick(attacker, defender)
|
||||
return TRUE
|
||||
return dropKick(attacker, defender)
|
||||
|
||||
return FALSE
|
||||
|
||||
///Gnashing Teeth: Harm Harm, consistent 20 force punch on every second harm punch
|
||||
/datum/martial_art/the_sleeping_carp/proc/strongPunch(mob/living/attacker, mob/living/defender)
|
||||
///this var is so that the strong punch is always aiming for the body part the user is targeting and not trying to apply to the chest before deviating
|
||||
// this var is so that the strong punch is always aiming for the body part the user is targeting and not trying to apply to the chest before deviating
|
||||
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
var/atk_verb = pick("precisely kick", "brutally chop", "cleanly hit", "viciously slam")
|
||||
defender.visible_message(span_danger("[attacker] [atk_verb]s [defender]!"), \
|
||||
span_userdanger("[attacker] [atk_verb]s you!"), null, null, attacker)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] [atk_verb]s [defender]!"),
|
||||
span_userdanger("[attacker] [atk_verb]s you!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You [atk_verb] [defender]!"))
|
||||
playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1)
|
||||
log_combat(attacker, defender, "strong punched (Sleeping Carp)")
|
||||
defender.apply_damage(20, attacker.get_attack_type(), affecting)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
///Crashing Wave Kick: Harm Disarm combo, throws people seven tiles backwards
|
||||
/datum/martial_art/the_sleeping_carp/proc/launchKick(mob/living/attacker, mob/living/defender)
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK)
|
||||
defender.visible_message(span_warning("[attacker] kicks [defender] square in the chest, sending them flying!"), \
|
||||
span_userdanger("You are kicked square in the chest by [attacker], sending you flying!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
playsound(get_turf(attacker), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
defender.visible_message(
|
||||
span_warning("[attacker] kicks [defender] square in the chest, sending them flying!"),
|
||||
span_userdanger("You are kicked square in the chest by [attacker], sending you flying!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
var/atom/throw_target = get_edge_target_turf(defender, attacker.dir)
|
||||
defender.throw_at(throw_target, 7, 4, attacker)
|
||||
defender.apply_damage(15, attacker.get_attack_type(), BODY_ZONE_CHEST, wound_bonus = CANT_WOUND)
|
||||
log_combat(attacker, defender, "launchkicked (Sleeping Carp)")
|
||||
return
|
||||
return TRUE
|
||||
|
||||
///Keelhaul: Disarm Disarm combo, knocks people down and deals substantial stamina damage, and also discombobulates them. Knocks objects out of their hands if they're already on the ground.
|
||||
/datum/martial_art/the_sleeping_carp/proc/dropKick(mob/living/attacker, mob/living/defender)
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK)
|
||||
playsound(get_turf(attacker), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
if(defender.body_position == STANDING_UP)
|
||||
defender.Knockdown(4 SECONDS)
|
||||
defender.visible_message(span_warning("[attacker] kicks [defender] in the head, sending them face first into the floor!"), \
|
||||
@@ -83,28 +91,32 @@
|
||||
defender.adjust_dizzy_up_to(10 SECONDS, 10 SECONDS)
|
||||
defender.adjust_temp_blindness_up_to(2 SECONDS, 10 SECONDS)
|
||||
log_combat(attacker, defender, "dropkicked (Sleeping Carp)")
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/grab_act(mob/living/attacker, mob/living/defender)
|
||||
if(!can_deflect(attacker)) //allows for deniability
|
||||
return ..()
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
if(defender.check_block(attacker, 0, "[attacker]'s grab", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
add_to_streak("G", defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
var/grab_log_description = "grabbed"
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1)
|
||||
if(defender.stat != DEAD && !defender.IsUnconscious() && defender.getStaminaLoss() >= 80) //We put our target to sleep.
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] carefully pinch a nerve in [defender]'s neck, knocking them out cold"),
|
||||
span_danger("[attacker] carefully pinch a nerve in [defender]'s neck, knocking them out cold!"),
|
||||
span_userdanger("[attacker] pinches something in your neck, and you fall unconscious!"),
|
||||
)
|
||||
grab_log_description = "grabbed and nerve pinched"
|
||||
defender.Unconscious(10 SECONDS)
|
||||
defender.apply_damage(20, STAMINA)
|
||||
log_combat(attacker, defender, "[grab_log_description] (Sleeping Carp)")
|
||||
return ..()
|
||||
return MARTIAL_ATTACK_INVALID // normal grab
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/attacker, mob/living/defender)
|
||||
if(attacker.grab_state == GRAB_KILL \
|
||||
@@ -129,36 +141,45 @@
|
||||
defender.investigate_log("has had [defender.p_their()] neck snapped by [attacker].", INVESTIGATE_DEATHS)
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
var/atk_verb = pick("kick", "chop", "hit", "slam")
|
||||
var/final_damage = rand(10, 15)
|
||||
if(defender.check_block(attacker, final_damage, "[attacker]'s [atk_verb]", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
add_to_streak("H", defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
var/atk_verb = pick("kick", "chop", "hit", "slam")
|
||||
defender.visible_message(span_danger("[attacker] [atk_verb]s [defender]!"), \
|
||||
span_userdanger("[attacker] [atk_verb]s you!"), null, null, attacker)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] [atk_verb]s [defender]!"),
|
||||
span_userdanger("[attacker] [atk_verb]s you!"),
|
||||
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
||||
null,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You [atk_verb] [defender]!"))
|
||||
|
||||
defender.apply_damage(rand(10,15), attacker.get_attack_type(), affecting, wound_bonus = CANT_WOUND)
|
||||
defender.apply_damage(final_damage, attacker.get_attack_type(), affecting, wound_bonus = CANT_WOUND)
|
||||
playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1)
|
||||
log_combat(attacker, defender, "punched (Sleeping Carp)")
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/disarm_act(mob/living/attacker, mob/living/defender)
|
||||
if(!can_deflect(attacker)) //allows for deniability
|
||||
return ..()
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
|
||||
add_to_streak("D", defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return TRUE
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
||||
playsound(defender, 'sound/weapons/punch1.ogg', 25, TRUE, -1)
|
||||
defender.apply_damage(20, STAMINA)
|
||||
log_combat(attacker, defender, "disarmed (Sleeping Carp)")
|
||||
|
||||
return ..()
|
||||
return MARTIAL_ATTACK_INVALID // normal disarm
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user)
|
||||
if(!can_use(carp_user) || !carp_user.combat_mode)
|
||||
|
||||
@@ -18,13 +18,32 @@ If you make a derivative work from this code, you must include this notification
|
||||
/datum/martial_art/wrestling
|
||||
name = "Wrestling"
|
||||
id = MARTIALART_WRESTLING
|
||||
var/datum/action/slam/slam = new/datum/action/slam()
|
||||
var/datum/action/throw_wrassle/throw_wrassle = new/datum/action/throw_wrassle()
|
||||
var/datum/action/kick/kick = new/datum/action/kick()
|
||||
var/datum/action/strike/strike = new/datum/action/strike()
|
||||
var/datum/action/drop/drop = new/datum/action/drop()
|
||||
VAR_PRIVATE/datum/action/slam/slam
|
||||
VAR_PRIVATE/datum/action/throw_wrassle/throw_wrassle
|
||||
VAR_PRIVATE/datum/action/kick/kick
|
||||
VAR_PRIVATE/datum/action/strike/strike
|
||||
VAR_PRIVATE/datum/action/drop/drop
|
||||
|
||||
/datum/martial_art/wrestling/New()
|
||||
. = ..()
|
||||
slam = new(src)
|
||||
throw_wrassle = new(src)
|
||||
kick = new(src)
|
||||
strike = new(src)
|
||||
drop = new(src)
|
||||
|
||||
/datum/martial_art/wrestling/Destroy()
|
||||
slam = null
|
||||
throw_wrassle = null
|
||||
kick = null
|
||||
strike = null
|
||||
drop = null
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/wrestling/proc/check_streak(mob/living/attacker, mob/living/defender)
|
||||
if(defender.check_block(attacker, 10, "[attacker]'s [streak]", UNARMED_ATTACK))
|
||||
return FALSE
|
||||
|
||||
switch(streak)
|
||||
if("drop")
|
||||
streak = ""
|
||||
@@ -51,10 +70,11 @@ If you make a derivative work from this code, you must include this notification
|
||||
/datum/action/slam
|
||||
name = "Slam (Cinch) - Slam a grappled opponent into the floor."
|
||||
button_icon_state = "wrassle_slam"
|
||||
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_HANDS_BLOCKED|AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/slam/Trigger(trigger_flags)
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
owner.visible_message(span_danger("[owner] prepares to BODY SLAM!"), "<b><i>Your next attack will be a BODY SLAM.</i></b>")
|
||||
owner.mind.martial_art.streak = "slam"
|
||||
@@ -62,10 +82,11 @@ If you make a derivative work from this code, you must include this notification
|
||||
/datum/action/throw_wrassle
|
||||
name = "Throw (Cinch) - Spin a cinched opponent around and throw them."
|
||||
button_icon_state = "wrassle_throw"
|
||||
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_HANDS_BLOCKED|AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/throw_wrassle/Trigger(trigger_flags)
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
owner.visible_message(span_danger("[owner] prepares to THROW!"), "<b><i>Your next attack will be a THROW.</i></b>")
|
||||
owner.mind.martial_art.streak = "throw"
|
||||
@@ -73,10 +94,11 @@ If you make a derivative work from this code, you must include this notification
|
||||
/datum/action/kick
|
||||
name = "Kick - A powerful kick, sends people flying away from you. Also useful for escaping from bad situations."
|
||||
button_icon_state = "wrassle_kick"
|
||||
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_CONSCIOUS // This is supposed to be usable while cuffed but it probably isn't
|
||||
|
||||
/datum/action/kick/Trigger(trigger_flags)
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
owner.visible_message(span_danger("[owner] prepares to KICK!"), "<b><i>Your next attack will be a KICK.</i></b>")
|
||||
owner.mind.martial_art.streak = "kick"
|
||||
@@ -84,10 +106,11 @@ If you make a derivative work from this code, you must include this notification
|
||||
/datum/action/strike
|
||||
name = "Strike - Hit a neaby opponent with a quick attack."
|
||||
button_icon_state = "wrassle_strike"
|
||||
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_HANDS_BLOCKED|AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/strike/Trigger(trigger_flags)
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
owner.visible_message(span_danger("[owner] prepares to STRIKE!"), "<b><i>Your next attack will be a STRIKE.</i></b>")
|
||||
owner.mind.martial_art.streak = "strike"
|
||||
@@ -95,37 +118,36 @@ If you make a derivative work from this code, you must include this notification
|
||||
/datum/action/drop
|
||||
name = "Drop - Smash down onto an opponent."
|
||||
button_icon_state = "wrassle_drop"
|
||||
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_HANDS_BLOCKED
|
||||
|
||||
/datum/action/drop/Trigger(trigger_flags)
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
owner.visible_message(span_danger("[owner] prepares to LEG DROP!"), "<b><i>Your next attack will be a LEG DROP.</i></b>")
|
||||
owner.mind.martial_art.streak = "drop"
|
||||
|
||||
/datum/martial_art/wrestling/teach(mob/living/owner, make_temporary=FALSE)
|
||||
if(..())
|
||||
to_chat(owner, span_userdanger("SNAP INTO A THIN TIM!"))
|
||||
to_chat(owner, span_danger("Place your cursor over a move at the top of the screen to see what it does."))
|
||||
drop.Grant(owner)
|
||||
kick.Grant(owner)
|
||||
slam.Grant(owner)
|
||||
throw_wrassle.Grant(owner)
|
||||
strike.Grant(owner)
|
||||
/datum/martial_art/wrestling/on_teach(mob/living/new_holder)
|
||||
. = ..()
|
||||
to_chat(new_holder, span_userdanger("SNAP INTO A THIN TIM!"))
|
||||
to_chat(new_holder, span_danger("Place your cursor over a move at the top of the screen to see what it does."))
|
||||
drop.Grant(new_holder)
|
||||
kick.Grant(new_holder)
|
||||
slam.Grant(new_holder)
|
||||
throw_wrassle.Grant(new_holder)
|
||||
strike.Grant(new_holder)
|
||||
|
||||
/datum/martial_art/wrestling/on_remove(mob/living/owner)
|
||||
to_chat(owner, span_userdanger("You no longer feel that the tower of power is too sweet to be sour..."))
|
||||
drop.Remove(owner)
|
||||
kick.Remove(owner)
|
||||
slam.Remove(owner)
|
||||
throw_wrassle.Remove(owner)
|
||||
strike.Remove(owner)
|
||||
/datum/martial_art/wrestling/on_remove(mob/living/remove_from)
|
||||
to_chat(remove_from, span_userdanger("You no longer feel that the tower of power is too sweet to be sour..."))
|
||||
drop?.Remove(remove_from)
|
||||
kick?.Remove(remove_from)
|
||||
slam?.Remove(remove_from)
|
||||
throw_wrassle?.Remove(remove_from)
|
||||
strike?.Remove(remove_from)
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/wrestling/harm_act(mob/living/attacker, mob/living/defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return 1
|
||||
log_combat(attacker, defender, "punched with wrestling")
|
||||
..()
|
||||
return check_streak(attacker, defender) ? MARTIAL_ATTACK_SUCCESS : MARTIAL_ATTACK_INVALID
|
||||
|
||||
/datum/martial_art/wrestling/proc/throw_wrassle(mob/living/attacker, mob/living/defender)
|
||||
if(!defender)
|
||||
@@ -444,36 +466,46 @@ If you make a derivative work from this code, you must include this notification
|
||||
return
|
||||
|
||||
/datum/martial_art/wrestling/disarm_act(mob/living/attacker, mob/living/defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return 1
|
||||
log_combat(attacker, defender, "wrestling-disarmed")
|
||||
..()
|
||||
return check_streak(attacker, defender) ? MARTIAL_ATTACK_SUCCESS : MARTIAL_ATTACK_INVALID
|
||||
|
||||
/datum/martial_art/wrestling/grab_act(mob/living/attacker, mob/living/defender)
|
||||
if(check_streak(attacker, defender))
|
||||
return 1
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
if(defender.check_block(attacker, 0, "[attacker]'s grab", UNARMED_ATTACK))
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
if(attacker.pulling == defender)
|
||||
return 1
|
||||
return MARTIAL_ATTACK_FAIL
|
||||
attacker.start_pulling(defender)
|
||||
defender.visible_message(span_danger("[attacker] gets [defender] in a cinch!"), \
|
||||
span_userdanger("You're put into a cinch by [attacker]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, attacker)
|
||||
defender.visible_message(
|
||||
span_danger("[attacker] gets [defender] in a cinch!"),
|
||||
span_userdanger("You're put into a cinch by [attacker]!"),
|
||||
span_hear("You hear aggressive shuffling!"),
|
||||
COMBAT_MESSAGE_RANGE,
|
||||
attacker,
|
||||
)
|
||||
to_chat(attacker, span_danger("You get [defender] in a cinch!"))
|
||||
defender.Stun(rand(6 SECONDS, 10 SECONDS))
|
||||
log_combat(attacker, defender, "cinched")
|
||||
return 1
|
||||
return MARTIAL_ATTACK_SUCCESS
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling
|
||||
name = "Wrestling Belt"
|
||||
var/datum/martial_art/wrestling/style = new
|
||||
var/datum/martial_art/wrestling/style
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/Initialize(mapload)
|
||||
. = ..()
|
||||
style = new()
|
||||
style.allow_temp_override = FALSE
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/Destroy()
|
||||
QDEL_NULL(style)
|
||||
return ..()
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(slot & ITEM_SLOT_BELT)
|
||||
style.teach(user, TRUE)
|
||||
return
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/dropped(mob/user)
|
||||
. = ..()
|
||||
if(user.get_item_by_slot(ITEM_SLOT_BELT) == src)
|
||||
style.remove(user)
|
||||
return
|
||||
style.fully_remove(user)
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
|
||||
/// Martial art on this mind
|
||||
var/datum/martial_art/martial_art
|
||||
var/static/default_martial_art = new/datum/martial_art
|
||||
/// List of antag datums on this mind
|
||||
var/list/antag_datums
|
||||
/// this mind's ANTAG_HUD should have this icon_state
|
||||
@@ -107,7 +106,6 @@
|
||||
|
||||
/datum/mind/New(_key)
|
||||
key = _key
|
||||
martial_art = default_martial_art
|
||||
init_known_skills()
|
||||
set_assigned_role(SSjob.GetJobType(/datum/job/unassigned)) // Unassigned by default.
|
||||
|
||||
@@ -181,9 +179,9 @@
|
||||
new_character.mind.set_current(null)
|
||||
|
||||
var/mob/living/old_current = current
|
||||
if(current)
|
||||
if(old_current)
|
||||
//transfer anyone observing the old character to the new one
|
||||
current.transfer_observers_to(new_character)
|
||||
old_current.transfer_observers_to(new_character)
|
||||
|
||||
// Offload all mind languages from the old holder to a temp one
|
||||
var/datum/language_holder/empty/temp_holder = new()
|
||||
@@ -205,7 +203,7 @@
|
||||
if(iscarbon(new_character))
|
||||
var/mob/living/carbon/carbon_character = new_character
|
||||
carbon_character.last_mind = src
|
||||
transfer_martial_arts(new_character)
|
||||
|
||||
RegisterSignal(new_character, COMSIG_LIVING_DEATH, PROC_REF(set_death_time))
|
||||
if(active || force_key_move)
|
||||
new_character.key = key //now transfer the key to link the client to our new body
|
||||
@@ -214,7 +212,9 @@
|
||||
new_character.client.init_verbs() // re-initialize character specific verbs
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MIND_TRANSFERRED, old_current)
|
||||
SEND_SIGNAL(current, COMSIG_MOB_MIND_TRANSFERRED_INTO)
|
||||
SEND_SIGNAL(current, COMSIG_MOB_MIND_TRANSFERRED_INTO, old_current)
|
||||
if(!isnull(old_current))
|
||||
SEND_SIGNAL(old_current, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, current)
|
||||
|
||||
//I cannot trust you fucks to do this properly
|
||||
/datum/mind/proc/set_original_character(new_original_character)
|
||||
@@ -510,19 +510,6 @@
|
||||
usr = current
|
||||
traitor_panel()
|
||||
|
||||
/datum/mind/proc/transfer_martial_arts(mob/living/new_character)
|
||||
if(!ishuman(new_character))
|
||||
return
|
||||
if(martial_art)
|
||||
if(martial_art.base) //Is the martial art temporary?
|
||||
martial_art.remove(new_character)
|
||||
else
|
||||
martial_art.teach(new_character)
|
||||
|
||||
/datum/mind/proc/has_martialart(string)
|
||||
if(martial_art && martial_art.id == string)
|
||||
return martial_art
|
||||
return FALSE
|
||||
|
||||
/datum/mind/proc/get_ghost(even_if_they_cant_reenter, ghosts_with_clients)
|
||||
for(var/mob/dead/observer/G in (ghosts_with_clients ? GLOB.player_list : GLOB.dead_mob_list))
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
var/movement_type = GROUND
|
||||
|
||||
var/atom/movable/pulling
|
||||
var/grab_state = 0
|
||||
var/grab_state = GRAB_PASSIVE
|
||||
/// The strongest grab we can acomplish
|
||||
var/max_grab = GRAB_KILL
|
||||
var/throwforce = 0
|
||||
|
||||
@@ -79,15 +79,12 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
|
||||
icon_state = "liver"
|
||||
greyscale_config = /datum/greyscale_config/mutant_organ
|
||||
greyscale_colors = GONDOLA_COLORS
|
||||
/// instance of the martial art granted on insertion
|
||||
var/datum/martial_art/hugs_of_the_gondola/pax_hugs
|
||||
|
||||
/obj/item/organ/internal/liver/gondola/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola)
|
||||
AddElement(/datum/element/noticable_organ, "left arm has small needles breaching the skin all over it.", BODY_ZONE_L_ARM)
|
||||
AddElement(/datum/element/noticable_organ, "right arm has small needles breaching the skin all over it.", BODY_ZONE_R_ARM)
|
||||
pax_hugs = new
|
||||
|
||||
/obj/item/organ/internal/liver/gondola/Insert(mob/living/carbon/liver_owner, special, movement_flags)
|
||||
. = ..()
|
||||
@@ -100,14 +97,13 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
|
||||
else
|
||||
to_chat(liver_owner, span_warning("You feel like something would be happening to your arms right now... if you still had them."))
|
||||
to_chat(liver_owner, span_notice("Hugging a target will pacify them, but you won't be able to carry much of anything anymore."))
|
||||
pax_hugs.teach(liver_owner)
|
||||
RegisterSignal(liver_owner, COMSIG_HUMAN_EQUIPPING_ITEM, PROC_REF(on_owner_equipping_item))
|
||||
RegisterSignal(liver_owner, COMSIG_LIVING_TRY_PULL, PROC_REF(on_owner_try_pull))
|
||||
RegisterSignal(liver_owner, COMSIG_CARBON_HELPED, PROC_REF(on_hug))
|
||||
|
||||
/obj/item/organ/internal/liver/gondola/Remove(mob/living/carbon/liver_owner, special, movement_flags)
|
||||
. = ..()
|
||||
pax_hugs.remove(liver_owner)
|
||||
UnregisterSignal(liver_owner, list(COMSIG_HUMAN_EQUIPPING_ITEM, COMSIG_LIVING_TRY_PULL))
|
||||
UnregisterSignal(liver_owner, list(COMSIG_HUMAN_EQUIPPING_ITEM, COMSIG_LIVING_TRY_PULL, COMSIG_CARBON_HELPED))
|
||||
|
||||
/// signal sent when prompting if an item can be equipped
|
||||
/obj/item/organ/internal/liver/gondola/proc/on_owner_equipping_item(mob/living/carbon/human/owner, obj/item/equip_target, slot)
|
||||
@@ -130,6 +126,18 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
|
||||
item_target.balloon_alert(owner, "too weak to pull this!")
|
||||
return COMSIG_LIVING_CANCEL_PULL
|
||||
|
||||
/obj/item/organ/internal/liver/gondola/proc/on_hug(mob/living/carbon/human/source, mob/living/carbon/hugged)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/list/covered_body_zones = source.get_covered_body_zones()
|
||||
var/pax_injected = 4
|
||||
if(BODY_ZONE_L_ARM in covered_body_zones)
|
||||
pax_injected -= 2
|
||||
if(BODY_ZONE_R_ARM in covered_body_zones)
|
||||
pax_injected -= 2
|
||||
if(pax_injected > 0 && hugged.reagents?.add_reagent(/datum/reagent/pax, pax_injected))
|
||||
to_chat(hugged, span_warning("You feel a tiny prick!"))
|
||||
|
||||
#undef GONDOLA_ORGAN_COLOR
|
||||
#undef GONDOLA_SCLERA_COLOR
|
||||
#undef GONDOLA_PUPIL_COLOR
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/obj/item/book/granter/martial/can_learn(mob/user)
|
||||
if(!martial)
|
||||
CRASH("Someone attempted to learn [type], which did not have a martial arts set.")
|
||||
if(user.mind.has_martialart(initial(martial.id)))
|
||||
if(istype(user.mind?.martial_art, martial))
|
||||
to_chat(user, span_warning("You already know [martial_name]!"))
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -19,7 +19,12 @@
|
||||
return TRUE
|
||||
|
||||
/obj/item/book/granter/martial/on_reading_finished(mob/user)
|
||||
to_chat(user, "[greet]")
|
||||
var/datum/martial_art/martial_to_learn = new martial()
|
||||
martial_to_learn.teach(user)
|
||||
if(!martial_to_learn.teach(user))
|
||||
to_chat(user, span_warning("You attempt to learn [martial_name] from [src], \
|
||||
but your current knowledge of martial arts conflicts with the new style, so it just doesn't stick with you."))
|
||||
uses += 1 // Return the use
|
||||
return
|
||||
|
||||
to_chat(user, "[greet]")
|
||||
user.log_message("learned the martial art [martial_name] ([martial_to_learn])", LOG_ATTACK, color = "orange")
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"Lock... Kick...",
|
||||
"Strike their abdomen, neck and back for critical damage...",
|
||||
"Slam... Lock...",
|
||||
"I could probably combine this with some other martial arts!",
|
||||
"I could probably combine this with some other martial arts! ...Wait, that's illegal.",
|
||||
"Words that kill...",
|
||||
"The last and final moment is yours...",
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "Teaches you the arts of Krav Maga in 5 short instructional videos beamed directly into your eyeballs."
|
||||
icon = 'icons/obj/scrolls.dmi'
|
||||
icon_state ="scroll2"
|
||||
var/datum/martial_art/krav_maga/style = new
|
||||
var/datum/martial_art/krav_maga/style
|
||||
|
||||
/obj/item/implant/krav_maga/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
@@ -13,17 +13,23 @@
|
||||
<b>Function:</b> Teaches even the clumsiest host the arts of Krav Maga."}
|
||||
return dat
|
||||
|
||||
/obj/item/implant/krav_maga/Initialize(mapload)
|
||||
. = ..()
|
||||
style = new()
|
||||
style.allow_temp_override = FALSE
|
||||
|
||||
/obj/item/implant/krav_maga/Destroy()
|
||||
QDEL_NULL(style)
|
||||
return ..()
|
||||
|
||||
/obj/item/implant/krav_maga/activate()
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/H = imp_in
|
||||
if(!ishuman(H))
|
||||
if(isnull(imp_in.mind))
|
||||
return
|
||||
if(!H.mind)
|
||||
if(style.fully_remove(imp_in))
|
||||
return
|
||||
if(H.mind.has_martialart(MARTIALART_KRAVMAGA))
|
||||
style.remove(H)
|
||||
else
|
||||
style.teach(H,1)
|
||||
|
||||
style.teach(imp_in, TRUE)
|
||||
|
||||
/obj/item/implanter/krav_maga
|
||||
name = "implanter (krav maga)"
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
pushed_mob.Knockdown(30)
|
||||
pushed_mob.apply_damage(10, BRUTE)
|
||||
pushed_mob.apply_damage(40, STAMINA)
|
||||
if(user.mind?.martial_art.smashes_tables && user.mind?.martial_art.can_use(user))
|
||||
if(user.mind?.martial_art?.smashes_tables && user.mind?.martial_art.can_use(user))
|
||||
deconstruct(FALSE)
|
||||
playsound(pushed_mob, 'sound/effects/tableslam.ogg', 90, TRUE)
|
||||
pushed_mob.visible_message(span_danger("[user] slams [pushed_mob] onto \the [src]!"), \
|
||||
@@ -198,7 +198,7 @@
|
||||
banged_limb?.receive_damage(30, wound_bonus = extra_wound)
|
||||
pushed_mob.apply_damage(60, STAMINA)
|
||||
take_damage(50)
|
||||
if(user.mind?.martial_art.smashes_tables && user.mind?.martial_art.can_use(user))
|
||||
if(user.mind?.martial_art?.smashes_tables && user.mind?.martial_art.can_use(user))
|
||||
deconstruct(FALSE)
|
||||
playsound(pushed_mob, 'sound/effects/bang.ogg', 90, TRUE)
|
||||
pushed_mob.visible_message(span_danger("[user] smashes [pushed_mob]'s [banged_limb.plaintext_zone] against \the [src]!"),
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
style.teach(user, make_temporary = TRUE)
|
||||
|
||||
/obj/item/skillchip/job/chef/on_deactivate(mob/living/carbon/user, silent = FALSE)
|
||||
style.remove(user)
|
||||
style.fully_remove(user)
|
||||
return ..()
|
||||
|
||||
@@ -74,12 +74,6 @@ GLOBAL_LIST_INIT(strippable_alien_humanoid_items, create_strippable_list(list(
|
||||
name = "[name] ([numba])"
|
||||
real_name = name
|
||||
|
||||
/mob/living/carbon/alien/adult/proc/grab(mob/living/carbon/human/target)
|
||||
if(target.check_block(src, 0, "[target]'s grab"))
|
||||
return FALSE
|
||||
target.grabbedby(src)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/alien/adult/setGrabState(newstate)
|
||||
if(newstate == grab_state)
|
||||
return
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
take_bodypart_damage(5 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
|
||||
else if(!iscarbon(hit_atom) && extra_speed)
|
||||
take_bodypart_damage(5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
|
||||
visible_message(span_danger("[src] crashes into [hit_atom][extra_speed ? " really hard" : ""]"),\
|
||||
visible_message(span_danger("[src] crashes into [hit_atom][extra_speed ? " really hard" : ""]!"),\
|
||||
span_userdanger("You violently crash into [hit_atom][extra_speed ? " extra hard" : ""]!"))
|
||||
log_combat(hit_atom, src, "crashes ")
|
||||
oof_noise = TRUE
|
||||
|
||||
@@ -566,7 +566,7 @@
|
||||
if (!IS_ORGANIC_LIMB(limb))
|
||||
. += (limb.brute_dam * limb.body_damage_coeff) + (limb.burn_dam * limb.body_damage_coeff)
|
||||
|
||||
/mob/living/carbon/grabbedby(mob/living/carbon/user, supress_message = FALSE)
|
||||
/mob/living/carbon/grabbedby(mob/living/user, supress_message = FALSE)
|
||||
if(user != src)
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -1105,9 +1105,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
if(SEND_SIGNAL(target, COMSIG_CARBON_PRE_HELP, user, attacker_style) & COMPONENT_BLOCK_HELP_ACT)
|
||||
return TRUE
|
||||
|
||||
if(attacker_style?.help_act(user, target) == MARTIAL_ATTACK_SUCCESS)
|
||||
return TRUE
|
||||
|
||||
if(target.body_position == STANDING_UP || (target.appears_alive() && target.stat != SOFT_CRIT && target.stat != HARD_CRIT))
|
||||
target.help_shake_act(user)
|
||||
if(target != user)
|
||||
@@ -1116,111 +1113,100 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
|
||||
user.do_cpr(target)
|
||||
|
||||
/datum/species/proc/grab(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
||||
if(attacker_style?.grab_act(user, target) == MARTIAL_ATTACK_SUCCESS)
|
||||
return TRUE
|
||||
target.grabbedby(user)
|
||||
return TRUE
|
||||
|
||||
///This proc handles punching damage. IMPORTANT: Our owner is the TARGET and not the USER in this proc. For whatever reason...
|
||||
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM) && !attacker_style?.pacifist_style)
|
||||
to_chat(user, span_warning("You don't want to harm [target]!"))
|
||||
return FALSE
|
||||
if(attacker_style?.harm_act(user,target) == MARTIAL_ATTACK_SUCCESS)
|
||||
return TRUE
|
||||
else
|
||||
|
||||
var/obj/item/organ/internal/brain/brain = user.get_organ_slot(ORGAN_SLOT_BRAIN)
|
||||
var/obj/item/bodypart/attacking_bodypart
|
||||
if(brain)
|
||||
attacking_bodypart = brain.get_attacking_limb(target)
|
||||
if(!attacking_bodypart)
|
||||
attacking_bodypart = user.get_active_hand()
|
||||
var/atk_verb = attacking_bodypart.unarmed_attack_verb
|
||||
var/atk_effect = attacking_bodypart.unarmed_attack_effect
|
||||
var/obj/item/organ/internal/brain/brain = user.get_organ_slot(ORGAN_SLOT_BRAIN)
|
||||
var/obj/item/bodypart/attacking_bodypart
|
||||
if(brain)
|
||||
attacking_bodypart = brain.get_attacking_limb(target)
|
||||
if(!attacking_bodypart)
|
||||
attacking_bodypart = user.get_active_hand()
|
||||
var/atk_verb = attacking_bodypart.unarmed_attack_verb
|
||||
var/atk_effect = attacking_bodypart.unarmed_attack_effect
|
||||
|
||||
if(atk_effect == ATTACK_EFFECT_BITE)
|
||||
if(user.is_mouth_covered(ITEM_SLOT_MASK))
|
||||
to_chat(user, span_warning("You can't [atk_verb] with your mouth covered!"))
|
||||
return FALSE
|
||||
user.do_attack_animation(target, atk_effect)
|
||||
|
||||
//has our target been shoved recently? If so, they're staggered and we get an easy hit.
|
||||
var/staggered = FALSE
|
||||
|
||||
//Someone in a grapple is much more vulnerable to being harmed by punches.
|
||||
var/grappled = FALSE
|
||||
|
||||
if(target.get_timed_status_effect_duration(/datum/status_effect/staggered))
|
||||
staggered = TRUE
|
||||
|
||||
if(target.pulledby && target.pulledby.grab_state >= GRAB_AGGRESSIVE)
|
||||
grappled = TRUE
|
||||
|
||||
var/damage = rand(attacking_bodypart.unarmed_damage_low, attacking_bodypart.unarmed_damage_high)
|
||||
var/limb_accuracy = attacking_bodypart.unarmed_effectiveness
|
||||
|
||||
var/obj/item/bodypart/affecting = target.get_bodypart(target.get_random_valid_zone(user.zone_selected))
|
||||
|
||||
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
|
||||
if(attacking_bodypart.unarmed_damage_low)
|
||||
if((target.body_position == LYING_DOWN) || HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) || staggered) //kicks and attacks against staggered targets never miss (provided your species deals more than 0 damage)
|
||||
miss_chance = 0
|
||||
else
|
||||
miss_chance = clamp(UNARMED_MISS_CHANCE_BASE - limb_accuracy + user.getStaminaLoss() + (user.getBruteLoss()*0.5), 0, UNARMED_MISS_CHANCE_MAX) //Limb miss chance + various damage. capped at 80 so there is at least a chance to land a hit.
|
||||
|
||||
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
|
||||
playsound(target.loc, attacking_bodypart.unarmed_miss_sound, 25, TRUE, -1)
|
||||
target.visible_message(span_danger("[user]'s [atk_verb] misses [target]!"), \
|
||||
span_danger("You avoid [user]'s [atk_verb]!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user)
|
||||
to_chat(user, span_warning("Your [atk_verb] misses [target]!"))
|
||||
log_combat(user, target, "attempted to punch")
|
||||
if(atk_effect == ATTACK_EFFECT_BITE)
|
||||
if(user.is_mouth_covered(ITEM_SLOT_MASK))
|
||||
to_chat(user, span_warning("You can't [atk_verb] with your mouth covered!"))
|
||||
return FALSE
|
||||
user.do_attack_animation(target, atk_effect)
|
||||
|
||||
var/armor_block = target.run_armor_check(affecting, MELEE)
|
||||
//has our target been shoved recently? If so, they're staggered and we get an easy hit.
|
||||
var/staggered = FALSE
|
||||
|
||||
playsound(target.loc, attacking_bodypart.unarmed_attack_sound, 25, TRUE, -1)
|
||||
//Someone in a grapple is much more vulnerable to being harmed by punches.
|
||||
var/grappled = FALSE
|
||||
|
||||
if(grappled && attacking_bodypart.grappled_attack_verb)
|
||||
atk_verb = attacking_bodypart.grappled_attack_verb
|
||||
target.visible_message(span_danger("[user] [atk_verb]ed [target]!"), \
|
||||
span_userdanger("You're [atk_verb]ed by [user]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, user)
|
||||
to_chat(user, span_danger("You [atk_verb] [target]!"))
|
||||
if(target.get_timed_status_effect_duration(/datum/status_effect/staggered))
|
||||
staggered = TRUE
|
||||
|
||||
target.lastattacker = user.real_name
|
||||
target.lastattackerckey = user.ckey
|
||||
if(target.pulledby && target.pulledby.grab_state >= GRAB_AGGRESSIVE)
|
||||
grappled = TRUE
|
||||
|
||||
if(user.limb_destroyer)
|
||||
target.dismembering_strike(user, affecting.body_zone)
|
||||
var/damage = rand(attacking_bodypart.unarmed_damage_low, attacking_bodypart.unarmed_damage_high)
|
||||
var/limb_accuracy = attacking_bodypart.unarmed_effectiveness
|
||||
|
||||
var/attack_direction = get_dir(user, target)
|
||||
var/attack_type = attacking_bodypart.attack_type
|
||||
if(atk_effect == ATTACK_EFFECT_KICK || grappled) //kicks and punches when grappling bypass armor slightly.
|
||||
if(damage >= 9)
|
||||
target.force_say()
|
||||
log_combat(user, target, grappled ? "grapple punched" : "kicked")
|
||||
target.apply_damage(damage, attack_type, affecting, armor_block - limb_accuracy, attack_direction = attack_direction)
|
||||
target.apply_damage(damage*1.5, STAMINA, affecting, armor_block - limb_accuracy)
|
||||
else // Normal attacks do not gain the benefit of armor penetration.
|
||||
target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction)
|
||||
target.apply_damage(damage*1.5, STAMINA, affecting, armor_block)
|
||||
if(damage >= 9)
|
||||
target.force_say()
|
||||
log_combat(user, target, "punched")
|
||||
var/obj/item/bodypart/affecting = target.get_bodypart(target.get_random_valid_zone(user.zone_selected))
|
||||
|
||||
//If we rolled a punch high enough to hit our stun threshold, or our target is staggered and they have at least 40 damage+stamina loss, we knock them down
|
||||
if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40)
|
||||
target.visible_message(span_danger("[user] knocks [target] down!"), \
|
||||
span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user)
|
||||
to_chat(user, span_danger("You knock [target] down!"))
|
||||
var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration
|
||||
target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block)
|
||||
log_combat(user, target, "got a stun punch with their previous punch")
|
||||
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
|
||||
if(attacking_bodypart.unarmed_damage_low)
|
||||
if((target.body_position == LYING_DOWN) || HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) || staggered) //kicks and attacks against staggered targets never miss (provided your species deals more than 0 damage)
|
||||
miss_chance = 0
|
||||
else
|
||||
miss_chance = clamp(UNARMED_MISS_CHANCE_BASE - limb_accuracy + user.getStaminaLoss() + (user.getBruteLoss()*0.5), 0, UNARMED_MISS_CHANCE_MAX) //Limb miss chance + various damage. capped at 80 so there is at least a chance to land a hit.
|
||||
|
||||
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
|
||||
playsound(target.loc, attacking_bodypart.unarmed_miss_sound, 25, TRUE, -1)
|
||||
target.visible_message(span_danger("[user]'s [atk_verb] misses [target]!"), \
|
||||
span_danger("You avoid [user]'s [atk_verb]!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user)
|
||||
to_chat(user, span_warning("Your [atk_verb] misses [target]!"))
|
||||
log_combat(user, target, "attempted to punch")
|
||||
return FALSE
|
||||
|
||||
var/armor_block = target.run_armor_check(affecting, MELEE)
|
||||
|
||||
playsound(target.loc, attacking_bodypart.unarmed_attack_sound, 25, TRUE, -1)
|
||||
|
||||
if(grappled && attacking_bodypart.grappled_attack_verb)
|
||||
atk_verb = attacking_bodypart.grappled_attack_verb
|
||||
target.visible_message(span_danger("[user] [atk_verb]ed [target]!"), \
|
||||
span_userdanger("You're [atk_verb]ed by [user]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, user)
|
||||
to_chat(user, span_danger("You [atk_verb] [target]!"))
|
||||
|
||||
target.lastattacker = user.real_name
|
||||
target.lastattackerckey = user.ckey
|
||||
|
||||
if(user.limb_destroyer)
|
||||
target.dismembering_strike(user, affecting.body_zone)
|
||||
|
||||
var/attack_direction = get_dir(user, target)
|
||||
var/attack_type = attacking_bodypart.attack_type
|
||||
if(atk_effect == ATTACK_EFFECT_KICK || grappled) //kicks and punches when grappling bypass armor slightly.
|
||||
if(damage >= 9)
|
||||
target.force_say()
|
||||
log_combat(user, target, grappled ? "grapple punched" : "kicked")
|
||||
target.apply_damage(damage, attack_type, affecting, armor_block - limb_accuracy, attack_direction = attack_direction)
|
||||
target.apply_damage(damage*1.5, STAMINA, affecting, armor_block - limb_accuracy)
|
||||
else // Normal attacks do not gain the benefit of armor penetration.
|
||||
target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction)
|
||||
target.apply_damage(damage*1.5, STAMINA, affecting, armor_block)
|
||||
if(damage >= 9)
|
||||
target.force_say()
|
||||
log_combat(user, target, "punched")
|
||||
|
||||
//If we rolled a punch high enough to hit our stun threshold, or our target is staggered and they have at least 40 damage+stamina loss, we knock them down
|
||||
if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40)
|
||||
target.visible_message(span_danger("[user] knocks [target] down!"), \
|
||||
span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user)
|
||||
to_chat(user, span_danger("You knock [target] down!"))
|
||||
var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration
|
||||
target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block)
|
||||
log_combat(user, target, "got a stun punch with their previous punch")
|
||||
|
||||
/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
||||
if(attacker_style?.disarm_act(user,target) == MARTIAL_ATTACK_SUCCESS)
|
||||
return TRUE
|
||||
if(user.body_position != STANDING_UP)
|
||||
return FALSE
|
||||
if(user == target)
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE)
|
||||
/mob/living/carbon/human/grippedby(mob/living/carbon/user, instant = FALSE)
|
||||
if(w_uniform)
|
||||
w_uniform.add_fingerprint(user)
|
||||
..()
|
||||
@@ -158,10 +158,6 @@
|
||||
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(get_random_valid_zone(dam_zone))
|
||||
|
||||
var/martial_result = user.apply_martial_art(src, modifiers)
|
||||
if (martial_result != MARTIAL_ATTACK_INVALID)
|
||||
return martial_result
|
||||
|
||||
if(LAZYACCESS(modifiers, RIGHT_CLICK)) //Always drop item in hand, if no item, get stunned instead.
|
||||
var/obj/item/I = get_active_held_item()
|
||||
if(I && !(I.item_flags & ABSTRACT) && dropItemToGround(I))
|
||||
|
||||
@@ -42,12 +42,13 @@
|
||||
/datum/species/mush/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
if(ishuman(C))
|
||||
mush = new(null)
|
||||
mush = new()
|
||||
mush.teach(C)
|
||||
mush.allow_temp_override = FALSE
|
||||
|
||||
/datum/species/mush/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
mush.remove(C)
|
||||
mush.fully_remove(C)
|
||||
QDEL_NULL(mush)
|
||||
|
||||
/datum/species/mush/handle_chemical(datum/reagent/chem, mob/living/carbon/human/affected, seconds_per_tick, times_fired)
|
||||
@@ -87,4 +88,3 @@
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -2392,31 +2392,6 @@ GLOBAL_LIST_EMPTY(fire_appearances)
|
||||
/mob/living/proc/get_attack_type()
|
||||
return BRUTE
|
||||
|
||||
|
||||
/**
|
||||
* Apply a martial art move from src to target.
|
||||
*
|
||||
* This is used to process martial art attacks against nonhumans.
|
||||
* It is also used to process martial art attacks by nonhumans, even against humans
|
||||
* Human vs human attacks are handled in species code right now.
|
||||
*/
|
||||
/mob/living/proc/apply_martial_art(mob/living/target, modifiers, is_grab = FALSE)
|
||||
if(HAS_TRAIT(target, TRAIT_MARTIAL_ARTS_IMMUNE))
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
var/datum/martial_art/style = mind?.martial_art
|
||||
if (!style)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
// will return boolean below since it's not invalid
|
||||
if (is_grab)
|
||||
return style.grab_act(src, target)
|
||||
if (LAZYACCESS(modifiers, RIGHT_CLICK))
|
||||
return style.disarm_act(src, target)
|
||||
if(combat_mode)
|
||||
if (HAS_TRAIT(src, TRAIT_PACIFISM))
|
||||
return FALSE
|
||||
return style.harm_act(src, target)
|
||||
return style.help_act(src, target)
|
||||
|
||||
/**
|
||||
* Returns an assoc list of assignments and minutes for updating a client's exp time in the databse.
|
||||
*
|
||||
|
||||
@@ -215,17 +215,34 @@
|
||||
adjust_fire_stacks(3)
|
||||
ignite_mob()
|
||||
|
||||
/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = FALSE)
|
||||
/**
|
||||
* Called when a mob is grabbing another mob.
|
||||
*/
|
||||
/mob/living/proc/grab(mob/living/target)
|
||||
if(!istype(target))
|
||||
return FALSE
|
||||
if(SEND_SIGNAL(src, COMSIG_LIVING_GRAB, target) & (COMPONENT_CANCEL_ATTACK_CHAIN|COMPONENT_SKIP_ATTACK))
|
||||
return FALSE
|
||||
if(target.check_block(src, 0, "[src]'s grab"))
|
||||
return FALSE
|
||||
target.grabbedby(src)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Called when this mob is grabbed by another mob.
|
||||
*/
|
||||
/mob/living/proc/grabbedby(mob/living/user, supress_message = FALSE)
|
||||
if(user == src || anchored || !isturf(user.loc))
|
||||
return FALSE
|
||||
if(!user.pulling || user.pulling != src)
|
||||
user.start_pulling(src, supress_message = supress_message)
|
||||
return
|
||||
|
||||
// This line arbitrarily prevents any non-carbon from upgrading grabs
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
if(!(status_flags & CANPUSH) || HAS_TRAIT(src, TRAIT_PUSHIMMUNE))
|
||||
to_chat(user, span_warning("[src] can't be grabbed more aggressively!"))
|
||||
return FALSE
|
||||
|
||||
if(user.grab_state >= GRAB_AGGRESSIVE && HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
to_chat(user, span_warning("You don't want to risk hurting [src]!"))
|
||||
return FALSE
|
||||
@@ -359,17 +376,9 @@
|
||||
if(operations.next_step(user, modifiers))
|
||||
return TRUE
|
||||
|
||||
var/martial_result = user.apply_martial_art(src, modifiers)
|
||||
if (martial_result != MARTIAL_ATTACK_INVALID)
|
||||
return martial_result
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/attack_paw(mob/living/carbon/human/user, list/modifiers)
|
||||
var/martial_result = user.apply_martial_art(src, modifiers)
|
||||
if (martial_result != MARTIAL_ATTACK_INVALID)
|
||||
return martial_result
|
||||
|
||||
if(LAZYACCESS(modifiers, RIGHT_CLICK))
|
||||
user.disarm(src)
|
||||
return TRUE
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
/mob/living/silicon/grippedby(mob/living/user, instant = FALSE)
|
||||
/mob/living/silicon/grippedby(mob/living/carbon/user, instant = FALSE)
|
||||
return //can't upgrade a simple pull into a more aggressive grab.
|
||||
|
||||
/mob/living/silicon/get_ear_protection()//no ears
|
||||
|
||||
@@ -155,8 +155,8 @@
|
||||
return FALSE
|
||||
if(isgolem(victim) && victim.has_status_effect(/datum/status_effect/golem/gold))
|
||||
return TRUE
|
||||
var/mob/living/carbon/human/human_victim = victim
|
||||
return human_victim.mind && istype(human_victim.mind.martial_art, /datum/martial_art/the_sleeping_carp)
|
||||
|
||||
return istype(victim.mind?.martial_art, /datum/martial_art/the_sleeping_carp)
|
||||
|
||||
/obj/effect/temp_visual/at_shield
|
||||
name = "anti-toolbox field"
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
|
||||
var/mob/living/carbon/human/swapper = allocate(/mob/living/carbon/human/consistent)
|
||||
var/mob/living/carbon/human/to_swap = allocate(/mob/living/carbon/human/consistent)
|
||||
swapper.real_name = "The Mindswapper"
|
||||
swapper.name = swapper.real_name
|
||||
to_swap.real_name = "The Guy Who Gets Mindswapped"
|
||||
to_swap.name = to_swap.real_name
|
||||
|
||||
swapper.forceMove(run_loc_floor_bottom_left)
|
||||
to_swap.forceMove(locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z))
|
||||
|
||||
@@ -1565,7 +1565,6 @@
|
||||
#include "code\datums\martial\_martial.dm"
|
||||
#include "code\datums\martial\boxing.dm"
|
||||
#include "code\datums\martial\cqc.dm"
|
||||
#include "code\datums\martial\hugs_of_the_gondola.dm"
|
||||
#include "code\datums\martial\krav_maga.dm"
|
||||
#include "code\datums\martial\mushpunch.dm"
|
||||
#include "code\datums\martial\plasma_fist.dm"
|
||||
|
||||
Reference in New Issue
Block a user