Spaces:
Paused
Paused
Commit History
-
Add Easy strategic ceiling (Phase 7 prerequisite)β
Claude +1: Claude Sonnet 5Unverified signatureAn Easy neighbour's INDUSTRY_CHAIN climb and RESEARCH_ORDER research now stop before antimatterforge/'antimatter' Containment, withholding the whole Strategic tier (and everything downstream of it: Star Dock, Leviathan, Helium Bomb, Plasma Rig, and β this phase β a rival Antimatter Gate) from Easy neighbours, the same argument aiDifficulty.js already makes for withholding marketAccess. Medium and Hard are unaffected. This lands first because the rival-Gate workstream depends on it: an Easy neighbour must never be able to reach antimatter_gate's prereqs to begin with. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>5e33d82 -
Unify the AI's counter-pick: out-of-triangle counters, soft-answerβ
Claude +1: Claude Sonnet 5Unverified signaturefallback, turret-wall reading, and a difficulty-shaped cadence Three catalog proposals all independently patched engine/aiMilitary.js's ~12-line counterToPlayerArmy; this lands them as one coherent rewrite of that function (plus pickNextUnitType's cadence) instead of three overlapping diffs, per docs/improvement-roadmap.md's Phase 2 collision call, and adds the difficulty dial on top of the unified result. - entities.js: an optional `counteredBy` field on out-of-triangle unit defs (dreadnought/breacher/colossus/wraith -> skiff, aegis -> lancer), each empirically proven by a new cost- or supply-parity duel in balance.test.js (not guessed) so the field is self-verifying and can never silently go stale. Aegis specifically needs the supply-parity metric: cost parity actually favours it, but armies are supply-capped late-game, and at equal supply the Lancer wins. Leviathan is left to the soft-answer fallback below rather than a certified counteredBy. - aiMilitary.js COUNTERβ¦2bf7ef0
-
Vary neighbour worlds' AI difficulty and personality across the galaxyβ
Claude +1: Claude Sonnet 5Unverified signatureToday the player's single splash-screen Difficulty + AI Strategy pick applies to every world in the galaxy uniformly β once you pick Hard, every world you ever visit plays Hard, with no variety to discover. neighbourAiProfile(seed, planetId) (engine/galaxy.js) resolves an independent, deterministic difficulty (with matching aiApm/aiMicro, never a mismatched pair) and AI Strategy for a world, derived from the galaxy seed + planet id the same way per-world map generation already is β no new randomness source, fully replay-safe. addPlanet now uses the player's actual settings only for the start seat (planetId === galaxy.activeId); every other world resolves its own profile instead. Nothing new is needed for "the player must discover it by playing" β galaxyStatus already hides everything about a world until galaxy.discovered has it. Written test-driven, per the new process (see CONTRIBUTING.md): the tests in test/livingGalaxy.test.js were written first, against neighbourAiProfile before β¦9f4b083 -
Tier 4: Rusher graduation on Hard β the last tier of the proposalβ
Claude +1: Claude Sonnet 5Unverified signaturerusherGraduates (engine/aiDifficulty.js, Hard only) is the one identity- level dial in the whole section-08 proposal rather than a magnitude one. Past aiIndustry.js's RUSHER_GRADUATE_TIME (20 minutes) into an Odyssey world, a non-developing archetype (today, only a Rusher) picks up the deep factory chain a patient developer would β the same third OR-condition strategy.wantsIndustryAlways already is on that gate. Pure time-based, no wave-outcome tracking needed: if the game is still running this far in, the opening rush has clearly either succeeded or become a non-factor. Read test/aiArchetypes.test.js first, as planned β nothing in it assumes a Rusher never touches a Refinery, so this doesn't conflict with anything there. Skirmish is untouched by construction: aiIndustry.js already returns on !state.endless before this new condition is ever read, and a skirmish never runs anywhere near 20 minutes anyway. Medium never graduates, however long the game runs. This completes the tiered imβ¦8101484 -
Tier 3: market barter for the AI, gated by difficultyβ
Claude +1: Claude Sonnet 5Unverified signatureThe one genuinely new mechanic in the section-08 proposal, not just a multiplier on something that already exists. market.js's sell/buy can't be reused for the AI as-is β they're hardcoded to state.players.player.resources and the single shared galaxy.credits, and there's no AI-side credit account to plug into. Added aiBarter(state) instead: a same-planet CONVERSION, never touching galaxy.credits, priced off the world's own live market (unitPrice/applySlippage, same as a player trade). Surplus/bottleneck are measured on the same scale: coverage = resources held / the priciest single unit-or-building-or-upgrade purchase that ever costs that commodity (SPENDABLE, moved from aiWorkers.js to entities.js so market.js can share it without an aiWorkers.js -> market.js dependency running the wrong way). A commodity past 5x that yardstick is "surplus"; the lowest-coverage spendable commodity is the "bottleneck". One lot per think-cycle, same lot size the player's own trades use. Deterministic:β¦b02b34f -
Tier 2: AI-only research pace by difficultyβ
Claude +1: Claude Sonnet 5Unverified signatureresearchPaceMult (engine/aiDifficulty.js) speeds up or slows down the AI's own Datacenter research (engine/techtree.js updateResearch) β Easy 1.3x (slower), Hard 0.75x (faster). researchTimeScale itself stays untouched and per-WORLD as before (a high-tech world is fast for whoever researches there); the new aiResearchPaceMult is a further per-OWNER factor applied only when building.owner === "ai", so a player researching on the exact same world sees no change at all β covered by an explicit regression test. Doctrine upgrades (production.js's instant-on-afford researchUpgrade) aren't timed, so this dial has nothing to touch there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G73oK4p3bnreizCcMUHVEy9bb52d4 -
Tier 1: worker target, war patience, and a seeded economic edge by difficultyβ
Claude +1: Claude Sonnet 5Unverified signatureThree economic dials on top of Tier 0's scaffold, each composing multiplicatively with the archetype/strategy layers already in place: - workerTargetMult (aiEconomy.js) scales the AI's worker headcount target β Easy 0.8x, Hard 1.25x. - graceMult/grievanceMult (diplomacy.js) nudge the Odyssey war-onset timing β Easy a touch more patient, Hard a touch less; deliberately mild since it's a third multiplicative layer, and GRACE_FLOOR still bounds the opening window regardless. - economicEdge (Hard only) seeds a synthetic `hardEdge` UPGRADES entry (gatherYieldMult/produceTimeMult) straight onto the AI's own upgrades at creation. gather.js/production.js need no changes at all to pick it up β they already read any upgrade field generically via upgradeMult. That last one required hardening committedDoctrine (entities.js), which used to return on ANY UPGRADES membership rather than checking `.doctrine` specifically β harmless while every entry had a doctrine, but hardEdge doesn'tβ¦b28c2f0 -
Move DIFFICULTY_OPTIONS into engine/aiDifficulty.js, add state.ai.difficultyβ
Claude +1: Claude Sonnet 5Unverified signatureScaffold for tiered difficulty economics: the Easy/Medium/Hard table now lives in engine/ (mirroring how aiStrategy.js already holds STRATEGIES) with a difficultyFor(state) resolver alongside it, and every state.ai now carries the picked difficulty as a plain string, threaded through boot.js's skirmish/Odyssey paths and galaxy.js's per-planet seeding, with save/load round-trip support. setup.js re-exports DIFFICULTY_OPTIONS so boot.js and existing tests are unaffected. No economic field is added to any difficulty tier yet β every new/updated test proves this lands as a pure no-op. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G73oK4p3bnreizCcMUHVEy53ce1fb