⚓ Seaworth Games

Remnants of the Precursors · ↑ Systems Map · Design series 01

ROTP Galaxy and Range

The board, and the rule that governs everything on it. Range in ROTP is not a fuel budget that depletes as a ship flies — it is a radius drawn around every system you and your allies have colonised. That single choice turns expansion into the mechanism by which you unlock the map, and turns alliances into an immediate military asset.

Scope base ROTP rules Core GalaxyShape · StarSystem · SystemInfo · SystemView

01The board

A scatter of stars in a shaped region, measured in light years.

A galaxy is a set of star systems placed by rejection sampling inside a region whose outline is chosen from fifteen shapes — rectangle, ellipse, spiral, cluster, maze, shuriken, fractal and others. Each system holds one planet (or an asteroid field), a star colour, and a position in light years. Distance is plain Euclidean; there are no lanes, no wormholes, and no terrain except nebulae.

Galaxy sizes
24–10k
stars, from Micro to Insane, plus dynamic and random
Minimum separation
1.9
light years between any two stars, scaled by the density option
Starting range
3
light years — most of the map is unreachable at turn one

The physical extent of the map is derived from the star count and a per-shape density factor, so a larger galaxy is genuinely bigger rather than more crowded. The star-density option scales both the map's linear dimension and the minimum separation together, which keeps the local texture constant while changing how far apart neighbours sit.

02Generation

Orion first, then empires, then everything else.

The pipeline runs in a fixed order, and the order matters:

  1. Nebulae are placed first, before any star system object exists — each one is anchored on a randomly chosen star position and validated against the map edge and other nebulae.
  2. Orion is placed as system index zero, before any empire. Several shapes special-case index zero to a fixed spot; on a circular elliptical map it lands dead centre, and the shape even punches a small legal disc into an otherwise-void middle so the point is valid.
  3. Empire neighbourhoods are built next, each as a home star plus two rings of nearby stars at roughly 3 and 6 light years. If placement fails repeatedly the whole map is discarded, the region is grown, and generation restarts.
  4. Remaining stars fill the rest by rejection sampling, up to ten attempts per star. If the attempt budget runs out the galaxy quietly ends up with fewer stars than requested.
  5. Planets are created lazily on first access, then nebulae with no stars in them are removed and the remainder enrich their central system's resources.

Empires are spaced by an empire buffer that targets roughly half the stars-per-empire ratio in light years, floored at three times the system buffer and capped at fifteen times it, then scaled by a user setting. Orion gets its own buffer, normally the larger of four system buffers or one and a half empire buffers.

Habitability is guaranteed, not hoped for

The ring systems around each homeworld carry a counter of how many friendly-environment planets are still needed and how many slots remain. When those numbers meet, the generator simply rerolls the system until it produces a habitable planet. No empire can be born into a pocket of radiated worlds with nowhere to go.

03Stars and planets

Colour decides everything: what grows there, and what it is worth.

Star colours

Six colours are produced, with a distribution that shifts by galaxy age:

AgeRedOrangeYellowBlueWhitePurple
Normal30%25%15%15%10%5%
Young20%20%15%30%10%5%
Old50%15%10%5%5%15%

The player's home star is always yellow; alien homeworlds and Orion draw from red, orange or yellow. A young galaxy is blue-heavy and therefore rich but hostile; an old one is red and purple, which means poor worlds and asteroid fields but the best mineral jackpots.

Colour to planet type

Fourteen planet types are ordered by hostility from Terran down to Radiated, plus asteroids. Star colour selects from a cumulative table over that ordering, so the marginals are striking:

StarCharacter
Yellow40% Terran, and never produces asteroids, radiated or toxic worlds. The best real estate in the game.
OrangeBroad spread, decent odds of habitable worlds. The workhorse colour.
Red5% Terran, 5% asteroids — mostly mediocre, occasionally fine.
WhiteSkewed hostile; tops out short of Terran.
BlueNever Terran, mostly hostile — but by far the richest in resources.
Purple20% asteroids, 25% radiated, and cannot exceed Minimal. Almost uninhabitable, and the biggest ultra-rich mines.

This is the design's cleanest economic tension. Habitability and resources are anti-correlated by star colour. Yellow stars give you population; blue and purple stars give you a production multiplier of two or three times on a world you may not be able to colonise for another forty turns. A blue-heavy young galaxy is a different game from a red-heavy old one.

Size, environment, resources

