mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-29 18:40:42 +00:00
## About The Pull Request <details> - renamed ai folder to announcer -- announcer -- - moved vox_fem to announcer - moved approachingTG to announcer - separated the ambience folder into ambience and instrumental -- ambience -- - created holy folder moved all related sounds there - created engineering folder and moved all related sounds there - created security folder and moved ambidet there - created general folder and moved ambigen there - created icemoon folder and moved all icebox-related ambience there - created medical folder and moved all medbay-related ambi there - created ruin folder and moves all ruins ambi there - created beach folder and moved seag and shore there - created lavaland folder and moved related ambi there - created aurora_caelus folder and placed its ambi there - created misc folder and moved the rest of the files that don't have a specific category into it -- instrumental -- - moved traitor folder here - created lobby_music folder and placed our songs there (title0 not used anywhere? - server-side modification?) -- items -- - moved secdeath to hailer - moved surgery to handling -- effects -- - moved chemistry into effects - moved hallucinations into effects - moved health into effects - moved magic into effects -- vehicles -- - moved mecha into vehicles created mobs folder -- mobs -- - moved creatures folder into mobs - moved voice into mobs renamed creatures to non-humanoids renamed voice to humanoids -- non-humanoids-- created cyborg folder created hiss folder moved harmalarm.ogg to cyborg -- humanoids -- -- misc -- moved ghostwhisper to misc moved insane_low_laugh to misc I give up trying to document this. </details> - [X] ambience - [x] announcer - [x] effects - [X] instrumental - [x] items - [x] machines - [x] misc - [X] mobs - [X] runtime - [X] vehicles - [ ] attributions ## Why It's Good For The Game This folder is so disorganized that it's vomit inducing, will make it easier to find and add new sounds, providng a minor structure to the sound folder. ## Changelog 🆑 grungussuss refactor: the sound folder in the source code has been reorganized, please report any oddities with sounds playing or not playing server: lobby music has been repathed to sound/music/lobby_music /🆑
415 lines
17 KiB
Plaintext
415 lines
17 KiB
Plaintext
#define SLAM_COMBO "GH"
|
|
#define KICK_COMBO "HH"
|
|
#define RESTRAIN_COMBO "GG"
|
|
#define PRESSURE_COMBO "DG"
|
|
#define CONSECUTIVE_COMBO "DDH"
|
|
|
|
/datum/martial_art/cqc
|
|
name = "CQC"
|
|
id = MARTIALART_CQC
|
|
help_verb = /mob/living/proc/CQC_help
|
|
smashes_tables = TRUE
|
|
display_combos = TRUE
|
|
/// 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/on_teach(mob/living/new_holder)
|
|
. = ..()
|
|
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/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)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!istype(attack_weapon, /obj/item/melee/touch_attack))
|
|
return
|
|
if(!can_use(cqc_user))
|
|
return
|
|
cqc_user.visible_message(
|
|
span_danger("[cqc_user] twists [attacker]'s arm, sending their [attack_weapon] back towards them!"),
|
|
span_userdanger("Making sure to avoid [attacker]'s [attack_weapon], you twist their arm to send it right back at them!"),
|
|
)
|
|
var/obj/item/melee/touch_attack/touch_weapon = attack_weapon
|
|
var/datum/action/cooldown/spell/touch/touch_spell = touch_weapon.spell_which_made_us?.resolve()
|
|
if(!touch_spell)
|
|
return
|
|
INVOKE_ASYNC(touch_spell, TYPE_PROC_REF(/datum/action/cooldown/spell/touch, do_hand_hit), touch_weapon, attacker, attacker)
|
|
return COMPONENT_NO_AFTERATTACK
|
|
|
|
/datum/martial_art/cqc/proc/check_block(mob/living/cqc_user, atom/movable/hitby, damage, attack_text, attack_type, ...)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!can_use(cqc_user) || !cqc_user.throw_mode || INCAPACITATED_IGNORING(cqc_user, INCAPABLE_GRAB))
|
|
return NONE
|
|
if(attack_type == PROJECTILE_ATTACK)
|
|
return NONE
|
|
if(!prob(block_chance))
|
|
return NONE
|
|
|
|
var/mob/living/attacker = GET_ASSAILANT(hitby)
|
|
if(istype(attacker) && cqc_user.Adjacent(attacker))
|
|
cqc_user.visible_message(
|
|
span_danger("[cqc_user] blocks [attack_text] and twists [attacker]'s arm behind [attacker.p_their()] back!"),
|
|
span_userdanger("You block [attack_text]!"),
|
|
)
|
|
attacker.Stun(4 SECONDS)
|
|
else
|
|
cqc_user.visible_message(
|
|
span_danger("[cqc_user] blocks [attack_text]!"),
|
|
span_userdanger("You block [attack_text]!"),
|
|
)
|
|
return SUCCESSFUL_BLOCK
|
|
|
|
|
|
/datum/martial_art/cqc/reset_streak(mob/living/new_target)
|
|
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(findtext(streak, SLAM_COMBO))
|
|
reset_streak()
|
|
return Slam(attacker, defender)
|
|
if(findtext(streak, KICK_COMBO))
|
|
reset_streak()
|
|
return Kick(attacker, defender)
|
|
if(findtext(streak, RESTRAIN_COMBO))
|
|
reset_streak()
|
|
return Restrain(attacker, defender)
|
|
if(findtext(streak, PRESSURE_COMBO))
|
|
reset_streak()
|
|
return Pressure(attacker, defender)
|
|
if(findtext(streak, CONSECUTIVE_COMBO))
|
|
reset_streak()
|
|
return Consecutive(attacker, defender)
|
|
return FALSE
|
|
|
|
/datum/martial_art/cqc/proc/Slam(mob/living/attacker, mob/living/defender)
|
|
if(defender.body_position != STANDING_UP)
|
|
return FALSE
|
|
|
|
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/items/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(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,
|
|
)
|
|
to_chat(attacker, span_danger("You kick [defender]'s head, knocking [defender.p_them()] out!"))
|
|
playsound(attacker, 'sound/items/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,
|
|
)
|
|
to_chat(attacker, span_danger("You kick [defender] back!"))
|
|
playsound(attacker, 'sound/items/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)")
|
|
|
|
return TRUE
|
|
|
|
/datum/martial_art/cqc/proc/Pressure(mob/living/attacker, mob/living/defender)
|
|
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,
|
|
)
|
|
to_chat(attacker, span_danger("You punch [defender]'s neck!"))
|
|
defender.adjustStaminaLoss(60)
|
|
playsound(attacker, 'sound/items/weapons/cqchit1.ogg', 50, TRUE, -1)
|
|
return TRUE
|
|
|
|
/datum/martial_art/cqc/proc/Restrain(mob/living/attacker, mob/living/defender)
|
|
if(restraining_mob?.resolve())
|
|
return FALSE
|
|
if(defender.stat != CONSCIOUS)
|
|
return FALSE
|
|
|
|
log_combat(attacker, defender, "restrained (CQC)")
|
|
defender.visible_message(
|
|
span_warning("[attacker] locks [defender] into a restraining position!"),
|
|
span_userdanger("You're locked into a restraining position by [attacker]!"),
|
|
span_hear("You hear shuffling and a muffled groan!"),
|
|
null,
|
|
attacker,
|
|
)
|
|
to_chat(attacker, span_danger("You lock [defender] into a restraining position!"))
|
|
defender.adjustStaminaLoss(20)
|
|
defender.Stun(10 SECONDS)
|
|
restraining_mob = WEAKREF(defender)
|
|
addtimer(VARSET_CALLBACK(src, restraining_mob, null), 5 SECONDS, TIMER_UNIQUE)
|
|
return TRUE
|
|
|
|
/datum/martial_art/cqc/proc/Consecutive(mob/living/attacker, mob/living/defender)
|
|
if(defender.stat != CONSCIOUS)
|
|
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/items/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)
|
|
return MARTIAL_ATTACK_INVALID
|
|
if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK))
|
|
return MARTIAL_ATTACK_FAIL
|
|
|
|
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 \
|
|
&& defender.stat != DEAD \
|
|
)
|
|
var/obj/item/bodypart/head = defender.get_bodypart(BODY_ZONE_HEAD)
|
|
if(!isnull(head))
|
|
playsound(defender, 'sound/effects/wounds/crack1.ogg', 100)
|
|
defender.visible_message(
|
|
span_danger("[attacker] snaps the neck of [defender]!"),
|
|
span_userdanger("Your neck is snapped by [attacker]!"),
|
|
span_hear("You hear a sickening snap!"),
|
|
ignored_mobs = attacker
|
|
)
|
|
to_chat(attacker, span_danger("In a swift motion, you snap the neck of [defender]!"))
|
|
log_combat(attacker, defender, "snapped neck")
|
|
defender.apply_damage(100, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND)
|
|
if(!HAS_TRAIT(defender, TRAIT_NODEATH))
|
|
defender.death()
|
|
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
|
|
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 = pick("kick", "stomp")
|
|
defender.apply_damage(bonus_damage, BRUTE)
|
|
|
|
playsound(defender, (picked_hit_type == "kick" || picked_hit_type == "stomp") ? 'sound/items/weapons/cqchit2.ogg' : 'sound/items/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(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK))
|
|
return MARTIAL_ATTACK_FAIL
|
|
|
|
add_to_streak("D", defender)
|
|
if(check_streak(attacker, defender))
|
|
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 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/items/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/items/weapons/punchmiss.ogg', 25, TRUE, -1)
|
|
log_combat(attacker, defender, "failed to disarm (CQC)")
|
|
return MARTIAL_ATTACK_FAIL
|
|
|
|
|
|
/mob/living/proc/CQC_help()
|
|
set name = "Remember The Basics"
|
|
set desc = "You try to remember some of the basics of CQC."
|
|
set category = "CQC"
|
|
to_chat(usr, "<b><i>You try to remember some of the basics of CQC.</i></b>")
|
|
|
|
to_chat(usr, "[span_notice("Slam")]: Grab Punch. Slam opponent into the ground, knocking them down.")
|
|
to_chat(usr, "[span_notice("CQC Kick")]: Punch Punch. Knocks opponent away. Knocks out stunned opponents and does stamina damage.")
|
|
to_chat(usr, "[span_notice("Restrain")]: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a chokehold.")
|
|
to_chat(usr, "[span_notice("Pressure")]: Shove Grab. Decent stamina damage.")
|
|
to_chat(usr, "[span_notice("Consecutive CQC")]: Shove Shove Punch. Mainly offensive move, huge damage and decent stamina damage.")
|
|
|
|
to_chat(usr, "<b><i>In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter attacks done to you.</i></b>")
|
|
|
|
///Subtype of CQC. Only used for the chef.
|
|
/datum/martial_art/cqc/under_siege
|
|
name = "Close Quarters Cooking"
|
|
///List of all areas that CQC will work in, defaults to Kitchen.
|
|
var/list/kitchen_areas = list(/area/station/service/kitchen)
|
|
|
|
/// Refreshes the valid areas from the cook's mapping config, adding areas in config to the list of possible areas.
|
|
/datum/martial_art/cqc/under_siege/proc/refresh_valid_areas()
|
|
var/list/additional_cqc_areas = CHECK_MAP_JOB_CHANGE(JOB_COOK, "additional_cqc_areas")
|
|
if(!additional_cqc_areas)
|
|
return
|
|
|
|
if(!islist(additional_cqc_areas))
|
|
stack_trace("Incorrect CQC area format from mapping configs. Expected /list, got: \[[additional_cqc_areas.type]\]")
|
|
return
|
|
|
|
for(var/path_as_text in additional_cqc_areas)
|
|
var/path = text2path(path_as_text)
|
|
if(!ispath(path, /area))
|
|
stack_trace("Invalid path in mapping config for chef CQC: \[[path_as_text]\]")
|
|
continue
|
|
|
|
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/martial_artist)
|
|
if(!is_type_in_list(get_area(martial_artist), kitchen_areas))
|
|
return FALSE
|
|
return ..()
|
|
|
|
#undef SLAM_COMBO
|
|
#undef KICK_COMBO
|
|
#undef RESTRAIN_COMBO
|
|
#undef PRESSURE_COMBO
|
|
#undef CONSECUTIVE_COMBO
|