// Global Constants
MAX_HEALTH = 10;
// Global Variables
var board = [[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0]];
var view;
var player = {x:0,y:0,health:MAX_HEALTH};
var narrative = "";
var drops = [];
var gems = 0;
var bombs = 0;
var aceOfHearts = false;
var aceOfDiams = false;
var aceOfClubs = false;
var aceOfSpades = false;
/* PURPOSE: to return a psuedorandom integer between the min and max parameters
PARAMETERS: min - minimum possible value to be returned
max - maximum possible value to be returned
*///RETURNS: newNumber - a psuedorandom integer that is either between or is one of the min or max paramters
function randomRange(min,max)
{
var newNumber = Math.floor((Math.random() * (max - min)) + min);
return newNumber;
}
// PURPOSE: to output the gameboard as a table of html entities and characters to the webpage
function drawBoard()
{
// Declare Variables
var outputBoard = document.getElementById("board");
var outputHTML;
// Initialize
outputHTML = "";
// Create table cells from the board array
for(var i = 0; i < 6; i++) // x axis
{
outputHTML += "<tr>";
for(var j = 0; j < 6; j++) // y axis
{
if (view[i][j] === false && board[i][j] !== "P")
{
outputHTML += "<td class=\"text-muted\">?</td>";
}
else
{
switch (board[i][j])
{
case "K":
outputHTML += "<td class=\"text-danger\">K</td>";
break;
case "Q":
outputHTML += "<td class=\"text-danger\">Q</td>";
break;
case "J":
outputHTML += "<td class=\"text-danger\">J</td>";
break;
case "S":
outputHTML += "<td>♠</td>";
break;
case "C":
outputHTML += "<td>♣</td>";
break;
case "D":
outputHTML += "<td>♦</td>";
break;
case "H":
outputHTML += "<td>♥</td>";
break;
case "P":
if (player.health > 0)
{
outputHTML += "<td class=\"text-primary\"><b>@</b></td>";
}
else
{
outputHTML += "<td class=\"text-danger\"><b>@</b></td>";
}
break;
case "W":
outputHTML += "<td><b>#</b></td>";
break;
case "h":
outputHTML += "<td>♡</td>";
break;
case "dh":
outputHTML += "<td class=\"text-danger\">♡</td>";
break;
case "g":
outputHTML += "<td>♢</td>";
break;
case "dg":
outputHTML += "<td class=\"text-danger\">♢</td>";
break;
case "B":
outputHTML += "<td>⚪</td>";
break;
case "dB":
outputHTML += "<td class=\"text-danger\">⚪</td>";
break;
case "":
outputHTML += "<td></td>";
break;
default:
outputHTML += "<td>Error: " + board[i][j] + "</td>";
}
}
}
outputHTML += "</tr>";
}
// Output to the page
outputBoard.innerHTML = outputHTML;
}
// PURPOSE: to output game information health, gems, bombs, and crystals collected to the webpage
function displayGameInfo()
{
// Declare Variables
var aces = "";
// Count Aces
if (aceOfClubs) { aces += "♣"; }
if (aceOfDiams) { aces += "♦"; }
if (aceOfHearts) { aces += "♥"; }
if (aceOfSpades) { aces += "♠"; }
// Display Player Info On The Page
document.getElementById("health").innerHTML = player.health;
document.getElementById("gems").innerHTML = gems;
document.getElementById("bombs").innerHTML = bombs;
document.getElementById("jewels").innerHTML = aces;
}
// PURPOSE: to update the array mapping which cells in the table the player is able to view
function updateView()
{
// North
if ((player.y-1) >= 0)
{
view[player.x][player.y-1] = true;
// North East
if ((player.x+1) <= 5)
{
view[player.x+1][player.y-1] = true;
}
}
// East
if ((player.x+1) <= 5)
{
view[player.x+1][player.y] = true;
// South East
if ((player.y+1) <= 5)
{
view[player.x+1][player.y+1] = true;
}
}
// South
if ((player.y+1) <= 5)
{
view[player.x][player.y+1] = true;
// South West
if ((player.x-1) >= 0)
{
view[player.x-1][player.y+1] = true;
}
}
// West
if ((player.x-1) >= 0)
{
view[player.x-1][player.y] = true;
// North West
if ((player.y-1) >= 0)
{
view[player.x-1][player.y-1] = true;
}
}
}
// PURPOSE: to check adjacent tiles for anything the player interacts with inherently by being next to. these currently consist only of enemy characters
function checkAdjacent()
{
// Declare Variables
var cellsX = [];
var cellsY = [];
var cell;
// Set Coordinates
cellsX[0] = player.x-1; // North
cellsY[0] = player.y;
cellsX[1] = player.x; // East
cellsY[1] = player.y+1;
cellsX[2] = player.x+1; // South
cellsY[2] = player.y;
cellsX[3] = player.x; // West
cellsY[3] = player.y-1;
// Check for enemies
for(var i = 0; i < 4; i++)
{
// If the target tile to view is on the board
if (cellsX[i] >= 0 && cellsX[i] <= 5 && cellsY[i] >= 0 && cellsY[i] <= 5)
{
// Get its contents
cell = board[cellsX[i]][cellsY[i]];
// Check if it is an enemy. If it is, take the appropriate amount of health from the player before removing it
switch(cell)
{
case "K":
player.health -= 3;
board[cellsX[i]][cellsY[i]] = drops.pop();
narrative += " You find your self face to face with a giant King Crab. Your sword pierces the soft underside of it's shell as it latches onto your nose with it's claw. It finally breaths its last leaving you down 3 health points.";
narrative += "<span class=\"text-danger\"><b><br />-3 HP<br /></b></span>"
break;
case "Q":
player.health -= 2;
board[cellsX[i]][cellsY[i]] = drops.pop();
narrative += " In the distance you spot a large yellow structure. As you approach you find it to be an enormous bee hive. Your realization comes too late as you are surrounded by the minions of the Queen Bee. You light them ablaze with fire magic, but not before recieving a few painful stings and a loss of 2 health points.";
narrative += "<span class=\"text-danger\"><b><br />-2 HP<br /></b></span>"
break;
case "J":
player.health -= 1;
board[cellsX[i]][cellsY[i]] = drops.pop();
narrative += " A large pot flies through the air landing firmly against your forehead. You chase down the culprit and teach them what for. Unfortunatly this doesn't replenish the health point you've lost.";
narrative += "<span class=\"text-danger\"><b><br />-1 HP<br /></b></span>"
break;
}
// Set players health text to red if less than 4
if (player.health < 4)
{
document.getElementById("health").className = " text-danger";
}
}
}
}
// PURPOSE: to check the table cell the player has moved to for items and if found add the item to the appropriate counter variable
function pickUpItem()
{
// Declare Variables
var item = board[player.x][player.y];
// Add item to appropriate counter
switch (item)
{
case "S":
aceOfSpades = true;
narrative += "<span class=\"text-success\"><b> You find the Obsidian Spade upon an ornate pedistol. Carefully, you remove it from its resting place.</b></span><br />";
break;
case "C":
aceOfClubs = true;
narrative += "<span class=\"text-success\"><b> The Emerald Clover catches your eye as you nearly walk over it. You proudly claim it for your own.</b></span><br />";
break;
case "D":
aceOfDiams = true;
narrative += "<span class=\"text-success\"><b> Set in the wall you find the largest Diamond you have ever seen. You quickly pocket it and move on.</b></span><br />";
break;
case "H":
aceOfHearts = true;
narrative += "<span class=\"text-success\"><b> At the bottom of a pool of water, nearly frozen over, you spot the Ruby Heart. Talk about cold... You gently dry it off and place it in your satchel.</b></span><br />";
break;
case "B":
case "dB":
bombs++;
document.getElementById("bombs").className = " text-success";
narrative += " On the ground near the defeated menace is a small bomb. This could be usefull.<br />";
break;
case "h":
case "dh":
// Increase health 1 per heart pickup
player.health++;
if (player.health > 3)
{
document.getElementById("health").className = " text-success";
}
narrative += " You feel your strength returning as you regain 1 health point.";
narrative += "<span class=\"text-success\"><b><br />+1 HP<br /></b></span>"
break;
case "g":
case "dg":
gems++;
narrative += " You find a small gemstone on the ground. This could be quite valuable.<br />";
break;
}
}
// PURPOSE: to check if the player has collected all 4 crystals and congratulate them if they have
function checkWin()
{
if (aceOfClubs && aceOfDiams && aceOfHearts && aceOfSpades)
{
// Congratulate the player on their victory
narrative += "<span class=\"text-success\"><br /><b>You've done it. The crystals are yours! You are now a legend.</b><br /></span>";
}
}
// PURPOSE: to check if the player has run out of health and died and inform them if they have
function checkLose()
{
if (player.health <= 0)
{
player.health = 0;
displayGameInfo();
// Tell the player they lost
narrative += "<span class=\"text-danger\"><br /><b>Your ghost lingers, haunting the confines of the crystal cave.</b><br /></span>";
}
}
// PURPOSE: to output collected narration text for the given turn to the webpage
function narrate()
{
document.getElementById("textOutput").innerHTML = "<b>" + narrative + "</b>";
narrative = "";
}
// PURPOSE: to reset the viewmap so the player can't see the whole map when they start
function setView()
{
view = [[false,false,false,false,false,false],[false,false,false,false,false,false],
[false,false,false,false,false,false],[false,false,false,false,false,false],
[false,false,false,false,false,false],[false,false,false,false,false,false]];
narrative += " A fog fills the space, settling as you move through it.";
}
// PURPOSE: to generate the starting conditions for the game
function setBoard()
{
// Declare Variables
var deck = ["K","K","K","K",
"Q","Q","Q","Q",
"J","J","J","J",
"S","C","D","H",
"P",
"W","W","W","W",
"W","W","W","W","W",
"h","h","h","h","h",
"g","g","g","g","g"];
var tmp;
var target;
var deckLoopCounter;
// Shuffle the Array
for(var i = 0; i < 36; i++)
{
tmp = deck[i];
target = randomRange(i,35);
deck[i] = deck[target];
deck[target] = tmp;
}
// Layout the array onto the board
deckLoopCounter = 0;
for(var i = 0; i < 6; i++) // x axis
{
for(var j = 0; j < 6; j++) // y axis
{
board[i][j] = deck[deckLoopCounter];
//find and store the players location (P)
if (board[i][j] === "P")
{
player.x = i;
player.y = j;
}
deckLoopCounter++;
}
}
// Set up item drop deck
drops = ["dB","dB","dB","dg",
"dg","dg","dh","dh",
"dh","dh","dh","dh",];
// Shuffle item drop deck
for(var i = 0; i < 12; i++)
{
tmp = drops[i];
target = randomRange(i,11);
drops[i] = drops[target];
drops[target] = tmp;
}
// Set game counters to default values
player.health = MAX_HEALTH;
gems = 0;
//hearts = 0;
bombs = 0;
aceOfHearts = false;
aceOfDiams = false;
aceOfClubs = false;
aceOfSpades = false;
// Reset text display classes
document.getElementById("health").className = "";
document.getElementById("bombs").className = "";
// Reset the view array
setView();
updateView();
// Begin the adventure narrative
narrative += " You find yourself, once again, in a cave. It's been about a month since your arrival. <span class=\"text-success\">Your mission: To collect the four great crystaline gem stones.</span> Crystals growing from the floor shimmer brightly as if to show you the way.<br /><br />";
// Draw the Board
checkAdjacent();
drawBoard();
displayGameInfo();
narrate();
}
// PURPOSE: called directly from the webpage, to use a bomb item and remove walls around the player character
function placeBomb ()
{
if (bombs > 0)
{
// Declare Variables
var cellsX = [];
var cellsY = [];
// Set Coordinates to check
cellsX[0] = player.x-1; // North
cellsY[0] = player.y;
cellsX[1] = player.x; // East
cellsY[1] = player.y+1;
cellsX[2] = player.x+1; // South
cellsY[2] = player.y;
cellsX[3] = player.x; // West
cellsY[3] = player.y-1;
// Check each adjacent square to the player for a wall
for(var i = 0; i < 4; i++)
{
// If the target tile to view is on the board
if (cellsX[i] >= 0 && cellsX[i] <= 5 && cellsY[i] >= 0 && cellsY[i] <= 5)
{
// If there is a wall, remove it.
if (board[cellsX[i]][cellsY[i]] === "W")
{
board[cellsX[i]][cellsY[i]] = "";
}
}
}
bombs--;
}
else
{
document.getElementById("bombs").className = "text-danger";
}
displayGameInfo();
drawBoard();
narrative += "<span class=\"text-danger\"> An ear shattering explosion resonates throughout the cave as walls around you fall away.</span>";
narrate();
}
// PURPOSE: called directly from the webpage, to move the character to an adjacent table cell
function movePlayer(direction)
{
direction = Number(direction);
// Remove the player character
board[player.x][player.y] = "";
// Move player in the direction according to input
switch (direction)
{
// North
case 0:
if ((player.x-1) >= 0 && board[player.x-1][player.y] !== "W")
{
player.x--;
}
break;
// East
case 1:
if ((player.y+1) <= 5 && board[player.x][player.y+1] !== "W")
{
player.y++;
}
break;
// South
case 2:
if ((player.x+1) <= 5 && board[player.x+1][player.y] !== "W")
{
player.x++;
}
break;
// West
case 3:
if ((player.y-1) >= 0 && board[player.x][player.y-1] !== "W")
{
player.y--;
}
break;
}
updateView();
pickUpItem();
// Place the player character
board[player.x][player.y] = "P";
checkAdjacent();
drawBoard();
displayGameInfo();
checkWin();
checkLose();
narrate();
}