Already live on the server via rsync; bringing the repo in sync. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1208 lines
52 KiB
JavaScript
1208 lines
52 KiB
JavaScript
var labyrinth = {
|
|
VERSION: 1.1,
|
|
DIR_TYPE: {
|
|
North: 0,
|
|
East: 1,
|
|
South: 2,
|
|
West: 3
|
|
},
|
|
PATH_TYPE: {
|
|
Undefined: 0,
|
|
Open: 1,
|
|
Wall: 2,
|
|
Door: 3
|
|
},
|
|
GAME_STATE: {
|
|
Wait: 0,
|
|
WarriorOneSelectRoom: 1,
|
|
WarriorTwoSelectRoom: 2,
|
|
WarriorOneTurn: 3,
|
|
WarriorTwoTurn: 4,
|
|
GameOver: 5
|
|
},
|
|
DRAGON_STATE: {
|
|
Asleep: 0,
|
|
Awake: 1
|
|
},
|
|
settings: {
|
|
debug: false,
|
|
travelSpeed: 200,
|
|
doorProb: .1,
|
|
wallProb: .8,
|
|
removeWallThreshold: 2,
|
|
removeWallProb: 0,
|
|
edgeWallBias: true,
|
|
treasureRoomDistance: 3,
|
|
maxLives: 3,
|
|
baseMoves: 2,
|
|
movesPerLife: 2,
|
|
movesWithTreasure: 4,
|
|
doorClosedProb: .2,
|
|
dragonWakeDistance: 3,
|
|
dragonFollows: 1
|
|
},
|
|
elements: {
|
|
board: null,
|
|
grid: null,
|
|
buttons: [],
|
|
chambers: [],
|
|
help: null
|
|
},
|
|
maze: {
|
|
chamberPaths: [],
|
|
stack: null,
|
|
visited: {},
|
|
lastChamber: null,
|
|
cancelTravel: false
|
|
},
|
|
game: {
|
|
init: false,
|
|
state: 0,
|
|
delayTimeout: null,
|
|
numberOfWarriors: 1,
|
|
warrior: [
|
|
{
|
|
lives: null,
|
|
secretRoom: null,
|
|
position: null,
|
|
moves: null
|
|
},
|
|
{
|
|
lives: null,
|
|
secretRoom: null,
|
|
position: null,
|
|
moves: null
|
|
}
|
|
],
|
|
dragon: {
|
|
position: null,
|
|
state: null,
|
|
visible: false
|
|
},
|
|
treasure: {
|
|
room: null,
|
|
warrior: -1,
|
|
visible: false
|
|
},
|
|
switchButtonOn: false,
|
|
level: 1,
|
|
help: null,
|
|
helpTimeout: null,
|
|
helpMessage: ""
|
|
},
|
|
audio: {
|
|
on: new Audio("audio/on.mp3"),
|
|
levelOne: new Audio("audio/levelOne.mp3"),
|
|
levelTwo: new Audio("audio/levelTwo.mp3"),
|
|
dragonFlying: new Audio("audio/dragonFlying.mp3"),
|
|
defeat: new Audio("audio/defeat.mp3"),
|
|
dragonAttacks: new Audio("audio/dragonAttacks.mp3"),
|
|
dragonWakes: new Audio("audio/dragonWakes.mp3"),
|
|
wall: new Audio("audio/wall.mp3"),
|
|
door: new Audio("audio/door.mp3"),
|
|
illegalMove: new Audio("audio/illegalMove.mp3"),
|
|
warriorMoves: new Audio("audio/warriorMoves.mp3"),
|
|
warriorOne: new Audio("audio/warriorOne.mp3"),
|
|
winner: new Audio("audio/winner.mp3"),
|
|
warriorTwo: new Audio("audio/warriorTwo.mp3"),
|
|
treasure: new Audio("audio/treasure.mp3")
|
|
},
|
|
log(msg) {
|
|
if (this.settings.debug) console.log(msg);
|
|
},
|
|
trackEvent(action, category, label, value) {
|
|
if (window.gaEnabled) {
|
|
try {
|
|
gtag('event', action, {
|
|
'event_category': category,
|
|
'event_label': label,
|
|
'value': value
|
|
});
|
|
}
|
|
catch (ex) { }
|
|
}
|
|
},
|
|
startMessageResolve: null,
|
|
serialAudio: new Audio(),
|
|
audioPlayResolve: null,
|
|
audioPlayTimeout: null,
|
|
audioMetadataListener() {
|
|
var duration = this.serialAudio.duration;
|
|
var self = this;
|
|
this.audioPlayTimeout = setTimeout(function() {
|
|
self.audioPlayTimeout = null;
|
|
var resolve = self.audioPlayResolve;
|
|
self.audioPlayResolve = null;
|
|
resolve();
|
|
}, duration * 1000);
|
|
},
|
|
playAudio(audio) {
|
|
return new Promise((resolve, reject) => {
|
|
if (this.audioPlayTimeout && this.audioPlayResolve) {
|
|
var timeout = this.audioPlayTimeout;
|
|
this.audioPlayTimeout = null;
|
|
clearTimeout(timeout);
|
|
var previousResolve = this.audioPlayResolve;
|
|
this.audioPlayResolve = null;
|
|
previousResolve();
|
|
}
|
|
this.audioPlayResolve = resolve;
|
|
this.serialAudio.src = audio.src;
|
|
this.serialAudio.play();
|
|
});
|
|
},
|
|
init() {
|
|
if (!window.URL || !window.Promise) {
|
|
alert("Sorry! Your browser is not supported.");
|
|
}
|
|
else {
|
|
let location = new URL(document.location);
|
|
if (location.searchParams.get("debug") == "1") this.settings.debug = true;
|
|
let travelSpeed = location.searchParams.get("travelSpeed");
|
|
if (!isNaN(parseInt(travelSpeed))) this.settings.travelSpeed = travelSpeed;
|
|
if (this.settings.debug) {
|
|
document.body.className = document.body.className + " debug";
|
|
var container = document.getElementById("container");
|
|
container.className = " layoutDebug";
|
|
document.addEventListener("onclick", event => {
|
|
if (event.keyCode === 88) this.maze.cancelTravel = true;
|
|
});
|
|
}
|
|
else {
|
|
document.addEventListener("contextmenu", function(event){
|
|
event.preventDefault();
|
|
}, false);
|
|
}
|
|
this.loadSettings();
|
|
this.initMenus();
|
|
this.initAudio();
|
|
this.initStartMessage();
|
|
}
|
|
},
|
|
loadSettings() {
|
|
try {
|
|
let helpEnabled = localStorage.getItem("helpEnabled");
|
|
this.toggleHelp(helpEnabled == null || helpEnabled == "true");
|
|
}
|
|
catch(ex) {}
|
|
},
|
|
saveSetting(key, value) {
|
|
try {
|
|
localStorage.setItem(key, value);
|
|
}
|
|
catch(ex) {}
|
|
},
|
|
toggleHelp(checked) {
|
|
let helpCheckbox = document.getElementById("help");
|
|
helpCheckbox.checked = checked;
|
|
let helpMessage = document.getElementById("helpMessage");
|
|
helpMessage.className = checked ? "show" : "";
|
|
this.saveSetting("helpEnabled", checked);
|
|
},
|
|
initMenus() {
|
|
var self = this;
|
|
document.getElementById("exit").onclick = function() {
|
|
self.trackEvent("Game Exit");
|
|
document.body.className = document.body.className.replace(" play", "");
|
|
};
|
|
document.getElementById("reset").onclick = function() {
|
|
self.trackEvent("Game Reset");
|
|
self.reset.call(self);
|
|
};
|
|
document.getElementById("help").onclick = function() {
|
|
self.trackEvent("Help " + (this.checked ? "Enabled" : "Disabled"));
|
|
self.toggleHelp.call(self, this.checked);
|
|
};
|
|
},
|
|
initStartMessage() {
|
|
var self = this;
|
|
document.getElementById("start").addEventListener("click", function() {
|
|
self.trackEvent("Game Started");
|
|
self.start.call(self);
|
|
});
|
|
},
|
|
initAudio() {
|
|
this.audioIndex = [
|
|
[
|
|
this.audio.dragonFlying,
|
|
this.audio.dragonAttacks,
|
|
this.audio.wall,
|
|
this.audio.illegalMove,
|
|
this.audio.warriorOne,
|
|
this.audio.warriorTwo
|
|
],
|
|
[
|
|
this.audio.defeat,
|
|
this.audio.dragonWakes,
|
|
this.audio.door,
|
|
this.audio.warriorMoves,
|
|
this.audio.winner,
|
|
this.audio.treasure
|
|
]
|
|
];
|
|
this.audioNameIndex = [
|
|
[
|
|
"Dragon Flying",
|
|
"Dragon Attacks",
|
|
"Wall",
|
|
"Illegal Move",
|
|
"Warrior One",
|
|
"Warrior Two"
|
|
],
|
|
[
|
|
"Defeat",
|
|
"Dragon Wakes",
|
|
"Door",
|
|
"Warrior Moves",
|
|
"Winner",
|
|
"Treasure"
|
|
]
|
|
];
|
|
var self = this;
|
|
this.serialAudio.addEventListener("loadedmetadata", function () {
|
|
self.audioMetadataListener.call(self)
|
|
}, false);
|
|
},
|
|
reset() {
|
|
this.initBoard();
|
|
this.initMaze().then(() => {
|
|
this.startGame();
|
|
});
|
|
},
|
|
initBoard() {
|
|
this.elements.help = document.getElementById("helpMessage");
|
|
this.elements.board = document.getElementById("board");
|
|
let board = this.elements.board;
|
|
board.innerHTML = "";
|
|
this.elements.grid = document.createElement("div");
|
|
let grid = this.elements.grid
|
|
grid.id = "grid";
|
|
this.elements.buttons = [];
|
|
this.elements.chambers = [];
|
|
var chamberPaths = this.maze.chamberPaths;
|
|
chamberPaths.splice(0);
|
|
for(let r=0; r<8; r++) {
|
|
chamberPaths.push([]);
|
|
let row = document.createElement("div");
|
|
row.className = "row";
|
|
for(let c=0; c<9; c++) {
|
|
let col = document.createElement("div");
|
|
col.className = "col";
|
|
let cell = document.createElement("div");
|
|
cell.className = "cell";
|
|
if (c == 0) {
|
|
var self = this;
|
|
col.id = "button-" + (r).toString();
|
|
col.className += " button";
|
|
if (r == 0) {
|
|
col.className += " switch";
|
|
var self = this;
|
|
col.onmousedown = function() {
|
|
self.toggleSwitch.call(self);
|
|
}
|
|
}
|
|
else if (r == 1) {
|
|
col.onmousedown = function(event) {
|
|
if (event.which == 1) {
|
|
self.nextTurn.call(self);
|
|
} else if (event.which == 3) {
|
|
self.toggleLevel.call(self);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
col.onmousedown = function(event) {
|
|
if (event.which == 1) {
|
|
self.playAudioClick.call(self, r-2, false);
|
|
} else if (event.which == 3) {
|
|
self.playAudioClick.call(self, r-2, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
chamberPaths[r].push([
|
|
r==0 ? this.PATH_TYPE.Wall : this.PATH_TYPE.Undefined,
|
|
c==8 ? this.PATH_TYPE.Wall : this.PATH_TYPE.Undefined,
|
|
r==7 ? this.PATH_TYPE.Wall : this.PATH_TYPE.Undefined,
|
|
c==1 ? this.PATH_TYPE.Wall : this.PATH_TYPE.Undefined
|
|
]);
|
|
col.id = "chamber-" + (r).toString() + "-" + (c-1).toString();
|
|
col.className += " chamber";
|
|
cell.onmousedown = function(event) {
|
|
self.chamberSelect([r, c-1], event);
|
|
}
|
|
}
|
|
if (c == 0) {
|
|
this.elements.buttons.push(col);
|
|
}
|
|
else {
|
|
if (c == 1) this.elements.chambers.push([]);
|
|
this.elements.chambers[this.elements.chambers.length - 1].push(col);
|
|
if (r < 7) {
|
|
let southWall = document.createElement("div");
|
|
southWall.className = "southWall";
|
|
col.appendChild(southWall);
|
|
}
|
|
if (c < 8) {
|
|
let eastWall = document.createElement("div");
|
|
eastWall.className = "eastWall";
|
|
col.appendChild(eastWall);
|
|
}
|
|
}
|
|
col.appendChild(cell);
|
|
row.appendChild(col);
|
|
}
|
|
grid.appendChild(row);
|
|
}
|
|
board.appendChild(grid);
|
|
},
|
|
showSep(row, col, dir, type) {
|
|
if (this.settings.debug) {
|
|
var classSuffix = type == this.PATH_TYPE.Wall ? "WallDebug" : (type == this.PATH_TYPE.Door ? "DoorDebug" : "OpenDebug");
|
|
var chamberCell = this.elements.chambers[row][col].querySelector(".cell");
|
|
var classPrefix = "";
|
|
if (dir == this.DIR_TYPE.North) classPrefix = "north";
|
|
if (dir == this.DIR_TYPE.East) classPrefix = "east";
|
|
if (dir == this.DIR_TYPE.South) classPrefix = "south";
|
|
if (dir == this.DIR_TYPE.West) classPrefix = "west";
|
|
chamberCell.className = chamberCell.className.replace(new RegExp("\\s" + classPrefix + "[^\\s]+"), "") + " " + classPrefix + classSuffix;
|
|
}
|
|
},
|
|
setPath(row, col, dir, type) {
|
|
var chamberPaths = this.maze.chamberPaths;
|
|
chamberPaths[row][col][dir] = type;
|
|
if (dir == this.DIR_TYPE.East || dir == this.DIR_TYPE.South) this.showSep(row, col, dir, type);
|
|
if (dir == this.DIR_TYPE.North && row != 0) {
|
|
chamberPaths[row - 1][col][this.DIR_TYPE.South] = type;
|
|
this.showSep(row -1 , col, this.DIR_TYPE.South, type);
|
|
} else if (dir == this.DIR_TYPE.East && col != 7) {
|
|
chamberPaths[row][col + 1][this.DIR_TYPE.West] = type;
|
|
} else if (dir == this.DIR_TYPE.South && row != 7) {
|
|
chamberPaths[row + 1][col][this.DIR_TYPE.North] = type;
|
|
} else if (dir == this.DIR_TYPE.West && col != 0) {
|
|
chamberPaths[row][col - 1][this.DIR_TYPE.East] = type;
|
|
this.showSep(row, col - 1, this.DIR_TYPE.East, type);
|
|
}
|
|
},
|
|
getPaths(row, col) {
|
|
var chamberPaths = this.maze.chamberPaths;
|
|
return {
|
|
north: chamberPaths[row][col][this.DIR_TYPE.North],
|
|
east: chamberPaths[row][col][this.DIR_TYPE.East],
|
|
south: chamberPaths[row][col][this.DIR_TYPE.South],
|
|
west: chamberPaths[row][col][this.DIR_TYPE.West]
|
|
}
|
|
},
|
|
wallOrNot() {
|
|
return Math.random() <= this.settings.wallProb ? this.PATH_TYPE.Wall : this.openOrDoor();
|
|
},
|
|
openOrDoor() {
|
|
return Math.random() <= this.settings.doorProb ? this.PATH_TYPE.Door : this.PATH_TYPE.Open;
|
|
},
|
|
travelMaze() {
|
|
return new Promise((resolve, reject) => {
|
|
var stack = this.maze.stack;
|
|
var pos = stack[stack.length - 1];
|
|
var wallProb = this.settings.wallProb;
|
|
var visited = this.maze.visited;
|
|
var chamberPaths = this.maze.chamberPaths;
|
|
var row = pos[0];
|
|
var col = pos[1];
|
|
visited[row.toString() + "_" + col.toString()] = true;
|
|
if (this.settings.debug) {
|
|
var lastChamber = this.maze.lastChamber;
|
|
var chamber = this.elements.chambers[row][col];
|
|
if (chamber.className.indexOf("traveledDebug") == -1) chamber.className += " traveledDebug";
|
|
chamber.className += " travelingDebug";
|
|
if (lastChamber) lastChamber.className = lastChamber.className.replace(" travelingDebug", "");
|
|
this.maze.lastChamber = chamber;
|
|
var chamberCell = chamber.querySelector(".cell");
|
|
if (chamberCell.innerHTML == "") chamberCell.innerHTML = stack.length;
|
|
}
|
|
if (this.settings.edgeWallBias && row > 0 && chamberPaths[row][col][this.DIR_TYPE.North] == this.PATH_TYPE.Undefined && visited[(row - 1).toString() + "_" + col.toString()]) {
|
|
this.setPath(row, col, this.DIR_TYPE.North, this.wallOrNot(col == 0 || col == 11 ? 1 : wallProb)); // Bias for keeping walls near the left/right edges
|
|
}
|
|
if (this.settings.edgeWallBias && col < 7 && chamberPaths[row][col][this.DIR_TYPE.East] == this.PATH_TYPE.Undefined && visited[row.toString() + "_" + ((col + 1).toString()).toString()]) {
|
|
this.setPath(row, col, this.DIR_TYPE.East, this.wallOrNot(row == 0 || row == 11 ? 1 : wallProb)); // Bias for keeping walls near the top/bottom edges
|
|
}
|
|
if (this.settings.edgeWallBias && row < 7 && chamberPaths[row][col][this.DIR_TYPE.South] == this.PATH_TYPE.Undefined && visited[(row + 1).toString() + "_" + col.toString()]) {
|
|
this.setPath(row, col, this.DIR_TYPE.South, this.wallOrNot(col == 0 || col == 11 ? 1 : wallProb)); // Bias for keeping walls near the left/right edges
|
|
}
|
|
if (this.settings.edgeWallBias && col > 0 && chamberPaths[row][col][this.DIR_TYPE.West] == this.PATH_TYPE.Undefined && visited[row.toString() + "_" + ((col - 1).toString()).toString()]) {
|
|
this.setPath(row, col, this.DIR_TYPE.West, this.wallOrNot(row == 0 || row == 11 ? 1 : wallProb)); // Bias for keeping walls near the top/bottom edges
|
|
}
|
|
var opts = [];
|
|
var paths = this.getPaths(row, col);
|
|
if (paths.north == this.PATH_TYPE.Undefined) {
|
|
opts.push(this.DIR_TYPE.North)
|
|
} else if (this.settings.edgeWallBias && row == 0 && paths.south == this.PATH_TYPE.Undefined) {
|
|
opts.push(this.DIR_TYPE.South); opts.push(this.DIR_TYPE.South); // Extra bias to turn south if at top
|
|
}
|
|
if (paths.east == this.PATH_TYPE.Undefined) {
|
|
opts.push(this.DIR_TYPE.East);
|
|
} else if (this.settings.edgeWallBias && col == 7 && paths.west == this.PATH_TYPE.Undefined) {
|
|
opts.push(this.DIR_TYPE.West); opts.push(this.DIR_TYPE.West); // Extra bias to turn west if at right
|
|
}
|
|
if (paths.south == this.PATH_TYPE.Undefined) {
|
|
opts.push(this.DIR_TYPE.South);
|
|
} else if (this.settings.edgeWallBias && row == 7 && paths.north == this.PATH_TYPE.Undefined) {
|
|
opts.push(this.DIR_TYPE.North); opts.push(this.DIR_TYPE.North); // Extra bias to turn north if at bottom
|
|
}
|
|
if (paths.west == this.PATH_TYPE.Undefined) {
|
|
opts.push(this.DIR_TYPE.West);
|
|
} else if (this.settings.edgeWallBias && col == 0 && paths.east == this.PATH_TYPE.Undefined) {
|
|
opts.push(this.DIR_TYPE.East); opts.push(this.DIR_TYPE.East); // Extra bias to turn east if at left
|
|
}
|
|
if (opts.length == 0) {
|
|
if (this.settings.debug) {
|
|
var popRow = stack[stack.length - 1][0];
|
|
var popCol = stack[stack.length - 1][1];
|
|
var cell = this.elements.chambers[popRow][popCol].querySelector(".cell");
|
|
cell.innerHTML = "";
|
|
}
|
|
stack.pop();
|
|
}
|
|
else {
|
|
var dir = opts[Math.floor(Math.random() * opts.length)];
|
|
this.setPath(row, col, dir, this.openOrDoor());
|
|
stack.push([
|
|
row + (dir == this.DIR_TYPE.North ? -1 : (dir == this.DIR_TYPE.South ? 1 : 0)),
|
|
col + (dir == this.DIR_TYPE.West ? -1 : (dir == this.DIR_TYPE.East ? 1 : 0))
|
|
]);
|
|
}
|
|
if (!this.maze.cancelTravel) {
|
|
var self = this;
|
|
if (stack.length > 0) {
|
|
if (this.settings.debug) {
|
|
setTimeout(function() {
|
|
self.travelMaze.call(self).then(() => resolve())
|
|
}, this.settings.travelSpeed);
|
|
}
|
|
else {
|
|
this.travelMaze().then(() => resolve());
|
|
}
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
}
|
|
});
|
|
},
|
|
removeWalls() {
|
|
return new Promise((resolve, reject) => {
|
|
if (this.settings.removeWallProb > 0 && this.settings.removeWallThreshold < 4) {
|
|
var chamberPaths = this.maze.chamberPaths;
|
|
for(let r=1; r<7; r++) {
|
|
for(let c=1; c<7; c++) {
|
|
var opts = [];
|
|
for(dir=0; dir<4; dir++) {
|
|
if (chamberPaths[r][c][dir] == this.PATH_TYPE.Wall) opts.push(dir);
|
|
}
|
|
if (opts.length >= this.settings.removeWallThreshold && Math.random() <= this.settings.removeWallProb) {
|
|
var removeDir = Math.floor(Math.random() * opts.length);
|
|
var type = this.openOrDoor();
|
|
this.setPath(r, c, opts[removeDir], type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
resolve();
|
|
});
|
|
},
|
|
initMaze() {
|
|
return new Promise((resolve, reject) => {
|
|
this.maze.stack = [[Math.floor(Math.random() * 8), Math.floor(Math.random() * 8)]];
|
|
this.maze.visited = {};
|
|
this.maze.lastChamber = null;
|
|
this.maze.cancelTravel = false;
|
|
let self = this;
|
|
this.travelMaze().then(() => setTimeout(function() {
|
|
self.removeWalls.call(self).then(() => resolve());
|
|
}, this.settings.travelSpeed));
|
|
});
|
|
},
|
|
startGame() {
|
|
this.game.level = 1
|
|
this.game.numberOfWarriors = 1;
|
|
this.game.warrior[0] = {
|
|
lives: this.settings.maxLives,
|
|
secretRoom: null,
|
|
position: null,
|
|
moves: null
|
|
};
|
|
this.game.warrior[1] = {
|
|
lives: this.settings.maxLives,
|
|
secretRoom: null,
|
|
position: null,
|
|
moves: null
|
|
};
|
|
this.game.treasure = {
|
|
room: null,
|
|
warrior: -1,
|
|
visible: false
|
|
}
|
|
this.game.dragon = {
|
|
position: null,
|
|
state: this.DRAGON_STATE.Asleep,
|
|
visible: false
|
|
};
|
|
this.selectWarriorRoom(0);
|
|
},
|
|
start() {
|
|
document.body.className += " play";
|
|
if (!this.game.init) {
|
|
this.reset();
|
|
this.game.init = true;
|
|
}
|
|
},
|
|
toggleSwitch() {
|
|
this.game.switchButtonOn = !this.game.switchButtonOn;
|
|
this.elements.buttons[0].className = this.elements.buttons[0].className.replace(" selected", "");
|
|
if (this.game.switchButtonOn) this.elements.buttons[0].className += " selected";
|
|
},
|
|
toggleSwitchOff() {
|
|
if (this.game.switchButtonOn) {
|
|
this.elements.buttons[0].className = this.elements.buttons[0].className.replace(" selected", "");
|
|
this.game.switchButtonOn = false;
|
|
}
|
|
},
|
|
toggleLevel() {
|
|
this.game.level = this.game.level == 1 ? 2 : 1;
|
|
let sound = this.game.level == 1 ? this.audio.levelOne : this.audio.levelTwo;
|
|
this.help("Switched to game level " + (this.game.level == 1 ? "one (no doors)" : "two (with doors)"));
|
|
this.playAudio(sound);
|
|
},
|
|
playAudioClick(index, secondary) {
|
|
if (!secondary) secondary = this.game.switchButtonOn ? true : false;
|
|
this.toggleSwitchOff();
|
|
let message = "Playing sound \"" + this.audioNameIndex[secondary ? 1 : 0][index] + "\"";
|
|
this.help(message, true, true);
|
|
var timestamp = (new Date()).getTime();
|
|
this.playAudio(this.audioIndex[secondary ? 1 : 0][index]).then(() => {
|
|
let duration = (new Date()).getTime() - timestamp;
|
|
if (duration < 1000) {
|
|
var self = this;
|
|
setTimeout(function() { self.resetHelpMessage.call(self); }, 1000 - duration);
|
|
}
|
|
else {
|
|
this.resetHelpMessage();
|
|
}
|
|
});
|
|
},
|
|
numToText(warriorNumber, oneText, twoText) {
|
|
return warriorNumber == 0 ? (oneText ? oneText : "one") : (twoText ? twoText : "two");
|
|
},
|
|
selectWarriorRoom(warriorNumber) {
|
|
this.game.state = warriorNumber == 0 ? this.GAME_STATE.WarriorOneSelectRoom : this.GAME_STATE.WarriorTwoSelectRoom;
|
|
this.playAudio(warriorNumber == 0 ? this.audio.warriorOne : this.audio.warriorTwo);
|
|
this.help("Pick a secret room for warrior " + this.numToText(warriorNumber, "one", "two or tap \"Next Turn\" for a one player game"))
|
|
this.log("Select secret room for warrior " + this.numToText(warriorNumber));
|
|
|
|
},
|
|
illegalWarriorRoom(warriorNumber) {
|
|
this.log("No room selected for warrior " + this.numToText(warriorNumber));
|
|
this.help("Invalid secret room", true);
|
|
this.playAudio(this.audio.illegalMove);
|
|
},
|
|
nextTurn() {
|
|
if (this.game.switchButtonOn) {
|
|
this.toggleSwitchOff();
|
|
this.toggleLevel();
|
|
}
|
|
else {
|
|
if (this.game.state == this.GAME_STATE.WarriorOneSelectRoom) {
|
|
if (!this.game.warrior[0].secretRoom) {
|
|
this.illegalWarriorRoom(0);
|
|
}
|
|
else {
|
|
this.selectWarriorRoom(1);
|
|
}
|
|
} else if (this.game.state == this.GAME_STATE.WarriorTwoSelectRoom) {
|
|
this.startTurns();
|
|
} else if (this.game.state == this.GAME_STATE.WarriorOneTurn) {
|
|
this.finishWarriorTurn(0);
|
|
} else if (this.game.state == this.GAME_STATE.WarriorTwoTurn) {
|
|
this.finishWarriorTurn(1);
|
|
}
|
|
}
|
|
},
|
|
startTurns() {
|
|
document.body.className += " gameStarted";
|
|
this.game.numberOfWarriors = this.game.warrior[1].secretRoom ? 2 : 1;
|
|
this.log("Number of players: " + this.game.numberOfWarriors);
|
|
this.setTreasureRoom();
|
|
this.log("Treasure room at: " + this.game.treasure.room);
|
|
this.warriorTurn(0);
|
|
},
|
|
warriorTurn(warriorNumber) {
|
|
this.game.state = warriorNumber == 0 ? this.GAME_STATE.WarriorOneTurn : this.GAME_STATE.WarriorTwoTurn;
|
|
let moves = this.resetWarriorMoves(warriorNumber)
|
|
let message = "Warrior " + this.numToText(warriorNumber) + "'s turn with " + moves + " move" + (moves == 1 ? "" : "s");
|
|
this.help(message);
|
|
this.log(message);
|
|
this.playAudio(warriorNumber == 0 ? this.audio.warriorOne : this.audio.warriorTwo);
|
|
},
|
|
illegalMove(warriorNumber, chamber) {
|
|
this.help("Illegal move for warrior " + this.numToText(warriorNumber), true);
|
|
this.log("Illegal move to " + chamber + " for warrior " + this.numToText(warriorNumber));
|
|
this.playAudio(this.audio.illegalMove);
|
|
},
|
|
chamberSelect(chamber, event) {
|
|
if (!this.game.delayTimeout) {
|
|
var self = this;
|
|
this.game.delayTimeout = setTimeout(function() { self.game.delayTimeout = null; }, 250);
|
|
if (!this.audioPlayTimeout) {
|
|
if (this.game.state == this.GAME_STATE.WarriorOneSelectRoom) {
|
|
this.setWarriorRoom(0, chamber);
|
|
} else if (this.game.state == this.GAME_STATE.WarriorTwoSelectRoom) {
|
|
if (chamber[0] == this.game.warrior[0].secretRoom[0] && chamber[1] == this.game.warrior[0].secretRoom[1]) {
|
|
this.playAudio(this.audio.illegalMove);
|
|
}
|
|
else {
|
|
this.setWarriorRoom(1, chamber);
|
|
}
|
|
} else if (this.game.state == this.GAME_STATE.WarriorOneTurn || this.game.state == this.GAME_STATE.WarriorTwoTurn) {
|
|
let warriorNumber = this.game.state == this.GAME_STATE.WarriorOneTurn ? 0 : 1;
|
|
this.warriorMoving(warriorNumber, chamber);
|
|
} else if (this.game.state == this.GAME_STATE.GameOver) {
|
|
this.log("Ignoring selection since game is over");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
warriorMoving(warriorNumber, chamber) {
|
|
if (this.settings.debug) {
|
|
document.querySelectorAll(".treasureOptionDebug").forEach(function(optionChamber){
|
|
optionChamber.className = optionChamber.className.replace(" treasureOptionDebug", "");
|
|
});
|
|
document.querySelectorAll(".treasureDebug").forEach(function(optionChamber){
|
|
optionChamber.className = optionChamber.className.replace(" treasureDebug", "");
|
|
});
|
|
}
|
|
let position = this.game.warrior[warriorNumber].position;
|
|
let dir = this.getMoveDirection(this.game.warrior[warriorNumber].position, chamber);
|
|
if (dir == null) {
|
|
this.illegalMove(warriorNumber, chamber);
|
|
}
|
|
else {
|
|
this.game.warrior[warriorNumber].moves--;
|
|
let type = this.getPathType(position, dir);
|
|
let warriorName = this.numToText(warriorNumber);
|
|
if (type == this.PATH_TYPE.Wall) {
|
|
let message = "Warrior " + warriorName + " moves into wall";
|
|
this.help(message, true);
|
|
this.log(message);
|
|
this.renderWall(position, dir);
|
|
this.playAudio(this.audio.wall).then(() => {
|
|
this.finishWarriorTurn(warriorNumber);
|
|
});
|
|
} else if (this.game.level == 2 && type == this.PATH_TYPE.Door) {
|
|
if (Math.random() <= this.settings.doorClosedProb) {
|
|
let message = "Warrior " + warriorName + " moves into closed door";
|
|
this.help(message);
|
|
this.log(message);
|
|
this.playAudio(this.audio.door).then(() => {
|
|
this.finishWarriorTurn(warriorNumber);
|
|
});
|
|
}
|
|
else {
|
|
this.log("Warrior " + warriorName + " moves successfully thru door");
|
|
this.warriorMoved(warriorNumber, chamber);
|
|
}
|
|
} else {
|
|
this.log("Warrior " + warriorName + " moves successfully");
|
|
this.warriorMoved(warriorNumber, chamber);
|
|
}
|
|
}
|
|
},
|
|
warriorMoved(warriorNumber, chamber) {
|
|
this.playAudio(this.audio.warriorMoves).then(() => {
|
|
this.game.warrior[warriorNumber].position = chamber;
|
|
this.renderWarriorPosition(warriorNumber);
|
|
this.checkTreasureFound(warriorNumber).then(() => {
|
|
if (this.game.treasure.warrior == warriorNumber && this.getDistance(chamber, this.game.warrior[warriorNumber].secretRoom) == 0) {
|
|
this.help("Warrior " + this.numToText(warriorNumber) + " wins!!");
|
|
this.log("Warrior " + this.numToText(warriorNumber) + " wins");
|
|
this.trackEvent("Game Won");
|
|
this.game.warrior[warriorNumber].moves = 0;
|
|
this.playAudio(this.audio.winner).then(() => {
|
|
this.game.state = this.GAME_STATE.GameOver;
|
|
});
|
|
}
|
|
else {
|
|
this.checkWarriorBattle().then(() => {
|
|
this.checkDragonWakes(warriorNumber).then(() => {
|
|
this.checkDragonAttacks().then((attacked) => {
|
|
if (attacked) {
|
|
this.game.warrior[warriorNumber].moves = 0;
|
|
}
|
|
let remainingMoves = this.game.warrior[warriorNumber].moves;
|
|
if (remainingMoves == 0) {
|
|
this.finishWarriorTurn(warriorNumber)
|
|
}
|
|
else {
|
|
let message = "Warrior " + this.numToText(warriorNumber) + " has " + remainingMoves + " move" + (remainingMoves == 1 ? "" : "s") + " remaining";
|
|
this.help(message);
|
|
this.log(message);
|
|
};
|
|
});
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
},
|
|
checkWarriorBattle() {
|
|
return new Promise((resolve, reject) => {
|
|
let bothWarriorsLive = this.game.numberOfWarriors == 2 && this.game.warrior[0].lives > 0 && this.game.warrior[1].lives > 0;
|
|
if (bothWarriorsLive && this.game.treasure.warrior >=0 && this.getDistance(this.game.warrior[0].position, this.game.warrior[1].position) == 0) {
|
|
this.log("Warriors battle for the treasure");
|
|
let winner = Math.floor(Math.random() * 2);
|
|
let message = "Warrior " + (winner == 0 ? "one" : "two") + " " + (winner == this.game.treasure.warrior ? "keeps" : "steals") + " the treasure";
|
|
this.game.treasure.warrior = winner;
|
|
this.help(message);
|
|
this.log(message);
|
|
this.playAudio(winner == 0 ? this.audio.warriorOne : this.audio.warriorTwo).then(() =>{
|
|
this.playAudio(this.audio.treasure).then(() =>{
|
|
resolve();
|
|
})
|
|
})
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
});
|
|
},
|
|
renderWall(position, dir) {
|
|
if (this.getPathType(position, dir) == this.PATH_TYPE.Wall) {
|
|
let wall = null;
|
|
if (dir == this.DIR_TYPE.North && position[0] != 0) {
|
|
wall = this.elements.chambers[position[0] - 1][position[1]].querySelector(".southWall");
|
|
} else if (dir == this.DIR_TYPE.West && position[1] != 0) {
|
|
wall = this.elements.chambers[position[0]][position[1] - 1].querySelector(".eastWall");
|
|
} else if (dir == this.DIR_TYPE.South && position[0] != 7) {
|
|
wall = this.elements.chambers[position[0]][position[1]].querySelector(".southWall");
|
|
} else if (dir == this.DIR_TYPE.East && position[1] != 7) {
|
|
wall = this.elements.chambers[position[0]][position[1]].querySelector(".eastWall");
|
|
}
|
|
if (wall) {
|
|
wall.style.visibility = "visible";
|
|
}
|
|
}
|
|
},
|
|
finishWarriorTurn(currentWarrior) {
|
|
if (this.game.state != this.GAME_STATE.GameOver) {
|
|
if (currentWarrior == 0 && this.game.numberOfWarriors == 2 && this.game.warrior[1].lives > 0) {
|
|
this.warriorTurn(1);
|
|
}
|
|
else {
|
|
this.moveDragon().then(() => {
|
|
this.warriorTurn(this.game.warrior[0].lives > 0 ? 0 : 1);
|
|
});
|
|
}
|
|
}
|
|
},
|
|
checkDragonWakes(warriorNumber) {
|
|
return new Promise((resolve, reject) => {
|
|
if (this.game.dragon.state == this.DRAGON_STATE.Asleep) {
|
|
if (this.getDistance(this.game.warrior[warriorNumber].position, this.game.warrior[warriorNumber].secretRoom) != 0) {
|
|
let dragonDistance = this.getDistance(this.game.warrior[warriorNumber].position, this.game.dragon.position);
|
|
if (dragonDistance <= this.settings.dragonWakeDistance) {
|
|
this.help("Dragon awakes!");
|
|
this.log("Dragon awakes");
|
|
this.trackEvent("Dragon Awakes");
|
|
this.playAudio(this.audio.dragonWakes).then(() => {
|
|
this.help("");
|
|
this.game.dragon.state = this.DRAGON_STATE.Awake;
|
|
resolve();
|
|
});
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
});
|
|
},
|
|
unsafeWarriors: function() {
|
|
let warriors = [];
|
|
if (this.game.warrior[0].lives > 0 && !this.warriorSafe(0)) warriors.push(0);
|
|
if (this.game.numberOfWarriors == 2 && this.game.warrior[1].lives > 0 && !this.warriorSafe(1)) warriors.push(1);
|
|
return warriors;
|
|
},
|
|
moveDragon() {
|
|
return new Promise((resolve, reject) => {
|
|
if (this.game.dragon.state == this.DRAGON_STATE.Awake) {
|
|
let dragonFlies = true;
|
|
let moveTowards = null;
|
|
let followWarrior = -1;
|
|
if (this.game.treasure.warrior < 0) {
|
|
let warriors = this.unsafeWarriors();
|
|
if (warriors.length == 2) {
|
|
let warriorOneDistance = this.getDistance(this.game.dragon.position, this.game.warrior[0].position);
|
|
let warriorTwoDistance = this.getDistance(this.game.dragon.position, this.game.warrior[1].position);
|
|
followWarrior = warriorOneDistance < warriorTwoDistance ? 0 : (warriorOneDistance > warriorTwoDistance ? 1 : Math.floor(Math.random() * 2));
|
|
}
|
|
else {
|
|
followWarrior = warriors[0];
|
|
}
|
|
}
|
|
if (this.game.treasure.warrior >= 0) {
|
|
followWarrior = this.game.treasure.warrior;
|
|
let message = "Dragon follows treasure with warrior " + (followWarrior == 0 ? "one" : "two");
|
|
this.help(message, true);
|
|
this.log(message);
|
|
moveTowards = this.game.warrior[followWarrior].position;
|
|
} else if (followWarrior >= 0) {
|
|
let message = "Dragon follows warrior " + (followWarrior == 0 ? "one" : "two");
|
|
if (this.game.dragon.visible) {
|
|
this.help(message, true);
|
|
}
|
|
else {
|
|
let warriorText = "closest warrior";
|
|
if (this.game.numberOfWarriors == 1 || this.game.warrior[1].lives == 0) {
|
|
warriorText = "warrior one";
|
|
}
|
|
else if (this.game.numberOfWarriors == 2 && this.game.warrior[0].lives == 0) {
|
|
warriorText = "warrior two";
|
|
}
|
|
this.help("Dragon follows " + warriorText, true);
|
|
}
|
|
this.log(message);
|
|
moveTowards = this.game.warrior[followWarrior].position;
|
|
}
|
|
else if (this.getDistance(this.game.dragon.position, this.game.treasure.room) > 0) {
|
|
this.log("Dragon returns towards treasure");
|
|
if (!this.game.treasure.visible) {
|
|
this.help("Dragon moves to an unknown location towards the treasure room", true);
|
|
this.log("Hiding dragon since the treasure room location is unknown");
|
|
this.game.dragon.visible = false;
|
|
}
|
|
else {
|
|
this.help("Dragon moves back towards the treasure room", true);
|
|
}
|
|
moveTowards = this.game.treasure.room;
|
|
} else {
|
|
this.log("Dragon stays in treasure room");
|
|
if (!this.game.treasure.visible) {
|
|
this.game.dragon.visible = false;
|
|
}
|
|
dragonFlies = false;
|
|
}
|
|
if (dragonFlies) {
|
|
if (moveTowards) {
|
|
let lastPosition = this.game.dragon.position;
|
|
let moveY = Math.sign(moveTowards[0] - lastPosition[0]);
|
|
let moveX = Math.sign(moveTowards[1] - lastPosition[1]);
|
|
let newPosition = [
|
|
lastPosition[0] + moveY,
|
|
lastPosition[1] + moveX
|
|
];
|
|
this.game.dragon.position = newPosition;
|
|
this.renderDragonPosition();
|
|
}
|
|
this.playAudio(this.audio.dragonFlying).then(() => {
|
|
this.checkDragonAttacks().then(() => {
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
});
|
|
},
|
|
checkDragonAttacks() {
|
|
return new Promise((resolve, reject) => {
|
|
let warriors = this.unsafeWarriors();
|
|
let self = this;
|
|
let threatenedWarriors = [];
|
|
warriors.forEach(function(warrior) {
|
|
if (self.getDistance(self.game.dragon.position, self.game.warrior[warrior].position) == 0) threatenedWarriors.push(warrior);
|
|
});
|
|
let attackWarrior = threatenedWarriors.length == 1 ? threatenedWarriors[0] : -1;
|
|
let multipleWarriors = threatenedWarriors.length == 2;
|
|
if (multipleWarriors) {
|
|
if (this.game.treasure.warrior >= 0) {
|
|
attackWarrior = this.game.treasure.warrior;
|
|
}
|
|
else {
|
|
attackWarrior = Math.floor(Math.random() * 2);
|
|
}
|
|
}
|
|
if (attackWarrior >= 0 ) {
|
|
this.dragonAttack(attackWarrior).then((attacked) => {
|
|
resolve(true);
|
|
});
|
|
}
|
|
else {
|
|
resolve(false);
|
|
}
|
|
});
|
|
},
|
|
dragonAttack(warriorNumber) {
|
|
return new Promise((resolve, reject) => {
|
|
let message = "Dragon attacks warrior " + this.numToText(warriorNumber);
|
|
this.help(message);
|
|
this.log(message);
|
|
if (!this.game.dragon.visible) {
|
|
this.game.dragon.visible = true;
|
|
this.renderDragonPosition();
|
|
}
|
|
this.playAudio(warriorNumber == 0 ? this.audio.warriorOne : this.audio.warriorTwo).then(() => {
|
|
this.completeAttack(warriorNumber).then(() => {
|
|
resolve();
|
|
});
|
|
});
|
|
});
|
|
},
|
|
completeAttack(warriorNumber) {
|
|
return new Promise((resolve, reject) => {
|
|
if (this.game.treasure.warrior == warriorNumber) this.game.treasure.warrior = -1;
|
|
this.playAudio(this.audio.dragonAttacks).then(() => {
|
|
this.help("");
|
|
this.renderTreasurePosition();
|
|
this.removeLife(warriorNumber).then(() => {
|
|
resolve();
|
|
})
|
|
});
|
|
});
|
|
},
|
|
removeLife(warriorNumber) {
|
|
return new Promise((resolve, reject) => {
|
|
this.game.warrior[warriorNumber].lives--;
|
|
let lives = this.game.warrior[warriorNumber].lives;
|
|
this.log("Warrior " + this.numToText(warriorNumber) + " has " + lives + " lives");
|
|
if (lives < 1) {
|
|
this.killWarrior(warriorNumber).then(() => {
|
|
resolve();
|
|
});
|
|
}
|
|
else {
|
|
this.help("Warrior " + this.numToText(warriorNumber) + " has " + lives + " lives left", true);
|
|
var secretRoom = this.game.warrior[warriorNumber].secretRoom;
|
|
this.game.warrior[warriorNumber].position = secretRoom;
|
|
this.renderWarriorPosition(warriorNumber);
|
|
resolve();
|
|
}
|
|
});
|
|
},
|
|
killWarrior(warriorNumber) {
|
|
return new Promise((resolve, reject) => {
|
|
let message = "Warrior " + this.numToText(warriorNumber) + " has been killed!";
|
|
if (this.game.warrior[0].lives < 1 && (this.game.numberOfWarriors == 1 || this.game.warrior[1].lives < 1)) {
|
|
this.game.state = this.GAME_STATE.GameOver;
|
|
this.trackEvent("Game Lost");
|
|
}
|
|
this.trackEvent("Warrior Killed");
|
|
this.help(message, true);
|
|
this.log(message);
|
|
this.playAudio(this.audio.defeat).then(() => {
|
|
this.removeWarrior(warriorNumber);
|
|
this.removeSecretRoom(warriorNumber);
|
|
resolve();
|
|
});
|
|
});
|
|
},
|
|
checkTreasureFound(warriorNumber) {
|
|
return new Promise((resolve, reject) => {
|
|
let warriorPosition = this.game.warrior[warriorNumber].position;
|
|
let treasureRoom = this.game.treasure.room;
|
|
if (this.game.treasure.warrior < 0 && this.getDistance(warriorPosition, treasureRoom) == 0) {
|
|
let message = "Warrior " + this.numToText(warriorNumber) + " found the treasure!";
|
|
this.trackEvent("Treasure Found");
|
|
this.help(message, true);
|
|
this.log(message);
|
|
this.game.warrior[warriorNumber].moves = 0;
|
|
this.game.treasure.warrior = warriorNumber;
|
|
this.game.treasure.visible = true;
|
|
this.renderTreasureMarker();
|
|
this.renderTreasurePosition();
|
|
this.playAudio(this.audio.treasure).then(() => {
|
|
resolve();
|
|
})
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
});
|
|
},
|
|
renderTreasureMarker() {
|
|
let treasureRoom = this.game.treasure.room;
|
|
let treasureMarker = document.createElement("div");
|
|
treasureMarker.className = "treasureRoom";
|
|
let chamberElement = this.elements.chambers[treasureRoom[0]][treasureRoom[1]];
|
|
chamberElement.appendChild(treasureMarker);
|
|
},
|
|
warriorSafe(warriorNumber) {
|
|
return this.getDistance(this.game.warrior[warriorNumber].position, this.game.warrior[warriorNumber].secretRoom) == 0;
|
|
},
|
|
resetWarriorMoves(warriorNumber) {
|
|
let moves = this.settings.movesPerLife + (this.game.warrior[warriorNumber].lives * this.settings.movesPerLife);
|
|
if (this.game.treasure.warrior == warriorNumber) moves = this.settings.movesWithTreasure;
|
|
this.game.warrior[warriorNumber].moves = moves;
|
|
return moves;
|
|
},
|
|
getMoveDirection(startPos, nextPos) {
|
|
let dir = null;
|
|
let distance = this.getDistance(startPos, nextPos);
|
|
if (distance == 1) {
|
|
let y = startPos[0] - nextPos[0];
|
|
let x = startPos[1] - nextPos[1];
|
|
if (y == 1) {
|
|
dir = this.DIR_TYPE.North;
|
|
} else if (y == -1) {
|
|
dir = this.DIR_TYPE.South;
|
|
} else if (x == 1) {
|
|
dir = this.DIR_TYPE.West;
|
|
} else if (x == -1) {
|
|
dir = this.DIR_TYPE.East;
|
|
}
|
|
}
|
|
return dir;
|
|
},
|
|
getPathType(position, dir) {
|
|
return this.maze.chamberPaths[position[0]][position[1]][dir];
|
|
},
|
|
setWarriorRoom(warriorNumber, chamber) {
|
|
this.help("Pick a different room or tap \"Next Turn\"");
|
|
this.log("Secret room for warrior " + this.numToText(warriorNumber) + " is " + chamber.toString());
|
|
if (this.settings.debug) {
|
|
document.querySelectorAll(".traveledDebug,.travelingDebug").forEach(function(chamber) {
|
|
chamber.className = chamber.className.replace(" traveledDebug", "").replace(" travelingDebug", "");
|
|
});
|
|
var container = document.querySelector("#container:not(.layoutDebug)");
|
|
if (container) container.className += " layoutDebug";
|
|
}
|
|
this.playAudio(this.audio.warriorMoves);
|
|
this.removeSecretRoom(warriorNumber);
|
|
let markerClass = "secretRoom" + this.numToText(warriorNumber, "One", "Two");
|
|
let warriorMarker = document.createElement("div");
|
|
warriorMarker.className = markerClass;
|
|
let chamberElement = this.elements.chambers[chamber[0]][chamber[1]];
|
|
chamberElement.appendChild(warriorMarker);
|
|
this.game.warrior[warriorNumber].secretRoom = chamber;
|
|
this.game.warrior[warriorNumber].position = chamber;
|
|
this.renderWarriorPosition(warriorNumber);
|
|
},
|
|
removeSecretRoom(warriorNumber) {
|
|
let secretRoom = this.game.warrior[warriorNumber].secretRoom;
|
|
let markerClass = "secretRoom" + this.numToText(warriorNumber, "One", "Two");
|
|
if (secretRoom) {
|
|
let chamberElement = this.elements.chambers[secretRoom[0]][secretRoom[1]];
|
|
let warriorMarker = chamberElement.querySelector("." + markerClass);
|
|
if (warriorMarker) {
|
|
chamberElement.removeChild(warriorMarker);
|
|
}
|
|
}
|
|
},
|
|
renderWarriorPosition(warriorNumber) {
|
|
this.removeWarrior(warriorNumber);
|
|
let name = "warrior" + this.numToText(warriorNumber, "One", "Two");
|
|
let position = this.game.warrior[warriorNumber].position;
|
|
let warriorMarker = document.createElement("div");
|
|
warriorMarker.id = name;
|
|
warriorMarker.className = name;
|
|
warriorMarker.style.zIndex = (position[0] * 100) + warriorNumber + 1;
|
|
let chamberElement = this.elements.chambers[position[0]][position[1]];
|
|
chamberElement.appendChild(warriorMarker);
|
|
if (this.game.treasure.warrior == warriorNumber) this.renderTreasurePosition();
|
|
},
|
|
removeWarrior(warriorNumber) {
|
|
let name = "warrior" + this.numToText(warriorNumber, "One", "Two");
|
|
let warriorElement = document.getElementById(name);
|
|
if (warriorElement) {
|
|
warriorElement.parentNode.removeChild(warriorElement);
|
|
}
|
|
},
|
|
renderDragonPosition() {
|
|
let dragonElement = document.getElementById("dragon");
|
|
if (dragonElement) {
|
|
dragonElement.parentNode.removeChild(dragonElement);
|
|
}
|
|
if (this.game.dragon.visible || this.settings.debug) {
|
|
let position = this.game.dragon.position;
|
|
let dragonMarker = document.createElement("div");
|
|
dragonMarker.id = "dragon";
|
|
dragonMarker.className = "dragon";
|
|
dragonMarker.style.zIndex = (position[0] * 100) + 4;
|
|
let chamberElement = this.elements.chambers[position[0]][position[1]];
|
|
chamberElement.appendChild(dragonMarker);
|
|
}
|
|
},
|
|
renderTreasurePosition() {
|
|
if (this.game.treasure.visible || this.settings.debug) {
|
|
let treasureElement = document.getElementById("treasure");
|
|
if (treasureElement) {
|
|
treasureElement.parentNode.removeChild(treasureElement);
|
|
}
|
|
let withWarrior = this.game.treasure.warrior >= 0;
|
|
let position = this.game.treasure.room;
|
|
if (withWarrior) {
|
|
position = this.game.warrior[this.game.treasure.warrior].position;
|
|
}
|
|
let treasureMarker = document.createElement("div");
|
|
treasureMarker.id = "treasure";
|
|
treasureMarker.className = "treasure" + (withWarrior ? " withWarrior" : "");
|
|
treasureMarker.style.zIndex = (position[0] * 100) + 3;
|
|
let chamberElement = this.elements.chambers[position[0]][position[1]];
|
|
chamberElement.appendChild(treasureMarker);
|
|
}
|
|
},
|
|
setTreasureRoom() {
|
|
let opts = [];
|
|
for(let row=0; row<8; row++) {
|
|
for(let col=0; col<8; col++) {
|
|
if (this.getDistance([row,col], this.game.warrior[0].secretRoom) > this.settings.treasureRoomDistance) {
|
|
if (this.game.numberOfWarriors == 1 || this.getDistance([row,col], this.game.warrior[1].secretRoom) > this.settings.treasureRoomDistance) {
|
|
opts.push([row,col]);
|
|
if (this.settings.debug) this.elements.chambers[row][col].className += " treasureOptionDebug";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
let treasurePos = this.game.treasure.room = opts[Math.floor(Math.random() * opts.length)];
|
|
if (this.settings.debug) this.elements.chambers[treasurePos[0]][treasurePos[1]].className += " treasureDebug";
|
|
this.game.treasure.room = treasurePos;
|
|
this.game.dragon.position = treasurePos;
|
|
if (this.settings.debug) {
|
|
this.renderDragonPosition();
|
|
this.renderTreasurePosition();
|
|
}
|
|
},
|
|
getDistance(posA, posB) {
|
|
return Math.abs(posA[0] - posB[0]) + Math.abs(posA[1] - posB[1]);
|
|
},
|
|
help(message, temporary, skipTimeout) {
|
|
if (!temporary) {
|
|
this.game.helpMessage = message;
|
|
}
|
|
if (temporary || !this.game.helpTimeout) {
|
|
this.elements.help.innerText = message;
|
|
if (temporary && !skipTimeout) {
|
|
if (this.game.helpTimeout) clearTimeout(this.game.helpTimeout);
|
|
var self = this;
|
|
this.game.helpTimeout = setTimeout(function() {
|
|
self.game.helpTimeout = null;
|
|
self.resetHelpMessage.call(self);
|
|
}, 2500);
|
|
}
|
|
}
|
|
},
|
|
resetHelpMessage() {
|
|
this.elements.help.innerText = this.game.helpMessage;
|
|
}
|
|
}
|
|
window.addEventListener('DOMContentLoaded', (event) => { labyrinth.init() });
|