@zimjs/game
Version:
Game module for ZIM JavaScript Canvas Framework
1,230 lines (1,149 loc) • 92.5 kB
JavaScript
// ZIM - https://zimjs.com - Code Creativity!
// JavaScript Canvas Framework for General Interactive Media
// free to use - donations welcome of course! https://zimjs.com/donate
// ZIM GAME - see https://zimjs.com/code#libraries for examples
// ~~~~~~~~~~~~~~~~~~~~~~~~
// DESCRIPTION - LeaderBoard coded in 2017, Board in 2019 (c) ZIM
// Helper code for making games on the HTML Canvas with JavaScript
// ZIM already has a number of functions and classes that can help with games for example:
// well... just about everthing in ZIM ;-) Okay, here are a list of common ones:
// hitTestPoint, hitTestReg, hitTestRect, hitTestCircle, hitTestGrid
// Sprite, Dynamo, Scroller, Accelerator, loadAssets and asset
// animate, move, Ticker, GamePad, MotionController
// Label, Button, Slider, Dial, Tabs, Pane, ColorPicker, Swipe, Swiper, Indicator
// scale, scaleTo, center, centerReg, addTo, removeFrom
// Circle, Rectangle, Triangle
// constrain, Damp, ProportionDamp
// The Game Module has LeaderBoard(), Meter(), Board(), Person(), Orb(), Tree(), Timer(), Scorer(), and Dialog()
// DOCS
// Docs are provided at https://zimjs.com/docs.html
// See GAME MODULE at bottom
// ~~~~~~~~~~~~~~~~~~~~~~~~
import zim from "zimjs";
// note - removed the ES5 module pattern as we are getting zim from import
// ~~~~~~~~~~~~~~~~~~~~~~~~
var WW = window||{};
zim.LeaderBoard = function(data, title, width, height, corner, backgroundColor, titleColor, colors, total, scoreWidth, scorePlaces, scoreZeros, spacing, arrows, borderColor, borderWidth, shadowColor, shadowBlur, reverse, allowZero, font, fontSize, nameShift, scoreShift, rankShift) {
var sig = "data, title, width, height, corner, backgroundColor, titleColor, colors, total, scoreWidth, scorePlaces, scoreZeros, spacing, arrows, borderColor, borderWidth, shadowColor, shadowBlur, reverse, allowZero, font, fontSize, nameShift, scoreShift, rankShift";
var duo; if (duo = zob(zim.LeaderBoard, arguments, sig, this)) return duo;
this.arguments = arguments;
if (zot(data)) data = "localStorage";
if (zot(width)) width = 400;
if (zot(height)) height = 600;
this.super_constructor(width, height);
if (zot(corner)) corner = 20;
if (zot(backgroundColor)) backgroundColor = "white";
if (zot(titleColor)) titleColor = "#222";
if (zot(total)) total = 10;
if (zot(scoreWidth)) scoreWidth = 300;
if (zot(scorePlaces)) scorePlaces = 6;
if (zot(scoreZeros)) scoreZeros = false;
if (zot(spacing)) spacing = 10;
if (zot(arrows)) arrows = false;
if (!zot(borderColor) && zot(borderWidth)) borderWidth = 2;
if (zot(shadowColor)) shadowColor = "rgba(0,0,0,.3)";
if (zot(shadowBlur)) shadowBlur = 14;
if (zot(reverse)) reverse = false;
if (zot(allowZero)) allowZero = false;
if (zot(font)) font = "courier";
if (zot(fontSize)) fontSize = 60;
if (zot(nameShift)) nameShift = 0;
if (zot(scoreShift)) scoreShift = 0;
if (zot(rankShift)) rankShift = 0;
if (typeof frame == "undefined" || zot(frame)) var frame = zimDefaultFrame;
var backing = this.backing = new zim.Rectangle(width, height, backgroundColor, borderColor, borderWidth, corner);
backing.mouseEnabled = false;
var backingEvent = backing.on("click", function() { });
backing.off("click", backingEvent);
backing.off("click", backingEvent);
this.addChild(backing);
this.setBounds(0, 0, width, height);
this.backdrop = new Rectangle(2000, 1000, "rgba(0,0,0,.01)").center(this, 0);
if (typeof frame == "undefined" && typeof zimDefaultFrame != "undefined") {var frame = zimDefaultFrame;}
var stage = frame.stage;
this.backdrop.on("mousedown", function() {
stage = that.stage;
that.removeFrom();
that.dispatchEvent("close");
if (stage) stage.update();
});
this.filled = false;
this.info = {reverse: reverse, total: total, allowZero: allowZero, type: gameSaved}; // ES6 to fix
if (shadowColor != -1 && shadowBlur > 0) backing.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur);
var grid = this.grid = new zim.Container();
var row;
var stepper;
var rank;
var score;
var that = this;
var c = {
rankBackgroundColor: zim.darker,
rankColor: zim.light,
currentRankBackgroundColor: zim.pink,
currentRankColor: "white",
nameBackgroundColor: zim.lighter,
nameColor: zim.darker,
currentNameBackgroundColor: "#f0d2e8",
currentNameColor: zim.darker,
scoreBackgroundColor: zim.light,
scoreColor: zim.darker,
currentScoreBackgroundColor: "#f0d2e8",
currentScoreColor: zim.darker
};
var c = zim.merge(c, colors);
var fakeText = zim.decimals(8, -scorePlaces, true); // force text to 000008 to start
var winSteppers;
var gameSaved;
var button;
var winRow;
if (data == "localStorage") {
initLocalStorage();
} else if (!Array.isArray(data)) { // data is a key to get the data from the ZIM Game Database
that.dataSource = "database";
that.key = data;
zim.async("https://zimjs.com/gamedata.php?id=" + data, gameData);
function gameData(d) {
if (d == "error") {
var e = new createjs.Event("error");
e.type = "data";
that.dispatchEvent(e);
initLocalStorage(); // drop to localStorage
return;
}
if (d == "noscores") {
d = [];
}
data = d;
makeGrid();
}
} else {
that.dataSource = "custom";
makeGrid();
}
function initLocalStorage() {
// localStorage.clear();
that.dataSource = "localStorage";
if (localStorage && localStorage.gameData) {
data = JSON.parse(localStorage.gameData);
} else {
data = [];
}
makeGrid();
}
var keydownEvent;
function makeGrid() {
scaleStart = that.scaleX;
that.sca(1);
that.filled = false;
frame.off("keydown", keydownEvent);
if (!zot(title)) {
var titleText = that.titleText = new zim.Label({
text: title,
size: fontSize,
color: titleColor,
align: "center",
font: font
}).addTo(grid);
titleText.x = titleText.width / 2;
titleText.mouseEnabled = false;
}
var winCheck;
if (!zot(that.winner)) winSteppers = [];
backing.mouseEnabled = false;
backing.off("click", backingEvent);
for (var j = 0; j < total; j++) {
winCheck = j == that.winner;
var p, s;
if (data[j]) {
p = data[j].player;
s = data[j].score;
} else {
p = s = " ";
}
row = new zim.Container();
rank = new zim.Label({
text: (j + 1),
size: 50,
color: j == that.winner ? c.currentRankColor : c.rankColor,
align: "center",
valign: "center",
backing: new zim.Rectangle(100, 100, winCheck ? c.currentRankBackgroundColor : c.rankBackgroundColor),
});
rank.reg(-rank.width / 2, -rank.height / 2);
rank.label.regY = -rankShift;
rank.addTo(row);
if (arrows && !zot(that.winner)) {
rank.mov(0, j >= that.winner ? 50 : 0)
.mov(0, j > that.winner ? 50 : 0);
}
for (var i = 0; i < 3; i++) {
stepper = new zim.Stepper({
list: winCheck ? "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-*_".split("") : p[i],
width: 70,
continuous: true,
label: new zim.Label({text: "", font: font, color: j == that.winner ? c.currentNameColor : c.nameColor, size: fontSize, align: "center", shiftV: -5 - nameShift}),
backgroundColor: winCheck ? c.currentNameBackgroundColor : c.nameBackgroundColor,
vertical: false,
arrows: false,
arrows2: (winCheck && arrows),
corner: 0,
shadowBlur: 0
}).sca(100 / 60);
if (winCheck) {
backing.mouseEnabled = true;
backing.on("click", backingEvent);
if (frame.tabOrder) frame.tabOrder.push(stepper);
winSteppers.push(stepper);
stepper.currentValue = "_";
stepper.on("change", function(e) {
if (e.target.text != "_") {
e.target.label.y = 19 - nameShift;
e.target.stage.update();
}
var done = zim.loop(winSteppers, function(s) {
if (s.currentValue == "_") return false;
});
if (done) {
that.filled = true;
winScore.text = "";
button.loc(winScore.backing).addTo(winRow);
if (that.stage) that.stage.update();
}
that.dispatchEvent("change");
});
if (i == 0) stepper.keyFocus = true;
} else {
stepper.label.y = 19 - nameShift;
}
// stepper.label.reg(0,-2-nameShift)
// stepper.label.mov(0,2+nameShift)
stepper.x = rank.width + spacing + i * (stepper.width + spacing);
if (arrows && !zot(that.winner)) {
stepper.mov(0, j >= that.winner ? 50 : 0).mov(0, j > that.winner ? 50 : 0);
}
// stepper.enabled = winCheck;
row.addChild(stepper);
var scoreText = new zim.Label({
text: fakeText,
color: winCheck ? c.currentScoreColor : c.scoreColor,
font: font,
size: fontSize + 4,
align: "right",
valign: "center",
backing: new zim.Rectangle(scoreWidth, 100, winCheck ? c.currentScoreBackgroundColor : c.scoreBackgroundColor)
});
scoreText.text = scoreZeros ? zim.decimals(s, -scorePlaces, true) : s;
scoreText.reg(-scoreText.width / 2, -scoreText.height / 2);
scoreText.label.regY = -4 - scoreShift;
scoreText.label.skewX = 10;
row.addChild(scoreText);
scoreText.x = rank.width + spacing + 3 * (stepper.width + spacing) + 60;
// scoreText.outline()
if (arrows && !zot(that.winner)) {
scoreText.mov(0, j >= that.winner ? 50 : 0)
.mov(0, j > that.winner ? 50 : 0);
}
}
if (winCheck) {
winRow = row;
var winScore = scoreText;
button = that.button = new zim.Button({
label: new zim.Label({text: "SAVE", size: 50, align: "center", color: c.currentRankColor, rollColor: c.currentRankBackgroundColor}),
width: scoreText.width,
backgroundColor: c.currentRankBackgroundColor,
rollBackgroundColor: c.currentRankColor,
height: 100,
corner: 0,
shadowBlur: 0
});
// button.x = scoreText.x-60;
// button.y = scoreText.y;
if (frame.tabOrder) frame.tabOrder.push(button);
button.on("mousedown", that.submitScore);
keydownEvent = frame.on("keydown", function(e) {
if (!that.stage) return;
if (button.focus && e.keyCode == 13) { // enter key
submitScore();
e.preventDefault();
}
});
}
row.addTo(grid);
row.x = 0;
row.y = (zot(title) ? 0 : (titleText.height + spacing * 2)) + j * (100 + spacing);
row.mouseChildren = winCheck;
row.mouseEnabled = winCheck;
}
if (!zot(title)) {titleText.center(grid); titleText.y = 0;}
grid.scaleTo(that, 95, 95)
.center(that);
that.sca(scaleStart);
if (stage) stage.update();
}
this.submitScore = function() {
button.text = that.dataSource == "localStorage" ? "LOCAL" : "SENT";
winRow.mouseChildren = false;
winRow.mouseEnbabled = false;
that.stage.update();
if (zot(data[that.winner])) data[that.winner] = {};
data[that.winner].player = winSteppers[0].currentValue + winSteppers[1].currentValue + winSteppers[2].currentValue;
var e = new createjs.Event("press");
var player = e.player = data[that.winner].player;
var score = e.score = data[that.winner].score;
e.key = that.key;
e.info = that.info;
that.dispatchEvent(e);
if (that.dataSource == "custom") return;
if (zim.decimals(score, null, null, null, null, null, e)) that.save();
return that;
};
this.score = function(score) {
if (!Array.isArray(data)) {
timeout(.1, function() {that.score(score);});
return;
}
if (!zot(that.pendingIndex)) that.cancel();
var position;
if (data.length == 0) {
position = 0;
data.push({player: "", score: score});
} else {
position = zim.loop(data, function(s, i) {
if ((!reverse && s.score <= score) || (reverse && s.score >= score)) {
data.splice(i, 0, {player: "", score: score});
return i;
}
});
}
if (position === true && (allowZero || score > 0) && (data.length == 0 || data.length < total)) {
data.push({player: "", score: score});
position = data.length - 1;
}
if (position !== true) {
that.pendingIndex = position;
that.redraw(null, position);
}
return position !== true ? position : null;
};
this.save = function() {
if (zot(that.pendingIndex)) return that;
if (that.dataSource == "database") {
var player = data[that.pendingIndex].player;
var score = data[that.pendingIndex].score;
zim.async("https://zimjs.com/gamedata.php?id=" + that.key + "&player=" + player + "&score=" + score + "&reverse=" + reverse + "&total=" + total + "&allowZero=" + allowZero, gameSaved);
}
if (that.dataSource == "localStorage") {
that.pendingIndex = null;
if (localStorage) localStorage.gameData = JSON.stringify(data);
setTimeout(function() {
button.text = "DONE";
if (that.stage) that.stage.update();
}, 500);
setTimeout(function() {that.redraw();}, 1500);
}
return that;
};
function gameSaved(d) {
if (d == "error") {
var e = new createjs.Event("error");
e.type = "save";
that.dispatchEvent(e);
button.text = "ERROR";
data.splice(that.pendingIndex, 1);
} else {
var e = new createjs.Event("save");
e.data = data = d;
that.dispatchEvent(e);
button.text = "DONE";
}
that.pendingIndex = null;
if (that.stage) that.stage.update();
setTimeout(function() {that.redraw();}, 1000);
}
this.startTime = function() {
zim.async("https://zimjs.com/gamedata.php?id=" + that.key + "&command=start", timeReply);
return that;
};
this.stopTime = function() {
zim.async("https://zimjs.com/gamedata.php?id=" + that.key + "&command=stop", timeReply);
return that;
};
function timeReply(data) { };
this.cancel = function() {
if (zot(that.pendingIndex)) return that;
data.splice(that.pendingIndex, 1);
that.pendingIndex = null;
that.redraw();
var e = new createjs.Event("cancel");
e.data = data;
that.dispatchEvent(e);
return that;
};
var scaleStart = that.scaleX;
this.redraw = function(newData, newWinner) {
if (newData) data = newData;
scaleStart = that.scaleX;
that.dispose();
if (zot(newWinner)) {that.winner = null;} else {that.winner = newWinner;}
grid.removeAllChildren();
makeGrid();
if (that.stage) that.stage.update();
return that;
};
this.dispose = function() {
if (winSteppers) {
var ind;
zim.loop(winSteppers, function(s) {
if (frame.tabOrder) {
var ind = frame.tabOrder.indexOf(s);
if (ind > -1) frame.tabOrder.splice(ind, 1);
}
s.dispose();
});
if (frame.tabOrder) {
ind = frame.tabOrder.indexOf(button);
if (ind > -1) frame.tabOrder.splice(ind, 1);
}
if (button) button.dispose();
}
};
};
zim.extend(zim.LeaderBoard, zim.Container);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
zim.Meter = function(stage, vertical, horizontal, color, textColor, padding, decimals, alpha, skew) {
var sig = "stage, vertical, horizontal, color, textColor, padding, decimals, alpha, skew";
var duo; if (duo = zob(zim.Meter, arguments, sig, this)) return duo;
this.arguments = arguments;
if (zot(vertical)) vertical = "bottom";
if (zot(horizontal)) horizontal = "left";
if (zot(padding)) padding = 20;
if (zot(decimals)) decimals = 0;
if (zot(color)) color = "#acd241"; // frame.green
if (zot(textColor)) textColor = "black"; // frame.green
if (zot(alpha)) alpha = .6;
if (zot(skew)) skew = 10;
this.super_constructor("", 30, null, textColor, null, null, null, "center", "center", null, null, null, null, null, new zim.Rectangle(100, 40, color));
var that = this;
var meterFunction;
var initFunction;
if (zot(stage)) {initFunction = that.on("added", init);} else {init();}
var fps = new zim.Label({text: "FPS", size: 18, color: textColor}).rot(-90).addTo(that).alp(.5);
fps.x = 59;
fps.y = 17;
function init() {
if (zot(stage)) stage = that.stage;
if (zot(stage)) return;
that.off("added", initFunction);
stage.addChild(that);
that.alpha = alpha;
that.skewX = skew;
that.setBounds(null);
that.pos(padding, padding, horizontal, vertical);
// that.x = horizontal=="left"?padding+skew/2+50:stage.getBounds().width-that.width-padding-skew/2+50;
// that.y = vertical=="top"?padding:stage.getBounds().height-that.height-padding;
meterFunction = zim.Ticker.add(function() {
that.text = zim.decimals(createjs.Ticker.getMeasuredFPS(), decimals, true);
if (stage) stage.update();
}, stage);
}
this.position = function(v, h) {
if (!zot(v)) vertical = v;
if (!zot(h)) horizontal = h;
that.setBounds(null);
// that.x = horizontal=="left"?padding+skew/2+50:stage.getBounds().width-that.width-padding-skew/2+50;
// that.y = vertical=="top"?padding:stage.getBounds().height-that.height-padding;
that.pos(padding, padding, horizontal, vertical);
return that;
};
this.dispose = function() {
zim.Ticker.remove(meterFunction);
};
};
zim.extend(zim.Meter, zim.Label);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
zim.Board = function(size, cols, rows, backgroundColor, rollBackgroundColor, borderColor, borderWidth, icon, isometric, indicatorColor, indicatorBorderColor, indicatorBorderWidth, indicatorSize, indicatorType, arrows, arrowColor, arrowRollColor, swipe, info, labels, color, scaleMin, scaleMax, buffer) {
var sig = "size, cols, rows, backgroundColor, rollBackgroundColor, borderColor, borderWidth, icon, isometric, indicatorColor, indicatorBorderColor, indicatorBorderWidth, indicatorSize, indicatorType, arrows, arrowColor, arrowRollColor, swipe, info, labels, color, scaleMin, scaleMax, buffer";
var duo; if (duo = zob(zim.Board, arguments, sig, this)) return duo;
this.arguments = arguments;
if (zot(size)) size = 50;
this.size = size;
if (zot(cols)) cols = zot(rows) ? 8 : rows;
if (zot(rows)) rows = cols;
this.cols = cols;
this.rows = rows;
this.num = cols * rows;
if (zot(backgroundColor)) backgroundColor = "#eee";
if (zot(rollBackgroundColor)) rollBackgroundColor = "#aaa";
if (zot(borderColor)) borderColor = "#111";
if (zot(borderWidth)) borderWidth = 2;
if (zot(isometric)) isometric = true;
var isoFirst = isometric;
if (zot(indicatorColor)) indicatorColor = null;
if (zot(indicatorBorderColor)) indicatorBorderColor = "#111";
if (zot(indicatorBorderWidth)) indicatorBorderWidth = 2;
if (zot(indicatorType)) indicatorType = "circle";
if (indicatorType != "circle") indicatorType = "rectangle";
if (zot(indicatorSize)) indicatorSize = indicatorType == "rectangle" ? (size - indicatorBorderWidth) : size / 4;
if (zot(arrows)) arrows = true;
if (zot(arrowColor)) arrowColor = "rgba(0,0,0,.4)";
if (zot(arrowRollColor)) arrowRollColor = "#fff";
if (zot(swipe)) swipe = arrows;
var timeType = typeof TIME == "undefined" ? "seconds" : TIME;
function emptyInfo() {
// info is rows (j) then cols (i)
info = [];
zim.loop(rows, function(j) {
var inf = info[j] = [];
zim.loop(cols, function(i) {
inf[i] = {data: "x", color: backgroundColor, icon: icon ? icon.clone() : null, items: []};
});
});
}
if (zot(info)) {
// create empty info if no provided info
emptyInfo();
} else if (typeof info == "string") {
if (info.match(/zimon/) && typeof ZIMON !== 'undefined') info = ZIMON.parse(info);
else emptyInfo();
} else if (!Array.isArray(info) || info.length == 0) {
emptyInfo();
} else {
// info are rows (j) then cols (i)
var info2 = [];
var i0 = 0;
// get most cols
zim.loop(Math.max(cols, info.length), function(j) {
if (info[j] && info[j].length > i0) i0 = info[j].length;
});
zim.loop(Math.max(cols, info.length), function(j) {
var inf = info2[j] = [];
zim.loop(Math.max(rows, i0), function(i) {
if (info[j] && !zot(info[j][i])) {
if (zot(info[j][i].data)) info[j][i].data = "x";
if (zot(info[j][i].color)) info[j][i].color = backgroundColor;
if (zot(info[j][i].icon)) info[j][i].icon = icon ? icon.clone() : null;
if (zot(info[j][i].items)) info[j][i].items = [];
inf[i] = info[j][i];
}
else inf[i] = {data: "x", color: backgroundColor, icon: icon ? icon.clone() : null, items: []};
});
});
info = copy(info2);
}
this.info = info;
if (zot(labels)) labels = false;
if (zot(color)) color = "#666";
if (zot(scaleMin)) scaleMin = 1.2;
if (zot(scaleMax)) scaleMax = 1.8;
if (zot(swipe)) swipe = true;
if (zot(buffer)) buffer = 2;
this.super_constructor();
this.type = "Board";
this.buffer = buffer;
var that = this;
var holder = new zim.Container().addTo(this);
var container = new zim.Container(size, size);
new zim.Rectangle(size, size, zik(backgroundColor), zik(borderColor), zik(borderWidth)).addTo(container);
// labels for debugging
if (labels) new zim.Label({text: "", color: color, align: "center", valign: "center"}).center(container);
var tiles = this.tiles = new zim.Tile(container.centerReg(), cols, rows);
if (isometric) {
tiles.rot(45)
.centerReg(holder);
holder.sca(2, 1);
} else {
tiles.centerReg(holder);
}
this.arrows = arrows;
var startCol = 0;
var startRow = 0;
var lastStartCol = 0;
var lastStartRow = 0;
Object.defineProperty(this, 'numCols', {
get: function() {
return that.info[0].length;
},
set: function(value) {
zog("zim.Board() - numCols is read only");
}
});
Object.defineProperty(this, 'numRows', {
get: function() {
return that.info.length;
},
set: function(value) {
zog("zim.Board() - numRows is read only");
}
});
Object.defineProperty(this, 'startCol', {
get: function() {
return startCol;
},
set: function(value) {
startCol = zim.constrain(value, 0, that.numCols - cols);
if (startCol != lastStartCol) {
that.update();
that.shiftPath(lastStartCol, startCol); // no obj so for all pieces
}
lastStartCol = startCol;
}
});
Object.defineProperty(this, 'startRow', {
get: function() {
return startRow;
},
set: function(value) {
startRow = zim.constrain(value, 0, that.numRows - rows);
if (startRow != lastStartRow) {
that.update();
that.shiftPath(null, null, lastStartRow, startRow); // no obj so for all pieces
}
lastStartRow = startRow;
}
});
Object.defineProperty(this, 'data', {
// gets board data only - not all data
get: function() {
var data = [];
zim.loop(startRow + rows, function(j) {
var d = [];
data.push(d);
zim.loop(startCol + cols, function(i) {
d.push(that.info[j][i].data);
}, null, null, null, startCol);
}, null, null, null, startRow);
return data;
},
set: function(value) {
zog("zim.Board() - data is read only - use setData(tile) or change info property and update()");
}
});
Object.defineProperty(this, 'isometric', {
get: function() {
return isometric;
},
set: function(value) {
if (value != isometric) {
isometric = value;
that.removeArrows();
if (isometric) {
holder.removeAllChildren();
that.tiles.rot(45).centerReg(holder);
var ss = isoFirst ? 1 : 1.2;
holder.sca(2 / ss, 1 / ss).mov(0, (isoFirst ? 20 : 0));
} else {
holder.removeAllChildren();
that.tiles.rot(0).centerReg(holder);
holder.sca(1 * (isoFirst ? 1.2 : 1)).mov(0, (isoFirst ? -20 : 0));
}
if (swipe) {
var swap = {left: "right", right: "left", up: "down", down: "up"};
if (that.swipeEvent) that.swipe.off("swipe", that.swipeEvent);
that.swipe = new zim.Swipe(that, null, null, isometric);
that.swipeEvent = that.swipe.on("swipe", function(e) {
if (e.target.direction == "none") return;
that.moveCamera(swap[e.target.direction]);
});
}
that.setArrows();
that.update();
if (that.stage) that.stage.update();
}
}
});
this.update = function() {
// updates data, colors and pieces for currently visible board
if (labels) {
tiles.loop(function(tile) {
tile.getChildAt(1).text = that.getData(tile);
});
}
that.pieces.loop(function(piece) {
piece.visible = false;
});
that.clearBoardColors();
that.clearBoardIcons();
zim.loop(rows + startRow, function(j) {
zim.loop(cols + startCol, function(i) {
var info = that.info[j][i];
var tile = that.getTile(i - startCol, j - startRow);
that.setColor(tile, info.color, true);
if (info.icon) that.setIcon(tile, info.icon, true);
zim.loop(info.items, function(item) {
that.add(item, i - startCol, j - startRow, null, null, null, true);
});
}, null, null, null, startCol);
}, null, null, null, startRow);
if (that.stage) that.stage.update();
return that;
};
if (swipe) {
this.swipe = new zim.Swipe(this, null, null, isometric);
this.swipeEvent = this.swipe.on("swipe", function(e) {
if (e.target.direction == "none") return;
var swap = {left: "right", right: "left", up: "down", down: "up"};
that.moveCamera(swap[e.target.direction]);
});
}
this.moveCamera = function(dir) {
// moves camera one square left, right, up or down
// by setting startCol and startRow
// which moves any items, paths and sets activeData
if (dir == "left") {
if (that.arrowRight && startCol == that.numCols - cols) that.arrowRight.hov(arrowRollColor);
that.startCol = startCol - 1;
if (that.arrowLeft && startCol == 0) that.arrowLeft.hov(-1);
} else if (dir == "right") {
if (that.arrowLeft && startCol == 0) that.arrowLeft.hov(arrowRollColor);
that.startCol = startCol + 1;
if (that.arrowRight && startCol == that.numCols - cols) that.arrowRight.hov(-1);
} else if (dir == "up") {
if (that.arrowDown && startRow == that.numRows - rows) that.arrowDown.hov(arrowRollColor);
that.startRow = startRow - 1;
if (that.arrowUp && startRow == 0) that.arrowUp.hov(-1);
} else if (dir == "down") {
if (that.arrowUp && startRow == 0) that.arrowUp.hov(arrowRollColor);
that.startRow = startRow + 1;
if (that.arrowDown && startRow == that.numRows - rows) that.arrowDown.hov(-1);
}
return that;
};
this.positionBoard = function(i, j) {
// starts board off at provided location in info
that.startCol = i;
that.startRow = j;
if (that.arrows) that.setArrowHover();
return that;
};
this.setArrowHover = function() {
if (that.arrowLeft) that.arrowLeft.hov(startCol == 0 ? -1 : arrowRollColor);
if (that.arrowRight) that.arrowRight.hov(startCol == that.numCols - cols ? -1 : arrowRollColor);
if (that.arrowUp) that.arrowUp.hov(startRow == 0 ? -1 : arrowRollColor);
if (that.arrowDown) that.arrowDown.hov(startRow == that.numRows - rows ? -1 : arrowRollColor);
return that;
};
this.addCol = function(index) {
// adds info column at an index
if (zot(index)) index = that.numCols;
zim.loop(that.info, function(inf, i) {
inf.splice(index, 0, {data: "x", color: backgroundColor, icon: icon ? icon.clone() : null, items: []});
});
if (that.arrows) {
that.setArrows();
that.setArrowHover();
}
that.update();
return that;
};
this.addRow = function(index) {
// adds info row at an index
if (zot(index)) index = that.numRows;
var inf = [];
zim.loop(that.numCols, function() {
inf.push({data: "x", color: backgroundColor, icon: icon ? icon.clone() : null, items: []});
});
that.info.splice(index, 0, inf);
if (that.arrows) {
that.setArrows();
that.setArrowHover();
}
that.update();
return that;
};
this.setArrows = function() {
// sets arrows to handle shifting board
if (!that.arrows) return;
if (that.info.length > rows || that.info[0].length > cols) {
if (!that.arrowUp) {
that.arrowUp = new Triangle({color: arrowColor}).sca(.4).center(holder);
if (isometric) {
that.arrowUp
.rot(45)
.mov(tiles.width / 2, tiles.width / 2 - 50);
} else {
that.arrowUp
.mov(tiles.width / 2 + 40, -30);
}
that.arrowDown = new Triangle({color: arrowColor}).sca(.4).center(holder);
if (isometric) {
that.arrowDown
.rot(+45 - 180)
.mov(tiles.width / 2 - 50, tiles.width / 2);
} else {
that.arrowDown
.rot(-180)
.mov(tiles.width / 2 + 10, +30);
}
that.arrowUp.on("mousedown", function() {
that.moveCamera("up");
if (that.stage) that.stage.update();
});
that.arrowDown.on("mousedown", function() {
that.moveCamera("down");
if (that.stage) that.stage.update();
});
}
} else { // may have removed data so no scroll is needed
if (that.arrowUp) removeRowArrows();
}
var colArrows = zim.loop(that.info, function(d) {
if (d.length > cols) return "yes";
});
if (colArrows == "yes") {
if (!that.arrowLeft) {
that.arrowLeft = new Triangle({color: arrowColor}).sca(.4).cur().center(holder);
if (isometric) {
that.arrowLeft
.rot(+45 - 180 + 90)
.mov(-tiles.width / 2, tiles.width / 2 - 50);
} else {
that.arrowLeft
.rot(-180 + 90)
.mov(-60, tiles.width / 2 + 40);
}
that.arrowRight = new Triangle({color: arrowColor}).sca(.4).center(holder);
that.arrowRight.n = "b";
if (isometric) {
that.arrowRight
.rot(45 + 90)
.mov(-tiles.width / 2 + 50, tiles.width / 2);
} else {
that.arrowRight
.rot(+90)
.mov(0, tiles.width / 2 + 10);
}
that.arrowLeft.on("mousedown", function() {
that.moveCamera("left");
});
that.arrowRight.on("mousedown", function() {
that.moveCamera("right");
});
// FIX bounds so move camera not board
}
that.setArrowHover();
} else {
if (that.arrowLeft) removeColArrows();
}
return that;
};
that.setArrows();
this.removeArrows = function() {
removeColArrows();
removeRowArrows();
return that;
};
function removeColArrows() {
if (!that.arrowLeft || !that.arrowRight) return;
that.arrowLeft.removeAllEventListeners();
that.arrowRight.removeAllEventListeners();
that.arrowLeft.removeFrom();
that.arrowLeft = null;
that.arrowRight.removeFrom();
that.arrowRight = null;
}
function removeRowArrows() {
if (!that.arrowUp || !that.arrowDown) return;
that.arrowUp.removeAllEventListeners();
that.arrowDown.removeAllEventListeners();
that.arrowUp.removeFrom();
that.arrowUp = null;
that.arrowDown.removeFrom();
that.arrowDown = null;
}
that.lastTile = null;
tiles.tap(function(e) {
that.currentTile = e.target;
});
tiles.on("mouseover", function(e) {
if (that.timeout) that.timeout.clear();
e.target.lastColor = e.target.getChildAt(0).color;
e.target.getChildAt(0).color = rollBackgroundColor;
that.currentTile = e.target;
if (e.target != that.lastTile) {that.dispatchEvent("change");}
that.lastTile = e.target;
if (that.stage) that.stage.update();
});
tiles.on("mouseout", outHandler);
zimDefaultFrame.canvas.addEventListener("mouseleave", outHandler);
function outHandler(e) {
that.timeout = zim.timeout(timeType == "seconds" ? .05 : 50, function() {
that.currentTile = null;
that.lastTile = null;
that.dispatchEvent("change");
});
if (e.target && e.target.getChildAt) e.target.getChildAt(0).color = e.target.lastColor;
if (that.lastTile) that.lastTile.getChildAt(0).color = that.lastTile.lastColor;
if (that.stage) that.stage.update();
};
this.getIndexes = function(tile) {
// gets the row and col for a tile
var n = tiles.getChildIndex(tile);
var col = n % cols;
var row = Math.floor(n / cols);
return {col: col, row: row};
};
this.getInfo = function(a, b) {
// gets the info object for a tile (or i,j info point)
if (zot(a)) return;
if (zot(b)) {
var indexes = that.getIndexes(a);
a = indexes.col + startCol;
b = indexes.row + startRow;
}
if (a < 0 || a > that.numCols - 1 || b < 0 || b > that.numRows - 1) return;
return that.info[b][a];
};
this.getData = function(a, b) {
// gets items from info for a tile (or i,j info point)
if (zot(a)) return;
return that.getInfo(a, b).data;
};
this.getColor = function(a, b) {
// gets the color data for a tile (or i,j info point)
if (zot(a)) return;
return that.getInfo(a, b).color;
};
this.getIcon = function(a, b) {
// gets the icon for a tile (or i,j info point)
if (zot(a)) return;
return that.getInfo(a, b).icon;
};
this.getItems = function(a, b) {
// gets items from info for a tile (or i,j info point)
if (zot(a)) return;
var i = that.getInfo(a, b);
if (i) return that.getInfo(a, b).items;
};
this.getAllItems = function(filter) {
// gets an array of all items - add optional filter
var items = [];
if (zot(filter)) filter = {};
else filter = normalizeFilter(filter);
zim.loop(that.info, function(rows, j) {
zim.loop(rows, function(info, i) {
if (!includeTest(i, j, filter)) return;
zim.loop(info.items, function(item) {
items.push(item);
});
});
});
return items;
};
this.getTilesAround = function(a, b) {
// gets tiles around a tile (or i,j info point)
if (zot(a)) return;
if (zot(b)) {
var indexes = that.getIndexes(a);
a = indexes.col + startCol;
b = indexes.row + startRow;
}
if (a < 0 || a > that.numCols - 1 || b < 0 || b > that.numRows - 1) return [];
return [
that.getTile(a - 1, b - 1), that.getTile(a - 0, b - 1), that.getTile(a + 1, b - 1),
that.getTile(a + 1, b - 0), that.getTile(a + 1, b + 1), that.getTile(a - 0, b + 1),
that.getTile(a - 1, b + 1), that.getTile(a - 1, b - 0)
];
};
tiles.loop(function(t) {
if (indicatorType == "circle") {
t.indicator = new zim.Circle(zik(indicatorSize), zik(indicatorColor), zik(indicatorBorderColor), indicatorBorderWidth).center(t).alp(0);
} else {
var size = zik(indicatorSize);
t.indicator = new zim.Rectangle(size, size, zik(indicatorColor), zik(indicatorBorderColor), indicatorBorderWidth).centerReg(t).alp(0);
}
t.mouseChildren = false;
var i = that.getIndexes(t);
t.boardCol = i.col;
t.boardRow = i.row;
var icon = that.getInfo(t).icon;
t.icon = icon;
if (icon) icon.center(t.getChildAt(0));
});
this.getTile = function(col, row) {
// gets tile at visible col and row
if (col < 0 || row < 0 || col > that.cols - 1 || row > that.rows - 1) return;
return tiles.getChildAt(row * cols + col);
};
this.setData = function(tile, value) {
// updates a data entry for a tile
that.getInfo(tile).data = value;
return that.data;
};
this.setColor = function(tile, color, internal) {
// adds a color to board and info for the color
tile.lastColor = tile.getChildAt(0).color = color;
if (zot(internal)) that.getInfo(tile).color = color;
return that;
};
this.setIcon = function(tile, icon, internal) {
if (zot(icon)) return;
// adds an icon to board and info for the icon
if (zot(internal)) that.getInfo(tile).icon = icon;
if (tile.icon) tile.icon.removeFrom();
tile.icon = icon;
icon.center(tile.getChildAt(0));
return that;
};
this.clearInfo = function(filter) {
if (zot(filter)) filter = {};
else filter = normalizeFilter(filter);
// clears info for data, colors and items
zim.loop(that.info, function(rows, j) {
zim.loop(rows, function(inf, i) {
if (!includeTest(i, j, filter)) return;
inf.data = "x";
zim.loop(inf.items, function(item) {
item.boardCol = null;
item.boardRow = null;
item.tile = null;
item.removeFrom();
});
inf.items = [];
inf.icon = that.icon ? that.icon.clone() : null;
inf.color = backgroundColor;
var tile = that.getTile(i - startCol, j - startRow);
if (tile) {
tile.getChildAt(0).color = backgroundColor;
if (inf.icon) inf.icon.center(tile.getChildAt(0));
}
});
});
return that;
};
this.clearData = function(filter) {
if (zot(filter)) filter = {};
else filter = normalizeFilter(filter);
// clears data but leaves colors and items
zim.loop(that.info, function(rows, j) {
zim.loop(rows, function(info, i) {
if (!includeTest(i, j, filter)) return;
info.data = "x";
});
});
return that;
};
this.clearItems = function(filter) {
if (zot(filter)) filter = {};
else filter = normalizeFilter(filter);
// clears items but leaves data and colors
zim.loop(that.info, function(rows, j) {
zim.loop(rows, function(info, i) {
if (!includeTest(i, j, filter)) return;
zim.loop(info.items, function(item) {
item.boardCol = null;
item.boardRow = null;
item.tile = null;
item.removeFrom();
});
info.items = [];
});
});
return that;
};
this.clearColors = function(filter) {
if (zot(filter)) filter = {};
else filter = normalizeFilter(filter);
// clears color but leaves data and items
zim.loop(that.info, function(rows, j) {
zim.loop(rows, function(info, i) {
if (!includeTest(i, j, filter)) return;
info.color = backgroundColor;
var tile = that.getTile(i - startCol, j - startRow);
if (tile) tile.getChildAt(0).color = backgroundColor;
});
});
return that;
};
this.clearBoardColors = function() {
// clears board colors but leaves color info
zim.loop(tiles, function(tile) {
tile.getChildAt(0).color = backgroundColor;
});
return that;
};
this.clearIcons = function(filter) {
if (zot(filter)) filter = {};
else filter = normalizeFilter(filter);
// clears color but leaves data and items
zim.loop(that.info, function(rows, j) {
zim.loop(rows, function(info, i) {
if (!includeTest(i, j, filter)) return;
if (info.icon) {
info.icon.removeFrom();
if (info.icon.dispose) info.icon.dispose();
info.icon = null;
}
info.icon = that.icon ? that.icon.clone() : null;
var tile = that.getTile(i - startCol, j - startRow);
if (tile && info.icon) info.icon.center(tile.getChildAt(0));
});
});
return that;
};
this.clearBoardIcons = function() {
// clears board icons but leaves icon info
zim.loop(tiles, function(tile) {
if (tile.icon) tile.icon.removeFrom();
tile.icon = null;
});
return that;
};
this.getRandomTile = function(filter) {
if (zot(filter)) filter = {};
else filter = normalizeFilter(filter);
// gets random visible tile
var tile;
var count = 0;
while (!tile && count < 10000) {
var i = zim.rand(0, cols - 1) + startCol;
var j = zim.rand(0, rows - 1) + startRow;
if (filter && includeTest(i, j, filter)) tile = that.getTile(i - startCol, j - startRow);
count++;
}
return tile;
};
function normalizeFilter(filter) {
if (filter.constructor != {}.constructor) {
// assume filtering by data
filter = {data: !Array.isArray(filter) ? [filter] : filter};
return filter;
}
var types = ["data", "notData", "color", "notColor", "icon", "notIcon", "item", "notItem", "col", "notCol", "row", "notRow"];
var wrong = ["datas", "notDatas", "colors", "notColors", "icons", "notIcons", "items", "notItems", "cols", "notCols", "rows", "notRows"];
zim.loop(wrong, function(w, i) {
if (filter[w]) filter[types[i]] = filter[w];
delete filter[w];
});
zim.loop(types, function(type) {
if (!zot(filter[type]) && !Array.isArray(filter[type])) filter[type] = [filter[type]];
});
return filter;
}
function includeTest(i, j, filter) {
// test for there or not there and if wrong - then return false else return true
if (!zot(filter.data) && filter.data.indexOf(that.info[j][i].data) == -1) return false;
if (!zot(filter.notData) && filter.notData.indexOf(that.info[j][i].data) != -1) return false;
if (!zot(filter.color) && filter.color.indexOf(that.info[j][i].color) == -1) return false;
if (!zot(filter.notColor) && filter.notColor.indexOf(that.info[j][i].color) != -1) return false;
if (!zot(filter.icon) && (!that.info[j][i].icon || filter.icon.indexOf(that.info[j][i].icon.type) == -1)) return false;
if (!zot(filter.notIcon) && (that.info[j][i].icon && filter.notIcon.indexOf(that.info[j][i].icon.type) != -1)) return false;
if (!zot(filter.item) || !zot(filter.notItem)) {
var itemList = that.getItems(i, j);
if (!zot(filter.item)) {
var noMatch = zim.loop(itemList, function(it) {
if (filter.item.indexOf(it) != -1) return "yes";
});
// making it through the loop returns true and we are supposed to match something
if (noMatch === true) return false;
}
if (!zot(filter.notItem)) {
var match = zim.loop(itemList, function(it) {
if (filter.notItem.indexOf(it) != -1) return "yes";
});
// we matched something and we are not supposed to
if (match == "yes") return false;
}
}
if (!zot(filter.col) && filter.col.indexOf(i - startCol) == -1) return fa