From ac6c47f601d44dff8f1d3528b13d120119ae5d56 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Tue, 2 Dec 2025 17:13:58 +1100 Subject: [PATCH] Several file changes just to make high frequency blade null rods block mechs, mech melee blocking finally implemented (#94089) ## About The Pull Request High frequency blades, both null rod variant and admeme variant, can block mech melee attacks. For the former, that is the only thing it can block. Great if you're fighting a lot of mechs as a chaplain I guess. And you're also really committed to the bit. Weapons that were vibro subtypes are now claymore subtypes. The only difference here is that they now have 30% block instead of 35% AP. Null rod high frequency blades are now two-handed. This mostly determines force changes (10 unwielded, 18 wielded), and mech attack block chances. Mech melee attacks respect block...assuming the blocking source can even block the attack in the first place. Currently, the few sources that can block/avoid mech attacks are; - high frequency blades - energy katanas - Those staff nullrods (its a holy force field, iunno) - wizard modsuit shield (and it will eat literally every single charge it has to do that) - Sleeping Carp evasion (and only at half the possible chance) - CQC defense mode (themed as dodging the attack, and also halved) - probably something I overlooked when I implemented OVERWHELMING_ATTACK originally and have overlooked here as well. Just think 'could this help avoid being hit by a road roller being dropped on you' and go with your gut as to whether or not it is appropriate if you spot something in the wild that seemingly can block a mech. ## Why It's Good For The Game > High Frequency Blade I wanted to elevate the meme and that is as deep as this goes. Also I wanted to make this two-handed, much like the true version. The only thing it is lacking is the cool attack functionality, but I'll be damned if I can get that to work in a sensible fashion for a crew weapon... > Vibro subtype A lot less of these than I thought. And most of them seemed more appropriate as claymore types anyway. > Mech Block I seeded this previously by making mech clamps respect block. I've now come back to fully implement it in order to facilitate MGR memes. For the most part, mechs should still enjoy being largely unblocked by most sources, even from things like operative suit shields, and certainly not from actual shields (which I've stripped the ability to block the attack from entirely) and melee weapons. The sources that can block them do so poorly. Or, in the case of the high frequency blade, very well and that's pretty much the only thing it IS good at blocking. ## Changelog :cl: balance: High frequency blades (both null rod and admin versions) are able to block melee attacks from mechs. balance: High frequency blade null rods are now two-handed weapons. balance: Mech melee attacks can be blocked or avoided by a few rare sources. /:cl: --- code/datums/components/shielded.dm | 13 +- code/datums/martial/cqc.dm | 20 ++- code/datums/martial/sleeping_carp.dm | 4 +- code/game/objects/items/melee/energy.dm | 9 ++ code/game/objects/items/melee/misc.dm | 8 +- code/game/objects/items/shields.dm | 4 +- code/game/objects/items/spear.dm | 2 +- code/game/objects/items/weaponry.dm | 15 ++- .../changeling/powers/mutations.dm | 3 + code/modules/antagonists/cult/cult_items.dm | 2 +- .../heretic/items/heretic_blades.dm | 5 + code/modules/clothing/outfits/ert.dm | 2 +- code/modules/fishing/fish/_fish.dm | 5 + code/modules/hydroponics/soil.dm | 5 + .../job_types/chaplain/chaplain_nullrod.dm | 117 +++++++++++------- .../lavaland/mining_loot/cursed_katana.dm | 2 +- .../mob_spawn/corpses/mining_corpses.dm | 2 +- code/modules/mod/modules/modules_antag.dm | 6 +- code/modules/projectiles/guns/magic/staff.dm | 2 +- .../mecha/equipment/tools/work_tools.dm | 2 - .../vehicles/mecha/mech_melee_attack.dm | 5 + .../Scripts/94089_vibro_repaths.txt | 5 + 22 files changed, 165 insertions(+), 73 deletions(-) create mode 100644 tools/UpdatePaths/Scripts/94089_vibro_repaths.txt diff --git a/code/datums/components/shielded.dm b/code/datums/components/shielded.dm index 8be81267828..1f3269dab2d 100644 --- a/code/datums/components/shielded.dm +++ b/code/datums/components/shielded.dm @@ -28,6 +28,8 @@ var/show_charge_as_alpha = FALSE /// The item we use for recharging var/recharge_path + /// The item can block OVERWHELMING_ATTACK, which is mostly used by mech melee attacks. + var/can_block_overwhelming = FALSE /// The cooldown tracking when we were last hit COOLDOWN_DECLARE(recently_hit_cd) @@ -36,7 +38,7 @@ /// A callback for the sparks/message that play when a charge is used, see [/datum/component/shielded/proc/default_run_hit_callback] var/datum/callback/on_hit_effects -/datum/component/shielded/Initialize(max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, show_charge_as_alpha = FALSE, recharge_path = null, starting_charges = null, shield_icon_file = 'icons/effects/effects.dmi', shield_icon = "shield-old", shield_inhand = FALSE, run_hit_callback) +/datum/component/shielded/Initialize(max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, show_charge_as_alpha = FALSE, recharge_path = null, can_block_overwhelming = FALSE, starting_charges = null, shield_icon_file = 'icons/effects/effects.dmi', shield_icon = "shield-old", shield_inhand = FALSE, run_hit_callback) if(!isitem(parent) || max_charges <= 0) return COMPONENT_INCOMPATIBLE @@ -47,6 +49,7 @@ src.lose_multiple_charges = lose_multiple_charges src.show_charge_as_alpha = show_charge_as_alpha src.recharge_path = recharge_path + src.can_block_overwhelming = can_block_overwhelming src.shield_icon_file = shield_icon_file src.shield_icon = shield_icon src.shield_inhand = shield_inhand @@ -165,6 +168,11 @@ if(current_charges <= 0) return + + // if our shield is unable to block OVERWHELMING_ATTACK type attacks, we just let it pass. + if(attack_type == OVERWHELMING_ATTACK && !can_block_overwhelming) + return + . = COMPONENT_HIT_REACTION_BLOCK var/charge_loss = 1 // how many charges do we lose @@ -175,6 +183,9 @@ else if(damage < 3) charge_loss = 0 + else if(attack_type == OVERWHELMING_ATTACK && !lose_multiple_charges) // Always expend all charges when blocking an overwhelming attack unless we're using our shield like health. + charge_loss = max_charges + adjust_charge(-charge_loss) INVOKE_ASYNC(src, PROC_REF(actually_run_hit_callback), owner, attack_text, current_charges) diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index 223697af576..4e3815a1e5d 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -50,20 +50,30 @@ return NONE if(attack_type == PROJECTILE_ATTACK) return NONE - if(!prob(block_chance)) + + var/blocking_text = "block" + var/blocking_text_s = "blocks" + var/potential_block_chance = block_chance + + if(attack_type == OVERWHELMING_ATTACK) + blocking_text = "dodge" + blocking_text_s = "dodges" + potential_block_chance = clamp(round(potential_block_chance / (attack_type == OVERWHELMING_ATTACK ? 2 : 1), 1), 0, 100) + + if(!prob(potential_block_chance)) return NONE var/mob/living/attacker = GET_ASSAILANT(hitby) if(istype(attacker) && cqc_user.Adjacent(attacker)) cqc_user.visible_message( - span_danger("[cqc_user] blocks [attack_text] and twists [attacker]'s arm behind [attacker.p_their()] back!"), - span_userdanger("You block [attack_text]!"), + span_danger("[cqc_user] [blocking_text_s] [attack_text] and twists [attacker]'s arm behind [attacker.p_their()] back!"), + span_userdanger("You [blocking_text] [attack_text]!"), ) attacker.Stun(4 SECONDS) else cqc_user.visible_message( - span_danger("[cqc_user] blocks [attack_text]!"), - span_userdanger("You block [attack_text]!"), + span_danger("[cqc_user] [blocking_text_s] [attack_text]!"), + span_userdanger("You [blocking_text] [attack_text]!"), ) return SUCCESSFUL_BLOCK diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index d489dd3d732..a7978c40d57 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -280,11 +280,11 @@ ) return COMPONENT_NO_AFTERATTACK -/// If our user has committed to being as nautically radical as they can be, they may be able to avoid incoming attacks. +/// 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/the_sleeping_carp/proc/check_dodge(mob/living/carp_user, atom/movable/hitby, damage, attack_text, attack_type, ...) SIGNAL_HANDLER - var/determine_avoidance = clamp(carp_style_check(carp_user), 0, 75) + var/determine_avoidance = clamp(round(carp_style_check(carp_user) / (attack_type == OVERWHELMING_ATTACK ? 2 : 1), 1), 0, 75) if(!can_deflect(carp_user)) return diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 98219df708c..189a9423268 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -214,6 +214,9 @@ if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) return FALSE + if(attack_type == OVERWHELMING_ATTACK) + return FALSE + if(attack_type == LEAP_ATTACK) final_block_chance -= 25 //OH GOD GET IT OFF ME @@ -509,6 +512,12 @@ if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) return FALSE + if(attack_type == OVERWHELMING_ATTACK) + return FALSE + + if(attack_type == LEAP_ATTACK) + final_block_chance -= 25 + if(prob(final_block_chance) && charge) expend_charge(owner) return TRUE diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 1f97cb21bb2..b0d917da2f5 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -94,7 +94,7 @@ INVOKE_ASYNC(baned_target, TYPE_PROC_REF(/mob/living/carbon/human, emote), "scream") /obj/item/melee/sabre/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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you. return ..() @@ -178,7 +178,7 @@ AddComponent(/datum/component/jousting) /obj/item/melee/parsnip_sabre/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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you. return ..() @@ -214,7 +214,7 @@ block_sound = 'sound/items/weapons/parry.ogg' /obj/item/melee/beesword/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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you. return ..() @@ -543,7 +543,7 @@ desc = "[initial(desc)] Its handle is made of [material.name]." /obj/item/melee/cleric_mace/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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a...mace to a gunfight, and also you aren't going to really block someone full body tackling you with a mace. Or a road roller, if one happened to hit you. return ..() diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 9fa8714e098..4393a980e00 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -54,7 +54,7 @@ if(attack_type == LEAP_ATTACK) effective_block_chance = 100 if(attack_type == OVERWHELMING_ATTACK) - effective_block_chance -= 25 + effective_block_chance = 0 final_block_chance = clamp(effective_block_chance, 0, 100) . = ..() if(.) @@ -345,7 +345,7 @@ var/effective_block_chance = final_block_chance if(attack_type == OVERWHELMING_ATTACK) - effective_block_chance -= 25 + effective_block_chance = 0 if(attack_type == PROJECTILE_ATTACK) var/obj/projectile/our_projectile = hitby diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm index 6264e8cd371..be6a468e1b9 100644 --- a/code/game/objects/items/spear.dm +++ b/code/game/objects/items/spear.dm @@ -323,7 +323,7 @@ /* * Bamboo Spear */ -/obj/item/spear/bamboospear //Blatant imitation of spear, but all natural. Also not valid for explosive modification. +/obj/item/spear/bamboospear //Blatant imitation of spear, but all natural. icon_state = "bamboo_spear0" base_icon_state = "bamboo_spear0" icon_prefix = "bamboo_spear" diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 736e5754d73..852f3af1260 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -155,7 +155,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 return BRUTELOSS /obj/item/claymore/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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you. return ..() @@ -415,6 +415,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 alt_simple = string_list(alt_simple) AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -15) +/obj/item/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) + if(attack_type == OVERWHELMING_ATTACK) + final_block_chance = 0 //Not a high freuqnecy blade, sorry pal + return ..() + /datum/armor/item_katana fire = 100 acid = 50 @@ -637,6 +642,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon_state = inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]" return ..() +/obj/item/bambostaff/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) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) + final_block_chance = 0 //Don't bring a staff to a gunfight, and also you aren't going to really block someone full body tackling you with a staff. Or a road roller, if one happened to hit you. + return ..() + /obj/item/cane name = "cane" desc = "A cane used by a true gentleman. Or a clown." @@ -1198,7 +1208,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 playsound(src, SFX_BULLET_MISS, 75, TRUE) return TRUE return FALSE - if(prob(final_block_chance * (HAS_TRAIT(src, TRAIT_WIELDED) ? 2 : 1))) + var/stop_that_blade = (final_block_chance + (attack_type == OVERWHELMING_ATTACK ? 25 : 0)) * (HAS_TRAIT(src, TRAIT_WIELDED) ? 2 : 1) + if(prob(stop_that_blade)) owner.visible_message(span_danger("[owner] parries [attack_text] with [src]!")) return TRUE return FALSE diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index cc2350e685c..409c51e6866 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -523,6 +523,9 @@ loc.visible_message(span_warning("The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!"), span_warning("We inflate our hand into a strong shield."), span_hear("You hear organic matter ripping and tearing!")) /obj/item/shield/changeling/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) + if(attack_type == OVERWHELMING_ATTACK) + return FALSE + if(remaining_uses < 1) if(ishuman(loc)) var/mob/living/carbon/human/H = loc diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index ed423464aa3..2a150443e77 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -55,7 +55,7 @@ Striking a noncultist, however, will tear their flesh."} if(owner.get_active_held_item() != src) block_message = "[owner] parries [attack_text] with [src] in their offhand" - if(IS_CULTIST(owner) && prob(final_block_chance) && attack_type != (PROJECTILE_ATTACK || OVERWHELMING_ATTACK)) + if(IS_CULTIST(owner) && prob(final_block_chance) && (attack_type != PROJECTILE_ATTACK || attack_type != OVERWHELMING_ATTACK)) new /obj/effect/temp_visual/cult/sparks(get_turf(owner)) owner.visible_message(span_danger("[block_message]")) return TRUE diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm index 3d4924d2211..d5dc25187b5 100644 --- a/code/modules/antagonists/heretic/items/heretic_blades.dm +++ b/code/modules/antagonists/heretic/items/heretic_blades.dm @@ -304,6 +304,11 @@ return ITEM_INTERACT_BLOCKING return NONE +/obj/item/melee/sickly_blade/cursed/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) + if(attack_type == OVERWHELMING_ATTACK) + return FALSE + return ..() + // Weaker blade variant given to people so they can participate in the heretic arena spell /obj/item/melee/sickly_blade/training name = "\improper imperfect blade" diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm index 93f352539da..1a4116b9579 100644 --- a/code/modules/clothing/outfits/ert.dm +++ b/code/modules/clothing/outfits/ert.dm @@ -188,7 +188,7 @@ name = "Inquisition Commander" back = /obj/item/mod/control/pre_equipped/responsory/inquisitory/commander - r_hand = /obj/item/nullrod/vibro/talking/chainsword + r_hand = /obj/item/nullrod/claymore/talking/chainsword backpack_contents = null /datum/outfit/centcom/ert/security/inquisitor diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index f46b31086a9..c51b6602478 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -259,6 +259,11 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( slapperoni(user, iteration = 1) return MANUAL_SUICIDE +/obj/item/fish/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) + if(attack_type == OVERWHELMING_ATTACK) + return FALSE + return ..() + /obj/item/fish/proc/slapperoni(mob/living/user, iteration) stoplag(0.1 SECONDS) user.visible_message(span_bolddanger(suicide_slap_text)) diff --git a/code/modules/hydroponics/soil.dm b/code/modules/hydroponics/soil.dm index 4b6389923a2..c46685ac689 100644 --- a/code/modules/hydroponics/soil.dm +++ b/code/modules/hydroponics/soil.dm @@ -175,6 +175,11 @@ qdel(src) return ITEM_INTERACT_SUCCESS +/obj/item/soil_sack/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) + if(attack_type == OVERWHELMING_ATTACK) + return FALSE + return ..() + ///Remove slowdown and add block chance when wielded. /obj/item/soil_sack/proc/on_wield() slowdown = 0 diff --git a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm index a734904b905..549060e62ca 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm @@ -128,7 +128,7 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -3) /obj/item/nullrod/claymore/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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you. return ..() @@ -191,62 +191,26 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) SET_ATTACK_FORCE(attack_modifiers, rand(max(force - 15, 1), force + 15)) return ..() -/// Vibro Variant -/// This subtype possesses armor penetration and is sharp. - -/obj/item/nullrod/vibro - name = "high frequency blade" - desc = "Bad references are the DNA of the soul." - icon = 'icons/obj/weapons/sword.dmi' - icon_state = "hfrequency0" - inhand_icon_state = "hfrequency1" - worn_icon_state = "hfrequency0" - icon_angle = -45 - lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' - w_class = WEIGHT_CLASS_BULKY - armour_penetration = 35 - slot_flags = ITEM_SLOT_BACK - sharpness = SHARP_EDGED - attack_verb_continuous = list("chops", "slices", "cuts", "zandatsu's") - attack_verb_simple = list("chop", "slice", "cut", "zandatsu") - hitsound = 'sound/items/weapons/rapierhit.ogg' - menu_description = "A sharp blade which partially penetrates armor. Very effective at butchering bodies. Can be worn on the back." - var/list/alt_continuous = list("stabs", "pierces", "impales") - var/list/alt_simple = list("stab", "pierce", "impale") - -/obj/item/nullrod/vibro/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, -3) - -/obj/item/nullrod/vibro/Initialize(mapload) - . = ..() - AddComponent( - /datum/component/butchering, \ - speed = 7 SECONDS, \ - effectiveness = 110, \ - ) - -/obj/item/nullrod/vibro/spellblade +/obj/item/nullrod/claymore/spellblade name = "dormant spellblade" desc = "The blade grants the wielder nearly limitless power...if they can figure out how to turn it on, that is." icon = 'icons/obj/weapons/guns/magic.dmi' icon_state = "spellblade" inhand_icon_state = "spellblade" + slot_flags = ITEM_SLOT_BACK lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' worn_icon_state = "spellblade" hitsound = 'sound/items/weapons/rapierhit.ogg' - menu_description = "A sharp blade which partially penetrates armor. Very effective at butchering bodies. Can be worn on the back." + menu_description = "A sharp blade which provides a low chance of blocking incoming melee attacks. Can be worn on the back." -/obj/item/nullrod/vibro/talking +/obj/item/nullrod/claymore/talking name = "possessed blade" desc = "When the station falls into chaos, it's nice to have a friend by your side." icon = 'icons/obj/weapons/sword.dmi' icon_state = "talking_sword" inhand_icon_state = "talking_sword" + slot_flags = ITEM_SLOT_BACK icon_angle = 45 lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' @@ -254,13 +218,13 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) attack_verb_continuous = list("chops", "slices", "cuts") attack_verb_simple= list("chop", "slice", "cut") hitsound = 'sound/items/weapons/rapierhit.ogg' - menu_description = "A sharp blade which partially penetrates armor. Able to awaken a friendly spirit to provide guidance. Very effective at butchering bodies. Can be worn on the back." + menu_description = "A sharp blade which provides a low chance of blocking incoming melee attacks. Able to awaken a friendly spirit to provide guidance. Can be worn on the back." -/obj/item/nullrod/vibro/talking/Initialize(mapload) +/obj/item/nullrod/spellblade/talking/Initialize(mapload) . = ..() AddComponent(/datum/component/spirit_holding) -/obj/item/nullrod/vibro/talking/chainsword +/obj/item/nullrod/claymore/talking/chainsword name = "possessed chainsaw sword" desc = "Suffer not a heretic to live." icon_state = "chainswordon" @@ -275,13 +239,70 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) toolspeed = 0.5 //same speed as an active chainsaw chaplain_spawnable = FALSE //prevents being pickable as a chaplain weapon (it has 30 force) -/obj/item/nullrod/vibro/talking/chainsword/Initialize(mapload) +/obj/item/nullrod/spellblade/talking/chainsword/Initialize(mapload) . = ..() AddElement(/datum/element/cuffable_item) //Thanks goodness it cannot be selected by chappies + AddComponent( + /datum/component/butchering, \ + speed = 7 SECONDS, \ + effectiveness = 110, \ + ) /// Other Variants /// Not a special category on their own, but usually possess more unique mechanics +// High Frequency Blade - Two-handed, has armor penetration, and can block exosuit attacks relatively easily. Can't block anything else. + +/obj/item/nullrod/vibro + name = "high frequency blade" + desc = "Bad references are the DNA of the soul." + icon = 'icons/obj/weapons/sword.dmi' + icon_state = "hfrequency0" + inhand_icon_state = "hfrequency0" + base_icon_state = "hfrequency" + worn_icon_state = "hfrequency0" + icon_angle = -45 + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + w_class = WEIGHT_CLASS_BULKY + force = 10 + armour_penetration = 35 + block_chance = 40 + slot_flags = ITEM_SLOT_BACK + sharpness = SHARP_EDGED + attack_verb_continuous = list("chops", "slices", "cuts", "zandatsu's") + attack_verb_simple = list("chop", "slice", "cut", "zandatsu") + hitsound = 'sound/items/weapons/rapierhit.ogg' + block_sound = 'sound/items/weapons/parry.ogg' + menu_description = "A sharp blade which partially penetrates armor. Unusualy adept at blocking melee attacks from exosuits. Very effective at butchering bodies. Can be worn on the back." + var/list/alt_continuous = list("stabs", "pierces", "impales") + var/list/alt_simple = list("stab", "pierce", "impale") + +/obj/item/nullrod/vibro/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, -3) + AddComponent(/datum/component/two_handed, \ + force_unwielded = 10, \ + force_wielded = 18, \ + ) + AddComponent( + /datum/component/butchering, \ + speed = 7 SECONDS, \ + effectiveness = 110, \ + ) + +/obj/item/nullrod/vibro/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) + if(prob(final_block_chance * (HAS_TRAIT(src, TRAIT_WIELDED) ? 2 : 1)) && attack_type == OVERWHELMING_ATTACK) + owner.visible_message(span_danger("[owner] parries [attack_text] with [src]!")) + return TRUE + return FALSE + +/obj/item/nullrod/vibro/update_icon_state() + icon_state = inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]" + return ..() + // God Hand - Cannot be dropped. Does burn damage. /obj/item/nullrod/godhand @@ -585,7 +606,7 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) AddElement(/datum/element/nullrod_core) AddComponent(/datum/component/faction_granter, FACTION_CARP, holy_role_required = HOLY_ROLE_PRIEST, grant_message = span_boldnotice("You are blessed by Carp-Sie. Wild space carp will no longer attack you.")) -// Monk's Staff - Higher block, lower damage. +// Monk's Staff - Good block, two-handed. Great for showing off. /obj/item/nullrod/bostaff name = "monk's staff" @@ -620,7 +641,7 @@ GLOBAL_LIST_INIT(nullrod_variants, init_nullrod_variants()) return ..() /obj/item/nullrod/bostaff/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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a stick to a gunfight, and also you aren't going to really block someone full body tackling you with a stick. Or a road roller, if one happened to hit you. return ..() diff --git a/code/modules/mining/lavaland/mining_loot/cursed_katana.dm b/code/modules/mining/lavaland/mining_loot/cursed_katana.dm index 8de94828932..4b0019166f7 100644 --- a/code/modules/mining/lavaland/mining_loot/cursed_katana.dm +++ b/code/modules/mining/lavaland/mining_loot/cursed_katana.dm @@ -107,7 +107,7 @@ return ..() /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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you. return ..() diff --git a/code/modules/mob_spawn/corpses/mining_corpses.dm b/code/modules/mob_spawn/corpses/mining_corpses.dm index da860fdb3b6..876283599fa 100644 --- a/code/modules/mob_spawn/corpses/mining_corpses.dm +++ b/code/modules/mob_spawn/corpses/mining_corpses.dm @@ -350,7 +350,7 @@ dame.physique = FEMALE dame.update_body() if(prob(30)) - back = /obj/item/nullrod/vibro/talking + back = /obj/item/nullrod/claymore/talking else back = /obj/item/shield/buckler belt = /obj/item/nullrod/claymore diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index 6b7d814aa3e..44443c90fa2 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -29,6 +29,8 @@ var/shield_icon = "shield-red" /// Charges the shield should start with. var/charges + /// Whether or not we allow this shield to block overwhelming attacks, such as from mechs. + var/block_overwhelming_attacks = FALSE /obj/item/mod/module/energy_shield/Initialize(mapload) . = ..() @@ -43,6 +45,7 @@ charge_recovery = charge_recovery, \ lose_multiple_charges = lose_multiple_charges, \ starting_charges = charges, \ + can_block_overwhelming = block_overwhelming_attacks, \ shield_icon_file = shield_icon_file, \ shield_icon = shield_icon) RegisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(shield_reaction)) @@ -64,7 +67,7 @@ SIGNAL_HANDLER if(mod.hit_reaction(owner, hitby, attack_text, 0, damage, attack_type)) - drain_power(use_energy_cost) + drain_power(use_energy_cost + use_energy_cost * (attack_type == OVERWHELMING_ATTACK ? (damage/100) : 0)) return SUCCESSFUL_BLOCK return NONE @@ -80,6 +83,7 @@ max_charges = 5 recharge_start_delay = 20 SECONDS charge_increment_delay = 3 SECONDS + block_overwhelming_attacks = TRUE // It's magic, bitch shield_icon_file = 'icons/effects/magic.dmi' shield_icon = "mageshield" required_slots = list() diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index 6792f653a05..b1d664a6271 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -264,7 +264,7 @@ ) /obj/item/gun/magic/staff/spellblade/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) - if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK)) + if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK || attack_type == OVERWHELMING_ATTACK) final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you. return ..() diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm index f8ccec3e202..76a23c28159 100644 --- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -108,8 +108,6 @@ return ..() if(victim.check_block(chassis, clamp_damage, name, attack_type = OVERWHELMING_ATTACK)) - source.visible_message(span_danger("[chassis] attempts to squeeze [victim] with [src], but the [name] is blocked!"), span_userdanger("You attempt to squeeze [victim] with [src], but [victim.p_They()] managed to block the attempt!"), ignored_mobs = victim) - to_chat(victim, span_userdanger("You block [chassis]'s attempt to squeeze you with [src]!")) return ..() if(iscarbon(victim) && killer_clamp)//meme clamp here diff --git a/code/modules/vehicles/mecha/mech_melee_attack.dm b/code/modules/vehicles/mecha/mech_melee_attack.dm index 3aee7762b76..6d868f52e36 100644 --- a/code/modules/vehicles/mecha/mech_melee_attack.dm +++ b/code/modules/vehicles/mecha/mech_melee_attack.dm @@ -100,9 +100,14 @@ if(!isnull(user) && HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, span_warning("You don't want to harm other living beings!")) return + mecha_attacker.do_attack_animation(src) if(mecha_attacker.damtype == BRUTE) step_away(src, mecha_attacker, 15) + + if(check_block(mecha_attacker, mecha_attacker.force * 3, "the [mecha_attacker.attack_verbs[1]]", attack_type = OVERWHELMING_ATTACK)) + return + switch(mecha_attacker.damtype) if(BRUTE) if(mecha_attacker.force > 35) // durand and other heavy mechas diff --git a/tools/UpdatePaths/Scripts/94089_vibro_repaths.txt b/tools/UpdatePaths/Scripts/94089_vibro_repaths.txt new file mode 100644 index 00000000000..4ee856206b9 --- /dev/null +++ b/tools/UpdatePaths/Scripts/94089_vibro_repaths.txt @@ -0,0 +1,5 @@ +/obj/item/nullrod/claymore/spellblade : /obj/item/nullrod/vibro/spellblade{@OLD} + +/obj/item/nullrod/claymore/talking : /obj/item/nullrod/vibro/talking{@OLD} + +/obj/item/nullrod/claymore/talking/chainsword : /obj/item/nullrod/vibro/talking/chainsword{@OLD} \ No newline at end of file