Quick answer
Create one Memory request containing the exact Nuker ID, target room, X, Y, and a confirmation string generated from those target fields. Require integer coordinates from 0 through 49, an owned active Nuker, zero cooldown, linear distance within NUKE_RANGE, at least NUKER_ENERGY_CAPACITY Energy, and at least NUKER_GHODIUM_CAPACITY Ghodium. Disable the request before calling launchNuke(), store the return code, and verify later state.
Treat launchNuke() as irreversible
A submitted launch cannot be converted into a different target by later code. This guide therefore does not automatically choose rooms, players, coordinates, or timing.
function describeNuker(nuker) {
if (!nuker) {
return { found: false };
}
return {
found: true,
id: nuker.id,
roomName: nuker.pos.roomName,
owned: nuker.my === true,
active: nuker.isActive() === true,
cooldown: nuker.cooldown,
energy: nuker.store.getUsedCapacity(
RESOURCE_ENERGY
),
ghodium: nuker.store.getUsedCapacity(
RESOURCE_GHODIUM
)
};
}
Bind confirmation to the exact target
function buildNukeConfirmation(roomName, x, y) {
return 'LAUNCH_NUKE_' + roomName + '_' + x + '_' + y;
}
A generic value such as LAUNCH does not prove that the player reviewed the current target. A target-bound phrase becomes invalid whenever the room or coordinate changes.
Create a one-time request
Memory.nuker ??= {};
Memory.nuker.launchRequest = {
enabled: true,
nukerId: 'replace-with-owned-nuker-id',
targetRoom: 'W2N2',
x: 25,
y: 25,
confirmation: 'LAUNCH_NUKE_W2N2_25_25'
};
Review the whole object. Turning on only enabled is not sufficient confirmation.
Build a testable launch plan
function evaluateNukeRequest(input) {
const request = input.request;
if (!request || request.enabled !== true) {
return { ready: false, reason: 'disabled' };
}
if (
typeof request.targetRoom !== 'string'
|| !Number.isInteger(request.x)
|| !Number.isInteger(request.y)
|| request.x < 0
|| request.x > 49
|| request.y < 0
|| request.y > 49
) {
return { ready: false, reason: 'invalid-target' };
}
if (
request.confirmation !== buildNukeConfirmation(
request.targetRoom,
request.x,
request.y
)
) {
return { ready: false, reason: 'confirmation-mismatch' };
}
if (input.owned !== true) {
return { ready: false, reason: 'not-owner' };
}
if (input.active !== true) {
return { ready: false, reason: 'structure-inactive' };
}
if (!Number.isFinite(input.cooldown) || input.cooldown > 0) {
return { ready: false, reason: 'nuker-waiting' };
}
if (!Number.isFinite(input.distance) || input.distance > NUKE_RANGE) {
return { ready: false, reason: 'target-out-of-range' };
}
if (input.energyAvailable < NUKER_ENERGY_CAPACITY) {
return { ready: false, reason: 'energy-shortage' };
}
if (input.ghodiumAvailable < NUKER_GHODIUM_CAPACITY) {
return { ready: false, reason: 'ghodium-shortage' };
}
return { ready: true, reason: 'ready' };
}
Preflight cannot reproduce every protected-location rule. The API return code remains authoritative.
Recover and validate the Nuker
function getOwnedNuker(nukerId) {
const structure = typeof nukerId === 'string'
? Game.getObjectById(nukerId)
: null;
if (
!structure
|| structure.structureType !== STRUCTURE_NUKER
|| structure.my !== true
) {
return null;
}
return structure;
}
Use the exact ID instead of selecting the first Nuker in a room. Multiple Nukers or copied configuration must not change the source structure.
Complete launch handler
function handleNukeRequest() {
const request = Memory.nuker?.launchRequest;
if (!request || request.enabled !== true) {
return { status: 'disabled' };
}
const nuker = getOwnedNuker(request.nukerId);
if (!nuker) {
request.enabled = false;
request.status = 'nuker-missing';
return { status: request.status };
}
const distance = Game.map.getRoomLinearDistance(
nuker.room.name,
request.targetRoom
);
const energyAvailable = nuker.store.getUsedCapacity(
RESOURCE_ENERGY
);
const ghodiumAvailable = nuker.store.getUsedCapacity(
RESOURCE_GHODIUM
);
const plan = evaluateNukeRequest({
request,
owned: nuker.my,
active: nuker.isActive(),
cooldown: nuker.cooldown,
distance,
energyAvailable,
ghodiumAvailable
});
request.checkedAt = Game.time;
request.status = plan.reason;
if (!plan.ready) {
request.enabled = false;
return { status: plan.reason };
}
const target = new RoomPosition(
request.x,
request.y,
request.targetRoom
);
request.enabled = false;
request.status = 'submitted';
request.submittedAt = Game.time;
request.before = {
nukerId: nuker.id,
sourceRoom: nuker.room.name,
targetRoom: target.roomName,
x: target.x,
y: target.y,
distance,
cooldown: nuker.cooldown,
energyAvailable,
ghodiumAvailable
};
const result = nuker.launchNuke(target);
request.result = result;
request.resultAt = Game.time;
request.status = result === OK
? 'accepted'
: 'failed-review-required';
return {
status: request.status,
result,
before: request.before
};
}
module.exports.loop = function () {
const outcome = handleNukeRequest();
if (
outcome.status === 'accepted'
|| outcome.status === 'failed-review-required'
) {
console.log(JSON.stringify({
type: 'launch-nuke-result',
...outcome
}));
}
};
Disable before the API call
request.enabled = false;
const result = nuker.launchNuke(target);
Any retry requires a new review. A failed request should not fire later when cooldown, resources, or room state changes.
Verify later evidence
function inspectSubmittedNukeRequest(request) {
const nuker = getOwnedNuker(request?.nukerId);
const targetRoom = Game.rooms[
request?.targetRoom
];
return {
nukerFound: Boolean(nuker),
nukerCooldown: nuker?.cooldown ?? null,
energy: nuker
? nuker.store.getUsedCapacity(RESOURCE_ENERGY)
: null,
ghodium: nuker
? nuker.store.getUsedCapacity(RESOURCE_GHODIUM)
: null,
targetVisible: Boolean(targetRoom),
visibleNukes: targetRoom
? targetRoom.find(FIND_NUKES).map(nuke => ({
id: nuke.id,
x: nuke.pos.x,
y: nuke.pos.y,
timeToLand: nuke.timeToLand
}))
: []
};
}
Do not require target-room visibility
A missing Game.rooms[targetRoom] entry means the room is not currently visible. It does not prove the launch failed. Use the saved API result and source Nuker state, then inspect target-room Nuke objects when visibility becomes available.
Handle return codes
| Code | Meaning | Review |
|---|---|---|
OK | Launch scheduled | Cooldown, resources and later Nuke evidence |
ERR_NOT_OWNER | Nuker not yours | ID and ownership |
ERR_NOT_ENOUGH_RESOURCES | Energy or Ghodium missing | Both Store resources |
ERR_INVALID_TARGET | Target location rejected | Protected areas and target rules |
ERR_NOT_IN_RANGE | Room beyond Nuker range | NUKE_RANGE and linear distance |
ERR_INVALID_ARGS | Invalid RoomPosition | Room name and coordinates |
ERR_TIRED | Nuker cooldown active | nuker.cooldown |
ERR_RCL_NOT_ENOUGH | Structure inactive | RCL and isActive() |
Debugging checklist
- Use the exact owned Nuker ID.
- Validate 0–49 coordinates.
- Bind confirmation to target room and position.
- Check active state and cooldown.
- Calculate current linear distance.
- Use named Energy and Ghodium capacity constants.
- Disable stale and submitted requests.
- Save the full before snapshot and return code.
- Do not require target-room visibility.
- Verify later evidence without claiming damage outcomes.
Scope and next steps
This guide does not choose a target, estimate damage, model Ramparts, select launch timing, coordinate multiple Nukers, or retry rejected launches. Continue with reviewed Rampart access changes.
Frequently asked questions
Can one generic confirmation phrase be reused?
It should not be. Build the phrase from the exact target so copied or edited requests fail closed.
Why close the request after a resource shortage?
Otherwise it may launch later as soon as logistics fill the Nuker, without a new human review.
Can preflight guarantee the location is valid?
No. Keep ERR_INVALID_TARGET and the current official result as the final same-tick authority.