FalloutRisk/scss/dist/index.js

651 lines
28 KiB
JavaScript

"use strict";
/*===============================
RISK
===============================*/
//SVG map adapted from https://commons.wikimedia.org/wiki/File:Risk_board.svg
//Built using svg, sass and plain javascript
/* Instructions
Aim: To control all the areas on the map
You control the dark blue areas
Every turn you get additional troops to place on the map.
The number of troops is increased by:
* Owning more areas
* Increases slightly after each turn
* Controlling all areas on a continent
To place a troop click on an area you control when it's the fortify stage
Once your reserve is 0 the stage changes to the battle stage.
To attack an opponent select an area you control to attack from and a neighbouring opponent to attack
You must have a least one troop to attack an opponent.
If you win the opponents territory will become yours and remaining troops will split between the two areas
If you lose the troops in your area will become 0
Click 'End Turn' to continue the game and pass control to the AI
*/
/* Data */
var continents = [{
areas: ["indonesia", "new_guinea", "eastern_australia", "western_australia"],
name: "oceania",
bonus: 2
}, {
areas: ["brazil", "peru", "venezuela", "argentina"],
name: "South America",
bonus: 2
}, {
areas: ["egypt", "north_africa", "east_africa", "congo", "south_africa", "madagascar"],
name: "africa",
bonus: 3
}, {
areas: ["iceland", "uk", "scandinavia", "northern_europe", "western_europe", "ukraine", "southern_europe"],
name: "europe",
bonus: 5
}, {
areas: ["central_america", "eastern_us", "western_us", "quebec", "ontario", "alberta", "northwest_territory", "alaska", "greenland"],
name: "North America",
bonus: 5
}, {
areas: ["middle_east", "afghanistan", "ural", "siberia", "irkutsk", "yakutsk", "kamchatka", "mongolia", "japan", "china", "siam", "india"],
name: "asia",
bonus: 7
}];
var countries = [{ name: "indonesia", continent: "oceania", owner: "none", color: "white", "army": 0, neighbours: ["siam", "western_australia", "new_guinea"] }, { name: "new_guinea", continent: "oceania", owner: "none", color: "white", "army": 0, neighbours: ["indonesia", "eastern_australia", "western_australia"] }, { name: "eastern_australia", continent: "oceania", owner: "none", color: "white", "army": 0, neighbours: ["western_australia", "new_guinea"] }, { name: "western_australia", continent: "oceania", owner: "none", color: "white", "army": 0, neighbours: ["eastern_australia", "new_guinea", "indonesia"] }, { name: "ural", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["ukraine", "siberia", "afghanistan", "china"] }, { name: "siberia", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["ural", "mongolia", "yakutsk", "irkutsk", "china"] }, { name: "afghanistan", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["ukraine", "ural", "middle_east", "china", "india"] }, { name: "irkutsk", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["yakutsk", "siberia", "kamchatka", "mongolia"] }, { name: "yakutsk", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["irkutsk", "siberia", "kamchatka"] }, { name: "kamchatka", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["alaska", "yakutsk", "japan", "irkutsk", "mongolia"] }, { name: "middle_east", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["ukraine", "afghanistan", "india", "egypt", "east_africa", "southern_europe"] }, { name: "india", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["middle_east", "siam", "afghanistan", "china"] }, { name: "siam", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["indonesia", "india", "china"] }, { name: "china", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["ural", "siberia", "afghanistan", "mongolia", "siam", "india"] }, { name: "mongolia", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["irkutsk", "siberia", "kamchatka", "china", "japan"] }, { name: "japan", continent: "asia", owner: "none", color: "white", "army": 0, neighbours: ["kamchatka", "mongolia"] }, { name: "egypt", continent: "africa", owner: "none", color: "white", "army": 0, neighbours: ["middle_east", "southern_europe", "north_africa", "east_africa"] }, { name: "north_africa", continent: "africa", owner: "none", color: "white", "army": 0, neighbours: ["egypt", "southern_europe", "western_europe", "east_africa", "congo", "brazil"] }, { name: "east_africa", continent: "africa", owner: "none", color: "white", "army": 0, neighbours: ["middle_east", "egypt", "north_africa", "congo", "madagascar", "south_africa"] }, { name: "congo", continent: "africa", owner: "none", color: "white", "army": 0, neighbours: ["south_africa", "north_africa", "east_africa"] }, { name: "south_africa", continent: "africa", owner: "none", color: "white", "army": 0, neighbours: ["congo", "madagascar", "east_africa"] }, { name: "madagascar", continent: "africa", owner: "none", color: "white", "army": 0, neighbours: ["south_africa", "east_africa"] }, { name: "brazil", continent: "South America", owner: "none", color: "white", "army": 0, neighbours: ["peru", "argentina", "north_africa", "venezuela"] }, { name: "peru", continent: "South America", owner: "none", color: "white", "army": 0, neighbours: ["brazil", "argentina", "venezuela"] }, { name: "argentina", continent: "South America", owner: "none", color: "white", "army": 0, neighbours: ["brazil", "peru"] }, { name: "venezuela", continent: "South America", owner: "none", color: "white", "army": 0, neighbours: ["brazil", "peru", "central_america"] }, { name: "iceland", continent: "europe", owner: "none", color: "white", "army": 0, neighbours: ["greenland", "uk", "scandinavia"] }, { name: "scandinavia", continent: "europe", owner: "none", color: "white", "army": 0, neighbours: ["iceland", "uk", "ukraine", "northern_europe"] }, { name: "northern_europe", continent: "europe", owner: "none", color: "white", "army": 0, neighbours: ["ukraine", "uk", "scandinavia", "southern_europe", "western_europe"] }, { name: "western_europe", continent: "europe", owner: "none", color: "white", "army": 0, neighbours: ["north_africa", "uk", "northern_europe", "southern_europe"] }, { name: "southern_europe", continent: "europe", owner: "none", color: "white", "army": 0, neighbours: ["north_africa", "egypt", "northern_europe", "western_europe", "middle_east", "ukraine"] }, { name: "uk", continent: "europe", owner: "none", color: "white", "army": 0, neighbours: ["western_europe", "iceland", "northern_europe", "scandinavia"] }, { name: "ukraine", continent: "europe", owner: "none", color: "white", "army": 0, neighbours: ["scandinavia", "ural", "northern_europe", "southern_europe", "afghanistan", "middle_east"] }, { name: "greenland", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["iceland", "quebec", "ontario", "northwest_territory"] }, { name: "central_america", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["venezuela", "eastern_us", "western_us"] }, { name: "eastern_us", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["central_america", "quebec", "ontario", "western_us"] }, { name: "western_us", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["eastern_us", "central_america", "ontario", "alberta"] }, { name: "alaska", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["kamchatka", "alberta", "northwest_territory"] }, { name: "alberta", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["alaska", "western_us", "ontario", "northwest_territory"] }, { name: "ontario", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["greenland", "quebec", "alberta", "western_us", "eastern_us", "northwest_territory"] }, { name: "quebec", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["greenland", "eastern_us", "ontario"] }, { name: "northwest_territory", continent: "North America", owner: "none", color: "white", "army": 0, neighbours: ["greenland", "alaska", "alberta", "ontario"] }];
var players = [{
"name": "Napoleon",
"country": "France",
"color": "#030f63",
"army": 10,
"reserve": 10,
"areas": [],
"bonus": 2,
"alive": true
}, {
"name": "Elizabeth I",
"country": "England",
"color": "#d6040e",
"army": 20,
"reserve": 20,
"areas": [],
"bonus": 2,
"alive": true
}, {
"name": "Washington",
"country": "USA",
"color": "#d86b04",
"army": 20,
"reserve": 20,
"areas": [],
"bonus": 2,
"alive": true
}, { "name": "Genghis Khan",
"country": "Mongolia",
"color": "#0eb7ae",
"army": 20,
"reserve": 20,
"areas": [],
"bonus": 2,
"alive": true
}, { "name": "Catherine",
"country": "Russia",
"color": "#104704",
"army": 20,
"reserve": 20,
"areas": [],
"bonus": 2,
"alive": true
}, { "name": "Isabella",
"country": "Spain",
"color": "#c6c617",
"army": 20,
"reserve": 20,
"areas": [],
"bonus": 2,
"alive": true
}];
//Helper Functions
Array.prototype.containsArray = function (array) {
if (arguments[1]) {
var index = arguments[1],
last = arguments[2];
} else {
var index = 0,
last = 0;this.sort();array.sort();
};
return index == array.length || (last = this.indexOf(array[index], last)) > -1 && this.containsArray(array, ++index, ++last);
};
function shuffle(array) {
var currentIndex = array.length,
temporaryValue,
randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
//DOM Elements
var infoName = Array.from(document.getElementsByClassName('country'));
var infoLeader = Array.from(document.getElementsByClassName('leader'));
var infoIncome = Array.from(document.getElementsByClassName('income'));
var areas = Array.from(document.getElementsByClassName('area'));
var bar = Array.from(document.getElementsByClassName('bar'));
var map = document.querySelector('svg');
//Modals
var modal = document.querySelector('#start-modal');
var reserveDisplay = document.querySelector('#reserve');
var chosenLeader = document.querySelector('#chosen-leader');
var chosenCountry = document.querySelector('#chosen-country');
var submitName = document.querySelector('#submit-name');
var bonusModal = document.querySelector('.bonus-modal');
var bonusModalAmount = document.querySelector('.bonus-modal-amount');
var bonusModalText = document.querySelector('.bonus-modal-text');
var bonusModalPlayer = document.querySelector('.bonus-modal-player');
var winModal = document.querySelector('#win-modal');
var winMessage = document.querySelector('.win-message');
var playAgain = document.querySelector('#play-again');
//Info Panels
var playerName = document.querySelector('.player-name');
var playerCountry = document.querySelector('.player-country');
var restart = document.querySelector('#restart');
var playerPanel = document.querySelector('.player-panel');
var infoPanel = document.querySelector('.info');
var turnInfo = document.querySelector('.turn-info');
var turnInfoMessage = document.querySelector('.turn-info-message');
var end = document.querySelector('#end');
//Create Game Object
var Gamestate = {};
Gamestate.countries = JSON.parse(JSON.stringify(countries)); //Array of Countries on Map
Gamestate.players = JSON.parse(JSON.stringify(players)); //Array of all players
Gamestate.player = JSON.parse(JSON.stringify(players))[0]; //Human Player
Gamestate.stage = "Fortify"; // Fortify, Battle or AI Turn
Gamestate.turn = 1;
Gamestate.aiTurn = false;
Gamestate.timeInterval = 1000; //Time between AI Turns
Gamestate.gameOver = false;
Gamestate.prevCountry = null; //Store previously selected country
Gamestate.prevTarget = null; //Store previously selected target;
//Game Setup
Gamestate.init = function () {
modal.style.display = "block";
winModal.style.display = "none";
submitName.addEventListener('click', this.start.bind(this));
restart.addEventListener('click', this.restart.bind(this));
map.addEventListener('mousedown', this.handleClick.bind(this));
end.addEventListener('click', this.handleEndTurn.bind(this));
playAgain.addEventListener('click', this.restart.bind(this));
};
Gamestate.start = function () {
var _this = this;
//Reset Variables on Start/Restart
end.style.pointerEvents = "auto";
map.style.pointerEvents = "auto";
modal.style.display = "none";
playerPanel.style.display = "flex";
infoPanel.style.display = "block";
this.aiTurn = false;
this.timeInterval = 1000;
this.gameOver = false;
this.prevCountry = null;
this.prevTarget = null;
this.turn = 1;
this.stage = "Fortify";
turnInfoMessage.textContent = "Click on your own areas to place reserve armies";
this.countries = JSON.parse(JSON.stringify(countries));
this.players = JSON.parse(JSON.stringify(players));
this.player = this.players[0];
this.players[0].name = chosenLeader.value;
this.players[0].country = chosenCountry.value;
reserveDisplay.innerHTML = 12;
playerName.textContent = chosenLeader.value;
playerCountry.textContent = chosenCountry.value;
if (this.prevTarget) {
this.prevTarget.classList.remove('flash');
}
//Add Players details to Info Panel
for (var j = 0; j < this.players.length; j++) {
infoName[j].innerHTML = this.players[j].country;
infoLeader[j].innerHTML = this.players[j].name;
infoName[j].parentElement.classList.remove('defeated');
bar[j].style.background = this.players[j].color;
}
//Add Initial Armies to Game
shuffle(areas).forEach(function (area, i) {
_this.countries.forEach(function (country) {
if (country.name === area.id) {
//Using module as i = 42 areas
country.army = _this.placeInitialArmy(i);
country.owner = _this.players[i % 6].name;
country.color = _this.players[i % 6].color;
_this.players[i % 6].areas.push(area.id);
setTimeout(function () {
area.style.fill = country.color;
area.nextElementSibling.textContent = country.army;
}, 25 * i);
}
});
});
this.player.army += 10;
this.player.reserve += 10;
this.updateInfo();
};
//Handle Initial Army Placement at Random
Gamestate.placeInitialArmy = function (i) {
var reserve = this.players[i % 6].reserve;
if (i > 35) {
//dump remaining army on last area
this.players[i % 6].reserve = this.players[i % 6].bonus;
this.players[i % 6].army += this.players[i % 6].reserve;
return reserve;
}
if (this.players[i % 6].reserve > 2) {
var rand = Math.floor(Math.random() * 4);
this.players[i % 6].reserve -= rand;
return rand;
} else {
return 0;
}
};
//Win/Lose Handlers
Gamestate.win = function (player) {
winMessage.textContent = player.name;
winMessage.style.color = player.color;
winModal.style.display = "block";
};
Gamestate.restart = function () {
modal.style.display = "block";
winModal.style.display = "none";
};
//Update Display and Strength Bar
Gamestate.updateInfo = function () {
turnInfo.textContent = this.stage;
var totalArmy = 0;
this.players.forEach(function (player) {
totalArmy += player.army;
});
this.players.forEach(function (player, i) {
infoIncome[i].innerHTML = player.bonus;
bar[i].style.width = player.army / totalArmy * 600 + 'px';
});
};
/*Gameplay*/
Gamestate.handleEndTurn = function () {
if (this.aiTurn) {
return;
}
this.aiTurn = true;
end.style.pointerEvents = "none";
map.style.pointerEvents = "none";
this.aiMove();
};
//Bonus Handlers
Gamestate.unitBonus = function (player, i) {
player.bonus = 0;
player.bonus += Math.ceil(player.areas.length / 3);
player.bonus += this.continentBonus(player);
player.bonus = Math.ceil(player.bonus * (this.turn / 5));
if (player.bonus < 2) {
player.bonus = 2;
}
infoIncome[i].innerHTML = player.bonus;
return player.bonus;
};
Gamestate.continentBonus = function (player) {
var bonus = 0;
continents.forEach(function (continent) {
if (player.areas.containsArray(continent.areas)) {
bonus += continent.bonus;
}
});
return bonus;
};
//Player
Gamestate.handleClick = function (e) {
if (this.stage === "Fortify") {
this.addArmy(e);
} else if (this.stage === "Battle") {
this.attack(e);
}
};
//Fortify area on player click
Gamestate.addArmy = function (e) {
var _this2 = this;
this.countries.forEach(function (country) {
//Check if Target is in country array and player has enough in reserve and player owns territory
if (e.target.id === country.name && _this2.player.reserve > 0 && country.owner === _this2.player.name) {
if (e.shiftKey) {
country.army += _this2.player.reserve;
_this2.player.reserve = 0;
} else {
country.army += 1;
_this2.player.reserve -= 1;
}
reserveDisplay.innerHTML = _this2.player.reserve;
e.target.nextElementSibling.textContent = country.army;
//Once reserve is empty, battle stage can start
if (_this2.player.reserve === 0) {
_this2.stage = "Battle";
turnInfo.textContent = _this2.stage;
turnInfoMessage.textContent = "Choose a country to attack from then a target";
}
}
});
};
//Attack handler finds Attacking and defending countries and passes to the battle function
Gamestate.attack = function (e) {
var _this3 = this;
//Remove flash animation from previous area
if (this.prevTarget) {
this.prevTarget.classList.remove('flash');
}
this.countries.forEach(function (country) {
if (e.target.id === country.name) {
e.target.classList.add('flash');
_this3.prevTarget = e.target;
if (_this3.prevCountry) {
if (_this3.prevCountry.name !== country.name && _this3.prevCountry.owner !== country.owner && _this3.prevCountry.owner === _this3.player.name) {
_this3.prevCountry.neighbours.forEach(function (neighbour) {
if (neighbour === country.name && neighbour.owner !== country.name && _this3.prevCountry.army > 0) {
return _this3.battle(_this3.prevCountry, country, _this3.player, 0);
}
});
}
}
_this3.prevCountry = country;
}
});
};
//Computer
//Handles AI Moves
Gamestate.aiMove = function () {
var _this4 = this;
if (this.gameOver) {
return;
}
if (this.prevTarget) {
this.prevTarget.classList.remove('flash');
}
this.stage = "AI Turn";
turnInfoMessage.textContent = "";
var _loop = function _loop(i) {
setTimeout(function () {
//Handle after last player finished turn
if (i === _this4.players.length) {
//Handle if human player defeated
if (_this4.player.areas.length === 0) {
_this4.timeInterval = 10;
_this4.player.alive = false;
return _this4.aiMove();
}
_this4.turn += 1;
_this4.aiTurn = false;
_this4.stage = "Fortify";
turnInfoMessage.textContent = "Click on your own areas to place reserve armies";
var bonus = _this4.unitBonus(_this4.player, 0);
_this4.player.reserve += bonus;
_this4.player.army += bonus;
end.style.pointerEvents = "auto";
map.style.pointerEvents = "auto";
infoName[i - 1].parentElement.classList.remove('highlight');
infoName[0].parentElement.classList.add('highlight');
reserveDisplay.innerHTML = _this4.player.reserve;
return _this4.updateInfo();
}
//Handle turn
infoName[i - 1].parentElement.classList.remove('highlight');
if (_this4.players[i].alive) {
infoName[i].parentElement.classList.add('highlight');
_this4.players[i].reserve = _this4.unitBonus(_this4.players[i], i);
_this4.players[i].army += _this4.players[i].reserve;
//Fortify
var areaToFortify = ["", 0];
_this4.players[i].areas.forEach(function (area) {
_this4.countries.forEach(function (country) {
if (country.name === area && _this4.players[i].reserve > 0) {
country.neighbours.forEach(function (neighbour) {
_this4.countries.forEach(function (c) {
if (c.name === neighbour && c.owner !== _this4.players[i].name) {
var continent = void 0;
continents.forEach(function (x) {
if (x.name === country.continent) {
continent = x;
}
});
var count = 0;
continent.areas.forEach(function (x) {
_this4.players[i].areas.forEach(function (y) {
if (y === x) {
count++;
}
});
});
var ratio = count / continent.areas.length;
if (ratio >= areaToFortify[1]) {
areaToFortify = [country, ratio];
}
}
});
});
}
});
});
areaToFortify[0].army += _this4.players[i].reserve;
_this4.players[i].reserve = 0;
var areaOnMap = document.getElementById("" + areaToFortify[0].name);
areaOnMap.nextElementSibling.textContent = areaToFortify[0].army;
//Attack
_this4.players[i].areas.forEach(function (area) {
_this4.countries.forEach(function (country) {
if (country.name === area && country.army > 1) {
_this4.aiAttack(country, i);
}
});
});
_this4.updateInfo();
}
}, _this4.timeInterval * i);
};
for (var i = 1; i <= this.players.length; i++) {
_loop(i);
}
};
//Find Attacking and defending countries on AI Attack
Gamestate.aiAttack = function (country, i) {
var _this5 = this;
//Add possible targets to array
var possibleTargets = [];
country.neighbours.forEach(function (neighbour) {
_this5.countries.forEach(function (opponent) {
if (neighbour === opponent.name && opponent.army + 1 < country.army && country.owner !== opponent.owner) {
possibleTargets.push(opponent);
}
});
});
//Check which is best target by checking if taking area will control continent
var target = [possibleTargets[0], 0];
var continent = void 0;
possibleTargets.forEach(function (poss) {
continents.forEach(function (x) {
if (x.name === poss.continent) {
continent = x;
}
});
var count = 0;
continent.areas.forEach(function (x) {
_this5.players[i].areas.forEach(function (y) {
if (y === x) {
count++;
}
});
});
var ratio = count / continent.areas.length;
if (ratio >= target[1]) {
target = [poss, ratio];
}
});
if (!target[0]) {
return;
}
this.battle(country, target[0], this.players[i], i);
};
//Battle function for Player and AI
Gamestate.battle = function (country, opponent, player, i) {
var defender = document.getElementById("" + opponent.name);
var attacker = document.getElementById("" + country.name);
var opp = void 0;
this.players.forEach(function (p) {
if (p.name === opponent.owner) {
opp = p;
}
});
//Battle Logic
while (opponent.army >= 0) {
if (country.army === 0) {
attacker.nextElementSibling.textContent = 0;
defender.nextElementSibling.textContent = opponent.army;
return;
}
if (Math.random() > Math.random()) {
country.army -= 1;
} else {
opponent.army -= 1;
}
}
//Handle if Attacker Wins
if (opponent.army <= 0) {
//Remove area from defenders areas array
this.players.forEach(function (player) {
if (player.name === opponent.owner) {
var index = player.areas.indexOf(opponent.name);
if (index > -1) {
player.areas.splice(index, 1);
}
}
});
//Swap defender area to attacker and distribute army evenly between areas
opponent.owner = player.name;
opponent.color = player.color;
player.areas.push(opponent.name);
defender.style.fill = opponent.color;
defender.nextElementSibling.textContent = Math.floor(country.army / 2);
opponent.army = Math.floor(country.army / 2);
attacker.nextElementSibling.textContent = Math.ceil(country.army / 2);
country.army = Math.ceil(country.army / 2);
//If Defender has no areas left they are eliminated
if (opp.areas.length === 0) {
opp.alive = false;
var index = this.players.indexOf(opp);
infoName[index].parentElement.classList.add('defeated');
}
}
//Calcualting total army for each player
player.army = 0;
opp.army = 0;
this.countries.forEach(function (c) {
player.areas.forEach(function (area) {
if (area === c.name) {
player.army += c.army;
}
});
opp.areas.forEach(function (area) {
if (area === c.name) {
opp.army += c.army;
}
});
});
//Display Bonus modal if player controls continent
if (this.player.alive) {
continents.forEach(function (continent) {
if (player.areas.containsArray(continent.areas)) {
var matchedCountry = continent.areas.some(function (a) {
return a === opponent.name;
});
if (matchedCountry) {
bonusModal.style.display = "block";
bonusModalPlayer.textContent = player.name + " controls";
bonusModalText.textContent = continent.name;
bonusModalText.style.color = player.color;
bonusModalAmount.textContent = continent.bonus;
setTimeout(function () {
bonusModal.style.display = "none";
}, 2000);
}
}
});
}
//Win Condition
if (player.areas.length === 42) {
this.gameOver = true;
this.win(player);
}
};
//Initialize Game
Gamestate.init();