Compose same-plan Harass and Reinforcements with original reserve costs

This commit is contained in:
Quintine committed 2026-10-16 06:48:04 +11:00
1 parent feb2b03251
commit be0644c0e9
15 files changed
+288 -30

No files matched your search

+1 -2
View File
@@ -411,9 +411,8 @@ function calculate(input: BattleResolutionInput): BattleResolutionQuote {
!(side === d && reinforcements.length),
'Reinforcements needs a unique physical card and valid weapon and defense slot pair.');
requireQuote(!input.homeworld && !(side.leaderSkills?.length || (side === a ? d : a).leaderSkills?.length) &&
!slots.some(isHarassWithdraw) &&
!hasStone,
'Reinforcements cannot combine with Homeworld, leader skills, own Harass & Withdraw or Stone Burner.');
'Reinforcements cannot combine with Homeworld, leader skills or Stone Burner.');
const reserves = side.reinforcementsReserves!;
requireQuote(!!reserves && typeof reserves === 'object' && !Array.isArray(reserves),
'Reinforcements needs own typed reserves.');
+1 -2
View File
@@ -823,8 +823,7 @@ function plans(g: GameView): Action[] {
if ((!leader && (weapon || defense)) || !validBattleSlotPair(w, d, specialForLeader(w,leader)))
continue;
const reinforcements = weapon === 'ecaz-reinforcements' || defense === 'ecaz-reinforcements';
if (reinforcements && (weapon === 'ecaz-harass-withdraw' ||
defense === 'ecaz-harass-withdraw' || isStoneBurner(w))) continue;
if (reinforcements && isStoneBurner(w)) continue;
if (voice) {
const used =
playedVoiceMatch(
+1 -1
View File
@@ -121,7 +121,7 @@ export function cardPresentation(card: VisibleCard): CardPresentation {
? 'Recruits has development controls during Revival. Earlier paid revivals, pending transactions, later free-rate changes and repeated use this turn remain guarded pending their rulings.'
: ecaz.card.effect === 'harassWithdraw'
? 'Harass & Withdraw has development controls in either battle-card slot, with physical allocation choices after reveal. Stone Burner provisionally compares undialed forces remaining after successful withdrawal; additional optional modules remain guarded.'
: 'Reinforcements has development controls in either battle-card slot, including the explicit Advanced Occupy card variant. It spends three of the card user’s own reserve forces and adds +2 battle score without extra spice support. Charging that cost on every revealed outcome is provisional; same-plan Harass & Withdraw, Stone Burner and other optional modules remain guarded.',
: 'Reinforcements has development controls in either battle-card slot, including the explicit Advanced Occupy card variant. It spends three of the card user’s own reserve forces and adds +2 battle score without extra spice support. All-outcome payment and paying its original reserve cost before same-plan Harass returns are provisional. Returned forces cannot fund or change that cost. Stone Burner and other optional modules remain guarded.',
topics: RULE_TOPICS.filter((topic) => topic.id === (ecaz.card.effect === 'harassWithdraw' ? 'card-harass-withdraw' : ecaz.card.effect === 'reinforcements' ? 'card-reinforcements' : 'card-recruits')),
};
const topicIds =
+2 -2
View File
@@ -21252,8 +21252,8 @@ function validatePlan(
'Chemistry as a weapon needs another defense; Weirding Way as a defense needs another weapon.',
);
if ([w, d].some(isReinforcements)) {
requireRule(![w, d].some(card => isHarassWithdraw(card) || isStoneBurner(card)),
'Reinforcements cannot share this bounded plan with Harass & Withdraw or Stone Burner.');
requireRule(![w, d].some(isStoneBurner),
'Reinforcements cannot share this bounded plan with Stone Burner.');
currentReinforcementsCost(g, p);
}
if ([w, d].some(isHarassWithdraw)) currentHarassWithdrawQuote(g, p, plan);
+4 -3
View File
@@ -4950,15 +4950,15 @@ export const RULE_TOPICS: RuleTopic[] = [
'In the independent Ecaz Treachery Cards variant, place your held Reinforcements card in either battle-card slot; it is neither a weapon nor a defense. A category Prescience answer is None, not the name of this card. One physical card cannot fill both slots.',
'Have three own forces in reserves when sealing. Classic/paired Ecaz/Moritani Basic/Advanced and explicitly selected native Advanced Occupy prototypes spend ordinary reserves first and then elite reserves, moving exactly three to corresponding Tanks subpools at resolution. These are the actual card holder’s reserves, not the variable ally’s pool; no extra forces arrive.',
'The normal-outcome score gains 2 without adding to the physical dial, spice support or on-board casualties. The card and its reserve cost are consumed even on a Traitor victory, a mutual Traitor result or a Lasgun/Shield explosion; successful Traitor calls still decide the outcome directly.',
'All-outcome payment, normal-first selection and reserve transfer counting as battle losses remain provisional interpretations, not publisher rulings. The explicit Advanced Occupy/independent-card profile is verified through native and human play; Basic/unprofiled co-side, own same-plan Harass/Reinforcements, Stone Burner and other optional modules remain guarded.',
'All-outcome payment, normal-first selection and reserve transfer counting as battle losses remain provisional interpretations, not publisher rulings. Same-plan Harass & Withdraw provisionally pays the original three-reserve cost before undialed forces return; returned reserves cannot fund or change that quote. Basic/unprofiled co-side, Stone Burner and other optional modules remain guarded.',
],
related: ['battle-cards', 'battle', 'card-recruits', 'card-harass-withdraw', 'implementation-checklist'],
checklist: [
{ area: 'Implementation', status: 'Partial', detail: 'Physical card, both slots, own typed reserve cost, score-only bonus and single mandatory discard connect in classic/paired modes and explicit native Advanced Occupy. Selected lead cards/payment and variable ally casualties stay separate.', evidence: ['game/reinforcements.ts', 'game/battle-resolution-quote.ts', 'game/engine.ts'] },
{ area: 'Implementation', status: 'Partial', detail: 'Physical card, both slots, own typed reserve cost, score-only bonus and mandatory discard connect in supported profiles. Same-plan Harass preserves the original reserve quote before return; selected lead cards/payment and variable ally casualties stay separate.', evidence: ['game/reinforcements.ts', 'game/battle-resolution-quote.ts', 'game/engine.ts'] },
{ area: 'Player controls', status: 'Partial', detail: 'Owner-only availability, exact cost guidance and both battle selectors support the card; private category answers remain None.', evidence: ['components/battle-preparation.tsx', 'components/game-table.tsx'] },
{ area: 'AI', status: 'Partial', detail: 'Four profiles consider legal physical slot candidates and the normal score bonus; strategy and calibration remain unfinished.', evidence: ['game/bots.ts'] },
{ area: 'Documentation', status: 'Partial', detail: 'The printed effect and unresolved Traitor, explosion, type-selection and accounting interpretations are distinguished from this temporary prototype.', evidence: ['docs/ECAZ_TREACHERY_RULES.md', 'docs/REINFORCEMENTS_RUNTIME.md'] },
{ area: 'Verification', status: 'Partial', detail: 'Existing rule/control proofs plus combined-card67 cases, actual27-case program, four policies, natural combined games and390px decisive equal-leader Reinforcements cover the bounded profile. Full faction/optional-module acceptance remains open; comprehensive assurance follows all rules.', evidence: ['tests/reinforcements.test.ts', 'tests/reinforcements-engine.test.ts', 'tests/ecaz-occupy-cards-runtime.test.ts', 'docs/ECAZ_OCCUPY_RULES.md'] },
{ area: 'Verification', status: 'Partial', detail: 'Original rule/control proof and same-plan Harass regressions cover both slots, unfunded original reserves, typed cost-before-return, Traitor/explosion and fixed/variable Occupy. Actual mobile control and legal four-profile smoke are bounded evidence; complete modes, calibration and final assurance remain open.', evidence: ['tests/harass-reinforcements.test.ts', 'tests/reinforcements.test.ts', 'tests/reinforcements-engine.test.ts', 'tests/ecaz-occupy-cards-runtime.test.ts', 'docs/ECAZ_OCCUPY_RULES.md'] },
],
},
{
@@ -4975,6 +4975,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'Discard Harass after use, including a win by your own Traitor call. Reveal-before-explosion return and card-specific discard precedence are explicit implementation inferences; neither is a dedicated combined FAQ ruling.',
'For multiple legal physical allocations, choose all undialed ordinary and elite counters by sector after both plans reveal and before traitor declarations. Unique returns are automatic. The selected return is public; it is not an extra sealed plan element. Stone Burner provisionally compares the undialed forces remaining after successful withdrawal, including same-plan, opposing and copied Stone. Additional optional modules remain guarded. The printed card forbids use on your own Homeworld.',
'In explicitly selected Advanced Occupy, only the actual card user’s undialed forces return. An Ecaz user preserves its original mandatory fixed count at free full strength; an allied user uses its native variable commitment, while canceled Occupy uses its selected lead’s ordinary own pool. Returned reserves remain outside losses and Face Dance. Basic/unprofiled co-side, public starts and full acceptance remain gated.',
'In supported same-plan Reinforcements, the provisional order pays three original own reserves before Harass returns undialed counters. Future returns cannot fund or change that reserve quote; neither the +2 score bonus nor that cost adds to the physical commitment. Both cards discard after use. An opposing successful Traitor cancels Harass but not the provisional Reinforcements cost.',
],
related: ['battle-cards', 'battle', 'card-recruits', 'ecaz-modules', 'implementation-checklist'],
checklist: [