|
|
@ -1,6 +1,6 @@ |
|
|
|
!(function() { |
|
|
|
!(function () { |
|
|
|
|
|
|
|
|
|
|
|
class Svg { |
|
|
|
class Svg { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Build a node from XML |
|
|
|
* Build a node from XML |
|
|
|
* |
|
|
|
* |
|
|
@ -38,70 +38,70 @@ class Svg { |
|
|
|
static fromXMLg(code, wrapperOpts = null) { |
|
|
|
static fromXMLg(code, wrapperOpts = null) { |
|
|
|
return Svg.fromXML(code, 'g', wrapperOpts); |
|
|
|
return Svg.fromXML(code, 'g', wrapperOpts); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* --------- Shared Constants --------- */ |
|
|
|
/* --------- Shared Constants --------- */ |
|
|
|
const BOARD_SIZE = 121; |
|
|
|
const BOARD_SIZE = 121; |
|
|
|
|
|
|
|
|
|
|
|
const METAL_SEQ = ['lead', 'tin', 'iron', 'copper', 'silver', 'gold']; |
|
|
|
const METAL_SEQ = ['lead', 'tin', 'iron', 'copper', 'silver', 'gold']; |
|
|
|
|
|
|
|
|
|
|
|
const SYMBOLS_METALS = [ |
|
|
|
const SYMBOLS_METALS = [ |
|
|
|
'mercury', 'lead', 'tin', 'iron', 'copper', 'silver', 'gold' |
|
|
|
'mercury', 'lead', 'tin', 'iron', 'copper', 'silver', 'gold' |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
const SYMBOLS_ALL = [ |
|
|
|
const SYMBOLS_ALL = [ |
|
|
|
'salt', 'air', 'fire', 'water', 'earth', 'mercury', 'lead', |
|
|
|
'salt', 'air', 'fire', 'water', 'earth', 'mercury', 'lead', |
|
|
|
'tin', 'iron', 'copper', 'silver', 'gold', 'mors', 'vitae' |
|
|
|
'tin', 'iron', 'copper', 'silver', 'gold', 'mors', 'vitae' |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Convert grid coordinates to gameGrid array index |
|
|
|
* Convert grid coordinates to gameGrid array index |
|
|
|
* |
|
|
|
* |
|
|
|
* @param {Number} x |
|
|
|
* @param {Number} x |
|
|
|
* @param {Number} y |
|
|
|
* @param {Number} y |
|
|
|
* @returns {Number} |
|
|
|
* @returns {Number} |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
function xyToGridIndex(x, y) { |
|
|
|
function xyToGridIndex(x, y) { |
|
|
|
return y * 11 + x |
|
|
|
return y * 11 + x |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Convert grid index to X, Y |
|
|
|
* Convert grid index to X, Y |
|
|
|
* |
|
|
|
* |
|
|
|
* @param {Number} index |
|
|
|
* @param {Number} index |
|
|
|
* @returns {{x: Number, y: Number}} |
|
|
|
* @returns {{x: Number, y: Number}} |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
function gridIndexToXy(index) { |
|
|
|
function gridIndexToXy(index) { |
|
|
|
return { |
|
|
|
return { |
|
|
|
x: index % 11, |
|
|
|
x: index % 11, |
|
|
|
y: Math.floor(index / 11) |
|
|
|
y: Math.floor(index / 11) |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Get if a coordinate is outside the game board. |
|
|
|
* Get if a coordinate is outside the game board. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param x |
|
|
|
* @param x |
|
|
|
* @param y |
|
|
|
* @param y |
|
|
|
* @return {boolean|boolean} |
|
|
|
* @return {boolean|boolean} |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
function isXyOutside(x, y) { |
|
|
|
function isXyOutside(x, y) { |
|
|
|
return x < 0 |
|
|
|
return x < 0 |
|
|
|
|| x > 10 |
|
|
|
|| x > 10 |
|
|
|
|| y < 0 |
|
|
|
|| y < 0 |
|
|
|
|| y > 10 |
|
|
|
|| y > 10 |
|
|
|
|| (y <= 5 && x > 5 + y) |
|
|
|
|| (y <= 5 && x > 5 + y) |
|
|
|
|| (y > 5 && x < y - 5); |
|
|
|
|| (y > 5 && x < y - 5); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Game board |
|
|
|
* Game board |
|
|
|
* |
|
|
|
* |
|
|
|
* Orb grid coordinates: |
|
|
|
* Orb grid coordinates: |
|
|
|
* x - grid X coordinate (counted from the left edge of a triangle starting in the top left corner) |
|
|
|
* x - grid X coordinate (counted from the left edge of a triangle starting in the top left corner) |
|
|
|
* y - grid Y coordinate (row) |
|
|
|
* y - grid Y coordinate (row) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
class Board { |
|
|
|
class Board { |
|
|
|
constructor() { |
|
|
|
constructor() { |
|
|
|
this.$bg = document.getElementById('boardbg'); |
|
|
|
this.$bg = document.getElementById('boardbg'); |
|
|
|
this.$orbs = document.getElementById('orbs'); |
|
|
|
this.$orbs = document.getElementById('orbs'); |
|
|
@ -601,14 +601,14 @@ class Board { |
|
|
|
getOrbByIndex(n) { |
|
|
|
getOrbByIndex(n) { |
|
|
|
return this.grid[n]; |
|
|
|
return this.grid[n]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Random number generator |
|
|
|
* Random number generator |
|
|
|
* |
|
|
|
* |
|
|
|
* Uses Mullbery32 from https://stackoverflow.com/a/47593316/2180189
|
|
|
|
* Uses Mullbery32 from https://stackoverflow.com/a/47593316/2180189
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
class Rng { |
|
|
|
class Rng { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Construct with a given or random seed |
|
|
|
* Construct with a given or random seed |
|
|
|
* |
|
|
|
* |
|
|
@ -651,9 +651,9 @@ class Rng { |
|
|
|
nextInt(max) { |
|
|
|
nextInt(max) { |
|
|
|
return Math.floor((max + 1) * this.next()); |
|
|
|
return Math.floor((max + 1) * this.next()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class SettingsStorage { |
|
|
|
class SettingsStorage { |
|
|
|
constructor() { |
|
|
|
constructor() { |
|
|
|
// this object is never overwritten, references are stable
|
|
|
|
// this object is never overwritten, references are stable
|
|
|
|
this.settings = { |
|
|
|
this.settings = { |
|
|
@ -695,9 +695,9 @@ class SettingsStorage { |
|
|
|
save() { |
|
|
|
save() { |
|
|
|
localStorage.setItem('sigmar_settings', JSON.stringify(this.settings)); |
|
|
|
localStorage.setItem('sigmar_settings', JSON.stringify(this.settings)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class Game { |
|
|
|
class Game { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Init the game |
|
|
|
* Init the game |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -944,7 +944,7 @@ class Game { |
|
|
|
const allo = template.includes(i); |
|
|
|
const allo = template.includes(i); |
|
|
|
allowedTable.push(allo); |
|
|
|
allowedTable.push(allo); |
|
|
|
|
|
|
|
|
|
|
|
let { x, y } = gridIndexToXy(i); |
|
|
|
let {x, y} = gridIndexToXy(i); |
|
|
|
if (!allo && !isXyOutside(x, y)) { |
|
|
|
if (!allo && !isXyOutside(x, y)) { |
|
|
|
outsideTemplate.push(i); |
|
|
|
outsideTemplate.push(i); |
|
|
|
} |
|
|
|
} |
|
|
@ -973,7 +973,7 @@ class Game { |
|
|
|
this.board.grid[n] = null; |
|
|
|
this.board.grid[n] = null; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const findAvailableIndexWithNeighbours = (count, except=null) => { |
|
|
|
const findAvailableIndexWithNeighbours = (count, except = null) => { |
|
|
|
let candidates = []; |
|
|
|
let candidates = []; |
|
|
|
for (let i = 0; i < template.length; i++) { |
|
|
|
for (let i = 0; i < template.length; i++) { |
|
|
|
const n = template[i]; |
|
|
|
const n = template[i]; |
|
|
@ -994,7 +994,7 @@ class Game { |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const findAvailableIndex = (except=null) => { |
|
|
|
const findAvailableIndex = (except = null) => { |
|
|
|
for (let i = 6; i >= 0; i--) { |
|
|
|
for (let i = 6; i >= 0; i--) { |
|
|
|
const n = findAvailableIndexWithNeighbours(i, except); |
|
|
|
const n = findAvailableIndexWithNeighbours(i, except); |
|
|
|
if (n !== false) return n; |
|
|
|
if (n !== false) return n; |
|
|
@ -1277,19 +1277,16 @@ class Game { |
|
|
|
this.board.removeOrbByIndex(n); |
|
|
|
this.board.removeOrbByIndex(n); |
|
|
|
this.selectedOrb = null; |
|
|
|
this.selectedOrb = null; |
|
|
|
wantRefresh = true; |
|
|
|
wantRefresh = true; |
|
|
|
} |
|
|
|
} else if (this.selectedOrb === null) { |
|
|
|
else if (this.selectedOrb === null) { |
|
|
|
|
|
|
|
// first selection
|
|
|
|
// first selection
|
|
|
|
this.selectedOrb = { n, orb }; |
|
|
|
this.selectedOrb = {n, orb}; |
|
|
|
orb.node.classList.add('selected'); |
|
|
|
orb.node.classList.add('selected'); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
if (this.selectedOrb.n === n) { |
|
|
|
if (this.selectedOrb.n === n) { |
|
|
|
// orb clicked twice
|
|
|
|
// orb clicked twice
|
|
|
|
orb.node.classList.remove('selected'); |
|
|
|
orb.node.classList.remove('selected'); |
|
|
|
this.selectedOrb = null; |
|
|
|
this.selectedOrb = null; |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
// second orb in a pair
|
|
|
|
// second orb in a pair
|
|
|
|
const otherSymbol = this.selectedOrb.orb.symbol; |
|
|
|
const otherSymbol = this.selectedOrb.orb.symbol; |
|
|
|
|
|
|
|
|
|
|
@ -1308,7 +1305,7 @@ class Game { |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// Bad selection, select it as the first orb.
|
|
|
|
// Bad selection, select it as the first orb.
|
|
|
|
this.selectedOrb.orb.node.classList.remove('selected'); |
|
|
|
this.selectedOrb.orb.node.classList.remove('selected'); |
|
|
|
this.selectedOrb = { n, orb }; |
|
|
|
this.selectedOrb = {n, orb}; |
|
|
|
orb.node.classList.add('selected'); |
|
|
|
orb.node.classList.add('selected'); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -1395,10 +1392,10 @@ class Game { |
|
|
|
this.nextMetal = METAL_SEQ[METAL_SEQ.indexOf(this.nextMetal) + 1]; |
|
|
|
this.nextMetal = METAL_SEQ[METAL_SEQ.indexOf(this.nextMetal) + 1]; |
|
|
|
console.debug(`Next metal unlocked: ${this.nextMetal}`); |
|
|
|
console.debug(`Next metal unlocked: ${this.nextMetal}`); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Start */ |
|
|
|
/* Start */ |
|
|
|
|
|
|
|
|
|
|
|
window.game = new Game(); |
|
|
|
window.game = new Game(); |
|
|
|
|
|
|
|
|
|
|
|
})(); |
|
|
|
})(); |
|
|
|