DEFENSE · TOWER REPAIR RESERVE

How to Repair Structures with Towers Without Spending Defense Energy

Run Tower repair only after attack and healing are clear, preserve a configurable Energy reserve plus TOWER_ENERGY_COST, exclude Walls and Ramparts, rank ordinary structures by hit ratio and range, save repair() results, and verify later hits.

Verification statusChinese source article: Reviewed in full · Official docs: Checked — StructureTower.repair(), whole-room range, falloff, TOWER_ENERGY_COST and return codes · Policy boundary: The hit-ratio threshold, Energy reserve, action order and excluded structure classes are project policies

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official docs
Checked — StructureTower.repair(), whole-room range, falloff, TOWER_ENERGY_COST and return codes
Policy boundary
The hit-ratio threshold, Energy reserve, action order and excluded structure classes are project policies
Execution boundary
OK schedules repair; structure hits and actual range-adjusted effect require later observation
JavaScript syntax
Passed
Offline repair review
Passed — combat gate, injury gate, reserve plus action cost, Wall and Rampart exclusion, ratio, range and stable ties
Screeps Console test
Pending
Live Tower repair, falloff, power effect, over-repair and reserve test
Pending
Last verified
July 26, 2026

Quick answer

Do not repair while an attack target or injured owned Creep needs the Tower. Require an owned active Tower with at least repairReserve + TOWER_ENERGY_COST Energy, filter ordinary damaged structures below a documented hit-ratio threshold, exclude Walls and Ramparts, select the lowest ratio then nearest range and stable ID, call tower.repair(target), and verify structure hits later.

Run repair after attack and healing

The Tower API does not build a defense priority for you. Use one dispatcher that makes the order explicit:

function chooseTowerAction(input) {
  if (input.attackTarget) {
    return 'attack';
  }

  if (input.healTarget) {
    return 'heal';
  }

  if (input.repairTarget) {
    return 'repair';
  }

  return 'idle';
}

This guide treats attack before heal before repair as a project policy. A room may choose a different emergency order, but multiple independent modules should not silently compete for the same Tower.

Use hit ratio for ordinary structures

A fixed hit number has different meaning for Roads, Extensions, Spawns and Storage. A ratio makes the baseline comparable:

function getStructureHitRatio(structure) {
  if (
    !structure
    || !Number.isFinite(structure.hits)
    || !Number.isFinite(structure.hitsMax)
    || structure.hitsMax <= 0
  ) {
    return null;
  }

  return structure.hits / structure.hitsMax;
}
const TOWER_REPAIR_RATIO_LIMIT = 0.8;

The value 0.8 is an example room policy, not an official recommendation. Repairs may be postponed or raised depending on defense risk and Energy income.

Protect reserve plus action cost

const TOWER_REPAIR_ENERGY_RESERVE = 500;

function towerCanSpendOnRepair(tower, reserve) {
  const energy = tower.store.getUsedCapacity(
    RESOURCE_ENERGY
  );

  return tower.isActive() === true
    && energy >= reserve + TOWER_ENERGY_COST;
}

Checking only energy >= reserve permits one repair action to cross the intended floor. The reserve itself is a policy and should reflect expected attacks and refill time.

Select a deterministic repair target

function selectTowerRepairTarget(
  towers,
  structures,
  ratioLimit
) {
  const candidates = structures.filter(structure => {
    const ratio = getStructureHitRatio(structure);

    return Number.isFinite(ratio)
      && structure.hits < structure.hitsMax
      && ratio < ratioLimit
      && structure.structureType !== STRUCTURE_WALL
      && structure.structureType !== STRUCTURE_RAMPART;
  });

  if (towers.length === 0 || candidates.length === 0) {
    return null;
  }

  return [...candidates].sort((left, right) => {
    const ratioDifference =
      getStructureHitRatio(left)
      - getStructureHitRatio(right);

    if (ratioDifference !== 0) {
      return ratioDifference;
    }

    const leftRange = Math.min(
      ...towers.map(tower =>
        tower.pos.getRangeTo(left)
      )
    );
    const rightRange = Math.min(
      ...towers.map(tower =>
        tower.pos.getRangeTo(right)
      )
    );

    if (leftRange !== rightRange) {
      return leftRange - rightRange;
    }

    return left.id.localeCompare(right.id);
  })[0] || null;
}

This version prioritizes damage ratio before range and does not assign extra business value to a Spawn over a Road. Add structure importance only as a documented room policy.

Complete Tower repair example

