Issue: 95% of it works, but hardly. The condition "if(moving == 1)" does not work, if it is true it will exit release() without allowing the next release() cycle to start. Probably because queue order is getting rearranged [release() is being called before Moving is set to 1]).
Diagram:

Code:
clock
var/timer = 0
var/mob/player/m
New(sponser)
m = sponser
m.moving = 0
proc
refresh()
timer = 0
cooldown()
while( timer > 0 )
sleep(10)
timer--
world << output("[timer]", "output")
increment()
// sleep(10)
timer++
world << output("<b>[timer]</b>", "output")
mob/player
icon ='base.dmi'
New()
.=..()
var
moving = 0
last_dir
clock/run_ready
clock/standing
reset_in_process = FALSE
release_in_process = FALSE
const
STATE_NORMAL = 16
STATE_RUNNING = 32
state = STATE_NORMAL
verb
release()
if( state == STATE_NORMAL ) return
if( release_in_process == FALSE )
release_in_process = TRUE
world << output("<font color = red> NEW RELEASE ", "output")
if( standing == null ) standing = new(src)
standing.refresh()
for( var/i = 0; i<=4 ; i++ )
world << output("<font color = red>loop [i]", "output")
if( moving == 1 ) // <--this part is the only condition that doesn't work.
world << output("<font color = red>moving = 1", "output")
del standing
release_in_process = FALSE
return
standing.timer++ ;; sleep (10)
world << output("<b><font color = red>[standing.timer]</b>", "output")
if ( standing.timer >= 4 )
deactivate_run()
standing.refresh()
del standing
release_in_process = FALSE
break
release_in_process = FALSE
else
world << output("<font color = red>release rejected", "output")
proc
activate_run()
state = STATE_RUNNING
icon_state = "run"
world << output("run!", "output")
deactivate_run()
state = STATE_NORMAL
icon_state = ""
world << output("stop run!", "output")
run_walk(var/dir)
if(run_ready == null ) run_ready = new(src)
if( run_ready.timer == 0 )
run_ready.increment()
run_ready.cooldown()
else if( dir == last_dir)
run_ready.increment()
if( run_ready.timer >= 6 )
activate_run()
run_ready.refresh()
else
run_ready.refresh()
last_dir = dir
reset_movement()
reset_in_process = TRUE
sleep(20)
if (moving == 1)
moving = 0
world << output("<font color = blue> [moving]", "output")
reset_in_process = FALSE
Move()
if(..())
moving = 1
world << output("<font color = blue> [moving]", "output")
if( state == STATE_NORMAL )
run_walk(dir)
if( reset_in_process == FALSE)
reset_movement()
Thoughts:
I feel I've gotta be doing something wrong -_-. Or atleast extremely ugly, rofl. I also feel a lot of those vars keeping tracks of processes may be unnecessary?
As it happens, I haven't implemented all of your logic here, just a sample handling that transition between walking and running after 4 seconds of movement, and running to walking after 4 seconds of inactivity. In my case, the difference between running and walking is a 0.3 second delay.
Principally speaking, RunState doesn't need to hold a reference to the client it operates on, it should be independent of that information. I just fed it in to provide a little print-out.
The basic premise is you schedule events for some point in the future (like spawn), but you can also cancel them before they happen.
So when someone first moves, we schedule a "run" event for them, 4 seconds in the future. Assuming nothing interferes with that, they'll start running in 4 seconds time.
We also schedule another event, every time they move, "cancel run", for 0.5 seconds time. When that fires, it simply cancels the "run" event. If they moved less than 0.5 seconds ago, we re-schedule it for 0.5 seconds in the future. This kind of acts like an activity timer, to ensure they are pretty constantly pressing movement keys. If they stop before that 4 seconds is up, this will make sure they don't enter running state.
Okay, so they have been pressing it, and "run" fires. It sets the running state, and cancels the "cancel run" event, to make sure we don't accidentally reset ourselves.
Walking is comparatively easier, we just schedule a "walk" event for 4 seconds in the future. If they move again before then, we re-schedule it, moving the time it'll fire. If they don't move in 4 seconds? Event fires, walking state is restored.
The using client can simply check run_state.running as appropriate, and Move() triggers the moved() logic in run_state. All run_state logic and events are well contained, and well defined.
What do you think?
If you are worried about the library performance, Valekor used the library to good effect, altering Dragonball Phoenix's internals and going from 60 players at max CPU, to 110 players at 60% CPU, on the same machine. So it really works, if you use it well.