ID:266033
 
Run System: When you walk (hold the arrow key buttons down) for 4 seconds straight you should start running. Once your running if you let go for more then 4 seconds you should exit run mode.

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:
Image and video hosting by TinyPic

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?
My EventScheduler library happens to play quite well here:

Event/RunEvent
var/RunState/run_state

New(var/RunState/run_state)
src.run_state = run_state

Event/RunEvent/Run
New(var/RunState/run_state)
..(run_state)

fire()
run_state.make_run()

Event/RunEvent/CancelRun
New(var/RunState/run_state)
..(run_state)

fire()
run_state.cancel_run()

Event/RunEvent/Walk
New(var/RunState/run_state)
..(run_state)

fire()
run_state.make_walk()

RunState
var/client/client
var/Event/RunEvent/CancelRun/cancel_run
var/Event/RunEvent/Run/make_run
var/Event/RunEvent/Walk/make_walk
var/make_run_scheduled = 0
var/running = 0

New(var/client/C)
client = C
cancel_run = new(src)
make_run = new(src)
make_walk = new(src)

proc
cancel_run()
reset_state(0)
client << "Stopped running attempt"

make_run()
reset_state(1)
client << "Now running"

make_walk()
reset_state(0)
client << "Now walking"

moved()
if (!running)
if(!make_run_scheduled)
client << "Started running attempt"
run_scheduler.schedule(make_run, 40)
make_run_scheduled = 1
run_scheduler.reschedule(cancel_run, 5)
else
run_scheduler.reschedule(make_walk, 40)

reset_state(var/running)
run_scheduler.cancel(make_run)
run_scheduler.cancel(cancel_run)
run_scheduler.cancel(make_walk)
make_run_scheduled = 0
src.running = running


client
var/RunState/run_state

New()
..()
run_state = new(src)

Move()
src.run_state.moved()
if (!src.run_state.running)
sleep(3)
..()

var/EventScheduler/run_scheduler = new()

world
New()
..()
run_scheduler.start()


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.