function runTowerRepair(room, options = {}) {
  if (!room) {
    return { status: 'room-not-visible' };
  }

  const attackTarget = room.find(
    FIND_HOSTILE_CREEPS
  )[0] || null;
  if (attackTarget) {
    return { status: 'attack-priority' };
  }

  const healTarget = room.find(FIND_MY_CREEPS, {
    filter: creep =>
      creep.hits > 0
      && creep.hits < creep.hitsMax
  })[0] || null;
  if (healTarget) {
    return { status: 'heal-priority' };
  }

  const reserve = Number.isFinite(options.reserve)
    ? Math.max(0, options.reserve)
    : TOWER_REPAIR_ENERGY_RESERVE;
  const ratioLimit = Number.isFinite(options.ratioLimit)
    ? Math.max(0, Math.min(1, options.ratioLimit))
    : TOWER_REPAIR_RATIO_LIMIT;
  const towers = room.find(FIND_MY_STRUCTURES, {
    filter: structure =>
      structure.structureType === STRUCTURE_TOWER
      && towerCanSpendOnRepair(structure, reserve)
  });

  if (towers.length === 0) {
    return { status: 'repair-energy-protected' };
  }

  const target = selectTowerRepairTarget(
    towers,
    room.find(FIND_STRUCTURES),
    ratioLimit
  );
  if (!target) {
    return { status: 'no-repair-target' };
  }

  const snapshot = {
    gameTick: Game.time,
    targetId: target.id,
    structureType: target.structureType,
    hits: target.hits,
    hitsMax: target.hitsMax,
    hitRatio: getStructureHitRatio(target),
    ratioLimit,
    reserve
  };
  const results = towers.map(tower => ({
    towerId: tower.id,
    range: tower.pos.getRangeTo(target),
    energyBefore: tower.store.getUsedCapacity(
      RESOURCE_ENERGY
    ),
    result: tower.repair(target)
  }));

  return {
    status: results.some(item => item.result === OK)
      ? 'repair-scheduled'
      : 'repair-rejected',
    snapshot,
    results
  };
}
module.exports.loop = function () {
  const room = Game.rooms.W1N1;
  if (!room) {
    return;
  }

  const outcome = runTowerRepair(room, {
    ratioLimit: TOWER_REPAIR_RATIO_LIMIT,
    reserve: TOWER_REPAIR_ENERGY_RESERVE
  });

  if (
    outcome.status === 'repair-rejected'
    || Game.time % 100 === 0
  ) {
    console.log(JSON.stringify({
      type: 'tower-repair-status',
      roomName: room.name,
      ...outcome
    }));
  }
};

Keep Walls and Ramparts separate

Walls and Ramparts often use absolute target bands, emergency minimums and escalating budgets rather than an ordinary structure ratio. They are excluded here so an almost empty fortification does not permanently consume every idle Tower action.

function isOrdinaryRepairTarget(structure) {
  return structure.structureType !== STRUCTURE_WALL
    && structure.structureType !== STRUCTURE_RAMPART;
}

Understand multi-Tower over-repair

All Towers in this baseline target one structure. That can exceed its missing hits. A production allocator should estimate range-adjusted repair, active Tower power effects, assigned repair and remaining need before allocating another Tower.

Verify repair later

Recover the structure by ID and compare hits with the saved snapshot. Other Creeps or Towers can also repair it, and damage can occur in the same period, so the net hit delta is not perfect attribution.

Handle return codes

CodeMeaningReview
OKRepair scheduledStructure hits later
ERR_NOT_OWNERTower not yoursSelection and ownership
ERR_NOT_ENOUGH_ENERGYInsufficient EnergyReserve, cost and competing actions
ERR_INVALID_TARGETStructure invalidRefresh current target
ERR_RCL_NOT_ENOUGHTower inactiveRCL and isActive()

Debugging checklist

  • Exit when an attack target exists.
  • Exit when an injured owned Creep exists.
  • Use one Tower action dispatcher.
  • Require reserve plus TOWER_ENERGY_COST.
  • Document the ratio threshold.
  • Exclude Walls and Ramparts.
  • Use stable ratio, range and ID ordering.
  • Save every repair return code.
  • Watch for over-repair.
  • Verify net hits later.

Scope and next steps

This guide does not maintain Walls or Ramparts, predict exact repair output, model Tower power effects, assign structure business values, coordinate haulers or prevent over-repair. Return to the English article library for construction and defense topics.

Frequently asked questions

Why not use one fixed hit threshold?

Ordinary structures have different maximum hits, so one number can represent minor Road damage but severe Spawn damage.

Can Tower repair return ERR_NOT_IN_RANGE?

No. Towers act across their room; distance changes effect rather than producing that range error.

Should every idle Tower repair?

Only according to your room budget. A defense reserve can be more valuable than repairing minor damage immediately.

Official documentation

SOURCE AND SCOPE

Review the source, evidence, or next system

This English guide is rewritten for a focused search intent while preserving the technical scope and verification boundaries of its Chinese source. Live-room evidence is claimed only when the verification record says it exists.