Make Fremen allied revival grants cancelable
Bind the original Fremen/ally/turn grant before Karama allowance or prevention. A prevented grant leaves intrinsic free rates and prior payments intact. Permit late grants under the explicit provisional Recruits current-rate policy, with shared controls, minimal bot support and native public chronology evidence. Complete rules and browser/deployed acceptance remain open.
This commit is contained in:
1 parent
d63efccb55
commit
0e3d6a250e
23 files changed
+1183
-44
No files matched your search
@@ -0,0 +1,66 @@
|
||||
'use client';
|
||||
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import type { Action, GameView } from '@/game/engine';
|
||||
|
||||
export function FremenRevivalGrant({
|
||||
game,
|
||||
act,
|
||||
busy,
|
||||
}: {
|
||||
game: GameView;
|
||||
act: (action: Action) => void;
|
||||
busy: boolean;
|
||||
}) {
|
||||
const grant = game.fremenRevivalGrant;
|
||||
const me = game.players.find((player) => player.id === game.me);
|
||||
if (!grant || game.status !== 'playing' || game.phase !== 4 ||
|
||||
me?.faction !== 'fremen' || me.ally !== grant.recipient) return null;
|
||||
const recipient = game.players.find((player) => player.id === grant.recipient)?.name ?? 'your ally';
|
||||
const disabled = busy || !!game.truthtrance || !!game.nexusTraitors?.pending ||
|
||||
!!grant.blocked || grant.granted;
|
||||
return (
|
||||
<section className="notice space-y-3" aria-label="Fremen ally free revival">
|
||||
<h3 className="font-serif text-xl">Fremen ally revival</h3>
|
||||
<p className="muted">
|
||||
Grant {recipient} an ordinary free force revival rate of three this phase. This
|
||||
replaces their native ordinary rate rather than adding three. Ordinary total
|
||||
revival and special-force limits still apply.
|
||||
</p>
|
||||
<p className="fine">
|
||||
Provisional current-rate policy: Recruits doubles the current granted rate, including applicable bonuses,
|
||||
before caps. Without other bonuses, three becomes six.
|
||||
Later grants use the same current-rate calculation;
|
||||
your ally’s revival controls show the actual remaining allowance.
|
||||
Previously recorded free returns use the allowance. Earlier paid returns keep their payments and count
|
||||
toward the total revival limit; there is no refund or retroactive
|
||||
reclassification.
|
||||
</p>
|
||||
<p className="fine">
|
||||
Another player may use Karama before the original alliance grant takes effect.
|
||||
Canceling blocks this Fremen grant to the current ally for this Revival;
|
||||
the ally retains its intrinsic rate and Recruits. Completed revivals and
|
||||
payments stay unchanged. This response timing and prevention scope are provisional.
|
||||
</p>
|
||||
{grant.granted && (
|
||||
<p className="muted">Free revival has been granted to {recipient} for this phase.</p>
|
||||
)}
|
||||
{grant.blocked && (
|
||||
<p className="notice" id="fremen-revival-grant-unavailable">{grant.blocked}</p>
|
||||
)}
|
||||
<Button
|
||||
data-testid="fremen-revival-grant-submit"
|
||||
className="game-action"
|
||||
disabled={disabled}
|
||||
aria-describedby={grant.blocked ? 'fremen-revival-grant-unavailable' : undefined}
|
||||
onClick={() => {
|
||||
if (!disabled) act({ type: 'grantRevival' });
|
||||
}}
|
||||
>
|
||||
Grant ally free revival
|
||||
<ArrowRight size={15} />
|
||||
</Button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
+12
-11
@@ -52,6 +52,7 @@ import { NexusSardaukar } from './nexus-sardaukar';
|
||||
import { TerrorBoardMarkers } from './terror-board-markers';
|
||||
import { AmbassadorBoardMarkers } from './ambassador-board-markers';
|
||||
import { CharityClaim } from './charity-claim';
|
||||
import { FremenRevivalGrant } from './fremen-revival-grant';
|
||||
import { homeworldRevivalActionBlock } from '@/game/homeworld-revival-deployment-options';
|
||||
import { GuildHomeworldShipment } from './guild-homeworld-shipment';
|
||||
import { JunctionTransport } from './junction-transport';
|
||||
@@ -2423,6 +2424,7 @@ export function GameTable({
|
||||
advisor: 'Spiritual advisor',
|
||||
emperorGift: 'Emperor spice gift',
|
||||
emperorRevival: 'Emperor extra revival',
|
||||
fremenRevivalGrant: 'Fremen allied free revival',
|
||||
bgCharity: 'Bene Gesserit charity',
|
||||
choamCharity: 'CHOAM charity income',
|
||||
choamInflation: 'CHOAM Inflation placement',
|
||||
@@ -2546,6 +2548,14 @@ export function GameTable({
|
||||
allow five forces.
|
||||
</p>
|
||||
)}
|
||||
{g.response.kind === 'fremenRevivalGrant' && (
|
||||
<p className="notice">
|
||||
Fremen offered their current ally the ordinary free-revival rate of three.
|
||||
Karama can prevent this grant before it takes effect. Recruits uses the
|
||||
current valid rate after settlement, with prior returns and payments retained.
|
||||
Response timing and prevention of this grant for the current Revival are provisional.
|
||||
</p>
|
||||
)}
|
||||
{g.response.kind === 'choamCharity' && (
|
||||
<p className="muted">
|
||||
CHOAM receives{' '}
|
||||
@@ -4367,19 +4377,10 @@ export function GameTable({
|
||||
? ' · Tleilaxu half-price discount'
|
||||
: ''}
|
||||
</p>
|
||||
{me.faction === 'fremen' &&
|
||||
me.ally &&
|
||||
!g.freeRevival.includes(me.ally) &&
|
||||
actionButton('Grant ally three free revivals', {
|
||||
type: 'grantRevival',
|
||||
}, !!g.recruitsPreview?.grantRevivalBlocked,
|
||||
g.recruitsPreview?.grantRevivalBlocked ? 'recruits-grant-unavailable' : undefined)}
|
||||
{me.faction === 'fremen' && me.ally && !g.freeRevival.includes(me.ally) && g.recruitsPreview?.grantRevivalBlocked && (
|
||||
<p className="notice" id="recruits-grant-unavailable">{g.recruitsPreview.grantRevivalBlocked}</p>
|
||||
)}
|
||||
<FremenRevivalGrant game={g} act={act} busy={busy} />
|
||||
{g.freeRevival.includes(me.id) && !g.revival.freeBlocked && (
|
||||
<p className="muted">
|
||||
Fremen allow you up to {g.recruitsPreview?.active ? 'six' : 'three'} free force revivals this phase.
|
||||
Fremen’s grant is active. Your current free allowance above includes Recruits and any applicable bonuses.
|
||||
</p>
|
||||
)}
|
||||
{amountInput}
|
||||
|
||||
Reference in new issue
Block a user