|
- define([
- 'misc/pathfinder'
- ], function(
- pathfinder
- ) {
- var sqrt = Math.sqrt.bind(Math);
- var ceil = Math.ceil.bind(Math);
- var random = Math.random.bind(Math);
-
- return {
- graph: null,
-
- collisionMap: null,
- cells: [],
- width: 0,
- height: 0,
-
- init: function(collisionMap) {
- this.collisionMap = collisionMap;
-
- this.width = collisionMap.length;
- this.height = collisionMap[0].length;
-
- this.cells = _.get2dArray(this.width, this.height, 'array');
-
- this.graph = new pathfinder.Graph(collisionMap, {
- diagonal: true
- });
- },
-
- addRegion: function(obj) {
- var lowX = obj.x;
- var lowY = obj.y;
- var highX = lowX + obj.width;
- var highY = lowY + obj.height;
- var cells = this.cells;
-
- for (var i = lowX; i < highX; i++) {
- var row = cells[i];
- for (var j = lowY; j < highY; j++) {
- if (!row[j])
- continue;
- row[j].push(obj);
- }
- }
- },
-
- addObject: function(obj, x, y, fromX, fromY) {
- var row = this.cells[x];
-
- if (!row)
- return;
-
- var cell = row[y];
-
- if (!cell)
- return;
-
- var cLen = cell.length;
- for (var i = 0; i < cLen; i++) {
- var c = cell[i];
-
- //If we have fromX and fromY, check if the target cell doesn't contain the same obj (like a notice area)
- if ((c.width) && (fromX)) {
- if ((fromX < c.x) || (fromY < c.y) || (fromX >= c.x + c.width) || (fromY >= c.y + c.height)) {
- c.collisionEnter(obj);
- obj.collisionEnter(c);
- }
- } else {
- //If a callback returns true, it means we collide
- if (c.collisionEnter(obj))
- return;
- obj.collisionEnter(c);
- }
- }
-
- cell.push(obj);
- return true;
- },
- removeObject: function(obj, x, y, toX, toY) {
- var row = this.cells[x];
-
- if (!row)
- return;
-
- var cell = row[y];
-
- if (!cell)
- return;
-
- var oId = obj.id;
- var cLen = cell.length;
- for (var i = 0; i < cLen; i++) {
- var c = cell[i];
-
- if (c.id != oId) {
- //If we have toX and toY, check if the target cell doesn't contain the same obj (like a notice area)
- if ((c.width) && (toX)) {
- if ((toX < c.x) || (toY < c.y) || (toX >= c.x + c.width) || (toY >= c.y + c.height)) {
- c.collisionExit(obj);
- obj.collisionExit(c);
- }
- } else {
- c.collisionExit(obj);
- obj.collisionExit(c);
- }
- } else {
- cell.splice(i, 1);
- i--;
- cLen--;
- }
- }
- },
-
- isValid: function(x, y) {
- var row = this.cells[x];
-
- if ((!row) || (row.length <= y) || (!this.graph.grid[x][y]))
- return false;
- else
- return true;
- },
-
- getCell: function(x, y) {
- var row = this.cells[x];
-
- if (!row)
- return [];
-
- var cell = row[y];
-
- if (!cell)
- return [];
-
- return cell;
- },
- getArea: function(x1, y1, x2, y2, filter) {
- var width = this.width;
- var height = this.height;
-
- x1 = ~~x1;
- y1 = ~~y1;
-
- x2 = ~~x2;
- y2 = ~~y2;
-
- if (x1 < 0)
- x1 = 0;
- if (x2 >= width)
- x2 = width - 1;
- if (y1 < 0)
- y1 = 0;
- if (y2 >= height)
- y2 = height - 1;
-
- var cells = this.cells;
- var grid = this.graph.grid;
-
- var result = [];
- for (var i = x1; i <= x2; i++) {
- var row = cells[i];
- var gridRow = grid[i];
- for (var j = y1; j <= y2; j++) {
- if (!gridRow[j])
- continue;
-
- var cell = row[j];
- var cLen = cell.length;
- for (var k = 0; k < cLen; k++) {
- var c = cell[k];
-
- if (filter) {
- if (filter(c))
- result.push(c);
- } else
- result.push(c);
- }
- }
- }
-
- return result;
- },
-
- getOpenCellInArea: function(x1, y1, x2, y2) {
- var width = this.width;
- var height = this.height;
-
- x1 = ~~x1;
- y1 = ~~y1;
-
- x2 = ~~x2;
- y2 = ~~y2;
-
- if (x1 < 0)
- x1 = 0;
- else if (x2 >= width)
- x2 = width - 1;
- if (y1 < 0)
- y1 = 0;
- else if (y2 >= height)
- y2 = height - 1;
-
- var cells = this.cells;
- var grid = this.graph.grid;
-
- for (var i = x1; i <= x2; i++) {
- var row = cells[i];
- var gridRow = grid[i];
- for (var j = y1; j <= y2; j++) {
- if (!gridRow[j])
- continue;
-
- var cell = row[j];
- if (cell.length == 0) {
- return {
- x: i,
- y: j
- };
- } else {
- //If the only contents are notices, we can still use it
- var allNotices = !cell.some(c => !c.notice);
- if (allNotices) {
- return {
- x: i,
- y: j
- };
- }
- }
- }
- }
-
- return null;
- },
-
- getPath: function(from, to) {
- var graph = this.graph;
- var grid = graph.grid;
-
- if (!to) {
- to = {
- x: ~~(random() * grid.length),
- y: ~~(random() * grid[0].length)
- };
- }
-
- var fromX = ~~from.x;
- var fromY = ~~from.y;
-
- if ((!grid[fromX]) || (grid[fromX].length <= fromY) || (fromX < 0) || (fromY < 0))
- return [];
-
- var toX = ~~to.x;
- var toY = ~~to.y;
-
- if ((!grid[toX]) || (grid[toX].length <= toY) || (toX < 0) || (toY < 0))
- return [];
-
- var path = pathfinder.astar.search(graph, {
- x: fromX,
- y: fromY
- }, {
- x: toX,
- y: toY
- }, {
- closest: true
- });
-
- return path;
- },
- isTileBlocking: function(x, y) {
- if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height))
- return true;
-
- x = ~~x;
- y = ~~y;
-
- var node = this.graph.grid[x][y];
- if (node)
- return node.isWall();
- else
- return false;
- },
- isCellOpen: function(x, y) {
- if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height))
- return true;
-
- var cells = this.cells[x][y];
- var cLen = cells.length;
- for (var i = 0; i < cLen; i++) {
- var c = cells[i];
- if (!c.notice)
- return false;
- }
-
- return true;
- },
- hasLos: function(fromX, fromY, toX, toY) {
- if ((fromX < 0) || (fromY < 0) || (fromX >= this.width) | (fromY >= this.height) || (toX < 0) || (toY < 0) || (toX >= this.width) | (toY >= this.height))
- return false;
-
- var graphGrid = this.graph.grid;
-
- if ((!graphGrid[fromX][fromY]) || (!graphGrid[toX][toY]))
- return false;
-
- var dx = toX - fromX;
- var dy = toY - fromY;
-
- var distance = sqrt((dx * dx) + (dy * dy));
-
- dx /= distance;
- dy /= distance;
-
- fromX += 0.5;
- fromY += 0.5;
-
- distance = ceil(distance);
-
- var x = 0;
- var y = 0;
-
- for (var i = 0; i < distance; i++) {
- fromX += dx;
- fromY += dy;
-
- x = ~~fromX;
- y = ~~fromY;
-
- if (!graphGrid[x][y])
- return false;
- else if ((x == toX) && (y == toY))
- return true;
- }
-
- return true;
- },
-
- getClosestPos: function(fromX, fromY, toX, toY, target) {
- var tried = {};
-
- var hasLos = this.hasLos.bind(this, toX, toY);
-
- var width = this.width;
- var height = this.height;
-
- var collisionMap = this.collisionMap;
- var cells = this.cells;
-
- var reverseX = (fromX > toX);
- var reverseY = (fromY > toY);
-
- for (var c = 1; c <= 10; c++) {
- var x1 = toX - c;
- var y1 = toY - c;
- var x2 = toX + c;
- var y2 = toY + c;
-
- var lowX, lowY, highX, highY, incX, incY;
-
- if (reverseX) {
- incX = -1;
- lowX = x2;
- highX = x1 - 1;
- }
- else {
- incX = 1;
- lowX = x1;
- highX = x2 + 1;
- }
-
- if (reverseY) {
- incY = -1;
- lowY = y2;
- highY = y1 - 1;
- }
- else {
- incY = 1;
- lowY = y1;
- highY = y2 + 1;
- }
-
- for (var i = lowX; i != highX; i += incX) {
- if ((i < 0) || (i >= width))
- continue;
-
- var row = collisionMap[i];
- var cellRow = cells[i];
-
- var t = tried[i];
- if (!t) {
- t = tried[i] = {};
- }
-
- for (var j = lowY; j != highY; j += incY) {
- if (t[j])
- continue;
-
- t[j] = 1;
-
- if (
- ((i == toX) && (j == toY)) ||
- ((j < 0) || (j >= height)) ||
- (row[j])
- )
- continue;
-
- var cell = cellRow[j];
- var cLen = cell.length;
- var blocking = false;
- for (var k = 0; k < cLen; k++) {
- var aggro = cell[k].aggro;
- if (aggro) {
- blocking = aggro.list.some(a => a.obj == target);
- if (blocking)
- break;
- }
- }
- if (blocking)
- continue;
- else if (!hasLos(i, j))
- continue;
-
- return {
- x: i,
- y: j
- };
- }
- }
- }
- },
-
- mobsCollide: function(x, y, obj) {
- if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height))
- return true;
-
- var cell = this.cells[x][y];
- var cLen = cell.length;
-
- if (cLen == 1)
- return false;
-
- var found = false;
- for (var i = 0; i < cLen; i++) {
- var c = cell[i];
- if (c.aggro) {
- if ((!found) && (c == obj))
- found = true;
- else
- return true;
- }
- }
-
- return false;
- },
-
- setCollision: function(x, y, collides) {
- var grid = this.graph.grid;
- if (!grid[x][y]) {
- grid[x][y] = new pathfinder.astar.GridNode(x, y, collides ? 0 : 1);
- }
- else {
- grid[x][y].weight = collides ? 0 : 1;
- pathfinder.astar.cleanNode(grid[x][y]);
- }
- }
- };
- });
|