--- name: efs-research-tree description: Analyze Emperor of the Fading Suns (EFS) games with the EFS Research Tree site at https://efs.ignorelists.com/techgraph/. Covers mod data (units, techs, cities, sects, relics, combat tables), the user's game (visible units, stacks, known techs, structures), the galaxy and planet maps, and the combat simulator with batch runs. Use it for questions like "which enemy stacks are on planet X", "what can my house build", or "design a stack that beats this one with minimal losses". --- # EFS Research Tree: guide for agents - Site: https://efs.ignorelists.com/techgraph/ (for example `?mod=%2Fdata%2Fhyperion`) - Written for an agent that has a browser or plain HTTP access and no source code. - Updated 2026-10-18. Everything except [workflows.md](skill/workflows.md) section 8 ("Planned") exists on the site today. This page is the short path. The details are in five topic files, each small enough to read in one go. Read only the one you need. | File | Read it for | | --- | --- | | [skill/data.md](skill/data.md) | Sections 1–2: URL parameters, tabs, mods and the fallback chain, raw `.dat` files, prebuilt mod and galaxy JSON | | [skill/saves.md](skill/saves.md) | Section 3: the user's game, the agent export format, the full export format, resolving unit rows, affiliation | | [skill/combat-rules.md](skill/combat-rules.md) | Section 4: rounds, hit chance, damage, targeting, stack bonuses, withdrawal, sects, what the sim assumes | | [skill/combat-sim.md](skill/combat-sim.md) | Section 5 and 6.0: the agent API (`window.efs` and the Node module), setting up a battle, setup JSON, batch results, the DOM fallback | | [skill/workflows.md](skill/workflows.md) | W1–W5 step by step, pitfalls (7), planned features (8) | Section numbers like "(4.5)" point into these files. If you can't fetch them, ask the user for the whole guide as one file: **AI Agent** (toolbar) → **download the whole guide as one file**. ## Ground rules - **Never read, parse or decode a `.sav` file, and never upload one anywhere.** In the user's own browser, with their game already loaded, work there directly. Anywhere else, ask the user for an **agent export**: **Manage**, select the game, **Export for Agents**, pick the planets the question is about, and send you `()-agent.json`. One or two planets come to 20–50 KB (3.1, 3.2). - **Use the agent API (5.0):** `window.efs` in the site's page, or the module `/techgraph/efs-agent.v1.es.js` in Node. Both run Combat Sim batches and return a small JSON summary. Script the page's controls only for what the API lacks (6.0); the page is far too large for accessibility-tree tools. All data files can also be fetched over HTTP (2.x). - **Stacks:** ministry units and house units never share a stack, and relics only go in house stacks (4.5). Every attacker needs movement left, or must be towable with a towing unit in the stack (4.5). At most 20 slots, relics included. ## Quick path: beat a defended stack with minimal losses Budget: about 15 minutes and 30–50 tool calls. The expensive steps are moving data through the model and reading long printouts. Keep both small. 1. **Read the user's game locally.** Parse the agent export (3.2) in a script and print only what you need: aggregates and short lists, never every unit. - A unit's row is the prebuilt unit row with `groupId == type` and `techLevel == tLvl` (3.4). Units with the same `stackId` form a stack. - The user's own units are those whose `controllingOwner ?? owner` is the export's `house`. Units with a `ministry` field belong to that ministry office, even when the house controls them (3.4). 2. **Pick the target.** The stack on the planet, its city (the `structures` row on the same hex; a VAU CITY multiplies non-Psy defense by 5), and each unit's weapons, armor, psy defense and rank (2.2). 3. **List the candidates.** Your units within a few jumps (4.9), house and ministry separately. Add buildable units (W3) at experience 0, and house relics if the house knows Theurgy. 4. **Shape the stack** using the rules that decide most fights: - **Psy ignores structure armor and fires first.** Against a city garrison, psy units do the killing (4.3). - **Screens.** Each enemy shooter targets a different unit, lowest rank first, and only units its weapon can hit (`target.dat`; in Hyperion Direct fire can't hit foot or mech). Add at least as many low-rank, high-armor units as the enemy has shooters able to hit them, so your psy units are never shot (4.4). - **A noble and an officer** add +15 accuracy and agility to the whole stack. **Elite** units are ×1.2, green ×0.8. **Assault** orders are ×1.2 attack and ×0.8 defense (4.3, 4.5). - **Relics** (house stacks only, need Theurgy): Rod of Holy Smiting ×1.5 strength, Eye of the Prophet +4 accuracy, Sabaton +4 agility (4.5). 5. **Simulate with the agent API** (5.0): - **In the user's browser**, with their game open: find the target in `window.efs.combatSim.stacks()` and assign it with `assignStack("defender", id)`. That fills the hex terrain and the city. Take the setup once with `getSetup()` (below). - **In your own browser**: first load an export of just the target planet (about 20 KB) with **Manage → New Game → Create from JSON** (6.0 feeds its file picker). The new game becomes the active one. Then as above. - **In Node**: download the module, `loadMod("/data/hyperion")`, and write the defender into a setup yourself: its units, the city on its hex and the hex terrain (5.2). - For each candidate, put its units into that setup's attacker and run 500 battles. That's one call per candidate, and 5–15 s of compute. 6. **Rank** by attacker wins, then deaths per battle, then health lost per battle. Take one unit out at a time (ablation) to see what matters. 7. **Check legality** before you recommend: no house/ministry mix, relics only in house stacks, no jump units, every unit can move or be towed, and the units can reach the hex in time (4.5, 4.9). ```js // In the page. In Node: import { loadMod, runBatch } from "./efs-agent.v1.mjs", then runBatch(mod, setup, n, options). const efs = window.efs; await efs.ready(); // Once: assign the target, then keep the setup with the defender, its hex and its city. const target = (await efs.combatSim.stacks()) .find(s => s.group.startsWith("Player save") && s.title === "VRIL-YA (#8) surface (30, 9)"); await efs.combatSim.assignStack("defender", target.id); // returns the import status line const baseSetup = efs.combatSim.getSetup(); // A slot for the setup's units. typeId is the unit row id; ministry only for ministry units. const slot = (typeId, sect, experience, health = 100, loyalty = 75, extra = {}) => ({ magic: `unit-${baseSetup.mod}-1`, type: String(typeId), sect, ...extra, status: { health, loyalty, experience, spotted: true, routed: false, inCargo: false, inCarrier: false, plague: false, mightHavePlague: false } }); // Per candidate, in one call: run the batch on a detached sim and return the summary. async function runCandidate(units, { stance = "Neutral", battles = 500, knownTech, seed = 1 } = {}) { const setup = structuredClone(baseSetup); setup.attacker.stance = stance; if (knownTech) setup.attacker.player.knownTech = { ...setup.attacker.player.knownTech, ...knownTech }; setup.attacker.stack.units = units.map((unit, stackPos) => ({ stack: "A", stackPos, unit })); return efs.runBatch(setup, battles, { seed }); } // Example: two elite Eskatonic Heavy Mechs (row id 1281) on Normal orders, Theurgy known. await runCandidate([slot(1281, "Esk", 2), slot(1281, "Esk", 2)], { knownTech: { theurgy: true } }); ``` - The summary has `outcomes`, `meanRounds`, `attacker.deadPerBattle`, `attacker.healthLostPerBattle`, and a row per slot (5.3). It also has the `seed`, which reproduces the batch exactly, and the stack `warnings` (5.0). - To show a watching user the winner: `efs.combatSim.loadSetup(setup)`, then `await efs.combatSim.runBatch(500)`, which adds a batch card to Results. - Stances: `Neutral` (Normal orders), `Offensive` (Assault), `Defensive` (Feint). Sects: `Ort`, `SAe`, `Esk`, `Inc`, `Ave`, `Bro`, `Men`, `Sym`, `Vau`. A relic slot is `slot("r_", "Ort", 0)` (5.2). - Units that already moved this turn need `extra: { movePoints: n }`, or the movement warning cannot see them (5.2). - Set the attacker's six known-tech flags yourself: the base setup has whatever the defender's import left (4.8). - If `window.efs` is missing, drive the page's controls instead (6.0). ## Combat in one screen - **Hit:** `roll(0..100) + accuracy − agility >= 50`. The defender's terrain adds agility; attackers get none (4.2). - **Damage:** attack number = health × strength (sect) × experience × orders × psychology tech × Rod. Defense number = health × armor or psy defense (sect) × experience × orders × structure armor factor (not against Psy) × defense relics. The ratio picks a `damage.dat` column, and 1-5 or worse does nothing in Hyperion (4.3). - **Phases:** Hyperion land combat fires Psy ×2, Air ×2, Indirect ×2, Water ×4, Direct ×3, Close ×4 each round. A unit killed early never fires its later weapons (4.1). - **Ending:** a side loses when it has no active combat units. A ship-led stack makes the fight one round long (4.1). Units withdraw on damage unless loyalty holds; a noble and an officer make that rare (4.6). - **Who fights:** jump and space units surrender in land combat, and non-combat units don't fight (4.5).