diff --git a/cypress.json b/cypress.json
index fe6cedc..4882bd6 100644
--- a/cypress.json
+++ b/cypress.json
@@ -9,7 +9,8 @@
"topbar_actions.spec.js",
"map_info.spec.js",
"narrator.spec.js",
- "manual.spec.js"
+ "manual.spec.js",
+ "movement_drag.spec.js"
],
"video": false
}
diff --git a/cypress/integration/core/movement.spec.js b/cypress/integration/core/movement.spec.js
index f81401a..d7e5e85 100644
--- a/cypress/integration/core/movement.spec.js
+++ b/cypress/integration/core/movement.spec.js
@@ -51,6 +51,7 @@ context("Units movements", () => {
click("#icon32a");
click("#cell62");
+ click("#modal-ok");
cy.get('#icon32a[src="./src/images/board/mob/roman/1.png"]').should(
"exist"
@@ -63,6 +64,7 @@ context("Units movements", () => {
click("#icon32a");
click("#cell33");
+ click("#modal-ok");
cy.get('#icon32a[src="./src/images/board/mob/roman/1.png"]').should(
"exist"
diff --git a/cypress/integration/movement_drag.spec.js b/cypress/integration/movement_drag.spec.js
new file mode 100644
index 0000000..0c0656d
--- /dev/null
+++ b/cypress/integration/movement_drag.spec.js
@@ -0,0 +1,103 @@
+///
+
+import { start, click, endTurn, moreStrength } from "../utils/ui.js";
+
+context("Human Soldiers movements using drag and drop", () => {
+ it("User drags a soldier 2 steps and cannot move anymore; then next turn user drags it 2 steps again", () => {
+ start();
+
+ cy.get("#tooltip32a").drag("#cell30");
+
+ click('#icon30a[src="./src/images/board/mob/roman/grey/1.png"]');
+ cy.get("#movement").should("contain", "Movements left: [0]");
+ click("#cell32");
+
+ cy.get('#icon30a[src="./src/images/board/mob/roman/grey/1.png"]').should(
+ "exist"
+ );
+
+ endTurn();
+
+ cy.get("#tooltip30a").drag("#cell32");
+
+ cy.get('#icon32a[src="./src/images/board/mob/roman/grey/1.png"]').should(
+ "exist"
+ );
+ });
+
+ it("User drags a soldier 1 step and then move it 1 step again; after that, it cannot be moved anymore", () => {
+ start();
+
+ cy.get("#tooltip32a").drag("#cell31");
+ click('#icon31a[src="./src/images/board/mob/roman/1.png"]');
+ cy.get("#movement").should("contain", "Movements left: [1]");
+
+ cy.get("#tooltip31a").drag("#cell30");
+ click('#icon30a[src="./src/images/board/mob/roman/grey/1.png"]');
+ cy.get("#movement").should("contain", "Movements left: [0]");
+
+ cy.get("#tooltip30a").drag("#cell31", { force: true });
+ click("#modal-ok");
+ cy.get('#icon30a[src="./src/images/board/mob/roman/grey/1.png"]').should(
+ "exist"
+ );
+ });
+
+ it("User cannot drag a soldier more than 2 steps", () => {
+ start();
+
+ cy.get("#tooltip32a").drag("#cell62", { force: true });
+ click("#modal-ok");
+
+ cy.get('#icon32a[src="./src/images/board/mob/roman/1.png"]').should(
+ "exist"
+ );
+ click("#icon32a");
+ cy.get("#movement").should("contain", "Movements left: [2]");
+ });
+
+ it("User cannot drag a soldier into an obstacle", () => {
+ start();
+
+ cy.get("#tooltip32a").drag("#cell33", { force: true });
+ click("#modal-ok");
+
+ cy.get('#icon32a[src="./src/images/board/mob/roman/1.png"]').should(
+ "exist"
+ );
+
+ click("#icon32a");
+ cy.get("#movement").should("contain", "Movements left: [2]");
+ });
+
+ it("User can drag a soldier after moving to next map", () => {
+ start(19);
+
+ cy.get("#icon71a").should("not.exist");
+
+ endTurn();
+
+ click("#icon64a");
+ moreStrength();
+ moreStrength();
+
+ click("#cell54").then(() => {
+ cy.get("#modal-content").should(
+ "contain",
+ "Victory! The area is safe again."
+ );
+ click("#modal-ok");
+
+ cy.get("#modal-content").should("contain", "A new map awaits you...");
+ click("#modal-ok");
+
+ cy.get("#icon71a").should("exist");
+
+ endTurn();
+
+ cy.get("#icon54a").should("not.exist");
+ cy.get("#tooltip71a").drag("#cell72");
+ cy.get("#icon72a").should("exist");
+ });
+ });
+});
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index ca4d256..e6b370d 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -23,3 +23,5 @@
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
+
+require("@4tw/cypress-drag-drop");
diff --git a/package-lock.json b/package-lock.json
index f29cd6e..827a867 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,6 +4,12 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "@4tw/cypress-drag-drop": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@4tw/cypress-drag-drop/-/cypress-drag-drop-1.6.0.tgz",
+ "integrity": "sha512-B61iPspk2hZuuo3mjmlTqYZXJ9tusc8VyEk+5KMO/FTBrHKDWqYp8ANOJnIkRz6QfYZbx+qBoKBu7MTfvBCKew==",
+ "dev": true
+ },
"@cypress/listr-verbose-renderer": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz",
diff --git a/package.json b/package.json
index 8c9c29c..6dcf13c 100644
--- a/package.json
+++ b/package.json
@@ -22,5 +22,8 @@
"bugs": {
"url": "https://github.com/W01fw00d/barbarians/issues"
},
- "homepage": "https://github.com/W01fw00d/barbarians#readme"
+ "homepage": "https://github.com/W01fw00d/barbarians#readme",
+ "devDependencies": {
+ "@4tw/cypress-drag-drop": "^1.6.0"
+ }
}
diff --git a/src/scripts/browser/BrowserUtils.js b/src/scripts/browser/BrowserUtils.js
index 9ae06cd..90a686c 100644
--- a/src/scripts/browser/BrowserUtils.js
+++ b/src/scripts/browser/BrowserUtils.js
@@ -4,6 +4,8 @@ function BrowserUtils() {
};
this.showMessage = function (message, onClose) {
+ //TODO: add a flag to disable this feature
+ // (take into account that next map won't load without user confirming modal right now...)
$("#modal-content").html(message);
$("#modal").modal("show");
onClose &&
diff --git a/src/scripts/game/Game.js b/src/scripts/game/Game.js
index 08a4458..8c2891a 100644
--- a/src/scripts/game/Game.js
+++ b/src/scripts/game/Game.js
@@ -80,9 +80,10 @@ Game.prototype.getUnit = function (icon) {
},
annotation = icon[icon.length - 1];
- let units = this.players[unitsAnnotationCorralation[annotation][0]].units[
- unitsAnnotationCorralation[annotation][1]
- ];
+ let units =
+ this.players[unitsAnnotationCorralation[annotation][0]].units[
+ unitsAnnotationCorralation[annotation][1]
+ ];
let unitsLength = units.length;
for (i = 0; i < unitsLength; i++) {
@@ -95,8 +96,6 @@ Game.prototype.getUnit = function (icon) {
Game.prototype.onCellClick = function (event, unit) {
const target = event.target.id;
- let newMapLevel;
-
//if this cell has an icon and the icon represents unit or town data, show that data instead of moving unit
if (target.indexOf("icon") !== -1 && this.getUnit(target)) {
// showIconData.apply(targetIcon);
@@ -123,6 +122,7 @@ Game.prototype.onCellClick = function (event, unit) {
if (newMapLevel) {
this.currentMapLevel = newMapLevel;
this.map.generate(this.currentMapLevel, this.players);
+ this.bindDrag();
}
this.resetBoardBindings();
@@ -149,6 +149,7 @@ Game.prototype.moveMode = function (unit) {
if (newMapLevel) {
this.currentMapLevel = newMapLevel;
this.map.generate(this.currentMapLevel, this.players);
+ this.bindDrag();
}
this.resetBoardBindings();
@@ -163,6 +164,71 @@ Game.prototype.moveMode = function (unit) {
});
};
+Game.prototype.bindDrag = function () {
+ document.querySelectorAll(".cell").forEach((node) => {
+ const handleDrop = (event) => {
+ var data = event.dataTransfer.getData("Text");
+
+ const checkEncounter = (unit) => {
+ const target = event.target.id;
+
+ //if this cell has an icon and the icon represents unit or town data, don't do anything
+ if (
+ (target.indexOf("icon") === -1 || !this.getUnit(target)) &&
+ unit.movements > 0 &&
+ unit.cell.replace("icon", "").substring(0, 2) !==
+ target.replace("cell", "")
+ ) {
+ const dataElement = document.getElementById(data);
+ result = this.players.human.moveSoldier(unit, target);
+
+ if (result) {
+ event.target.appendChild(dataElement);
+
+ this.encounter.check(unit, this.players);
+
+ this.levelManager.checkEndOfLevelCondition(
+ this.currentMapLevel,
+ this.players,
+ (newMapLevel) => {
+ if (newMapLevel) {
+ this.currentMapLevel = newMapLevel;
+ this.map.generate(this.currentMapLevel, this.players);
+ this.bindDrag();
+ }
+
+ this.resetBoardBindings();
+ }
+ );
+ }
+ } else {
+ this.browserUtils.showMessage("Invalid movement");
+ }
+ };
+
+ event.preventDefault();
+
+ const draggedIcon = data.replace("tooltip", "icon");
+
+ const unit = this.infoLayer.findUnit(
+ draggedIcon,
+ this.players.human.units.mobs
+ );
+ checkEncounter(unit);
+ };
+
+ node.addEventListener("drop", handleDrop, false);
+
+ node.addEventListener(
+ "dragover",
+ (event) => {
+ event.preventDefault();
+ },
+ false
+ );
+ });
+};
+
Game.prototype.bindIconClick = function () {
$(".icon").one("click", (event) => {
event.stopPropagation();
@@ -175,6 +241,16 @@ Game.prototype.bindIconClick = function () {
this.bindIconClick();
}
});
+
+ Array.from(document.getElementsByClassName("icon-wrapper")).forEach(
+ (node) => {
+ const handleDragstart = (event) => {
+ event.dataTransfer.setData("Text", event.currentTarget.id);
+ };
+
+ node.addEventListener("dragstart", handleDragstart, false);
+ }
+ );
};
Game.prototype.resetBoardBindings = function () {
@@ -193,6 +269,7 @@ Game.prototype.bindAll = function () {
if (confirm("Reset current map?")) {
this.map.generate(this.currentMapLevel, this.players);
this.bindIconClick();
+ this.bindDrag();
}
});
@@ -201,6 +278,7 @@ Game.prototype.bindAll = function () {
if (newMapLevel) {
this.currentMapLevel = newMapLevel;
this.map.generate(this.currentMapLevel, this.players);
+ this.bindDrag();
}
$("#end_turn").html("End turn (+3 gold)");
@@ -257,4 +335,6 @@ Game.prototype.bindAll = function () {
enableAnimationsCheckbox.addEventListener("change", ({ currentTarget }) => {
this.animationManager.enableAnimations = currentTarget.checked;
});
+
+ this.bindDrag();
};
diff --git a/src/scripts/game/InfoLayer.js b/src/scripts/game/InfoLayer.js
index 9c448f5..ec9344b 100644
--- a/src/scripts/game/InfoLayer.js
+++ b/src/scripts/game/InfoLayer.js
@@ -9,7 +9,6 @@ function InfoLayer(painter) {
mode: null,
unit: null,
},
- color,
unit;
switch (type) {
@@ -90,4 +89,5 @@ function InfoLayer(painter) {
return unit;
};
+ this.findUnit = findUnit;
}
diff --git a/src/scripts/players/Player.js b/src/scripts/players/Player.js
index b470c77..3588d7c 100644
--- a/src/scripts/players/Player.js
+++ b/src/scripts/players/Player.js
@@ -26,6 +26,7 @@ Player.prototype.setGold = function (gold) {
};
Player.prototype.showModal = function (message) {
+ //TODO: use BrowserUtils modal here
$("#modal-content").html(message);
$("#modal").modal("show");
};
@@ -45,7 +46,7 @@ Player.prototype.moveSoldier = function (unit, target) {
Math.abs(finalCell[1] - initialCell[1]);
if (icon === null && movement > 0 && movement <= unit.movements) {
- //Move the soldier icon to he selected cell, and calculate movements left
+ // Move the soldier icon to the selected cell, and calculate movements left
unit.cell = "icon" + finalCell[0] + "" + finalCell[1] + initialCell[2];
unit.movements -= movement;
@@ -53,7 +54,7 @@ Player.prototype.moveSoldier = function (unit, target) {
this.mapPainter.clearCell(initialCell[0], initialCell[1]);
} else {
- if (unit.player === "Roman") {
+ if (unit.player === "human") {
this.showModal("Invalid movement");
result = null;
}
diff --git a/src/scripts/units/IconTemplates.js b/src/scripts/units/IconTemplates.js
index 583f9ac..d9292f9 100644
--- a/src/scripts/units/IconTemplates.js
+++ b/src/scripts/units/IconTemplates.js
@@ -1,25 +1,25 @@
//TODO all this should probably go into browser/
function IconTemplates() {}
-IconTemplates.prototype.getBase = function (id, title, img) {
- return (
- '' +
- ''
- );
-};
+IconTemplates.prototype.getBase = (id, title, img, draggable = false) =>
+ `` +
+ `` +
+ ``;
-IconTemplates.prototype.getMob = function (id, name, img, extraTitle = "") {
+IconTemplates.prototype.getMob = function (
+ id,
+ name,
+ img,
+ extraTitle = "",
+ draggable = false
+) {
const title = `[${name}]${extraTitle}`;
- return this.getBase(id, title, `mob/${img}`);
+ return this.getBase(id, title, `mob/${img}`, draggable);
};
IconTemplates.prototype.getStarterAIMob = function (id, name) {
@@ -47,11 +47,14 @@ IconTemplates.prototype.getSoldierIconByStrength = function (strength) {
};
IconTemplates.prototype.getHumanMob = function (id, name, movements, strength) {
+ const draggable = true;
+
return this.getMob(
id,
name,
`roman/${this.getSoldierIconByStrength(strength)}`,
- ` | Moves: [${movements}] | Strength: [${strength}]`
+ ` | Moves: [${movements}] | Strength: [${strength}]`,
+ draggable
);
};