Planet size is drawn from a per-type range on a five-light-year grid, with a geometric tail if the roll lands on either endpoint — Terran worlds run 85–100, Radiated 10–40. Environment is derived from type: the six worst types are hostile, the six best get a flat one-in-twelve chance of being Fertile, and Minimal sits alone as always Normal.

Resources are five tiers giving production multipliers of ×0.33 to ×3. Poor worlds key off star colour — orange stars are the poorest, purple stars can never be poor at all. Rich worlds key off colour and type, and the pattern is deliberately perverse: the more hostile the planet, the better the odds. A radiated world around a purple star is 60% likely to be rich or ultra-rich.

Ancient artifacts are a flat 10% chance, and only on the five habitable types. They multiply research on that colony and grant free technologies when the system is first scouted.

04Homeworlds and Orion

Two deterministic points on an otherwise random map.

A homeworld is not rolled. Its planet type, size and any resource or environment flags come straight from the race's data file — every original race gets a Terran world of base size 100. The colony starts with 50 population, 30 factories, two scouts and a colony ship. Around it sit the two rings of nearby stars, with the habitability guarantee described above.

Companion worlds are an option that grants each empire extra starting colonies. Each is placed at exactly one light year from the homeworld, gets an Orion-class star, and always receives a Terran planet of base size 60 with 30 population and 20 factories already on it.

Orion

Orion is deterministic in everything but its star colour: a Terran, fertile, size-120 world with Orion ruins worth three bonus technologies, guarded by a single very powerful monster. It is the map's fixed prize, placed before anything else so that nothing crowds it.

The guardian carries the Death Ray as plunder — a weapon flagged as unresearchable, so killing the guardian is the only way any empire in the game can ever obtain it. That is a clean piece of design: a landmark that is worth taking for a reason nothing else can substitute for.

Optional guardians elsewhere

Every unsettled system can also roll a lesser guardian — jellyfish, cuttlefish, crystal, pirates, amoeba — with probability scaled by planet size and biased toward artifact, rich, fertile and gaia worlds. It is off by default. When enabled it does something valuable: it puts a price on the best real estate, so the strongest planets are not simply first-come.

05The range model

The most consequential rule in the game, and it is three lines long.

// SystemInfo.java
public boolean inShipRange(int i)          { return distances[i] <= empire().shipRange(); }
public boolean inScoutRange(int i)         { return distances[i] <= empire().scoutRange(); }
public boolean withinRange(int i, float r) { return distances[i] <= r; }

And distances[] is the whole model:

// SystemInfo.calculateSystemDistances()
List<StarSystem> alliedSystems = new ArrayList<>(empire().allColonizedSystems());
...
for (Empire ally: empire().allies())
    alliedSystems.addAll(ally.allColonizedSystems());
for (int i=0; i<distances.length; i++)
    distances[i] = empire().distanceToSystem(gal.system(i), alliedSystems);

// ...and distanceToSystem is simply the minimum straight-line distance
float distanceToSystem(StarSystem sys, List<StarSystem> froms) {
    float distance = Float.MAX_VALUE;
    for (StarSystem from: froms)
        distance = min(from.distanceTo(sys), distance);
    return distance;
}

So distances[i] is the distance from system i to the nearest colony belonging to you or to any of your allies. A system is reachable if that number is inside your range. There is no fuel consumed, no path budget, and no return-trip accounting: a fleet sitting just inside the radius can cross the entire galaxy in a single hop, provided the destination is also inside it.

RANGE IS A UNION OF RADII, NOT A FUEL TANK my colony my colony ALLY colony reachable reachable via ally out of range out of range a fleet parked here still cannot go Colonising anywhere adds a new circle. Signing an alliance adds all of theirs, immediately.

Two radii

RadiusValueWho gets it
shipRange The fuel-range tech ladder: 3, 4, 5, 6, 7, 8, 9, 10, then unlimited Every ordinary ship. This is the empire's real border.
scoutRange shipRange + 3 Only designs mounting the Reserve Fuel Tanks special. Despite the name it has nothing to do with scout hulls — a battleship with tanks gets it too.

A fleet's range is the minimum across its designs, so one ordinary escort drags an entire extended-range fleet back to normal range. The stock scout and colony ship both ship with reserve tanks fitted, which is why your first colony ship can always reach one ring further than your warships.

Why this choice matters so much

Because range is territorial rather than consumable, expansion is how you unlock the map. Every colony is simultaneously an economic asset and a forward operating base. That gives borders and chokepoints real meaning, makes a badly-placed colony a strategic liability rather than just a poor investment, and gives alliances an instant military payoff: signing one extends your reach into your partner's space that turn, with no ships built and no technology researched.

