├── README.md ├── callback.js ├── callback.test.js ├── grafana.json ├── pebble.js ├── resources.js └── screepsplus.js /README.md: -------------------------------------------------------------------------------- 1 | # Screeps 2 | 3 | [Screeps](https://screeps.com/) is a great game I'm playing with my son to help him learn to program. 4 | It's all programmed in JavaScript (running in [Node 6.6](https://nodejs.org/en/) [`vm`](https://nodejs.org/api/vm.html), 5 | using [V8 JavaScript engine](https://github.com/v8/v8), 6 | [implementing most of ECMAScript 2015/6](http://node.green/) [or here](https://kangax.github.io/compat-table/es6/), 7 | with the [Lodash](https://lodash.com/) library available as `_`), 8 | and has a reasonably well [documented API](http://support.screeps.com/hc/en-us/articles/203084991-API-Reference). 9 | 10 | Here are some modules I'm happy to share with the world and him. If I take a hiatus from playing, I'll share my 11 | entire code base. 12 | 13 | # Disclaimer 14 | 15 | Note that I don't pretend to be a JavaScript engineer nor a game AI programmer. Indeed, I learned ECMAScript 2015 16 | just for this game; the last thing I had read about JavaScript was almost a decade ago, 17 | [*JavaScript, the Good Parts*](http://shop.oreilly.com/product/9780596517748.do), and I have done almost no 18 | production coding in JavaScript. 19 | 20 | # Modules 21 | 22 | * `callback.js` - A simple JavaScript "class" for registering callback functions and firing 23 | events to them. 24 | 25 | * `resources.js` - A module that analyzes all the rooms and summarizes the data about each 26 | of them for later use. I call this at the top of my main loop each tick. 27 | 28 | * `screepsplus.js` - A module that creates a `Memory.stats` object that can be used to 29 | import data into [ScreepsPl.us](https://screepspl.us/)'s Grafana tracking system. You 30 | can register callbacks to add data to this without changing this code. Be sure to add 31 | this in your main loop and also add as the final thing you do the record of your CPU used. 32 | 33 | * `pebble.js` - A module that formats things for display on my Pebble Time Round watch, 34 | using [ScreepsTime](https://github.com/bthaase/ScreepsTime) watch face. I display 35 | three things: Percentage to next GCL, Percentage to next RCL (for the closest room), 36 | and if there have been any enemies in the last 300 ticks, including the current number 37 | of enemies and the time (in NYC) the enemies were last seen. 38 | 39 | * `grafana.json` - An exported Grafana module that graphs the stats from my above 40 | `screepsplus.js`, as well as some data (e.g., my "ratchet" mechanism) that I haven't 41 | exported but which is tied in via the above-mentioned callbacks. 42 | 43 | 44 | # How To Use WebStorm 45 | 46 | * Install Steam Client using Steam for Mac 47 | * Let it download your source code to local filesystem. 48 | * Location: `~/Library/Application Support/Screeps/scripts/screeps.com/default` 49 | * Seems like each "branch" has its own directory 50 | * `brew install node` (use v6.6.0 [which is what Screeps uses](http://support.screeps.com/hc/en-us/articles/205960931-Server-side-architecture-overview)) 51 | * `git clone https://github.com/Garethp/ScreepsAutocomplete.git` somewhere 52 | * Install WebStorm 53 | 54 | ## Configuring WebStorm Project 55 | 56 | * Import the Screeps source code directory as a new, empty project in WebStorm 57 | * Settings -> Languages & Frameworks -> Node.js and NPM -> Node.js Core Library *ENABLE* 58 | * Now statements like `require` and variables like `global` will work 59 | * Settings -> Languages & Frameworks -> JavaScript 60 | * JavaScript Language Version *ECMAScript 6* 61 | * Prefer Strict Mode 62 | * -> Libraries: Enable ECMAScript 6 library 63 | * Settings -> Languages & Frameworks -> JavaScript Libraries 64 | * Add: ScreepsAutocomplete [per instructions](https://github.com/Garethp/ScreepsAutocomplete) 65 | * Set up `.gitignore` using [JetBrains template](https://raw.githubusercontent.com/github/gitignore/master/Global/JetBrains.gitignore) 66 | * Configure loDash 67 | * `console.log(_.VERSION)` in Screeps console => `3.10.1` 68 | * Clone it from git somewhere outside your project 69 | * `git checkout -b refs/tags/3.10.1` 70 | * Set up in WebStorm: 71 | * Settings -> Languages & Frameworks -> JavaScript -> Libraries 72 | * Click `Add`, and then in the `Edit Library` window: 73 | * Name: lodash 74 | * Framework type: custom 75 | * Visibility: Global 76 | * Version (it doesn't seem to save this, so leave blank) 77 | * Click `+` and add your cloned, checked out GitHub repo of lodash 78 | * Click `+` for docs and add `https://lodash.com/docs/3.10.1` 79 | * Click `OK` a few times and you're done 80 | * Don't do this: 81 | * Settings -> Languages & Frameworks -> Node.js and NPM "for current project" 82 | * Click `+` on the bottom 83 | * Search for `lodash` in the "Available Packages" window that pops up 84 | * Check "Specify Version" and put in 3.10.1 and click `Install Package` 85 | * It loads into a "node_modules". Unless, of course, that's what you want (I don't) 86 | 87 | # Using WebStrorm and Screeps 88 | 89 | * Any time you save a file in WebStorm *and then swap foreground program back to Screeps Steam Client*, 90 | the Screeps client automatically pushes it to the server. However, the italicized part doesn't 91 | always seem to be true. 92 | 93 | -------------------------------------------------------------------------------- /callback.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Callback is a class (use with new) that stores functions to call 4 | // back later, and they're called with a specified object. 5 | 6 | function Callback() { 7 | this.handlers = []; // observers 8 | } 9 | 10 | Callback.prototype = { 11 | 12 | subscribe: function(fn) { 13 | this.handlers.push(fn); 14 | }, 15 | 16 | unsubscribe: function(fn) { 17 | this.handlers = this.handlers.filter( 18 | function(item) { 19 | if (item !== fn) { 20 | return item; 21 | } 22 | } 23 | ); 24 | }, 25 | 26 | fire: function(o, thisObj) { 27 | // TODO: Put error handling around the call? 28 | this.handlers.forEach(function(item) { 29 | try { 30 | item.call(thisObj, o); 31 | } catch (err) { 32 | console.log('Ignored error calling back ', item.name, 'with', o, '-', err); 33 | } 34 | }); 35 | } 36 | } 37 | 38 | module.exports = { 39 | Callback 40 | }; -------------------------------------------------------------------------------- /callback.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const cb = require('callback'); 3 | 4 | // Create our callback function and store in our global context 5 | global.callback_test = new cb.Callback(); 6 | 7 | function callback_test() { 8 | const cbfunc = function(item) { 9 | console.log("fired:", item); 10 | }; 11 | 12 | global.callback_test.subscribe(cbfunc); 13 | global.callback_test.fire('event #1'); 14 | global.callback_test.unsubscribe(cbfunc); 15 | global.callback_test.fire('event #2'); 16 | global.callback_test.subscribe(cbfunc); 17 | global.callback_test.fire('event #3'); 18 | } 19 | 20 | module.exports = { 21 | callback_test, 22 | }; 23 | -------------------------------------------------------------------------------- /grafana.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_SCREEPSPL.US", 5 | "label": "screepspl.us", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "graphite", 9 | "pluginName": "Graphite" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "panel", 15 | "id": "graph", 16 | "name": "Graph", 17 | "version": "" 18 | }, 19 | { 20 | "type": "grafana", 21 | "id": "grafana", 22 | "name": "Grafana", 23 | "version": "3.1.1" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "graphite", 28 | "name": "Graphite", 29 | "version": "1.0.0" 30 | } 31 | ], 32 | "id": null, 33 | "title": "Admiral", 34 | "tags": [], 35 | "style": "dark", 36 | "timezone": "browser", 37 | "editable": true, 38 | "hideControls": false, 39 | "sharedCrosshair": false, 40 | "rows": [ 41 | { 42 | "collapse": false, 43 | "editable": true, 44 | "height": "100px", 45 | "panels": [ 46 | { 47 | "aliasColors": {}, 48 | "bars": false, 49 | "datasource": "${DS_SCREEPSPL.US}", 50 | "editable": true, 51 | "error": false, 52 | "fill": 0, 53 | "grid": { 54 | "threshold1": null, 55 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 56 | "threshold2": null, 57 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 58 | }, 59 | "id": 1, 60 | "isNew": true, 61 | "legend": { 62 | "avg": true, 63 | "current": true, 64 | "max": true, 65 | "min": true, 66 | "show": false, 67 | "total": false, 68 | "values": true 69 | }, 70 | "lines": true, 71 | "linewidth": 1, 72 | "links": [], 73 | "nullPointMode": "connected", 74 | "percentage": false, 75 | "pointradius": 5, 76 | "points": false, 77 | "renderer": "flot", 78 | "seriesOverrides": [], 79 | "span": 4, 80 | "stack": false, 81 | "steppedLine": false, 82 | "targets": [ 83 | { 84 | "hide": false, 85 | "refId": "A", 86 | "target": "screeps.roomSummary.$Room.num_creeps" 87 | } 88 | ], 89 | "timeFrom": null, 90 | "timeShift": null, 91 | "title": "Total Creeps", 92 | "tooltip": { 93 | "msResolution": false, 94 | "shared": true, 95 | "sort": 0, 96 | "value_type": "cumulative" 97 | }, 98 | "type": "graph", 99 | "xaxis": { 100 | "show": true 101 | }, 102 | "yaxes": [ 103 | { 104 | "format": "short", 105 | "label": null, 106 | "logBase": 1, 107 | "max": null, 108 | "min": 0, 109 | "show": true 110 | }, 111 | { 112 | "format": "short", 113 | "label": null, 114 | "logBase": 1, 115 | "max": null, 116 | "min": null, 117 | "show": true 118 | } 119 | ] 120 | }, 121 | { 122 | "aliasColors": {}, 123 | "bars": false, 124 | "datasource": "${DS_SCREEPSPL.US}", 125 | "editable": true, 126 | "error": false, 127 | "fill": 0, 128 | "grid": { 129 | "threshold1": null, 130 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 131 | "threshold2": null, 132 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 133 | }, 134 | "id": 10, 135 | "isNew": true, 136 | "legend": { 137 | "avg": false, 138 | "current": false, 139 | "max": false, 140 | "min": false, 141 | "show": false, 142 | "total": false, 143 | "values": false 144 | }, 145 | "lines": true, 146 | "linewidth": 1, 147 | "links": [], 148 | "nullPointMode": "connected", 149 | "percentage": false, 150 | "pointradius": 5, 151 | "points": false, 152 | "renderer": "flot", 153 | "seriesOverrides": [], 154 | "span": 4, 155 | "stack": false, 156 | "steppedLine": false, 157 | "targets": [ 158 | { 159 | "refId": "A", 160 | "target": "screeps.roomSummary.$Room.spawns_spawning" 161 | } 162 | ], 163 | "timeFrom": null, 164 | "timeShift": null, 165 | "title": "Spawning", 166 | "tooltip": { 167 | "msResolution": false, 168 | "shared": true, 169 | "sort": 0, 170 | "value_type": "cumulative" 171 | }, 172 | "type": "graph", 173 | "xaxis": { 174 | "show": true 175 | }, 176 | "yaxes": [ 177 | { 178 | "format": "short", 179 | "label": null, 180 | "logBase": 1, 181 | "max": null, 182 | "min": 0, 183 | "show": true 184 | }, 185 | { 186 | "format": "short", 187 | "label": null, 188 | "logBase": 1, 189 | "max": null, 190 | "min": null, 191 | "show": true 192 | } 193 | ] 194 | }, 195 | { 196 | "aliasColors": {}, 197 | "bars": false, 198 | "datasource": "${DS_SCREEPSPL.US}", 199 | "editable": true, 200 | "error": false, 201 | "fill": 0, 202 | "grid": { 203 | "threshold1": null, 204 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 205 | "threshold2": null, 206 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 207 | }, 208 | "id": 7, 209 | "isNew": true, 210 | "legend": { 211 | "avg": false, 212 | "current": false, 213 | "max": false, 214 | "min": false, 215 | "show": false, 216 | "total": false, 217 | "values": false 218 | }, 219 | "lines": true, 220 | "linewidth": 1, 221 | "links": [], 222 | "nullPointMode": "connected", 223 | "percentage": false, 224 | "pointradius": 5, 225 | "points": false, 226 | "renderer": "flot", 227 | "seriesOverrides": [ 228 | { 229 | "alias": "screeps.roomSummary.W56S31.num_enemies", 230 | "color": "#BF1B00" 231 | } 232 | ], 233 | "span": 4, 234 | "stack": false, 235 | "steppedLine": false, 236 | "targets": [ 237 | { 238 | "refId": "A", 239 | "target": "screeps.roomSummary.$Room.num_enemies" 240 | } 241 | ], 242 | "timeFrom": null, 243 | "timeShift": null, 244 | "title": "Enemy Creeps", 245 | "tooltip": { 246 | "msResolution": false, 247 | "shared": true, 248 | "sort": 0, 249 | "value_type": "cumulative" 250 | }, 251 | "type": "graph", 252 | "xaxis": { 253 | "show": true 254 | }, 255 | "yaxes": [ 256 | { 257 | "format": "short", 258 | "label": null, 259 | "logBase": 1, 260 | "max": null, 261 | "min": 0, 262 | "show": true 263 | }, 264 | { 265 | "format": "short", 266 | "label": null, 267 | "logBase": 1, 268 | "max": null, 269 | "min": null, 270 | "show": true 271 | } 272 | ] 273 | } 274 | ], 275 | "title": "Row" 276 | }, 277 | { 278 | "collapse": false, 279 | "editable": true, 280 | "height": "150px", 281 | "panels": [ 282 | { 283 | "aliasColors": {}, 284 | "bars": false, 285 | "datasource": "${DS_SCREEPSPL.US}", 286 | "editable": true, 287 | "error": false, 288 | "fill": 0, 289 | "grid": { 290 | "threshold1": null, 291 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 292 | "threshold2": null, 293 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 294 | }, 295 | "id": 2, 296 | "isNew": true, 297 | "legend": { 298 | "avg": false, 299 | "current": false, 300 | "max": false, 301 | "min": false, 302 | "show": false, 303 | "total": false, 304 | "values": false 305 | }, 306 | "lines": true, 307 | "linewidth": 1, 308 | "links": [], 309 | "nullPointMode": "connected", 310 | "percentage": false, 311 | "pointradius": 5, 312 | "points": false, 313 | "renderer": "flot", 314 | "seriesOverrides": [], 315 | "span": 6, 316 | "stack": false, 317 | "steppedLine": false, 318 | "targets": [ 319 | { 320 | "refId": "A", 321 | "target": "screeps.roomSummary.$Room.storage_energy" 322 | }, 323 | { 324 | "refId": "B", 325 | "target": "alias(movingAverage(screeps.roomSummary.$Room.storage_energy, '1hour'), 'MA')" 326 | } 327 | ], 328 | "timeFrom": null, 329 | "timeShift": null, 330 | "title": "Storage Energy", 331 | "tooltip": { 332 | "msResolution": false, 333 | "shared": true, 334 | "sort": 0, 335 | "value_type": "cumulative" 336 | }, 337 | "type": "graph", 338 | "xaxis": { 339 | "show": true 340 | }, 341 | "yaxes": [ 342 | { 343 | "format": "short", 344 | "label": null, 345 | "logBase": 1, 346 | "max": null, 347 | "min": null, 348 | "show": true 349 | }, 350 | { 351 | "format": "short", 352 | "label": null, 353 | "logBase": 1, 354 | "max": null, 355 | "min": null, 356 | "show": true 357 | } 358 | ] 359 | }, 360 | { 361 | "aliasColors": {}, 362 | "bars": false, 363 | "datasource": "${DS_SCREEPSPL.US}", 364 | "editable": true, 365 | "error": false, 366 | "fill": 0, 367 | "grid": { 368 | "threshold1": null, 369 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 370 | "threshold2": null, 371 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 372 | }, 373 | "id": 4, 374 | "isNew": true, 375 | "legend": { 376 | "avg": false, 377 | "current": false, 378 | "max": false, 379 | "min": true, 380 | "show": false, 381 | "total": false, 382 | "values": true 383 | }, 384 | "lines": true, 385 | "linewidth": 1, 386 | "links": [], 387 | "nullPointMode": "connected", 388 | "percentage": false, 389 | "pointradius": 5, 390 | "points": false, 391 | "renderer": "flot", 392 | "seriesOverrides": [], 393 | "span": 3, 394 | "stack": false, 395 | "steppedLine": false, 396 | "targets": [ 397 | { 398 | "refId": "A", 399 | "target": "screeps.roomSummary.$Room.source_energy" 400 | } 401 | ], 402 | "timeFrom": null, 403 | "timeShift": null, 404 | "title": "Source Energy", 405 | "tooltip": { 406 | "msResolution": false, 407 | "shared": true, 408 | "sort": 0, 409 | "value_type": "cumulative" 410 | }, 411 | "type": "graph", 412 | "xaxis": { 413 | "show": true 414 | }, 415 | "yaxes": [ 416 | { 417 | "format": "short", 418 | "label": null, 419 | "logBase": 1, 420 | "max": null, 421 | "min": null, 422 | "show": true 423 | }, 424 | { 425 | "format": "short", 426 | "label": null, 427 | "logBase": 1, 428 | "max": null, 429 | "min": null, 430 | "show": true 431 | } 432 | ] 433 | }, 434 | { 435 | "aliasColors": {}, 436 | "bars": false, 437 | "datasource": "${DS_SCREEPSPL.US}", 438 | "editable": true, 439 | "error": false, 440 | "fill": 0, 441 | "grid": { 442 | "threshold1": null, 443 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 444 | "threshold2": null, 445 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 446 | }, 447 | "id": 6, 448 | "isNew": true, 449 | "legend": { 450 | "avg": false, 451 | "current": false, 452 | "max": false, 453 | "min": false, 454 | "show": false, 455 | "total": false, 456 | "values": false 457 | }, 458 | "lines": true, 459 | "linewidth": 1, 460 | "links": [], 461 | "nullPointMode": "connected", 462 | "percentage": false, 463 | "pointradius": 5, 464 | "points": false, 465 | "renderer": "flot", 466 | "seriesOverrides": [], 467 | "span": 3, 468 | "stack": false, 469 | "steppedLine": false, 470 | "targets": [ 471 | { 472 | "refId": "A", 473 | "target": "screeps.roomSummary.$Room.energy_avail" 474 | } 475 | ], 476 | "timeFrom": null, 477 | "timeShift": null, 478 | "title": "Spawn Energy", 479 | "tooltip": { 480 | "msResolution": false, 481 | "shared": true, 482 | "sort": 0, 483 | "value_type": "cumulative" 484 | }, 485 | "type": "graph", 486 | "xaxis": { 487 | "show": true 488 | }, 489 | "yaxes": [ 490 | { 491 | "format": "short", 492 | "label": null, 493 | "logBase": 1, 494 | "max": null, 495 | "min": null, 496 | "show": true 497 | }, 498 | { 499 | "format": "short", 500 | "label": null, 501 | "logBase": 1, 502 | "max": null, 503 | "min": null, 504 | "show": true 505 | } 506 | ] 507 | }, 508 | { 509 | "aliasColors": {}, 510 | "bars": false, 511 | "datasource": "${DS_SCREEPSPL.US}", 512 | "editable": true, 513 | "error": false, 514 | "fill": 0, 515 | "grid": { 516 | "threshold1": null, 517 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 518 | "threshold2": null, 519 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 520 | }, 521 | "id": 5, 522 | "isNew": true, 523 | "legend": { 524 | "avg": false, 525 | "current": false, 526 | "max": false, 527 | "min": false, 528 | "show": false, 529 | "total": false, 530 | "values": false 531 | }, 532 | "lines": true, 533 | "linewidth": 1, 534 | "links": [], 535 | "nullPointMode": "connected", 536 | "percentage": false, 537 | "pointradius": 5, 538 | "points": false, 539 | "renderer": "flot", 540 | "seriesOverrides": [], 541 | "span": 3, 542 | "stack": false, 543 | "steppedLine": false, 544 | "targets": [ 545 | { 546 | "refId": "A", 547 | "target": "screeps.roomSummary.$Room.link_energy" 548 | } 549 | ], 550 | "timeFrom": null, 551 | "timeShift": null, 552 | "title": "Link Energy", 553 | "tooltip": { 554 | "msResolution": false, 555 | "shared": true, 556 | "sort": 0, 557 | "value_type": "cumulative" 558 | }, 559 | "type": "graph", 560 | "xaxis": { 561 | "show": true 562 | }, 563 | "yaxes": [ 564 | { 565 | "format": "short", 566 | "label": null, 567 | "logBase": 1, 568 | "max": null, 569 | "min": null, 570 | "show": true 571 | }, 572 | { 573 | "format": "short", 574 | "label": null, 575 | "logBase": 1, 576 | "max": null, 577 | "min": null, 578 | "show": true 579 | } 580 | ] 581 | }, 582 | { 583 | "aliasColors": {}, 584 | "bars": false, 585 | "datasource": "${DS_SCREEPSPL.US}", 586 | "editable": true, 587 | "error": false, 588 | "fill": 0, 589 | "grid": { 590 | "threshold1": null, 591 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 592 | "threshold2": null, 593 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 594 | }, 595 | "id": 8, 596 | "isNew": true, 597 | "legend": { 598 | "avg": false, 599 | "current": false, 600 | "max": false, 601 | "min": false, 602 | "show": false, 603 | "total": false, 604 | "values": false 605 | }, 606 | "lines": true, 607 | "linewidth": 1, 608 | "links": [], 609 | "nullPointMode": "connected", 610 | "percentage": false, 611 | "pointradius": 5, 612 | "points": false, 613 | "renderer": "flot", 614 | "seriesOverrides": [], 615 | "span": 3, 616 | "stack": false, 617 | "steppedLine": false, 618 | "targets": [ 619 | { 620 | "refId": "A", 621 | "target": "screeps.roomSummary.$Room.creep_energy" 622 | } 623 | ], 624 | "timeFrom": null, 625 | "timeShift": null, 626 | "title": "Creep Energy", 627 | "tooltip": { 628 | "msResolution": false, 629 | "shared": true, 630 | "sort": 0, 631 | "value_type": "cumulative" 632 | }, 633 | "type": "graph", 634 | "xaxis": { 635 | "show": true 636 | }, 637 | "yaxes": [ 638 | { 639 | "format": "short", 640 | "label": null, 641 | "logBase": 1, 642 | "max": null, 643 | "min": 0, 644 | "show": true 645 | }, 646 | { 647 | "format": "short", 648 | "label": null, 649 | "logBase": 1, 650 | "max": null, 651 | "min": null, 652 | "show": true 653 | } 654 | ] 655 | }, 656 | { 657 | "aliasColors": {}, 658 | "bars": false, 659 | "datasource": "${DS_SCREEPSPL.US}", 660 | "editable": true, 661 | "error": false, 662 | "fill": 0, 663 | "grid": { 664 | "threshold1": null, 665 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 666 | "threshold2": null, 667 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 668 | }, 669 | "id": 3, 670 | "isNew": true, 671 | "legend": { 672 | "avg": false, 673 | "current": false, 674 | "max": false, 675 | "min": false, 676 | "show": false, 677 | "total": false, 678 | "values": false 679 | }, 680 | "lines": true, 681 | "linewidth": 1, 682 | "links": [], 683 | "nullPointMode": "connected", 684 | "percentage": false, 685 | "pointradius": 5, 686 | "points": false, 687 | "renderer": "flot", 688 | "seriesOverrides": [], 689 | "span": 3, 690 | "stack": false, 691 | "steppedLine": false, 692 | "targets": [ 693 | { 694 | "refId": "A", 695 | "target": "screeps.roomSummary.$Room.container_energy" 696 | } 697 | ], 698 | "timeFrom": null, 699 | "timeShift": null, 700 | "title": "Container Energy", 701 | "tooltip": { 702 | "msResolution": false, 703 | "shared": true, 704 | "sort": 0, 705 | "value_type": "cumulative" 706 | }, 707 | "type": "graph", 708 | "xaxis": { 709 | "show": true 710 | }, 711 | "yaxes": [ 712 | { 713 | "format": "short", 714 | "label": null, 715 | "logBase": 1, 716 | "max": null, 717 | "min": null, 718 | "show": true 719 | }, 720 | { 721 | "format": "short", 722 | "label": null, 723 | "logBase": 1, 724 | "max": null, 725 | "min": null, 726 | "show": true 727 | } 728 | ] 729 | }, 730 | { 731 | "aliasColors": {}, 732 | "bars": false, 733 | "datasource": "${DS_SCREEPSPL.US}", 734 | "editable": true, 735 | "error": false, 736 | "fill": 0, 737 | "grid": { 738 | "threshold1": null, 739 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 740 | "threshold2": null, 741 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 742 | }, 743 | "id": 11, 744 | "isNew": true, 745 | "legend": { 746 | "avg": false, 747 | "current": false, 748 | "max": false, 749 | "min": false, 750 | "show": false, 751 | "total": false, 752 | "values": false 753 | }, 754 | "lines": true, 755 | "linewidth": 1, 756 | "links": [], 757 | "nullPointMode": "connected", 758 | "percentage": false, 759 | "pointradius": 5, 760 | "points": false, 761 | "renderer": "flot", 762 | "seriesOverrides": [], 763 | "span": 3, 764 | "stack": false, 765 | "steppedLine": false, 766 | "targets": [ 767 | { 768 | "refId": "A", 769 | "target": "screeps.roomSummary.$Room.tower_energy" 770 | } 771 | ], 772 | "timeFrom": null, 773 | "timeShift": null, 774 | "title": "Tower Energy", 775 | "tooltip": { 776 | "msResolution": false, 777 | "shared": true, 778 | "sort": 0, 779 | "value_type": "cumulative" 780 | }, 781 | "type": "graph", 782 | "xaxis": { 783 | "show": true 784 | }, 785 | "yaxes": [ 786 | { 787 | "format": "short", 788 | "label": null, 789 | "logBase": 1, 790 | "max": null, 791 | "min": 0, 792 | "show": true 793 | }, 794 | { 795 | "format": "short", 796 | "label": null, 797 | "logBase": 1, 798 | "max": null, 799 | "min": null, 800 | "show": true 801 | } 802 | ] 803 | } 804 | ], 805 | "title": "New row" 806 | }, 807 | { 808 | "collapse": false, 809 | "editable": true, 810 | "height": "200px", 811 | "panels": [ 812 | { 813 | "aliasColors": {}, 814 | "bars": false, 815 | "datasource": "${DS_SCREEPSPL.US}", 816 | "editable": true, 817 | "error": false, 818 | "fill": 0, 819 | "grid": { 820 | "threshold1": null, 821 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 822 | "threshold2": null, 823 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 824 | }, 825 | "id": 9, 826 | "isNew": true, 827 | "legend": { 828 | "alignAsTable": false, 829 | "avg": false, 830 | "current": false, 831 | "max": true, 832 | "min": true, 833 | "rightSide": false, 834 | "show": true, 835 | "total": false, 836 | "values": true 837 | }, 838 | "lines": true, 839 | "linewidth": 1, 840 | "links": [], 841 | "maxDataPoints": "", 842 | "nullPointMode": "connected", 843 | "percentage": false, 844 | "pointradius": 5, 845 | "points": false, 846 | "renderer": "flot", 847 | "seriesOverrides": [ 848 | { 849 | "alias": "Bucket", 850 | "yaxis": 2 851 | }, 852 | { 853 | "alias": "Tick Limit", 854 | "yaxis": 2 855 | } 856 | ], 857 | "span": 4, 858 | "stack": false, 859 | "steppedLine": false, 860 | "targets": [ 861 | { 862 | "hide": false, 863 | "refId": "D", 864 | "target": "alias(screeps.cpu.bucket, 'Bucket')" 865 | }, 866 | { 867 | "refId": "A", 868 | "target": "alias(screeps.cpu.used, 'Used')" 869 | }, 870 | { 871 | "hide": true, 872 | "refId": "B", 873 | "target": "alias(screeps.cpu.limit, 'Limit')" 874 | }, 875 | { 876 | "hide": true, 877 | "refId": "C", 878 | "target": "alias(screeps.cpu.tickLimit, 'Tick Limit')" 879 | }, 880 | { 881 | "hide": true, 882 | "refId": "E", 883 | "target": "alias(movingAverage(screeps.cpu.used, '5min'), 'Avg Used')" 884 | } 885 | ], 886 | "timeFrom": null, 887 | "timeShift": null, 888 | "title": "CPU", 889 | "tooltip": { 890 | "msResolution": false, 891 | "shared": true, 892 | "sort": 0, 893 | "value_type": "cumulative" 894 | }, 895 | "type": "graph", 896 | "xaxis": { 897 | "show": true 898 | }, 899 | "yaxes": [ 900 | { 901 | "format": "short", 902 | "label": null, 903 | "logBase": 1, 904 | "max": null, 905 | "min": null, 906 | "show": true 907 | }, 908 | { 909 | "format": "none", 910 | "label": null, 911 | "logBase": 1, 912 | "max": null, 913 | "min": null, 914 | "show": true 915 | } 916 | ] 917 | }, 918 | { 919 | "aliasColors": {}, 920 | "bars": false, 921 | "datasource": "${DS_SCREEPSPL.US}", 922 | "editable": true, 923 | "error": false, 924 | "fill": 0, 925 | "grid": { 926 | "threshold1": null, 927 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 928 | "threshold2": null, 929 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 930 | }, 931 | "id": 12, 932 | "isNew": true, 933 | "legend": { 934 | "avg": false, 935 | "current": false, 936 | "max": false, 937 | "min": false, 938 | "show": false, 939 | "total": false, 940 | "values": false 941 | }, 942 | "lines": true, 943 | "linewidth": 2, 944 | "links": [], 945 | "nullPointMode": "connected", 946 | "percentage": false, 947 | "pointradius": 5, 948 | "points": false, 949 | "renderer": "flot", 950 | "seriesOverrides": [], 951 | "span": 4, 952 | "stack": false, 953 | "steppedLine": false, 954 | "targets": [ 955 | { 956 | "refId": "B", 957 | "target": "screeps.memory.used" 958 | } 959 | ], 960 | "timeFrom": null, 961 | "timeShift": null, 962 | "title": "Memory", 963 | "tooltip": { 964 | "msResolution": false, 965 | "shared": true, 966 | "sort": 0, 967 | "value_type": "cumulative" 968 | }, 969 | "type": "graph", 970 | "xaxis": { 971 | "show": true 972 | }, 973 | "yaxes": [ 974 | { 975 | "format": "bytes", 976 | "label": null, 977 | "logBase": 1, 978 | "max": null, 979 | "min": null, 980 | "show": true 981 | }, 982 | { 983 | "format": "short", 984 | "label": null, 985 | "logBase": 1, 986 | "max": null, 987 | "min": null, 988 | "show": true 989 | } 990 | ] 991 | }, 992 | { 993 | "title": "GCL", 994 | "error": false, 995 | "span": 2, 996 | "editable": true, 997 | "type": "graph", 998 | "isNew": true, 999 | "id": 23, 1000 | "targets": [ 1001 | { 1002 | "target": "screeps.gcl.progress", 1003 | "refId": "A" 1004 | } 1005 | ], 1006 | "datasource": "${DS_SCREEPSPL.US}", 1007 | "renderer": "flot", 1008 | "yaxes": [ 1009 | { 1010 | "label": null, 1011 | "show": true, 1012 | "logBase": 1, 1013 | "min": null, 1014 | "max": null, 1015 | "format": "short" 1016 | }, 1017 | { 1018 | "label": null, 1019 | "show": true, 1020 | "logBase": 1, 1021 | "min": null, 1022 | "max": null, 1023 | "format": "short" 1024 | } 1025 | ], 1026 | "xaxis": { 1027 | "show": true 1028 | }, 1029 | "grid": { 1030 | "threshold1": null, 1031 | "threshold2": null, 1032 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1033 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1034 | }, 1035 | "lines": true, 1036 | "fill": 0, 1037 | "linewidth": 2, 1038 | "points": false, 1039 | "pointradius": 5, 1040 | "bars": false, 1041 | "stack": false, 1042 | "percentage": false, 1043 | "legend": { 1044 | "show": false, 1045 | "values": false, 1046 | "min": false, 1047 | "max": false, 1048 | "current": false, 1049 | "total": false, 1050 | "avg": false 1051 | }, 1052 | "nullPointMode": "connected", 1053 | "steppedLine": false, 1054 | "tooltip": { 1055 | "value_type": "cumulative", 1056 | "shared": true, 1057 | "sort": 0, 1058 | "msResolution": false 1059 | }, 1060 | "timeFrom": null, 1061 | "timeShift": null, 1062 | "aliasColors": {}, 1063 | "seriesOverrides": [], 1064 | "links": [] 1065 | }, 1066 | { 1067 | "aliasColors": {}, 1068 | "bars": false, 1069 | "datasource": "${DS_SCREEPSPL.US}", 1070 | "editable": true, 1071 | "error": false, 1072 | "fill": 4, 1073 | "grid": { 1074 | "threshold1": null, 1075 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1076 | "threshold2": null, 1077 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1078 | }, 1079 | "id": 16, 1080 | "isNew": true, 1081 | "legend": { 1082 | "avg": false, 1083 | "current": false, 1084 | "max": false, 1085 | "min": false, 1086 | "show": false, 1087 | "total": false, 1088 | "values": false 1089 | }, 1090 | "lines": true, 1091 | "linewidth": 0, 1092 | "links": [], 1093 | "nullPointMode": "connected", 1094 | "percentage": false, 1095 | "pointradius": 5, 1096 | "points": false, 1097 | "renderer": "flot", 1098 | "seriesOverrides": [], 1099 | "span": 2, 1100 | "stack": false, 1101 | "steppedLine": false, 1102 | "targets": [ 1103 | { 1104 | "refId": "A", 1105 | "target": "screeps.roomSummary.$Room.ground_resources.energy" 1106 | } 1107 | ], 1108 | "timeFrom": null, 1109 | "timeShift": null, 1110 | "title": "Ground Energy", 1111 | "tooltip": { 1112 | "msResolution": false, 1113 | "shared": true, 1114 | "sort": 0, 1115 | "value_type": "cumulative" 1116 | }, 1117 | "type": "graph", 1118 | "xaxis": { 1119 | "show": true 1120 | }, 1121 | "yaxes": [ 1122 | { 1123 | "format": "short", 1124 | "label": null, 1125 | "logBase": 1, 1126 | "max": null, 1127 | "min": null, 1128 | "show": true 1129 | }, 1130 | { 1131 | "format": "short", 1132 | "label": null, 1133 | "logBase": 1, 1134 | "max": null, 1135 | "min": null, 1136 | "show": true 1137 | } 1138 | ] 1139 | } 1140 | ], 1141 | "title": "New row" 1142 | }, 1143 | { 1144 | "collapse": false, 1145 | "editable": true, 1146 | "height": "100px", 1147 | "panels": [ 1148 | { 1149 | "aliasColors": {}, 1150 | "bars": false, 1151 | "datasource": "${DS_SCREEPSPL.US}", 1152 | "editable": true, 1153 | "error": false, 1154 | "fill": 0, 1155 | "grid": { 1156 | "threshold1": null, 1157 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1158 | "threshold2": null, 1159 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1160 | }, 1161 | "id": 13, 1162 | "isNew": true, 1163 | "legend": { 1164 | "avg": false, 1165 | "current": false, 1166 | "max": false, 1167 | "min": false, 1168 | "show": false, 1169 | "total": false, 1170 | "values": false 1171 | }, 1172 | "lines": true, 1173 | "linewidth": 1, 1174 | "links": [], 1175 | "nullPointMode": "connected", 1176 | "percentage": false, 1177 | "pointradius": 5, 1178 | "points": false, 1179 | "renderer": "flot", 1180 | "seriesOverrides": [], 1181 | "span": 3, 1182 | "stack": false, 1183 | "steppedLine": false, 1184 | "targets": [ 1185 | { 1186 | "refId": "A", 1187 | "target": "alias(screeps.roomSummary.$Room.structure_info.road.min_hits, 'Road minimum hits')", 1188 | "textEditor": true 1189 | } 1190 | ], 1191 | "timeFrom": null, 1192 | "timeShift": null, 1193 | "title": "Worst Road", 1194 | "tooltip": { 1195 | "msResolution": false, 1196 | "shared": true, 1197 | "sort": 0, 1198 | "value_type": "cumulative" 1199 | }, 1200 | "type": "graph", 1201 | "xaxis": { 1202 | "show": true 1203 | }, 1204 | "yaxes": [ 1205 | { 1206 | "format": "short", 1207 | "label": null, 1208 | "logBase": 1, 1209 | "max": null, 1210 | "min": null, 1211 | "show": true 1212 | }, 1213 | { 1214 | "format": "short", 1215 | "label": null, 1216 | "logBase": 1, 1217 | "max": null, 1218 | "min": null, 1219 | "show": true 1220 | } 1221 | ] 1222 | }, 1223 | { 1224 | "aliasColors": {}, 1225 | "bars": false, 1226 | "datasource": "${DS_SCREEPSPL.US}", 1227 | "editable": true, 1228 | "error": false, 1229 | "fill": 0, 1230 | "grid": { 1231 | "threshold1": null, 1232 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1233 | "threshold2": null, 1234 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1235 | }, 1236 | "id": 18, 1237 | "isNew": true, 1238 | "legend": { 1239 | "avg": false, 1240 | "current": false, 1241 | "max": false, 1242 | "min": false, 1243 | "show": false, 1244 | "total": false, 1245 | "values": false 1246 | }, 1247 | "lines": true, 1248 | "linewidth": 1, 1249 | "links": [], 1250 | "nullPointMode": "connected", 1251 | "percentage": false, 1252 | "pointradius": 5, 1253 | "points": false, 1254 | "renderer": "flot", 1255 | "seriesOverrides": [], 1256 | "span": 3, 1257 | "stack": false, 1258 | "steppedLine": false, 1259 | "targets": [ 1260 | { 1261 | "refId": "A", 1262 | "target": "screeps.roomSummary.$Room.structure_info.container.min_hits" 1263 | } 1264 | ], 1265 | "timeFrom": null, 1266 | "timeShift": null, 1267 | "title": "Worst Container", 1268 | "tooltip": { 1269 | "msResolution": false, 1270 | "shared": true, 1271 | "sort": 0, 1272 | "value_type": "cumulative" 1273 | }, 1274 | "type": "graph", 1275 | "xaxis": { 1276 | "show": true 1277 | }, 1278 | "yaxes": [ 1279 | { 1280 | "format": "short", 1281 | "label": null, 1282 | "logBase": 1, 1283 | "max": null, 1284 | "min": null, 1285 | "show": true 1286 | }, 1287 | { 1288 | "format": "short", 1289 | "label": null, 1290 | "logBase": 1, 1291 | "max": null, 1292 | "min": null, 1293 | "show": true 1294 | } 1295 | ] 1296 | }, 1297 | { 1298 | "aliasColors": {}, 1299 | "bars": false, 1300 | "datasource": "${DS_SCREEPSPL.US}", 1301 | "editable": true, 1302 | "error": false, 1303 | "fill": 0, 1304 | "grid": { 1305 | "threshold1": null, 1306 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1307 | "threshold2": null, 1308 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1309 | }, 1310 | "id": 19, 1311 | "isNew": true, 1312 | "legend": { 1313 | "avg": false, 1314 | "current": false, 1315 | "max": false, 1316 | "min": false, 1317 | "show": false, 1318 | "total": false, 1319 | "values": false 1320 | }, 1321 | "lines": true, 1322 | "linewidth": 1, 1323 | "links": [], 1324 | "nullPointMode": "connected", 1325 | "percentage": false, 1326 | "pointradius": 5, 1327 | "points": false, 1328 | "renderer": "flot", 1329 | "seriesOverrides": [ 1330 | { 1331 | "alias": "Worst Rampart", 1332 | "color": "#BF1B00" 1333 | } 1334 | ], 1335 | "span": 3, 1336 | "stack": false, 1337 | "steppedLine": false, 1338 | "targets": [ 1339 | { 1340 | "refId": "A", 1341 | "target": "alias(screeps.roomSummary.$Room.structure_info.rampart.min_hits, 'Worst Rampart')", 1342 | "textEditor": true 1343 | } 1344 | ], 1345 | "timeFrom": null, 1346 | "timeShift": null, 1347 | "title": "Worst Rampart", 1348 | "tooltip": { 1349 | "msResolution": false, 1350 | "shared": true, 1351 | "sort": 0, 1352 | "value_type": "cumulative" 1353 | }, 1354 | "type": "graph", 1355 | "xaxis": { 1356 | "show": true 1357 | }, 1358 | "yaxes": [ 1359 | { 1360 | "format": "short", 1361 | "label": null, 1362 | "logBase": 1, 1363 | "max": null, 1364 | "min": null, 1365 | "show": true 1366 | }, 1367 | { 1368 | "format": "short", 1369 | "label": null, 1370 | "logBase": 1, 1371 | "max": null, 1372 | "min": null, 1373 | "show": true 1374 | } 1375 | ] 1376 | }, 1377 | { 1378 | "aliasColors": {}, 1379 | "bars": false, 1380 | "datasource": "${DS_SCREEPSPL.US}", 1381 | "editable": true, 1382 | "error": false, 1383 | "fill": 0, 1384 | "grid": { 1385 | "threshold1": null, 1386 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1387 | "threshold2": null, 1388 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1389 | }, 1390 | "id": 20, 1391 | "isNew": true, 1392 | "legend": { 1393 | "avg": false, 1394 | "current": false, 1395 | "max": false, 1396 | "min": false, 1397 | "show": false, 1398 | "total": false, 1399 | "values": false 1400 | }, 1401 | "lines": true, 1402 | "linewidth": 1, 1403 | "links": [], 1404 | "nullPointMode": "connected", 1405 | "percentage": false, 1406 | "pointradius": 5, 1407 | "points": false, 1408 | "renderer": "flot", 1409 | "seriesOverrides": [ 1410 | { 1411 | "alias": "Worst Wall", 1412 | "color": "#BF1B00" 1413 | } 1414 | ], 1415 | "span": 3, 1416 | "stack": false, 1417 | "steppedLine": false, 1418 | "targets": [ 1419 | { 1420 | "refId": "A", 1421 | "target": "alias(screeps.roomSummary.$Room.structure_info.constructedWall.min_hits, 'Worst Wall')", 1422 | "textEditor": true 1423 | } 1424 | ], 1425 | "timeFrom": null, 1426 | "timeShift": null, 1427 | "title": "Worst Wall", 1428 | "tooltip": { 1429 | "msResolution": false, 1430 | "shared": true, 1431 | "sort": 0, 1432 | "value_type": "cumulative" 1433 | }, 1434 | "type": "graph", 1435 | "xaxis": { 1436 | "show": true 1437 | }, 1438 | "yaxes": [ 1439 | { 1440 | "format": "short", 1441 | "label": null, 1442 | "logBase": 1, 1443 | "max": null, 1444 | "min": null, 1445 | "show": true 1446 | }, 1447 | { 1448 | "format": "short", 1449 | "label": null, 1450 | "logBase": 1, 1451 | "max": null, 1452 | "min": null, 1453 | "show": true 1454 | } 1455 | ] 1456 | } 1457 | ], 1458 | "title": "New row" 1459 | }, 1460 | { 1461 | "collapse": false, 1462 | "editable": true, 1463 | "height": "150px", 1464 | "panels": [ 1465 | { 1466 | "aliasColors": {}, 1467 | "bars": false, 1468 | "datasource": "${DS_SCREEPSPL.US}", 1469 | "editable": true, 1470 | "error": false, 1471 | "fill": 1, 1472 | "grid": { 1473 | "threshold1": null, 1474 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1475 | "threshold2": null, 1476 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1477 | }, 1478 | "id": 14, 1479 | "isNew": true, 1480 | "legend": { 1481 | "avg": false, 1482 | "current": false, 1483 | "max": false, 1484 | "min": false, 1485 | "show": false, 1486 | "total": false, 1487 | "values": false 1488 | }, 1489 | "lines": true, 1490 | "linewidth": 2, 1491 | "links": [], 1492 | "nullPointMode": "connected", 1493 | "percentage": false, 1494 | "pointradius": 5, 1495 | "points": false, 1496 | "renderer": "flot", 1497 | "seriesOverrides": [ 1498 | { 1499 | "alias": "screeps.roomSummary.W55S31.controller_downgrade", 1500 | "color": "#BF1B00" 1501 | } 1502 | ], 1503 | "span": 4, 1504 | "stack": false, 1505 | "steppedLine": false, 1506 | "targets": [ 1507 | { 1508 | "refId": "A", 1509 | "target": "screeps.roomSummary.$Room.controller_downgrade" 1510 | } 1511 | ], 1512 | "timeFrom": null, 1513 | "timeShift": null, 1514 | "title": "Controller Downgrade", 1515 | "tooltip": { 1516 | "msResolution": false, 1517 | "shared": true, 1518 | "sort": 0, 1519 | "value_type": "cumulative" 1520 | }, 1521 | "type": "graph", 1522 | "xaxis": { 1523 | "show": true 1524 | }, 1525 | "yaxes": [ 1526 | { 1527 | "format": "short", 1528 | "label": null, 1529 | "logBase": 1, 1530 | "max": null, 1531 | "min": null, 1532 | "show": true 1533 | }, 1534 | { 1535 | "format": "short", 1536 | "label": null, 1537 | "logBase": 1, 1538 | "max": null, 1539 | "min": null, 1540 | "show": true 1541 | } 1542 | ] 1543 | }, 1544 | { 1545 | "aliasColors": {}, 1546 | "bars": false, 1547 | "datasource": "${DS_SCREEPSPL.US}", 1548 | "editable": true, 1549 | "error": false, 1550 | "fill": 1, 1551 | "grid": { 1552 | "threshold1": null, 1553 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1554 | "threshold2": null, 1555 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1556 | }, 1557 | "id": 15, 1558 | "isNew": true, 1559 | "legend": { 1560 | "avg": false, 1561 | "current": false, 1562 | "max": false, 1563 | "min": false, 1564 | "show": false, 1565 | "total": false, 1566 | "values": false 1567 | }, 1568 | "lines": true, 1569 | "linewidth": 2, 1570 | "links": [], 1571 | "nullPointMode": "connected", 1572 | "percentage": false, 1573 | "pointradius": 5, 1574 | "points": false, 1575 | "renderer": "flot", 1576 | "seriesOverrides": [], 1577 | "span": 4, 1578 | "stack": false, 1579 | "steppedLine": false, 1580 | "targets": [ 1581 | { 1582 | "refId": "A", 1583 | "target": "screeps.roomSummary.$Room.controller_progress" 1584 | } 1585 | ], 1586 | "timeFrom": null, 1587 | "timeShift": null, 1588 | "title": "Controller Progress", 1589 | "tooltip": { 1590 | "msResolution": false, 1591 | "shared": true, 1592 | "sort": 0, 1593 | "value_type": "cumulative" 1594 | }, 1595 | "type": "graph", 1596 | "xaxis": { 1597 | "show": true 1598 | }, 1599 | "yaxes": [ 1600 | { 1601 | "format": "short", 1602 | "label": null, 1603 | "logBase": 1, 1604 | "max": null, 1605 | "min": null, 1606 | "show": true 1607 | }, 1608 | { 1609 | "format": "short", 1610 | "label": null, 1611 | "logBase": 1, 1612 | "max": null, 1613 | "min": null, 1614 | "show": true 1615 | } 1616 | ] 1617 | }, 1618 | { 1619 | "aliasColors": {}, 1620 | "bars": false, 1621 | "datasource": "${DS_SCREEPSPL.US}", 1622 | "editable": true, 1623 | "error": false, 1624 | "fill": 1, 1625 | "grid": { 1626 | "threshold1": null, 1627 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1628 | "threshold2": null, 1629 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1630 | }, 1631 | "id": 17, 1632 | "isNew": true, 1633 | "legend": { 1634 | "avg": false, 1635 | "current": false, 1636 | "max": false, 1637 | "min": false, 1638 | "show": false, 1639 | "total": false, 1640 | "values": false 1641 | }, 1642 | "lines": true, 1643 | "linewidth": 2, 1644 | "links": [], 1645 | "nullPointMode": "connected", 1646 | "percentage": false, 1647 | "pointradius": 5, 1648 | "points": false, 1649 | "renderer": "flot", 1650 | "seriesOverrides": [], 1651 | "span": 4, 1652 | "stack": false, 1653 | "steppedLine": false, 1654 | "targets": [ 1655 | { 1656 | "refId": "A", 1657 | "target": "screeps.roomSummary.$Room.num_construction_sites" 1658 | } 1659 | ], 1660 | "timeFrom": null, 1661 | "timeShift": null, 1662 | "title": "Construction Sites", 1663 | "tooltip": { 1664 | "msResolution": false, 1665 | "shared": true, 1666 | "sort": 0, 1667 | "value_type": "cumulative" 1668 | }, 1669 | "type": "graph", 1670 | "xaxis": { 1671 | "show": true 1672 | }, 1673 | "yaxes": [ 1674 | { 1675 | "format": "short", 1676 | "label": null, 1677 | "logBase": 1, 1678 | "max": null, 1679 | "min": 0, 1680 | "show": true 1681 | }, 1682 | { 1683 | "format": "short", 1684 | "label": null, 1685 | "logBase": 1, 1686 | "max": null, 1687 | "min": null, 1688 | "show": true 1689 | } 1690 | ] 1691 | } 1692 | ], 1693 | "title": "New row" 1694 | }, 1695 | { 1696 | "collapse": false, 1697 | "editable": true, 1698 | "height": "100px", 1699 | "panels": [ 1700 | { 1701 | "title": "Mineral Storage", 1702 | "error": false, 1703 | "span": 4, 1704 | "editable": true, 1705 | "type": "graph", 1706 | "isNew": true, 1707 | "id": 21, 1708 | "targets": [ 1709 | { 1710 | "target": "screeps.roomSummary.$Room.storage_minerals", 1711 | "refId": "A" 1712 | } 1713 | ], 1714 | "datasource": "${DS_SCREEPSPL.US}", 1715 | "renderer": "flot", 1716 | "yaxes": [ 1717 | { 1718 | "label": null, 1719 | "show": true, 1720 | "logBase": 1, 1721 | "min": null, 1722 | "max": null, 1723 | "format": "short" 1724 | }, 1725 | { 1726 | "label": null, 1727 | "show": true, 1728 | "logBase": 1, 1729 | "min": null, 1730 | "max": null, 1731 | "format": "short" 1732 | } 1733 | ], 1734 | "xaxis": { 1735 | "show": true 1736 | }, 1737 | "grid": { 1738 | "threshold1": null, 1739 | "threshold2": null, 1740 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1741 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1742 | }, 1743 | "lines": true, 1744 | "fill": 0, 1745 | "linewidth": 1, 1746 | "points": false, 1747 | "pointradius": 5, 1748 | "bars": false, 1749 | "stack": false, 1750 | "percentage": false, 1751 | "legend": { 1752 | "show": false, 1753 | "values": false, 1754 | "min": false, 1755 | "max": false, 1756 | "current": false, 1757 | "total": false, 1758 | "avg": false 1759 | }, 1760 | "nullPointMode": "connected", 1761 | "steppedLine": false, 1762 | "tooltip": { 1763 | "value_type": "cumulative", 1764 | "shared": true, 1765 | "sort": 0, 1766 | "msResolution": false 1767 | }, 1768 | "timeFrom": null, 1769 | "timeShift": null, 1770 | "aliasColors": {}, 1771 | "seriesOverrides": [], 1772 | "links": [] 1773 | }, 1774 | { 1775 | "title": "Mineral Available", 1776 | "error": false, 1777 | "span": 4, 1778 | "editable": true, 1779 | "type": "graph", 1780 | "isNew": true, 1781 | "id": 22, 1782 | "targets": [ 1783 | { 1784 | "target": "screeps.roomSummary.$Room.mineral_amount", 1785 | "refId": "A" 1786 | } 1787 | ], 1788 | "datasource": "${DS_SCREEPSPL.US}", 1789 | "renderer": "flot", 1790 | "yaxes": [ 1791 | { 1792 | "label": null, 1793 | "show": true, 1794 | "logBase": 1, 1795 | "min": null, 1796 | "max": null, 1797 | "format": "short" 1798 | }, 1799 | { 1800 | "label": null, 1801 | "show": true, 1802 | "logBase": 1, 1803 | "min": null, 1804 | "max": null, 1805 | "format": "short" 1806 | } 1807 | ], 1808 | "xaxis": { 1809 | "show": true 1810 | }, 1811 | "grid": { 1812 | "threshold1": null, 1813 | "threshold2": null, 1814 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1815 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1816 | }, 1817 | "lines": true, 1818 | "fill": 0, 1819 | "linewidth": 1, 1820 | "points": false, 1821 | "pointradius": 5, 1822 | "bars": false, 1823 | "stack": false, 1824 | "percentage": false, 1825 | "legend": { 1826 | "show": false, 1827 | "values": false, 1828 | "min": false, 1829 | "max": false, 1830 | "current": false, 1831 | "total": false, 1832 | "avg": false 1833 | }, 1834 | "nullPointMode": "connected", 1835 | "steppedLine": false, 1836 | "tooltip": { 1837 | "value_type": "cumulative", 1838 | "shared": true, 1839 | "sort": 0, 1840 | "msResolution": false 1841 | }, 1842 | "timeFrom": null, 1843 | "timeShift": null, 1844 | "aliasColors": {}, 1845 | "seriesOverrides": [], 1846 | "links": [] 1847 | } 1848 | ], 1849 | "title": "New row" 1850 | }, 1851 | { 1852 | "title": "New row", 1853 | "height": "150px", 1854 | "editable": true, 1855 | "collapse": false, 1856 | "panels": [ 1857 | { 1858 | "title": "Terminal Energy", 1859 | "error": false, 1860 | "span": 4, 1861 | "editable": true, 1862 | "type": "graph", 1863 | "isNew": true, 1864 | "id": 24, 1865 | "targets": [ 1866 | { 1867 | "target": "screeps.roomSummary.$Room.terminal_energy", 1868 | "refId": "A" 1869 | } 1870 | ], 1871 | "datasource": "${DS_SCREEPSPL.US}", 1872 | "renderer": "flot", 1873 | "yaxes": [ 1874 | { 1875 | "label": null, 1876 | "show": true, 1877 | "logBase": 1, 1878 | "min": null, 1879 | "max": null, 1880 | "format": "short" 1881 | }, 1882 | { 1883 | "label": null, 1884 | "show": true, 1885 | "logBase": 1, 1886 | "min": null, 1887 | "max": null, 1888 | "format": "short" 1889 | } 1890 | ], 1891 | "xaxis": { 1892 | "show": true 1893 | }, 1894 | "grid": { 1895 | "threshold1": null, 1896 | "threshold2": null, 1897 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1898 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1899 | }, 1900 | "lines": true, 1901 | "fill": 0, 1902 | "linewidth": 1, 1903 | "points": false, 1904 | "pointradius": 5, 1905 | "bars": false, 1906 | "stack": false, 1907 | "percentage": false, 1908 | "legend": { 1909 | "show": false, 1910 | "values": false, 1911 | "min": false, 1912 | "max": false, 1913 | "current": false, 1914 | "total": false, 1915 | "avg": false 1916 | }, 1917 | "nullPointMode": "connected", 1918 | "steppedLine": false, 1919 | "tooltip": { 1920 | "value_type": "cumulative", 1921 | "shared": true, 1922 | "sort": 0, 1923 | "msResolution": false 1924 | }, 1925 | "timeFrom": null, 1926 | "timeShift": null, 1927 | "aliasColors": {}, 1928 | "seriesOverrides": [], 1929 | "links": [] 1930 | }, 1931 | { 1932 | "title": "Terminal Minerals", 1933 | "error": false, 1934 | "span": 4, 1935 | "editable": true, 1936 | "type": "graph", 1937 | "isNew": true, 1938 | "id": 25, 1939 | "targets": [ 1940 | { 1941 | "target": "screeps.roomSummary.$Room.terminal_minerals", 1942 | "refId": "A" 1943 | } 1944 | ], 1945 | "datasource": "${DS_SCREEPSPL.US}", 1946 | "renderer": "flot", 1947 | "yaxes": [ 1948 | { 1949 | "label": null, 1950 | "show": true, 1951 | "logBase": 1, 1952 | "min": 0, 1953 | "max": null, 1954 | "format": "short" 1955 | }, 1956 | { 1957 | "label": null, 1958 | "show": true, 1959 | "logBase": 1, 1960 | "min": null, 1961 | "max": null, 1962 | "format": "short" 1963 | } 1964 | ], 1965 | "xaxis": { 1966 | "show": true 1967 | }, 1968 | "grid": { 1969 | "threshold1": null, 1970 | "threshold2": null, 1971 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 1972 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 1973 | }, 1974 | "lines": true, 1975 | "fill": 0, 1976 | "linewidth": 1, 1977 | "points": false, 1978 | "pointradius": 5, 1979 | "bars": false, 1980 | "stack": false, 1981 | "percentage": false, 1982 | "legend": { 1983 | "show": false, 1984 | "values": false, 1985 | "min": false, 1986 | "max": false, 1987 | "current": false, 1988 | "total": false, 1989 | "avg": false 1990 | }, 1991 | "nullPointMode": "connected", 1992 | "steppedLine": false, 1993 | "tooltip": { 1994 | "value_type": "cumulative", 1995 | "shared": true, 1996 | "sort": 0, 1997 | "msResolution": false 1998 | }, 1999 | "timeFrom": null, 2000 | "timeShift": null, 2001 | "aliasColors": {}, 2002 | "seriesOverrides": [], 2003 | "links": [] 2004 | }, 2005 | { 2006 | "title": "Credits", 2007 | "error": false, 2008 | "span": 4, 2009 | "editable": true, 2010 | "type": "graph", 2011 | "isNew": true, 2012 | "id": 26, 2013 | "targets": [ 2014 | { 2015 | "target": "screeps.market.credits", 2016 | "refId": "A" 2017 | } 2018 | ], 2019 | "datasource": "${DS_SCREEPSPL.US}", 2020 | "renderer": "flot", 2021 | "yaxes": [ 2022 | { 2023 | "label": null, 2024 | "show": true, 2025 | "logBase": 1, 2026 | "min": 0, 2027 | "max": null, 2028 | "format": "short" 2029 | }, 2030 | { 2031 | "label": null, 2032 | "show": true, 2033 | "logBase": 1, 2034 | "min": null, 2035 | "max": null, 2036 | "format": "short" 2037 | } 2038 | ], 2039 | "xaxis": { 2040 | "show": true 2041 | }, 2042 | "grid": { 2043 | "threshold1": null, 2044 | "threshold2": null, 2045 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 2046 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 2047 | }, 2048 | "lines": true, 2049 | "fill": 0, 2050 | "linewidth": 2, 2051 | "points": false, 2052 | "pointradius": 5, 2053 | "bars": false, 2054 | "stack": false, 2055 | "percentage": false, 2056 | "legend": { 2057 | "show": false, 2058 | "values": false, 2059 | "min": false, 2060 | "max": false, 2061 | "current": false, 2062 | "total": false, 2063 | "avg": false 2064 | }, 2065 | "nullPointMode": "connected", 2066 | "steppedLine": false, 2067 | "tooltip": { 2068 | "value_type": "cumulative", 2069 | "shared": true, 2070 | "sort": 0, 2071 | "msResolution": false 2072 | }, 2073 | "timeFrom": null, 2074 | "timeShift": null, 2075 | "aliasColors": {}, 2076 | "seriesOverrides": [], 2077 | "links": [] 2078 | } 2079 | ] 2080 | } 2081 | ], 2082 | "time": { 2083 | "from": "now-3h", 2084 | "to": "now" 2085 | }, 2086 | "timepicker": { 2087 | "refresh_intervals": [ 2088 | "5s", 2089 | "10s", 2090 | "30s", 2091 | "1m", 2092 | "5m", 2093 | "15m", 2094 | "30m", 2095 | "1h", 2096 | "2h", 2097 | "1d" 2098 | ], 2099 | "time_options": [ 2100 | "5m", 2101 | "15m", 2102 | "1h", 2103 | "6h", 2104 | "12h", 2105 | "24h", 2106 | "2d", 2107 | "7d", 2108 | "30d" 2109 | ] 2110 | }, 2111 | "templating": { 2112 | "list": [ 2113 | { 2114 | "current": {}, 2115 | "datasource": "${DS_SCREEPSPL.US}", 2116 | "hide": 0, 2117 | "includeAll": true, 2118 | "multi": false, 2119 | "name": "Room", 2120 | "options": [], 2121 | "query": "screeps.roomSummary.*", 2122 | "refresh": 1, 2123 | "type": "query" 2124 | } 2125 | ] 2126 | }, 2127 | "annotations": { 2128 | "list": [] 2129 | }, 2130 | "refresh": "1m", 2131 | "schemaVersion": 12, 2132 | "version": 23, 2133 | "links": [], 2134 | "gnetId": null 2135 | } -------------------------------------------------------------------------------- /pebble.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const resources = require('resources'); 3 | 4 | // Feeds information into my Pebble Time Round 5 | // See: https://github.com/bthaase/ScreepsTime 6 | // Call this after Memory.stats is configured! 7 | 8 | // We use Memory.pebble and Memory.pebble_meta 9 | 10 | // TODOs 11 | // 1. Store the maximum enemy count for the last 10 minutes and show it on the watch 12 | // 2. Store any GCL or RCL changes for the last 2 hours and point it out 13 | 14 | 15 | // Important data: 16 | // 1. Emergency creeps spawned 17 | // 2. Enemy creeps around 18 | // 3. RCL/GCL changes 19 | // 4. Storage energy reserves low 20 | // 5. CPU bucket used up 21 | // 6. Wall or rampart level low 22 | // 7. Tower energy low 23 | 24 | const LAST_ENEMY_TICK = ['pebble_meta', 'last_enemy']; 25 | const LAST_ENEMY_TIME = ['pebble_meta', 'last_enemy_time']; 26 | const ENEMY_TICKS_ALERT = 300; // Alert for 300 ticks 27 | 28 | function send_to_pebble() { 29 | 30 | const ris = resources.summarize_rooms(); 31 | 32 | // Show our progress to next GCL 33 | const gclPct = Game.gcl.progress / Game.gcl.progressTotal * 100.0; 34 | const gclText = "GCL " + gclPct.toFixed(1); 35 | 36 | // Show our progress to next RCL (for closest one) 37 | const rclPct = _.max(Object.keys(ris).map(k => ris[k].controller_progress / ris[k].controller_needed)) * 100.0; 38 | const rclText = "RCL " + rclPct.toFixed(1); 39 | const rclColor = rclPct < 90 ? "#002200" : "#005500"; 40 | // console.log('Pebble RCL:', rclPct, rclText, rclColor); 41 | 42 | // Enemies in the last five minutes 43 | let lastEnemy = _.get(Memory, LAST_ENEMY_TICK, 0); 44 | let lastEnemyTime = _.get(Memory, LAST_ENEMY_TIME, ""); 45 | const numEnemies = _.sum(ris, r => r.num_enemies); 46 | if (numEnemies > 0) { 47 | lastEnemy = Game.time; 48 | lastEnemyTime = new Date().toLocaleTimeString('en-US', {timeZone: 'America/New_York', hour: '2-digit', minute:'2-digit'}); 49 | console.log('Pebble enemies!', numEnemies, lastEnemy, lastEnemyTime); 50 | } 51 | _.set(Memory, LAST_ENEMY_TICK, lastEnemy); 52 | _.set(Memory, LAST_ENEMY_TIME, lastEnemyTime); 53 | 54 | let enemyText = ''; 55 | let enemyColor = "#000000"; 56 | let enemyColor2 = "#000000" 57 | let enemyBlink = false; 58 | let enemyProgress = 0; 59 | 60 | if (lastEnemy + ENEMY_TICKS_ALERT >= Game.time) { 61 | enemyText = numEnemies + ' EN ' + lastEnemyTime; 62 | enemyColor = '#7F0000'; 63 | enemyColor2 = '#2F0000'; 64 | enemyBlink = false; 65 | // Progress from 80% to 20% over those ticks 66 | enemyProgress = 60 * (1.0 - (Game.time - lastEnemy) / ENEMY_TICKS_ALERT) + 20; 67 | } 68 | 69 | 70 | Memory.pebble = { 71 | vibrate: 0, 72 | 0: { progress: gclPct, bold: false, blink: false, bgColor: "#00007F", bgSecondColor: null, textColor: "#FFFFFF", textSecondColor: null, text: gclText }, 73 | 1: { progress: rclPct, bold: false, blink: false, bgColor: rclColor, bgSecondColor: null, textColor: "#FFFFFF", textSecondColor: null, text: rclText }, 74 | 2: { progress: enemyProgress, bold: false, blink: enemyBlink, bgColor: enemyColor, bgSecondColor: enemyColor2, textColor: "#FFFFFF", textSecondColor: null, text: enemyText }, 75 | // 3: { progress: 70, bold: false, blink: false, bgColor: "#0000FF", bgSecondColor: "#000066", textColor: "#CCCCCC", textSecondColor: null, text: "Bucket: 7357" }, 76 | 3: { progress: 0, bold: false, blink: false, bgColor: '#000000', bgSecondColor: null, textColor: "#CCCCCC", textSecondColor: null, text: "" }, 77 | }; 78 | } // send_to_pebble 79 | 80 | module.exports = { 81 | send_to_pebble, 82 | }; -------------------------------------------------------------------------------- /resources.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Resources Module handles determining what sort of mode we should be operating in. 4 | // 5 | // CRITICAL, LOW, NORMAL 6 | // 7 | // The mode is based upon a combination of factors, including: 8 | // Room Controller Level 9 | // Room Structures - Storage, Container 10 | // Room Sources (probably a linear relationship to other things like minimum stored energy) 11 | 12 | // Things which are expected to vary based upon the resource mode, room level, and sources: 13 | // Creep behavior (e.g., no upgrading room controller at CRITICAL) 14 | // Number of creeps of each type 15 | // Body size/configuration of creeps 16 | // Minimum level of repair for decayable things (storage, roads, ramparts) 17 | // Minimum level of repair of walls 18 | 19 | // Resource budget is complex. 20 | // 1. Income averages to 10 energy per tick per source 21 | // 2. A creep lasts 1500 ticks, 22 | // a. takes 3 ticks per body part to build (CREEP_SPAWN_TIME) 23 | // b. takes a variable energy cost per body part (BODYPART_COST) 24 | // 3. Number of structures differs at controller level (CONTROLLER_STRUCTURES, no arrays) 25 | // 26 | 27 | 28 | // Determines the number of containers that are adjacent to sources. 29 | // NOTE: THIS MUST MATCH CALCULATIONS IN role.harvester2.determine_destination()!!! 30 | function count_source_containers(room) { 31 | let room_sources = room.find(FIND_SOURCES); 32 | 33 | // Go through all sources and all nearby containers, and pick one that is not 34 | // claimed by another harvester2 for now. 35 | // TODO: Prefer to pick one at a source that isn't already claimed. 36 | let retval = 0; 37 | 38 | source_container_search: 39 | for (let source of room_sources) { 40 | let nearby_containers = 41 | source.pos.findInRange(FIND_STRUCTURES, 2, { filter: s => s.structureType == STRUCTURE_CONTAINER }); 42 | // console.log(room.name + ', source: ' + source.id + ', nearby containers: ' + nearby_containers.length); 43 | for (let nc of nearby_containers) { 44 | if (nc.pos.getRangeTo(source) >= 2.0) { 45 | // We can't say 1.999 above I don't think, in the findInRange, so double check. 46 | continue; 47 | } 48 | retval++; 49 | } // nearby_containers 50 | } // room_sources 51 | 52 | return retval; 53 | } // num_source_containers 54 | 55 | 56 | // Summarizes the situation in a room in a single object. 57 | // Room can be a string room name or an actual room object. 58 | function summarize_room_internal(room) { 59 | if (_.isString(room)) { 60 | room = Game.rooms[room]; 61 | } 62 | if (room == null) { 63 | return null; 64 | } 65 | if (room.controller == null || !room.controller.my) { 66 | // Can null even happen? 67 | return null; 68 | } 69 | const controller_level = room.controller.level; 70 | const controller_progress = room.controller.progress; 71 | const controller_needed = room.controller.progressTotal; 72 | const controller_downgrade = room.controller.ticksToDowngrade; 73 | const controller_blocked = room.controller.upgradeBlocked; 74 | const controller_safemode = room.controller.safeMode ? room.controller.safeMode : 0; 75 | const controller_safemode_avail = room.controller.safeModeAvailable; 76 | const controller_safemode_cooldown = room.controller.safeModeCooldown; 77 | const has_storage = room.storage != null; 78 | const storage_energy = room.storage ? room.storage.store[RESOURCE_ENERGY] : 0; 79 | const storage_minerals = room.storage ? _.sum(room.storage.store) - storage_energy : 0; 80 | const energy_avail = room.energyAvailable; 81 | const energy_cap = room.energyCapacityAvailable; 82 | const containers = room.find(FIND_STRUCTURES, { filter: s => s.structureType == STRUCTURE_CONTAINER }); 83 | const num_containers = containers == null ? 0 : containers.length; 84 | const container_energy = _.sum(containers, c => c.store.energy); 85 | const sources = room.find(FIND_SOURCES); 86 | const num_sources = sources == null ? 0 : sources.length; 87 | const source_energy = _.sum(sources, s => s.energy); 88 | const links = room.find(FIND_STRUCTURES, { filter: s => s.structureType == STRUCTURE_LINK && s.my }); 89 | const num_links = links == null ? 0 : links.length; 90 | const link_energy = _.sum(links, l => l.energy); 91 | const minerals = room.find(FIND_MINERALS); 92 | const mineral = minerals && minerals.length > 0 ? minerals[0] : null; 93 | const mineral_type = mineral ? mineral.mineralType : ""; 94 | const mineral_amount = mineral ? mineral.mineralAmount : 0; 95 | const extractors = room.find(FIND_STRUCTURES, { filter: s => s.structureType == STRUCTURE_EXTRACTOR }); 96 | const num_extractors = extractors.length; 97 | const creeps = _.filter(Game.creeps, c => c.pos.roomName == room.name && c.my); 98 | const num_creeps = creeps ? creeps.length : 0; 99 | const enemy_creeps = room.find(FIND_HOSTILE_CREEPS); 100 | const creep_energy = _.sum(Game.creeps, c => c.pos.roomName == room.name ? c.carry.energy : 0); 101 | const num_enemies = enemy_creeps ? enemy_creeps.length : 0; 102 | const spawns = room.find(FIND_MY_SPAWNS); 103 | const num_spawns = spawns ? spawns.length : 0; 104 | const spawns_spawning = _.sum(spawns, s => s.spawning ? 1 : 0); 105 | const towers = room.find(FIND_STRUCTURES, { filter: s => s.structureType == STRUCTURE_TOWER && s.my }); 106 | const num_towers = towers ? towers.length : 0; 107 | const tower_energy = _.sum(towers, t => t.energy); 108 | const const_sites = room.find(FIND_CONSTRUCTION_SITES); 109 | const my_const_sites = room.find(FIND_CONSTRUCTION_SITES, { filter: cs => cs.my }); 110 | const num_construction_sites = const_sites.length; 111 | const num_my_construction_sites = my_const_sites.length; 112 | const num_source_containers = count_source_containers(room); 113 | const has_terminal = room.terminal != null; 114 | const terminal_energy = room.terminal ? room.terminal.store[RESOURCE_ENERGY] : 0; 115 | const terminal_minerals = room.terminal ? _.sum(room.terminal.store) - terminal_energy : 0; 116 | 117 | // Get info on all our structures 118 | // TODO: Split roads to those on swamps vs those on dirt 119 | const structure_types = new Set(room.find(FIND_STRUCTURES).map(s => s.structureType)); 120 | const structure_info = {}; 121 | for (const s of structure_types) { 122 | const ss = room.find(FIND_STRUCTURES, {filter: str => str.structureType == s}); 123 | structure_info[s] = { 124 | count: ss.length, 125 | min_hits: _.min(ss, 'hits').hits, 126 | max_hits: _.max(ss, 'hits').hits, 127 | }; 128 | } 129 | // console.log(JSON.stringify(structure_info)); 130 | 131 | const ground_resources = room.find(FIND_DROPPED_RESOURCES); 132 | // const ground_resources_short = ground_resources.map(r => ({ amount: r.amount, resourceType: r.resourceType })); 133 | const reduced_resources = _.reduce(ground_resources, (acc, res) => { acc[res.resourceType] = _.get(acc, [res.resourceType], 0) + res.amount; return acc; }, {}); 134 | 135 | // _.reduce([{resourceType: 'energy', amount: 200},{resourceType: 'energy', amount:20}], (acc, res) => { acc[res.resourceType] = _.get(acc, [res.resourceType], 0) + res.amount; return acc; }, {}); 136 | 137 | // console.log(JSON.stringify(reduced_resources)); 138 | 139 | // Number of each kind of creeps 140 | // const creep_types = new Set(creeps.map(c => c.memory.role)); 141 | const creep_counts = _.countBy(creeps, c => c.memory.role); 142 | 143 | // Other things we can count: 144 | // Tower count, energy 145 | // Minimum health of ramparts, walls 146 | // Minimum health of roads 147 | // Number of roads? 148 | // Resources (energy/minerals) on the ground? 149 | 150 | // Other things we can't count but we _can_ track manually: 151 | // Energy spent on repairs 152 | // Energy spent on making creeps 153 | // Energy lost to links 154 | // 155 | // Energy in a source when it resets (wasted/lost energy) 156 | 157 | let retval = { 158 | room_name: room.name, // In case this gets taken out of context 159 | controller_level, 160 | controller_progress, 161 | controller_needed, 162 | controller_downgrade, 163 | controller_blocked, 164 | controller_safemode, 165 | controller_safemode_avail, 166 | controller_safemode_cooldown, 167 | energy_avail, 168 | energy_cap, 169 | num_sources, 170 | source_energy, 171 | mineral_type, 172 | mineral_amount, 173 | num_extractors, 174 | has_storage, 175 | storage_energy, 176 | storage_minerals, 177 | has_terminal, 178 | terminal_energy, 179 | terminal_minerals, 180 | num_containers, 181 | container_energy, 182 | num_links, 183 | link_energy, 184 | num_creeps, 185 | creep_counts, 186 | creep_energy, 187 | num_enemies, 188 | num_spawns, 189 | spawns_spawning, 190 | num_towers, 191 | tower_energy, 192 | structure_info, 193 | num_construction_sites, 194 | num_my_construction_sites, 195 | ground_resources: reduced_resources, 196 | num_source_containers, 197 | }; 198 | 199 | // console.log('Room ' + room.name + ': ' + JSON.stringify(retval)); 200 | return retval; 201 | } // summarize_room 202 | 203 | function summarize_rooms() { 204 | const now = Game.time; 205 | 206 | // First check if we cached it 207 | if (global.summarized_room_timestamp == now) { 208 | return global.summarized_rooms; 209 | } 210 | 211 | let retval = {}; 212 | 213 | for (let r in Game.rooms) { 214 | let summary = summarize_room_internal(Game.rooms[r]); 215 | retval[r] = summary; 216 | } 217 | 218 | global.summarized_room_timestamp = now; 219 | global.summarized_rooms = retval; 220 | 221 | // console.log('All rooms: ' + JSON.stringify(retval)); 222 | return retval; 223 | } // summarize_rooms 224 | 225 | function summarize_room(room) { 226 | if (_.isString(room)) { 227 | room = Game.rooms[room]; 228 | } 229 | if (room == null) { 230 | return null; 231 | } 232 | 233 | const sr = summarize_rooms(); 234 | 235 | return sr[room.name]; 236 | } 237 | 238 | module.exports = { 239 | summarize_room, 240 | summarize_rooms, 241 | }; 242 | -------------------------------------------------------------------------------- /screepsplus.js: -------------------------------------------------------------------------------- 1 | // Module to format data in memory for use with the https://screepspl.us 2 | // Grafana utility run by ags131. 3 | // 4 | // Installation: Run a node script from https://github.com/ScreepsPlus/node-agent 5 | // and configure your screepspl.us token and Screeps login (if you use Steam, 6 | // you have to create a password on the Profile page in Screeps), 7 | // then run that in the background (e.g., on Linode, AWS, your always-on Mac). 8 | // 9 | // Then, put whatever you want in Memory.stats, which will be collected every 10 | // 15 seconds (yes, not every tick) by the above script and sent to screepspl.us. 11 | // In this case, I call the collect_stats() routine below at the end of every 12 | // trip through the main loop, with the absolute final call at the end of the 13 | // main loop to update the final CPU usage. 14 | // 15 | // Then, configure a Grafana page (see example code) which graphs stuff whichever 16 | // way you like. 17 | // 18 | // This module uses my resources module, which analyzes the state of affairs 19 | // for every room you can see. 20 | 21 | 22 | "use strict"; 23 | const resources = require('resources'); 24 | const cb = require('callback'); 25 | 26 | global.stats_callbacks = new cb.Callback(); 27 | 28 | // Tell us that you want a callback when we're collecting the stats. 29 | // We will send you in the partially completed stats object. 30 | function add_stats_callback(cbfunc) { 31 | global.stats_callbacks.subscribe(cbfunc); 32 | } 33 | 34 | 35 | // Update the Memory.stats with useful information for trend analysis and graphing. 36 | // Also calls all registered stats callback functions before returning. 37 | function collect_stats() { 38 | 39 | // Don't overwrite things if other modules are putting stuff into Memory.stats 40 | if (Memory.stats == null) { 41 | Memory.stats = { tick: Game.time }; 42 | } 43 | 44 | // Note: This is fragile and will change if the Game.cpu API changes 45 | Memory.stats.cpu = Game.cpu; 46 | // Memory.stats.cpu.used = Game.cpu.getUsed(); // AT END OF MAIN LOOP 47 | 48 | // Note: This is fragile and will change if the Game.gcl API changes 49 | Memory.stats.gcl = Game.gcl; 50 | 51 | const memory_used = RawMemory.get().length; 52 | // console.log('Memory used: ' + memory_used); 53 | Memory.stats.memory = { 54 | used: memory_used, 55 | // Other memory stats here? 56 | }; 57 | 58 | Memory.stats.market = { 59 | credits: Game.market.credits, 60 | num_orders: Game.market.orders ? Object.keys(Game.market.orders).length : 0, 61 | }; 62 | 63 | Memory.stats.roomSummary = resources.summarize_rooms(); 64 | 65 | // Add callback functions which we can call to add additional 66 | // statistics to here, and have a way to register them. 67 | // 1. Merge in the current repair ratchets into the room summary 68 | // TODO: Merge in the current creep desired numbers into the room summary 69 | global.stats_callbacks.fire(Memory.stats); 70 | } // collect_stats 71 | 72 | module.exports = { 73 | collect_stats, 74 | add_stats_callback, 75 | }; 76 | --------------------------------------------------------------------------------