Spaces:
Running
Running
/** | |
* @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); | |
} | |