diff --git a/static/js/dom.js b/static/js/dom.js index b725dff..4339b79 100644 --- a/static/js/dom.js +++ b/static/js/dom.js @@ -127,9 +127,20 @@ document.addEventListener("DOMContentLoaded", () => { el.addEventListener("click", (ev) => { let modal = document.querySelector("#modal"); + let region = ev.target.closest(".node").dataset["name"]; + modal.dataset["region"] = ev.target.closest(".node").dataset.name; modal.dataset["action"] = "ATTACK"; + let selector = modal.querySelector(".target"); + selector.replaceChildren(""); + for (let neighbour of Region.getRegion(region).neighbours) { + let opt = document.createElement("option"); + opt.value = neighbour.name; + opt.textContent = neighbour.name; + selector.appendChild(opt); + } + modal.classList.remove("hidden"); }) ); diff --git a/static/js/index.js b/static/js/index.js index 0b6c4bf..046dab6 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -99,7 +99,7 @@ document.addEventListener("DOMContentLoaded", () => { updateDom(); } } else { - if (currentPlayer().act(data)) { + if (await currentPlayer().act(data)) { currentPlayer().endTurn(); } } diff --git a/static/js/player.js b/static/js/player.js index 6516370..d36d8a0 100644 --- a/static/js/player.js +++ b/static/js/player.js @@ -2,6 +2,8 @@ const PHASE_REINFORCE = 1; const PHASE_ATTACK = 2; const PHASE_FORTIFY = 3; +let totalDice = 0; + class Player { constructor(id, name) { this.name = name; @@ -13,6 +15,7 @@ class Player { this.isPlaying = false; this.reinforcementsPlaced = 0; this.reinforcementsAvailable = 0; + this.offenderRegion = null; this.turnPhase = PHASE_REINFORCE; this.resetColor(); @@ -81,17 +84,19 @@ class Player { * @param data Data received via socket * @returns {boolean} Whether this player's turn has ended or not. */ - act(data) { + async act(data) { console.log(`player: ${this.id}`); console.log(data); if (this.turnPhase === PHASE_REINFORCE) { - if (this.reinforce(data)) { - this.reinforcementsPlaced += 1; - } + if (data.region !== undefined) { + if (this.reinforce(data)) { + this.reinforcementsPlaced += 1; + } - if (this.reinforcementsPlaced === this.reinforcementsAvailable) { - this.turnPhase = PHASE_ATTACK; + if (this.reinforcementsPlaced === this.reinforcementsAvailable) { + this.turnPhase = PHASE_ATTACK; + } } return false; @@ -102,10 +107,7 @@ class Player { } if (this.turnPhase === PHASE_ATTACK && data.action === "ATTACK") { - if (this.attack(data)) { - this.turnPhase = PHASE_FORTIFY; - } - + await this.attack(data); return false; } @@ -123,7 +125,76 @@ class Player { * * @param data Data received via socket */ - attack(data) {} + async attack(data) { + let offender = Region.getRegion(data.startRegion); + let defender = Region.getRegion(data.endRegion); + let offenderStrength = parseInt(data.strength); + // Assume this for now. + let defenderStrength = 1; + + // Basic validation on game state + if ( + offender.owner !== this || + defender.owner === this || + offenderStrength > 3 || + offenderStrength <= 0 || + offenderStrength >= offender.strength || + (this.offenderRegion !== null && this.offenderRegion !== offender) + ) { + return false; + } + + /* How do Risk attacks work? + - Offender signs 1-3 armies, defender signs 1-2 armies + - Both roll respective dice + - Compare pairs of highest die in the rolls to remove armies. + */ + + if (this.offenderRegion === null) { + this.offenderRegion = offender; + } + + let offenderRolls = []; + let defenderRolls = []; + + // Get random values + for (let i = 0; i < offenderStrength; i++) { + offenderRolls.push(await random.get(6, `dice-${totalDice}`)); + totalDice += 1; + } + + for (let i = 0; i < defenderStrength; i++) { + defenderRolls.push(await random.get(6, `dice-${totalDice}`)); + totalDice += 1; + } + + console.log(`attacker rolls: ${offenderRolls}`); + console.log(`defender rolls: ${defenderRolls}`); + + offenderRolls.sort(); + defenderRolls.sort(); + + // Compare and settle. + while (offenderRolls.length * defenderRolls.length > 0) { + let offenderResult = offenderRolls.pop(); + let defenderResult = defenderRolls.pop(); + + if (offenderResult > defenderResult) { + defender.strength -= 1; + } else { + offender.strength -= 1; + } + + if (defender.strength === 0) { + defender.strength = offenderRolls.length + 1; + offender.strength -= offenderRolls.length + 1; + defender.owner = this; + break; + } + } + + updateDom(); + } /** * Process an action which is to attack another region. @@ -138,7 +209,8 @@ class Player { if ( sender.owner === this && receiver.owner === this && - sender.strength > strength + sender.strength > strength && + strength > 0 ) { receiver.reinforce(strength); sender.strength -= strength; @@ -168,6 +240,7 @@ class Player { this.isPlaying = true; this.reinforcementsPlaced = 0; this.reinforcementsAvailable = this.additionalReinforcements(); + this.offenderRegion = null; this.turnPhase = PHASE_REINFORCE; }