lychees's picture
Upload 569 files
87b3b3a
/**
* @class Visual map display
* @param {object} [options]
* @param {int} [options.width=ROT.DEFAULT_WIDTH]
* @param {int} [options.height=ROT.DEFAULT_HEIGHT]
* @param {int} [options.fontSize=15]
* @param {string} [options.fontFamily="monospace"]
* @param {string} [options.fontStyle=""] bold/italic/none/both
* @param {string} [options.fg="#ccc"]
* @param {string} [options.bg="#000"]
* @param {int} [options.fps=25]
* @param {float} [options.spacing=1]
* @param {float} [options.border=0]
* @param {string} [options.layout="rect"]
*/
ROT.Display = function(options) {
var canvas = document.createElement("canvas");
this._context = canvas.getContext("2d");
this._data = {};
this._dirty = false; /* false = nothing, true = all, object = dirty cells */
this._options = {};
this._backend = null;
var defaultOptions = {
width: ROT.DEFAULT_WIDTH,
height: ROT.DEFAULT_HEIGHT,
layout: "rect",
fontSize: 15,
fps: 25,
spacing: 1,
border: 0,
fontFamily: "monospace",
fontStyle: "",
fg: "#ccc",
bg: "#000"
};
for (var p in options) { defaultOptions[p] = options[p]; }
this.setOptions(defaultOptions);
this.DEBUG = this.DEBUG.bind(this);
this._interval = setInterval(this._tick.bind(this), 1000/this._options.fps);
}
/**
* Debug helper, ideal as a map generator callback. Always bound to this.
* @param {int} x
* @param {int} y
* @param {int} what
*/
ROT.Display.prototype.DEBUG = function(x, y, what) {
var colors = [this._options.bg, this._options.fg];
this.draw(x, y, null, null, colors[what % colors.length]);
}
/**
* Clear the whole display (cover it with background color)
*/
ROT.Display.prototype.clear = function() {
this._data = {};
this._dirty = true;
}
/**
* @see ROT.Display
*/
ROT.Display.prototype.setOptions = function(options) {
for (var p in options) { this._options[p] = options[p]; }
if (options.width || options.height || options.fontSize || options.fontFamily || options.spacing || options.layout) {
if (options.layout) {
this._backend = new ROT.Display[options.layout.capitalize()](this._context);
}
var font = (this._options.fontStyle ? this._options.fontStyle + " " : "") + this._options.fontSize + "px " + this._options.fontFamily;
this._context.font = font;
this._backend.compute(this._options);
this._context.font = font;
this._context.textAlign = "center";
this._context.textBaseline = "middle";
this._dirty = true;
}
return this;
}
/**
* Returns currently set options
* @returns {object} Current options object
*/
ROT.Display.prototype.getOptions = function() {
return this._options;
}
/**
* Returns the DOM node of this display
* @returns {node} DOM node
*/
ROT.Display.prototype.getContainer = function() {
return this._context.canvas;
}
/**
* Compute the maximum width/height to fit into a set of given constraints
* @param {int} availWidth Maximum allowed pixel width
* @param {int} availHeight Maximum allowed pixel height
* @returns {int[2]} cellWidth,cellHeight
*/
ROT.Display.prototype.computeSize = function(availWidth, availHeight) {
return this._backend.computeSize(availWidth, availHeight, this._options);
}
/**
* Compute the maximum font size to fit into a set of given constraints
* @param {int} availWidth Maximum allowed pixel width
* @param {int} availHeight Maximum allowed pixel height
* @returns {int} fontSize
*/
ROT.Display.prototype.computeFontSize = function(availWidth, availHeight) {
return this._backend.computeFontSize(availWidth, availHeight, this._options);
}
/**
* @param {int} x
* @param {int} y
* @param {string} ch
* @param {string} [fg] foreground color
* @param {string} [bg] background color
*/
ROT.Display.prototype.draw = function(x, y, ch, fg, bg) {
if (!fg) { fg = this._options.fg; }
if (!bg) { bg = this._options.bg; }
this._data[x+","+y] = [x, y, ch, fg, bg];
if (this._dirty === true) { return; } /* will already redraw everything */
if (!this._dirty) { this._dirty = {}; } /* first! */
this._dirty[x+","+y] = true;
}
/**
* Draws a text at given position. Optionally wraps at a maximum length. Currently does not work with hex layout.
* @param {int} x
* @param {int} y
* @param {string} text May contain color/background format specifiers, %c{name}/%b{name}, both optional. %c{}/%b{} resets to default.
* @param {int} [maxWidth] wrap at what width?
* @returns {int} lines drawn
*/
ROT.Display.prototype.drawText = function(x, y, text, maxWidth) {
var fg = null;
var bg = null;
var cx = x;
var cy = y;
var lines = 1;
if (!maxWidth) { maxWidth = this._options.width-x; }
var tokens = ROT.Text.tokenize(text, maxWidth);
while (tokens.length) { /* interpret tokenized opcode stream */
var token = tokens.shift();
switch (token.type) {
case ROT.Text.TYPE_TEXT:
for (var i=0;i<token.value.length;i++) {
this.draw(cx++, cy, token.value.charAt(i), fg, bg);
}
break;
case ROT.Text.TYPE_FG:
fg = token.value || null;
break;
case ROT.Text.TYPE_BG:
bg = token.value || null;
break;
case ROT.Text.TYPE_NEWLINE:
cx = x;
cy++;
lines++
break;
}
}
return lines;
}
/**
* Timer tick: update dirty parts
*/
ROT.Display.prototype._tick = function() {
if (!this._dirty) { return; }
if (this._dirty === true) { /* draw all */
this._context.fillStyle = this._options.bg;
this._context.fillRect(0, 0, this._context.canvas.width, this._context.canvas.height);
for (var id in this._data) { /* redraw cached data */
this._draw(id, false);
}
} else { /* draw only dirty */
for (var key in this._dirty) {
this._draw(key, true);
}
}
this._dirty = false;
}
/**
* @param {string} key What to draw
* @param {bool} clearBefore Is it necessary to clean before?
*/
ROT.Display.prototype._draw = function(key, clearBefore) {
var data = this._data[key];
if (data[4] != this._options.bg) { clearBefore = true; }
this._backend.draw(data, clearBefore);
}