DEFENSE · STAGED FORTIFICATION REPAIR

How to Repair Fortifications to a Room-Specific Stage Instead of hitsMax

Configure a room-specific absolute hits limit, select the weakest Wall or Rampart below both the limit and hitsMax, require Creep Energy and active WORK, use range 3, save repair() and movement results, and raise stages only through a separate reviewed policy.

Verification statusChinese source article: Reviewed in full · Official docs: Checked — StructureWall, StructureRampart, Creep.repair(), repair range, active WORK and return codes · Policy boundary: The hits limit, weakest-first order, Energy policy and stage changes are room strategies, not official safety values

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official docs
Checked — StructureWall, StructureRampart, Creep.repair(), repair range, active WORK and return codes
Policy boundary
The hits limit, weakest-first order, Energy policy and stage changes are room strategies, not official safety values
Execution boundary
OK schedules repair; hits, Store and boosted repair output require later observation
JavaScript syntax
Passed
Offline repair review
Passed — invalid limit, structure filtering, current hits, distance ties, Creep Energy, active WORK and range states
Screeps Console test
Pending
Live repair, boosts, pathing, stage completion, RCL hitsMax and multi-repairer test
Pending
Last verified
July 26, 2026

Quick answer

Store an explicit positive hitsLimit for each room. Select only Walls and Ramparts whose current hits are below both that limit and their current hitsMax. Order candidates by lowest hits, then range and stable ID. Require a non-spawning owned Creep with Energy and at least one active WORK part, call repair(), move to range 3 only on ERR_NOT_IN_RANGE, save every result, and stop when no target remains below the current stage.

Do not repair every fortification to hitsMax

const unsafeCandidates = room.find(FIND_STRUCTURES, {
  filter: structure =>
    structure.hits < structure.hitsMax
});

Walls and Ramparts can remain below their maximum for a very long time. A generic damaged-structure filter can make them absorb most repair Energy and crowd out upgrading, construction, ordinary maintenance and reserves.

Make the hits limit room-specific

Memory.defenseRepair ??= {};
Memory.defenseRepair.W1N1 = {
  enabled: true,
  hitsLimit: 100000
};

The number is an example, not an official defense standard. Different rooms need different stages based on RCL, Energy income, Storage reserves, threat frequency, Tower coverage, repairer count and the value protected by each Rampart.

function readDefenseRepairConfig(roomName) {
  const config = Memory.defenseRepair?.[roomName];

  if (
    !config
    || config.enabled !== true
    || !Number.isFinite(config.hitsLimit)
    || config.hitsLimit <= 0
  ) {
    return {
      enabled: false,
      hitsLimit: null
    };
  }

  return {
    enabled: true,
    hitsLimit: config.hitsLimit
  };
}

Select the weakest eligible target