It also produces the game's characteristic opening. At range three, most of the galaxy is simply unreachable, and the first real question is not "where do I want to go" but "which of the four systems I can reach opens up the most next".

06What range gates

Almost everything, including several things that are not obviously spatial.

SystemGateNotes
Fleet movement canReach / canSendTo The engine refuses an out-of-range deployment outright. A per-design variant lets the interface send only the colony ship somewhere the escorts cannot follow.
Retreat inShipRange You can only retreat to systems inside your own radius, which is what makes an overextended fleet genuinely trapped.
Transports shipRange only Reserve fuel tanks never extend population transports — they always use the base radius.
First contact withinRange(id, shipRange) Contact fires the moment any of their systems falls inside your radius. You meet neighbours by growing toward them.
Diplomacy, trade, spying inEconomicRange See below — this one is symmetric.
Declaring war inShipRange(empId) Asymmetric: uses only your own range. You cannot declare war on someone you could not attack.
Colonisation targets inShipRange + scouted Colonisation itself is not range-checked — a colony ship must physically be in orbit — so range is enforced upstream by movement.
AI target valuation inShipRange An out-of-range system is valued at exactly zero as an attack or invasion target.

Economic range is symmetric

public boolean inEconomicRange(int empId) {
    Empire e = galaxy().empire(empId);
    float range = max(e.scoutRange(), scoutRange());     // note: the larger of the two
    for (StarSystem sys: e.allColonizedSystems())
        if (sys != null && sv.distance(sys.id) <= range)
            return true;
    return false;
}

This is a genuinely interesting asymmetry in the design. Almost every range check uses your radius, but the diplomatic one uses the larger of the two empires' radii. A long-ranged neighbour therefore drags you into diplomatic contact with them whether or not your own propulsion tech could reach. Reaching out is something an empire can do unilaterally.

Since economic range gates trade, embassies, spy networks and most of the diplomacy interface, an empire that invests in propulsion becomes the diplomatic hub of its neighbourhood almost as a side effect. Distant empires, meanwhile, are functionally inert — you cannot trade with them, spy on them or negotiate with them at all.

07Travel and speed

Distance over warp, walked one light year at a time.

Travel time is distance divided by speed, except that the path is walked in one-light-year segments so that nebulae can charge a different rate for the segments they touch. Turn count is the ceiling of that time.

if (!passesThroughNebula(from, to))
    return dist/speed - 0.01f;

// otherwise walk it in ~1 ly segments
float stepTime    = 1.0f/speed;
float nebStepTime = 1.0f/speedInNebulae();
for (int i=1; i<=numSegments; i++)
    travelTime += passesThroughNebula(segment) ? nebStepTime : stepTime;
return travelTime - 0.01f;
The 0.01 deduction is deliberate: everything downstream takes a ceiling, so an accumulated rounding error would cost a whole extra turn.

A fleet moves at the speed of its slowest ship. Engine warp runs from 1 to 9 across nine technology levels, and options can rescale that ladder to grow faster or follow a Fibonacci sequence.

Arrival is stored as an absolute time stamped at launch, and resolved after the clock ticks — so there is no genuine partial-turn arrival. What is partial is the rendering: the map interpolates the icon across whole turns so it lands exactly on the destination, and because scanning radii follow the fleet's interpolated position, a fleet in transit really does see as it goes.

One practical consequence worth knowing: fleets deployed to the same destination with the same integer turn count are merged into a single fleet object. Sending reinforcements that arrive on the same turn produces one stack, not two.

08Stargates and hyperspace communications

Two technologies that change movement rather than range.

TechnologyCostEffect
Stargate 3000 BC per colony, plus 300 BC per turn upkeep Travel between two of your own gated colonies takes exactly one turn regardless of distance. Rally moves through gates are free.
Hyperspace Communications None — no cost, no upkeep Lets you redirect fleets already in transit, relaunching them from their current interpolated position, and makes every fleet assignable rather than only those in orbit.

The stargate's upkeep is unusually punishing — 300 BC per turn is a large standing cost, levied against the whole empire's production. The game gives you an explicit escape: an empire under financial pressure will scrap a gate to stop paying for it. Gates are also strictly per-empire; allies do not share them, and a captured colony loses its gate.

Hyperspace Communications is the more elegant of the two because it changes a rule rather than adding a number. But note the interaction with the range model: a redirect still measures range from your colonies, not from the fleet's current position, so you cannot use a mid-flight redirect to reach past your border even if the fleet is sitting right next to the target. Range is a property of your territory, permanently, and no movement technology relaxes it.

