TooAngel/screeps

View on GitHub
src/visualizer.js

Summary

Maintainability
D
2 days
Test Coverage
'use strict';
global.visualizer = {

  drawPosition(rv, position, text, color) {
    rv.text(text, position.x, position.y + 0.2, {
      color: color,
      font: 0.7,
      opacity: 0.5,
    });
  },

  drawPath(rv, path, color) {
    if (path.length) {
      rv.poly(path.map((p) => [p.x, p.y]), {
        stroke: color,
        strokeWidth: 0.1,
        opacity: 0.5,
      });
    }
  },

  /**
   * draw fixed paths in room
   */
  showRoomPaths() {
    for (const room of _.values(Game.rooms)) {
      const rv = room.visual;
      const paths = room.getMemoryPaths();
      for (const route of _.values(paths)) {
        this.drawPath(rv, route.path, 'white');
      }
    }
  },

  /**
   * draw creep paths from using moveTo
   */
  showCreepPaths() {
    for (const creep of _.values(Game.creeps)) {
      const rv = creep.room.visual;
      if (creep.memory._move) {
        const path = Room.deserializePath(creep.memory._move.path);
        this.drawPath(rv, path, 'red');
      }
    }
  },

  /**
   * draw structures
   */
  showStructures() {
    for (const room of _.values(Game.rooms)) {
      if (!room.isMy()) {
        continue;
      }
      const rv = room.visual;
      if (room.memory.position && room.memory.position.structure) {
        const structures = room.memory.position.structure;
        for (const structType of Object.keys(structures)) {
          const text = structType.substr(0, 1).toUpperCase() + structType.substr(1, 1);
          for (const structure of structures[structType]) {
            if (!structure) {
              continue;
            }
            this.drawPosition(rv, structure, text, 'blue');
          }
        }
      }
    }
  },

  showBlockers() {
    for (const room of _.values(Game.rooms)) {
      if (!room.isMy()) {
        continue;
      }
      const rv = room.visual;
      if (room.memory.walls && room.memory.walls.layer) {
        for (const layer of Object.keys(room.memory.walls.layer)) {
          for (const pos of room.memory.walls.layer[layer]) {
            this.drawPosition(rv, pos, layer, 'blue');
            rv.rect(pos.x - 0.5, pos.y - 0.5, 1, 1, {
              fill: 'transparent',
              stroke: 'blue',
            });
          }
        }
      }
      if (room.memory.walls && room.memory.walls.ramparts) {
        for (const pos of room.memory.walls.ramparts) {
          rv.circle(pos, {
            radius: 0.5,
            fill: 'transparent',
            stroke: 'blue',
          });
        }
      }
    }
  },

  /**
   * draw creep positions
   */
  showCreeps() {
    for (const room of _.values(Game.rooms)) {
      if (!room.isMy()) {
        continue;
      }
      const rv = room.visual;
      if (room.memory.position) {
        const creeps = room.memory.position.creep;
        for (const positionName of Object.keys(creeps)) {
          let text = positionName.substr(0, 1);
          const target = Game.getObjectById(positionName);
          if (target) {
            if (target.structureType) {
              text = target.structureType.substr(0, 1);
            } else {
              text = 's'; // source
            }
          }
          for (const creep of creeps[positionName]) {
            if (creep) {
              this.drawPosition(rv, creep, text, 'yellow');
            }
          }
        }
      }
    }
  },

  showCostMatrix(roomName, costMatrixCallback) {
    const rv = new RoomVisual(roomName);
    const cm = costMatrixCallback(roomName);
    if (cm) {
      for (let x = 0; x < 50; ++x) {
        for (let y = 0; y < 50; ++y) {
          let fill = '#00FF00';
          const value = cm.get(x, y);
          const calculated = Math.min(255, 5 * value);
          if (config.visualizer.showCostMatrixValues) {
            this.drawPosition(rv, new RoomPosition(x, y, roomName), value, 'blue');
          }

          if (value) {
            fill = `#${(0.8 * calculated).toString(16)}0A0A`;
          }
          let opacity = 0;
          if (value > 0) {
            opacity = 0.15 + 0.3 * (calculated / 255);
          }
          rv.rect(x - 0.5, y - 0.5, 1, 1, {
            fill: fill,
            opacity: opacity,
          });
        }
      }
    }
  },

  showCostMatrices() {
    for (const room of _.values(Game.rooms)) {
      if (!room.isMy()) {
        continue;
      }
      if (room.isMy()) {
        this.showCostMatrix(room.name, room.getCostMatrixCallback());
      }
    }
  },

  showSearch(search) {
    if (search) {
      const rv = {};
      const getRV = (pos) => {
        if (!rv[pos.roomName]) {
          rv[pos.roomName] = new RoomVisual(pos.roomName);
        }
        return rv[pos.roomName];
      };
      let prevPos = search.path[0];
      const style = {
        color: search.incomplete ? 'red' : 'green',
      };
      for (const pi of search.path) {
        if (prevPos.roomName === pi.roomName) {
          getRV(pi).line(prevPos, pi, style);
        } else {
          const dx = prevPos.x === 0 ? -0.5 : prevPos.x === 49 ? 0.5 : 0;
          const dy = prevPos.y === 0 ? -0.5 : prevPos.y === 49 ? 0.5 : 0;
          getRV(prevPos).line(prevPos.x, prevPos.y, prevPos.x + dx, prevPos.y + dy, style);
          getRV(pi).line(pi.x, pi.y, pi.x - dx, pi.y - dy, style);
        }
        prevPos = pi;
      }
    }
  },

  render() {
    if (config.visualizer.showCostMatrices) {
      this.showCostMatrices();
    }
    if (config.visualizer.showRoomPaths) {
      this.showRoomPaths();
    }
    if (config.visualizer.showCreepPaths) {
      this.showCreepPaths();
    }
    if (config.visualizer.showStructures) {
      this.showStructures();
    }
    if (config.visualizer.showCreeps) {
      this.showCreeps();
    }
    if (config.visualizer.showBlockers) {
      this.showBlockers();
    }
  },
};

