├── .gitconsensus.yaml ├── README.md └── src ├── classes ├── JavaScript │ ├── Es6LRUMapWithSizeAndTtl.js │ ├── WorldPosition.js │ ├── bitSet.js │ ├── class.RoomVisualCache_module.js │ └── creepsSingingSongs.js └── TypeScript │ └── .gitignore ├── client-abuse └── JavaScript │ ├── LoAN_tampermonkey_inject_for_any_client.js │ ├── inject_script_tag.js │ ├── run_window.onTick()_inside_the_client_per_tick.js │ ├── saveAlliancesInMemory.js │ ├── util.inject.Birthday.js │ ├── util.inject.RoomTracker.js │ ├── util.inject.RoomViewNotifier.js │ └── util.inject.TEMPLATE.js ├── globals ├── Cached dynamic properties.js ├── Entity Message Bus.js ├── JavaScript │ ├── Global functions etc. example.js │ ├── Reverse lookup tables for errors, colors, and resources.js │ ├── adjust_CPU_limit_based_on_bucket_levels.js │ ├── boostComponentsObject.js │ ├── calculateTickTimeInGame.js │ ├── command to clear in-game console.js │ ├── determineFileFunctionLineWithinCode.js │ ├── hasRespawned.js │ ├── optimizedIsActive.js │ ├── resourceColors.js │ ├── respawn assist to clear memory and flags.js │ ├── setTimeout_setInterval.js │ ├── to get memory size.js │ ├── tool.marketCalculator.js │ └── voiceConsole.js ├── Memory segment emulation.js ├── Reverse lookup tables for errors, colors, and resources.js ├── TypeScript │ └── .gitignore ├── queueAction() system.js └── upkeep_costs.js ├── logging ├── JavaScript │ └── .gitignore └── TypeScript │ └── .gitignore ├── misc ├── JavaScript │ ├── Calculate Cost of a Mine.js │ ├── Check if room is a source keeper room.js │ ├── Global Tracking.js │ ├── Memory Cache.js │ ├── Minimal Starting AI.js │ ├── OwnedStructure Memory.js │ ├── Remote mining generator.js │ ├── Reset Memory to default.js │ ├── Simple benchmarks.js │ ├── Simplified grid class.js │ ├── String encryption.js │ ├── Uint8ArrayConversion.js │ ├── Unicode directional arrows.js │ ├── WorldPosition uniform global coordinate system.js │ ├── actually commented evil tower code.js │ ├── bunkerLayoutsHumanReadable.js │ ├── colors.js │ ├── get room type without visibility (but regex^^).js │ ├── how to delete the memory of dead creeps (in memoriam!).js │ ├── minCutWallRampartsPlacement.js │ ├── module.exports example.js │ ├── moveTo version supporting raw PathFinder arguments, and a moveByPath which directly reads serialized strings.js │ ├── powerCreepChatter.js │ ├── protocolBufferStorage.js │ ├── pushdownAutomataStateMachine.js │ ├── roomDescribe.js │ ├── screeps_astar.js │ └── sos_lib_crypto.js ├── Kotlin │ ├── .gitignore │ ├── DistanceTransform │ │ └── DistanceTransform.kt │ ├── MinCut │ │ └── MinCut.kt │ └── VipoOS │ │ ├── Kernel.kt │ │ ├── Process.kt │ │ ├── Program.kt │ │ ├── Programs │ │ └── Demo.kt │ │ ├── Scheduler.kt │ │ └── Signals.kt ├── TypeScript │ ├── Creep intent tracker.ts │ ├── Typescript roomScan.ts │ └── moving.average.ts ├── migrate room to sim.md └── screeps body calculator.md └── prototypes ├── JavaScript ├── Creep │ ├── Creep action error handler.js │ ├── Creep.getOffExit.js │ ├── Freshly minted getActiveBodyparts accounting for boosts!.js │ ├── Idle_Suspend for creeps.js │ ├── excuseMe.js │ ├── prototype.Creep.moveToStandByPos.js │ ├── untitled_activeBodyparts.js │ └── util.fun.singing.js ├── DefineProperty Tutorial.js ├── Monkey Patching Tutorial.js ├── Room │ ├── Room.mineral.js │ └── prototype.Room.structures.js ├── RoomObject │ ├── Generalized target locking (with examples).js │ ├── lookForNear.js │ ├── lookNear.js │ └── roomObjectSay.js ├── RoomPosition │ ├── findFirstInRange implementation for RoomPosition.js │ ├── prototype.RoomPosition.toString_fromString.js │ └── toString()s_w_HTML_link_and_selection.js ├── RoomVisual │ └── RawVisual Structures.js ├── Source │ └── Memory for Source (or other objects).js ├── StructureLink │ └── modified link.transferEnergy to prevent redundant multiple sends to the same target.js └── functionMiddleware.js └── TypeScript ├── .gitignore └── excuseMe.ts /.gitconsensus.yaml: -------------------------------------------------------------------------------- 1 | # See https://github.com/gitconsensus/GitConsensusCLI for more information about this file. 2 | 3 | version: 3 4 | 5 | # Don't count any vote from a user who votes for multiple options 6 | prevent_doubles: true 7 | 8 | # Add extra labels for the vote counts and age when merging 9 | extra_labels: true 10 | 11 | 12 | pull_requests: 13 | 14 | # At least six people should sign off on any pull request. 15 | quorum: 6 16 | 17 | # Required percentage of "yes" votes (ignoring abstentions). It's a good idea to give "no" votes more power. 18 | threshold: 0.74 19 | 20 | # Number of hours after last action (commit or opening the pull request) before issue can be merged 21 | merge_delay: 240 22 | 23 | # Number of votes at which the merge_delay gets ignored, assuming no negative votes. 24 | delay_override: 18 25 | 26 | # Close pull requests that don't pass after thirty days without any activity (new commits). 27 | timeout: 720 28 | 29 | # Do not allow changes to the license. 30 | license_lock: true 31 | 32 | # Allow the consensus rules (this file) to be changed. 33 | consensus_lock: false 34 | 35 | # Wait for at least ten days before merging any new consensus rules. 36 | consensus_delay: 240 37 | 38 | # Allow anyone to vote on this project, even if they've never contributed. 39 | contributors_only: false 40 | 41 | # Don't put any restrictions on who can vote. 42 | collaborators_only: false 43 | 44 | -------------------------------------------------------------------------------- /src/classes/JavaScript/Es6LRUMapWithSizeAndTtl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * posted 3 April 2018 by @warinternal 3 | * 4 | * A cache that can exhibit both least recently used (LRU) and max time to live (TTL) eviction policies. 5 | * 6 | * Internally the cache is backed by a `Map` but also maintains a linked list of entries to support the eviction policies. 7 | * Source: https://github.com/ianp/es6-lru-cache 8 | */ 9 | 'use strict'; 10 | 11 | class LRU { 12 | 13 | // cache entries are objects with 14 | // key - duplicated here to make iterator based methods more efficient 15 | // value 16 | // prev - a pointer 17 | // next - a pointer 18 | // expires - time of death in Date.now 19 | 20 | /** 21 | * 22 | * @param {number} ttl - the max. time to live, in ticks 23 | * @param {number} max - the max. number of entries in the cache 24 | * @param {Object|Iterable} data - the data to initialize the cache with 25 | */ 26 | constructor({ ttl, max, data = {} }) { 27 | this.data = new Map(); 28 | if (max) { this.max = max; } 29 | if (ttl) { this.ttl = ttl; } 30 | // this.head = undefined 31 | // this.tail = undefined 32 | if (data) { 33 | if (data[Symbol.iterator]) { 34 | for (const [key, value] in data) { 35 | this.set(key, value); 36 | } 37 | } else { 38 | Object.keys(data).forEach(key => this.set(key, data[key])); 39 | } 40 | } 41 | } 42 | 43 | clear() { 44 | this.data.clear(); 45 | this.head = undefined; 46 | this.tail = undefined; 47 | } 48 | 49 | delete(key) { 50 | const curr = this.data.get(key); 51 | if (this.data.delete(key)) { 52 | this._remove(curr); 53 | return true; 54 | } 55 | return false; 56 | } 57 | 58 | entries() { 59 | return this.it(entry => [entry.key, entry.value]); 60 | } 61 | 62 | evict() { 63 | let curr,count = 0; 64 | const {max} = this; 65 | const now = this.ttl ? Game.time : false; 66 | for (curr = this.head; curr; curr = curr.next) { 67 | ++count; 68 | if ((max && max < count) || (now && now > curr.expires)) { 69 | this.data.delete(curr.key); 70 | this._remove(curr); 71 | } 72 | } 73 | return this.data.size; 74 | } 75 | 76 | forEach(callback) { 77 | const iterator = this.it(entry => { 78 | callback(entry.key, entry.value); // todo: support thisArg parameter 79 | return true; 80 | }); 81 | while (iterator.next()) { /* no-op */ } 82 | } 83 | 84 | get(key) { 85 | const entry = this.data.get(key); 86 | if (entry) { 87 | if (entry.expires && entry.expires < Game.time) { 88 | this.delete(key); 89 | } else { 90 | this._remove(entry); 91 | this._insert(entry); 92 | return entry.value; 93 | } 94 | } 95 | return null; 96 | } 97 | 98 | has(key) { 99 | const entry = this.data.get(key); 100 | if (entry) { 101 | if (entry.expires && entry.expires < Game.time) { 102 | this.delete(key); 103 | } else { 104 | return true; 105 | } 106 | } 107 | return false; 108 | } 109 | 110 | keys() { 111 | return this.it(entry => entry.key); 112 | } 113 | 114 | set(key, value) { 115 | let curr = this.data.get(key); 116 | if (curr) { 117 | this._remove(curr); 118 | } else { 119 | this.data.set(key, curr = {}); 120 | } 121 | curr.key = key; 122 | curr.value = value; 123 | if (this.ttl) { curr.expires = Game.time + this.ttl; } 124 | this._insert(curr); 125 | this.evict(); 126 | return this; 127 | } 128 | 129 | get size() { 130 | // run an eviction then we will report the correct size 131 | return this.evict(); 132 | } 133 | 134 | values() { 135 | return this.it(entry => entry.value); 136 | } 137 | 138 | [Symbol.iterator]() { 139 | return this.it(entry => [entry.key, entry.value]); 140 | } 141 | 142 | *it(accessFn) { 143 | this.evict(); 144 | let curr; 145 | for (curr = this.head; curr; curr = curr.next) 146 | yield accessFn(curr); 147 | } 148 | 149 | /** 150 | * Remove entry `curr` from the linked list. 151 | * @private 152 | */ 153 | _remove(curr) { 154 | if (!curr.prev) { 155 | this.head = curr.next; 156 | } else { 157 | curr.prev.next = curr.next; 158 | } 159 | if (!curr.next) { 160 | this.tail = curr.prev; 161 | } else { 162 | curr.next.prev = curr.prev; 163 | } 164 | } 165 | 166 | /** 167 | * Insert entry `curr` into the head of the linked list. 168 | * @private 169 | */ 170 | _insert(curr) { 171 | if (!this.head) { 172 | this.head = curr; 173 | this.tail = curr; 174 | } else { 175 | const node = this.head; 176 | curr.prev = node.prev; 177 | curr.next = node; 178 | if (!node.prev) { 179 | this.head = curr; 180 | } else { 181 | node.prev.next = curr; 182 | } 183 | node.prev = curr; 184 | } 185 | } 186 | } 187 | 188 | module.exports = LRU; -------------------------------------------------------------------------------- /src/classes/JavaScript/WorldPosition.js: -------------------------------------------------------------------------------- 1 | // warinternal 9 October 2016 at 22:03 2 | 3 | /** 4 | * Uniform screep's world position with E0S0 as origin. 5 | */ 6 | 'use strict'; 7 | class WorldPosition 8 | { 9 | /** @property int x */ 10 | /** @property int y */ 11 | 12 | /** 13 | * @params {Object} point 14 | * @params {number} point.x - world position x (-3025 to 3025) 15 | * @params {number} point.y - world position y (-3025 to 3025) 16 | */ 17 | constructor(x,y) { 18 | this.x = x; 19 | this.y = y; 20 | Object.seal(this); 21 | } 22 | 23 | /** 24 | * @params {Object} point 25 | * @params {number} point.x 26 | * @params {number} point.y 27 | */ 28 | getRangeTo(point) { 29 | return this.getRangeToXY(point.x, point.y); 30 | } 31 | ​ 32 | /** 33 | * @params {number} x 34 | * @params {number} y 35 | */ 36 | getRangeToXY(x,y) { 37 | return this.getChebyshevDist(x,y); 38 | } 39 | 40 | inRangeTo(point, range) { 41 | return this.inRangeToXY(point.x, point.y, range); 42 | } 43 | 44 | inRangeToXY(x,y,range) { 45 | return (this.getRangeToXY(x,y) <= range); 46 | } 47 | 48 | getDirectionTo(point) { 49 | return this.getDirectionToXY(point.x, point.y); 50 | } 51 | 52 | /** 53 | * @params {number} x - world coordinate x 54 | * @params {number} y - world coordinate y 55 | * ..don't question it. don't even think about it. 56 | */ 57 | getDirectionToXY(x,y) { 58 | let [dx,dy] = [x - this.x, y - this.y]; 59 | let arc = Math.atan2(dy, dx) * (180 / Math.PI); 60 | let dir = Math.round((arc / 45) + 3); 61 | return (dir == 0)?8:dir; 62 | } 63 | 64 | findRouteToWorldPosition(pos, opts) { 65 | return Game.map.findRoute(this.getRoomName(), pos.getRoomName(), opts); 66 | } 67 | 68 | findPathToWorldPosition(pos, opts) { 69 | let src = this.toRoomPosition(); 70 | let dst = pos.toRoomPosition(); 71 | return PathFinder.search(src, dst, opts); 72 | } 73 | 74 | /** 75 | * @params [WorldPosition] - array of other world positions to compare 76 | */ 77 | findClosestByRange(arr) { 78 | return _.min(arr, p => this.getRangeTo(p.wpos)); 79 | } 80 | 81 | /** @returns String - name of the room this point belongs to */ 82 | getRoomName() { 83 | let [x,y] = [Math.floor(this.x / 50), Math.floor(this.y / 50)] 84 | let result = ""; 85 | result += (x < 0 ? "W" + String(~x) : "E" + String(x)); 86 | result += (y < 0 ? "N" + String(~y) : "S" + String(y)); 87 | return result; 88 | } 89 | 90 | /** @returns boolean - do we have visibility in the room this point belongs to? */ 91 | isVisible() { 92 | let name = this.getRoomName(); 93 | return (Game.rooms[name] !== undefined); 94 | } 95 | 96 | /** @returns boolean - is this room part of the highways between sectors? */ 97 | isHighway() { 98 | let roomName = this.getRoomName(); 99 | let parsed = roomName.match(/^[WE]([0-9]+)[NS]([0-9]+)$/); 100 | return (parsed[1] % 10 === 0) || (parsed[2] % 10 === 0); 101 | } 102 | 103 | /** @returns boolean - do I own this point in space? */ 104 | isMine() { 105 | let roomName = this.getRoomName(); 106 | return _.get(Game.rooms, roomName + '.controller.my', false); 107 | } 108 | 109 | /** Distance functions */ 110 | ​ 111 | /** 112 | * @params {Object} point 113 | * @params {number} point.x 114 | * @params {number} point.y 115 | */ 116 | getEuclidDist(pos) { 117 | return Math.hypot( pos.x - this.x, pos.y - this.y ); 118 | } 119 | 120 | /** 121 | * @params {Object} point 122 | * @params {number} point.x 123 | * @params {number} point.y 124 | */ 125 | getManhattanDist(pos) { 126 | return Math.abs(pos.x - this.x) + Math.abs(pos.y - this.y); 127 | } 128 | 129 | // yeah. and with that, it'll give you the correct distance of diagonals, whereas manhattan won't consider that. 130 | /** 131 | * @params {Object} point 132 | * @params {number} point.x 133 | * @params {number} point.y 134 | */ 135 | getChebyshevDist(x,y) { 136 | return Math.max( Math.abs((x-this.x)), Math.abs((y-this.y)) ); 137 | } 138 | 139 | /** serialization */ 140 | serialize() { 141 | return this.x + "_" + this.y; 142 | } 143 | 144 | static deserialize(str) { 145 | let [x,y] = str.split('_'); 146 | return new WorldPosition(x,y); 147 | } 148 | 149 | /** [object WorldPosition] */ 150 | get [Symbol.toStringTag]() { 151 | return 'WorldPosition'; 152 | } 153 | 154 | 155 | /** 156 | * @params {RoomPosition} roomPos 157 | * @params {number} roomPos.x 158 | * @params {number} roomPos.y 159 | * @params {String} roomPos.roomName 160 | * @returns {WorldPosition} 161 | */ 162 | static fromRoomPosition(roomPos) { 163 | let {x,y,roomName} = roomPos; 164 | if(!_.inRange(x, 0, 50)) throw new RangeError('x value ' + x + ' not in range'); 165 | if(!_.inRange(y, 0, 50)) throw new RangeError('y value ' + y + ' not in range'); 166 | if(roomName == 'sim') throw new RangeError('Sim room does not have world position'); 167 | let [name,h,wx,v,wy] = roomName.match(/^([WE])([0-9]+)([NS])([0-9]+)$/); 168 | if(h == 'W') x = ~x; 169 | if(v == 'N') y = ~y; 170 | return new WorldPosition( (50*wx)+x, (50*wy)+y ); 171 | } 172 | 173 | toRoomPosition() { 174 | let [rx,x] = [Math.floor(this.x / 50), this.x % 50]; 175 | let [ry,y] = [Math.floor(this.y / 50), this.y % 50]; 176 | if( rx < 0 && x < 0 ) x = (49 - ~x); 177 | if( ry < 0 && y < 0 ) y = (49 - ~y); 178 | return new RoomPosition(x,y,this.getRoomName()); 179 | } 180 | 181 | /** [world pos 1275,1275] */ 182 | toString() { 183 | return "[world pos " + this.x + "," + this.y + "]"; 184 | } 185 | } 186 | ​ 187 | Object.defineProperty(RoomObject.prototype, "wpos", { 188 | get: function () { 189 | if(!this._wpos) 190 | this._wpos = WorldPosition.fromRoomPosition(this.pos); 191 | return this._wpos; 192 | }, 193 | configurable: true, 194 | enumerable: false 195 | }); 196 | ​ 197 | RoomPosition.prototype.toWorldPosition = function() { 198 | if(!this._wpos) 199 | this._wpos = WorldPosition.fromRoomPosition(this); 200 | return this._wpos; 201 | } 202 | ​ 203 | module.exports = WorldPosition; -------------------------------------------------------------------------------- /src/classes/JavaScript/bitSet.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Posted 23 April 2019 by @warinternal 4 | * os.ds.bitset.js 5 | */ 6 | 'use strict'; 7 | 8 | exports.BitSet = class { 9 | /** 10 | * Defaults to 1 unsigned 32 bit int 11 | * @param {*} val 12 | */ 13 | constructor(val = 1) { 14 | this.store = new Uint32Array(val); 15 | this.width = this.store.BYTES_PER_ELEMENT * 8; 16 | } 17 | 18 | calcIndex(bit) { 19 | return [~~(bit / this.width), bit % this.width]; 20 | } 21 | 22 | isset(bit) { 23 | const [b, i] = this.calcIndex(bit); 24 | return !!(this.store[b] & (1 << i)); 25 | } 26 | 27 | set(bit) { 28 | const [b, i] = this.calcIndex(bit); 29 | if (b >= this.store.length) 30 | this.resize(b + 1); 31 | this.store[b] |= (1 << i); 32 | return this; 33 | } 34 | 35 | unset(bit) { 36 | const [b, i] = this.calcIndex(bit); 37 | this.store[b] &= ~(1 << i); 38 | return this; 39 | } 40 | 41 | resize(length = 1) { 42 | const old = this.store; 43 | this.store = new Uint32Array(length); 44 | this.store.set(old); 45 | return this; 46 | } 47 | 48 | clear() { 49 | this.store = new Uint32Array(0); 50 | return this; 51 | } 52 | 53 | static from(val) { 54 | return new this(val); 55 | } 56 | 57 | toString() { 58 | return `[BitSet ${this.store.length}]`; 59 | } 60 | }; -------------------------------------------------------------------------------- /src/classes/JavaScript/class.RoomVisualCache_module.js: -------------------------------------------------------------------------------- 1 | /* Posted April 2nd, 2017 by @semperrabbit*/ 2 | /* 3 | * require('class.RoomVisualCache'); 4 | * 5 | * Include this module *after* you defined your custom RoomVisual prototypes. 6 | * Caching changes RoomObjects to RoomPositions automatically. On commit(), 7 | * your custom prototypes may break if they do not expect RoomPositions. 8 | * 9 | * Example: 10 | var rvc = new RoomVisualCache(Game.rooms[roomName].visual); 11 | rvc.loadString(Memory.rooms[roomName].visCache); 12 | 13 | rvc.text(10, 10, "this is addition to anything saved"); // stores the text command and parameters to its cache 14 | rvc.commit(); // displays visual from cached data 15 | 16 | Memory.rooms[roomName].visCache = rvc.saveString(); // saves any changes back to memory 17 | 18 | */ 19 | 20 | // Used with JSON.parse to ensure any RoomPosition gets properly initialized as 21 | // a RoomObject, not a raw object 22 | global.ROOM_OBJECT_REVIVER = function(name, val) { 23 | if( typeof val == 'object' && val.x !== undefined && 24 | val.y !== undefined && val.roomName !== undefined) { 25 | return new RoomPosition(val.x, val.y, val.roomName); 26 | } 27 | return val; 28 | } 29 | 30 | var RoomVisualCache = function(rv) { 31 | this.visual = rv; 32 | this.cache = []; 33 | } 34 | 35 | RoomVisualCache.prototype.register = function(func, ...args){ 36 | var name = func.name || func; // allow for passing a function object or name 37 | this.cache.push({name, args}); 38 | } 39 | 40 | RoomVisualCache.prototype.saveString = function() { 41 | return JSON.stringify(this.cache); 42 | } 43 | 44 | RoomVisualCache.prototype.loadString = function(str) { 45 | if(!str) { 46 | this.cache = []; 47 | return; 48 | } 49 | this.cache = JSON.parse(str, ROOM_OBJECT_REVIVER); 50 | } 51 | 52 | RoomVisualCache.prototype.commit = function() { 53 | var i; 54 | for(i in this.cache) { 55 | var {name, args} = this.cache[i]; 56 | RoomVisual.prototype[name].apply(this.visual, args); 57 | } 58 | } 59 | 60 | RoomVisualCache.prototype.getSize = function() { 61 | return this.rv.getSize(); 62 | } 63 | 64 | RoomVisualCache.prototype.clear = function() { 65 | this.cache = []; 66 | this.rv.clear(); 67 | } 68 | 69 | RoomVisualCache.registerPrototype = function() { 70 | var excludes = ['constructor', 'getSize', 'clear']; 71 | var funcList = _.filter(Object.keys(RoomVisual.prototype), f=>excludes.indexOf(f) === -1); 72 | for(let funcName of funcList) { 73 | RoomVisualCache.prototype[funcName] = function(...args) { 74 | var i, test, callArgs = []; 75 | for(i in args) { // change all RoomObjects into their corresponding RoomPositions 76 | test = args[i]; 77 | if(test.pos) { callArgs.push(test.pos); 78 | } else { callArgs.push(test); 79 | } 80 | } 81 | RoomVisualCache.prototype.register.apply(this, [funcName].concat(callArgs)); 82 | } 83 | } 84 | } 85 | RoomVisualCache.registerPrototype(); 86 | 87 | 88 | RoomVisualCache.test = function(roomName){ 89 | var rv = Game.rooms[roomName] ? Game.rooms[roomName].visual : undefined; 90 | var rvc = new RoomVisualCache(rv); 91 | var rvc2 = new RoomVisualCache(rv); 92 | rvc2.text(('CPU: '+Game.cpu.getUsed()), _.sample(Game.creeps)); 93 | rvc2.text('Total Creeps: ' + Object.keys(Game.creeps).length, 10, 2); 94 | 95 | rvc.loadString(Memory.testRoomVisualCache || rvc2.saveString()); 96 | rvc.circle(25, 25, {radius: 5}); 97 | rvc.commit(); 98 | 99 | Memory.testRoomVisualCache = rvc2.saveString(); 100 | 101 | } 102 | 103 | module.exports = global.RoomVisualCache = RoomVisualCache; -------------------------------------------------------------------------------- /src/classes/JavaScript/creepsSingingSongs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 26 February 2018 by @Lucifer (fihercho) 3 | */ 4 | class CreepsSing { 5 | sing(){ 6 | function compare(a,b) { 7 | if (a.ticksToLive === b.ticksToLive){ 8 | return 0 9 | }else{ 10 | return a.ticksToLive < b.ticksToLive ? 1:-1 11 | } 12 | } 13 | let creeps = Object.values(Game.creeps) 14 | .filter(creep => creep.memory.role === 'Singer') 15 | .sort(compare) 16 | 17 | let song = ["Buddy you are a boy make a big noise", 18 | "Playin' in the street", 19 | "gonna be a big man some day", 20 | "You got mud on yo' face", 21 | "You big disgrace", 22 | "Kickin' your can all over the place", 23 | "Singin'", 24 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 25 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 26 | "Buddy you're a young man hard man", 27 | "Shoutin' in the street", 28 | "gonna take on the world some day", 29 | "You got blood on yo' face", 30 | "You big disgrace", 31 | "Wavin' your banner all over the place", 32 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 33 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 34 | "Sing it!", 35 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 36 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 37 | "Buddy you're an old man poor man", 38 | "Pleadin' with your eyes", 39 | "gonna make you some peace some day", 40 | "You got mud on your face", 41 | "Big disgrace", 42 | "Somebody better put you back into your place", 43 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 44 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 45 | "Sing it!", 46 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 47 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 48 | "Everybody", 49 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 50 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 51 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 52 | "W E W I L L","","W E W I L L","","R O C K YOU !!!", 53 | "(Alright)"] 54 | let flag = Game.flags.helloFlag 55 | for(let i = 0; i < creeps.length;i++){ 56 | let creep = creeps[i] 57 | if(creep.pos.roomName === flag.pos.roomName){ 58 | let x = flag.pos.x + i * 3 59 | let y = flag.pos.y 60 | let roomName = flag.pos.roomName 61 | creep.moveTo(new RoomPosition(x, y,roomName)) 62 | let sentence = song[Game.time % song.length] 63 | let words = sentence.split(' ') 64 | if(words.length > creeps.length){ 65 | for(let k = 0;k 16 | if(!window.LoANInjected){ 17 | window.LoANInjected = true; 18 | xhr=new XMLHttpRequest(); 19 | xhr.open('GET', 'https://raw.githubusercontent.com/semperrabbit/loan-browser-ext/master/dist/alliance-overlay.user.js', true); 20 | xhr.onreadystatechange=function(){ 21 | if(xhr.readyState===XMLHttpRequest.DONE&&xhr.status===200){ 22 | let src=document.createElement('script'); 23 | src.lang='javascript'; 24 | src.innerHTML=xhr.responseText; 25 | document.head.appendChild(src); 26 | console.log('resp',xhr.responseText); 27 | } 28 | }; 29 | xhr.send(); 30 | } 31 | ` 32 | console.log(output.split('\n').join(';')); 33 | 34 | } 35 | 36 | global.forceInjectLoAN = ()=>{global.LoANInjected = false; injectLoAN();} 37 | 38 | injectLoAN(); -------------------------------------------------------------------------------- /src/client-abuse/JavaScript/inject_script_tag.js: -------------------------------------------------------------------------------- 1 | /* Posted February 18th, 2017 by @semperrabbit */ 2 | 3 | document.injectScriptTag = function injectScriptTag(url){ 4 | return new Promise(function(good, bad){ 5 | const xhr = new XMLHttpRequest(); 6 | xhr.open('GET', url, true); 7 | xhr.onload = function () { 8 | if (xhr.status >= 200 && xhr.status < 300) { 9 | let src=document.createElement('script'); 10 | src.lang='javascript'; 11 | src.innerHTML=xhr.responseText; 12 | document.head.appendChild(src); 13 | console.log('resp',xhr.responseText); 14 | good({status: this.status, responseText: xhr.responseText}); 15 | } else { 16 | bad({ status: this.status, statusText: xhr.statusText }); 17 | } 18 | }; 19 | xhr.onerror = function () { 20 | bad({ status: this.status, statusText: xhr.statusText }); 21 | }; 22 | xhr.send(); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /src/client-abuse/JavaScript/run_window.onTick()_inside_the_client_per_tick.js: -------------------------------------------------------------------------------- 1 | /* Posted December 3rd, 2017 by @semperrabbit */ 2 | 3 | /* needs to be put in util.inject.TEMPLATE in conjunction with a definition of `window.onTick()`*/ 4 | (function(){ 5 | if(window.tickHook) 6 | return; 7 | angular.element($('body')).injector().get('Connection').onRoomUpdate(angular.element(document.getElementsByClassName("room ng-scope")).scope(), function() 8 | { 9 | if(window.onTick) 10 | window.onTick(); 11 | }) 12 | window.tickHook = true; 13 | })(); -------------------------------------------------------------------------------- /src/client-abuse/JavaScript/saveAlliancesInMemory.js: -------------------------------------------------------------------------------- 1 | /* Posted January 26th, 2017 by @semperrabbit */ 2 | /** 3 | * Inject alliance data into Memory.alliances in the form of Memory.alliances[alliance][player]. 4 | * The code will auto-update every 6 hrs of your leaving the client open. 5 | * 6 | * Usage: 7 | * saveAlliancesInMemory(); 8 | * Memory usage after calling: 9 | * if(Memory.alliances[alliance][player]) { 10 | * console.log(player + ' is in alliance ' + alliance); 11 | * } else { 12 | * console.log(player + ' is not in alliance ' + alliance); 13 | * } 14 | * 15 | * Special thanks to akusnayesa for teaching me how Promises *really* work. 16 | * 17 | * @author SemperRabbit 18 | */ 19 | global.saveAlliancesInMemory = function saveAlliancesInMemory(){ 20 | if(!global.alliancesSavedInMemory) { 21 | global.alliancesSavedInMemory = true; 22 | var script = `Saving alliance data to Memory...`; 57 | console.log(_(script).split('\n').map(s=>s.trim()).join('')); 58 | } 59 | } -------------------------------------------------------------------------------- /src/client-abuse/JavaScript/util.inject.Birthday.js: -------------------------------------------------------------------------------- 1 | /* Posted July 5th, 2019 by @semperrabbit */ 2 | 3 | // v1.4 4 | // special thanks to ags131, Robalian, and QGazQ for the assists 5 | // Author: SemperRabbit 6 | // 20190705 7 | 8 | global.injectBirthday = function(){//* 9 | if(!global.BirthdayInjected) { 10 | global.BirthdayInjected = true; 11 | var output = `Trying to inject Birthday code! 12 | ` 78 | console.log(output.replace(/(\r\n|\n|\r)\t+|(\r\n|\n|\r) +|(\r\n|\n|\r)/gm, '')); 79 | } 80 | //*/ 81 | } 82 | 83 | global.forceInjectBirthday = ()=>{global.BirthdayInjected = false; injectBirthday();} 84 | 85 | injectBirthday(); -------------------------------------------------------------------------------- /src/client-abuse/JavaScript/util.inject.RoomTracker.js: -------------------------------------------------------------------------------- 1 | /* Posted April 4th, 2018 by @semperrabbit */ 2 | /* 3 | * require('util.inject.RoomTracker'); 4 | * 5 | * Allows for the retrieval of rooms currently being viewed in the client from in-game code. 6 | * 7 | * injectRoomTracker() will be called on each global reload. To manually inject into a client after a global reset, or upon opening an additional tab, 8 | * call forceInjectRoomTracker(). 9 | * 10 | * Use `getViewedRooms()` each tick to retrieve any viewed rooms. It returns an array or rooms. 11 | */ 12 | global.injectRoomTracker = function(){//* 13 | if(!global.RoomTrackerInjected) { 14 | global.RoomTrackerInjected = true; 15 | var output = `Trying to inject RoomTracker code! 16 | ` 36 | console.log(output.replace(/(\r\n|\n|\r)\t+|(\r\n|\n|\r) +|(\r\n|\n|\r)/gm, '')); 37 | } 38 | //*/ 39 | } 40 | 41 | global.forceInjectRoomTracker = ()=>{global.RoomTrackerInjected = false; injectRoomTracker();} 42 | 43 | injectRoomTracker(); 44 | 45 | global.getViewedRooms = function getViewedRooms(){ 46 | global.roomsViewed = global.roomsViewed ? _.filter(global.roomsViewed, (v)=>v.tick>=Game.time-1) : []; 47 | return roomsViewed = global.roomsViewed.map(v=>v.roomName); 48 | } -------------------------------------------------------------------------------- /src/client-abuse/JavaScript/util.inject.RoomViewNotifier.js: -------------------------------------------------------------------------------- 1 | /* Posted December 3rd, 2018 by @semperrabbit*/ 2 | 3 | // Note: excessive use of client's API connection may cause devs to lock it down 4 | global.injectRoomViewNotifier = function(){//* remove one / before this comment if things break... 5 | if(!global.RoomViewNotifierInjected) { 6 | global.RoomViewNotifierInjected = true; 7 | var output = `Trying to inject RoomViewNotifier code! 8 | ` 28 | console.log(output.replace(/(\r\n|\n|\r)\t+|(\r\n|\n|\r) +|(\r\n|\n|\r)/gm, '')); 29 | } 30 | //*/ 31 | } 32 | 33 | global.forceInjectRoomViewNotifier = ()=>{global.RoomViewNotifierInjected = false; injectRoomViewNotifier();} 34 | 35 | injectRoomViewNotifier(); -------------------------------------------------------------------------------- /src/client-abuse/JavaScript/util.inject.TEMPLATE.js: -------------------------------------------------------------------------------- 1 | /* Posted February 11th, 2017 by @semperrabbit */ 2 | 3 | global.injectNAME = function(){//* 4 | if(!global.NAMEInjected) { 5 | global.NAMEInjected = true; 6 | var output = `Trying to inject NAME code! 7 | ` 10 | console.log(output.replace(/(\r\n|\n|\r)\t+|(\r\n|\n|\r) +|(\r\n|\n|\r)/gm, '')); 11 | } 12 | //*/ 13 | } 14 | 15 | global.forceInjectNAME = ()=>{global.NAMEInjected = false; injectNAME();} 16 | 17 | injectNAME(); -------------------------------------------------------------------------------- /src/globals/Cached dynamic properties.js: -------------------------------------------------------------------------------- 1 | // warinternal 28 November 2016 at 01:32 2 | 3 | /** first we put the function in global */ 4 | global.DEFINE_CACHED_GETTER = function( 5 | proto, 6 | propertyName, 7 | fn, 8 | enumerable = false 9 | ) { 10 | Object.defineProperty(proto, propertyName, { 11 | get: function() { 12 | if (this === proto || this == null) return null; 13 | var result = fn.call(this, this); 14 | Object.defineProperty(this, propertyName, { 15 | value: result, 16 | configurable: true, 17 | enumerable: false 18 | }); 19 | return result; 20 | }, 21 | configurable: true, 22 | enumerable: enumerable 23 | }); 24 | }; 25 | 26 | /** Then we define some properties! */ 27 | DEFINE_CACHED_GETTER(Creep.prototype, "carryTotal", c => _.sum(c.carry)); 28 | DEFINE_CACHED_GETTER( 29 | Creep.prototype, 30 | "carryCapacityAvailable", 31 | c => c.carryCapacity - c.carryTotal 32 | ); 33 | -------------------------------------------------------------------------------- /src/globals/Entity Message Bus.js: -------------------------------------------------------------------------------- 1 | // warinternal 30 March 2017 at 06:43 2 | 3 | /** 4 | * Receive message on room object. Extend this message to any 5 | * entity using the message bus. 6 | * 7 | * @param mixed msg - string or object sent 8 | * @param number tick - the tick the message was sent on 9 | * 10 | * @return false to repeat message (up until it expires) 11 | * 12 | * ex: StructureTerminal.prototype.receiveMessage = function(msg) {} 13 | */ 14 | RoomObject.prototype.receiveMessage = function(msg, sender, tick) { 15 | var AB = Game.time & 1; 16 | console.log(`Receiving message ${JSON.stringify(msg)} on channel ${AB}`); 17 | }; 18 | 19 | /** 20 | * Send a message to an entity to be received on the next tick. 21 | * The next tick delivery ensures all messages can be processed 22 | * and states updated before logic begins, as well as preventing 23 | * infinite loops. 24 | * 25 | * @param string id - object id to receive 26 | * @param mixed data - string or object to send 27 | */ 28 | global.sendMessage = function(id, data = {}, expire = 5, sender = "global") { 29 | if (typeof id !== "string") 30 | throw new TypeError("Expected id string or flag name"); 31 | var AB = 1 - (Game.time & 1); 32 | console.log(`Sending message on to ${id} on channel ${AB}`); 33 | if (!Memory.messages) Memory.messages = []; 34 | if (!Memory.messages[AB]) Memory.messages[AB] = []; 35 | return Memory.messages[AB].push({ 36 | id, 37 | sender, 38 | data: JSON.stringify(data), 39 | tick: Game.time, 40 | expire: Game.time + expire 41 | }); 42 | }; 43 | 44 | /** 45 | * Helper to pass in the sender id 46 | */ 47 | RoomObject.prototype.sendMessage = function(id, data = {}, expire = 5) { 48 | return sendMessage(id, data, expire, this.id || this.name); 49 | }; 50 | 51 | /** 52 | * Process loop for message bus 53 | * Call once per tick to deliver messages to entities. 54 | * 55 | * Messages may deliver at a later time. 56 | * 57 | */ 58 | global.processMessages = function() { 59 | var AB = Game.time & 1; 60 | var obj, status; 61 | if (!Memory.messages || !Memory.messages[AB] || !Memory.messages[AB].length) 62 | return; 63 | _.remove(Memory.messages[AB], function({ id, sender, data, tick, expire }) { 64 | if (Game.time > expire) return true; 65 | obj = Game.getObjectById(id) || Game.flags[id]; 66 | if (!obj) return false; 67 | status = obj.receiveMessage(JSON.parse(data), sender, tick); 68 | return status == undefined ? true : status; 69 | }); 70 | }; 71 | -------------------------------------------------------------------------------- /src/globals/JavaScript/Global functions etc. example.js: -------------------------------------------------------------------------------- 1 | // maxion 15 October 2017 at 05:45 2 | 3 | // globals.js 4 | global.MY_CONSTANT = 'String constant.'; 5 | global.exampleFunc = function() { 6 | console.log('This is an example.'); 7 | }; 8 | global.otherFunc = function(prop = 'default value') { 9 | console.log(MY_CONSTANT + ' ' + prop); 10 | }; 11 | ​ 12 | // main.js above the loop 13 | require('globals'); -------------------------------------------------------------------------------- /src/globals/JavaScript/Reverse lookup tables for errors, colors, and resources.js: -------------------------------------------------------------------------------- 1 | // warinternal 27 February 2017 at 04:41 2 | 3 | /** 4 | * Lookup tables 5 | */ 6 | global.MSG_ERR = _(global) 7 | .pick((v,k) => k.startsWith('ERR_')) 8 | .invert() 9 | .value(); 10 | MSG_ERR[OK] = "OK"; 11 | ​ 12 | global.MSG_COLOR = _(global) 13 | .pick((v,k) => k.startsWith('COLOR_')) 14 | .invert() 15 | .value(); 16 | 17 | global.MSG_FIND = _(global) 18 | .pick((v,k) => k.startsWith('FIND_')) 19 | .invert() 20 | .value(); 21 | 22 | global.MSG_STRUCT = _(global) 23 | .pick((v,k) => k.startsWith('STRUCTURE_')) 24 | .invert() 25 | .value(); 26 | 27 | global.MSG_RES = _(global) 28 | .pick((v,k) => k.startsWith('RESOURCE_')) 29 | .invert() 30 | .value(); -------------------------------------------------------------------------------- /src/globals/JavaScript/adjust_CPU_limit_based_on_bucket_levels.js: -------------------------------------------------------------------------------- 1 | /* Posted March 2nd, 2018 by @semperrabbit */ 2 | 3 | global.BUCKET_MAX = 10000; 4 | global.clamp = function clamp(min, val, max){ 5 | if(val < min) return min; 6 | if(val > max) return max; 7 | return val; 8 | } 9 | 10 | /** 11 | * Adjust your CPU limit per tick based on current and target bucket levels. It will never dip 12 | * below a fifth of your bucket, to help out 10 CPU users. 13 | * 14 | * This uses sine functions to adjust a limit multiplier from 0 at 0 bucket, to 1 at the target 15 | * bucket, to 2 at full bucket. If you are a 10 CPU user, after the multiplier hits 1.5, it will 16 | * add 1 to the multiplier, so you can burn through more of the available bucket. This is to assist 17 | * in taking full advantage of the free 1k bucket during reset storms. 18 | * 19 | * https://imgur.com/a/9PN5z shows the curve of the multiplier where the target bucket is 8k (default) 20 | * 21 | * @author semperrabbit 20180302 22 | * 23 | * @param int limit - Your current static limit (Game.cpu.limit) 24 | * @param int bucket - Your current bucket (Game.cpu.bucket) 25 | * @param int target - The bucket level you want your AI to stablize at 26 | * (Optional: defaults to 8000) 27 | * @param int maxCpuPerTick - What you want to recognize as the max limit for your code to use 28 | * (Optional: defaults to 495) 29 | */ 30 | global.adjustedCPULimit = function adjustedCPULimit(limit, bucket, target = BUCKET_MAX * 0.8, maxCpuPerTick = 495){ 31 | var multiplier = 1; 32 | if (bucket < target) { 33 | multiplier = Math.sin( Math.PI * bucket / (2 * target)); 34 | } 35 | if (bucket > target) { 36 | // Thanks @Deign for support with the sine function below 37 | multiplier = 2+Math.sin((Math.PI*(bucket - BUCKET_MAX))/(2*(BUCKET_MAX-target))); 38 | // take care of our 10 CPU folks, to dip into their bucket reserves more... 39 | // help them burn through excess bucket above the target. 40 | if(limit === 10 && multiplier > 1.5) 41 | multiplier += 1; 42 | } 43 | 44 | return clamp(Math.round(limit*0.2), Math.round(limit*multiplier), maxCpuPerTick); 45 | } -------------------------------------------------------------------------------- /src/globals/JavaScript/boostComponentsObject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 13 March 2018 by @shibdib 3 | * Boost Components 4 | */ 5 | global.BOOST_COMPONENTS = { 6 | //Tier 3 7 | [RESOURCE_CATALYZED_GHODIUM_ALKALIDE]: [RESOURCE_GHODIUM_ALKALIDE, RESOURCE_CATALYST], 8 | [RESOURCE_CATALYZED_GHODIUM_ACID]: [RESOURCE_GHODIUM_ACID, RESOURCE_CATALYST], 9 | [RESOURCE_CATALYZED_ZYNTHIUM_ACID]: [RESOURCE_ZYNTHIUM_ACID, RESOURCE_CATALYST], 10 | [RESOURCE_CATALYZED_ZYNTHIUM_ALKALIDE]: [RESOURCE_ZYNTHIUM_ALKALIDE, RESOURCE_CATALYST], 11 | [RESOURCE_CATALYZED_LEMERGIUM_ALKALIDE]: [RESOURCE_LEMERGIUM_ALKALIDE, RESOURCE_CATALYST], 12 | [RESOURCE_CATALYZED_LEMERGIUM_ACID]: [RESOURCE_LEMERGIUM_ACID, RESOURCE_CATALYST], 13 | [RESOURCE_CATALYZED_KEANIUM_ALKALIDE]: [RESOURCE_KEANIUM_ALKALIDE, RESOURCE_CATALYST], 14 | [RESOURCE_CATALYZED_KEANIUM_ACID]: [RESOURCE_KEANIUM_ACID, RESOURCE_CATALYST], 15 | [RESOURCE_CATALYZED_UTRIUM_ACID]: [RESOURCE_UTRIUM_ACID, RESOURCE_CATALYST], 16 | [RESOURCE_CATALYZED_UTRIUM_ALKALIDE]: [RESOURCE_UTRIUM_ALKALIDE, RESOURCE_CATALYST], 17 | //Tier 2 18 | [RESOURCE_GHODIUM_ACID]: [RESOURCE_GHODIUM_HYDRIDE, RESOURCE_HYDROXIDE], 19 | [RESOURCE_GHODIUM_ALKALIDE]: [RESOURCE_GHODIUM_OXIDE, RESOURCE_HYDROXIDE], 20 | [RESOURCE_ZYNTHIUM_ACID]: [RESOURCE_ZYNTHIUM_HYDRIDE, RESOURCE_HYDROXIDE], 21 | [RESOURCE_ZYNTHIUM_ALKALIDE]: [RESOURCE_ZYNTHIUM_OXIDE, RESOURCE_HYDROXIDE], 22 | [RESOURCE_LEMERGIUM_ALKALIDE]: [RESOURCE_LEMERGIUM_OXIDE, RESOURCE_HYDROXIDE], 23 | [RESOURCE_LEMERGIUM_ACID]: [RESOURCE_LEMERGIUM_HYDRIDE, RESOURCE_HYDROXIDE], 24 | [RESOURCE_KEANIUM_ALKALIDE]: [RESOURCE_KEANIUM_OXIDE, RESOURCE_HYDROXIDE], 25 | [RESOURCE_KEANIUM_ACID]: [RESOURCE_KEANIUM_HYDRIDE, RESOURCE_HYDROXIDE], 26 | [RESOURCE_UTRIUM_ACID]: [RESOURCE_UTRIUM_HYDRIDE, RESOURCE_HYDROXIDE], 27 | [RESOURCE_UTRIUM_ALKALIDE]: [RESOURCE_UTRIUM_OXIDE, RESOURCE_HYDROXIDE], 28 | //Tier 1 29 | [RESOURCE_GHODIUM_HYDRIDE]: [RESOURCE_GHODIUM, RESOURCE_HYDROGEN], 30 | [RESOURCE_GHODIUM_OXIDE]: [RESOURCE_GHODIUM, RESOURCE_OXYGEN], 31 | [RESOURCE_ZYNTHIUM_HYDRIDE]: [RESOURCE_ZYNTHIUM, RESOURCE_HYDROGEN], 32 | [RESOURCE_ZYNTHIUM_OXIDE]: [RESOURCE_ZYNTHIUM, RESOURCE_OXYGEN], 33 | [RESOURCE_LEMERGIUM_OXIDE]: [RESOURCE_LEMERGIUM, RESOURCE_OXYGEN], 34 | [RESOURCE_LEMERGIUM_HYDRIDE]: [RESOURCE_LEMERGIUM, RESOURCE_HYDROGEN], 35 | [RESOURCE_KEANIUM_OXIDE]: [RESOURCE_KEANIUM, RESOURCE_OXYGEN], 36 | [RESOURCE_KEANIUM_HYDRIDE]: [RESOURCE_KEANIUM, RESOURCE_HYDROGEN], 37 | [RESOURCE_UTRIUM_HYDRIDE]: [RESOURCE_UTRIUM, RESOURCE_HYDROGEN], 38 | [RESOURCE_UTRIUM_OXIDE]: [RESOURCE_UTRIUM, RESOURCE_OXYGEN], 39 | //Base 40 | [RESOURCE_GHODIUM]: [RESOURCE_ZYNTHIUM_KEANITE, RESOURCE_UTRIUM_LEMERGITE], 41 | [RESOURCE_HYDROXIDE]: [RESOURCE_OXYGEN, RESOURCE_HYDROGEN], 42 | [RESOURCE_ZYNTHIUM_KEANITE]: [RESOURCE_ZYNTHIUM, RESOURCE_KEANIUM], 43 | [RESOURCE_UTRIUM_LEMERGITE]: [RESOURCE_UTRIUM, RESOURCE_LEMERGIUM] 44 | }; -------------------------------------------------------------------------------- /src/globals/JavaScript/calculateTickTimeInGame.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Tick length calculation by Kamots 17 januari 2019 3 | // Provides global.tickTime as seconds 4 | global.calcTickTime = function(tickSamples = 1000) { // Call this from 1st line of main loop. Can adjust samples used for calculation from there. 5 | let millis = Date.now(); 6 | 7 | // Set some sane defaults 8 | if (typeof Memory.lastTickMillis == "undefined") Memory.lastTickMillis = millis - 1010; 9 | if (typeof Memory.lastTickTime == "undefined") Memory.lastTickTime = 1.01; 10 | if (typeof Memory.tickTimeCount == "undefined") Memory.tickTimeCount = 0; 11 | if (typeof Memory.tickTimeTotal == "undefined") Memory.tickTimeTotal = 0; 12 | 13 | let lastTickMillis = Number(Memory.lastTickMillis); 14 | let tickTimeCount = Number(Memory.tickTimeCount); 15 | let tickTimeTotal = Number(Memory.tickTimeTotal); 16 | 17 | if (tickTimeCount >= (tickSamples-1)) { 18 | tickTimeTotal += millis - lastTickMillis; 19 | tickTimeCount++; 20 | global.tickTime = (tickTimeTotal / tickTimeCount) / 1000; 21 | console.log("Calculated tickTime as", global.tickTime, "from", tickTimeCount, "samples."); 22 | Memory.lastTickTime = global.tickTime; 23 | Memory.tickTimeTotal = millis - lastTickMillis; 24 | Memory.tickTimeCount = 1; 25 | Memory.lastTickMillis = millis; 26 | } else { 27 | global.tickTime = Number(Memory.lastTickTime); 28 | tickTimeTotal += millis - lastTickMillis; 29 | Memory.tickTimeTotal = tickTimeTotal; 30 | tickTimeCount++; 31 | Memory.tickTimeCount = tickTimeCount; 32 | Memory.lastTickMillis = millis; 33 | } 34 | return; 35 | } -------------------------------------------------------------------------------- /src/globals/JavaScript/command to clear in-game console.js: -------------------------------------------------------------------------------- 1 | // GimmeCookies 30 Dec 2018 at 13:59 2 | 3 | /** 4 | * Clear the in-game console 5 | * Usage: `clear()` in the console 6 | */ 7 | global.clear = function() { 8 | console.log( 9 | "" 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /src/globals/JavaScript/determineFileFunctionLineWithinCode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 13 January 2018 by @knightshade 3 | */ 4 | Object.defineProperty(global, '__stack', { 5 | 6 | get: function() { 7 | 8 | var orig = Error.prepareStackTrace; 9 | 10 | Error.prepareStackTrace = function(_, stack) { 11 | 12 | return stack; 13 | 14 | }; 15 | 16 | var err = new Error; 17 | 18 | Error.captureStackTrace(err, arguments.callee); 19 | 20 | var stack = err.stack; 21 | 22 | Error.prepareStackTrace = orig; 23 | 24 | return stack; 25 | 26 | } 27 | 28 | }); 29 | 30 | 31 | 32 | Object.defineProperty(global, '__line', { 33 | 34 | get: function() { 35 | 36 | return __stack[1].getLineNumber(); 37 | 38 | } 39 | 40 | }); 41 | 42 | 43 | 44 | Object.defineProperty(global, '__function', { 45 | 46 | get: function() { 47 | 48 | return __stack[1].getFunctionName(); 49 | 50 | } 51 | 52 | }); 53 | 54 | Object.defineProperty(global, '__file', { 55 | 56 | get: function() { 57 | 58 | return __stack[1].getFileName(); 59 | 60 | } 61 | 62 | }); -------------------------------------------------------------------------------- /src/globals/JavaScript/hasRespawned.js: -------------------------------------------------------------------------------- 1 | /* Posted March 31st, 2018 by @semperrabbit*/ 2 | 3 | /** 4 | * global.hasRespawned() 5 | * 6 | * @author: SemperRabbit 7 | * @version: 1.1 8 | * @date: 180331 9 | * @return: boolean whether this is the first tick after a respawn or not 10 | * 11 | * The checks are set as early returns in case of failure, and are ordered 12 | * from the least CPU intensive checks to the most. The checks are as follows: 13 | * 14 | * If it has returned true previously during this tick, return true again 15 | * Check Game.time === 0 (returns true for sim room "respawns") 16 | * There are no creeps 17 | * There is only 1 room in Game.rooms 18 | * The 1 room has a controller 19 | * The controller is RCL 1 with no progress 20 | * The controller is in safemode with the initial value 21 | * There is only 1 StructureSpawn 22 | * 23 | * The only time that all of these cases are true, is the first tick of a respawn. 24 | * If all of these are true, you have respawned. 25 | * 26 | * v1.1 (by qnz): - fixed a condition where room.controller.safeMode can be SAFE_MODE_DURATION too 27 | * - improved performance of creep number check (https://jsperf.com/isempty-vs-isemptyobject/23) 28 | */global.hasRespawned = function hasRespawned(){ 29 | // check for multiple calls on same tick 30 | if(Memory.respawnTick && Memory.respawnTick === Game.time) { 31 | return true; 32 | } 33 | 34 | // server reset or sim 35 | if(Game.time === 0) { 36 | Memory.respawnTick = Game.time; 37 | return true; 38 | } 39 | 40 | // check for 0 creeps 41 | for(const creepName in Game.creeps) { 42 | return false; 43 | } 44 | 45 | // check for only 1 room 46 | const rNames = Object.keys(Game.rooms); 47 | if(rNames.length !== 1) { 48 | return false; 49 | } 50 | 51 | // check for controller, progress and safe mode 52 | const room = Game.rooms[rNames[0]]; 53 | if(!room.controller || !room.controller.my || room.controller.level !== 1 || room.controller.progress || 54 | !room.controller.safeMode || room.controller.safeMode <= SAFE_MODE_DURATION-1) { 55 | return false; 56 | } 57 | 58 | // check for 1 spawn 59 | if(Object.keys(Game.spawns).length !== 1) { 60 | return false; 61 | } 62 | 63 | // if all cases point to a respawn, you've respawned 64 | Memory.respawnTick = Game.time; 65 | return true; 66 | } 67 | -------------------------------------------------------------------------------- /src/globals/JavaScript/optimizedIsActive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 24 February 2018 by @tigga 3 | */ 4 | let isActive = OwnedStructure.prototype.isActive; 5 | OwnedStructure.prototype.isActive = function() { 6 | if (this.room.memory && this.room.memory.maxRCL && this.room.memory.maxRCL == (this.room.controller.level || 0)) { 7 | return true; 8 | } 9 | 10 | return isActive.call(this); 11 | } -------------------------------------------------------------------------------- /src/globals/JavaScript/resourceColors.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 12 September 2017 by @engineeryo 3 | */ 4 | global.RES_COLORS = { 5 | H: '#989898', 6 | O: '#989898', 7 | U: '#48C5E5', 8 | L: '#24D490', 9 | K: '#9269EC', 10 | Z: '#D9B478', 11 | X: '#F26D6F', 12 | energy: '#FEE476', 13 | battery: '#FEE476', 14 | power: '#F1243A', 15 | 16 | reductant: '#989898', 17 | oxidant: '#989898', 18 | utrium_bar: '#48C5E5', 19 | lemergium_bar: '#24D490', 20 | keanium_bar: '#9269EC', 21 | zynthium_bar: '#D9B478', 22 | purifier: '#F26D6F', 23 | 24 | OH: '#B4B4B4', 25 | ZK: '#B4B4B4', 26 | UL: '#B4B4B4', 27 | G: '#FFFFFF', 28 | 29 | ghodium_melt: '#FFFFFF', 30 | composite: '#FFFFFF', 31 | crystal: '#FFFFFF', 32 | liquid: '#FFFFFF', 33 | 34 | UH: '#50D7F9', 35 | UO: '#50D7F9', 36 | KH: '#A071FF', 37 | KO: '#A071FF', 38 | LH: '#00F4A2', 39 | LO: '#00F4A2', 40 | ZH: '#FDD388', 41 | ZO: '#FDD388', 42 | GH: '#FFFFFF', 43 | GO: '#FFFFFF', 44 | 45 | UH2O: '#50D7F9', 46 | UHO2: '#50D7F9', 47 | KH2O: '#A071FF', 48 | KHO2: '#A071FF', 49 | LH2O: '#00F4A2', 50 | LHO2: '#00F4A2', 51 | ZH2O: '#FDD388', 52 | ZHO2: '#FDD388', 53 | GH2O: '#FFFFFF', 54 | GHO2: '#FFFFFF', 55 | 56 | XUH2O: '#50D7F9', 57 | XUHO2: '#50D7F9', 58 | XKH2O: '#A071FF', 59 | XKHO2: '#A071FF', 60 | XLH2O: '#00F4A2', 61 | XLHO2: '#00F4A2', 62 | XZH2O: '#FDD388', 63 | XZHO2: '#FDD388', 64 | XGH2O: '#FFFFFF', 65 | XGHO2: '#FFFFFF' 66 | 67 | XGHO2: '#FFFFFF', 68 | 69 | metal: '#956F5C', 70 | alloy: '#956F5C', 71 | tube: '#956F5C', 72 | fixtures: '#956F5C', 73 | frame: '#956F5C', 74 | hydraulics: '#956F5C', 75 | machine: '#956F5C', 76 | 77 | biomass: '#84B012', 78 | cell: '#84B012', 79 | phlegm: '#84B012', 80 | tissue: '#84B012', 81 | muscle: '#84B012', 82 | organoid: '#84B012', 83 | organism: '#84B012', 84 | 85 | silicon: '#4DA7E5', 86 | wire: '#4DA7E5', 87 | switch: '#4DA7E5', 88 | transistor: '#4DA7E5', 89 | microchip: '#4DA7E5', 90 | circuit: '#4DA7E5', 91 | device: '#4DA7E5', 92 | 93 | mist: '#DA6BF5', 94 | condensate: '#DA6BF5', 95 | concentrate: '#DA6BF5', 96 | extract: '#DA6BF5', 97 | spirit: '#DA6BF5', 98 | emanation: '#DA6BF5', 99 | essence: '#DA6BF5' 100 | } -------------------------------------------------------------------------------- /src/globals/JavaScript/respawn assist to clear memory and flags.js: -------------------------------------------------------------------------------- 1 | // semperrabbit 25 November 2016 at 22:27 2 | 3 | // to be used after you respawn into a new location 4 | // but before you spawn your first creep... 5 | global.respawn = function() { 6 | for (let f in Game.flags) { 7 | Game.flags[f].remove(); 8 | } 9 | Memory = {}; 10 | RawMemory.set(""); 11 | }; 12 | -------------------------------------------------------------------------------- /src/globals/JavaScript/setTimeout_setInterval.js: -------------------------------------------------------------------------------- 1 | /* Posted August 11th, 2018 by @semperrabbit*/ 2 | /** 3 | * global.setTimeout() - works like external to screeps except measured in ticks, not milliseconds 4 | * global.clearTimeout() - works like external to screeps 5 | * 6 | * global.setInterval() - works like external to screeps except measured in ticks, not milliseconds 7 | * global.clearInterval() - works like external to screeps 8 | * 9 | * global.runTimeout() - required to run inside loop to force tick increment for all timeouts 10 | * 11 | * @author: SemperRabbit 12 | * @version: 1.2 13 | * @date: 180811 14 | * 15 | * NOTE: global resets will clear all timeouts and intervals... 16 | * 17 | * setTimeout() acts as it regularly would in JS outside of screeps, except that it is measured in 18 | * ticks as opposed to milliseconds. It returns a timeout ID, which can be cancelled via 19 | * clearTimeout(id). runTimeout() is required to increment the tick count. setInterval() and 20 | * clearInterval() work the same way. 21 | * 22 | * Example: 23 | * setInterval(()=>{console.log('every 3 ticks')}, 3); 24 | * 25 | * var a = setTimeout(()=>{console.log('5 ticks from start')}, 5); 26 | * clearTimeout(a) // removes the "5 ticks from start" timeout 27 | * 28 | * module.exports.loop = function() { 29 | * runTimeout(); 30 | * // remainder of loop 31 | * } 32 | * 33 | * ChangeLog: 34 | * v1.0 initial commit 35 | * v1.1 refactored function storage from module scoped array to internal to the generator 36 | * v1.2 added setInterval/clearInterval in addition to setTimeout/clearTimeout 37 | */ 38 | 39 | 40 | 41 | // Storage for timer generators 42 | var timerStor = []; 43 | 44 | // timer generator, calling function every time `ticks % count === 0` 45 | function *timerGen(func, count, interval = false){ 46 | var id = timerStor.length; 47 | var ticks = 0; 48 | yield id; // used to return the id to setTimeout() for registration in timerStor 49 | while(true){ 50 | ticks++; 51 | if(ticks % count === 0 && ticks !== 0){ 52 | if(!interval) 53 | timerStor[id] = undefined; 54 | yield func(); // run the function 55 | } else { 56 | yield false; // do not run the function 57 | } 58 | } 59 | } 60 | 61 | // must be run inside the loop for the tick count to proceed 62 | global.runTimeout = function runTimeout(){ 63 | for(var i=0;i${text} 17 | ` 49 | .replace(/(\r\n|\n|\r)\t+|(\r\n|\n|\r) +|(\r\n|\n|\r)/gm,"")); 50 | } -------------------------------------------------------------------------------- /src/globals/Memory segment emulation.js: -------------------------------------------------------------------------------- 1 | // dissi 29 November 2016 at 07:15 2 | 3 | global.CACHE_MEMORY_SEGMENT = {}; 4 | global.CACHE_MEMORY_SEGMENT_VERSION = {}; 5 | global.CACHE_MEMORY_SEGMENT_DIRTY = {}; 6 | 7 | global.MEMSEG_ROUTES_matrixes = "MatrixesSwap"; 8 | var preLoadOnInit = [ 9 | MEMSEG_ROUTES_matrixes 10 | ]; 11 | var tickSaved = Game.time - 1; 12 | global.initMemorySegments = function() { 13 | var cpuNow = Game.cpu.getUsed(); 14 | Memory; 15 | reportDuration("MEMLOAD_ALL", Game.cpu.getUsed() - cpuNow); 16 | for (var i = 0; i < preLoadOnInit.length; i++) { 17 | getMemorySegment(preLoadOnInit[i]); 18 | } 19 | } 20 | 21 | global.getMemorySegment = function(theSegmentName) { 22 | if (!Memory.segments) { 23 | Memory.segments = {}; 24 | } 25 | if (!Memory.segments[theSegmentName]) { 26 | return {}; 27 | } 28 | if (!CACHE_MEMORY_SEGMENT[theSegmentName] || CACHE_MEMORY_SEGMENT_VERSION[theSegmentName] != getMemorySegmentVersion(theSegmentName)) { 29 | var cpuNow = Game.cpu.getUsed(); 30 | CACHE_MEMORY_SEGMENT[theSegmentName] = JSON.parse(Memory.segments[theSegmentName]); 31 | CACHE_MEMORY_SEGMENT_VERSION[theSegmentName] = getMemorySegmentVersion(theSegmentName); 32 | var used = Game.cpu.getUsed() - cpuNow; 33 | reportDuration("MEMLOAD_" + theSegmentName, used); 34 | log("Loaded memory segment: [" + theSegmentName + "] took " + used.toFixed(2) + "ms", "memstore") 35 | } 36 | return CACHE_MEMORY_SEGMENT[theSegmentName]; 37 | } 38 | 39 | global.getMemorySegmentVersion = function(theSegmentName) { 40 | if (!Memory.segmentsBookKeeping) { 41 | Memory.segmentsBookKeeping = {}; 42 | } 43 | if (!Memory.segmentsBookKeeping[theSegmentName]) { 44 | Memory.segmentsBookKeeping[theSegmentName] = 0; 45 | } 46 | return Memory.segmentsBookKeeping[theSegmentName]; 47 | } 48 | 49 | global.increaseMemorySegmentVersion = function(theSegmentName) { 50 | Memory.segmentsBookKeeping[theSegmentName]++; 51 | } 52 | 53 | global.storeMemorySegment = function(theSegmentName, theData) { 54 | if (!Memory.segments) { 55 | Memory.segments = {}; 56 | } 57 | 58 | CACHE_MEMORY_SEGMENT[theSegmentName] = theData; 59 | if (tickSaved == Game.time) // after game loop access 60 | { 61 | handleSaveOfDirtySegment(theSegmentName); 62 | } else { 63 | CACHE_MEMORY_SEGMENT_DIRTY[theSegmentName] = true; 64 | } 65 | } 66 | 67 | global.setMemoryDelayStore = function() { 68 | tickSaved = Game.time - 1; 69 | } 70 | 71 | global.storeDirtyMemory = function() { 72 | for (var key in CACHE_MEMORY_SEGMENT_DIRTY) { 73 | handleSaveOfDirtySegment(key); 74 | } 75 | CACHE_MEMORY_SEGMENT_DIRTY = {}; 76 | tickSaved = Game.time; 77 | } 78 | 79 | function handleSaveOfDirtySegment(theSegmentName) { 80 | var cpuNow = Game.cpu.getUsed(); 81 | Memory.segments[theSegmentName] = JSON.stringify(CACHE_MEMORY_SEGMENT[theSegmentName]); 82 | increaseMemorySegmentVersion(theSegmentName); 83 | var used = Game.cpu.getUsed() - cpuNow; 84 | reportDuration("MEMSTORE_" + theSegmentName, used); 85 | log("Stored memory segment: [" + theSegmentName + "] took " + used.toFixed(2) + "ms", "memstore"); 86 | } 87 | 88 | 89 | function log(theMessage, theCategory) { 90 | console.log("[" + theCategory + "] - " + theMessage); 91 | } 92 | 93 | function reportDuration(theOperationName, theUsedCpu); { 94 | log("Operation [" + theOperationName + "] took [" + theUsedCpu.toFixed(2) + "] CPU", "durationReport") 95 | } -------------------------------------------------------------------------------- /src/globals/Reverse lookup tables for errors, colors, and resources.js: -------------------------------------------------------------------------------- 1 | // warinternal 27 February 2017 at 04:41 2 | /** 3 | * Lookup tables 4 | */ 5 | global.MSG_ERR = _(global) 6 | .pick((v, k) => k.startsWith("ERR_")) 7 | .invert() 8 | .value(); 9 | MSG_ERR[OK] = "OK"; 10 | 11 | global.MSG_COLOR = _(global) 12 | .pick((v, k) => k.startsWith("COLOR_")) 13 | .invert() 14 | .value(); 15 | 16 | global.MSG_FIND = _(global) 17 | .pick((v, k) => k.startsWith("FIND_")) 18 | .invert() 19 | .value(); 20 | 21 | global.MSG_STRUCT = _(global) 22 | .pick((v, k) => k.startsWith("STRUCTURE_")) 23 | .invert() 24 | .value(); 25 | 26 | global.MSG_RES = _(global) 27 | .pick((v, k) => k.startsWith("RESOURCE_")) 28 | .invert() 29 | .value(); 30 | -------------------------------------------------------------------------------- /src/globals/TypeScript/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screepers/screeps-snippets/8b557a3fcb82cb734fca155b07d5a48622f9da60/src/globals/TypeScript/.gitignore -------------------------------------------------------------------------------- /src/globals/queueAction() system.js: -------------------------------------------------------------------------------- 1 | // helam 3 January 2017 at 01:37 2 | 3 | /** 4 | * Used to create unique id numbers 5 | * Author: Helam 6 | * @returns {*|number} 7 | */ 8 | global.getId = function() { 9 | if (Memory.globalId == undefined || Memory.globalId > 10000) { 10 | Memory.globalId = 0; 11 | } 12 | Memory.globalId = Memory.globalId + 1; 13 | return Memory.globalId; 14 | }; 15 | 16 | /** 17 | * INTERNAL USE ONLY. 18 | * Author: Helam 19 | * @param id 20 | * @param action 21 | * @param stopResult 22 | * @param tickLimit 23 | * @param startTime 24 | * @constructor 25 | */ 26 | global.QueuedAction = function({ 27 | id, 28 | action, 29 | stopResult, 30 | tickLimit, 31 | startTime 32 | }) { 33 | this.id = id || getId(); 34 | this.action = id ? action : `return (${action.toString()})()`; 35 | this.stopResult = stopResult; 36 | this.tickLimit = tickLimit || 100; 37 | this.startTime = startTime || Game.time; 38 | }; 39 | 40 | /** 41 | * INTERNAL USE ONLY. 42 | * Run the queued action and return false if: 43 | * 1. There is an error 44 | * 2. The return value of the queued action is equal to the stopResult 45 | * 3. The queued action has been run [tickLimit] number of times 46 | * Author: Helam 47 | * @returns {boolean} 48 | */ 49 | QueuedAction.prototype.run = function() { 50 | let func = Function(this.action); 51 | try { 52 | let result = func(); 53 | if (result === this.stopResult) { 54 | return false; 55 | } 56 | if (Game.time - this.startTime >= this.tickLimit) { 57 | return false; 58 | } 59 | } catch (error) { 60 | console.log(error.stack); 61 | return false; 62 | } 63 | return true; 64 | }; 65 | 66 | /** 67 | * INTERNAL USE ONLY. 68 | * Add the action to the queue. 69 | * Author: Helam 70 | */ 71 | QueuedAction.prototype.add = function() { 72 | Memory.queuedActions[this.id] = this; 73 | }; 74 | 75 | /** 76 | * INTERNAL USE ONLY. 77 | * Remove the queued action from the queue. 78 | * Author: Helam 79 | */ 80 | QueuedAction.prototype.clear = function() { 81 | delete Memory.queuedActions[this.id]; 82 | }; 83 | 84 | /** 85 | * Put somewhere in the main loop. 86 | * Calls all of the queued actions. 87 | * Author: Helam 88 | */ 89 | global.runQueuedActions = function() { 90 | Object.keys(Memory.queuedActions || {}).forEach(id => { 91 | let action = new QueuedAction(Memory.queuedActions[id]); 92 | if (!action.run()) action.clear(); 93 | }); 94 | }; 95 | 96 | /** 97 | * Call this function to add an action to the queue. 98 | * Author: Helam 99 | * @param action {Function} (the function you want called) 100 | * @param stopResult (return value of the function that should signal removing the action from the queue) 101 | * @param tickLimit (max number of ticks to call the function. default 100) 102 | */ 103 | global.queueAction = function(action, stopResult, tickLimit) { 104 | if (!Memory.queuedActions) Memory.queuedActions = {}; 105 | let newAction = new QueuedAction({ action, stopResult, tickLimit }); 106 | newAction.add(); 107 | }; 108 | -------------------------------------------------------------------------------- /src/globals/upkeep_costs.js: -------------------------------------------------------------------------------- 1 | // warinternal 24 November 2016 at 04:15 2 | global.RAMPART_UPKEEP = 3 | RAMPART_DECAY_AMOUNT / REPAIR_POWER / RAMPART_DECAY_TIME; 4 | global.ROAD_UPKEEP = ROAD_DECAY_AMOUNT / REPAIR_POWER / ROAD_DECAY_TIME; 5 | global.CONTAINER_UPKEEP = 6 | CONTAINER_DECAY / REPAIR_POWER / CONTAINER_DECAY_TIME_OWNED; 7 | global.REMOTE_CONTAINER_UPKEEP = 8 | CONTAINER_DECAY / REPAIR_POWER / CONTAINER_DECAY_TIME; 9 | -------------------------------------------------------------------------------- /src/logging/JavaScript/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screepers/screeps-snippets/8b557a3fcb82cb734fca155b07d5a48622f9da60/src/logging/JavaScript/.gitignore -------------------------------------------------------------------------------- /src/logging/TypeScript/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/screepers/screeps-snippets/8b557a3fcb82cb734fca155b07d5a48622f9da60/src/logging/TypeScript/.gitignore -------------------------------------------------------------------------------- /src/misc/JavaScript/Calculate Cost of a Mine.js: -------------------------------------------------------------------------------- 1 | // Gankdalf 7 December 2016 at 22:35 2 | function calculateCostOfaMine(distance, swampCount, mineCapacity) { 3 | //Get the number of WORK parts needed 4 | const energy_generated = mineCapacity / ENERGY_REGEN_TIME; 5 | const work_needed = energy_generated / HARVEST_POWER; 6 | 7 | //Get the travel time for the creeps 8 | //(will be used more with non-one-to-one creeps) 9 | const miner_travel_time = distance; 10 | const carry_travel_time = distance * 2; 11 | 12 | //Get the number of carry parts needed to move the generated energy in one trip 13 | //(can in theory be split between multiple creeps) 14 | const carry_needed = Math.ceil( 15 | carry_travel_time * (energy_generated / CARRY_CAPACITY) 16 | ); 17 | 18 | //Get the number of move parts needed to move the work and carry parts at 1:1 on roads 19 | //(including a single work part for the carry creep) 20 | const work_move_needed = Math.ceil(work_needed / 2); 21 | const carry_move_needed = Math.ceil((carry_needed + 1) / 2); 22 | 23 | //Get the cost per tick for a container 24 | const container_cost = 25 | CONTAINER_DECAY / CONTAINER_DECAY_TIME_OWNED / REPAIR_POWER; 26 | 27 | //Get the one-time energy cost to create the needed needed creeps 28 | const miner_cost = 29 | work_needed * BODYPART_COST["work"] + 30 | work_move_needed * BODYPART_COST["move"]; 31 | const carry_cost = 32 | carry_needed * BODYPART_COST["carry"] + 33 | carry_move_needed * BODYPART_COST["move"] + 34 | BODYPART_COST["work"]; 35 | 36 | //Get the cost per-tick to create the needed creeps 37 | const carry_cost_per_tick = 38 | carry_cost / (CREEP_LIFE_TIME - carry_travel_time); 39 | const miner_cost_per_tick = 40 | miner_cost / (CREEP_LIFE_TIME - miner_travel_time); 41 | 42 | //Get the number of ticks required in a normal creep life cycle required to spawn the needed creeps 43 | //(This accounts for the time when two miners will exist at the same time for a single source) 44 | const miner_tick_cost_per_cycle = 45 | (((work_needed + work_move_needed) * 3) / 46 | (CREEP_LIFE_TIME - miner_travel_time)) * 47 | CREEP_LIFE_TIME; 48 | const carry_tick_cost_per_cycle = 49 | (((carry_needed + carry_move_needed) * 3) / 50 | (CREEP_LIFE_TIME - carry_travel_time)) * 51 | CREEP_LIFE_TIME; 52 | 53 | //Get the repair cost to maintain the roads 54 | const plain_road_cost = 55 | ((distance - swampCount) * (ROAD_DECAY_AMOUNT / ROAD_DECAY_TIME)) / 56 | REPAIR_POWER; 57 | const swamp_road_cost = 58 | (swampCount * 59 | (ROAD_DECAY_AMOUNT / ROAD_DECAY_TIME) * 60 | CONSTRUCTION_COST_ROAD_SWAMP_RATIO) / 61 | REPAIR_POWER; 62 | 63 | return { 64 | totalEnergyCostPerTick: 65 | Math.round( 66 | (carry_cost_per_tick + 67 | miner_cost_per_tick + 68 | swamp_road_cost + 69 | plain_road_cost + 70 | container_cost) * 71 | 100 72 | ) / 100, 73 | spawnTicksPerCycle: Math.ceil( 74 | miner_tick_cost_per_cycle + carry_tick_cost_per_cycle 75 | ), 76 | spawnEnergyCapacityRequired: Math.max(miner_cost, carry_cost), 77 | initialStructureCost: 78 | (distance - swampCount) * CONSTRUCTION_COST["road"] + 79 | swampCount * 80 | CONSTRUCTION_COST["road"] * 81 | CONSTRUCTION_COST_ROAD_SWAMP_RATIO + 82 | CONSTRUCTION_COST["container"] 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /src/misc/JavaScript/Check if room is a source keeper room.js: -------------------------------------------------------------------------------- 1 | // issacar 18 April 2017 at 20:49 2 | 3 | let parsed = /^[WE]([0-9]+)[NS]([0-9]+)$/.exec(roomName); 4 | let fMod = parsed[1] % 10; 5 | let sMod = parsed[2] % 10; 6 | let isSK = 7 | !(fMod === 5 && sMod === 5) && 8 | (fMod >= 4 && fMod <= 6) && 9 | (sMod >= 4 && sMod <= 6); 10 | -------------------------------------------------------------------------------- /src/misc/JavaScript/Global Tracking.js: -------------------------------------------------------------------------------- 1 | // ags131 7 February 2017 at 00:49 2 | 3 | /* @ags131 Adam Shumann - MIT Licensed https://opensource.org/licenses/MIT */ 4 | 5 | function globalInit() { 6 | Memory.GlobalID = Memory.GlobalID || 0; 7 | let gid = Memory.GlobalID++; 8 | Memory.globals = Memory.globals || {}; 9 | Memory.globals[gid] = { 10 | id: gid, 11 | init: Date.now(), 12 | firstTick: Game.time 13 | }; 14 | global.G = new Proxy( 15 | {}, 16 | { 17 | get: (target, name) => Memory.globals[gid][name], 18 | set: (target, name, value) => (Memory.globals[gid][name] = value) 19 | } 20 | ); 21 | Object.keys(Memory.globals) 22 | .slice(0, -60) 23 | .forEach(k => delete Memory.globals[k]); 24 | } 25 | 26 | function globalTick() { 27 | let now = Date.now(); 28 | G.lastRun = now; 29 | G.lastTick = Game.time; 30 | } 31 | -------------------------------------------------------------------------------- /src/misc/JavaScript/Memory Cache.js: -------------------------------------------------------------------------------- 1 | // postcrafter 20 May 2017 at 00:32 2 | 3 | function wrapLoop(fn) { 4 | let memory; 5 | let tick; 6 | 7 | return () => { 8 | if (tick && tick + 1 === Game.time && memory) { 9 | // this line is required to disable the default Memory deserialization 10 | delete global.Memory; 11 | Memory = memory; 12 | } else { 13 | memory = Memory; 14 | } 15 | 16 | tick = Game.time; 17 | 18 | fn(); 19 | 20 | // there are two ways of saving Memory with different advantages and disadvantages 21 | // 1. RawMemory.set(JSON.stringify(Memory)); 22 | // + ability to use custom serialization method 23 | // - you have to pay for serialization 24 | // - unable to edit Memory via Memory watcher or console 25 | // 2. RawMemory._parsed = Memory; 26 | // - undocumented functionality, could get removed at any time 27 | // + the server will take care of serialization, it doesn't cost any CPU on your site 28 | // + maintain full functionality including Memory watcher and console 29 | 30 | // this implementation uses the official way of saving Memory 31 | RawMemory.set(JSON.stringify(Memory)); 32 | }; 33 | } 34 | 35 | module.exports.loop = wrapLoop(function() { 36 | // game logic 37 | }); 38 | -------------------------------------------------------------------------------- /src/misc/JavaScript/Minimal Starting AI.js: -------------------------------------------------------------------------------- 1 | // WolfWings 6 February 2018 at 04:20 2 | 3 | // Use a Red/White flag as a 'rally point' when there's nothing to do in a room. 4 | // Use a Yellow/Yellow flag to mark an exit row that leads TO a room to remote-mine. 5 | // Use a Yellow/Grey flag to mark an exit leading back FROM a room to where more storage is. 6 | // REMEMBER TO BUILD ROADS AND EXTENSIONS! This is not an automated AI, you control construction! 7 | ​ 8 | var repairFilter = (object) => ( (object.my !== false) && (object.structureType !== STRUCTURE_WALL) && (object.structureType !== STRUCTURE_RAMPART) && (object.hits < object.hitsMax) && (object.hits < object.hitsMax - 500) ); 9 | ​ 10 | module.exports.loop = () => { 11 | if ((Game.time % 100) === 0) { 12 | for(let name in Memory.creeps) { 13 | if(!Game.creeps[name]) { 14 | delete Memory.creeps[name]; 15 | } 16 | } 17 | } 18 | ​ 19 | var creeps = {}; 20 | for (let name in Game.creeps) { 21 | let creep = Game.creeps[name]; 22 | if (!creep.my) { 23 | continue; 24 | } 25 | let room = creep.memory.room || creep.room.name; 26 | creeps[room] = creeps[room] || []; 27 | creeps[room].push(creep); 28 | } 29 | ​ 30 | for (let roomIndex in Game.rooms) { 31 | let room = Game.rooms[roomIndex]; 32 | let spawns = undefined; 33 | if (creeps[roomIndex] && creeps[roomIndex].length > 0) { 34 | creeps[roomIndex].sort((a, b) => (a.ticksToLive - b.ticksToLive)); 35 | } 36 | let structures = room.find(FIND_STRUCTURES); 37 | let my_structures = _.filter(structures, (object) => (object.my === true)); 38 | let towers = _.filter(my_structures, (object) => (object.structureType === STRUCTURE_TOWER)); 39 | let tanks = undefined; 40 | let repair = undefined; 41 | let hostile_creeps = undefined; 42 | let wounded_creeps = undefined; 43 | ​ 44 | for (let tower of towers) { 45 | do { 46 | hostile_creeps = hostile_creeps || room.find(FIND_HOSTILE_CREEPS); 47 | if (hostile_creeps.length > 0) { 48 | tower.attack(tower.pos.findClosestByRange(hostile_creeps)); 49 | break; 50 | } 51 | ​ 52 | wounded_creeps = wounded_creeps || _.filter(creeps[roomIndex], (object) => (object.hits < object.hitsMax) ); 53 | if (wounded_creeps.length > 0) { 54 | tower.heal(tower.pos.findClosestByRange(wounded_creeps)); 55 | break; 56 | } 57 | } while (false); 58 | } 59 | ​ 60 | do { 61 | let body = null; 62 | creeps[roomIndex] = creeps[roomIndex] || []; 63 | if ((creeps[roomIndex].length < 3) && 64 | (room.energyAvailable >= 250)) { 65 | body = [WORK,CARRY,MOVE,MOVE]; 66 | } else if ((creeps[roomIndex].length < 20) && 67 | (room.energyAvailable === room.energyCapacityAvailable)) { 68 | body = [WORK,WORK,CARRY,MOVE]; 69 | if (room.energyAvailable >= 1300) { 70 | body = [WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,CARRY,CARRY,CARRY,CARRY,CARRY,CARRY,CARRY,MOVE,MOVE,MOVE,MOVE,MOVE,MOVE,MOVE]; 71 | } else if (room.energyAvailable >= 800) { 72 | body = [WORK,WORK,WORK,WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE,MOVE]; 73 | } else if (room.energyAvailable >= 550) { 74 | body = [WORK,WORK,WORK,CARRY,CARRY,MOVE,MOVE,MOVE]; 75 | } 76 | } 77 | ​ 78 | if (body !== null) { 79 | spawns = spawns || room.find(FIND_MY_SPAWNS, {filter: (object) => (object.spawning === null) } ); 80 | if (spawns.length > 0) { 81 | var spawn = spawns.pop(); 82 | spawn.spawnCreep(body, room.name + ":" + Game.time, { memory: { room: spawn.room.name } } ); 83 | } 84 | } 85 | } while (false); 86 | ​ 87 | for (let creep of creeps[roomIndex]) { 88 | if (creep.memory.full) { 89 | if (creep.carry.energy === 0) { 90 | creep.memory.full = false; 91 | } 92 | } else { 93 | if (creep.carry.energy === creep.carryCapacity) { 94 | creep.memory.full = true; 95 | } 96 | } 97 | ​ 98 | let target; 99 | let result; 100 | ​ 101 | if (creep.memory.full) { 102 | do { 103 | if (tanks === undefined) { 104 | tanks = _.filter(my_structures, (object) => ( ( (object.structureType === STRUCTURE_SPAWN) || (object.structureType === STRUCTURE_EXTENSION) || (object.structureType == STRUCTURE_TOWER) ) && (object.energy < object.energyCapacity) ) ); 105 | } 106 | if (tanks.length > 0) { 107 | target = creep.pos.findClosestByRange(tanks); 108 | if (target.energyCapacity !== undefined) { 109 | result = creep.transfer(target, RESOURCE_ENERGY); 110 | } else { 111 | result = ERR_NOT_IN_RANGE; 112 | } 113 | break; 114 | } 115 | ​ 116 | target = creep.pos.findClosestByRange(room.find(FIND_MY_CONSTRUCTION_SITES)); 117 | if ((target === null) && 118 | (creep.room.name !== roomIndex)) { 119 | target = creep.pos.findClosestByRange(creep.room.find(FIND_MY_CONSTRUCTION_SITES)); 120 | } 121 | if (target !== null) { 122 | result = creep.build(target); 123 | break; 124 | } 125 | ​ 126 | if (repair === undefined) { 127 | repair = _.filter(structures, repairFilter ) 128 | if ((repair.length === 0) && 129 | (roomIndex !== creep.room.name)) { 130 | repair = creep.room.find(FIND_STRUCTURES, {filter: repairFilter } ); 131 | } 132 | repair.sort((a, b) => (a.id.localeCompare(b.id))); 133 | } 134 | if (repair.length > 0) { 135 | target = repair.pop(); 136 | result = creep.repair(target); 137 | break; 138 | } 139 | ​ 140 | target = creep.pos.findClosestByRange(creep.room.find(FIND_FLAGS, { filter: (flag) => flag.color === COLOR_YELLOW && flag.secondaryColor === COLOR_GREY})); 141 | if (target !== null) { 142 | result = ERR_NOT_IN_RANGE; 143 | break; 144 | } 145 | ​ 146 | target = room.controller; 147 | result = creep.upgradeController(target); 148 | } while (false); 149 | } else { 150 | do { 151 | target = creep.pos.findClosestByRange(FIND_DROPPED_RESOURCES, {filter: (object) => (object.resourceType === RESOURCE_ENERGY) }); 152 | if (target !== null) { 153 | result = creep.pickup(target); 154 | break; 155 | } 156 | ​ 157 | let sources = creep.room.find(FIND_SOURCES_ACTIVE); 158 | if (sources.length === 0) { 159 | sources = creep.room.find(FIND_FLAGS, { filter: (flag) => flag.color === COLOR_YELLOW && flag.secondaryColor === COLOR_YELLOW}); 160 | } 161 | target = creep.pos.findClosestByRange(sources); 162 | if (target !== null) { 163 | if (target.energy) { 164 | result = creep.harvest(target); 165 | } else { 166 | result = ERR_NOT_IN_RANGE; 167 | } 168 | break; 169 | } 170 | ​ 171 | if (creep.carry.energy > 0) { 172 | creep.memory.full = true; 173 | } else { 174 | target = creep.room.find(FIND_FLAGS, {filter: (object) => ( (object.color === COLOR_RED) && (object.secondaryColor === COLOR_WHITE) ) } ); 175 | if (target.length > 0) { 176 | target = target.pop(); 177 | result = ERR_NOT_IN_RANGE; 178 | } 179 | } 180 | } 181 | while (false); 182 | } 183 | ​ 184 | if (result === ERR_NOT_IN_RANGE) { 185 | creep.moveTo(target); 186 | } 187 | } 188 | } 189 | } -------------------------------------------------------------------------------- /src/misc/JavaScript/OwnedStructure Memory.js: -------------------------------------------------------------------------------- 1 | // warinternal 27 December 2016 at 18:51 2 | 3 | // This is called during global reset to set up structure memory, 4 | // because it doesn't need to be called often. 5 | if (!Memory.structures) { 6 | console.log("[Memory] Initializing structure memory"); 7 | Memory.structures = {}; 8 | } 9 | 10 | // Adds structure memory to OwnedStructure things. 11 | // Easier to reason about garbage collection in this implementation. 12 | Object.defineProperty(OwnedStructure.prototype, "memory", { 13 | get: function() { 14 | if (!Memory.structures[this.id]) Memory.structures[this.id] = {}; 15 | return Memory.structures[this.id]; 16 | }, 17 | set: function(v) { 18 | return _.set(Memory, "structures." + this.id, v); 19 | }, 20 | configurable: true, 21 | enumerable: false 22 | }); 23 | 24 | // Call this periodically to garbage collect structure memory 25 | // (I find once every 10k ticks is fine) 26 | global.GCStructureMemory = function() { 27 | for (var id in Memory.structures) 28 | if (!Game.structures[id]) { 29 | console.log( 30 | "Garbage collecting structure " + 31 | id + 32 | ", " + 33 | JSON.stringify(Memory.structures[id]) 34 | ); 35 | delete Memory.structures[id]; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /src/misc/JavaScript/Remote mining generator.js: -------------------------------------------------------------------------------- 1 | // domnomnom 1 January 2017 at 08:29 2 | 3 | // identity function for string interpolation. 4 | // interp`foo ${baz} bar` == `foo ${baz} bar` 5 | const interp = (strings, ...values) => { 6 | const out = []; 7 | for (let i = 0; i < values.length; ++i) { 8 | out.push(strings[i]); 9 | out.push(values[i] + ""); 10 | } 11 | out.push(strings[strings.length - 1]); // len(strings) = len(values) + 1 12 | return out.join(""); 13 | }; 14 | 15 | // returns an array of creepName lines. The last number represents the repeat count and where it is inserted. 16 | // example use: repeat`banker:${'E45N52'}_${2}` --> ['banker:E45N52_0', 'banker:E45N52_1'] 17 | const repeat = (strings, ...values) => { 18 | const lines = []; 19 | const numRepeats = values[values.length - 1]; 20 | for (let i = 0; i < numRepeats; ++i) { 21 | values[values.length - 1] = i; 22 | lines.push(interp(strings, ...values)); 23 | } 24 | return lines; 25 | }; 26 | 27 | // remoteMine('E45N52', [1,2], 'E45N53') --> 28 | // claim:E45N52 29 | // mine:E45N52_0 30 | // mine:E45N52_1 31 | // mule:d_E45N52_0-d_E45N53_0 32 | // mule:d_E45N52_1-d_E45N53_0 33 | // mule:d_E45N52_1-d_E45N53_1 34 | const remoteMine = (roomName, numMulesPerSite, deliverTarget) => { 35 | const lines = [].concat( 36 | `claim:${roomName}`, 37 | repeat`mine:${roomName}_${numMulesPerSite.length}`, 38 | ...numMulesPerSite.map( 39 | (numMules, siteIndex) => 40 | repeat`mule:d_${roomName}_${siteIndex}-d_${deliverTarget}_${numMules}` 41 | ) 42 | ); 43 | 44 | return lines.map(line => ` ${line}\n`).join(""); 45 | }; 46 | -------------------------------------------------------------------------------- /src/misc/JavaScript/Reset Memory to default.js: -------------------------------------------------------------------------------- 1 | // Doctor Zuber 23 July 2018 at 07:41 2 | 3 | // warning, this does exactly what it says. it removes all memory 4 | // and leaves you with the base 4 empty objects. 5 | ​ 6 | function resetMemory(){ 7 | RawMemory.set('{}'); 8 | Memory.creeps = {}; 9 | Memory.rooms = {}; 10 | Memory.flags = {}; 11 | Memory.spawns = {}; 12 | } -------------------------------------------------------------------------------- /src/misc/JavaScript/Simple benchmarks.js: -------------------------------------------------------------------------------- 1 | // warinternal 13 March 2017 at 03:44 2 | 3 | /** 4 | * Simple benchmark test with sanity check 5 | * 6 | * Usage: benchmark([ 7 | * () => doThing(), 8 | * () => doThingAnotherWay(), 9 | * ]); 10 | * 11 | * Output: 12 | * 13 | * Benchmark results, 1 loop(s): 14 | * Time: 1.345, Avg: 1.345, Function: () => doThing() 15 | * Time: 1.118, Avg: 1.118, Function: () => doThingAnotherWay() 16 | */ 17 | function benchmark(arr, iter = 1) { 18 | var exp, 19 | r, 20 | i, 21 | j, 22 | len = arr.length; 23 | var start, end, used; 24 | var results = _.map(arr, fn => ({ fn: fn.toString(), time: 0, avg: 0 })); 25 | for (j = 0; j < iter; j++) { 26 | for (i = 0; i < len; i++) { 27 | start = Game.cpu.getUsed(); 28 | results[i].rtn = arr[i](); 29 | used = Game.cpu.getUsed() - start; 30 | if (i > 0 && results[i].rtn != results[0].rtn) 31 | throw new Error("Results are not the same!"); 32 | results[i].time += used; 33 | } 34 | } 35 | console.log(`Benchmark results, ${iter} loop(s): `); 36 | _.each(results, res => { 37 | res.avg = _.round(res.time / iter, 3); 38 | res.time = _.round(res.time, 3); 39 | console.log(`Time: ${res.time}, Avg: ${res.avg}, Function: ${res.fn}`); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /src/misc/JavaScript/Simplified grid class.js: -------------------------------------------------------------------------------- 1 | // warinternal 1 February 2017 at 04:06 2 | /** 3 | * Grid.js 4 | */ 5 | "use strict"; 6 | 7 | class Grid { 8 | /** @var height */ 9 | /** @var width */ 10 | 11 | /** 12 | * @param int 13 | * @param int 14 | */ 15 | constructor(width, height) { 16 | this.width = width; 17 | this.height = height; 18 | this.arr = []; 19 | } 20 | 21 | /** 22 | * @param int 23 | * @param int 24 | */ 25 | set(x, y, val) { 26 | if (x > this.width || y > this.height) 27 | throw new RangeError("Out of bounds"); 28 | let pos = y * this.height + x; 29 | this.arr[pos] = val; 30 | return this; 31 | } 32 | 33 | /** 34 | * @param int 35 | * @param int 36 | */ 37 | get(x, y) { 38 | let pos = y * this.height + x; 39 | return this.arr[pos]; 40 | } 41 | 42 | /** 43 | * 44 | */ 45 | toString() { 46 | return this.arr.toString(); 47 | } 48 | } 49 | 50 | module.exports = Grid; 51 | -------------------------------------------------------------------------------- /src/misc/JavaScript/String encryption.js: -------------------------------------------------------------------------------- 1 | // warinternal 24 May 2017 at 04:46 2 | 3 | /** 4 | * Vernam cipher 5 | * 6 | * @param string str - Plaintext or encryped message 7 | * @param string phrase - The passphrase you wish to use 8 | * @param Number off - (Optional) Offset value to use during xor. 32 just makes the encoded string more readable. 9 | */ 10 | function xorStr(str, phrase, off = 32) { 11 | var newStr = ""; 12 | for (var i = 0; i < str.length; i++) 13 | newStr += String.fromCharCode( 14 | str.charCodeAt(i) ^ (off + phrase.charCodeAt(i % phrase.length)) 15 | ); 16 | return newStr; 17 | } 18 | -------------------------------------------------------------------------------- /src/misc/JavaScript/Uint8ArrayConversion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 25 August 2017 by @Daboross 3 | * 4 | * String storage, encoding and decoding Uint8Array arrays. 5 | * 6 | * All credit for figuring out the actual implementation goes to dissi (@dissi) and ScreepsDiplomacy 7 | * (https://github.com/ButAds/ScreepsDiplomacy). 8 | * 9 | * This is a copy of the internals of ScreepsDiplomacy's DiplomacyPacket, but optimized for use encoding directly 10 | * from and decoding directly to Uint8Arrays. 11 | */ 12 | const stringStorage = global.StringStorage = { 13 | encode: function (byteArray) { 14 | var BITS_PER_CHARACTER = 15, 15 | BITS_PER_BYTE = 8; 16 | var result = []; 17 | var bitNum = 0; 18 | var currentCharData = 0; 19 | for (var i = 0; i < byteArray.length; i++) { 20 | var thisByte = byteArray[i]; 21 | for (var j = 0; j < BITS_PER_BYTE; j++) { 22 | var thisBit = thisByte >> j & 0x1; 23 | 24 | currentCharData |= thisBit << bitNum; 25 | bitNum += 1; 26 | if (bitNum >= BITS_PER_CHARACTER) { 27 | result.push(String.fromCodePoint(currentCharData)); 28 | bitNum = 0; 29 | currentCharData = 0; 30 | } 31 | } 32 | } 33 | if (currentCharData) { 34 | // To be honest, this _could_ have data in it that's = 0, but a null byte is not very well serialized 35 | // to JSON. Instead, we just append 2 '0's whenever decoding something, and that works out alright. 36 | result.push(String.fromCodePoint(currentCharData)); 37 | } 38 | return result.join(''); 39 | }, 40 | decode: function (string) { 41 | var BITS_PER_CHARACTER = 15, 42 | BITS_PER_BYTE = 8; 43 | // Add in two 0 bytes to the end to account for any 0's that were stripped at the end of the encoding. 44 | var result = new Uint8Array(Math.ceil(string.length * BITS_PER_CHARACTER / BITS_PER_BYTE) + 2); 45 | var resultPos = 0; 46 | 47 | var bitNum = 0; 48 | var currentByte = 0; 49 | for (var i = 0; i < string.length; i++) { 50 | var thisCharData = string.codePointAt(i); 51 | for (var j = 0; j < BITS_PER_CHARACTER; j++) { 52 | var bit = thisCharData >> j & 0x1; 53 | currentByte |= bit << bitNum; 54 | bitNum += 1; 55 | if (bitNum >= BITS_PER_BYTE) { 56 | result[resultPos++] = currentByte; 57 | bitNum = 0; 58 | currentByte = 0; 59 | } 60 | } 61 | } 62 | // This could have been unmodified, but at worst that just adds an extra '0' to the end! 63 | // Pbf ignores bytes after the message ends, so it doesn't really matter. 64 | result[resultPos++] = currentByte; 65 | // fill the rest of the array up with 0s 66 | for (resultPos; resultPos < result.length; resultPos++) { 67 | result[resultPos] = 0; 68 | } 69 | return result; 70 | } 71 | }; -------------------------------------------------------------------------------- /src/misc/JavaScript/Unicode directional arrows.js: -------------------------------------------------------------------------------- 1 | // warinternal 11 April 2017 at 06:11 2 | global.UNICODE_ARROWS = { 3 | [TOP] : "\u2191", 4 | [TOP_RIGHT] : "\u2197", 5 | [RIGHT] : "\u2192", 6 | [BOTTOM_RIGHT] : "\u2198", 7 | [BOTTOM] : "\u2193", 8 | [BOTTOM_LEFT] : "\u2199", 9 | [LEFT] : "\u2190", 10 | [TOP_LEFT] : "\u2196" 11 | }; -------------------------------------------------------------------------------- /src/misc/JavaScript/WorldPosition uniform global coordinate system.js: -------------------------------------------------------------------------------- 1 | // warinternal 24 November 2016 at 04:18 2 | 3 | /** 4 | * Uniform screep's world position with E0S0 as origin. 5 | */ 6 | 'use strict'; 7 | class WorldPosition 8 | { 9 | /** @property int x */ 10 | /** @property int y */ 11 | 12 | /** 13 | * @params {Object} point 14 | * @params {number} point.x - world position x (-3025 to 3025) 15 | * @params {number} point.y - world position y (-3025 to 3025) 16 | */ 17 | constructor(x,y) { 18 | this.x = x; 19 | this.y = y; 20 | Object.seal(this); 21 | } 22 | 23 | /** 24 | * @params {Object} point 25 | * @params {number} point.x 26 | * @params {number} point.y 27 | */ 28 | getRangeTo(point) { 29 | return this.getRangeToXY(point.x, point.y); 30 | } 31 | 32 | /** 33 | * @params {number} x 34 | * @params {number} y 35 | */ 36 | getRangeToXY(x,y) { 37 | return this.getChebyshevDist(x,y); 38 | } 39 | 40 | inRangeTo(point, range) { 41 | return this.inRangeToXY(point.x, point.y, range); 42 | } 43 | 44 | inRangeToXY(x,y,range) { 45 | return (this.getRangeToXY(x,y) <= range); 46 | } 47 | 48 | getDirectionTo(point) { 49 | return this.getDirectionToXY(point.x, point.y); 50 | } 51 | 52 | /** 53 | * @params {number} x - world coordinate x 54 | * @params {number} y - world coordinate y 55 | * ..don't question it. don't even think about it. 56 | */ 57 | getDirectionToXY(x,y) { 58 | let [dx,dy] = [x - this.x, y - this.y]; 59 | let arc = Math.atan2(dy, dx) * (180 / Math.PI); 60 | let dir = Math.round((arc / 45) + 3); 61 | return (dir == 0)?8:dir; 62 | } 63 | 64 | findRouteToWorldPosition(pos, opts) { 65 | return Game.map.findRoute(this.getRoomName(), pos.getRoomName(), opts); 66 | } 67 | 68 | findPathToWorldPosition(pos, opts) { 69 | let src = this.toRoomPosition(); 70 | let dst = pos.toRoomPosition(); 71 | return PathFinder.search(src, dst, opts); 72 | } 73 | 74 | /** 75 | * @params [WorldPosition] - array of other world positions to compare 76 | */ 77 | findClosestByRange(arr) { 78 | return _.min(arr, p => this.getRangeTo(p.wpos)); 79 | } 80 | 81 | /** @returns String - name of the room this point belongs to */ 82 | getRoomName() { 83 | let [x,y] = [Math.floor(this.x / 50), Math.floor(this.y / 50)] 84 | var result = ""; 85 | result += (x < 0 ? "W" + String(~x) : "E" + String(x)); 86 | result += (y < 0 ? "N" + String(~y) : "S" + String(y)); 87 | return result; 88 | } 89 | 90 | /** @returns boolean - do we have visibility in the room this point belongs to? */ 91 | isVisible() { 92 | let name = this.getRoomName(); 93 | return (Game.rooms[name] !== undefined); 94 | } 95 | 96 | /** @returns boolean - is this room part of the highways between sectors? */ 97 | isHighway() { 98 | let roomName = this.getRoomName(); 99 | let parsed = roomName.match(/^[WE]([0-9]+)[NS]([0-9]+)$/); 100 | return (parsed[1] % 10 === 0) || (parsed[2] % 10 === 0); 101 | } 102 | 103 | /** @returns boolean - do I own this point in space? */ 104 | isMine() { 105 | let roomName = this.getRoomName(); 106 | return _.get(Game.rooms, roomName + '.controller.my', false); 107 | } 108 | 109 | /** Distance functions */ 110 | 111 | /** 112 | * @params {Object} point 113 | * @params {number} point.x 114 | * @params {number} point.y 115 | */ 116 | getEuclidDist(pos) { 117 | return Math.hypot( pos.x - this.x, pos.y - this.y ); 118 | } 119 | 120 | /** 121 | * @params {Object} point 122 | * @params {number} point.x 123 | * @params {number} point.y 124 | */ 125 | getManhattanDist(pos) { 126 | return Math.abs(pos.x - this.x) + Math.abs(pos.y - this.y); 127 | } 128 | 129 | // yeah. and with that, it'll give you the correct distance of diagonals, whereas manhattan won't consider that. 130 | /** 131 | * @params {Object} point 132 | * @params {number} point.x 133 | * @params {number} point.y 134 | */ 135 | getChebyshevDist(x,y) { 136 | return Math.max( Math.abs((x-this.x)), Math.abs((y-this.y)) ); 137 | } 138 | 139 | /** serialization */ 140 | serialize() { 141 | return this.x + "_" + this.y; 142 | } 143 | 144 | static deserialize(str) { 145 | let [x,y] = str.split('_'); 146 | return new WorldPosition(x,y); 147 | } 148 | 149 | /** [object WorldPosition] */ 150 | get [Symbol.toStringTag]() { 151 | return 'WorldPosition'; 152 | } 153 | 154 | 155 | /** 156 | * @params {RoomPosition} roomPos 157 | * @params {number} roomPos.x 158 | * @params {number} roomPos.y 159 | * @params {String} roomPos.roomName 160 | * @returns {WorldPosition} 161 | */ 162 | static fromRoomPosition(roomPos) { 163 | let {x,y,roomName} = roomPos; 164 | if(!_.inRange(x, 0, 50)) throw new RangeError('x value ' + x + ' not in range'); 165 | if(!_.inRange(y, 0, 50)) throw new RangeError('y value ' + y + ' not in range'); 166 | if(roomName == 'sim') throw new RangeError('Sim room does not have world position'); 167 | let [name,h,wx,v,wy] = roomName.match(/^([WE])([0-9]+)([NS])([0-9]+)$/); 168 | if(h == 'W') wx = ~wx; 169 | if(v == 'N') wy = ~wy; 170 | return new WorldPosition( (50*wx)+x, (50*wy)+y ); 171 | } 172 | 173 | toRoomPosition() { 174 | let [rx,x] = [Math.floor(this.x / 50), this.x % 50]; 175 | let [ry,y] = [Math.floor(this.y / 50), this.y % 50]; 176 | if( rx < 0 && x < 0 ) x = (49 - ~x); 177 | if( ry < 0 && y < 0 ) y = (49 - ~y); 178 | return new RoomPosition(x,y,this.getRoomName()); 179 | } 180 | 181 | /** [world pos 1275,1275] */ 182 | toString() { 183 | return "[world pos " + this.x + "," + this.y + "]"; 184 | } 185 | } 186 | 187 | Object.defineProperty(RoomObject.prototype, "wpos", { 188 | get: function () { 189 | if(!this._wpos) 190 | this._wpos = WorldPosition.fromRoomPosition(this.pos); 191 | return this._wpos; 192 | }, 193 | configurable: true, 194 | enumerable: false 195 | }); 196 | 197 | RoomPosition.prototype.toWorldPosition = function() { 198 | if(!this._wpos) 199 | this._wpos = WorldPosition.fromRoomPosition(this); 200 | return this._wpos; 201 | } 202 | 203 | module.exports = WorldPosition; -------------------------------------------------------------------------------- /src/misc/JavaScript/actually commented evil tower code.js: -------------------------------------------------------------------------------- 1 | // daboross 30 December 2016 at 10:48 2 | 3 | // Get all rooms, wrap in a lodash chain (so we can execute the following methods directly on the object) 4 | _(Game.rooms) 5 | // Filter by ones that we own 6 | .filter(r => 7 | _.get(r, ["controller", "my"]) 8 | // Iterate over each room 9 | .forEach(r => { 10 | // Find all structures in the room, wrap the result in a lodash chain 11 | _(r.find(FIND_MY_STRUCTURES)) 12 | // Filter the structures by ones which are towers 13 | .filter("structureType", STRUCTURE_TOWER) 14 | // Shuffle the towers (so they happen in a random order) 15 | .shuffle() 16 | // "zip" the list of towers with the following information 17 | // (zip turns two lists [1, 2, 3], [a, b, c, d] into [[1, a], [2, b], [3, c], [undefined, d]], etc.) 18 | .zip( 19 | // For the other list, let's find all hostile creeps in the room 20 | _( 21 | r 22 | .find(FIND_HOSTILE_CREEPS) 23 | // Since we don't want to waste our energy, filter out all hostiles with no hostile parts 24 | .filter(x => { 25 | // Inside the filter, we're going to iterate over each bodypart of the creep, using "some" 26 | // "_.some" returns true the instant the inner condition returns true for any of the parts. 27 | // In this case, the inner condition is checking if the part's type (y.type) is in this list. 28 | // In other words, if the part is an ATTACK,WORK,RANGED_ATTACK or CARRY part. (we care about 29 | // CARRY parts since they can withdraw energy from structures) 30 | return _.some(x.body, y => 31 | [ATTACK, WORK, RANGED_ATTACK, CARRY].includes(y.type) 32 | ); 33 | }) 34 | // Now, we shuffle the targets (so they also appear in a random order) 35 | // We need to shuffle both the towers and the targets so that if there are more of one than the other, it is truly random which one is left unattacked. 36 | .shuffle() 37 | // This "ends" the lodash chain, executing the filter and shuffle, and giving us back a plain array 38 | // which can be used by "zip" 39 | .value() 40 | ) 41 | ) 42 | // Now that we have the "zipped" array, let's end the outer lodash chain. This does another forEach, except 43 | // this time it's over the [tower, target] pairs. 44 | .forEach(t => { 45 | // '!_.some(t, x => !x)' is a somewhat roundabout way of saying "are all things in this array true?" 46 | // Remember that zip() will include 'undefined' for some items if we have more towers than hostiles, or more hostiles than towers. This _.some() will return true if either term is undefined, and then '!_.some...' will be false. 47 | !_.some(t, x => !x) && 48 | // '&& ...' here is another somewhat roundabout way of saying "do the second action only if the first is true". In this case, it will only execute t[0].attack(t[1]) if '!_.some(t, x => !x)' is true. 49 | // Now, for the actual attack. Since zip() gives us pairs in the form of [item_in_first_array, item_in_second_array], 't' will be an array like [tower, hostile]. With that in mind, it makes perfect sense to say tower.attack(hostile) to actually perform the attack. 50 | t[0].attack(t[1]); 51 | }); 52 | }) 53 | ); 54 | -------------------------------------------------------------------------------- /src/misc/JavaScript/bunkerLayoutsHumanReadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 19 October 2017 by @sparr 3 | */ 4 | 5 | // maps letters in the layout arrays to structures and vice versa 6 | exports.layoutKey = { 7 | 'A': STRUCTURE_SPAWN, 8 | 'N': STRUCTURE_NUKER, 9 | 'K': STRUCTURE_LINK, 10 | 'L': STRUCTURE_LAB, 11 | 'E': STRUCTURE_EXTENSION, 12 | 'S': STRUCTURE_STORAGE, 13 | 'T': STRUCTURE_TOWER, 14 | 'O': STRUCTURE_OBSERVER, 15 | 'M': STRUCTURE_TERMINAL, 16 | 'P': STRUCTURE_POWER_SPAWN, 17 | '.': STRUCTURE_ROAD, 18 | 'C': STRUCTURE_CONTAINER, 19 | 'R': STRUCTURE_RAMPART, 20 | 'W': STRUCTURE_WALL, 21 | }; 22 | _.merge(exports.layoutKey, _.invert(exports.layoutKey)); 23 | 24 | // the preferred layout, if there's enough room 25 | exports.bunkerLayout = [ 26 | ' ..E...E.. ', 27 | ' .EE.EEE.EE. ', 28 | '.EE.E.E.E.EE.', 29 | '.E.EEA.EEE.E.', 30 | 'E.EEE.T.EEE.E', 31 | '.E.E.T.T.A.E.', 32 | '.EE.NSKMP.E.E', 33 | '.E.E.T.T.E.E.', 34 | 'E.EEE.T.OLL..', 35 | '.E.EEA.ELL.L.', 36 | '.EE.E.E.L.LL.', 37 | ' .EE.E.E.LL. ', 38 | ' ..E.E.... ', 39 | ]; 40 | 41 | exports.bunkerExtensionOrder = [ 42 | ' 3 7 ', 43 | ' 43 447 78 ', 44 | ' 43 2 4 7 78 ', 45 | ' 3 24 887 7 ', 46 | '3 242 887 7', 47 | ' 4 2 7 ', 48 | ' 44 8 8', 49 | ' 5 5 8 8 ', 50 | '5 566 ', 51 | ' 5 56 6 ', 52 | ' 65 5 6 ', 53 | ' 65 5 6 ', 54 | ' 6 6 ', 55 | ]; 56 | 57 | exports.bunkerRoadOrder = [ 58 | ' .. ... .. ', 59 | ' . 2 7 . ', 60 | '. 2 2 7 7 .', 61 | '. 2 2 7 .', 62 | ' 2 2 3 7 ', 63 | '. 2 2 3 7 7 .', 64 | '. 2 7 8 ', 65 | '. 5 5 . . 8 .', 66 | ' 5 5 . ..', 67 | '. 5 5 . .', 68 | '. 5 5 6 . .', 69 | ' . 5 6 . . ', 70 | ' .. . .... ', 71 | ]; 72 | 73 | exports.bunkerRampartOrder = [ 74 | ' 555555555 ', 75 | ' 55777777755 ', 76 | '5577777777755', 77 | '57777 77775', 78 | '5777 3 7775', 79 | '577 333 775', 80 | '577 33333 775', 81 | '577 333 775', 82 | '5777 3 7775', 83 | '57777 77775', 84 | '5577777777755', 85 | ' 55777777755 ', 86 | ' 555555555 ', 87 | ]; 88 | 89 | // just the core of the bunker, plus two spawns 90 | exports.coreLayout = [ 91 | ' . ', 92 | ' AT. ', 93 | ' .T.T. ', 94 | '.NSKMP.', 95 | ' .T.T. ', 96 | ' .TAO ', 97 | ' . ', 98 | ]; 99 | 100 | // just the lab block, for placement elsewhere if necessary 101 | exports.labLayout = [ 102 | ' LL.', 103 | 'LL.L', 104 | 'L.LL', 105 | '.LL ', 106 | ]; 107 | 108 | // rapid-fill extension block, if there's room 109 | exports.extensionLayout = [ 110 | ' EEE ', 111 | ' EErrEE ', 112 | ' EErEErEE ', 113 | ' EErEEErrEE', 114 | 'EErECECEErE', 115 | ' rEEEKEEEr ', 116 | 'ErEECECErEE', 117 | 'EErrEEErEE ', 118 | ' EErEErEE ', 119 | ' EErrEE ', 120 | ' EEE ', 121 | ]; 122 | 123 | /** 124 | * Get all the positions for a certain structure/letter from a layout 125 | * @param {String[]} layout 126 | * @param {String|String} char letter or structure to return, optional 127 | * @return {{x:Number,y:Number}[]} array of coordinate objects 128 | * @return {Object} map of structure types to arrays of coordinate objects 129 | */ 130 | exports.getPositions = function(layout, char) { 131 | if (typeof(char) === 'string') { 132 | char = [char]; 133 | } 134 | const height = layout.length; 135 | const width = layout[0].length; 136 | const top = height / 2 | 0; 137 | const left = width / 2 | 0; 138 | if (char instanceof Array) { 139 | const positions = []; 140 | for (let c of char) { 141 | if (c.length>1) { 142 | if (c in exports.layoutKey) { 143 | c = exports.layoutKey[c]; 144 | } else { 145 | continue; 146 | } 147 | } 148 | for (let y = 0; y < height; y++) { 149 | for (let x = 0; x < width; x++) { 150 | if (layout[y][x] === c) { 151 | positions.push({x: x-left, y: y-top}); 152 | } 153 | } 154 | } 155 | } 156 | return positions; 157 | } else { 158 | const positions = {}; 159 | for (let y = 0; y < height; y++) { 160 | for (let x = 0; x < width; x++) { 161 | const char = layout[y][x]; 162 | positions[exports.layoutKey[char]] = positions[exports.layoutKey[char]] || []; 163 | positions[exports.layoutKey[char]].push({x: x-left, y: y-top}); 164 | } 165 | } 166 | } 167 | }; 168 | -------------------------------------------------------------------------------- /src/misc/JavaScript/colors.js: -------------------------------------------------------------------------------- 1 | // dissi 14 December 2016 at 23:18 2 | 3 | function getColorBasedOnPercentage(thePercentage) { 4 | var hue = Math.floor(((100 - thePercentage) * 120) / 100); // go from green to red 5 | var saturation = Math.abs(thePercentage - 50) / 50; 6 | return hsv2rgb(hue, saturation, 1); 7 | } 8 | 9 | var hsv2rgb = function(h, s, v) { 10 | // adapted from http://schinckel.net/2012/01/10/hsv-to-rgb-in-javascript/ 11 | var rgb, 12 | i, 13 | data = []; 14 | if (s === 0) { 15 | rgb = [v, v, v]; 16 | } else { 17 | h = h / 60; 18 | i = Math.floor(h); 19 | data = [v * (1 - s), v * (1 - s * (h - i)), v * (1 - s * (1 - (h - i)))]; 20 | switch (i) { 21 | case 0: 22 | rgb = [v, data[2], data[0]]; 23 | break; 24 | case 1: 25 | rgb = [data[1], v, data[0]]; 26 | break; 27 | case 2: 28 | rgb = [data[0], v, data[2]]; 29 | break; 30 | case 3: 31 | rgb = [data[0], data[1], v]; 32 | break; 33 | case 4: 34 | rgb = [data[2], data[0], v]; 35 | break; 36 | default: 37 | rgb = [v, data[0], data[1]]; 38 | break; 39 | } 40 | } 41 | return ( 42 | "#" + 43 | rgb 44 | .map(function(x) { 45 | return ("0" + Math.round(x * 255).toString(16)).slice(-2); 46 | }) 47 | .join("") 48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /src/misc/JavaScript/get room type without visibility (but regex^^).js: -------------------------------------------------------------------------------- 1 | // enrico 25 February 2017 at 23:38 2 | let isAlleyRoom = /^[WE]\d*0[NS]\d*0$/.test(roomName); 3 | let isCoreRoom = /(^[WE]\d*5[NS]\d*5$)|(^[WE]\d*5[NS]\d*5$)/.test(roomName); 4 | let isCenterRoom = /^[WE]\d*[4-6]+[NS]\d*[4-6]+$/.test(roomName); // = core room + sk rooms 5 | let isSourceKeeperRoom = /(^[WE]\d*[4-6][NS]\d*[4|6]$)|(^[WE]\d*[4|6][NS]\d*[4-6]$)/.test( 6 | roomName 7 | ); 8 | let isControllerRoom = /(^[WE]\d*[1-9]+[NS]\d*[1-3|7-9]+$)|(^[WE]\d*[1-3|7-9]+[NS]\d*[1-9]+$)/.test( 9 | roomName 10 | ); 11 | -------------------------------------------------------------------------------- /src/misc/JavaScript/how to delete the memory of dead creeps (in memoriam!).js: -------------------------------------------------------------------------------- 1 | // artritus 20 August 2016 at 01:57 2 | 3 | // delete memory of dead creeps 4 | // do this BEFORE spawning new creeps or the memory will get deleted before they exist 5 | for (var i in Memory.creeps) { 6 | if (!Game.creeps[i]) { 7 | delete Memory.creeps[i]; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/misc/JavaScript/module.exports example.js: -------------------------------------------------------------------------------- 1 | // maxion 13 August 2017 at 20:39 2 | 3 | // in module.js 4 | var thing = { 5 | foo: function() { 6 | console.log('hello world'); 7 | }, 8 | bar: function(param = 'world') { // default value if param is undefined (or not passed to the function) 9 | console.log('hello ' + param); 10 | } 11 | }; 12 | module.exports = thing; 13 | ​ 14 | // in main.js above the loop 15 | var functionModule = require('module.js'); 16 | ​ 17 | // inside loop 18 | functionModule.foo(); 19 | functionModule.bar('human'); -------------------------------------------------------------------------------- /src/misc/JavaScript/moveTo version supporting raw PathFinder arguments, and a moveByPath which directly reads serialized strings.js: -------------------------------------------------------------------------------- 1 | // daboross 12 December 2016 at 00:28 2 | 3 | /** 4 | * Utility function turning a direction constant into a dx/dy difference. 5 | */ 6 | const directionToDxDy = function(dir) { 7 | switch (dir) { 8 | case TOP: 9 | return [0, -1]; 10 | case TOP_RIGHT: 11 | return [1, -1]; 12 | case RIGHT: 13 | return [1, 0]; 14 | case BOTTOM_RIGHT: 15 | return [1, 1]; 16 | case BOTTOM: 17 | return [0, 1]; 18 | case BOTTOM_LEFT: 19 | return [-1, 1]; 20 | case LEFT: 21 | return [-1, 0]; 22 | case TOP_LEFT: 23 | return [-1, -1]; 24 | default: 25 | return null; 26 | } 27 | }; 28 | 29 | /** 30 | * Utility function turning a dx/dy difference into a direction constant. 31 | * 32 | * Note: ignores magnitude of arguments, and only looks at sign. 33 | */ 34 | const dxDyToDirection = function(dx, dy) { 35 | if (dx < 0) { 36 | if (dy < 0) { 37 | return TOP_LEFT; 38 | } else if (dy > 0) { 39 | return BOTTOM_LEFT; 40 | } else { 41 | return LEFT; 42 | } 43 | } else if (dx > 0) { 44 | if (dy < 0) { 45 | return TOP_RIGHT; 46 | } else if (dy > 0) { 47 | return BOTTOM_RIGHT; 48 | } else { 49 | return RIGHT; 50 | } 51 | } else { 52 | if (dy < 0) { 53 | return TOP; 54 | } else if (dy > 0) { 55 | return BOTTOM; 56 | } else { 57 | // both dx and dy are 0! 58 | return null; 59 | } 60 | } 61 | }; 62 | 63 | /** 64 | * Searches for a path using PathFinder and the given opts, turns the path into a Room.findPath-compatible 65 | * serialized result, and returns that result. 66 | * 67 | * Please ensure that all arguments have been validated when passing in, and that targetPos is a raw position 68 | * (not a RoomObject with a pos property). 69 | */ 70 | const findPathPathFinder = function(originPos, targetPos, options) { 71 | const result = PathFinder.search( 72 | originPos, 73 | { 74 | pos: targetPos, 75 | range: "range" in options ? options.range : 1 76 | }, 77 | options 78 | ); 79 | 80 | const path = result.path; 81 | var resultStringArray = []; // it's faster to use [...].join('') than to continuously add to a string. 82 | var roomToConvert = originPos.roomName; 83 | 84 | if (path.length < 1) { 85 | return ""; 86 | } 87 | 88 | // The serialized format starts with the second position's x and y values, then the direction from the 89 | // first pos to second, then direction from second to third, etc. 90 | 91 | if (path[0].x > 9) { 92 | resultStringArray.push(path[0].x); 93 | } else { 94 | resultStringArray.push(0, path[0].x); // 0-pad 95 | } 96 | if (path[0].y > 9) { 97 | resultStringArray.push(path[0].y); 98 | } else { 99 | resultStringArray.push(0, path[0].y); // 0-pad 100 | } 101 | 102 | var last_x = originPos.x; 103 | var last_y = originPos.y; 104 | var pos, dx, dy, dir; 105 | for (var i = 0; i < path.length; i++) { 106 | pos = path[i]; 107 | dx = pos.x - last_x; 108 | dy = pos.y - last_y; 109 | if (dx === -49) { 110 | dx = 1; 111 | } else if (dx === 49) { 112 | dx = -1; 113 | } 114 | if (dy === -49) { 115 | dy = 1; 116 | } else if (dy === 49) { 117 | dy = -1; 118 | } 119 | 120 | resultStringArray.push(dxDyToDirection(dx, dy)); 121 | if (pos.roomName != roomToConvert) { 122 | break; 123 | } 124 | last_x = pos.x; 125 | last_y = pos.y; 126 | } 127 | return resultStringArray.join(""); 128 | }; 129 | 130 | Creep.prototype.defaultMoveTo = Creep.prototype.moveTo; 131 | 132 | /** 133 | * Custom replacement of moveTo, which just calls moveTo unless a 'roomCallback' argument is passed in in the 134 | * options. The memory format this function uses is identical to the default moveTo's, so it is supported 135 | * alternate* calling this function with and without the 'roomCallback' option. 136 | * 137 | * When passed roomCallback, this function is identical to moveTo, except it: 138 | * - assumes that Creep.prototype.moveByPath has already been optimized to deal with 139 | * serialized paths, and will pass it purely serialized paths. 140 | * - does not accept the 'serializeMemory' option, and will always assume it is set to true 141 | * - does not accept any of the 'costCallback', 'ignoreCreeps', 'ignoreRoads' or 'ignoreDestructibleStructures' 142 | * options. (note: roomCallback is used by PathFinder instead of the costCallback used by findPath) 143 | * - passes all arguments on to PathFinder.search as is. 144 | * - accepts one additional option, 'range', which is passed into PathFinder as part of the target object. 145 | */ 146 | Creep.prototype.moveTo = function(arg1, arg2, arg3) { 147 | var x, y, roomName, opts; 148 | if (arg3 === undefined) { 149 | if (arg1.pos) { 150 | arg1 = arg1.pos; 151 | } 152 | x = arg1.x; 153 | y = arg1.y; 154 | roomName = arg1.roomName; 155 | opts = arg2 || {}; 156 | } else { 157 | x = arg1; 158 | y = arg2; 159 | roomName = this.pos.roomName; 160 | opts = arg3 || {}; 161 | } 162 | 163 | if (!("roomCallback" in opts)) { 164 | return this.defaultMoveTo(arg1, arg2, arg3); // Compatible memory format. 165 | } 166 | if (!_.isNumber(x) || !_.isNumber(y) || !_.isString(roomName)) { 167 | return ERR_INVALID_TARGET; 168 | } 169 | if (!_.isObject(opts)) { 170 | return ERR_INVALID_ARGS; 171 | } 172 | if (!this.my) { 173 | return ERR_NOT_OWNER; 174 | } 175 | if (this.spawning) { 176 | return ERR_BUSY; 177 | } 178 | if (this.fatigue > 0) { 179 | return ERR_TIRED; 180 | } 181 | if (!this.hasActiveBodyparts(MOVE)) { 182 | return ERR_NO_BODYPART; 183 | } 184 | 185 | const targetPos = new RoomPosition(x, y, roomName); 186 | 187 | if (this.pos.isNearTo(targetPos)) { 188 | if (this.pos.isEqualTo(targetPos)) { 189 | return OK; 190 | } else { 191 | return this.move(this.pos.getDirectionTo(targetPos)); 192 | } 193 | } 194 | 195 | const reusePath = 196 | _.isObject(this.memory) && ("reusePath" in opts ? opts.reusePath : 5); 197 | 198 | if (reusePath) { 199 | var _move = this.memory._move; 200 | 201 | if ( 202 | _.isObject(_move) && 203 | Game.time <= _move.time + Number(reusePath) && 204 | _move.room == this.pos.roomName && 205 | _move.dest.room == targetPos.roomName && 206 | _move.dest.x == targetPos.x && 207 | _move.dest.y == targetPos.y 208 | ) { 209 | // moveByPath is optimized to deal with serialized paths already, and it's more CPU to 210 | // re-serialize each tick with a smaller string than it is to store the larger string the 211 | // whole time. 212 | var byPathResult = this.moveByPath(_move.path); 213 | if ( 214 | byPathResult !== ERR_NOT_FOUND && 215 | byPathResult !== ERR_INVALID_ARGS && 216 | byPathResult !== ERR_NO_PATH 217 | ) { 218 | return byPathResult; 219 | } 220 | } 221 | } 222 | 223 | if (opts.noPathFinding) { 224 | return ERR_NOT_FOUND; 225 | } 226 | 227 | // This uses PathFinder, and returns the result as an already-serialized path. 228 | const path = findPathPathFinder(this.pos, targetPos, opts); 229 | 230 | if (reusePath) { 231 | this.memory._move = { 232 | dest: { 233 | x: targetPos.x, 234 | y: targetPos.y, 235 | room: targetPos.roomName 236 | }, 237 | time: Game.time, 238 | path: path, 239 | room: this.pos.roomName 240 | }; 241 | } 242 | 243 | return this.moveByPath(path); 244 | }; 245 | 246 | Creep.prototype.defaultMoveByPath = Creep.prototype.moveByPath; 247 | 248 | /** 249 | * Version of moveByPath, built to read raw serialized path strings without deserializing. 250 | * 251 | * If passed a non-string argument, this will just invoke the default moveByPath code. 252 | * 253 | * When passed a string, it should behave identically to the default moveByPath, but hopefully slightly faster. 254 | */ 255 | Creep.prototype.moveByPath = function(path) { 256 | if (!_.isString(path)) { 257 | return this.defaultMoveByPath(path); 258 | } 259 | var path_len = path.length; 260 | if (path_len < 5) { 261 | return ERR_NO_PATH; 262 | } 263 | var my_x = this.pos.x, 264 | my_y = this.pos.y; 265 | var x_to_check = +path.slice(0, 2); 266 | var y_to_check = +path.slice(2, 4); 267 | var dir, dxdy; 268 | // The path serialization format basically starts with the second position x, second position y, and then 269 | // follows with a list of directions *to get to each position*. To clarify, the first direction, at idx=4, 270 | // gives the direction *from the first position to the second position*. So, to find the first position, 271 | // we subtract that! I do think this is actually more performant than trying to do any more complicated 272 | // logic in the loop. 273 | dxdy = directionToDxDy(+path[4]); 274 | x_to_check -= dxdy[0]; 275 | y_to_check -= dxdy[1]; 276 | // Since we start at 4 again, we'll be re-adding what we just subtracted above - this lets us check both the 277 | // first and second positions correctly! 278 | for (var idx = 4; idx < path_len; idx++) { 279 | // Essentially at this point, *_to_check represent the point reached by the *last* movement (the pos 280 | // reached by the movement at (idx - 1) since idx just got incremented at the start of this loop) 281 | // Also, if this is the first iteration and x/y_to_check match the first pos, idx is at 4, the fifth 282 | // pos, directly after the initial x/y, and also the first direction to go! 283 | if (x_to_check === my_x && y_to_check == my_y) { 284 | dir = +path[idx]; 285 | return this.move(dir); 286 | } 287 | dxdy = directionToDxDy(+path[idx]); 288 | if (dxdy === null) { 289 | return ERR_INVALID_ARGS; 290 | } 291 | x_to_check += dxdy[0]; 292 | y_to_check += dxdy[1]; 293 | } 294 | return ERR_NOT_FOUND; 295 | }; 296 | -------------------------------------------------------------------------------- /src/misc/JavaScript/powerCreepChatter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 30 June 2019 by @kittytack 3 | * If I can opgen, do opgen... 4 | */ 5 | if (creep.usePower(PWR_GENERATE_OPS) == OK) { 6 | const noises = ['Meow', 'Ding', 'Beep', 'Purr']; // Array of random noises 7 | const punctuations = ['!', '...', '~', '.']; // Array of random punctuation 8 | creep.say(_.sample(noises) + _.sample(punctuations), true); // Say a random noise, followed by a random punctuation 9 | } -------------------------------------------------------------------------------- /src/misc/JavaScript/pushdownAutomataStateMachine.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 18 October 2017 by @warinternal 3 | * 4 | * Pushdown automata state machine 5 | */ 6 | 7 | /** Call this to run the current state */ 8 | RoomObject.prototype.invokeState = function() { 9 | if(!this.memory.stack || !this.memory.stack.length) 10 | return false; 11 | var [[state,scope]] = this.memory.stack; 12 | var method = `run${state}`; 13 | if(!this[method]) 14 | return false; 15 | this[method](scope); 16 | return true; 17 | }; 18 | 19 | /** 20 | * @param {string} [defaultState] - Fallback state if none defined. 21 | */ 22 | RoomObject.prototype.getState = function (defaultState = 'I') { 23 | if(!this.memory.stack) 24 | return defaultState; 25 | return this.memory.stack[0][0] || defaultState; 26 | }; 27 | 28 | /** 29 | * @param {string} state - Name of state to switch to. 30 | * @param {*} scope - Any data you want to supply to the state. 31 | */ 32 | RoomObject.prototype.setState = function (state, scope) { 33 | if (state == null) 34 | throw new TypeError('State can not be null'); 35 | if (!this.memory.stack) 36 | this.memory.stack = [[]]; 37 | this.memory.stack[0] = [state, scope]; 38 | return state; 39 | }; 40 | 41 | /** 42 | * @param {string} state - Name of state to push 43 | * @param {*} scope - Any data you want to supply to the state. 44 | */ 45 | RoomObject.prototype.pushState = function (state, scope={}) { 46 | if (!this.memory.stack) 47 | this.memory.stack = []; 48 | var method = `run${state}`; 49 | if (this[method] == null) 50 | throw new Error(`No such state or action ${method}`); 51 | if (this.memory.stack.length >= 100) 52 | throw new Error('Automata stack limit exceeded'); 53 | this.memory.stack.unshift([state, scope]); 54 | return state; 55 | }; 56 | 57 | /** Pop the current state off the stack */ 58 | RoomObject.prototype.popState = function () { 59 | if (!this.memory.stack || !this.memory.stack.length) 60 | return; 61 | const [state] = this.memory.stack.shift(); 62 | if (!this.memory.stack.length) 63 | this.memory.stack = undefined; 64 | }; 65 | 66 | /** Clear the stack */ 67 | RoomObject.prototype.clearState = function() { 68 | this.memory.stack = undefined; 69 | }; 70 | 71 | /** Example state - goto location */ 72 | Creep.prototype.runGoto = function (scope) { 73 | var { pos, range = 1 } = scope; 74 | var roomPos = _.create(RoomPosition.prototype, pos); 75 | if (this.moveTo(roomPos, { range: range }) === ERR_NO_PATH) 76 | this.popState(); 77 | }; 78 | 79 | /** Example state - goto room */ 80 | Creep.prototype.runGotoRoom = function (scope) { 81 | if (this.moveToRoom(scope) === ERR_NO_PATH) 82 | this.popState(); 83 | }; 84 | 85 | /** 86 | * Example - Heal self and flee 87 | * Push this state when you start to get hurt. Creep will heal 88 | * and go back to what it was doing. If it keeps getting hurt, it 89 | * will leave the room, and try to go back to healing. 90 | */ 91 | Creep.prototype.runHealSelf = function (scope) { 92 | this.heal(this); 93 | // take this opportunity to flee 94 | if (this.hits >= this.hitsMax) { // If we're back to full, we're done 95 | return this.popState(); 96 | } else if(this.hits / this.hitsMax < 0.5) { // Otherwise run away 97 | // Find neighboring room 98 | this.pushState('GotoRoom', /* neighbor */); 99 | } 100 | }; -------------------------------------------------------------------------------- /src/misc/JavaScript/roomDescribe.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Posted 20 June 2019 by @engineeryo 3 | * Get type of room from name 4 | * 5 | * @author engineeryo 6 | * @co-author warinternal 7 | */ 8 | 9 | global.ROOM_STANDARD = 'room' 10 | global.ROOM_SOURCE_KEEPER = 'source_keeper' 11 | global.ROOM_CENTER = 'center' 12 | global.ROOM_HIGHWAY = 'highway' 13 | global.ROOM_CROSSROAD = 'highway_portal' 14 | 15 | Room.describe = function(name) { 16 | const [EW, NS] = name.match(/\d+/g) 17 | if (EW%10 == 0 && NS%10 == 0) { 18 | return ROOM_CROSSROAD 19 | } 20 | else if (EW%10 == 0 || NS%10 == 0) { 21 | return ROOM_HIGHWAY 22 | } 23 | else if (EW%5 == 0 && NS%5 == 0) { 24 | return ROOM_CENTER 25 | } 26 | else if (Math.abs(5 - EW%10) <= 1 && Math.abs(5 - NS%10) <= 1) { 27 | return ROOM_SOURCE_KEEPER 28 | } 29 | else { 30 | return ROOM_STANDARD 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/misc/JavaScript/sos_lib_crypto.js: -------------------------------------------------------------------------------- 1 | // tedivm 27 May 2017 2 | // https://gist.github.com/tedivm/188b95437afa797515a4472d01c9ca09 3 | 4 | /* 5 | Copyright (c) 2017 Robert Hafner 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | */ 15 | 16 | /* 17 | This crypto library was made for the game Screeps. 18 | It is not intended to be used in "real" situations- it has not been reviewed, 19 | it was not built by an expert, and it probably has a billion holes. It was 20 | created for fun and should only be used for fun. For all real purposes it should 21 | be considered plain text. 22 | This library uses Screeps `Memory` to store keys using a label. It will 23 | automatically create keys where they do not exist, or they can be passed in 24 | explicitly from another source. 25 | The cipher used is a simple autokeyed streamcipher with an initialization vector 26 | and block padding. In other words a message encrypted twice with the same key 27 | will have different outputs, and the original message size can only be 28 | approximated. 29 | */ 30 | 31 | let crypto = {}; 32 | 33 | // Reduce information leakage by padding message to fit a full block. On block 34 | // of additional entropy is also padded to the beginning of the message. 35 | crypto.blocksize = 4; 36 | 37 | // skip lower unicode characters since they are symbols which may not 38 | // transfer well. 39 | crypto.minnumber = 0; 40 | crypto.maxnumber = Math.pow(2, 16) - 1 - crypto.minnumber; 41 | 42 | // Key will be autogenerated if it doesn't exist 43 | crypto.getKey = function(label, length = 256) { 44 | if (!Memory.sos) { 45 | return false; 46 | } 47 | 48 | if (!Memory.sos.crypto) { 49 | Memory.sos.crypto = {}; 50 | } 51 | 52 | if (!Memory.sos.crypto.keys) { 53 | Memory.sos.crypto.keys = {}; 54 | } 55 | 56 | if (!Memory.sos.crypto.keys[label]) { 57 | let key = ""; 58 | while (key.length < length) { 59 | key += this.getCharacterFromNumber(_.random(0, this.maxnumber)); 60 | } 61 | Memory.sos.crypto.keys[label] = key; 62 | } 63 | return Memory.sos.crypto.keys[label]; 64 | }; 65 | 66 | // Manually set the key for a specific label. 67 | crypto.saveKey = function(label, key) { 68 | if (!Memory.sos.crypto) { 69 | Memory.sos.crypto = {}; 70 | } 71 | 72 | if (!Memory.sos.crypto.keys) { 73 | Memory.sos.crypto.keys = {}; 74 | } 75 | 76 | Memory.sos.crypto.keys[label] = key; 77 | }; 78 | 79 | // Remove key for a specific label. 80 | crypto.removeKey = function(label) { 81 | if (!Memory.sos.crypto) { 82 | return; 83 | } 84 | 85 | if (!Memory.sos.crypto.keys) { 86 | return; 87 | } 88 | 89 | if (!!Memory.sos.crypto.keys[label]) { 90 | delete Memory.sos.crypto.keys[label]; 91 | } 92 | }; 93 | 94 | // If 'askey' is true the label will be used as a key, otherwise it 95 | // will be pulled from the getKey function. 96 | crypto.encrypt = function(string, label, askey = false) { 97 | const key = askey ? label : this.getKey(label); 98 | 99 | // string + one character for initialization + one to define padding amount 100 | const message_size = string.length + 2; 101 | 102 | // Get number of blocks (rounded up) and add one more for entropy. 103 | const blocks = Math.ceil(message_size / this.blocksize) + 1; 104 | 105 | // Calculate full message size. 106 | const message_size_filled = blocks * this.blocksize; 107 | 108 | // Calculate number of needed padding characters. 109 | const padding_count = message_size_filled - message_size; 110 | 111 | // Start output with random character, saving it's value to add to keystream. 112 | let output = this.getCharacterFromNumber(_.random(0, this.maxnumber)); 113 | let lastkey_value = this.getNumberFromCharacter(output); 114 | 115 | // Add padding count and padding characters to front of message. 116 | let prefix = ""; 117 | prefix += this.getCharacterFromNumber(padding_count); 118 | for (let i = 0; i < padding_count; i++) { 119 | prefix += this.getCharacterFromNumber(_.random(0, this.maxnumber)); 120 | } 121 | string = prefix + string; 122 | 123 | // Loop over string and build output. 124 | for (let i = 0; i < string.length; i++) { 125 | // Get number that represents current character in string. 126 | const base_value = this.getNumberFromCharacter(string[i]); 127 | 128 | // Get numeric value of current key character 129 | const key_value = this.getNumberFromCharacter(key[i % key.length]); 130 | 131 | // Add current value, key value, and lastkey_value. Modulus by max number. 132 | let value = base_value + ((key_value + lastkey_value) % this.maxnumber); 133 | 134 | // If number is higher than maxnumber subtract maxnumber. 135 | if (value > this.maxnumber) { 136 | value = value - this.maxnumber; 137 | } 138 | 139 | // Add ciphertext character to output string. 140 | output += this.getCharacterFromNumber(value); 141 | 142 | // Save current cleartext character to feed into next round. 143 | lastkey_value = base_value; 144 | } 145 | 146 | return output; 147 | }; 148 | 149 | // If 'askey' is true the label will be used as a key, otherwise it 150 | // will be pulled from the getKey function. 151 | crypto.decrypt = function(string, label, askey = false) { 152 | const key = askey ? label : this.getKey(label); 153 | let padding = Infinity; 154 | let output = ""; 155 | let lastchar = string[0]; 156 | string = string.substr(1); 157 | for (let i = 0; i < string.length; i++) { 158 | // Get numeric value of current key character 159 | const key_value = this.getNumberFromCharacter(key[i % key.length]); 160 | 161 | // Get the numeric value of the last ciphertext character. 162 | const modifier = this.getNumberFromCharacter(lastchar[0]); 163 | 164 | // Add modifier and key value, mod by maxnumber, and subtract from ciphertext value. 165 | let value = 166 | this.getNumberFromCharacter(string[i]) - 167 | ((key_value + modifier) % this.maxnumber); 168 | 169 | // If value is less than zero add maxnumber back. 170 | if (value < 0) { 171 | value = this.maxnumber + value; 172 | } 173 | 174 | // Store last cleartext character to act as modifier for next stage. 175 | lastchar = this.getCharacterFromNumber(value); 176 | 177 | if (i == 0) { 178 | // Get padding value 179 | padding = value; 180 | } else if (padding <= 0) { 181 | // Add cleartext character to output message 182 | output += lastchar; 183 | } else { 184 | // Discard current character as it is part of the block padding 185 | padding--; 186 | } 187 | } 188 | 189 | return output; 190 | }; 191 | 192 | // Converts unicode character to number. 193 | crypto.getNumberFromCharacter = function(char) { 194 | let number = char.charCodeAt(0); 195 | number = number - this.minnumber; 196 | return number; 197 | }; 198 | 199 | // Converts number into unicode. Number should be less than maxnumber. 200 | crypto.getCharacterFromNumber = function(number) { 201 | return String.fromCharCode(+number + +this.minnumber); 202 | }; 203 | 204 | module.exports = crypto; 205 | -------------------------------------------------------------------------------- /src/misc/Kotlin/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /src/misc/Kotlin/DistanceTransform/DistanceTransform.kt: -------------------------------------------------------------------------------- 1 | package AET.Colony.Planner 2 | 3 | import screeps.api.* 4 | import kotlin.math.min 5 | 6 | /** 7 | Distance transform based on Screeps Slack #automation pinned files 8 | Thanks to bames, sparr and semperrabbit 9 | 10 | Converted to Kotlin by Vipo 11 | 12 | */ 13 | 14 | class DistanceTransform(private val room: Room) { 15 | 16 | // The value in the CostMatrix is how many open tiles there is in all directions 17 | fun distanceTransformAllDirections() : PathFinder.CostMatrix { 18 | val costMatrix = buildableTilesForRoom() 19 | 20 | val bits = costMatrix._bits 21 | 22 | val oob = 255 23 | 24 | var A = 0; var B = 0; var C = 0 25 | var D = 0; var E = 0; var F = 0 26 | var G = 0; var H = 0; var I = 0 27 | 28 | for (n in 51..2499) { 29 | if(bits[n] != 0) { 30 | A = bits[n-51] 31 | B = bits[n-50] 32 | C = bits[n-49] 33 | D = bits[n-1] 34 | 35 | if(n % 50 == 0) {A = oob; D = oob } 36 | if(n % 50 == 49) {C = oob} 37 | 38 | bits[n] = min(min(min(A, B), min(C, D)), 254) + 1 39 | } 40 | } 41 | 42 | for(n in 2448 downTo 0) { 43 | E = bits[n] 44 | F = bits[n+1] 45 | G = bits[n+49] 46 | H = bits[n+50] 47 | I = bits[n+51] 48 | 49 | if(n > 2400) {G = oob; H = oob; I = oob} 50 | if(n % 50 == 49) {F = oob; I = oob} 51 | if(n % 50 == 0) {G = oob} 52 | 53 | bits[n] = min(min(min(F, G) + 1, min(H, I) + 1), E) 54 | } 55 | 56 | return costMatrix 57 | } 58 | 59 | // The value in the CostMatrix is how many open tiles there is up and left (the value is the bottom right corner) 60 | fun distanceTransformUpLeft() : PathFinder.CostMatrix { 61 | val costMatrix = buildableTilesForRoom() 62 | 63 | val bits = costMatrix._bits 64 | 65 | val oob = 255 66 | 67 | var A = 0; var B = 0; 68 | var D = 0; 69 | 70 | for (n in 51..2499) { 71 | if(bits[n] != 0) { 72 | A = bits[n-51] 73 | B = bits[n-50] 74 | D = bits[n-1] 75 | 76 | if(n % 50 == 0) {A = oob; D = oob } 77 | 78 | bits[n] = min(min(A, B), min(D, 254)) + 1 79 | } 80 | } 81 | 82 | return costMatrix 83 | } 84 | 85 | private fun buildableTilesForRoom() : PathFinder.CostMatrix { 86 | val costMatrix = PathFinder.CostMatrix() 87 | val terrain = Game.map.getRoomTerrain(room.name).getRawBuffer() 88 | 89 | val bits = costMatrix._bits 90 | 91 | // Everything but edges 92 | for (y in 2..47) 93 | for (x in 2..47) 94 | if(terrain[y*50+x].and(TERRAIN_MASK_WALL as Int) == 0) 95 | bits[x*50+y] = 1 96 | 97 | // Northwards 98 | for(x in 1..48) 99 | if(terrain[x+50].and(TERRAIN_MASK_WALL as Int) == 0 100 | && terrain[x].and(TERRAIN_MASK_WALL as Int) != 0 101 | && terrain[x-1].and(TERRAIN_MASK_WALL as Int) != 0 102 | && terrain[x+1].and(TERRAIN_MASK_WALL as Int) != 0) 103 | bits[x*50+1] = 1 104 | 105 | // Eastwards 106 | for(y in 1..48) 107 | if(terrain[y*50+48].and(TERRAIN_MASK_WALL as Int) == 0 108 | && terrain[y*50+49].and(TERRAIN_MASK_WALL as Int) != 0 109 | && terrain[(y-1)*50+49].and(TERRAIN_MASK_WALL as Int) != 0 110 | && terrain[(y+1)*50+49].and(TERRAIN_MASK_WALL as Int) != 0) 111 | bits[y+2400] = 1 112 | 113 | // Southwards 114 | for(x in 1..48) 115 | if(terrain[x+2400].and(TERRAIN_MASK_WALL as Int) == 0 116 | && terrain[x+2450].and(TERRAIN_MASK_WALL as Int) != 0 117 | && terrain[x+2449].and(TERRAIN_MASK_WALL as Int) != 0 118 | && terrain[x+2451].and(TERRAIN_MASK_WALL as Int) != 0) 119 | bits[x*50+48] = 1 120 | 121 | // Westwards 122 | for(y in 1..48) 123 | if(terrain[y*50+1].and(TERRAIN_MASK_WALL as Int) == 0 124 | && terrain[y*50].and(TERRAIN_MASK_WALL as Int) != 0 125 | && terrain[(y-1)*50].and(TERRAIN_MASK_WALL as Int) != 0 126 | && terrain[(y+1)*50].and(TERRAIN_MASK_WALL as Int) != 0) 127 | bits[y+50] = 1 128 | 129 | return costMatrix 130 | } 131 | 132 | fun displayCostMatrix(dt: PathFinder.CostMatrix) { 133 | val vis = room.visual 134 | 135 | val bits = dt._bits 136 | 137 | for (x in 0..50) { 138 | for (y in 0..50) { 139 | val value = bits[x*50+y] 140 | if(value > 0) { 141 | vis.text(value.toString(), x.toDouble(),y.toDouble()+0.2) 142 | } 143 | } 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /src/misc/Kotlin/VipoOS/Kernel.kt: -------------------------------------------------------------------------------- 1 | package example.os 2 | 3 | import screeps.api.Game 4 | 5 | class Kernel { 6 | 7 | private val scheduler = Scheduler() 8 | 9 | private val maxCpu = 16 // Running on shard 3, leaving some cpu for the final processing of statistics and saving of memory 10 | 11 | fun spawnProcess(program: Program, pri: Int) = scheduler.spawnProcess(program, pri) 12 | 13 | fun loop() { 14 | console.log() 15 | console.log("Starting kernel loop with ${(maxCpu - Game.cpu.getUsed()).toString().take(5)} cpu left") 16 | 17 | if(true) 18 | scheduler.printStats() 19 | 20 | scheduler.wakeSleepingProcesses() 21 | 22 | while (Game.cpu.getUsed() < maxCpu) { 23 | val process = scheduler.getNextProcess() ?: break 24 | 25 | val startCpu = Game.cpu.getUsed() 26 | var signal: Signal? = null 27 | 28 | try { 29 | signal = process.run() 30 | } catch (e: Exception) { 31 | console.log("Got exception while running pid ${process.pid} (${process.getProgramName()}) : $e") 32 | signal = SleepSignal(1) 33 | } 34 | val spentCpu = Game.cpu.getUsed() - startCpu 35 | process.addCpuUsage(spentCpu) 36 | 37 | when(signal) { 38 | is ExitSignal -> scheduler.killProcess(process) 39 | is SleepSignal -> scheduler.sleepProcess(process) 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/misc/Kotlin/VipoOS/Process.kt: -------------------------------------------------------------------------------- 1 | package example.os 2 | 3 | import screeps.api.Game 4 | 5 | class Process(val pid: Int, val pri: Int, val program: Program) { 6 | 7 | private var sleepUntil: Int = 0 8 | 9 | private var cpuUsage = 0.0 10 | private var sleepCount = 0 11 | 12 | private val exe = program.execute().iterator() 13 | 14 | fun getSleepUntil() = sleepUntil 15 | fun getProgramName() = program.getProgramName() 16 | fun getClassName() = program.getClassName() 17 | 18 | fun run() : Signal { 19 | val signal = exe.next() 20 | 21 | when(signal) { 22 | is SleepSignal -> {sleepUntil = Game.time + signal.duration; sleepCount++} 23 | } 24 | 25 | return signal 26 | } 27 | 28 | fun addCpuUsage(spent: Double){ 29 | cpuUsage += spent 30 | } 31 | 32 | fun getCpuUsage() = cpuUsage 33 | fun getSleepCount() = sleepCount 34 | } -------------------------------------------------------------------------------- /src/misc/Kotlin/VipoOS/Program.kt: -------------------------------------------------------------------------------- 1 | package example.os 2 | 3 | abstract class Program { 4 | 5 | private val className by lazy { this::class.simpleName ?: "Unknown" } 6 | 7 | abstract fun execute() : Sequence 8 | 9 | open fun getProgramName() = getClassName() 10 | 11 | fun getClassName() = className 12 | } -------------------------------------------------------------------------------- /src/misc/Kotlin/VipoOS/Programs/Demo.kt: -------------------------------------------------------------------------------- 1 | package example.os.programs 2 | 3 | 4 | import example.os.* 5 | 6 | class Demo(private val id: Int) : Program() { 7 | 8 | override fun getProgramName() = getClassName() + " ($id)" 9 | 10 | override fun execute(): Sequence { 11 | return sequence { 12 | var i = 0 13 | var someCondition = false 14 | 15 | val name = getProgramName() 16 | 17 | console.log("This is program $name going to do a normal Yield") 18 | yield(YieldSignal()) 19 | 20 | console.log("This is program $name going to sleep one tick") 21 | yield(SleepSignal(1)) 22 | 23 | while(true) { 24 | if(someCondition) 25 | yield(ExitSignal(0)) 26 | 27 | console.log("This is program $name in forever loop: ${i++}") 28 | yield(SleepSignal(1)) 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/misc/Kotlin/VipoOS/Scheduler.kt: -------------------------------------------------------------------------------- 1 | package example.os 2 | 3 | import screeps.api.Game 4 | 5 | class Scheduler { 6 | var pid = 0 7 | 8 | private val processes = mutableMapOf() 9 | private val runningProcesses = mutableListOf() 10 | private val sleepingProcesses = mutableListOf() 11 | 12 | fun getNextProcess() = runningProcesses.firstOrNull() 13 | 14 | // Only call these when a process gets added to one of the lists. 15 | private fun reorderRunningProcesses() = runningProcesses.sortBy { it.pri } 16 | private fun reorderSleepingProcesses() = sleepingProcesses.sortBy { it.getSleepUntil() } 17 | 18 | fun spawnProcess(program: Program, pri: Int) : Process { 19 | val newPid = pid++ 20 | val newProcess = Process(newPid, pri, program) 21 | 22 | processes[newPid] = newProcess 23 | runningProcesses.add(newProcess) 24 | reorderRunningProcesses() 25 | 26 | return newProcess 27 | } 28 | 29 | fun killProcess(process: Process) { 30 | processes.remove(process.pid) 31 | runningProcesses.remove(process) 32 | sleepingProcesses.remove(process) 33 | } 34 | 35 | fun sleepProcess(process: Process) { 36 | runningProcesses.remove(process) 37 | sleepingProcesses.add(process) 38 | 39 | reorderSleepingProcesses() 40 | } 41 | 42 | fun wakeSleepingProcesses() { 43 | if(sleepingProcesses.isEmpty()) 44 | return 45 | 46 | val wakeUp = mutableListOf() 47 | 48 | while(sleepingProcesses.first().getSleepUntil() <= Game.time) 49 | wakeUp.add(sleepingProcesses.removeAt(0)) 50 | 51 | runningProcesses.addAll(wakeUp) 52 | 53 | if(wakeUp.isNotEmpty()) 54 | reorderRunningProcesses() 55 | } 56 | 57 | fun printStats() { 58 | console.log("Scheduler has ${processes.size} processes (${runningProcesses.size} running, ${sleepingProcesses.size} sleeping)") 59 | console.log("Running:") 60 | if(runningProcesses.isNotEmpty()) 61 | runningProcesses.forEach { console.log("Pid ${it.pid} (${it.pri}) : ${it.getProgramName()} " + 62 | "${it.getCpuUsage().toString().take(5)} CPU spent over ${it.getSleepCount()} sleeps (${(it.getCpuUsage() / it.getSleepCount()).toString().take(5)}/sleep)") } 63 | console.log("Sleeping:") 64 | if(sleepingProcesses.isNotEmpty()) 65 | sleepingProcesses.forEach { console.log("Pid ${it.pid} : ${it.getProgramName()} (${it.getSleepUntil() - Game.time} ticks left) " + 66 | "${it.getCpuUsage().toString().take(5)} CPU spent over ${it.getSleepCount()} sleeps (${(it.getCpuUsage() / it.getSleepCount()).toString().take(5)}/sleep)") } 67 | } 68 | } -------------------------------------------------------------------------------- /src/misc/Kotlin/VipoOS/Signals.kt: -------------------------------------------------------------------------------- 1 | package example.os 2 | 3 | // This is for being able to print ${signal.type} when we don't know the subclass 4 | enum class SignalType { 5 | EXIT, 6 | SLEEP, 7 | YIELD 8 | } 9 | 10 | abstract class Signal(val type: SignalType) 11 | 12 | class ExitSignal(val exitCode: Int) : Signal(SignalType.EXIT) 13 | 14 | class SleepSignal(val duration: Int) : Signal(SignalType.SLEEP) 15 | 16 | class YieldSignal : Signal(SignalType.YIELD) -------------------------------------------------------------------------------- /src/misc/TypeScript/Creep intent tracker.ts: -------------------------------------------------------------------------------- 1 | // unfleshedone 3 June 2017 at 20:56 2 | // =================================================== 3 | // Usage: 4 | // For telling right side of the creep what his left side is doing. 5 | 6 | if (creep.intentTracker.canMove()) 7 | creep.move(...) 8 | 9 | if (creep.intentTracker.canAttack()) 10 | creep.attack(...) 11 | 12 | // =================================================== 13 | // intent.tracker.d.ts 14 | 15 | interface IIntentTracker 16 | { 17 | canMove(): boolean; 18 | canHarvest(): boolean; 19 | canAttack(): boolean; 20 | canBuild(): boolean; 21 | canRepair(): boolean; 22 | canDismantle(): boolean; 23 | canAttackController(): boolean; 24 | canRangedHeal(): boolean; 25 | canHeal(): boolean; 26 | canRangedAttack(): boolean; 27 | canRangedMassAttack(): boolean; 28 | canUpgradeController(): boolean; 29 | canClaimController(): boolean; 30 | canTransfer(): boolean; 31 | canWithdraw(): boolean; 32 | canDrop(): boolean; 33 | canPickup(): boolean; 34 | } 35 | 36 | interface Creep 37 | { 38 | readonly intentTracker: IIntentTracker; 39 | } 40 | 41 | // =================================================== 42 | // intent.tracker.ts 43 | 44 | enum Buckets 45 | { 46 | eMeleePipeline, 47 | eRangedPipeline, 48 | } 49 | 50 | type HostType = Creep; 51 | 52 | interface IIntent 53 | { 54 | args: any[]; 55 | } 56 | 57 | export class IntentTracker implements IIntentTracker 58 | { 59 | public static WrapIntents(host: HostType) 60 | { 61 | if ((host as any)._intentsWrapped) 62 | return; 63 | (host as any)._intentsWrapped = true; 64 | 65 | IntentTracker.WrapIntent(host, "harvest"); 66 | IntentTracker.WrapIntent(host, "attack"); 67 | IntentTracker.WrapIntent(host, "build"); 68 | IntentTracker.WrapIntent(host, "repair"); 69 | IntentTracker.WrapIntent(host, "dismantle"); 70 | IntentTracker.WrapIntent(host, "attackController"); 71 | IntentTracker.WrapIntent(host, "rangedHeal"); 72 | IntentTracker.WrapIntent(host, "heal"); 73 | IntentTracker.WrapIntent(host, "rangedAttack"); 74 | IntentTracker.WrapIntent(host, "rangedMassAttack"); 75 | 76 | IntentTracker.WrapIntent(host, "upgradeController"); 77 | IntentTracker.WrapIntent(host, "claimController"); 78 | IntentTracker.WrapIntent(host, "move"); 79 | IntentTracker.WrapIntent(host, "transfer"); 80 | IntentTracker.WrapIntent(host, "withdraw"); 81 | IntentTracker.WrapIntent(host, "drop"); 82 | IntentTracker.WrapIntent(host, "pickup"); 83 | } 84 | 85 | private static WrapIntent(host: HostType, functionName: string) 86 | { 87 | const descriptor = Object.getOwnPropertyDescriptor(host, functionName); 88 | if (!descriptor) 89 | return; 90 | 91 | const hasAccessor = descriptor.get || descriptor.set; 92 | if (hasAccessor) 93 | return; 94 | 95 | const isFunction = typeof descriptor.value === "function"; 96 | if (!isFunction) 97 | return; 98 | 99 | const originalFunction = (host as any)[functionName]; 100 | 101 | let buckets = IntentTracker.Pipelines[functionName]; 102 | if (buckets === undefined) 103 | buckets = []; 104 | 105 | (host as any)[functionName] = function(this: any, ...args: any[]) 106 | { 107 | const res = originalFunction.apply(this, args); 108 | if (res === OK) 109 | this.intentTracker.onIntent(functionName, buckets, args); 110 | return res; 111 | }; 112 | } 113 | 114 | private static Pipelines: { [name: string]: Buckets[] } = 115 | { 116 | attack: [Buckets.eMeleePipeline], 117 | harvest: [Buckets.eMeleePipeline], 118 | build: [Buckets.eMeleePipeline, Buckets.eRangedPipeline], 119 | repair: [Buckets.eMeleePipeline, Buckets.eRangedPipeline], 120 | dismantle: [Buckets.eMeleePipeline], 121 | attackController: [Buckets.eMeleePipeline], 122 | rangedHeal: [Buckets.eMeleePipeline, Buckets.eRangedPipeline], 123 | heal: [Buckets.eMeleePipeline], 124 | rangedAttack: [Buckets.eRangedPipeline], 125 | rangedMassAttack: [Buckets.eRangedPipeline], 126 | }; 127 | 128 | private pipelines: Set = new Set(); 129 | private intents: Map = new Map(); 130 | 131 | public onIntent(name: string, buckets: Buckets[], args: any[]) 132 | { 133 | this.intents.set(name, { args }); 134 | _.each(buckets, (b) => this.pipelines.add(b)); 135 | } 136 | 137 | private checkIntent(name: string): boolean 138 | { 139 | const buckets = IntentTracker.Pipelines[name]; 140 | 141 | if (buckets === undefined) 142 | return !this.intents.has(name); 143 | else 144 | return _.all(buckets, (b) => !this.pipelines.has(b)); 145 | } 146 | 147 | public canMove(): boolean 148 | { 149 | return this.checkIntent("move"); 150 | } 151 | public canHarvest(): boolean 152 | { 153 | return this.checkIntent("harvest"); 154 | } 155 | public canTransfer(): boolean 156 | { 157 | return this.checkIntent("transfer"); 158 | } 159 | public canAttack(): boolean 160 | { 161 | return this.checkIntent("attack"); 162 | } 163 | public canBuild(): boolean 164 | { 165 | return this.checkIntent("build"); 166 | } 167 | public canRepair(): boolean 168 | { 169 | return this.checkIntent("repair"); 170 | } 171 | public canDismantle(): boolean 172 | { 173 | return this.checkIntent("dismantle"); 174 | } 175 | public canAttackController(): boolean 176 | { 177 | return this.checkIntent("attackController"); 178 | } 179 | public canRangedHeal(): boolean 180 | { 181 | return this.checkIntent("rangedHeal"); 182 | } 183 | public canHeal(): boolean 184 | { 185 | return this.checkIntent("heal"); 186 | } 187 | public canRangedAttack(): boolean 188 | { 189 | return this.checkIntent("rangedAttack"); 190 | } 191 | public canRangedMassAttack(): boolean 192 | { 193 | return this.checkIntent("rangedMassAttack"); 194 | } 195 | public canUpgradeController(): boolean 196 | { 197 | return this.checkIntent("upgradeController"); 198 | } 199 | public canClaimController(): boolean 200 | { 201 | return this.checkIntent("claimController"); 202 | } 203 | public canWithdraw(): boolean 204 | { 205 | return this.checkIntent("withdraw"); 206 | } 207 | public canDrop(): boolean 208 | { 209 | return this.checkIntent("drop"); 210 | } 211 | public canPickup(): boolean 212 | { 213 | return this.checkIntent("pickup"); 214 | } 215 | } 216 | 217 | // =================================================== 218 | // main.ts 219 | 220 | if (!Creep.prototype.hasOwnProperty("intentTracker")) 221 | { 222 | Object.defineProperty(Creep.prototype, "intentTracker", 223 | { 224 | get(this: any) 225 | { 226 | if (this.__intentTracker === undefined) 227 | this.__intentTracker = new IntentTracker(); 228 | return this.__intentTracker; 229 | }, 230 | configurable: false, 231 | enumerable: false, 232 | }); 233 | } 234 | 235 | export function loop() 236 | { 237 | // run this before screeps-profiler wrap 238 | IntentTracker.WrapIntents(Creep.prototype); 239 | 240 | // main loop 241 | } -------------------------------------------------------------------------------- /src/misc/TypeScript/Typescript roomScan.ts: -------------------------------------------------------------------------------- 1 | // crzytrane 13 March 2017 at 12:06 2 | public roomScan(sampleSize): this { 3 | let terrainData = this.room.lookForAtArea(LOOK_TERRAIN, 0, 0, 49, 49); 4 | let sampleBlockCount: number = 50 / sampleSize; 5 | 6 | let sampleBlocks: { [y: number]: { [x: number]: { freeSpaces } } } = {}; 7 | let blockY: number; 8 | let blockX: number; 9 | let sampleY: number; 10 | let sampleX: number; 11 | for (blockY = 0; blockY < sampleBlockCount; blockY++) { 12 | sampleBlocks[blockY] = {}; 13 | for (blockX = 0; blockX < sampleBlockCount; blockX++) { 14 | sampleBlocks[blockY][blockX] = { freeSpaces: 0 }; 15 | 16 | for (sampleY = 0; sampleY < sampleSize; sampleY++) { 17 | for (sampleX = 0; sampleX < sampleSize; sampleX++) { 18 | if (terrainData[blockY * sampleSize + sampleY][blockX * sampleSize + sampleX] != 'wall') { 19 | sampleBlocks[blockY][blockX].freeSpaces++; 20 | } 21 | } 22 | } 23 | } 24 | } 25 | for (let sampleYIndex in sampleBlocks) { 26 | for (let sampleXIndex in sampleBlocks[sampleYIndex]) { 27 | let x: number = Number(sampleXIndex) * sampleSize + sampleSize / 2; 28 | let y: number = Number(sampleYIndex) * sampleSize + sampleSize / 2; 29 | let percentageFree: number = sampleBlocks[sampleYIndex][sampleXIndex].freeSpaces / (sampleSize * sampleSize); 30 | 31 | let radius: number = percentageFree * sampleSize/2; 32 | this.room.visual.circle(x, y, {radius: radius, fill: this.getColour(percentageFree), opacity: 0.2}) 33 | this.room.visual.text(sampleBlocks[sampleYIndex][sampleXIndex].freeSpaces, x, y + 0.25); 34 | } 35 | } 36 | 37 | return this; 38 | } -------------------------------------------------------------------------------- /src/misc/TypeScript/moving.average.ts: -------------------------------------------------------------------------------- 1 | // unfleshedone 2 May 2017 at 07:12 2 | export class MovingAverage 3 | { 4 | public static Setup(name: string, memory: any, timespan: number) 5 | { 6 | if (memory[name] === undefined) 7 | memory[name] = new MovingAverage(timespan); 8 | else 9 | Object.setPrototypeOf(memory[name], MovingAverage.prototype); 10 | } 11 | 12 | private _movingAverage: number = 0; 13 | private _variance: number = 0; 14 | 15 | private count: number = 0; 16 | 17 | private _startTime?: number; 18 | 19 | private previousTime?: number; 20 | 21 | private previousResetTime?: number; 22 | 23 | private intermediateTotal?: number; 24 | 25 | private _runningTotal: number = 0; 26 | private _min?: number; 27 | private _max?: number; 28 | 29 | public get runningTotal() { return this._runningTotal; } 30 | 31 | public get min() { return this._min; } 32 | 33 | public get max() { return this._max; } 34 | 35 | public get startTime() { return this._startTime; } 36 | 37 | public get movingAverage() 38 | { 39 | if (this.previousTime && Game.time - this.previousTime > 10) 40 | this.push(0); 41 | 42 | return this._movingAverage; 43 | } 44 | 45 | public get variance() { return this._variance / this.count; } 46 | 47 | constructor(private timespan: number, private accumulateFor?: number) 48 | { 49 | } 50 | 51 | public push(incoming: number) 52 | { 53 | const time = Game.time; 54 | 55 | this.updateStartTime(time); 56 | this.updateTotal(incoming); 57 | 58 | const { value, final } = this.updateAccumulator(incoming, time); 59 | 60 | if (final) 61 | { 62 | this.updateMinMax(value); 63 | this.updateMA(value, time); 64 | this.updateCount(); 65 | } 66 | } 67 | 68 | protected updateStartTime(time: number) 69 | { 70 | if (this._startTime === undefined) 71 | this._startTime = time; 72 | } 73 | 74 | protected updateTotal(value: number) 75 | { 76 | this._runningTotal += value; 77 | } 78 | 79 | protected updateMinMax(value: number) 80 | { 81 | if (this._min === undefined || this._min > value) 82 | this._min = value; 83 | if (this._max === undefined || this._max < value) 84 | this._max = value; 85 | } 86 | 87 | protected updateMA(value: number, time: number) 88 | { 89 | if (this.previousTime) 90 | { 91 | // calculate moving average 92 | const a = this.alpha(time, this.previousTime); 93 | const previousMa = this._movingAverage; 94 | this._movingAverage = a * value + (1 - a) * this._movingAverage; 95 | 96 | // calculate variance 97 | this._variance += (value - previousMa) * (value - this._movingAverage); 98 | } 99 | else 100 | this._movingAverage = value; 101 | this.previousTime = time; 102 | } 103 | 104 | protected updateCount() 105 | { 106 | this.count++; 107 | } 108 | 109 | protected alpha(t: number, pt: number) 110 | { 111 | return 1 - (Math.exp(- (t - pt) / this.timespan)); 112 | } 113 | 114 | protected updateAccumulator(value: number, time: number): { value: number; final: boolean; } 115 | { 116 | if (this.accumulateFor === undefined) 117 | return { value, final: true }; 118 | 119 | if (!this.previousResetTime) 120 | this.previousResetTime = time; 121 | 122 | if (this.intermediateTotal === undefined) 123 | this.intermediateTotal = value; 124 | else 125 | this.intermediateTotal += value; 126 | 127 | const out = this.intermediateTotal; 128 | const final = time - this.previousResetTime > this.accumulateFor; 129 | 130 | if (final) 131 | { 132 | this.intermediateTotal = 0; 133 | this.previousResetTime = time; 134 | } 135 | 136 | return { value: out, final }; 137 | } 138 | } -------------------------------------------------------------------------------- /src/misc/migrate room to sim.md: -------------------------------------------------------------------------------- 1 | // semperrabbit:semperrexoff: 4 Dec 2017 at 04:30 2 | 3 | https://github.com/Esryok/screeps-browser-ext/raw/master/migrate-screeps-room.user.js 4 | -------------------------------------------------------------------------------- /src/misc/screeps body calculator.md: -------------------------------------------------------------------------------- 1 | // nitroevil 20 Sep 2016 at 20:38 2 | 3 | https://codepen.io/Puciek/full/jAKWXE/ -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Creep/Creep action error handler.js: -------------------------------------------------------------------------------- 1 | // warinternal 29 April 2017 at 21:13 2 | 3 | /** 4 | * Globally patch creep actions to log error codes. 5 | */ 6 | [ 7 | "attack", 8 | "attackController", 9 | "build", 10 | "claimController", 11 | "dismantle", 12 | "drop", 13 | "generateSafeMode", 14 | "harvest", 15 | "heal", 16 | "move", 17 | "moveByPath", 18 | "moveTo", 19 | "pickup", 20 | "rangedAttack", 21 | "rangedHeal", 22 | "rangedMassAttack", 23 | "repair", 24 | "reserveController", 25 | "signController", 26 | "suicide", 27 | "transfer", 28 | "upgradeController", 29 | "withdraw" 30 | ].forEach(function(method) { 31 | let original = Creep.prototype[method]; 32 | // Magic 33 | Creep.prototype[method] = function() { 34 | let status = original.apply(this, arguments); 35 | if (typeof status === "number" && status < 0) { 36 | console.log( 37 | `Creep ${this.name} action ${method} failed with status ${status} at ${ 38 | this.pos 39 | }` 40 | ); 41 | } 42 | return status; 43 | }; 44 | }); 45 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Creep/Creep.getOffExit.js: -------------------------------------------------------------------------------- 1 | // engineeryo 7 February 2017 at 04:46 2 | 3 | global.DIRECTIONS = { 4 | // [x, y] adders 5 | 1: [0, -1], 6 | 2: [1, -1], 7 | 3: [1, 0], 8 | 4: [1, 1], 9 | 5: [0, 1], 10 | 6: [-1, 1], 11 | 7: [-1, 0], 12 | 8: [-1, -1] 13 | }; 14 | 15 | RoomPosition.prototype.fromDirection = function(direction) { 16 | // returns a RoomPosition given a RoomPosition and a direction 17 | return new RoomPosition( 18 | this.x + DIRECTIONS[direction][0], 19 | this.y + DIRECTIONS[direction][1], 20 | this.roomName 21 | ); 22 | }; 23 | 24 | Creep.prototype.getOffExit = function() { 25 | let directionsFromExit = { 26 | // Legal directions from a given exit 27 | x: { 28 | 49: [7, 8, 6], 29 | 0: [3, 4, 2] 30 | }, 31 | y: { 32 | 49: [1, 8, 2], 33 | 0: [5, 6, 4] 34 | } 35 | }; 36 | 37 | if (directionsFromExit["x"][this.pos.x]) { 38 | // Are we on the left / right exits? 39 | var allowedDirections = directionsFromExit.x[this.pos.x]; 40 | } else if (directionsFromExit["y"][this.pos.y]) { 41 | // or are we on the top / bottom exits? 42 | var allowedDirections = directionsFromExit.y[this.pos.y]; 43 | } 44 | 45 | if (!allowedDirections) { 46 | // Not on an exit tile 47 | console.log(this.name + " isnt on an exit tile"); 48 | return false; 49 | } 50 | 51 | for (let direction of allowedDirections) { 52 | let stuff = this.pos.fromDirection(direction).look(); // collection of things at our potential target 53 | if ( 54 | _.findIndex( 55 | stuff, 56 | p => 57 | p.type == "creep" || 58 | (p.structure && OBSTACLE_OBJECT_TYPES[p.structure.structureType]) || 59 | p.terrain == "wall" 60 | ) == -1 61 | ) { 62 | // longhand for 'is there an obstacle there?' 63 | this.move(direction); 64 | break; // save that CPU, yo 65 | } 66 | } 67 | }; 68 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Creep/Freshly minted getActiveBodyparts accounting for boosts!.js: -------------------------------------------------------------------------------- 1 | // daboross 4 December 2016 at 22:32 2 | Creep.prototype.getActiveBodypartsBoostEquivalent = function(type, action) { 3 | var total = 0; 4 | for (var i = this.body.length; i-- > 0; ) { 5 | var x = this.body[i]; 6 | if (x.hits <= 0) { 7 | break; 8 | } 9 | if (x.type == type) { 10 | if (x.boost !== undefined) { 11 | total += BOOSTS[type][x.boost][action]; 12 | } else { 13 | total += 1; 14 | } 15 | } 16 | } 17 | return total; 18 | }; 19 | 20 | Creep.prototype.getBodypartsBoostEquivalent = function(type, action) { 21 | var total = 0; 22 | for (var i = this.body.length; i-- > 0; ) { 23 | var x = this.body[i]; 24 | if (x.type == type) { 25 | if (x.boost !== undefined) { 26 | total += BOOSTS[type][x.boost][action]; 27 | } else { 28 | total += 1; 29 | } 30 | } 31 | } 32 | return total; 33 | }; 34 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Creep/Idle_Suspend for creeps.js: -------------------------------------------------------------------------------- 1 | // proximo 5 December 2016 at 01:27 2 | 3 | /** 4 | * Set the unit to idle-mode until recall tick 5 | * 6 | * @type {int} 7 | */ 8 | Object.defineProperty(Creep.prototype, "idle", { 9 | get: function() { 10 | if (this.memory.idle === undefined) return 0; 11 | if (this.memory.idle <= Game.time) { 12 | this.idle = undefined; 13 | return 0; 14 | } 15 | return this.memory.idle; 16 | }, 17 | set: function(val) { 18 | if (!val && this.memory.idle) { 19 | delete this.memory.idle; 20 | } else { 21 | this.memory.idle = val; 22 | } 23 | } 24 | }); 25 | 26 | /** 27 | * Set the unit to idle-mode for ticks given 28 | * 29 | * @type {int} 30 | */ 31 | Creep.prototype.idleFor = function(ticks = 0) { 32 | if (ticks > 0) { 33 | console.log("Suspend", this, "for", ticks, this.target); 34 | this.idle = Game.time + ticks; 35 | } else { 36 | this.idle = undefined; 37 | } 38 | }; 39 | 40 | /* Usage: 41 | In the loop that executes all creeps, add something like: 42 | if(creep.idle) continue; 43 | 44 | And if you want to idle something, for example between mineral mine actions you just do: 45 | creep.idleFor(6); 46 | */ 47 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Creep/excuseMe.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A set of functions that makes creeps tell other creeps to get out of the way using creep memory 3 | * 4 | * call so creep reacts to being nudged 5 | * Creep.giveWay() - swaps places with creep that nudged it 6 | * Creep.giveWay(true) - moves into random available spot 7 | * Creep.giveWay({pos: controller.pos, range: 3 }) - moves into random available spot in range of target, if none are avaiable fallbacks to random spot 8 | */ 9 | 10 | /* 11 | * if alwaysNudge false you have to call Creep.move with additional argument - 12 | * creep.move(direction, true); - for creep to nudge other creeps, 13 | * so it's not compatible with creep.moveTo 14 | * 15 | * if alwaysNudge is true then creeps... always nudge creeps in front of them 16 | */ 17 | const alwaysNudge = true; 18 | 19 | /* 20 | * some utils that I'm using 21 | */ 22 | const offsetX = [0, 0, 1, 1, 1, 0, -1, -1, -1]; 23 | const offsetY = [0, -1, -1, 0, 1, 1, 1, 0, -1]; 24 | function getRandomDir() { 25 | return (Math.floor(Math.random() * 8) + 1); 26 | } 27 | function getOppositeDir(dir) { 28 | return ((dir + 3) % 8 + 1); 29 | } 30 | 31 | /** 32 | * returns a weighted random direction from given position 33 | * prefers empty tiles over ones with creeps 34 | * never picks a direction that would result in hitting a wall or an obstacle structure 35 | * 36 | * @param {RoomPosition} pos 37 | */ 38 | function getNudgeDirection_Random(pos) { 39 | const room = Game.rooms[pos.roomName]; 40 | const terrain = Game.map.getRoomTerrain(pos.roomName); 41 | let totalWeight = 0; 42 | let dirCandidates = new Uint8Array(9); 43 | for (let dir = TOP; dir <= TOP_LEFT; ++dir) { 44 | let posX = pos.x + offsetX[dir]; 45 | let posY = pos.y + offsetY[dir]; 46 | if (posX < 1 || posX > 48 || posY < 1 || posY > 48) 47 | continue; 48 | if ((terrain.get(posX, posY) & TERRAIN_MASK_WALL) > 0) 49 | continue; 50 | if (room.lookForAt(LOOK_STRUCTURES, posX, posY).find(s => OBSTACLE_OBJECT_TYPES.includes(s.structureType))) 51 | continue; 52 | 53 | const hasCreeps = room.lookForAt(LOOK_CREEPS, posX, posY).length > 0; 54 | const addWeight = hasCreeps ? 1 : 2; 55 | dirCandidates[dir] += addWeight; 56 | totalWeight += dirCandidates[dir]; 57 | } 58 | 59 | let sum = 0; 60 | let rnd = _.random(1, totalWeight, false); 61 | for (let dir = TOP; dir <= TOP_LEFT; ++dir) { 62 | if (dirCandidates[dir] > 0) { 63 | sum += dirCandidates[dir]; 64 | if (rnd <= sum) { 65 | return dir; 66 | } 67 | } 68 | } 69 | 70 | // this should never happen, unless creep is spawned into a corner 71 | // or structure is built next to it and seals the only path out 72 | return getRandomDir(); 73 | } 74 | 75 | /** 76 | * returns a weighted random direction from given position 77 | * tries to stay in targets range, if it's impossible then fallbacks to random direction 78 | * prefers empty tiles over ones with creeps 79 | * never picks a direction that would result in hitting a wall or an obstacle structure 80 | * 81 | * @param {RoomPosition} pos 82 | * @param {Object} target 83 | * @param {RoomPosition} target.pos 84 | * @param {number} target.range 85 | */ 86 | function getNudgeDirection_KeepRange(pos, target) { 87 | const room = Game.rooms[pos.roomName]; 88 | const terrain = Game.map.getRoomTerrain(pos.roomName); 89 | let keepRangeTotalWeight = 0; 90 | let keepRangeDirCandidates = new Uint8Array(9); 91 | let randomTotalWeight = 0; 92 | let randomDirCandidates = new Uint8Array(9); 93 | for (let dir = TOP; dir <= TOP_LEFT; ++dir) { 94 | let posX = pos.x + offsetX[dir]; 95 | let posY = pos.y + offsetY[dir]; 96 | if (posX < 1 || posX > 48 || posY < 1 || posY > 48) 97 | continue; 98 | if ((terrain.get(posX, posY) & TERRAIN_MASK_WALL) > 0) 99 | continue; 100 | if (room.lookForAt(LOOK_STRUCTURES, posX, posY).find(s => OBSTACLE_OBJECT_TYPES.includes(s.structureType))) 101 | continue; 102 | 103 | const hasCreeps = room.lookForAt(LOOK_CREEPS, posX, posY).length > 0; 104 | const addWeight = hasCreeps ? 1 : 2; 105 | randomDirCandidates[dir] += addWeight; 106 | if (target.pos.inRangeTo(posX, posY, target.range)) 107 | keepRangeDirCandidates[dir] += addWeight; 108 | keepRangeTotalWeight += keepRangeDirCandidates[dir]; 109 | randomTotalWeight += randomDirCandidates[dir]; 110 | } 111 | 112 | const dirCandidates = keepRangeTotalWeight > 0 ? keepRangeDirCandidates : randomDirCandidates; 113 | const totalWeight = keepRangeTotalWeight > 0 ? keepRangeTotalWeight : randomTotalWeight; 114 | let sum = 0; 115 | if (totalWeight > 0) { 116 | let rnd = _.random(1, totalWeight, false); 117 | for (let dir = TOP; dir <= TOP_LEFT; ++dir) { 118 | if (dirCandidates[dir] > 0) { 119 | sum += dirCandidates[dir]; 120 | if (rnd <= sum) { 121 | return dir; 122 | } 123 | } 124 | } 125 | } 126 | 127 | // this should never happen, unless creep is spawned into a corner 128 | // or structure is built next to it and seals the only path out 129 | return getRandomDir(); 130 | } 131 | 132 | /** 133 | * a nudge 134 | * 135 | * @param {RoomPosition} pos - a nudge origin point 136 | * @param {DirectionConstant} direction 137 | */ 138 | function excuseMe(pos, direction) { 139 | const nextX = pos.x + offsetX[direction]; 140 | const nextY = pos.y + offsetY[direction]; 141 | if (nextX > 49 || nextX < 0 || nextY > 49 || nextY < 0) 142 | return; 143 | 144 | const room = Game.rooms[pos.roomName]; 145 | const creeps = room.lookForAt(LOOK_CREEPS, nextX, nextY); 146 | if (creeps.length > 0 && creeps[0].my) 147 | creeps[0].memory.excuseMe = getOppositeDir(direction); 148 | const powerCreeps = room.lookForAt(LOOK_POWER_CREEPS, nextX, nextY); 149 | if (powerCreeps.length > 0 && powerCreeps[0].my) 150 | powerCreeps[0].memory.excuseMe = getOppositeDir(direction); 151 | } 152 | 153 | /* 154 | * 155 | */ 156 | let creepsThatTriedToMove = {}; 157 | const move = Creep.prototype.move; 158 | Creep.prototype.move = function (direction, nudge) { 159 | if ((alwaysNudge || nudge) && _.isNumber(direction)) 160 | excuseMe(this.pos, direction); 161 | creepsThatTriedToMove[this.name] = this.pos; 162 | return move.call(this, direction); 163 | }; 164 | 165 | /* 166 | * call this on creeps that should react to being nudged 167 | */ 168 | function giveWay(creep, arg) { 169 | if (creep.memory.excuseMe) { 170 | if (!arg) 171 | creep.move(creep.memory.excuseMe, true); 172 | else if (typeof arg === 'object') 173 | creep.move(getNudgeDirection_KeepRange(creep.pos, arg), true); 174 | else 175 | creep.move(getNudgeDirection_Random(creep.pos), true); 176 | } 177 | } 178 | Creep.prototype.giveWay = function(arg) { 179 | giveWay(this, arg); 180 | }; 181 | PowerCreep.prototype.giveWay = function(arg) { 182 | giveWay(this, arg); 183 | }; 184 | 185 | /* 186 | * clears nudges from memory of creeps that moved 187 | * call on tick start 188 | */ 189 | function clearNudges() { 190 | for (let creepName in creepsThatTriedToMove) { 191 | const creep = Game.creeps[creepName]; 192 | const powerCreep = Game.powerCreeps[creepName]; 193 | const prevPos = creepsThatTriedToMove[creepName]; 194 | if ((!creep || !creep.pos.isEqualTo(prevPos)) && (!powerCreep || !powerCreep.pos.isEqualTo(prevPos))) { 195 | const creepMemory = Memory.creeps[creepName]; 196 | if (creepMemory) 197 | creepMemory.excuseMe = undefined; 198 | const powerCreepMemory = Memory.powerCreeps[creepName]; 199 | if (powerCreepMemory) 200 | powerCreepMemory.excuseMe = undefined; 201 | delete creepsThatTriedToMove[creepName]; 202 | } 203 | } 204 | } 205 | 206 | module.exports = { 207 | clearNudges: clearNudges 208 | }; -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Creep/prototype.Creep.moveToStandByPos.js: -------------------------------------------------------------------------------- 1 | /* Posted Jan 8th, 2017 by @semperrabbit*/ 2 | 3 | /** 4 | * Move a creep to a stand by location identified via flag or memory location in the room. 5 | * Returns true if it moved in this command or false if the creep did not move to identify 6 | * whether a move may be made elsewhere in the creep's code to prevent double pathfinding 7 | * and double intents each tick. 8 | * Valid flag names are [roomName]_pos_[roleName] and [roomName]_pos_[stateName]. 9 | * Valid memory locations are room.memory.pos[roleName] and room.memory.pos[stateName]. 10 | * Memory locations must be an object in the form of {x, y, roomName}. 11 | * 12 | * @author SemperRabbit 13 | * @return {boolean} 14 | */ 15 | Creep.prototype.moveToStandByPos = function(){ 16 | var homeRoom = this.memory.homeRoom || this.pos.roomName; 17 | var roomMem = Game.rooms[homeRoom].memory; 18 | var state = this.memory.state; 19 | var role = this.memory.role; 20 | var pos;//, x, y, roomName; 21 | 22 | if(state !== undefined) { 23 | if(!pos && Game.flags[homeRoom+'_pos_'+state]){ 24 | pos = Game.flags[homeRoom+'_pos_'+state].pos; 25 | } 26 | if(!pos && roomMem.pos && roomMem.pos[state]) { 27 | var {x, y, roomName} = roomMem.pos[state]; 28 | pos = new RoomPosition(x, y, roomName); 29 | } 30 | } 31 | if(role !== undefined) { 32 | if(!pos && Game.flags[homeRoom+'_pos_'+role]){ 33 | pos = Game.flags[homeRoom+'_pos_'+role].pos; 34 | } 35 | if(!pos && roomMem.pos && roomMem.pos[role]) { 36 | var {x, y, roomName} = roomMem.pos[role]; 37 | pos = new RoomPosition(x, y, roomName); 38 | } 39 | } 40 | 41 | if(pos !== undefined) { 42 | this.moveTo(pos); 43 | return true; 44 | } else { 45 | return false; 46 | } 47 | } -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Creep/untitled_activeBodyparts.js: -------------------------------------------------------------------------------- 1 | // proximo 30 October 2016 at 04:57 2 | 3 | /** 4 | * Creep method optimizations "getActiveBodyparts" 5 | */ 6 | Creep.prototype.getActiveBodyparts = function (type) { 7 | var count = 0; 8 | for (var i = this.body.length; i-- > 0;) { 9 | if (this.body[i].hits > 0) { 10 | if (this.body[i].type === type) { 11 | count++; 12 | } 13 | } else break; 14 | } 15 | return count; 16 | }; 17 | ​ 18 | /** 19 | * Fast check if bodypart exists 20 | */ 21 | Creep.prototype.hasActiveBodyparts = function (type) { 22 | for (var i = this.body.length; i-- > 0;) { 23 | if (this.body[i].hits > 0) { 24 | if (this.body[i].type === type) { 25 | return true; 26 | } 27 | } else break; 28 | } 29 | return false; 30 | }; -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Creep/util.fun.singing.js: -------------------------------------------------------------------------------- 1 | /* Posted Oct 23rd, 2016 by @semperrabbit*/ 2 | /* This code gives a simple example of prototyping and allows a creep to say multiple parts of a single string*/ 3 | 4 | /* require('util.fun.singing'); 5 | * NOTES: sentences are broken down using | to seperate pieces 6 | * public will default to true 7 | * 8 | * Creep.prototype.sing(sentence, public) 9 | * creep will sing a different part of sentence per tick 10 | */ 11 | 12 | Creep.prototype.sing = function(sentence, public){ 13 | if(public === undefined)public = true; 14 | let words = sentence.split("|"); 15 | this.say(words[Game.time % words.length], public); 16 | } -------------------------------------------------------------------------------- /src/prototypes/JavaScript/DefineProperty Tutorial.js: -------------------------------------------------------------------------------- 1 | // helam 1 January 2017 at 17:54 2 | 3 | // Tutorial for defining custom properties using Object.defineProperty 4 | // This has MANY uses but these specific examples will show how to make a 5 | // '.sources' property for rooms so you can just do room.sources instead of 6 | // room.find(FIND_SOURCES); The tutorial contains 4 different ways to define 7 | // the same property, each one adds on to the previous one to make it a little 8 | // bit better and show you different options you have when defining your own 9 | // custom properties. Each version has its own benefits and draw backs so its up 10 | // to you to choose the best one for your situation. Note that you will only want 11 | // one of these for each property. 12 | 13 | // You will pass 3 arguments to Object.defineProperty: 14 | // Argument 1: The prototype you want to add the property to. 15 | // We will use Room.prototype for this example but you can use 16 | // any prototype (Creep.prototype, StructureSpawn.prototype, etc.) 17 | // Argument 2: the name of the property you want to define, in a string. 18 | // We are using 'sources' for this example but it can be 'foo', 'myProp', etc. 19 | // Argument 3: An object containing options that set up the property. 20 | // See below examples. 21 | 22 | // AUTHOR: Helam 23 | 24 | // VERSION 1 - basic property with getter only and no caching 25 | Object.defineProperty(Room.prototype, 'sources', { 26 | // This is the getter function, when you type room.sources it will 27 | // have the value returned by this function 28 | get: function() { 29 | // this if statement is to prevent an obscure bug that can be caused by the screeps profiler. 30 | // its not necessary normally. 31 | if(this === Room.prototype || this == undefined) 32 | return; 33 | // since we are defining the property on the Room prototype, 34 | // 'this' in the line below whatever room object we are getting 35 | // the .sources from 36 | return this.find(FIND_SOURCES); 37 | }, 38 | // this makes it so the property doesn't show up when enumerating the properties of the creep 39 | enumerable: false, 40 | // this makes the characteristics of the property modifiable and also makes the property deletable 41 | configurable: true 42 | }); 43 | 44 | // VERSION 2 45 | // this version stores the value of the property locally on the object so 46 | // that if you get the property from the object more than once in the same tick 47 | // it will return the stored value instead of finding the value again. 48 | Object.defineProperty(Room.prototype, 'sources', { 49 | get: function() { 50 | if(this === Room.prototype || this == undefined) 51 | return; 52 | // this._sources will have no value the first time this is called, 53 | // so it will find the value and store it there so the next time 54 | // you get the property in the same tick it will return the stored 55 | // value. The reason we use ._sources instead of .sources here is 56 | // because if we try to access .sources in here it will call the 57 | // getter function again and cause an infinite loop! putting a '_' 58 | // in front of a variable name is just a naming style that means 59 | // the variable isnt meant to be accessed by outside functions. 60 | // this is also sometimes called a 'private' variable. 61 | if (!this._sources) { 62 | this._sources = this.find(FIND_SOURCES); 63 | } 64 | return this._sources; 65 | }, 66 | enumerable: false, 67 | configurable: true 68 | }); 69 | 70 | // VERSION 3 71 | // This version adds a setter function. If you want to be able to assign your custom 72 | // property a value then you must add a setter, otherwise you will get an error when 73 | // assigning a value. In this particular case you would not set room.sources to anything 74 | // because the getter value does the setting for you but I will show how to do the setter 75 | // anyway. 76 | Object.defineProperty(Room.prototype, 'sources', { 77 | get: function() { 78 | if(this === Room.prototype || this == undefined) 79 | return; 80 | if (!this._sources) { 81 | this._sources = this.find(FIND_SOURCES); 82 | } 83 | return this._sources; 84 | }, 85 | set: function(value) { 86 | // we set the stored private variable so 87 | // the next time the getter is called it returns 88 | // this new value 89 | this._sources = value; 90 | }, 91 | enumerable: false, 92 | configurable: true 93 | }); 94 | 95 | // VERSION 4 96 | // This version shows how to add memory caching to the property. 97 | // Caching the value in memory does not make sense in certain situations 98 | // but I recommend this version for this particular example as it will 99 | // make it so you only every do room.find(FIND_SOURCES) once per room and 100 | // NEVER need to call it again unless the memory value gets deleted. You 101 | // can do this in this situation because the sources in a room never change. 102 | Object.defineProperty(Room.prototype, 'sources', { 103 | get: function() { 104 | if(this === Room.prototype || this == undefined) 105 | return; 106 | // if we dont have the value stored in the private variable 107 | if (!this._sources) { 108 | // try to get it from memory 109 | // if its not in memory, find it and store it in memory 110 | // only storing the id's. best to avoid storing full objects 111 | // in memory. See the screeps documentation page 112 | // called 'Working with Memory' to find out why. 113 | if (!this.memory.sourceIds) { 114 | this.memory.sourceIds = this.find(FIND_SOURCES).map(source => source.id); 115 | } 116 | this._sources = this.memory.sourceIds.map(id => Game.getObjectById(id)); 117 | } 118 | return this._sources; 119 | }, 120 | set: function(value) { 121 | // when storing in memory you will want to change the setter 122 | // to set the memory value as well as the local value 123 | this.memory.sources = value.map(source => source.id); 124 | this._sources = value; 125 | }, 126 | enumerable: false, 127 | configurable: true 128 | }); 129 | 130 | 131 | // OTHER TOY EXAMPLES 132 | 133 | // .isFull property to tell if creep's carry parts are full 134 | Object.defineProperty(Creep.prototype, 'isFull', { 135 | get: function() { 136 | if (!this._isFull) { 137 | this._isFull = _.sum(this.carry) === this.carryCapacity; 138 | } 139 | return this._isFull; 140 | }, 141 | enumerable: false, 142 | configurable: true 143 | }); 144 | 145 | // A little more advanced, adds a .memory property to all sources. 146 | // there is an example of adding memory to structures pinned to the 147 | // help channel as well. I didnt write this function, i belive it was 148 | // written by artem, one of the developers of screeps. I just modified it 149 | // a little for my purposes. 150 | Object.defineProperty(Source.prototype, 'memory', { 151 | configurable: true, 152 | get: function() { 153 | if(_.isUndefined(Memory.mySourcesMemory)) { 154 | Memory.mySourcesMemory = {}; 155 | } 156 | if(!_.isObject(Memory.mySourcesMemory)) { 157 | return undefined; 158 | } 159 | return Memory.mySourcesMemory[this.id] = Memory.mySourcesMemory[this.id] || {}; 160 | }, 161 | set: function(value) { 162 | if(_.isUndefined(Memory.mySourcesMemory)) { 163 | Memory.mySourcesMemory = {}; 164 | } 165 | if(!_.isObject(Memory.mySourcesMemory)) { 166 | throw new Error('Could not set source memory'); 167 | } 168 | Memory.mySourcesMemory[this.id] = value; 169 | } 170 | }); 171 | 172 | // Adds a .freeSpaceCount property to sources that returns a number 173 | // telling you how many spots are around the source that are not natural 174 | // walls. THIS PARTICULAR IMPLEMENTATION DEPENDS ON ADDING .memory TO SOURCES 175 | // USING THE PREVIOUS EXAMPLE. 176 | Object.defineProperty(Source.prototype, 'freeSpaceCount', { 177 | get: function () { 178 | if (this._freeSpaceCount == undefined) { 179 | if (this.memory.freeSpaceCount == undefined) { 180 | var freeSpaceCount = 0; 181 | [this.pos.x - 1, this.pos.x, this.pos.x + 1].forEach(x => { 182 | [this.pos.y - 1, this.pos.y, this.pos.y + 1].forEach(y => { 183 | if (Game.map.getTerrainAt(x, y, this.pos.roomName) != 'wall') 184 | freeSpaceCount++; 185 | }, this); 186 | }, this); 187 | this.memory.freeSpaceCount = freeSpaceCount; 188 | } 189 | this._freeSpaceCount = this.memory.freeSpaceCount; 190 | } 191 | return this._freeSpaceCount; 192 | }, 193 | enumerable: false, 194 | configurable: true 195 | }); -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Room/Room.mineral.js: -------------------------------------------------------------------------------- 1 | // helam 1 February 2017 at 08:34 2 | /** 3 | * Defines a .mineral property for rooms that caches and gives you the mineral object for a room 4 | * Author: Helam 5 | */ 6 | Object.defineProperty(Room.prototype, "mineral", { 7 | get: function() { 8 | if (this == Room.prototype || this == undefined) return undefined; 9 | if (!this._mineral) { 10 | if (this.memory.mineralId === undefined) { 11 | let [mineral] = this.find(FIND_MINERALS); 12 | if (!mineral) { 13 | return (this.memory.mineralId = null); 14 | } 15 | this._mineral = mineral; 16 | this.memory.mineralId = mineral.id; 17 | } else { 18 | this._mineral = Game.getObjectById(this.memory.mineralId); 19 | } 20 | } 21 | return this._mineral; 22 | }, 23 | enumerable: false, 24 | configurable: true 25 | }); 26 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Room/prototype.Room.structures.js: -------------------------------------------------------------------------------- 1 | /* Posted March 10th, 2018 by @semperrabbit*/ 2 | /** 3 | Module: prototype.Room.structures v1.8 4 | Author: SemperRabbit 5 | Date: 20180309-13,20180411,20200524 6 | Usage: require('prototype.Room.structures'); 7 | 8 | This module will provide structure caching and extends the Room 9 | class' prototype to provide `room.controller`-like properties 10 | for all structure types. It will cache the object IDs of a 11 | room.find() grouped by type as IDs in global. Once the property 12 | is requested, it will chech the cache (and refresh if required), 13 | then return the appropriate objects by maping the cache's IDs 14 | into game objects for that tick. 15 | 16 | Changelog: 17 | 1.0: Initial publish 18 | 1.1: Changed multipleList empty results from `null` to `[]` 19 | Bugfix: changed singleList returns from arrays to single objects or undefined 20 | 1.2: Added intra-tick caching in addition to inter-tick caching 21 | 1.3: Multiple bugfixes 22 | 1.4: Moved STRUCTURE_POWER_BANK to `multipleList` due to proof of *possibility* of multiple 23 | in same room. 24 | 1.5: Added CPU Profiling information for Room.prototype._checkRoomCache() starting on line 47 25 | 1.6: Added tick check for per-tick caching, in preperation for the potential "persistent Game 26 | object" update. Edits on lines 73, 77-83, 95, 99-105 27 | 1.7: Added Factory support (line 46) 28 | 1.8: Made Factory support permanant and cleaner 29 | */ 30 | 31 | var roomStructures = {}; 32 | var roomStructuresExpiration = {}; 33 | 34 | const CACHE_TIMEOUT = 50; 35 | const CACHE_OFFSET = 4; 36 | 37 | const multipleList = [ 38 | STRUCTURE_SPAWN, STRUCTURE_EXTENSION, STRUCTURE_ROAD, STRUCTURE_WALL, 39 | STRUCTURE_RAMPART, STRUCTURE_KEEPER_LAIR, STRUCTURE_PORTAL, STRUCTURE_LINK, 40 | STRUCTURE_TOWER, STRUCTURE_LAB, STRUCTURE_CONTAINER, STRUCTURE_POWER_BANK, 41 | ]; 42 | 43 | const singleList = [ 44 | STRUCTURE_OBSERVER, STRUCTURE_POWER_SPAWN, STRUCTURE_EXTRACTOR, STRUCTURE_NUKER, 45 | STRUCTURE_FACTORY, //STRUCTURE_TERMINAL, STRUCTURE_CONTROLLER, STRUCTURE_STORAGE, 46 | ]; 47 | 48 | function getCacheExpiration(){ 49 | return CACHE_TIMEOUT + Math.round((Math.random()*CACHE_OFFSET*2)-CACHE_OFFSET); 50 | } 51 | 52 | /********* CPU Profiling stats for Room.prototype._checkRoomCache ********** 53 | calls time avg function 54 | 550106 5581.762 0.01015 Room._checkRoomCache 55 | 56 | calls with cache reset: 4085 57 | avg for cache reset: 0.137165 58 | calls without reset: 270968 59 | avg without reset: 0.003262 60 | ****************************************************************************/ 61 | Room.prototype._checkRoomCache = function _checkRoomCache(){ 62 | // if cache is expired or doesn't exist 63 | if(!roomStructuresExpiration[this.name] || !roomStructures[this.name] || roomStructuresExpiration[this.name] < Game.time){ 64 | roomStructuresExpiration[this.name] = Game.time + getCacheExpiration(); 65 | roomStructures[this.name] = _.groupBy(this.find(FIND_STRUCTURES), s=>s.structureType); 66 | var i; 67 | for(i in roomStructures[this.name]){ 68 | roomStructures[this.name][i] = _.map(roomStructures[this.name][i], s=>s.id); 69 | } 70 | } 71 | } 72 | 73 | multipleList.forEach(function(type){ 74 | Object.defineProperty(Room.prototype, type+'s', { 75 | get: function(){ 76 | if(this['_'+type+'s'] && this['_'+type+'s_ts'] === Game.time){ 77 | return this['_'+type+'s']; 78 | } else { 79 | this._checkRoomCache(); 80 | if(roomStructures[this.name][type]) { 81 | this['_'+type+'s_ts'] = Game.time; 82 | return this['_'+type+'s'] = roomStructures[this.name][type].map(Game.getObjectById); 83 | } else { 84 | this['_'+type+'s_ts'] = Game.time; 85 | return this['_'+type+'s'] = []; 86 | } 87 | } 88 | }, 89 | set: function(){}, 90 | enumerable: false, 91 | configurable: true, 92 | }); 93 | }); 94 | 95 | singleList.forEach(function(type){ 96 | Object.defineProperty(Room.prototype, type, { 97 | get: function(){ 98 | if(this['_'+type] && this['_'+type+'_ts'] === Game.time){ 99 | return this['_'+type]; 100 | } else { 101 | this._checkRoomCache(); 102 | if(roomStructures[this.name][type]) { 103 | this['_'+type+'_ts'] = Game.time; 104 | return this['_'+type] = Game.getObjectById(roomStructures[this.name][type][0]); 105 | } else { 106 | this['_'+type+'_ts'] = Game.time; 107 | return this['_'+type] = undefined; 108 | } 109 | } 110 | }, 111 | set: function(){}, 112 | enumerable: false, 113 | configurable: true, 114 | }); 115 | }); -------------------------------------------------------------------------------- /src/prototypes/JavaScript/RoomObject/Generalized target locking (with examples).js: -------------------------------------------------------------------------------- 1 | // warinternal 4 February 2017 at 21:44 2 | 3 | /** 4 | * Generalized target locking function for actors with memory. 5 | * 6 | * Valid actors include creeps, flags, and structures if you assign them memory. 7 | * 8 | * The selector function picks all available candidates, but only runs during 9 | * the target selection phase. This is where your CPU heavy work should go. 10 | * 11 | * The validator function is ran for each candidate, and once per call to 12 | * ensure the target is still valid for use, so you want this function to be as 13 | * cheap as possible. The parameter is technically optional, with all values 14 | * being considered valid. But then why are you using this? 15 | * 16 | * The chooser function is ran once at the end of target selection, to pick 17 | * which of the valid candidates you want to use. This parameter is optional, 18 | * defaulting to the first item in the array if omitted. It expects a single 19 | * result so opt for a _.min or _.max over a sort. 20 | * 21 | * The prop parameter is the key used to store the target's id in memory. This 22 | * optionally allows us to have multiple target locks with different names. 23 | * 24 | * @param function selector - Gets a list of target candidates 25 | * @param function validator - Check if a target is still valid 26 | * @param function chooser - Pick the best target from the list 27 | * @param string prop - Property name in memory to store the target id 28 | */ 29 | RoomObject.prototype.getTarget = function( 30 | selector, 31 | validator = _.identity, 32 | chooser = _.first, 33 | prop = "tid" 34 | ) { 35 | var tid = this.memory[prop]; 36 | var target = Game.getObjectById(tid); 37 | if (target == null || !validator(target)) { 38 | this.room.visual.circle(this.pos, { fill: "red" }); 39 | var candidates = _.filter(selector.call(this, this), validator); 40 | if (candidates && candidates.length) target = chooser(candidates, this); 41 | else target = null; 42 | if (target) this.memory[prop] = target.id; 43 | else delete this.memory[prop]; 44 | } 45 | if (target) 46 | target.room.visual.line(this.pos, target.pos, { 47 | lineStyle: "dashed", 48 | opacity: 0.5 49 | }); 50 | return target; 51 | }; 52 | 53 | /** 54 | * Similar to getTarget, but ensures no other actor is assigned to this target. 55 | * 56 | * @param function selector - Gets a list of target candidates 57 | * @param function restrictor - Called at start of target selection, expected to return array of invalid targets 58 | * @param function validator - Check if a target is still valid 59 | * @param function chooser - Pick the best target from the list 60 | * @param string prop - Property name in memory to store the target id 61 | */ 62 | RoomObject.prototype.getUniqueTarget = function( 63 | selector, 64 | restrictor, 65 | validator = _.identity, 66 | chooser = _.first, 67 | prop = "tid" 68 | ) { 69 | var tid = this.memory[prop]; 70 | var target = Game.getObjectById(tid); 71 | if (target == null || !validator(target)) { 72 | this.clearTarget(prop); 73 | var invalid = restrictor.call(this, this) || []; 74 | var candidates = _.filter( 75 | selector.call(this, this), 76 | x => validator(x) && !invalid.includes(x.id) 77 | ); 78 | if (candidates && candidates.length) target = chooser(candidates, this); 79 | else target = null; 80 | if (target) this.memory[prop] = target.id; 81 | // console.log(`New target on tick ${Game.time}: ${target}`); 82 | } 83 | if (target) 84 | target.room.visual.line(this.pos, target.pos, { 85 | lineStyle: "dashed", 86 | opacity: 0.5 87 | }); 88 | return target; 89 | }; 90 | 91 | RoomObject.prototype.clearTarget = function(prop = "tid") { 92 | // delete this.memory[prop]; 93 | this.memory[prop] = undefined; 94 | }; 95 | 96 | /** 97 | * Examples 98 | */ 99 | 100 | Creep.prototype.getRepairTarget = function() { 101 | return this.getTarget( 102 | ({ room, pos }) => room.find(FIND_STRUCTURES), 103 | structure => structure.hits < structure.hitsMax, 104 | candidates => _.min(candidates, "hits") 105 | ); 106 | }; 107 | 108 | Creep.prototype.getLoadedContainerTarget = function() { 109 | return this.getTarget( 110 | ({ room, pos }) => 111 | room.find(FIND_STRUCTURES, { 112 | filter: s => s.structureType === STRUCTURE_CONTAINER 113 | }), 114 | container => _.sum(container.store) > 0, 115 | containers => _.max(containers, c => _.sum(container.store)) 116 | ); 117 | }; 118 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/RoomObject/lookForNear.js: -------------------------------------------------------------------------------- 1 | // warinternal 25 November 2016 at 19:30 2 | RoomObject.prototype.lookForNear = function(lookFor, asArray, range = 1) { 3 | let { x, y } = this.pos; 4 | return this.room.lookForAtArea( 5 | lookFor, 6 | Math.max(0, y - range), 7 | Math.max(0, x - range), 8 | Math.min(49, y + range), 9 | Math.min(49, x + range), 10 | asArray 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/RoomObject/lookNear.js: -------------------------------------------------------------------------------- 1 | // warinternal 25 November 2016 at 19:30 2 | RoomObject.prototype.lookNear = function(asArray, range = 1) { 3 | let { x, y } = this.pos; 4 | return this.room.lookAtArea( 5 | Math.max(0, y - range), 6 | Math.max(0, x - range), 7 | Math.min(49, y + range), 8 | Math.min(49, x + range), 9 | asArray 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/RoomObject/roomObjectSay.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 7 October 2018 by @mototroller 3 | * 4 | * Author: Mototroller 5 | * Usage: copy-paste 6 | * Licence: MIT 7 | * Version: 1.0 8 | * 9 | * Description: 10 | * Simple prototype extention which allows every room object to use 11 | * creep.say() method analogue: popup bubble with given text will be shown. 12 | * Uses RoomVisual, so is should be enabled in GUI (enabled by default). 13 | */ 14 | 15 | /// @param {String} what - message will be displayed 16 | RoomObject.prototype.say = function(what) { 17 | this.room.visual.line(this.pos.x, this.pos.y, this.pos.x + 1 - 0.2, this.pos.y - 1, { 18 | // Line from object to message bubble 19 | color: "#eeeeee", 20 | opacity: 0.9, 21 | width: 0.1 22 | }).circle(this.pos, { 23 | // Small dot marker at the top of object 24 | fill: "#aaffaa", 25 | opacity: 0.9 26 | }).text(what, this.pos.x + 1, this.pos.y - 1, { 27 | // Fake message, used to align background (to make black border) 28 | color: "black", 29 | opacity: 0.9, 30 | align: "left", 31 | font: "bold 0.6 Arial", 32 | backgroundColor: "black", 33 | backgroundPadding: 0.3 34 | }).text(what, this.pos.x + 1, this.pos.y - 1, { 35 | // Real message 36 | color: "black", 37 | opacity: 0.9, 38 | align: "left", 39 | font: "bold 0.6 Arial", 40 | backgroundColor: "#eeeeee", 41 | backgroundPadding: 0.2 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/RoomPosition/findFirstInRange implementation for RoomPosition.js: -------------------------------------------------------------------------------- 1 | // proximo 6 December 2016 at 17:15 2 | RoomPosition.prototype.findFirstInRange = function(type, range) { 3 | const room = this.room; 4 | if (room === undefined) return undefined; 5 | 6 | const xMin = Math.max(0, this.x - range); 7 | const xMax = Math.min(49, this.x + range); 8 | const yMin = Math.max(0, this.y - range); 9 | const yMax = Math.min(49, this.y + range); 10 | 11 | for (let y = yMin; y <= yMax; y++) { 12 | for (let x = xMin; x <= xMax; x++) { 13 | if (x === this.x && y === this.y) continue; 14 | 15 | let result = room.lookForAt(LOOK_STRUCTURES, x, y); 16 | 17 | for (let i = 0; i < result.length; i++) { 18 | if (result[i].structureType === type) { 19 | return result[i]; 20 | } 21 | } 22 | } 23 | } 24 | return undefined; 25 | }; 26 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/RoomPosition/prototype.RoomPosition.toString_fromString.js: -------------------------------------------------------------------------------- 1 | /* Posted December 25th, 2016 by @semperrabbit */ 2 | 3 | // Special thanks to @helam for finding the client selection code 4 | RoomPosition.prototype.toString = function (htmlLink = true, id = undefined, memWatch = undefined) { 5 | if(htmlLink){ 6 | var onClick = ''; 7 | if(id) onClick += `angular.element('body').injector().get('RoomViewPendingSelector').set('${id}');`; 8 | if(memWatch) onClick += `angular.element($('section.memory')).scope().Memory.addWatch('${memWatch}');angular.element($('section.memory')).scope().Memory.selectedObjectWatch='${memWatch}';` 9 | return `[${ this.roomName } ${ this.x },${ this.y }]`; 10 | } 11 | return `[${ this.roomName } ${ this.x },${ this.y }]`; 12 | }; 13 | 14 | RoomPosition.fromString = function(str, dontThrowError = false){ 15 | let temp = str.split(/[\[\] ,]/); 16 | if(Game.rooms.sim && temp.length == 7) // sometimes sim's pos.toString() gives wierd 17 | temp = ['', temp[2], temp[4], temp[5], '']; // stuff like "[room sim pos 25,25]" 18 | 19 | if(dontThrowError){ 20 | if(temp.length !== 5) return ERR_INVALID_ARGS; 21 | if(!/^(W|E)\d+(N|S)\d+$/.test(temp[1]) && temp[1]!=='sim') return ERR_INVALID_ARGS; 22 | if(!/^\d+$/.test(temp[2])) return ERR_INVALID_ARGS; 23 | if(!/^\d+$/.test(temp[3])) return ERR_INVALID_ARGS; 24 | } 25 | 26 | return new RoomPosition(temp[2], temp[3], temp[1]); 27 | } -------------------------------------------------------------------------------- /src/prototypes/JavaScript/RoomPosition/toString()s_w_HTML_link_and_selection.js: -------------------------------------------------------------------------------- 1 | /* Posted Jan 14th, 2017 by @semperrabbit*/ 2 | /* This code will provide the ability to toString() Creep, Structure, StructureSpawn and Flag objects to the console with a link that will take you to the room, select the creep and add the temporary Memory watch to the Memory tab. (highlighting Flag object currently does not work, but it will still take you to the room and add the Memory watch)*/ 3 | 4 | // Special thanks to @helam for finding the client selection code 5 | RoomPosition.prototype.toString = function (htmlLink = true, id = undefined, memWatch = undefined) { 6 | if(htmlLink){ 7 | var onClick = ''; 8 | if(id) onClick += `angular.element('body').injector().get('RoomViewPendingSelector').set('${id}');`; 9 | if(memWatch) onClick += `angular.element($('section.memory')).scope().Memory.addWatch('${memWatch}');angular.element($('section.memory')).scope().Memory.selectedObjectWatch='${memWatch}';` 10 | return `[${ this.roomName } ${ this.x },${ this.y }]`; 11 | } 12 | return `[${ this.roomName } ${ this.x },${ this.y }]`; 13 | }; 14 | 15 | Creep.prototype.toString = function (htmlLink = true){ 16 | return `[${(this.name ? this.name : this.id)} ${this.pos.toString(htmlLink, this.id, 'creeps.'+this.name)}]`; 17 | } 18 | 19 | Structure.prototype.toString = function (htmlLink = true){ 20 | return `[structure (${this.structureType}) #${this.id} ${this.pos.toString(htmlLink, this.id, 'structures.' + this.id)}]`; 21 | } 22 | 23 | StructureSpawn.prototype.toString = function (htmlLink = true){ 24 | return `[structure (${this.structureType}) #${this.id} ${this.pos.toString(htmlLink, this.id, 'spawns.' + this.name)}]`; 25 | } 26 | 27 | Flag.prototype.toString = function (htmlLink = true){ 28 | return `[flag ${this.name} ${this.pos.toString(htmlLink, this.name, 'flags.'+this.name)}]`; 29 | } -------------------------------------------------------------------------------- /src/prototypes/JavaScript/RoomVisual/RawVisual Structures.js: -------------------------------------------------------------------------------- 1 | // ags131 6 February 2017 at 21:14 2 | /*********************************************/ 3 | /********** Moved to Screepers repo **********/ 4 | /** https://github.com/screepers/RoomVisual **/ 5 | /*********************************************/ 6 | const colors = { 7 | gray: "#555555", 8 | light: "#AAAAAA", 9 | road: "#666", // >:D 10 | dark: "#181818", 11 | outline: "#8FBB93" 12 | }; 13 | 14 | RoomVisual.prototype.structure = function(x, y, type, opts = {}) { 15 | opts = Object.assign( 16 | { 17 | opacity: 1 18 | }, 19 | opts 20 | ); 21 | switch (type) { 22 | case STRUCTURE_EXTENSION: 23 | this.circle(x, y, { 24 | radius: 0.5, 25 | fill: colors.dark, 26 | stroke: colors.outline, 27 | strokeWidth: 0.05, 28 | opacity: opts.opacity 29 | }); 30 | this.circle(x, y, { 31 | radius: 0.35, 32 | fill: colors.gray, 33 | opacity: opts.opacity 34 | }); 35 | break; 36 | case STRUCTURE_SPAWN: 37 | this.circle(x, y, { 38 | radius: 0.7, 39 | fill: colors.dark, 40 | stroke: "#CCCCCC", 41 | strokeWidth: 0.1, 42 | opacity: opts.opacity 43 | }); 44 | break; 45 | case STRUCTURE_LINK: { 46 | let osize = 0.3; 47 | let isize = 0.2; 48 | let outer = [[0.0, -0.5], [0.4, 0.0], [0.0, 0.5], [-0.4, 0.0]]; 49 | let inner = [[0.0, -0.3], [0.25, 0.0], [0.0, 0.3], [-0.25, 0.0]]; 50 | outer = relPoly(x, y, outer); 51 | inner = relPoly(x, y, inner); 52 | outer.push(outer[0]); 53 | inner.push(inner[0]); 54 | this.poly(outer, { 55 | fill: colors.dark, 56 | stroke: colors.outline, 57 | strokeWidth: 0.05, 58 | opacity: opts.opacity 59 | }); 60 | this.poly(inner, { 61 | fill: colors.gray, 62 | stroke: false, 63 | opacity: opts.opacity 64 | }); 65 | break; 66 | } 67 | case STRUCTURE_TERMINAL: { 68 | let outer = [ 69 | [0.0, -0.8], 70 | [0.55, -0.55], 71 | [0.8, 0.0], 72 | [0.55, 0.55], 73 | [0.0, 0.8], 74 | [-0.55, 0.55], 75 | [-0.8, 0.0], 76 | [-0.55, -0.55] 77 | ]; 78 | let inner = [ 79 | [0.0, -0.65], 80 | [0.45, -0.45], 81 | [0.65, 0.0], 82 | [0.45, 0.45], 83 | [0.0, 0.65], 84 | [-0.45, 0.45], 85 | [-0.65, 0.0], 86 | [-0.45, -0.45] 87 | ]; 88 | outer = relPoly(x, y, outer); 89 | inner = relPoly(x, y, inner); 90 | outer.push(outer[0]); 91 | inner.push(inner[0]); 92 | this.poly(outer, { 93 | fill: colors.dark, 94 | stroke: colors.outline, 95 | strokeWidth: 0.05, 96 | opacity: opts.opacity 97 | }); 98 | this.poly(inner, { 99 | fill: colors.light, 100 | stroke: false, 101 | opacity: opts.opacity 102 | }); 103 | this.rect(x - 0.45, y - 0.45, 0.9, 0.9, { 104 | fill: colors.gray, 105 | stroke: colors.dark, 106 | strokeWidth: 0.1, 107 | opacity: opts.opacity 108 | }); 109 | break; 110 | } 111 | case STRUCTURE_LAB: 112 | this.circle(x, y - 0.025, { 113 | radius: 0.55, 114 | fill: colors.dark, 115 | stroke: colors.outline, 116 | strokeWidth: 0.05, 117 | opacity: opts.opacity 118 | }); 119 | this.circle(x, y - 0.025, { 120 | radius: 0.4, 121 | fill: colors.gray, 122 | opacity: opts.opacity 123 | }); 124 | this.rect(x - 0.45, y + 0.3, 0.9, 0.25, { 125 | fill: colors.dark, 126 | stroke: false, 127 | opacity: opts.opacity 128 | }); 129 | { 130 | let box = [[-0.45, 0.3], [-0.45, 0.55], [0.45, 0.55], [0.45, 0.3]]; 131 | box = relPoly(x, y, box); 132 | this.poly(box, { 133 | stroke: colors.outline, 134 | strokeWidth: 0.05, 135 | opacity: opts.opacity 136 | }); 137 | } 138 | break; 139 | case STRUCTURE_TOWER: 140 | this.circle(x, y, { 141 | radius: 0.6, 142 | // fill: colors.dark, 143 | fill: "transparent", 144 | stroke: colors.outline, 145 | strokeWidth: 0.05, 146 | opacity: opts.opacity 147 | }); 148 | this.rect(x - 0.4, y - 0.3, 0.8, 0.6, { 149 | fill: colors.gray, 150 | opacity: opts.opacity 151 | }); 152 | this.rect(x - 0.2, y - 0.9, 0.4, 0.5, { 153 | fill: colors.light, 154 | stroke: colors.dark, 155 | strokeWidth: 0.07, 156 | opacity: opts.opacity 157 | }); 158 | break; 159 | } 160 | }; 161 | 162 | function relPoly(x, y, poly) { 163 | return poly.map(p => { 164 | p[0] += x; 165 | p[1] += y; 166 | return p; 167 | }); 168 | } 169 | 170 | RoomVisual.prototype.test = function test() { 171 | let demopos = [8, 8]; 172 | this.clear(); 173 | this.structure(demopos[0] + 0, demopos[1] + 0, STRUCTURE_LAB); 174 | this.structure(demopos[0] + 1, demopos[1] + 1, STRUCTURE_TOWER); 175 | this.structure(demopos[0] + 2, demopos[1] + 0, STRUCTURE_LINK); 176 | this.structure(demopos[0] + 3, demopos[1] + 1, STRUCTURE_TERMINAL); 177 | this.structure(demopos[0] + 4, demopos[1] + 0, STRUCTURE_EXTENSION); 178 | this.structure(demopos[0] + 5, demopos[1] + 1, STRUCTURE_SPAWN); 179 | this.text(this.getSize() + "B", 10, 11); 180 | }; 181 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/Source/Memory for Source (or other objects).js: -------------------------------------------------------------------------------- 1 | // w4rl0ck 26 April 2017 at 23:41 2 | 3 | Object.defineProperty(Source.prototype, "memory", { 4 | configurable: true, 5 | get() { 6 | if (_.isUndefined(this.room.memory.sources)) { 7 | this.room.memory.sources = {}; 8 | } 9 | return (this.room.memory.sources[this.id] = 10 | this.room.memory.sources[this.id] || {}); 11 | }, 12 | set(value) { 13 | if (_.isUndefined(this.room.memory.sources)) { 14 | this.room.memory.sources = {}; 15 | } 16 | if (!_.isObject(Memory.structure)) { 17 | throw new Error("Could not set structure memory"); 18 | } 19 | this.room.memory.sources[this.id] = value; 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/StructureLink/modified link.transferEnergy to prevent redundant multiple sends to the same target.js: -------------------------------------------------------------------------------- 1 | // helam 3 January 2017 at 15:36 2 | const ACCEPTABLE_FULL_AMOUNT = LINK_CAPACITY * (1 - LINK_LOSS_RATIO); 3 | StructureLink.prototype._singleTransferEnergy = 4 | StructureLink.prototype.transferEnergy; 5 | StructureLink.prototype.transferEnergy = function(target, amount) { 6 | if (target._isFull) return ERR_FULL; 7 | 8 | let transferResult = this._singleTransferEnergy.apply(this, arguments); 9 | 10 | if (transferResult === OK) { 11 | let transferred = (amount || this.energy) * (1 - LINK_LOSS_RATIO); 12 | if (target.energy + transferred >= ACCEPTABLE_FULL_AMOUNT) 13 | target._isFull = true; 14 | } 15 | return transferResult; 16 | }; 17 | -------------------------------------------------------------------------------- /src/prototypes/JavaScript/functionMiddleware.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Posted 18 September 2017 by @warinternal 3 | * 4 | * Loops over only functions on the prototype and 5 | * passes them to a callback function. 6 | */ 7 | function forEachFn(proto, cb) { 8 | var names = Object.getOwnPropertyNames(proto); 9 | var name,i,desc; 10 | for(i=0; i 48 || posY < 1 || posY > 48) 70 | continue; 71 | if ((terrain.get(posX, posY) & TERRAIN_MASK_WALL) > 0) 72 | continue; 73 | if (room.lookForAt(LOOK_STRUCTURES, posX, posY).find(s => OBSTACLE_OBJECT_TYPES.includes(s.structureType))) 74 | continue; 75 | 76 | const hasCreeps = room.lookForAt(LOOK_CREEPS, posX, posY).length > 0; 77 | const addWeight = hasCreeps ? 1 : 2; 78 | dirCandidates[dir] += addWeight; 79 | totalWeight += dirCandidates[dir]; 80 | } 81 | 82 | let sum = 0; 83 | let rnd = _.random(1, totalWeight, false); 84 | for (let dir = TOP; dir <= TOP_LEFT; ++dir) { 85 | if (dirCandidates[dir] > 0) { 86 | sum += dirCandidates[dir]; 87 | if (rnd <= sum) { 88 | return dir; 89 | } 90 | } 91 | } 92 | 93 | // this should never happen, unless creep is spawned into a corner 94 | // or structure is built next to it and seals the only path out 95 | return getRandomDir(); 96 | } 97 | 98 | /* 99 | * returns a weighted random direction from given position 100 | * tries to stay in targets range, if it's impossible then fallbacks to random direction 101 | * prefers empty tiles over ones with creeps 102 | * never picks a direction that would result in hitting a wall or an obstacle structure 103 | */ 104 | function getNudgeDirection_KeepRange(pos: RoomPosition, target: { pos: RoomPosition; range: number; }) { 105 | const room = Game.rooms[pos.roomName]; 106 | const terrain = Game.map.getRoomTerrain(pos.roomName); 107 | let keepRangeTotalWeight = 0; 108 | let keepRangeDirCandidates = new Uint8Array(9); 109 | let randomTotalWeight = 0; 110 | let randomDirCandidates = new Uint8Array(9); 111 | for (let dir = TOP; dir <= TOP_LEFT; ++dir) { 112 | let posX = pos.x + offsetX[dir]; 113 | let posY = pos.y + offsetY[dir]; 114 | if (posX < 1 || posX > 48 || posY < 1 || posY > 48) 115 | continue; 116 | if ((terrain.get(posX, posY) & TERRAIN_MASK_WALL) > 0) 117 | continue; 118 | if (room.lookForAt(LOOK_STRUCTURES, posX, posY).find(s => OBSTACLE_OBJECT_TYPES.includes(s.structureType))) 119 | continue; 120 | 121 | const hasCreeps = room.lookForAt(LOOK_CREEPS, posX, posY).length > 0; 122 | const addWeight = hasCreeps ? 1 : 2; 123 | randomDirCandidates[dir] += addWeight; 124 | if (target.pos.inRangeTo(posX, posY, target.range)) 125 | keepRangeDirCandidates[dir] += addWeight; 126 | keepRangeTotalWeight += keepRangeDirCandidates[dir]; 127 | randomTotalWeight += randomDirCandidates[dir]; 128 | } 129 | 130 | const dirCandidates = keepRangeTotalWeight > 0 ? keepRangeDirCandidates : randomDirCandidates; 131 | const totalWeight = keepRangeTotalWeight > 0 ? keepRangeTotalWeight : randomTotalWeight; 132 | let sum = 0; 133 | if (totalWeight > 0) { 134 | let rnd = _.random(1, totalWeight, false); 135 | for (let dir = TOP; dir <= TOP_LEFT; ++dir) { 136 | if (dirCandidates[dir] > 0) { 137 | sum += dirCandidates[dir]; 138 | if (rnd <= sum) { 139 | return dir; 140 | } 141 | } 142 | } 143 | } 144 | 145 | // this should never happen, unless creep is spawned into a corner 146 | // or structure is built next to it and seals the only path out 147 | return getRandomDir(); 148 | } 149 | 150 | /* 151 | * a nudge 152 | */ 153 | function excuseMe(pos: RoomPosition, direction: DirectionConstant) { 154 | const nextX = pos.x + offsetX[direction]; 155 | const nextY = pos.y + offsetY[direction]; 156 | if (nextX > 49 || nextX < 0 || nextY > 49 || nextY < 0) 157 | return; 158 | 159 | const room = Game.rooms[pos.roomName]; 160 | const creeps = room.lookForAt(LOOK_CREEPS, nextX, nextY); 161 | if (creeps.length > 0 && creeps[0].my) 162 | creeps[0].memory.excuseMe = getOppositeDir(direction); 163 | const powerCreeps = room.lookForAt(LOOK_POWER_CREEPS, nextX, nextY); 164 | if (powerCreeps.length > 0 && powerCreeps[0].my) 165 | powerCreeps[0].memory.excuseMe = getOppositeDir(direction); 166 | } 167 | 168 | /* 169 | * 170 | */ 171 | let creepsThatTriedToMove: { [key: string]: RoomPosition; } = {}; 172 | const move = Creep.prototype.move; 173 | Creep.prototype.move = function (direction: DirectionConstant | Creep, nudge?: boolean) { 174 | if ((alwaysNudge || nudge) && _.isNumber(direction)) 175 | excuseMe(this.pos, direction); 176 | creepsThatTriedToMove[this.name] = this.pos; 177 | return move.call(this, direction); 178 | }; 179 | 180 | /* 181 | * call this on creeps that should react to being nudged 182 | */ 183 | function giveWay(creep: AnyCreep, arg?: boolean | { pos: RoomPosition; range: number; }) { 184 | if (creep.memory.excuseMe) { 185 | if (!arg) 186 | creep.move(creep.memory.excuseMe, true); 187 | else if (typeof arg === 'object') 188 | creep.move(getNudgeDirection_KeepRange(creep.pos, arg), true); 189 | else 190 | creep.move(getNudgeDirection_Random(creep.pos), true); 191 | } 192 | } 193 | Creep.prototype.giveWay = function (arg?: boolean | { pos: RoomPosition; range: number; }) { 194 | giveWay(this, arg); 195 | }; 196 | PowerCreep.prototype.giveWay = function (arg?: boolean | { pos: RoomPosition; range: number; }) { 197 | giveWay(this, arg); 198 | }; 199 | 200 | /* 201 | * clears nudges from memory of creeps that moved 202 | * call on tick start 203 | */ 204 | export function clearNudges() { 205 | for (let creepName in creepsThatTriedToMove) { 206 | const creep = Game.creeps[creepName]; 207 | const powerCreep = Game.powerCreeps[creepName]; 208 | const prevPos = creepsThatTriedToMove[creepName]; 209 | if ((!creep || !creep.pos.isEqualTo(prevPos)) && (!powerCreep || !powerCreep.pos.isEqualTo(prevPos))) { 210 | const creepMemory = Memory.creeps[creepName]; 211 | if (creepMemory) 212 | creepMemory.excuseMe = undefined; 213 | const powerCreepMemory = Memory.powerCreeps[creepName]; 214 | if (powerCreepMemory) 215 | powerCreepMemory.excuseMe = undefined; 216 | delete creepsThatTriedToMove[creepName]; 217 | } 218 | } 219 | } --------------------------------------------------------------------------------