Roguelike turns

So, I’ve been making a roguelike for a while, and I’ve just recently started thinking about the turn system. Right now, I have a very simple system. Every entity has a step() method. Every time a key is pressed, first the player’s step method is called, then I loop through the enemies and npc’s and call their step methods. This has worked fine so far, but it’s a bit limited.

For example: Let’s say we want the player to fire an arrow, and then every other entity waits until the arrow has hit something. This would not work with my system, because the enemies step right after the player steps. The other entities would step right as the arrow is fired, instead of waiting for it to hit something.

So, does anyone know of a method for timing a roguelike that is better than mine, but not too complex? Thanks!

I have all creatures return an Action that then get’s processed. Only once it’s done does that creature’s turn finish and I begin the next one. Something like:


interface Creature
{
  public Action takeTurn();
}

interface Action
{
  public void update();
  public boolean isFinished();
}

class Map
{
  public void update()
  {
    switch (state)
    {
      TAKE_TURN:
         action = creature.takeTurn()
      PERFORM_ACTION:
         action.update();
         if action.isFinished()
           creature = getNextCreature()
           state = TAKE_TURN
     }
  }

One of the nice things is that most of the logic goes in the action, so it can be shared between player, npc and enemies easily. Shooting an arrow would be in a ShootArrowAction, and once it’s created it works the same regardless of who actually shot it.

I’m not sure why the firing action isn’t resolved in the player’s step()? Is the arrow a separate entity? If so, then you probably need to prioritize the arrow’s step() before anyone else. If you want to animate the arrow in steps, you should think of animation steps as separate from the simulation steps.

I’ve adapted the following for use in my roguelike and am liking it quite a bit: http://roguebasin.roguelikedevelopment.org/index.php/A_simple_turn_scheduling_system_--_Python_implementation

It essentially keeps a list of which events occur on each tick. When advanceTime() is called (For example, when the player moves, he might call advanceTime(5)), it cycles through each tick and calls whatever AI or Events need updating until it reaches the new tick. Unfortunately I need to leave for class now, but this should hopefully help point you in the right direction when creating your system.

I’m sure that there’s improvements to be made here, as I’ve only been learning Java for a couple of months now, so just remember that this is probably not as well written as it could be.

package net.krazyweb.dungeoncrawler;

import java.util.ArrayList;
import java.util.HashMap;

import net.krazyweb.dungeoncrawler.entity.LivingEntity;
import net.krazyweb.dungeoncrawler.entity.livingentities.Player;
import net.krazyweb.dungeoncrawler.event.Event;

public class Ticker {
	
	private long ticks;
	
	private HashMap<Long, ArrayList<LivingEntity>> schedule;
	private HashMap<Long, ArrayList<Event>> eventSchedule;
	
	public Ticker(long ticks) {
		this.ticks = ticks;
		this.schedule = new HashMap<Long, ArrayList<LivingEntity>>();
		this.eventSchedule = new HashMap<Long, ArrayList<Event>>();
	}
	
	public void advanceTime(int time) {
		for (int t = 0; t < time; t++) {
			
			ticks += 1;
			
			if (schedule.containsKey(ticks)) {
				for (int e = 0; e < schedule.get(ticks).size(); e++) {
					LivingEntity entity = schedule.get(ticks).get(e);
					if (!(entity instanceof Player))
						entity.ai.action(entity);
				}
			}

			if (eventSchedule.containsKey(ticks)) {
				for (int e = 0; e < eventSchedule.get(ticks).size(); e++) {
					Event event = eventSchedule.get(ticks).get(e);
					event.action();
				}
			}
			
		}
	}
	
	public long scheduleTurn(int interval, LivingEntity entity) {
		
		if (!schedule.containsKey(ticks + interval)) {
			schedule.put((ticks + interval), new ArrayList<LivingEntity>());
			schedule.get(ticks + interval).add(entity);
		} else {
			schedule.get(ticks + interval).add(entity);
		}
		
		return ticks + interval;
		
	}
	
	public long scheduleEvent(int interval, Event event) {
		
		if (!eventSchedule.containsKey(ticks + interval)) {
			eventSchedule.put((ticks + interval), new ArrayList<Event>());
			eventSchedule.get(ticks + interval).add(event);
		} else {
			eventSchedule.get(ticks + interval).add(event);
		}
		
		return ticks + interval;
		
	}
	
	public void unScheduleTurn(long nextMoveTick, LivingEntity entity) {
		
		if (schedule.containsKey(nextMoveTick)) {
			schedule.get(nextMoveTick).remove(entity);
		}
		
	}
	
	public void unScheduleEvent(long nextMoveTick, Event event) {
		
		if (eventSchedule.containsKey(nextMoveTick)) {
			eventSchedule.get(nextMoveTick).remove(event);
		}
		
	}
	
	public void scheduleTurnLoad(long tickToAdd, LivingEntity entity) {
		
		if (!schedule.containsKey(tickToAdd)) {
			schedule.put((tickToAdd), new ArrayList<LivingEntity>());
			schedule.get(tickToAdd).add(entity);
		} else {
			schedule.get(tickToAdd).add(entity);
		}
		
	}
	
	public long getTicks() {
		return ticks;
	}
	
}

You don’t put missiles in the same system as player/monster turns in roguelikes (althrough it would be logical if you were making RPG). Missiles are instant things, these are part of display system, not game logic system. Players/monsters do their things. When one of the actions is fire a missile, you stop the execution of player turns (actually you don’t have to stop anything since roguelikes are turn based) and display animation of missile moving around. When all animations are finished the player is allowed to press next button.

Also note that things will get hairy if you have various speed of monsters. In such case the typical solution is to move the entity (monster/player) with the highest remaining speed, when none of the entites have enough speed to move the speed is replenished by the base speed.