xxxxxxxxxx
538
// The Labyrinth is based on the book Dictionary of Khazars by Milorad Pavic. Original texts are from the book.
// Maze template reference to @Grilly86 and Maze generation algorithm on Wikipedia.
// Images are from open source.
// Game concept: Ardak Mukanova, 2020.
// You are in the flow of time. You can travel in time, but you can not control your travel. Be careful on your way. Try not to be stuck in limbo.
// Rules: create your path to the exit. Collect artifacts on your way. You can collect artifacts and texts only while passing through them. Reveal hidden objects by clicking on your path. Try to create your individual story. While entering the exit you appear in the new room.
// Use WASD or arrow keys. Press SHIFT to hide the array grid. Press SHIFT to reveal the maze pattern.
var cellStack = [0];
var cols = 48
var rows = 24;
var cellWidth = 20;
var cells = [];
var currentCell = 0;
var wallWidth = 4;
var playerPos = 0;
var posHistory = [0];
var KEY_D = 68;
var KEY_A = 65;
var KEY_W = 87;
var KEY_S = 83;
var BG_COLOR = 255;
var WALL_COLOR = 0;
var TRACK_COLOR = 100;
var TARGET_COLOR = 0;
var mg;
var pg;
let egg, keys, letter, mirror, lantern, padlock, ring, salt, sword, book;
let tx1 = 'In his pocket were the key that augured death and the egg that could save him from a deadly day... The egg was marked with a date, the key with a small gold handle.';
let tx2 = 'They believe that in the life of every man there are knot points, small parts of time like keys. Hence, every Khazar had his own stick and in the course of his life would put notches on it, carving states of clear consciousness or moments of the sublime fulfillment of life. Each of these markings was named after an animal or a precious stone. And called a "dream." To the Khazars, therefore, a dream was not just the day of our nights; it could also be the mysterious starry night of our days.';
let tx3 = 'The letters of language! Here we come to the bottom of the shadow. The earth`s alphabet mirrors heaven`s and shares the fate of language!';
let tx4 = 'Both were made of shiny salt, but one was fast and the other slow. Whatever the fast mirror picked up, reflecting the world like an advance on the future, the slow mirror returned, settling the debt of the former, because it was as slow in relation to the present as the other was fast.';
let tx5 = 'He could kill a fish in the water with his saber, or at night hang a lantern on a sword impaled in the ground and then, when his enemy was facing the light, attack him from the darkness with a knife. He marked each of these movements with a different sign of the zodiac, and each star of these constellations represented a single death.';
let tx6 = 'Be careful, in future, not to place the cross on the lock like that, when the spirit is residing outside the book. It fears the cross and, not daring to go back into the book, it wreaks havoc all around.';
let tx7 = 'He wore different-colored rings, each color corresponding to a note on the tennote scale he used. He would show the singers one of his fingers, depending on the color of the ring, and it would call forth the voice it sought, just as every animal chooses its own kind of food; then they sang unerringly, although they had never heard the song before.';
let tx8 = 'The letters of the Khazar alphabet take their names from salted foods, and the numbers from types of salt; the Khazars recognize seven types of salt. Only the salty regard of God does not cause aging; otherwise the Khazars believe that aging comes from looking at one`s own body or another`s, because looks plow and tear through bodies with the most varied and lethal tools, creating their passions, hates, plans, and cravings.';
let tx9 = 'An apple tree stood there, and he waited for the wind to blow. When it did, and the apples began falling, he knew he would not be able to spike any of them with his sword. He turned out to be right, confirming that he was swifter and quicker with his sword in his sleep than when awake. Maybe that was because he practiced in his dreams.';
let tx10 = 'I dreamed I was wading through waist-high water, reading a book. The water was the Kura River, muddy, full of weeds, the kind you drink through your hair or beard. Whenever a big wave comes along I lift up my book to keep it from getting wet, and then continue reading.';
function preload() {
egg = loadImage('pngegg_small.png');
keys = loadImage('key_small.png');
letter = loadImage('pngwing_small.png');
mirror = loadImage('mirror_small.png');
lantern = loadImage('lantern_small.png');
padlock = loadImage('padlock_small.png');
ring = loadImage('ring_small.png');
salt = loadImage('salt_small.png');
sword = loadImage('sword_small.png');
book = loadImage('palm-leaf_small.png');
}
function randomizeColors() {
var hue = random(360);
BG_COLOR = color(hue, 200, 0);
TRACK_COLOR = color(hue, 150, 150);
WALL_COLOR = color(hue, 100, 255);
}
function setup() {
// dynamic fullscreen setup
// createCanvas(window.innerWidth,window.innerHeight);
// cols=Math.floor(width / cellWidth);
// rows=Math.floor(height / cellWidth);
// fixed size setup
colorMode(HSB);
var w = cols * cellWidth;
var h = rows * cellWidth;
randomizeColors();
TARGET_COLOR = color(0, 100, 100);
createCanvas(w, h);
pixelDensity(1);
mg = createGraphics(w, h);
pg = createGraphics(w, h);
wallWidth = cellWidth / 30;
generateMaze();
updatePlayerGraphics();
}
function draw() {
image(mg, 0, 0);
image(pg, 0, 0);
// hidden grid reveal with SHIFT
for (let x = 0; x < 200; x++) {
for (let y = 0; y < 100; y++) { //inside loop
ellipse(x * 20, y * 20, 15, 15);
}
}
if (keyCode === SHIFT) {
blendMode(ADD);
fill(255, 0, 0);
ellipse(mouseX, mouseY, 100, 100);
} else {
blendMode(BLEND); // to the default mode
}
// // egg
// fill(255);
// rect(450, 450, 50, 50);
// //letter
// fill(255);
// rect(600, 0, 50, 50);
// //keys
// fill(255);
// rect(50, 100, 50, 50);
// //mirror
// fill(255);
// rect(250, 250, 50, 50);
// // lantern
// fill(255);
// rect(900, 150, 50, 50);
// // padlock
// fill(255);
// rect(700, 350, 50, 50);
// // ring
// fill(255);
// rect(0, 350, 50, 50);
// // salt
// fill(255);
// rect(400, 80, 50, 50);
// // sword
// fill(255);
// rect(600, 180, 50, 50);
// // book
// fill(255);
// rect(910, 300, 50, 50);
// for egg
if (checkState(mouseX, mouseY, 450, 450, 50, 50) && mouseIsPressed === true) {
image(egg, 440, 430, 65, 50);
console.log('In his pocket were the key that augured death and the egg that could save him from a deadly day... The egg was marked with a date, the key with a small gold handle.');
fill(0);
rect(455, 375, 195, 50);
fill(200);
textSize(10);
text(tx1, 455, 375, 200, 200); // wraps within the text box
}
// for letter
if (checkState(mouseX, mouseY, 600, 0, 50, 50) && mouseIsPressed === true) {
image(letter, 600, 0, 50, 50);
console.log('The letters of language! Here we come to the bottom of the shadow. The earth`s alphabet mirrors heaven`s and shares the fate of language!');
fill(0);
rect(640, 50, 195, 50);
fill(200);
textSize(10);
text(tx3, 640, 50, 200, 200); // wraps within the text box
}
// for keys
if (checkState(mouseX, mouseY, 50, 100, 50, 50) && mouseIsPressed === true) {
image(keys, 50, 100, 60, 60);
console.log('They believe that in the life of every man there are knot points, small parts of time like keys. Hence, every Khazar had his own stick and in the course of his life would put notches on it, carving states of clear consciousness or moments of the sublime fulfillment of life. Each of these markings was named after an animal or a precious stone. And called a "dream." To the Khazars, therefore, a dream was not just the day of our nights; it could also be the mysterious starry night of our days.');
fill(0);
rect(120, 100, 200, 150);
fill(200);
textSize(10);
text(tx2, 120, 100, 200, 200); // wraps within the text box
}
// for mirror
if (checkState(mouseX, mouseY, 250, 250, 50, 50) && mouseIsPressed === true) {
image(mirror, 250, 250, 50, 70);
console.log('Both were made of shiny salt, but one was fast and the other slow. Whatever the fast mirror picked up, reflecting the world like an advance on the future, the slow mirror returned, settling the debt of the former, because it was as slow in relation to the present as the other was fast.');
fill(0);
rect(300, 250, 200, 90);
fill(200);
textSize(10);
text(tx4, 305, 250, 200, 200); // wraps within the text box
}
// for lantern
if (checkState(mouseX, mouseY, 900, 150, 50, 50) && mouseIsPressed === true) {
image(lantern, 900, 150, 60, 60);
console.log('He could kill a fish in the water with his saber, or at night hang a lantern on a sword impaled in the ground and then, when his enemy was facing the light, attack him from the darkness with a knife. He marked each of these movements with a different sign of the zodiac, and each star of these constellations represented a single death.');
fill(0);
rect(760, 50, 200, 100);
fill(200);
textSize(10);
text(tx5, 760, 50, 200, 200); // wraps within the text box
}
// for padlock
if (checkState(mouseX, mouseY, 700, 350, 50, 50) && mouseIsPressed === true) {
image(padlock, 700, 350, 50, 50);
console.log('Be careful, in future, not to place the cross on the lock like that, when the spirit is residing outside the book. It fears the cross and, not daring to go back into the book, it wreaks havoc all around.');
fill(0);
rect(700, 280, 200, 60);
fill(200);
textSize(10);
text(tx6, 700, 280, 200, 200); // wraps within the text box
}
// for ring
if (checkState(mouseX, mouseY, 0, 350, 50, 50) && mouseIsPressed === true) {
image(ring, 0, 350, 50, 50);
console.log('He wore different-colored rings, each color corresponding to a note on the tennote scale he used. He would show the singers one of his fingers, depending on the color of the ring, and it would call forth the voice it sought, just as every animal chooses its own kind of food; then they sang unerringly, although they had never heard the song before.');
fill(0);
rect(60, 350, 210, 100);
fill(200);
textSize(10);
text(tx7, 60, 350, 210, 200); // wraps within the text box
}
// for salt
if (checkState(mouseX, mouseY, 400, 80, 50, 50) && mouseIsPressed === true) {
image(salt, 400, 80, 60, 60);
console.log('The letters of the Khazar alphabet take their names from salted foods, and the numbers from types of salt; the Khazars recognize seven types of salt. Only the salty regard of God does not cause aging; otherwise the Khazars believe that aging comes from looking at one`s own body or another`s, because looks plow and tear through bodies with the most varied and lethal tools, creating their passions, hates, plans, and cravings.');
fill(0);
rect(400, 140, 200, 130);
fill(200);
textSize(10);
text(tx8, 400, 140, 210, 200); // wraps within the text box
}
// for sword
if (checkState(mouseX, mouseY, 600, 180, 50, 50) && mouseIsPressed === true) {
image(sword, 600, 180, 60, 60);
console.log('An apple tree stood there, and he waited for the wind to blow. When it did, and the apples began falling, he knew he would not be able to spike any of them with his sword. He turned out to be right, confirming that he was swifter and quicker with his sword in his sleep than when awake. Maybe that was because he practiced in his dreams.');
fill(0);
rect(600, 240, 200, 100);
fill(200);
textSize(10);
text(tx9, 600, 240, 210, 200); // wraps within the text box
}
// for book
if (checkState(mouseX, mouseY, 910, 300, 50, 50) && mouseIsPressed === true) {
image(book, 895, 290, 60, 60);
console.log('I dreamed I was wading through waist-high water, reading a book. The water was the Kura River, muddy, full of weeds, the kind you drink through your hair or beard. Whenever a big wave comes along I lift up my book to keep it from getting wet, and then continue reading.');
fill(0);
rect(760, 350, 190, 90);
fill(200);
textSize(10);
text(tx10, 760, 350, 200, 200); // wraps within the text box
}
if (keyIsPressed) {
updatePlayerGraphics();
}
}
function keyReleased() {
triggeredBefore = 0;
}
function keyPressed() {
updatePlayerGraphics();
}
var triggeredBefore;
function updatePlayerGraphics() {
if (triggeredBefore > millis() - 150) return;
triggeredBefore = millis();
var px = getX(playerPos);
var py = getY(playerPos);
if (py > 0 && (keyIsDown(UP_ARROW) || keyIsDown(KEY_W)) && cells[playerPos].walls[0] == false) {
py -= 1;
} else if (py < rows - 1 && (keyIsDown(DOWN_ARROW) || keyIsDown(KEY_S)) && cells[playerPos].walls[2] == false) {
py += 1;
} else if (px < cols - 1 && (keyIsDown(RIGHT_ARROW) || keyIsDown(KEY_D)) && cells[playerPos].walls[1] == false) {
px += 1;
} else if (px > 0 && (keyIsDown(LEFT_ARROW) || keyIsDown(KEY_A)) && cells[playerPos].walls[3] == false) {
px -= 1;
}
var newPos = getIndex(px, py);
if (newPos !== playerPos) {
playerPos = newPos;
posHistory.push(newPos);
if (cells[playerPos].type == "end") {
setTimeout(function() {
generateMaze();
}, 300);
}
}
var drawX = px * cellWidth + cellWidth / 2;
var drawY = py * cellWidth + cellWidth / 2;
pg.clear();
for (var i = 0; i < posHistory.length - 1; i++) {
pg.strokeWeight(cellWidth / 3);
pg.stroke(TRACK_COLOR);
var i1 = posHistory[i];
var x1 = getX(i1) * cellWidth + cellWidth / 2;
var y1 = getY(i1) * cellWidth + cellWidth / 2;
var i2 = posHistory[i + 1];
var x2 = getX(i2) * cellWidth + cellWidth / 2;
var y2 = getY(i2) * cellWidth + cellWidth / 2;
pg.line(x1, y1, x2, y2)
}
pg.strokeWeight(2);
pg.fill(0, 255, 255);
pg.stroke(10, 60, 10);
pg.ellipse(drawX, drawY, cellWidth / 2);
}
// for egg
function checkState(mX, mY, posX, posY, w, h) {
if ((mX >= posX && mX <= posX + w) && (mY >= posY && mY <= posY + h)) {
return true;
} else {
return false;
}
}
function getIndex(x, y) {
return x + y * cols;
}
function getX(i) {
return i % cols;
}
function getY(i) {
return Math.floor(i / cols);
}
function generateMaze() {
playerPos = 0;
triggeredBefore = null;
posHistory = [0];
randomizeColors();
mg.clear();
cells = [];
currentCell = 0;
for (var y = 0; y < rows; y++) {
for (var x = 0; x < cols; x++) {
var type = "default";
if (x == 0 && y == 0) {
type = "start";
}
if (x == cols - 1 && y == rows - 1) {
type = "end";
}
cells.push(new Cell(x, y, cellWidth / 2, type));
}
}
var countSteps = 0;
while (typeof currentCell !== "undefined") {
countSteps++;
currentCell = generateMazeStep();
}
//console.log("MAZE GENERATED IN " + countSteps + " STEPS.");
mg.background(BG_COLOR);
for (var i = 0; i < cells.length; i++) {
cells[i].draw();
}
updatePlayerGraphics();
}
function generateMazeStep() {
var cc = cells[currentCell];
cc.visited = true;
var nextCell = selectUnvisitedNeighbor(currentCell);
if (typeof nextCell !== "undefined") {
cellStack.push(nextCell);
var nc = cells[nextCell];
nc.visited = true;
nc.removeWallBetween(cc);
} else {
nextCell = cellStack.shift();
}
return nextCell;
}
function selectUnvisitedNeighbor(ci) {
var neighbors = [];
var x = getX(ci);
var y = getY(ci);
if (x > 0) {
var i = getIndex(x - 1, y);
if (!cells[i].visited) {
neighbors.push(i);
}
}
if (x < cols - 1) {
var i = getIndex(x + 1, y);
if (!cells[i].visited) {
neighbors.push(i);
}
}
if (y > 0) {
var i = getIndex(x, y - 1);
if (!cells[i].visited) {
neighbors.push(i);
}
}
if (y < rows - 1) {
var i = getIndex(x, y + 1);
if (!cells[i].visited) {
neighbors.push(i);
}
}
//console.log("neighbors of " + getX(currentCell) + ":" + getY(currentCell));
//console.log(neighbors);
return random(neighbors);
}
function Cell(x, y, r, type) {
this.x = x;
this.y = y;
this.r = r;
this.walls = [true, true, true, true];
this.visited = false;
this.type = type || "default";
}
Cell.prototype.draw = function() {
var x1 = this.x * cellWidth;
var y1 = this.y * cellWidth;
var x2 = x1 + this.r * 2;
var y2 = y1 + this.r * 2;
mg.noFill();
mg.stroke(WALL_COLOR);
mg.strokeWeight(wallWidth);
if (this.walls[0]) {
// top
mg.line(x1, y1, x2, y1);
}
if (this.walls[1]) {
// right
mg.line(x2, y1, x2, y2);
}
if (this.walls[2]) {
//bottom
mg.line(x1, y2, x2, y2);
}
if (this.walls[3]) {
//left
mg.line(x1, y1, x1, y2);
}
if (this.type == "end") {
mg.noStroke();
mg.fill(TARGET_COLOR);
mg.ellipse(x1 + cellWidth / 2, y1 + cellWidth / 2, cellWidth / 2);
}
}
Cell.prototype.removeWallBetween = function(other) {
var dx = this.x - other.x;
var dy = this.y - other.y;
if (dx == 1 && dy == 0) {
// remove left wall
this.walls[3] = false;
other.walls[1] = false;
} else if (dx == -1 && dy == 0) {
// remove right wall
this.walls[1] = false;
other.walls[3] = false;
} else if (dy == 1 && dx == 0) {
// remove bottom wall
this.walls[0] = false;
other.walls[2] = false;
} else if (dy == -1 && dx == 0) {
// remove top wall
this.walls[2] = false;
other.walls[0] = false;
}
}