feat: Implement smart auto-pass for non-active players and add a UI button to suspend it.

This commit is contained in:
2025-12-23 01:23:43 +01:00
parent 23b8e3203d
commit e655e3efe2
2 changed files with 55 additions and 15 deletions

View File

@@ -78,6 +78,7 @@ export const GameView: React.FC<GameViewProps> = ({ gameState, currentPlayerId }
const [hoveredCard, setHoveredCard] = useState<CardInstance | null>(null);
const [dragAnimationMode, setDragAnimationMode] = useState<'start' | 'end'>('end');
const [previewTappedIds, setPreviewTappedIds] = useState<Set<string>>(new Set());
const [stopRequested, setStopRequested] = useState(false);
// Auto-Pass Priority if Yielding
useEffect(() => {
@@ -162,7 +163,31 @@ export const GameView: React.FC<GameViewProps> = ({ gameState, currentPlayerId }
// If I manually enable it, isBotTurn is false. We simply don't interfere.
// This allows accurate Manual Yielding!
}
}, [gameState.activePlayerId, gameState.step, isBotTurn]); // Removed isYielding dependency to avoid loops?
}, [gameState.activePlayerId, gameState.step, isBotTurn]);
// --- Smart Auto-Pass (Suspend Logic) ---
useEffect(() => {
setStopRequested(false);
}, [gameState.step, gameState.turn]);
useEffect(() => {
// Smart Auto-Pass Logic for NAP
if (!gameState.activePlayerId) return;
const amActivePlayer = gameState.activePlayerId === currentPlayerId;
const amPriorityPlayer = gameState.priorityPlayerId === currentPlayerId;
// Condition: I am NAP, I have Priority, and I have NOT requested a stop.
// Logic: Auto-Pass.
if (!amActivePlayer && amPriorityPlayer && !stopRequested) {
if (gameState.step === 'declare_blockers') return; // Explicit wait for blockers
console.log("[Smart Auto-Pass] Auto-passing priority as NAP (No Suspend requested).");
const timer = setTimeout(() => {
socketService.socket.emit('game_strict_action', { action: { type: 'PASS_PRIORITY' } });
}, 800);
return () => clearTimeout(timer);
}
}, [gameState.activePlayerId, gameState.priorityPlayerId, stopRequested, currentPlayerId, gameState.step]);
// If I access `isYielding` inside `setIsYielding`, I don't need it in dependency.
// But wait, the `if (['declare_...'].includes)` logic needs to potentially set it false.
// setIsYielding(false) is fine.

View File

@@ -10,6 +10,8 @@ interface PhaseStripProps {
contextData?: any;
isYielding?: boolean;
onYieldToggle?: () => void;
stopRequested?: boolean;
onToggleSuspend?: () => void;
}
export const PhaseStrip: React.FC<PhaseStripProps> = ({
@@ -18,7 +20,9 @@ export const PhaseStrip: React.FC<PhaseStripProps> = ({
onAction,
contextData,
isYielding,
onYieldToggle
onYieldToggle,
stopRequested,
onToggleSuspend
}) => {
const currentPhase = gameState.phase as Phase;
const currentStep = gameState.step as Step;
@@ -63,12 +67,6 @@ export const PhaseStrip: React.FC<PhaseStripProps> = ({
}
}
} else if (currentStep === 'declare_blockers') {
// If it's MY turn (Active Player), I should NEVER verify blocks myself?
// Actually Rules say AP gets priority after blocks.
// So if I have priority, it MUST mean blocks are done (or I'm waiting for them, but then I wouldn't have priority?)
// Wait, if I am AP, and I have priority in this step, it means blocks are implicitly done (flag should be true).
// Fallback: If I am Active Player, always show "To Damage".
const showToDamage = gameState.blockersDeclared || isMyTurn; // UI Safety for AP
if (showToDamage) {
@@ -88,19 +86,36 @@ export const PhaseStrip: React.FC<PhaseStripProps> = ({
else if (gameState.phase === 'main2') actionLabel = "End Turn";
else actionLabel = "Pass";
} else {
// Resolve
// const topItem = gameState.stack![gameState.stack!.length - 1]; // Unused
// Resolve Logic
actionLabel = "Resolve";
actionType = 'PASS_PRIORITY';
ActionIcon = Zap;
actionColor = "bg-amber-600 hover:bg-amber-500 shadow-[0_0_10px_rgba(245,158,11,0.4)]";
}
} else {
// Waiting
actionLabel = "Waiting...";
ActionIcon = Hand;
actionColor = "bg-white/5 text-slate-500 cursor-not-allowed";
isActionEnabled = false;
// NOT PRIORITY (Waiting)
// Suspend Button Logic for NAP
if (!isMyTurn) {
isActionEnabled = true;
if (stopRequested) {
actionLabel = "Stop Set";
ActionIcon = Hand;
actionColor = "bg-red-600 hover:bg-red-500 animate-pulse font-bold border border-red-400";
actionType = 'TOGGLE_SUSPEND';
} else {
actionLabel = "Suspend";
ActionIcon = Hand;
actionColor = "bg-yellow-600/80 hover:bg-yellow-500 text-yellow-50 border border-yellow-500/50";
actionType = 'TOGGLE_SUSPEND';
}
} else {
// I am AP but don't have priority? (Maybe waiting for server?)
actionLabel = "Waiting...";
ActionIcon = Hourglass;
actionColor = "bg-white/5 text-slate-500 cursor-not-allowed";
isActionEnabled = false;
}
}
const handleAction = (e: React.MouseEvent) => {