From eb316ce9c1f2ba7f1fa1f1dc65d9b987ef091419 Mon Sep 17 00:00:00 2001 From: SELFHELL <99771731+SELFHELL@users.noreply.github.com> Date: Thu, 19 Mar 2026 13:45:43 -0500 Subject: [PATCH 1/9] Initial Commit --- modular_darkpack/modules/martial/cqb.dm | 341 ++++++++++++++ .../modules/martial/streetboxing.dm | 438 ++++++++++++++++++ modular_darkpack/modules/martial/swords.dm | 165 +++++++ .../storyteller_dice/code/roll_subtypes.dm | 27 ++ tgstation.dme | 1 + 5 files changed, 972 insertions(+) create mode 100644 modular_darkpack/modules/martial/cqb.dm create mode 100644 modular_darkpack/modules/martial/streetboxing.dm create mode 100644 modular_darkpack/modules/martial/swords.dm diff --git a/modular_darkpack/modules/martial/cqb.dm b/modular_darkpack/modules/martial/cqb.dm new file mode 100644 index 000000000000..2c1ee7a5d382 --- /dev/null +++ b/modular_darkpack/modules/martial/cqb.dm @@ -0,0 +1,341 @@ +#define SLAM_COMBO "GH" +#define KICK_COMBO "HH" +#define RESTRAIN_COMBO "GG" +#define PRESSURE_COMBO "DG" +#define CONSECUTIVE_COMBO "DDH" + +/datum/martial_art/darkpack/cqb + name = "CQC" + id = MARTIALART_CQB + 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 + +/datum/martial_art/cqc/activate_style(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/deactivate_style(mob/living/remove_from) + UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_LIVING_CHECK_BLOCK)) + return ..() + + +/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.get_stamina_loss() >= 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.adjust_organ_loss(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.adjust_stamina_loss(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.adjust_stamina_loss(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.adjust_stamina_loss(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.adjust_stamina_loss(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, "You try to remember some of the basics of CQC.") + + 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, "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.") + + + +#undef SLAM_COMBO +#undef KICK_COMBO +#undef RESTRAIN_COMBO +#undef PRESSURE_COMBO +#undef CONSECUTIVE_COMBO diff --git a/modular_darkpack/modules/martial/streetboxing.dm b/modular_darkpack/modules/martial/streetboxing.dm new file mode 100644 index 000000000000..e15075aa5959 --- /dev/null +++ b/modular_darkpack/modules/martial/streetboxing.dm @@ -0,0 +1,438 @@ +#define LEFT_RIGHT_COMBO "DH" +#define RIGHT_LEFT_COMBO "HD" +#define LEFT_LEFT_COMBO "HH" +#define RIGHT_RIGHT_COMBO "DD" + +#define STRAIGHT_PUNCH "straight_punch" +#define RIGHT_HOOK "right_hook" +#define LEFT_HOOK "left_hook" +#define UPPERCUT "uppercut" +#define LIGHT_JAB "light_jab" +#define DISCOMBOBULATE "discombobulate" +#define BLIND_JAB "blind_jab" +#define CRAVEN_BLOW "craven_blow" +#define NO_COMBO "" + +/datum/martial_art/darkpack/streetboxing + name = "Boxing" + id = MARTIALART_BOXING + pacifist_style = TRUE + help_verb = /mob/living/proc/boxing_help + /// Boolean on whether we are sportsmanlike in our tussling; TRUE means we have restrictions + var/honorable_boxer = TRUE + /// Default damage type for our boxing. + var/default_damage_type = STAMINA + /// List of traits applied to users of this martial art. + var/list/boxing_traits = list(TRAIT_BOXING_READY) + +/datum/martial_art/boxing/can_teach(mob/living/new_holder) + return ishuman(new_holder) + +/datum/martial_art/boxing/activate_style(mob/living/new_holder) + . = ..() + new_holder.add_traits(boxing_traits, BOXING_TRAIT) + RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block)) + +/datum/martial_art/boxing/deactivate_style(mob/living/remove_from) + remove_from.remove_traits(boxing_traits, BOXING_TRAIT) + UnregisterSignal(remove_from, list(COMSIG_LIVING_CHECK_BLOCK)) + return ..() + +///Unlike most instances of this proc, this is actually called in _proc/tussle() +///Returns a multiplier on our skill damage bonus. +/datum/martial_art/boxing/proc/check_streak(mob/living/attacker, mob/living/defender, obj/item/bodypart/arm/active_arm) + if(check_behind(attacker, defender) && !honorable_boxer) + reset_streak() + return CRAVEN_BLOW + + if(HAS_TRAIT(attacker, TRAIT_DETECTIVES_TASTE) && defender.is_blind()) //In short: discombobulate + reset_streak() + return DISCOMBOBULATE + + if(findtext(streak, LEFT_LEFT_COMBO) && active_arm.body_zone == BODY_ZONE_R_ARM || findtext(streak, RIGHT_RIGHT_COMBO) && active_arm.body_zone == BODY_ZONE_L_ARM) + reset_streak() + if(attacker.is_blind()) + return BLIND_JAB + else + return LIGHT_JAB + + else if(findtext(streak, LEFT_LEFT_COMBO) && active_arm.body_zone == BODY_ZONE_L_ARM || findtext(streak, RIGHT_RIGHT_COMBO) && active_arm.body_zone == BODY_ZONE_R_ARM) + reset_streak() + return STRAIGHT_PUNCH + + if(findtext(streak, LEFT_RIGHT_COMBO) || findtext(streak, RIGHT_LEFT_COMBO)) + reset_streak() + if(active_arm.body_zone == BODY_ZONE_L_ARM) + if(findtext(streak, RIGHT_LEFT_COMBO)) + return LEFT_HOOK + + else if(active_arm.body_zone == BODY_ZONE_R_ARM) + if(findtext(streak, LEFT_RIGHT_COMBO)) + return RIGHT_HOOK + else + return UPPERCUT + + return NO_COMBO + +/// An extra effect on some moves and attacks. +/datum/martial_art/boxing/proc/perform_extra_effect(mob/living/attacker, mob/living/defender) + return + +/datum/martial_art/boxing/disarm_act(mob/living/attacker, mob/living/defender) + if(honor_check(defender)) + add_to_streak("D", defender) + tussle(attacker, defender) + return MARTIAL_ATTACK_SUCCESS + +/datum/martial_art/boxing/grab_act(mob/living/attacker, mob/living/defender) + if(honorable_boxer) + attacker.balloon_alert(attacker, "no grabbing while boxing!") + return MARTIAL_ATTACK_FAIL + return MARTIAL_ATTACK_INVALID //UNLESS YOU'RE EVIL + +/datum/martial_art/boxing/harm_act(mob/living/attacker, mob/living/defender) + if(honor_check(defender)) + add_to_streak("H", defender) + tussle(attacker, defender) + return MARTIAL_ATTACK_SUCCESS + +// Our only boxing move, which occurs on literally all attacks; the tussle. However, quite a lot morphs the results of this proc. Combos, unlike most martial arts attacks, are checked in this proc rather than our standard unarmed procs +/datum/martial_art/boxing/proc/tussle(mob/living/attacker, mob/living/defender) + + if(honorable_boxer) //Being a good sport, you never hit someone on the ground or already knocked down. It shows you're the better person. + if(defender.body_position == LYING_DOWN && defender.get_stamina_loss() >= 100 || defender.IsUnconscious()) //If they're in stamcrit or unconscious, don't bloody punch them + attacker.balloon_alert(attacker, "unsportsmanlike behaviour!") + return FALSE + + var/obj/item/bodypart/arm/active_arm = attacker.get_active_hand() + + //The values between which damage is rolled for punches + var/lower_force = active_arm.unarmed_damage_low + var/upper_force = active_arm.unarmed_damage_high + + //Determines knockout potential and armor penetration (if that matters) + var/base_unarmed_effectiveness = active_arm.unarmed_effectiveness + + //Determines attack sound based on attacker arm + var/attack_sound = active_arm.unarmed_attack_sound + + // Out athletics skill is added as a damage bonus + var/athletics_skill = attacker.st_get_stat(STAT_BRAWL) // DARKPACK EDIT CHANGE - STORYTELLER_STATS + + // If true, grants experience for punching; we only gain experience if we punch another boxer. + var/grant_experience = FALSE + + // What type of damage does our kind of boxing do? Defaults to STAMINA for normal boxing, unless you're performing EVIL BOXING. Subtypes use different damage types. + var/damage_type = honorable_boxer ? default_damage_type : attacker.get_attack_type() + + attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) + + // Our potential wound bonus on a punch. Only applies if we're dishonorable. Otherwise, we can't wound. + var/possible_wound_bonus = honorable_boxer ? 0 : CANT_WOUND + + // Determines damage dealt on a punch. Against a boxing defender, we apply our skill bonus. + var/damage = rand(lower_force, upper_force) + + // Attack verbs for our visible chat messages. + var/current_atk_verb = "punches" + var/current_atk_verbed = "punched" + + if(defender.check_block(attacker, damage, "[attacker]'s punch", UNARMED_ATTACK)) + return FALSE + + // Similar to a normal punch, should we have a value of 0 for our lower force, we simply miss outright. + if(!lower_force) + playsound(defender.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1) + defender.visible_message(span_warning("[attacker]'s punch misses [defender]!"), \ + span_danger("You avoid [attacker]'s punch!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, attacker) + to_chat(attacker, span_warning("Your punch misses [defender]!")) + log_combat(attacker, defender, "attempted to hit", "punch (boxing) ") + return FALSE + + var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected)) + + if(honor_check(defender)) + var/strength_bonus = HAS_TRAIT(attacker, TRAIT_STRENGTH) ? 2 : 0 //Investing into genetic strength improvements makes you a better boxer + + var/obj/item/organ/cyberimp/chest/spine/potential_spine = attacker.get_organ_slot(ORGAN_SLOT_SPINE) //Getting a cyberspine also pushes you further than just mere meat + if(istype(potential_spine)) + strength_bonus *= potential_spine.strength_bonus + + var/streak_augmentation = check_streak(attacker, defender, active_arm) + + var/combo_multiplier = 0 + + switch(streak_augmentation) + if(STRAIGHT_PUNCH) + current_atk_verb = "straight punches" + current_atk_verbed = "straight punched" + combo_multiplier = 1 + + if(LIGHT_JAB) + current_atk_verb = "light jabs" + current_atk_verbed = "light jabbed" + combo_multiplier = 1 + + if(LEFT_HOOK) + current_atk_verb = "left hooks" + current_atk_verbed = "left hooked" + combo_multiplier = 1.5 + attacker.changeNext_move(CLICK_CD_MELEE * 1.5) + + if(RIGHT_HOOK) + current_atk_verb = "right hooks" + current_atk_verbed = "right hooked" + combo_multiplier = 1.5 + attacker.changeNext_move(CLICK_CD_MELEE * 1.5) + + if(UPPERCUT) + current_atk_verb = "uppercuts" + current_atk_verbed = "uppercutted" + base_unarmed_effectiveness *= 1.5 + combo_multiplier = 1 + attacker.changeNext_move(CLICK_CD_MELEE * 1.5) + + if(DISCOMBOBULATE) + current_atk_verb = "discombobulates" + current_atk_verbed = "discombobulated" + affecting = defender.get_bodypart(defender.get_random_valid_zone(BODY_ZONE_HEAD)) + defender.adjust_confusion_up_to(20 SECONDS, 50 SECONDS) + defender.adjust_dizzy_up_to(20 SECONDS, 50 SECONDS) + combo_multiplier = 1 + + if(BLIND_JAB) + current_atk_verb = "blind jabs" + current_atk_verbed = "blind jabbed" + combo_multiplier = 0.5 + attacker.changeNext_move(CLICK_CD_MELEE * 1.5) + + if(CRAVEN_BLOW) + current_atk_verb = "sucker punches" + current_atk_verbed = "sucker punch" + possible_wound_bonus = damage + combo_multiplier = 2 + possible_wound_bonus *= 1.5 + affecting = defender.get_bodypart(defender.get_random_valid_zone(BODY_ZONE_HEAD)) + defender.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) //why yes, this could result in them being knocked out in one. + + damage += round((athletics_skill + strength_bonus) * combo_multiplier, 1) + + if(combo_multiplier >= 1) + perform_extra_effect(attacker, defender) + + if(defender.stat <= HARD_CRIT) // Do not grant experience against dead targets + grant_experience = TRUE + + var/armor_block = defender.run_armor_check(affecting, MELEE, armour_penetration = base_unarmed_effectiveness) + + playsound(defender, attack_sound, 25, TRUE, -1) + + defender.visible_message( + span_danger("[attacker] [current_atk_verb] [defender]!"), + span_userdanger("You're [current_atk_verbed] by [attacker]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + COMBAT_MESSAGE_RANGE, + attacker, + ) + + to_chat(attacker, span_danger("You [current_atk_verbed] [defender]!")) + + // Determines the total amount of experience earned per punch + var/experience_earned = round(damage/4, 1) + + defender.apply_damage(damage, damage_type, affecting, armor_block, wound_bonus = possible_wound_bonus) + + log_combat(attacker, defender, "punched (boxing) ") + + if(defender.stat == DEAD || !honor_check(defender)) //early returning here so we don't worry about knockout probs or experience gain + return TRUE + + if(grant_experience) + skill_experience_adjustment(attacker, defender, (damage/lower_force)) + + //Determine our attackers athletics level as a knockout probability bonus + var/attacker_athletics_skill = (attacker.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) + base_unarmed_effectiveness) + + // Defender boxing skill and armor block are used as a defense here. This has already factored in base_unarmed_effectiveness from the attacker + var/defender_athletics_skill = clamp(defender.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER), 0, 100) + + //Determine our final probability, using a clamp to stop any prob() weirdness. + var/final_knockout_probability = clamp(round(attacker_athletics_skill - defender_athletics_skill, 1), 0 , 100) + + if(!prob(final_knockout_probability)) + return TRUE + + crit_effect(attacker, defender, armor_block, damage_type, damage) + + experience_earned *= 2 //Double our experience gain on a crit hit + + playsound(defender, 'sound/effects/coin2.ogg', 40, TRUE) + new /obj/effect/temp_visual/crit(get_turf(defender)) + skill_experience_adjustment(attacker, defender, experience_earned) //double experience for a successful crit + + return TRUE + +/// Our crit effect. For normal boxing, this applies a stagger, then applies a knockout if they're staggered. Other types of boxing apply different kinds of effects. +/datum/martial_art/boxing/proc/crit_effect(mob/living/attacker, mob/living/defender, armor_block = 0, damage_type = STAMINA, damage = 0) + if(defender.get_timed_status_effect_duration(/datum/status_effect/staggered)) + 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.SetSleeping(10 SECONDS) + log_combat(attacker, defender, "knocked out (boxing) ") + else + defender.visible_message( + span_danger("[attacker] staggers [defender] with a haymaker!"), + span_userdanger("You're nearly knocked off your feet by [attacker]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + COMBAT_MESSAGE_RANGE, + attacker, + ) + defender.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) + to_chat(attacker, span_danger("You stagger [defender] with a haymaker!")) + log_combat(attacker, defender, "staggered (boxing) ") + + if(attacker.pulling == defender && attacker.grab_state >= GRAB_AGGRESSIVE) // dubious a normal boxer will be in a state where this happens, buuuut. + var/atom/throw_target = get_edge_target_turf(defender, attacker.dir) + defender.throw_at(throw_target, 2, 2, attacker) + +/// Returns whether whoever is checked by this proc is complying with the rules of boxing. The boxer cannot block non-boxers, and cannot apply their scariest moves against non-boxers. +/datum/martial_art/boxing/proc/honor_check(mob/living/possible_boxer) + if(!honorable_boxer) + return TRUE //You scoundrel!! + + if(!HAS_TRAIT(possible_boxer, TRAIT_BOXING_READY)) + return FALSE + + return TRUE + +/// Handles our instances of experience gain while boxing. It also applies the exercised status effect. +/datum/martial_art/boxing/proc/skill_experience_adjustment(mob/living/boxer, mob/living/defender, experience_value) + //Boxing in heavier gravity gives you more experience + var/gravity_modifier = boxer.has_gravity() > STANDARD_GRAVITY ? 1 : 2 + + //You gotta sleep before you get any experience! + boxer.mind?.adjust_experience(/datum/skill/athletics, round(experience_value / gravity_modifier, 1)) + boxer.apply_status_effect(/datum/status_effect/exercised) + +/// Handles our blocking signals, similar to hit_reaction() on items. Only blocks while the boxer is in throw mode. +/datum/martial_art/boxing/proc/check_block(mob/living/boxer, atom/movable/hitby, damage, attack_text, attack_type, ...) + SIGNAL_HANDLER + + if(!can_use(boxer) || !boxer.throw_mode || INCAPACITATED_IGNORING(boxer, INCAPABLE_GRAB)) + return NONE + + if(attack_type != UNARMED_ATTACK) + return NONE + + //Determines unarmed defense against boxers using our current active arm. + var/obj/item/bodypart/arm/active_arm = boxer.get_active_hand() + var/base_unarmed_effectiveness = active_arm.unarmed_effectiveness + + // Out athletics skill is added to our block potential + var/athletics_skill_rands = boxer.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) + + var/block_chance = base_unarmed_effectiveness + athletics_skill_rands + + var/block_text = pick("block", "evade") + + var/mob/living/attacker = GET_ASSAILANT(hitby) + + if(!honor_check(attacker)) + return NONE + + var/experience_earned = round(damage/4, 1) + + if(!damage) + experience_earned = 2 + + // WE reward experience for getting punched while boxing + skill_experience_adjustment(boxer, attacker, experience_earned) //just getting hit a bunch doesn't net you much experience however + + if(!prob(block_chance)) + return NONE + + if(istype(attacker) && boxer.Adjacent(attacker)) + attacker.apply_damage(10, default_damage_type) + boxer.apply_damage(5, STAMINA) + perform_extra_effect(boxer, attacker) + + boxer.visible_message( + span_danger("[boxer] [block_text]s [attack_text]!"), + span_userdanger("You [block_text] [attack_text]!"), + ) + if(block_text == "evade") + playsound(boxer.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1) + + return SUCCESSFUL_BLOCK + +/datum/martial_art/boxing/can_use(mob/living/martial_artist) + if(!ishuman(martial_artist)) + return FALSE + return ..() + +/mob/living/proc/boxing_help() + set name = "Focus on your Form" + set desc = "You focus on how to make the most of your boxing form." + set category = "Boxing" + to_chat(usr, "You focus on your form, visualizing how best to throw a punch.") + + to_chat(usr, "What moves you perform depend on what mouse buttons you click, and whether the last button clicked matches which hand you have selected when you throw the last punch.") + + to_chat(usr, "[span_notice("Straight Punch")]: Left Left/Right Right with the matching hand. Regular damage.") + to_chat(usr, "[span_notice("Jab")]: Left Left/Right Right with the opposite hand. Regular damage. If you're blind, you'll make a blind jab instead.") + to_chat(usr, "[span_notice("Left/Right Hook")]: Left Right/Right Left with the matching hand. Does extra damage, but slows your next hit.") + to_chat(usr, "[span_notice("Uppercut")]: Left Right/Right Left with the opposite hand. Has a higher probability to knock out the target, but slows your next hit.") + + to_chat(usr, "While in Throw Mode, you can block incoming punches and return a bit of damage back to an attacker. Blocking attacks this way causes you to lose some stamina damage.") + +// Boxing Variants! + +/// Evil Boxing; for sick, evil scoundrels. Has no honor, making it more lethal (therefore unable to be used by pacifists). +/// Grants Strength and Stimmed to speed up any experience gain. + +/datum/martial_art/boxing/evil + name = "Evil Boxing" + id = MARTIALART_EVIL_BOXING + pacifist_style = FALSE + help_verb = /mob/living/proc/evil_boxing_help + honorable_boxer = FALSE + boxing_traits = list(TRAIT_BOXING_READY, TRAIT_STRENGTH, TRAIT_STIMMED) + +/mob/living/proc/evil_boxing_help() + set name = "Focus on Brawling" + set desc = "You ponder how best to rearrange the faces of your enemies." + set category = "Evil Boxing" + to_chat(usr, "You contemplate on the violence ahead, visualizing how best to throw a punch.") + + to_chat(usr, "What moves you perform depend on what mouse buttons you click, and whether the last button clicked matches which hand you have selected when you throw the last punch.") + + to_chat(usr, "[span_notice("Straight Punch")]: Left Left/Right Right with the matching hand. Regular damage.") + to_chat(usr, "[span_notice("Jab")]: Left Left/Right Right with the opposite hand. Regular damage. If you're blind, you'll make a blind jab instead.") + to_chat(usr, "[span_notice("Left/Right Hook")]: Left Right/Right Left with the matching hand. Does extra damage, but slows your next hit.") + to_chat(usr, "[span_notice("Uppercut")]: Left Right/Right Left with the opposite hand. Has a higher probability to knock out the target, but slows your next hit.") + to_chat(usr, "[span_notice("Sucker Punch")]: Any combination done to a vulnerable target becomes a sucker punch. This could knock them out in one!.") + + to_chat(usr, "While in Throw Mode, you can block incoming punches and return a bit of damage back to an attacker. Blocking attacks this way causes you to lose some stamina damage.") + + +#undef LEFT_RIGHT_COMBO +#undef RIGHT_LEFT_COMBO +#undef LEFT_LEFT_COMBO +#undef RIGHT_RIGHT_COMBO + +#undef STRAIGHT_PUNCH +#undef RIGHT_HOOK +#undef LEFT_HOOK +#undef UPPERCUT +#undef LIGHT_JAB +#undef DISCOMBOBULATE +#undef BLIND_JAB +#undef CRAVEN_BLOW +#undef NO_COMBO diff --git a/modular_darkpack/modules/martial/swords.dm b/modular_darkpack/modules/martial/swords.dm new file mode 100644 index 000000000000..aa5037ae0eea --- /dev/null +++ b/modular_darkpack/modules/martial/swords.dm @@ -0,0 +1,165 @@ +#define ATTACK_STRIKE "Hilt Strike" +#define ATTACK_SLICE "Wide Slice" +#define ATTACK_DASH "Dash Attack" +#define ATTACK_CUT "Tendon Cut" +#define ATTACK_CLOAK "Dark Cloak" +#define ATTACK_SHATTER "Shatter" + +/obj/item/organ/cyberimp/arm/toolkit/shard + name = "dark spoon shard" + desc = "An eerie metal shard surrounded by dark energies...of soup drinking. You probably don't think you should have been able to find this." + icon = 'icons/obj/mining_zones/artefacts.dmi' + icon_state = "cursed_katana_organ" + organ_flags = ORGAN_ORGANIC | ORGAN_FROZEN | ORGAN_UNREMOVABLE + items_to_create = list(/obj/item/kitchen/spoon) + extend_sound = 'sound/items/unsheath.ogg' + retract_sound = 'sound/items/sheath.ogg' + +/obj/item/organ/cyberimp/arm/toolkit/shard/attack_self(mob/user, modifiers) + . = ..() + to_chat(user, span_userdanger("The mass goes up your arm and goes inside it!")) + playsound(user, 'sound/effects/magic/demon_consume.ogg', 50, TRUE) + var/index = user.get_held_index_of_item(src) + swap_zone(IS_LEFT_INDEX(index) ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM) + user.temporarilyRemoveItemFromInventory(src, TRUE) + Insert(user) + +/obj/item/organ/cyberimp/arm/toolkit/shard/screwdriver_act(mob/living/user, obj/item/screwtool) + return + +/obj/item/organ/cyberimp/arm/toolkit/shard/katana + name = "dark shard" + desc = "An eerie metal shard surrounded by dark energies." + items_to_create = list(/obj/item/cursed_katana) + +/obj/item/organ/cyberimp/arm/toolkit/shard/katana/Retract() + var/obj/item/cursed_katana/katana = active_item + if(!katana || katana.shattered) + return FALSE + if(!katana.drew_blood) + to_chat(owner, span_userdanger("[katana] lashes out at you in hunger!")) + playsound(owner, 'sound/effects/magic/demon_attack1.ogg', 50, TRUE) + owner.apply_damage(25, BRUTE, hand, wound_bonus = 10, sharpness = SHARP_EDGED) + katana.drew_blood = FALSE + katana.wash(CLEAN_TYPE_BLOOD) + return ..() + +/obj/item/cursed_katana + name = "testing katana" + desc = "It's a regular Katana.. like one of those japanese animes." + icon = 'icons/obj/mining_zones/artefacts.dmi' + icon_state = "cursed_katana" + icon_angle = -45 + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + force = 15 + armour_penetration = 30 + block_chance = 30 + block_sound = 'sound/items/weapons/parry.ogg' + sharpness = SHARP_EDGED + w_class = WEIGHT_CLASS_HUGE + attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") + hitsound = 'sound/items/weapons/bladeslice.ogg' + resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | FREEZE_PROOF + var/datum/storyteller_roll/melee_dexterity/dex_roll + var/datum/storyteller_roll/melee_strength/strength_roll + var/static/list/combo_list = list( + ATTACK_STRIKE = list(COMBO_STEPS = list(LEFT_ATTACK, LEFT_ATTACK, RIGHT_ATTACK), COMBO_PROC = PROC_REF(strike)), + ATTACK_SLICE = list(COMBO_STEPS = list(RIGHT_ATTACK, LEFT_ATTACK, LEFT_ATTACK), COMBO_PROC = PROC_REF(slice)), + ATTACK_CUT = list(COMBO_STEPS = list(RIGHT_ATTACK, RIGHT_ATTACK, LEFT_ATTACK), COMBO_PROC = PROC_REF(cut)), + ) + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/cursed_katana/Initialize(mapload) + . = ..() + alt_continuous = string_list(alt_continuous) + alt_simple = string_list(alt_simple) + AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple) + AddComponent( \ + /datum/component/combo_attacks, \ + combos = combo_list, \ + max_combo_length = 4, \ + examine_message = span_notice("This seems to be a skilled weapon... perhaps I could use my experience?"), \ + reset_message = "you return to neutral stance", \ + can_attack_callback = CALLBACK(src, PROC_REF(can_combo_attack)) \ + ) + +/obj/item/cursed_katana/examine(mob/user) + . = ..() + . += drew_blood ? span_nicegreen("It's sated... for now.") : span_danger("It will not be sated until it tastes blood.") + +/obj/item/cursed_katana/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) + var/datum/storyteller_roll/melee_block/parry_roll = new() + var/puller_result = pulled_roll.st_roll(user, src) + final_block_chance = puller_result * 10 //I dont see what can go wrong with allowing a theoretical 100% parry chance for an individual hit + return ..() + +/obj/item/cursed_katana/proc/can_combo_attack(mob/user, mob/living/target) //prevents the unworthy from properly using blades + return target.stat != DEAD && target != user && (user.st_get_stat(STAT_MELEE) >= 4) + +/obj/item/cursed_katana/proc/strike(mob/living/target, mob/user) + user.visible_message(span_warning("[user] strikes [target] with [src]'s hilt!"), + span_notice("You hilt strike [target]!")) + to_chat(target, span_userdanger("You've been struck by [user]!")) + playsound(src, 'sound/items/weapons/genhit3.ogg', 50, TRUE) + RegisterSignal(target, COMSIG_MOVABLE_IMPACT, PROC_REF(strike_throw_impact)) + var/atom/throw_target = get_edge_target_turf(target, user.dir) + target.throw_at(throw_target, 5, 3, user, FALSE, gentle = TRUE) + target.apply_damage(damage = 17, exposed_wound_bonus = 10) + to_chat(target, span_userdanger("You've been struck by [user]!")) + user.do_attack_animation(target, ATTACK_EFFECT_PUNCH) + +/obj/item/cursed_katana/proc/strike_throw_impact(mob/living/source, atom/hit_atom, datum/thrownthing/thrownthing) + SIGNAL_HANDLER + + UnregisterSignal(source, COMSIG_MOVABLE_IMPACT) + if(isclosedturf(hit_atom)) + source.apply_damage(damage = 5) + if(ishostile(source)) + var/mob/living/simple_animal/hostile/target = source + target.ranged_cooldown += 5 SECONDS + else if(iscarbon(source)) + var/mob/living/carbon/target = source + target.set_confusion_if_lower(8 SECONDS) + return NONE + +/obj/item/cursed_katana/proc/slice(mob/living/target, mob/user) + user.visible_message(span_warning("[user] does a wide slice!"), + span_notice("You do a wide slice!")) + playsound(src, 'sound/items/weapons/bladeslice.ogg', 50, TRUE) + user.do_item_attack_animation(target, used_item = src, animation_type = ATTACK_ANIMATION_SLASH) + var/turf/user_turf = get_turf(user) + var/dir_to_target = get_dir(user_turf, get_turf(target)) + var/static/list/cursed_katana_slice_angles = list(0, -45, 45, -90, 90) //so that the animation animates towards the target clicked and not towards a side target + for(var/iteration in cursed_katana_slice_angles) + var/turf/turf = get_step(user_turf, turn(dir_to_target, iteration)) + user.do_attack_animation(turf, ATTACK_EFFECT_SLASH) + for(var/mob/living/additional_target in turf) + if(user.Adjacent(additional_target) && additional_target.density) + additional_target.apply_damage(damage = 15, sharpness = SHARP_EDGED, exposed_wound_bonus = 10) + to_chat(additional_target, span_userdanger("You've been sliced by [user]!")) + target.apply_damage(damage = 5, sharpness = SHARP_EDGED, wound_bonus = 10) + +/obj/item/cursed_katana/proc/cut(mob/living/target, mob/user) + user.visible_message(span_warning("[user] cuts [target]'s tendons!"), + span_notice("You tendon cut [target]!")) + to_chat(target, span_userdanger("Your tendons have been cut by [user]!")) + user.do_item_attack_animation(target, used_item = src, animation_type = ATTACK_ANIMATION_SLASH) + target.apply_damage(damage = 15, sharpness = SHARP_EDGED, wound_bonus = 15) + user.do_attack_animation(target, ATTACK_EFFECT_DISARM) + playsound(src, 'sound/items/weapons/rapierhit.ogg', 50, TRUE) + var/datum/status_effect/stacking/saw_bleed/bloodletting/status = target.has_status_effect(/datum/status_effect/stacking/saw_bleed/bloodletting) + if(!status) + target.apply_status_effect(/datum/status_effect/stacking/saw_bleed/bloodletting, 6) + else + status.add_stacks(6) + + +#undef ATTACK_STRIKE +#undef ATTACK_SLICE +#undef ATTACK_DASH +#undef ATTACK_CUT +#undef ATTACK_CLOAK +#undef ATTACK_SHATTER diff --git a/modular_darkpack/modules/storyteller_dice/code/roll_subtypes.dm b/modular_darkpack/modules/storyteller_dice/code/roll_subtypes.dm index da9b36d83d51..41d0aa0a5b07 100644 --- a/modular_darkpack/modules/storyteller_dice/code/roll_subtypes.dm +++ b/modular_darkpack/modules/storyteller_dice/code/roll_subtypes.dm @@ -44,6 +44,33 @@ reroll_cooldown = 1 TURNS numerical = TRUE +//Combat Feats +/datum/storyteller_roll/melee_block + bumper_text = "parrying" + applicable_stats = list(STAT_DEXTERITY, STAT_MELEE) + numerical = TRUE + +/datum/storyteller_roll/melee_dexterity + bumper_text = "piercing" + applicable_stats = list(STAT_DEXTERITY, STAT_MELEE) + +/datum/storyteller_roll/melee_strength + bumper_text = "slashing" + applicable_stats = list(STAT_STAT_STRENGTH, STAT_MELEE) + +/datum/storyteller_roll/brawl_block + bumper_text = "blocking" + applicable_stats = list(STAT_DEXTERITY, STAT_MELEE) + numerical = TRUE + +/datum/storyteller_roll/brawl_dexterity + bumper_text = "striking" + applicable_stats = list(STAT_DEXTERITY, STAT_BRAWL) + +/datum/storyteller_roll/brawl_strength + bumper_text = "smashing" + applicable_stats = list(STAT_STRENGTH, STAT_BRAWL) + // Mental Feats /datum/storyteller_roll/investigation bumper_text = "investigation" diff --git a/tgstation.dme b/tgstation.dme index b2b7794628a9..50c81ad32aa4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7261,6 +7261,7 @@ #include "modular_darkpack\modules\looc\code\verbs.dm" #include "modular_darkpack\modules\mannequin\code\mannequin_subtypes.dm" #include "modular_darkpack\modules\mapping_helpers\code\viewport_helper.dm" +#include "modular_darkpack\modules\martial\swords.dm" #include "modular_darkpack\modules\masquerade\code\blood_hunt_skull.dm" #include "modular_darkpack\modules\masquerade\code\human.dm" #include "modular_darkpack\modules\masquerade\code\logging_machine.dm" From 51838f32e26918ab5f3ed40cb953a879afd38e70 Mon Sep 17 00:00:00 2001 From: SELFHELL <99771731+SELFHELL@users.noreply.github.com> Date: Thu, 19 Mar 2026 17:33:26 -0500 Subject: [PATCH 2/9] More things --- code/datums/components/butchering.dm | 2 +- code/datums/martial/sleeping_carp.dm | 4 + code/modules/surgery/bodyparts/head.dm | 4 +- modular_darkpack/modules/martial/cqb.dm | 11 +++ modular_darkpack/modules/martial/swords.dm | 75 +++---------------- .../discipline/temporis/temporis_effects.dm | 4 + .../storyteller_dice/code/roll_subtypes.dm | 2 +- 7 files changed, 35 insertions(+), 67 deletions(-) diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 71621f623d29..067838433f74 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -54,7 +54,7 @@ if (!source.get_sharpness() && !can_be_blunt) return - if (!user.combat_mode) + if (user.combat_mode) //DARKPACK EDIT CHANGE- quality of life for melee weapons, doesnt make sense you couldnt do combos in combat mode return // Can we butcher it? diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index b1cb83c88467..51295e54ed8b 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -262,6 +262,10 @@ span_userdanger("You deflect [hitting_projectile]!"), ) playsound(carp_user, SFX_BULLET_MISS, 75, TRUE) + animate(carp_user, alpha = 0, time = 0.1 SECONDS) + new /obj/effect/temporis/weskar(carp_user.loc, carp_user) + sleep(0.1 SECONDS) + animate(carp_user, alpha = 225, time = 0.1 SECONDS) hitting_projectile.firer = carp_user hitting_projectile.set_angle(rand(0, 360))//SHING return COMPONENT_BULLET_PIERCED diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 73a526361f0d..1eed059d86a0 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -96,7 +96,7 @@ show_eyeless = FALSE /// Can this head be dismembered normally? - can_dismember = FALSE + can_dismember = TRUE //DARKPACK EDIT- For QOL it's much easier to leave it enabled by default, undismemberable heads are silly TGcode stuff /obj/item/bodypart/head/Initialize(mapload) . = ..() @@ -164,7 +164,7 @@ if (!can_dismember) return FALSE - if(!HAS_TRAIT(owner, TRAIT_CURSED) && owner.stat < HARD_CRIT) + if (owner.stat < HARD_CRIT) return FALSE return ..() diff --git a/modular_darkpack/modules/martial/cqb.dm b/modular_darkpack/modules/martial/cqb.dm index 2c1ee7a5d382..66cbe60dbe43 100644 --- a/modular_darkpack/modules/martial/cqb.dm +++ b/modular_darkpack/modules/martial/cqb.dm @@ -17,6 +17,17 @@ . = ..() RegisterSignal(new_holder, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block)) + if (iscarbon(owner)) + var/mob/living/carbon/carbon_owner = owner + for (var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts) + if (!istype(limb, /obj/item/bodypart/arm) && !istype(limb, /obj/item/bodypart/leg)) + continue + + LAZYADD(affected_bodyparts, limb) + + limb.unarmed_damage_low += 5 + limb.unarmed_damage_high += 5 + limb.unarmed_attack_sound = 'sound/items/weapons/cqchit1.ogg' /datum/martial_art/cqc/deactivate_style(mob/living/remove_from) UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_LIVING_CHECK_BLOCK)) diff --git a/modular_darkpack/modules/martial/swords.dm b/modular_darkpack/modules/martial/swords.dm index aa5037ae0eea..36341b1ff4e6 100644 --- a/modular_darkpack/modules/martial/swords.dm +++ b/modular_darkpack/modules/martial/swords.dm @@ -1,50 +1,8 @@ #define ATTACK_STRIKE "Hilt Strike" #define ATTACK_SLICE "Wide Slice" -#define ATTACK_DASH "Dash Attack" #define ATTACK_CUT "Tendon Cut" -#define ATTACK_CLOAK "Dark Cloak" -#define ATTACK_SHATTER "Shatter" -/obj/item/organ/cyberimp/arm/toolkit/shard - name = "dark spoon shard" - desc = "An eerie metal shard surrounded by dark energies...of soup drinking. You probably don't think you should have been able to find this." - icon = 'icons/obj/mining_zones/artefacts.dmi' - icon_state = "cursed_katana_organ" - organ_flags = ORGAN_ORGANIC | ORGAN_FROZEN | ORGAN_UNREMOVABLE - items_to_create = list(/obj/item/kitchen/spoon) - extend_sound = 'sound/items/unsheath.ogg' - retract_sound = 'sound/items/sheath.ogg' - -/obj/item/organ/cyberimp/arm/toolkit/shard/attack_self(mob/user, modifiers) - . = ..() - to_chat(user, span_userdanger("The mass goes up your arm and goes inside it!")) - playsound(user, 'sound/effects/magic/demon_consume.ogg', 50, TRUE) - var/index = user.get_held_index_of_item(src) - swap_zone(IS_LEFT_INDEX(index) ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM) - user.temporarilyRemoveItemFromInventory(src, TRUE) - Insert(user) - -/obj/item/organ/cyberimp/arm/toolkit/shard/screwdriver_act(mob/living/user, obj/item/screwtool) - return - -/obj/item/organ/cyberimp/arm/toolkit/shard/katana - name = "dark shard" - desc = "An eerie metal shard surrounded by dark energies." - items_to_create = list(/obj/item/cursed_katana) - -/obj/item/organ/cyberimp/arm/toolkit/shard/katana/Retract() - var/obj/item/cursed_katana/katana = active_item - if(!katana || katana.shattered) - return FALSE - if(!katana.drew_blood) - to_chat(owner, span_userdanger("[katana] lashes out at you in hunger!")) - playsound(owner, 'sound/effects/magic/demon_attack1.ogg', 50, TRUE) - owner.apply_damage(25, BRUTE, hand, wound_bonus = 10, sharpness = SHARP_EDGED) - katana.drew_blood = FALSE - katana.wash(CLEAN_TYPE_BLOOD) - return ..() - -/obj/item/cursed_katana +/obj/item/testing_katana name = "testing katana" desc = "It's a regular Katana.. like one of those japanese animes." icon = 'icons/obj/mining_zones/artefacts.dmi' @@ -62,8 +20,6 @@ attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut") hitsound = 'sound/items/weapons/bladeslice.ogg' resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | FREEZE_PROOF - var/datum/storyteller_roll/melee_dexterity/dex_roll - var/datum/storyteller_roll/melee_strength/strength_roll var/static/list/combo_list = list( ATTACK_STRIKE = list(COMBO_STEPS = list(LEFT_ATTACK, LEFT_ATTACK, RIGHT_ATTACK), COMBO_PROC = PROC_REF(strike)), ATTACK_SLICE = list(COMBO_STEPS = list(RIGHT_ATTACK, LEFT_ATTACK, LEFT_ATTACK), COMBO_PROC = PROC_REF(slice)), @@ -72,7 +28,7 @@ var/list/alt_continuous = list("stabs", "pierces", "impales") var/list/alt_simple = list("stab", "pierce", "impale") -/obj/item/cursed_katana/Initialize(mapload) +/obj/item/testing_katana/Initialize(mapload) . = ..() alt_continuous = string_list(alt_continuous) alt_simple = string_list(alt_simple) @@ -86,20 +42,16 @@ can_attack_callback = CALLBACK(src, PROC_REF(can_combo_attack)) \ ) -/obj/item/cursed_katana/examine(mob/user) - . = ..() - . += drew_blood ? span_nicegreen("It's sated... for now.") : span_danger("It will not be sated until it tastes blood.") - -/obj/item/cursed_katana/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) +/obj/item/testing_katana/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) var/datum/storyteller_roll/melee_block/parry_roll = new() - var/puller_result = pulled_roll.st_roll(user, src) - final_block_chance = puller_result * 10 //I dont see what can go wrong with allowing a theoretical 100% parry chance for an individual hit + var/puller_result = parry_roll.st_roll(owner, src) + final_block_chance = puller_result * 5 //I dont see what can go wrong with allowing a theoretical 100% parry chance for an individual hit. There was infact something wrong return ..() -/obj/item/cursed_katana/proc/can_combo_attack(mob/user, mob/living/target) //prevents the unworthy from properly using blades +/obj/item/testing_katana/proc/can_combo_attack(mob/living/carbon/user, mob/living/target) //prevents the unworthy from properly using blades return target.stat != DEAD && target != user && (user.st_get_stat(STAT_MELEE) >= 4) -/obj/item/cursed_katana/proc/strike(mob/living/target, mob/user) +/obj/item/testing_katana/proc/strike(mob/living/target, mob/user) user.visible_message(span_warning("[user] strikes [target] with [src]'s hilt!"), span_notice("You hilt strike [target]!")) to_chat(target, span_userdanger("You've been struck by [user]!")) @@ -111,7 +63,7 @@ to_chat(target, span_userdanger("You've been struck by [user]!")) user.do_attack_animation(target, ATTACK_EFFECT_PUNCH) -/obj/item/cursed_katana/proc/strike_throw_impact(mob/living/source, atom/hit_atom, datum/thrownthing/thrownthing) +/obj/item/testing_katana/proc/strike_throw_impact(mob/living/source, atom/hit_atom, datum/thrownthing/thrownthing) SIGNAL_HANDLER UnregisterSignal(source, COMSIG_MOVABLE_IMPACT) @@ -125,15 +77,15 @@ target.set_confusion_if_lower(8 SECONDS) return NONE -/obj/item/cursed_katana/proc/slice(mob/living/target, mob/user) +/obj/item/testing_katana/proc/slice(mob/living/target, mob/user) user.visible_message(span_warning("[user] does a wide slice!"), span_notice("You do a wide slice!")) playsound(src, 'sound/items/weapons/bladeslice.ogg', 50, TRUE) user.do_item_attack_animation(target, used_item = src, animation_type = ATTACK_ANIMATION_SLASH) var/turf/user_turf = get_turf(user) var/dir_to_target = get_dir(user_turf, get_turf(target)) - var/static/list/cursed_katana_slice_angles = list(0, -45, 45, -90, 90) //so that the animation animates towards the target clicked and not towards a side target - for(var/iteration in cursed_katana_slice_angles) + var/static/list/testing_katana_slice_angles = list(0, -45, 45, -90, 90) //so that the animation animates towards the target clicked and not towards a side target + for(var/iteration in testing_katana_slice_angles) var/turf/turf = get_step(user_turf, turn(dir_to_target, iteration)) user.do_attack_animation(turf, ATTACK_EFFECT_SLASH) for(var/mob/living/additional_target in turf) @@ -142,7 +94,7 @@ to_chat(additional_target, span_userdanger("You've been sliced by [user]!")) target.apply_damage(damage = 5, sharpness = SHARP_EDGED, wound_bonus = 10) -/obj/item/cursed_katana/proc/cut(mob/living/target, mob/user) +/obj/item/testing_katana/proc/cut(mob/living/target, mob/user) user.visible_message(span_warning("[user] cuts [target]'s tendons!"), span_notice("You tendon cut [target]!")) to_chat(target, span_userdanger("Your tendons have been cut by [user]!")) @@ -159,7 +111,4 @@ #undef ATTACK_STRIKE #undef ATTACK_SLICE -#undef ATTACK_DASH #undef ATTACK_CUT -#undef ATTACK_CLOAK -#undef ATTACK_SHATTER diff --git a/modular_darkpack/modules/powers/code/discipline/temporis/temporis_effects.dm b/modular_darkpack/modules/powers/code/discipline/temporis/temporis_effects.dm index d1be6f5b3570..401e9716f752 100644 --- a/modular_darkpack/modules/powers/code/discipline/temporis/temporis_effects.dm +++ b/modular_darkpack/modules/powers/code/discipline/temporis/temporis_effects.dm @@ -22,3 +22,7 @@ /obj/effect/temporis/clothos_gift effect_alpha = 155 effect_fadeout = 0.5 SECONDS + +/obj/effect/temporis/weskar + effect_alpha = 155 + effect_fadeout = 0.3 SECONDS diff --git a/modular_darkpack/modules/storyteller_dice/code/roll_subtypes.dm b/modular_darkpack/modules/storyteller_dice/code/roll_subtypes.dm index 41d0aa0a5b07..e401025e8a4f 100644 --- a/modular_darkpack/modules/storyteller_dice/code/roll_subtypes.dm +++ b/modular_darkpack/modules/storyteller_dice/code/roll_subtypes.dm @@ -56,7 +56,7 @@ /datum/storyteller_roll/melee_strength bumper_text = "slashing" - applicable_stats = list(STAT_STAT_STRENGTH, STAT_MELEE) + applicable_stats = list(STAT_STRENGTH, STAT_MELEE) /datum/storyteller_roll/brawl_block bumper_text = "blocking" From 37aac03f64884ea0c71dd0bd6a712ad7a3b7542c Mon Sep 17 00:00:00 2001 From: SELFHELL <99771731+SELFHELL@users.noreply.github.com> Date: Fri, 20 Mar 2026 19:24:22 -0500 Subject: [PATCH 3/9] Kung-Fu Version 1 + Dodge Animation Function --- code/datums/martial/sleeping_carp.dm | 4 - modular_darkpack/modules/martial/cqb.dm | 5 + modular_darkpack/modules/martial/defines.dm | 1 + modular_darkpack/modules/martial/kungfu.dm | 243 ++++++++++++++++++++ tgstation.dme | 2 + 5 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 modular_darkpack/modules/martial/defines.dm create mode 100644 modular_darkpack/modules/martial/kungfu.dm diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 51295e54ed8b..b1cb83c88467 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -262,10 +262,6 @@ span_userdanger("You deflect [hitting_projectile]!"), ) playsound(carp_user, SFX_BULLET_MISS, 75, TRUE) - animate(carp_user, alpha = 0, time = 0.1 SECONDS) - new /obj/effect/temporis/weskar(carp_user.loc, carp_user) - sleep(0.1 SECONDS) - animate(carp_user, alpha = 225, time = 0.1 SECONDS) hitting_projectile.firer = carp_user hitting_projectile.set_angle(rand(0, 360))//SHING return COMPONENT_BULLET_PIERCED diff --git a/modular_darkpack/modules/martial/cqb.dm b/modular_darkpack/modules/martial/cqb.dm index 66cbe60dbe43..572c609417cf 100644 --- a/modular_darkpack/modules/martial/cqb.dm +++ b/modular_darkpack/modules/martial/cqb.dm @@ -350,3 +350,8 @@ #undef RESTRAIN_COMBO #undef PRESSURE_COMBO #undef CONSECUTIVE_COMBO + +// animate(carp_user, alpha = 0, time = 0.1 SECONDS) +// new /obj/effect/temporis/weskar(carp_user.loc, carp_user) +// sleep(0.1 SECONDS) +// animate(carp_user, alpha = 225, time = 0.1 SECONDS) diff --git a/modular_darkpack/modules/martial/defines.dm b/modular_darkpack/modules/martial/defines.dm new file mode 100644 index 000000000000..130a67138f44 --- /dev/null +++ b/modular_darkpack/modules/martial/defines.dm @@ -0,0 +1 @@ +#define MARTIALART_DARKPACK_KUNGFU "kungfu" diff --git a/modular_darkpack/modules/martial/kungfu.dm b/modular_darkpack/modules/martial/kungfu.dm new file mode 100644 index 000000000000..e8ee14885c78 --- /dev/null +++ b/modular_darkpack/modules/martial/kungfu.dm @@ -0,0 +1,243 @@ +#define LAUNCH_KICK_COMBO "HD" +#define DROP_KICK_COMBO "DD" +#define KNEE_STOMACH_COMBO "GH" + +/datum/martial_art/kungfu + name = "Kung Fu" + id = MARTIALART_DARKPACK_KUNGFU + help_verb = /mob/living/proc/kungfu_help + display_combos = TRUE + grab_state_modifier = 1 + + +/datum/martial_art/kungfu/activate_style(mob/living/new_holder) + . = ..() + //RegisterSignal(new_holder, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) + RegisterSignal(new_holder, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile)) + RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_dodge)) + +/datum/martial_art/kungfu/deactivate_style(mob/living/remove_from) + UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_PRE_BULLET_ACT, COMSIG_LIVING_CHECK_BLOCK)) + return ..() + +/datum/martial_art/kungfu/proc/check_streak(mob/living/attacker, mob/living/defender) + + if(findtext(streak,LAUNCH_KICK_COMBO)) + reset_streak() + return launch_kick(attacker, defender) + + if(findtext(streak,DROP_KICK_COMBO)) + reset_streak() + return drop_kick(attacker, defender) + + if(findtext(streak,KNEE_STOMACH_COMBO)) + reset_streak() + return knee_stomach(attacker, defender) + + return FALSE + +/// Frontal Kick: Harm Disarm combo, knocks back relative to Attacker Str - Defender Fort +/datum/martial_art/kungfu/proc/launch_kick(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(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1) + var/atom/throw_target = get_edge_target_turf(defender, attacker.dir) + var/throw_distance = max(1, (attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA))) //If the defenders fortitude is greater than the attackers strength, it defaults to 1 + defender.throw_at(throw_target, throw_distance, 4, attacker) + defender.apply_damage(15, attacker.get_attack_type(), BODY_ZONE_CHEST, wound_bonus = CANT_WOUND) + log_combat(attacker, defender, "Frontal Kicked (Kungfu)") + return TRUE + +/// Roundhouse Kick: 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/kungfu/proc/drop_kick(mob/living/attacker, mob/living/defender) + attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) + 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!"), \ + span_userdanger("You are kicked in the head by [attacker], sending you crashing to the floor!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) + else + defender.drop_all_held_items() + defender.visible_message(span_warning("[attacker] kicks [defender] in the head!"), \ + span_userdanger("You are kicked in the head by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) + defender.apply_damage(40, STAMINA) + defender.adjust_dizzy_up_to(10 SECONDS, 10 SECONDS) + log_combat(attacker, defender, "Roundhoused (KungFu)") + return TRUE + +/// Flying Knee: Grab Harm combo, causes them to be silenced and briefly stunned, as well as doing a moderate amount of stamina damage. +/datum/martial_art/kungfu/proc/knee_stomach(mob/living/attacker, mob/living/defender) + attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) + playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1) + defender.visible_message( + span_warning("[attacker] violently slams [attacker.p_their()] knee into [defender]!"), + span_userdanger("You slam your knee straight into [defender]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + COMBAT_MESSAGE_RANGE, + attacker, + ) + defender.apply_damage(20, STAMINA) + defender.adjust_silence_up_to(5 SECONDS, 5 SECONDS) + log_combat(attacker, defender, "kneed in the stomach (Kung-Fu)") + return TRUE + +/datum/martial_art/kungfu/grab_act(mob/living/attacker, mob/living/defender) + if(!can_deflect(attacker)) //allows for deniability + 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 MARTIAL_ATTACK_SUCCESS + + var/grab_log_description = "grabbed" + attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) + playsound(defender, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1) + defender.apply_damage(20, STAMINA) + log_combat(attacker, defender, "[grab_log_description] (Sleeping Carp)") + return MARTIAL_ATTACK_INVALID // normal grab + +/datum/martial_art/kungfu/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 MARTIAL_ATTACK_SUCCESS + + return MARTIAL_ATTACK_INVALID // normal punch + +/datum/martial_art/kungfu/disarm_act(mob/living/attacker, mob/living/defender) + if(!can_deflect(attacker)) //allows for deniability + 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 MARTIAL_ATTACK_SUCCESS + + attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) + playsound(defender, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1) + defender.apply_damage(20, STAMINA) + log_combat(attacker, defender, "disarmed (Sleeping Carp)") + return MARTIAL_ATTACK_INVALID // normal disarm + +/datum/martial_art/kungfu/proc/can_deflect(mob/living/user) + if(!can_use(user) || !user.combat_mode) + return FALSE + if(INCAPACITATED_IGNORING(user, INCAPABLE_GRAB)) //NO STUN + return FALSE + if(!(user.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE + return FALSE + if(HAS_TRAIT(user, TRAIT_HULK)) //NO HULK + return FALSE + if(!isturf(user.loc)) //NO MOTHERFLIPPIN MECHS! + return FALSE + return TRUE + +/datum/martial_art/kungfu/proc/DodgeAnimation(mob/living/user) + //set waitfor = FALSE + if(user.is_clan(/datum/vampire_clan/true_brujah)) + animate(user, alpha = 0, time = 0.1 SECONDS) + new /obj/effect/temporis/weskar(user.loc, user) + animate(user, alpha = 225, time = 0.1 SECONDS) + else + animate(user, pixel_x = rand(-16,16), pixel_y = rand(-16,16), time = 0.2 SECONDS) + animate(user, pixel_x = 0, pixel_y = 0, time = 1, loop = 0) + + +/datum/martial_art/kungfu/proc/hit_by_projectile(mob/living/user, obj/projectile/hitting_projectile, def_zone) + SIGNAL_HANDLER + + var/determine_avoidance = 100 + + determine_avoidance = ((user.st_get_stat(STAT_BRAWL) + user.st_get_stat(STAT_DEXTERITY)) * 10) + + if(istype(hitting_projectile, /obj/projectile/bullet/harpoon)) // WHITE WHALE HOLY GRAIL + return NONE + + if(!user.is_clan(/datum/vampire_clan/true_brujah)) + return NONE //No, you cant dodge bullets normally, bum. + + if(!can_deflect(user)) + return NONE + + if(!prob(determine_avoidance)) + return NONE + + user.visible_message( + span_danger("[user] effortlessly dodges the [hitting_projectile]! [user.p_They()] is unnaturally fast!"), + span_userdanger("You deflect [hitting_projectile]!"), + ) + DodgeAnimation() + playsound(user, SFX_BULLET_MISS, 75, TRUE) + hitting_projectile.firer = user + //hitting_projectile.set_angle(rand(0, 360)) theoretically it should go straight through if you avoided + return COMPONENT_BULLET_PIERCED + +/// If our user has committed to being as martial arty as they can be, they may be able to avoid incoming attacks. +/datum/martial_art/kungfu/proc/check_dodge(mob/living/user, atom/movable/hitby, damage, attack_text, attack_type, ...) + SIGNAL_HANDLER + + var/determine_avoidance = ((user.st_get_stat(STAT_BRAWL) + user.st_get_stat(STAT_DEXTERITY)) * 2) + + if(!can_deflect(user)) + return + + if(user.throw_mode) + determine_avoidance *= 2 + + if(attack_type == PROJECTILE_ATTACK || attack_type == THROWN_PROJECTILE_ATTACK) + return NONE + + if(!prob(determine_avoidance)) + return NONE + + user.visible_message( + span_danger("[user] cleanly avoids [attack_text] with incredible speed!"), + span_userdanger("You dodge [attack_text]"), + ) + playsound(user.loc, 'sound/items/weapons/punchmiss.ogg', 25, TRUE, -1) + DodgeAnimation() + + return SUCCESSFUL_BLOCK + +/mob/living/proc/kungfu_help() + set name = "Recall Teachings" + set desc = "Remember the martial techniques of the Kung-Fu" + set category = "Martial Arts" + + to_chat(usr, span_info("You retreat inward and recall your past training")) + to_chat(usr, "[span_notice("Frontal Kick")]: Punch Shove. Launch your opponent away from you with incredible force!") + to_chat(usr, "[span_notice("Roundhouse Kick")]: Shove Shove. Nonlethally kick an opponent to the floor, knocking them down, discombobulating them and dealing substantial stamina damage. If they're already prone, disarm them as well.") + to_chat(usr, "[span_notice("Flying Knee")]: Grab Punch. Deliver a knee jab into the opponent, dealing high stamina damage, as well as briefly stunning them, winding them and making it difficult for them to speak.") + to_chat(usr, "[span_notice("Grabs and Shoves")]: While in combat mode, your typical grab and shove do decent stamina damage, and your grabs harder to break. If you grab someone who has substantial amounts of stamina damage, you knock them out!") + + +#undef LAUNCH_KICK_COMBO +#undef DROP_KICK_COMBO +#undef KNEE_STOMACH_COMBO + +/obj/item/clothing/gloves/kungfu_gloves + name = "Debugging Gloves" + desc = "Delete at some point" + icon_state = "black" + greyscale_colors = COLOR_BLACK + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT + heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT + resistance_flags = NONE + +/obj/item/clothing/gloves/kungfu_gloves/Initialize(mapload) + . = ..() + AddComponent(/datum/component/martial_art_giver, /datum/martial_art/kungfu) diff --git a/tgstation.dme b/tgstation.dme index 50c81ad32aa4..363fb120dfa9 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7261,6 +7261,8 @@ #include "modular_darkpack\modules\looc\code\verbs.dm" #include "modular_darkpack\modules\mannequin\code\mannequin_subtypes.dm" #include "modular_darkpack\modules\mapping_helpers\code\viewport_helper.dm" +#include "modular_darkpack\modules\martial\defines.dm" +#include "modular_darkpack\modules\martial\kungfu.dm" #include "modular_darkpack\modules\martial\swords.dm" #include "modular_darkpack\modules\masquerade\code\blood_hunt_skull.dm" #include "modular_darkpack\modules\masquerade\code\human.dm" From b959b2555189f68b92ca9844a17b359c1cc51144 Mon Sep 17 00:00:00 2001 From: SELFHELL <99771731+SELFHELL@users.noreply.github.com> Date: Fri, 20 Mar 2026 22:29:38 -0500 Subject: [PATCH 4/9] Kung Fu GFX refractor & new SFX TODO: Clean up & add dice rolling --- modular_darkpack/modules/martial/kungfu.dm | 54 +++++++++++++----- .../modules/martial/sounds/frontalkick.ogg | Bin 0 -> 11386 bytes .../modules/martial/sounds/frontalkick2.ogg | Bin 0 -> 15266 bytes .../modules/martial/sounds/grabbed.ogg | Bin 0 -> 16184 bytes .../modules/martial/sounds/kneeing.ogg | Bin 0 -> 17564 bytes .../modules/martial/sounds/mainpunch.ogg | Bin 0 -> 15139 bytes .../modules/martial/sounds/roundhousekick.ogg | Bin 0 -> 7924 bytes modular_darkpack/modules/martial/swords.dm | 2 +- 8 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 modular_darkpack/modules/martial/sounds/frontalkick.ogg create mode 100644 modular_darkpack/modules/martial/sounds/frontalkick2.ogg create mode 100644 modular_darkpack/modules/martial/sounds/grabbed.ogg create mode 100644 modular_darkpack/modules/martial/sounds/kneeing.ogg create mode 100644 modular_darkpack/modules/martial/sounds/mainpunch.ogg create mode 100644 modular_darkpack/modules/martial/sounds/roundhousekick.ogg diff --git a/modular_darkpack/modules/martial/kungfu.dm b/modular_darkpack/modules/martial/kungfu.dm index e8ee14885c78..edb3942bfad5 100644 --- a/modular_darkpack/modules/martial/kungfu.dm +++ b/modular_darkpack/modules/martial/kungfu.dm @@ -15,6 +15,18 @@ //RegisterSignal(new_holder, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignal(new_holder, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile)) RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_dodge)) + if (iscarbon(new_holder)) + var/list/obj/item/bodypart/affected_bodyparts + var/mob/living/carbon/human/carbon_owner = new_holder + for (var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts) + if (!istype(limb, /obj/item/bodypart/arm) && !istype(limb, /obj/item/bodypart/leg)) + continue + + LAZYADD(affected_bodyparts, limb) + + limb.unarmed_damage_low += 5 + limb.unarmed_damage_high += 5 + limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/frontalkick2.ogg' /datum/martial_art/kungfu/deactivate_style(mob/living/remove_from) UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_PRE_BULLET_ACT, COMSIG_LIVING_CHECK_BLOCK)) @@ -46,7 +58,7 @@ COMBAT_MESSAGE_RANGE, attacker, ) - playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/frontalkick.ogg', 50, TRUE, -1) var/atom/throw_target = get_edge_target_turf(defender, attacker.dir) var/throw_distance = max(1, (attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA))) //If the defenders fortitude is greater than the attackers strength, it defaults to 1 defender.throw_at(throw_target, throw_distance, 4, attacker) @@ -57,7 +69,7 @@ /// Roundhouse Kick: 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/kungfu/proc/drop_kick(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) - playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/roundhousekick.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!"), \ @@ -74,7 +86,7 @@ /// Flying Knee: Grab Harm combo, causes them to be silenced and briefly stunned, as well as doing a moderate amount of stamina damage. /datum/martial_art/kungfu/proc/knee_stomach(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) - playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/kneeing.ogg', 50, TRUE, -1) defender.visible_message( span_warning("[attacker] violently slams [attacker.p_their()] knee into [defender]!"), span_userdanger("You slam your knee straight into [defender]!"), @@ -100,7 +112,7 @@ var/grab_log_description = "grabbed" attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) - playsound(defender, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1) + playsound(defender, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 25, TRUE, -1) defender.apply_damage(20, STAMINA) log_combat(attacker, defender, "[grab_log_description] (Sleeping Carp)") return MARTIAL_ATTACK_INVALID // normal grab @@ -144,16 +156,12 @@ return FALSE return TRUE -/datum/martial_art/kungfu/proc/DodgeAnimation(mob/living/user) - //set waitfor = FALSE - if(user.is_clan(/datum/vampire_clan/true_brujah)) - animate(user, alpha = 0, time = 0.1 SECONDS) - new /obj/effect/temporis/weskar(user.loc, user) +/datum/martial_art/kungfu/proc/reset_animation(mob/living/user, fadein) + if(fadein) animate(user, alpha = 225, time = 0.1 SECONDS) + return else - animate(user, pixel_x = rand(-16,16), pixel_y = rand(-16,16), time = 0.2 SECONDS) - animate(user, pixel_x = 0, pixel_y = 0, time = 1, loop = 0) - + animate(user, pixel_x = 0, pixel_y = 0, time = 0.1 SECONDS) /datum/martial_art/kungfu/proc/hit_by_projectile(mob/living/user, obj/projectile/hitting_projectile, def_zone) SIGNAL_HANDLER @@ -176,11 +184,18 @@ user.visible_message( span_danger("[user] effortlessly dodges the [hitting_projectile]! [user.p_They()] is unnaturally fast!"), - span_userdanger("You deflect [hitting_projectile]!"), + span_userdanger("You dodge [hitting_projectile]!"), ) - DodgeAnimation() playsound(user, SFX_BULLET_MISS, 75, TRUE) hitting_projectile.firer = user + var/mob/living/carbon/human/dodger = user + if(dodger.is_clan(/datum/vampire_clan/true_brujah)) + animate(user, alpha = 0, time = 0.2 SECONDS) + new /obj/effect/temporis/weskar(user.loc, user) + addtimer(CALLBACK(src, PROC_REF(reset_animation), user, TRUE), 0.1 SECONDS) + else + animate(user, pixel_x = rand(-16,16), pixel_y = rand(-16,16), time = 0.2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(reset_animation), user, FALSE), 0.1 SECONDS) //hitting_projectile.set_angle(rand(0, 360)) theoretically it should go straight through if you avoided return COMPONENT_BULLET_PIERCED @@ -207,7 +222,16 @@ span_userdanger("You dodge [attack_text]"), ) playsound(user.loc, 'sound/items/weapons/punchmiss.ogg', 25, TRUE, -1) - DodgeAnimation() + var/mob/living/carbon/human/dodger = user + if(dodger.is_clan(/datum/vampire_clan/true_brujah)) + animate(user, alpha = 0, time = 0.3 SECONDS) + new /obj/effect/temporis/weskar(user.loc, user) + addtimer(CALLBACK(src, PROC_REF(reset_animation), user, TRUE), 0.1 SECONDS) + else + animate(user, pixel_x = rand(-16,16), pixel_y = rand(-16,16), time = 0.1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(reset_animation), user, FALSE), 0.1 SECONDS) + + return SUCCESSFUL_BLOCK diff --git a/modular_darkpack/modules/martial/sounds/frontalkick.ogg b/modular_darkpack/modules/martial/sounds/frontalkick.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4e21014060d5c584cb61d14a83ae39ab5d1976aa GIT binary patch literal 11386 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 Zbb!qE&%bOTY{B=sec%gBG9$-9`d{5B=q&&M literal 0 HcmV?d00001 diff --git a/modular_darkpack/modules/martial/sounds/frontalkick2.ogg b/modular_darkpack/modules/martial/sounds/frontalkick2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ba37073c466ddffc8edd6e32bf86f15abe9c0026 GIT binary patch literal 15266 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 F{|5wPbr%2t literal 0 HcmV?d00001 diff --git a/modular_darkpack/modules/martial/sounds/kneeing.ogg b/modular_darkpack/modules/martial/sounds/kneeing.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1f79ebc6ffbe4f6e8f3e84fabc5ce5bb1151dc07 GIT binary patch literal 17564 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 literal 0 HcmV?d00001 diff --git a/modular_darkpack/modules/martial/sounds/mainpunch.ogg b/modular_darkpack/modules/martial/sounds/mainpunch.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e81ba852dc644ba67768a3a462dd0b94670c66c5 GIT binary patch literal 15139 zcmeIZcT|&2w>Nwx1PIm8JJL%C5FjAk5UHUD0)!^LgVLLNgB0lkQUfTxgd$x~Ktw>A zNEbm+RFG-~R4lxK`+m;zocEvet#!V?zV%HebM4uC>TmCBW>40{)YH=f00aMorgyfv zCnU3Y`*#pODC|;@i+At|1FYR}@&JIC4$$ed3uJmy^S{DL%@c`K9aM-(^Z369YKp&G zq9+$Hat`xQl9M5SkjRq?{N%5Dfa@hU_aF_j%#|!tIFSkXdAs~w3q<+%QxtQ-3Iw15 zKqQzGu3Ht%9uMQjm~p-3#Z3C{a$$^^uJg(p*^P?^X9`x9Vv_76Vy80kz)6K0S`n=A zDOym$cu@_T>^N}^GL@u4=6Rp+V3>a;Ix1ddsTPzk{w-3OK5kw4J8!&>iVcj++Z2dD zgXtp1HK>paizw=w#Zjqj^2QG!BvP&qBD>h*A&L@d*WV#W=HlouNyIn<#qZqlo>~#? zfA=AxrJor`r8UACud78K0hLM@Yy7xYEq6Rz1$s7K0OiI8WCB2GxkO621TBoal@=HQ z02tbw^+_P_Xcq5i3ojj%fj|iWAOK1(r=L=(pYcvVTZE7;dKx#9Nr>^*(sFIKrTvVreAP*ykDFrzg^DmHNII)c7G>s~+irU>x6~1Eq zj>znylx~&x#le%K8^v;yWU9QFKu;u>dtW?QN}&Cl5^sr|BEnC2fsNMFN+Ttx{Imy=ccIOpM4Us9+;jPtT*nbr{ zEq4ksdA?{^V!HE7N$AXbF9BU97jF42t#6x18t%Aa%=YxAS7nYWR5UjbhZX-Da4>*| z3MR1P^#7H(Bnc*R28~J9lwQZe>uSr>fQ&tcipwq2{G?@9laNv!ky00tQX7%6nUw8S zm{(gzlp3qvz2CI+KSjDz0~Y~+5D~o~5j~uU4vtKmq8mehf-di4IT4*8#P|&A?>SDh zXpjN54*7f0_(uT%KtI~dIzG*7%q%*Olg3*}&*OCFE%5(SFrGyjvyg$M0Wv{ACd@)w zdYDL)D&jKZQ(x*zkK3(k(T96>+#8ci;OubZzL8@Ni>?!KP0^Z=uAGt-Yh19zB(PQ% zxWd_Rj5xCL5&#$x^!hR{x)ni=r^o<6CW>K7{Y*3J%s+V%V+w>R1?m~aKl%U713iO6 ze^n>Pe;Ofo^hurRlQz>odBigc)HH>)r&gaT!|Yt5E=BaQ!! zg$P-oH7k$;7?1^1s3f6(i?YdrQg4_}OeI<1#rr$DS;PbsCz=8PP6VO^d7=N`h5z0m zGmr!ZE=!O*eA0q=P3}=-v=zvsoKlae29ak&E-Y~}x@Ij4m%teE!Vd<_0f1_#1!2sh zlU?ae6i*Q`m{m7r^(MZLyzM>kRsCezpxT=RM;hbV$o|Uf6WHUb2j2h* zi470{0|t0gTnNOC$lKy6)pf+bThWO?29(tmHNwo`=T1PcHW+ zk?QZuz>H6t3w0n+os5vQGbWG5lUs7I&I6rP*}30JZ-#$Pmgl(xCppA88FfZpvZtI@ zdMgc{+B_XkcLrT1CMy>$-Nh;oU`>C3ZB%G5X@b0LEH{z#7IgGS-F}^#^Z2U=}wzeY*|G%4%;|ylO|VJ zxnP^xIP8*UAlW`=n<~dH>}OopvFKCZ!s+S@mu}~DO&fwvuq~~pY zk;9xTcBxgJ#8f%W?@Ks@+=4v-gvU_;+Sk(+8bnIiGN?GXTbTheZUQi}k&tbMY!#Kb zG!?Q{Fk+x(mSo;3C76?TVm+tl9~_pga7YU#f|Lql;_|irFE_gRdH5w z8tSqIo7tw+2GQf5*5M`vHbnB0xMJK9L7#4=^!JPdK}I`CSf) zxDpeel$J?eAjyFXxI#X;ilVi(QNf&C+&sK|{AUFOg@i@O%lO|1aDf;A0{PpcI$6OX zkiSpZ{r{Z2Pfpk;{3lNOMxmhp9@r7mT88@i#>ZmE9LHylDUOAY*^gO|nT~1Xk%}lq zWoZqqW9DNRNpHEMjKZ-B1n87Ii$bnc!XoGyx;M-h9M1eUL}p?JnhwYNHGn5 zEjBU9oU-$s4cH(3IiQR^B^EO&>x!5DE(7atfb} zzI8XfT@F@jy?@jfpjxtV@bjwG^74Y2h(YFhkRtxz+8!^*;lcKugr9r5{GcM-_ zOlLWq5*45^k+cOC-48yhEAH6ZW)we+P%c?Z`@Oz4zPz{h^3V63CmjCYu%wxHq{eGu z$2DH(mq<$7R~Nu+@Txit_b+S@&AYpnsnxHGTkZ(&s*GjsQo#1O?(RK%{_|j;RqK<| z_x*j;@bYqmt-s~+Ldl-w+xorLZ@W+KqAr%-z93A=FYlIggAq`->qvS1?oJ~-0Z#qE zsv*aG89b$0-8ZTvP?BVg!oJqw7aH%IA9v}wQdb}D{%s|7=lY?B|Mqe=t{}ri<&)2n zi3Rg;1rnmZ_JXEMOKgpjuC&_jJ@nRS80huPXxT>f{dz*#vc1OS{w{vL;mH$k6Netz zrC)y8PcK>v-#0FL|BcyDXHAc_@2_?sy(^`CmEHdtILe2wlo^rT3EubbAkH((dwWTt zU-cF471@P5s&N@>>#E$9Zl%YWcghb)Bux74i;db6@c0)Sch$Pqesa8oO$73(G#%nS z|14C?gtysuU)z0HoM3prq<-FA9_JsX7Cg@h$Pq^b${Xd25K{D1-8C-FcsdK4PMviD znPL}0I<;Fnky#rJ%360>0MlOgPU}GdVY+cf=~!W*;tO4#6=fF*`_a#HVF}Zh*6K9m zpS-AERdmT&1jk>;;6?EVZE*Hn_;yFvD9NW%B4yQjdXjeEqx4AR?FR>$iY>gE&Qx)Q zj#=N2gai4AOl5-u{-#Pz>%*b?`*M0c8m79zor*80gP1gcNZj%vGY`+9A^br`uf~nu z%$tr~$F8&UsH3|;-^9>U&=MMawD59BnoML$@9!1QC`8Mvo=IxSh7Sj+%NHc^$-n$W zffpB(exrKTM&AN89G_uD@=<1Ki4swT+|c^k92EozNDeGQ9X%k6PM1p>lJ8?`NvpM7 z<%5X`lz~^v;TssBOSJ$1bnNI3Mk;zQ#K`LA-hc}4(f{n9upVs1~cD(a)%m@Cp#y1qVjTS0&2c*Frn_nX)?o+%UfzRb_ePzfE z!l9enJoAjK2u-B1Ax(?0t1NzAz4i1~JQp>%c;W>UV&mCt*~}A?(@B$y9qmzHgU;oq zk_g6X@W-4r!cm)no-XlxeIYvE)(O`ByP;KJt|FVf`FR@I`UjTfFy%oio_k&ee*F^Y zN%Aj#C8!CBc_BUmMOb5`$xmCC$^H46C5%$uN~Vd=<_>+U%a9hLpFt&rvc6wnycK@d z{ChIHcW+Iq&eX_dpNt2GIb8_>XsV+q!rCM0$UXPBodzOv{c!E81IT?+ST-XWX1#4`&H1awo`Ap^O%3_(IsittB~79O6ORdGpS0Al^&$h z<#`$8GJJg~?9-YfkWeD3Tu5K9FC%45NN85iN;=Ptx0UjRS6dp6QzTm_aW%->Sn0Ii zYnQJKYUZ00JY!sU>)HeBkmc3gmFk>YlhMO=skArs%u=XU7bN>gKeJ4LPsXjct+sHU zIIFx}#b$aK%cpPGVFI$L7e<*oEpO=z@pmr~KO5|y)AY@1PIxN#`=^z;M794!VR6Ij za_QE!#VmBm3U532l(x@1yYj+YgxN zoie?Wjw-os>n^;>tD2C@JTrgpx_G3(}^W)~XWEwLD9; z!utxNBUR6TzeW9Nx%XQ$e=3EibrXN)mkRs!kFLq8LmFE)PMSaKeU7wlt=>3$ibTCKeIDnTB5^SLT8rBbd<@s6XZ zMtWZ{yXqo98mc2mIhw3e0h+2+B|_I>Gf-38Nl!R5y$1)FnKz&d^G6hh{)qHbWiZa0WsiL&wj6lEYk{=v zGBl7^0kfbH;N)cyry63S*=!P_Hm%D>s9F{$wB|ih46{_BOVG=6&lF|7$gUqV-?u09 z7hUV|AaF;@DP#Q3-kY;TTp5W%+c|pW-sCq>;MIEOqM`cAi){$$riqwPj2veq+2VM%<1 zRbW5z()C4xu5k2H3yB2J?+RC9NKUhL?X=mQFRj33@;0P;`RlkC+M`Hbew7IaL{ha` zy_$u4xBk+$b#1$%6MH-T6EFE-Lv5sY#q|z2a@x!@Lo{WEb^a_}1y*%_`yz28ZL-26 zmsr?2-6?g~8$P?iJ8ICeb>onJk@f}`6igV@BX{C~!2d=ktr92+_D_jA-+c!edc6Ah*+_}^c zsc>Ui=b-HyxH?U_nIIl^8oH|w!olq?^hVPn^fTesm83=coxxhH&$+qlb&_y|PGUzc z;*9p29eik!kJ?SotG%-_98w$n<+ak;`kz7VmkUV{fX)}bNiz{+kx>TszhAfgEUSb; zBz+9?ir)?&!JVBcK=dZVY3UaEoa22u)A92WeIxh;^6C4R8u{ibueE z2PG;q&1ZBONtBk9jue^(cslhV_umpOFEFjh&hB;hJM&a!bYf?? zGD9%~JDD#g~aF@j2of$k49CaxWbSJ5x82atU>`XF($Wq7(s)bTWk1zkQEk6>i*4wo-pBceNvA{2Jw_>z?;oStgmT z36`6_4BEMAc+>s~WB%*Wan<&}J}j8B;3Z-|1?I0Y8_imNEkans6Nh{c^kbL- zS&7t748`w3Z$PXDQx_Z&-k^b-g&tH~39R6sn?-xu_t|{Rr2WN`eerRuhDt801)Gmn zdOtJWoi67DAUb6TbJlLbwX*^^5ctkBNce0e3wK?MLew`z3x%s~Qx{21?ynD?MXnl4 z46l>`dc)47FFLoF(Lbn5wW|7~08?EyUTfrs@;u9%ZP^y$8i5@sz4Hz$B%$6+VwqT0 z$zwS?;1}BG{2N)fyJ-g$X$T5&%H~>A@iO?2qMvv4w(DXyT)Ev3eurjsf2^x1Fnud} z{i)vfVc?~zU`pUQ1rvDc!YCcGfVSro@Zdva17D>4{rq!l{MQe*-OD!SRgr}}bK$9H z0^^hA2briRl=%r1rkQ37gm&mMnlT1)4Y&sB{`%HSA9J zj^V%YbVxEzIdhvYNT#^JU*F;ecv$<1eQg*YW4XzZcsfF_biN71?qw;BrQ_D+uxVmj#+ossisnyw5y*g@im(B|Ka^y-MPfRwiCIyHOEs*y=O4i7fSOljjun zq~0fYcLg`t+8Ku+cdIojhbZFTMU8LK#%)hK_}3^|mne}gg3N_GY=8U}vLf8C%#Z{f zl^^y1Q)5hK*})CSnZm4^v=)TOxN=zN&uU#KwipW8Em>mF{jKVmk1=S8_^GlBrRL%z z&GHFcQv*Uao*mOrkl0|O+u~$Z-JnmS)V#6X^rmISO!fM-H|RnJCR|DLIZ#rJo!2C<~QwD&HA9lEHL$bs_CA%z1f?G4&YS)8ix4%)?&QZIQWfdhDl z)=56M7@MMro~BO1n1KrVfFi>QmZk!srAht<1ty^jtV|Xu3d{oOrSA%4E~C^wLPPg8 z1GIM;Mce{6&kDG(gQp7mqvEWcvg~gUTWL>egb$c1)|d z4tr8(uj(M%(bi%_WUU2LC`8XI+MPp-d1;$|jZ$A^9c)G6#kL`57g|}2G>ekRBp7w; z*T_6KZ!x04!PwYm|CWv@`zM(L^ zyi+1It##!3we#t@h*D%LlMbuXP<8`}lz;xQKX%S8*t013&A_M4zogEai07==br1Fx zMrVoIG-NojzIU;(N9QvXAa8; zhM29e@FUm#q7v=>yF@OQ_bxU-EEfgJ)p^i>-CCfM&5q$Q?U+6;a~ON=tXcjYK8y(V z__#jnN@yrcQ%{^)YO0W-ohL6_m8;(4n8y=*^B?`mKPz`iPW;7-*-GSc4(Ed)1&&xS zzNMlOVaY43;WG>|YSAx71X&h%sebyOK`4WNb9FiAx2wKD7t`65_zBRrcHdMGceBLA z#_75S%g@wxi!xGk6LevQ_s!Gu2(K=t3XtrjW{p8T>T)arTqh}?wmP64OWVNERkve< zcX6U&scD@2u;?)2Hzk~K{mox;1(=4xV#qengldOC@#}_Lik}D0z%JmO{LzNn(mY+3 z`{S7g?gyxy(6`>R?|&S5eUmI}x&7-{6bG<2xQxF1Fs&~+Dy1yNZBP3qS>wTh{l=R3VJ65XRrNx+S zYZG_aKD>-%LqU`8p0Q7wF{9Zu@7XNRhKhMq>py5!$ySO|^Pd%?A8@icxR0oJBILy(q4`KC#kg&* zr5ieR3;%X_pcVXpSym544@w$f#86ku2TUb3vte)J8sr%yS}${&l~i*<7-E>LjO@&^ zK!D6W5mTH%!nX5gC@hA0UON{dfQW73)xOU$M&dfmVm$l7DI)k8MciIwah&SPl`J2L z3~xLCP?Hdib^ra)U(1{4)_9K3-W~RN`moNn4OF?(OAY;cU^VLY9vV5M`0NVn;?*Wm z6cMGUZd~>mQTUzHN~|(`tWWMNd&xY+T{o;|x8g_h_JP<3ar3#k6|Jmf2l+i_cU=P9 zDx;f3O4M7I7g;# z&xh#nTGA3q8J#c3up9T>fVmM6AYp33PPZzg39pKabYWKY4M#<h?UIQ_zHFXjS%6_5&>c)z-FDBRzI#N5%4V@ayZ84FeGskBL}J!8A8B)W7a zlE13^Pe>JzQc-pDZsh9-J_OT8hA`8cb9pZ?S8T6 zt!qh0iALOh98m#4pa|pm*v?uYO|yT@SMRK2`Amew znAl@3;QDmKaH@Em6TabnM?g(;gFVIvMG9)%A7StN;Ac4Fzh&v5m>aOvK3`E)AyJH$ zE8nbTmT<16UAfP~rQJzmLgjR`J~isBr;eH@(XgiNei%+igH7|=-T>8uI$N>cj?VF) z`&Rf|u`<1>w%O@+G#-?u*=By=u|GOoAJFMIQ<=vII9EB&iuvNVQ0dimfmh3jx>{o$ zQ6iL(@_RJ_zFb-&e)b)Vu&+z!ba({A=wroY1K$G zKS|E7za{7Q4)xP4bZr{3H)q5eHCC!;JC{0VpG-zNlw^>wH1Zzr?ro?E)kdHh&wE(j z`=B5cL;dd4*`!--k0&~ElQ_FO#cjhZ!^&=H(Kop?rTCh~n2Z>{y?f`5quTqeoJhU& z_39`K7H+FE7pUR{>1zr$fwhdQqs{sjTS_49;aHJ)m8ZXT#oqPP2H536!FXf4ZQHP# zCM_?uu?%~<<$wkECajsUR+mq%RzNsUeQKW=;hZl*Nga%WEU ztn>K$!^MRhQ61rB<%7gR>#dsod_3g?s#vv7L6oOZx{#zqlc6%Yt)v0bZpyPRophnf z8>^}VJghIejs?YQ+I;xbUUnu=t!GcwLMsvKO4;9jDJrygU*8>25*rlOX+;;*U5#q( z8lTQLdk(~_+a&h0VE7Tauell?ymu3vhQNU}Re2lN)!R0H!i}PA#tv)w;!&f zIOgHX@#;P2K$`rPKB+&Q-Q5Hr1dz=_r;oW_jco&mk#_fQj>o$5tNBT@M@J|UA8)+s ziwN)qhkS$A<`xuL+64$eoXgcXV5bWwVZ@Vwy}$Vr94>ELrrULXcP+dcNK<_gX=IV1 zT3cDr+Vj9xB#WsF0W3Eqwlr?;LUxe1%|~IQB5OAXW?vr05)7uTfp}FLNBIx6aqE;D z%AJQXbTpJsyYDhJ2Hz7h6iCVK`)&ovPUZc;l8$L&_LME%gV+x8t88=4y(yb|Ji{n- z&QeH7=rXG$@PR29V^TM=qc244p?VVcoBFw0Uqv8g>_{!o0}7zIi|J>t zw18HD!Tt}rFWmVk_*%vi57JxnCeqFb7RGW{)XG)cxli`0wl9^<*V8?`w&z9E4t<~z z?Rcrav2};W8WN)t!52Gs@8IHZy?MuO+MbaiGn|9T!{H&XI!$YT7U40J!sW|V`Pldl zB5tSiExz7Jj;!4!OR9BB-ru!3oz68c8q@;cw@G!ljc4F& z4-rqn@4zO*0`BphErq8^?C>s%taA~$+<%1jz8YIrSeh6mj$k9P9tJ*g1^6bo6iTYSiwh>y6)v6kPw$SPIIH8VvQM{cyo}` zQz&58)qq*c_H$wjEKcgCYVrLXV$5#EX|QZL)81iQXE~v|V04$8j*iaCIYP|ntcF65 zPvpD;MR0fDs()K!F5k-*t%4e??E6Uzh@4@*5A|558FBK5$?XjJXyr~-=%WdKT28tW z9~$*l5k^>`X?P*&tED3Z431aFd1$rKM^>hR=pA;^lRx(oB8txfcb35_X_bm1gz0`C7RgZUK zvOo_E(DZkN!ET^+jN@o}YCLyqeiH=}GMeXZU$``K%ZN;cuW6G1~jc-MWLkVSw zZ=~z^`ZTDavlGD?IeI^Wh9Yi`iY3wyL=Vrpa{2LKZH|qc)gn~_#@C5Wc%0xH-GUT_ znVeH$(r3uHuP>6y_@)}~^CB@NCv87A9HIB*zho}PcHaL z+HdEGmh+q3!P-&p-7L97SVt3-#|`l7V8ULa%H@mRNDsotGv6wN^HKI!v8k2~Va-to zn^uHKFMWw_p;1R+a89#jMj&G=O{oZGa*)m&c`ZM8)gNy`AEQ(3QWDB~Rv(H6xaCNh zV|WWEYndIo+^~+I#n%bDhpvJbvO(+cQcn=4(XA|ZJ!jaM(OfB&r4lj(!Gk{Mp3ZhCjjS1(wz%{!95M5)_oETo!SPMH7R+L9#Llqyd~3c5sYzIQpRfRK3urPigg z#s_z>x^E;Fi4oHBMZmg7!_(Z$on^zWZt^@m9H6lP$uU6gL2`6k7dF{6`6yfJqAgdJ ze9h!jbQPx7+NLdx&17EY`-0)?Z~>Vk=`{XWT03pz%wM{GN)E*8f&IjJGd?yftAF+% z#@cD}{=>MNJl)Il5_q?((pqFxPRiP;7>(B!8gnblXyCbQn8 z#3entrnkI@qJz!xYahJm^6{49T@3MrJeXaeY&hqVW!V+P=ykj-{zAx-BCrLSCBUFCC=HNUXbi+~iub`&~|ljV|o= zM2*r<8X-JXJX(YVfeUC(W#)7mVZju!+X8_XIK`SE(_VhC8puN1mZi8x^vq^R*%1j| zXHvAkJMH1js;`n+o)GQA>NDl9t>X_s<8#8AhYf9C$C%yXOn|CE?J{0cn07yDjb$5; zp?@tP0!<)D#KN=GT)DW+B+wLSxAZjNx(#w<0D$T}o0COb6qr`^z;J8Gvf2GcTG%vJ zZ_ivny74zWsYWimqA#0KasRethxp5fi{1NJa%B8xt_?ZJcb?S>&EH%vi_Dz(Vtu zP0FX&3tQB5d+Uz7rDyNz?{D*Y*ib)l$hGT)hj3q=jP|#wi^6Ys%lotY<7Oa?+lgRxEV?}6G^O=W~hk8*0aC1L;pbUKC>OrOvK z(>13xl?+tY2V2Z2=P7xEKD&rZa}@OFh?PSYMcACF{Nnv?&K184wUlqQenZ_c2+?4; zto74HXZ8jz4uV(7RXg;QQy|#ImDW~A!p*t&Jw3B#c z;Lzow%~fWnZ_h9A=c#|(O_xO?#Sq=E-l@5OrQ;y$lM@pX<{YkUI6QQ!U9R2R;V83& zMw73$?Q;`y#J`6>NXR&$oyhU~GqT~??!}D=N14H`N7?XFz9GPZ)%UK0yc>7`B-Kyf zp!^uZUl9r-pjprq8s3;z$w8rM3Y~e#e5hc{~aeSOpPsIHlrNfJNKwhzReL2 zwA1pcZ}^@GiGJPBDMXQ5wdb6fUzqaNJrMwzm4@G24q@n4-{1oQlxP0r_V~}*wL!4% zxIb7&nLqp}0Ih-*`y6yH7y0gCeh#kbd$i=DrP-0z7_QdAgFr6y-&109mzWB`!}$>AS04ENUp6$l9U+&1FBkY#Yn0KXl2Y1g-35|0I!o4Ukm-On}hu^>)0 z1;d(ZIHLz14-F+UaSCj=zjbc8tJHQJ6?zmEm>G?0Y|yE)jP|~|pviy4*+zKQ9(J#6 zHc*N>v2U~dl?)44Iu|Eik>aVcZJX4^sxpldI@5<&755Pe7MVuM)wjMo+^$3)gr(Wu z3eNgw@w3zP5;kqDNAZzr5QA}RkHSS>mzv?XH>4AU^?p5QtxifADlGuTXHiaAMt7U` zP#*Tr?YJF$=2Vq?&UhfbxF7K2_W1T+wO+8Y1t_{TKJtR+m4LTubwzRoHse1eE#x=2K+hPa4X8?ZAngDdQ+;D_Ym*id-pEvE1lMKe&z?mcYlxR zM@fi_R8&wLI)-+=dTeH4xbwV5@!7V9A}8wo-Air{E?;@Weh#(FhGArQIw@!un-&O> zhw>nSllgC-K?%gJK@Iz4chhB%)SMC(ZXRMKt>j--*&gv3DyzFiIJ|mhlb+t7M_Cbm zuHo7>Rl>V#lRJ?b{Q0eOB@Xs4X0>KC6ow2Z-7Z{wY;`_o;B&*bs9Q|*YrQ}JSZCi< zHMo7#Vf_({wf$_Hd?r9KfzG(Z*eUhrOHQxHKtV@GPF1!xOV*^r`1!8sVM=z9LV9It zu}8tlJ&8h^OhC*;*!!Db*Q3LYc|Lylu=6cCJp9}7moKM(n!NMyQ{W-%LmY`c}|yyfK6<#N}tSumE0~2xJ`SMCBhFF5U-;k!}8j04o7NF189+ zcY3u};PeV^43!fIpz7jVb5`y*>!|xl+eJm(zqxq#RgwG0aRgmV-P4VS$E^LW&3ZAbq(#L}l4Pyht$*MftOEvWbACWaMJ*q^Y%H`ZMcKSgw+%bcWN&5 zfhW7 zHzPM!BeG1Tv=9kyD=M5tlA4v26ZXX+e66w|{h9 zE1gQHD5T3v@Y98`ry#Ug`JUpI!?Fk`ixcFHsutkX6}tw2jc>5Ss*C^5ud#!w`krb~ zHW@Lq9Px5uCbMtxll@Nb3AmjR^l{I9D1S;0_2sku{v|I=9eT@kp~b#15kfB}@tVyH zz7X~2G$DtAc=US7dUI{UZ@7uSe$#m4TZ@hA_MT{`5ew$9Mv&*~SWheVh-HwMRS?rV z)`uS((3X7nF#GPuJrDnpgJdOBR0F`aU>Tu6k5DjaoriZNMf4c~5<>h&@}3yxO2tBwd}kCYgRBq{(URuLy&F__d6}5>3goi!VK<{{O2ZZD&np^T zjJC9%zDmr%v~JSgTj+_}U5yXtk*}EuhX@9B;|xj$T38frq(N7vL(aK7;rGD1`lLzUh1?jCFlz%n?b@a+k^_8RQ&${uT zl*O==ohP(={Kx6v`)Yvta#S6%`$u0;M|Q*i8}s^)2mAjG{9i`^1s!#dpl=8ct=*&t zveZGmiyB_8K>E6r3txtoUU|s^R=_5Ylt!A;{>B0i3CJV5Jm3lmhAgu5{uUKLg3?Ho z6GsRMBDDW{hainX3mgySRAkU;PRr7BRIQZz+v=Ybv@>Jkp#$8sO!2QVS@YO1z?rn> zLoq?#q^~9bzI=Ti03m(?LujM_&(gnks0Om&Al?w_@JgfcBdAAwe-q%#4B2riVbE+K zWkd1k8pvK@+c?n14+owAAbJ{&Y3fb|!brh#9^Q4tZX-HUFr88odHJoKc-ki-1Sls@ z3tCZSq{zsW#?*k~l}BRO(<{55fQ-yqX+VJkEHBJYFqKlWoL5;bSZKv**n;N8bS{XV>S!Yx(q@h&KNhzD^(dNamvlP9pfQt!ba|DL z0+C2mui&^54Ye6`D>-#~--$?(sHS}-iY9I@Imizo9-(Odsu_t1wG`yThlx$*+nW?U zn71G~pAEz{;{gbDWh@ja=ae4IG0JWj<|?R=%5W>-976y)F_mbqtEL7xAxgU!&qY%V z^eb-CMY=*douI*GP>uA<3+Yh=CW=m|E|jMj=^vs4a645B`et}U^ihGX3gDPJiw|vg zJs~>$hRt$SI*&MAe2_|i-kZLy#NA(2I<2 zX+UuSjmZpZGL~RD*KR6?4T5C>wDy%T0bYqwuyw_V3v=xjkSo-4gl7vamheC2TiXxBW7SfT>Tk((OuLfM8C7;tcE)J;1Nn4-- zqBz$i)xQh6So(MMe?*x;!I>mN`$r)IzA&x9r**d*Y%jYG`-VUsg>j(e-ifKeBq~w} z6$~Wgfh2~1b|WQ=IE@#M`p5Jn-XI&|4vmKymn14v2!tN*a8Cl4PN$l*`DRng$_wb! zx-s7zVzqGGKfA6sEXS45GU}gA)La%rt8Tp=Rnv$Gk2W%C!G!1ZAcI*kCY2LWO1;Qs z0mdd{{?VqrnEL_Q6>WlS;@VFWbYtRpAOJhkrGR5vu6Zr~m_{CAk#>_BfN;}AL5l=h zGtjCK(sOK}RiR8lmN6ingu)f(h*yu~{zIoiJPDOgpZiInsDxu;3-J|+P?0W?qNs)y zLiEoYQ?;;AOwlROY#~QU^z?;Lge&GD%OK}b2^o-CMIkh0LWLStPM@nrClD&oR3r`( zLOcdlu8gY&Elx4^Py`VHMFJU@%bEj-9Dn?h3*DRbClHv+=s5Qfr=5#CPNP?o3+?TTc; z;p77#B`sqPIv;_@iKryF^m-k@(RJLM<=91u-{~QTQuTt7!qO-!0mC;?7!*i43|l$# zq+SXqjYE=+l}kC&*y8vu^{qQEE4dF5jFNSsb^%ZVub=@20#()FYoV-&nE0ffzi_x& zIr-2A2_-G?3v_eUCpkJ=Bx1C*b+C(nv8yK&(G&5bbmQ4Dg{zLYM4D?ZeD1{%$ADZIYx3Hg@e?5S_ zvN8gIPx;v%;w@_-{nD3VSppS%SeKr_VG#RVw)%tci(4%3-~VQ3(z)c`u>-BY$|pIl z^Fb!}y>{DSk3Ay~u5EqsW|*bh{e9BHug)!@Wa_c%Zk)Dz!s_GX)9{?$sQS{)woh|b zWZ%V>%8?E8U+V=Q?oWC1!8&-&B<|FW!>888$qwdCef)8*tRdazWaR^@>hz(rug6x~ zz5w?wgu>DmSsPO>SefV%6wbx*o?B&;u>!;VE{x3OMo+xm7ppJc{>RJSrwrKEe_*{5 zHZPGu_iPVZYTtNgbWk*_>Z%ce&uK3aV7{zc^@8nG^D2y0VN@Nwp0U)^e2@Je`}b$v zsIpk6+dM|&I#tn$cX3lWdZ}Fua4%`zkUH}4ch6_h4#xNQ=;-OOyVhN>()|2Ry$xXd zt*JvuwBA$@6>Xw?;qRz;jzkxBvq{I>w5S@ z1siXf)3YNis^+V~ODaVM!&kaq5UzhMH_-aF>RV@YrYSS|e1P5#=gQX6te1bt&k9BD zvCMs`z``|>=(=O+>s<+x&1*Jxm|u#Qy;r{4;e)Zy&d+m+aYX+6*QWKBr#>E-h?TiK zDy!{y_XXcT`-fc6Hq6nTwYkH<&ddAo4w{;4=F7NSaYyLG{h-*|;Fp@aVLROGYFoVR zA_j*$Mk0?Iyf}3E$oNRt!%F7;%1HXH0VdP()~U-fz<>7H8+t*9U*HVINpr=$%&upr zxFJsay)=LH^-8OTcE_*oY7xeDl*nJ91h2n<7__iYVD`fnr4;+X)jZ> zgYeb%DO;u9wG->LQ(`bac3bu719C|scx5=d_M%}br*^B{6K{W?;sdMbAnR_)=hjT~ zFRH6{(f4=MyxVN0=X?4hXGy#48fkt>qq+4m+c2By8169me5U{0piqa{a5`~mM`Q7PyFW&&6Dh4$ zs|P=FH1J-#?)A(wziIsLwEmpxjz>d1|AOfE1lSNOQZUE zwF|S==YEaRbz8=6W`(w#@8#`%(gpcyxK1fplWEpISuX;eP=D2ZBqtoM2Rw8Tnz*wx zBn;%>d}}p_K!XYVo|!i?c-e0cTZSH{UqMVA)M{DdfXNh_CGB#e=+ zsmMTn`+hXj+J6nr_jX6Zuc2FzrtNFjY?_!VHk+o&e!IC0?)dcU1J$pz5N+^TJK|oQ z)b|ye-McNa283&ASZi$^Y9P1-9Q%T!YCH?aTc0UJ$=h)Z{Hh|)|QueQ}j*8A2meVuVM(p0VA zAQ2{CtEiS?R%_N)iw^0MCS^^^!7|Dmv|)HC%4&JuAl1+q;^+FiX`*w8`Uzz-aLuC} ziPLAn+pZVo8|9rNwO(v<741js!*_&_Tz)-xT7Mb6{V?oS>bv$a9(uEPC33p+dnw>Pg&>VAgLX6Doc=3b3E9kR_Ku-na~ zVnSp6u^y*OccNWax6TE8BvEcg4;y()|9b9u&@s<%p5?t1#_8(z7SV`5*QzSqFC;V- zfkxz@;0TSv=ggf?L3k8;zz`ixB3x@b$1P0vke68ji!5cs@|;Z1sjy0Ob2FYjks5U^ zjZ|cy4D!NoW#m3m1G>90>m>3cn&19Q%7G8jc!2dZ5%h?jE0obaBM)obJY^s+cRJ}@ z(ru^nMVjB!snX~O!MV{zE7s-Yr;am1zYpa)rq1o;#pP2gj;g^h=S2kwM8xAMrH}!4 z?z2Q$Q~4!sFR$0RUFY0$;43fL-}8=ZQ@Ypqn>u*(?wW9Odb4jm?@*5(6_i%qB_0-)JyKRi1cf)H=?uG z$akGtC!V~bHhLZGiQabf3VkZ^!b!g;O2wNLjUSnL+!;JvxGU~}o0?wdfGXS3z*XbU z+1cy83dB!bLwQ(RQu~!hHhLh$T>w`q(OGGa=qJtMvZpdPWNX}(R=9V%*t1VJb;P_p zr(ocjFLQ;Q*4M=%*;4`KFFA(WW{<~qI0wFeqjLDbrG)Q?k1uuGFufl;y85HfT9vkN zv;K-l$(3)DCoWf??fUTf*F?|rTbSu^L6{=T8KHakjN;; z*<*R%#wR>&{ry$4jpViy-@L!@!d?H=zU1E1k=`$-0?b$Ddk1^Us0S+OrfbK?bS_rwGXVvltq>2cCNuSF|A<8{9&M-#ysyOj z6gxy#`kL3&rkC2Ob!1f0qqGTjO>{K@`TnbLsXdYBYX7)}#yaD5qu=OcMPzcI%tWD} zWLdh#2|rX$%%Xlq%+;gnU*|?1^u1}rE`NDlPQR&&SHrB{=DFq=B7`P=TNlnDj#T$# z%5VjdBP}4ux7ejohih*pM5Pr-AoLortTU4_ctv$8h)TZZv8eEqfo=@{I^|kEIRE49AtVRVq6X_ z&ytO=3?X%sjxsPIFa^$VyPiQ{Jj?K`Ef^{!JIkmtzd4!QZ5b=_QVVcw(|cmwXqW{K zz$2p4SbTr?92dVwAo}jDx}qbDug~{QYpdMuVtk?#1&@W>!&|5`H-dvTOZ6jEw zVdh)A*vbA66QB8S$2!B*p5V0mdaqtv=z-?|r68>pmG=7~Xy2$BBJ>90eHvYq0@`1vg=*ke>c5Ft zPdd+=iIZE87%N*`zS=qA+A@<553ZcK+Wq~?HQOi4UnI6J z9)O3gI}iUn+V|qV-=n33(;hKewL{4($9%OZ$1~RWB#e2V-XVNba^roJ*Y&uG#D249?38(CGyL0w z?_quw-Wyz#P?L9_wooI2nuyXxJPx@JP7Mk3jh!LtvWN*G8Abzo{uz#Qy$+Qb)k zJMdd&b!7QVQF4AqO?+d(vlrwYij6^!TM}P=*l_rbf6)qT&`K$}ecJjtOZPtt|Dy_3 zk{;E^ijPMw**seQM?N8|+P~u^vApD6I#ZVs{c-KdEe6M=djpxwJZ}8c?p)aep;G68 zwc64}O!rgyCHAJQ&i8X&O1U5Ax|kj1R=)Pzbx*3GoQ-@$h7HBH(raRW8$KTH%vKFS zBPvZ+xg$t%1Aeo*?gf71?&-DFeF-Q;8A}VS$dmW0k^FJ!&-U}iW{@$yV2{kAe74_w zm>;5($7boSkWcq8Py)ABJ=k=)$37thHe+l4b_Q5$s=(h4UOOj9(Kor4ot=H?S(st) zCOqur7o}AJJL#9wE1T2og6)c4^w?l_rku?<1{dtvx?gEfU+c?pQ{#lU@XqWjBT{N> z`F~9NT_}VroAUqoy*5|?hpy?0RY~+}w66FvEcv_Hur$hfDF9zy-6R$I8dpgp-o$)) x@j7g*rTN%mXmVTFus4KcpN{^S=BqTN2IE(|a+AS3OAS!8Q6@ynQ2F1|e*vwHZ-oE= literal 0 HcmV?d00001 diff --git a/modular_darkpack/modules/martial/swords.dm b/modular_darkpack/modules/martial/swords.dm index 36341b1ff4e6..107c4b7493a0 100644 --- a/modular_darkpack/modules/martial/swords.dm +++ b/modular_darkpack/modules/martial/swords.dm @@ -36,7 +36,7 @@ AddComponent( \ /datum/component/combo_attacks, \ combos = combo_list, \ - max_combo_length = 4, \ + max_combo_length = 3, \ examine_message = span_notice("This seems to be a skilled weapon... perhaps I could use my experience?"), \ reset_message = "you return to neutral stance", \ can_attack_callback = CALLBACK(src, PROC_REF(can_combo_attack)) \ From 245bcdae08a37ba07c2859e89f0ad9242bfe3d2e Mon Sep 17 00:00:00 2001 From: SELFHELL <99771731+SELFHELL@users.noreply.github.com> Date: Sat, 21 Mar 2026 15:55:22 -0500 Subject: [PATCH 5/9] More SFX & adjustments --- modular_darkpack/modules/martial/kungfu.dm | 20 +++++++++--------- .../modules/martial/sounds/mainpunch2.ogg | Bin 0 -> 10816 bytes 2 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 modular_darkpack/modules/martial/sounds/mainpunch2.ogg diff --git a/modular_darkpack/modules/martial/kungfu.dm b/modular_darkpack/modules/martial/kungfu.dm index edb3942bfad5..890af82020df 100644 --- a/modular_darkpack/modules/martial/kungfu.dm +++ b/modular_darkpack/modules/martial/kungfu.dm @@ -26,7 +26,7 @@ limb.unarmed_damage_low += 5 limb.unarmed_damage_high += 5 - limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/frontalkick2.ogg' + limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/mainpunch2.ogg' /datum/martial_art/kungfu/deactivate_style(mob/living/remove_from) UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_PRE_BULLET_ACT, COMSIG_LIVING_CHECK_BLOCK)) @@ -60,7 +60,7 @@ ) playsound(attacker, 'modular_darkpack/modules/martial/sounds/frontalkick.ogg', 50, TRUE, -1) var/atom/throw_target = get_edge_target_turf(defender, attacker.dir) - var/throw_distance = max(1, (attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA))) //If the defenders fortitude is greater than the attackers strength, it defaults to 1 + var/throw_distance = clamp((attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA)), 1, 3) defender.throw_at(throw_target, throw_distance, 4, attacker) defender.apply_damage(15, attacker.get_attack_type(), BODY_ZONE_CHEST, wound_bonus = CANT_WOUND) log_combat(attacker, defender, "Frontal Kicked (Kungfu)") @@ -86,7 +86,7 @@ /// Flying Knee: Grab Harm combo, causes them to be silenced and briefly stunned, as well as doing a moderate amount of stamina damage. /datum/martial_art/kungfu/proc/knee_stomach(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) - playsound(attacker, 'modular_darkpack/modules/martial/sounds/kneeing.ogg', 50, TRUE, -1) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 50, TRUE, -1) defender.visible_message( span_warning("[attacker] violently slams [attacker.p_their()] knee into [defender]!"), span_userdanger("You slam your knee straight into [defender]!"), @@ -94,7 +94,10 @@ COMBAT_MESSAGE_RANGE, attacker, ) - defender.apply_damage(20, STAMINA) + var/roll_success = SSroll.storyteller_roll((attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), difficulty = 8, roller = attacker) + if(roll_success) + defender.Knockdown(3 SECONDS) + defender.apply_damage(40, STAMINA) defender.adjust_silence_up_to(5 SECONDS, 5 SECONDS) log_combat(attacker, defender, "kneed in the stomach (Kung-Fu)") return TRUE @@ -112,7 +115,7 @@ var/grab_log_description = "grabbed" attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) - playsound(defender, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 25, TRUE, -1) + playsound(defender, 'modular_darkpack/modules/martial/sounds/frontalkick2.ogg', 25, TRUE, -1) defender.apply_damage(20, STAMINA) log_combat(attacker, defender, "[grab_log_description] (Sleeping Carp)") return MARTIAL_ATTACK_INVALID // normal grab @@ -168,10 +171,7 @@ var/determine_avoidance = 100 - determine_avoidance = ((user.st_get_stat(STAT_BRAWL) + user.st_get_stat(STAT_DEXTERITY)) * 10) - - if(istype(hitting_projectile, /obj/projectile/bullet/harpoon)) // WHITE WHALE HOLY GRAIL - return NONE + determine_avoidance = ((user.st_get_stat(STAT_BRAWL) + user.st_get_stat(STAT_DEXTERITY)) * 3) if(!user.is_clan(/datum/vampire_clan/true_brujah)) return NONE //No, you cant dodge bullets normally, bum. @@ -203,7 +203,7 @@ /datum/martial_art/kungfu/proc/check_dodge(mob/living/user, atom/movable/hitby, damage, attack_text, attack_type, ...) SIGNAL_HANDLER - var/determine_avoidance = ((user.st_get_stat(STAT_BRAWL) + user.st_get_stat(STAT_DEXTERITY)) * 2) + var/determine_avoidance = ((user.st_get_stat(STAT_BRAWL) + user.st_get_stat(STAT_DEXTERITY))) if(!can_deflect(user)) return diff --git a/modular_darkpack/modules/martial/sounds/mainpunch2.ogg b/modular_darkpack/modules/martial/sounds/mainpunch2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..2c0f7b2b8cdd5488fed70cf6081949bff237ebde GIT binary patch literal 10816 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 Date: Sat, 21 Mar 2026 17:59:44 -0500 Subject: [PATCH 6/9] Necksnap (Move to CQB Later) --- modular_darkpack/modules/martial/kungfu.dm | 35 ++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/modular_darkpack/modules/martial/kungfu.dm b/modular_darkpack/modules/martial/kungfu.dm index 890af82020df..ec6fbcd5cf2f 100644 --- a/modular_darkpack/modules/martial/kungfu.dm +++ b/modular_darkpack/modules/martial/kungfu.dm @@ -24,8 +24,9 @@ LAZYADD(affected_bodyparts, limb) - limb.unarmed_damage_low += 5 - limb.unarmed_damage_high += 5 + //limb.unarmed_damage_low += 5 Unsure on this one + //limb.unarmed_damage_high += 5 + limb.unarmed_attack_effect = null limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/mainpunch2.ogg' /datum/martial_art/kungfu/deactivate_style(mob/living/remove_from) @@ -121,6 +122,36 @@ return MARTIAL_ATTACK_INVALID // normal grab /datum/martial_art/kungfu/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)) + if(!do_after(attacker, (20 - (attacker.st_get_stat(STAT_DEXTERITY) + attacker.st_get_stat(STAT_MEDICINE))) , defender)) + defender.balloon_alert(attacker, "failed to necksnap!") + to_chat(attacker, span_warning("You fail to grip [defender]'s neck!")) + var/snappower = clamp((1 + attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA)), 0, 10) + if(snappower == 0) + defender.balloon_alert(attacker, "not strong enough to necksnap!") + defender.visible_message( + span_notice("[attacker] fails to snap the neck of [defender]."), + span_userdanger("[attacker]'s weak hands were unable to snap your neck'."), + ) + return MARTIAL_ATTACK_FAIL + 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") //I would call kill() for normal humans but necksnapping a NPC with Str 5 already does it + defender.apply_damage(snappower LETHAL_TTRPG_DAMAGE, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) + return MARTIAL_ATTACK_SUCCESS + if(defender.check_block(attacker, 10, attacker.name, UNARMED_ATTACK)) return MARTIAL_ATTACK_FAIL From 30cbd7d1de3eeddb80f533b146e90c56b1c0e6e3 Mon Sep 17 00:00:00 2001 From: SELFHELL <99771731+SELFHELL@users.noreply.github.com> Date: Sun, 22 Mar 2026 15:44:49 -0500 Subject: [PATCH 7/9] Street Boxing SFX + Dodge Animation TODO: Combo Moves --- code/datums/components/butchering.dm | 3 +- .../modules/martial/artdefines.dm | 3 + modular_darkpack/modules/martial/cqb.dm | 191 +++--- modular_darkpack/modules/martial/defines.dm | 1 - modular_darkpack/modules/martial/kungfu.dm | 78 +-- .../modules/martial/sounds/bell.ogg | Bin 0 -> 11486 bytes .../modules/martial/sounds/cross.ogg | Bin 0 -> 7768 bytes .../modules/martial/sounds/harmboxing.ogg | Bin 0 -> 8066 bytes .../modules/martial/sounds/hook.ogg | Bin 0 -> 8903 bytes .../modules/martial/sounds/jab combo.ogg | Bin 0 -> 9976 bytes .../modules/martial/sounds/swipe.ogg | Bin 0 -> 8576 bytes .../modules/martial/sounds/uppercut.ogg | Bin 0 -> 7705 bytes .../modules/martial/streetboxing.dm | 607 +++++++----------- modular_darkpack/modules/martial/swords.dm | 3 +- tgstation.dme | 4 +- 15 files changed, 351 insertions(+), 539 deletions(-) create mode 100644 modular_darkpack/modules/martial/artdefines.dm delete mode 100644 modular_darkpack/modules/martial/defines.dm create mode 100644 modular_darkpack/modules/martial/sounds/bell.ogg create mode 100644 modular_darkpack/modules/martial/sounds/cross.ogg create mode 100644 modular_darkpack/modules/martial/sounds/harmboxing.ogg create mode 100644 modular_darkpack/modules/martial/sounds/hook.ogg create mode 100644 modular_darkpack/modules/martial/sounds/jab combo.ogg create mode 100644 modular_darkpack/modules/martial/sounds/swipe.ogg create mode 100644 modular_darkpack/modules/martial/sounds/uppercut.ogg diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 067838433f74..35c896388f74 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -334,6 +334,7 @@ var/static/list/butcher_spots = typecacheof(list( /obj/structure/table, /obj/structure/bed, + /obj/structure/chair, //DARKPACK EDIT BUTCHERING: Chairs added because of prevelence and the general non-supporting of construction mechanics /obj/machinery/stasis, /obj/structure/kitchenspike, )) @@ -345,7 +346,7 @@ break if (!found_spot) - to_chat(user, span_warning("You need a better spot to butcher [victim]!")) + to_chat(user, span_warning("You need to butcher [victim] on a table/chair!")) //DARKPACK EDIT BUTCHERING ORIGINAL: "You need a better spot to butcher [victim]!" return var/obj/item/bodypart/limb = victim.get_bodypart(deprecise_zone(user.zone_selected)) diff --git a/modular_darkpack/modules/martial/artdefines.dm b/modular_darkpack/modules/martial/artdefines.dm new file mode 100644 index 000000000000..38e40c14dac8 --- /dev/null +++ b/modular_darkpack/modules/martial/artdefines.dm @@ -0,0 +1,3 @@ +#define MARTIALART_DARKPACK_KUNGFU "kungfu" +#define MARTIALART_DARKPACK_CQB "cqb" +#define MARTIALART_DARKPACK_BOXING "streetboxing" diff --git a/modular_darkpack/modules/martial/cqb.dm b/modular_darkpack/modules/martial/cqb.dm index 572c609417cf..890fceb39954 100644 --- a/modular_darkpack/modules/martial/cqb.dm +++ b/modular_darkpack/modules/martial/cqb.dm @@ -2,44 +2,42 @@ #define KICK_COMBO "HH" #define RESTRAIN_COMBO "GG" #define PRESSURE_COMBO "DG" -#define CONSECUTIVE_COMBO "DDH" -/datum/martial_art/darkpack/cqb +/datum/martial_art/darkpack_cqb name = "CQC" - id = MARTIALART_CQB + id = MARTIALART_DARKPACK_CQB 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 -/datum/martial_art/cqc/activate_style(mob/living/new_holder) +/datum/martial_art/darkpack_cqb/activate_style(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)) - if (iscarbon(owner)) - var/mob/living/carbon/carbon_owner = owner + if (iscarbon(new_holder)) + var/list/obj/item/bodypart/affected_bodyparts + var/mob/living/carbon/human/carbon_owner = new_holder for (var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts) if (!istype(limb, /obj/item/bodypart/arm) && !istype(limb, /obj/item/bodypart/leg)) continue LAZYADD(affected_bodyparts, limb) - limb.unarmed_damage_low += 5 - limb.unarmed_damage_high += 5 + //limb.unarmed_damage_low += 5 Unsure on this one + //limb.unarmed_damage_high += 5 + limb.unarmed_attack_effect = null limb.unarmed_attack_sound = 'sound/items/weapons/cqchit1.ogg' -/datum/martial_art/cqc/deactivate_style(mob/living/remove_from) - UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_LIVING_CHECK_BLOCK)) +/datum/martial_art/darkpack_cqb/deactivate_style(mob/living/remove_from) return ..() -/datum/martial_art/cqc/reset_streak(mob/living/new_target) +/datum/martial_art/darkpack_cqb/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) +/datum/martial_art/darkpack_cqb/proc/check_streak(mob/living/attacker, mob/living/defender) if(findtext(streak, SLAM_COMBO)) reset_streak() return Slam(attacker, defender) @@ -52,16 +50,13 @@ 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) +/datum/martial_art/darkpack_cqb/proc/Slam(mob/living/attacker, mob/living/defender) if(defender.body_position != STANDING_UP) return FALSE - attacker.do_attack_animation(defender) + attacker.do_attack_animation(defender) //Potentially change the flow of this combo to describe a failed slam if the Stam vs Str difference is high for optimal brick wall gameplay. Potentially 6 Str?? defender.visible_message( span_danger("[attacker] slams [defender] into the ground!"), span_userdanger("You're slammed into the ground by [attacker]!"), @@ -72,16 +67,20 @@ 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)") + defender.Knockdown(3 SECONDS) + var/stun_time = SSroll.storyteller_roll((attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), difficulty = 6, numerical = TRUE, roller = attacker) //In THEORY this should be attacker weighted, with high stamima users shrugging it off. + var/defended_time = SSroll.storyteller_roll(defender.st_get_stat(STAT_STAMINA) * 2, difficulty = (attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), numerical = TRUE, roller = defender) + stun_time = clamp((stun_time-defended_time), 0, 10) + defender.Paralyze(stun_time SECONDS) + log_combat(attacker, defender, "slammed (CQB)") return TRUE -/datum/martial_art/cqc/proc/Kick(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_cqb/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.get_stamina_loss() >= 100) + if(defender.body_position == LYING_DOWN && !defender.IsUnconscious() && !iskindred(defender) && defender.get_stamina_loss() >= 0) //This is EXTREMELY conditional to make sure it's not abused to shit log_combat(attacker, defender, "knocked out (Head kick)(CQC)") defender.visible_message( span_danger("[attacker] kicks [defender]'s head, knocking [defender.p_them()] out!"), @@ -93,10 +92,10 @@ 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) + var/helmet_protection = (defender.run_armor_check(BODY_ZONE_HEAD, MELEE) + (defender.st_get_stat(STAT_STAMINA) * 5)) defender.apply_effect(20 SECONDS, EFFECT_KNOCKDOWN, helmet_protection) defender.apply_effect(10 SECONDS, EFFECT_UNCONSCIOUS, helmet_protection) - defender.adjust_organ_loss(ORGAN_SLOT_BRAIN, 15, 150) + //defender.adjust_organ_loss(ORGAN_SLOT_BRAIN, 15, 150) brain damage is the WORST else defender.visible_message( @@ -117,7 +116,7 @@ return TRUE -/datum/martial_art/cqc/proc/Pressure(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_cqb/proc/Pressure(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender) log_combat(attacker, defender, "pressured (CQC)") defender.visible_message( @@ -128,17 +127,32 @@ attacker, ) to_chat(attacker, span_danger("You punch [defender]'s neck!")) - defender.adjust_stamina_loss(60) + defender.adjust_dizzy_up_to((10-defender.st_get_stat(STAT_STAMINA)) SECONDS, 10 SECONDS) + defender.adjust_stamina_loss(50) playsound(attacker, 'sound/items/weapons/cqchit1.ogg', 50, TRUE, -1) return TRUE -/datum/martial_art/cqc/proc/Restrain(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_cqb/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)") + var/stun_time = SSroll.storyteller_roll((attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), difficulty = 6, numerical = TRUE, roller = attacker) //In THEORY this should be attacker weighted, with high stamima users shrugging it off. + var/defended_time = SSroll.storyteller_roll(defender.st_get_stat(STAT_STAMINA) + defender.st_get_stat(STAT_ATHLETICS), difficulty = (attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), numerical = TRUE, roller = defender) + var/total_time = stun_time - defended_time + if(total_time <= 0) + log_combat(attacker, defender, "failed restrained (CQB)") + defender.visible_message( + span_warning("[attacker] failes to get [defender] into a restraining hold!"), + span_userdanger("You've managed to resist a restraining hold by [attacker]!"), + span_hear("You hear shuffling and a muffled groan!"), + null, + attacker, + ) + to_chat(attacker, span_danger("You fail to lock [defender] into a restraining position!")) + defender.adjust_stamina_loss(20) + return TRUE + log_combat(attacker, defender, "restrained (CQB)") defender.visible_message( span_warning("[attacker] locks [defender] into a restraining position!"), span_userdanger("You're locked into a restraining position by [attacker]!"), @@ -148,34 +162,12 @@ ) to_chat(attacker, span_danger("You lock [defender] into a restraining position!")) defender.adjust_stamina_loss(20) - defender.Stun(10 SECONDS) + defender.Stun(total_time 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.adjust_stamina_loss(50) - defender.apply_damage(25, attacker.get_attack_type()) - return TRUE - -/datum/martial_art/cqc/grab_act(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_cqb/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)) @@ -203,7 +195,7 @@ 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) +/datum/martial_art/darkpack_cqb/harm_act(mob/living/attacker, mob/living/defender) if(attacker.grab_state == GRAB_KILL \ && attacker.zone_selected == BODY_ZONE_HEAD \ && attacker.pulling == defender \ @@ -211,6 +203,18 @@ ) var/obj/item/bodypart/head = defender.get_bodypart(BODY_ZONE_HEAD) if(!isnull(head)) + if(!do_after(attacker, (20 - (attacker.st_get_stat(STAT_DEXTERITY) + attacker.st_get_stat(STAT_MEDICINE))) , defender)) + defender.balloon_alert(attacker, "failed to necksnap!") + to_chat(attacker, span_warning("Your hands slip off [defender]'s neck!")) + return MARTIAL_ATTACK_FAIL + var/snappower = clamp((1 + attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA)), 0, 10) + if(snappower == 0) + defender.balloon_alert(attacker, "not strong enough to necksnap!") + defender.visible_message( + span_notice("[attacker] fails to snap the neck of [defender]."), + span_userdanger("[attacker]'s weak hands were unable to snap your neck'."), + ) + return MARTIAL_ATTACK_FAIL playsound(defender, 'sound/effects/wounds/crack1.ogg', 100) defender.visible_message( span_danger("[attacker] snaps the neck of [defender]!"), @@ -219,17 +223,14 @@ 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) + log_combat(attacker, defender, "snapped neck") //I would call kill() for normal humans but necksnapping a NPC with Str 5 already does it + defender.apply_damage(snappower LETHAL_TTRPG_DAMAGE, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) return MARTIAL_ATTACK_SUCCESS - if(defender.check_block(attacker, 10, attacker.name, UNARMED_ATTACK)) + if(defender.check_block(attacker, 10, attacker.name, UNARMED_ATTACK)) //it's impossible to miss the neck of someone you're already strangling to death return MARTIAL_ATTACK_FAIL - if(attacker.resting && defender.stat != DEAD && defender.body_position == STANDING_UP) + if(attacker.resting && defender.stat != DEAD && defender.body_position == STANDING_UP) //This probably needs to go, unsure currently defender.visible_message( span_danger("[attacker] leg sweeps [defender]!"), span_userdanger("Your legs are sweeped by [attacker]!"), @@ -249,28 +250,27 @@ 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) + var/obj/item/bodypart/arm/active_arm = attacker.get_active_hand() + var/stomp_force = ((active_arm.unarmed_damage_high + attacker.st_get_stat(STAT_STRENGTH))*(1 + ((attacker.st_get_stat(STAT_STRENGTH) - 2) / 5))) //I would prefer to move the different stomp effects into the attack chain properly, but that's a jankier solution then doing this + var/picked_hit_type = pick("kick", "stomp") + defender.apply_damage(stomp_force, BRUTE) + playsound(defender, (picked_hit_type == "kick" || picked_hit_type == "stomp") ? 'sound/items/weapons/cqchit2.ogg' : 'sound/items/weapons/cqchit1.ogg', 50, TRUE, -1) - 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 - 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 + return MARTIAL_ATTACK_INVALID //Outside these two exceptions, punching logic operates normally -/datum/martial_art/cqc/disarm_act(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_cqb/disarm_act(mob/living/attacker, mob/living/defender) if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK)) return MARTIAL_ATTACK_FAIL @@ -288,6 +288,7 @@ attacker, ) to_chat(attacker, span_danger("You put [defender] into a chokehold!")) + //this is gonna be a tricky one to figure out defender.SetSleeping(40 SECONDS) restraining_mob = null if(attacker.grab_state < GRAB_NECK && !HAS_TRAIT(attacker, TRAIT_PACIFISM)) @@ -329,17 +330,16 @@ return MARTIAL_ATTACK_FAIL -/mob/living/proc/CQC_help() +/mob/living/proc/CQB_help() set name = "Remember The Basics" - set desc = "You try to remember some of the basics of CQC." - set category = "CQC" - to_chat(usr, "You try to remember some of the basics of CQC.") + set desc = "You try to remember some of the basics of CQB." + set category = "Martial Art" + to_chat(usr, "You try to remember some of the basics of CQB.") 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("CQB 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, "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.") @@ -349,9 +349,18 @@ #undef KICK_COMBO #undef RESTRAIN_COMBO #undef PRESSURE_COMBO -#undef CONSECUTIVE_COMBO -// animate(carp_user, alpha = 0, time = 0.1 SECONDS) -// new /obj/effect/temporis/weskar(carp_user.loc, carp_user) -// sleep(0.1 SECONDS) -// animate(carp_user, alpha = 225, time = 0.1 SECONDS) +/obj/item/clothing/gloves/cqb_gloves + name = "Debugging Gloves" + desc = "Delete at some point" + icon_state = "black" + greyscale_colors = COLOR_BLACK + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT + heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT + resistance_flags = NONE + +/obj/item/clothing/gloves/cqb_gloves/Initialize(mapload) + . = ..() + AddComponent(/datum/component/martial_art_giver, /datum/martial_art/darkpack_cqb) diff --git a/modular_darkpack/modules/martial/defines.dm b/modular_darkpack/modules/martial/defines.dm deleted file mode 100644 index 130a67138f44..000000000000 --- a/modular_darkpack/modules/martial/defines.dm +++ /dev/null @@ -1 +0,0 @@ -#define MARTIALART_DARKPACK_KUNGFU "kungfu" diff --git a/modular_darkpack/modules/martial/kungfu.dm b/modular_darkpack/modules/martial/kungfu.dm index ec6fbcd5cf2f..9a3ad213a2b5 100644 --- a/modular_darkpack/modules/martial/kungfu.dm +++ b/modular_darkpack/modules/martial/kungfu.dm @@ -2,7 +2,7 @@ #define DROP_KICK_COMBO "DD" #define KNEE_STOMACH_COMBO "GH" -/datum/martial_art/kungfu +/datum/martial_art/darkpack_kungfu name = "Kung Fu" id = MARTIALART_DARKPACK_KUNGFU help_verb = /mob/living/proc/kungfu_help @@ -10,7 +10,7 @@ grab_state_modifier = 1 -/datum/martial_art/kungfu/activate_style(mob/living/new_holder) +/datum/martial_art/darkpack_kungfu/activate_style(mob/living/new_holder) . = ..() //RegisterSignal(new_holder, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignal(new_holder, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile)) @@ -27,13 +27,13 @@ //limb.unarmed_damage_low += 5 Unsure on this one //limb.unarmed_damage_high += 5 limb.unarmed_attack_effect = null - limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/mainpunch2.ogg' + limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/harmboxing.ogg' -/datum/martial_art/kungfu/deactivate_style(mob/living/remove_from) +/datum/martial_art/darkpack_kungfu/deactivate_style(mob/living/remove_from) UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_PRE_BULLET_ACT, COMSIG_LIVING_CHECK_BLOCK)) return ..() -/datum/martial_art/kungfu/proc/check_streak(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_kungfu/proc/check_streak(mob/living/attacker, mob/living/defender) if(findtext(streak,LAUNCH_KICK_COMBO)) reset_streak() @@ -50,7 +50,7 @@ return FALSE /// Frontal Kick: Harm Disarm combo, knocks back relative to Attacker Str - Defender Fort -/datum/martial_art/kungfu/proc/launch_kick(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_kungfu/proc/launch_kick(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!"), @@ -68,26 +68,28 @@ return TRUE /// Roundhouse Kick: 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/kungfu/proc/drop_kick(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_kungfu/proc/drop_kick(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) playsound(attacker, 'modular_darkpack/modules/martial/sounds/roundhousekick.ogg', 50, TRUE, -1) - if(defender.body_position == STANDING_UP) - defender.Knockdown(4 SECONDS) + var/kickpower = SSroll.storyteller_roll((attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), difficulty = 7, numerical = TRUE, roller = attacker) + if(defender.body_position == STANDING_UP && (kickpower >= 0)) + defender.Knockdown(kickpower SECONDS) defender.visible_message(span_warning("[attacker] kicks [defender] in the head, sending them face first into the floor!"), \ span_userdanger("You are kicked in the head by [attacker], sending you crashing to the floor!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) else defender.drop_all_held_items() defender.visible_message(span_warning("[attacker] kicks [defender] in the head!"), \ span_userdanger("You are kicked in the head by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) + defender.apply_damage(10, attacker.get_attack_type()) defender.apply_damage(40, STAMINA) defender.adjust_dizzy_up_to(10 SECONDS, 10 SECONDS) log_combat(attacker, defender, "Roundhoused (KungFu)") return TRUE /// Flying Knee: Grab Harm combo, causes them to be silenced and briefly stunned, as well as doing a moderate amount of stamina damage. -/datum/martial_art/kungfu/proc/knee_stomach(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_kungfu/proc/knee_stomach(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) - playsound(attacker, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 50, TRUE, -1) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 70, TRUE, -1) defender.visible_message( span_warning("[attacker] violently slams [attacker.p_their()] knee into [defender]!"), span_userdanger("You slam your knee straight into [defender]!"), @@ -103,7 +105,7 @@ log_combat(attacker, defender, "kneed in the stomach (Kung-Fu)") return TRUE -/datum/martial_art/kungfu/grab_act(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_kungfu/grab_act(mob/living/attacker, mob/living/defender) if(!can_deflect(attacker)) //allows for deniability return MARTIAL_ATTACK_INVALID @@ -121,37 +123,7 @@ log_combat(attacker, defender, "[grab_log_description] (Sleeping Carp)") return MARTIAL_ATTACK_INVALID // normal grab -/datum/martial_art/kungfu/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)) - if(!do_after(attacker, (20 - (attacker.st_get_stat(STAT_DEXTERITY) + attacker.st_get_stat(STAT_MEDICINE))) , defender)) - defender.balloon_alert(attacker, "failed to necksnap!") - to_chat(attacker, span_warning("You fail to grip [defender]'s neck!")) - var/snappower = clamp((1 + attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA)), 0, 10) - if(snappower == 0) - defender.balloon_alert(attacker, "not strong enough to necksnap!") - defender.visible_message( - span_notice("[attacker] fails to snap the neck of [defender]."), - span_userdanger("[attacker]'s weak hands were unable to snap your neck'."), - ) - return MARTIAL_ATTACK_FAIL - 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") //I would call kill() for normal humans but necksnapping a NPC with Str 5 already does it - defender.apply_damage(snappower LETHAL_TTRPG_DAMAGE, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) - return MARTIAL_ATTACK_SUCCESS - +/datum/martial_art/darkpack_kungfu/harm_act(mob/living/attacker, mob/living/defender) if(defender.check_block(attacker, 10, attacker.name, UNARMED_ATTACK)) return MARTIAL_ATTACK_FAIL @@ -161,7 +133,7 @@ return MARTIAL_ATTACK_INVALID // normal punch -/datum/martial_art/kungfu/disarm_act(mob/living/attacker, mob/living/defender) +/datum/martial_art/darkpack_kungfu/disarm_act(mob/living/attacker, mob/living/defender) if(!can_deflect(attacker)) //allows for deniability return MARTIAL_ATTACK_INVALID if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK)) @@ -177,7 +149,7 @@ log_combat(attacker, defender, "disarmed (Sleeping Carp)") return MARTIAL_ATTACK_INVALID // normal disarm -/datum/martial_art/kungfu/proc/can_deflect(mob/living/user) +/datum/martial_art/darkpack_kungfu/proc/can_deflect(mob/living/user) if(!can_use(user) || !user.combat_mode) return FALSE if(INCAPACITATED_IGNORING(user, INCAPABLE_GRAB)) //NO STUN @@ -190,23 +162,21 @@ return FALSE return TRUE -/datum/martial_art/kungfu/proc/reset_animation(mob/living/user, fadein) +/datum/martial_art/darkpack_kungfu/proc/reset_animation(mob/living/user, fadein) if(fadein) animate(user, alpha = 225, time = 0.1 SECONDS) return else animate(user, pixel_x = 0, pixel_y = 0, time = 0.1 SECONDS) -/datum/martial_art/kungfu/proc/hit_by_projectile(mob/living/user, obj/projectile/hitting_projectile, def_zone) +/datum/martial_art/darkpack_kungfu/proc/hit_by_projectile(mob/living/user, obj/projectile/hitting_projectile, def_zone) SIGNAL_HANDLER - var/determine_avoidance = 100 - - determine_avoidance = ((user.st_get_stat(STAT_BRAWL) + user.st_get_stat(STAT_DEXTERITY)) * 3) - if(!user.is_clan(/datum/vampire_clan/true_brujah)) return NONE //No, you cant dodge bullets normally, bum. + var/determine_avoidance = ((user.st_get_stat(STAT_ATHLETICS) + user.st_get_stat(STAT_DEXTERITY)) * 7) + if(!can_deflect(user)) return NONE @@ -231,10 +201,10 @@ return COMPONENT_BULLET_PIERCED /// If our user has committed to being as martial arty as they can be, they may be able to avoid incoming attacks. -/datum/martial_art/kungfu/proc/check_dodge(mob/living/user, atom/movable/hitby, damage, attack_text, attack_type, ...) +/datum/martial_art/darkpack_kungfu/proc/check_dodge(mob/living/user, atom/movable/hitby, damage, attack_text, attack_type, ...) SIGNAL_HANDLER - var/determine_avoidance = ((user.st_get_stat(STAT_BRAWL) + user.st_get_stat(STAT_DEXTERITY))) + var/determine_avoidance = ((user.st_get_stat(STAT_ATHLETICS) + user.st_get_stat(STAT_DEXTERITY))) if(!can_deflect(user)) return @@ -295,4 +265,4 @@ /obj/item/clothing/gloves/kungfu_gloves/Initialize(mapload) . = ..() - AddComponent(/datum/component/martial_art_giver, /datum/martial_art/kungfu) + AddComponent(/datum/component/martial_art_giver, /datum/martial_art/darkpack_kungfu) diff --git a/modular_darkpack/modules/martial/sounds/bell.ogg b/modular_darkpack/modules/martial/sounds/bell.ogg new file mode 100644 index 0000000000000000000000000000000000000000..6a23df1f7f2f2e4825ced7718115fca5a913c908 GIT binary patch literal 11486 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 literal 0 HcmV?d00001 diff --git a/modular_darkpack/modules/martial/sounds/cross.ogg b/modular_darkpack/modules/martial/sounds/cross.ogg new file mode 100644 index 0000000000000000000000000000000000000000..39afbaf6b905b6120fdab9037a8d57bf1ae0a4d5 GIT binary patch literal 7768 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 J{>=EN{Xcc~tXcp7 literal 0 HcmV?d00001 diff --git a/modular_darkpack/modules/martial/sounds/harmboxing.ogg b/modular_darkpack/modules/martial/sounds/harmboxing.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c3e98e3fa1d74ec1f8acacf92eb9e4c7d3313cf5 GIT binary patch literal 8066 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 HmVy5RKrTMU literal 0 HcmV?d00001 diff --git a/modular_darkpack/modules/martial/sounds/hook.ogg b/modular_darkpack/modules/martial/sounds/hook.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ac00ebf1e02faf1cad78242893f549cad8de6d04 GIT binary patch literal 8903 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 O3F#!jEElB)(ET5kl%A9T literal 0 HcmV?d00001 diff --git a/modular_darkpack/modules/martial/streetboxing.dm b/modular_darkpack/modules/martial/streetboxing.dm index e15075aa5959..1c31fa417ba1 100644 --- a/modular_darkpack/modules/martial/streetboxing.dm +++ b/modular_darkpack/modules/martial/streetboxing.dm @@ -1,438 +1,265 @@ -#define LEFT_RIGHT_COMBO "DH" -#define RIGHT_LEFT_COMBO "HD" -#define LEFT_LEFT_COMBO "HH" -#define RIGHT_RIGHT_COMBO "DD" - -#define STRAIGHT_PUNCH "straight_punch" -#define RIGHT_HOOK "right_hook" -#define LEFT_HOOK "left_hook" -#define UPPERCUT "uppercut" -#define LIGHT_JAB "light_jab" -#define DISCOMBOBULATE "discombobulate" -#define BLIND_JAB "blind_jab" -#define CRAVEN_BLOW "craven_blow" -#define NO_COMBO "" - -/datum/martial_art/darkpack/streetboxing - name = "Boxing" - id = MARTIALART_BOXING - pacifist_style = TRUE - help_verb = /mob/living/proc/boxing_help - /// Boolean on whether we are sportsmanlike in our tussling; TRUE means we have restrictions - var/honorable_boxer = TRUE - /// Default damage type for our boxing. - var/default_damage_type = STAMINA - /// List of traits applied to users of this martial art. - var/list/boxing_traits = list(TRAIT_BOXING_READY) - -/datum/martial_art/boxing/can_teach(mob/living/new_holder) - return ishuman(new_holder) - -/datum/martial_art/boxing/activate_style(mob/living/new_holder) - . = ..() - new_holder.add_traits(boxing_traits, BOXING_TRAIT) - RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block)) +#define UPPERCUT_COMBO "HDH" +#define JAB_COMBO "GHH" +#define CROSS_COMBO "DH" +#define DIRTY_COMBO "GD" + +/datum/martial_art/darkpack_boxing + name = "Kung Fu" + id = MARTIALART_DARKPACK_BOXING + help_verb = /mob/living/proc/streetboxing_help + display_combos = TRUE + grab_state_modifier = 1 + -/datum/martial_art/boxing/deactivate_style(mob/living/remove_from) - remove_from.remove_traits(boxing_traits, BOXING_TRAIT) +/datum/martial_art/darkpack_boxing/activate_style(mob/living/new_holder) + . = ..() + //RegisterSignal(new_holder, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) + RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_dodge)) + if (iscarbon(new_holder)) + var/list/obj/item/bodypart/affected_bodyparts + var/mob/living/carbon/human/carbon_owner = new_holder + for (var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts) + if (!istype(limb, /obj/item/bodypart/arm) && !istype(limb, /obj/item/bodypart/leg)) + continue + + LAZYADD(affected_bodyparts, limb) + + //limb.unarmed_damage_low += 5 Unsure on this one + //limb.unarmed_damage_high += 5 + limb.unarmed_attack_effect = null + limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/mainpunch2.ogg' + +/datum/martial_art/darkpack_boxing/deactivate_style(mob/living/remove_from) UnregisterSignal(remove_from, list(COMSIG_LIVING_CHECK_BLOCK)) return ..() -///Unlike most instances of this proc, this is actually called in _proc/tussle() -///Returns a multiplier on our skill damage bonus. -/datum/martial_art/boxing/proc/check_streak(mob/living/attacker, mob/living/defender, obj/item/bodypart/arm/active_arm) - if(check_behind(attacker, defender) && !honorable_boxer) - reset_streak() - return CRAVEN_BLOW +/datum/martial_art/darkpack_boxing/proc/check_streak(mob/living/attacker, mob/living/defender) - if(HAS_TRAIT(attacker, TRAIT_DETECTIVES_TASTE) && defender.is_blind()) //In short: discombobulate + if(findtext(streak,UPPERCUT_COMBO)) reset_streak() - return DISCOMBOBULATE + return uppercut(attacker, defender) - if(findtext(streak, LEFT_LEFT_COMBO) && active_arm.body_zone == BODY_ZONE_R_ARM || findtext(streak, RIGHT_RIGHT_COMBO) && active_arm.body_zone == BODY_ZONE_L_ARM) + if(findtext(streak,JAB_COMBO)) reset_streak() - if(attacker.is_blind()) - return BLIND_JAB - else - return LIGHT_JAB + return jab_combo(attacker, defender) - else if(findtext(streak, LEFT_LEFT_COMBO) && active_arm.body_zone == BODY_ZONE_L_ARM || findtext(streak, RIGHT_RIGHT_COMBO) && active_arm.body_zone == BODY_ZONE_R_ARM) + if(findtext(streak,CROSS_COMBO)) reset_streak() - return STRAIGHT_PUNCH + return cross_punch(attacker, defender) - if(findtext(streak, LEFT_RIGHT_COMBO) || findtext(streak, RIGHT_LEFT_COMBO)) + if(findtext(streak,DIRTY_COMBO)) reset_streak() - if(active_arm.body_zone == BODY_ZONE_L_ARM) - if(findtext(streak, RIGHT_LEFT_COMBO)) - return LEFT_HOOK - - else if(active_arm.body_zone == BODY_ZONE_R_ARM) - if(findtext(streak, LEFT_RIGHT_COMBO)) - return RIGHT_HOOK - else - return UPPERCUT - - return NO_COMBO - -/// An extra effect on some moves and attacks. -/datum/martial_art/boxing/proc/perform_extra_effect(mob/living/attacker, mob/living/defender) - return - -/datum/martial_art/boxing/disarm_act(mob/living/attacker, mob/living/defender) - if(honor_check(defender)) - add_to_streak("D", defender) - tussle(attacker, defender) - return MARTIAL_ATTACK_SUCCESS - -/datum/martial_art/boxing/grab_act(mob/living/attacker, mob/living/defender) - if(honorable_boxer) - attacker.balloon_alert(attacker, "no grabbing while boxing!") - return MARTIAL_ATTACK_FAIL - return MARTIAL_ATTACK_INVALID //UNLESS YOU'RE EVIL - -/datum/martial_art/boxing/harm_act(mob/living/attacker, mob/living/defender) - if(honor_check(defender)) - add_to_streak("H", defender) - tussle(attacker, defender) - return MARTIAL_ATTACK_SUCCESS - -// Our only boxing move, which occurs on literally all attacks; the tussle. However, quite a lot morphs the results of this proc. Combos, unlike most martial arts attacks, are checked in this proc rather than our standard unarmed procs -/datum/martial_art/boxing/proc/tussle(mob/living/attacker, mob/living/defender) - - if(honorable_boxer) //Being a good sport, you never hit someone on the ground or already knocked down. It shows you're the better person. - if(defender.body_position == LYING_DOWN && defender.get_stamina_loss() >= 100 || defender.IsUnconscious()) //If they're in stamcrit or unconscious, don't bloody punch them - attacker.balloon_alert(attacker, "unsportsmanlike behaviour!") - return FALSE - - var/obj/item/bodypart/arm/active_arm = attacker.get_active_hand() - - //The values between which damage is rolled for punches - var/lower_force = active_arm.unarmed_damage_low - var/upper_force = active_arm.unarmed_damage_high - - //Determines knockout potential and armor penetration (if that matters) - var/base_unarmed_effectiveness = active_arm.unarmed_effectiveness + return dirty_hit(attacker, defender) - //Determines attack sound based on attacker arm - var/attack_sound = active_arm.unarmed_attack_sound - - // Out athletics skill is added as a damage bonus - var/athletics_skill = attacker.st_get_stat(STAT_BRAWL) // DARKPACK EDIT CHANGE - STORYTELLER_STATS - - // If true, grants experience for punching; we only gain experience if we punch another boxer. - var/grant_experience = FALSE - - // What type of damage does our kind of boxing do? Defaults to STAMINA for normal boxing, unless you're performing EVIL BOXING. Subtypes use different damage types. - var/damage_type = honorable_boxer ? default_damage_type : attacker.get_attack_type() - - attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) - - // Our potential wound bonus on a punch. Only applies if we're dishonorable. Otherwise, we can't wound. - var/possible_wound_bonus = honorable_boxer ? 0 : CANT_WOUND - - // Determines damage dealt on a punch. Against a boxing defender, we apply our skill bonus. - var/damage = rand(lower_force, upper_force) - - // Attack verbs for our visible chat messages. - var/current_atk_verb = "punches" - var/current_atk_verbed = "punched" - - if(defender.check_block(attacker, damage, "[attacker]'s punch", UNARMED_ATTACK)) - return FALSE - - // Similar to a normal punch, should we have a value of 0 for our lower force, we simply miss outright. - if(!lower_force) - playsound(defender.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1) - defender.visible_message(span_warning("[attacker]'s punch misses [defender]!"), \ - span_danger("You avoid [attacker]'s punch!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, attacker) - to_chat(attacker, span_warning("Your punch misses [defender]!")) - log_combat(attacker, defender, "attempted to hit", "punch (boxing) ") - return FALSE - - var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected)) - - if(honor_check(defender)) - var/strength_bonus = HAS_TRAIT(attacker, TRAIT_STRENGTH) ? 2 : 0 //Investing into genetic strength improvements makes you a better boxer - - var/obj/item/organ/cyberimp/chest/spine/potential_spine = attacker.get_organ_slot(ORGAN_SLOT_SPINE) //Getting a cyberspine also pushes you further than just mere meat - if(istype(potential_spine)) - strength_bonus *= potential_spine.strength_bonus - - var/streak_augmentation = check_streak(attacker, defender, active_arm) - - var/combo_multiplier = 0 - - switch(streak_augmentation) - if(STRAIGHT_PUNCH) - current_atk_verb = "straight punches" - current_atk_verbed = "straight punched" - combo_multiplier = 1 - - if(LIGHT_JAB) - current_atk_verb = "light jabs" - current_atk_verbed = "light jabbed" - combo_multiplier = 1 - - if(LEFT_HOOK) - current_atk_verb = "left hooks" - current_atk_verbed = "left hooked" - combo_multiplier = 1.5 - attacker.changeNext_move(CLICK_CD_MELEE * 1.5) - - if(RIGHT_HOOK) - current_atk_verb = "right hooks" - current_atk_verbed = "right hooked" - combo_multiplier = 1.5 - attacker.changeNext_move(CLICK_CD_MELEE * 1.5) - - if(UPPERCUT) - current_atk_verb = "uppercuts" - current_atk_verbed = "uppercutted" - base_unarmed_effectiveness *= 1.5 - combo_multiplier = 1 - attacker.changeNext_move(CLICK_CD_MELEE * 1.5) - - if(DISCOMBOBULATE) - current_atk_verb = "discombobulates" - current_atk_verbed = "discombobulated" - affecting = defender.get_bodypart(defender.get_random_valid_zone(BODY_ZONE_HEAD)) - defender.adjust_confusion_up_to(20 SECONDS, 50 SECONDS) - defender.adjust_dizzy_up_to(20 SECONDS, 50 SECONDS) - combo_multiplier = 1 - - if(BLIND_JAB) - current_atk_verb = "blind jabs" - current_atk_verbed = "blind jabbed" - combo_multiplier = 0.5 - attacker.changeNext_move(CLICK_CD_MELEE * 1.5) - - if(CRAVEN_BLOW) - current_atk_verb = "sucker punches" - current_atk_verbed = "sucker punch" - possible_wound_bonus = damage - combo_multiplier = 2 - possible_wound_bonus *= 1.5 - affecting = defender.get_bodypart(defender.get_random_valid_zone(BODY_ZONE_HEAD)) - defender.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) //why yes, this could result in them being knocked out in one. - - damage += round((athletics_skill + strength_bonus) * combo_multiplier, 1) - - if(combo_multiplier >= 1) - perform_extra_effect(attacker, defender) - - if(defender.stat <= HARD_CRIT) // Do not grant experience against dead targets - grant_experience = TRUE - - var/armor_block = defender.run_armor_check(affecting, MELEE, armour_penetration = base_unarmed_effectiveness) - - playsound(defender, attack_sound, 25, TRUE, -1) + return FALSE +/// Frontal Kick: Harm Disarm combo, knocks back relative to Attacker Str - Defender Fort +/datum/martial_art/darkpack_boxing/proc/uppercut(mob/living/attacker, mob/living/defender) + attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) defender.visible_message( - span_danger("[attacker] [current_atk_verb] [defender]!"), - span_userdanger("You're [current_atk_verbed] by [attacker]!"), + 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, 'modular_darkpack/modules/martial/sounds/frontalkick.ogg', 50, TRUE, -1) + var/atom/throw_target = get_edge_target_turf(defender, attacker.dir) + var/throw_distance = clamp((attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA)), 1, 3) + defender.throw_at(throw_target, throw_distance, 4, attacker) + defender.apply_damage(15, attacker.get_attack_type(), BODY_ZONE_CHEST, wound_bonus = CANT_WOUND) + log_combat(attacker, defender, "Frontal Kicked (Kungfu)") + return TRUE - to_chat(attacker, span_danger("You [current_atk_verbed] [defender]!")) - - // Determines the total amount of experience earned per punch - var/experience_earned = round(damage/4, 1) - - defender.apply_damage(damage, damage_type, affecting, armor_block, wound_bonus = possible_wound_bonus) - - log_combat(attacker, defender, "punched (boxing) ") +/// Roundhouse Kick: 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/darkpack_boxing/proc/jab_combo(mob/living/attacker, mob/living/defender) + attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/roundhousekick.ogg', 50, TRUE, -1) + var/kickpower = SSroll.storyteller_roll((attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), difficulty = 7, numerical = TRUE, roller = attacker) + if(defender.body_position == STANDING_UP && (kickpower >= 0)) + defender.Knockdown(kickpower SECONDS) + defender.visible_message(span_warning("[attacker] kicks [defender] in the head, sending them face first into the floor!"), \ + span_userdanger("You are kicked in the head by [attacker], sending you crashing to the floor!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) + else + defender.drop_all_held_items() + defender.visible_message(span_warning("[attacker] kicks [defender] in the head!"), \ + span_userdanger("You are kicked in the head by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) + defender.apply_damage(10, attacker.get_attack_type()) + defender.apply_damage(40, STAMINA) + defender.adjust_dizzy_up_to(10 SECONDS, 10 SECONDS) + log_combat(attacker, defender, "Roundhoused (KungFu)") + return TRUE - if(defender.stat == DEAD || !honor_check(defender)) //early returning here so we don't worry about knockout probs or experience gain - return TRUE +/// Flying Knee: Grab Harm combo, causes them to be silenced and briefly stunned, as well as doing a moderate amount of stamina damage. +/datum/martial_art/darkpack_boxing/proc/cross_punch(mob/living/attacker, mob/living/defender) + attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 70, TRUE, -1) + defender.visible_message( + span_warning("[attacker] violently slams [attacker.p_their()] knee into [defender]!"), + span_userdanger("You slam your knee straight into [defender]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + COMBAT_MESSAGE_RANGE, + attacker, + ) + var/roll_success = SSroll.storyteller_roll((attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), difficulty = 8, roller = attacker) + if(roll_success) + defender.Knockdown(3 SECONDS) + defender.apply_damage(40, STAMINA) + defender.adjust_silence_up_to(5 SECONDS, 5 SECONDS) + log_combat(attacker, defender, "kneed in the stomach (Kung-Fu)") + return TRUE - if(grant_experience) - skill_experience_adjustment(attacker, defender, (damage/lower_force)) +/// Flying Knee: Grab Harm combo, causes them to be silenced and briefly stunned, as well as doing a moderate amount of stamina damage. +/datum/martial_art/darkpack_boxing/proc/dirty_hit(mob/living/attacker, mob/living/defender) + attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 70, TRUE, -1) + defender.visible_message( + span_warning("[attacker] violently slams [attacker.p_their()] knee into [defender]!"), + span_userdanger("You slam your knee straight into [defender]!"), + span_hear("You hear a sickening sound of flesh hitting flesh!"), + COMBAT_MESSAGE_RANGE, + attacker, + ) + var/roll_success = SSroll.storyteller_roll((attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), difficulty = 8, roller = attacker) + if(roll_success) + defender.Knockdown(3 SECONDS) + defender.apply_damage(40, STAMINA) + defender.adjust_silence_up_to(5 SECONDS, 5 SECONDS) + log_combat(attacker, defender, "kneed in the stomach (Kung-Fu)") + return TRUE - //Determine our attackers athletics level as a knockout probability bonus - var/attacker_athletics_skill = (attacker.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) + base_unarmed_effectiveness) +/datum/martial_art/darkpack_boxing/grab_act(mob/living/attacker, mob/living/defender) + if(defender.check_block(attacker, 0, "[attacker]'s grab", UNARMED_ATTACK)) + return MARTIAL_ATTACK_FAIL - // Defender boxing skill and armor block are used as a defense here. This has already factored in base_unarmed_effectiveness from the attacker - var/defender_athletics_skill = clamp(defender.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER), 0, 100) + add_to_streak("G", defender) + if(check_streak(attacker, defender)) + return MARTIAL_ATTACK_SUCCESS + defender.apply_damage(15, STAMINA) + return MARTIAL_ATTACK_INVALID //Boxing is not known for holds at all - //Determine our final probability, using a clamp to stop any prob() weirdness. - var/final_knockout_probability = clamp(round(attacker_athletics_skill - defender_athletics_skill, 1), 0 , 100) +/datum/martial_art/darkpack_boxing/harm_act(mob/living/attacker, mob/living/defender) + if(defender.check_block(attacker, 10, attacker.name, UNARMED_ATTACK)) + return MARTIAL_ATTACK_FAIL - if(!prob(final_knockout_probability)) - return TRUE + add_to_streak("H", defender) + if(check_streak(attacker, defender)) + return MARTIAL_ATTACK_SUCCESS - crit_effect(attacker, defender, armor_block, damage_type, damage) + return MARTIAL_ATTACK_INVALID //You're gonna punch someone in the face normally and like it - experience_earned *= 2 //Double our experience gain on a crit hit +/datum/martial_art/darkpack_boxing/disarm_act(mob/living/attacker, mob/living/defender) + if(!can_deflect(attacker)) //you arent swiping at someone on the ground + return MARTIAL_ATTACK_INVALID + if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK)) + return MARTIAL_ATTACK_FAIL - playsound(defender, 'sound/effects/coin2.ogg', 40, TRUE) - new /obj/effect/temp_visual/crit(get_turf(defender)) - skill_experience_adjustment(attacker, defender, experience_earned) //double experience for a successful crit + add_to_streak("D", defender) + if(check_streak(attacker, defender)) + return MARTIAL_ATTACK_SUCCESS - return TRUE + playsound(defender, 'modular_darkpack/modules/martial/sounds/swipe.ogg', 25, TRUE, -1) + defender.apply_damage(20, STAMINA) + return MARTIAL_ATTACK_INVALID //Essentially taking a swipe at their face -/// Our crit effect. For normal boxing, this applies a stagger, then applies a knockout if they're staggered. Other types of boxing apply different kinds of effects. -/datum/martial_art/boxing/proc/crit_effect(mob/living/attacker, mob/living/defender, armor_block = 0, damage_type = STAMINA, damage = 0) - if(defender.get_timed_status_effect_duration(/datum/status_effect/staggered)) - 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.SetSleeping(10 SECONDS) - log_combat(attacker, defender, "knocked out (boxing) ") - else - defender.visible_message( - span_danger("[attacker] staggers [defender] with a haymaker!"), - span_userdanger("You're nearly knocked off your feet by [attacker]!"), - span_hear("You hear a sickening sound of flesh hitting flesh!"), - COMBAT_MESSAGE_RANGE, - attacker, - ) - defender.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) - to_chat(attacker, span_danger("You stagger [defender] with a haymaker!")) - log_combat(attacker, defender, "staggered (boxing) ") - - if(attacker.pulling == defender && attacker.grab_state >= GRAB_AGGRESSIVE) // dubious a normal boxer will be in a state where this happens, buuuut. - var/atom/throw_target = get_edge_target_turf(defender, attacker.dir) - defender.throw_at(throw_target, 2, 2, attacker) - -/// Returns whether whoever is checked by this proc is complying with the rules of boxing. The boxer cannot block non-boxers, and cannot apply their scariest moves against non-boxers. -/datum/martial_art/boxing/proc/honor_check(mob/living/possible_boxer) - if(!honorable_boxer) - return TRUE //You scoundrel!! - - if(!HAS_TRAIT(possible_boxer, TRAIT_BOXING_READY)) +/datum/martial_art/darkpack_boxing/proc/can_deflect(mob/living/user) + if(!can_use(user) || !user.combat_mode) + return FALSE + if(INCAPACITATED_IGNORING(user, INCAPABLE_GRAB)) //NO STUN + return FALSE + if(!(user.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE + return FALSE + if(HAS_TRAIT(user, TRAIT_HULK)) //NO HULK + return FALSE + if(!isturf(user.loc)) //NO MOTHERFLIPPIN MECHS! return FALSE - return TRUE -/// Handles our instances of experience gain while boxing. It also applies the exercised status effect. -/datum/martial_art/boxing/proc/skill_experience_adjustment(mob/living/boxer, mob/living/defender, experience_value) - //Boxing in heavier gravity gives you more experience - var/gravity_modifier = boxer.has_gravity() > STANDARD_GRAVITY ? 1 : 2 - - //You gotta sleep before you get any experience! - boxer.mind?.adjust_experience(/datum/skill/athletics, round(experience_value / gravity_modifier, 1)) - boxer.apply_status_effect(/datum/status_effect/exercised) - -/// Handles our blocking signals, similar to hit_reaction() on items. Only blocks while the boxer is in throw mode. -/datum/martial_art/boxing/proc/check_block(mob/living/boxer, atom/movable/hitby, damage, attack_text, attack_type, ...) +/datum/martial_art/darkpack_boxing/proc/reset_animation(mob/living/user, fadein) + if(fadein) + animate(user, alpha = 225, time = 0.1 SECONDS) + return + else + animate(user, alpha = 225, pixel_x = 0, pixel_y = 0, time = 0.1 SECONDS) + +/datum/martial_art/darkpack_boxing/proc/dodge_animation(mob/living/user) + var/new_pixel_x + var/new_pixel_y + switch(user.dir) + if(EAST) + new_pixel_x = rand(-16, -8) + new_pixel_y = rand(-24, 24) + if(WEST) + new_pixel_x = rand(8, 16) + new_pixel_y = rand(-24, 24) + if(NORTH) + new_pixel_x = rand(-16,16) + new_pixel_y = rand(-16, -8) + if(SOUTH) + new_pixel_x = rand(-16,16) + new_pixel_y = rand(8, 16) + animate(user, alpha = 200, pixel_x = new_pixel_x, pixel_y = new_pixel_y, time = 0.2 SECONDS) + +/// Like the hit game "Punch Out!!"" (1984) you can dodge incoming punches at you.. melee weapons and projectiles? not so lucky +/datum/martial_art/darkpack_boxing/proc/check_dodge(mob/living/user, atom/movable/hitby, damage, attack_text, attack_type, ...) SIGNAL_HANDLER - if(!can_use(boxer) || !boxer.throw_mode || INCAPACITATED_IGNORING(boxer, INCAPABLE_GRAB)) - return NONE - - if(attack_type != UNARMED_ATTACK) - return NONE - - //Determines unarmed defense against boxers using our current active arm. - var/obj/item/bodypart/arm/active_arm = boxer.get_active_hand() - var/base_unarmed_effectiveness = active_arm.unarmed_effectiveness - - // Out athletics skill is added to our block potential - var/athletics_skill_rands = boxer.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) - - var/block_chance = base_unarmed_effectiveness + athletics_skill_rands + var/determine_avoidance = ((user.st_get_stat(STAT_ATHLETICS) + user.st_get_stat(STAT_DEXTERITY) + user.st_get_stat(STAT_BRAWL)) * 2) //Theoretical max of 40% with Cel 5 - var/block_text = pick("block", "evade") + if(!can_deflect(user)) + return - var/mob/living/attacker = GET_ASSAILANT(hitby) + if(user.throw_mode) //Theoretical max of 80% with Cel 5 + determine_avoidance *= 2 - if(!honor_check(attacker)) + if(attack_type != UNARMED_ATTACK) return NONE - var/experience_earned = round(damage/4, 1) - - if(!damage) - experience_earned = 2 - - // WE reward experience for getting punched while boxing - skill_experience_adjustment(boxer, attacker, experience_earned) //just getting hit a bunch doesn't net you much experience however - - if(!prob(block_chance)) + if(!prob(determine_avoidance)) return NONE - if(istype(attacker) && boxer.Adjacent(attacker)) - attacker.apply_damage(10, default_damage_type) - boxer.apply_damage(5, STAMINA) - perform_extra_effect(boxer, attacker) - - boxer.visible_message( - span_danger("[boxer] [block_text]s [attack_text]!"), - span_userdanger("You [block_text] [attack_text]!"), + user.visible_message( + span_danger("[user] cleanly dodges [attack_text] with incredible speed!"), + span_userdanger("You dodge [attack_text]"), ) - if(block_text == "evade") - playsound(boxer.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1) + playsound(user.loc, 'sound/items/weapons/punchmiss.ogg', 25, TRUE, -1) + var/mob/living/attacker = GET_ASSAILANT(hitby) + user.setDir(turn(attacker.dir, 180)) + var/mob/living/carbon/human/dodger = user + dodge_animation(dodger) + addtimer(CALLBACK(src, PROC_REF(reset_animation), dodger, FALSE), 0.1 SECONDS) + return SUCCESSFUL_BLOCK -/datum/martial_art/boxing/can_use(mob/living/martial_artist) - if(!ishuman(martial_artist)) - return FALSE - return ..() +/mob/living/proc/streetboxing_help() + set name = "Recall Teachings" + set desc = "Remember the martial techniques of the Kung-Fu" + set category = "Martial Arts" + + to_chat(usr, span_info("You retreat inward and recall your past training")) + to_chat(usr, "[span_notice("Frontal Kick")]: Punch Shove. Launch your opponent away from you with incredible force!") + to_chat(usr, "[span_notice("Roundhouse Kick")]: Shove Shove. Nonlethally kick an opponent to the floor, knocking them down, discombobulating them and dealing substantial stamina damage. If they're already prone, disarm them as well.") + to_chat(usr, "[span_notice("Flying Knee")]: Grab Punch. Deliver a knee jab into the opponent, dealing high stamina damage, as well as briefly stunning them, winding them and making it difficult for them to speak.") + to_chat(usr, "[span_notice("Grabs and Shoves")]: While in combat mode, your typical grab and shove do decent stamina damage, and your grabs harder to break. If you grab someone who has substantial amounts of stamina damage, you knock them out!") + +#undef UPPERCUT_COMBO +#undef JAB_COMBO +#undef CROSS_COMBO +#undef DIRTY_COMBO + +/obj/item/clothing/gloves/boxing_gloves + name = "Debugging Gloves" + desc = "Delete at some point" + icon_state = "black" + greyscale_colors = COLOR_BLACK + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT + heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT + resistance_flags = NONE + +/obj/item/clothing/gloves/boxing_gloves/Initialize(mapload) + . = ..() + AddComponent(/datum/component/martial_art_giver, /datum/martial_art/darkpack_boxing) -/mob/living/proc/boxing_help() - set name = "Focus on your Form" - set desc = "You focus on how to make the most of your boxing form." - set category = "Boxing" - to_chat(usr, "You focus on your form, visualizing how best to throw a punch.") - - to_chat(usr, "What moves you perform depend on what mouse buttons you click, and whether the last button clicked matches which hand you have selected when you throw the last punch.") - - to_chat(usr, "[span_notice("Straight Punch")]: Left Left/Right Right with the matching hand. Regular damage.") - to_chat(usr, "[span_notice("Jab")]: Left Left/Right Right with the opposite hand. Regular damage. If you're blind, you'll make a blind jab instead.") - to_chat(usr, "[span_notice("Left/Right Hook")]: Left Right/Right Left with the matching hand. Does extra damage, but slows your next hit.") - to_chat(usr, "[span_notice("Uppercut")]: Left Right/Right Left with the opposite hand. Has a higher probability to knock out the target, but slows your next hit.") - - to_chat(usr, "While in Throw Mode, you can block incoming punches and return a bit of damage back to an attacker. Blocking attacks this way causes you to lose some stamina damage.") - -// Boxing Variants! - -/// Evil Boxing; for sick, evil scoundrels. Has no honor, making it more lethal (therefore unable to be used by pacifists). -/// Grants Strength and Stimmed to speed up any experience gain. - -/datum/martial_art/boxing/evil - name = "Evil Boxing" - id = MARTIALART_EVIL_BOXING - pacifist_style = FALSE - help_verb = /mob/living/proc/evil_boxing_help - honorable_boxer = FALSE - boxing_traits = list(TRAIT_BOXING_READY, TRAIT_STRENGTH, TRAIT_STIMMED) - -/mob/living/proc/evil_boxing_help() - set name = "Focus on Brawling" - set desc = "You ponder how best to rearrange the faces of your enemies." - set category = "Evil Boxing" - to_chat(usr, "You contemplate on the violence ahead, visualizing how best to throw a punch.") - - to_chat(usr, "What moves you perform depend on what mouse buttons you click, and whether the last button clicked matches which hand you have selected when you throw the last punch.") - - to_chat(usr, "[span_notice("Straight Punch")]: Left Left/Right Right with the matching hand. Regular damage.") - to_chat(usr, "[span_notice("Jab")]: Left Left/Right Right with the opposite hand. Regular damage. If you're blind, you'll make a blind jab instead.") - to_chat(usr, "[span_notice("Left/Right Hook")]: Left Right/Right Left with the matching hand. Does extra damage, but slows your next hit.") - to_chat(usr, "[span_notice("Uppercut")]: Left Right/Right Left with the opposite hand. Has a higher probability to knock out the target, but slows your next hit.") - to_chat(usr, "[span_notice("Sucker Punch")]: Any combination done to a vulnerable target becomes a sucker punch. This could knock them out in one!.") - - to_chat(usr, "While in Throw Mode, you can block incoming punches and return a bit of damage back to an attacker. Blocking attacks this way causes you to lose some stamina damage.") - - -#undef LEFT_RIGHT_COMBO -#undef RIGHT_LEFT_COMBO -#undef LEFT_LEFT_COMBO -#undef RIGHT_RIGHT_COMBO - -#undef STRAIGHT_PUNCH -#undef RIGHT_HOOK -#undef LEFT_HOOK -#undef UPPERCUT -#undef LIGHT_JAB -#undef DISCOMBOBULATE -#undef BLIND_JAB -#undef CRAVEN_BLOW -#undef NO_COMBO diff --git a/modular_darkpack/modules/martial/swords.dm b/modular_darkpack/modules/martial/swords.dm index 107c4b7493a0..2b56a2dfb38c 100644 --- a/modular_darkpack/modules/martial/swords.dm +++ b/modular_darkpack/modules/martial/swords.dm @@ -1,3 +1,4 @@ +/* #define ATTACK_STRIKE "Hilt Strike" #define ATTACK_SLICE "Wide Slice" #define ATTACK_CUT "Tendon Cut" @@ -108,7 +109,7 @@ else status.add_stacks(6) - #undef ATTACK_STRIKE #undef ATTACK_SLICE #undef ATTACK_CUT +*/ diff --git a/tgstation.dme b/tgstation.dme index 363fb120dfa9..1b1de786df56 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7261,8 +7261,10 @@ #include "modular_darkpack\modules\looc\code\verbs.dm" #include "modular_darkpack\modules\mannequin\code\mannequin_subtypes.dm" #include "modular_darkpack\modules\mapping_helpers\code\viewport_helper.dm" -#include "modular_darkpack\modules\martial\defines.dm" +#include "modular_darkpack\modules\martial\artdefines.dm" +#include "modular_darkpack\modules\martial\cqb.dm" #include "modular_darkpack\modules\martial\kungfu.dm" +#include "modular_darkpack\modules\martial\streetboxing.dm" #include "modular_darkpack\modules\martial\swords.dm" #include "modular_darkpack\modules\masquerade\code\blood_hunt_skull.dm" #include "modular_darkpack\modules\masquerade\code\human.dm" From d891463e0f6338c1ec9836dece0c7505d35540e5 Mon Sep 17 00:00:00 2001 From: SELFHELL <99771731+SELFHELL@users.noreply.github.com> Date: Sun, 22 Mar 2026 19:51:54 -0500 Subject: [PATCH 8/9] Boxing: Finish Cross Punch and Liver Punch --- modular_darkpack/modules/martial/kungfu.dm | 3 +- .../sounds/{jab combo.ogg => jabcombo.ogg} | Bin .../modules/martial/streetboxing.dm | 91 ++++++++++-------- 3 files changed, 54 insertions(+), 40 deletions(-) rename modular_darkpack/modules/martial/sounds/{jab combo.ogg => jabcombo.ogg} (100%) diff --git a/modular_darkpack/modules/martial/kungfu.dm b/modular_darkpack/modules/martial/kungfu.dm index 9a3ad213a2b5..6f1c5312b74a 100644 --- a/modular_darkpack/modules/martial/kungfu.dm +++ b/modular_darkpack/modules/martial/kungfu.dm @@ -59,11 +59,12 @@ COMBAT_MESSAGE_RANGE, attacker, ) + to_chat(attacker, span_danger("You kick [defender] square in the chest, sending them flying!")) playsound(attacker, 'modular_darkpack/modules/martial/sounds/frontalkick.ogg', 50, TRUE, -1) var/atom/throw_target = get_edge_target_turf(defender, attacker.dir) var/throw_distance = clamp((attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA)), 1, 3) defender.throw_at(throw_target, throw_distance, 4, attacker) - defender.apply_damage(15, attacker.get_attack_type(), BODY_ZONE_CHEST, wound_bonus = CANT_WOUND) + defender.apply_damage(15, attacker.get_attack_type(), BODY_ZONE_CHEST) log_combat(attacker, defender, "Frontal Kicked (Kungfu)") return TRUE diff --git a/modular_darkpack/modules/martial/sounds/jab combo.ogg b/modular_darkpack/modules/martial/sounds/jabcombo.ogg similarity index 100% rename from modular_darkpack/modules/martial/sounds/jab combo.ogg rename to modular_darkpack/modules/martial/sounds/jabcombo.ogg diff --git a/modular_darkpack/modules/martial/streetboxing.dm b/modular_darkpack/modules/martial/streetboxing.dm index 1c31fa417ba1..eba8ce0b2c29 100644 --- a/modular_darkpack/modules/martial/streetboxing.dm +++ b/modular_darkpack/modules/martial/streetboxing.dm @@ -1,6 +1,6 @@ #define UPPERCUT_COMBO "HDH" #define JAB_COMBO "GHH" -#define CROSS_COMBO "DH" +#define CROSS_COMBO "DHH" #define DIRTY_COMBO "GD" /datum/martial_art/darkpack_boxing @@ -26,8 +26,7 @@ //limb.unarmed_damage_low += 5 Unsure on this one //limb.unarmed_damage_high += 5 - limb.unarmed_attack_effect = null - limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/mainpunch2.ogg' + //limb.unarmed_attack_sound = 'modular_darkpack/modules/martial/sounds/harmboxing.ogg' /datum/martial_art/darkpack_boxing/deactivate_style(mob/living/remove_from) UnregisterSignal(remove_from, list(COMSIG_LIVING_CHECK_BLOCK)) @@ -55,42 +54,38 @@ /// Frontal Kick: Harm Disarm combo, knocks back relative to Attacker Str - Defender Fort /datum/martial_art/darkpack_boxing/proc/uppercut(mob/living/attacker, mob/living/defender) - attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) + attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) + uppercut_animation(attacker) + addtimer(CALLBACK(src, PROC_REF(reset_animation), attacker, FALSE), 0.1 SECONDS) 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_warning("[attacker] uppercuts [defender] square in the jaw, sending you flying"), + span_userdanger("You are uppercut in the jaw by [attacker], sending you flying!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker, ) - playsound(attacker, 'modular_darkpack/modules/martial/sounds/frontalkick.ogg', 50, TRUE, -1) + + playsound(attacker, 'modular_darkpack/modules/martial/sounds/uppercut.ogg', 50, TRUE, -1) var/atom/throw_target = get_edge_target_turf(defender, attacker.dir) var/throw_distance = clamp((attacker.st_get_stat(STAT_STRENGTH) - defender.st_get_stat(STAT_STAMINA)), 1, 3) defender.throw_at(throw_target, throw_distance, 4, attacker) - defender.apply_damage(15, attacker.get_attack_type(), BODY_ZONE_CHEST, wound_bonus = CANT_WOUND) + defender.apply_damage(6 * attacker.st_get_stat(STAT_STRENGTH), attacker.get_attack_type(), BODY_ZONE_HEAD) log_combat(attacker, defender, "Frontal Kicked (Kungfu)") return TRUE -/// Roundhouse Kick: 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. +/// Jab Combo: Hit the other guy twice in quick succession /datum/martial_art/darkpack_boxing/proc/jab_combo(mob/living/attacker, mob/living/defender) - attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) - playsound(attacker, 'modular_darkpack/modules/martial/sounds/roundhousekick.ogg', 50, TRUE, -1) - var/kickpower = SSroll.storyteller_roll((attacker.st_get_stat(STAT_STRENGTH) + attacker.st_get_stat(STAT_BRAWL)), difficulty = 7, numerical = TRUE, roller = attacker) - if(defender.body_position == STANDING_UP && (kickpower >= 0)) - defender.Knockdown(kickpower SECONDS) - defender.visible_message(span_warning("[attacker] kicks [defender] in the head, sending them face first into the floor!"), \ - span_userdanger("You are kicked in the head by [attacker], sending you crashing to the floor!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) - else - defender.drop_all_held_items() - defender.visible_message(span_warning("[attacker] kicks [defender] in the head!"), \ - span_userdanger("You are kicked in the head by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) - defender.apply_damage(10, attacker.get_attack_type()) - defender.apply_damage(40, STAMINA) + attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH) + playsound(attacker, 'modular_darkpack/modules/martial/sounds/jabcombo.ogg', 50, TRUE, -1) + defender.visible_message(span_warning("[attacker] rapidly jabs [defender]'s head!"), \ + span_userdanger("You are jabbed in the head by [attacker], leaving you disoriented!"), span_hear("You hear a sickening sound of knuckles hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) + defender.adjust_stamina_loss(45) + defender.apply_damage(20, attacker.get_attack_type(), BODY_ZONE_HEAD) defender.adjust_dizzy_up_to(10 SECONDS, 10 SECONDS) - log_combat(attacker, defender, "Roundhoused (KungFu)") + log_combat(attacker, defender, "Jab Combo'd (Boxing)") return TRUE -/// Flying Knee: Grab Harm combo, causes them to be silenced and briefly stunned, as well as doing a moderate amount of stamina damage. +/// Cross Punch: Figure out /datum/martial_art/darkpack_boxing/proc/cross_punch(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) playsound(attacker, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 70, TRUE, -1) @@ -109,7 +104,7 @@ log_combat(attacker, defender, "kneed in the stomach (Kung-Fu)") return TRUE -/// Flying Knee: Grab Harm combo, causes them to be silenced and briefly stunned, as well as doing a moderate amount of stamina damage. +/// Dirty Move: Liver Punch or something /datum/martial_art/darkpack_boxing/proc/dirty_hit(mob/living/attacker, mob/living/defender) attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK) playsound(attacker, 'modular_darkpack/modules/martial/sounds/grabbed.ogg', 70, TRUE, -1) @@ -158,7 +153,7 @@ if(check_streak(attacker, defender)) return MARTIAL_ATTACK_SUCCESS - playsound(defender, 'modular_darkpack/modules/martial/sounds/swipe.ogg', 25, TRUE, -1) + //playsound(defender, 'modular_darkpack/modules/martial/sounds/swipe.ogg', 25, TRUE, -1) defender.apply_damage(20, STAMINA) return MARTIAL_ATTACK_INVALID //Essentially taking a swipe at their face @@ -185,19 +180,37 @@ /datum/martial_art/darkpack_boxing/proc/dodge_animation(mob/living/user) var/new_pixel_x var/new_pixel_y - switch(user.dir) - if(EAST) - new_pixel_x = rand(-16, -8) - new_pixel_y = rand(-24, 24) - if(WEST) - new_pixel_x = rand(8, 16) - new_pixel_y = rand(-24, 24) - if(NORTH) - new_pixel_x = rand(-16,16) - new_pixel_y = rand(-16, -8) - if(SOUTH) - new_pixel_x = rand(-16,16) - new_pixel_y = rand(8, 16) + var/userdir = user.dir + switch(userdir) + if(EAST) + new_pixel_x = rand(-16, -8) + new_pixel_y = rand(-24, 24) + if(WEST) + new_pixel_x = rand(8, 16) + new_pixel_y = rand(-24, 24) + if(NORTH) + new_pixel_x = rand(-16,16) + new_pixel_y = rand(-16, -8) + if(SOUTH) + new_pixel_x = rand(-16,16) + new_pixel_y = rand(8, 16) + animate(user, alpha = 200, pixel_x = new_pixel_x, pixel_y = new_pixel_y, time = 0.2 SECONDS) + +/datum/martial_art/darkpack_boxing/proc/uppercut_animation(mob/living/user) + var/new_pixel_x + var/new_pixel_y + var/userdir = user.dir + switch(userdir) + if(EAST) + new_pixel_x = rand(0, 4) + new_pixel_y = rand(0, 12) + if(WEST) + new_pixel_x = rand(-4, 0) + new_pixel_y = rand(0, 12) + if(NORTH) + new_pixel_y = rand(0, 12) + if(SOUTH) + new_pixel_y = rand(0, 12) animate(user, alpha = 200, pixel_x = new_pixel_x, pixel_y = new_pixel_y, time = 0.2 SECONDS) /// Like the hit game "Punch Out!!"" (1984) you can dodge incoming punches at you.. melee weapons and projectiles? not so lucky From a0d90b93b241976cb6bbd748336eaf7adc61520e Mon Sep 17 00:00:00 2001 From: SELFHELL <99771731+SELFHELL@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:32:25 -0500 Subject: [PATCH 9/9] Update code/datums/components/butchering.dm Co-authored-by: chazzyjazzy <33268885+chazzyjazzy@users.noreply.github.com> --- code/datums/components/butchering.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 6338fef245ab..ebc29681cd9e 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -346,7 +346,7 @@ break if (!found_spot) - to_chat(user, span_warning("You need to butcher [victim] on a table/chair!")) //DARKPACK EDIT BUTCHERING ORIGINAL: "You need a better spot to butcher [victim]!" + to_chat(user, span_warning("You need to butcher [victim] on a table/chair!")) //DARKPACK EDIT BUTCHERING ORIGINAL: to_chat(user, span_warning("You need a better spot to butcher [victim]!")) return var/obj/item/bodypart/limb = victim.get_bodypart(deprecise_zone(user.zone_selected))