ID:154749
 
After having messed around with my roguelike, I ran into the issue that turns are really basic.

var
turn = 0

proc
take_turn(mob/m)
turn++

var
ai_distance = world.view * 2

for(var/mob/o in orange(ai_distance, m))
o.ai()

mob
animate_movement = NO_STEPS

proc
ai()

player
text = "@"

Move()
. = ..()

take_turn(src)

enemy
ai()
// do targeting/movement/etc


This works fine but I realized that later on I would want to be able to allow players and enemies to go multiple (or possibly less) times per "turn". I'm not entirely sure how to go about setting such a system up.
One mechanism is for creatures to have a 'speed' stat, and an internal tick value. Then, every time something takes a turn, you go through everything that could be taking a turn, subtracting its speed value from its internal tick count. Internal tick count < 0? Take a turn, add some standard delay to internal tick count.

So say the standard delay is 1000, the player has speed 250, a bat has speed 500, and a slime has speed 100. Everybody starts at delay 1000. We'll say ties are broken in speed order, but any deterministic mechanism will do. You'll see the following turns:

Bat
Bat
Player
Bat
Bat
Player
Bat
Slime
Bat
Player

So the bat acts really often, the slime barely gets a look in, and the player is in the middle. 'haste' and 'slow' style spells work by changing the speed stat, as do magic items that make you faster.

My 2011 GIAD entry, Mirage Arcana, implements something like that, and the code is available, though hacky, if you'd like to see it in action.
In response to Jp
I managed to make monsters move at different rates using what you described. I also had a look at Mirage Arcana (neat game by the way! :P) but I don't quite get how to make the player get multiple turns.

mob
icon = 'players.dmi'

animate_movement = NO_STEPS

var
speed = 100
turn_count = 1000

proc
take_turn()
world << "\red [src] moves"

move_rand()

Bump(mob/m)
if(istype(m))
world << "\magenta [src] bumps [m]"

/*============================================================*/

mob
player
icon_state = "human"

Move()
. = ..()

world << "--------------------------------------------------------------------------"

world << "\blue [src] moves"

next_turn(src)

Stat()
for(var/mob/enemy/m in world)
stat("[m]", "speed: [m.speed], turn_count: [m.turn_count]")

/*============================================================*/

mob
enemy
rat
icon_state = "rat"

speed = 5000 // super quick rat

giant_rat
icon_state = "giant_rat"

speed = 500

turtle
icon_state = "turtle"

speed = 100

/*============================================================*/

world
view = 7

icon_size = 16

mob = /mob/player

proc
next_turn(mob/m)
var
ai_dist = world.view * 2

for(var/mob/enemy/o in orange(ai_dist, m))
o.turn_count -= o.speed

while(o.turn_count <= 0)
o.take_turn()

o.turn_count += 1000