diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 8fec6c9c01..afb0e6c44a 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -108,7 +108,7 @@
W.afterattack(A, src, 1, params) // 1 indicates adjacency
else
if(ismob(A)) // No instant mob attacking
- setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ setClickCooldown(get_attack_speed())
UnarmedAttack(A, 1)
trigger_aiming(TARGET_CAN_CLICK)
@@ -129,7 +129,7 @@
W.afterattack(A, src, 1, params) // 1: clicking something Adjacent
else
if(ismob(A)) // No instant mob attacking
- setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ setClickCooldown(get_attack_speed())
UnarmedAttack(A, 1)
trigger_aiming(TARGET_CAN_CLICK)
return
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index b41dd9c57b..5b4f29a6a4 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -46,6 +46,22 @@ avoid code duplication. This includes items that may sometimes act as a standard
return 0
return I.attack(src, user, user.zone_sel.selecting)
+// Used to get how fast a mob should attack, and influences click delay.
+// This is just for inheritence.
+/mob/proc/get_attack_speed()
+ return DEFAULT_ATTACK_COOLDOWN
+
+// Same as above but actually does useful things.
+// W is the item being used in the attack, if any. modifier is if the attack should be longer or shorter than usual, for whatever reason.
+/mob/living/get_attack_speed(var/obj/item/W)
+ var/speed = DEFAULT_ATTACK_COOLDOWN
+ if(W && istype(W))
+ speed = W.attackspeed
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.attack_speed_percent))
+ speed *= M.attack_speed_percent
+ return speed
+
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
// Click parameters is the params string from byond Click() code, see that documentation.
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
@@ -68,7 +84,7 @@ avoid code duplication. This includes items that may sometimes act as a standard
msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
/////////////////////////
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
user.do_attack_animation(M)
var/hit_zone = M.resolve_item_attack(src, user, target_zone)
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 8cf8948bb7..a80ff05eac 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -59,7 +59,7 @@
if(!..())
return 0
- setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ setClickCooldown(get_attack_speed())
A.attack_generic(src,rand(5,6),"bitten")
/*
@@ -87,7 +87,7 @@
custom_emote(1,"[friendly] [A]!")
return
- setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ setClickCooldown(get_attack_speed())
if(isliving(A))
target_mob = A
PunchTarget()
@@ -96,7 +96,7 @@
A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext)
/mob/living/simple_animal/RangedAttack(var/atom/A)
- setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ setClickCooldown(get_attack_speed())
var/distance = get_dist(src, A)
if(prob(spattack_prob) && (distance >= spattack_min_range) && (distance <= spattack_max_range))
diff --git a/code/_onclick/rig.dm b/code/_onclick/rig.dm
index 436e7353ec..5f2561c25c 100644
--- a/code/_onclick/rig.dm
+++ b/code/_onclick/rig.dm
@@ -74,7 +74,7 @@
return 0
rig.selected_module.engage(A, alert_ai)
if(ismob(A)) // No instant mob attacking - though modules have their own cooldowns
- setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ setClickCooldown(get_attack_speed())
return 1
return 0
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 05ef232595..d16084ae66 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -125,7 +125,7 @@
if(user.species.can_shred(user))
set_status(0)
user.do_attack_animation(src)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
visible_message("\The [user] slashes at [src]!")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
add_hiddenprint(user)
@@ -205,7 +205,7 @@
src.bugged = 1
else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
if (W.force >= src.toughness)
user.do_attack_animation(src)
visible_message("[src] has been [W.attack_verb.len? pick(W.attack_verb) : "attacked"] with [W] by [user]!")
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 76eb2da2d5..2ed722e129 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -96,7 +96,7 @@ for reference:
return
return
else
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
switch(W.damtype)
if("fire")
health -= W.force * 1
@@ -214,7 +214,7 @@ for reference:
if(health <= 0)
explode()
return
-
+
/obj/machinery/deployable/barrier/emp_act(severity)
if(stat & (BROKEN|NOPOWER))
return
diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm
index bf40ad9fff..870b080c79 100644
--- a/code/game/machinery/doors/blast_door.dm
+++ b/code/game/machinery/doors/blast_door.dm
@@ -132,7 +132,7 @@
else if(src.density && (user.a_intent == I_HURT)) //If we can't pry it open and it's a weapon, let's hit it.
var/obj/item/weapon/W = C
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
if(W.damtype == BRUTE || W.damtype == BURN)
user.do_attack_animation(src)
if(W.force < min_force)
@@ -162,7 +162,7 @@
else if(src.density && (user.a_intent == I_HURT)) //If we can't pry it open and it's not a weapon.... Eh, let's attack it anyway.
var/obj/item/weapon/W = C
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
if(W.damtype == BRUTE || W.damtype == BURN)
user.do_attack_animation(src)
if(W.force < min_force) //No actual non-weapon item shouls have a force greater than the min_force, but let's include this just in case.
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 4c3823f11e..02437194bd 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -260,7 +260,7 @@
//psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them.
if(src.density && istype(I, /obj/item/weapon) && user.a_intent == I_HURT && !istype(I, /obj/item/weapon/card))
var/obj/item/weapon/W = I
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
if(W.damtype == BRUTE || W.damtype == BURN)
user.do_attack_animation(src)
if(W.force < min_force)
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 4fc02c70cc..d25473e709 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -161,7 +161,7 @@
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
visible_message("[user] smashes against the [src.name].", 1)
user.do_attack_animation(src)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
take_damage(25)
return
return src.attackby(user, user)
@@ -246,7 +246,7 @@
//If it's a weapon, smash windoor. Unless it's an id card, agent card, ect.. then ignore it (Cards really shouldnt damage a door anyway)
if(src.density && istype(I, /obj/item/weapon) && !istype(I, /obj/item/weapon/card))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(I))
var/aforce = I.force
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
visible_message("[src] was hit by [I].")
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index fe0ebfdb2f..9e88c95594 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -381,7 +381,7 @@ var/list/turret_icons
else
//if the turret was attacked with the intention of harming it:
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(I))
take_damage(I.force * 0.5)
if(I.force * 0.5 > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off
if(!attacked && !emagged)
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index db8fc51992..f71a40a011 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -505,7 +505,7 @@
return
/obj/mecha/attack_hand(mob/user as mob)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
src.log_message("Attack by hand/paw. Attacker - [user].",1)
if(istype(user,/mob/living/carbon/human))
@@ -513,7 +513,6 @@
if(H.species.can_shred(user))
if(!prob(src.deflect_chance))
src.take_damage(15)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1)
user << "You slash at the armored suit!"
@@ -666,7 +665,7 @@
return
/obj/mecha/proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
src.log_message("Attacked by [W]. Attacker - [user]")
if(prob(src.deflect_chance))
user << "\The [W] bounces off [src.name]."
@@ -1763,7 +1762,7 @@
/obj/mecha/attack_generic(var/mob/user, var/damage, var/attack_message)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
if(!damage)
return 0
diff --git a/code/game/objects/effects/alien/aliens.dm b/code/game/objects/effects/alien/aliens.dm
index 3d9713cd29..2c864f0a56 100644
--- a/code/game/objects/effects/alien/aliens.dm
+++ b/code/game/objects/effects/alien/aliens.dm
@@ -120,7 +120,7 @@
/obj/effect/alien/resin/attackby(obj/item/weapon/W as obj, mob/user as mob)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
var/aforce = W.force
health = max(0, health - aforce)
playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
@@ -227,7 +227,7 @@ Alien plants should do something if theres a lot of poison
return
/obj/effect/alien/weeds/attackby(var/obj/item/weapon/W, var/mob/user)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
if(W.attack_verb.len)
visible_message("\The [src] have been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]")
else
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index 4cc39d4e67..a26c1169d5 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -21,7 +21,7 @@
return
/obj/effect/spider/attackby(var/obj/item/weapon/W, var/mob/user)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
if(W.attack_verb.len)
visible_message("\The [src] have been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]")
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 8b00612641..ff7be9f549 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -80,6 +80,7 @@
var/list/sprite_sheets_obj = list()
var/toolspeed = 1.0 // This is a multipler on how 'fast' a tool works. e.g. setting this to 0.5 will make the tool work twice as fast.
+ var/attackspeed = DEFAULT_ATTACK_COOLDOWN // How long click delay will be when using this, in 1/10ths of a second. Checked in the user's get_attack_speed().
var/addblends // Icon overlay for ADD highlights when applicable.
/obj/item/New()
@@ -457,7 +458,7 @@ var/list/global/slot_flags_enumeration = list(
M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
msg_admin_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") //BS12 EDIT ALG
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
user.do_attack_animation(M)
src.add_fingerprint(user)
diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm
index 8eec816a50..2435e807f9 100644
--- a/code/game/objects/items/devices/flash.dm
+++ b/code/game/objects/items/devices/flash.dm
@@ -62,7 +62,7 @@
user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to flash [M.name] ([M.ckey])")
msg_admin_attack("[user.name] ([user.ckey]) Used the [src.name] to flash [M.name] ([M.ckey]) (JMP)")
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
user.do_attack_animation(M)
if(!clown_check(user)) return
@@ -75,9 +75,6 @@
if(!check_capacitor(user))
return
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
- user.do_attack_animation(M)
-
playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1)
var/flashfail = 0
@@ -147,7 +144,7 @@
/obj/item/device/flash/attack_self(mob/living/carbon/user as mob, flag = 0, emp = 0)
if(!user || !clown_check(user)) return
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
if(broken)
user.show_message("The [src.name] is broken", 2)
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 083f83c1c9..cfd3b398e3 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -163,7 +163,7 @@
else
user << "\The [M]'s pupils narrow."
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //can be used offensively
+ user.setClickCooldown(user.get_attack_speed(src)) //can be used offensively
M.flash_eyes()
else
return ..()
diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm
index 63a0df6d32..7b156c025f 100644
--- a/code/game/objects/items/stacks/nanopaste.dm
+++ b/code/game/objects/items/stacks/nanopaste.dm
@@ -34,7 +34,7 @@
if(!S.get_damage())
user << "Nothing to fix here."
else if(can_use(1))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
if(S.open >= 2)
if(do_after(user,5 * toolspeed))
S.heal_damage(20, 20, robo_repair = 1)
diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm
index 897ac43ff4..b1f623081d 100644
--- a/code/game/objects/items/weapons/handcuffs.dm
+++ b/code/game/objects/items/weapons/handcuffs.dm
@@ -81,7 +81,7 @@
msg_admin_attack("[key_name(user)] attempted to handcuff [key_name(H)]")
feedback_add_details("handcuffs","H")
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
user.do_attack_animation(H)
user.visible_message("\The [user] has put [cuff_type] on \the [H]!")
@@ -286,7 +286,7 @@ var/last_chew = 0
msg_admin_attack("[key_name(user)] attempted to legcuff [key_name(H)]")
feedback_add_details("legcuffs","H")
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
user.do_attack_animation(H)
user.visible_message("\The [user] has put [cuff_type] on \the [H]!")
diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm
index 53aa3258e1..24d6ee4f59 100644
--- a/code/game/objects/items/weapons/melee/energy.dm
+++ b/code/game/objects/items/weapons/melee/energy.dm
@@ -217,7 +217,7 @@
var/obj/O = AM
O.emp_act(3) // A weaker severity is used because this has infinite uses.
playsound(get_turf(O), 'sound/effects/EMPulse.ogg', 100, 1)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) // A lot of objects don't set click delay.
+ user.setClickCooldown(user.get_attack_speed(src)) // A lot of objects don't set click delay.
return ..()
/obj/item/weapon/melee/energy/sword/ionic_rapier/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
diff --git a/code/game/objects/items/weapons/trays.dm b/code/game/objects/items/weapons/trays.dm
index 41bcedbf21..c2ea991d98 100644
--- a/code/game/objects/items/weapons/trays.dm
+++ b/code/game/objects/items/weapons/trays.dm
@@ -17,7 +17,7 @@
var/max_carry = 10
/obj/item/weapon/tray/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
// Drop all the things. All of them.
overlays.Cut()
for(var/obj/item/I in carrying)
diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm
index e8ce7430c9..c077668bbd 100644
--- a/code/game/objects/items/weapons/weaponry.dm
+++ b/code/game/objects/items/weapons/weaponry.dm
@@ -21,7 +21,7 @@
msg_admin_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)")
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
user.do_attack_animation(M)
if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey")
@@ -134,7 +134,7 @@
qdel(src)
/obj/effect/energy_net/user_unbuckle_mob(mob/user)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
visible_message("[user] begins to tear at \the [src]!")
if(do_after(usr, escape_time, src, incapacitation_flags = INCAPACITATION_DEFAULT & ~(INCAPACITATION_RESTRAINED | INCAPACITATION_BUCKLED_FULLY)))
if(!buckled_mob)
diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm
index 0bf155dc49..9bceee8f6e 100644
--- a/code/game/objects/structures/catwalk.dm
+++ b/code/game/objects/structures/catwalk.dm
@@ -81,7 +81,7 @@
health = maxhealth
else
take_damage(C.force)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(C))
return ..()
/obj/structure/catwalk/Crossed()
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 2dcb1ddaad..d1516a9e66 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -55,7 +55,7 @@
/obj/structure/displaycase/attackby(obj/item/weapon/W as obj, mob/user as mob)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
user.do_attack_animation(src)
playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1)
src.health -= W.force
diff --git a/code/game/objects/structures/fitness.dm b/code/game/objects/structures/fitness.dm
index 3bb158a576..d29ad16f74 100644
--- a/code/game/objects/structures/fitness.dm
+++ b/code/game/objects/structures/fitness.dm
@@ -18,7 +18,7 @@
to_chat(user, "You need more energy to use the punching bag. Go eat something.")
else
if(user.a_intent == I_HURT)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
flick("[icon_state]_hit", src)
playsound(src.loc, 'sound/effects/woodhit.ogg', 25, 1, -1)
user.do_attack_animation(src)
diff --git a/code/game/objects/structures/flora/trees.dm b/code/game/objects/structures/flora/trees.dm
index d7960b5982..1b5322cfa7 100644
--- a/code/game/objects/structures/flora/trees.dm
+++ b/code/game/objects/structures/flora/trees.dm
@@ -36,7 +36,7 @@
to_chat(user, "\The [W] is ineffective at harming \the [src].")
hit_animation()
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
user.do_attack_animation(src)
// Shakes the tree slightly, more or less stolen from lockers.
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 2f0a032f21..aec6ce94c1 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -27,7 +27,7 @@
/obj/structure/grille/attack_hand(mob/user as mob)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
playsound(loc, 'sound/effects/grillehit.ogg', 80, 1)
user.do_attack_animation(src)
@@ -151,7 +151,7 @@
//window placing end
else if(!(W.flags & CONDUCT) || !shock(user, 70))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
user.do_attack_animation(src)
playsound(loc, 'sound/effects/grillehit.ogg', 80, 1)
switch(W.damtype)
diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm
index 7000e39974..1acafd5726 100644
--- a/code/game/objects/structures/railing.dm
+++ b/code/game/objects/structures/railing.dm
@@ -258,7 +258,7 @@
else
playsound(loc, 'sound/effects/grillehit.ogg', 50, 1)
take_damage(W.force)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
return ..()
diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm
index f6ee039977..02ea01556a 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm
@@ -72,7 +72,7 @@ var/global/list/stool_cache = list() //haha stool
/obj/item/weapon/stool/attack(mob/M as mob, mob/user as mob)
if (prob(5) && istype(M,/mob/living))
user.visible_message("[user] breaks [src] over [M]'s back!")
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
user.do_attack_animation(M)
user.drop_from_inventory(src)
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 0228b1d943..3bdbca1b54 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -18,7 +18,7 @@
/obj/structure/toilet/attack_hand(mob/living/user as mob)
if(swirlie)
- usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ usr.setClickCooldown(user.get_attack_speed())
usr.visible_message("[user] slams the toilet seat onto [swirlie.name]'s head!", "You slam the toilet seat onto [swirlie.name]'s head!", "You hear reverberating porcelain.")
swirlie.adjustBruteLoss(5)
return
@@ -54,7 +54,7 @@
return
if(istype(I, /obj/item/weapon/grab))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(I))
var/obj/item/weapon/grab/G = I
if(isliving(G.affecting))
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 49f3bb8437..eaf9b47103 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -172,7 +172,7 @@
playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1)
/obj/structure/window/attack_hand(mob/user as mob)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
if(HULK in user.mutations)
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!"))
user.visible_message("[user] smashes through [src]!")
@@ -200,7 +200,7 @@
return
/obj/structure/window/attack_generic(var/mob/user, var/damage)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
if(!damage)
return
if(damage >= 10)
@@ -295,7 +295,7 @@
var/obj/item/frame/F = W
F.try_build(src)
else
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
if(W.damtype == BRUTE || W.damtype == BURN)
user.do_attack_animation(src)
hit(W.force)
diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index e227bb7467..01633b65d3 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -90,7 +90,7 @@
radiate()
add_fingerprint(user)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
var/rotting = (locate(/obj/effect/overlay/wallrot) in src)
if (HULK in user.mutations)
if (rotting || !prob(material.hardness))
@@ -104,7 +104,7 @@
/turf/simulated/wall/attack_generic(var/mob/user, var/damage, var/attack_message, var/wallbreaker)
radiate()
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
var/rotting = (locate(/obj/effect/overlay/wallrot) in src)
if(!damage || !wallbreaker)
try_touch(user, rotting)
@@ -122,7 +122,7 @@
/turf/simulated/wall/attackby(obj/item/weapon/W as obj, mob/user as mob)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
if (!user.)
user << "You don't have the dexterity to do this!"
return
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 0b02b98ef3..a5440483c7 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -209,7 +209,8 @@ var/list/admin_verbs_debug = list(
/client/proc/show_gm_status,
/datum/admins/proc/change_weather,
/datum/admins/proc/change_time,
- /client/proc/admin_give_modifier
+ /client/proc/admin_give_modifier,
+ /client/proc/simple_DPS
)
var/list/admin_verbs_paranoid_debug = list(
@@ -290,6 +291,7 @@ var/list/admin_verbs_hideable = list(
/client/proc/kill_airgroup,
/client/proc/debug_controller,
/client/proc/startSinglo,
+ /client/proc/simple_DPS,
/client/proc/cmd_debug_mob_lists,
/client/proc/cmd_debug_using_map,
/client/proc/cmd_debug_del_all,
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 981d5c7b7b..02c3fbc7b6 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -16,6 +16,56 @@
// callproc moved to code/modules/admin/callproc
+/client/proc/simple_DPS()
+ set name = "Simple DPS"
+ set category = "Debug"
+ set desc = "Gives a really basic idea of how much hurt something in-hand does."
+
+ var/obj/item/I = null
+ var/mob/living/user = null
+ if(isliving(usr))
+ user = usr
+ I = user.get_active_hand()
+ if(!I || !istype(I))
+ to_chat(user, "You need to have something in your active hand, to use this verb.")
+ return
+ var/weapon_attack_speed = user.get_attack_speed(I) / 10
+ var/weapon_damage = I.force
+
+ if(istype(I, /obj/item/weapon/gun))
+ var/obj/item/weapon/gun/G = I
+ var/obj/item/projectile/P
+
+ if(istype(I, /obj/item/weapon/gun/energy))
+ var/obj/item/weapon/gun/energy/energy_gun = G
+ P = new energy_gun.projectile_type()
+
+ else if(istype(I, /obj/item/weapon/gun/projectile))
+ var/obj/item/weapon/gun/projectile/projectile_gun = G
+ var/obj/item/ammo_casing/ammo = projectile_gun.chambered
+ P = ammo.BB
+
+ else
+ to_chat(user, "DPS calculation by this verb is not supported for \the [G]'s type. Energy or Ballistic only, sorry.")
+
+ weapon_damage = P.damage
+ weapon_attack_speed = G.fire_delay / 10
+ qdel(P)
+
+ var/DPS = weapon_damage / weapon_attack_speed
+ to_chat(user, "Damage: [weapon_damage]")
+ to_chat(user, "Attack Speed: [weapon_attack_speed]/s")
+ to_chat(user, "\The [I] does [DPS] damage per second.")
+ if(DPS > 0)
+ to_chat(user, "At your maximum health ([user.getMaxHealth()]), it would take approximately;")
+ to_chat(user, "[(user.getMaxHealth() - config.health_threshold_softcrit) / DPS] seconds to softcrit you. ([config.health_threshold_softcrit] health)")
+ to_chat(user, "[(user.getMaxHealth() - config.health_threshold_crit) / DPS] seconds to hardcrit you. ([config.health_threshold_crit] health)")
+ to_chat(user, "[(user.getMaxHealth() - config.health_threshold_dead) / DPS] seconds to kill you. ([config.health_threshold_dead] health)")
+
+ else
+ to_chat(user, "You need to be a living mob, with hands, and for an object to be in your active hand, to use this verb.")
+ return
+
/client/proc/Cell()
set category = "Debug"
set name = "Cell"
diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm
index b66abd61da..f08f28d97a 100644
--- a/code/modules/hydroponics/spreading/spreading.dm
+++ b/code/modules/hydroponics/spreading/spreading.dm
@@ -238,7 +238,7 @@
/obj/effect/plant/attackby(var/obj/item/weapon/W, var/mob/user)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
plant_controller.add_plant(src)
if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/surgical/scalpel))
diff --git a/code/modules/hydroponics/spreading/spreading_response.dm b/code/modules/hydroponics/spreading/spreading_response.dm
index 80d72055eb..12747666c4 100644
--- a/code/modules/hydroponics/spreading/spreading_response.dm
+++ b/code/modules/hydroponics/spreading/spreading_response.dm
@@ -61,7 +61,7 @@
"You hear shredding and ripping.")
unbuckle()
else
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
health -= rand(1,5)
var/text = pick("rip","tear","pull", "bite", "tug")
user.visible_message(\
diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm
index 4eee4ee91b..4a924fdca3 100644
--- a/code/modules/hydroponics/trays/tray.dm
+++ b/code/modules/hydroponics/trays/tray.dm
@@ -568,7 +568,7 @@
return
else if(O.force && seed)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(O))
user.visible_message("\The [seed.display_name] has been attacked by [user] with \the [O]!")
if(!dead)
health -= O.force
diff --git a/code/modules/mob/_modifiers/modifiers.dm b/code/modules/mob/_modifiers/modifiers.dm
index 3facabe6f9..7164396f29 100644
--- a/code/modules/mob/_modifiers/modifiers.dm
+++ b/code/modules/mob/_modifiers/modifiers.dm
@@ -42,6 +42,7 @@
var/accuracy_dispersion // Positive numbers make gun firing cover a wider tile range, and therefore more inaccurate. Negatives help negate dispersion penalties.
var/metabolism_percent // Adjusts the mob's metabolic rate, which affects reagent processing. Won't affect mobs without reagent processing.
var/icon_scale_percent // Makes the holder's icon get scaled up or down.
+ var/attack_speed_percent // Makes the holder's 'attack speed' (click delay) shorter or longer.
/datum/modifier/New(var/new_holder, var/new_origin)
holder = new_holder
@@ -206,6 +207,9 @@
if(!isnull(icon_scale_percent))
effects += "Your appearance is [multipler_to_percentage(icon_scale_percent, TRUE)] [icon_scale_percent > 1 ? "larger" : "smaller"]."
+ if(!isnull(attack_speed_percent))
+ effects += "The delay between attacking is [multipler_to_percentage(attack_speed_percent, TRUE)] [disable_duration_percent > 1.0 ? "longer" : "shorter"]."
+
return jointext(effects, "
")
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 6c3cd7f1db..6b07aa8b0c 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -486,7 +486,7 @@
return
var/obj/item/weapon/weldingtool/WT = W
if (WT.remove_fuel(0))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(WT))
adjustBruteLoss(-30)
updatehealth()
add_fingerprint(user)
@@ -502,7 +502,7 @@
return
var/obj/item/stack/cable_coil/coil = W
if (coil.use(1))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
adjustFireLoss(-30)
updatehealth()
for(var/mob/O in viewers(user, null))
diff --git a/code/modules/mob/living/simple_animal/slime/combat.dm b/code/modules/mob/living/simple_animal/slime/combat.dm
index 0068ee728c..8554a27e5f 100644
--- a/code/modules/mob/living/simple_animal/slime/combat.dm
+++ b/code/modules/mob/living/simple_animal/slime/combat.dm
@@ -213,7 +213,7 @@
// Otherwise they're probably fighting the slime.
if(prob(25))
visible_message("\The [user]'s [W] passes right through [src]!")
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
return
..()
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index 1508aff08a..b6ad2fff2c 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -411,7 +411,7 @@
user << "You can't reach your [src.name] while holding [tool] in your [owner.get_bodypart_name(grasp)]."
return 0
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(tool))
if(!do_mob(user, owner, 10))
user << "You must stand still to do that."
return 0
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 39ce99d188..0c5f8ebaac 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -699,7 +699,7 @@
var/mob/living/carbon/human/H = user
if(H.species.can_shred(H))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
user.visible_message("[user.name] slashes at the [src.name]!", "You slash at the [src.name]!")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 216332cbdd..8cdcf67178 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -527,7 +527,7 @@
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
if(H.species.can_shred(H))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed())
for(var/mob/M in viewers(src))
M.show_message("[user.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2)
broken()
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 6721cbd3bb..fc89bab93d 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -101,7 +101,7 @@
user << "\The [blocked] is in the way!"
return
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things
+ user.setClickCooldown(user.get_attack_speed(src)) //puts a limit on how fast people can eat/drink things
self_feed_message(user)
reagents.trans_to_mob(user, issmall(user) ? ceil(amount_per_transfer_from_this/2) : amount_per_transfer_from_this, CHEM_INGEST)
feed_sound(user)
@@ -119,7 +119,7 @@
other_feed_message_start(user, target)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
if(!do_mob(user, target))
return
diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm
index c49c76be01..100aa43165 100644
--- a/code/modules/reagents/reagent_containers/food/snacks.dm
+++ b/code/modules/reagents/reagent_containers/food/snacks.dm
@@ -68,7 +68,7 @@
user << "\The [blocked] is in the way!"
return
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things
+ user.setClickCooldown(user.get_attack_speed(src)) //puts a limit on how fast people can eat/drink things
if (fullness <= 50)
M << "You hungrily chew out a piece of [src] and gobble it!"
if (fullness > 50 && fullness <= 150)
@@ -101,7 +101,7 @@
user.visible_message("[user] cannot force anymore of [src] down [M]'s throat.")
return 0
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
if(!do_mob(user, M)) return
M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]")
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index e21baa48e2..bc83d8c9cf 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -51,7 +51,7 @@
user.visible_message("[user] attempts to force [M] to swallow \the [src].")
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(src))
if(!do_mob(user, M))
return
diff --git a/code/modules/shieldgen/energy_field.dm b/code/modules/shieldgen/energy_field.dm
index 5dc6af651d..e558a2621e 100644
--- a/code/modules/shieldgen/energy_field.dm
+++ b/code/modules/shieldgen/energy_field.dm
@@ -49,7 +49,7 @@
if(W.force)
adjust_strength(-W.force / 20)
user.do_attack_animation(src)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
..()
/obj/effect/energy_field/attack_hand(var/mob/living/user)
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
index eb70ca64ce..f725508c88 100644
--- a/code/modules/vehicles/vehicle.dm
+++ b/code/modules/vehicles/vehicle.dm
@@ -94,7 +94,7 @@
if(health < maxhealth)
if(open)
health = min(maxhealth, health+10)
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
playsound(src, T.usesound, 50, 1)
user.visible_message("[user] repairs [src]!"," You repair [src]!")
else
@@ -104,7 +104,7 @@
else
user << "Unable to repair while [src] is off."
else if(hasvar(W,"force") && hasvar(W,"damtype"))
- user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.setClickCooldown(user.get_attack_speed(W))
switch(W.damtype)
if("fire")
health -= W.force * fire_dam_coeff
diff --git a/code/modules/xenobio/items/extracts.dm b/code/modules/xenobio/items/extracts.dm
index 87542b70f0..8d7d338bad 100644
--- a/code/modules/xenobio/items/extracts.dm
+++ b/code/modules/xenobio/items/extracts.dm
@@ -899,6 +899,7 @@
evasion = 2
slowdown = -1
+ attack_speed_percent = 0.75
// *********************