diff --git a/spec/engine/processor/intents/movementSpec.js b/spec/engine/processor/intents/movementSpec.js index e42456e1..59e0ae87 100644 --- a/spec/engine/processor/intents/movementSpec.js +++ b/spec/engine/processor/intents/movementSpec.js @@ -6,8 +6,12 @@ const _ =require('lodash'), roomsEnv = require('../../../helpers/mocks/rooms'), creepsEnv = require('../../../helpers/mocks/creeps'), powerCreepsEnv = require('../../../helpers/mocks/powerCreeps'), + users = require('../../../helpers/mocks/users'), intents = require('../../../helpers/mocks/intents'); +const OWNER = users.defaultId; +const HOSTILE = 'hostile-user-id'; + describe('movement', ()=>{ let scope; @@ -183,6 +187,78 @@ describe('movement', ()=>{ }); }); + describe('Safe mode', ()=>{ + let owner, invader; + + beforeEach(()=>{ + owner = creepsEnv.createCreep('scout', {x: 24, y: 25, user: OWNER}); + invader = creepsEnv.createCreep('scout', {x: 24, y: 24, user: HOSTILE}); + movement.init(scope.roomObjects, roomsEnv.terrain.E2S7); + }); + + it('allows the owner to move onto a stationary hostile', ()=>{ + owner.move(1); + movement.check(OWNER); + intents.ticks(); + + expect(owner.x).toBe(24); expect(owner.y).toBe(24); + expect(invader.x).toBe(24); expect(invader.y).toBe(24); + }); + + it('allows the owner to move onto a hostile whose own move was rejected', ()=>{ + // Invader tries to step onto another owner creep and fails; that + // rejection must not cascade-cancel the owner entering the invader tile. + const owner2 = creepsEnv.createCreep('scout', {x: 25, y: 24, user: OWNER}); + movement.init(scope.roomObjects, roomsEnv.terrain.E2S7); + + owner.move(1); + invader.move(3); + movement.check(OWNER); + intents.ticks(); + + expect(owner.x).toBe(24); expect(owner.y).toBe(24); + expect(invader.x).toBe(24); expect(invader.y).toBe(24); + expect(owner2.x).toBe(25); expect(owner2.y).toBe(24); + }); + + it('still prevents hostiles from moving onto the owner', ()=>{ + invader.move(5); + movement.check(OWNER); + intents.ticks(); + + expect(owner.x).toBe(24); expect(owner.y).toBe(25); + expect(invader.x).toBe(24); expect(invader.y).toBe(24); + }); + + it('still blocks the owner without safe mode', ()=>{ + owner.move(1); + movement.check(false); + intents.ticks(); + + expect(owner.x).toBe(24); expect(owner.y).toBe(25); + expect(invader.x).toBe(24); expect(invader.y).toBe(24); + }); + + it('still cascades when a friendly creep fails to move', ()=>{ + intents.reset(); + const lead = creepsEnv.createCreep('scout', {x: 24, y: 24, user: OWNER}); + const mid = creepsEnv.createCreep('scout', {x: 24, y: 25, user: OWNER}); + const trail = creepsEnv.createCreep('scout', {x: 24, y: 26, user: OWNER}); + movement.init(scope.roomObjects, roomsEnv.terrain.E2S7); + + // lead walks into a wall; followers must stay put + lead.move(4); + mid.move(1); + trail.move(1); + movement.check(OWNER); + intents.ticks(); + + expect(lead.x).toBe(24); expect(lead.y).toBe(24); + expect(mid.x).toBe(24); expect(mid.y).toBe(25); + expect(trail.x).toBe(24); expect(trail.y).toBe(26); + }); + }); + describe('Single Power Creep',()=>{ let operator; beforeEach(()=>{ diff --git a/src/processor/intents/movement.js b/src/processor/intents/movement.js index caf97029..13f88914 100644 --- a/src/processor/intents/movement.js +++ b/src/processor/intents/movement.js @@ -158,7 +158,7 @@ exports.check = function(roomIsInSafeMode) { if(object) { var key = `${object.x},${object.y}`; - if(matrix[key]) { + if(matrix[key] && !(roomIsInSafeMode == matrix[key].user && object.user != matrix[key].user)) { removeFromMatrix(key); } }