mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-22 11:37:40 +01:00
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 <alfalfascout@users.noreply.github.com> * 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 <alfalfascout@users.noreply.github.com> * Apply suggestions from CRUNCH review Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan <alfalfascout@users.noreply.github.com> * 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 <alfalfascout@users.noreply.github.com> * Apply suggestions from CRUNCH review. Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan <alfalfascout@users.noreply.github.com> * Apply suggestions from CRUNCH review Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com> Signed-off-by: Alan <alfalfascout@users.noreply.github.com> * 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 <alfalfascout@users.noreply.github.com> * 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 <alfalfascout@users.noreply.github.com> * 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 <alfalfascout@users.noreply.github.com> --------- Signed-off-by: Alan <alfalfascout@users.noreply.github.com> Co-authored-by: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com>
This commit is contained in:
@@ -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
|
||||
@@ -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. <br>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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user