const getLines = function(room) {
  if (!room.controller) {
    return [];
  }
  const energy = (room.memory.energyStats && Math.floor(room.memory.energyStats.average)) ||
    room.energyAvailable;
  const storedE = room.storage ? room.storage.store[RESOURCE_ENERGY] : 0;
  const queueL = room.memory.queue ? room.memory.queue.length : 0;
  const rclP = Math.floor(100 * (room.controller.progressTotal ? room.controller.progress / room.controller.progressTotal : 1));

  const lines = [
    {label: `Energy Average :`, value: energy, coefficient: energy / room.energyCapacityAvailable},
    {label: `Stored Energy :`, value: storedE, coefficient: Math.min(storedE, 500000) / 500000},
    {label: `Queue length :`, value: queueL, coefficient: (20 - Math.min(queueL, 20)) / 20},
    {label: `RCL ${room.controller.level} progress :`, value: rclP, coefficient: rclP / 100},
  ];
  return lines;
};

global.visualizer.myRoomDataDraw = function(roomName) {
  const room = Game.rooms[roomName];
  const lines = getLines(room);

  const fontSize = 0.65;
  const color = (coefficient) => `rgb(${Math.floor(-(coefficient - 1) * 255)},${Math.floor(coefficient * 255)},0)`;

  let y = 0;
  let line;
  for (line of lines) {
    room.visual.text(line.label, 0.5, 0.75 + 2 * y * fontSize, {
      color: 'rgb(255,255,255)',
      font: fontSize,
      align: 'left',
    });
    if (line.value !== undefined) {
      room.visual.text(`${line.value}`, 6, 1.5 * fontSize + 2 * y * fontSize, {
        color: color(line.coefficient),
        font: fontSize * 2,
        align: 'left',
      });
    }
    y++;
  }
};