class Warrior extends GameElement { constructor(x, y, game, civilization, asset) { super(x, y, game, asset, false); this.civilization = civilization; this.isSelected = false; this.civilization.balance -= this.constructor.initialCosts; this.setNeedsAction(true); } onClick() { if (this.civilization.player !== player) return; this.game.selectCivilization(this.civilization); if (!this.game.selectedObject && this.needsAction) { this.isSelected = true; this.game.selectWarrior(this); this.game.draggingElement = this.constructor.getDraggingObject(this.game); } } static getDraggingObject(game, className = 'farmer', image = 'knight.svg') { return super.getDraggingObject(game, className, image); } getPossibleTiles(player) { return this.checkSurroundings(this.x, this.y, player); } merge(warrior) { this.rank += warrior.rank || 1; this.rank = Math.min(this.rank, 4); warrior.kill(); this.kill(); const ranks = [Farmer, Hoplite, Servant, Knight]; this.civilization.balance += warrior.constructor.initialCosts + this.constructor.initialCosts; this.game.addWarrior(this.x, this.y, this.civilization, ranks[this.rank - 1]); // TODO: Switch image } move(x, y) { if (!this.needsAction) return false; if (!this.isPossibleDestination(x, y, this.civilization.player)) return false; this.game.field[this.x][this.y].object = null; const tile = this.game.field[x][y]; if (!tile.claimedBy || tile.claimedBy.player === this.civilization.player) { // Friendly territory if (tile.object instanceof Tree) { // Tree tile.object.cutDown(); } else if (tile.object instanceof Warrior) { // Obstacle is a friendly warrior tile.object.merge(this); this.game.deselectObject(); return true; } } else { // Hostile territory // Check surrounding tiles if(tile.getAdjacentTiles().find(adjTile => adjTile.claimedBy !== this.civilization && !!adjTile.object && (adjTile.object instanceof Warrior || adjTile.object instanceof Tower) && adjTile.object.rank >= this.rank)) { return false; } if (tile.object instanceof Tree) { // No object/troop on tile tile.object.cutDown(); } else if (tile.object instanceof Warrior) { // Obstacle is an hostile warrior if (tile.object.rank < this.rank) { // Hostile warrior/tower is weaker than own troop tile.object.kill(); } } else if (tile.object instanceof Building) { if (tile.object.rank < this.rank) { tile.object.destroy(); } } } this.x = x; this.y = y; this.game.deselectObject(); this.setNeedsAction(false); const prevCiv = tile.claimedBy; tile.object = this; tile.overtake(this.civilization); if(prevCiv instanceof Civilization && prevCiv !== this.civilization) { console.log(prevCiv.uuid); prevCiv.split(); } this.update(); } checkSurroundings(x, y, player, step = 0, excluded = []) { const field = this.game.field; const possibleSurroundings = []; const neighbours = field[x][y].getAdjacentTiles().filter(tile => !excluded.includes(tile)); neighbours.forEach(neighbour => { const {x, y} = neighbour.pos; if (x < 0 || x >= this.game.fieldSize.x || y < 0 || y >= this.game.fieldSize.y) return; if (this.isPossibleTile(x, y)) { possibleSurroundings.push(field[x][y]); if (step < 4 && !!field[x][y].claimedBy && field[x][y].claimedBy.player === player) possibleSurroundings.push(...this.checkSurroundings(x, y, player, ++step, [...excluded, ...neighbours, ...possibleSurroundings])); } }); return possibleSurroundings; } isPossibleTile(x, y) { const tile = this.game.field[x][y]; if (!!tile.claimedBy && tile.claimedBy.player === this.civilization.player) { // Friendly territory if (!tile.object || tile.object instanceof Tree) { // No object/troop on tile return true; } if (tile.object instanceof Warrior) { // Obstacle is a friendly warrior if (tile.object.rank <= 4 - this.rank) { // Warrior isn't yet on max level return true; } } // Otherwise there is an unavoidable obstacle } else { // Hostile territory if (!tile.object || tile.object instanceof Tree) { // No object/troop on tile // TODO: Check surrounding tiles return true; } if (tile.object instanceof Warrior || tile.object instanceof Building) { // Obstacle is an hostile warrior if (tile.object.rank < this.rank) { // Hostile warrior/tower is weaker than own troop // TODO: Check surrounding tiles return true; } } // Otherwise there is an unavoidable obstacle } return false; } isPossibleDestination(x, y, player) { return this.getPossibleTiles(player).includes(this.game.field[x][y]); } kill() { delete this.game.warriors[this.uuid]; this.element.parentNode.removeChild(this.element); this.game.field[this.x][this.y].object = null; // TODO: Show gravestone } setNeedsAction(needsAction) { this.needsAction = needsAction; if (this.civilization.player === player && needsAction) { this.element.classList.add('waiting'); } else { this.element.classList.remove('waiting'); } } } class Farmer extends Warrior { constructor(x, y, game, civilization) { super(x, y, game, civilization, 'farmer.svg'); this.rank = 1; this.costsPerRound = 2; } static getDraggingObject(game) { return super.getDraggingObject(game, 'farmer', 'farmer.svg'); } static get initialCosts() { return 10; } } class Hoplite extends Warrior { constructor(x, y, game, civilization) { super(x, y, game, civilization, 'hoplite.svg'); this.rank = 2; this.costsPerRound = 6; } static getDraggingObject(game) { return super.getDraggingObject(game, 'hoplite', 'hoplite.svg'); } static get initialCosts() { return 20; } } class Servant extends Warrior { constructor(x, y, game, civilization) { super(x, y, game, civilization, ''); this.rank = 3; this.costsPerRound = 18; } static getDraggingObject(game) { return super.getDraggingObject(game, 'servant', 'servant.svg'); } static get initialCosts() { return 30; } } class Knight extends Warrior { constructor(x, y, game, civilization) { super(x, y, game, civilization, 'knight.svg'); this.rank = 4; this.costsPerRound = 36; } static getDraggingObject(game) { return super.getDraggingObject(game, 'knight', 'knight.svg'); } static get initialCosts() { return 40; } }