ID:267794
 
I was thinking if every "player mob" had a timer on him for whenever he was upgrading something about himself, would it lag the game? If you used spawn() like so...

proc/timer()
spawn(10)
src.timer-=1
src.timer()
return

what would be the most efficient way of doing this? Or would having a timer at all be a bad idea?
should I just do this?

proc/timer()
spawn(1000)
//do normal stuff here


say like I put in the variable change in stat...

Stat()
src.timer-=1

would stat update every tick? Hmm...
Jon Snow wrote:
say like I put in the variable change in stat...

Stat()
src.timer-=1

would stat update every tick? Hmm...

I'm no lag expert so I can't really answer your first part, but with the Stat() stuff it won't update every tick.
Stat() works like any other proc. It starts, then does all the stuff, then it starts again. So Stat() will update every [time it takes to complete Stat()].
Timers are fine if you need them, but spawn() is usually a better alternative, if it's possible to use it how you want it.
Yes and no. The other answers in this post are good ones, I'm simply going to elaborate a little on what causes lag during a process like yours.

It's almost always less laggy if you have ONE timer proc going that calls other procs periodically than if you leave it the atoms themselves. Let's say I have 10 mobs, and each mob calls and update() proc every 10 seconds. That's 10 procs going at relatively the same time. If, instead, you have a global timer() proc that, every 10 seconds, loops through all the mobs and calls their update() procs. The first mob in the list has it's proc called. The second mob will NOT call it's update proc until the first one is done (has returned).

It's a slight difference, but can make all the difference. Try it yourself. Have a statpanel that displays world.cpu. Then have the mobs take care of themselves, and then try it with a global proc.
Having a continuously updating timer for each mob would be a drain, yes. This is generally the wrong way to implement a timer.

The right way is to keep track of the start time, then periodically check on it and compare it to current time. You can easily spawn() a call to a proc that checks on it when the timer is expected to elapse--and if it's been paused or changed by the time the proc is called, it can just spawn() again based on a new estimate of when time will elapse.

If every mob in the game has this kind of timer, then you're probably better off having a global proc to keep track of them all. It can decide who's likely to go off first, and spawn() itself for the next trigger event.

As an example of a good way to implement timers, here's a snippet of code I'm using in Incursion for the decision timers.
timer
var/triggered=0
var/startvalue
var/timestarted
var/player/owner
var/theobject
var/theproc
var/list/callargs
var/obj/hourglass/hourglass
var/pausetime=0
var/hidden=0

// in _time ticks, this timer for player P will call
// _object._proc(_args) to perform some action
New(_time,player/P,_object,_proc,_args)
startvalue=_time
timestarted=world.time
owner=P
theobject=_object
theproc=_proc
callargs=_args
// create the player's list of active timers if there isn't a list yet
if(!P.timers) P.timers=list()
hourglass=new(src)
P.timers+=src
// timers may be paused; gamepaused is a global var
if(gamepaused) pausetime=world.time
spawn(_time) Trigger()

// break all ties so the garbage collector will take this
// but don't delete immediately because something may still be using it
proc/PreDel()
if(owner && owner.timers) owner.timers-=src
if(hourglass) del(hourglass)

Del()
PreDel()
..()

proc/Hide()
if(hourglass) hourglass.Hide()
hidden=1

proc/Show()
if(hourglass) hourglass.Show()
hidden=0

proc/TimeLeft()
return max(startvalue+timestarted-(pausetime?(pausetime):world.time),0)

// cut the elapsed time by half
proc/HalfReset()
var/elapsed=(pausetime?(pausetime):world.time)-timestarted
var/timeleft=startvalue-elapsed
timeleft+=round(elapsed/2)
timestarted=(pausetime?(pausetime):world.time)+timeleft-startvalue
if(hourglass)
del(hourglass)
hourglass=new(src)

// completely reset
proc/Reset()
timestarted=(pausetime?(pausetime):world.time)
if(hourglass)
del(hourglass)
hourglass=new(src)

// this proc checks if it's time to trigger, and if so, it does;
// otherwise it spawns itself
proc/Trigger()
if(triggered) return
if(!owner || !theobject)
PreDel()
return
var/timeleft=TimeLeft()
if(timeleft>0)
// spawn again in at least a second; this timer needn't be exact
spawn(pausetime?max(timeleft,10):timeleft) Trigger()
return
triggered=1
call(theobject,theproc)(callargs)
/* This is a recent change; the next line used to be del(src),
but that screws with the call above. If the above proc
does any spawning, the deletion of this datum could cascade
and prematurely end the proc. */

// remove some references so the garbage collector can take this when finished
PreDel()

proc/Pause()
if(!pausetime) pausetime=world.time
Hide()

proc/Unpause()
timestarted+=world.time-pausetime
pausetime=0
Show()
The PreDel() thing I only just put in. It occurs to me now that premature timer deletion could explain some of the more arcane bugs that have cropped up in the past--or at least, it can't be doing any good.

Lummox JR