From cbf1c491c0a50cf09be565ba6b1b5e5e53c93a94 Mon Sep 17 00:00:00 2001 From: Kristoffer Omdal Date: Tue, 17 Aug 2021 23:34:54 +0200 Subject: [PATCH 1/4] Game.GetObjectById support for union of Id's --- dist/index.d.ts | 3 ++- dist/screeps-tests.ts | 9 ++++++--- src/game.ts | 2 +- src/helpers.ts | 1 + 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/dist/index.d.ts b/dist/index.d.ts index aaf3ceac..2c1a49e4 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1567,7 +1567,7 @@ interface Game { * @param id The unique identifier. * @returns an object instance or null if it cannot be found. */ - getObjectById(id: Id): T | null; + getObjectById>(id: T): fromId | null; /** * Get an object with the specified unique ID. It may be a game object of any type. Only objects from the rooms which are visible to you can be accessed. @@ -2027,6 +2027,7 @@ declare namespace Tag { } } type Id = string & Tag.OpaqueTag; +type fromId = T extends Id ? R : never; /** * `InterShardMemory` object provides an interface for communicating between shards. * Your script is executed separatedly on each shard, and their `Memory` objects are isolated from each other. diff --git a/dist/screeps-tests.ts b/dist/screeps-tests.ts index acb05448..9d017cb9 100644 --- a/dist/screeps-tests.ts +++ b/dist/screeps-tests.ts @@ -51,9 +51,12 @@ function resources(o: GenericStore): ResourceConstant[] { } type StoreStructure = StructureContainer | StructureStorage | StructureLink; - const storeID: Id = "1234" as Id; // Strict assertion required - const stringID: string = storeID; // Id assignable implicitly to string - const storeObject = Game.getObjectById(storeID)!; + const storeUnionID: Id = "1234" as Id; // Strict assertion required + const storeIdUnion: StoreStructure["id"] = "1234" as StoreStructure["id"]; + const stringID: string = storeUnionID; // Id assignable implicitly to string + const stringID2: string = storeIdUnion; // Id assignable implicitly to string + const storeObject = Game.getObjectById(storeUnionID)!; + const storeObject2 = Game.getObjectById(storeIdUnion)!; // Object recognized switch (storeObject.structureType) { diff --git a/src/game.ts b/src/game.ts index b18165d0..35f686fc 100644 --- a/src/game.ts +++ b/src/game.ts @@ -72,7 +72,7 @@ interface Game { * @param id The unique identifier. * @returns an object instance or null if it cannot be found. */ - getObjectById(id: Id): T | null; + getObjectById>(id: T): fromId | null; /** * Get an object with the specified unique ID. It may be a game object of any type. Only objects from the rooms which are visible to you can be accessed. diff --git a/src/helpers.ts b/src/helpers.ts index 7284aab3..335d7f78 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -433,3 +433,4 @@ declare namespace Tag { } } type Id = string & Tag.OpaqueTag; +type fromId = T extends Id ? R : never; From a9b9488d1643286445ea29cde4fc5b7317533c50 Mon Sep 17 00:00:00 2001 From: Kristoffer Omdal Date: Wed, 18 Aug 2021 18:31:11 +0200 Subject: [PATCH 2/4] Add dtslint $ExpectType to tests --- dist/index.d.ts | 4 +- dist/screeps-tests.ts | 269 ++++++++++++++++++++++-------------------- src/game.ts | 2 +- src/map.ts | 2 +- 4 files changed, 148 insertions(+), 129 deletions(-) diff --git a/dist/index.d.ts b/dist/index.d.ts index 2c1a49e4..b3a34fdb 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1588,7 +1588,7 @@ interface Game { * @param groupInterval If set to 0 (default), the notification will be scheduled immediately. * Otherwise, it will be grouped with other notifications and mailed out later using the specified time in minutes. */ - notify(message: string, groupInterval?: number): undefined; + notify(message: string, groupInterval?: number): void; } declare var Game: Game; @@ -2762,7 +2762,7 @@ type EFFECT_COLLAPSE_TIMER = 1002; * The options that can be accepted by `findRoute()` and friends. */ interface RouteOptions { - routeCallback: (roomName: string, fromRoomName: string) => any; + routeCallback: (roomName: string, fromRoomName: string) => number; } interface RoomStatusPermanent { diff --git a/dist/screeps-tests.ts b/dist/screeps-tests.ts index 9d017cb9..5cb896d5 100644 --- a/dist/screeps-tests.ts +++ b/dist/screeps-tests.ts @@ -41,13 +41,14 @@ function resources(o: GenericStore): ResourceConstant[] { // Game object Id types { const creepId: Id = "1" as Id; - const creepOne: Creep | null = Game.getObjectById(creepId); - const creepTwo: Creep | null = Game.getObjectById("2"); // deprecated - const creepThree: Creep = new Creep(creepId); // Works with typed ID + const creepOne: Creep | null = Game.getObjectById(creepId); // $ExpectType Creep | null + const creepTwo: Creep | null = Game.getObjectById("2"); // deprecated $ExpectType Creep | null + // Works with typed ID + const creepThree: Creep = new Creep(creepId); // $ExpectType Creep if (creepOne) { - creepOne.hits; - const recycle = Game.getObjectById(creepOne.id); + creepOne.hits; // $ExpectType number + const recycle = Game.getObjectById(creepOne.id); // $ExpectType Creep | null } type StoreStructure = StructureContainer | StructureStorage | StructureLink; @@ -55,8 +56,8 @@ function resources(o: GenericStore): ResourceConstant[] { const storeIdUnion: StoreStructure["id"] = "1234" as StoreStructure["id"]; const stringID: string = storeUnionID; // Id assignable implicitly to string const stringID2: string = storeIdUnion; // Id assignable implicitly to string - const storeObject = Game.getObjectById(storeUnionID)!; - const storeObject2 = Game.getObjectById(storeIdUnion)!; + const storeObject = Game.getObjectById(storeUnionID)!; // $ExpectType StoreStructure + const storeObject2 = Game.getObjectById(storeIdUnion)!; // $ExpectType StructureContainer | StructureStorage | StructureLink // Object recognized switch (storeObject.structureType) { @@ -69,7 +70,7 @@ function resources(o: GenericStore): ResourceConstant[] { } // Default type is unknown if untyped Id provided - const untyped = Game.getObjectById("untyped"); + const untyped = Game.getObjectById("untyped"); // $ExpectType unknown } // Game.creeps @@ -92,7 +93,7 @@ function resources(o: GenericStore): ResourceConstant[] { PowerCreep.create("steve", POWER_CLASS.OPERATOR) === OK; for (const i in Game.powerCreeps) { - const powerCreep = Game.powerCreeps[i]; + const powerCreep = Game.powerCreeps[i]; // $ExpectType PowerCreep if (powerCreep.ticksToLive === undefined) { // Not spawned in world; spawn creep @@ -109,7 +110,7 @@ function resources(o: GenericStore): ResourceConstant[] { } else { // Boost resource const targetSource = Game.getObjectById("targetSourceID") as Source; - const sourceEffect = targetSource.effects.find(effect => effect.effect === PWR_REGEN_SOURCE && effect.level > 0); + const sourceEffect = targetSource.effects.find(effect => effect.effect === PWR_REGEN_SOURCE && effect.level > 0); // $ExpectType RoomObjectEffect | undefined if (!sourceEffect && powerCreep.powers[PWR_REGEN_SOURCE] && powerCreep.powers[PWR_REGEN_SOURCE].cooldown === 0) { powerCreep.usePower(PWR_REGEN_SOURCE, targetSource); } @@ -128,7 +129,7 @@ function resources(o: GenericStore): ResourceConstant[] { powerCreep.upgrade(PWR_GENERATE_OPS); } - const myPowaCreeps = Game.rooms.sim.find(FIND_MY_POWER_CREEPS); + const myPowaCreeps = Game.rooms.sim.find(FIND_MY_POWER_CREEPS); // $ExpectType PowerCreep[] // Constant type checking POWER_INFO[PWR_GENERATE_OPS].className === POWER_CLASS.OPERATOR; @@ -142,24 +143,24 @@ function resources(o: GenericStore): ResourceConstant[] { Game.spawns[i].createCreep(body); // Test StructureSpawn.Spawning - let creep: Spawning | null = Game.spawns[i].spawning; + let creep = Game.spawns[i].spawning; // $ExpectType Spawning | null if (creep) { - const name: string = creep.name; - const needTime: number = creep.needTime; - const remainingTime: number = creep.remainingTime; - const creepSpawn: StructureSpawn = creep.spawn; + const name: string = creep.name; // $ExpectType string + const needTime: number = creep.needTime; // $ExpectType number + const remainingTime: number = creep.remainingTime; // $ExpectType number + const creepSpawn: StructureSpawn = creep.spawn; // $ExpectType StructureSpawn const cancelStatus: OK | ERR_NOT_OWNER = creep.cancel(); const setDirectionStatus: OK | ERR_NOT_OWNER | ERR_INVALID_ARGS = creep.setDirections([TOP, BOTTOM, LEFT, RIGHT]); } - creep = new StructureSpawn.Spawning("" as Id); - creep = StructureSpawn.Spawning("" as Id); + creep = new StructureSpawn.Spawning("" as Id); // $ExpectType Spawning + creep = StructureSpawn.Spawning("" as Id); // $ExpectType Spawning const invaderCore = new StructureInvaderCore("" as Id); - const invader = invaderCore.spawning; + const invader = invaderCore.spawning; // $ExpectType Spawning | null if (invader) { - const name = invader.name; + const name = invader.name; // $ExpectType string } } } @@ -167,7 +168,7 @@ function resources(o: GenericStore): ResourceConstant[] { // Game.time { - let time = Game.time; + let time = Game.time; // $ExpectType number time += 1; } @@ -181,11 +182,11 @@ function resources(o: GenericStore): ResourceConstant[] { { for (const name in Game.creeps) { - const startCpu = Game.cpu.getUsed(); + const startCpu = Game.cpu.getUsed(); // $ExpectType number // creep logic goes here - const elapsed = Game.cpu.getUsed() - startCpu; + const elapsed = Game.cpu.getUsed() - startCpu; // $ExpectType number } } @@ -198,7 +199,7 @@ function resources(o: GenericStore): ResourceConstant[] { // Game.cpu.halt() { if (Game.cpu.hasOwnProperty("halt")) { - Game.cpu.halt!(); + Game.cpu.halt!(); // $ExpectType never } } @@ -217,17 +218,17 @@ function resources(o: GenericStore): ResourceConstant[] { // Game.getObjectById(id) { - creep.memory.sourceId = creep.pos.findClosestByRange(FIND_SOURCES)!.id; - const source = Game.getObjectById(creep.memory.sourceId); + creep.memory.sourceId = creep.pos.findClosestByRange(FIND_SOURCES)!.id; // $ExpectType Id + const source = Game.getObjectById(creep.memory.sourceId); // $ExpectType Source | null } // Game.notify(message, [groupInterval]) { if (creep.hits < creep.memory.lastHits) { - Game.notify(`Creep ${creep} has been attacked at ${creep.pos}!`); + Game.notify(`Creep ${creep} has been attacked at ${creep.pos}!`); // $ExpectType void } - creep.memory.lastHits = creep.hits; + creep.memory.lastHits = creep.hits; // $ExpectType number } { @@ -242,12 +243,12 @@ function resources(o: GenericStore): ResourceConstant[] { // Game.map.describeExits() { - const exits = Game.map.describeExits("W8N3"); + const exits: ExitsInformation = Game.map.describeExits("W8N3"); // $ExpectType ExitsInformation // tslint:disable-next-line:newline-per-chained-call keys(exits).map(exitKey => { - const nextRoom = exits[exitKey]; + const nextRoom = exits[exitKey]; // $ExpectType string | undefined const exitDir = +exitKey as ExitConstant; - const exitPos = creep.pos.findClosestByRange(exitDir); + const exitPos = creep.pos.findClosestByRange(exitDir); // $ExpectType RoomPosition | null return { nextRoom, exitPos }; }); } @@ -258,7 +259,7 @@ function resources(o: GenericStore): ResourceConstant[] { if (creep.room !== anotherRoomName) { const exitDir = Game.map.findExit(creep.room, anotherRoomName); if (exitDir !== ERR_NO_PATH && exitDir !== ERR_INVALID_ARGS) { - const exit = creep.pos.findClosestByRange(exitDir); + const exit = creep.pos.findClosestByRange(exitDir); // $ExpectType RoomPosition | null if (exit !== null) { creep.moveTo(exit); } @@ -275,10 +276,10 @@ function resources(o: GenericStore): ResourceConstant[] { // Game.map.findRoute() { - const route = Game.map.findRoute(creep.room, anotherRoomName); + const route = Game.map.findRoute(creep.room, anotherRoomName); // $ExpectType -2 | { exit: ExitConstant; room: string; }[] if (route !== ERR_NO_PATH && route.length > 0) { - const exit = creep.pos.findClosestByRange(route[0].exit); + const exit = creep.pos.findClosestByRange(route[0].exit); // $ExpectType RoomPosition | null if (exit !== null) { creep.moveTo(exit); } @@ -287,6 +288,7 @@ function resources(o: GenericStore): ResourceConstant[] { { const route = Game.map.findRoute(creep.room, anotherRoomName, { + // $ExpectType -2 | { exit: ExitConstant; room: string; }[] routeCallback(roomName, fromRoomName) { if (roomName === "W10S10") { // avoid this room @@ -305,6 +307,7 @@ function resources(o: GenericStore): ResourceConstant[] { // prioritizing highways and owned rooms const allowedRooms = { [from.roomName]: true }; const route = Game.map.findRoute(from.roomName, to.roomName, { + // $ExpectType -2 | { exit: ExitConstant; room: string; }[] routeCallback(roomName) { const parsed = /^[WE]([0-9]+)[NS]([0-9]+)$/.exec(roomName); if (parsed !== null) { @@ -329,6 +332,7 @@ function resources(o: GenericStore): ResourceConstant[] { // Invoke PathFinder, allowing access only to rooms from `findRoute` const ret = PathFinder.search(from, [to], { + // $ExpectType PathFinderPath roomCallback: roomName => { if (allowedRooms[roomName] === undefined) { return false; @@ -342,7 +346,7 @@ function resources(o: GenericStore): ResourceConstant[] { // Game.map.getRoomLinearDistance(roomName1, roomName2, [continuous]) { - Game.map.getRoomLinearDistance("W1N1", "W4N2"); // 3 + Game.map.getRoomLinearDistance("W1N1", "W4N2"); // 3 $ExpectType number Game.map.getRoomLinearDistance("E65S55", "W65S55", false); // 131 Game.map.getRoomLinearDistance("E65S55", "W65S55", true); // 11 } @@ -351,17 +355,17 @@ function resources(o: GenericStore): ResourceConstant[] { // Game.map.getTerrainAt(pos) { - Game.map.getTerrainAt(25, 20, "W10N10"); + Game.map.getTerrainAt(25, 20, "W10N10"); // $ExpectType Terrain } { - Game.map.getTerrainAt(new RoomPosition(25, 20, "W10N10")); + Game.map.getTerrainAt(new RoomPosition(25, 20, "W10N10")); // $ExpectType Terrain } // Game.map.getRoomStatus(roomName) { - const roomStatus = Game.map.getRoomStatus(room.name); + const roomStatus = Game.map.getRoomStatus(room.name); // $ExpectType RoomStatus if (roomStatus.status === "normal") { creep.moveTo(room.getPositionAt(25, 25)!); } @@ -371,47 +375,48 @@ function resources(o: GenericStore): ResourceConstant[] { { // Game.market.calcTransactionCost(amount, roomName1, roomName2) - const cost = Game.market.calcTransactionCost(1000, "W0N0", "W10N5"); + const cost = Game.market.calcTransactionCost(1000, "W0N0", "W10N5"); // $ExpectType number // Game.market.cancelOrder(orderId) for (const id in Game.market.orders) { - Game.market.cancelOrder(id); + Game.market.cancelOrder(id); // $ExpectType ScreepsReturnCode } // Game.market.changeOrderPrice(orderId, newPrice) - Game.market.changeOrderPrice("57bec1bf77f4d17c4c011960", 9.95); + Game.market.changeOrderPrice("57bec1bf77f4d17c4c011960", 9.95); // $ExpectType ScreepsReturnCode // Game.market.createOrder({type, resourceType, price, totalAmount, [roomName]}) - Game.market.createOrder({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM, price: 9.95, totalAmount: 10000, roomName: "W1N1" }); - Game.market.createOrder({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM, price: 9.95, totalAmount: 10000 }); + Game.market.createOrder({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM, price: 9.95, totalAmount: 10000, roomName: "W1N1" }); // $ExpectType ScreepsReturnCode + Game.market.createOrder({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM, price: 9.95, totalAmount: 10000 }); // $ExpectType ScreepsReturnCode // Game.market.deal(orderId, amount, [yourRoomName]) - Game.market.deal("57cd2b12cda69a004ae223a3", 1000, "W1N1"); + Game.market.deal("57cd2b12cda69a004ae223a3", 1000, "W1N1"); // $ExpectType ScreepsReturnCode const amountToBuy = 2000; const maxTransferEnergyCost = 500; - const orders = Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); + const orders = Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); // $ExpectType Order[] for (const i of orders) { if (i.roomName) { - const transferEnergyCost = Game.market.calcTransactionCost(amountToBuy, "W1N1", i.roomName); + const transferEnergyCost = Game.market.calcTransactionCost(amountToBuy, "W1N1", i.roomName); // $ExpectType number if (transferEnergyCost < maxTransferEnergyCost) { - Game.market.deal(i.id, amountToBuy, "W1N1"); + Game.market.deal(i.id, amountToBuy, "W1N1"); // $ExpectType ScreepsReturnCode break; } } } // Game.market.extendOrder(orderId, addAmount) - Game.market.extendOrder("57bec1bf77f4d17c4c011960", 10000); + Game.market.extendOrder("57bec1bf77f4d17c4c011960", 10000); // $ExpectType ScreepsReturnCode // Game.market.getAllOrders([filter]) - Game.market.getAllOrders(); - Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); + Game.market.getAllOrders(); // $ExpectType Order[] + Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); // $ExpectType Order[] const targetRoom = "W1N1"; Game.market.getAllOrders( + // $ExpectType Order[] currentOrder => currentOrder.resourceType === RESOURCE_GHODIUM && currentOrder.type === ORDER_SELL && @@ -419,27 +424,26 @@ function resources(o: GenericStore): ResourceConstant[] { ); // Game.market.getOrderById(id) - const order = Game.market.getOrderById("55c34a6b5be41a0a6e80c123"); + const order = Game.market.getOrderById("55c34a6b5be41a0a6e80c123"); // $ExpectType Order | null // Subscription tokens - Game.market.getAllOrders({ type: ORDER_SELL, resourceType: SUBSCRIPTION_TOKEN }); - Game.market.createOrder({ type: ORDER_BUY, resourceType: SUBSCRIPTION_TOKEN, totalAmount: 10000000, price: 1 }); - - const priceHistory = Game.market.getHistory(RESOURCE_FIXTURES); + Game.market.getAllOrders({ type: ORDER_SELL, resourceType: SUBSCRIPTION_TOKEN }); // $ExpectType Order[] + Game.market.createOrder({ type: ORDER_BUY, resourceType: SUBSCRIPTION_TOKEN, totalAmount: 10000000, price: 1 }); // $ExpectType ScreepsReturnCode + const priceHistory = Game.market.getHistory(RESOURCE_FIXTURES); // $ExpectType PriceHistory[] const avgPrice: number = priceHistory[0].avgPrice; const stddevPrice: number = priceHistory[0].stddevPrice; const volume: number = priceHistory[0].volume; // Game.market.getHistory([resourceType]) - const energyHistory = Game.market.getHistory(RESOURCE_ENERGY); - const pixelHistory = Game.market.getHistory(PIXEL); + const energyHistory = Game.market.getHistory(RESOURCE_ENERGY); // $ExpectType PriceHistory[] + const pixelHistory = Game.market.getHistory(PIXEL); // $ExpectType PriceHistory[] } // PathFinder { - const pfCreep = Game.creeps.John; + const pfCreep = Game.creeps.John; // $ExpectType Creep // tslint:disable-next-line:newline-per-chained-call const goals = pfCreep.room.find(FIND_SOURCES).map(source => { @@ -449,13 +453,15 @@ function resources(o: GenericStore): ResourceConstant[] { }); const ret = PathFinder.search(pfCreep.pos, goals, { + // $ExpectType PathFinderPath // 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]; + const curRoom = Game.rooms[roomName]; // $ExpectType Room + // In this example `room` will always exist, but since // PathFinder supports searches which span multiple rooms // you should be careful! @@ -488,7 +494,7 @@ function resources(o: GenericStore): ResourceConstant[] { }, }); - const pos = ret.path[0]; + const pos = ret.path[0]; // $ExpectType RoomPosition pfCreep.move(pfCreep.pos.getDirectionTo(pos)); } @@ -562,25 +568,26 @@ function resources(o: GenericStore): ResourceConstant[] { // Find Overloads { - const creeps = room.find(FIND_HOSTILE_CREEPS); + const creeps = room.find(FIND_HOSTILE_CREEPS); // $ExpectType Creep[] creeps[0].say(creeps[1].name); - const flags = room.find(FIND_FLAGS); + const flags = room.find(FIND_FLAGS); // $ExpectType Flag[] flags[0].remove(); - const spawns = room.find(FIND_HOSTILE_SPAWNS); + const spawns = room.find(FIND_HOSTILE_SPAWNS); // $ExpectType StructureSpawn[] spawns[0].spawning; - const sources = room.find(FIND_SOURCES); + const sources = room.find(FIND_SOURCES); // $ExpectType Source[] sources[0].ticksToRegeneration; - const resources = room.find(FIND_DROPPED_RESOURCES); + const resources = room.find(FIND_DROPPED_RESOURCES); // $ExpectType Resource[] resources[0].resourceType; - const sites = room.find(FIND_CONSTRUCTION_SITES); + const sites = room.find(FIND_CONSTRUCTION_SITES); // $ExpectType ConstructionSite[] sites[0].remove(); const extensionsites = room.find(FIND_CONSTRUCTION_SITES, { + // $ExpectType ConstructionSite<"extension">[] filter: (site): site is ConstructionSite => { return site.structureType === STRUCTURE_EXTENSION; }, @@ -589,12 +596,13 @@ function resources(o: GenericStore): ResourceConstant[] { extensionsites[0].structureType === STRUCTURE_EXTENSION; // Should have type (_HasRoomPosition | RoomPosition)[] - const exits = room.find(FIND_EXIT); + const exits = room.find(FIND_EXIT); // $ExpectType RoomPosition[] - const creepsHere = room.lookForAt(LOOK_CREEPS, 10, 10); + const creepsHere = room.lookForAt(LOOK_CREEPS, 10, 10); // $ExpectType Creep[] creepsHere[0].getActiveBodyparts(ATTACK); const towers = room.find(FIND_MY_STRUCTURES, { + // $ExpectType StructureTower[] filter: structure => { return structure.structureType === STRUCTURE_TOWER; }, @@ -610,6 +618,7 @@ function resources(o: GenericStore): ResourceConstant[] { }; const tower = room.find(FIND_MY_STRUCTURES, { + // $ExpectType StructureTower filter: isTower, })[0]; tower.attack(creeps[0]); @@ -623,12 +632,13 @@ function resources(o: GenericStore): ResourceConstant[] { { // Should have type Creep - const hostileCreep = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS); + const hostileCreep = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS); // $ExpectType Creep | null if (hostileCreep !== null) { creep.say(hostileCreep.name); } const tower = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { + // $ExpectType StructureTower | null filter: structure => { return structure.structureType === STRUCTURE_TOWER; }, @@ -647,6 +657,7 @@ function resources(o: GenericStore): ResourceConstant[] { }; const tower2 = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { + // $ExpectType StructureTower | null filter: isStructureType(STRUCTURE_TOWER), algorithm: "astar", }); @@ -655,13 +666,14 @@ function resources(o: GenericStore): ResourceConstant[] { tower2.attack(powerCreep); } - const creepWithEnergy = creep.pos.findClosestByPath(creep.room.find(FIND_CREEPS), { filter: c => c.store.energy > 0 }); + const creepWithEnergy = creep.pos.findClosestByPath(creep.room.find(FIND_CREEPS), { filter: c => c.store.energy > 0 }); // $ExpectType Creep | null const creepAbove = creep.pos.findClosestByPath(creep.room.find(FIND_CREEPS).map(c => c.pos), { filter: p => p.getDirectionTo(creep) === TOP, }); const rampart = creep.pos.findClosestByRange(FIND_HOSTILE_STRUCTURES, { + // $ExpectType StructureRampart | null filter: structure => { return structure.structureType === STRUCTURE_RAMPART; }, @@ -671,10 +683,11 @@ function resources(o: GenericStore): ResourceConstant[] { } // Should have type Creep[] - const hostileCreeps = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 10); + const hostileCreeps = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 10); // $ExpectType Creep[] hostileCreeps[0].saying; const labs = creep.pos.findInRange(FIND_MY_STRUCTURES, 4, { + // $ExpectType StructureLab[] filter: structure => { return structure.structureType === STRUCTURE_LAB; }, @@ -686,7 +699,7 @@ function resources(o: GenericStore): ResourceConstant[] { // LookAt Finds { - const matrix = room.lookAtArea(10, 10, 20, 20, false); + const matrix = room.lookAtArea(10, 10, 20, 20, false); // $ExpectType LookAtResultMatrix for (const y in matrix) { const row = matrix[y]; for (const x in row) { @@ -698,18 +711,18 @@ function resources(o: GenericStore): ResourceConstant[] { } } - const nukes = room.lookForAt(LOOK_NUKES, creep.pos); + const nukes = room.lookForAt(LOOK_NUKES, creep.pos); // $ExpectType Nuke[] nukes[0].launchRoomName; - const flags = room.lookForAtArea(LOOK_FLAGS, 10, 10, 20, 20); + const flags = room.lookForAtArea(LOOK_FLAGS, 10, 10, 20, 20); // $ExpectType LookForAtAreaResultMatrix const x = flags[10]; const y = x[11]; const entry = y[0]; entry.flag.remove(); - const creeps = room.lookForAtArea(LOOK_CREEPS, 10, 10, 20, 20, true); + const creeps = room.lookForAtArea(LOOK_CREEPS, 10, 10, 20, 20, true); // $ExpectType LookForAtAreaResultArray creeps[0].x; creeps[0].y; @@ -726,29 +739,29 @@ function resources(o: GenericStore): ResourceConstant[] { const extension = new StructureExtension("" as Id); - const e1: number = extension.store.getUsedCapacity(RESOURCE_ENERGY); - const e2: number = extension.store[RESOURCE_ENERGY]; + const e1: number = extension.store.getUsedCapacity(RESOURCE_ENERGY); // $ExpectType number + const e2: number = extension.store[RESOURCE_ENERGY]; // $ExpectType number // Invalid resource type for extension - const eg1: null = extension.store.getUsedCapacity(RESOURCE_GHODIUM); - const eg2: null = extension.store.getFreeCapacity(RESOURCE_GHODIUM); - const eg3: null = extension.store.getCapacity(RESOURCE_GHODIUM); - const eg4: 0 = extension.store.G; + const eg1: null = extension.store.getUsedCapacity(RESOURCE_GHODIUM); // $ExpectType null + const eg2: null = extension.store.getFreeCapacity(RESOURCE_GHODIUM); // $ExpectType null + const eg3: null = extension.store.getCapacity(RESOURCE_GHODIUM); // $ExpectType null + const eg4: 0 = extension.store.G; // $ExpectType 0 const storage = new StructureStorage("" as Id); - const sg1: number = storage.store.getUsedCapacity(RESOURCE_GHODIUM); - const sg2: number = storage.store.getFreeCapacity(RESOURCE_GHODIUM); - const sg3: number = storage.store.getCapacity(RESOURCE_GHODIUM); + const sg1: number = storage.store.getUsedCapacity(RESOURCE_GHODIUM); // $ExpectType number + const sg2: number = storage.store.getFreeCapacity(RESOURCE_GHODIUM); // $ExpectType number + const sg3: number = storage.store.getCapacity(RESOURCE_GHODIUM); // $ExpectType number } // Advanced Structure types { - const owned = Game.getObjectById("blah")!; - const owner = owned.owner && owned.owner.username; + const owned = Game.getObjectById("blah")!; // $ExpectType AnyOwnedStructure + const owner = owned.owner && owned.owner.username; // $ExpectType string | undefined owned.notifyWhenAttacked(false); - const structs = room.find(FIND_MY_STRUCTURES); + const structs = room.find(FIND_MY_STRUCTURES); // $ExpectType AnyOwnedStructure[] structs.forEach(struct => { switch (struct.structureType) { case STRUCTURE_CONTROLLER: @@ -760,17 +773,19 @@ function resources(o: GenericStore): ResourceConstant[] { } }); - const unowned = Game.getObjectById("blah2")!; + const unowned = Game.getObjectById("blah2")!; // $ExpectType AnyStructure const hp = unowned.hits / unowned.hitsMax; // test discriminated union switch (unowned.structureType) { case STRUCTURE_TOWER: + unowned; // $ExpectType StructureTower unowned.heal(Game.creeps.myCreep); break; case STRUCTURE_CONTAINER: case STRUCTURE_STORAGE: case STRUCTURE_TERMINAL: + unowned.store; // $ExpectType StoreDefinition const energyPercent = unowned.store.energy / unowned.storeCapacity; break; case STRUCTURE_WALL: @@ -796,24 +811,25 @@ function resources(o: GenericStore): ResourceConstant[] { { // Test that you can use signatures - EXTENSION_ENERGY_CAPACITY[Game.rooms.myRoom.controller!.level]; + EXTENSION_ENERGY_CAPACITY[Game.rooms.myRoom.controller!.level]; // $ExpectType number - REACTIONS[Object.keys(creep.carry)[0]]; + REACTIONS[Object.keys(creep.carry)[0]]; // $ExpectType { [resource: string]: string; } - BOOSTS[creep.body[0].type]; + BOOSTS[creep.body[0].type as string]; // $ExpectType { [boost: string]: { [action: string]: number; }; } } // Tombstones { - const tombstone = room.find(FIND_TOMBSTONES)[0]; + const tombstone = room.find(FIND_TOMBSTONES)[0]; // $ExpectType Tombstone + tombstone.creep; // $ExpectType AnyCreep (tombstone.creep as PowerCreep).spawnCooldownTime; (tombstone.creep as Creep).my; - tombstone.store.energy; + tombstone.store; // $ExpectType StoreDefinitionUnlimited - tombstone.id; + tombstone.id; // $ExpectType Id const creep = Game.creeps["dave"]; creep.withdraw(tombstone, RESOURCE_ENERGY); @@ -822,7 +838,10 @@ function resources(o: GenericStore): ResourceConstant[] { // Ruin { - const ruin = room.find(FIND_RUINS)[0]; + const ruin = room.find(FIND_RUINS)[0]; // $ExpectType Ruin + + ruin.store; // $ExpectType StoreDefinitionUnlimited + ruin.structure; // $ExpectType AnyStructure creep.withdraw(ruin, RESOURCE_ENERGY); powerCreep.withdraw(ruin, RESOURCE_ENERGY); @@ -838,7 +857,7 @@ function resources(o: GenericStore): ResourceConstant[] { // 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 }); // $ExpectType StructurePortal[] portals.forEach((p: StructurePortal) => { const state = p.ticksToDecay === undefined ? "stable" : "unstable"; if (p.destination instanceof RoomPosition) { @@ -852,14 +871,14 @@ function resources(o: GenericStore): ResourceConstant[] { // ConstructionSite { - room.createConstructionSite(10, 10, STRUCTURE_EXTENSION); - room.createConstructionSite(10, 11, STRUCTURE_SPAWN, "mySpawn"); + room.createConstructionSite(10, 10, STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode + room.createConstructionSite(10, 11, STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode const pos = new RoomPosition(10, 10, room.name); - room.createConstructionSite(pos, STRUCTURE_EXTENSION); - room.createConstructionSite(pos, STRUCTURE_SPAWN, "mySpawn"); - pos.createConstructionSite(STRUCTURE_EXTENSION); - pos.createConstructionSite(STRUCTURE_SPAWN, "mySpawn"); + room.createConstructionSite(pos, STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode + room.createConstructionSite(pos, STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode + pos.createConstructionSite(STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode + pos.createConstructionSite(STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode } // StructureLab @@ -870,32 +889,32 @@ function resources(o: GenericStore): ResourceConstant[] { 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) { - lab0.runReaction(lab1, lab2); + lab0.runReaction(lab1, lab2); // $ExpectType ScreepsReturnCode } // nevermind, reverse that - lab0.reverseReaction(lab1, lab2); + lab0.reverseReaction(lab1, lab2); // $ExpectType ScreepsReturnCode } } // Room event log { - room.getEventLog(); - room.getEventLog(true); + room.getEventLog(); // $ExpectType EventItem[] + room.getEventLog(true); // $ExpectType EventItem[] - const events = room.getEventLog(); + const events = room.getEventLog(); // $ExpectType EventItem[] - const event = events[0]; + const event = events[0]; // $ExpectType EventItem switch (event.event) { case EVENT_ATTACK: - const attackType: EventAttackType = event.data.attackType; + const attackType: EventAttackType = event.data.attackType; // $ExpectType EventAttackType break; case EVENT_BUILD: - const energySpent: number = event.data.energySpent; + const energySpent: number = event.data.energySpent; // $ExpectTypenumber break; case EVENT_POWER: - const power = event.data.power; + const power = event.data.power; // $ExpectType PowerConstant break; } } @@ -905,7 +924,7 @@ function resources(o: GenericStore): ResourceConstant[] { { const room = Game.rooms[""]; - const myTerrain = room.getTerrain(); + const myTerrain = room.getTerrain(); // $ExpectType RoomTerrain const ret = myTerrain.get(5, 5); if (ret === 0) { @@ -918,7 +937,7 @@ function resources(o: GenericStore): ResourceConstant[] { /*wall*/ } - const enemyTerrain = new Room.Terrain("W2N5"); + const enemyTerrain = new Room.Terrain("W2N5"); // $ExpectType RoomTerrain } // Creep.body @@ -944,15 +963,15 @@ function atackPower(creep: Creep) { creep.transfer(factory, RESOURCE_LEMERGIUM_BAR, 16); creep.transfer(factory, RESOURCE_ENERGY, 8); - factory.produce(RESOURCE_PHLEGM); + factory.produce(RESOURCE_PHLEGM); // $ExpectType ScreepsReturnCode - factory.produce(RESOURCE_BATTERY); - factory.produce(RESOURCE_ENERGY); + factory.produce(RESOURCE_BATTERY); // $ExpectType ScreepsReturnCode + factory.produce(RESOURCE_ENERGY); // $ExpectType ScreepsReturnCode - factory.produce(RESOURCE_GHODIUM); - factory.produce(RESOURCE_GHODIUM_MELT); + factory.produce(RESOURCE_GHODIUM); // $ExpectType ScreepsReturnCode + factory.produce(RESOURCE_GHODIUM_MELT); // $ExpectType ScreepsReturnCode - creep.withdraw(factory, RESOURCE_PHLEGM); + creep.withdraw(factory, RESOURCE_PHLEGM); // $ExpectType ScreepsReturnCode // Energy and ghodium commodities COMMODITIES[RESOURCE_ENERGY]; @@ -1008,12 +1027,12 @@ function atackPower(creep: Creep) { // Horse armor!Pixels! { - const ret: OK | ERR_NOT_ENOUGH_RESOURCES | ERR_FULL = Game.cpu.generatePixel(); + const ret: OK | ERR_NOT_ENOUGH_RESOURCES = Game.cpu.generatePixel(); // $ExpectType 0 | -6 } // Game.map.visual { - const mapVis = Game.map.visual; + const mapVis = Game.map.visual; // $ExpectType MapVisual const point1 = new RoomPosition(1, 1, "E1N1"); const point2 = new RoomPosition(1, 1, "E1N8"); const point3 = new RoomPosition(1, 1, "E8N8"); @@ -1025,9 +1044,9 @@ function atackPower(creep: Creep) { .poly([point1, point2, point3, point4]) .rect(point3, 50, 50); - const size: number = mapVis.getSize(); + const size: number = mapVis.getSize(); // $ExpectType number - const visData = mapVis.export(); - mapVis.clear(); - mapVis.import(visData); + const visData = mapVis.export(); // $ExpectType string + mapVis.clear(); // $ExpectType MapVisual + mapVis.import(visData); // $ExpectType MapVisual } diff --git a/src/game.ts b/src/game.ts index 35f686fc..c6f29cf7 100644 --- a/src/game.ts +++ b/src/game.ts @@ -93,7 +93,7 @@ interface Game { * @param groupInterval If set to 0 (default), the notification will be scheduled immediately. * Otherwise, it will be grouped with other notifications and mailed out later using the specified time in minutes. */ - notify(message: string, groupInterval?: number): undefined; + notify(message: string, groupInterval?: number): void; } declare var Game: Game; diff --git a/src/map.ts b/src/map.ts index 53f4d4fd..9d33dc19 100644 --- a/src/map.ts +++ b/src/map.ts @@ -2,7 +2,7 @@ * The options that can be accepted by `findRoute()` and friends. */ interface RouteOptions { - routeCallback: (roomName: string, fromRoomName: string) => any; + routeCallback: (roomName: string, fromRoomName: string) => number; } interface RoomStatusPermanent { From 8413bc29eeee4d8d5bbfe433da48f49887ed5bcc Mon Sep 17 00:00:00 2001 From: Kristoffer Omdal Date: Wed, 18 Aug 2021 18:36:03 +0200 Subject: [PATCH 3/4] formatting fixes --- dist/screeps-tests.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dist/screeps-tests.ts b/dist/screeps-tests.ts index 5cb896d5..6f980331 100644 --- a/dist/screeps-tests.ts +++ b/dist/screeps-tests.ts @@ -287,8 +287,8 @@ function resources(o: GenericStore): ResourceConstant[] { } { + // $ExpectType -2 | { exit: ExitConstant; room: string; }[] const route = Game.map.findRoute(creep.room, anotherRoomName, { - // $ExpectType -2 | { exit: ExitConstant; room: string; }[] routeCallback(roomName, fromRoomName) { if (roomName === "W10S10") { // avoid this room @@ -306,8 +306,8 @@ function resources(o: GenericStore): ResourceConstant[] { // Use `findRoute` to calculate a high-level plan for this path, // prioritizing highways and owned rooms const allowedRooms = { [from.roomName]: true }; + // $ExpectType -2 | { exit: ExitConstant; room: string; }[] const route = Game.map.findRoute(from.roomName, to.roomName, { - // $ExpectType -2 | { exit: ExitConstant; room: string; }[] routeCallback(roomName) { const parsed = /^[WE]([0-9]+)[NS]([0-9]+)$/.exec(roomName); if (parsed !== null) { @@ -331,8 +331,8 @@ function resources(o: GenericStore): ResourceConstant[] { } // Invoke PathFinder, allowing access only to rooms from `findRoute` + // $ExpectType PathFinderPath const ret = PathFinder.search(from, [to], { - // $ExpectType PathFinderPath roomCallback: roomName => { if (allowedRooms[roomName] === undefined) { return false; @@ -415,8 +415,8 @@ function resources(o: GenericStore): ResourceConstant[] { Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); // $ExpectType Order[] const targetRoom = "W1N1"; + // $ExpectType Order[] Game.market.getAllOrders( - // $ExpectType Order[] currentOrder => currentOrder.resourceType === RESOURCE_GHODIUM && currentOrder.type === ORDER_SELL && @@ -452,8 +452,8 @@ function resources(o: GenericStore): ResourceConstant[] { return { pos: source.pos, range: 1 }; }); + // $ExpectType PathFinderPath const ret = PathFinder.search(pfCreep.pos, goals, { - // $ExpectType PathFinderPath // We need to set the defaults costs higher so that we // can set the road cost lower in `roomCallback` plainCost: 2, @@ -586,8 +586,8 @@ function resources(o: GenericStore): ResourceConstant[] { const sites = room.find(FIND_CONSTRUCTION_SITES); // $ExpectType ConstructionSite[] sites[0].remove(); + // $ExpectType ConstructionSite<"extension">[] const extensionsites = room.find(FIND_CONSTRUCTION_SITES, { - // $ExpectType ConstructionSite<"extension">[] filter: (site): site is ConstructionSite => { return site.structureType === STRUCTURE_EXTENSION; }, @@ -601,8 +601,8 @@ function resources(o: GenericStore): ResourceConstant[] { const creepsHere = room.lookForAt(LOOK_CREEPS, 10, 10); // $ExpectType Creep[] creepsHere[0].getActiveBodyparts(ATTACK); + // $ExpectType StructureTower[] const towers = room.find(FIND_MY_STRUCTURES, { - // $ExpectType StructureTower[] filter: structure => { return structure.structureType === STRUCTURE_TOWER; }, @@ -617,8 +617,8 @@ function resources(o: GenericStore): ResourceConstant[] { return structure.structureType === STRUCTURE_TOWER; }; + // $ExpectType StructureTower const tower = room.find(FIND_MY_STRUCTURES, { - // $ExpectType StructureTower filter: isTower, })[0]; tower.attack(creeps[0]); @@ -637,8 +637,8 @@ function resources(o: GenericStore): ResourceConstant[] { creep.say(hostileCreep.name); } + // $ExpectType StructureTower | null const tower = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { - // $ExpectType StructureTower | null filter: structure => { return structure.structureType === STRUCTURE_TOWER; }, @@ -656,8 +656,8 @@ function resources(o: GenericStore): ResourceConstant[] { }; }; + // $ExpectType StructureTower | null const tower2 = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { - // $ExpectType StructureTower | null filter: isStructureType(STRUCTURE_TOWER), algorithm: "astar", }); @@ -672,8 +672,8 @@ function resources(o: GenericStore): ResourceConstant[] { filter: p => p.getDirectionTo(creep) === TOP, }); + // $ExpectType StructureRampart | null const rampart = creep.pos.findClosestByRange(FIND_HOSTILE_STRUCTURES, { - // $ExpectType StructureRampart | null filter: structure => { return structure.structureType === STRUCTURE_RAMPART; }, @@ -686,8 +686,8 @@ function resources(o: GenericStore): ResourceConstant[] { const hostileCreeps = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 10); // $ExpectType Creep[] hostileCreeps[0].saying; + // $ExpectType StructureLab[] const labs = creep.pos.findInRange(FIND_MY_STRUCTURES, 4, { - // $ExpectType StructureLab[] filter: structure => { return structure.structureType === STRUCTURE_LAB; }, From dae2af2f3834f18494d447c1a5af20b21ccf4e33 Mon Sep 17 00:00:00 2001 From: Kristoffer Omdal Date: Wed, 18 Aug 2021 22:51:04 +0200 Subject: [PATCH 4/4] Split tests into multiple files --- dist/screeps-tests.ts | 1044 --------------------------------- dist/tests/Tombs_Ruins.ts | 28 + dist/tests/constants.ts | 8 + dist/tests/creep.ts | 61 ++ dist/tests/factory.ts | 71 +++ dist/tests/find.ts | 163 +++++ dist/tests/game-object-ids.ts | 34 ++ dist/tests/game.cpu.ts | 54 ++ dist/tests/game.map.ts | 151 +++++ dist/tests/game.market.ts | 68 +++ dist/tests/game.ts | 45 ++ dist/tests/helpers.ts | 30 + dist/tests/memory.ts | 66 +++ dist/tests/pathfinder.ts | 57 ++ dist/tests/room.ts | 56 ++ dist/tests/store.ts | 25 + dist/tests/structure.ts | 67 +++ dist/tests/structureLab.ts | 14 + dist/tests/structureSpawn.ts | 28 + dist/tsconfig.json | 3 + 20 files changed, 1029 insertions(+), 1044 deletions(-) create mode 100644 dist/tests/Tombs_Ruins.ts create mode 100644 dist/tests/constants.ts create mode 100644 dist/tests/creep.ts create mode 100644 dist/tests/factory.ts create mode 100644 dist/tests/find.ts create mode 100644 dist/tests/game-object-ids.ts create mode 100644 dist/tests/game.cpu.ts create mode 100644 dist/tests/game.map.ts create mode 100644 dist/tests/game.market.ts create mode 100644 dist/tests/game.ts create mode 100644 dist/tests/helpers.ts create mode 100644 dist/tests/memory.ts create mode 100644 dist/tests/pathfinder.ts create mode 100644 dist/tests/room.ts create mode 100644 dist/tests/store.ts create mode 100644 dist/tests/structure.ts create mode 100644 dist/tests/structureLab.ts create mode 100644 dist/tests/structureSpawn.ts diff --git a/dist/screeps-tests.ts b/dist/screeps-tests.ts index 6f980331..c1af3e39 100644 --- a/dist/screeps-tests.ts +++ b/dist/screeps-tests.ts @@ -6,1047 +6,3 @@ // Feel free to add more test cases in the form of a sample code. // TODO: add more test cases. - -// Sample inputs - -const creep: Creep = Game.creeps.sampleCreep; -const room: Room = Game.rooms.W10S10; -const flag: Flag = Game.flags.Flag1; -const powerCreep: PowerCreep = Game.powerCreeps.samplePowerCreep; -const spawn: StructureSpawn = Game.spawns.Spawn1; -const body: BodyPartConstant[] = [WORK, WORK, CARRY, MOVE]; - -// Sample inputs for Game.map.findRoute testing -const anotherRoomName: Room = Game.rooms.W10S11; - -// Sample memory extensions -interface CreepMemory { - sourceId: Id; - lastHits: number; -} - -// Typescript always uses 'string' as the type of a key inside 'for in' loops. -// In case of objects with a restricted set of properties (e.g. ResourceConstant as key in StoreDefinition) -// the type of the key should be narrowed down in order to prevent casting (key as ResourceConstant). -// This helper function provides strongly typed keys for such objects. -// See discussion (https://github.com/Microsoft/TypeScript/pull/12253) why Object.keys does not return typed keys. -function keys(o: T): Array { - return Object.keys(o) as Array; -} - -function resources(o: GenericStore): ResourceConstant[] { - return Object.keys(o) as ResourceConstant[]; -} - -// Game object Id types -{ - const creepId: Id = "1" as Id; - const creepOne: Creep | null = Game.getObjectById(creepId); // $ExpectType Creep | null - const creepTwo: Creep | null = Game.getObjectById("2"); // deprecated $ExpectType Creep | null - // Works with typed ID - const creepThree: Creep = new Creep(creepId); // $ExpectType Creep - - if (creepOne) { - creepOne.hits; // $ExpectType number - const recycle = Game.getObjectById(creepOne.id); // $ExpectType Creep | null - } - - type StoreStructure = StructureContainer | StructureStorage | StructureLink; - const storeUnionID: Id = "1234" as Id; // Strict assertion required - const storeIdUnion: StoreStructure["id"] = "1234" as StoreStructure["id"]; - const stringID: string = storeUnionID; // Id assignable implicitly to string - const stringID2: string = storeIdUnion; // Id assignable implicitly to string - const storeObject = Game.getObjectById(storeUnionID)!; // $ExpectType StoreStructure - const storeObject2 = Game.getObjectById(storeIdUnion)!; // $ExpectType StructureContainer | StructureStorage | StructureLink - - // Object recognized - switch (storeObject.structureType) { - case STRUCTURE_CONTAINER: - storeObject.structureType === "container"; - case STRUCTURE_STORAGE: - storeObject.structureType === "storage"; - default: - storeObject.structureType === "link"; - } - - // Default type is unknown if untyped Id provided - const untyped = Game.getObjectById("untyped"); // $ExpectType unknown -} - -// Game.creeps - -{ - for (const i in Game.creeps) { - Game.creeps[i].moveTo(flag); - } -} - -// Game.flags - -{ - creep.moveTo(Game.flags.Flag1); -} - -// Game.powerCreeps - -{ - PowerCreep.create("steve", POWER_CLASS.OPERATOR) === OK; - - for (const i in Game.powerCreeps) { - const powerCreep = Game.powerCreeps[i]; // $ExpectType PowerCreep - - if (powerCreep.ticksToLive === undefined) { - // Not spawned in world; spawn creep - const spawn = Game.getObjectById("powerSpawnID") as StructurePowerSpawn; - powerCreep.spawn(spawn); - } else { - // Generate Ops - if ( - powerCreep.powers[PWR_GENERATE_OPS] && - powerCreep.powers[PWR_GENERATE_OPS].cooldown === 0 && - (powerCreep.carry.ops || 0) < 10 - ) { - Game.powerCreeps[i].usePower(PWR_GENERATE_OPS); - } else { - // Boost resource - const targetSource = Game.getObjectById("targetSourceID") as Source; - const sourceEffect = targetSource.effects.find(effect => effect.effect === PWR_REGEN_SOURCE && effect.level > 0); // $ExpectType RoomObjectEffect | undefined - if (!sourceEffect && powerCreep.powers[PWR_REGEN_SOURCE] && powerCreep.powers[PWR_REGEN_SOURCE].cooldown === 0) { - powerCreep.usePower(PWR_REGEN_SOURCE, targetSource); - } - } - } - - // AnyCreep type checks - creep.attack(powerCreep); - creep.heal(powerCreep); - creep.rangedAttack(powerCreep); - creep.rangedHeal(powerCreep); - creep.transfer(powerCreep, RESOURCE_ENERGY); - powerCreep.transfer(creep, RESOURCE_ENERGY); - - // Upgrading - powerCreep.upgrade(PWR_GENERATE_OPS); - } - - const myPowaCreeps = Game.rooms.sim.find(FIND_MY_POWER_CREEPS); // $ExpectType PowerCreep[] - - // Constant type checking - POWER_INFO[PWR_GENERATE_OPS].className === POWER_CLASS.OPERATOR; - typeof POWER_INFO[PWR_GENERATE_OPS].level[0] === "number"; -} - -// Game.spawns - -{ - for (const i in Game.spawns) { - Game.spawns[i].createCreep(body); - - // Test StructureSpawn.Spawning - let creep = Game.spawns[i].spawning; // $ExpectType Spawning | null - if (creep) { - const name: string = creep.name; // $ExpectType string - const needTime: number = creep.needTime; // $ExpectType number - const remainingTime: number = creep.remainingTime; // $ExpectType number - const creepSpawn: StructureSpawn = creep.spawn; // $ExpectType StructureSpawn - - const cancelStatus: OK | ERR_NOT_OWNER = creep.cancel(); - const setDirectionStatus: OK | ERR_NOT_OWNER | ERR_INVALID_ARGS = creep.setDirections([TOP, BOTTOM, LEFT, RIGHT]); - } - - creep = new StructureSpawn.Spawning("" as Id); // $ExpectType Spawning - creep = StructureSpawn.Spawning("" as Id); // $ExpectType Spawning - - const invaderCore = new StructureInvaderCore("" as Id); - const invader = invaderCore.spawning; // $ExpectType Spawning | null - if (invader) { - const name = invader.name; // $ExpectType string - } - } -} - -// Game.time - -{ - let time = Game.time; // $ExpectType number - time += 1; -} - -// Game.cpu.getUsed() - -{ - if (Game.cpu.getUsed() > Game.cpu.tickLimit / 2) { - // Half CPU Usged - } -} - -{ - for (const name in Game.creeps) { - const startCpu = Game.cpu.getUsed(); // $ExpectType number - - // creep logic goes here - - const elapsed = Game.cpu.getUsed() - startCpu; // $ExpectType number - } -} - -// Game.cpu.setShardLimits() - -{ - Game.cpu.setShardLimits({ shard0: 20, shard1: 10 }); -} - -// Game.cpu.halt() -{ - if (Game.cpu.hasOwnProperty("halt")) { - Game.cpu.halt!(); // $ExpectType never - } -} - -// Game.cpu.unlock() -{ - if (!Game.cpu.unlocked) { - if (!Game.cpu.unlockedTime) { - const unlock_state = Game.cpu.unlock(); - if (unlock_state === OK) { - // Unlimited cosmic power! - } - } - } -} - -// Game.getObjectById(id) - -{ - creep.memory.sourceId = creep.pos.findClosestByRange(FIND_SOURCES)!.id; // $ExpectType Id - const source = Game.getObjectById(creep.memory.sourceId); // $ExpectType Source | null -} - -// Game.notify(message, [groupInterval]) - -{ - if (creep.hits < creep.memory.lastHits) { - Game.notify(`Creep ${creep} has been attacked at ${creep.pos}!`); // $ExpectType void - } - creep.memory.lastHits = creep.hits; // $ExpectType number -} - -{ - if (Game.spawns["Spawn1"].energy === 0) { - Game.notify( - "Spawn1 is out of energy", - 180, // group these notifications for 3 hours - ); - } -} - -// Game.map.describeExits() - -{ - const exits: ExitsInformation = Game.map.describeExits("W8N3"); // $ExpectType ExitsInformation - // tslint:disable-next-line:newline-per-chained-call - keys(exits).map(exitKey => { - const nextRoom = exits[exitKey]; // $ExpectType string | undefined - const exitDir = +exitKey as ExitConstant; - const exitPos = creep.pos.findClosestByRange(exitDir); // $ExpectType RoomPosition | null - return { nextRoom, exitPos }; - }); -} - -// Game.map.findExit() - -{ - if (creep.room !== anotherRoomName) { - const exitDir = Game.map.findExit(creep.room, anotherRoomName); - if (exitDir !== ERR_NO_PATH && exitDir !== ERR_INVALID_ARGS) { - const exit = creep.pos.findClosestByRange(exitDir); // $ExpectType RoomPosition | null - if (exit !== null) { - creep.moveTo(exit); - } - } - } else { - // go to some place in another room - } -} - -{ - creep.moveTo(new RoomPosition(25, 25, anotherRoomName.name)); -} - -// Game.map.findRoute() - -{ - const route = Game.map.findRoute(creep.room, anotherRoomName); // $ExpectType -2 | { exit: ExitConstant; room: string; }[] - - if (route !== ERR_NO_PATH && route.length > 0) { - const exit = creep.pos.findClosestByRange(route[0].exit); // $ExpectType RoomPosition | null - if (exit !== null) { - creep.moveTo(exit); - } - } -} - -{ - // $ExpectType -2 | { exit: ExitConstant; room: string; }[] - const route = Game.map.findRoute(creep.room, anotherRoomName, { - routeCallback(roomName, fromRoomName) { - if (roomName === "W10S10") { - // avoid this room - return Infinity; - } - return 1; - }, - }); -} - -{ - const from = new RoomPosition(25, 25, "E1N1"); - const to = new RoomPosition(25, 25, "E4N1"); - - // Use `findRoute` to calculate a high-level plan for this path, - // prioritizing highways and owned rooms - const allowedRooms = { [from.roomName]: true }; - // $ExpectType -2 | { exit: ExitConstant; room: string; }[] - const route = Game.map.findRoute(from.roomName, to.roomName, { - 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; - if (isHighway || isMyRoom) { - return 1; - } else { - return 2.5; - } - } else { - return 2.5; - } - }, - }); - - if (route !== ERR_NO_PATH) { - route.forEach(info => { - allowedRooms[info.room] = true; - }); - } - - // Invoke PathFinder, allowing access only to rooms from `findRoute` - // $ExpectType PathFinderPath - const ret = PathFinder.search(from, [to], { - roomCallback: roomName => { - if (allowedRooms[roomName] === undefined) { - return false; - } else { - return true; - } - }, - }); -} - -// Game.map.getRoomLinearDistance(roomName1, roomName2, [continuous]) - -{ - Game.map.getRoomLinearDistance("W1N1", "W4N2"); // 3 $ExpectType number - Game.map.getRoomLinearDistance("E65S55", "W65S55", false); // 131 - Game.map.getRoomLinearDistance("E65S55", "W65S55", true); // 11 -} - -// Game.map.getTerrainAt(x, y, roomName) -// Game.map.getTerrainAt(pos) - -{ - Game.map.getTerrainAt(25, 20, "W10N10"); // $ExpectType Terrain -} - -{ - Game.map.getTerrainAt(new RoomPosition(25, 20, "W10N10")); // $ExpectType Terrain -} - -// Game.map.getRoomStatus(roomName) - -{ - const roomStatus = Game.map.getRoomStatus(room.name); // $ExpectType RoomStatus - if (roomStatus.status === "normal") { - creep.moveTo(room.getPositionAt(25, 25)!); - } -} - -// Game.market - -{ - // Game.market.calcTransactionCost(amount, roomName1, roomName2) - const cost = Game.market.calcTransactionCost(1000, "W0N0", "W10N5"); // $ExpectType number - - // Game.market.cancelOrder(orderId) - for (const id in Game.market.orders) { - Game.market.cancelOrder(id); // $ExpectType ScreepsReturnCode - } - - // Game.market.changeOrderPrice(orderId, newPrice) - Game.market.changeOrderPrice("57bec1bf77f4d17c4c011960", 9.95); // $ExpectType ScreepsReturnCode - - // Game.market.createOrder({type, resourceType, price, totalAmount, [roomName]}) - Game.market.createOrder({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM, price: 9.95, totalAmount: 10000, roomName: "W1N1" }); // $ExpectType ScreepsReturnCode - Game.market.createOrder({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM, price: 9.95, totalAmount: 10000 }); // $ExpectType ScreepsReturnCode - - // Game.market.deal(orderId, amount, [yourRoomName]) - Game.market.deal("57cd2b12cda69a004ae223a3", 1000, "W1N1"); // $ExpectType ScreepsReturnCode - - const amountToBuy = 2000; - const maxTransferEnergyCost = 500; - const orders = Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); // $ExpectType Order[] - - for (const i of orders) { - if (i.roomName) { - const transferEnergyCost = Game.market.calcTransactionCost(amountToBuy, "W1N1", i.roomName); // $ExpectType number - - if (transferEnergyCost < maxTransferEnergyCost) { - Game.market.deal(i.id, amountToBuy, "W1N1"); // $ExpectType ScreepsReturnCode - break; - } - } - } - - // Game.market.extendOrder(orderId, addAmount) - Game.market.extendOrder("57bec1bf77f4d17c4c011960", 10000); // $ExpectType ScreepsReturnCode - - // Game.market.getAllOrders([filter]) - Game.market.getAllOrders(); // $ExpectType Order[] - Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); // $ExpectType Order[] - - const targetRoom = "W1N1"; - // $ExpectType Order[] - 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"); // $ExpectType Order | null - - // Subscription tokens - Game.market.getAllOrders({ type: ORDER_SELL, resourceType: SUBSCRIPTION_TOKEN }); // $ExpectType Order[] - Game.market.createOrder({ type: ORDER_BUY, resourceType: SUBSCRIPTION_TOKEN, totalAmount: 10000000, price: 1 }); // $ExpectType ScreepsReturnCode - const priceHistory = Game.market.getHistory(RESOURCE_FIXTURES); // $ExpectType PriceHistory[] - - const avgPrice: number = priceHistory[0].avgPrice; - const stddevPrice: number = priceHistory[0].stddevPrice; - const volume: number = priceHistory[0].volume; - - // Game.market.getHistory([resourceType]) - const energyHistory = Game.market.getHistory(RESOURCE_ENERGY); // $ExpectType PriceHistory[] - const pixelHistory = Game.market.getHistory(PIXEL); // $ExpectType PriceHistory[] -} - -// PathFinder - -{ - const pfCreep = Game.creeps.John; // $ExpectType Creep - - // 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. - return { pos: source.pos, range: 1 }; - }); - - // $ExpectType PathFinderPath - 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]; // $ExpectType Room - - // 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(); - - // tslint:disable-next-line:newline-per-chained-call - 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 - // tslint:disable-next-line:newline-per-chained-call - curRoom.find(FIND_CREEPS).forEach(thisCreep => { - costs.set(thisCreep.pos.x, thisCreep.pos.y, 0xff); - }); - - return costs; - }, - }); - - const pos = ret.path[0]; // $ExpectType RoomPosition - pfCreep.move(pfCreep.pos.getDirectionTo(pos)); -} - -// RawMemory - -{ - // RawMemory.segments - - RawMemory.setActiveSegments([0, 3]); - // on the next tick - const segmentZero = RawMemory.segments[0]; - RawMemory.segments[3] = '{"foo": "bar", "counter": 15}'; - - // RawMemory.foreignSegment - - RawMemory.setActiveForeignSegment("player"); - // on the next tick - const playerSegment = RawMemory.foreignSegment; - // --> {"username": "player", "id": 40, "data": "Hello!"} - - // RawMemory.interShardSegment - - RawMemory.interShardSegment = JSON.stringify({ - creeps: { - Bob: { role: "claimer" }, - }, - }); - - // on another shard - const interShardData = JSON.parse(RawMemory.interShardSegment); - if (interShardData.creeps[creep.name]) { - creep.memory = interShardData[creep.name]; - delete interShardData.creeps[creep.name]; // tslint:disable-line no-dynamic-delete - } - RawMemory.interShardSegment = JSON.stringify(interShardData); - - // RawMemory.get() - const myMemory = JSON.parse(RawMemory.get()); - - // RawMemory.set(value) - RawMemory.set(JSON.stringify(myMemory)); - - // RawMemory.setActiveSegments(ids) - RawMemory.setActiveSegments([0, 3]); - - // RawMemory.setActiveForeignSegment(username, [id]) - RawMemory.setActiveForeignSegment("player"); - RawMemory.setActiveForeignSegment("player", 10); - RawMemory.setActiveForeignSegment(null); - - // RawMemory.setDefaultPublicSegment(id) - RawMemory.setPublicSegments([5, 20, 21]); - RawMemory.setDefaultPublicSegment(5); - RawMemory.setDefaultPublicSegment(null); - - // RawMemory.setPublicSegments(ids) - RawMemory.setPublicSegments([5, 3]); - RawMemory.setPublicSegments([]); -} - -// InterShardMemory - -{ - let localShardData = ""; - InterShardMemory.setLocal(localShardData); - localShardData = InterShardMemory.getLocal(); - - const remoteShardData: string = InterShardMemory.getRemote("shard2") || ""; -} - -// Find Overloads - -{ - const creeps = room.find(FIND_HOSTILE_CREEPS); // $ExpectType Creep[] - creeps[0].say(creeps[1].name); - - const flags = room.find(FIND_FLAGS); // $ExpectType Flag[] - flags[0].remove(); - - const spawns = room.find(FIND_HOSTILE_SPAWNS); // $ExpectType StructureSpawn[] - spawns[0].spawning; - - const sources = room.find(FIND_SOURCES); // $ExpectType Source[] - sources[0].ticksToRegeneration; - - const resources = room.find(FIND_DROPPED_RESOURCES); // $ExpectType Resource[] - resources[0].resourceType; - - const sites = room.find(FIND_CONSTRUCTION_SITES); // $ExpectType ConstructionSite[] - sites[0].remove(); - - // $ExpectType ConstructionSite<"extension">[] - const extensionsites = room.find(FIND_CONSTRUCTION_SITES, { - filter: (site): site is ConstructionSite => { - return site.structureType === STRUCTURE_EXTENSION; - }, - }); - // Should always be true. needs proper testing - extensionsites[0].structureType === STRUCTURE_EXTENSION; - - // Should have type (_HasRoomPosition | RoomPosition)[] - const exits = room.find(FIND_EXIT); // $ExpectType RoomPosition[] - - const creepsHere = room.lookForAt(LOOK_CREEPS, 10, 10); // $ExpectType Creep[] - creepsHere[0].getActiveBodyparts(ATTACK); - - // $ExpectType StructureTower[] - const towers = room.find(FIND_MY_STRUCTURES, { - filter: structure => { - return structure.structureType === STRUCTURE_TOWER; - }, - }); - towers[0].attack(creeps[0]); - towers[0].attack(creeps[0] as AnyCreep); - towers[0].attack(powerCreep); - towers[0].attack(spawns[0]); - towers[0].heal(powerCreep); - - const isTower = (structure: AnyStructure): structure is StructureTower => { - return structure.structureType === STRUCTURE_TOWER; - }; - - // $ExpectType StructureTower - const tower = room.find(FIND_MY_STRUCTURES, { - filter: isTower, - })[0]; - tower.attack(creeps[0]); - tower.attack(creeps[0] as AnyCreep); - tower.attack(powerCreep); - tower.attack(spawns[0]); - tower.heal(powerCreep); -} - -// RoomPosition Finds - -{ - // Should have type Creep - const hostileCreep = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS); // $ExpectType Creep | null - if (hostileCreep !== null) { - creep.say(hostileCreep.name); - } - - // $ExpectType StructureTower | null - const tower = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { - filter: structure => { - return structure.structureType === STRUCTURE_TOWER; - }, - algorithm: "astar", - }); - if (tower !== null) { - tower.attack(creep); - tower.attack(powerCreep); - } - - // Generic type predicate filter - const isStructureType = >(structureType: T) => { - return (structure: AnyStructure): structure is S => { - return structure.structureType === structureType; - }; - }; - - // $ExpectType StructureTower | null - const tower2 = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { - filter: isStructureType(STRUCTURE_TOWER), - algorithm: "astar", - }); - if (tower2 !== null) { - tower2.attack(creep); - tower2.attack(powerCreep); - } - - const creepWithEnergy = creep.pos.findClosestByPath(creep.room.find(FIND_CREEPS), { filter: c => c.store.energy > 0 }); // $ExpectType Creep | null - - const creepAbove = creep.pos.findClosestByPath(creep.room.find(FIND_CREEPS).map(c => c.pos), { - filter: p => p.getDirectionTo(creep) === TOP, - }); - - // $ExpectType StructureRampart | null - const rampart = creep.pos.findClosestByRange(FIND_HOSTILE_STRUCTURES, { - filter: structure => { - return structure.structureType === STRUCTURE_RAMPART; - }, - }); - if (rampart !== null) { - rampart.isPublic; - } - - // Should have type Creep[] - const hostileCreeps = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 10); // $ExpectType Creep[] - hostileCreeps[0].saying; - - // $ExpectType StructureLab[] - const labs = creep.pos.findInRange(FIND_MY_STRUCTURES, 4, { - filter: structure => { - return structure.structureType === STRUCTURE_LAB; - }, - }); - - labs[0].boostCreep(creep); -} - -// LookAt Finds - -{ - const matrix = room.lookAtArea(10, 10, 20, 20, false); // $ExpectType LookAtResultMatrix - for (const y in matrix) { - const row = matrix[y]; - for (const x in row) { - const pos = new RoomPosition(+x, +y, room.name); - const objects = row[x]; - if (objects.length > 0) { - objects.map(o => o.type); - } - } - } - - const nukes = room.lookForAt(LOOK_NUKES, creep.pos); // $ExpectType Nuke[] - - nukes[0].launchRoomName; - - const flags = room.lookForAtArea(LOOK_FLAGS, 10, 10, 20, 20); // $ExpectType LookForAtAreaResultMatrix - - const x = flags[10]; - const y = x[11]; - const entry = y[0]; - entry.flag.remove(); - - const creeps = room.lookForAtArea(LOOK_CREEPS, 10, 10, 20, 20, true); // $ExpectType LookForAtAreaResultArray - - creeps[0].x; - creeps[0].y; - creeps[0].creep.move(TOP); -} - -// StoreDefinition - -{ - for (const resourceType of resources(creep.carry)) { - const amount = creep.carry[resourceType]; - creep.drop(resourceType, amount); - } - - const extension = new StructureExtension("" as Id); - - const e1: number = extension.store.getUsedCapacity(RESOURCE_ENERGY); // $ExpectType number - const e2: number = extension.store[RESOURCE_ENERGY]; // $ExpectType number - - // Invalid resource type for extension - const eg1: null = extension.store.getUsedCapacity(RESOURCE_GHODIUM); // $ExpectType null - const eg2: null = extension.store.getFreeCapacity(RESOURCE_GHODIUM); // $ExpectType null - const eg3: null = extension.store.getCapacity(RESOURCE_GHODIUM); // $ExpectType null - const eg4: 0 = extension.store.G; // $ExpectType 0 - - const storage = new StructureStorage("" as Id); - - const sg1: number = storage.store.getUsedCapacity(RESOURCE_GHODIUM); // $ExpectType number - const sg2: number = storage.store.getFreeCapacity(RESOURCE_GHODIUM); // $ExpectType number - const sg3: number = storage.store.getCapacity(RESOURCE_GHODIUM); // $ExpectType number -} - -// Advanced Structure types -{ - const owned = Game.getObjectById("blah")!; // $ExpectType AnyOwnedStructure - const owner = owned.owner && owned.owner.username; // $ExpectType string | undefined - owned.notifyWhenAttacked(false); - - const structs = room.find(FIND_MY_STRUCTURES); // $ExpectType AnyOwnedStructure[] - structs.forEach(struct => { - switch (struct.structureType) { - case STRUCTURE_CONTROLLER: - const usernameOptional: string | undefined = struct.owner && struct.owner.username; - break; - default: - const usernameRequired: string = struct.owner.username; - break; - } - }); - - const unowned = Game.getObjectById("blah2")!; // $ExpectType AnyStructure - const hp = unowned.hits / unowned.hitsMax; - - // test discriminated union - switch (unowned.structureType) { - case STRUCTURE_TOWER: - unowned; // $ExpectType StructureTower - unowned.heal(Game.creeps.myCreep); - break; - case STRUCTURE_CONTAINER: - case STRUCTURE_STORAGE: - case STRUCTURE_TERMINAL: - unowned.store; // $ExpectType StoreDefinition - const energyPercent = unowned.store.energy / unowned.storeCapacity; - break; - case STRUCTURE_WALL: - case STRUCTURE_RAMPART: - const wallHp = unowned.hits / unowned.hitsMax; - 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, - })[0]; - const to = from.pos.findClosestByPath(FIND_MY_STRUCTURES, { - 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)); -} - -{ - // Test that you can use signatures - EXTENSION_ENERGY_CAPACITY[Game.rooms.myRoom.controller!.level]; // $ExpectType number - - REACTIONS[Object.keys(creep.carry)[0]]; // $ExpectType { [resource: string]: string; } - - BOOSTS[creep.body[0].type as string]; // $ExpectType { [boost: string]: { [action: string]: number; }; } -} - -// Tombstones - -{ - const tombstone = room.find(FIND_TOMBSTONES)[0]; // $ExpectType Tombstone - - tombstone.creep; // $ExpectType AnyCreep - (tombstone.creep as PowerCreep).spawnCooldownTime; - (tombstone.creep as Creep).my; - - tombstone.store; // $ExpectType StoreDefinitionUnlimited - - tombstone.id; // $ExpectType Id - - const creep = Game.creeps["dave"]; - creep.withdraw(tombstone, RESOURCE_ENERGY); -} - -// Ruin - -{ - const ruin = room.find(FIND_RUINS)[0]; // $ExpectType Ruin - - ruin.store; // $ExpectType StoreDefinitionUnlimited - ruin.structure; // $ExpectType AnyStructure - - creep.withdraw(ruin, RESOURCE_ENERGY); - powerCreep.withdraw(ruin, RESOURCE_ENERGY); -} - -{ - if (Game.cpu.hasOwnProperty("getHeapStatistics")) { - const heap = Game.cpu.getHeapStatistics!(); - heap.total_heap_size; - } -} - -// StructurePortal - -{ - const portals = room.find(FIND_STRUCTURES, { filter: s => s.structureType === STRUCTURE_PORTAL }); // $ExpectType StructurePortal[] - portals.forEach((p: StructurePortal) => { - const state = p.ticksToDecay === undefined ? "stable" : "unstable"; - if (p.destination instanceof RoomPosition) { - Game.notify(`Found ${state} inter-room portal to ${p.destination}`); - } else { - Game.notify(`Found ${state} inter-shard portal to ${p.destination.shard} ${p.destination.room}`); - } - }); -} - -// ConstructionSite - -{ - room.createConstructionSite(10, 10, STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode - room.createConstructionSite(10, 11, STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode - - const pos = new RoomPosition(10, 10, room.name); - room.createConstructionSite(pos, STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode - room.createConstructionSite(pos, STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode - pos.createConstructionSite(STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode - pos.createConstructionSite(STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode -} - -// StructureLab - -{ - const lab0 = Game.getObjectById("lab0"); - 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) { - lab0.runReaction(lab1, lab2); // $ExpectType ScreepsReturnCode - } - // nevermind, reverse that - lab0.reverseReaction(lab1, lab2); // $ExpectType ScreepsReturnCode - } -} - -// Room event log - -{ - room.getEventLog(); // $ExpectType EventItem[] - room.getEventLog(true); // $ExpectType EventItem[] - - const events = room.getEventLog(); // $ExpectType EventItem[] - - const event = events[0]; // $ExpectType EventItem - - switch (event.event) { - case EVENT_ATTACK: - const attackType: EventAttackType = event.data.attackType; // $ExpectType EventAttackType - break; - case EVENT_BUILD: - const energySpent: number = event.data.energySpent; // $ExpectTypenumber - break; - case EVENT_POWER: - const power = event.data.power; // $ExpectType PowerConstant - break; - } -} - -// Room.Terrain - -{ - const room = Game.rooms[""]; - - const myTerrain = room.getTerrain(); // $ExpectType RoomTerrain - - 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"); // $ExpectType RoomTerrain -} - -// Creep.body -function atackPower(creep: Creep) { - return creep.body - .map(part => { - if (part.type === ATTACK) { - const multiplier = part.boost ? BOOSTS[part.type][part.boost].attack : 1; - return multiplier * ATTACK_POWER; - } - return 0; - }) - .reduce((a, b) => a + b); -} - -// Factories and Commodities - -{ - const factory = new StructureFactory("" as Id); - - creep.transfer(factory, RESOURCE_CELL, 20); - creep.transfer(factory, RESOURCE_OXIDANT, 36); - creep.transfer(factory, RESOURCE_LEMERGIUM_BAR, 16); - creep.transfer(factory, RESOURCE_ENERGY, 8); - - factory.produce(RESOURCE_PHLEGM); // $ExpectType ScreepsReturnCode - - factory.produce(RESOURCE_BATTERY); // $ExpectType ScreepsReturnCode - factory.produce(RESOURCE_ENERGY); // $ExpectType ScreepsReturnCode - - factory.produce(RESOURCE_GHODIUM); // $ExpectType ScreepsReturnCode - factory.produce(RESOURCE_GHODIUM_MELT); // $ExpectType ScreepsReturnCode - - creep.withdraw(factory, RESOURCE_PHLEGM); // $ExpectType ScreepsReturnCode - - // Energy and ghodium commodities - COMMODITIES[RESOURCE_ENERGY]; - COMMODITIES[RESOURCE_GHODIUM]; - - // Mineral commodities - COMMODITIES[RESOURCE_UTRIUM]; - COMMODITIES[RESOURCE_LEMERGIUM]; - COMMODITIES[RESOURCE_KEANIUM]; - COMMODITIES[RESOURCE_ZYNTHIUM]; - COMMODITIES[RESOURCE_OXYGEN]; - COMMODITIES[RESOURCE_HYDROGEN]; - COMMODITIES[RESOURCE_CATALYST]; - - // Commodity commodities - COMMODITIES[RESOURCE_UTRIUM_BAR]; - COMMODITIES[RESOURCE_LEMERGIUM_BAR]; - COMMODITIES[RESOURCE_ZYNTHIUM_BAR]; - COMMODITIES[RESOURCE_KEANIUM_BAR]; - COMMODITIES[RESOURCE_GHODIUM_MELT]; - COMMODITIES[RESOURCE_OXIDANT]; - COMMODITIES[RESOURCE_REDUCTANT]; - COMMODITIES[RESOURCE_PURIFIER]; - COMMODITIES[RESOURCE_BATTERY]; - COMMODITIES[RESOURCE_COMPOSITE]; - COMMODITIES[RESOURCE_CRYSTAL]; - COMMODITIES[RESOURCE_LIQUID]; - COMMODITIES[RESOURCE_WIRE]; - COMMODITIES[RESOURCE_SWITCH]; - COMMODITIES[RESOURCE_TRANSISTOR]; - COMMODITIES[RESOURCE_MICROCHIP]; - COMMODITIES[RESOURCE_CIRCUIT]; - COMMODITIES[RESOURCE_DEVICE]; - COMMODITIES[RESOURCE_CELL]; - COMMODITIES[RESOURCE_PHLEGM]; - COMMODITIES[RESOURCE_TISSUE]; - COMMODITIES[RESOURCE_MUSCLE]; - COMMODITIES[RESOURCE_ORGANOID]; - COMMODITIES[RESOURCE_ORGANISM]; - COMMODITIES[RESOURCE_ALLOY]; - COMMODITIES[RESOURCE_TUBE]; - COMMODITIES[RESOURCE_FIXTURES]; - COMMODITIES[RESOURCE_FRAME]; - COMMODITIES[RESOURCE_HYDRAULICS]; - COMMODITIES[RESOURCE_MACHINE]; - COMMODITIES[RESOURCE_CONDENSATE]; - COMMODITIES[RESOURCE_CONCENTRATE]; - COMMODITIES[RESOURCE_EXTRACT]; - COMMODITIES[RESOURCE_SPIRIT]; - COMMODITIES[RESOURCE_EMANATION]; - COMMODITIES[RESOURCE_ESSENCE]; -} - -// Horse armor!Pixels! -{ - const ret: OK | ERR_NOT_ENOUGH_RESOURCES = Game.cpu.generatePixel(); // $ExpectType 0 | -6 -} - -// Game.map.visual -{ - const mapVis = Game.map.visual; // $ExpectType MapVisual - const point1 = new RoomPosition(1, 1, "E1N1"); - const point2 = new RoomPosition(1, 1, "E1N8"); - const point3 = new RoomPosition(1, 1, "E8N8"); - const point4 = new RoomPosition(1, 1, "E1N8"); - - mapVis - .line(point1, point2) - .circle(point3, { fill: "#f2f2f2" }) - .poly([point1, point2, point3, point4]) - .rect(point3, 50, 50); - - const size: number = mapVis.getSize(); // $ExpectType number - - const visData = mapVis.export(); // $ExpectType string - mapVis.clear(); // $ExpectType MapVisual - mapVis.import(visData); // $ExpectType MapVisual -} diff --git a/dist/tests/Tombs_Ruins.ts b/dist/tests/Tombs_Ruins.ts new file mode 100644 index 00000000..37c2bc5b --- /dev/null +++ b/dist/tests/Tombs_Ruins.ts @@ -0,0 +1,28 @@ +// Tombstones + +{ + const tombstone = room.find(FIND_TOMBSTONES)[0]; // $ExpectType Tombstone + + tombstone.creep; // $ExpectType AnyCreep + (tombstone.creep as PowerCreep).spawnCooldownTime; + (tombstone.creep as Creep).my; + + tombstone.store; // $ExpectType StoreDefinitionUnlimited + + tombstone.id; // $ExpectType Id + + const creep = Game.creeps["dave"]; + creep.withdraw(tombstone, RESOURCE_ENERGY); +} + +// Ruin + +{ + const ruin = room.find(FIND_RUINS)[0]; // $ExpectType Ruin + + ruin.store; // $ExpectType StoreDefinitionUnlimited + ruin.structure; // $ExpectType AnyStructure + + creep.withdraw(ruin, RESOURCE_ENERGY); + powerCreep.withdraw(ruin, RESOURCE_ENERGY); +} diff --git a/dist/tests/constants.ts b/dist/tests/constants.ts new file mode 100644 index 00000000..7b73b141 --- /dev/null +++ b/dist/tests/constants.ts @@ -0,0 +1,8 @@ +{ + // Test that you can use signatures + EXTENSION_ENERGY_CAPACITY[Game.rooms.myRoom.controller!.level]; // $ExpectType number + + REACTIONS[Object.keys(creep.carry)[0]]; // $ExpectType { [resource: string]: string; } + + BOOSTS[creep.body[0].type as string]; // $ExpectType { [boost: string]: { [action: string]: number; }; } +} diff --git a/dist/tests/creep.ts b/dist/tests/creep.ts new file mode 100644 index 00000000..86296914 --- /dev/null +++ b/dist/tests/creep.ts @@ -0,0 +1,61 @@ +// Game.powerCreeps + +{ + PowerCreep.create("steve", POWER_CLASS.OPERATOR) === OK; + + for (const i in Game.powerCreeps) { + const powerCreep = Game.powerCreeps[i]; // $ExpectType PowerCreep + + if (powerCreep.ticksToLive === undefined) { + // Not spawned in world; spawn creep + const spawn = Game.getObjectById("powerSpawnID") as StructurePowerSpawn; + powerCreep.spawn(spawn); + } else { + // Generate Ops + if ( + powerCreep.powers[PWR_GENERATE_OPS] && + powerCreep.powers[PWR_GENERATE_OPS].cooldown === 0 && + (powerCreep.carry.ops || 0) < 10 + ) { + Game.powerCreeps[i].usePower(PWR_GENERATE_OPS); + } else { + // Boost resource + const targetSource = Game.getObjectById("targetSourceID") as Source; + const sourceEffect = targetSource.effects.find(effect => effect.effect === PWR_REGEN_SOURCE && effect.level > 0); // $ExpectType RoomObjectEffect | undefined + if (!sourceEffect && powerCreep.powers[PWR_REGEN_SOURCE] && powerCreep.powers[PWR_REGEN_SOURCE].cooldown === 0) { + powerCreep.usePower(PWR_REGEN_SOURCE, targetSource); + } + } + } + + // AnyCreep type checks + creep.attack(powerCreep); + creep.heal(powerCreep); + creep.rangedAttack(powerCreep); + creep.rangedHeal(powerCreep); + creep.transfer(powerCreep, RESOURCE_ENERGY); + powerCreep.transfer(creep, RESOURCE_ENERGY); + + // Upgrading + powerCreep.upgrade(PWR_GENERATE_OPS); + } + + const myPowaCreeps = Game.rooms.sim.find(FIND_MY_POWER_CREEPS); // $ExpectType PowerCreep[] + + // Constant type checking + POWER_INFO[PWR_GENERATE_OPS].className === POWER_CLASS.OPERATOR; + typeof POWER_INFO[PWR_GENERATE_OPS].level[0] === "number"; +} + +// Creep.body +function atackPower(creep: Creep) { + return creep.body + .map(part => { + if (part.type === ATTACK) { + const multiplier = part.boost ? BOOSTS[part.type][part.boost].attack : 1; + return multiplier * ATTACK_POWER; + } + return 0; + }) + .reduce((a, b) => a + b); +} diff --git a/dist/tests/factory.ts b/dist/tests/factory.ts new file mode 100644 index 00000000..38cd9fef --- /dev/null +++ b/dist/tests/factory.ts @@ -0,0 +1,71 @@ +// Factories and Commodities + +{ + const factory = new StructureFactory("" as Id); + + creep.transfer(factory, RESOURCE_CELL, 20); + creep.transfer(factory, RESOURCE_OXIDANT, 36); + creep.transfer(factory, RESOURCE_LEMERGIUM_BAR, 16); + creep.transfer(factory, RESOURCE_ENERGY, 8); + + factory.produce(RESOURCE_PHLEGM); // $ExpectType ScreepsReturnCode + + factory.produce(RESOURCE_BATTERY); // $ExpectType ScreepsReturnCode + factory.produce(RESOURCE_ENERGY); // $ExpectType ScreepsReturnCode + + factory.produce(RESOURCE_GHODIUM); // $ExpectType ScreepsReturnCode + factory.produce(RESOURCE_GHODIUM_MELT); // $ExpectType ScreepsReturnCode + + creep.withdraw(factory, RESOURCE_PHLEGM); // $ExpectType ScreepsReturnCode + + // Energy and ghodium commodities + COMMODITIES[RESOURCE_ENERGY]; + COMMODITIES[RESOURCE_GHODIUM]; + + // Mineral commodities + COMMODITIES[RESOURCE_UTRIUM]; + COMMODITIES[RESOURCE_LEMERGIUM]; + COMMODITIES[RESOURCE_KEANIUM]; + COMMODITIES[RESOURCE_ZYNTHIUM]; + COMMODITIES[RESOURCE_OXYGEN]; + COMMODITIES[RESOURCE_HYDROGEN]; + COMMODITIES[RESOURCE_CATALYST]; + + // Commodity commodities + COMMODITIES[RESOURCE_UTRIUM_BAR]; + COMMODITIES[RESOURCE_LEMERGIUM_BAR]; + COMMODITIES[RESOURCE_ZYNTHIUM_BAR]; + COMMODITIES[RESOURCE_KEANIUM_BAR]; + COMMODITIES[RESOURCE_GHODIUM_MELT]; + COMMODITIES[RESOURCE_OXIDANT]; + COMMODITIES[RESOURCE_REDUCTANT]; + COMMODITIES[RESOURCE_PURIFIER]; + COMMODITIES[RESOURCE_BATTERY]; + COMMODITIES[RESOURCE_COMPOSITE]; + COMMODITIES[RESOURCE_CRYSTAL]; + COMMODITIES[RESOURCE_LIQUID]; + COMMODITIES[RESOURCE_WIRE]; + COMMODITIES[RESOURCE_SWITCH]; + COMMODITIES[RESOURCE_TRANSISTOR]; + COMMODITIES[RESOURCE_MICROCHIP]; + COMMODITIES[RESOURCE_CIRCUIT]; + COMMODITIES[RESOURCE_DEVICE]; + COMMODITIES[RESOURCE_CELL]; + COMMODITIES[RESOURCE_PHLEGM]; + COMMODITIES[RESOURCE_TISSUE]; + COMMODITIES[RESOURCE_MUSCLE]; + COMMODITIES[RESOURCE_ORGANOID]; + COMMODITIES[RESOURCE_ORGANISM]; + COMMODITIES[RESOURCE_ALLOY]; + COMMODITIES[RESOURCE_TUBE]; + COMMODITIES[RESOURCE_FIXTURES]; + COMMODITIES[RESOURCE_FRAME]; + COMMODITIES[RESOURCE_HYDRAULICS]; + COMMODITIES[RESOURCE_MACHINE]; + COMMODITIES[RESOURCE_CONDENSATE]; + COMMODITIES[RESOURCE_CONCENTRATE]; + COMMODITIES[RESOURCE_EXTRACT]; + COMMODITIES[RESOURCE_SPIRIT]; + COMMODITIES[RESOURCE_EMANATION]; + COMMODITIES[RESOURCE_ESSENCE]; +} diff --git a/dist/tests/find.ts b/dist/tests/find.ts new file mode 100644 index 00000000..d1274b38 --- /dev/null +++ b/dist/tests/find.ts @@ -0,0 +1,163 @@ +// Find Overloads + +{ + const creeps = room.find(FIND_HOSTILE_CREEPS); // $ExpectType Creep[] + creeps[0].say(creeps[1].name); + + const flags = room.find(FIND_FLAGS); // $ExpectType Flag[] + flags[0].remove(); + + const spawns = room.find(FIND_HOSTILE_SPAWNS); // $ExpectType StructureSpawn[] + spawns[0].spawning; + + const sources = room.find(FIND_SOURCES); // $ExpectType Source[] + sources[0].ticksToRegeneration; + + const resources = room.find(FIND_DROPPED_RESOURCES); // $ExpectType Resource[] + resources[0].resourceType; + + const sites = room.find(FIND_CONSTRUCTION_SITES); // $ExpectType ConstructionSite[] + sites[0].remove(); + + // $ExpectType ConstructionSite<"extension">[] + const extensionsites = room.find(FIND_CONSTRUCTION_SITES, { + filter: (site): site is ConstructionSite => { + return site.structureType === STRUCTURE_EXTENSION; + }, + }); + // Should always be true. needs proper testing + extensionsites[0].structureType === STRUCTURE_EXTENSION; + + // Should have type (_HasRoomPosition | RoomPosition)[] + const exits = room.find(FIND_EXIT); // $ExpectType RoomPosition[] + + const creepsHere = room.lookForAt(LOOK_CREEPS, 10, 10); // $ExpectType Creep[] + creepsHere[0].getActiveBodyparts(ATTACK); + + // $ExpectType StructureTower[] + const towers = room.find(FIND_MY_STRUCTURES, { + filter: structure => { + return structure.structureType === STRUCTURE_TOWER; + }, + }); + towers[0].attack(creeps[0]); + towers[0].attack(creeps[0] as AnyCreep); + towers[0].attack(powerCreep); + towers[0].attack(spawns[0]); + towers[0].heal(powerCreep); + + const isTower = (structure: AnyStructure): structure is StructureTower => { + return structure.structureType === STRUCTURE_TOWER; + }; + + // $ExpectType StructureTower + const tower = room.find(FIND_MY_STRUCTURES, { + filter: isTower, + })[0]; + tower.attack(creeps[0]); + tower.attack(creeps[0] as AnyCreep); + tower.attack(powerCreep); + tower.attack(spawns[0]); + tower.heal(powerCreep); +} + +// RoomPosition Finds + +{ + // Should have type Creep + const hostileCreep = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS); // $ExpectType Creep | null + if (hostileCreep !== null) { + creep.say(hostileCreep.name); + } + + // $ExpectType StructureTower | null + const tower = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { + filter: structure => { + return structure.structureType === STRUCTURE_TOWER; + }, + algorithm: "astar", + }); + if (tower !== null) { + tower.attack(creep); + tower.attack(powerCreep); + } + + // Generic type predicate filter + const isStructureType = >(structureType: T) => { + return (structure: AnyStructure): structure is S => { + return structure.structureType === structureType; + }; + }; + + // $ExpectType StructureTower | null + const tower2 = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, { + filter: isStructureType(STRUCTURE_TOWER), + algorithm: "astar", + }); + if (tower2 !== null) { + tower2.attack(creep); + tower2.attack(powerCreep); + } + + const creepWithEnergy = creep.pos.findClosestByPath(creep.room.find(FIND_CREEPS), { filter: c => c.store.energy > 0 }); // $ExpectType Creep | null + + const creepAbove = creep.pos.findClosestByPath(creep.room.find(FIND_CREEPS).map(c => c.pos), { + filter: p => p.getDirectionTo(creep) === TOP, + }); + + // $ExpectType StructureRampart | null + const rampart = creep.pos.findClosestByRange(FIND_HOSTILE_STRUCTURES, { + filter: structure => { + return structure.structureType === STRUCTURE_RAMPART; + }, + }); + if (rampart !== null) { + rampart.isPublic; + } + + // Should have type Creep[] + const hostileCreeps = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 10); // $ExpectType Creep[] + hostileCreeps[0].saying; + + // $ExpectType StructureLab[] + const labs = creep.pos.findInRange(FIND_MY_STRUCTURES, 4, { + filter: structure => { + return structure.structureType === STRUCTURE_LAB; + }, + }); + + labs[0].boostCreep(creep); +} + +// LookAt Finds + +{ + const matrix = room.lookAtArea(10, 10, 20, 20, false); // $ExpectType LookAtResultMatrix + for (const y in matrix) { + const row = matrix[y]; + for (const x in row) { + const pos = new RoomPosition(+x, +y, room.name); + const objects = row[x]; + if (objects.length > 0) { + objects.map(o => o.type); + } + } + } + + const nukes = room.lookForAt(LOOK_NUKES, creep.pos); // $ExpectType Nuke[] + + nukes[0].launchRoomName; + + const flags = room.lookForAtArea(LOOK_FLAGS, 10, 10, 20, 20); // $ExpectType LookForAtAreaResultMatrix + + const x = flags[10]; + const y = x[11]; + const entry = y[0]; + entry.flag.remove(); + + const creeps = room.lookForAtArea(LOOK_CREEPS, 10, 10, 20, 20, true); // $ExpectType LookForAtAreaResultArray + + creeps[0].x; + creeps[0].y; + creeps[0].creep.move(TOP); +} diff --git a/dist/tests/game-object-ids.ts b/dist/tests/game-object-ids.ts new file mode 100644 index 00000000..c4e929d3 --- /dev/null +++ b/dist/tests/game-object-ids.ts @@ -0,0 +1,34 @@ +// Game object Id types +{ + const creepId: Id = "1" as Id; + const creepOne: Creep | null = Game.getObjectById(creepId); // $ExpectType Creep | null + const creepTwo: Creep | null = Game.getObjectById("2"); // deprecated $ExpectType Creep | null + // Works with typed ID + const creepThree: Creep = new Creep(creepId); // $ExpectType Creep + + if (creepOne) { + creepOne.hits; // $ExpectType number + const recycle = Game.getObjectById(creepOne.id); // $ExpectType Creep | null + } + + type StoreStructure = StructureContainer | StructureStorage | StructureLink; + const storeUnionID: Id = "1234" as Id; // Strict assertion required + const storeIdUnion: StoreStructure["id"] = "1234" as StoreStructure["id"]; + const stringID: string = storeUnionID; // Id assignable implicitly to string + const stringID2: string = storeIdUnion; // Id assignable implicitly to string + const storeObject = Game.getObjectById(storeUnionID)!; // $ExpectType StoreStructure + const storeObject2 = Game.getObjectById(storeIdUnion)!; // $ExpectType StructureContainer | StructureStorage | StructureLink + + // Object recognized + switch (storeObject.structureType) { + case STRUCTURE_CONTAINER: + storeObject.structureType === "container"; + case STRUCTURE_STORAGE: + storeObject.structureType === "storage"; + default: + storeObject.structureType === "link"; + } + + // Default type is unknown if untyped Id provided + const untyped = Game.getObjectById("untyped"); // $ExpectType unknown +} diff --git a/dist/tests/game.cpu.ts b/dist/tests/game.cpu.ts new file mode 100644 index 00000000..d96c3dab --- /dev/null +++ b/dist/tests/game.cpu.ts @@ -0,0 +1,54 @@ +// Game.cpu.getUsed() + +{ + if (Game.cpu.getUsed() > Game.cpu.tickLimit / 2) { + // Half CPU Usged + } +} + +{ + for (const name in Game.creeps) { + const startCpu = Game.cpu.getUsed(); // $ExpectType number + + // creep logic goes here + + const elapsed = Game.cpu.getUsed() - startCpu; // $ExpectType number + } +} + +// Game.cpu.setShardLimits() + +{ + Game.cpu.setShardLimits({ shard0: 20, shard1: 10 }); +} + +// Game.cpu.halt() +{ + if (Game.cpu.hasOwnProperty("halt")) { + Game.cpu.halt!(); // $ExpectType never + } +} + +// Game.cpu.unlock() +{ + if (!Game.cpu.unlocked) { + if (!Game.cpu.unlockedTime) { + const unlock_state = Game.cpu.unlock(); + if (unlock_state === OK) { + // Unlimited cosmic power! + } + } + } +} + +{ + if (Game.cpu.hasOwnProperty("getHeapStatistics")) { + const heap = Game.cpu.getHeapStatistics!(); + heap.total_heap_size; + } +} + +// Horse armor!Pixels! +{ + const ret: OK | ERR_NOT_ENOUGH_RESOURCES = Game.cpu.generatePixel(); // $ExpectType 0 | -6 +} diff --git a/dist/tests/game.map.ts b/dist/tests/game.map.ts new file mode 100644 index 00000000..6bf4e619 --- /dev/null +++ b/dist/tests/game.map.ts @@ -0,0 +1,151 @@ +// Game.map.describeExits() + +{ + const exits: ExitsInformation = Game.map.describeExits("W8N3"); // $ExpectType ExitsInformation + // tslint:disable-next-line:newline-per-chained-call + keys(exits).map(exitKey => { + const nextRoom = exits[exitKey]; // $ExpectType string | undefined + const exitDir = +exitKey as ExitConstant; + const exitPos = creep.pos.findClosestByRange(exitDir); // $ExpectType RoomPosition | null + return { nextRoom, exitPos }; + }); +} + +// Game.map.findExit() + +{ + if (creep.room !== anotherRoomName) { + const exitDir = Game.map.findExit(creep.room, anotherRoomName); + if (exitDir !== ERR_NO_PATH && exitDir !== ERR_INVALID_ARGS) { + const exit = creep.pos.findClosestByRange(exitDir); // $ExpectType RoomPosition | null + if (exit !== null) { + creep.moveTo(exit); + } + } + } else { + // go to some place in another room + } +} + +{ + creep.moveTo(new RoomPosition(25, 25, anotherRoomName.name)); +} + +// Game.map.findRoute() + +{ + const route = Game.map.findRoute(creep.room, anotherRoomName); // $ExpectType -2 | { exit: ExitConstant; room: string; }[] + + if (route !== ERR_NO_PATH && route.length > 0) { + const exit = creep.pos.findClosestByRange(route[0].exit); // $ExpectType RoomPosition | null + if (exit !== null) { + creep.moveTo(exit); + } + } +} + +{ + // $ExpectType -2 | { exit: ExitConstant; room: string; }[] + const route = Game.map.findRoute(creep.room, anotherRoomName, { + routeCallback(roomName, fromRoomName) { + if (roomName === "W10S10") { + // avoid this room + return Infinity; + } + return 1; + }, + }); +} + +{ + const from = new RoomPosition(25, 25, "E1N1"); + const to = new RoomPosition(25, 25, "E4N1"); + + // Use `findRoute` to calculate a high-level plan for this path, + // prioritizing highways and owned rooms + const allowedRooms = { [from.roomName]: true }; + // $ExpectType -2 | { exit: ExitConstant; room: string; }[] + const route = Game.map.findRoute(from.roomName, to.roomName, { + 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; + if (isHighway || isMyRoom) { + return 1; + } else { + return 2.5; + } + } else { + return 2.5; + } + }, + }); + + if (route !== ERR_NO_PATH) { + route.forEach(info => { + allowedRooms[info.room] = true; + }); + } + + // Invoke PathFinder, allowing access only to rooms from `findRoute` + // $ExpectType PathFinderPath + const ret = PathFinder.search(from, [to], { + roomCallback: roomName => { + if (allowedRooms[roomName] === undefined) { + return false; + } else { + return true; + } + }, + }); +} + +// Game.map.getRoomLinearDistance(roomName1, roomName2, [continuous]) + +{ + Game.map.getRoomLinearDistance("W1N1", "W4N2"); // 3 $ExpectType number + Game.map.getRoomLinearDistance("E65S55", "W65S55", false); // 131 + Game.map.getRoomLinearDistance("E65S55", "W65S55", true); // 11 +} + +// Game.map.getTerrainAt(x, y, roomName) +// Game.map.getTerrainAt(pos) + +{ + Game.map.getTerrainAt(25, 20, "W10N10"); // $ExpectType Terrain +} + +{ + Game.map.getTerrainAt(new RoomPosition(25, 20, "W10N10")); // $ExpectType Terrain +} + +// Game.map.getRoomStatus(roomName) + +{ + const roomStatus = Game.map.getRoomStatus(room.name); // $ExpectType RoomStatus + if (roomStatus.status === "normal") { + creep.moveTo(room.getPositionAt(25, 25)!); + } +} + +// Game.map.visual +{ + const mapVis = Game.map.visual; // $ExpectType MapVisual + const point1 = new RoomPosition(1, 1, "E1N1"); + const point2 = new RoomPosition(1, 1, "E1N8"); + const point3 = new RoomPosition(1, 1, "E8N8"); + const point4 = new RoomPosition(1, 1, "E1N8"); + + mapVis + .line(point1, point2) + .circle(point3, { fill: "#f2f2f2" }) + .poly([point1, point2, point3, point4]) + .rect(point3, 50, 50); + + const size: number = mapVis.getSize(); // $ExpectType number + + const visData = mapVis.export(); // $ExpectType string + mapVis.clear(); // $ExpectType MapVisual + mapVis.import(visData); // $ExpectType MapVisual +} diff --git a/dist/tests/game.market.ts b/dist/tests/game.market.ts new file mode 100644 index 00000000..02a111de --- /dev/null +++ b/dist/tests/game.market.ts @@ -0,0 +1,68 @@ +// Game.market + +{ + // Game.market.calcTransactionCost(amount, roomName1, roomName2) + const cost = Game.market.calcTransactionCost(1000, "W0N0", "W10N5"); // $ExpectType number + + // Game.market.cancelOrder(orderId) + for (const id in Game.market.orders) { + Game.market.cancelOrder(id); // $ExpectType ScreepsReturnCode + } + + // Game.market.changeOrderPrice(orderId, newPrice) + Game.market.changeOrderPrice("57bec1bf77f4d17c4c011960", 9.95); // $ExpectType ScreepsReturnCode + + // Game.market.createOrder({type, resourceType, price, totalAmount, [roomName]}) + Game.market.createOrder({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM, price: 9.95, totalAmount: 10000, roomName: "W1N1" }); // $ExpectType ScreepsReturnCode + Game.market.createOrder({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM, price: 9.95, totalAmount: 10000 }); // $ExpectType ScreepsReturnCode + + // Game.market.deal(orderId, amount, [yourRoomName]) + Game.market.deal("57cd2b12cda69a004ae223a3", 1000, "W1N1"); // $ExpectType ScreepsReturnCode + + const amountToBuy = 2000; + const maxTransferEnergyCost = 500; + const orders = Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); // $ExpectType Order[] + + for (const i of orders) { + if (i.roomName) { + const transferEnergyCost = Game.market.calcTransactionCost(amountToBuy, "W1N1", i.roomName); // $ExpectType number + + if (transferEnergyCost < maxTransferEnergyCost) { + Game.market.deal(i.id, amountToBuy, "W1N1"); // $ExpectType ScreepsReturnCode + break; + } + } + } + + // Game.market.extendOrder(orderId, addAmount) + Game.market.extendOrder("57bec1bf77f4d17c4c011960", 10000); // $ExpectType ScreepsReturnCode + + // Game.market.getAllOrders([filter]) + Game.market.getAllOrders(); // $ExpectType Order[] + Game.market.getAllOrders({ type: ORDER_SELL, resourceType: RESOURCE_GHODIUM }); // $ExpectType Order[] + + const targetRoom = "W1N1"; + // $ExpectType Order[] + 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"); // $ExpectType Order | null + + // Subscription tokens + Game.market.getAllOrders({ type: ORDER_SELL, resourceType: SUBSCRIPTION_TOKEN }); // $ExpectType Order[] + Game.market.createOrder({ type: ORDER_BUY, resourceType: SUBSCRIPTION_TOKEN, totalAmount: 10000000, price: 1 }); // $ExpectType ScreepsReturnCode + const priceHistory = Game.market.getHistory(RESOURCE_FIXTURES); // $ExpectType PriceHistory[] + + const avgPrice: number = priceHistory[0].avgPrice; + const stddevPrice: number = priceHistory[0].stddevPrice; + const volume: number = priceHistory[0].volume; + + // Game.market.getHistory([resourceType]) + const energyHistory = Game.market.getHistory(RESOURCE_ENERGY); // $ExpectType PriceHistory[] + const pixelHistory = Game.market.getHistory(PIXEL); // $ExpectType PriceHistory[] +} diff --git a/dist/tests/game.ts b/dist/tests/game.ts new file mode 100644 index 00000000..0f16330c --- /dev/null +++ b/dist/tests/game.ts @@ -0,0 +1,45 @@ +// Game.creeps + +{ + for (const i in Game.creeps) { + Game.creeps[i].moveTo(flag); + } +} + +// Game.flags + +{ + creep.moveTo(Game.flags.Flag1); +} + +// Game.time + +{ + let time = Game.time; // $ExpectType number + time += 1; +} + +// Game.getObjectById(id) + +{ + creep.memory.sourceId = creep.pos.findClosestByRange(FIND_SOURCES)!.id; // $ExpectType Id + const source = Game.getObjectById(creep.memory.sourceId); // $ExpectType Source | null +} + +// Game.notify(message, [groupInterval]) + +{ + if (creep.hits < creep.memory.lastHits) { + Game.notify(`Creep ${creep} has been attacked at ${creep.pos}!`); // $ExpectType void + } + creep.memory.lastHits = creep.hits; // $ExpectType number +} + +{ + if (Game.spawns["Spawn1"].energy === 0) { + Game.notify( + "Spawn1 is out of energy", + 180, // group these notifications for 3 hours + ); + } +} diff --git a/dist/tests/helpers.ts b/dist/tests/helpers.ts new file mode 100644 index 00000000..f0b8b0cf --- /dev/null +++ b/dist/tests/helpers.ts @@ -0,0 +1,30 @@ +// Sample inputs + +const creep: Creep = Game.creeps.sampleCreep; +const room: Room = Game.rooms.W10S10; +const flag: Flag = Game.flags.Flag1; +const powerCreep: PowerCreep = Game.powerCreeps.samplePowerCreep; +const spawn: StructureSpawn = Game.spawns.Spawn1; +const body: BodyPartConstant[] = [WORK, WORK, CARRY, MOVE]; + +// Sample inputs for Game.map.findRoute testing +const anotherRoomName: Room = Game.rooms.W10S11; + +// Sample memory extensions +interface CreepMemory { + sourceId: Id; + lastHits: number; +} + +// Typescript always uses 'string' as the type of a key inside 'for in' loops. +// In case of objects with a restricted set of properties (e.g. ResourceConstant as key in StoreDefinition) +// the type of the key should be narrowed down in order to prevent casting (key as ResourceConstant). +// This helper function provides strongly typed keys for such objects. +// See discussion (https://github.com/Microsoft/TypeScript/pull/12253) why Object.keys does not return typed keys. +function keys(o: T): Array { + return Object.keys(o) as Array; +} + +function resources(o: GenericStore): ResourceConstant[] { + return Object.keys(o) as ResourceConstant[]; +} diff --git a/dist/tests/memory.ts b/dist/tests/memory.ts new file mode 100644 index 00000000..6d7641b1 --- /dev/null +++ b/dist/tests/memory.ts @@ -0,0 +1,66 @@ +// RawMemory + +{ + // RawMemory.segments + + RawMemory.setActiveSegments([0, 3]); + // on the next tick + const segmentZero = RawMemory.segments[0]; + RawMemory.segments[3] = '{"foo": "bar", "counter": 15}'; + + // RawMemory.foreignSegment + + RawMemory.setActiveForeignSegment("player"); + // on the next tick + const playerSegment = RawMemory.foreignSegment; + // --> {"username": "player", "id": 40, "data": "Hello!"} + + // RawMemory.interShardSegment + + RawMemory.interShardSegment = JSON.stringify({ + creeps: { + Bob: { role: "claimer" }, + }, + }); + + // on another shard + const interShardData = JSON.parse(RawMemory.interShardSegment); + if (interShardData.creeps[creep.name]) { + creep.memory = interShardData[creep.name]; + delete interShardData.creeps[creep.name]; // tslint:disable-line no-dynamic-delete + } + RawMemory.interShardSegment = JSON.stringify(interShardData); + + // RawMemory.get() + const myMemory = JSON.parse(RawMemory.get()); + + // RawMemory.set(value) + RawMemory.set(JSON.stringify(myMemory)); + + // RawMemory.setActiveSegments(ids) + RawMemory.setActiveSegments([0, 3]); + + // RawMemory.setActiveForeignSegment(username, [id]) + RawMemory.setActiveForeignSegment("player"); + RawMemory.setActiveForeignSegment("player", 10); + RawMemory.setActiveForeignSegment(null); + + // RawMemory.setDefaultPublicSegment(id) + RawMemory.setPublicSegments([5, 20, 21]); + RawMemory.setDefaultPublicSegment(5); + RawMemory.setDefaultPublicSegment(null); + + // RawMemory.setPublicSegments(ids) + RawMemory.setPublicSegments([5, 3]); + RawMemory.setPublicSegments([]); +} + +// InterShardMemory + +{ + let localShardData = ""; + InterShardMemory.setLocal(localShardData); + localShardData = InterShardMemory.getLocal(); + + const remoteShardData: string = InterShardMemory.getRemote("shard2") || ""; +} diff --git a/dist/tests/pathfinder.ts b/dist/tests/pathfinder.ts new file mode 100644 index 00000000..5236a2d9 --- /dev/null +++ b/dist/tests/pathfinder.ts @@ -0,0 +1,57 @@ +// PathFinder + +{ + const pfCreep = Game.creeps.John; // $ExpectType Creep + + // 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. + return { pos: source.pos, range: 1 }; + }); + + // $ExpectType PathFinderPath + 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]; // $ExpectType Room + + // 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(); + + // tslint:disable-next-line:newline-per-chained-call + 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 + // tslint:disable-next-line:newline-per-chained-call + curRoom.find(FIND_CREEPS).forEach(thisCreep => { + costs.set(thisCreep.pos.x, thisCreep.pos.y, 0xff); + }); + + return costs; + }, + }); + + const pos = ret.path[0]; // $ExpectType RoomPosition + pfCreep.move(pfCreep.pos.getDirectionTo(pos)); +} diff --git a/dist/tests/room.ts b/dist/tests/room.ts new file mode 100644 index 00000000..603f5ad3 --- /dev/null +++ b/dist/tests/room.ts @@ -0,0 +1,56 @@ +// Room event log + +{ + room.getEventLog(); // $ExpectType EventItem[] + room.getEventLog(true); // $ExpectType EventItem[] + + const events = room.getEventLog(); // $ExpectType EventItem[] + + const event = events[0]; // $ExpectType EventItem + + switch (event.event) { + case EVENT_ATTACK: + const attackType: EventAttackType = event.data.attackType; // $ExpectType EventAttackType + break; + case EVENT_BUILD: + const energySpent: number = event.data.energySpent; // $ExpectTypenumber + break; + case EVENT_POWER: + const power = event.data.power; // $ExpectType PowerConstant + break; + } +} + +// Room.Terrain + +{ + const room = Game.rooms[""]; + + const myTerrain = room.getTerrain(); // $ExpectType RoomTerrain + + 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"); // $ExpectType RoomTerrain +} + +// ConstructionSite + +{ + room.createConstructionSite(10, 10, STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode + room.createConstructionSite(10, 11, STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode + + const pos = new RoomPosition(10, 10, room.name); + room.createConstructionSite(pos, STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode + room.createConstructionSite(pos, STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode + pos.createConstructionSite(STRUCTURE_EXTENSION); // $ExpectType ScreepsReturnCode + pos.createConstructionSite(STRUCTURE_SPAWN, "mySpawn"); // $ExpectType ScreepsReturnCode +} diff --git a/dist/tests/store.ts b/dist/tests/store.ts new file mode 100644 index 00000000..e2c9cf47 --- /dev/null +++ b/dist/tests/store.ts @@ -0,0 +1,25 @@ +// StoreDefinition + +{ + for (const resourceType of resources(creep.carry)) { + const amount = creep.carry[resourceType]; + creep.drop(resourceType, amount); + } + + const extension = new StructureExtension("" as Id); + + const e1: number = extension.store.getUsedCapacity(RESOURCE_ENERGY); // $ExpectType number + const e2: number = extension.store[RESOURCE_ENERGY]; // $ExpectType number + + // Invalid resource type for extension + const eg1: null = extension.store.getUsedCapacity(RESOURCE_GHODIUM); // $ExpectType null + const eg2: null = extension.store.getFreeCapacity(RESOURCE_GHODIUM); // $ExpectType null + const eg3: null = extension.store.getCapacity(RESOURCE_GHODIUM); // $ExpectType null + const eg4: 0 = extension.store.G; // $ExpectType 0 + + const storage = new StructureStorage("" as Id); + + const sg1: number = storage.store.getUsedCapacity(RESOURCE_GHODIUM); // $ExpectType number + const sg2: number = storage.store.getFreeCapacity(RESOURCE_GHODIUM); // $ExpectType number + const sg3: number = storage.store.getCapacity(RESOURCE_GHODIUM); // $ExpectType number +} diff --git a/dist/tests/structure.ts b/dist/tests/structure.ts new file mode 100644 index 00000000..73ab5058 --- /dev/null +++ b/dist/tests/structure.ts @@ -0,0 +1,67 @@ +// Advanced Structure types +{ + const owned = Game.getObjectById("blah")!; // $ExpectType AnyOwnedStructure + const owner = owned.owner && owned.owner.username; // $ExpectType string | undefined + owned.notifyWhenAttacked(false); + + const structs = room.find(FIND_MY_STRUCTURES); // $ExpectType AnyOwnedStructure[] + structs.forEach(struct => { + switch (struct.structureType) { + case STRUCTURE_CONTROLLER: + const usernameOptional: string | undefined = struct.owner && struct.owner.username; + break; + default: + const usernameRequired: string = struct.owner.username; + break; + } + }); + + const unowned = Game.getObjectById("blah2")!; // $ExpectType AnyStructure + const hp = unowned.hits / unowned.hitsMax; + + // test discriminated union + switch (unowned.structureType) { + case STRUCTURE_TOWER: + unowned; // $ExpectType StructureTower + unowned.heal(Game.creeps.myCreep); + break; + case STRUCTURE_CONTAINER: + case STRUCTURE_STORAGE: + case STRUCTURE_TERMINAL: + unowned.store; // $ExpectType StoreDefinition + const energyPercent = unowned.store.energy / unowned.storeCapacity; + break; + case STRUCTURE_WALL: + case STRUCTURE_RAMPART: + const wallHp = unowned.hits / unowned.hitsMax; + 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, + })[0]; + const to = from.pos.findClosestByPath(FIND_MY_STRUCTURES, { + 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)); +} + +// StructurePortal + +{ + const portals = room.find(FIND_STRUCTURES, { filter: s => s.structureType === STRUCTURE_PORTAL }); // $ExpectType StructurePortal[] + portals.forEach((p: StructurePortal) => { + const state = p.ticksToDecay === undefined ? "stable" : "unstable"; + if (p.destination instanceof RoomPosition) { + Game.notify(`Found ${state} inter-room portal to ${p.destination}`); + } else { + Game.notify(`Found ${state} inter-shard portal to ${p.destination.shard} ${p.destination.room}`); + } + }); +} diff --git a/dist/tests/structureLab.ts b/dist/tests/structureLab.ts new file mode 100644 index 00000000..f81e5b12 --- /dev/null +++ b/dist/tests/structureLab.ts @@ -0,0 +1,14 @@ +// StructureLab + +{ + const lab0 = Game.getObjectById("lab0"); + 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) { + lab0.runReaction(lab1, lab2); // $ExpectType ScreepsReturnCode + } + // nevermind, reverse that + lab0.reverseReaction(lab1, lab2); // $ExpectType ScreepsReturnCode + } +} diff --git a/dist/tests/structureSpawn.ts b/dist/tests/structureSpawn.ts new file mode 100644 index 00000000..f118f27d --- /dev/null +++ b/dist/tests/structureSpawn.ts @@ -0,0 +1,28 @@ +// Game.spawns + +{ + for (const i in Game.spawns) { + Game.spawns[i].createCreep(body); + + // Test StructureSpawn.Spawning + let creep = Game.spawns[i].spawning; // $ExpectType Spawning | null + if (creep) { + const name: string = creep.name; // $ExpectType string + const needTime: number = creep.needTime; // $ExpectType number + const remainingTime: number = creep.remainingTime; // $ExpectType number + const creepSpawn: StructureSpawn = creep.spawn; // $ExpectType StructureSpawn + + const cancelStatus: OK | ERR_NOT_OWNER = creep.cancel(); + const setDirectionStatus: OK | ERR_NOT_OWNER | ERR_INVALID_ARGS = creep.setDirections([TOP, BOTTOM, LEFT, RIGHT]); + } + + creep = new StructureSpawn.Spawning("" as Id); // $ExpectType Spawning + creep = StructureSpawn.Spawning("" as Id); // $ExpectType Spawning + + const invaderCore = new StructureInvaderCore("" as Id); + const invader = invaderCore.spawning; // $ExpectType Spawning | null + if (invader) { + const name = invader.name; // $ExpectType string + } + } +} diff --git a/dist/tsconfig.json b/dist/tsconfig.json index 8dcc302c..1e43200c 100644 --- a/dist/tsconfig.json +++ b/dist/tsconfig.json @@ -19,5 +19,8 @@ "files": [ "index.d.ts", "screeps-tests.ts" + ], + "include": [ + "./tests/**/*.ts" ] }