diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm
index 7136175519c..20747361d33 100644
--- a/code/ZAS/Airflow.dm
+++ b/code/ZAS/Airflow.dm
@@ -126,7 +126,7 @@ obj/item/check_airflow_movable(n)
step_towards(src, src.airflow_dest)
var/mob/M = src
if(istype(M) && M.client)
- M.client.move_delay = world.time + vsc.airflow_mob_slowdown
+ M.setMoveCooldown(vsc.airflow_mob_slowdown)
airflow_dest = null
airflow_speed = 0
airflow_time = 0
diff --git a/code/__defines/items_clothing.dm b/code/__defines/items_clothing.dm
index b822c4badce..aa32b0016ec 100644
--- a/code/__defines/items_clothing.dm
+++ b/code/__defines/items_clothing.dm
@@ -24,15 +24,13 @@
// Flags bitmasks.
#define NOBLUDGEON 0x1 // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
-#define USEDELAY 0x2 // 1 second extra delay on use. (Can be used once every 2s)
-#define CONDUCT 0x4 // Conducts electricity. (metal etc.)
-#define ON_BORDER 0x8 // Item has priority to check when entering or leaving.
-#define NOBLOODY 0x10 // Used for items if they don't want to get a blood overlay.
-#define NODELAY 0x20 // 1 second attack-by delay skipped (Can be used once every 0.2s). Most objects have a 1s attack-by delay, which doesn't require a flag.
-#define OPENCONTAINER 0x40 // Is an open container for chemistry purposes.
-#define PHORONGUARD 0x80 // Does not get contaminated by phoron.
-#define NOREACT 0x100 // Reagents don't react inside this container.
-#define PROXMOVE 0x200 // Does this object require proximity checking in Enter()?
+#define CONDUCT 0x2 // Conducts electricity. (metal etc.)
+#define ON_BORDER 0x4 // Item has priority to check when entering or leaving.
+#define NOBLOODY 0x8 // Used for items if they don't want to get a blood overlay.
+#define OPENCONTAINER 0x10 // Is an open container for chemistry purposes.
+#define PHORONGUARD 0x20 // Does not get contaminated by phoron.
+#define NOREACT 0x40 // Reagents don't react inside this container.
+#define PROXMOVE 0x80 // Does this object require proximity checking in Enter()?
//Flags for items (equipment)
#define THICKMATERIAL 0x1 // Prevents syringes, parapens and hyposprays if equiped to slot_suit or slot_head.
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index b0858101d68..5bcab4704d4 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -61,8 +61,6 @@
#define HEAVY 64
#define ALLMOBS (HUMAN|MONKEY|ALIEN|ROBOT|SLIME|SIMPLE_ANIMAL|HEAVY)
-#define NEXT_MOVE_DELAY 8
-
// Robot AI notifications
#define ROBOT_NOTIFICATION_NEW_UNIT 1
#define ROBOT_NOTIFICATION_NEW_NAME 2
@@ -82,6 +80,9 @@
#define APPEARANCE_ALL_HAIR (APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR)
#define APPEARANCE_ALL 0xFFFF
+// Click cooldown
+#define DEFAULT_ATTACK_COOLDOWN 8 //Default timeout for aggressive actions
+
#define MIN_SUPPLIED_LAW_NUMBER 15
#define MAX_SUPPLIED_LAW_NUMBER 50
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index e05cbeb9ba2..4dee15388de 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -15,7 +15,6 @@
return
if(control_disabled || stat) return
- next_move = world.time + 9
if(ismob(A))
ai_actual_track(A)
@@ -52,9 +51,8 @@
CtrlClickOn(A)
return
- if(world.time <= next_move)
+ if(!canClick())
return
- next_move = world.time + 9
if(aiCamera.in_camera_mode)
aiCamera.camera_mode_off()
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 33e8dae8d62..61b98a99943 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -4,7 +4,7 @@
*/
// 1 decisecond click delay (above and beyond mob/next_move)
-/mob/var/next_click = 0
+/mob/var/next_click = 0
/*
Before anything else, defer these calls to a per-mobtype handler. This allows us to
@@ -15,12 +15,14 @@
Note that this proc can be overridden, and is in the case of screen objects.
*/
-/atom/Click(location,control,params)
+
+/atom/Click(var/location, var/control, var/params) // This is their reaction to being clicked on (standard proc)
if(src)
usr.ClickOn(src, params)
-/atom/DblClick(location,control,params)
+
+/atom/DblClick(var/location, var/control, var/params)
if(src)
- usr.DblClickOn(src,params)
+ usr.DblClickOn(src, params)
/*
Standard mob ClickOn()
@@ -35,8 +37,8 @@
* item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent
* mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
*/
-/mob/proc/ClickOn( var/atom/A, var/params )
- if(world.time <= next_click)
+/mob/proc/ClickOn(var/atom/A, var/params)
+ if(world.time <= next_click) // Hard check, before anything else, to avoid crashing
return
next_click = world.time + 1
@@ -66,16 +68,17 @@
face_atom(A) // change direction to face what you clicked on
- if(next_move > world.time) // in the year 2000...
+ if(!canClick()) // in the year 2000...
return
- if(istype(loc,/obj/mecha))
- if(!locate(/turf) in list(A,A.loc)) // Prevents inventory from being drilled
+ if(istype(loc, /obj/mecha))
+ if(!locate(/turf) in list(A, A.loc)) // Prevents inventory from being drilled
return
var/obj/mecha/M = loc
- return M.click_action(A,src)
+ return M.click_action(A, src)
if(restrained())
+ setClickCooldown(10)
RestrainedClickOn(A)
return
@@ -85,79 +88,78 @@
return
throw_mode_off()
- if(!istype(A,/obj/item/weapon/gun) && !isturf(A) && !istype(A,/obj/screen))
+ if(!istype(A, /obj/item/weapon/gun) && !isturf(A) && !istype(A, /obj/screen))
last_target_click = world.time
var/obj/item/W = get_active_hand()
- if(W == A)
- next_move = world.time + 6
- if(W.flags&USEDELAY)
- next_move += 5
+ if(W == A) // Handle attack_self
W.attack_self(src)
if(hand)
update_inv_l_hand(0)
else
update_inv_r_hand(0)
-
return
- // operate two STORAGE levels deep here (item in backpack in src; NOT item in box in backpack in src)
+ //Atoms on your person
+ // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because contents depth does not equate inventory storage depth.
var/sdepth = A.storage_depth(src)
- if(A == loc || (A in loc) || (sdepth != -1 && sdepth <= 1))
-
+ if((!isturf(A) && A == loc) || (sdepth != -1 && sdepth <= 1))
// faster access to objects already on you
if(A in contents)
- next_move = world.time + 6 // on your person
+ setMoveCooldown(5) //taking an item off of an inventory slot
else
- next_move = world.time + 8 // in a box/bag or in your square
-
- // No adjacency needed
+ setMoveCooldown(10) //getting something out of a backpack
+
if(W)
- if(W.flags&USEDELAY)
- next_move += 5
-
var/resolved = W.resolve_attackby(A, src)
if(!resolved && A && W)
- W.afterattack(A,src,1,params) // 1 indicates adjacency
+ W.afterattack(A, src, 1, params) // 1 indicates adjacency
else
+ if(ismob(A)) // No instant mob attacking
+ setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
UnarmedAttack(A, 1)
return
if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that
return
- // Allows you to click on a box's contents, if that box is on the ground, but no deeper than that
+ //Atoms on turfs (not on your person)
+ // A is a turf or is on a turf, or in something on a turf (pen in a box); but not something in something on a turf (pen in a box in a backpack)
sdepth = A.storage_depth_turf()
if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1))
- next_move = world.time + 10
-
if(A.Adjacent(src)) // see adjacent.dm
+ setMoveCooldown(10)
+
if(W)
- if(W.flags&USEDELAY)
- next_move += 5
-
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
var/resolved = W.resolve_attackby(A,src)
if(!resolved && A && W)
- W.afterattack(A,src,1,params) // 1: clicking something Adjacent
+ W.afterattack(A, src, 1, params) // 1: clicking something Adjacent
else
+ if(ismob(A)) // No instant mob attacking
+ setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
UnarmedAttack(A, 1)
return
else // non-adjacent click
if(W)
- W.afterattack(A,src,0,params) // 0: not Adjacent
+ W.afterattack(A, src, 0, params) // 0: not Adjacent
else
RangedAttack(A, params)
return
-/mob/proc/changeNext_move(num)
- next_move = world.time + num
+/mob/proc/setClickCooldown(var/timeout)
+ next_move = max(world.time + timeout, next_move)
-// Default behavior: ignore double clicks, consider them normal clicks instead
+/mob/proc/canClick()
+ if(config.no_click_cooldown || next_move <= world.time)
+ return 1
+ return 0
+
+// Default behavior: ignore double clicks, the second click that makes the doubleclick call already calls for a normal click
/mob/proc/DblClickOn(var/atom/A, var/params)
- ClickOn(A,params)
+ return
/*
Translates into attack_hand, etc.
@@ -201,14 +203,12 @@
LaserEyes(A) // moved into a proc below
else if(TK in mutations)
switch(get_dist(src,A))
- if(0)
- ;
if(1 to 5) // not adjacent may mean blocked by window
- next_move += 2
+ setMoveCooldown(2)
if(5 to 7)
- next_move += 5
+ setMoveCooldown(5)
if(8 to tk_maxrange)
- next_move += 10
+ setMoveCooldown(10)
else
return
A.attack_tk(src)
@@ -231,7 +231,6 @@
/mob/living/carbon/MiddleClickOn(var/atom/A)
swap_hand()
-
// In case of use break glass
/*
/atom/proc/MiddleClick(var/mob/M as mob)
@@ -307,7 +306,7 @@
return
/mob/living/LaserEyes(atom/A)
- next_move = world.time + 6
+ setClickCooldown(4)
var/turf/T = get_turf(src)
var/turf/U = get_turf(A)
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index 59860116889..414071a964a 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -35,7 +35,7 @@
if(stat || lockcharge || weakened || stunned || paralysis)
return
- if(next_move >= world.time)
+ if(!canClick())
return
face_atom(A) // change direction to face what you clicked on
@@ -68,9 +68,6 @@
return
if(W == A)
- next_move = world.time + 8
- if(W.flags&USEDELAY)
- next_move += 5
W.attack_self(src)
return
@@ -78,9 +75,6 @@
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents)
if(A == loc || (A in loc) || (A in contents))
// No adjacency checks
- next_move = world.time + 8
- if(W.flags&USEDELAY)
- next_move += 5
var/resolved = A.attackby(W,src)
if(!resolved && A && W)
@@ -93,16 +87,12 @@
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc && isturf(A.loc.loc))
if(isturf(A) || isturf(A.loc))
if(A.Adjacent(src)) // see adjacent.dm
- next_move = world.time + 10
- if(W.flags&USEDELAY)
- next_move += 5
var/resolved = A.attackby(W, src)
if(!resolved && A && W)
W.afterattack(A, src, 1, params)
return
else
- next_move = world.time + 10
W.afterattack(A, src, 0, params)
return
return
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index d4f323e323d..62df4c26c86 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -52,9 +52,8 @@
/obj/screen/item_action/Click()
if(!usr || !owner)
return 1
- if(usr.next_move >= world.time)
+ if(!usr.canClick())
return
- usr.next_move = world.time + 6
if(usr.stat || usr.restrained() || usr.stunned || usr.lying)
return 1
@@ -84,7 +83,7 @@
name = "storage"
/obj/screen/storage/Click()
- if(world.time <= usr.next_move)
+ if(!usr.canClick())
return 1
if(usr.stat || usr.paralysis || usr.stunned || usr.weakened)
return 1
@@ -94,7 +93,6 @@
var/obj/item/I = usr.get_active_hand()
if(I)
usr.ClickOn(master)
- usr.next_move = world.time+2
return 1
/obj/screen/gun
@@ -480,7 +478,7 @@
/obj/screen/inventory/Click()
// At this point in client Click() code we have passed the 1/10 sec check and little else
// We don't even know if it's a middle click
- if(world.time <= usr.next_move)
+ if(!usr.canClick())
return 1
if(usr.stat || usr.paralysis || usr.stunned || usr.weakened)
return 1
@@ -491,12 +489,10 @@
if(iscarbon(usr))
var/mob/living/carbon/C = usr
C.activate_hand("r")
- usr.next_move = world.time+2
if("l_hand")
if(iscarbon(usr))
var/mob/living/carbon/C = usr
C.activate_hand("l")
- usr.next_move = world.time+2
if("swap")
usr:swap_hand()
if("hand")
@@ -505,5 +501,4 @@
if(usr.attack_ui(slot_id))
usr.update_inv_l_hand(0)
usr.update_inv_r_hand(0)
- usr.next_move = world.time+6
return 1
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index d3c3df942e3..0cca5569c25 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -6,11 +6,13 @@
// No comment
/atom/proc/attackby(obj/item/W, mob/user)
return
+
/atom/movable/attackby(obj/item/W, mob/user)
if(!(W.flags&NOBLUDGEON))
visible_message("[src] has been hit by [user] with [W].")
/mob/living/attackby(obj/item/I, mob/user)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(istype(I) && ismob(user))
I.attack(src, user)
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index abc0e6114ed..324dcc234d9 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -32,8 +32,8 @@
if(client.buildmode)
build_click(src, client.buildmode, params, A)
return
- if(world.time <= next_move) return
- next_move = world.time + 8
+ if(!canClick()) return
+ setClickCooldown(4)
// You are responsible for checking config.ghost_interaction when you override this function
// Not all of them require checking, see below
A.attack_ghost(src)
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 179a470fc6b..95c77d67080 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -38,15 +38,6 @@
return
else if(TK in mutations)
- switch(get_dist(src,A))
- if(1 to 5) // not adjacent may mean blocked by window
- next_move += 2
- if(5 to 7)
- next_move += 5
- if(8 to 15)
- next_move += 10
- if(16 to 128)
- return
A.attack_tk(src)
/mob/living/RestrainedClickOn(var/atom/A)
diff --git a/code/_onclick/rig.dm b/code/_onclick/rig.dm
index ad9346ec15f..600d8c56193 100644
--- a/code/_onclick/rig.dm
+++ b/code/_onclick/rig.dm
@@ -48,12 +48,14 @@
..()
/mob/living/carbon/human/proc/HardsuitClickOn(atom/A)
+ if(!canClick())
+ return
if(back)
var/obj/item/weapon/rig/rig = back
if(istype(rig) && rig.selected_module)
- if(world.time <= next_move) return 1
- next_move = world.time + 8
rig.selected_module.engage(A)
+ if(ismob(A)) // No instant mob attacking - though modules have their own cooldowns
+ setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
return 1
return 0
diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm
index f3419b074af..f772ac8ea9c 100644
--- a/code/_onclick/telekinesis.dm
+++ b/code/_onclick/telekinesis.dm
@@ -111,12 +111,16 @@ var/const/tk_maxrange = 15
if(0)
;
if(1 to 5) // not adjacent may mean blocked by window
- if(!proximity)
- user.next_move += 2
+ ;
+ //TODO replace these with movement timeouts
+ //if(!proximity)
+ // user.next_move += 2
if(5 to 7)
- user.next_move += 5
+ ;
+ //user.next_move += 5
if(8 to tk_maxrange)
- user.next_move += 10
+ ;
+ //user.next_move += 10
else
user << "Your mind won't reach that far."
return
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 06adfe42f96..a0558775e95 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -139,6 +139,7 @@ var/list/gamemode_cache = list()
var/welder_vision = 1
var/generate_asteroid = 0
+ var/no_click_cooldown = 0
//Used for modifying movement speed for mobs.
//Unversal modifiers
@@ -328,6 +329,9 @@ var/list/gamemode_cache = list()
if ("generate_asteroid")
config.generate_asteroid = 1
+ if ("no_click_cooldown")
+ config.no_click_cooldown = 1
+
if("allow_admin_ooccolor")
config.allow_admin_ooccolor = 1
diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm
index 44486d605b5..123bb97a3fe 100644
--- a/code/game/gamemodes/blob/theblob.dm
+++ b/code/game/gamemodes/blob/theblob.dm
@@ -157,6 +157,7 @@
attackby(var/obj/item/weapon/W, var/mob/user)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
src.visible_message("The [src.name] has been attacked with \the [W][(user ? " by [user]." : ".")]")
var/damage = 0
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 9dc39f257b3..7a8e81a1f2a 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -186,6 +186,7 @@
src.bugged = 1
else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if (W.force >= src.toughness)
user.do_attack_animation(src)
visible_message("[src] has been [pick(W.attack_verb)] with [W] by [user]!")
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 2da65d273fd..ccf2fb97ae3 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -64,7 +64,7 @@ for reference:
var/health = 100
var/maxhealth = 100
var/material/material
-
+
/obj/structure/barricade/New(var/newloc, var/material_name)
..(newloc)
if(!material_name)
@@ -77,7 +77,7 @@ for reference:
desc = "This space is blocked off by a barricade made of [material.display_name]."
color = material.icon_colour
maxhealth = material.integrity
- health = maxhealth
+ health = maxhealth
/obj/structure/barricade/get_material()
return material
@@ -99,6 +99,7 @@ for reference:
return
return
else
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
switch(W.damtype)
if("fire")
src.health -= W.force * 1
@@ -111,6 +112,7 @@ for reference:
qdel(src)
return
..()
+
/obj/structure/barricade/proc/dismantle()
material.place_dismantled_product(get_turf(src))
qdel(src)
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 9075da2a056..2def8f80860 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -266,6 +266,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)
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 dc3edc93283..e50af2bcf0a 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -229,6 +229,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)
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 5d184f0b07c..2fa0281ecd3 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -338,7 +338,7 @@ var/list/turret_icons
else
//if the turret was attacked with the intention of harming it:
- user.changeNext_move(NEXT_MOVE_DELAY)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
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 96dda70158f..573ede3fb0f 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -505,6 +505,7 @@
return
/obj/mecha/attack_hand(mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
src.log_message("Attack by hand/paw. Attacker - [user].",1)
if(istype(user,/mob/living/carbon/human))
@@ -664,6 +665,7 @@
return
/obj/mecha/proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
src.log_message("Attacked by [W]. Attacker - [user]")
if(prob(src.deflect_chance))
user << "\The [W] bounces off [src.name]."
@@ -1683,6 +1685,7 @@
/obj/mecha/attack_generic(var/mob/user, var/damage, var/attack_message)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(!damage)
return 0
diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm
index 1bb11016d73..5257cff014e 100644
--- a/code/game/objects/effects/aliens.dm
+++ b/code/game/objects/effects/aliens.dm
@@ -98,6 +98,7 @@
return
/obj/effect/alien/resin/attack_hand()
+ usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if (HULK in usr.mutations)
usr << "You easily destroy the [name]."
for(var/mob/O in oviewers(src))
@@ -124,6 +125,7 @@
/obj/effect/alien/resin/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
var/aforce = W.force
health = max(0, health - aforce)
playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
@@ -231,6 +233,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)
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/items.dm b/code/game/objects/items.dm
index 34625759e33..8f36b1d007b 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -172,7 +172,6 @@
else
if(isliving(src.loc))
return
- user.next_move = max(user.next_move+2,world.time + 2)
user.put_in_active_hand(src)
return
@@ -607,10 +606,10 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
usr.visible_message("[zoomdevicename ? "[usr] looks up from the [src.name]" : "[usr] lowers the [src.name]"].")
return
-
-
+
/obj/item/proc/pwr_drain()
return 0 // Process Kill
/obj/item/proc/resolve_attackby(atom/A, mob/source)
return A.attackby(src,source)
+
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 91b19ae0879..60cf0474df1 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -341,9 +341,12 @@
if(!req_breakout())
return
+ if(!escapee.canClick())
+ return
+
+ escapee.setClickCooldown(100)
+
//okay, so the closet is either welded or locked... resist!!!
- escapee.next_move = world.time + 100
- escapee.last_special = world.time + 100
escapee << "You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)"
visible_message("The [src] begins to shake violently!")
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 149d6bf3941..e52db4f150d 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -30,6 +30,7 @@
/obj/structure/grille/attack_hand(mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
playsound(loc, 'sound/effects/grillehit.ogg', 80, 1)
user.do_attack_animation(src)
@@ -155,7 +156,8 @@
//window placing end
else if(!(W.flags & CONDUCT) || !shock(user, 70))
- user.do_attack_animation(src)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.do_attack_animation(src)
playsound(loc, 'sound/effects/grillehit.ogg', 80, 1)
switch(W.damtype)
if("fire")
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index b91f6bb6413..2bb2c29a390 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -171,6 +171,7 @@
playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1)
/obj/structure/window/attack_hand(mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(HULK in user.mutations)
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!"))
user.visible_message("[user] smashes through [src]!")
@@ -198,6 +199,7 @@
return
/obj/structure/window/attack_generic(var/mob/user, var/damage)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(!damage)
return
if(damage >= 10)
@@ -268,6 +270,7 @@
new glasstype(loc)
qdel(src)
else
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
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 5cc6ee92894..cd3397858b2 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -56,6 +56,7 @@
radiate()
add_fingerprint(user)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
var/rotting = (locate(/obj/effect/overlay/wallrot) in src)
if (HULK in user.mutations)
if (rotting || !prob(material.hardness))
@@ -69,6 +70,7 @@
/turf/simulated/wall/attack_generic(var/mob/user, var/damage, var/attack_message, var/wallbreaker)
radiate()
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
var/rotting = (locate(/obj/effect/overlay/wallrot) in src)
if(!damage || !wallbreaker)
try_touch(user, rotting)
@@ -86,6 +88,7 @@
/turf/simulated/wall/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if (!user.)
user << "You don't have the dexterity to do this!"
return
diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm
index 07d83e6f640..e8f2cfa9189 100644
--- a/code/modules/hydroponics/spreading/spreading.dm
+++ b/code/modules/hydroponics/spreading/spreading.dm
@@ -234,6 +234,7 @@
/obj/effect/plant/attackby(var/obj/item/weapon/W, var/mob/user)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
plant_controller.add_plant(src)
if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel))
diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm
index faf0e835516..4716a191b84 100644
--- a/code/modules/hydroponics/trays/tray.dm
+++ b/code/modules/hydroponics/trays/tray.dm
@@ -533,6 +533,7 @@
user << "You [anchored ? "wrench" : "unwrench"] \the [src]."
else if(O.force && seed)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
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/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 310225d7364..65d1f0fa898 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1311,9 +1311,10 @@
set desc = "Pop a joint back into place. Extremely painful."
set src in view(1)
- if(!isliving(usr) || usr.next_move > world.time)
+ if(!isliving(usr) || !usr.canClick())
return
- usr.next_move = world.time + 20
+
+ usr.setClickCooldown(20)
if(usr.stat > 0)
usr << "You are unconcious and cannot do that!"
diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm
index 51b39343eab..a5ad3f58450 100644
--- a/code/modules/mob/living/carbon/resist.dm
+++ b/code/modules/mob/living/carbon/resist.dm
@@ -27,10 +27,11 @@
spawn() escape_legcuffs()
/mob/living/carbon/proc/escape_handcuffs()
- if(!(last_special <= world.time)) return
+ //if(!(last_special <= world.time)) return
- next_move = world.time + 100
- last_special = world.time + 100
+ //These two lines represent a significant buff to grabs...
+ if(!canClick()) return
+ setClickCooldown(100)
if(can_break_cuffs()) //Don't want to do a lot of logic gating here.
break_handcuffs()
@@ -60,11 +61,11 @@
)
drop_from_inventory(handcuffed)
-/mob/living/carbon/proc/escape_legcuffs()
- if(!(last_special <= world.time)) return
+/mob/living/carbon/proc/escape_legcuffs()
+ if(!canClick())
+ return
- next_move = world.time + 100
- last_special = world.time + 100
+ setClickCooldown(100)
if(can_break_cuffs()) //Don't want to do a lot of logic gating here.
break_legcuffs()
@@ -149,14 +150,15 @@
return ..()
/mob/living/carbon/escape_buckle()
+ if(!canClick())
+ return
+
+ setClickCooldown(100)
if(!buckled) return
- if(!(last_special <= world.time)) return
if(!restrained())
..()
else
- next_move = world.time + 100
- last_special = world.time + 100
visible_message(
"[usr] attempts to unbuckle themself!",
"You attempt to unbuckle yourself. (This will take around 2 minutes and you need to stand still)"
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 632bd4dc737..c306bacdcde 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -574,7 +574,7 @@ default behaviour is:
set category = "IC"
if(can_resist())
- next_move = world.time + 20
+ setClickCooldown(20)
process_resist()
/mob/living/proc/can_resist()
@@ -582,7 +582,7 @@ default behaviour is:
//so just check weakened instead.
if(stat || weakened)
return 0
- if(next_move > world.time)
+ if(!canClick())
return 0
return 1
diff --git a/code/modules/mob/living/simple_animal/borer/borer_captive.dm b/code/modules/mob/living/simple_animal/borer/borer_captive.dm
index c0b2999b2fe..e666f7ac716 100644
--- a/code/modules/mob/living/simple_animal/borer/borer_captive.dm
+++ b/code/modules/mob/living/simple_animal/borer/borer_captive.dm
@@ -35,7 +35,7 @@
return
/mob/living/captive_brain/can_resist()
- return !(stat || next_move > world.time)
+ return !(stat || !canClick())
/mob/living/captive_brain/process_resist()
//Resisting control by an alien mind.
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 0eb187213df..82cd1683ccf 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -269,7 +269,6 @@
/mob/living/simple_animal/attackby(var/obj/item/O, var/mob/user)
if(istype(O, /obj/item/stack/medical))
- user.changeNext_move(4)
if(stat != DEAD)
var/obj/item/stack/medical/MED = O
if(health < maxHealth)
@@ -286,12 +285,12 @@
if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead.
if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch))
harvest(user)
- else
+ else
attacked_with_item(O, user)
//TODO: refactor mob attackby(), attacked_by(), and friends.
/mob/living/simple_animal/proc/attacked_with_item(var/obj/item/O, var/mob/user)
- user.changeNext_move(8)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(!O.force)
visible_message("[user] gently taps [src] with \the [O].")
return
@@ -308,7 +307,7 @@
usr << "This weapon is ineffective, it does no damage."
visible_message("\The [src] has been attacked with \the [O] by [user].")
- user.do_attack_animation(src)
+ user.do_attack_animation(src)
/mob/living/simple_animal/movement_delay()
var/tally = 0 //Incase I need to add stuff other than "speed" later
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index e08fb82fb85..43269113d9d 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -277,8 +277,6 @@
if (W)
W.attack_self(src)
update_inv_r_hand()
- if(next_move < world.time)
- next_move = world.time + 2
return
/*
@@ -886,9 +884,9 @@ mob/proc/yank_out_object()
set desc = "Remove an embedded item at the cost of bleeding and pain."
set src in view(1)
- if(!isliving(usr) || usr.next_move > world.time)
+ if(!isliving(usr) || !usr.canClick())
return
- usr.next_move = world.time + 20
+ usr.setClickCooldown(20)
if(usr.stat == 1)
usr << "You are unconcious and cannot do that!"
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
index f179920e3d6..8960d5128e3 100644
--- a/code/modules/mob/mob_grab.dm
+++ b/code/modules/mob/mob_grab.dm
@@ -209,7 +209,7 @@
return
if(state == GRAB_UPGRADING)
return
- if(assailant.next_move > world.time)
+ if(!assailant.canClick())
return
if(world.time < (last_action + UPGRADE_COOLDOWN))
return
@@ -250,7 +250,7 @@
hud.name = "kill"
affecting.Stun(10) //10 ticks of ensured grab
else if(state < GRAB_UPGRADING)
- assailant.visible_message("[assailant] starts to tighten \his grip on [affecting]'s neck!")
+ assailant.visible_message("[assailant] starts to tighten \his grip on [affecting]'s neck!")
hud.icon_state = "kill1"
state = GRAB_KILL
@@ -259,10 +259,10 @@
assailant.attack_log += "\[[time_stamp()]\] Strangled (kill intent) [affecting.name] ([affecting.ckey])"
msg_admin_attack("[key_name(assailant)] strangled (kill intent) [key_name(affecting)]")
- assailant.next_move = world.time + 10
+ affecting.setClickCooldown(10)
affecting.losebreath += 1
affecting.set_dir(WEST)
- adjust_position()
+ adjust_position()
//This is used to make sure the victim hasn't managed to yackety sax away before using the grab.
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 9dc893a286c..8f0c90062b3 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -10,6 +10,9 @@
return (!mover.density || !density || lying)
return
+/mob/proc/setMoveCooldown(var/timeout)
+ if(client)
+ client.move_delay = max(world.time + timeout, client.move_delay)
/client/North()
..()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 1d1b905c456..87689d99691 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -151,10 +151,10 @@
if (world.time % 3) //to prevent spam
user << "[src] is not ready to fire again!"
return
-
+
var/shoot_time = (burst - 1)* burst_delay
- user.next_move = world.time + shoot_time //no clicking on things while shooting
- if(user.client) user.client.move_delay = world.time + shoot_time //no moving while shooting either
+ user.setClickCooldown(shoot_time) //no clicking on things while shooting
+ user.setMoveCooldown(shoot_time) //no moving while shooting either
next_fire_time = world.time + shoot_time
//actually attempt to shoot
@@ -186,9 +186,9 @@
update_held_icon()
//update timing
- user.next_move = world.time + 4
- if(user.client) user.client.move_delay = world.time + move_delay
- next_fire_time = world.time + fire_delay
+ user.setClickCooldown(4)
+ user.setMoveCooldown(move_delay)
+ next_fire_time = world.time + fire_delay
if(muzzle_flash)
set_light(0)
diff --git a/code/modules/projectiles/guns/launcher/rocket.dm b/code/modules/projectiles/guns/launcher/rocket.dm
index 9747922caf2..12338ee5c34 100644
--- a/code/modules/projectiles/guns/launcher/rocket.dm
+++ b/code/modules/projectiles/guns/launcher/rocket.dm
@@ -7,7 +7,7 @@
throw_speed = 2
throw_range = 10
force = 5.0
- flags = CONDUCT | USEDELAY
+ flags = CONDUCT
slot_flags = 0
origin_tech = list(TECH_COMBAT = 8, TECH_MATERIAL = 5)
fire_sound = 'sound/effects/bang.ogg'
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index 339722fee3d..15059ee327f 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -40,6 +40,8 @@
playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
+ user.setClickCooldown(4)
+
if(reagents.has_reagent("sacid"))
message_admins("[key_name_admin(user)] fired sulphuric acid from \a [src].")
log_game("[key_name(user)] fired sulphuric acid from \a [src].")
diff --git a/html/changelogs/Kelenius-ofClicksAndCooldowns.yml b/html/changelogs/Kelenius-ofClicksAndCooldowns.yml
new file mode 100644
index 00000000000..a6768a8573e
--- /dev/null
+++ b/html/changelogs/Kelenius-ofClicksAndCooldowns.yml
@@ -0,0 +1,6 @@
+author: Kelenius
+
+delete-after: True
+
+changes:
+ - experiment: "Click cooldowns have been removed on pretty much everything that isn't an attack."