app/controllers/GraphicalViewMouseController.js
import Moves from '../entities/creatures/moves/Moves.js';
import Pather from '../entities/creatures/strategies/Pather.js';
import UIMessageEvent from './UIMessageEvent.js';
/**
* Controller that listens for mouse actions on dungeon views
* and converts them to game moves
*/
export default class GraphicalViewMouseController {
/**
* Instantiates a controller and binds event handlers to the document
* @param {GraphicalViewSharedData} sharedData - The data object containing the dungeon
* @param {graphicalDungeonView} graphicalDungeonView - The view that will receive the clicks
*/
constructor(sharedData, graphicalDungeonView) {
var dom = graphicalDungeonView.getDom();
function getMovesFor(tileDom) {
var dungeon = sharedData.getDungeon();
var player = dungeon.getPlayableCharacter();
var playerLocation = dungeon.getTile(player); // TODO: Ensure that tile isn't empty
var targetX = tileDom.getAttribute('data-x');
var targetY = tileDom.getAttribute('data-y');
var creature = dungeon.getTile(targetX, targetY).getCreature();
var abilityIndex = sharedData.getTargettedAbility();
var itemIndex = sharedData.getTargettedItem();
if(abilityIndex !== null) {
return [new Moves.UseAbilityMove(playerLocation, abilityIndex, targetX, targetY)];
} else if(itemIndex !== null) {
return [new Moves.UseItemMove(playerLocation, itemIndex, dungeon.getTile(targetX, targetY))];
} else if(creature && creature.isEnemy(player)) {
return [new Moves.AttackMove(playerLocation, targetX, targetY)];
} else {
var dx = targetX - playerLocation.getX();
var dy = targetY - playerLocation.getY();
if(dx === 0 && dy === 0) {
return [new Moves.WaitMove(playerLocation)];
} else if(Math.abs(dx) <= 1 && Math.abs(dy) <= 1 && (dx !== 0 || dy !== 0)) {
return [new Moves.MovementMove(playerLocation, dx, dy)];
} else if(playerLocation.getCreature()) {
return Pather.getMoveSequenceToward(dungeon, player, dungeon.getTile(targetX, targetY));
}
}
}
function getTileFor(tileDom) {
var dungeon = sharedData.getDungeon();
var targetX = tileDom.getAttribute('data-x');
var targetY = tileDom.getAttribute('data-y');
return dungeon.getTile(targetX, targetY);
}
function updateHoverAttribute(tileDom) {
var dungeon = sharedData.getDungeon();
var player = dungeon.getPlayableCharacter();
var moves = getMovesFor(tileDom);
if(moves && moves[0] && !moves[0].getReasonIllegal(dungeon, player, getTileFor(tileDom))) {
tileDom.setAttribute('data-move', moves[0].constructor.name);
} else {
tileDom.setAttribute('data-move', '');
}
}
function anyNewEnemies(e1, e2) {
var tmp1 = e1.map(c=>c.getId()).sort();
var tmp2 = e2.map(c=>c.getId()).sort();
while(tmp2.length) {
if(tmp1[0] === tmp2[0]) {
tmp1.shift();
tmp2.shift();
} else if(tmp1[0] < tmp2[0]) {
tmp1.shift(); // Enemies are allowed to disappear, but not appear
} else {
return true;
}
}
}
// Arrow key handler
/*eslint-env jquery*/
$(dom).on('click tap', '.cell', function() {
const self = this;
const dungeon = sharedData.getDungeon();
const player = dungeon.getPlayableCharacter();
const enemies = player.getVisibleEnemies(dungeon);
const moves = getMovesFor(this) || [];
if(moves.length === 0) {
sharedData.dispatchUIEvent(new UIMessageEvent('No path to location'));
} else {
moves.forEach(function(move) {
// Note, optionalTargetTile (3rd param) only relevant for 1-length move sequences
var reason = move.getReasonIllegal(dungeon, player, getTileFor(self));
if(reason) {
sharedData.dispatchUIEvent(new UIMessageEvent(reason));
return false;
} if(anyNewEnemies(enemies, player.getVisibleEnemies(dungeon))) {
return false;
} else {
player.setNextMove(move);
dungeon.resolveUntilBlocked();
sharedData.unsetAttackMode();
sharedData.unsetTargettedAbility();
sharedData.unsetTargettedItem();
}
});
}
});
var lastHoverTile;
$(dom).on('mouseover', '.cell', function() {
var tileDom = lastHoverTile = this;
var targetX = tileDom.getAttribute('data-x');
var targetY = tileDom.getAttribute('data-y');
sharedData.setInspectedTile(targetX, targetY);
updateHoverAttribute(tileDom);
});
sharedData.addObserver(()=>lastHoverTile && updateHoverAttribute(lastHoverTile));
}
}