function selectDefenseRepairTarget(
  creep,
  structures,
  hitsLimit
) {
  if (!Number.isFinite(hitsLimit) || hitsLimit <= 0) {
    return null;
  }

  const candidates = structures.filter(structure =>
    (
      structure.structureType === STRUCTURE_WALL
      || structure.structureType === STRUCTURE_RAMPART
    )
    && Number.isFinite(structure.hits)
    && Number.isFinite(structure.hitsMax)
    && structure.hits < structure.hitsMax
    && structure.hits < hitsLimit
  );

  return [...candidates].sort((left, right) => {
    if (left.hits !== right.hits) {
      return left.hits - right.hits;
    }

    const rangeDifference =
      creep.pos.getRangeTo(left)
      - creep.pos.getRangeTo(right);

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

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

Weakest-first evens out obvious thin points. It is not a complete fortification-value model: a Rampart over a Spawn and an outer Wall can have different strategic importance.

Require Energy and active WORK

function inspectRepairCreep(creep) {
  if (!creep || creep.my !== true) {
    return { ready: false, reason: 'creep-missing' };
  }

  if (creep.spawning === true) {
    return { ready: false, reason: 'creep-spawning' };
  }

  const energy = creep.store.getUsedCapacity(
    RESOURCE_ENERGY
  );
  const activeWork = creep.getActiveBodyparts(WORK);

  if (energy <= 0) {
    return { ready: false, reason: 'energy-empty' };
  }

  if (activeWork <= 0) {
    return { ready: false, reason: 'no-active-work' };
  }

  return {
    ready: true,
    reason: 'ready',
    energy,
    activeWork
  };
}

A WORK part in the original body is not enough after damage. Use current active parts.

Complete staged repair example

function runDefenseRepair(room, creep) {
  if (!room || !creep || creep.room.name !== room.name) {
    return { status: 'room-or-creep-unavailable' };
  }

  const config = readDefenseRepairConfig(room.name);
  if (!config.enabled) {
    return { status: 'repair-disabled' };
  }

  const creepState = inspectRepairCreep(creep);
  if (!creepState.ready) {
    return { status: creepState.reason };
  }

  const target = selectDefenseRepairTarget(
    creep,
    room.find(FIND_STRUCTURES),
    config.hitsLimit
  );

  if (!target) {
    return {
      status: 'stage-complete',
      hitsLimit: config.hitsLimit
    };
  }

  const before = {
    gameTick: Game.time,
    targetId: target.id,
    targetType: target.structureType,
    targetHits: target.hits,
    targetHitsMax: target.hitsMax,
    hitsLimit: config.hitsLimit,
    range: creep.pos.getRangeTo(target),
    creepEnergy: creepState.energy,
    activeWork: creepState.activeWork
  };
  const result = creep.repair(target);

  if (result === ERR_NOT_IN_RANGE) {
    const moveResult = creep.moveTo(target, {
      reusePath: 5,
      range: 3
    });

    return {
      status: 'moving-to-target',
      result,
      moveResult,
      before
    };
  }

  return {
    status: result === OK
      ? 'repair-scheduled'
      : 'repair-rejected',
    result,
    before
  };
}
module.exports.loop = function () {
  const room = Game.rooms.W1N1;
  const creep = Game.creeps.Repairer1;
  const outcome = runDefenseRepair(room, creep);

  if (
    outcome.status === 'repair-rejected'
    || outcome.status === 'stage-complete'
    || Game.time % 100 === 0
  ) {
    console.log(JSON.stringify({
      type: 'fortification-repair-status',
      roomName: room?.name || null,
      creepName: creep?.name || null,
      ...outcome
    }));
  }
};

Move to repair range 3

const moveResult = creep.moveTo(target, {
  range: 3,
  reusePath: 5
});

Roads, traffic and obstacles can still make movement fail, so preserve the movement result instead of assuming the Creep arrived.

Stop at the current stage

The selector requires both structure.hits < hitsLimit and structure.hits < structure.hitsMax. If the configured limit exceeds a current maximum, fully repaired Structures still leave the candidate list.

function isBelowDefenseStage(structure, hitsLimit) {
  return Number.isFinite(hitsLimit)
    && hitsLimit > 0
    && structure.hits < hitsLimit
    && structure.hits < structure.hitsMax;
}

Raise the stage separately

Do not increment the limit merely because this tick has no target. A separate policy can require all current targets to meet the stage, Storage Energy above a reserve, no active battle, non-urgent Controller work, and explicit configuration approval.

function mayReviewNextDefenseStage(input) {
  return Boolean(
    input.currentStageComplete
    && input.storageEnergy >= input.storageReserve
    && input.hostileCount === 0
    && input.playerApproved
  );
}

This returns permission to review a change, not a new automatic limit.

Verify later state

function inspectRepairResult(before) {
  const target = Game.getObjectById(before.targetId);

  return target
    ? {
        targetFound: true,
        hitsBefore: before.targetHits,
        hitsNow: target.hits,
        hitsLimit: before.hitsLimit
      }
    : {
        targetFound: false,
        hitsBefore: before.targetHits,
        hitsLimit: before.hitsLimit
      };
}

Other Creeps, Towers, damage and boosts can affect the observed hit delta, so do not attribute the entire change to one action without more evidence.

Handle return codes

CodeTypical causeResponse
OKRepair scheduledRe-read hits later
ERR_NOT_OWNERCreep not yoursCurrent Creep ownership
ERR_BUSYCreep spawningWait
ERR_NOT_ENOUGH_RESOURCESNo EnergySupply chain and Store
ERR_INVALID_TARGETTarget invalid or goneRefresh current selection
ERR_NOT_IN_RANGEBeyond repair rangeMove to range 3
ERR_NO_BODYPARTNo active WORKBody damage and replacement

Debugging checklist

  • Use a positive room-specific hits limit.
  • Filter only Walls and Ramparts.
  • Require hits below both stage and hitsMax.
  • Sort by hits, range and stable ID.
  • Require Creep Energy and active WORK.
  • Save repair and movement return codes.
  • Move to range 3.
  • Stop when the stage is complete.
  • Raise stages through a separate reviewed policy.
  • Verify current hits later.

Scope and next steps

This guide does not value individual fortification positions, predict boosts, coordinate Towers, choose room-wide emergency priorities, supply the repairer, or automatically raise stages. Return to the English article library for defense and logistics topics.

Frequently asked questions

Why select lowest hits instead of lowest ratio?

For high-maximum fortifications, an absolute staged target is easier to budget and compare. A ratio can remain tiny for a very long time.

Can Tower repair use this selector?

The target policy can be adapted, but Tower repair has different range behavior, Energy ownership and action allocation. Do not copy the Creep return-code table unchanged.

Should Ramparts and Walls share one limit?

They can for a simple stage, but a mature defense may use separate targets based on protected Structures and wall placement.

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.