From 4b19e5863e78df7137d189830396743735b91cab Mon Sep 17 00:00:00 2001 From: L Date: Sat, 30 May 2020 06:16:34 -0300 Subject: [PATCH 1/2] cooldown --- code/__DEFINES/cooldowns.dm | 16 ++++++++++++++++ code/datums/datum.dm | 10 ++++++++++ code/modules/paperwork/filingcabinet.dm | 20 +++++++++----------- tgstation.dme | 1 + 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 code/__DEFINES/cooldowns.dm diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm new file mode 100644 index 0000000000..44aaf4bb95 --- /dev/null +++ b/code/__DEFINES/cooldowns.dm @@ -0,0 +1,16 @@ +/* + * Cooldown system based on an datum-level associative lazylist using timers. + * If you are running hot procs that require high performance, checking world.time directly through a variable will always be faster. + * If you are not, then this should be fine to use, it's not very expensive. + * If you want a stoppable timer either make new macros or use a different system. Do not make every timer stoppable, that increases performance cost. +*/ + +//INDEXES +#define COOLDOWN_EMPLOYMENT_CABINET "employment cabinet" + +//MACROS +#define COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, /proc/end_cooldown, cd_source, cd_index), cd_time)) + +#define COOLDOWN_CHECK(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index) + +#define COOLDOWN_END(cd_source, cd_index) LAZYREMOVE(cd_source.cooldowns, cd_index) diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 6202ac444e..20802ba01a 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -39,6 +39,9 @@ /// A weak reference to another datum var/datum/weakref/weak_reference + ///Lazy associative list of currently active cooldowns. + var/list/cooldowns + #ifdef TESTING var/running_find_references var/last_find_references = 0 @@ -201,3 +204,10 @@ qdel(D) else return returned + + +///Callback called by a timer to end an associative-list-indexed cooldown. +/proc/end_cooldown(datum/source, index) + if(QDELETED(source)) + return + COOLDOWN_END(source, index) diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 5e882eb8d0..95d4bbacaa 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -186,9 +186,8 @@ GLOBAL_LIST_EMPTY(employmentCabinets) /obj/structure/filingcabinet/employment - var/cooldown = 0 icon_state = "employmentcabinet" - var/virgin = 1 + var/virgin = TRUE /obj/structure/filingcabinet/employment/Initialize() . = ..() @@ -213,13 +212,12 @@ GLOBAL_LIST_EMPTY(employmentCabinets) new /obj/item/paper/contract/employment(src, employee) /obj/structure/filingcabinet/employment/interact(mob/user) - if(!cooldown) - if(virgin) - fillCurrent() - virgin = 0 - cooldown = 1 - sleep(100) // prevents the devil from just instantly emptying the cabinet, ensuring an easy win. - cooldown = 0 - else + if(COOLDOWN_CHECK(src, COOLDOWN_EMPLOYMENT_CABINET)) to_chat(user, "[src] is jammed, give it a few seconds.") - ..() + return ..() + + COOLDOWN_START(src, COOLDOWN_EMPLOYMENT_CABINET, 10 SECONDS) // prevents the devil from just instantly emptying the cabinet, ensuring an easy win. + if(virgin) + fillCurrent() + virgin = FALSE + return ..() diff --git a/tgstation.dme b/tgstation.dme index b6bf5b4ea8..ef022c429b 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -38,6 +38,7 @@ #include "code\__DEFINES\configuration.dm" #include "code\__DEFINES\construction.dm" #include "code\__DEFINES\contracts.dm" +#include "code\__DEFINES\cooldowns.dm" #include "code\__DEFINES\cult.dm" #include "code\__DEFINES\diseases.dm" #include "code\__DEFINES\DNA.dm" From 3aefc8ae10b520b0f7c006b9ddba297a04eaf4eb Mon Sep 17 00:00:00 2001 From: L Date: Sat, 27 Jun 2020 07:01:19 -0300 Subject: [PATCH 2/2] tg changes --- code/__DEFINES/cooldowns.dm | 69 ++++++++++++++++++++++--- code/datums/datum.dm | 30 +++++++++-- code/modules/paperwork/filingcabinet.dm | 4 +- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm index 44aaf4bb95..29c7a25dad 100644 --- a/code/__DEFINES/cooldowns.dm +++ b/code/__DEFINES/cooldowns.dm @@ -1,16 +1,71 @@ +//// COOLDOWN SYSTEMS +/* + * We have 2 cooldown systems: timer cooldowns (divided between stoppable and regular) and world.time cooldowns. + * + * When to use each? + * + * * Adding a commonly-checked cooldown, like on a subsystem to check for processing + * * * Use the world.time ones, as they are cheaper. + * + * * Adding a rarely-used one for special situations, such as giving an uncommon item a cooldown on a target. + * * * Timer cooldown, as adding a new variable on each mob to track the cooldown of said uncommon item is going too far. + * + * * Triggering events at the end of a cooldown. + * * * Timer cooldown, registering to its signal. + * + * * Being able to check how long left for the cooldown to end. + * * * Either world.time or stoppable timer cooldowns, depending on the other factors. Regular timer cooldowns do not support this. + * + * * Being able to stop the timer before it ends. + * * * Either world.time or stoppable timer cooldowns, depending on the other factors. Regular timer cooldowns do not support this. +*/ + + /* * Cooldown system based on an datum-level associative lazylist using timers. - * If you are running hot procs that require high performance, checking world.time directly through a variable will always be faster. - * If you are not, then this should be fine to use, it's not very expensive. - * If you want a stoppable timer either make new macros or use a different system. Do not make every timer stoppable, that increases performance cost. */ //INDEXES #define COOLDOWN_EMPLOYMENT_CABINET "employment cabinet" -//MACROS -#define COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, /proc/end_cooldown, cd_source, cd_index), cd_time)) -#define COOLDOWN_CHECK(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index) +//TIMER COOLDOWN MACROS -#define COOLDOWN_END(cd_source, cd_index) LAZYREMOVE(cd_source.cooldowns, cd_index) +#define COMSIG_CD_STOP(cd_index) "cooldown_[cd_index]" +#define COMSIG_CD_RESET(cd_index) "cd_reset_[cd_index]" + +#define TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, /proc/end_cooldown, cd_source, cd_index), cd_time)) + +#define TIMER_COOLDOWN_CHECK(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index) + +#define TIMER_COOLDOWN_END(cd_source, cd_index) LAZYREMOVE(cd_source.cooldowns, cd_index) + +/* + * Stoppable timer cooldowns. + * Use indexes the same as the regular tiemr cooldowns. + * They make use of the TIMER_COOLDOWN_CHECK() and TIMER_COOLDOWN_END() macros the same, just not the TIMER_COOLDOWN_START() one. + * A bit more expensive than the regular timers, but can be reset before they end and the time left can be checked. +*/ + +#define S_TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, /proc/end_cooldown, cd_source, cd_index), cd_time, TIMER_STOPPABLE)) + +#define S_TIMER_COOLDOWN_RESET(cd_source, cd_index) reset_cooldown(cd_source, cd_index) + +#define S_TIMER_COOLDOWN_TIMELEFT(cd_source, cd_index) (timeleft(TIMER_COOLDOWN_CHECK(cd_source, cd_index))) + + +/* + * Cooldown system based on storing world.time on a variable, plus the cooldown time. + * Better performance over timer cooldowns, lower control. Same functionality. +*/ + +#define COOLDOWN_DECLARE(cd_index) var/##cd_index = 0 + +#define COOLDOWN_START(cd_source, cd_index, cd_time) (cd_source.cd_index = world.time + cd_time) + +//Returns true if the cooldown has run its course, false otherwise +#define COOLDOWN_FINISHED(cd_source, cd_index) (cd_source.cd_index < world.time) + +#define COOLDOWN_RESET(cd_source, cd_index) cd_source.cd_index = 0 + +#define COOLDOWN_TIMELEFT(cd_source, cd_index) (max(0, cd_source.cd_index - world.time)) diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 20802ba01a..7756cfd906 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -205,9 +205,33 @@ else return returned - -///Callback called by a timer to end an associative-list-indexed cooldown. +/** + * Callback called by a timer to end an associative-list-indexed cooldown. + * + * Arguments: + * * source - datum storing the cooldown + * * index - string index storing the cooldown on the cooldowns associative list + * + * This sends a signal reporting the cooldown end. + */ /proc/end_cooldown(datum/source, index) if(QDELETED(source)) return - COOLDOWN_END(source, index) + SEND_SIGNAL(source, COMSIG_CD_STOP(index)) + TIMER_COOLDOWN_END(source, index) + + +/** + * Proc used by stoppable timers to end a cooldown before the time has ran out. + * + * Arguments: + * * source - datum storing the cooldown + * * index - string index storing the cooldown on the cooldowns associative list + * + * This sends a signal reporting the cooldown end, passing the time left as an argument. + */ +/proc/reset_cooldown(datum/source, index) + if(QDELETED(source)) + return + SEND_SIGNAL(source, COMSIG_CD_RESET(index), S_TIMER_COOLDOWN_TIMELEFT(source, index)) + TIMER_COOLDOWN_END(source, index) diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 95d4bbacaa..b368589bc3 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -212,11 +212,11 @@ GLOBAL_LIST_EMPTY(employmentCabinets) new /obj/item/paper/contract/employment(src, employee) /obj/structure/filingcabinet/employment/interact(mob/user) - if(COOLDOWN_CHECK(src, COOLDOWN_EMPLOYMENT_CABINET)) + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_EMPLOYMENT_CABINET)) to_chat(user, "[src] is jammed, give it a few seconds.") return ..() - COOLDOWN_START(src, COOLDOWN_EMPLOYMENT_CABINET, 10 SECONDS) // prevents the devil from just instantly emptying the cabinet, ensuring an easy win. + TIMER_COOLDOWN_START(src, COOLDOWN_EMPLOYMENT_CABINET, 10 SECONDS) // prevents the devil from just instantly emptying the cabinet, ensuring an easy win. if(virgin) fillCurrent() virgin = FALSE