From 6a83c1ad67eec2d49a385a6a8675da54f0f3467c Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 12 Aug 2026 23:23:39 +0000 Subject: [PATCH] Migrate two-handed weapons to the new attack chain. (#32313) * Migrate two-handed weapons to the new attack chain. * Apply suggestions from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * Separate two-handed weapons into several files in their own folder. * Formatting tweaks. * Apply suggestions from CRUNCH review. * Include paradise.dme. * Migrate a bit more, clean up a bit more. * Apply suggestions from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * Apply suggestions from CRUNCH review Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * Hopefully resolve CRLF error. * Define some variables. * Apply suggestions from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * Apply suggestions from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * Apply suggestions from CRUNCH review Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * Fix supermatter halberd dusting condition, spelling errors. * Apply suggestion from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * GITHUB NO. PUT THAT BACK. * Fix pyro claws door force. * Restore the coveted trailing newline. * Apply suggestion from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan * Migrate bo staff to the two handed folder and new attack chain. * Apply suggestions from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan --------- Signed-off-by: Alan Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> --- code/datums/components/forces_doors_open.dm | 16 +- .../objects/items/weapons/two_handed/axes.dm | 109 ++ .../items/weapons/two_handed/hammers.dm | 216 ++++ .../weapons/two_handed/misc_two_handed.dm | 435 +++++++ .../items/weapons/two_handed/push_broom.dm | 169 +++ .../items/weapons/two_handed/spears.dm | 320 ++++++ code/game/objects/items/weapons/twohanded.dm | 1004 ----------------- code/modules/martial_arts/martial.dm | 82 -- paradise.dme | 6 +- 9 files changed, 1268 insertions(+), 1089 deletions(-) create mode 100644 code/game/objects/items/weapons/two_handed/axes.dm create mode 100644 code/game/objects/items/weapons/two_handed/hammers.dm create mode 100644 code/game/objects/items/weapons/two_handed/misc_two_handed.dm create mode 100644 code/game/objects/items/weapons/two_handed/push_broom.dm create mode 100644 code/game/objects/items/weapons/two_handed/spears.dm delete mode 100644 code/game/objects/items/weapons/twohanded.dm diff --git a/code/datums/components/forces_doors_open.dm b/code/datums/components/forces_doors_open.dm index 949d8ceedea..86987002ab6 100644 --- a/code/datums/components/forces_doors_open.dm +++ b/code/datums/components/forces_doors_open.dm @@ -75,7 +75,7 @@ // open unpowered if(can_force_open_while_unpowered && !airlock.arePowerSystemsOn()) - INVOKE_ASYNC(src, PROC_REF(open_unpowered_door), airlock) + INVOKE_ASYNC(src, PROC_REF(open_unpowered_door), airlock, user) return TRUE // open powered @@ -88,8 +88,12 @@ if(!no_sound) playsound(parent, open_sound, 100, 1) + var/obj/item/parent_item = parent + parent_item.door_force_try_message(airlock, user) + if(do_after_once(user, time_to_open, target = airlock, attempt_cancel_message = "You decide to stop prying [airlock] with [parent].")) if(airlock.open(TRUE)) + parent_item.door_force_success_message(airlock, user) return // successfully opened // opening failed @@ -97,8 +101,10 @@ to_chat(user, SPAN_WARNING("Despite your attempts, [airlock] refuses to open.")) /// open door without checks -/datum/component/forces_doors_open/proc/open_unpowered_door(obj/machinery/door/door) +/datum/component/forces_doors_open/proc/open_unpowered_door(obj/machinery/door/door, mob/user) door.open(TRUE) + var/obj/item/parent_item = parent + parent_item.door_force_success_message(door, user) /// subtype for mantis blades /datum/component/forces_doors_open/mantis/on_interact(datum/source, mob/user, atom/target) @@ -115,3 +121,9 @@ if(try_to_force_open_airlock(user, target)) return ITEM_INTERACT_COMPLETE + +/obj/item/proc/door_force_try_message(obj/machinery/door/door, mob/user) + return + +/obj/item/proc/door_force_success_message(obj/machinery/door/door, mob/user) + return diff --git a/code/game/objects/items/weapons/two_handed/axes.dm b/code/game/objects/items/weapons/two_handed/axes.dm new file mode 100644 index 00000000000..b0e3eec6032 --- /dev/null +++ b/code/game/objects/items/weapons/two_handed/axes.dm @@ -0,0 +1,109 @@ +/* + * Fireaxe + */ +/// DEM AXES MAN, marker -Agouri +/obj/item/fireaxe + base_icon_state = "fireaxe" + lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' + icon = 'icons/obj/weapons/melee.dmi' + icon_state = "fireaxe0" + name = "fire axe" + desc = "Truly, the weapon of a madman. Who would think to fight fire with an axe?" + force = 5 + throwforce = 15 + sharp = TRUE + w_class = WEIGHT_CLASS_BULKY + slot_flags = ITEM_SLOT_BACK + toolspeed = 0.25 + attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + usesound = 'sound/items/crowbar.ogg' + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 30) + resistance_flags = FIRE_PROOF + var/force_unwielded = 5 + var/force_wielded = 24 + new_attack_chain = TRUE + +/obj/item/fireaxe/Initialize(mapload) + . = ..() + AddComponent(/datum/component/forces_doors_open) + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.7, \ + _parryable_attack_types = MELEE_ATTACK, \ + _parry_cooldown = (10 / 3) SECONDS, \ + _requires_two_hands = TRUE) // 2.3333 seconds of parry cooldown for 30% uptime. + AddComponent(/datum/component/two_handed, \ + force_unwielded = force_unwielded, \ + force_wielded = force_wielded, \ + icon_wielded = "[base_icon_state]1") + +/obj/item/fireaxe/update_icon_state() // Currently only here to fuck with the on-mob icons. + icon_state = "[base_icon_state]0" + return ..() + +/obj/item/fireaxe/after_attack(atom/target, mob/user, proximity_flag, click_parameters) + if(!proximity_flag) + return FINISH_ATTACK + if(!HAS_TRAIT(src, TRAIT_WIELDED)) // Destroys windows and grilles in one hit. + return ..() + if(!istype(target, /obj/structure/window) && !istype(target, /obj/structure/grille)) + return ..() + + var/obj/structure/target_structure = target + target_structure.obj_destruction("fireaxe") + return FINISH_ATTACK + +/// Blatant imitation of the fireaxe, but made out of bone. +/obj/item/fireaxe/boneaxe + icon_state = "bone_axe0" + base_icon_state = "bone_axe" + name = "bone axe" + desc = "A large, vicious axe crafted out of several sharpened bone plates and crudely tied together. Made of monsters, by killing monsters, for killing monsters." + force_wielded = 23 + needs_permit = TRUE + +/obj/item/fireaxe/energized + desc = "Someone with a love for fire axes decided to turn this one into a high-powered energy weapon. Seems excessive." + force_wielded = 35 + armor_penetration_flat = 10 + armor_penetration_percentage = 30 + var/charge = 20 + var/max_charge = 20 + +/obj/item/fireaxe/energized/Initialize(mapload) + . = ..() + // only update the new args + START_PROCESSING(SSobj, src) + AddComponent(/datum/component/two_handed, \ + force_wielded = force_wielded, \ + icon_wielded = "[base_icon_state]2") + +/obj/item/fireaxe/energized/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/fireaxe/energized/process() + charge = min(charge + 1, max_charge) + +/obj/item/fireaxe/energized/after_attack(mob/living/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(!HAS_TRAIT(src, TRAIT_WIELDED) || charge != max_charge) + return + + if(!isliving(target)) + return + + charge = 0 + playsound(loc, 'sound/magic/lightningbolt.ogg', 5, 1) + target.visible_message( + SPAN_DANGER("[user] slams the charged axe into [target] with all [user.p_their()] might!"), + SPAN_USERDANGER("[user] slams into you with incredible force!"), + SPAN_HEAR("You hear a collossal impact!") + ) + do_sparks(1, 1, src) + target.KnockDown(8 SECONDS) + var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src))) + target.throw_at(throw_target, 5, 1) + return FINISH_ATTACK diff --git a/code/game/objects/items/weapons/two_handed/hammers.dm b/code/game/objects/items/weapons/two_handed/hammers.dm new file mode 100644 index 00000000000..e327dfef443 --- /dev/null +++ b/code/game/objects/items/weapons/two_handed/hammers.dm @@ -0,0 +1,216 @@ +// SINGULOHAMMER. +/obj/item/singularityhammer + name = "singularity hammer" + desc = "The pinnacle of close combat technology, the hammer harnesses the power of a miniaturized singularity to deal crushing blows." + lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' + icon = 'icons/obj/weapons/magical_weapons.dmi' + icon_state = "singulohammer0" + base_icon_state = "singulohammer" + flags = CONDUCT + slot_flags = ITEM_SLOT_BACK + force = 5 + throwforce = 15 + throw_range = 1 + w_class = WEIGHT_CLASS_HUGE + armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 0, BOMB = 50, RAD = 0, FIRE = 100, ACID = 100) + resistance_flags = FIRE_PROOF | ACID_PROOF + var/charged = 2 + origin_tech = "combat=4;bluespace=4;plasmatech=7" + new_attack_chain = TRUE + +/obj/item/singularityhammer/Initialize(mapload) + . = ..() + AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (4 / 3) SECONDS, _requires_two_hands = TRUE) // 0.3333 seconds of cooldown for 75% uptime + AddComponent(/datum/component/two_handed, \ + force_wielded = 40, \ + force_unwielded = force, \ + icon_wielded = "[base_icon_state]1") + START_PROCESSING(SSobj, src) + +/obj/item/singularityhammer/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/singularityhammer/process() + if(charged < 2) + charged++ + +/obj/item/singularityhammer/update_icon_state() // Currently only here to fuck with the on-mob icons. + icon_state = "singulohammer0" + +/obj/item/singularityhammer/proc/vortex(turf/pull, mob/wielder) + for(var/atom/movable/X in range(5, pull)) + if(X.move_resist == INFINITY) + continue + if(X == wielder) + continue + if((X) && (!X.anchored) && (!ishuman(X))) + step_towards(X, pull) + step_towards(X, pull) + step_towards(X, pull) + else if(ishuman(X)) + var/mob/living/carbon/human/H = X + if(HAS_TRAIT(H, TRAIT_MAGPULSE)) + continue + H.Weaken(4 SECONDS) + step_towards(H, pull) + step_towards(H, pull) + step_towards(H, pull) + +/obj/item/singularityhammer/after_attack(mob/living/target, mob/user, proximity_flag, click_parameters) + if(!proximity_flag) + return FINISH_ATTACK + if(!HAS_TRAIT(src, TRAIT_WIELDED)) + return ..() + if(charged < 2) + return ..() + charged = 0 + if(isliving(target)) + target.take_organ_damage(20, 0) + playsound(user, 'sound/weapons/marauder.ogg', 50, 1) + var/turf/target_turf = get_turf(target) + vortex(target_turf, user) + return FINISH_ATTACK + +/obj/item/mjollnir + name = "Mjolnir" + desc = "A weapon worthy of a god, able to strike with the force of a lightning bolt. It crackles with barely contained energy." + lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' + icon = 'icons/obj/weapons/magical_weapons.dmi' + icon_state = "mjollnir0" + base_icon_state = "mjollnir" + flags = CONDUCT + slot_flags = ITEM_SLOT_BACK + force = 5 + throwforce = 30 + w_class = WEIGHT_CLASS_HUGE + origin_tech = "combat=4;powerstorage=7" + new_attack_chain = TRUE + +/obj/item/mjollnir/Initialize(mapload) + . = ..() + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.25, \ + _parryable_attack_types = ALL_ATTACK_TYPES, \ + _parry_cooldown = (4 / 3) SECONDS, \ + _requires_two_hands = TRUE) // 0.3333 seconds of parry cooldown for 75% uptime. + AddComponent(/datum/component/two_handed, \ + force_wielded = 25, \ + force_unwielded = force, \ + icon_wielded = "[base_icon_state]1") + +/obj/item/mjollnir/proc/shock(mob/living/target) + do_sparks(5, 1, target.loc) + target.visible_message( + SPAN_DANGER("[target] was shocked by [src]!"), + SPAN_USERDANGER("You feel a powerful shock course through your body sending you flying!"), + SPAN_DANGER("You hear a heavy electrical crack!") + ) + var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src))) + target.throw_at(throw_target, 200, 4) + +/obj/item/mjollnir/after_attack(mob/living/target, mob/user, proximity_flag, click_parameters) + if(!isliving(target)) + return ..() + + if(!HAS_TRAIT(src, TRAIT_WIELDED)) + return ..() + + playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + target.Stun(6 SECONDS) + shock(target) + return FINISH_ATTACK + +/obj/item/mjollnir/throw_impact(atom/target) + . = ..() + if(isliving(target)) + var/mob/living/L = target + L.Stun(6 SECONDS) + shock(L) + +/obj/item/mjollnir/update_icon_state() // Currently only here to fuck with the on-mob icons. + icon_state = "mjollnir0" + +/obj/item/knighthammer + name = "singuloth knight's hammer" + desc = "A hammer made of sturdy metal with a golden skull adorned with wings on either side of the head.
This weapon causes devastating damage to those it hits due to a power field sustained by a mini-singularity inside of the hammer." + lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' + icon = 'icons/obj/weapons/magical_weapons.dmi' + icon_state = "knighthammer0" + base_icon_state = "knighthammer" + flags = CONDUCT + slot_flags = ITEM_SLOT_BACK + force = 5 + throwforce = 15 + throw_range = 1 + w_class = WEIGHT_CLASS_HUGE + var/charged = 5 + origin_tech = "combat=5;bluespace=4" + new_attack_chain = TRUE + +/obj/item/knighthammer/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.25, \ + _parryable_attack_types = ALL_ATTACK_TYPES, \ + _parry_cooldown = (4 / 3) SECONDS, \ + _requires_two_hands = TRUE) // 0.3333 seconds of parry cooldown for 75% uptime. + AddComponent(/datum/component/two_handed, \ + force_wielded = 30, \ + force_unwielded = force, \ + icon_wielded = "[base_icon_state]1") + +/obj/item/knighthammer/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/knighthammer/process() + if(charged < 5) + charged++ + +/obj/item/knighthammer/update_icon_state() // Currently only here to fuck with the on-mob icons. + icon_state = "knighthammer0" + +/obj/item/knighthammer/after_attack(atom/target, mob/user, proximity_flag, click_parameters) + if(!proximity_flag) + return FINISH_ATTACK + if(charged < 5) + return ..() + + charged = 0 + if(isliving(target)) + var/mob/living/Z = target + if(Z.health > HEALTH_THRESHOLD_CRIT) + Z.visible_message( + SPAN_DANGER("[Z.name] was sent flying by a blow from [src]!"), + SPAN_USERDANGER("You feel a powerful blow connect with your body and send you flying!"), + SPAN_DANGER("You hear something heavy impact flesh!") + ) + var/atom/throw_target = get_edge_target_turf(Z, get_dir(src, get_step_away(Z, src))) + Z.throw_at(throw_target, 200, 4) + // Target is in crit, check if we're holding securely enough to gib them. + else if(HAS_TRAIT(src, TRAIT_WIELDED)) + Z.visible_message( + SPAN_DANGER("[Z.name] was blown to pieces by the power of [src]!"), + SPAN_USERDANGER("You feel a powerful blow rip you apart!"), + SPAN_DANGER("You hear a heavy impact and the sound of ripping flesh!") + ) + Z.gib() + playsound(user, 'sound/weapons/marauder.ogg', 50, 1) + return FINISH_ATTACK + if(HAS_TRAIT(src, TRAIT_WIELDED)) + if(iswallturf(target)) + var/turf/simulated/wall/Z = target + Z.ex_act(EXPLODE_HEAVY) + else if(isstructure(target) || ismecha(target)) + var/obj/Z = target + Z.ex_act(EXPLODE_HEAVY) + charged = 3 + playsound(user, 'sound/weapons/marauder.ogg', 50, 1) + return FINISH_ATTACK diff --git a/code/game/objects/items/weapons/two_handed/misc_two_handed.dm b/code/game/objects/items/weapons/two_handed/misc_two_handed.dm new file mode 100644 index 00000000000..738b0771a98 --- /dev/null +++ b/code/game/objects/items/weapons/two_handed/misc_two_handed.dm @@ -0,0 +1,435 @@ +/* + * Double-Bladed Energy Swords - Cheridan + */ +/obj/item/dualsaber + name = "double-bladed energy sword" + desc = "Handle with care." + icon = 'icons/obj/weapons/energy_melee.dmi' + lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' + hitsound = "swing_hit" + icon_state = "dualsaber0" + force = 3 + throwforce = 5 + throw_speed = 1 + throw_range = 5 + w_class = WEIGHT_CLASS_SMALL + var/w_class_on = WEIGHT_CLASS_BULKY + armor_penetration_flat = 10 + armor_penetration_percentage = 50 + origin_tech = "magnets=4;syndicate=5" + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 70) + resistance_flags = FIRE_PROOF + light_power = 2 + needs_permit = TRUE + var/hacked = FALSE + var/blade_color + var/brightness_on = 2 + var/colormap = list( + red = LIGHT_COLOR_RED, + blue = LIGHT_COLOR_LIGHTBLUE, + green = LIGHT_COLOR_GREEN, + purple = LIGHT_COLOR_PURPLE, + rainbow = LIGHT_COLOR_WHITE, + ) + var/force_unwielded = 3 + var/force_wielded = 34 + var/wieldsound = 'sound/weapons/saberon.ogg' + var/unwieldsound = 'sound/weapons/saberoff.ogg' + new_attack_chain = TRUE + +/obj/item/dualsaber/Initialize(mapload) + . = ..() + if(!blade_color) + blade_color = pick("red", "blue", "green", "purple") + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.25, \ + _parryable_attack_types = ALL_ATTACK_TYPES, \ + _parry_cooldown = (4 / 3) SECONDS, /* 0.33 seconds of parry cooldown for 75% uptime. */ \ + _requires_two_hands = TRUE) + AddComponent(/datum/component/two_handed, \ + force_wielded = force_wielded, \ + force_unwielded = force_unwielded, \ + wieldsound = wieldsound, \ + unwieldsound = unwieldsound, \ + attacksound = 'sound/weapons/blade1.ogg', \ + wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ + unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ + only_sharp_when_wielded = TRUE) + +/obj/item/dualsaber/update_icon_state() + if(HAS_TRAIT(src, TRAIT_WIELDED)) + icon_state = "dualsaber[blade_color]1" + set_light(brightness_on, l_color=colormap[blade_color]) + else + icon_state = "dualsaber0" + set_light(0) + +/obj/item/dualsaber/interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(cigarette_lighter_act(user, target)) + return ITEM_INTERACT_COMPLETE + return ..() + +/obj/item/dualsaber/pre_attack(atom/target, mob/living/user, params) + if(HAS_TRAIT(user, TRAIT_HULK)) + to_chat(user, SPAN_WARNING("You grip the blade too hard and accidentally drop it!")) + if(HAS_TRAIT(src, TRAIT_WIELDED)) + user.drop_item_to_ground(src) + return FINISH_ATTACK + if(HAS_TRAIT(user, TRAIT_CLUMSY) && HAS_TRAIT(src, TRAIT_WIELDED) && prob(40) && force) + to_chat(user, SPAN_WARNING("You twirl around a bit before losing your balance and impaling yourself on [src]!")) + user.take_organ_damage(20, 25) + return FINISH_ATTACK + + if((HAS_TRAIT(src, TRAIT_WIELDED)) && prob(50)) + INVOKE_ASYNC(src, PROC_REF(jedi_spin), user) + return ..() + +/obj/item/dualsaber/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item) + var/obj/item/clothing/mask/cigarette/cig = ..() + if(!cig) + return !isnull(cig) + + if(!HAS_TRAIT(src, TRAIT_WIELDED)) + to_chat(user, SPAN_WARNING("You need to activate [src] before you can light anything with it!")) + return TRUE + + if(target == user) + user.visible_message( + SPAN_DANGER("[user] flips through the air and spins [src] wildly! It brushes against [user.p_their()] [cig] and sets it alight!"), + SPAN_NOTICE("You flip through the air and twist [src] so it brushes against [cig], lighting it with the blade."), + SPAN_DANGER("You hear an energy blade slashing something!") + ) + else + user.visible_message( + SPAN_DANGER("[user] flips through the air and slashes at [user] with [src]! The blade barely misses, brushing against [user.p_their()] [cig] and setting it alight!"), + SPAN_NOTICE("You flip through the air and slash [src] at [cig], lighting it for [target]."), + SPAN_DANGER("You hear an energy blade slashing something!") + ) + user.do_attack_animation(target) + playsound(user.loc, hitsound, 50, TRUE) + cig.light(user, target) + INVOKE_ASYNC(src, PROC_REF(jedi_spin), user) + return TRUE + +/obj/item/dualsaber/proc/jedi_spin(mob/living/user) + for(var/i in list(NORTH, SOUTH, EAST, WEST, EAST, SOUTH, NORTH, SOUTH, EAST, WEST, EAST, SOUTH)) + user.setDir(i) + if(i == WEST) + user.SpinAnimation(7, 1) + sleep(1) + +/obj/item/dualsaber/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + if(!HAS_TRAIT(src, TRAIT_WIELDED)) + return FALSE + . = ..() + if(!.) // They did not block the attack. + return + + if(attack_type == THROWN_PROJECTILE_ATTACK) + if(!isitem(hitby)) + return TRUE + var/obj/item/TT = hitby + //Timer set to 0.2 seconds to ensure item finshes the throwing to prevent double embeds + addtimer(CALLBACK(TT, TYPE_PROC_REF(/atom/movable, throw_at), locateUID(TT.thrownby), 10, 4, owner), 0.2 SECONDS) + return TRUE + if(isitem(hitby)) + melee_attack_chain(owner, hitby.loc) + else + melee_attack_chain(owner, hitby) + return TRUE + +// In case it just so happens that it is still activated on the ground, prevents hulk from picking it up. +/obj/item/dualsaber/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) + if(HAS_TRAIT(src, TRAIT_WIELDED)) + to_chat(user, SPAN_WARNING("You can't pick up such a dangerous item with your meaty hands without losing fingers, better not to!")) + return TRUE + +/obj/item/dualsaber/green + blade_color = "green" + +/obj/item/dualsaber/red + blade_color = "red" + +/obj/item/dualsaber/purple + blade_color = "purple" + +/obj/item/dualsaber/blue + blade_color = "blue" + +/obj/item/dualsaber/proc/on_wield(obj/item/source, mob/living/carbon/user) + if(user && HAS_TRAIT(user, TRAIT_HULK)) + to_chat(user, SPAN_WARNING("You lack the grace to wield this!")) + return COMPONENT_TWOHANDED_BLOCK_WIELD + w_class = w_class_on + +/obj/item/dualsaber/proc/on_unwield() + w_class = initial(w_class) + +/obj/item/dualsaber/IsReflect() + if(HAS_TRAIT(src, TRAIT_WIELDED)) + return TRUE + +/obj/item/dualsaber/multitool_act(mob/user, obj/item/I) + . = TRUE + if(!I.use_tool(src, user, 0, volume = I.tool_volume)) + return + if(!hacked) + hacked = TRUE + to_chat(user, SPAN_WARNING("2XRNBW_ENGAGE")) + blade_color = "rainbow" + update_icon() + else + to_chat(user, SPAN_WARNING("It's starting to look like a triple rainbow - no, nevermind.")) + +// PYRO CLAWS +/obj/item/pyro_claws + name = "hardplasma energy claws" + desc = "The power of the sun, in the claws of your hand." + lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' + icon = 'icons/obj/weapons/energy_melee.dmi' + icon_state = "pyro_claws" + flags = ABSTRACT | NODROP | DROPDEL + force = 22 + damtype = BURN + armor_penetration_percentage = 50 + sharp = TRUE + attack_effect_override = ATTACK_EFFECT_CLAW + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut", "savaged", "clawed") + sprite_sheets_inhand = list( + "Vox" = 'icons/mob/clothing/species/vox/held.dmi', + "Drask" = 'icons/mob/clothing/species/drask/held.dmi' + ) + toolspeed = 0.5 + var/lifetime = 60 SECONDS + var/next_spark_time + new_attack_chain = TRUE + +/obj/item/pyro_claws/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + AddComponent(/datum/component/forces_doors_open) + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.5, \ + _parryable_attack_types = ALL_ATTACK_TYPES) + AddComponent(/datum/component/two_handed, require_twohands = TRUE) + +/obj/item/pyro_claws/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/pyro_claws/customised_abstract_text(mob/living/carbon/owner) + return SPAN_WARNING("[owner.p_they(TRUE)] [owner.p_have(FALSE)] energy claws extending [owner.p_their(FALSE)] wrists.") + +/obj/item/pyro_claws/process() + lifetime -= 2 SECONDS + if(lifetime <= 0) + visible_message(SPAN_WARNING("[src] slides back into the depths of [loc]'s wrists.")) + do_sparks(rand(1, 6), 1, loc) + qdel(src) + return + if(prob(15)) + do_sparks(rand(1, 6), 1, loc) + +/obj/item/pyro_claws/door_force_try_message(obj/machinery/door/door, mob/user) + user.visible_message( + SPAN_WARNING("[user] jams [user.p_their()] [name] into [door] and starts prying it open!"), + SPAN_WARNING("You start forcing [door] open."), + SPAN_HEAR("You hear a metal screeching sound.") + ) + +/obj/item/pyro_claws/door_force_success_message(obj/machinery/door/door, mob/user) + user.visible_message( + SPAN_WARNING("[user] forces [door] open with [user.p_their()] [name]!"), + SPAN_WARNING("You force open [door]."), + SPAN_HEAR("You hear a metal screeching come to a halt.") + ) + +/obj/item/pyro_claws/interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(prob(60) && world.time > next_spark_time) + do_sparks(rand(1, 6), 1, loc) + next_spark_time = world.time + 0.8 SECONDS + return NONE + +/obj/item/clothing/gloves/color/black/pyro_claws + name = "Fusion gauntlets" + desc = "A pair of heavy combat gauntlets that project lethal energy claws via the power of a captive pyroclastic anomaly core." + icon_state = "pyro" + inhand_icon_state = null + worn_icon_state = null + can_be_cut = FALSE + actions_types = list(/datum/action/item_action/toggle) + dyeable = FALSE + materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 4000, MAT_TITANIUM = 4000, MAT_PLASMA = 8000) + var/on_cooldown = FALSE + var/obj/item/assembly/signaler/anomaly/pyro/core + var/next_spark_time + +/obj/item/clothing/gloves/color/black/pyro_claws/Destroy() + QDEL_NULL(core) + return ..() + +/obj/item/clothing/gloves/color/black/pyro_claws/examine(mob/user) + . = ..() + if(core) + . += SPAN_NOTICE("[src] are fully operational!") + else + . += SPAN_WARNING("It is missing a pyroclastic anomaly core.") + +/obj/item/clothing/gloves/color/black/pyro_claws/item_action_slot_check(slot) + if(slot == ITEM_SLOT_GLOVES) + return TRUE + +/obj/item/clothing/gloves/color/black/pyro_claws/ui_action_click(mob/user) + if(!core) + to_chat(user, SPAN_NOTICE("[src] has no core to power it!")) + return + if(on_cooldown) + to_chat(user, SPAN_NOTICE("[src] is on cooldown!")) + return + if((user.l_hand && !user.drop_l_hand()) || (user.r_hand && !user.drop_r_hand())) + to_chat(user, SPAN_NOTICE("[src] are unable to deploy the blades with the items in your hands!")) + return + var/obj/item/W = new /obj/item/pyro_claws + user.visible_message( + SPAN_WARNING("[user] deploys [W] from [user.p_their()] wrists in a shower of sparks!"), + SPAN_NOTICE("You deploy [W] from your wrists!"), + SPAN_HEAR("You hear the shower of sparks!") + ) + user.put_in_hands(W) + on_cooldown = TRUE + set_nodrop(TRUE, user) + addtimer(CALLBACK(src, PROC_REF(reboot)), 2 MINUTES) + if(world.time > next_spark_time) + do_sparks(rand(1,6), 1, loc) + next_spark_time = world.time + 0.8 SECONDS + +/obj/item/clothing/gloves/color/black/pyro_claws/wirecutter_act(mob/living/user, obj/item/I) + return + +/obj/item/clothing/gloves/color/black/pyro_claws/item_interaction(mob/living/user, obj/item/used, list/modifiers) + if(!istype(used, /obj/item/assembly/signaler/anomaly/pyro)) + return ..() + + if(core) + to_chat(user, SPAN_NOTICE("[src] already has a [used]!")) + return ITEM_INTERACT_COMPLETE + + if(!user.drop_item()) + to_chat(user, SPAN_WARNING("[used] is stuck to your hand!")) + return ITEM_INTERACT_COMPLETE + + to_chat(user, SPAN_NOTICE("You insert [used] into [src], and [src] starts to warm up.")) + used.forceMove(src) + core = used + return ITEM_INTERACT_COMPLETE + +/obj/item/clothing/gloves/color/black/pyro_claws/proc/reboot() + on_cooldown = FALSE + set_nodrop(FALSE, loc) + atom_say("Internal plasma canisters recharged. Gloves sufficiently cooled") + + +/obj/item/bostaff + name = "bo staff" + desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts. Can be wielded to both kill and incapacitate." + icon = 'icons/obj/weapons/melee.dmi' + icon_state = "bostaff0" + base_icon_state = "bostaff" + lefthand_file = 'icons/mob/inhands/staves_lefthand.dmi' + righthand_file = 'icons/mob/inhands/staves_righthand.dmi' + force = 10 + w_class = WEIGHT_CLASS_BULKY + slot_flags = ITEM_SLOT_BACK + throwforce = 20 + attack_verb = list("smashed", "slammed", "whacked", "thwacked") + new_attack_chain = TRUE + +/obj/item/bostaff/Initialize(mapload) + . = ..() + AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES) + AddComponent(/datum/component/two_handed, force_wielded = 24, force_unwielded = force, icon_wielded = "[base_icon_state]1") + +/obj/item/bostaff/update_icon_state() + icon_state = "[base_icon_state]0" + +/obj/item/bostaff/pre_attack(atom/target, mob/living/user, params) + add_fingerprint(user) + + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + to_chat(user, SPAN_WARNING("You feel violence is not the answer.")) + return FINISH_ATTACK + + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) + to_chat(user, SPAN_WARNING("You club yourself over the head with [src].")) + user.do_attack_animation(target) + user.Weaken(6 SECONDS) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.apply_damage(2 * force, BRUTE, "head") + else + user.take_organ_damage(2 * force) + return FINISH_ATTACK + + if(isrobot(target)) + return ..() + + if(!isliving(target)) + return ..() + + var/mob/living/carbon/carbon_target = target + if(carbon_target.stat) + to_chat(user, SPAN_WARNING("It would be dishonorable to attack a foe while [carbon_target.p_they()] cannot retaliate.")) + return FINISH_ATTACK + + if(user.a_intent != INTENT_DISARM) + return ..() + + if(!HAS_TRAIT(src, TRAIT_WIELDED)) + return ..() + if(!ishuman(target)) + return ..() + + var/mob/living/carbon/human/human_target = target + var/list/fluffmessages = list("[user] clubs [human_target] with [src]!", + "[user] smacks [human_target] with the butt of [src]!", + "[user] broadsides [human_target] with [src]!", + "[user] smashes [human_target]'s head with [src]!", + "[user] beats [human_target] with front of [src]!", + "[user] twirls and slams [human_target] with [src]!") + human_target.visible_message( + SPAN_WARNING("[pick(fluffmessages)]"), + SPAN_USERDANGER("[pick(fluffmessages)]"), + SPAN_DANGER("You hear someone being attacked with a weapon!") + ) + user.do_attack_animation(target) + playsound(get_turf(user), 'sound/effects/woodhit.ogg', 75, TRUE, -1) + human_target.apply_damage(rand(13, 20), STAMINA) + if(prob(10)) + human_target.visible_message( + SPAN_WARNING("[human_target] collapses!"), + SPAN_USERDANGER("Your legs give out!"), + SPAN_HEAR("You hear a body fall to the ground!") + ) + human_target.Weaken(8 SECONDS) + if(human_target.getStaminaLoss() && !human_target.IsSleeping()) + var/total_health = (human_target.health - human_target.getStaminaLoss()) + if(total_health <= HEALTH_THRESHOLD_CRIT && !human_target.stat) + human_target.visible_message( + SPAN_WARNING("[user] delivers a heavy hit to [human_target]'s head, knocking [human_target.p_them()] out cold!"), + SPAN_USERDANGER("[user] knocks you unconscious!"), + SPAN_HEAR("You hear a body fall to the ground!") + ) + human_target.SetSleeping(60 SECONDS) + human_target.adjustBrainLoss(25) + return FINISH_ATTACK + +/obj/item/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) + if(HAS_TRAIT(src, TRAIT_WIELDED)) + return ..() + return FALSE diff --git a/code/game/objects/items/weapons/two_handed/push_broom.dm b/code/game/objects/items/weapons/two_handed/push_broom.dm new file mode 100644 index 00000000000..7b955caefe1 --- /dev/null +++ b/code/game/objects/items/weapons/two_handed/push_broom.dm @@ -0,0 +1,169 @@ +/// Max number of atoms a broom can sweep at once. +#define BROOM_PUSH_LIMIT 20 + +/obj/item/push_broom + name = "push broom" + desc = "This is my BROOMSTICK! It can be used manually or braced with two hands to sweep items as you move. It has a telescopic handle for compact storage." + icon = 'icons/obj/janitor.dmi' + icon_state = "broom0" + base_icon_state = "broom" + lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' + force = 8 + throwforce = 10 + throw_speed = 3 + attack_verb = list("swept", "brushed off", "bludgeoned", "whacked") + resistance_flags = FLAMMABLE + new_attack_chain = TRUE + +/obj/item/push_broom/Initialize(mapload) + . = ..() + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.75, \ + _parryable_attack_types = MELEE_ATTACK, \ + _parry_cooldown = (7 / 3) SECONDS, \ + _requires_two_hands = TRUE) + AddComponent(/datum/component/two_handed, \ + force_wielded = 12, \ + force_unwielded = force, \ + icon_wielded = "[base_icon_state]1", \ + wield_callback = CALLBACK(src, PROC_REF(wield)), \ + unwield_callback = CALLBACK(src, PROC_REF(unwield))) + +/obj/item/push_broom/update_icon_state() + icon_state = "[base_icon_state]0" + +/obj/item/push_broom/proc/wield(obj/item/source, mob/user) + to_chat(user, SPAN_NOTICE("You brace [src] against the ground in a firm sweeping stance.")) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(sweep)) + +/obj/item/push_broom/proc/unwield(obj/item/source, mob/user) + UnregisterSignal(user, COMSIG_MOVABLE_MOVED) + +/obj/item/push_broom/interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(isturf(target) || isitem(target)) + return ..() + + if(user.a_intent != INTENT_HELP) + return ..() + + sweep(user, target, FALSE) + add_fingerprint(user) + return ITEM_INTERACT_COMPLETE + +/obj/item/push_broom/proc/sweep(mob/user, atom/A, moving = TRUE) + SIGNAL_HANDLER + var/turf/current_item_loc = moving ? user.loc : (isturf(A) ? A : A.loc) + if(!isturf(current_item_loc)) + return + var/turf/new_item_loc = get_step(current_item_loc, user.dir) + var/obj/machinery/disposal/target_bin = locate(/obj/machinery/disposal) in new_item_loc.contents + var/obj/structure/janitorialcart/jani_cart = locate(/obj/structure/janitorialcart) in new_item_loc.contents + var/obj/vehicle/janicart/jani_vehicle = locate(/obj/vehicle/janicart) in new_item_loc.contents + var/trash_amount = 1 + for(var/obj/item/garbage in current_item_loc.contents) + if(garbage.anchored) + continue + var/obj/item/storage/bag/trash/bag = jani_vehicle?.mybag || jani_cart?.my_bag + var/obj/trashed_into + if(bag?.can_be_inserted(garbage, TRUE)) + bag.handle_item_insertion(garbage, user, TRUE) + trashed_into = bag + else if(target_bin) + move_into_storage(user, target_bin, garbage) + trashed_into = target_bin + else + garbage.Move(new_item_loc, user.dir) + if(trashed_into) + to_chat(user, SPAN_NOTICE("You sweep the pile of garbage into [trashed_into].")) + trash_amount++ + if(trash_amount > BROOM_PUSH_LIMIT) + break + if(trash_amount > 1) + playsound(loc, 'sound/weapons/sweeping.ogg', 70, TRUE, -1) + +/obj/item/push_broom/proc/move_into_storage(mob/user, obj/storage, obj/trash) + trash.forceMove(storage) + storage.update_icon() + +/obj/item/push_broom/traitor + name = "titanium push broom" + desc = "This is my BROOMSTICK! All of the functionality of a normal broom, but at least half again more robust." + attack_verb = list("smashed", "slammed", "whacked", "thwacked", "swept") + force = 10 + +/obj/item/push_broom/traitor/Initialize(mapload) + . = ..() + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.25, \ + _parryable_attack_types = ALL_ATTACK_TYPES, \ + _parry_cooldown = (4 / 3) SECONDS, \ + _requires_two_hands = TRUE) // 0.3333 seconds of parry cooldown for 75% uptime. + // Parent component handles this. + AddComponent(/datum/component/two_handed, force_wielded = 25, force_unwielded = force) + +/obj/item/push_broom/traitor/examine(mob/user) + . = ..() + if(isAntag(user)) + . += SPAN_WARNING("When wielded, the broom has different effects depending on your intent, similar to a martial art. \ + Help intent will sweep foes away from you, disarm intent sweeps their legs from under them, grab intent confuses \ + and minorly fatigues them, and harm intent hits them normally.") + +/obj/item/push_broom/traitor/interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(!HAS_TRAIT(src, TRAIT_WIELDED) || !ishuman(target)) + return ..() + + var/mob/living/carbon/human/human_target = target + + switch(user.a_intent) + if(INTENT_HELP) + human_target.visible_message( + SPAN_DANGER("[user] sweeps [human_target] away!"), + SPAN_USERDANGER("[user] sweeps you away!"), + SPAN_HEAR("You hear sweeping.") + ) + user.do_attack_animation(human_target, ATTACK_EFFECT_BOOP) + playsound(loc, 'sound/weapons/sweeping.ogg', 70, TRUE, -1) + + var/atom/throw_target = get_edge_target_turf(human_target, get_dir(src, get_step_away(human_target, src))) + human_target.throw_at(throw_target, 3, 1) + add_attack_logs(user, human_target, "Swept away with titanium push broom", ATKLOG_ALL) + return ITEM_INTERACT_COMPLETE + + if(INTENT_DISARM) + if(human_target.stat || IS_HORIZONTAL(human_target)) + return ..() + + human_target.visible_message( + SPAN_DANGER("[user] sweeps [human_target]'s legs out from under [human_target.p_them()]!"), + SPAN_USERDANGER("[user] sweeps your legs out from under you!"), + SPAN_HEAR("You hear sweeping.") + ) + user.do_attack_animation(human_target, ATTACK_EFFECT_KICK) + playsound(get_turf(user), 'sound/effects/hit_kick.ogg', 50, TRUE, -1) + + human_target.apply_damage(5, BRUTE) + human_target.KnockDown(4 SECONDS) + add_attack_logs(user, human_target, "Leg swept with titanium push broom", ATKLOG_ALL) + return ITEM_INTERACT_COMPLETE + + if(INTENT_GRAB) + human_target.visible_message( + SPAN_DANGER("[user] smacks [human_target] with the brush of [user.p_their()] broom!"), + SPAN_USERDANGER("[user] smacks you with the brush of [user.p_their()] broom!"), + SPAN_HEAR("You hear a smacking noise.") + ) + user.do_attack_animation(human_target, ATTACK_EFFECT_DISARM) + playsound(get_turf(user), 'sound/effects/woodhit.ogg', 50, TRUE, -1) + + human_target.AdjustConfused(4 SECONDS, 0, 4 SECONDS) // No stacking infinitely. + human_target.apply_damage(15, STAMINA) + add_attack_logs(user, human_target, "Swept with the brush of the titanium push broom", ATKLOG_ALL) + return ITEM_INTERACT_COMPLETE + + if(INTENT_HARM) + return ..() + +#undef BROOM_PUSH_LIMIT diff --git a/code/game/objects/items/weapons/two_handed/spears.dm b/code/game/objects/items/weapons/two_handed/spears.dm new file mode 100644 index 00000000000..fe874ae898e --- /dev/null +++ b/code/game/objects/items/weapons/two_handed/spears.dm @@ -0,0 +1,320 @@ +/// Spears. +/obj/item/spear + name = "spear" + desc = "A haphazardly-constructed yet still deadly weapon of ancient design." + icon = 'icons/obj/weapons/spears.dmi' + base_icon_state = "spearglass" + icon_state = "spearglass0" + lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' + force = 10 + w_class = WEIGHT_CLASS_BULKY + slot_flags = ITEM_SLOT_BACK + var/force_unwielded = 10 + var/force_wielded = 18 + throwforce = 20 + throw_speed = 4 + armor_penetration_flat = 5 + materials = list(MAT_METAL = 1150, MAT_GLASS = 2075) + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "poked", "jabbed", "torn", "gored") + sharp = TRUE + no_spin_thrown = TRUE + var/obj/item/grenade/explosive = null + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 50, ACID = 30) + needs_permit = TRUE + new_attack_chain = TRUE + +/obj/item/spear/Initialize(mapload) + . = ..() + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.7, \ + _parryable_attack_types = MELEE_ATTACK, \ + _parry_cooldown = (10 / 3) SECONDS, \ + _requires_two_hands = TRUE) // 2.3333 seconds of parry cooldown for 30% uptime. + AddComponent(/datum/component/two_handed, \ + force_wielded = force_wielded, \ + force_unwielded = force_unwielded, \ + icon_wielded = "[base_icon_state]1") + +/obj/item/spear/update_icon_state() + icon_state = "[base_icon_state]0" + +/obj/item/spear/proc/add_plasmaglass() + // Re-add the component to reset the stats. + force_wielded = 19 + force_unwielded = 11 + throwforce = 21 + base_icon_state = "spearplasma" + AddComponent(/datum/component/two_handed, \ + force_wielded = force_wielded, \ + force_unwielded = force_unwielded, \ + icon_wielded = "[base_icon_state]1") + + update_icon() + +/obj/item/spear/CheckParts(list/parts_list) + var/obj/item/shard/tip = locate() in parts_list + if(istype(tip, /obj/item/shard/plasma)) + // Re-add the component to reset the stats. + add_plasmaglass() + + update_icon() + qdel(tip) + ..() + +/obj/item/spear/after_attack(mob/living/target, mob/user, proximity_flag, click_parameters) + if(!proximity_flag) + return FINISH_ATTACK + if(explosive && HAS_TRAIT(src, TRAIT_WIELDED)) + explosive.forceMove(target) + explosive.prime() + qdel(src) + return FINISH_ATTACK + return ..() + +/obj/item/spear/throw_impact(atom/target) + . = ..() + if(explosive) + explosive.prime() + qdel(src) + +/// Blatant imitation of spear, but made out of bone. Not valid for explosive modification. +/obj/item/spear/bonespear + name = "bone spear" + desc = "A haphazardly-constructed yet still deadly weapon. The pinnacle of modern technology." + base_icon_state = "bone_spear" + icon_state = "bone_spear0" + force = 11 + force_unwielded = 11 + force_wielded = 20 // I have no idea how to balance. + throwforce = 22 + armor_penetration_percentage = 15 // Enhanced armor piercing. + +// Blatant imitation of spear, but all natural. Also not valid for explosive modification. +/obj/item/spear/bamboo + name = "bamboo spear" + desc = "A haphazardly-constructed bamboo stick with a sharpened tip, ready to poke holes into unsuspecting people." + base_icon_state = "bamboo_spear" + icon_state = "bamboo_spear0" + throwforce = 22 + +// GREY TIDE. +/obj/item/spear/grey_tide + name = "\improper Grey Tide" + desc = "Recovered from the aftermath of a revolt aboard Defense Outpost Theta Aegis, in which a seemingly endless tide of Assistants caused heavy casualities among Nanotrasen military forces." + force_unwielded = 15 + force_wielded = 25 + attack_verb = list("gored") + +/obj/item/spear/grey_tide/after_attack(mob/living/target, mob/living/user, proximity_flag, click_parameters) + if(!proximity_flag) + return FINISH_ATTACK + user.faction |= "greytide(\ref[user])" + if(!isliving(target)) + return ..() + if(istype (target, /mob/living/simple_animal/hostile/illusion)) + return FINISH_ATTACK + if(!target.stat && prob(50)) + var/mob/living/simple_animal/hostile/illusion/M = new(user.loc) + M.faction = user.faction.Copy() + M.attack_sound = hitsound + M.Copy_Parent(user, 100, user.health/2.5, 12, 30) + M.GiveTarget(target) + return FINISH_ATTACK + +// Putting heads on spears. +/obj/item/spear/item_interaction(mob/living/user, obj/item/used, list/modifiers) + if(!istype(used, /obj/item/organ/external/head)) + return ..() + + if(!(user.unequip(src) && user.drop_item())) + to_chat(user, SPAN_WARNING("You can't attach [src] to [used] when one is stuck to your hand!")) + return ITEM_INTERACT_COMPLETE + + to_chat(user, SPAN_NOTICE("You stick [used] onto the spear and stand it upright on the ground.")) + var/obj/structure/headspear/head_spear = new /obj/structure/headspear(get_turf(src)) + var/matrix/transform_matrix = matrix() + used.transform = transform_matrix + var/image/spear_overlays = image(used.icon, used.icon_state) + spear_overlays.overlays = used.overlays.Copy() + head_spear.overlays += spear_overlays + used.forceMove(head_spear) + head_spear.mounted_head = used + forceMove(head_spear) + head_spear.contained_spear = src + head_spear.add_fingerprint(user) + return ITEM_INTERACT_COMPLETE + +/obj/structure/headspear + name = "head on a spear" + desc = "How barbaric." + icon_state = "headspear" + anchored = TRUE + var/obj/item/organ/external/head/mounted_head = null + var/obj/item/spear/contained_spear = null + +/obj/structure/headspear/Destroy() + QDEL_NULL(mounted_head) + QDEL_NULL(contained_spear) + return ..() + +/obj/structure/headspear/attack_hand(mob/living/user) + user.visible_message( + SPAN_WARNING("[user] kicks over [src]!"), + SPAN_DANGER("You kick down [src]!"), + SPAN_HEAR("You hear a sharp kick and a head rolling!") + ) + playsound(src, 'sound/weapons/genhit.ogg', 50, 1) + var/turf/T = get_turf(src) + if(contained_spear) + contained_spear.forceMove(T) + contained_spear = null + if(mounted_head) + mounted_head.forceMove(T) + mounted_head = null + qdel(src) + +/// Supermatter Halberd, used by Oblivion Enforcers. +/obj/item/supermatter_halberd + name = "supermatter halberd" + desc = "The revered weapon of Oblivion Enforcers, used to enforce the Order's will." + lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' + icon = 'icons/obj/weapons/magical_weapons.dmi' + icon_state = "smhalberd0" + base_icon_state = "smhalberd" + force = 5 + sharp = TRUE + damtype = BURN + w_class = WEIGHT_CLASS_BULKY + slot_flags = ITEM_SLOT_BACK + throwforce = 15 + toolspeed = 0.25 + attack_verb = list("enlightened", "enforced", "cleaved", "stabbed", "whacked") + hitsound = 'sound/weapons/bladeslice.ogg' + resistance_flags = FIRE_PROOF + var/static/list/obliteration_targets = list(/turf/simulated/wall, /obj/machinery/door/airlock) + /// Whether we'll knockdown on hit + var/charged = TRUE + new_attack_chain = TRUE + +/obj/item/supermatter_halberd/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SUPERMATTER_IMMUNE, ROUNDSTART_TRAIT) // So it can't be dusted by the SM. + AddComponent(/datum/component/forces_doors_open) + AddComponent(/datum/component/parry, \ + _stamina_constant = 2, \ + _stamina_coefficient = 0.25, \ + _parryable_attack_types = ALL_ATTACK_TYPES, \ + _parry_cooldown = (4 / 3) SECONDS, \ + _requires_two_hands = TRUE) // 0.3333 seconds of parry cooldown for 75% uptime. + AddComponent(/datum/component/two_handed, \ + force_wielded = 40, \ + force_unwielded = force, \ + icon_wielded = "[base_icon_state]1") + +/obj/item/supermatter_halberd/update_icon_state() + icon_state = "[base_icon_state]0" + return ..() + +/obj/item/supermatter_halberd/interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(!HAS_TRAIT(src, TRAIT_WIELDED)) + return ..() + + // Dusting dead people. + if(isliving(target)) + var/mob/living/living_target = target + if(living_target.stat != DEAD) + return ..() // Attack as normal. + + visible_message(SPAN_DANGER("[user] raises [src] high, ready to bring it down on [living_target]!")) + if(!do_after(user, 1 SECONDS, TRUE, living_target)) + to_chat(user, SPAN_NOTICE("You lower [src]. There'll be time to obliterate them later...")) + return ITEM_INTERACT_COMPLETE + + visible_message( + SPAN_DANGER("[user] brings down [src], obliterating [living_target] with a heavy blow!"), + SPAN_DANGER("A deafening resonance fills the air, followed by silence...") + ) + user.do_attack_animation(living_target) + playsound(loc, 'sound/effects/supermatter.ogg', 50, TRUE) + living_target.dust() + return ITEM_INTERACT_COMPLETE + + // Walls and airlock obliteration logic. + if(!is_type_in_list(target, obliteration_targets)) + return ..() + + if(istype(target, /turf/simulated/wall/indestructible)) + return ..() + + user.visible_message( + SPAN_DANGER("[user] embeds [src] into [target] and starts to obliterate it!"), + SPAN_NOTICE("You embed [src] into [target] and start to obliterate it."), + SPAN_DANGER("You hear something being struck by a weapon!") // Default deaf message. + ) + user.do_attack_animation(target) + playsound(loc, hitsound, 50, TRUE) + + var/obj/effect/temp_visual/obliteration_rays/rays = new(get_turf(target)) + + if(!do_after(user, 5 SECONDS * toolspeed, target = target)) + user.visible_message( + SPAN_NOTICE("[user] removes [src] from [target]."), + SPAN_NOTICE("You remove [src] from [target]. There'll be time to obliterate it later...") + ) + qdel(rays) + return ITEM_INTERACT_COMPLETE + + user.visible_message( + SPAN_DANGER("[user] obliterates [target]!"), + SPAN_NOTICE("You obliterate [target]."), + SPAN_DANGER("A deafening resonance fills the air, followed by silence...") + ) + new /obj/effect/temp_visual/obliteration(target, target) + playsound(loc, 'sound/effects/supermatter.ogg', 25, TRUE) + + if(iswallturf(target)) + var/turf/target_turf = target + target_turf.ChangeTurf(/turf/simulated/floor/plating) + return ITEM_INTERACT_COMPLETE + + if(istype(target, /obj/machinery/door/airlock)) + qdel(target) + return ITEM_INTERACT_COMPLETE + + qdel(rays) + return ITEM_INTERACT_COMPLETE + +/obj/item/supermatter_halberd/after_attack(atom/target, mob/user, proximity_flag, click_parameters) + if(!proximity_flag) + return FINISH_ATTACK + + if(!HAS_TRAIT(src, TRAIT_WIELDED)) + return ..() + + if(isliving(target) && charged) + var/mob/living/living_target = target + playsound(loc, 'sound/magic/lightningbolt.ogg', 5, TRUE) + living_target.visible_message( + SPAN_DANGER("[src] flares with energy and shocks [living_target]!"), + SPAN_USERDANGER("You're shocked by [src]!"), + SPAN_HEAR("You hear shocking!") + ) + living_target.KnockDown(4 SECONDS) + do_sparks(3, FALSE, src) + charged = FALSE + addtimer(CALLBACK(src, PROC_REF(recharge)), 4 SECONDS) + return FINISH_ATTACK + + // Same behavior as a fireaxe for windows. + if(istype(target, /obj/structure/window) || istype(target, /obj/structure/grille)) + var/obj/structure/target_structure = target + target_structure.obj_destruction("fireaxe") + return FINISH_ATTACK + +/obj/item/supermatter_halberd/proc/recharge() + charged = TRUE + playsound(loc, 'sound/machines/sm/accent/normal/1.ogg', 25, TRUE) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm deleted file mode 100644 index d0d5f754283..00000000000 --- a/code/game/objects/items/weapons/twohanded.dm +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * Fireaxe - */ -/// DEM AXES MAN, marker -Agouri -/obj/item/fireaxe - base_icon_state = "fireaxe" - lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' - icon = 'icons/obj/weapons/melee.dmi' - icon_state = "fireaxe0" - name = "fire axe" - desc = "Truly, the weapon of a madman. Who would think to fight fire with an axe?" - force = 5 - throwforce = 15 - sharp = TRUE - w_class = WEIGHT_CLASS_BULKY - slot_flags = ITEM_SLOT_BACK - toolspeed = 0.25 - attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") - hitsound = 'sound/weapons/bladeslice.ogg' - usesound = 'sound/items/crowbar.ogg' - armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 30) - resistance_flags = FIRE_PROOF - - var/force_unwielded = 5 - var/force_wielded = 24 - -/obj/item/fireaxe/Initialize(mapload) - . = ..() - AddComponent(/datum/component/forces_doors_open) - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.7, _parryable_attack_types = MELEE_ATTACK, _parry_cooldown = (10 / 3) SECONDS, _requires_two_hands = TRUE) // 2.3333 seconds of cooldown for 30% uptime - AddComponent(/datum/component/two_handed, force_unwielded = force_unwielded, force_wielded = force_wielded, icon_wielded = "[base_icon_state]1") - -/obj/item/fireaxe/update_icon_state() //Currently only here to fuck with the on-mob icons. - icon_state = "[base_icon_state]0" - return ..() - -/obj/item/fireaxe/afterattack__legacy__attackchain(atom/A, mob/user, proximity) - if(!proximity) - return - if(HAS_TRAIT(src, TRAIT_WIELDED)) //destroys windows and grilles in one hit - if(istype(A, /obj/structure/window) || istype(A, /obj/structure/grille)) - var/obj/structure/W = A - W.obj_destruction("fireaxe") - -/// Blatant imitation of the fireaxe, but made out of bone. -/obj/item/fireaxe/boneaxe - icon_state = "bone_axe0" - base_icon_state = "bone_axe" - name = "bone axe" - desc = "A large, vicious axe crafted out of several sharpened bone plates and crudely tied together. Made of monsters, by killing monsters, for killing monsters." - force_wielded = 23 - needs_permit = TRUE - -/obj/item/fireaxe/energized - desc = "Someone with a love for fire axes decided to turn this one into a high-powered energy weapon. Seems excessive." - force_wielded = 35 - armor_penetration_flat = 10 - armor_penetration_percentage = 30 - var/charge = 20 - var/max_charge = 20 - -/obj/item/fireaxe/energized/Initialize(mapload) - . = ..() - // only update the new args - START_PROCESSING(SSobj, src) - AddComponent(/datum/component/two_handed, force_wielded = force_wielded, icon_wielded = "[base_icon_state]2") - -/obj/item/fireaxe/energized/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/fireaxe/energized/process() - charge = min(charge + 1, max_charge) - -/obj/item/fireaxe/energized/attack__legacy__attackchain(mob/M, mob/user) - . = ..() - if(HAS_TRAIT(src, TRAIT_WIELDED) && charge == max_charge) - if(isliving(M)) - var/mob/living/target = M - charge = 0 - playsound(loc, 'sound/magic/lightningbolt.ogg', 5, 1) - user.visible_message(SPAN_DANGER("[user] slams the charged axe into [M.name] with all [user.p_their()] might!")) - do_sparks(1, 1, src) - target.KnockDown(8 SECONDS) - var/atom/throw_target = get_edge_target_turf(M, get_dir(src, get_step_away(M, src))) - M.throw_at(throw_target, 5, 1) - -/* - * Double-Bladed Energy Swords - Cheridan - */ -/obj/item/dualsaber - name = "double-bladed energy sword" - desc = "Handle with care." - icon = 'icons/obj/weapons/energy_melee.dmi' - lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' - hitsound = "swing_hit" - icon_state = "dualsaber0" - force = 3 - throwforce = 5 - throw_speed = 1 - throw_range = 5 - w_class = WEIGHT_CLASS_SMALL - var/w_class_on = WEIGHT_CLASS_BULKY - armor_penetration_flat = 10 - armor_penetration_percentage = 50 - origin_tech = "magnets=4;syndicate=5" - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 70) - resistance_flags = FIRE_PROOF - light_power = 2 - needs_permit = TRUE - var/hacked = FALSE - var/blade_color - var/brightness_on = 2 - var/colormap = list(red = LIGHT_COLOR_RED, blue = LIGHT_COLOR_LIGHTBLUE, green = LIGHT_COLOR_GREEN, purple = LIGHT_COLOR_PURPLE, rainbow = LIGHT_COLOR_WHITE) - var/force_unwielded = 3 - var/force_wielded = 34 - var/wieldsound = 'sound/weapons/saberon.ogg' - var/unwieldsound = 'sound/weapons/saberoff.ogg' - -/obj/item/dualsaber/Initialize(mapload) - . = ..() - if(!blade_color) - blade_color = pick("red", "blue", "green", "purple") - AddComponent(/datum/component/parry, \ - _stamina_constant = 2, \ - _stamina_coefficient = 0.25, \ - _parryable_attack_types = ALL_ATTACK_TYPES, \ - _parry_cooldown = (4 / 3) SECONDS, /* 0.33 seconds of cooldown for 75% uptime */ \ - _requires_two_hands = TRUE) - AddComponent(/datum/component/two_handed, \ - force_wielded = force_wielded, \ - force_unwielded = force_unwielded, \ - wieldsound = wieldsound, \ - unwieldsound = unwieldsound, \ - attacksound = 'sound/weapons/blade1.ogg', \ - wield_callback = CALLBACK(src, PROC_REF(on_wield)), \ - unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \ - only_sharp_when_wielded = TRUE) - -/obj/item/dualsaber/update_icon_state() - if(HAS_TRAIT(src, TRAIT_WIELDED)) - icon_state = "dualsaber[blade_color]1" - set_light(brightness_on, l_color=colormap[blade_color]) - else - icon_state = "dualsaber0" - set_light(0) - -/obj/item/dualsaber/attack__legacy__attackchain(mob/target, mob/living/user) - if(cigarette_lighter_act(user, target)) - return - - if(HAS_TRAIT(user, TRAIT_HULK)) - to_chat(user, SPAN_WARNING("You grip the blade too hard and accidentally drop it!")) - if(HAS_TRAIT(src, TRAIT_WIELDED)) - user.drop_item_to_ground(src) - return - ..() - if(HAS_TRAIT(user, TRAIT_CLUMSY) && HAS_TRAIT(src, TRAIT_WIELDED) && prob(40) && force) - to_chat(user, SPAN_WARNING("You twirl around a bit before losing your balance and impaling yourself on [src].")) - user.take_organ_damage(20, 25) - return - if((HAS_TRAIT(src, TRAIT_WIELDED)) && prob(50)) - INVOKE_ASYNC(src, PROC_REF(jedi_spin), user) - -/obj/item/dualsaber/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item) - var/obj/item/clothing/mask/cigarette/cig = ..() - if(!cig) - return !isnull(cig) - - if(!HAS_TRAIT(src, TRAIT_WIELDED)) - to_chat(user, SPAN_WARNING("You need to activate [src] before you can light anything with it!")) - return TRUE - - if(target == user) - user.visible_message( - SPAN_DANGER("[user] flips through the air and spins [src] wildly! It brushes against [user.p_their()] [cig] and sets it alight!"), - SPAN_NOTICE("You flip through the air and twist [src] so it brushes against [cig], lighting it with the blade."), - SPAN_DANGER("You hear an energy blade slashing something!") - ) - else - user.visible_message( - SPAN_DANGER("[user] flips through the air and slashes at [user] with [src]! The blade barely misses, brushing against [user.p_their()] [cig] and setting it alight!"), - SPAN_NOTICE("You flip through the air and slash [src] at [cig], lighting it for [target]."), - SPAN_DANGER("You hear an energy blade slashing something!") - ) - user.do_attack_animation(target) - playsound(user.loc, hitsound, 50, TRUE) - cig.light(user, target) - INVOKE_ASYNC(src, PROC_REF(jedi_spin), user) - return TRUE - -/obj/item/dualsaber/proc/jedi_spin(mob/living/user) - for(var/i in list(NORTH, SOUTH, EAST, WEST, EAST, SOUTH, NORTH, SOUTH, EAST, WEST, EAST, SOUTH)) - user.setDir(i) - if(i == WEST) - user.SpinAnimation(7, 1) - sleep(1) - -/obj/item/dualsaber/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - if(!HAS_TRAIT(src, TRAIT_WIELDED)) - return FALSE - . = ..() - if(!.) // they did not block the attack - return - - if(attack_type == THROWN_PROJECTILE_ATTACK) - if(!isitem(hitby)) - return TRUE - var/obj/item/TT = hitby - addtimer(CALLBACK(TT, TYPE_PROC_REF(/atom/movable, throw_at), locateUID(TT.thrownby), 10, 4, owner), 0.2 SECONDS) //Timer set to 0.2 seconds to ensure item finshes the throwing to prevent double embeds - return TRUE - if(isitem(hitby)) - melee_attack_chain(owner, hitby.loc) - else - melee_attack_chain(owner, hitby) - return TRUE - -/obj/item/dualsaber/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) //In case thats just so happens that it is still activated on the groud, prevents hulk from picking it up - if(HAS_TRAIT(src, TRAIT_WIELDED)) - to_chat(user, SPAN_WARNING("You can't pick up such a dangerous item with your meaty hands without losing fingers, better not to!")) - return TRUE - -/obj/item/dualsaber/green - blade_color = "green" - -/obj/item/dualsaber/red - blade_color = "red" - -/obj/item/dualsaber/purple - blade_color = "purple" - -/obj/item/dualsaber/blue - blade_color = "blue" - -/obj/item/dualsaber/proc/on_wield(obj/item/source, mob/living/carbon/user) - if(user && HAS_TRAIT(user, TRAIT_HULK)) - to_chat(user, SPAN_WARNING("You lack the grace to wield this!")) - return COMPONENT_TWOHANDED_BLOCK_WIELD - w_class = w_class_on - -/obj/item/dualsaber/proc/on_unwield() - w_class = initial(w_class) - -/obj/item/dualsaber/IsReflect() - if(HAS_TRAIT(src, TRAIT_WIELDED)) - return TRUE - -/obj/item/dualsaber/multitool_act(mob/user, obj/item/I) - . = TRUE - if(!I.use_tool(src, user, 0, volume = I.tool_volume)) - return - if(!hacked) - hacked = TRUE - to_chat(user, SPAN_WARNING("2XRNBW_ENGAGE")) - blade_color = "rainbow" - update_icon() - else - to_chat(user, SPAN_WARNING("It's starting to look like a triple rainbow - no, nevermind.")) - -//spears -/obj/item/spear - name = "spear" - desc = "A haphazardly-constructed yet still deadly weapon of ancient design." - icon = 'icons/obj/weapons/spears.dmi' - base_icon_state = "spearglass" - icon_state = "spearglass0" - lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' - force = 10 - w_class = WEIGHT_CLASS_BULKY - slot_flags = ITEM_SLOT_BACK - var/force_unwielded = 10 - var/force_wielded = 18 - throwforce = 20 - throw_speed = 4 - armor_penetration_flat = 5 - materials = list(MAT_METAL = 1150, MAT_GLASS = 2075) - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("attacked", "poked", "jabbed", "torn", "gored") - sharp = TRUE - no_spin_thrown = TRUE - var/obj/item/grenade/explosive = null - armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 50, ACID = 30) - needs_permit = TRUE - -/obj/item/spear/Initialize(mapload) - . = ..() - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.7, _parryable_attack_types = MELEE_ATTACK, _parry_cooldown = (10 / 3) SECONDS, _requires_two_hands = TRUE) // 2.3333 seconds of cooldown for 30% uptime - AddComponent(/datum/component/two_handed, \ - force_wielded = force_wielded, \ - force_unwielded = force_unwielded, \ - icon_wielded = "[base_icon_state]1") - -/obj/item/spear/update_icon_state() - icon_state = "[base_icon_state]0" - -/obj/item/spear/proc/add_plasmaglass() - // re-add the component to reset the stats - force_wielded = 19 - force_unwielded = 11 - throwforce = 21 - base_icon_state = "spearplasma" - AddComponent(/datum/component/two_handed, \ - force_wielded = force_wielded, \ - force_unwielded = force_unwielded, \ - icon_wielded = "[base_icon_state]1") - - update_icon() - -/obj/item/spear/CheckParts(list/parts_list) - var/obj/item/shard/tip = locate() in parts_list - if(istype(tip, /obj/item/shard/plasma)) - // re-add the component to reset the stats - add_plasmaglass() - - update_icon() - qdel(tip) - ..() - - -/obj/item/spear/afterattack__legacy__attackchain(atom/movable/AM, mob/user, proximity) - if(!proximity) - return - if(isturf(AM)) //So you can actually melee with it - return - if(explosive && HAS_TRAIT(src, TRAIT_WIELDED)) - explosive.forceMove(AM) - explosive.prime() - qdel(src) - -/obj/item/spear/throw_impact(atom/target) - . = ..() - if(explosive) - explosive.prime() - qdel(src) - -/// Blatant imitation of spear, but made out of bone. Not valid for explosive modification. -/obj/item/spear/bonespear - name = "bone spear" - desc = "A haphazardly-constructed yet still deadly weapon. The pinnacle of modern technology." - base_icon_state = "bone_spear" - icon_state = "bone_spear0" - force = 11 - force_unwielded = 11 - force_wielded = 20 //I have no idea how to balance - throwforce = 22 - armor_penetration_percentage = 15 //Enhanced armor piercing - -//Blatant imitation of spear, but all natural. Also not valid for explosive modification. -/obj/item/spear/bamboo - name = "bamboo spear" - desc = "A haphazardly-constructed bamboo stick with a sharpened tip, ready to poke holes into unsuspecting people." - base_icon_state = "bamboo_spear" - icon_state = "bamboo_spear0" - throwforce = 22 - -//GREY TIDE -/obj/item/spear/grey_tide - name = "\improper Grey Tide" - desc = "Recovered from the aftermath of a revolt aboard Defense Outpost Theta Aegis, in which a seemingly endless tide of Assistants caused heavy casualities among Nanotrasen military forces." - force_unwielded = 15 - force_wielded = 25 - attack_verb = list("gored") - -/obj/item/spear/grey_tide/afterattack__legacy__attackchain(atom/movable/AM, mob/living/user, proximity) - ..() - if(!proximity) - return - user.faction |= "greytide(\ref[user])" - if(isliving(AM)) - var/mob/living/L = AM - if(istype (L, /mob/living/simple_animal/hostile/illusion)) - return - if(!L.stat && prob(50)) - var/mob/living/simple_animal/hostile/illusion/M = new(user.loc) - M.faction = user.faction.Copy() - M.attack_sound = hitsound - M.Copy_Parent(user, 100, user.health/2.5, 12, 30) - M.GiveTarget(L) - -//Putting heads on spears -/obj/item/spear/attackby__legacy__attackchain(obj/item/I, mob/living/user) - if(istype(I, /obj/item/organ/external/head)) - if(user.unequip(src) && user.drop_item()) - to_chat(user, SPAN_NOTICE("You stick [I] onto the spear and stand it upright on the ground.")) - var/obj/structure/headspear/HS = new /obj/structure/headspear(get_turf(src)) - var/matrix/M = matrix() - I.transform = M - var/image/IM = image(I.icon, I.icon_state) - IM.overlays = I.overlays.Copy() - HS.overlays += IM - I.forceMove(HS) - HS.mounted_head = I - forceMove(HS) - HS.contained_spear = src - else - return ..() - -/obj/structure/headspear - name = "head on a spear" - desc = "How barbaric." - icon_state = "headspear" - anchored = TRUE - var/obj/item/organ/external/head/mounted_head = null - var/obj/item/spear/contained_spear = null - -/obj/structure/headspear/Destroy() - QDEL_NULL(mounted_head) - QDEL_NULL(contained_spear) - return ..() - -/obj/structure/headspear/attack_hand(mob/living/user) - user.visible_message(SPAN_WARNING("[user] kicks over [src]!"), SPAN_DANGER("You kick down [src]!")) - playsound(src, 'sound/weapons/genhit.ogg', 50, 1) - var/turf/T = get_turf(src) - if(contained_spear) - contained_spear.forceMove(T) - contained_spear = null - if(mounted_head) - mounted_head.forceMove(T) - mounted_head = null - qdel(src) - -// SINGULOHAMMER -/obj/item/singularityhammer - name = "singularity hammer" - desc = "The pinnacle of close combat technology, the hammer harnesses the power of a miniaturized singularity to deal crushing blows." - lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' - icon = 'icons/obj/weapons/magical_weapons.dmi' - icon_state = "singulohammer0" - base_icon_state = "singulohammer" - flags = CONDUCT - slot_flags = ITEM_SLOT_BACK - force = 5 - throwforce = 15 - throw_range = 1 - w_class = WEIGHT_CLASS_HUGE - armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 0, BOMB = 50, RAD = 0, FIRE = 100, ACID = 100) - resistance_flags = FIRE_PROOF | ACID_PROOF - var/charged = 2 - origin_tech = "combat=4;bluespace=4;plasmatech=7" - -/obj/item/singularityhammer/Initialize(mapload) - . = ..() - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (4 / 3) SECONDS, _requires_two_hands = TRUE) // 0.3333 seconds of cooldown for 75% uptime - AddComponent(/datum/component/two_handed, \ - force_wielded = 40, \ - force_unwielded = force, \ - icon_wielded = "[base_icon_state]1") - START_PROCESSING(SSobj, src) - -/obj/item/singularityhammer/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/singularityhammer/process() - if(charged < 2) - charged++ - -/obj/item/singularityhammer/update_icon_state() //Currently only here to fuck with the on-mob icons. - icon_state = "singulohammer0" - -/obj/item/singularityhammer/proc/vortex(turf/pull, mob/wielder) - for(var/atom/movable/X in range(5, pull)) - if(X.move_resist == INFINITY) - continue - if(X == wielder) - continue - if((X) && (!X.anchored) && (!ishuman(X))) - step_towards(X, pull) - step_towards(X, pull) - step_towards(X, pull) - else if(ishuman(X)) - var/mob/living/carbon/human/H = X - if(HAS_TRAIT(H, TRAIT_MAGPULSE)) - continue - H.Weaken(4 SECONDS) - step_towards(H, pull) - step_towards(H, pull) - step_towards(H, pull) - -/obj/item/singularityhammer/afterattack__legacy__attackchain(atom/A, mob/user, proximity) - if(!proximity) - return - if(HAS_TRAIT(src, TRAIT_WIELDED)) - if(charged == 2) - charged = 0 - if(isliving(A)) - var/mob/living/Z = A - Z.take_organ_damage(20, 0) - playsound(user, 'sound/weapons/marauder.ogg', 50, 1) - var/turf/target = get_turf(A) - vortex(target, user) - -/obj/item/mjollnir - name = "Mjolnir" - desc = "A weapon worthy of a god, able to strike with the force of a lightning bolt. It crackles with barely contained energy." - lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' - icon = 'icons/obj/weapons/magical_weapons.dmi' - icon_state = "mjollnir0" - base_icon_state = "mjollnir" - flags = CONDUCT - slot_flags = ITEM_SLOT_BACK - force = 5 - throwforce = 30 - w_class = WEIGHT_CLASS_HUGE - origin_tech = "combat=4;powerstorage=7" - -/obj/item/mjollnir/Initialize(mapload) - . = ..() - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (4 / 3) SECONDS, _requires_two_hands = TRUE) // 0.3333 seconds of cooldown for 75% uptime - AddComponent(/datum/component/two_handed, \ - force_wielded = 25, \ - force_unwielded = force, \ - icon_wielded = "[base_icon_state]1") - -/obj/item/mjollnir/proc/shock(mob/living/target) - do_sparks(5, 1, target.loc) - target.visible_message(SPAN_DANGER("[target] was shocked by [src]!"), - SPAN_USERDANGER("You feel a powerful shock course through your body sending you flying!"), - SPAN_DANGER("You hear a heavy electrical crack!")) - var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src))) - target.throw_at(throw_target, 200, 4) - -/obj/item/mjollnir/attack__legacy__attackchain(mob/living/M, mob/user) - ..() - if(HAS_TRAIT(src, TRAIT_WIELDED)) - playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - M.Stun(6 SECONDS) - shock(M) - -/obj/item/mjollnir/throw_impact(atom/target) - . = ..() - if(isliving(target)) - var/mob/living/L = target - L.Stun(6 SECONDS) - shock(L) - -/obj/item/mjollnir/update_icon_state() //Currently only here to fuck with the on-mob icons. - icon_state = "mjollnir0" - -/obj/item/knighthammer - name = "singuloth knight's hammer" - desc = "A hammer made of sturdy metal with a golden skull adorned with wings on either side of the head.
This weapon causes devastating damage to those it hits due to a power field sustained by a mini-singularity inside of the hammer." - lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' - icon = 'icons/obj/weapons/magical_weapons.dmi' - icon_state = "knighthammer0" - base_icon_state = "knighthammer" - flags = CONDUCT - slot_flags = ITEM_SLOT_BACK - force = 5 - throwforce = 15 - throw_range = 1 - w_class = WEIGHT_CLASS_HUGE - var/charged = 5 - origin_tech = "combat=5;bluespace=4" - -/obj/item/knighthammer/Initialize(mapload) - . = ..() - START_PROCESSING(SSobj, src) - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (4 / 3) SECONDS, _requires_two_hands = TRUE) // 0.3333 seconds of cooldown for 75% uptime - AddComponent(/datum/component/two_handed, \ - force_wielded = 30, \ - force_unwielded = force, \ - icon_wielded = "[base_icon_state]1") - -/obj/item/knighthammer/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/knighthammer/process() - if(charged < 5) - charged++ - -/obj/item/knighthammer/update_icon_state() //Currently only here to fuck with the on-mob icons. - icon_state = "knighthammer0" - -/obj/item/knighthammer/afterattack__legacy__attackchain(atom/A, mob/user, proximity) - if(!proximity) - return - if(charged == 5) - charged = 0 - if(isliving(A)) - var/mob/living/Z = A - if(Z.health >= 1) - Z.visible_message(SPAN_DANGER("[Z.name] was sent flying by a blow from [src]!"), - SPAN_USERDANGER("You feel a powerful blow connect with your body and send you flying!"), - SPAN_DANGER("You hear something heavy impact flesh!.")) - var/atom/throw_target = get_edge_target_turf(Z, get_dir(src, get_step_away(Z, src))) - Z.throw_at(throw_target, 200, 4) - playsound(user, 'sound/weapons/marauder.ogg', 50, 1) - else if(HAS_TRAIT(src, TRAIT_WIELDED) && Z.health < 1) - Z.visible_message(SPAN_DANGER("[Z.name] was blown to pieces by the power of [src]!"), - SPAN_USERDANGER("You feel a powerful blow rip you apart!"), - SPAN_DANGER("You hear a heavy impact and the sound of ripping flesh!.")) - Z.gib() - playsound(user, 'sound/weapons/marauder.ogg', 50, 1) - if(HAS_TRAIT(src, TRAIT_WIELDED)) - if(iswallturf(A)) - var/turf/simulated/wall/Z = A - Z.ex_act(EXPLODE_HEAVY) - charged = 3 - playsound(user, 'sound/weapons/marauder.ogg', 50, 1) - else if(isstructure(A) || ismecha(A)) - var/obj/Z = A - Z.ex_act(EXPLODE_HEAVY) - charged = 3 - playsound(user, 'sound/weapons/marauder.ogg', 50, 1) - -// PYRO CLAWS -/obj/item/pyro_claws - name = "hardplasma energy claws" - desc = "The power of the sun, in the claws of your hand." - lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' - icon = 'icons/obj/weapons/energy_melee.dmi' - icon_state = "pyro_claws" - flags = ABSTRACT | NODROP | DROPDEL - force = 22 - damtype = BURN - armor_penetration_percentage = 50 - sharp = TRUE - attack_effect_override = ATTACK_EFFECT_CLAW - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut", "savaged", "clawed") - sprite_sheets_inhand = list("Vox" = 'icons/mob/clothing/species/vox/held.dmi', "Drask" = 'icons/mob/clothing/species/drask/held.dmi') - toolspeed = 0.5 - var/lifetime = 60 SECONDS - var/next_spark_time - -/obj/item/pyro_claws/Initialize(mapload) - . = ..() - START_PROCESSING(SSobj, src) - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES) - AddComponent(/datum/component/two_handed, require_twohands = TRUE) - -/obj/item/pyro_claws/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/pyro_claws/customised_abstract_text(mob/living/carbon/owner) - return SPAN_WARNING("[owner.p_they(TRUE)] [owner.p_have(FALSE)] energy claws extending [owner.p_their(FALSE)] wrists.") - -/obj/item/pyro_claws/process() - lifetime -= 2 SECONDS - if(lifetime <= 0) - visible_message(SPAN_WARNING("[src] slides back into the depths of [loc]'s wrists.")) - do_sparks(rand(1,6), 1, loc) - qdel(src) - return - if(prob(15)) - do_sparks(rand(1,6), 1, loc) - -/obj/item/pyro_claws/afterattack__legacy__attackchain(atom/target, mob/user, proximity) - if(!proximity) - return - if(prob(60) && world.time > next_spark_time) - do_sparks(rand(1,6), 1, loc) - next_spark_time = world.time + 0.8 SECONDS - if(istype(target, /obj/machinery/door/airlock)) - var/obj/machinery/door/airlock/A = target - - if(!A.requiresID() || A.allowed(user)) - return - - if(A.locked) - to_chat(user, SPAN_NOTICE("The airlock's bolts prevent it from being forced.")) - return - - if(A.arePowerSystemsOn()) - user.visible_message(SPAN_WARNING("[user] jams [user.p_their()] [name] into the airlock and starts prying it open!"), SPAN_WARNING("You start forcing the airlock open."), SPAN_WARNING("You hear a metal screeching sound.")) - playsound(A, 'sound/machines/airlock_alien_prying.ogg', 150, 1) - if(!do_after(user, 25, target = A)) - return - - user.visible_message(SPAN_WARNING("[user] forces the airlock open with [user.p_their()] [name]!"), SPAN_WARNING("You force open the airlock."), SPAN_WARNING("You hear a metal screeching sound.")) - A.open(2) - -/obj/item/clothing/gloves/color/black/pyro_claws - name = "Fusion gauntlets" - desc = "A pair of heavy combat gauntlets that project lethal energy claws via the power of a captive pyroclastic anomaly core." - icon_state = "pyro" - inhand_icon_state = null - worn_icon_state = null - can_be_cut = FALSE - actions_types = list(/datum/action/item_action/toggle) - dyeable = FALSE - materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 4000, MAT_TITANIUM = 4000, MAT_PLASMA = 8000) - var/on_cooldown = FALSE - var/obj/item/assembly/signaler/anomaly/pyro/core - var/next_spark_time - -/obj/item/clothing/gloves/color/black/pyro_claws/Destroy() - QDEL_NULL(core) - return ..() - -/obj/item/clothing/gloves/color/black/pyro_claws/examine(mob/user) - . = ..() - if(core) - . += SPAN_NOTICE("[src] are fully operational!") - else - . += SPAN_WARNING("It is missing a pyroclastic anomaly core.") - -/obj/item/clothing/gloves/color/black/pyro_claws/item_action_slot_check(slot) - if(slot == ITEM_SLOT_GLOVES) - return TRUE - -/obj/item/clothing/gloves/color/black/pyro_claws/ui_action_click(mob/user) - if(!core) - to_chat(user, SPAN_NOTICE("[src] has no core to power it!")) - return - if(on_cooldown) - to_chat(user, SPAN_NOTICE("[src] is on cooldown!")) - return - if((user.l_hand && !user.drop_l_hand()) || (user.r_hand && !user.drop_r_hand())) - to_chat(user, SPAN_NOTICE("[src] are unable to deploy the blades with the items in your hands!")) - return - var/obj/item/W = new /obj/item/pyro_claws - user.visible_message(SPAN_WARNING("[user] deploys [W] from [user.p_their()] wrists in a shower of sparks!"), SPAN_NOTICE("You deploy [W] from your wrists!"), SPAN_WARNING("You hear the shower of sparks!")) - user.put_in_hands(W) - on_cooldown = TRUE - set_nodrop(TRUE, user) - addtimer(CALLBACK(src, PROC_REF(reboot)), 2 MINUTES) - if(world.time > next_spark_time) - do_sparks(rand(1,6), 1, loc) - next_spark_time = world.time + 0.8 SECONDS - -/obj/item/clothing/gloves/color/black/pyro_claws/wirecutter_act(mob/living/user, obj/item/I) - return - -/obj/item/clothing/gloves/color/black/pyro_claws/item_interaction(mob/living/user, obj/item/used, list/modifiers) - if(!istype(used, /obj/item/assembly/signaler/anomaly/pyro)) - return ..() - - if(core) - to_chat(user, SPAN_NOTICE("[src] already has a [used]!")) - return ITEM_INTERACT_COMPLETE - - if(!user.drop_item()) - to_chat(user, SPAN_WARNING("[used] is stuck to your hand!")) - return ITEM_INTERACT_COMPLETE - - to_chat(user, SPAN_NOTICE("You insert [used] into [src], and [src] starts to warm up.")) - used.forceMove(src) - core = used - return ITEM_INTERACT_COMPLETE - -/obj/item/clothing/gloves/color/black/pyro_claws/proc/reboot() - on_cooldown = FALSE - set_nodrop(FALSE, loc) - atom_say("Internal plasma canisters recharged. Gloves sufficiently cooled") - -/// Max number of atoms a broom can sweep at once -#define BROOM_PUSH_LIMIT 20 - -/obj/item/push_broom - name = "push broom" - desc = "This is my BROOMSTICK! It can be used manually or braced with two hands to sweep items as you move. It has a telescopic handle for compact storage." - icon = 'icons/obj/janitor.dmi' - icon_state = "broom0" - base_icon_state = "broom" - lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' - force = 8 - throwforce = 10 - throw_speed = 3 - attack_verb = list("swept", "brushed off", "bludgeoned", "whacked") - resistance_flags = FLAMMABLE - -/obj/item/push_broom/Initialize(mapload) - . = ..() - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.75, _parryable_attack_types = MELEE_ATTACK, _parry_cooldown = (7 / 3) SECONDS, _requires_two_hands = TRUE) - AddComponent(/datum/component/two_handed, \ - force_wielded = 12, \ - force_unwielded = force, \ - icon_wielded = "[base_icon_state]1", \ - wield_callback = CALLBACK(src, PROC_REF(wield)), \ - unwield_callback = CALLBACK(src, PROC_REF(unwield))) - -/obj/item/push_broom/update_icon_state() - icon_state = "[base_icon_state]0" - -/obj/item/push_broom/proc/wield(obj/item/source, mob/user) - to_chat(user, SPAN_NOTICE("You brace [src] against the ground in a firm sweeping stance.")) - RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(sweep)) - -/obj/item/push_broom/proc/unwield(obj/item/source, mob/user) - UnregisterSignal(user, COMSIG_MOVABLE_MOVED) - -/obj/item/push_broom/afterattack__legacy__attackchain(atom/A, mob/user, proximity) - . = ..() - if(!proximity) - return - sweep(user, A, FALSE) - -/obj/item/push_broom/proc/sweep(mob/user, atom/A, moving = TRUE) - SIGNAL_HANDLER - var/turf/current_item_loc = moving ? user.loc : (isturf(A) ? A : A.loc) - if(!isturf(current_item_loc)) - return - var/turf/new_item_loc = get_step(current_item_loc, user.dir) - var/obj/machinery/disposal/target_bin = locate(/obj/machinery/disposal) in new_item_loc.contents - var/obj/structure/janitorialcart/jani_cart = locate(/obj/structure/janitorialcart) in new_item_loc.contents - var/obj/vehicle/janicart/jani_vehicle = locate(/obj/vehicle/janicart) in new_item_loc.contents - var/trash_amount = 1 - for(var/obj/item/garbage in current_item_loc.contents) - if(garbage.anchored) - continue - var/obj/item/storage/bag/trash/bag = jani_vehicle?.mybag || jani_cart?.my_bag - var/obj/trashed_into - if(bag?.can_be_inserted(garbage, TRUE)) - bag.handle_item_insertion(garbage, user, TRUE) - trashed_into = bag - else if(target_bin) - move_into_storage(user, target_bin, garbage) - trashed_into = target_bin - else - garbage.Move(new_item_loc, user.dir) - if(trashed_into) - to_chat(user, SPAN_NOTICE("You sweep the pile of garbage into [trashed_into].")) - trash_amount++ - if(trash_amount > BROOM_PUSH_LIMIT) - break - if(trash_amount > 1) - playsound(loc, 'sound/weapons/sweeping.ogg', 70, TRUE, -1) - -/obj/item/push_broom/proc/move_into_storage(mob/user, obj/storage, obj/trash) - trash.forceMove(storage) - storage.update_icon() - -/obj/item/push_broom/traitor - name = "titanium push broom" - desc = "This is my BROOMSTICK! All of the functionality of a normal broom, but at least half again more robust." - attack_verb = list("smashed", "slammed", "whacked", "thwacked", "swept") - force = 10 - -/obj/item/push_broom/traitor/Initialize(mapload) - . = ..() - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (4 / 3) SECONDS, _requires_two_hands = TRUE) // 0.3333 seconds of cooldown for 75% uptime - // parent component handles this - AddComponent(/datum/component/two_handed, force_wielded = 25, force_unwielded = force) - -/obj/item/push_broom/traitor/examine(mob/user) - . = ..() - if(isAntag(user)) - . += "When wielded, the broom has different effects depending on your intent, similar to a martial art. \ - Help intent will sweep foes away from you, disarm intent sweeps their legs from under them, grab intent confuses \ - and minorly fatigues them, and harm intent hits them normally." - -/obj/item/push_broom/traitor/attack__legacy__attackchain(mob/target, mob/living/user) - if(!HAS_TRAIT(src, TRAIT_WIELDED) || !ishuman(target)) - return ..() - - var/mob/living/carbon/human/H = target - - switch(user.a_intent) - if(INTENT_HELP) - H.visible_message(SPAN_DANGER("[user] sweeps [H] away!"), \ - SPAN_USERDANGER("[user] sweeps you away!"), \ - SPAN_ITALICS("You hear sweeping.")) - playsound(loc, 'sound/weapons/sweeping.ogg', 70, TRUE, -1) - - var/atom/throw_target = get_edge_target_turf(H, get_dir(src, get_step_away(H, src))) - H.throw_at(throw_target, 3, 1) - - add_attack_logs(user, H, "Swept away with titanium push broom", ATKLOG_ALL) - - if(INTENT_DISARM) - if(H.stat || IS_HORIZONTAL(H)) - return ..() - - H.visible_message(SPAN_DANGER("[user] sweeps [H]'s legs out from under [H.p_them()]!"), \ - SPAN_USERDANGER("[user] sweeps your legs out from under you!"), \ - SPAN_ITALICS("You hear sweeping.")) - - user.do_attack_animation(H, ATTACK_EFFECT_KICK) - playsound(get_turf(user), 'sound/effects/hit_kick.ogg', 50, TRUE, -1) - H.apply_damage(5, BRUTE) - H.KnockDown(4 SECONDS) - - add_attack_logs(user, H, "Leg swept with titanium push broom", ATKLOG_ALL) - - if(INTENT_GRAB) - H.visible_message(SPAN_DANGER("[user] smacks [H] with the brush of [user.p_their()] broom!"), \ - SPAN_USERDANGER("[user] smacks you with the brush of [user.p_their()] broom!"), \ - SPAN_ITALICS("You hear a smacking noise.")) - - user.do_attack_animation(H, ATTACK_EFFECT_DISARM) - playsound(get_turf(user), 'sound/effects/woodhit.ogg', 50, TRUE, -1) - H.AdjustConfused(4 SECONDS, 0, 4 SECONDS) //no stacking infinitely - H.apply_damage(15, STAMINA) - - add_attack_logs(user, H, "Swept with the brush of the titanium push broom", ATKLOG_ALL) - - if(INTENT_HARM) - return ..() - -#undef BROOM_PUSH_LIMIT - -/// Supermatter Halberd, used by Oblivion Enforcers -/obj/item/supermatter_halberd - name = "supermatter halberd" - desc = "The revered weapon of Oblivion Enforcers, used to enforce the Order's will." - lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons_righthand.dmi' - icon = 'icons/obj/weapons/magical_weapons.dmi' - icon_state = "smhalberd0" - base_icon_state = "smhalberd" - force = 5 - sharp = TRUE - damtype = BURN - w_class = WEIGHT_CLASS_BULKY - slot_flags = ITEM_SLOT_BACK - throwforce = 15 - toolspeed = 0.25 - attack_verb = list("enlightened", "enforced", "cleaved", "stabbed", "whacked") - hitsound = 'sound/weapons/bladeslice.ogg' - resistance_flags = FIRE_PROOF - var/static/list/obliteration_targets = list(/turf/simulated/wall, /obj/machinery/door/airlock) - /// Whether we'll knockdown on hit - var/charged = TRUE - -/obj/item/supermatter_halberd/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_SUPERMATTER_IMMUNE, ROUNDSTART_TRAIT) //so it can't be dusted by the SM - AddComponent(/datum/component/forces_doors_open) - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (4 / 3) SECONDS, _requires_two_hands = TRUE) // 0.3333 seconds of cooldown for 75% uptime - AddComponent(/datum/component/two_handed, force_wielded = 40, force_unwielded = force, icon_wielded = "[base_icon_state]1") - -/obj/item/supermatter_halberd/update_icon_state() - icon_state = "[base_icon_state]0" - return ..() - -/obj/item/supermatter_halberd/afterattack__legacy__attackchain(atom/A, mob/user, proximity) - if(!proximity) - return - - if(!HAS_TRAIT(src, TRAIT_WIELDED)) - return - - if(istype(A, /obj/structure/window) || istype(A, /obj/structure/grille)) //same behavior as a fireaxe for windows - var/obj/structure/W = A - W.obj_destruction("fireaxe") - - //dusting dead people + knocking down people - if(isliving(A)) - var/mob/living/target = A - if(target.stat == DEAD) - visible_message(SPAN_DANGER("[user] raises [src] high, ready to bring it down on [target]!")) - if(do_after(user, 1 SECONDS, TRUE, target)) - visible_message(SPAN_DANGER("[user] brings down [src], obliterating [target] with a heavy blow!")) - playsound(loc, 'sound/effects/supermatter.ogg', 50, TRUE) - target.dust() - return - to_chat(user, SPAN_NOTICE("You lower [src]. There'll be time to obliterate them later...")) - return - - if(charged) - playsound(loc, 'sound/magic/lightningbolt.ogg', 5, TRUE) - target.visible_message(SPAN_DANGER("[src] flares with energy and shocks [target]!"), \ - SPAN_USERDANGER("You're shocked by [src]!"), \ - SPAN_WARNING("You hear shocking.")) - target.KnockDown(4 SECONDS) - do_sparks(3, FALSE, src) - charged = FALSE - addtimer(CALLBACK(src, PROC_REF(recharge)), 4 SECONDS) - - //walls and airlock obliteration logic - if(!is_type_in_list(A, obliteration_targets)) - return - - if(istype(A, /turf/simulated/wall/indestructible)) - return - - to_chat(user, SPAN_NOTICE("You start to obliterate [A].")) - playsound(loc, hitsound, 50, TRUE) - - var/obj/effect/temp_visual/obliteration_rays/rays = new(get_turf(A)) - - if(do_after(user, 5 SECONDS * toolspeed, target = A)) - new /obj/effect/temp_visual/obliteration(A, A) - playsound(loc, 'sound/effects/supermatter.ogg', 25, TRUE) - - if(iswallturf(A)) - var/turf/AT = A - AT.ChangeTurf(/turf/simulated/floor/plating) - return - - if(istype(A, /obj/machinery/door/airlock)) - qdel(A) - return - - qdel(rays) - return - -/obj/item/supermatter_halberd/proc/recharge() - charged = TRUE - playsound(loc, 'sound/machines/sm/accent/normal/1.ogg', 25, TRUE) diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm index 5616166679f..fcdfe8033a6 100644 --- a/code/modules/martial_arts/martial.dm +++ b/code/modules/martial_arts/martial.dm @@ -370,88 +370,6 @@ new /obj/effect/decal/cleanable/ash(get_turf(src)) qdel(src) -/obj/item/bostaff - name = "bo staff" - desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts. Can be wielded to both kill and incapacitate." - icon = 'icons/obj/weapons/melee.dmi' - icon_state = "bostaff0" - base_icon_state = "bostaff" - lefthand_file = 'icons/mob/inhands/staves_lefthand.dmi' - righthand_file = 'icons/mob/inhands/staves_righthand.dmi' - force = 10 - w_class = WEIGHT_CLASS_BULKY - slot_flags = ITEM_SLOT_BACK - throwforce = 20 - attack_verb = list("smashed", "slammed", "whacked", "thwacked") - -/obj/item/bostaff/Initialize(mapload) - . = ..() - AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES) - AddComponent(/datum/component/two_handed, force_wielded = 24, force_unwielded = force, icon_wielded = "[base_icon_state]1") - -/obj/item/bostaff/update_icon_state() - icon_state = "[base_icon_state]0" - -/obj/item/bostaff/attack__legacy__attackchain(mob/target, mob/living/user) - add_fingerprint(user) - if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) - to_chat(user, "You club yourself over the head with [src].") - user.Weaken(6 SECONDS) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - H.apply_damage(2*force, BRUTE, "head") - else - user.take_organ_damage(2*force) - return - if(isrobot(target)) - return ..() - if(!isliving(target)) - return ..() - var/mob/living/carbon/C = target - if(C.stat) - to_chat(user, SPAN_WARNING("It would be dishonorable to attack a foe while [C.p_they()] cannot retaliate.")) - return - if(HAS_TRAIT(user, TRAIT_PACIFISM)) - to_chat(user, SPAN_WARNING("You feel violence is not the answer.")) - return - switch(user.a_intent) - if(INTENT_DISARM) - if(!HAS_TRAIT(src, TRAIT_WIELDED)) - return ..() - if(!ishuman(target)) - return ..() - - var/mob/living/carbon/human/H = target - var/list/fluffmessages = list("[user] clubs [H] with [src]!", \ - "[user] smacks [H] with the butt of [src]!", \ - "[user] broadsides [H] with [src]!", \ - "[user] smashes [H]'s head with [src]!", \ - "[user] beats [H] with front of [src]!", \ - "[user] twirls and slams [H] with [src]!") - H.visible_message(SPAN_WARNING("[pick(fluffmessages)]"), \ - SPAN_USERDANGER("[pick(fluffmessages)]")) - playsound(get_turf(user), 'sound/effects/woodhit.ogg', 75, TRUE, -1) - H.apply_damage(rand(13,20), STAMINA) - if(prob(10)) - H.visible_message(SPAN_WARNING("[H] collapses!"), \ - SPAN_USERDANGER("Your legs give out!")) - H.Weaken(8 SECONDS) - if(H.getStaminaLoss() && !H.IsSleeping()) - var/total_health = (H.health - H.getStaminaLoss()) - if(total_health <= HEALTH_THRESHOLD_CRIT && !H.stat) - H.visible_message(SPAN_WARNING("[user] delivers a heavy hit to [H]'s head, knocking [H.p_them()] out cold!"), \ - SPAN_USERDANGER("[user] knocks you unconscious!")) - H.SetSleeping(60 SECONDS) - H.adjustBrainLoss(25) - return - else - return ..() - -/obj/item/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) - if(HAS_TRAIT(src, TRAIT_WIELDED)) - return ..() - return FALSE - /atom/movable/screen/combo icon_state = "" mouse_opacity = MOUSE_OPACITY_TRANSPARENT diff --git a/paradise.dme b/paradise.dme index 84facfa67d1..0ab033058ce 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1509,7 +1509,6 @@ #include "code\game\objects\items\weapons\stunbaton.dm" #include "code\game\objects\items\weapons\teleprod.dm" #include "code\game\objects\items\weapons\thurible.dm" -#include "code\game\objects\items\weapons\twohanded.dm" #include "code\game\objects\items\weapons\weaponry.dm" #include "code\game\objects\items\weapons\whetstone.dm" #include "code\game\objects\items\weapons\bio_chips\bio_chip_fluff.dm" @@ -1546,6 +1545,11 @@ #include "code\game\objects\items\weapons\storage\secure.dm" #include "code\game\objects\items\weapons\storage\toolbox.dm" #include "code\game\objects\items\weapons\storage\uplink_kits.dm" +#include "code\game\objects\items\weapons\two_handed\axes.dm" +#include "code\game\objects\items\weapons\two_handed\hammers.dm" +#include "code\game\objects\items\weapons\two_handed\misc_two_handed.dm" +#include "code\game\objects\items\weapons\two_handed\push_broom.dm" +#include "code\game\objects\items\weapons\two_handed\spears.dm" #include "code\game\objects\structures\aliens.dm" #include "code\game\objects\structures\barsign.dm" #include "code\game\objects\structures\bedsheet_bin.dm"