view engine-runner.js @ 62:3355248e2638

Fixed a top-window display bug in curses.
author Atul Varma <varmaa@toolness.com>
date Fri, 16 May 2008 13:44:46 -0700
parents 7dc2c7bded08
children 5c35e18a9d1a
line wrap: on
line source

function Zui() {
}

Zui.prototype = {
  setVersion: function(version) {
  },

  // Returns a 2-element list containing the width and height of the
  // screen, in characters.  The width may be 255, which means
  // "infinite".

  getSize: function() {
  },
  onLineInput: function(callback) {
  },
  onCharacterInput: function(callback) {
  },
  onSave: function(callback) {
  },
  onRestore: function(callback) {
  },
  onQuit: function() {
  },
  onRestart: function(callback) {
  },
  onWimpOut: function(callback) {
  },
  onBreakpoint: function(callback) {
  },

  // From the Z-Machine spec for set_text_style: Sets the text style
  // to: Roman (if 0), Reverse Video (if 1), Bold (if 2), Italic (4),
  // Fixed Pitch (8). In some interpreters (though this is not
  // required) a combination of styles is possible (such as reverse
  // video and bold). In these, changing to Roman should turn off all
  // the other styles currently set.

  onSetStyle: function(textStyle, foreground, background) {
  },

  // From the Z-Machine spec for split_window: Splits the screen so
  // that the upper window has the given number of lines: or, if
  // this is zero, unsplits the screen again.

  onSplitWindow: function(numLines) {
  },
  onSetWindow: function(window) {
  },

  // From the Z-Machine spec for erase_window: Erases window with
  // given number (to background colour); or if -1 it unsplits the
  // screen and clears the lot; or if -2 it clears the screen
  // without unsplitting it.

  onEraseWindow: function(window) {
  },
  onEraseLine: function() {
  },
  onSetCursor: function(x, y) {
  },

  // From the Z-Machine spec for buffer_mode: If set to 1, text output
  // on the lower window in stream 1 is buffered up so that it can be
  // word-wrapped properly. If set to 0, it isn't.

  onSetBufferMode: function(flag) {
  },
  onSetInputStream: function() {
  },
  onGetCursor: function() {
  },
  onPrint: function(output) {
  },
  onPrintTable: function(lines) {
  }
};

function EngineRunner(engine, zui, logfunc) {
  this._engine = engine;
  this._zui = zui;
  this._isRunning = false;
  this._isInLoop = false;
  this._isWaitingForCallback = false;

  if (logfunc) {
    this._log = logfunc;
  } else {
    this._log = function() {};
  }

  var self = this;

  this.__proto__ = {
    stop: function() {
      self._isRunning = false;
    },

    run: function() {
      var size = self._zui.getSize();
      self._zui.setVersion(self._engine.m_version);

      self._isRunning = true;
      self._engine.m_memory[0x20] = size[1];
      self._engine.m_memory[0x21] = size[0];
      self._continueRunning();
    },

    _continueRunning: function() {
      while (self._isRunning && !self._isWaitingForCallback) {
        self._loop();
      }
    },

    _receiveLineInput: function(input) {
      self._isWaitingForCallback = false;
      self._engine.answer(1, input);
      if (!self._isInLoop) {
        self._continueRunning();
      } else {
        /* We're still inside _loop(), so just return. */
      }
    },

    _receiveCharacterInput: function(input) {
      self._isWaitingForCallback = false;
      self._engine.answer(0, input);
      if (!self._isInLoop) {
        self._continueRunning();
      } else {
        /* We're still inside _loop(), so just return. */
      }
    },

    _loop: function() {
      if (self._isInLoop)
        throw new Error("Already in loop!");

      self._isInLoop = true;
      var engine = self._engine;

      engine.run();

      var text = engine.consoleText();
      if (text)
        self._zui.onPrint(text);

      var effect = '"' + engine.effect(0) + '"';

      var logString = "[ " + engine.effect(0);

      for (var i = 1; engine.effect(i) != undefined; i++) {
        var value = engine.effect(i);
        if (typeof value == "string")
          value = value.quote();
        logString += ", " + value;
      }

      self._log(logString + " ]");

      switch (effect) {
      case GNUSTO_EFFECT_INPUT:
        self._isWaitingForCallback = true;
        self._zui.onLineInput(self._receiveLineInput);
        break;
      case GNUSTO_EFFECT_INPUT_CHAR:
        self._isWaitingForCallback = true;
        self._zui.onCharacterInput(self._receiveCharacterInput);
        break;
      case GNUSTO_EFFECT_SAVE:
      case GNUSTO_EFFECT_RESTORE:
        throw new Error("Unimplemented effect: " + effect);
      case GNUSTO_EFFECT_QUIT:
        self.stop();
        self._zui.onQuit();
        break;
      case GNUSTO_EFFECT_RESTART:
        self.stop();
        self._zui.onRestart();
        break;
      case GNUSTO_EFFECT_WIMP_OUT:
      case GNUSTO_EFFECT_BREAKPOINT:
      case GNUSTO_EFFECT_FLAGS_CHANGED:
      case GNUSTO_EFFECT_PIRACY:
        throw new Error("Unimplemented effect: " + effect);
      case GNUSTO_EFFECT_STYLE:
        self._zui.onSetStyle(engine.effect(1),
                             engine.effect(2),
                             engine.effect(3));
        break;
      case GNUSTO_EFFECT_SOUND:
        throw new Error("Unimplemented effect: " + effect);
      case GNUSTO_EFFECT_SPLITWINDOW:
        self._zui.onSplitWindow(engine.effect(1));
        break;
      case GNUSTO_EFFECT_SETWINDOW:
        self._zui.onSetWindow(engine.effect(1));
        break;
      case GNUSTO_EFFECT_ERASEWINDOW:
        self._zui.onEraseWindow(engine.effect(1));
        break;
      case GNUSTO_EFFECT_ERASELINE:
        throw new Error("Unimplemented effect: " + effect);
      case GNUSTO_EFFECT_SETCURSOR:
        self._zui.onSetCursor(engine.effect(2),
                              engine.effect(1));
        break;
      case GNUSTO_EFFECT_SETBUFFERMODE:
        self._zui.onSetBufferMode(engine.effect(1));
        break;
      case GNUSTO_EFFECT_SETINPUTSTREAM:
      case GNUSTO_EFFECT_GETCURSOR:
      case GNUSTO_EFFECT_PRINTTABLE:
        throw new Error("Unimplemented effect: " + effect);
      }

      self._isInLoop = false;
    }
  };
}