import { NeutralShip } from './NeutralShip.js'; /** * The ESCORT CONTRACT's transport (data/combat.json → transport — the * neutral freighter from assets/images/ships-transport.png): a PERSISTENT * player-side craft the player rendevouses with at a local waypoint and * leads through the jump gates to a planet / space station (js/scenes/ * GameScene.js → the escort's updateEscort). * * It rides the NeutralShip's escort/engage AI verbatim (hold the ring * around the player, fight the NEAREST pirate up with its own volley, * never aim at the player — js/combat/NeutralShip.js) with ONE difference * that makes it a convoy member instead of a passing escort: the break-off * window is lapsed (escortMs = Infinity), so it never peels off. It stays * for the life of the contract — the contract's reset (GameScene's * landing hook) is what ends it, not the escort clock. * * PLAYER-SAFE BY CONSTRUCTION (inherited): the target pool is the enemy * roster, the collide passes never route an 'ally' bolt into the player, * and the player's auto-fire never targets this roster. * * THE PERSISTENT FLAG (`persistent = true`) is the seam the CombatSystem * reads (its `active` + `_neutralOnly` gates skip a persistent ally): a * standing convoy must NOT hold the jump gate open or keep the * encounter's "active" flag up — the fight is over the moment the last * pirate is down, even with the convoy still flying. * * ART + SCALE: the transport sheet is 180×320 with the art facing north * (the LONG side is the ship's length). EnemyShip's scale rule assumes a * square sheet (scale = size / frameWidth) — wrong for a portrait * freighter. So `size` (data → transport.size, 135) reads as the hull's * WORLD LENGTH: ~2.5× a fighter's 54. We re-scale by the sheet's long * side (320) and re-anchor the hit circle to the new scale. */ export class TransportShip extends NeutralShip { /** * @param {object} scene the combat scene * @param {number} x spawn * @param {number} y spawn * @param {number} index slot (orbit direction alternates) * @param {object} [c] the transport's FULL config (data → transport) * @param {object} [o] NeutralShip's options (escortMs is lapsed below) */ constructor(scene, x, y, index, c = null, o = {}) { // The break-off window is lapsed (Infinity) — a convoy member stays. super(scene, x, y, index, c, { ...o, escortMs: Number.POSITIVE_INFINITY }); this.persistent = true; // CombatSystem's active/neutralOnly gates skip this this.isTransport = true; // Portrait-sheet re-scale (see the class doc): size = world length. const fw = Number(c?.frameWidth) || 128; const fh = Number(c?.frameHeight) || 128; const longSide = Math.max(fw, fh); const size = Number(this.size) || 54; const s = size / longSide; this.setScale(s); const body = this.body; if (body && typeof body.setCircle === 'function') body.setCircle(this.hitRadius / s); } }