From 04fa6faab0aa6c3b3d68c214df91dec16418c0c7 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Mon, 7 Sep 2026 00:00:53 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=20Stop=20rejected=20moves=20from?= =?UTF-8?q?=20blocking=20the=20owner=20creeps=20from=20moving?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug with movement in a safemoded room, where an hostile creep would try to move onto an owner-occupied tile, and being rejected. The rejection cascade would cause all chained moves to cancel, even those from the owner moving onto the hostile-occupied tile, which is not a blocked under safemode rules. --- spec/engine/processor/intents/movementSpec.js | 76 +++++++++++++++++++ src/processor/intents/movement.js | 2 +- 2 files changed, 77 insertions(+), 1 deletion(-) 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); } }