09Nebulae

The only terrain on the board, and it does three unrelated things.

Nebulae are rectangular regions placed at generation time, anchored on existing stars. Count scales with galaxy size — roughly one per twenty stars at normal frequency — and on very large maps the game trades count for size, producing fewer but proportionally larger clouds.

EffectDetail
No shields Ships inside a nebula have zero shields, and so do planets. Planetary shields cannot even be built there. Since shields subtract flat damage from every shot, this does not weaken defenders slightly — it removes an entire defensive layer.
Slow travel Every ship crosses a nebula at warp 1 regardless of engines, charged per light-year segment.
Rich central system A nebula containing enough stars enriches its most central planet to rich or ultra-rich, with the odds of ultra-rich scaling with how many stars it contains.

The combination is what makes them interesting rather than merely obstructive: a nebula is valuable ground that is slow to reach and impossible to defend properly. It creates a specific kind of contested space, where a technologically superior fleet loses much of its advantage and the prize is worth fighting over anyway.

10Fog of war

Two independent clocks, five levels of scan, and only one kind of staleness that expires.

Each empire keeps one view per system, holding a remembered snapshot: the owner, name, planet data, population, factories, missile bases, shield level, stargate presence, and the fleets last seen in orbit. Two separate timestamps track how it was learned:

ClockCoversBehaviour
Scout time Astronomical facts — name, owner, planet type, size, artifacts Once set it is never cleared. "Scouted" is permanent and boolean.
Spy time Colony intelligence — population, factories, bases, shields, stargate Reset to zero when the system changes owner. A conquest wipes your intelligence back to nothing while leaving the system still "scouted".

Each turn every system gets exactly one refresh, the best available, chosen by a strict priority chain:

  1. My colony → full scan.
  2. My fleet in orbit, with no battle in progress → full scan. You do not get the numbers while a fight is unresolved.
  3. A colony scanner reaches it → planet scan (no colony numbers).
  4. A fleet scanner reaches it → ship scan.
  5. Otherwise, if previously scouted → the remembered orbiting-fleet list is cleared.
Only fleet sightings expire

That last step is the only staleness the game actively cleans up. Fleet positions are forgotten after one turn without observation — but population, factories, missile bases and shields simply sit at whatever value they held when you last looked, with no indication of age beyond a report-age counter.

This is exactly the right asymmetry. Fleets move, so remembered fleet positions are actively misleading and get purged; colony statistics change slowly, so a stale number is still a useful estimate. It means the interface can show you a confident-looking figure that is forty turns old, which is a feature rather than a bug — deciding whether to trust it is part of the game.

Scanners

Four scanner technologies raise two radii: a planet scanning range of 3 to 9 measured from colonies, and a ship scanning range of 0 to 3 measured from each fleet's live position. Both, for system scanning purposes, are gated on the top scanner technology — so long-range system scanning arrives all at once rather than improving gradually. Ship detection uses the same radii but is not gated, so intermediate scanners still improve what you see moving around.

Alliances share knowledge, but weakly: an ally sharing scan reveals name, owner and planet, and pointedly not what is in orbit. Allies tell you where things are, not what is moving.

11Quirks worth knowing

Places where the implementation diverges from what the data appears to promise.

  • Orion-ruins planets are effectively unreachable. The artifact roll tests the ordinary artifact chance first, then reuses the same random number against the Orion-artifact probability. Since the second branch requires the roll to have already exceeded the first, and the Orion probability defaults to zero, it essentially never fires. Orion itself is placed explicitly, so the map still has one — but random Orion-grade worlds do not appear.
  • Companion worlds sit one light year from the homeworld and skip every proximity check — well inside the 1.9 ly minimum separation that every other star must respect. They can also land outside the map boundary.
  • "Unlimited" fuel range is the literal number 99999, not an infinity sentinel, and it is multiplied by the range option like every other value. Consumers that care test an explicit unlimited flag instead, and the map renderer bails out rather than drawing a 99999-light-year circle.
  • The nearby-systems list compares a squared distance to a linear threshold. The constant is 64 and the comment says it is twice maximum warp, but the comparison is against the squared distance — so the real radius is 8 light years, not 64.
  • A green star type exists and is never produced. It is declared and registered, but no generator emits it; the code silently aliases it to orange, and the orange planet-type table is still literally named after green.
  • Homeworld placement fails silently to the map centre. If a shape cannot produce a valid specific location after 2000 attempts, it returns the exact centre of the galaxy — and the diagnostic message for that case is commented out.