UNPKG

@screeps/engine

Version:

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

253 lines (209 loc) 7.63 kB
var _ = require('lodash'), utils = require('../../utils'), driver = utils.getDriver(), C = driver.constants, matrix, objects, affectedCnt, roomObjects, roomTerrain; function canMove(object) { return object.type == 'powerCreep' || (!!object._pulled || !object._oldFatigue && _.some(object.body, i => i.hits > 0 && i.type == C.MOVE)); } function checkObstacleAtXY(x,y,object, roomIsInSafeMode) { var hasObstacle = false, hasRoad = false; _.forEach(roomObjects, (i) => { if (i.x != x || i.y != y) { return; } if ((i.type == 'creep' || i.type == 'powerCreep') && !objects[i._id] && (!roomIsInSafeMode || roomIsInSafeMode != object.user || roomIsInSafeMode == object.user && object.user == i.user) || i.type != 'creep' && i.type != 'powerCreep' && _.contains(C.OBSTACLE_OBJECT_TYPES, i.type) || i.type == 'rampart' && !i.isPublic && i.user != object.user || i.type == 'constructionSite' && i.user == object.user && _.contains(C.OBSTACLE_OBJECT_TYPES, i.structureType)) { hasObstacle = true; return false; } if(i.type == 'road') { hasRoad = true; } }); if(hasObstacle) { return true; } return utils.checkTerrain(roomTerrain, x, y, C.TERRAIN_MASK_WALL) && !hasRoad; } function calcResourcesWeight(creep) { var totalCarry = _.sum(creep.store), weight = 0; for(var i = creep.body.length-1; i >= 0; i--) { if(!totalCarry) { break; } var part = creep.body[i]; if(part.type != C.CARRY || !part.hits) { continue; } var boost = 1; if(part.boost) { boost = C.BOOSTS[C.CARRY][part.boost].capacity || 1; } totalCarry -= Math.min(totalCarry, C.CARRY_CAPACITY * boost); weight++; } return weight; } exports.init = function(_roomObjects, _roomTerrain) { matrix = {}; objects = {}; affectedCnt = {}; roomObjects = _roomObjects; roomTerrain = _roomTerrain; }; exports.addPulling = function(object, target) { const checkRecursiveTarget = t=>t._id==object._id || !!t._pull && !!roomObjects[t._pull] && checkRecursiveTarget(roomObjects[t._pull]); if(!checkRecursiveTarget(target)) { object._pull = target._id; target._pulled = object._id; } }; exports.removePulling = function(object) { if(object._pull && !!roomObjects[object._pull]) { delete roomObjects[object._pull]._pulled; } delete object._pull; }; exports.add = function(object, dx, dy) { var newX = object.x + dx, newY = object.y + dy; if (newX >= 50) newX = 49; if (newY >= 50) newY = 49; if (newX < 0) newX = 0; if (newY < 0) newY = 0; var key = `${newX},${newY}`; matrix[key] = matrix[key] || []; matrix[key].push(object); affectedCnt[key] = affectedCnt[key]+1 || 1; }; exports.isTileBusy = function(x,y) { return !!matrix[`${x},${y}`]; }; exports.check = function(roomIsInSafeMode) { var newMatrix = {}; for(var i in matrix) { var [x,y] = i.split(/,/), resultingMoveObject; x = parseInt(x); y = parseInt(y); if(matrix[i].length > 1) { var rates = _.map(matrix[i], (object) => { var moves = object.type == 'powerCreep' ? 0 : utils.calcBodyEffectiveness(object.body, C.MOVE, 'fatigue', 1), weight = object.type == 'powerCreep' ? 0 : _.filter(object.body, (i) => i.type != C.MOVE && i.type != C.CARRY).length; weight += object.type == 'powerCreep' ? 0 : calcResourcesWeight(object); weight = weight || 1; var key = `${object.x},${object.y}`, rate1 = affectedCnt[key] || 0; if(matrix[key] && _.any(matrix[key], {x,y})) { rate1 = 100; } return { object, rate1, rate2: !!object._pulled?1:0, rate3: !!object._pull?1:0, rate4: moves / weight }; }); rates.sort((a,b) => b.rate1 - a.rate1 || b.rate2 - a.rate2 || b.rate3 - a.rate3 || b.rate4 - a.rate4); resultingMoveObject = rates[0].object; } else { resultingMoveObject = matrix[i][0]; } objects[resultingMoveObject._id] = {x,y}; newMatrix[i] = resultingMoveObject; } matrix = newMatrix; function removeFromMatrix(i) { var object = matrix[i]; objects[matrix[i]._id] = null; delete matrix[i]; if(object) { var key = `${object.x},${object.y}`; if(matrix[key]) { removeFromMatrix(key); } } } for(var i in matrix) { var [x,y] = i.split(/,/); x = parseInt(x); y = parseInt(y); var object = matrix[i]; if(!!object._pulled && !!roomObjects[object._pulled]) { if(roomObjects[object._pulled]._pull != object._id || i != `${roomObjects[object._pulled].x},${roomObjects[object._pulled].y}`) { delete roomObjects[object._pulled]._pull; delete object._pulled; } } if(!canMove(object) || !!checkObstacleAtXY(x,y, object, roomIsInSafeMode)) { removeFromMatrix(i); } } }; exports.execute = function(object, scope) { const {bulk, roomController, gameTime} = scope; var move = objects[object._id]; if(!move) { return; } if(!canMove(object)) { return; } var cellObjects = _.filter(roomObjects, (i) => i.x == move.x && i.y == move.y); var fatigueRate = 2; if(_.any(cellObjects, {type: 'swamp'}) || utils.checkTerrain(roomTerrain, move.x, move.y, C.TERRAIN_MASK_SWAMP)) { fatigueRate = 10; } var road = _.find(cellObjects, {type: 'road'}); if(road) { fatigueRate = 1; if(object.type == 'powerCreep') { road.nextDecayTime -= C.ROAD_WEAROUT_POWER_CREEP; } else { road.nextDecayTime -= C.ROAD_WEAROUT * object.body.length; } bulk.update(road, {nextDecayTime: road.nextDecayTime}); } if(!roomController || roomController.user === object.user || !(roomController.safeMode > gameTime)) { var constructionSite = _.find(cellObjects, (i) => i.type == 'constructionSite' && i.user != object.user); if (constructionSite) { bulk.remove(constructionSite._id); if(constructionSite.progress > 1) { require('./_create-energy')(constructionSite.x, constructionSite.y, constructionSite.room, Math.floor(constructionSite.progress/2), 'energy', scope); } } } var fatigue; if(object.type == 'creep') { fatigue = _(object.body).filter((i) => i.type != C.MOVE && i.type != C.CARRY).size(); fatigue += calcResourcesWeight(object); fatigue *= fatigueRate; } if(utils.isAtEdge(move) && !utils.isAtEdge(object)) { fatigue = 0; object._fatigue = 0; bulk.update(object, { x: move.x, y: move.y, fatigue }); } else { bulk.update(object, { x: move.x, y: move.y }); if(object.type == 'creep') { require('./creeps/_add-fatigue')(object, fatigue, scope); } } };