A heroes adventure

by Sam Fereday

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.0.8/chance.min.js"></script>
<button id="dungeon">
  Travel To Dungeon
</button>

<button id="guild">
  Travel To Guild
</button>

<div id="console">
  <div id="innerText">...</div><span class="blink">|</span>
</div>

CSS

#console {
  height: 20em;
  font-family: Courier;
  color: #CCCCCC;
  background: #000000;
  border: 3px double #CCCCCC;
  padding: 10px;
  overflow-y: auto;
}

#innerText {
  display: inline;
}

@keyframes blink {
  0% {
    color: black;
  }
  50% {
    color: white;
  }
  100% {
    color: black;
  }
}

.blink {
  animation: blink .7s linear infinite;
}

JavaScript

// Da libs
var ch = new Chance();

// Da utils
var gameloop = (function() {
  'use strict';
  var reqAnimFrame = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    };

  return function(callback) {
    var lastUpdate = +new Date();
    (function loop() {
      callback(((+new Date()) - lastUpdate) / 1000);
      reqAnimFrame(loop);
      lastUpdate = +new Date();
    }());
  };
}());

function dist(v1, v2) {
  var a = v1.x - v2.x;
  var b = v1.y - v2.y;
  return Math.sqrt(a * a + b * b);
}

function log(str, nobreak) {

  var objDiv = document.getElementById("console");
  objDiv.scrollTop = objDiv.scrollHeight;

  if (nobreak) {
    document.getElementById("innerText").innerHTML += str
    return;
  }

  document.getElementById("innerText").innerHTML += str + "<br />";

}

var StateMachine = function(initialState, otherStates) {

  //this.states = states || {};
  this.initialState = initialState;
  this.usedStates = otherStates;
  this.states = [];

  return this;

};

StateMachine.prototype.Top = function() {

  return this.states.length > 0 ? this.states[this.states.length - 1] : this.initialState;

};

StateMachine.prototype.Pop = function() {

  this.Top().Exit();
  this.states.pop();

  // Return to initial state since no more to pop.
  if (this.states.length === 0) {
    this.Top().Enter();
    log("A state changed to: " + this.initialState.id);
    return;
  }

};

StateMachine.prototype.Clear = function() {

  // Not sure if will need to perform exit routines on all before clear.
  this.states.length = 0;

};

StateMachine.prototype.Push = function(id, params, cb) {

  // It might be that you wish to instantiate each state at runtime, so test this out.
  let state = this.usedStates.find(x => x.id === id);

  if (state.length === 0)
    return;

  if (this.Top().id === id) {
    console.error("Cannot force duplicate...