From cd430ecb5adc81b597e01d55f455d7e7c6d84f69 Mon Sep 17 00:00:00 2001 From: Skyler Kehren Date: Sat, 13 Oct 2018 21:08:58 +0300 Subject: [PATCH 1/3] Implements Room.Terrain and room.getTerrain --- dist/index.d.ts | 23 ++++- dist/screeps-tests.ts | 207 ++++++++++++++++++++++-------------------- src/literals.ts | 5 + src/room-terrain.ts | 10 +- src/room.ts | 8 ++ 5 files changed, 153 insertions(+), 100 deletions(-) diff --git a/dist/index.d.ts b/dist/index.d.ts index 42b7d8a6..8dcfc240 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1744,6 +1744,11 @@ type STRUCTURE_CONTAINER = "container"; type STRUCTURE_NUKER = "nuker"; type STRUCTURE_PORTAL = "portal"; +// Terrain mask constants +type TERRAIN_MASK_WALL = 1; +type TERRAIN_MASK_SWAMP = 2; +type TERRAIN_MASK_LAVA = 4; + // Resource Constants type ResourceConstant = @@ -2809,7 +2814,15 @@ interface RoomTerrain { * @param y Y position in the room. * @return number Number of terrain mask like: TERRAIN_MASK_SWAMP | TERRAIN_MASK_WALL */ - get(x: number, y: number): number; + get(x: number, y: number): 0 | TERRAIN_MASK_WALL | TERRAIN_MASK_SWAMP; +} + +interface RoomTerrainConstructor extends _Constructor { + /** + * Get room terrain for the specified room. This method works for any room in the world even if you have no access to it. + * @param roomName String name of the room. + */ + new (roomName: string): RoomTerrain; } declare class RoomVisual { /** @@ -3182,6 +3195,11 @@ interface Room { * @returns A RoomPosition object or null if it cannot be obtained. */ getPositionAt(x: number, y: number): RoomPosition | null; + /** + * Get room terrain for the specified room. This method works for any room in the world even if you have no access to it. + * @param roomName String name of the room. + */ + getTerrain(): RoomTerrain; /** * Get the list of objects at the specified room position. * @param x The X position. @@ -3282,6 +3300,9 @@ interface Room { interface RoomConstructor extends _Constructor { new (id: string): Room; + + Terrain: RoomTerrainConstructor; + /** * Serialize a path array into a short string representation, which is suitable to store in memory. * @param path A path array retrieved from `Room.findPath`. diff --git a/dist/screeps-tests.ts b/dist/screeps-tests.ts index 4b7a3722..444e7ff7 100644 --- a/dist/screeps-tests.ts +++ b/dist/screeps-tests.ts @@ -121,7 +121,7 @@ function keys(o: T): Array { if (Game.spawns["Spawn1"].energy === 0) { Game.notify( "Spawn1 is out of energy", - 180 // group these notifications for 3 hours + 180, // group these notifications for 3 hours ); } } @@ -130,13 +130,12 @@ function keys(o: T): Array { { const exits = Game.map.describeExits("W8N3"); - keys(exits) - .map((exitKey) => { - const nextRoom = exits[exitKey]; - const exitDir = +exitKey as ExitConstant; - const exitPos = creep.pos.findClosestByRange(exitDir); - return {nextRoom, exitPos}; - }); + keys(exits).map(exitKey => { + const nextRoom = exits[exitKey]; + const exitDir = +exitKey as ExitConstant; + const exitPos = creep.pos.findClosestByRange(exitDir); + return { nextRoom, exitPos }; + }); } // Game.map.findExit() @@ -180,7 +179,7 @@ function keys(o: T): Array { return Infinity; } return 1; - } + }, }); } @@ -195,11 +194,8 @@ function keys(o: T): Array { routeCallback(roomName) { const parsed = /^[WE]([0-9]+)[NS]([0-9]+)$/.exec(roomName); if (parsed !== null) { - const isHighway = (parseInt(parsed[1], 10) % 10 === 0) || - (parseInt(parsed[2], 10) % 10 === 0); - const isMyRoom = Game.rooms[roomName] && - Game.rooms[roomName].controller && - Game.rooms[roomName].controller!.my; + const isHighway = parseInt(parsed[1], 10) % 10 === 0 || parseInt(parsed[2], 10) % 10 === 0; + const isMyRoom = Game.rooms[roomName] && Game.rooms[roomName].controller && Game.rooms[roomName].controller!.my; if (isHighway || isMyRoom) { return 1; } else { @@ -208,24 +204,24 @@ function keys(o: T): Array { } else { return 2.5; } - } + }, }); if (route !== ERR_NO_PATH) { - route.forEach((info) => { + route.forEach(info => { allowedRooms[info.room] = true; }); } // Invoke PathFinder, allowing access only to rooms from `findRoute` const ret = PathFinder.search(from, [to], { - roomCallback: (roomName) => { + roomCallback: roomName => { if (allowedRooms[roomName] === undefined) { return false; } else { return true; } - } + }, }); } @@ -299,9 +295,12 @@ function keys(o: T): Array { Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); const targetRoom = "W1N1"; - Game.market.getAllOrders((currentOrder) => currentOrder.resourceType === RESOURCE_GHODIUM && - currentOrder.type === ORDER_SELL && - Game.market.calcTransactionCost(1000, targetRoom, currentOrder.roomName!) < 500); + Game.market.getAllOrders( + currentOrder => + currentOrder.resourceType === RESOURCE_GHODIUM && + currentOrder.type === ORDER_SELL && + Game.market.calcTransactionCost(1000, targetRoom, currentOrder.roomName!) < 500, + ); // Game.market.getOrderById(id) const order = Game.market.getOrderById("55c34a6b5be41a0a6e80c123"); @@ -316,54 +315,49 @@ function keys(o: T): Array { { const pfCreep = Game.creeps.John; - const goals = pfCreep.room.find(FIND_SOURCES) - .map((source) => { - // We can't actually walk on sources-- set `range` to 1 - // so we path next to it. - return { pos: source.pos, range: 1 }; - }); + const goals = pfCreep.room.find(FIND_SOURCES).map(source => { + // We can't actually walk on sources-- set `range` to 1 + // so we path next to it. + return { pos: source.pos, range: 1 }; + }); - const ret = PathFinder.search( - pfCreep.pos, goals, - { - // We need to set the defaults costs higher so that we - // can set the road cost lower in `roomCallback` - plainCost: 2, - swampCost: 10, - - roomCallback(roomName) { - const curRoom = Game.rooms[roomName]; - // In this example `room` will always exist, but since - // PathFinder supports searches which span multiple rooms - // you should be careful! - if (!curRoom) { - return false; + const ret = PathFinder.search(pfCreep.pos, goals, { + // We need to set the defaults costs higher so that we + // can set the road cost lower in `roomCallback` + plainCost: 2, + swampCost: 10, + + roomCallback(roomName) { + const curRoom = Game.rooms[roomName]; + // In this example `room` will always exist, but since + // PathFinder supports searches which span multiple rooms + // you should be careful! + if (!curRoom) { + return false; + } + const costs = new PathFinder.CostMatrix(); + + curRoom.find(FIND_STRUCTURES).forEach(struct => { + if (struct.structureType === STRUCTURE_ROAD) { + // Favor roads over plain tiles + costs.set(struct.pos.x, struct.pos.y, 1); + } else if ( + struct.structureType !== STRUCTURE_CONTAINER && + (struct.structureType !== STRUCTURE_RAMPART || !(struct as OwnedStructure).my) + ) { + // Can't walk through non-walkable buildings + costs.set(struct.pos.x, struct.pos.y, 0xff); } - const costs = new PathFinder.CostMatrix(); - - curRoom.find(FIND_STRUCTURES) - .forEach((struct) => { - if (struct.structureType === STRUCTURE_ROAD) { - // Favor roads over plain tiles - costs.set(struct.pos.x, struct.pos.y, 1); - } else if (struct.structureType !== STRUCTURE_CONTAINER && - (struct.structureType !== STRUCTURE_RAMPART || - !(struct as OwnedStructure).my)) { - // Can't walk through non-walkable buildings - costs.set(struct.pos.x, struct.pos.y, 0xff); - } - }); - - // Avoid creeps in the room - curRoom.find(FIND_CREEPS) - .forEach((thisCreep) => { - costs.set(thisCreep.pos.x, thisCreep.pos.y, 0xff); - }); - - return costs; - }, - } - ); + }); + + // Avoid creeps in the room + curRoom.find(FIND_CREEPS).forEach(thisCreep => { + costs.set(thisCreep.pos.x, thisCreep.pos.y, 0xff); + }); + + return costs; + }, + }); const pos = ret.path[0]; pfCreep.move(pfCreep.pos.getDirectionTo(pos)); @@ -390,8 +384,8 @@ function keys(o: T): Array { RawMemory.interShardSegment = JSON.stringify({ creeps: { - Bob: {role: "claimer"} - } + Bob: { role: "claimer" }, + }, }); // on another shard @@ -454,9 +448,9 @@ function keys(o: T): Array { creepsHere[0].getActiveBodyparts(ATTACK); const towers = room.find(FIND_MY_STRUCTURES, { - filter: (structure) => { - return (structure.structureType === STRUCTURE_TOWER); - } + filter: structure => { + return structure.structureType === STRUCTURE_TOWER; + }, }); towers[0].attack(creeps[0]); } @@ -471,18 +465,18 @@ function keys(o: T): Array { } const tower = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { - filter: (structure) => { + filter: structure => { return structure.structureType === STRUCTURE_TOWER; - } + }, }); if (tower !== null) { tower.attack(creep); } const rampart = creep.pos.findClosestByRange(FIND_HOSTILE_STRUCTURES, { - filter: (structure) => { + filter: structure => { return structure.structureType === STRUCTURE_RAMPART; - } + }, }); if (rampart !== null) { rampart.isPublic; @@ -493,9 +487,9 @@ function keys(o: T): Array { hostileCreeps[0].saying; const labs = creep.pos.findInRange(FIND_MY_STRUCTURES, 4, { - filter: (structure) => { + filter: structure => { return structure.structureType === STRUCTURE_LAB; - } + }, }); labs[0].boostCreep(creep); @@ -511,7 +505,7 @@ function keys(o: T): Array { const pos = new RoomPosition(+x, +y, room.name); const objects = row[x]; if (objects.length > 0) { - objects.map((o) => o.type); + objects.map(o => o.type); } } } @@ -556,34 +550,31 @@ function keys(o: T): Array { switch (unowned.structureType) { case STRUCTURE_TOWER: unowned.heal(Game.creeps.myCreep); - break; + break; case STRUCTURE_CONTAINER: case STRUCTURE_STORAGE: case STRUCTURE_TERMINAL: const energyPercent = unowned.store.energy / unowned.storeCapacity; - break; + break; case STRUCTURE_WALL: case STRUCTURE_RAMPART: const wallHp = unowned.hits / unowned.hitsMax; - break; + break; } // test discriminated union using filter functions on find const from = Game.rooms.myRoom.find(FIND_STRUCTURES, { - filter: (s) => ((s.structureType === STRUCTURE_CONTAINER - || s.structureType === STRUCTURE_STORAGE) - && s.store.energy > 0) + filter: s => (s.structureType === STRUCTURE_CONTAINER || s.structureType === STRUCTURE_STORAGE) && s.store.energy > 0, })[0]; const to = from.pos.findClosestByPath(FIND_MY_STRUCTURES, { - filter: (s) => ((s.structureType === STRUCTURE_SPAWN - || s.structureType === STRUCTURE_EXTENSION) - && s.energy < s.energyCapacity) + filter: s => (s.structureType === STRUCTURE_SPAWN || s.structureType === STRUCTURE_EXTENSION) && s.energy < s.energyCapacity, }); - Game.rooms.myRoom.find(FIND_MY_STRUCTURES, { - filter: (s) => s.structureType === STRUCTURE_RAMPART - }) - .forEach((r) => r.notifyWhenAttacked(false)); + Game.rooms.myRoom + .find(FIND_MY_STRUCTURES, { + filter: s => s.structureType === STRUCTURE_RAMPART, + }) + .forEach(r => r.notifyWhenAttacked(false)); } { @@ -604,12 +595,12 @@ function keys(o: T): Array { tombstone.id; - const creep = Game.creeps['dave']; + const creep = Game.creeps["dave"]; creep.withdraw(tombstone, RESOURCE_ENERGY); } { - if (Game.cpu.hasOwnProperty('getHeapStatistics')) { + if (Game.cpu.hasOwnProperty("getHeapStatistics")) { const heap = Game.cpu.getHeapStatistics!(); heap.total_heap_size; } @@ -618,9 +609,9 @@ function keys(o: T): Array { // StructurePortal { - const portals = room.find(FIND_STRUCTURES, {filter: (s) => s.structureType === STRUCTURE_PORTAL}); + const portals = room.find(FIND_STRUCTURES, { filter: s => s.structureType === STRUCTURE_PORTAL }); portals.forEach((p: StructurePortal) => { - const state = p.ticksToDecay === undefined ? 'stable' : 'unstable'; + const state = p.ticksToDecay === undefined ? "stable" : "unstable"; if (p.destination instanceof RoomPosition) { Game.notify(`Found ${state} inter-room portal to ${p.destination}`); } else { @@ -649,8 +640,7 @@ function keys(o: T): Array { const lab1 = Game.getObjectById("lab1"); const lab2 = Game.getObjectById("lab2"); if (lab0 !== null && lab1 !== null && lab2 !== null) { - if (lab1.mineralAmount >= LAB_REACTION_AMOUNT && lab2.mineralAmount >= LAB_REACTION_AMOUNT && - lab0.mineralType === null) { + if (lab1.mineralAmount >= LAB_REACTION_AMOUNT && lab2.mineralAmount >= LAB_REACTION_AMOUNT && lab0.mineralType === null) { lab0.runReaction(lab1, lab2); } } @@ -662,3 +652,24 @@ function keys(o: T): Array { room.getEventLog(); room.getEventLog(true); } + +// Room.Terrain + +{ + const room = Game.rooms[""]; + + const myTerrain = room.getTerrain(); + + const ret = myTerrain.get(5, 5); + if (ret === 0) { + /*plain*/ + } + if (ret === TERRAIN_MASK_SWAMP) { + /*swamp*/ + } + if (ret === TERRAIN_MASK_WALL) { + /*wall*/ + } + + const enemyTerrain = new Room.Terrain("W2N5"); +} diff --git a/src/literals.ts b/src/literals.ts index e9358625..74fec514 100644 --- a/src/literals.ts +++ b/src/literals.ts @@ -240,6 +240,11 @@ type STRUCTURE_CONTAINER = "container"; type STRUCTURE_NUKER = "nuker"; type STRUCTURE_PORTAL = "portal"; +// Terrain mask constants +type TERRAIN_MASK_WALL = 1; +type TERRAIN_MASK_SWAMP = 2; +type TERRAIN_MASK_LAVA = 4; + // Resource Constants type ResourceConstant = diff --git a/src/room-terrain.ts b/src/room-terrain.ts index efb0d51f..0ee753e2 100644 --- a/src/room-terrain.ts +++ b/src/room-terrain.ts @@ -8,5 +8,13 @@ interface RoomTerrain { * @param y Y position in the room. * @return number Number of terrain mask like: TERRAIN_MASK_SWAMP | TERRAIN_MASK_WALL */ - get(x: number, y: number): number; + get(x: number, y: number): 0 | TERRAIN_MASK_WALL | TERRAIN_MASK_SWAMP; +} + +interface RoomTerrainConstructor extends _Constructor { + /** + * Get room terrain for the specified room. This method works for any room in the world even if you have no access to it. + * @param roomName String name of the room. + */ + new (roomName: string): RoomTerrain; } diff --git a/src/room.ts b/src/room.ts index 8b22ecf0..2b0de0f0 100644 --- a/src/room.ts +++ b/src/room.ts @@ -174,6 +174,11 @@ interface Room { * @returns A RoomPosition object or null if it cannot be obtained. */ getPositionAt(x: number, y: number): RoomPosition | null; + /** + * Get room terrain for the specified room. This method works for any room in the world even if you have no access to it. + * @param roomName String name of the room. + */ + getTerrain(): RoomTerrain; /** * Get the list of objects at the specified room position. * @param x The X position. @@ -274,6 +279,9 @@ interface Room { interface RoomConstructor extends _Constructor { new (id: string): Room; + + Terrain: RoomTerrainConstructor; + /** * Serialize a path array into a short string representation, which is suitable to store in memory. * @param path A path array retrieved from `Room.findPath`. From f8f4ae92d451e34ac277f266f3067b73aab2c30a Mon Sep 17 00:00:00 2001 From: Skyler Kehren Date: Sat, 13 Oct 2018 21:48:29 +0300 Subject: [PATCH 2/3] disables newline-per-chained-call due to tslint/prettier fight --- dist/screeps-tests.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dist/screeps-tests.ts b/dist/screeps-tests.ts index 444e7ff7..d7befaf3 100644 --- a/dist/screeps-tests.ts +++ b/dist/screeps-tests.ts @@ -130,6 +130,7 @@ function keys(o: T): Array { { const exits = Game.map.describeExits("W8N3"); + // tslint:disable-next-line:newline-per-chained-call keys(exits).map(exitKey => { const nextRoom = exits[exitKey]; const exitDir = +exitKey as ExitConstant; @@ -315,6 +316,7 @@ function keys(o: T): Array { { const pfCreep = Game.creeps.John; + // tslint:disable-next-line:newline-per-chained-call const goals = pfCreep.room.find(FIND_SOURCES).map(source => { // We can't actually walk on sources-- set `range` to 1 // so we path next to it. @@ -337,6 +339,7 @@ function keys(o: T): Array { } const costs = new PathFinder.CostMatrix(); + // tslint:disable-next-line:newline-per-chained-call curRoom.find(FIND_STRUCTURES).forEach(struct => { if (struct.structureType === STRUCTURE_ROAD) { // Favor roads over plain tiles @@ -351,6 +354,7 @@ function keys(o: T): Array { }); // Avoid creeps in the room + // tslint:disable-next-line:newline-per-chained-call curRoom.find(FIND_CREEPS).forEach(thisCreep => { costs.set(thisCreep.pos.x, thisCreep.pos.y, 0xff); }); From 308dd8a9d5bffa11be43e37a49fe5effd624d792 Mon Sep 17 00:00:00 2001 From: Skyler Kehren Date: Sat, 13 Oct 2018 22:08:08 +0300 Subject: [PATCH 3/3] Updates getTerrain comment --- dist/index.d.ts | 4 ++-- src/room.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/index.d.ts b/dist/index.d.ts index 8dcfc240..27ca1096 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -3196,8 +3196,8 @@ interface Room { */ getPositionAt(x: number, y: number): RoomPosition | null; /** - * Get room terrain for the specified room. This method works for any room in the world even if you have no access to it. - * @param roomName String name of the room. + * Get a Room.Terrain object which provides fast access to static terrain data. + * This method works for any room in the world even if you have no access to it. */ getTerrain(): RoomTerrain; /** diff --git a/src/room.ts b/src/room.ts index 2b0de0f0..98eff554 100644 --- a/src/room.ts +++ b/src/room.ts @@ -175,8 +175,8 @@ interface Room { */ getPositionAt(x: number, y: number): RoomPosition | null; /** - * Get room terrain for the specified room. This method works for any room in the world even if you have no access to it. - * @param roomName String name of the room. + * Get a Room.Terrain object which provides fast access to static terrain data. + * This method works for any room in the world even if you have no access to it. */ getTerrain(): RoomTerrain; /**