'use strict'

class City extends kernel.process {
  constructor (...args) {
    super(...args)
    this.priority = PRIORITIES_CITY
  }

  getDescriptor () {
    return this.data.room
  }

  main () {
    if (!Game.rooms[this.data.room] || !Game.rooms[this.data.room].controller.my) {
      Room.removeCity(this.data.room)
      return this.suicide()
    }
    this.room = Game.rooms[this.data.room]

    // Detect when room level changes and clear spawnqueue.
    if (!this.data.prl) {
      this.data.prl = this.room.getPracticalRoomLevel()
    }
    const roomLevel = this.room.getPracticalRoomLevel()
    if (this.data.prl !== roomLevel) {
      qlib.send(`${this.data.room} has changed from PRL${this.data.prl} to PRL${roomLevel}`)
      this.data.prl = roomLevel
      this.room.clearSpawnQueue()
    }

    // Notify of room level changes
    if (!this.data.level) {
      this.data.level = this.room.controller.level
    }
    if (this.data.level !== this.room.controller.level) {
      qlib.send(`${this.data.room} has changed from level ${this.data.level} to level ${this.room.controller.level}`)
    }

    const spawns = this.room.find(FIND_MY_SPAWNS)
    if (spawns.length <= 0) {
      this.launchChildProcess('gethelp', 'empire_expand', {
        'colony': this.data.room,
        'recover': true
      })
      return
    }

    this.launchChildProcess('spawns', 'spawns', {
      'room': this.data.room
    })
    this.launchChildProcess('defense', 'city_defense', {
      'room': this.data.room
    })
    this.launchChildProcess('reboot', 'city_reboot', {
      'room': this.data.room
    })

    // If the room isn't planned launch the room layout program, otherwise launch construction program
    if (!this.room.getLayout().isPlanned()) {
      this.launchChildProcess('layout', 'city_layout', {
        'room': this.data.room
      })
    } else {
      this.launchChildProcess('construct', 'city_construct', {
        'room': this.data.room
      })
      this.launchChildProcess('fortify', 'city_fortify', {
        'room': this.data.room
      })
    }

    // Launch fillers
    let options = {
      'priority': 3
    }
    if (this.room.getRoomSetting('PURE_CARRY_FILLERS')) {
      options['carry_only'] = true
      options['energy'] = Math.max(Math.min(1600, this.room.energyCapacityAvailable / 2), 400)
    }
    const fillerQuantity = this.room.getRoomSetting('ADDITIONAL_FILLERS') ? 4 : 2
    this.launchCreepProcess('fillers', 'filler', this.data.room, fillerQuantity, options)

    // Launch mining if all level 2 extensions are build.
    if (this.room.energyCapacityAvailable > 500) {
      this.launchChildProcess('mining', 'city_mine', {
        'room': this.data.room
      })
    }

    const mineCount = this.room.getRoomSetting('REMOTE_MINES')
    const lastAdd = qlib.events.getTimeSinceEvent('addmine')
    if (mineCount && lastAdd >= 2000) {
      let remoteMines = this.room.getMines()
      if (remoteMines.length < mineCount) {
        const cpuUsage = sos.lib.monitor.getPriorityRunStats(PRIORITIES_CREEP_DEFAULT)
        if (cpuUsage && cpuUsage['long'] <= 1.25) {
          const mine = this.room.selectNextMine()
          if (mine) {
            this.room.addMine(mine)
            remoteMines = this.room.getMines()
          }
        }
      }

      let mineRoomName
      for (mineRoomName of remoteMines) {
        this.launchChildProcess(`mine_${mineRoomName}`, 'city_mine', {
          'room': this.data.room,
          'mine': mineRoomName
        })
      }
    }

    // Launch mineral extraction
    if (this.room.isEconomyCapable('EXTRACT_MINERALS') && this.room.getRoomSetting('EXTRACT_MINERALS')) {
      // Note that once the program starts it won't stop until the minerals are mined out regardless of economic
      // conditions.
      const mineral = this.room.find(FIND_MINERALS)[0]
      if (mineral.mineralAmount > 0 && !mineral.ticksToRegeneration) {
        this.launchChildProcess('extraction', 'city_extract', {
          'room': this.data.room
        })
      }
    }

    // Launch upgraders
    if (this.room.isEconomyCapable('UPGRADE_CONTROLLERS')) {
      let upgraderQuantity = this.room.getRoomSetting('UPGRADERS_QUANTITY')
      // If the room is not done being built up reduce the upgraders.
      if (this.room.controller.level > this.room.getPracticalRoomLevel()) {
        upgraderQuantity = 0
      }
      if (this.room.isEconomyCapable('EXTRA_UPGRADERS')) {
        upgraderQuantity += 2
      }
      if (this.room.isEconomyCapable('MORE_EXTRA_UPGRADERS')) {
        upgraderQuantity += 2
      }
      if (this.room.controller.level >= 8) {
        upgraderQuantity = 1
      }
      this.launchCreepProcess('upgraders', 'upgrader', this.data.room, upgraderQuantity, {
        'priority': 5
      })
    }
    if (this.room.controller.isTimingOut()) {
      this.launchCreepProcess('eupgrader', 'upgrader', this.data.room, 1, {
        priority: 1,
        energy: 200
      })
    }

    // Launch scouts to map out neighboring rooms
    if (this.room.getRoomSetting('SCOUTS')) {
      this.launchCreepProcess('scouts', 'spook', this.data.room, 1, {
        'priority': 4
      })
    }
  }
}

module.exports = City

@@ -639,32 +639,39 @@
 l) %7B%0A      qlib.
+notify.
 send(%60$%7Bthis.dat
@@ -999,16 +999,23 @@
    qlib.
+notify.
 send(%60$%7B

Fixed notifications in city program