From 3b3b2f479119d7e5d1b4bfeac1e2fabe0ef78e87 Mon Sep 17 00:00:00 2001 From: NovaBot <154629622+NovaBot13@users.noreply.github.com> Date: Fri, 2 Feb 2024 04:25:49 -0500 Subject: [PATCH] [MIRROR] Kicks Martial Arts out of the attack chain (yippee), makes it use signals, plus a large clean up of existing martial arts (#734) * Kicks Martial Arts out of the attack chain (yippee), makes it use signals, plus a large clean up of existing martial arts * Fix conflicts --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Mal <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/combat.dm | 6 +- .../signals/signals_mob/signals_mob_living.dm | 8 +- .../signals/signals_mob/signals_mob_main.dm | 2 + code/__DEFINES/melee.dm | 1 - code/_onclick/click.dm | 28 +- code/datums/brain_damage/special.dm | 5 +- code/datums/components/tackle.dm | 4 +- code/datums/martial/_martial.dm | 364 +++++++++++++++--- code/datums/martial/boxing.dm | 107 ++--- code/datums/martial/cqc.dm | 328 ++++++++++------ code/datums/martial/hugs_of_the_gondola.dm | 20 - code/datums/martial/krav_maga.dm | 189 ++++++--- code/datums/martial/mushpunch.dm | 69 ++-- code/datums/martial/plasma_fist.dm | 86 +++-- code/datums/martial/psychotic_brawl.dm | 60 ++- code/datums/martial/sleeping_carp.dm | 107 ++--- code/datums/martial/wrestling.dm | 132 ++++--- code/datums/mind/_mind.dm | 25 +- code/game/atoms_movable.dm | 2 +- .../dna_infuser/organ_sets/gondola_organs.dm | 20 +- .../granters/martial_arts/_martial_arts.dm | 11 +- .../items/granters/martial_arts/cqc.dm | 2 +- .../items/implants/implant_krav_maga.dm | 22 +- code/game/objects/structures/tables_racks.dm | 4 +- .../skill_learning/job_skillchips/chef.dm | 2 +- .../mob/living/carbon/alien/adult/adult.dm | 6 - code/modules/mob/living/carbon/carbon.dm | 2 +- .../mob/living/carbon/carbon_defense.dm | 2 +- .../mob/living/carbon/human/_species.dm | 178 ++++----- .../mob/living/carbon/human/human_defense.dm | 6 +- .../carbon/human/species_types/mushpeople.dm | 7 +- code/modules/mob/living/living.dm | 25 -- code/modules/mob/living/living_defense.dm | 31 +- .../mob/living/silicon/silicon_defense.dm | 2 +- .../hostile/megafauna/colossus.dm | 4 +- code/modules/unit_tests/spell_mindswap.dm | 4 + tgstation.dme | 1 - 37 files changed, 1171 insertions(+), 701 deletions(-) delete mode 100644 code/datums/martial/hugs_of_the_gondola.dm diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 19c87f3b4e0..33b7853cfd0 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -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 diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 7ac77efcaa7..2b113f853da 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -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 diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index 2023493ac95..6b63c1aaa9f 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -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" diff --git a/code/__DEFINES/melee.dm b/code/__DEFINES/melee.dm index df7320f5085..64fdfd1889e 100644 --- a/code/__DEFINES/melee.dm +++ b/code/__DEFINES/melee.dm @@ -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" diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index c907f45466d..3cb12ad8188 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -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) diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index d9348f98f4b..651881292e9 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -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 diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index 6ccb6aa7fdc..2a23deec611 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -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) /** diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm index 2af604cd8fe..e5dc7860b0b 100644 --- a/code/datums/martial/_martial.dm +++ b/code/datums/martial/_martial.dm @@ -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) + 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(holder_living, help_verb) - return + 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) diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm index da30104c9af..8ef30db63aa 100644 --- a/code/datums/martial/boxing.dm +++ b/code/datums/martial/boxing.dm @@ -3,69 +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/grab_act(mob/living/attacker, mob/living/defender) - to_chat(attacker, span_warning("Can't grab 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/harm_act(mob/living/attacker, mob/living/defender) +/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 - 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) - // NOVA EDIT CHANGE - var/sound/attack_sound - if(!active_arm.unarmed_attack_sound) - attack_sound = get_sfx("punch") - else - attack_sound = active_arm.unarmed_attack_sound - playsound(defender.loc, attack_sound, 25, TRUE, -1) - //NOVA EDIT END - - 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) . = ..() @@ -76,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) diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index ab92e854e87..8e33ac5a851 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -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 != CONSCIOUS) 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 + + 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 -/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 + 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/harm_act(mob/living/attacker, mob/living/defender) - if(!can_use(attacker)) +/datum/martial_art/cqc/grab_act(mob/living/attacker, mob/living/defender) + 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 ..() diff --git a/code/datums/martial/hugs_of_the_gondola.dm b/code/datums/martial/hugs_of_the_gondola.dm deleted file mode 100644 index a1fae03a35a..00000000000 --- a/code/datums/martial/hugs_of_the_gondola.dm +++ /dev/null @@ -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 diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index fcc432d41f8..d75437be2b7 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -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."), "Your next attack is cleared.") @@ -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."), "Your next attack is cleared.") @@ -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."), "Your next attack is cleared.") @@ -53,19 +68,20 @@ owner.visible_message(span_danger("[owner] assumes the Lung Punch stance!"), "Your next attack will be a Lung Punch.") 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,80 +100,138 @@ 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("[attacker] disarms [defender]!", \ - "You're disarmed by [attacker]!", "You hear aggressive shuffling!", COMBAT_MESSAGE_RANGE, attacker) - to_chat(attacker, "You disarm [defender]!") - 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 +<<<<<<< HEAD var/datum/martial_art/krav_maga/style = new +======= + var/datum/martial_art/krav_maga/style + clothing_traits = list(TRAIT_FAST_CUFFING) +>>>>>>> e13267b45 ([MIRROR] Kicks Martial Arts out of the attack chain (yippee), makes it use signals, plus a large clean up of existing martial arts (#734)) + +/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) . = ..() @@ -166,8 +240,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" diff --git a/code/datums/martial/mushpunch.dm b/code/datums/martial/mushpunch.dm index eea4439691f..e571f46be35 100644 --- a/code/datums/martial/mushpunch.dm +++ b/code/datums/martial/mushpunch.dm @@ -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("Your attack was interrupted!")) - 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("Your attack was interrupted!")) + 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 = "Sapienza Ophioglossoides: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 = "Sapienza Ophioglossoides: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].")) diff --git a/code/datums/martial/plasma_fist.dm b/code/datums/martial/plasma_fist.dm index ce2b2e6e2d3..1e278414936 100644 --- a/code/datums/martial/plasma_fist.dm +++ b/code/datums/martial/plasma_fist.dm @@ -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_notice("Apotheosis")] 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_notice("Apotheosis")] 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_notice("Apotheosis")] 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") @@ -109,12 +123,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) @@ -124,24 +139,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" diff --git a/code/datums/martial/psychotic_brawl.dm b/code/datums/martial/psychotic_brawl.dm index 671867f4252..9ba78f9ef45 100644 --- a/code/datums/martial/psychotic_brawl.dm +++ b/code/datums/martial/psychotic_brawl.dm @@ -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 diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 1275bd2da74..a52d2724ca2 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -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) - . = ..() - 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 - -/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_teach(mob/living/new_holder) . = ..() + 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/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.throw_mode) //FF EDIT, old: if(!can_use(carp_user) || !carp_user.throw_mode) diff --git a/code/datums/martial/wrestling.dm b/code/datums/martial/wrestling.dm index a28c2e75646..23591852ec9 100644 --- a/code/datums/martial/wrestling.dm +++ b/code/datums/martial/wrestling.dm @@ -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!"), "Your next attack will be a BODY SLAM.") 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!"), "Your next attack will be a THROW.") 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!"), "Your next attack will be a KICK.") 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!"), "Your next attack will be a STRIKE.") 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!"), "Your next attack will be a LEG DROP.") 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_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_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/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) diff --git a/code/datums/mind/_mind.dm b/code/datums/mind/_mind.dm index e33065651a3..23921bd84af 100644 --- a/code/datums/mind/_mind.dm +++ b/code/datums/mind/_mind.dm @@ -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) @@ -517,19 +517,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)) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 39892126c13..990f9812126 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -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 diff --git a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm index 2a5c776709c..70dd58f9f27 100644 --- a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm @@ -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 diff --git a/code/game/objects/items/granters/martial_arts/_martial_arts.dm b/code/game/objects/items/granters/martial_arts/_martial_arts.dm index 7646faec2c6..b7d186c99c0 100644 --- a/code/game/objects/items/granters/martial_arts/_martial_arts.dm +++ b/code/game/objects/items/granters/martial_arts/_martial_arts.dm @@ -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") diff --git a/code/game/objects/items/granters/martial_arts/cqc.dm b/code/game/objects/items/granters/martial_arts/cqc.dm index 697541e0216..b2191997586 100644 --- a/code/game/objects/items/granters/martial_arts/cqc.dm +++ b/code/game/objects/items/granters/martial_arts/cqc.dm @@ -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...", ) diff --git a/code/game/objects/items/implants/implant_krav_maga.dm b/code/game/objects/items/implants/implant_krav_maga.dm index fa3ccd1ccb2..4d921269beb 100644 --- a/code/game/objects/items/implants/implant_krav_maga.dm +++ b/code/game/objects/items/implants/implant_krav_maga.dm @@ -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 = {"Implant Specifications:
@@ -13,17 +13,23 @@ Function: 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)" diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 5e39bbdd6d8..423adb71044 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -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]!"), diff --git a/code/modules/library/skill_learning/job_skillchips/chef.dm b/code/modules/library/skill_learning/job_skillchips/chef.dm index 589978452e1..75bc494543c 100644 --- a/code/modules/library/skill_learning/job_skillchips/chef.dm +++ b/code/modules/library/skill_learning/job_skillchips/chef.dm @@ -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 ..() diff --git a/code/modules/mob/living/carbon/alien/adult/adult.dm b/code/modules/mob/living/carbon/alien/adult/adult.dm index 92f3febef2c..2cab03d670e 100644 --- a/code/modules/mob/living/carbon/alien/adult/adult.dm +++ b/code/modules/mob/living/carbon/alien/adult/adult.dm @@ -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 diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 4ec78f728aa..31530240bd1 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -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 diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index aa778643491..d0717972d59 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -612,7 +612,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, grabbed_part) // NOVA EDIT CHANGE - ORIGINAL: /mob/living/carbon/grabbedby(mob/living/carbon/user, supress_message = FALSE) +/mob/living/carbon/grabbedby(mob/living/user, supress_message = FALSE, grabbed_part) // NOVA EDIT CHANGE - ORIGINAL: /mob/living/carbon/grabbedby(mob/living/user, supress_message = FALSE) if(user != src) return ..() diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 0de67ef055d..e7561bf4a60 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1132,9 +1132,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) @@ -1143,115 +1140,104 @@ 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 - - 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/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 + //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 + //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.get_timed_status_effect_duration(/datum/status_effect/staggered)) + staggered = TRUE - if(target.pulledby && target.pulledby.grab_state >= GRAB_AGGRESSIVE) - grappled = 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/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/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") - return FALSE + 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 || get_sfx("punch"), 25, TRUE, -1) // NOVA EDIT - ORIGINAL: 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 - var/unarmed_sharpness = attacking_bodypart.unarmed_sharpness //NOVA EDIT ADDITION - If unarmed damage sharpness needs to be taken into account. - 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, sharpness = unarmed_sharpness) //NOVA EDIT - Applies sharpness if it does - ORIGINAL: 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!")) - /* NOVA EDIT REMOVAL - Less combat lethality and hard stungs - 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) - */ // SKYRAT REMOVAL END - target.StaminaKnockdown(20) //NOVA EDIT ADDITION - log_combat(user, target, "got a stun punch with their previous punch") + 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 + var/unarmed_sharpness = attacking_bodypart.unarmed_sharpness //NOVA EDIT ADDITION - If unarmed damage sharpness needs to be taken into account. + 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, sharpness = unarmed_sharpness) //NOVA EDIT - Applies sharpness if it does - ORIGINAL: 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!")) + /* NOVA EDIT REMOVAL - Less combat lethality and hard stuns + 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) + NOVA EDIT REMOVAL END */ + target.StaminaKnockdown(20) //NOVA EDIT ADDITION + 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) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 6afdcebd955..b0e4c79b86d 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -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)) diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index 59099cec175..a16d9e92637 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -45,12 +45,13 @@ if(!H.dna.mutant_bodyparts["caps"] || H.dna.mutant_bodyparts["caps"][MUTANT_INDEX_NAME] != "None") // NOVA EDIT - Customization - ORIGINAL: if(!H.dna.features["caps"]) H.dna.mutant_bodyparts["caps"] = list(MUTANT_INDEX_NAME = "Round", MUTANT_INDEX_COLOR_LIST = list(H.hair_color)) // NOVA EDIT - Customization - ORIGINAL: H.dna.features["caps"] = "Round" handle_mutant_bodyparts(H) - mush = new(null) - mush.teach(H) + 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) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index a05a750d743..a9747c9d34a 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -2470,31 +2470,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. * diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index e110ce6b11f..55cb51c97dd 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -227,17 +227,34 @@ adjust_fire_stacks(3) ignite_mob() -/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = FALSE, grabbed_part) // NOVA EDIT CHANGE - ORIGINAL: /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, grabbed_part) // NOVA EDIT CHANGE - ORIGINAL: /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 @@ -371,17 +388,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 diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index bb5f9169f67..e84758d9f58 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -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 diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index d794e493910..e256e4f2921 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -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" diff --git a/code/modules/unit_tests/spell_mindswap.dm b/code/modules/unit_tests/spell_mindswap.dm index 133f9662d91..f598bcc7263 100644 --- a/code/modules/unit_tests/spell_mindswap.dm +++ b/code/modules/unit_tests/spell_mindswap.dm @@ -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)) diff --git a/tgstation.dme b/tgstation.dme index 980cca03970..c8e370dfcc5 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1666,7 +1666,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"