UNPKG

@screeps/engine

Version:

This is a module for Screeps standalone server. See [main repository](https://github.com/screeps/screeps) for more info.

1,370 lines (1,159 loc) 59.8 kB
'use strict'; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _ = require('lodash'), utils = require('./../utils'), driver = utils.getRuntimeDriver(), C = driver.constants, pathfinding = require('@screeps/pathfinding'); var abs = Math.abs, min = Math.min, max = Math.max; var runtimeData, intents, register, globals; var positionsSetCacheCounter, createdFlagNames, createdSpawnNames, privateStore, createdConstructionSites; let TerrainConstructor = null; let TerrainConstructorSet = null; function getPathfinder(id, opts) { opts = opts || {}; _.defaults(opts, { maxOps: 2000, heuristicWeight: 1 }); var key = `${opts.maxOps},${opts.heuristicWeight}`; if (!privateStore[id].pfFinders[key]) { privateStore[id].pfFinders[key] = new pathfinding.AStarFinder({ diagonalMovement: 1, maxOpsLimit: opts.maxOps, heuristic: pathfinding.Heuristic.chebyshev, weight: opts.heuristicWeight }); } return privateStore[id].pfFinders[key]; } function makePathfindingGrid(id, opts, endNodesKey) { opts = opts || {}; var rows = new Array(50), obstacleTypes = _.clone(C.OBSTACLE_OBJECT_TYPES); if (opts.ignoreDestructibleStructures) { obstacleTypes = _.without(obstacleTypes, 'constructedWall', 'spawn', 'extension', 'link', 'storage', 'observer', 'tower', 'powerBank', 'powerSpawn', 'lab', 'terminal'); } if (opts.ignoreCreeps) { obstacleTypes = _.without(obstacleTypes, 'creep', 'powerCreep'); } for (var y = 0; y < 50; y++) { rows[y] = new Array(50); for (var x = 0; x < 50; x++) { rows[y][x] = x == 0 || y == 0 || x == 49 || y == 49 ? 11 : 2; //var terrainCode = register.terrainByRoom.spatial[id][y][x]; var terrainCode = runtimeData.staticTerrainData[id][y * 50 + x]; if (terrainCode & C.TERRAIN_MASK_WALL) { rows[y][x] = 0; } if (terrainCode & C.TERRAIN_MASK_SWAMP && rows[y][x] == 2) { rows[y][x] = 10; } } } register.objectsByRoomKeys[id].forEach(key => { var object = register.objectsByRoom[id][key]; if (_.contains(obstacleTypes, object.type) || !opts.ignoreDestructibleStructures && object.type == 'rampart' && !object.isPublic && object.user != runtimeData.user._id || !opts.ignoreDestructibleStructures && object.type == 'constructionSite' && object.user == runtimeData.user._id && _.contains(C.OBSTACLE_OBJECT_TYPES, object.structureType)) { rows[object.y][object.x] = 0; } if (object.type == 'road' && rows[object.y][object.x] > 0) { rows[object.y][object.x] = 1; } }); if (opts.ignore) { if (!_.isArray(opts.ignore)) { throw new Error('option `ignore` is not an array'); } _.forEach(opts.ignore, (i, key) => { if (!i) { return; } if (i.pos) { rows[i.pos.y][i.pos.x] = rows[i.pos.y][i.pos.x] > 2 ? 2 : rows[i.pos.y][i.pos.x]; } if (_.isObject(i) && !_.isUndefined(i.x) && !(i instanceof globals.RoomPosition)) { opts.ignore[key] = new globals.RoomPosition(i.x, i.y, id); } if (!_.isUndefined(i.x)) { rows[i.y][i.x] = rows[i.y][i.x] > 2 ? 2 : rows[i.y][i.x]; } }); } if (opts.avoid) { if (!_.isArray(opts.avoid)) { throw new Error('option `avoid` is not an array'); } _.forEach(opts.avoid, (i, key) => { if (!i) { return; } if (i.pos) { rows[i.pos.y][i.pos.x] = 0; } if (_.isObject(i) && !_.isUndefined(i.x) && !(i instanceof globals.RoomPosition)) { opts.avoid[key] = new globals.RoomPosition(i.x, i.y, id); } if (!_.isUndefined(i.x)) { rows[i.y][i.x] = 0; } }); } if (endNodesKey) { _.forEach(privateStore[id].pfEndNodes[endNodesKey], i => { if (!_.isUndefined(i.x)) { rows[i.y][i.x] = 999; } else if (!_.isUndefined(i.pos)) { rows[i.pos.y][i.pos.x] = 999; } }); } return new pathfinding.Grid(50, 50, rows); } function getPathfindingGrid(id, opts, endNodesKey) { var gridName = 'grid'; opts = opts || {}; if (opts.ignoreCreeps) { gridName += '_ignoreCreeps'; } if (opts.ignoreDestructibleStructures) { gridName += '_ignoreDestructibleStructures'; } if (_.isNumber(endNodesKey)) { gridName += '_endNodes' + endNodesKey; } if (opts.avoid) { gridName += '_avoid' + privateStore[id].positionsSetCache.key(opts.avoid); } if (opts.ignore) { gridName += '_ignore' + privateStore[id].positionsSetCache.key(opts.ignore); } if (!privateStore[id].pfGrid[gridName]) privateStore[id].pfGrid[gridName] = makePathfindingGrid(id, opts, endNodesKey); return privateStore[id].pfGrid[gridName].clone(); } function makePathfindingGrid2(id, opts) { opts = opts || {}; var costs = new globals.PathFinder.CostMatrix(); var obstacleTypes = _.clone(C.OBSTACLE_OBJECT_TYPES); obstacleTypes.push('portal'); if (opts.ignoreDestructibleStructures) { obstacleTypes = _.without(obstacleTypes, 'constructedWall', 'spawn', 'extension', 'link', 'storage', 'observer', 'tower', 'powerBank', 'powerSpawn', 'lab', 'terminal'); } if (opts.ignoreCreeps || register.rooms[id].controller && register.rooms[id].controller.safeMode && register.rooms[id].controller.my) { obstacleTypes = _.without(obstacleTypes, 'creep', 'powerCreep'); } if (register.objectsByRoomKeys[id]) { register.objectsByRoomKeys[id].forEach(key => { var object = register.objectsByRoom[id][key]; if (_.contains(obstacleTypes, object.type) || !opts.ignoreCreeps && register.rooms[id].controller && register.rooms[id].controller.safeMode && register.rooms[id].controller.my && (object.type == 'creep' || object.type == 'powerCreep') && object.user == runtimeData.user._id || !opts.ignoreDestructibleStructures && object.type == 'rampart' && !object.isPublic && object.user != runtimeData.user._id || !opts.ignoreDestructibleStructures && object.type == 'constructionSite' && object.user == runtimeData.user._id && _.contains(C.OBSTACLE_OBJECT_TYPES, object.structureType)) { costs.set(object.x, object.y, 0xFF); } if (object.type == 'swamp' && costs.get(object.x, object.y) == 0) { costs.set(object.x, object.y, opts.ignoreRoads ? 5 : 10); } if (!opts.ignoreRoads && object.type == 'road' && costs.get(object.x, object.y) < 0xFF) { costs.set(object.x, object.y, 1); } }); } return costs; } function getPathfindingGrid2(id, opts) { if (!privateStore[id]) { return new globals.PathFinder.CostMatrix(); } var gridName = 'grid2'; opts = opts || {}; if (opts.ignoreCreeps) { gridName += '_ignoreCreeps'; } if (opts.ignoreDestructibleStructures) { gridName += '_ignoreDestructibleStructures'; } if (opts.ignoreRoads) { gridName += '_ignoreRoads'; } if (!privateStore[id].pfGrid[gridName]) privateStore[id].pfGrid[gridName] = makePathfindingGrid2(id, opts); return privateStore[id].pfGrid[gridName]; } function _findPath2(id, fromPos, toPos, opts) { opts = opts || {}; if (fromPos.isEqualTo(toPos)) { return opts.serialize ? '' : []; } if (opts.avoid) { register.deprecated('`avoid` option cannot be used when `PathFinder.use()` is enabled. Use `costCallback` instead.'); opts.avoid = undefined; } if (opts.ignore) { register.deprecated('`ignore` option cannot be used when `PathFinder.use()` is enabled. Use `costCallback` instead.'); opts.ignore = undefined; } if (opts.maxOps === undefined && (opts.maxRooms === undefined || opts.maxRooms > 1) && fromPos.roomName != toPos.roomName) { opts.maxOps = 20000; } var searchOpts = { roomCallback: function (roomName) { var costMatrix = getPathfindingGrid2(roomName, opts); if (typeof opts.costCallback == 'function') { costMatrix = costMatrix.clone(); var resultMatrix = opts.costCallback(roomName, costMatrix); if (resultMatrix instanceof globals.PathFinder.CostMatrix) { costMatrix = resultMatrix; } } return costMatrix; }, maxOps: opts.maxOps, maxRooms: opts.maxRooms }; if (!opts.ignoreRoads) { searchOpts.plainCost = 2; searchOpts.swampCost = 10; } if (opts.plainCost) { searchOpts.plainCost = opts.plainCost; } if (opts.swampCost) { searchOpts.swampCost = opts.swampCost; } var ret = globals.PathFinder.search(fromPos, { range: Math.max(1, opts.range || 0), pos: toPos }, searchOpts); if (!opts.range && (ret.path.length && ret.path[ret.path.length - 1].isNearTo(toPos) && !ret.path[ret.path.length - 1].isEqualTo(toPos) || !ret.path.length && fromPos.isNearTo(toPos))) { ret.path.push(toPos); } var curX = fromPos.x, curY = fromPos.y; var resultPath = []; for (let i = 0; i < ret.path.length; i++) { let pos = ret.path[i]; if (pos.roomName != id) { break; } let result = { x: pos.x, y: pos.y, dx: pos.x - curX, dy: pos.y - curY, direction: utils.getDirection(pos.x - curX, pos.y - curY) }; curX = result.x; curY = result.y; resultPath.push(result); } if (opts.serialize) { return utils.serializePath(resultPath); } return resultPath; } function _findClosestByPath2(fromPos, objects, opts) { opts = opts || {}; if (_.isNumber(objects)) { objects = register.rooms[fromPos.roomName].find(objects, { filter: opts.filter }); } else if (opts.filter) { objects = _.filter(objects, opts.filter); } if (!objects.length) { return null; } var objectOnSquare = _.find(objects, obj => fromPos.isEqualTo(obj)); if (objectOnSquare) { return objectOnSquare; } var goals = _.map(objects, i => { if (i.pos) { i = i.pos; } return { range: 1, pos: i }; }); if (opts.avoid) { register.deprecated('`avoid` option cannot be used when `PathFinder.use()` is enabled. Use `costCallback` instead.'); } if (opts.ignore) { register.deprecated('`ignore` option cannot be used when `PathFinder.use()` is enabled. Use `costCallback` instead.'); } var searchOpts = { roomCallback: function (roomName) { if (register.objectsByRoom[roomName]) { var costMatrix = getPathfindingGrid2(roomName, opts); if (typeof opts.costCallback == 'function') { costMatrix = costMatrix.clone(); var resultMatrix = opts.costCallback(roomName, costMatrix); if (resultMatrix instanceof globals.PathFinder.CostMatrix) { costMatrix = resultMatrix; } } return costMatrix; } }, maxOps: opts.maxOps, maxRooms: 1 }; if (!opts.ignoreRoads) { searchOpts.plainCost = 2; searchOpts.swampCost = 10; } var ret = globals.PathFinder.search(fromPos, goals, searchOpts); var result = null; var lastPos = fromPos; if (ret.path.length) { lastPos = ret.path[ret.path.length - 1]; } objects.forEach(obj => { if (lastPos.isNearTo(obj)) { result = obj; } }); return result; } exports.make = function (_runtimeData, _intents, _register, _globals) { runtimeData = _runtimeData; intents = _intents; register = _register; globals = _globals; positionsSetCacheCounter = 1; createdFlagNames = []; createdSpawnNames = []; privateStore = {}; createdConstructionSites = 0; TerrainConstructor || (() => { for (var roomName in runtimeData.staticTerrainData) { var array = runtimeData.staticTerrainData[roomName]; TerrainConstructor = array.constructor; break; } })(); TerrainConstructorSet || (() => { TerrainConstructorSet = TerrainConstructor.prototype.set; })(); if (globals.Room) { return; } var data = id => { if (!runtimeData.rooms[id]) { throw new Error("Could not find a room with name " + id); } return runtimeData.rooms[id]; }; /** * Room * @param id * @returns {number} * @constructor */ var Room = register.wrapFn(function (id) { var gameInfo, gameId = id, match = id.match(/survival_(.*)$/); if (match) { gameId = match[1]; } if (runtimeData.games && gameId in runtimeData.games) { gameInfo = runtimeData.games[gameId]; } Object.defineProperty(this, 'name', { value: id, enumerable: true }); this.energyAvailable = 0; this.energyCapacityAvailable = 0; this.survivalInfo = gameInfo; privateStore[id] = { pfGrid: {}, pfFinders: {}, pfEndNodes: {}, pfDijkstraFinder: new pathfinding.DijkstraFinder({ diagonalMovement: 1 }), pathCache: {}, positionsSetCache: { cache: {}, key(array) { if (!_.isArray(array)) { return 0; } var positionsArray = _.map(array, i => { if (i && i.pos) { return i.pos; } if (_.isObject(i) && !_.isUndefined(i.x) && !(i instanceof globals.RoomPosition)) { return new globals.RoomPosition(i.x, i.y, id); } return i; }); var key = _.findKey(this.cache, objects => { return positionsArray.length == objects.length && _.every(positionsArray, j => _.any(objects, object => { if (!_.isObject(j) || !j.isEqualTo) { throw new Error('Invalid position ' + j + ', check your `opts` property'); } return j.isEqualTo(object); })); }); if (key === undefined) { key = positionsSetCacheCounter++; this.cache[key] = _.clone(array); } else { key = parseInt(key); } return key; } }, lookTypeRegisters: { creep: register.byRoom[id].creeps, energy: register.byRoom[id].energy, resource: register.byRoom[id].energy, source: register.byRoom[id].sources, mineral: register.byRoom[id].minerals, deposit: register.byRoom[id].deposits, structure: register.byRoom[id].structures, flag: register.byRoom[id].flags, constructionSite: register.byRoom[id].constructionSites, tombstone: register.byRoom[id].tombstones, ruin: register.byRoom[id].ruins, nuke: register.byRoom[id].nukes, powerCreep: register.byRoom[id].powerCreeps }, lookTypeSpatialRegisters: { creep: register.byRoom[id].spatial.creeps, energy: register.byRoom[id].spatial.energy, resource: register.byRoom[id].spatial.energy, source: register.byRoom[id].spatial.sources, mineral: register.byRoom[id].spatial.minerals, deposit: register.byRoom[id].spatial.deposits, structure: register.byRoom[id].spatial.structures, flag: register.byRoom[id].spatial.flags, constructionSite: register.byRoom[id].spatial.constructionSites, tombstone: register.byRoom[id].spatial.tombstones, ruin: register.byRoom[id].spatial.ruins, nuke: register.byRoom[id].spatial.nukes, powerCreep: register.byRoom[id].spatial.powerCreeps } }; if (runtimeData.customObjectPrototypes) { runtimeData.customObjectPrototypes.forEach(i => { if (i.opts.lookConstant) { privateStore[id].lookTypeRegisters[i.opts.lookConstant] = register.byRoom[id][i.opts.lookConstant]; privateStore[id].lookTypeSpatialRegisters[i.opts.lookConstant] = register.byRoom[id].spatial[i.opts.lookConstant]; } }); } this.visual = new globals.RoomVisual(id); }); Room.serializePath = register.wrapFn(function (path) { return utils.serializePath(path); }); Room.deserializePath = register.wrapFn(function (str) { return utils.deserializePath(str); }); Room.prototype.toString = register.wrapFn(function () { return `[room ${this.name}]`; }); Room.prototype.toJSON = register.wrapFn(function () { var result = {}; for (var i in this) { if (i[0] == '_' || _.contains(['toJSON', 'toString', 'controller', 'storage', 'terminal'], i)) { continue; } result[i] = this[i]; } return result; }); Object.defineProperty(Room.prototype, 'memory', { get: function () { if (_.isUndefined(globals.Memory.rooms) || globals.Memory.rooms === 'undefined') { globals.Memory.rooms = {}; } if (!_.isObject(globals.Memory.rooms)) { return undefined; } return globals.Memory.rooms[this.name] = globals.Memory.rooms[this.name] || {}; }, set: function (value) { if (_.isUndefined(globals.Memory.rooms) || globals.Memory.rooms === 'undefined') { globals.Memory.rooms = {}; } if (!_.isObject(globals.Memory.rooms)) { throw new Error('Could not set room memory'); } globals.Memory.rooms[this.name] = value; } }); Room.prototype.getEventLog = register.wrapFn(function (raw) { if (raw) { return runtimeData.roomEventLog[this.name] || '[]'; } var _register2 = register; let roomEventLogCache = _register2.roomEventLogCache; if (!roomEventLogCache[this.name]) { roomEventLogCache[this.name] = JSON.parse(runtimeData.roomEventLog[this.name] || '[]'); } return roomEventLogCache[this.name]; }); Room.prototype.find = register.wrapFn(function (type, opts) { var result = []; opts = opts || {}; if (register.findCache[type] && register.findCache[type][this.name]) { result = register.findCache[type][this.name]; } else { switch (type) { case C.FIND_EXIT: register.findCache[type] = register.findCache[type] || {}; register.findCache[type][this.name] = this.find(C.FIND_EXIT_TOP, opts).concat(this.find(C.FIND_EXIT_BOTTOM, opts)).concat(this.find(C.FIND_EXIT_RIGHT, opts)).concat(this.find(C.FIND_EXIT_LEFT, opts)); return _.clone(register.findCache[type][this.name]); case C.FIND_EXIT_TOP: case C.FIND_EXIT_RIGHT: case C.FIND_EXIT_BOTTOM: case C.FIND_EXIT_LEFT: register.findCache[type] = register.findCache[type] || {}; var exits = []; for (var i = 0; i < 50; i++) { var x = 0, y = 0; if (type == C.FIND_EXIT_LEFT || type == C.FIND_EXIT_RIGHT) { y = i; } else { x = i; } if (type == C.FIND_EXIT_RIGHT) { x = 49; } if (type == C.FIND_EXIT_BOTTOM) { y = 49; } exits.push(!(runtimeData.staticTerrainData[this.name][y * 50 + x] & C.TERRAIN_MASK_WALL)); } result = _.reduce(exits, (accum, i, key) => { if (i) { if (type == C.FIND_EXIT_TOP) { accum.push(this.getPositionAt(key, 0)); } if (type == C.FIND_EXIT_BOTTOM) { accum.push(this.getPositionAt(key, 49)); } if (type == C.FIND_EXIT_LEFT) { accum.push(this.getPositionAt(0, key)); } if (type == C.FIND_EXIT_RIGHT) { accum.push(this.getPositionAt(49, key)); } } return accum; }, []); register.findCache[type][this.name] = result; break; } } if (opts.filter) { result = _.filter(result, opts.filter); } else { result = _.clone(result); } return result; }); function _lookSpatialRegister(id, typeName, x, y, outArray, withCoords) { var item; if (typeName == 'terrain') { var result = 'plain'; var terrainCode = runtimeData.staticTerrainData[id][y * 50 + x]; if (terrainCode & C.TERRAIN_MASK_SWAMP) { result = 'swamp'; } if (terrainCode & C.TERRAIN_MASK_WALL) { result = 'wall'; } if (outArray) { item = { type: 'terrain', terrain: result }; if (withCoords) { item.x = x; item.y = y; } outArray.push(item); return; } return [result]; } if (x < 0 || y < 0 || x > 49 || y > 49) { throw new Error('look coords are out of bounds'); } var typeResult = privateStore[id].lookTypeSpatialRegisters[typeName][x * 50 + y]; if (typeResult) { if (outArray) { typeResult.forEach(i => { item = { type: typeName }; item[typeName] = i; if (withCoords) { item.x = x; item.y = y; } outArray.push(item); }); return; } return _.clone(typeResult); } return []; } function _lookAreaMixedRegister(id, type, top, left, bottom, right, withType, asArray, result) { var typeRegister = privateStore[id].lookTypeRegisters[type], keys = typeRegister && Object.keys(typeRegister); if (type != 'terrain' && keys.length < (bottom - top + 1) * (right - left + 1)) { // by objects var checkInside = i => { return (!i.pos && i.roomName == id || i.pos && i.pos.roomName == id) && i.pos && i.pos.y >= top && i.pos.y <= bottom && i.pos.x >= left && i.pos.x <= right || !i.pos && i.y >= top && i.y <= bottom && i.x >= left && i.x <= right; }; var item; keys.forEach(key => { var obj = typeRegister[key]; if (checkInside(obj)) { if (withType) { item = { type: type }; item[type] = obj; if (asArray) { result.push({ x: obj.x || obj.pos.x, y: obj.y || obj.pos.y, type, [type]: obj }); } else { result[obj.y || obj.pos.y][obj.x || obj.pos.x].push(item); } } else { if (asArray) { result.push({ x: obj.x || obj.pos.x, y: obj.y || obj.pos.y, [type]: obj }); } else { result[obj.y || obj.pos.y][obj.x || obj.pos.x] = result[obj.y || obj.pos.y][obj.x || obj.pos.x] || []; result[obj.y || obj.pos.y][obj.x || obj.pos.x].push(obj); } } } }); } else { // spatial for (var y = top; y <= bottom; y++) { for (var x = left; x <= right; x++) { if (asArray) { _lookSpatialRegister(id, type, x, y, result, true); } else { if (result[y][x]) { _lookSpatialRegister(id, type, x, y, result[y][x]); } else { result[y][x] = _lookSpatialRegister(id, type, x, y, undefined); } } } } } } Room.prototype.lookAt = register.wrapFn(function (firstArg, secondArg) { var _utils$fetchXYArgumen = utils.fetchXYArguments(firstArg, secondArg, globals), _utils$fetchXYArgumen2 = _slicedToArray(_utils$fetchXYArgumen, 2), x = _utils$fetchXYArgumen2[0], y = _utils$fetchXYArgumen2[1], result = []; _lookSpatialRegister(this.name, C.LOOK_CREEPS, x, y, result); _lookSpatialRegister(this.name, C.LOOK_ENERGY, x, y, result); _lookSpatialRegister(this.name, C.LOOK_RESOURCES, x, y, result); _lookSpatialRegister(this.name, C.LOOK_SOURCES, x, y, result); _lookSpatialRegister(this.name, C.LOOK_MINERALS, x, y, result); _lookSpatialRegister(this.name, C.LOOK_DEPOSITS, x, y, result); _lookSpatialRegister(this.name, C.LOOK_STRUCTURES, x, y, result); _lookSpatialRegister(this.name, C.LOOK_FLAGS, x, y, result); _lookSpatialRegister(this.name, C.LOOK_CONSTRUCTION_SITES, x, y, result); _lookSpatialRegister(this.name, C.LOOK_TERRAIN, x, y, result); _lookSpatialRegister(this.name, C.LOOK_NUKES, x, y, result); _lookSpatialRegister(this.name, C.LOOK_TOMBSTONES, x, y, result); _lookSpatialRegister(this.name, C.LOOK_RUINS, x, y, result); _lookSpatialRegister(this.name, C.LOOK_POWER_CREEPS, x, y, result); if (runtimeData.customObjectPrototypes) { runtimeData.customObjectPrototypes.forEach(i => { if (i.opts.lookConstant) { _lookSpatialRegister(this.name, i.opts.lookConstant, x, y, result); } }); } return result; }); Room.prototype.lookForAt = register.wrapFn(function (type, firstArg, secondArg) { var _utils$fetchXYArgumen3 = utils.fetchXYArguments(firstArg, secondArg, globals), _utils$fetchXYArgumen4 = _slicedToArray(_utils$fetchXYArgumen3, 2), x = _utils$fetchXYArgumen4[0], y = _utils$fetchXYArgumen4[1]; if (type != 'terrain' && !(type in privateStore[this.name].lookTypeSpatialRegisters)) { return C.ERR_INVALID_ARGS; } return _lookSpatialRegister(this.name, type, x, y); }); Room.prototype.lookAtArea = register.wrapFn(function (top, left, bottom, right, asArray) { var result = asArray ? [] : {}; if (!asArray) { for (var y = top; y <= bottom; y++) { result[y] = {}; for (var x = left; x <= right; x++) { result[y][x] = []; } } } _lookAreaMixedRegister(this.name, C.LOOK_CREEPS, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_ENERGY, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_RESOURCES, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_SOURCES, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_MINERALS, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_DEPOSITS, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_STRUCTURES, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_FLAGS, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_CONSTRUCTION_SITES, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_TERRAIN, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_NUKES, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_TOMBSTONES, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_RUINS, top, left, bottom, right, true, asArray, result); _lookAreaMixedRegister(this.name, C.LOOK_POWER_CREEPS, top, left, bottom, right, true, asArray, result); if (runtimeData.customObjectPrototypes) { runtimeData.customObjectPrototypes.forEach(i => { if (i.opts.lookConstant) { _lookAreaMixedRegister(this.name, i.opts.lookConstant, top, left, bottom, right, true, asArray, result); } }); } return result; }); Room.prototype.lookForAtArea = register.wrapFn(function (type, top, left, bottom, right, asArray) { var result = asArray ? [] : {}; if (!asArray) { for (var y = top; y <= bottom; y++) { result[y] = {}; } } _lookAreaMixedRegister(this.name, type, top, left, bottom, right, false, asArray, result); return result; }); Room.prototype.findPath = register.wrapFn(function (fromPos, toPos, opts) { if (fromPos.roomName != this.name) { return opts.serialize ? '' : []; } if (register._useNewPathFinder) { return _findPath2(this.name, fromPos, toPos, opts); } var fromX = fromPos.x, fromY = fromPos.y, path, cacheKeySuffix = ''; opts = _.clone(opts || {}); if (opts.ignoreCreeps) { cacheKeySuffix += '_ignoreCreeps'; } if (opts.ignoreDestructibleStructures) { cacheKeySuffix += '_ignoreDestructibleStructures'; } if (opts.avoid) { cacheKeySuffix += '_avoid' + privateStore[this.name].positionsSetCache.key(opts.avoid); } if (opts.ignore) { cacheKeySuffix += '_ignore' + privateStore[this.name].positionsSetCache.key(opts.ignore); } if (_.isNumber(toPos)) { if (!privateStore[this.name].pfEndNodes[toPos]) { return opts.serialize ? '' : []; } var grid = getPathfindingGrid(this.name, opts, toPos); path = privateStore[this.name].pfDijkstraFinder.findPath(fromX, fromY, -999, -999, grid); } else { if (toPos.roomName != this.name) { return opts.serialize ? '' : []; } var toX = toPos.x, toY = toPos.y, cacheKey = `${fromX},${fromY},${toX},${toY}${cacheKeySuffix}`; if (privateStore[this.name].pathCache[cacheKey]) { return opts.serialize ? utils.serializePath(privateStore[this.name].pathCache[cacheKey]) : _.cloneDeep(privateStore[this.name].pathCache[cacheKey]); } if (fromX == toX && fromY == toY) { return opts.serialize ? '' : []; } if (fromX < 0 || fromY < 0 || toX < 0 || toY < 0 || fromX >= 50 || fromY >= 50 || toX >= 50 || toY >= 50) { return opts.serialize ? '' : []; } if (abs(fromX - toX) < 2 && abs(fromY - toY) < 2) { var result = [{ x: toX, y: toY, dx: toX - fromX, dy: toY - fromY, direction: utils.getDirection(toX - fromX, toY - fromY) }]; return opts.serialize ? utils.serializePath(result) : result; } var grid = getPathfindingGrid(this.name, opts), finder = getPathfinder(this.name, opts); grid.setWalkableAt(toX, toY, true); path = finder.findPath(fromX, fromY, toX, toY, grid); } path.splice(0, 1); var curX = fromX, curY = fromY; var resultPath = _.map(path, step => { var result = { x: step[0], y: step[1], dx: step[0] - curX, dy: step[1] - curY, direction: utils.getDirection(step[0] - curX, step[1] - curY) }; curX = result.x; curY = result.y; return result; }); if (resultPath.length > 0) { var lastStep = resultPath[resultPath.length - 1], cacheKey = `${fromX},${fromY},${lastStep.x},${lastStep.y}${cacheKeySuffix}`; privateStore[this.name].pathCache[cacheKey] = _.cloneDeep(resultPath); } if (opts.serialize) { return utils.serializePath(resultPath); } return resultPath; }); Room.prototype.getPositionAt = register.wrapFn(function (x, y) { if (x < 0 || x > 49 || y < 0 || y > 49) { return null; } return new globals.RoomPosition(x, y, this.name); }); Room.prototype.createFlag = register.wrapFn(function (firstArg, secondArg, name, color, secondaryColor) { var _utils$fetchXYArgumen5 = utils.fetchXYArguments(firstArg, secondArg, globals), _utils$fetchXYArgumen6 = _slicedToArray(_utils$fetchXYArgumen5, 2), x = _utils$fetchXYArgumen6[0], y = _utils$fetchXYArgumen6[1]; if (_.isUndefined(x) || _.isUndefined(y) || x < 0 || x > 49 || y < 0 || y > 49) { return C.ERR_INVALID_ARGS; } if (_.size(globals.Game.flags) >= C.FLAGS_LIMIT) { return C.ERR_FULL; } if (_.isObject(firstArg)) { secondaryColor = color; color = name; name = secondArg; } if (!color) { color = C.COLOR_WHITE; } if (!secondaryColor) { secondaryColor = color; } if (!_.contains(C.COLORS_ALL, color)) { return C.ERR_INVALID_ARGS; } if (!_.contains(C.COLORS_ALL, secondaryColor)) { return C.ERR_INVALID_ARGS; } if (!name) { var cnt = 1; do { name = 'Flag' + cnt; cnt++; } while (_.any(register.flags, { name }) || createdFlagNames.indexOf(name) != -1); } if (_.any(register.flags, { name }) || createdFlagNames.indexOf(name) != -1) { return C.ERR_NAME_EXISTS; } if (name.length > 100) { return C.ERR_INVALID_ARGS; } createdFlagNames.push(name); const roomName = "" + this.name; globals.Game.flags[name] = new globals.Flag(name, color, secondaryColor, roomName, x, y); intents.pushByName('room', 'createFlag', { roomName, x, y, name, color, secondaryColor }); return name; }); Room.prototype.createConstructionSite = register.wrapFn(function (firstArg, secondArg, structureType, name) { var _utils$fetchXYArgumen7 = utils.fetchXYArguments(firstArg, secondArg, globals), _utils$fetchXYArgumen8 = _slicedToArray(_utils$fetchXYArgumen7, 2), x = _utils$fetchXYArgumen8[0], y = _utils$fetchXYArgumen8[1]; if (_.isUndefined(x) || _.isUndefined(y) || x < 0 || x > 49 || y < 0 || y > 49) { return C.ERR_INVALID_ARGS; } if (_.isString(secondArg) && _.isUndefined(structureType)) { structureType = secondArg; } if (!C.CONSTRUCTION_COST[structureType]) { return C.ERR_INVALID_ARGS; } if (structureType == 'spawn' && typeof name == 'string') { if (name.length > 100) { return C.ERR_INVALID_ARGS; } if (createdSpawnNames.indexOf(name) != -1) { return C.ERR_INVALID_ARGS; } if (_.any(register.spawns, { name }) || _.any(register.constructionSites, { structureType: 'spawn', name })) { return C.ERR_INVALID_ARGS; } } if (this.controller && this.controller.level > 0 && !this.controller.my) { return C.ERR_NOT_OWNER; } if (this.controller && this.controller.reservation && register.objectsByRoom[this.name] && register.objectsByRoom[this.name][this.controller.id] && register.objectsByRoom[this.name][this.controller.id].reservation.user != runtimeData.user._id) { return C.ERR_NOT_OWNER; } const roomName = "" + this.name; if (!utils.checkControllerAvailability(structureType, register.objectsByRoom[this.name], this.controller)) { return C.ERR_RCL_NOT_ENOUGH; } if (!utils.checkConstructionSite(register.objectsByRoom[roomName], structureType, x, y) || !utils.checkConstructionSite(runtimeData.staticTerrainData[roomName], structureType, x, y)) { return C.ERR_INVALID_TARGET; } if (_(runtimeData.userObjects).filter({ type: 'constructionSite' }).size() + createdConstructionSites >= C.MAX_CONSTRUCTION_SITES) { return C.ERR_FULL; } var intent = { roomName, x, y, structureType }; if (structureType == 'spawn') { if (typeof name !== 'string') { var cnt = 1; do { name = "Spawn" + cnt; cnt++; } while (_.any(register.spawns, { name }) || _.any(register.constructionSites, { structureType: 'spawn', name }) || createdSpawnNames.indexOf(name) != -1); } createdSpawnNames.push(name); intent.name = name; } createdConstructionSites++; intents.pushByName('room', 'createConstructionSite', intent); return C.OK; }); Room.prototype.getEndNodes = register.wrapFn(function (type, opts) { var key; opts = opts || {}; if (_.isUndefined(type)) { throw new Error('Find type cannot be undefined'); } if (!opts.filter && _.isNumber(type)) { key = type; } else { if (_.isNumber(type)) { type = this.find(type, opts); } key = privateStore[this.name].positionsSetCache.key(type); privateStore[this.name].pfEndNodes[key] = privateStore[this.name].positionsSetCache.cache[key]; } if (!privateStore[this.name].pfEndNodes[key]) { privateStore[this.name].pfEndNodes[key] = _.clone(type); if (_.isNumber(type)) { privateStore[this.name].pfEndNodes[key] = this.find(type, opts); } } return { key, objects: privateStore[this.name].pfEndNodes[key] }; }); Room.prototype.findExitTo = register.wrapFn(function (room) { return register.map.findExit(this.name, room); }); Room.prototype.getTerrain = register.wrapFn(function () { return new Room.Terrain(this.name); }); Object.defineProperty(globals, 'Room', { enumerable: true, value: Room }); /** * RoomVisual * @param id * @returns {object} * @constructor */ var RoomVisual = register.wrapFn(function (roomName) { this.roomName = roomName; }); RoomVisual.prototype.circle = register.wrapFn(function (x, y, style) { if (typeof x == 'object') { style = y; y = x.y; x = x.x; } globals.console.addVisual(this.roomName, { t: 'c', x, y, s: style }); return this; }); RoomVisual.prototype.line = register.wrapFn(function (x1, y1, x2, y2, style) { if (typeof x1 == 'object' && typeof y1 == 'object') { style = x2; x2 = y1.x; y2 = y1.y; y1 = x1.y; x1 = x1.x; } globals.console.addVisual(this.roomName, { t: 'l', x1, y1, x2, y2, s: style }); return this; }); RoomVisual.prototype.rect = register.wrapFn(function (x, y, w, h, style) { if (typeof x == 'object') { style = h; h = w; w = y; y = x.y; x = x.x; } globals.console.addVisual(this.roomName, { t: 'r', x, y, w, h, s: style }); return this; }); RoomVisual.prototype.poly = register.wrapFn(function (points, style) { if (_.isArray(points) && _.some(points)) { points = points.map(i => i.x !== undefined ? [i.x, i.y] : i); globals.console.addVisual(this.roomName, { t: 'p', points, s: style }); } return this; }); RoomVisual.prototype.text = register.wrapFn(function (text, x, y, style) { if (typeof x == 'object') { style = y; y = x.y; x = x.x; } globals.console.addVisual(this.roomName, { t: 't', text, x, y, s: style }); return this; }); RoomVisual.prototype.getSize = register.wrapFn(function () { return globals.console.getVisualSize(this.roomName); }); RoomVisual.prototype.clear = register.wrapFn(function () { globals.console.clearVisual(this.roomName); return this; }); RoomVisual.prototype.export = register.wrapFn(function () { return globals.console.getVisual(this.roomName); }); RoomVisual.prototype.import = register.wrapFn(function (data) { globals.console.addVisual(this.roomName, "" + data); return this; }); Object.defineProperty(globals, 'RoomVisual', { enumerable: true, value: RoomVisual }); Room.Terrain = register.wrapFn(function (roomName) { "use strict"; roomName = "" + roomName; const array = (runtimeData.staticTerrainData || {})[roomName]; if (!array) throw new Error(`Could not access room ${roomName}`); this.get = register.wrapFn(function (x, y) { const value = array[y * 50 + x]; return value & C.TERRAIN_MASK_WALL || value & C.TERRAIN_MASK_SWAMP || 0; }); this.getRawBuffer = register.wrapFn(function (destinationArray) { if (!!destinationArray) { TerrainConstructorSet.call(destinationArray, array); return destinationArray; } return new TerrainConstructor(array); }); }); }; exports.makePos = function (_register) { register = _register; if (globals.RoomPosition) { return; } /** * RoomPosition * @param x * @param y * @param roomName * @constructor */ const kMaxWorldSize = 256; const kMaxWorldSize2 = kMaxWorldSize >> 1; const roomNames = []; utils.getRoomNameFromXY = function (slowFn) { return function (xx, yy) { let id = xx + kMaxWorldSize2 << 8 | yy + kMaxWorldSize2; let roomName = roomNames[id]; if (roomName === undefined) { return roomNames[id] = slowFn(xx, yy); } else { return roomName; } }; }(utils.getRoomNameFromXY); roomNames[0] = 'sim'; let RoomPosition = register.wrapFn(function RoomPosition(xx, yy, roomName) { let xy = roomName === 'sim' ? [-kMaxWorldSize2, -kMaxWorldSize2] : utils.roomNameToXY(roomName); xy[0] += kMaxWorldSize2; xy[1] += kMaxWorldSize2; if (xy[0] < 0 || xy[0] > kMaxWorldSize || xy[0] !== xy[0] || xy[1] < 0 || xy[1] > kMaxWorldSize || xy[1] !== xy[1] || xx < 0 || xx > 49 || xx !== xx || yy < 0 || yy > 49 || yy !== yy) { throw new Error('Invalid arguments in RoomPosition constructor'); } Object.defineProperty(this, '__packedPos', { enumerable: false, value: xy[0] << 24 | xy[1] << 16 | xx << 8 | yy, writable: true }); }); Object.defineProperties(RoomPosition.prototype, { x: { enumerable: true, get() { return this.__packedPos >> 8 & 0xff; }, set(val) { if (val < 0 || val > 49 || val !== val) { throw new Error('Invalid coordinate'); } this.__packedPos = this.__packedPos & ~(0xff << 8) | val << 8; } }, y: { enumerable: true, get() { return this.__packedPos & 0xff; }, set(val) { if (val < 0 || val > 49 || val !== val) { throw new Error('Invalid coordinate'); } this.__packedPos = this.__packedPos & ~0xff | val; } }, roomName: { enumerable: true, get() { let roomName = roomNames[this.__packedPos >>> 16]; if (roomName === undefined) { return utils.getRoomNameFromXY((this.__packedPos >>> 24) - kMaxWorldSize2, (this.__packedPos >>> 16 & 0xff) - kMaxWorldSize2); } else { return roomName; } }, set(val) { let xy = val === 'sim' ? [-kMaxWorldSize2, -kMaxWorldSize2] : utils.roomNameToXY(val); xy[0] += kMaxWorldSize2; xy[1] += kMaxWorldSize2; if (xy[0] < 0 || xy[0] > kMaxWorldSize || xy[0] !== xy[0] || xy[1] < 0 || xy[1] > kMaxWorldSize || xy[1] !== xy[1]) { throw new Error('Invalid roomName'); } this.__packedPos = this.__packedPos & ~(0xffff << 16) | xy[0] << 24 | xy[1] << 16; } } }); RoomPosition.prototype.toJSON = register.wrapFn(function () { return Object.assign({ x: this.x, y: this.y, roomName: this.roomName }, this); }); RoomPosition.prototype.toString = register.wrapFn(function () { return `[room ${this.roomName} pos ${this.x},${this.y}]`; }); RoomPosition.prototype.inRangeTo = register.wrapFn(function (firstArg, secondArg, thirdArg) { var x = firstArg, y = secondArg, range = thirdArg, roomName = this.roomName; if (_.isUndefined(thirdArg)) { var pos = firstArg; if (pos.pos) { pos = pos.pos; } x = pos.x; y = pos.y; roomName = pos.roomName; range = secondArg; } return abs(x - this.x) <= range && abs(y - this.y) <= range && roomName == this.roomName; }); RoomPosition.prototype.isNearTo = register.wrapFn(function (firstArg, secondArg) { var _utils$fetchXYArgumen9 = utils.fetchXYArguments(firstArg, secondArg, globals), _utils$fetchXYArgumen10 = _slicedToArray(_utils$fetchXYArgumen9, 3), x = _utils$fetchXYArgumen10[0], y = _utils$fetchXYArgumen10[1], roomName = _utils$fetchXYArgumen10[2]; return abs(x - this.x) <= 1 && abs(y - this.y) <= 1 && (!roomName || roomName == this.roomName); }); RoomPosition.prototype.getDirectionTo = register.wrapFn(function (firstArg, secondArg) { var _utils$fetchXYArgumen11 = utils.fetchXYArguments(firstArg, secondArg, globals), _utils$fetchXYArgumen12 = _slicedToArray(_utils$fetchXYArgumen11, 3), x = _util