Files
Dune/docs/TWO_PLAYER_TWO_FACTIONS.md
T

131 lines
7.9 KiB
Markdown

# Two players controlling two factions each
## Status and authority
**Prototyped; wider rules and acceptance remain open.** The [GF9 classic rulebook, printed p. 6](https://www.gf9games.com/dunegame/wp-content/uploads/Dune-Rulebook.pdf#page=6)
offers a two-player setup in which each person plays two factions, with the
two-player four-stronghold victory requirement. The user-authorized revised
Advanced source, physical p. 4 (printed p. 2), offers the same choice and
threshold. The supplied PDF stays local; its identity and precedence are in
[the decision index](RULE_DECISIONS.md#authorized-source-amendment--1-october-2026).
The similarly titled movie game's double-faction rules are a different game
and are not authority for this mode.
Neither cited classic passage says whether the two factions controlled by one
person are automatically allied, how their holdings combine for victory, or
how controller identity affects every faction-counted ability. Do not silently
adopt the movie game's automatic alliances or blended inventories. A practical
first version can retain independent faction records, actual alliance choices,
and a four-stronghold target per eligible victory side as an explicitly
provisional policy. Resolve combined holdings and any conflicting interaction
from authoritative sources or document the chosen interpretation; this design
does not certify those answers.
## Model and setup
Keep four distinct `Player` faction records and their normal physical forces,
leaders, decks, private hands, turns and faction identities. Add an explicit,
lobby-validated association of those four distinct faction seats with exactly
two controllers, two seats per controller. A controller is not itself a
faction or a new recipient of faction income. Validate the complete mapping
before starting and reject ambiguous, duplicate, missing or stale assignments;
changing an assignment or faction clears readiness. Existing two-seat games,
already-started games, and saved positions without the new mode retain their
original interpretation and do not receive invented controller assignments.
Expose this as an explicit two-player setup option. Let each person create or
join their first seat and securely add/select their second faction before
readiness, with clear names and a persistent active-faction indicator. Avoid
claiming complete support for the mode until complete games and wider
interactions are verified. The existing model
still permits ordinary two-seat play and separate one-faction controllers.
## Separate controllers from faction seats
The `players` array currently represents faction seats, not physical humans.
For this option `game/victory-progress.ts` must use the validated controller
count for the printed two-player threshold; `players.length === 2` alone is
incorrect for four faction seats. Apply any agreed threshold increase through
the same shared victory projection and quote, and retain explicit ordinary,
alliance, Ecaz and special victory ordering. Never infer controller count by
names, cookies, browser tabs, AI labels or faction alliances.
Audit each other count before changing it. Faction turn order, physical pieces,
dealt cards, faction-specific payments and action ownership can still depend on
the four faction seats. Optional-module eligibility and phase rules referring
to players must be checked against their specific source; for example, existing
Tech Token gates use `players.length >= 3` in `game/engine.ts` and
`game/faction-module-profile.ts`. A global substitution of controller count
would silently change unrelated rules. Record uncertain interpretations and
keep unsupported combinations visibly provisional rather than fabricating a
new setup or automatic alliance.
## Authentication and switching
Today `db/schema.ts` makes `seats.token_hash` the primary key;
`db/rooms.ts` authenticates a token to one `player_id` and `act` rechecks that
exact unrevoked room/player/token tuple before the versioned action. The normal
`joinRoom` path returns `alreadySeated` for an authenticated caller. Room API
routes retain the original room-scoped HttpOnly cookie and use separately
scoped HttpOnly cookies for added faction seats. Reusing one token
for two database rows, trusting a caller-supplied seat ID as authorization, or
projecting both seats' private information into one general view would break
those existing boundaries.
The authenticated add-second-seat operation atomically validates the
lobby/controller assignment and creates
the second distinct seat credential. Provision separately random, room-scoped
HttpOnly credentials for both faction seats. A public active-seat selector may
choose which credential to present, but every API read, action, message,
control or recovery request must authenticate that selected credential and
verify its actual `player_id`; the selector itself grants no access. Apply the
same room-control, revocation, origin, retry, version and removal checks as
today. Preserve existing seat cookies and single-seat clients; use additive
schema or durable mapping changes if required, never reset the room database.
No secret token belongs in source, client-visible game state or logs.
On a faction switch, `app/page.tsx` should advance its existing request epoch,
discard stale cross-seat results and fetch the selected authorized view. Fence
in-flight actions and responses by room, selected seat and version so a delayed
response from the other faction cannot overwrite or act through the current
view. Explicitly handle refresh and recovery of both distinct credentials,
individual revocation, host assignment and relinquishment; a recovered or
revoked seat must not accidentally grant the other seat or an opponent. Keep
the UI explicit about which faction owns each pending decision. Existing
autopilot can operate a faction seat only under its existing authorization;
until full AI refinement, each offered decision needs a minimal legal bot path.
The prototype supports human controllers, an AI controller with two bot seats,
and ordinary existing human-seat autopilot. AI factions use independent legal
policies, not coordinated strategy or calibrated two-faction strength. The host
can add either AI faction, configure each and remove a bot seat; if the primary
bot leaves, its remaining bot is promoted to the controller identity. Each
controller must be entirely human or entirely AI. Accepting a handover into a
browser already holding a different active seat for the same room remains
unsupported. The mode cannot be disabled while a secondary faction is present.
Recovery replaces an existing
scoped credential for the recovered seat without overwriting another valid
legacy seat. Comprehensive recovery, revocation and custody acceptance remain
open.
## Integration and evidence
- Implement one shared controller/seat contract through lobby creation,
assignment, setup, the projected active seat, action dispatch and the
shared stronghold progress and victory quote. Retain source-specific faction
counts and provisional boundaries rather than just adding a selector or
changing the victory number.
- Include focused engine tests for valid/invalid mappings, original and changed
thresholds, faction-specific private state, controlled faction decisions,
ties and the intended victory-side interpretation. Exercise a real setup and
a meaningful sequence using both factions of each controller; include legal
minimal bot participation and usable action controls.
- Test authenticated add/switch/read/action with distinct credentials, denied
target seats, stale or concurrent switches and independent private views. Do
not expose or reset unrelated rooms; use isolated dedicated test records.
- Broader recovery, revocation, privacy and custody assurance, valid module
combinations, complete human/AI games, browser/mobile acceptance and deployed
verification remain required after the rules-first prototype. A passing
focused test or this document does not certify a complete mode or change the
publication gates.