392 lines
No EOL
8.8 KiB
JavaScript
392 lines
No EOL
8.8 KiB
JavaScript
// Variables
|
|
/// Game
|
|
var tilesGrid = [];
|
|
var tilesShown = [];
|
|
var flagsGrid = [];
|
|
var playing = true;
|
|
/// For loops
|
|
var rippling = false;
|
|
/// Games
|
|
var flags = gridBombs;
|
|
|
|
// Functions
|
|
/// Private
|
|
function _checkWin(){
|
|
// Matches
|
|
var matches = 0;
|
|
|
|
for(var y = 0; y < gridHeight; y++){
|
|
for(var x = 0; x < gridWidth; x++){
|
|
if(flagsGrid[y*gridHeight+x]
|
|
&& tilesGrid[y*gridHeight+x]){
|
|
matches++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(matches >= gridBombs){
|
|
_winGame();
|
|
}
|
|
}
|
|
function _updateScreen(){
|
|
// Mode of tile?
|
|
var tileMode = 0;
|
|
|
|
// Thing
|
|
for(var y = 0; y < gridHeight; y++){
|
|
for(var x = 0; x < gridWidth; x++){
|
|
// Drawing with CANVAS
|
|
let _tileWidth = UI_Canvas.width / gridWidth;
|
|
let _tileHeight = UI_Canvas.height / gridHeight;
|
|
|
|
// Drawing
|
|
/// New Object
|
|
ctx.beginPath();
|
|
|
|
/// Color?
|
|
ctx.fillStyle = "#ffffff";
|
|
|
|
// Game over, show mines
|
|
if(!playing
|
|
&& tilesGrid[y*gridHeight+x] == 1){
|
|
tileMode = 0;
|
|
}
|
|
// Numbered tiles
|
|
else if(!tilesGrid[y*gridHeight+x]
|
|
&& tilesShown[y*gridHeight+x]){
|
|
tileMode = 1;
|
|
}
|
|
// Flag tiles
|
|
else if(flagsGrid[y*gridHeight+x]){
|
|
tileMode = 2;
|
|
}
|
|
// Standard tiles
|
|
else{
|
|
tileMode = 3;
|
|
}
|
|
|
|
// What tile mode do we use?
|
|
switch(tileMode){
|
|
case 0:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 2,0, 16,16);
|
|
break;
|
|
case 1:
|
|
|
|
// Todo: Add numbered tiles support
|
|
switch(_getNumber(x,y)){
|
|
case "":
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 3,0, 16,16);
|
|
break;
|
|
case 1:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 0,1, 16,16);
|
|
break;
|
|
case 2:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 1,1, 16,16);
|
|
break;
|
|
case 3:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 2,1, 16,16);
|
|
break;
|
|
case 4:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 3,1, 16,16);
|
|
break;
|
|
case 5:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 0,2, 16,16);
|
|
break;
|
|
case 6:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 1,2, 16,16);
|
|
break;
|
|
case 7:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 2,2, 16,16);
|
|
break;
|
|
case 8:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 3,2, 16,16);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 2:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 1,0, 16,16);
|
|
break;
|
|
|
|
case 3:
|
|
drawTileMap("data/icons.png", x, y, _tileWidth, _tileHeight, 0,0, 16,16);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Win check
|
|
_checkWin();
|
|
|
|
// UI
|
|
UI_Flags.textContent = flags;
|
|
console.log(flags);
|
|
}
|
|
function _startGrid(){
|
|
/*
|
|
This is different from _createGrid
|
|
|
|
this will just start up the systems.
|
|
_createGrid will be triggered when you first click
|
|
making the grid spawn
|
|
*/
|
|
|
|
// Reset grid
|
|
tilesGrid = [];
|
|
tilesShown = [];
|
|
|
|
// Loops for Grids
|
|
for(var y = 0; y < gridHeight; y++){
|
|
for(var x = 0; x < gridWidth; x++){
|
|
// Add to shown
|
|
tilesGrid.push(0);
|
|
tilesShown.push(0);
|
|
flagsGrid.push(0);
|
|
}
|
|
}
|
|
}
|
|
function _createGrid(){
|
|
// Mouse to cursor pos
|
|
// Get mouse position
|
|
var _mx = mousePosition[0];
|
|
var _my = mousePosition[1];
|
|
|
|
// Convert it to local grid space
|
|
_mx -= UI_Canvas.offsetLeft;
|
|
_my -= UI_Canvas.offsetTop;
|
|
|
|
// Convert _mx and _my to be able to be used to find the tile the user wants
|
|
let _x = Math.floor(_mx / (UI_Canvas.width / gridWidth));
|
|
let _y = Math.floor(_my / (UI_Canvas.height / gridHeight));
|
|
|
|
// Random Bombs
|
|
for(var i = 0; i < gridBombs; i++){
|
|
// Placeholder positions
|
|
var _bx = 0;
|
|
var _by = 0;
|
|
|
|
// Checking for an unused space
|
|
while(true){
|
|
_bx = parseInt(Math.random() * 10);
|
|
_by = parseInt(Math.random() * 10);
|
|
|
|
if(tilesGrid[_by*gridHeight+_bx] == 0
|
|
&& _bx != _x && _by != _y){
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Apply position
|
|
tilesGrid[_by*gridHeight+_bx] = 1;
|
|
}
|
|
}
|
|
|
|
function _chkTile(x,y){
|
|
return tilesGrid[y*gridHeight+x];
|
|
}
|
|
function _setTile(x,y, val){
|
|
tilesShown[y*gridHeight+x] = val;
|
|
}
|
|
|
|
function _getNumber(x,y){
|
|
// Result number
|
|
var result = 0;
|
|
|
|
// Go through all tiles
|
|
for(var _y = y-1; _y < y+2; _y++){
|
|
for(var _x = x-1; _x < x+2; _x++){
|
|
if((_y >= 0 && _y < gridHeight)
|
|
&& (_x >= 0 && _x < gridWidth)){
|
|
if(_chkTile(_x,_y) > 0){
|
|
result++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(result == 0){
|
|
result = "";
|
|
}
|
|
|
|
// Return result
|
|
return result;
|
|
}
|
|
|
|
function spawnRipple(x, y) {
|
|
// Tile with bombs near?
|
|
if(_getNumber(x,y) != ""){
|
|
rippling = false;
|
|
return;
|
|
}
|
|
|
|
// Checking if this is a bad tile..
|
|
for (var _y = -1; _y < 2; _y++) {
|
|
for (var _x = -1; _x < 2; _x++) {
|
|
// Checking for things that will cause it to fail
|
|
if (_x == 0 && _y == 0) {
|
|
continue;
|
|
}
|
|
if (x + _x < 0 || x + _x >= gridWidth || y + _y < 0 || y + _y >= gridHeight) {
|
|
continue;
|
|
}
|
|
|
|
// No diagonal
|
|
if((_x == -1 && _y == -1)
|
|
|| (_x == -1 && _y == 1)
|
|
|| (_x == 1 && _y == -1)
|
|
|| (_x == 1 && _y == 1)){
|
|
continue;
|
|
}
|
|
|
|
// Bombs near?
|
|
if(_getNumber(x+_x, y+_y) != ""){
|
|
tilesShown[(y + _y) * gridWidth + (x + _x)] = 1;
|
|
continue;
|
|
}
|
|
|
|
// The beef and potatoes!
|
|
if (!tilesShown[(y + _y) * gridWidth + (x + _x)] && !_chkTile(x + _x, y + _y)) {
|
|
tilesShown[(y + _y) * gridWidth + (x + _x)] = 1;
|
|
spawnRipple(x + _x, y + _y);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Checking for a fail
|
|
for (var _y = -1; _y < 2; _y++) {
|
|
for (var _x = -1; _x < 2; _x++) {
|
|
// Checking for things that will cause it to fail
|
|
if (_x == 0 && _y == 0) {
|
|
continue;
|
|
}
|
|
if (x + _x < 0 || x + _x >= gridWidth || y + _y < 0 || y + _y >= gridHeight) {
|
|
continue;
|
|
}
|
|
|
|
// The beef and potatoes!
|
|
if (!tilesShown[(y + _y) * gridWidth + (x + _x)] && !_chkTile(x + _x, y + _y)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Failing..
|
|
rippling = false;
|
|
}
|
|
function _revealTiles(x, y) {
|
|
// Are we clicking on a flag?
|
|
if(flagsGrid[y*gridHeight+x] != 0){return};
|
|
|
|
// Set clicked tile
|
|
_setTile(x, y, 1);
|
|
|
|
// RIPPLE EFFECT METHOD
|
|
rippling = true;
|
|
// Force ripple ending if things carry on forever
|
|
setTimeout(function(){
|
|
rippling = false;
|
|
}, 1500);
|
|
|
|
// Ripple!
|
|
while(rippling){
|
|
spawnRipple(x,y);
|
|
}
|
|
|
|
// You messed up..
|
|
if (tilesGrid[y * gridWidth + x]) {
|
|
_endGame();
|
|
}
|
|
}
|
|
function _clickTile(){
|
|
// The whole reason I was going to use Divs is because
|
|
// It would have been easier but.. No.. Of course not
|
|
// Javascript is Never simple or it never works like C/C++ does.
|
|
|
|
// Get mouse position
|
|
var _mx = mousePosition[0];
|
|
var _my = mousePosition[1];
|
|
|
|
// Convert it to local grid space
|
|
_mx -= UI_Canvas.offsetLeft;
|
|
_my -= UI_Canvas.offsetTop;
|
|
|
|
// Convert _mx and _my to be able to be used to find the tile the user wants
|
|
let _x = Math.floor(_mx / (UI_Canvas.width / gridWidth));
|
|
let _y = Math.floor(_my / (UI_Canvas.height / gridHeight));
|
|
|
|
console.log(_x, _y);
|
|
|
|
// Check if we need to init the grid
|
|
let sum = 0;
|
|
for(var i = 0; i < tilesGrid.length; i++){
|
|
sum += tilesGrid[i];
|
|
}
|
|
if(sum == 0){
|
|
_createGrid();
|
|
}
|
|
|
|
// Update
|
|
_revealTiles(_x, _y);
|
|
}
|
|
function _addFlag(event){
|
|
// Prevent default
|
|
event.preventDefault();
|
|
|
|
// Too many flags?
|
|
if(flags <= 0){
|
|
return;
|
|
}
|
|
|
|
// Get mouse position
|
|
var _mx = mousePosition[0];
|
|
var _my = mousePosition[1];
|
|
|
|
// Convert it to local grid space
|
|
_mx -= UI_Canvas.offsetLeft;
|
|
_my -= UI_Canvas.offsetTop;
|
|
|
|
// Convert _mx and _my to be able to be used to find the tile the user wants
|
|
let _x = Math.floor(_mx / (UI_Canvas.width / gridWidth));
|
|
let _y = Math.floor(_my / (UI_Canvas.height / gridHeight));
|
|
|
|
// Now, let's add the flag!
|
|
flagsGrid[_y*gridHeight+_x] = !flagsGrid[_y*gridHeight+_x];
|
|
|
|
console.log("New Flag: " + flagsGrid[_y*gridHeight+_x]);
|
|
}
|
|
function _getFlags(){
|
|
flags = gridBombs;
|
|
for(var y = 0; y < gridHeight; y++){
|
|
for(var x = 0; x < gridWidth; x++){
|
|
if(flagsGrid[y*gridHeight+x] == 1){
|
|
flags--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Public
|
|
function _endGame(){
|
|
alert("YOU HIT A MINE!");
|
|
playing = false;
|
|
}
|
|
function _winGame(){
|
|
alert("You Won!");
|
|
}
|
|
function _onUpdate(){
|
|
// Drawing:
|
|
_getFlags();
|
|
_updateScreen();
|
|
}
|
|
function _onStart(){
|
|
// Init
|
|
_startGrid();
|
|
|
|
// Start loop
|
|
thread = window.setInterval(_onUpdate, 3);
|
|
}
|
|
|
|
// Events
|
|
window.addEventListener("load", _onStart);
|
|
UI_Canvas.addEventListener("click", _clickTile);
|
|
UI_Canvas.addEventListener("contextmenu", _addFlag); |