Counter each changing origin in a resident BG gather

Hold both physical groups until all required matching responses allow the original movement. Share normal packet denials across gather and ordinary moves, then resume one original movement suffix.
This commit is contained in:
Quintine committed 2026-10-24 23:16:02 +11:00
1 parent b2a20226d7
commit 0d8481e821
16 files changed
+987 -10

No files matched your search

+8
View File
@@ -2503,6 +2503,14 @@ export function GameTable({
{' '}Any already-played movement or declaration card keeps its original use. Choose a legal replacement if matching is prevented.
</p>
)}
{g.response.kind==='advisorFlip'&&g.response.advisorGatherMatchingSource&&(
<p className="notice">
Gathered group {g.response.advisorGatherMatchingPosition?.current} of {g.response.advisorGatherMatchingPosition?.total}:
{' '}the incoming forces from {territory(g.response.advisorGatherMatchingSource.origin).name} must match your residents.
{' '}Neither origin has moved, changed type or collected spice. Every required group response must allow the same original gather before it moves once.
{' '}Preventing one group leaves both origins and the movement unused, while this prevented packet here remains unavailable. Choose a legal replacement.
</p>
)}
{g.response.kind==='advisorFlip'&&g.response.advisorTransportMatchingSource&&(
<p className="notice">
The incoming transport group must match your residents before payment or force transfer.
+11
View File
@@ -10,6 +10,8 @@ import {
type PlanetologistMoveMode,
} from '@/game/planetologist-movement';
import { botGroundMoveAllowed } from '@/game/bot-mobility';
import { isAdvisor } from '@/game/advisors';
import { quoteAdvisorGatherMatching, AdvisorGatherMatchingError } from '@/game/advisor-gather-matching';
import {
gameTerritories,
location,
@@ -92,6 +94,12 @@ export function planetologistMoveDraft(
? 'The selected route is beyond the boosted range or is blocked.'
: 'Each selected source must reach the destination using its normal range.',
};
if(mode==='gather'){
try{
quoteAdvisorGatherMatching(game,{owner:me.id,move:me.moved??0,destination,sector,
advisors:isAdvisor(me,destination),group:Object.fromEntries(selected)});
}catch(error){if(!(error instanceof AdvisorGatherMatchingError))throw error;return {action:null,blocked:error.message};}
}
return {
action: {
type: 'move',
@@ -168,6 +176,9 @@ export function PlanetologistMovement({
gather forces from exactly two territories into the selected
destination.
</p>
{game.advanced&&me.faction==='beneGesserit'&&mode==='gather'&&(
<p className="notice">When joining your residents, each incoming origin that changes type has its own matching response. Both groups wait for every required allowance. Prevention leaves the movement unused and keeps both groups in place.</p>
)}
<label htmlFor={`${id}-mode`}>Movement mode</label>
<select
id={`${id}-mode`}