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."