ID:793976
 
(See the best response by Forum_account.)
Hello Can anyone give me an example of what should I use to add some cooldown to the techniques/attack on a demo I'm making?
A quick example that I'm writing in browser:

Cooldowns
//A datum will hold the list. This makes expanding things simpler.

var/list/cooldowns = list()
//The list of cooldowns currently in effect.

proc/Timer()
while(1)
for(var/x in cooldowns)
if(x!>0) continue
x--
sleep(10)

//This will loop through every entry in cooldowns, reducing
//anything that is greater than 0 by 1 second.

proc/AddCD(skill as text, length as num)
cooldowns[skill] = length
//Here we pass in the skill name and length of cooldown.
//It's added as an entry in cooldowns, with the length
//being the associated value.

mob
var/tmp/Cooldowns/Cooldowns
//Setting the var to hold the datum. tmp prevents it from
//being saved to avoid potential issues. There are pros
//and cons to having it, it's up to you whether you want
//your cooldowns to reset on login.

New()
..()
Cooldowns = new /Cooldowns
//Create the datum. If you don't want them to reset on
//login, just check to see if it exists first.

verb/Skill()
if(usr.Cooldowns.cooldowns["Skill"]>0) return
usr.Cooldowns.AddCD("Skill", 30)
//Here, we simply return if the skill's entry in cooldowns
//has a value greater than 0. You could also just check
//whether or not the value is 0 or not, but that opens you
//up to potential issues with skills/effects that reduce
//debuff times making things unusable.


Hopefully I didn't butcher that, I didn't test anything in the compiler, but that's about how you want to handle it.

You could use a list in the mob as well, but getting used to using datums for this kind of thing is pretty helpful, and you would probably use a datum to handle all of your timed effects like debuffs, buffs, cooldowns, quest time limits, etc anyway, so having it in place could save you time and effort later on.
whats the x for? sorry for the question don't know what it is and got undefined var
It's a counter. Just define it and it should work fine.
for(var/x in cooldowns)

It just tells for() to search every entry in cooldowns, and that you'll be referencing it somewhere in the loop. You might need to change x-- and if(!x) to cooldowns[x]-- and if(!cooldowns[x]), but my sleep deprived brain didn't consider it last night.
mob
verb
Attack()
for(var/mob/M in get_step(src,dir))
set category = "Taijutsu"
if(usr.Cooldowns.cooldowns["Attack"]>0) return
if(M==src) continue
damage(usr,M)
flick("punch",usr)
var/damage = usr.Taijutsu
M.Stamina -= damage
usr << "<b>You attack [M] by [damage]!</b>"
oview() << "[usr] attacks [M] by [damage]!"
usr.Cooldowns.AddCD("Attack", 10)


No errors but if i add the last line I can only use the verb once anyone know whats causing this or what should i do?
You need to spawn()-off the Timer() process in Cooldowns/New(), otherwise they never decrease.

Also, if(x!>0) should probably be if(x<=0) (although it seems silly to use continue to skip one line, I would've just reversed it).

Don't forget the fixes Robertbanks2 mentioned in post #4 (made my second comment irrelevant)
He does, but the issue at hand is that it wasn't meant to be copy pasted in. He shouldn't have TRIED to copy paste it in(which he obviously did). Andy, I suggest you try actually looking through the code to understand the logic behind it, rather than just mashing it into your game and hoping that everything works.

AFAIK, there's no difference in efficiency between using continue and just putting everything under the if(), so it's just a matter of preference. I like it that way because it helps prevent over-indentation when you need to add a bunch of things without having a ridiculously long if() check.

Also, I'm not really sure why I thought if(x!>0) would work at the time. I should probably stop answering questions at 3am.
Best response
Here's some code I wrote last night for the Action RPG Framework to handle cooldowns. It's a slightly different approach:

mob
var
list/cooldowns

proc
// triggers a cooldown or refreshes one that's still active
cooldown(cooldown_name, cooldown_duration)

if(!cooldowns)
cooldowns = list()

if(cooldowns[cooldown_name])
cooldowns[cooldown_name] = max(cooldowns[cooldown_name], world.time + cooldown_duration * world.tick_lag)
else
cooldowns[cooldown_name] = world.time + cooldown_duration * world.tick_lag

// each parameter is the name of a cooldown to check, this
// proc returns 1 if any of the names are still on cooldown
on_cooldown()

if(!cooldowns)
cooldowns = list()

for(var/a in args)
if(a in cooldowns)
if(cooldowns[a] > world.time)
return 1

return 0

You'd do something like this to use it:

mob
proc
attack()
// if the ability is on cooldown still, do nothing
if(on_cooldown("attack"))
return

// trigger a 20-tick cooldown
cooldown("attack", 20)

// do the attack...

Instead of having a periodic event to reduce the remaining time for each cooldown, this just remembers the time when each cooldown will stop. It's not necessarily better (though it's quite limiting to only allow whole second cooldowns), though if you don't need to have a periodic event it's best to avoid it.
In response to Forum_account
I'm not sure if there's much of a difference in efficiency, but on_cooldown() can probably just return if cooldowns[] is null or empty.
In response to Forum_account
Awesome. I didn't even know you could manipulate world.time like that, or that you could reference arguments that weren't specifically defined. The more you know.
In response to Kaiochao
Kaiochao wrote:
I'm not sure if there's much of a difference in efficiency, but on_cooldown() can probably just return if cooldowns[] is null or empty.

It doesn't remove entries from the list after the cooldown has expired. It just always checks the time.
In response to Forum_account
Haha, sorry! I completely forgot why I referred you to that design.
wow thanks everyone