diff --git a/package.json b/package.json index 998df6ad..cb4faef8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@screeps/engine", - "version": "2.1.1", + "version": "2.11.0", "bin": { "screeps-engine-main": "dist/main.js", "screeps-engine-runner": "dist/runner.js", @@ -13,15 +13,15 @@ "bulk-require": "^0.2.1" }, "devDependencies": { - "babel-plugin-transform-es2015-destructuring": "^6.0.2", - "babel-plugin-transform-strict-mode": "^6.0.2", - "babel-preset-es2015": "^6.0.15", - "gulp": "^3.8.8", - "gulp-babel": "^6.0.0", - "gulp-plumber": "^0.6.6", - "gulp-sourcemaps": "^1.3.0", - "gulp-traceur": "^0.13.0", - "gulp-watch": "^1.1.0" + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-preset-es2015": "^6.24.1", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", + "gulp-plumber": "^1.1.0", + "gulp-sourcemaps": "^2.6.0", + "gulp-traceur": "^0.17.2", + "gulp-watch": "^4.3.11" }, "license": "ISC", "author": "Artem Chivchalov ", diff --git a/src/game/console.js b/src/game/console.js index 28ea27e6..877085f9 100644 --- a/src/game/console.js +++ b/src/game/console.js @@ -1,10 +1,12 @@ var _ = require('lodash'), messages = {}, - commandResults = {}; + commandResults = {}, + visual = {}; exports.makeConsole = function(id, sandboxedFunctionWrapper) { messages[id] = []; commandResults[id] = []; + visual[id] = {}; return Object.create(null, { log: { writable: true, @@ -30,6 +32,31 @@ exports.makeConsole = function(id, sandboxedFunctionWrapper) { } commandResults[id].push(String(message)); }) + }, + addVisual: { + value: sandboxedFunctionWrapper(function(roomName, data) { + roomName = roomName || ""; + visual[id][roomName] = visual[id][roomName] || ""; + if(visual[id][roomName].length > 500*1024) { + throw new Error(`RoomVisual size in room ${roomName} has exceeded 500 KB limit`); + } + visual[id][roomName] += JSON.stringify(data)+"\n"; + }) + }, + getVisualSize: { + value: sandboxedFunctionWrapper(function(roomName) { + roomName = roomName || ""; + if(!visual[id][roomName]) { + return 0; + } + return visual[id][roomName].length; + }) + }, + clearVisual: { + value: sandboxedFunctionWrapper(function(roomName) { + roomName = roomName || ""; + visual[id][roomName] = ""; + }) } }); }; @@ -44,4 +71,10 @@ exports.getCommandResults = function(id) { var result = commandResults[id]; commandResults[id] = []; return result; +}; + +exports.getVisual = function(id) { + var result = visual[id]; + visual[id] = []; + return result; }; \ No newline at end of file diff --git a/src/game/construction-sites.js b/src/game/construction-sites.js index 32d5b63c..99438b8c 100644 --- a/src/game/construction-sites.js +++ b/src/game/construction-sites.js @@ -52,7 +52,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(!this.my && !(this.room && this.room.controller && this.room.controller.my)) { return C.ERR_NOT_OWNER; } - intents.set(this.id, 'remove', {}); + intents.pushByName('room', 'removeConstructionSite', {roomName: data(this.id).room, id: this.id}); return C.OK; }); diff --git a/src/game/creeps.js b/src/game/creeps.js index 4ba85d3d..d80601b0 100644 --- a/src/game/creeps.js +++ b/src/game/creeps.js @@ -6,6 +6,27 @@ var utils = require('./../utils'), var runtimeData, intents, register, globals, controllersClaimedInTick; +function _getActiveBodyparts(body, type) { + var count = 0; + for(var i = body.length-1; i>=0; i--) { + if (body[i].hits <= 0) + break; + if (body[i].type === type) + count++; + } + return count; +} + +function _hasActiveBodypart(body, type) { + for(var i = body.length-1; i>=0; i--) { + if (body[i].hits <= 0) + break; + if (body[i].type === type) + return true; + } + return false; +} + exports.make = function(_runtimeData, _intents, _register, _globals) { runtimeData = _runtimeData; @@ -116,7 +137,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(data(this.id).fatigue > 0) { return C.ERR_TIRED; } - if(this.getActiveBodyparts(C.MOVE) == 0) { + if(!_hasActiveBodypart(this.body, C.MOVE)) { return C.ERR_NO_BODYPART; } direction = +direction; @@ -129,16 +150,23 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { Creep.prototype.moveTo = register.wrapFn(function(firstArg, secondArg, opts) { + var visualized = false; + if(!this.my) { return C.ERR_NOT_OWNER; } if(this.spawning) { return C.ERR_BUSY; } - if(data(this.id).fatigue > 0) { + if(_.isObject(firstArg)) { + opts = _.clone(secondArg); + } + opts = opts || {}; + + if(data(this.id).fatigue > 0 && (!opts || !opts.visualizePathStyle)) { return C.ERR_TIRED; } - if(this.getActiveBodyparts(C.MOVE) == 0) { + if(!_hasActiveBodypart(this.body, C.MOVE)) { return C.ERR_NO_BODYPART; } @@ -151,11 +179,6 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { var targetPos = new globals.RoomPosition(x,y,roomName); - if(_.isObject(firstArg)) { - opts = _.clone(secondArg); - } - opts = opts || {}; - if(_.isUndefined(opts.reusePath)) { opts.reusePath = 5; } @@ -163,6 +186,10 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { opts.serializeMemory = true; } + if(opts.visualizePathStyle) { + _.defaults(opts.visualizePathStyle, {fill: 'transparent', stroke: '#fff', lineStyle: 'dashed', strokeWidth: .15, opacity: .1}); + } + if(x == this.pos.x && y == this.pos.y && roomName == this.pos.roomName) { return C.OK; } @@ -230,6 +257,10 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(path.length == 0) { return this.pos.isNearTo(targetPos) ? C.OK : C.ERR_NO_PATH; } + if(opts.visualizePathStyle) { + this.room.visual.poly(path, opts.visualizePathStyle); + visualized = true; + } var result = this.moveByPath(path); if(result == C.OK) { @@ -256,8 +287,12 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(path.length == 0) { return C.ERR_NO_PATH; } - this.move(path[0].direction); - return C.OK; + + if(opts.visualizePathStyle && !visualized) { + this.room.visual.poly(path, opts.visualizePathStyle); + } + + return this.move(path[0].direction); }); Creep.prototype.moveByPath = register.wrapFn(function(path) { @@ -298,7 +333,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.WORK) == 0) { + if(!_hasActiveBodypart(this.body, C.WORK)) { return C.ERR_NO_BODYPART; } if(!target || !target.id) { @@ -589,7 +624,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(!amount) { amount = Math.min( data(target.id)[resourceType], emptySpace ); } - if(data(target.id)[resourceType] || data(target.id)[resourceType] < amount) { + if(!data(target.id)[resourceType] || data(target.id)[resourceType] < amount) { return C.ERR_NOT_ENOUGH_RESOURCES; } if(amount > emptySpace) { @@ -656,7 +691,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { }); Creep.prototype.getActiveBodyparts = register.wrapFn(function(type) { - return _.filter(this.body, (i) => i.hits > 0 && i.type == type).length; + return _getActiveBodyparts(this.body, type); }); Creep.prototype.attack = register.wrapFn(function(target) { @@ -667,7 +702,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.ATTACK) == 0) { + if(!_hasActiveBodypart(this.body, C.ATTACK)) { return C.ERR_NO_BODYPART; } if(this.room.controller && !this.room.controller.my && this.room.controller.safeMode) { @@ -695,7 +730,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.RANGED_ATTACK) == 0) { + if(!_hasActiveBodypart(this.body, C.RANGED_ATTACK)) { return C.ERR_NO_BODYPART; } if(this.room.controller && !this.room.controller.my && this.room.controller.safeMode) { @@ -723,7 +758,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.RANGED_ATTACK) == 0) { + if(!_hasActiveBodypart(this.body, C.RANGED_ATTACK)) { return C.ERR_NO_BODYPART; } if(this.room.controller && !this.room.controller.my && this.room.controller.safeMode) { @@ -743,7 +778,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.HEAL) == 0) { + if(!_hasActiveBodypart(this.body, C.HEAL)) { return C.ERR_NO_BODYPART; } if(!target || !target.id || !register.creeps[target.id] || !(target instanceof globals.Creep)) { @@ -770,7 +805,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.HEAL) == 0) { + if(!_hasActiveBodypart(this.body, C.HEAL)) { return C.ERR_NO_BODYPART; } if(!target || !target.id || !register.creeps[target.id] || !(target instanceof globals.Creep)) { @@ -797,7 +832,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.WORK) == 0) { + if(!_hasActiveBodypart(this.body, C.WORK)) { return C.ERR_NO_BODYPART; } if(!this.carry.energy) { @@ -825,7 +860,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.WORK) == 0) { + if(!_hasActiveBodypart(this.body, C.WORK)) { return C.ERR_NO_BODYPART; } if(!this.carry.energy) { @@ -838,12 +873,12 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(!this.pos.inRangeTo(target, C.RANGE_BUILD)) { return C.ERR_NOT_IN_RANGE; } - if(_.contains(['spawn','extension','constructedWall'], target.structureType) && + if(_.contains(C.OBSTACLE_OBJECT_TYPES, target.structureType) && _.any(register.objectsByRoom[data(this.id).room], (i) => i.x == target.pos.x && i.y == target.pos.y && _.contains(C.OBSTACLE_OBJECT_TYPES, i.type))) { return C.ERR_INVALID_TARGET; } - var buildPower = this.getActiveBodyparts(C.WORK) * C.BUILD_POWER, + var buildPower = _getActiveBodyparts(this.body, C.WORK) * C.BUILD_POWER, buildRemaining = target.progressTotal - target.progress, buildEffect = Math.min(buildPower, buildRemaining, this.carry.energy); @@ -892,8 +927,9 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { return C.ERR_BUSY; } - var controllersClaimed = _.filter(runtimeData.userObjects, {type: 'controller'}).length + controllersClaimedInTick; - if (controllersClaimed && (!runtimeData.user.gcl || runtimeData.user.gcl < C.GCL_MULTIPLY * Math.pow(controllersClaimed, C.GCL_POW))) { + var controllersClaimed = runtimeData.user.rooms.length + controllersClaimedInTick; + if (controllersClaimed && + (!runtimeData.user.gcl || runtimeData.user.gcl < utils.calcNeededGcl(controllersClaimed + 1))) { return C.ERR_GCL_NOT_ENOUGH; } if (controllersClaimed >= C.GCL_NOVICE && runtimeData.rooms[this.room.name].novice > Date.now()) { @@ -903,7 +939,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { register.assertTargetObject(target); return C.ERR_INVALID_TARGET; } - if(this.getActiveBodyparts(C.CLAIM) == 0) { + if(!_hasActiveBodypart(this.body, C.CLAIM)) { return C.ERR_NO_BODYPART; } if(!target.pos.inRangeTo(this.pos, C.RANGE_CLAIM_CONTROLLER)) { @@ -939,7 +975,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { register.assertTargetObject(target); return C.ERR_INVALID_TARGET; } - if(this.getActiveBodyparts(C.CLAIM) < 5) { + if(!_getActiveBodyparts(this.body, C.CLAIM)) { return C.ERR_NO_BODYPART; } if(!target.pos.inRangeTo(this.pos, C.RANGE_ATTACK_CONTROLLER)) { @@ -948,6 +984,9 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(!target.owner && !target.reservation) { return C.ERR_INVALID_TARGET; } + if(data(target.id).upgradeBlocked > runtimeData.time) { + return C.ERR_TIRED; + } if(this.room.controller && !this.room.controller.my && this.room.controller.safeMode) { return C.ERR_NO_BODYPART; } @@ -964,7 +1003,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.WORK) == 0) { + if(!_hasActiveBodypart(this.body, C.WORK)) { return C.ERR_NO_BODYPART; } if(!this.carry.energy) { @@ -1016,7 +1055,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(target.reservation && target.reservation.username != runtimeData.user.username) { return C.ERR_INVALID_TARGET; } - if(!this.getActiveBodyparts(C.CLAIM)) { + if(!_hasActiveBodypart(this.body, C.CLAIM)) { return C.ERR_NO_BODYPART; } @@ -1061,7 +1100,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.spawning) { return C.ERR_BUSY; } - if(this.getActiveBodyparts(C.WORK) == 0) { + if(!_hasActiveBodypart(this.body, C.WORK)) { return C.ERR_NO_BODYPART; } if(!target || !target.id || !register.structures[target.id] || diff --git a/src/game/game.js b/src/game/game.js index 224a3e2b..c020a73a 100644 --- a/src/game/game.js +++ b/src/game/game.js @@ -283,7 +283,7 @@ } } - if (!object.off && (object.type == 'extension' || object.type == 'spawn')) { + if (!object.off && (object.type == 'extension' || object.type == 'spawn') && (object.user == runtimeData.user._id)) { register.rooms[object.room].energyAvailable += object.energy; register.rooms[object.room].energyCapacityAvailable += object.energyCapacity; } @@ -301,7 +301,7 @@ if (object.type == 'energy') { register._objects[i] = new globals.Energy(i); addObjectToRegister(register, 'energy', register._objects[i], object); - addObjectToFindCache(register, C.FIND_DROPPED_ENERGY, register.energy[i], object); + addObjectToFindCache(register, C.FIND_DROPPED_RESOURCES, register.energy[i], object); } if (object.type == 'nuke') { register._objects[i] = new globals.Nuke(i); @@ -458,7 +458,7 @@ if (runCodeCache[userId].runtimeData.user._id == '2') { runCodeCache[userId].codeModules = { main: "PathFinder.use(true); var healer = require('healer'), findAttack = require('findAttack'); for (var i in Game.creeps) { var creep = Game.creeps[i]; if (!creep.room) { continue; } if (creep.getActiveBodyparts('heal') > 0) { healer(creep); } else { findAttack(Game.creeps[i]); } require('shootAtWill')(creep); } for (var i in Memory.creeps) { if (!Game.creeps[i]) { delete Memory.creeps[i]; } }", - findAttack: "var flee = require('flee'); function checkPath(pos1, pos2) { var path = pos1.findPathTo(pos2); if (!path.length) { return false; } return path[path.length - 1].x == pos2.x && path[path.length - 1].y == pos2.y; } function costCallbackIgnoreRamparts(roomName, cm) { var ramparts = Game.rooms[roomName].find(FIND_STRUCTURES, {filter: i => i.structureType == STRUCTURE_RAMPART || i.structureType == STRUCTURE_WALL}); ramparts.forEach(i => cm.set(i.pos.x, i.pos.y, 0)); } module.exports = function (creep) { if (!creep.getActiveBodyparts(ATTACK) && creep.getActiveBodyparts(RANGED_ATTACK) && flee(creep, 3)) { return; } var target, healers = creep.room.find(FIND_MY_CREEPS, { filter: function (i) { return i.getActiveBodyparts('heal') > 0; } }); if (creep.hits < creep.hitsMax / 2 && healers.length > 0 && !creep.getActiveBodyparts(ATTACK)) { target = creep.pos.findClosestByPath(FIND_MY_CREEPS, { ignoreRoads: true, filter: function (i) { return i.getActiveBodyparts('heal') > 0; } }); if (!target || creep.moveTo(target, {maxRooms: 1, ignoreRoads: true}) != OK) { target = null; } } var nearCreeps = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 1, { filter: function (i) { return i.owner.username != 'Source Keeper' } }); if (nearCreeps) { creep.attack(nearCreeps[0]); } if (!target) { target = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS, { ignoreRoads: true, ignoreCreeps: true, filter: function (i) { return i.owner.username != 'Source Keeper' } }); if (target && (creep.getActiveBodyparts(ATTACK) || !creep.pos.inRangeTo(target, 3))) { creep.moveTo(target, {maxRooms: 1, ignoreRoads: true, ignoreCreeps: true}); } } if (!target) { target = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS, { ignoreRoads: true, filter: function (i) { return i.owner.username != 'Source Keeper' }, costCallback: costCallbackIgnoreRamparts }); if (target && (creep.getActiveBodyparts(ATTACK) || !creep.pos.inRangeTo(target, 3))) { creep.moveTo(target, {maxRooms: 1, ignoreRoads: true, costCallback: costCallbackIgnoreRamparts}); } } if (!target) { target = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS, { ignoreDestructibleStructures: true, ignoreRoads: true, filter: function (i) { return i.owner.username != 'Source Keeper' } }); if (target && (creep.getActiveBodyparts(ATTACK) || !creep.pos.inRangeTo(target, 3))) { creep.moveTo(target, {ignoreDestructibleStructures: true, maxRooms: 1, ignoreRoads: true}); } } if (!target) { if (creep.room.controller && creep.room.controller.level > 0 && !creep.room.find(FIND_HOSTILE_CREEPS).length) { var spawns = _.filter(creep.room.find(FIND_HOSTILE_SPAWNS), spawn => !checkPath(creep.pos, spawn.pos)); if (!spawns.length) { creep.suicide(); return; } target = spawns[0]; if (target) { creep.moveTo(target, {ignoreDestructibleStructures: true, maxRooms: 1, ignoreRoads: true}); } } return; } creep.attack(target); if (creep.getActiveBodyparts(WORK) > 0 && creep.memory._move && creep.memory._move.path) { var path = Room.deserializePath(creep.memory._move.path); if (path.length && creep.pos.isNearTo(path[0].x, path[0].y)) { var structures = creep.room.lookForAt('structure', path[0].x, path[0].y); if (structures.length > 0) { creep.dismantle(structures[0]); } } } }", + findAttack: "var flee = require('flee'); function checkPath(pos1, pos2) { var path = pos1.findPathTo(pos2); if (!path.length) { return false; } return path[path.length - 1].x == pos2.x && path[path.length - 1].y == pos2.y; } function costCallbackIgnoreRamparts(roomName, cm) { var ramparts = Game.rooms[roomName].find(FIND_STRUCTURES, {filter: i => i.structureType == STRUCTURE_RAMPART || i.structureType == STRUCTURE_WALL}); ramparts.forEach(i => cm.set(i.pos.x, i.pos.y, 0)); } module.exports = function (creep) { if (!creep.getActiveBodyparts(ATTACK) && creep.getActiveBodyparts(RANGED_ATTACK) && flee(creep, 3)) { return; } var target, healers = creep.room.find(FIND_MY_CREEPS, { filter: function (i) { return i.getActiveBodyparts('heal') > 0; } }); if (creep.hits < creep.hitsMax / 2 && healers.length > 0 && !creep.getActiveBodyparts(ATTACK)) { target = creep.pos.findClosestByPath(FIND_MY_CREEPS, { ignoreRoads: true, filter: function (i) { return i.getActiveBodyparts('heal') > 0; } }); if (!target || creep.moveTo(target, {maxRooms: 1, ignoreRoads: true}) != OK) { target = null; } } var nearCreeps = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 1, { filter: function (i) { return i.owner.username != 'Source Keeper' } }); if (nearCreeps) { creep.attack(nearCreeps[0]); } if (!target) { target = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS, { ignoreRoads: true, ignoreCreeps: true, filter: function (i) { return i.owner.username != 'Source Keeper' } }); if (target && (creep.getActiveBodyparts(ATTACK) || !creep.pos.inRangeTo(target, 3))) { creep.moveTo(target, {maxRooms: 1, ignoreRoads: true, ignoreCreeps: true}); } } if (!target) { target = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS, { ignoreRoads: true, filter: function (i) { return i.owner.username != 'Source Keeper' }, costCallback: costCallbackIgnoreRamparts }); if (target && (creep.getActiveBodyparts(ATTACK) || !creep.pos.inRangeTo(target, 3))) { creep.moveTo(target, {maxRooms: 1, ignoreRoads: true, costCallback: costCallbackIgnoreRamparts}); } } if (!target) { target = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS, { ignoreDestructibleStructures: true, ignoreRoads: true, filter: function (i) { return i.owner.username != 'Source Keeper' } }); if (target && (creep.getActiveBodyparts(ATTACK) || !creep.pos.inRangeTo(target, 3))) { creep.moveTo(target, {ignoreDestructibleStructures: true, maxRooms: 1, ignoreRoads: true}); } } if (!target) { if (creep.room.controller && creep.room.controller.level > 0 && !creep.room.find(FIND_HOSTILE_CREEPS).length) { var spawns = _.filter(creep.room.find(FIND_HOSTILE_SPAWNS), spawn => !checkPath(creep.pos, spawn.pos)); if (!spawns.length) { creep.suicide(); return; } target = spawns[0]; if (target) { creep.moveTo(target, {ignoreDestructibleStructures: true, maxRooms: 1, ignoreRoads: true}); } } return; } creep.attack(target); if ((creep.getActiveBodyparts(WORK) > 0 || creep.getActiveBodyparts(ATTACK) > 0) && creep.memory._move && creep.memory._move.path) { var path = Room.deserializePath(creep.memory._move.path); if (path.length && creep.pos.isNearTo(path[0].x, path[0].y)) { var structures = creep.room.lookForAt('structure', path[0].x, path[0].y); if (structures.length > 0) { creep.attack(structures[0]); creep.dismantle(structures[0]); } } } }", flee: "var rooms = require('rooms'); module.exports = function(creep, range) { var nearCreeps = creep.pos.findInRange(FIND_HOSTILE_CREEPS, range-1, {filter: i => i.getActiveBodyparts(ATTACK) > 0 || i.getActiveBodyparts(RANGED_ATTACK) > 0}); if(nearCreeps.length > 0) { var ret = PathFinder.search(creep.pos, _.map(nearCreeps, i => ({pos: i.pos, range: range})), { maxRooms: 1, flee: true, roomCallback(roomName) { if(!rooms.rooms[roomName] || rooms.rooms[roomName].time < Game.time) { rooms.rooms[roomName] = {costMatrix: rooms.createCostMatrix(roomName), time: Game.time}; } return rooms.rooms[roomName].costMatrix; } }); if(ret.path.length) { creep.moveTo(ret.path[0]); creep.say('flee'); return true; } } return false; }", healer: "var flee = require('flee'); module.exports = function (creep) { var target; var healTargets = creep.pos.findInRange(FIND_MY_CREEPS, 3); if(healTargets.length > 0) { healTargets = healTargets.sort((a,b) => (b.hitsMax - b.hits) - (a.hitsMax - a.hits)); if (creep.pos.isNearTo(healTargets[0])) { creep.heal(healTargets[0]); } else { creep.rangedHeal(healTargets[0]); } } if (creep.hits < creep.hitsMax / 2) { if (!flee(creep)) { target = creep.pos.findClosestByPath(FIND_MY_CREEPS, {filter: i => i.getActiveBodyparts('heal') > 0}); if (target) { creep.moveTo(target, {maxRooms: 1, ignoreRoads: true}); } } return; } target = creep.pos.findClosestByRange(FIND_MY_CREEPS, {filter: i => i.hits < i.hitsMax}); if (!target) { if (flee(creep, 4)) { return; } target = creep.pos.findClosestByRange(FIND_MY_CREEPS, {filter: i => i != creep && i.getActiveBodyparts(HEAL) == 0}); } if (!target) { creep.suicide(); return; } if (creep.pos.isNearTo(target)) { creep.move(creep.pos.getDirectionTo(target)); } else { creep.moveTo(target, {maxRooms: 1, ignoreRoads: true, reusePath: 0}); } if (creep.getActiveBodyparts(RANGED_ATTACK)) { require('shootAtWill')(creep); } }", rooms: "module.exports = { rooms: {}, createCostMatrix(roomName) { var cm = new PathFinder.CostMatrix; Game.rooms[roomName].find(FIND_CREEPS).forEach(i => cm.set(i.pos.x, i.pos.y, 255)); Game.rooms[roomName].find(FIND_STRUCTURES).forEach(i => { if(i.structureType != STRUCTURE_ROAD && i.structureType != STRUCTURE_CONTAINER) { cm.set(i.pos.x, i.pos.y, 255); } }); return cm; } } ", @@ -484,7 +484,7 @@ runCodeCache[userId].globals.require.timestamp = runCodeCache[userId].runtimeData.userCodeTimestamp; } - driver.config.emit('playerSandbox',runCodeCache[userId].globals, userId); + driver.config.emit('playerSandbox',runCodeCache[userId].globals, userId, runCodeCache[userId]); runCodeCache[userId].resetUsedCpu(); diff --git a/src/game/map.js b/src/game/map.js index 17eac5dd..cde16415 100644 --- a/src/game/map.js +++ b/src/game/map.js @@ -232,6 +232,10 @@ exports.makeMap = function(runtimeData, register) { getRoomLinearDistance(roomName1, roomName2, continuous) { return utils.calcRoomsDistance(roomName1, roomName2, continuous); + }, + + getWorldSize() { + return driver.getWorldSize(); } } }; diff --git a/src/game/market.js b/src/game/market.js index c3af34d1..23cdbbb2 100644 --- a/src/game/market.js +++ b/src/game/market.js @@ -18,7 +18,10 @@ exports.make = function(runtimeData, intents, register) { if(resourceType != 'all' && !_.contains(C.RESOURCES_ALL, resourceType) && resourceType != C.SUBSCRIPTION_TOKEN) { return {}; } - cachedOrders[resourceType] = JSON.parse(JSON.stringify(runtimeData.market.orders[resourceType] || '{}')); + cachedOrders[resourceType] = JSON.parse(JSON.stringify(runtimeData.market.orders[resourceType]) || '{}'); + for(var i in cachedOrders[resourceType]) { + cachedOrders[resourceType][i].price /= 1000; + } } return cachedOrders[resourceType]; } @@ -27,7 +30,7 @@ exports.make = function(runtimeData, intents, register) { calcTransactionCost: register.wrapFn(function(amount, roomName1, roomName2) { var distance = utils.calcRoomsDistance(roomName1, roomName2, true); - return Math.max(0, Math.ceil(amount * (Math.log((distance+9) * 0.1) + 0.1))); + return utils.calcTerminalEnergyCost(amount, distance); }), getAllOrders: register.wrapFn(function(filter) { @@ -39,7 +42,9 @@ exports.make = function(runtimeData, intents, register) { if(!runtimeData.market.orders.all[id]) { return null; } - return JSON.parse(JSON.stringify(runtimeData.market.orders.all[id])); + var result = JSON.parse(JSON.stringify(runtimeData.market.orders.all[id])); + result.price /= 1000; + return result; }), createOrder: register.wrapFn(function(type, resourceType, price, totalAmount, roomName) { @@ -105,6 +110,9 @@ exports.make = function(runtimeData, intents, register) { if(terminal[C.RESOURCE_ENERGY] < transferCost) { return C.ERR_NOT_ENOUGH_RESOURCES; } + if(terminal.cooldownTime > runtimeData.time) { + return C.ERR_TIRED; + } if(order.type == C.ORDER_BUY) { if(order.resourceType != C.RESOURCE_ENERGY && (!terminal[order.resourceType] || terminal[order.resourceType] < amount) || order.resourceType == C.RESOURCE_ENERGY && terminal[C.RESOURCE_ENERGY] < amount + transferCost) { @@ -167,7 +175,7 @@ exports.make = function(runtimeData, intents, register) { credits: { enumerable: true, get() { - return runtimeData.user.money || 0; + return (runtimeData.user.money || 0)/1000; } }, @@ -211,6 +219,7 @@ exports.make = function(runtimeData, intents, register) { i.id = ""+i._id; delete i._id; delete i.user; + i.price /= 1000; return i; }).indexBy('id').value(); } diff --git a/src/game/path-finder.js b/src/game/path-finder.js index c2396382..d489daaa 100644 --- a/src/game/path-finder.js +++ b/src/game/path-finder.js @@ -54,6 +54,9 @@ exports.make = function(runtimeData, intents, register, globals) { }), use: register.wrapFn(function(isActive) { + if(!isActive) { + register.deprecated('`PathFinder.use` is considered deprecated and will be removed soon.'); + } register._useNewPathFinder = !!isActive; }) }; diff --git a/src/game/rooms.js b/src/game/rooms.js index b2ee09ba..d000a7e1 100644 --- a/src/game/rooms.js +++ b/src/game/rooms.js @@ -331,7 +331,10 @@ function _findClosestByPath2(fromPos, objects, opts) { var costMatrix = getPathfindingGrid2(roomName, opts); if(typeof opts.costCallback == 'function') { costMatrix = costMatrix.clone(); - opts.costCallback(roomName, costMatrix); + var resultMatrix = opts.costCallback(roomName, costMatrix); + if(resultMatrix instanceof globals.PathFinder.CostMatrix) { + costMatrix = resultMatrix; + } } return costMatrix; } @@ -353,9 +356,6 @@ function _findClosestByPath2(fromPos, objects, opts) { } objects.forEach(obj => { - if(lastPos.isEqualTo(obj)) { - return obj; - } if(lastPos.isNearTo(obj)) { result = obj; } @@ -409,11 +409,6 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { this.name = id; - this.mode = id == 'sim' ? C.MODE_SIMULATION : - /^arena/.test(id) ? C.MODE_ARENA : - /^survival/.test(id) ? C.MODE_SURVIVAL : - C.MODE_WORLD; - this.energyAvailable = 0; this.energyCapacityAvailable = 0; @@ -488,6 +483,8 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { nuke: register.byRoom[id].spatial.nukes } }; + + this.visual = new globals.RoomVisual(id); }); Room.serializePath = register.wrapFn(function(path) { @@ -538,6 +535,10 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { Room.prototype.find = register.wrapFn(function(type, opts) { var result = []; opts = opts || {}; + if(type === C.FIND_DROPPED_ENERGY) { + register.deprecated('FIND_DROPPED_ENERGY constant is considered deprecated and will be removed soon. Please use FIND_DROPPED_RESOURCES instead.'); + type = C.FIND_DROPPED_RESOURCES; + } if(register.findCache[type] && register.findCache[type][this.name]) { result = register.findCache[type][this.name]; } @@ -977,9 +978,6 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { !utils.checkConstructionSite(runtimeData.staticTerrainData[this.name], structureType, x, y)) { return C.ERR_INVALID_TARGET; } - if(this.mode == C.MODE_ARENA) { - return C.ERR_INVALID_TARGET; - } if(_(runtimeData.userObjects).filter({type: 'constructionSite'}).size() + createdConstructionSites >= C.MAX_CONSTRUCTION_SITES) { return C.ERR_FULL; @@ -1045,6 +1043,77 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { }); globals.Room = 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) { + 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; + }); + + globals.RoomVisual = RoomVisual; }; exports.makePos = function(_register) { @@ -1102,8 +1171,16 @@ exports.makePos = function(_register) { }); RoomPosition.prototype.getDirectionTo = register.wrapFn(function(firstArg, secondArg) { - var [x,y] = utils.fetchXYArguments(firstArg, secondArg, globals); - return utils.getDirection(x - this.x, y - this.y); + var [x,y,roomName] = utils.fetchXYArguments(firstArg, secondArg, globals); + + if(!roomName || roomName == this.roomName) { + return utils.getDirection(x - this.x, y - this.y); + } + + var [thisRoomX, thisRoomY] = utils.roomNameToXY(this.roomName); + var [thatRoomX, thatRoomY] = utils.roomNameToXY(roomName); + + return utils.getDirection(thatRoomX*50 + x - thisRoomX*50 - this.x, thatRoomY*50 + y - thisRoomY*50 - this.y); }); RoomPosition.prototype.findPathTo = register.wrapFn(function(firstArg, secondArg, opts) { @@ -1352,4 +1429,4 @@ exports.makePos = function(_register) { }); globals.RoomObject = RoomObject; -}; \ No newline at end of file +}; diff --git a/src/game/structures.js b/src/game/structures.js index ce8388b6..41d0afc3 100644 --- a/src/game/structures.js +++ b/src/game/structures.js @@ -4,7 +4,7 @@ var utils = require('./../utils'), C = driver.constants, _ = require('lodash'); -var runtimeData, intents, register, globals, createdCreepNames; +var runtimeData, intents, register, globals, createdCreepNames, lastActivateSafeMode; function data(id) { if(!runtimeData.roomObjects[id]) { @@ -27,6 +27,8 @@ function _storeGetter(o) { function _transfer(target, resourceType, amount) { + register.deprecated('`Structure*.transfer` is considered deprecated and will be removed soon. Please use `Creep.withdraw` instead.'); + if (!target || !target.id || !register.creeps[target.id] || !(target instanceof globals.Creep)) { register.assertTargetObject(target); return C.ERR_INVALID_TARGET; @@ -62,6 +64,8 @@ function _transfer(target, resourceType, amount) { function _transferEnergy(target, amount) { + register.deprecated('`Structure*.transferEnergy` is considered deprecated and will be removed soon. Please use `Creep.withdraw` instead.'); + if(!target || !target.id || !register.creeps[target.id] || !(target instanceof globals.Creep)) { register.assertTargetObject(target); return C.ERR_INVALID_TARGET; @@ -105,6 +109,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { globals = _globals; createdCreepNames = []; + lastActivateSafeMode = null; if(globals.Structure) { return; @@ -260,7 +265,12 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { safeMode: o => o.safeMode && o.safeMode > runtimeData.time ? o.safeMode - runtimeData.time : undefined, safeModeCooldown: o => o.safeModeCooldown && o.safeModeCooldown > runtimeData.time ? o.safeModeCooldown - runtimeData.time : undefined, safeModeAvailable: o => o.safeModeAvailable || 0, - sign: o => o.sign ? { + sign: o => o.hardSign ? { + username: C.SYSTEM_USERNAME, + text: o.hardSign.text, + time: o.hardSign.time, + datetime: new Date(o.hardSign.datetime) + } : o.sign ? { username: runtimeData.users[o.sign.user].username, text: o.sign.text, time: o.sign.time, @@ -286,13 +296,19 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(this.safeModeAvailable <= 0) { return C.ERR_NOT_ENOUGH_RESOURCES; } - if(this.safeModeCooldown || this.upgradeBlocked > 0) { + if(this.safeModeCooldown || this.upgradeBlocked > 0 || + this.ticksToDowngrade < C.CONTROLLER_DOWNGRADE[this.level] - C.CONTROLLER_DOWNGRADE_SAFEMODE_THRESHOLD) { return C.ERR_TIRED; } if(_.any(register.structures, i => i.structureType == 'controller' && i.my && i.safeMode)) { return C.ERR_BUSY; } + if(lastActivateSafeMode) { + intents.remove(lastActivateSafeMode, 'activateSafeMode'); + } + lastActivateSafeMode = this.id; + intents.set(this.id, 'activateSafeMode', {}); return C.OK; }); @@ -470,7 +486,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { return C.ERR_NOT_ENOUGH_RESOURCES; } bodyPartsCount = bodyPartsCount || 0; - var nonBoostedParts = _(target.body).filter(i => !i.boost && C.BOOSTS[i.type][data(this.id).mineralType]).size(); + var nonBoostedParts = _(target.body).filter(i => !i.boost && C.BOOSTS[i.type] && C.BOOSTS[i.type][data(this.id).mineralType]).size(); if(!nonBoostedParts || bodyPartsCount && bodyPartsCount > nonBoostedParts) { return C.ERR_NOT_FOUND; @@ -531,8 +547,14 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { return C.ERR_RCL_NOT_ENOUGH; } } - if ((target instanceof globals.Creep) && !this.pos.inRangeTo(target, C.RANGE_TRANSFER)) { - return C.ERR_NOT_IN_RANGE; + if (target instanceof globals.Creep) { + + register.deprecated('`StructureLink.transferEnergy` applied to creeps is considered deprecated and will be ' + + 'removed soon. Please use `Creep.withdraw` instead.'); + + if (!this.pos.inRangeTo(target, C.RANGE_WITHDRAW)) { + return C.ERR_NOT_IN_RANGE; + } } if (!data(this.id).energy) { return C.ERR_NOT_ENOUGH_ENERGY; @@ -732,7 +754,8 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { utils.defineGameObjectProperties(StructureTerminal.prototype, data, { store: _storeGetter, - storeCapacity: (o) => o.energyCapacity + storeCapacity: (o) => o.energyCapacity, + cooldown: o => o.cooldownTime && o.cooldownTime > runtimeData.time ? o.cooldownTime - runtimeData.time : 0 }); StructureTerminal.prototype.transfer = register.wrapFn(_transfer); @@ -756,8 +779,11 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(!data(this.id)[resourceType] || data(this.id)[resourceType] < amount) { return C.ERR_NOT_ENOUGH_RESOURCES; } + if(data(this.id).cooldownTime > runtimeData.time) { + return C.ERR_TIRED; + } var range = utils.calcRoomsDistance(data(this.id).room, targetRoomName, true); - var cost = Math.max(0, Math.ceil(amount * (Math.log((range+9) * 0.1) + 0.1))); + var cost = utils.calcTerminalEnergyCost(amount,range); if(resourceType != C.RESOURCE_ENERGY && data(this.id).energy < cost || resourceType == C.RESOURCE_ENERGY && data(this.id).energy < amount + cost) { return C.ERR_NOT_ENOUGH_RESOURCES; @@ -1063,8 +1089,153 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { return name; }); + function calcEnergyAvailable(roomObjects, energyStructures){ + return _.sum(energyStructures, id => { + if (roomObjects[id] && !roomObjects[id].off && (roomObjects[id].type === 'spawn' || roomObjects[id].type === 'extension')) { + return roomObjects[id].energy; + } else { + return 0; + } + }); + } + + StructureSpawn.prototype.spawnCreep = register.wrapFn(function spawnCreep(body, name, options = {}) { + + if(!name || !_.isObject(options)) { + return C.ERR_INVALID_ARGS; + } + + if(globals.Game.creeps[name] || createdCreepNames.indexOf(name) != -1) { + return C.ERR_NAME_EXISTS; + } + + let energyStructures = options.energyStructures && _.uniq(_.map(options.energyStructures, 'id')); + + if(!this.my) { + return C.ERR_NOT_OWNER; + } + + if(data(this.id).spawning) { + return C.ERR_BUSY; + } + + if(data(this.id).off) { + return C.ERR_RCL_NOT_ENOUGH; + } + + if(!body || !_.isArray(body) || body.length === 0 || body.length > C.MAX_CREEP_SIZE) { + return C.ERR_INVALID_ARGS; + } + + for(let i=0; i ({type, hits: 100})) + } + }, + owner: { + enumerable: true, + get() { + return new Object({username: runtimeData.user.username}); + } + }, + ticksToLive: { + enumerable: true, + get() { + return C.CREEP_LIFE_TIME; + } + }, + carryCapacity: { + enumerable: true, + get() { + return _.reduce(body, (result, type) => result += type === C.CARRY ? C.CARRY_CAPACITY : 0, 0); + } + }, + carry: { + enumerable: true, + get() { + return {energy: 0}; + } + }, + fatigue: { + enumerable: true, + get() { + return 0; + } + }, + hits: { + enumerable: true, + get() { + return body.length * 100; + } + }, + hitsMax: { + enumerable: true, + get() { + return body.length * 100; + } + }, + saying: { + enumerable: true, + get() { + return undefined; + } + } + }); + + intents.set(this.id, 'createCreep', {name, body, energyStructures}); + + return C.OK; + }); + StructureSpawn.prototype.transferEnergy = register.wrapFn(function(target, amount) { + register.deprecated('`StructureSpawn.transferEnergy` is considered deprecated and will be removed soon. Please use `Creep.withdraw` instead.') if(!this.my) { return C.ERR_NOT_OWNER; } @@ -1131,25 +1302,22 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { StructureSpawn.prototype.renewCreep = register.wrapFn(function(target) { - if(!this.my) { - return C.ERR_NOT_OWNER; + if(this.spawning) { + return C.ERR_BUSY; } - if(!target || !target.id || !register.creeps[target.id] || !(target instanceof globals.Creep)) { + if(!target || !target.id || !register.creeps[target.id] || !(target instanceof globals.Creep) || target.spawning) { register.assertTargetObject(target); return C.ERR_INVALID_TARGET; } + if(!this.my || !target.my) { + return C.ERR_NOT_OWNER; + } if(runtimeData.roomObjects[this.id].off) { return C.ERR_RCL_NOT_ENOUGH; } - if(!target.my) { - return C.ERR_NOT_OWNER; - } if(!target.pos.inRangeTo(this.pos, C.RANGE_RENEW_CREEP)) { return C.ERR_NOT_IN_RANGE; } - if(this.spawning) { - return C.ERR_BUSY; - } if(this.room.energyAvailable < Math.ceil(C.SPAWN_RENEW_RATIO * utils.calcCreepCost(target.body) / C.CREEP_SPAWN_TIME / target.body.length)) { return C.ERR_NOT_ENOUGH_ENERGY; } @@ -1210,7 +1378,7 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { if(!this.my) { return C.ERR_NOT_OWNER; } - if(runtimeData.rooms[this.room.name].novice > Date.now()) { + if(runtimeData.rooms[this.room.name].novice > Date.now() || runtimeData.rooms[this.room.name].respawnArea > Date.now()) { return C.ERR_INVALID_TARGET; } if(!(pos instanceof globals.RoomPosition)) { @@ -1251,10 +1419,20 @@ exports.make = function(_runtimeData, _intents, _register, _globals) { StructurePortal.prototype.constructor = StructurePortal; utils.defineGameObjectProperties(StructurePortal.prototype, data, { - destination: o => new globals.RoomPosition(o.destination.x, o.destination.y, o.destination.room), + destination: o => { + if(o.destination.shard) { + return { + shard: o.destination.shard, + room: o.destination.room + }; + } + else { + return new globals.RoomPosition(o.destination.x, o.destination.y, o.destination.room); + } + }, ticksToDecay: (o) => o.decayTime ? o.decayTime - runtimeData.time : undefined }); globals.StructurePortal = StructurePortal; -}; \ No newline at end of file +}; diff --git a/src/processor.js b/src/processor.js index 3241b397..a118d161 100644 --- a/src/processor.js +++ b/src/processor.js @@ -9,20 +9,20 @@ var q = require('q'), var roomsQueue, usersQueue, lastRoomsStatsSaveTime = 0, currentHistoryPromise = q.when(); -function processRoom(roomId, intents, objects, terrain, gameTime, roomInfo, flags) { +function processRoom(roomId, {intents, objects, users, terrain, gameTime, roomInfo, flags}) { return q.when().then(() => { var bulk = driver.bulkObjectsWrite(), - userBulk = driver.bulkUsersWrite(), - flagsBulk = driver.bulkFlagsWrite(), - oldObjects = {}, - roomController, - hasNewbieWalls = false, - stats = driver.getRoomStatsUpdater(roomId), - objectsToHistory = {}, - roomSpawns = [], roomExtensions = [], - oldRoomInfo = _.clone(roomInfo); + userBulk = driver.bulkUsersWrite(), + flagsBulk = driver.bulkFlagsWrite(), + oldObjects = {}, + roomController, + hasNewbieWalls = false, + stats = driver.getRoomStatsUpdater(roomId), + objectsToHistory = {}, + roomSpawns = [], roomExtensions = [], + oldRoomInfo = _.clone(roomInfo); roomInfo.active = false; @@ -132,14 +132,14 @@ function processRoom(roomId, intents, objects, terrain, gameTime, roomInfo, flag object = objects[objectId]; if (objectId == 'room') { - require('./processor/intents/room/intents')(objectIntents, objects, terrain, bulk, userBulk, roomController, flags, flagsBulk); + require('./processor/intents/room/intents')(userId, objectIntents, objects, terrain, bulk, userBulk, roomController, flags, flagsBulk); continue; } if (!object || object._skip || object.user && object.user != userId) continue; if (object.type == 'creep') - require('./processor/intents/creeps/intents')(object, objectIntents, objects, terrain, bulk, userBulk, roomController, stats, gameTime, roomInfo); + require('./processor/intents/creeps/intents')(object, objectIntents, objects, terrain, bulk, userBulk, roomController, stats, gameTime, roomInfo, users); if (object.type == 'link') require('./processor/intents/links/intents')(object, objectIntents, objects, terrain, bulk, userBulk, roomController, stats); if (object.type == 'tower') @@ -150,9 +150,6 @@ function processRoom(roomId, intents, objects, terrain, gameTime, roomInfo, flag require('./processor/intents/spawns/intents')(object, objectIntents, objects, terrain, bulk, userBulk, roomController, stats, gameTime); if (object.type == 'constructionSite') { - if (objectIntents.remove) { - require('./processor/intents/construction-sites/remove')(object, objects, bulk); - } } if (object.type == 'rampart') { @@ -191,7 +188,7 @@ function processRoom(roomId, intents, objects, terrain, gameTime, roomInfo, flag if(object.type == 'controller') { if(objectIntents.unclaim) { - require('./processor/intents/controllers/unclaim')(object, objectIntents.unclaim, objects, terrain, bulk, userBulk, gameTime, roomInfo); + require('./processor/intents/controllers/unclaim')(object, objectIntents.unclaim, objects, terrain, bulk, userBulk, gameTime, roomInfo, users); } if(objectIntents.activateSafeMode) { require('./processor/intents/controllers/activateSafeMode')(object, objectIntents.activateSafeMode, objects, terrain, bulk, userBulk, gameTime, roomInfo); @@ -264,7 +261,7 @@ function processRoom(roomId, intents, objects, terrain, gameTime, roomInfo, flag if (object.type == 'tower') require('./processor/intents/towers/tick')(object, objects, terrain, bulk, userBulk, roomController); if (object.type == 'controller') - require('./processor/intents/controllers/tick')(object, objects, terrain, bulk, userBulk, roomController, gameTime, roomInfo); + require('./processor/intents/controllers/tick')(object, objects, terrain, bulk, userBulk, roomController, gameTime, roomInfo, users); if (object.type == 'lab') require('./processor/intents/labs/tick')(object, objects, terrain, bulk, userBulk, roomController, gameTime); if (object.type == 'container') @@ -384,8 +381,8 @@ function saveRoomHistory(roomId, objects, gameTime) { return currentHistoryPromise.then(() => { var promise = q.when(); - if (!(gameTime % 20)) { - var baseTime = Math.floor((gameTime - 1) / 20) * 20; + if (!(gameTime % driver.config.historyChunkSize)) { + var baseTime = Math.floor((gameTime - 1) / driver.config.historyChunkSize) * driver.config.historyChunkSize; promise = driver.history.upload(roomId, baseTime); } @@ -422,7 +419,15 @@ driver.connect('processor').then(() => driver.queue.create('rooms', 'read')) }) .then((result) => { driver.config.emit('processorLoopStage','processRoom', roomId); - processRoom(roomId, result[0], result[1], result[2], result[3], result[4], result[5]) + processRoom(roomId, { + intents: result[0], + objects: result[1].objects, + users: result[1].users, + terrain: result[2], + gameTime: result[3], + roomInfo: result[4], + flags: result[5] + }) .catch((error) => console.log('Error processing room '+roomId+':', _.isObject(error) ? (error.stack || error) : error)) .then(() => { return driver.clearRoomIntents(roomId); diff --git a/src/processor/intents/_damage.js b/src/processor/intents/_damage.js index 0ef5d593..96b7c8a9 100644 --- a/src/processor/intents/_damage.js +++ b/src/processor/intents/_damage.js @@ -3,43 +3,6 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -function damageBody(object, damage, roomObjects, roomTerrain, bulk) { - - let damageReduce = 0, damageEffective = damage; - - if(_.any(object.body, i => !!i.boost)) { - for(let i=0; i { if (target[resourceType] > 0) { require('./creeps/_create-energy')(target.x, target.y, target.room, @@ -97,15 +55,7 @@ module.exports = function(object, target, damage, damageType, roomObjects, roomT } } else { - if (target.type == 'creep') { - bulk.update(target, { - hits: target.hits, - body: target.body, - energy: target.energy, - energyCapacity: target.energyCapacity - }); - } - else { + if (target.type != 'creep') { bulk.update(target, {hits: target.hits}); } } @@ -129,20 +79,8 @@ module.exports = function(object, target, damage, damageType, roomObjects, roomT } if(attackBackPower) { - damageBody(object, attackBackPower, roomObjects, roomTerrain, bulk); + object._damageToApply = (object._damageToApply || 0) + attackBackPower; object.actionLog.attacked = {x: target.x, y: target.y}; - - if(object.hits <= 0) { - require('./creeps/_die')(object, roomObjects, bulk, stats); - } - else { - bulk.update(object, { - hits: object.hits, - body: object.body, - energy: object.energy, - energyCapacity: object.energyCapacity - }); - } } }; diff --git a/src/processor/intents/containers/tick.js b/src/processor/intents/containers/tick.js index fcdb0ca8..6f2456c5 100644 --- a/src/processor/intents/containers/tick.js +++ b/src/processor/intents/containers/tick.js @@ -5,7 +5,6 @@ var _ = require('lodash'), module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roomController, gameTime) { - if(!object.nextDecayTime || gameTime >= object.nextDecayTime-1) { object.hits = object.hits || 0; object.hits -= C.CONTAINER_DECAY; diff --git a/src/processor/intents/controllers/activateSafeMode.js b/src/processor/intents/controllers/activateSafeMode.js index 1742df85..7c24047d 100644 --- a/src/processor/intents/controllers/activateSafeMode.js +++ b/src/processor/intents/controllers/activateSafeMode.js @@ -8,7 +8,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs if(!object.user || !object.level) { return; } - if(!(object.safeModeAvailable >= 0)) { + if(!(object.safeModeAvailable > 0)) { return; } if(object.safeModeCooldown >= gameTime) { @@ -17,10 +17,13 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs if(object.upgradeBlocked > gameTime) { return; } + if(object.downgradeTime < gameTime + C.CONTROLLER_DOWNGRADE[object.level] - C.CONTROLLER_DOWNGRADE_SAFEMODE_THRESHOLD) { + return; + } bulk.update(object, { safeModeAvailable: object.safeModeAvailable - 1, safeMode: gameTime + C.SAFE_MODE_DURATION, safeModeCooldown: roomInfo.novice > Date.now() ? null : gameTime + C.SAFE_MODE_COOLDOWN }); -}; \ No newline at end of file +}; diff --git a/src/processor/intents/controllers/tick.js b/src/processor/intents/controllers/tick.js index a4b4f933..056febc7 100644 --- a/src/processor/intents/controllers/tick.js +++ b/src/processor/intents/controllers/tick.js @@ -3,7 +3,7 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roomController, gameTime, roomInfo) { +module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roomController, gameTime, roomInfo, users) { if(!object || object.type != 'controller') return; @@ -15,11 +15,25 @@ module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roo return; } - if(object._upgraded || !object.downgradeTime || object.tutorial) { + driver.addRoomToUser(object.room, users[object.user], bulkUsers); + + if(object._upgradeBlocked) { + bulk.update(object, {upgradeBlocked: object._upgradeBlocked}); + delete object._upgradeBlocked; + } + + if(!object.downgradeTime || object.tutorial) { bulk.update(object, {downgradeTime: gameTime + C.CONTROLLER_DOWNGRADE[object.level] + 1}); return; } + if(object._upgraded) { + bulk.update(object, {downgradeTime: Math.min( + object.downgradeTime + C.CONTROLLER_DOWNGRADE_RESTORE + 1, + gameTime + C.CONTROLLER_DOWNGRADE[object.level] + 1)}); + return; + } + if(gameTime == object.downgradeTime-3000) { driver.sendNotification(object.user, `Attention! Your Controller in room ${object.room} will be downgraded to level ${object.level-1} in 3000 ticks (~2 hours)! Upgrade it to prevent losing of this room. Learn more`); } @@ -30,6 +44,8 @@ module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roo object.level--; driver.sendNotification(object.user, `Your Controller in room ${object.room} has been downgraded to level ${object.level} due to absence of upgrading activity!`); if(object.level == 0) { + driver.removeRoomFromUser(object.room, users[object.user], bulkUsers); + object.progress = 0; object.user = null; object.downgradeTime = null; diff --git a/src/processor/intents/controllers/unclaim.js b/src/processor/intents/controllers/unclaim.js index 8ae2a361..a63370e0 100644 --- a/src/processor/intents/controllers/unclaim.js +++ b/src/processor/intents/controllers/unclaim.js @@ -3,7 +3,7 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUsers, gameTime, roomInfo) { +module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUsers, gameTime, roomInfo, users) { if(object.type != 'controller') { return; @@ -13,6 +13,8 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs return; } + driver.removeRoomFromUser(object.room, users[object.user], bulkUsers); + bulk.update(object, { user: null, level: 0, diff --git a/src/processor/intents/creeps/_create-energy.js b/src/processor/intents/creeps/_create-energy.js index f9a9b105..31644fff 100644 --- a/src/processor/intents/creeps/_create-energy.js +++ b/src/processor/intents/creeps/_create-energy.js @@ -3,7 +3,7 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(x, y, room, amount, roomObjects, bulk, resourceType) { +module.exports = function(x, y, room, amount, roomObjects, bulk, resourceType, dropToContainer) { resourceType = resourceType || 'energy'; @@ -15,9 +15,26 @@ module.exports = function(x, y, room, amount, roomObjects, bulk, resourceType) { var container = _.find(roomObjects, {type: 'container', x, y}); + if(!container && dropToContainer) { + container = { + room, + x, + y, + type: 'container', + energyCapacity: 0, + hits: C.CONTAINER_HITS, + hitsMax: 0 + }; + container._id = bulk.insert(container); + roomObjects[container._id] = container; + } + if(container && container.hits > 0) { var targetTotal = utils.calcResources(container); var toContainerAmount = Math.min(amount, container.energyCapacity - targetTotal); + if(dropToContainer) { + toContainerAmount = amount; + } if(toContainerAmount > 0) { container[resourceType] = container[resourceType] || 0; container[resourceType] += toContainerAmount; diff --git a/src/processor/intents/creeps/_die.js b/src/processor/intents/creeps/_die.js index 8c65dd82..8327a7f0 100644 --- a/src/processor/intents/creeps/_die.js +++ b/src/processor/intents/creeps/_die.js @@ -26,14 +26,15 @@ module.exports = function(object, roomObjects, bulk, stats, dropRate) { _.forEach(bodyResources, (amount, resourceType) => { if(amount > 0) { - require('./_create-energy')(object.x, object.y, object.room, Math.floor(amount), roomObjects, bulk, resourceType); + require('./_create-energy')(object.x, object.y, object.room, Math.floor(amount), roomObjects, bulk, + resourceType, object.dropToContainer); } }); C.RESOURCES_ALL.forEach(resourceType => { if (object[resourceType] > 0) { require('./_create-energy')(object.x, object.y, object.room, - object[resourceType], roomObjects, bulk, resourceType); + object[resourceType], roomObjects, bulk, resourceType, object.dropToContainer); } }); } diff --git a/src/processor/intents/creeps/_drop-resources-without-space.js b/src/processor/intents/creeps/_drop-resources-without-space.js new file mode 100644 index 00000000..57495ee2 --- /dev/null +++ b/src/processor/intents/creeps/_drop-resources-without-space.js @@ -0,0 +1,17 @@ +var _ = require('lodash'), + utils = require('../../../utils'), + driver = utils.getDriver(), + C = driver.constants; + +module.exports = function dropResourcesWithoutSpace(object, roomObjects, roomTerrain, bulk) { + for(var i=0; i gameTime) { + if(roomController && roomController.user != object.user && roomController.safeMode > gameTime || + roomController.upgradeBlocked > gameTime) { return; } @@ -37,10 +38,8 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs } if(target.user) { var downgradeTime = target.downgradeTime - effect; - bulk.update(target, { - downgradeTime, - upgradeBlocked: gameTime + C.CONTROLLER_ATTACK_BLOCKED_UPGRADE - }); + bulk.update(target, {downgradeTime}); + target._upgradeBlocked = gameTime + C.CONTROLLER_ATTACK_BLOCKED_UPGRADE; } object.actionLog.attack = {x: target.x, y: target.y}; }; \ No newline at end of file diff --git a/src/processor/intents/creeps/claimController.js b/src/processor/intents/creeps/claimController.js index 1ab381b1..8bd0b1c1 100644 --- a/src/processor/intents/creeps/claimController.js +++ b/src/processor/intents/creeps/claimController.js @@ -3,7 +3,7 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime) { +module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime, roomInfo, users) { if(object.type != 'creep') { return; @@ -25,9 +25,18 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs if(target.level > 0) { return; } + if ((_.filter(object.body, (i) => i.hits > 0 && i.type == C.CLAIM).length) === 0) { + return; + } if(target.reservation && target.reservation.user != object.user) { return; } + let user = users[object.user], + claimedRooms = user.rooms ? user.rooms.length : 0; + + if(user.gcl < utils.calcNeededGcl(claimedRooms + 1)) { + return; + } var level = 1; @@ -38,4 +47,6 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs downgradeTime: null, reservation: null }); + + driver.addRoomToUser(object.room, users[object.user], bulkUsers); }; \ No newline at end of file diff --git a/src/processor/intents/creeps/drop.js b/src/processor/intents/creeps/drop.js index 868d461b..c42e8ea7 100644 --- a/src/processor/intents/creeps/drop.js +++ b/src/processor/intents/creeps/drop.js @@ -17,7 +17,8 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk) { if(intent.amount > 0) { object[intent.resourceType] -= intent.amount; - require('./_create-energy')(object.x, object.y, object.room, intent.amount, roomObjects, bulk, intent.resourceType); + require('./_create-energy')(object.x, object.y, object.room, intent.amount, roomObjects, bulk, + intent.resourceType, object.dropToContainer); } bulk.update(object, {[intent.resourceType]: object[intent.resourceType]}); diff --git a/src/processor/intents/creeps/heal.js b/src/processor/intents/creeps/heal.js index b438b364..cd199b94 100644 --- a/src/processor/intents/creeps/heal.js +++ b/src/processor/intents/creeps/heal.js @@ -13,7 +13,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs } var target = roomObjects[intent.id]; - if(!target || target.type != 'creep' || target.spawning || target.hits >= target.hitsMax) { + if(!target || target.type != 'creep' || target.spawning) { return; } if(Math.abs(target.x - object.x) > C.RANGE_HEAL || Math.abs(target.y - object.y) > C.RANGE_HEAL) { @@ -25,26 +25,8 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs var healPower = utils.calcBodyEffectiveness(object.body, C.HEAL, 'heal', C.HEAL_POWER); - target.hits += healPower; + target._healToApply = (target._healToApply || 0) + healPower; - if(target.hits > target.hitsMax) { - target.hits = target.hitsMax; - } - - - recalcBody(target); object.actionLog.heal = {x: target.x, y: target.y}; target.actionLog.healed = {x: object.x, y: object.y}; - - bulk.update(target, { - hits: target.hits, - body: target.body, - energyCapacity: target.energyCapacity - }); - - function recalcBody(object) { - require('./_recalc-body')(object); - } - - }; \ No newline at end of file diff --git a/src/processor/intents/creeps/intents.js b/src/processor/intents/creeps/intents.js index a252567e..4970e0b9 100644 --- a/src/processor/intents/creeps/intents.js +++ b/src/processor/intents/creeps/intents.js @@ -21,10 +21,10 @@ function checkPriorities(intents, name) { return intents[name] && (!priorities[name] || !_.any(priorities[name], i => !!intents[i])); } -module.exports = function(object, objectIntents, roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime, roomInfo) { +module.exports = function(object, objectIntents, roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime, roomInfo, users) { creepActions.forEach(name => { if(checkPriorities(objectIntents, name)) { - modules[name](object, objectIntents[name], roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime, roomInfo); + modules[name](object, objectIntents[name], roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime, roomInfo, users); } }); }; \ No newline at end of file diff --git a/src/processor/intents/creeps/move.js b/src/processor/intents/creeps/move.js index a479b7c5..2547ea42 100644 --- a/src/processor/intents/creeps/move.js +++ b/src/processor/intents/creeps/move.js @@ -20,8 +20,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs return; } - var d = utils.getOffsetsByDirection(intent.direction), - attack = null, obstructed = false; + var d = utils.getOffsetsByDirection(intent.direction); if(!d) { return; @@ -35,22 +34,9 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs var targetObjects = _.filter(roomObjects, {x: object.x+dx, y: object.y+dy}); + if(!_.any(targetObjects, (target) => _.contains(C.OBSTACLE_OBJECT_TYPES, target.type) && + target.type != 'creep' || target.type == 'rampart' && !target.isPublic && object.user != target.user)) { - targetObjects.forEach((target) => { - if(!(roomController && roomController.user != object.user && roomController.safeMode > gameTime) && - !object._attack && _.filter(object.body, (i) => i.hits > 0 && i.type == C.ATTACK).length > 0 && - (_.contains(C.OBSTACLE_OBJECT_TYPES, target.type) || target.type == 'rampart' && !target.isPublic) && object.user != target.user && target.hits) { - attack = target; - } - else if(_.contains(C.OBSTACLE_OBJECT_TYPES, target.type) && target.type != 'creep' || target.type == 'rampart' && !target.isPublic && object.user != target.user) { - obstructed = true; - } - }); - - if(attack) { - require('./attack')(object, {id: attack._id, x: attack.x, y: attack.y}, roomObjects, roomTerrain, bulk); - } - else if(!obstructed) { movement.add(object, dx, dy); } }; \ No newline at end of file diff --git a/src/processor/intents/creeps/rangedHeal.js b/src/processor/intents/creeps/rangedHeal.js index 05491a22..bbb9c18c 100644 --- a/src/processor/intents/creeps/rangedHeal.js +++ b/src/processor/intents/creeps/rangedHeal.js @@ -13,7 +13,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs } var target = roomObjects[intent.id]; - if(!target || target.type != 'creep' || target.spawning || target.hits >= target.hitsMax) { + if(!target || target.type != 'creep' || target.spawning) { return; } if(Math.abs(target.x - object.x) > C.RANGE_RANGED_HEAL || Math.abs(target.y - object.y) > C.RANGE_RANGED_HEAL) { @@ -25,38 +25,8 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs var healPower = utils.calcBodyEffectiveness(object.body, C.HEAL, 'rangedHeal', C.RANGED_HEAL_POWER); - target.hits += healPower; + target._healToApply = (target._healToApply || 0) + healPower; - if(target.hits > target.hitsMax) { - target.hits = target.hitsMax; - } - - - recalcBody(target); object.actionLog.rangedHeal = {x: target.x, y: target.y}; target.actionLog.healed = {x: object.x, y: object.y}; - - bulk.update(target, { - hits: target.hits, - body: target.body, - energyCapacity: target.energyCapacity - }); - - function recalcBody(object) { - - var hits = object.hits; - - for(var i = object.body.length-1; i>=0; i--) { - if(hits > 100) - object.body[i].hits = 100; - else - object.body[i].hits = hits; - hits -= 100; - if(hits < 0) hits = 0; - } - - object.energyCapacity = _.filter(object.body, (i) => i.hits > 0 && i.type == C.CARRY).length * C.CARRY_CAPACITY; - } - - }; \ No newline at end of file diff --git a/src/processor/intents/creeps/tick.js b/src/processor/intents/creeps/tick.js index 479f5876..cd612ec8 100644 --- a/src/processor/intents/creeps/tick.js +++ b/src/processor/intents/creeps/tick.js @@ -4,6 +4,30 @@ var _ = require('lodash'), C = driver.constants, movement = require('../movement'); +function _applyDamage(object, damage) { + + let damageReduce = 0, damageEffective = damage; + + if(_.any(object.body, i => !!i.boost)) { + for(let i=0; i i.type == 'portal' && i.x == object.x && i.y == object.y); - if(portal) { - bulk.update(object, {interRoom: portal.destination}); + if(object.ageTime) { // since NPC creeps may appear right on portals without `ageTime` defined at the first tick + var portal = _.find(roomObjects, i => i.type == 'portal' && i.x == object.x && i.y == object.y); + if (portal) { + bulk.update(object, {interRoom: portal.destination}); + } } if(!object.tutorial) { @@ -67,7 +93,7 @@ module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roo C.RESOURCES_ALL.forEach(resourceType => { var amount = object[resourceType]; if (amount) { - require('./_create-energy')(object.x, object.y, object.room, amount, roomObjects, bulk, resourceType); + require('./_create-energy')(object.x, object.y, object.room, amount, roomObjects, bulk, resourceType, object.dropToContainer); } }); @@ -94,7 +120,7 @@ module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roo bulk.update(object._id, {fatigue: object.fatigue}); } - if(_.isNaN(object.hits)) { + if(_.isNaN(object.hits) || object.hits <= 0) { require('./_die')(object, roomObjects, bulk, stats); } @@ -102,4 +128,37 @@ module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roo require('./_die')(object, roomObjects, bulk, stats); } + let oldHits = object.hits; + + if (object._damageToApply) { + _applyDamage(object, object._damageToApply); + delete object._damageToApply; + } + + if (object._healToApply) { + object.hits += object._healToApply; + delete object._healToApply; + } + + if(object.hits > object.hitsMax) { + object.hits = object.hitsMax; + } + + if(object.hits <= 0) { + require('./_die')(object, roomObjects, bulk, stats); + } + else if(object.hits != oldHits) { + + require('./_recalc-body')(object); + + if(object.hits < oldHits) { + require('./_drop-resources-without-space')(object, roomObjects, roomTerrain, bulk); + } + + bulk.update(object, { + hits: object.hits, + body: object.body, + energyCapacity: object.energyCapacity + }); + } }; \ No newline at end of file diff --git a/src/processor/intents/creeps/upgradeController.js b/src/processor/intents/creeps/upgradeController.js index 832f4624..e46c5805 100644 --- a/src/processor/intents/creeps/upgradeController.js +++ b/src/processor/intents/creeps/upgradeController.js @@ -58,9 +58,12 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs if(target.tutorial && target.level == 1) { nextLevelProgress = 4; } - if (target.progress + boostedEffect >= nextLevelProgress) { + if (target.progress + boostedEffect >= nextLevelProgress && + target.downgradeTime >= gameTime + C.CONTROLLER_DOWNGRADE[target.level]) { + target.progress = target.progress + boostedEffect - nextLevelProgress; target.level++; + target.downgradeTime = gameTime + C.CONTROLLER_DOWNGRADE[target.level]; driver.sendNotification(target.user, `Your Controller in room ${target.room} has been upgraded to level ${target.level}.`); if(target.level == 8) { target.progress = 0; @@ -89,7 +92,8 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs bulk.update(target, { level: target.level, progress: target.progress, - safeModeAvailable: target.safeModeAvailable + safeModeAvailable: target.safeModeAvailable, + downgradeTime: target.downgradeTime }); }; \ No newline at end of file diff --git a/src/processor/intents/labs/boost-creep.js b/src/processor/intents/labs/boost-creep.js index fd7df21e..cb7e221f 100644 --- a/src/processor/intents/labs/boost-creep.js +++ b/src/processor/intents/labs/boost-creep.js @@ -17,7 +17,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk) { return; } - var nonBoostedParts = _.filter(target.body, i => !i.boost && C.BOOSTS[i.type][object.mineralType]); + var nonBoostedParts = _.filter(target.body, i => !i.boost && C.BOOSTS[i.type] && C.BOOSTS[i.type][object.mineralType]); if(!nonBoostedParts.length) { return; @@ -28,7 +28,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk) { } if(intent.bodyPartsCount) { - nonBoostedParts.slice(0,intent.bodyPartsCount); + nonBoostedParts = nonBoostedParts.slice(0,intent.bodyPartsCount); } while(object.mineralAmount >= C.LAB_BOOST_MINERAL && object.energy >= C.LAB_BOOST_ENERGY && nonBoostedParts.length) { @@ -48,4 +48,4 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk) { bulk.update(target, {body: target.body, energyCapacity: target.energyCapacity}); target.actionLog.healed = {x: object.x, y: object.y}; -}; \ No newline at end of file +}; diff --git a/src/processor/intents/movement.js b/src/processor/intents/movement.js index 70d8e0a6..a998a2c6 100644 --- a/src/processor/intents/movement.js +++ b/src/processor/intents/movement.js @@ -171,7 +171,7 @@ exports.execute = function(object, bulk, roomController, gameTime) { bulk.update(road, {nextDecayTime: road.nextDecayTime}); } - if(!roomController || !(roomController.safeMode > gameTime)) { + if(!roomController || roomController.user === object.user || !(roomController.safeMode > gameTime)) { var constructionSite = _.find(ceilObjects, (i) => i.type == 'constructionSite' && i.user != object.user); if (constructionSite) { require('./construction-sites/remove')(constructionSite, roomObjects, bulk); @@ -192,4 +192,4 @@ exports.execute = function(object, bulk, roomController, gameTime) { y: move.y, fatigue }); -}; \ No newline at end of file +}; diff --git a/src/processor/intents/nukers/launch-nuke.js b/src/processor/intents/nukers/launch-nuke.js index a6494e09..764d9b4c 100644 --- a/src/processor/intents/nukers/launch-nuke.js +++ b/src/processor/intents/nukers/launch-nuke.js @@ -19,7 +19,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs if(intent.x < 0 || intent.y < 0 || intent.x > 49 || intent.y > 49) { return; } - if(roomInfo.novice && roomInfo.novice > Date.now()) { + if(roomInfo.novice && roomInfo.novice > Date.now() || roomInfo.respawnArea && roomInfo.respawnArea > Date.now()) { return; } diff --git a/src/processor/intents/nukes/tick.js b/src/processor/intents/nukes/tick.js index 7d123b50..89b9003b 100644 --- a/src/processor/intents/nukes/tick.js +++ b/src/processor/intents/nukes/tick.js @@ -5,7 +5,7 @@ var _ = require('lodash'), module.exports = function(object, roomObjects, roomTerrain, bulk, bulkUsers, roomController, stats, gameTime, roomInfo) { - if(roomInfo.novice && roomInfo.novice > Date.now()) { + if(roomInfo.novice && roomInfo.novice > Date.now() || roomInfo.respawnArea && roomInfo.respawnArea > Date.now()) { bulk.remove(object._id); delete roomObjects[object._id]; return; diff --git a/src/processor/intents/room/create-construction-site.js b/src/processor/intents/room/create-construction-site.js index ab6e479d..8675a2cc 100644 --- a/src/processor/intents/room/create-construction-site.js +++ b/src/processor/intents/room/create-construction-site.js @@ -6,7 +6,7 @@ var _ = require('lodash'), var createdConstructionSiteCounter = 0; -module.exports = function(intent, roomObjects, roomTerrain, bulk, bulkUsers, roomController) { +module.exports = function(intent, userId, roomObjects, roomTerrain, bulk, bulkUsers, roomController) { if(intent.x <= 0 || intent.x >= 49 || intent.y <= 0 || intent.y >= 49) { return; @@ -18,7 +18,7 @@ module.exports = function(intent, roomObjects, roomTerrain, bulk, bulkUsers, roo if(/^(W|E)/.test(intent.roomName)) { - if (roomController && (roomController.user && roomController.user != intent.user || roomController.reservation && roomController.reservation.user != intent.user)) { + if (roomController && (roomController.user && roomController.user != userId || roomController.reservation && roomController.reservation.user != userId)) { return; } @@ -54,7 +54,7 @@ module.exports = function(intent, roomObjects, roomTerrain, bulk, bulkUsers, roo y: intent.y, type: 'constructionSite', room: intent.roomName, - user: intent.user, + user: userId, progress: 0, progressTotal }; diff --git a/src/processor/intents/room/create-flag.js b/src/processor/intents/room/create-flag.js index 20ed1c71..00be7d32 100644 --- a/src/processor/intents/room/create-flag.js +++ b/src/processor/intents/room/create-flag.js @@ -3,12 +3,12 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(intent, flags) { +module.exports = function(intent, flags, userId) { var name = intent.name.replace(/\|/g,"$VLINE$").replace(/~/g,"$TILDE$"); if(_.any(flags, i => { - return i.user == intent.user && _.any(i._parsed, j => j[0] == name); + return i.user == userId && _.any(i._parsed, j => j[0] == name); })) { return; } @@ -23,9 +23,9 @@ module.exports = function(intent, flags) { return; } - var flagItem = _.find(flags, {user: intent.user}); + var flagItem = _.find(flags, {user: userId}); if(!flagItem) { - flagItem = {user: intent.user, room: intent.roomName, _parsed: []}; + flagItem = {user: userId, room: intent.roomName, _parsed: []}; flags.push(flagItem); } diff --git a/src/processor/intents/room/destroy-structure.js b/src/processor/intents/room/destroy-structure.js index 1a7ac383..2af1598b 100644 --- a/src/processor/intents/room/destroy-structure.js +++ b/src/processor/intents/room/destroy-structure.js @@ -3,17 +3,17 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(intent, roomObjects, roomTerrain, bulk, bulkUsers, roomController) { +module.exports = function(intent, userId, roomObjects, roomTerrain, bulk, bulkUsers, roomController) { var object = roomObjects[intent.id]; if(!object || !C.CONSTRUCTION_COST[object.type]) return; - if(!roomController || roomController.user != intent.user) return; + if(!roomController || roomController.user != userId) return; if(object.type == C.STRUCTURE_WALL && object.decayTime && !object.user) return; - if(_.any(roomObjects, i => i.type == 'creep' && i.user != intent.user)) return; + if(_.any(roomObjects, i => i.type == 'creep' && i.user != userId)) return; bulk.remove(object._id); diff --git a/src/processor/intents/room/gen-energy.js b/src/processor/intents/room/gen-energy.js index 3431d986..b2c2634f 100644 --- a/src/processor/intents/room/gen-energy.js +++ b/src/processor/intents/room/gen-energy.js @@ -3,9 +3,9 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(intent, roomObjects, roomTerrain, bulk) { +module.exports = function(intent, userId, roomObjects, roomTerrain, bulk) { - if(intent.user != '3') { + if(userId != '3') { return; } diff --git a/src/processor/intents/room/intents.js b/src/processor/intents/room/intents.js index ccb14c5b..4e0bbf8c 100644 --- a/src/processor/intents/room/intents.js +++ b/src/processor/intents/room/intents.js @@ -1,6 +1,6 @@ var _ = require('lodash'); -module.exports = function(objectIntents, roomObjects, roomTerrain, bulk, bulkUsers, roomController, flags, flagsBulk) { +module.exports = function(userId, objectIntents, roomObjects, roomTerrain, bulk, bulkUsers, roomController, flags, flagsBulk) { flags.forEach(i => { i._parsed = i.data.split("|"); @@ -9,27 +9,32 @@ module.exports = function(objectIntents, roomObjects, roomTerrain, bulk, bulkUse if(objectIntents.removeFlag) { _.forEach(objectIntents.removeFlag, (i) => { - require('./remove-flag')(i, flags); + require('./remove-flag')(i, flags, userId); }); } if(objectIntents.createFlag) { _.forEach(objectIntents.createFlag, (i) => { - require('./create-flag')(i, flags); + require('./create-flag')(i, flags, userId); }); } if(objectIntents.createConstructionSite) { _.forEach(objectIntents.createConstructionSite, (i) => { - require('./create-construction-site')(i, roomObjects, roomTerrain, bulk, bulkUsers, roomController); + require('./create-construction-site')(i, userId, roomObjects, roomTerrain, bulk, bulkUsers, roomController); + }); + } + if(objectIntents.removeConstructionSite) { + _.forEach(objectIntents.removeConstructionSite, (i) => { + require('./remove-construction-site')(i, userId, roomObjects, roomTerrain, bulk, bulkUsers, roomController); }); } if(objectIntents.destroyStructure) { _.forEach(objectIntents.destroyStructure, (i) => { - require('./destroy-structure')(i, roomObjects, roomTerrain, bulk, bulkUsers, roomController); + require('./destroy-structure')(i, userId, roomObjects, roomTerrain, bulk, bulkUsers, roomController); }); } if(objectIntents.genEnergy) { - require('./gen-energy')(objectIntents.genEnergy, roomObjects, roomTerrain, bulk, bulkUsers, roomController); + require('./gen-energy')(objectIntents.genEnergy, userId, roomObjects, roomTerrain, bulk, bulkUsers, roomController); } flags.forEach(i => { diff --git a/src/processor/intents/construction-sites/remove.js b/src/processor/intents/room/remove-construction-site.js similarity index 61% rename from src/processor/intents/construction-sites/remove.js rename to src/processor/intents/room/remove-construction-site.js index d6dd02ac..b970ae0d 100644 --- a/src/processor/intents/construction-sites/remove.js +++ b/src/processor/intents/room/remove-construction-site.js @@ -3,13 +3,16 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(object, roomObjects, bulk) { +module.exports = function(intent, userId, roomObjects, roomTerrain, bulk, bulkUsers, roomController) { + + var object = roomObjects[intent.id]; if(!object || object.type != 'constructionSite') return; + if(object.user != userId && !(roomController && roomController.user == userId)) return; + bulk.remove(object._id); if(object.progress > 1) { require('../creeps/_create-energy')(object.x, object.y, object.room, Math.floor(object.progress/2), roomObjects, bulk); } - }; \ No newline at end of file diff --git a/src/processor/intents/room/remove-flag.js b/src/processor/intents/room/remove-flag.js index 4eca6a86..62b7cd6a 100644 --- a/src/processor/intents/room/remove-flag.js +++ b/src/processor/intents/room/remove-flag.js @@ -3,9 +3,9 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; -module.exports = function(intent, flags) { +module.exports = function(intent, flags, userId) { - var flagItem = _.find(flags, {user: intent.user}); + var flagItem = _.find(flags, {user: userId}); if(!flagItem) { return; } diff --git a/src/processor/intents/spawns/_charge-energy.js b/src/processor/intents/spawns/_charge-energy.js index cec9f8ea..e75efc63 100644 --- a/src/processor/intents/spawns/_charge-energy.js +++ b/src/processor/intents/spawns/_charge-energy.js @@ -3,20 +3,16 @@ var _ = require('lodash'), driver = utils.getDriver(), C = driver.constants; - -module.exports = function(spawn, roomObjects, cost, bulk, roomController) { - +function oldEnergyHandling(spawn, roomObjects, cost, bulk){ var spawns = _.filter(roomObjects, i => i.type == 'spawn' && i.user == spawn.user && !i.off); var extensions = _.filter(roomObjects, i => i.type == 'extension' && i.user == spawn.user && !i.off); - var availableEnergy = _.sum(extensions, 'energy') + _.sum(spawns, 'energy'); if(availableEnergy < cost) { return false; } - extensions.sort(utils.comparatorDistance(spawn)); - + spawns.sort(utils.comparatorDistance(spawn)); spawns.forEach((i) => { var neededEnergy = Math.min(cost, i.energy); i.energy -= neededEnergy; @@ -24,6 +20,11 @@ module.exports = function(spawn, roomObjects, cost, bulk, roomController) { bulk.update(i, {energy: i.energy}); }); + if(cost <= 0) { + return true; + } + + extensions.sort(utils.comparatorDistance(spawn)); extensions.forEach((extension) => { if(cost <= 0) { return; @@ -35,4 +36,43 @@ module.exports = function(spawn, roomObjects, cost, bulk, roomController) { }); return true; -}; \ No newline at end of file +} + +function newEnergyHandling(spawn, roomObjects, cost, bulk, energyStructures){ + energyStructures = _.filter(energyStructures, id => { + let energyStructure = roomObjects[id]; + + return energyStructure && !energyStructure.off && energyStructure.user === spawn.user && + (energyStructure.type === 'spawn' || energyStructure.type === 'extension'); + }); + + energyStructures = _.uniq(energyStructures); + + let availableEnergy = _.sum(energyStructures, id => roomObjects[id].energy); + if(availableEnergy < cost) { + return false; + } + + _.forEach(energyStructures, id => { + let energyStructure = roomObjects[id]; + + let energyChange = Math.min(cost, energyStructure.energy); + energyStructure.energy -= energyChange; + bulk.update(energyStructure, {energy: energyStructure.energy}); + + cost -= energyChange; + if(cost <= 0) { + return false; + } + }); + + return true; +} + +module.exports = function chargeEnergy(spawn, roomObjects, cost, bulk, energyStructures) { + if(energyStructures === undefined) { + return oldEnergyHandling(spawn, roomObjects, cost, bulk); + } else { + return newEnergyHandling(spawn, roomObjects, cost, bulk, energyStructures); + } +}; diff --git a/src/processor/intents/spawns/create-creep.js b/src/processor/intents/spawns/create-creep.js index 327d3006..8904e11d 100644 --- a/src/processor/intents/spawns/create-creep.js +++ b/src/processor/intents/spawns/create-creep.js @@ -19,7 +19,7 @@ module.exports = function(spawn, intent, roomObjects, roomTerrain, bulk, bulkUse intent.body = intent.body.slice(0, C.MAX_CREEP_SIZE); var cost = utils.calcCreepCost(intent.body); - var result = require('./_charge-energy')(spawn, roomObjects, cost, bulk, roomController); + var result = require('./_charge-energy')(spawn, roomObjects, cost, bulk, intent.energyStructures); if(!result) { return; diff --git a/src/processor/intents/spawns/renew-creep.js b/src/processor/intents/spawns/renew-creep.js index 8fe9a0e8..f3410f99 100644 --- a/src/processor/intents/spawns/renew-creep.js +++ b/src/processor/intents/spawns/renew-creep.js @@ -13,7 +13,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs } var target = roomObjects[intent.id]; - if(!target || target.type != 'creep' || target.user != object.user) { + if(!target || target.type != 'creep' || target.user != object.user || target.spawning) { return; } if(Math.abs(target.x - object.x) > C.RANGE_RENEW_CREEP || Math.abs(target.y - object.y) > C.RANGE_RENEW_CREEP) { @@ -29,7 +29,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs } var cost = Math.ceil(C.SPAWN_RENEW_RATIO * utils.calcCreepCost(target.body) / C.CREEP_SPAWN_TIME / target.body.length); - var result = require('./_charge-energy')(object, roomObjects, cost, bulk, roomController); + var result = require('./_charge-energy')(object, roomObjects, cost, bulk); if(!result) { return; @@ -37,7 +37,6 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs stats.inc('energyCreeps', object.user, cost); - target.ageTime += effect; target.actionLog.healed = {x: object.x, y: object.y}; bulk.inc(target, 'ageTime', effect); @@ -46,6 +45,8 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs i.boost = null; }); require('../creeps/_recalc-body')(target); + // we may not be able to hold all of the resources we could before now. + require('../creeps/_drop-resources-without-space')(target, roomObjects, roomTerrain, bulk); bulk.update(target, {body: target.body, energyCapacity: target.energyCapacity}); } diff --git a/src/processor/intents/terminal/send.js b/src/processor/intents/terminal/send.js index 2912992a..b542a007 100644 --- a/src/processor/intents/terminal/send.js +++ b/src/processor/intents/terminal/send.js @@ -17,8 +17,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk) { } var range = utils.calcRoomsDistance(object.room, intent.targetRoomName, true); - - var cost = Math.ceil(intent.amount * (Math.log((range+9) * 0.1) + 0.1)); + var cost = utils.calcTerminalEnergyCost(intent.amount, range); if(intent.resourceType != C.RESOURCE_ENERGY && object.energy < cost || intent.resourceType == C.RESOURCE_ENERGY && object.energy < intent.amount + cost) { diff --git a/src/processor/intents/towers/heal.js b/src/processor/intents/towers/heal.js index 320f85b0..9fe7e67b 100644 --- a/src/processor/intents/towers/heal.js +++ b/src/processor/intents/towers/heal.js @@ -19,9 +19,6 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs if(target.spawning) { return; } - if(target.hits >= target.hitsMax) { - return; - } if(object.energy < C.TOWER_ENERGY_COST) { return; } @@ -40,19 +37,7 @@ module.exports = function(object, intent, roomObjects, roomTerrain, bulk, bulkUs return; } - target.hits += effect; - - if(target.hits > target.hitsMax) { - target.hits = target.hitsMax; - } - - require('../creeps/_recalc-body')(target); - - bulk.update(target, { - hits: target.hits, - body: target.body, - energyCapacity: target.energyCapacity - }); + target._healToApply = (target._healToApply || 0) + effect; object.energy -= C.TOWER_ENERGY_COST; bulk.update(object, {energy: object.energy}); diff --git a/src/processor/market.js b/src/processor/market.js index a99ff838..c553515a 100644 --- a/src/processor/market.js +++ b/src/processor/market.js @@ -36,7 +36,7 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { } var range = utils.calcRoomsDistance(fromTerminal.room, toTerminal.room, true); - var transferCost = Math.max(0, Math.ceil(amount * (Math.log((range+9) * 0.1) + 0.1))); + var transferCost = utils.calcTerminalEnergyCost(amount,range); if(transferFeeTerminal === fromTerminal && (resourceType != C.RESOURCE_ENERGY && fromTerminal.energy < transferCost || @@ -73,13 +73,18 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { bulkObjects.update(terminal, {send: null}); + if(terminal.cooldownTime > gameTime) { + return; + } if(!terminalsByRoom[intent.targetRoomName] || !terminalsByRoom[intent.targetRoomName].user) { return; } - executeTransfer(terminal, terminalsByRoom[intent.targetRoomName], intent.resourceType, intent.amount, terminal, { + if(executeTransfer(terminal, terminalsByRoom[intent.targetRoomName], intent.resourceType, intent.amount, terminal, { description: intent.description ? intent.description.replace(/ order.price) { - var fee = utils.roundCredits((intent.newPrice - order.price) * order.remainingAmount * C.MARKET_FEE); + var fee = Math.ceil((intent.newPrice - order.price) * order.remainingAmount * C.MARKET_FEE); if (user.money < fee) { return; } - bulkUsers.update(user, {money: user.money - fee}); + bulkUsers.inc(user, 'money', -fee); bulkUsersMoney.insert({ date: new Date(), tick: gameTime, user: userIntents.user, type: 'market.fee', - balance: user.money, - change: -fee, + balance: user.money/1000, + change: -fee/1000, market: { changeOrderPrice: { orderId: intent.orderId, - oldPrice: order.price, - newPrice: intent.newPrice + oldPrice: order.price/1000, + newPrice: intent.newPrice/1000 } } }); } - bulkMarketOrders.update(order, {price: intent.newPrice}); + bulkMarketOrders.update(order._id, {price: intent.newPrice}); }); } @@ -191,21 +199,21 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { return; } - var fee = utils.roundCredits(order.price * intent.addAmount * C.MARKET_FEE); + var fee = Math.ceil(order.price * intent.addAmount * C.MARKET_FEE); if (user.money < fee) { return; } - bulkUsers.update(user, {money: user.money - fee}); + bulkUsers.inc(user, 'money', -fee); bulkUsersMoney.insert({ date: new Date(), tick: gameTime, user: userIntents.user, type: 'market.fee', - balance: user.money, - change: -fee, + balance: user.money/1000, + change: -fee/1000, market: { extendOrder: { orderId: intent.orderId, @@ -249,6 +257,7 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { if(!terminalsByRoom[intent.targetRoomName] || terminalsByRoom[intent.targetRoomName].user != userIntents.user) { return; } + terminalDeals.push(intent); }); } @@ -262,6 +271,13 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { targetTerminal = terminalsByRoom[deal.targetRoomName], buyer, seller; + if(!orderTerminal || !targetTerminal) { + return; + } + if(targetTerminal.cooldownTime > gameTime) { + return; + } + if(order.type == C.ORDER_SELL) { buyer = targetTerminal; seller = orderTerminal; @@ -284,12 +300,12 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { return; } - var dealCost = utils.roundCredits(amount * order.price); + var dealCost = amount * order.price; if(buyer.user) { dealCost = Math.min(dealCost, usersById[buyer.user].money || 0); amount = Math.floor(dealCost/order.price); - dealCost = utils.roundCredits(amount * order.price); + dealCost = amount * order.price; if(!amount) { return; } @@ -298,42 +314,42 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { if(executeTransfer(seller, buyer, order.resourceType, amount, targetTerminal, {order: { id: ""+order._id, type: order.type, - price: order.price + price: order.price/1000 }})) { if(seller.user) { - bulkUsers.update(usersById[seller.user], {money: (usersById[seller.user].money||0) + dealCost}); + bulkUsers.inc(usersById[seller.user], 'money', dealCost); bulkUsersMoney.insert({ date: new Date(), tick: gameTime, user: seller.user, type: 'market.sell', - balance: usersById[seller.user].money, - change: dealCost, + balance: usersById[seller.user].money/1000, + change: dealCost/1000, market: { resourceType: order.resourceType, roomName: order.roomName, targetRoomName: deal.targetRoomName, - price: order.price, + price: order.price/1000, npc: !buyer.user, amount } }); } if(buyer.user) { - bulkUsers.update(usersById[buyer.user], {money: (usersById[buyer.user].money||0) - dealCost}); + bulkUsers.inc(usersById[buyer.user], 'money', -dealCost); bulkUsersMoney.insert({ date: new Date(), tick: gameTime, user: buyer.user, type: 'market.buy', - balance: usersById[buyer.user].money, - change: -dealCost, + balance: usersById[buyer.user].money/1000, + change: -dealCost/1000, market: { resourceType: order.resourceType, roomName: order.roomName, targetRoomName: deal.targetRoomName, - price: order.price, + price: order.price/1000, npc: !seller.user, amount } @@ -343,6 +359,7 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { amount: order.amount - amount, remainingAmount: order.remainingAmount - amount }); + bulkObjects.update(targetTerminal, {cooldownTime: gameTime + C.TERMINAL_COOLDOWN}); } }); @@ -374,29 +391,25 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { return; } - var dealCost = utils.roundCredits(amount * order.price); + var dealCost = amount * order.price; if(buyer.user && (!buyer.money || buyer.money < dealCost)) { return; } + bulkUsers.inc(seller, 'money', dealCost); + bulkUsers.inc(seller, userFieldName, -amount); - - - bulkUsers.update(seller, { - money: (seller.money||0) + dealCost, - [userFieldName]: (seller[userFieldName]||0) - amount - }); bulkUsersMoney.insert({ date: new Date(), tick: gameTime, user: ""+seller._id, type: 'market.sell', - balance: seller.money, - change: dealCost, + balance: seller.money/1000, + change: dealCost/1000, market: { resourceType: order.resourceType, - price: order.price, + price: order.price/1000, amount } }); @@ -413,20 +426,19 @@ module.exports.execute = function(market, gameTime, terminals, bulkObjects) { } }); - bulkUsers.update(buyer, { - money: (buyer.money||0) - dealCost, - [userFieldName]: (buyer[userFieldName]||0) + amount - }); + bulkUsers.inc(buyer, 'money', -dealCost); + bulkUsers.inc(buyer, userFieldName, amount); + bulkUsersMoney.insert({ date: new Date(), tick: gameTime, user: ""+buyer._id, type: 'market.buy', - balance: buyer.money, - change: -dealCost, + balance: buyer.money/1000, + change: -dealCost/1000, market: { resourceType: order.resourceType, - price: order.price, + price: order.price/1000, amount } }); diff --git a/src/runner.js b/src/runner.js index 228800dc..274eb356 100644 --- a/src/runner.js +++ b/src/runner.js @@ -40,6 +40,12 @@ function runUser(userId, onlyInRoom) { if(runResult.memory) { promises.push(driver.saveUserMemory(userId, runResult.memory, onlyInRoom)); } + if(runResult.memorySegments) { + promises.push(driver.saveUserMemorySegments(userId, runResult.memorySegments)); + } + if(runResult.interShardSegment) { + promises.push(driver.saveUserMemoryInterShardSegment(userId, runResult.interShardSegment)); + } if(runResult.intents) { promises.push(driver.saveUserIntents(userId, runResult.intents)); } diff --git a/src/utils.js b/src/utils.js index f01284d7..27390984 100644 --- a/src/utils.js +++ b/src/utils.js @@ -434,8 +434,7 @@ exports.storeIntents = function(userId, userIntents, userRuntimeData) { name: ""+iCreateFlag.name, color: +iCreateFlag.color, secondaryColor: +iCreateFlag.secondaryColor, - roomName: iCreateFlag.roomName, - user: userId + roomName: iCreateFlag.roomName }) }); } @@ -455,8 +454,24 @@ exports.storeIntents = function(userId, userIntents, userRuntimeData) { y: parseInt(iCreateConstructionSite.y), structureType: ""+iCreateConstructionSite.structureType, name: ""+iCreateConstructionSite.name, - roomName: ""+iCreateConstructionSite.roomName, - user: userId + roomName: ""+iCreateConstructionSite.roomName + }); + }); + } + if(roomIntentsResult.removeConstructionSite) { + _.forEach(roomIntentsResult.removeConstructionSite, (iRemoveConstructionSite) => { + + intents[iRemoveConstructionSite.roomName] = + intents[iRemoveConstructionSite.roomName] || {}; + + var roomIntents = intents[iRemoveConstructionSite.roomName].room = + intents[iRemoveConstructionSite.roomName].room || {}; + + roomIntents.removeConstructionSite = roomIntents.removeConstructionSite || []; + + roomIntents.removeConstructionSite.push({ + roomName: ""+iRemoveConstructionSite.roomName, + id: ""+iRemoveConstructionSite.id }); }); } @@ -473,8 +488,7 @@ exports.storeIntents = function(userId, userIntents, userRuntimeData) { roomIntents.destroyStructure.push({ roomName: ""+iDestroyStructure.roomName, - id: ""+iDestroyStructure.id, - user: userId + id: ""+iDestroyStructure.id }); }); } @@ -492,8 +506,7 @@ exports.storeIntents = function(userId, userIntents, userRuntimeData) { roomIntents.removeFlag.push({ roomName: ""+iRemoveFlag.roomName, - name: ""+iRemoveFlag.name, - user: userId + name: ""+iRemoveFlag.name }); }); } @@ -511,7 +524,7 @@ exports.storeIntents = function(userId, userIntents, userRuntimeData) { intents.market.createOrder.push({ type: ""+iCreateOrder.type, resourceType: ""+iCreateOrder.resourceType, - price: exports.roundCredits(iCreateOrder.price), + price: parseInt(iCreateOrder.price*1000), totalAmount: parseInt(iCreateOrder.totalAmount), roomName: iCreateOrder.roomName ? ""+iCreateOrder.roomName : undefined }) @@ -530,7 +543,7 @@ exports.storeIntents = function(userId, userIntents, userRuntimeData) { intents.market.changeOrderPrice = intents.market.changeOrderPrice || []; intents.market.changeOrderPrice.push({ orderId: ""+iChangeOrderPrice.orderId, - newPrice: exports.roundCredits(iChangeOrderPrice.newPrice), + newPrice: parseInt(iChangeOrderPrice.newPrice*1000), }); }); } @@ -651,7 +664,8 @@ exports.storeIntents = function(userId, userIntents, userRuntimeData) { if(objectIntentsResult.createCreep) { objectIntents.createCreep = { name: ""+objectIntentsResult.createCreep.name, - body: _.filter(objectIntentsResult.createCreep.body, (i) => _.contains(C.BODYPARTS_ALL, i)) + body: _.filter(objectIntentsResult.createCreep.body, (i) => _.contains(C.BODYPARTS_ALL, i)), + energyStructures: objectIntentsResult.createCreep.energyStructures }; } if(objectIntentsResult.renewCreep) { @@ -839,28 +853,55 @@ exports.sendAttackingNotification = function(target, roomController) { }; exports.checkStructureAgainstController = function(object, roomObjects, roomController) { - + // owner-less objects are always active if(!object.user) { return true; } - if(!roomController || roomController.level < 1 || object.user && roomController.user != object.user) { + // eliminate some other easy cases + if(!roomController || roomController.level < 1 || roomController.user !== object.user) { return false; } - if(C.CONTROLLER_STRUCTURES[object.type][8] == 1) { - return C.CONTROLLER_STRUCTURES[object.type][roomController.level] != 0; + let allowedRemaining = C.CONTROLLER_STRUCTURES[object.type][roomController.level]; + + if(allowedRemaining === 0) { + return false; } - var objects = _.filter(roomObjects, {type: object.type, user: object.user}); + // if only one object ever allowed, this is it + if(C.CONTROLLER_STRUCTURES[object.type][8] === 1) { + return allowedRemaining !== 0; + } - if(objects.length > C.CONTROLLER_STRUCTURES[object.type][roomController.level]) { - objects.sort(exports.comparatorDistance(roomController)); - objects = _.take(objects, C.CONTROLLER_STRUCTURES[object.type][roomController.level]); - if(!_.contains(objects, object)) { - return false; + // Scan through the room objects of the same type and count how many are closer. + let foundSelf = false; + let objectDist = Math.max(Math.abs(object.x - roomController.x), Math.abs(object.y - roomController.y)); + let objectIds = _.keys(roomObjects); + for (let i = 0; i < objectIds.length; i++) { + let compareObj = roomObjects[objectIds[i]]; + if(compareObj.type === object.type && compareObj.user === object.user) { + let compareDist = Math.max(Math.abs(compareObj.x - roomController.x), Math.abs(compareObj.y - roomController.y)); + + if(compareDist < objectDist) { + allowedRemaining--; + if (allowedRemaining === 0) { + return false; + } + } else if(!foundSelf && compareDist === objectDist) { + // Objects of equal distance that are discovered before we scan over the selected object are considered closer + if(object === compareObj) { + foundSelf = true; + } else { + allowedRemaining--; + if (allowedRemaining === 0) { + return false; + } + } + } } } + return true; }; @@ -972,18 +1013,23 @@ exports.calcBodyEffectiveness = function(body, bodyPartType, methodName, basePow return power; }; -exports.roundCredits = function(value) { - return Math.ceil(((+value)*100).toFixed(0))/100; -}; - exports.calcRoomsDistance = function(room1, room2, continuous) { var [x1,y1] = exports.roomNameToXY(room1); var [x2,y2] = exports.roomNameToXY(room2); var dx = Math.abs(x2-x1); var dy = Math.abs(y2-y1); if(continuous) { - dx = Math.min(C.WORLD_WIDTH - dx, dx); - dy = Math.min(C.WORLD_HEIGHT - dy, dy); + var worldSize = driver.getWorldSize(); + dx = Math.min(worldSize - dx, dx); + dy = Math.min(worldSize - dy, dy); } return Math.max(dx, dy); +}; + +exports.calcTerminalEnergyCost = function(amount, range) { + return Math.ceil(amount * (1 - Math.exp(-range / 30))) +}; + +exports.calcNeededGcl = function(gclLevel) { + return C.GCL_MULTIPLY * Math.pow(gclLevel-1, C.GCL_POW); }; \ No newline at end of file