1var A=Object.defineProperty;var T=(c,h,t)=>h in c?A(c,h,{enumerable:!0,configurable:!0,writable:!0,value:t}):c[h]=t;var I=(c,h,t)=>T(c,typeof h!="symbol"?h+"":h,t);import{C as D,c as v}from"./StandardCardDeck-tKaoHSoz.js";import{A as g,I as C,S as w}from"./constants-B15WovBv.js";import{aE as y,aB as f}from"./App-D-ImILX3.js";import{p as S,P as m}from"./PointsService-D1QXg7ii.js";import"./BaseGame-D1nEkUH_.js";import"./main-Cag9XV9j.js";import"./gameInvites-Co2UxEv6.js";import"./playerMode-DD_Mirki.js";import"./logService-C5MzElq8.js";import"./badgeToastSound-CXv8xya1.js";class F extends D{constructor(t,e){const a=e??{},s=typeof a.rng=="function"?a.rng:void 0,i=v({rng:s,aceHigh:!0});let r;Array.isArray(a.seats)?r=a.seats:r=[{id:typeof(e==null?void 0:e.currentUserId)=="string"&&e.currentUserId||typeof a.userId=="string"&&a.userId||"user1",type:"human",isCurrentUser:!0,name:typeof(e==null?void 0:e.userName)=="string"&&e.userName?e.userName:"You"},{id:"ai1",type:"ai",name:"AI"}];super("crazy_8s",t,{...e,deck:i,seats:r,initialHandSize:(e==null?void 0:e.initialHandSize)||C,aiPacingMs:(e==null?void 0:e.aiPacingMs)||g});I(this,"aiTurnTimer");console.log(`ð Crazy8Game: Created with ${r.length} players`)}addEffect(t,e,a){this.state.effects=[...this.state.effects,{type:t,cardId:e,color:a,addedAt:Date.now()}],this.notifyStateListeners()}removeEffect(t){this.state.effects=this.state.effects.filter(e=>e.cardId!==t),this.notifyStateListeners()}acknowledgeEffect(t){var a,s;console.log("ð§¹ acknowledgeEffect called for:",t);const e=this.state.effects.find(i=>i.cardId===t);if(!e){console.log("â No effect found for:",t);return}console.log("â
Effect found, type:",e.type),this.state.effects=this.state.effects.filter(i=>i.cardId!==t),e.type==="drawn"&&((a=this.state.lastDrawnCard)==null?void 0:a.id)===t&&(console.log("ðï¸ Clearing lastDrawnCard"),this.state.lastDrawnCard=null),console.log("ð State after acknowledge:",{effectsCount:this.state.effects.length,lastDrawnCard:((s=this.state.lastDrawnCard)==null?void 0:s.id)||"null",highlightedCardIds:this.state.highlightedCardIds}),this.state.updatedAt=Date.now(),this.updateUIState(),this.notifyStateListeners()}scheduleAiTurn(t){this.aiTurnTimer&&clearTimeout(this.aiTurnTimer);const e=t||g;this.aiTurnTimer=setTimeout(()=>{this.processAITurn()},e)}hasAIOpponent(){return!this.state||!this.state.players?!0:this.state.players.some(t=>t.type==="ai")}advance(t=1){this.state.lastDrawnCard=null,super.advance(t),console.log("ð Turn advanced, lastDrawnCard cleared for new player:",this.state.currentPlayerId),this.applyPenaltiesIfNeeded()}applyPenaltiesIfNeeded(){const t=this.state.currentPlayerId;if(this.state.nextPlayerMustSkip){console.log("âï¸ Applying skip penalty to:",t),this.state.statusMessage=`${super.getPlayerName(t)} was skipped by a Jack!`,this.state.nextPlayerMustSkip=!1,this.state.updatedAt=Date.now(),this.updateUIState(),this.notifyStateListeners(),this.advance(1);return}if(this.state.nextPlayerMustDraw>0){const e=this.state.nextPlayerMustDraw;console.log("ð¥ Applying draw penalty:",e,"cards to:",t);const a=this.state.hands[t].length;this.drawTo(t,e);const s=this.state.hands[t];for(let i=a;i<s.length;i++)this.addEffect("drawn",s[i].id,"green");this.state.statusMessage=`${super.getPlayerName(t)} drew ${e} cards from Queen of Spades!`,this.state.nextPlayerMustDraw=0,this.state.updatedAt=Date.now(),this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners();return}this.state.twoStackActive&&this.state.pendingTwoDrawCount>0&&this.handleTwoStackAtTurnStart(t)}customizeInitialState(t,e){return{...t,gameType:"crazy_8s",topDiscardCard:null,currentSuit:null,activePlayerId:t.playersOrder[0]||"",canDraw:!0,mustPass:!1,pendingSuitSelection:!1,statusMessage:"Game starting...",userScore:0,aiScore:0,nextPlayerMustSkip:!1,nextPlayerMustDraw:0,twoStackActive:!1,pendingTwoDrawCount:0,twoStackTargetId:null,effects:[],playableCardIds:[],highlightedCardIds:[],availableActions:["draw"],uiState:"normal",suitSelectorVisible:!1}}start(){if(console.log("ð® Crazy8Game: Starting game"),this.initRound(this.state.drawPile,this.state.playersOrder,C),this.state.drawPile.length>0){const t=this.state.drawPile.pop();if(this.state.discardPile=[t],this.state.topDiscardCard=t,t.rank==="8"){const e=w[Math.floor(this.rng()*w.length)];this.state.currentSuit=e,this.state.statusMessage=`Starting card is an 8. Current suit is ${e}.`}else this.state.currentSuit=t.suit,this.state.statusMessage=`Game started. Current suit is ${t.suit}.`}this.state.gameStatus="playing",this.updateUIState(),super.start(),y("crazy_8s_start",this.state),console.log("ð Crazy8Game: Game started successfully")}canPlay(t,e,a){return t.rank==="8"?!0:!a.currentSuit||!e?!1:t.suit===a.currentSuit||t.rank===e.rank}resolvePlay(t,e,a){var s,i,r;if(a.lastPlayedCard=t,a.topDiscardCard=t,a.lastDrawnCard=null,a.hands[e].length===0){if(this.gameMode!=="multiplayer"){const d=a.players.find(l=>l.type==="human"),u=a.players.find(l=>l.type==="ai");
1if(d&&u){const l=e===d.id,o=l?this.calculateHandValue(a.hands[u.id]||[]):this.calculateHandValue(a.hands[d.id]||[]);a.userScore=l?o:0,a.aiScore=l?0:o}}a.gameWinner=e,a.status="ended",a.gameStatus="ended",a.statusMessage=`${super.getPlayerName(e)} wins!`,console.log("ð Crazy 8s Game Winner:",{winnerId:e,winnerName:super.getPlayerName(e),humanId:(s=a.players.find(d=>d.type==="human"))==null?void 0:s.id,aiId:(i=a.players.find(d=>d.type==="ai"))==null?void 0:i.id,allPlayers:a.players.map(d=>({id:d.id,name:d.name,type:d.type}))}),this.notifyStateListeners(),y("crazy_8s_end",a,{winner:e}),this.publishEvent("gameEnd"),f.play("game-end"),S.awardPoints(m.universal.completeGame,"completeGame","crazy_8s",this.gameId),e===((r=a.players.find(d=>d.type==="human"))==null?void 0:r.id)&&(f.play("win"),S.awardPoints(m.universal.winGame,"winGame","crazy_8s",this.gameId)),(async()=>{var d,u;if(await this.recordGameResultAndAdjustSkill(),this.gameMode==="multiplayer")this.endGame();else{const l=a.players.find(p=>p.type==="human"),o=a.players.find(p=>p.type==="ai");if(l&&o){const p=a.userScore??0,P=a.aiScore??0;console.log("ð Crazy 8s Scores:",{humanScore:p,aiScore:P,humanCards:((d=a.hands[l.id])==null?void 0:d.length)||0,aiCards:((u=a.hands[o.id])==null?void 0:u.length)||0,winner:e===l.id?"human":"ai"});const k={outcome:e===l.id?"win":"loss",score:p,opponent_score:P};this.endGame(k)}else this.endGame()}})();return}if(t.rank==="2"&&this.handleTwoPlayed(e,a),t.rank==="8")if(this.isAiPlayer(e)){const n=this.getAIOptimalSuit(e);a.currentSuit=n,a.statusMessage=`${super.getPlayerName(e)} played an 8 and chose ${n}!`}else{a.pendingSuitSelection=!0,a.statusMessage="Choose a suit for your 8!",a.updatedAt=Date.now(),this.updateUIState(),this.notifyStateListeners();return}else t.rank==="J"?(a.currentSuit=t.suit,a.nextPlayerMustSkip=!0,a.statusMessage=`${super.getPlayerName(e)} played a Jack! Next player must skip.`):t.rank==="Q"&&t.suit==="spades"?(a.currentSuit=t.suit,a.nextPlayerMustDraw=5,a.statusMessage=`${super.getPlayerName(e)} played Queen of Spades! Next player must draw 5.`):(a.currentSuit=t.suit,a.statusMessage=`${super.getPlayerName(e)} played ${t.rank} of ${t.suit}`);if(a.twoStackActive&&a.pendingTwoDrawCount>0&&a.twoStackTargetId){const n=super.getPlayerName(a.twoStackTargetId);a.statusMessage=`${super.getPlayerName(e)} played a 2! ${n} must play a 2 or draw ${a.pendingTwoDrawCount}.`}if(a.updatedAt=Date.now(),this.updatePlayabilityFlags(a),this.updateUIState(),this.notifyStateListeners(),y("crazy_8s_card_played",a,{playerId:e,card:t.rank+" of "+t.suit}),!a.pendingSuitSelection){this.advance(1);const n=this.getCurrentPlayer();(n==null?void 0:n.type)==="ai"&&this.scheduleAiTurn(500)}}applyEffects(){this.drainPendingEffects().forEach(e=>{console.log("ð¯ Processing effect:",e)})}handleTwoPlayed(t,e){const a=this.getNextPlayerId(t);e.twoStackActive=!0,e.pendingTwoDrawCount=(e.pendingTwoDrawCount||0)+2,e.twoStackTargetId=a}handleTwoStackAtTurnStart(t){return!this.state.twoStackActive||this.state.pendingTwoDrawCount<=0||this.state.twoStackTargetId!==t?"continue":this.canPlayerRespondWithTwo(t)?(this.state.canDraw=!1,this.state.mustPass=!1,this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners(),"continue"):(this.applyTwoStackPenalty(t),"drew")}applyTwoStackPenalty(t){const e=this.state.pendingTwoDrawCount,a=this.state.hands[t].length;this.drawTo(t,e);const s=this.state.hands[t];for(let i=a;i<s.length;i++)this.addEffect("drawn",s[i].id,"green");this.state.statusMessage=`${super.getPlayerName(t)} drew ${e} cards from stacked twos.`,this.clearTwoStack(),this.state.updatedAt=Date.now(),this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners()}clearTwoStack(){this.state.twoStackActive=!1,this.state.pendingTwoDrawCount=0,this.state.twoStackTargetId=null}getNextPlayerId(t){const e=this.state.playersOrder,s=(e.indexOf(t)+1)%e.length;return e[s]}canPlayerRespondWithTwo(t){return(this.state.hands[t]||[]).some(e=>e.rank==="2")}playCardByObject(t,e){const a=this.state.currentPlayerId,s=this.state.hands[a];if(console.log("ð¯ playCardByObject called with:",{cardId:t.id,cardSuit:t.suit,cardRank:t.rank,playerId:a,handSize:s==null?void 0:s.length}),!s)throw new Error("Player has no hand");console.log("ð¯ Searching in hand:",s.map(n=>({id:n.id,suit:n.suit,rank:n.rank})));const i=s.findIndex(n=>n.id===t.id||n.suit===t.suit&&n.rank===t.rank);
1if(console.log("ð¯ Card index found:",i),i===-1)throw console.error("â Card not found in hand!",{searchingFor:{id:t.id,suit:t.suit,rank:t.rank},handCards:s.map(n=>({id:n.id,suit:n.suit,rank:n.rank}))}),new Error("Card not in hand");if(!this.canPlay(t,this.state.topDiscardCard||void 0,this.state))throw new Error("Invalid play - card does not match suit or rank");this.wrapMultiplayerTurnAction("play_card",()=>(this.playCard_internal(i,e),this.state)),this.addEffect("highlight",t.id,"green");const r=this.getCurrentPlayer();(r==null?void 0:r.type)==="ai"&&this.scheduleAiTurn()}isCardPlayable(t){return this.canPlay(t,this.state.topDiscardCard||void 0,this.state)}playCard_internal(t,e){const a=this.state.currentPlayerId,s=this.state.hands[a];s[t];const i=[...s],[r]=i.splice(t,1);this.state.hands[a]=i,this.state.discardPile=[...this.state.discardPile,r],this.resolvePlay(r,a,this.state),f.play("card-place"),(r.rank==="8"||r.rank==="2"||r.rank==="J"||r.rank==="Q"&&r.suit==="spades")&&!this.isAiPlayer(a)&&S.awardPoints(m.crazy8s.playSpecialCard,"play_special","crazy_8s",this.gameId),r.rank==="8"&&e&&!this.isAiPlayer(a)&&this.selectSuit(e)}drawCard(){const t=this.state.currentPlayerId;if(!this.state.canDraw)throw new Error("Cannot draw - no cards available");console.log("ð¯ Drawing card for player:",t,"Draw pile size:",this.state.drawPile.length),this.wrapMultiplayerAction("draw_card",()=>(this.drawTo(t,1),f.play("card-deal"),this.state.lastDrawnCard=this.state.hands[t][this.state.hands[t].length-1],this.state.statusMessage=`${super.getPlayerName(t)} drew a card`,console.log("ð¯ After drawing - Hand size:",this.state.hands[t].length,"Draw pile size:",this.state.drawPile.length),this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners(),y("crazy_8s_turn",this.state,{action:"draw",playerId:t}),this.state.lastDrawnCard&&this.addEffect("drawn",this.state.lastDrawnCard.id,"green"),this.state))}passTurn(){const t=this.state.currentPlayerId;this.wrapMultiplayerTurnAction("pass_turn",()=>{this.state.statusMessage=`${super.getPlayerName(t)} passed their turn`,this.state.lastDrawnCard=null,this.gameMode!=="multiplayer"&&this.advance(1),this.updateUIState(),y("crazy_8s_turn",this.state,{action:"pass",playerId:t});const e=this.state.players[this.state.current];return(e==null?void 0:e.type)==="ai"&&this.scheduleAiTurn(500),this.state})}selectSuit(t){if(!this.state.pendingSuitSelection)throw new Error("No suit selection pending");this.wrapMultiplayerAction("select_suit",()=>{this.state.currentSuit=t,this.state.selectedSuit=t,this.state.pendingSuitSelection=!1,this.state.statusMessage=`Suit changed to ${t}!`,this.state.updatedAt=Date.now(),this.updateUIState(),this.notifyStateListeners(),this.advance(1);const e=this.getCurrentPlayer();return(e==null?void 0:e.type)==="ai"&&setTimeout(()=>this.processAITurn(),g),this.state})}cancelSuitSelection(){if(!this.state.pendingSuitSelection)return;const t=this.state.currentPlayerId,e=this.state.discardPile[this.state.discardPile.length-1];if(!e||e.rank!=="8")throw new Error("No pending wild 8 to cancel");this.wrapMultiplayerAction("cancel_suit_selection",()=>(this.state.discardPile=this.state.discardPile.slice(0,-1),this.state.hands[t]=[...this.state.hands[t],e],this.state.topDiscardCard=this.state.discardPile[this.state.discardPile.length-1]??null,this.state.lastPlayedCard=this.state.topDiscardCard,this.state.pendingSuitSelection=!1,this.state.selectedSuit=null,this.state.statusMessage=`${super.getPlayerName(t)} canceled suit selection`,this.state.updatedAt=Date.now(),this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners(),this.state))}processAITurn(){if(console.log("ð¤ AI Turn Processing - Current player:",this.state.currentPlayerId,"Status:",this.state.status),this.state.status==="ended"){console.log("â AI Turn aborted - game ended");return}const t=this.state.currentPlayerId;if(!this.isAiPlayer(t)){console.log("â AI Turn aborted - not AI player:",t);return}if(this.state.twoStackActive&&this.state.pendingTwoDrawCount>0&&this.handleTwoStackAtTurnStart(t)==="drew")return;const e=this.state.hands[t],a=this.getPlayableCards(e);if(console.log("ð¯ AI has",a.length,"playable cards out of",e.length,"total cards"),a.length>0){const s=this.getAICardChoice(a,e),i=e.findIndex(r=>
1r.id===s.id);console.log("ð AI playing card:",s.rank,"of",s.suit),this.wrapMultiplayerTurnAction("ai_play_card",()=>(this.playCard_internal(i),console.log("â
AI played card - turn should now be:",this.state.currentPlayerId),this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners(),this.state))}else this.state.canDraw?(console.log("ð¥ AI drawing card"),this.wrapMultiplayerAction("ai_draw_card",()=>{this.drawTo(t,1),this.state.lastDrawnCard=this.state.hands[t][this.state.hands[t].length-1],this.state.statusMessage=`${super.getPlayerName(t)} drew a card`;const s=this.state.lastDrawnCard;if(console.log("ð¥ AI drew:",s.rank,"of",s.suit),this.canPlay(s,this.state.topDiscardCard||void 0,this.state)){const i=this.rng()*100<this.getAIOptimalPlayChance();if(console.log("ð¯ Drawn card is playable, AI should play:",i),i){const r=this.state.hands[t].length-1;return setTimeout(()=>{console.log("ð AI playing drawn card immediately"),this.wrapMultiplayerTurnAction("ai_play_drawn_card",()=>(this.playCard_internal(r),console.log("â
AI played drawn card - turn should now be:",this.state.currentPlayerId),this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners(),this.state))},g/2),this.state}}return console.log("âï¸ AI passing turn after drawing"),this.wrapMultiplayerTurnAction("ai_pass_turn_after_draw",()=>(this.state.statusMessage=`${super.getPlayerName(t)} passed their turn`,this.gameMode!=="multiplayer"&&this.advance(1),console.log("â
AI passed turn - turn should now be:",this.state.currentPlayerId),this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners(),this.state)),this.state})):(console.log("âï¸ AI must pass - no cards to draw"),this.wrapMultiplayerTurnAction("ai_pass_turn",()=>(this.state.statusMessage=`${super.getPlayerName(t)} passed their turn`,this.gameMode!=="multiplayer"&&this.advance(1),console.log("â
AI passed turn - turn should now be:",this.state.currentPlayerId),this.updatePlayabilityFlags(this.state),this.updateUIState(),this.notifyStateListeners(),this.state)))}getPlayableCards(t){if(this.state.twoStackActive&&this.state.pendingTwoDrawCount>0&&this.state.twoStackTargetId===this.state.currentPlayerId){const a=t.filter(s=>s.rank==="2");return a.length>0?a:[]}return t.filter(a=>this.canPlay(a,this.state.topDiscardCard||void 0,this.state))}calculateHandValue(t){return t.reduce((e,a)=>{if(a.rank==="8")return e+50;if(["J","Q","K"].includes(a.rank))return e+10;if(a.rank==="A")return e+1;const s=parseInt(a.rank);return e+(isNaN(s)?0:s)},0)}getAICardChoice(t,e){const s=(5-this.getAISkillLevel())*20;if(this.rng()*100<s)return t[Math.floor(this.rng()*t.length)];const i=e.length,r=t.filter(l=>l.rank==="J"),n=t.find(l=>l.rank==="Q"&&l.suit==="spades"),d=t.filter(l=>l.rank==="8"),u=t.filter(l=>l.rank!=="8"&&l.rank!=="J"&&!(l.rank==="Q"&&l.suit==="spades"));if(i<=3){if(n)return n;if(r.length>0)return r[0]}return u.length>0?u.reduce((l,o)=>o.value>l.value?o:l):r.length>0?r[0]:n||(d.length>0?d[0]:t[0])}getAIOptimalSuit(t){const e=this.state.hands[t],a={hearts:0,diamonds:0,clubs:0,spades:0};return e.forEach(s=>{s.rank!=="8"&&a[s.suit]++}),w.reduce((s,i)=>
1a[i]>a[s]?i:s)}updatePlayabilityFlags(t){const e=t.currentPlayerId,a=t.hands[e],s=t.twoStackActive&&t.pendingTwoDrawCount>0&&t.twoStackTargetId===e,i=t.drawPile.length+Math.max(0,t.discardPile.length-1);t.canDraw=i>0&&!t.lastDrawnCard,s&&(t.canDraw=!1);const r=this.getPlayableCards(a);t.mustPass=r.length===0&&!t.canDraw,s&&(t.mustPass=!1),console.log("ð¯ Updated playability flags:",{currentPlayer:e,handSize:a.length,canDraw:t.canDraw,mustPass:t.mustPass,playableCardsCount:r.length,lastDrawnCard:t.lastDrawnCard?`${t.lastDrawnCard.rank} of ${t.lastDrawnCard.suit}`:"none"})}updateUIState(){const t=this.state,e=t.currentPlayerId,a=!this.isAiPlayer(e),s=t.status==="ended",i=t.twoStackActive&&t.pendingTwoDrawCount>0&&t.twoStackTargetId===e;if(a&&!s){const r=t.hands[e]||[],n=this.getPlayableCards(r);t.playableCardIds=n.map(d=>d.id),i&&n.length>0&&(t.highlightedCardIds=n.map(d=>d.id))}else t.playableCardIds=[];i&&t.playableCardIds.length>0||(t.highlightedCardIds=[],t.lastDrawnCard&&(t.highlightedCardIds=[t.lastDrawnCard.id])),t.availableActions=[],a&&!s&&(t.playableCardIds.length>0&&t.availableActions.push("play"),t.canDraw&&t.availableActions.push("draw"),t.mustPass&&t.availableActions.push("pass"),i&&(t.availableActions=t.availableActions.filter(r=>r==="play"))),t.pendingSuitSelection?t.uiState="selectingSuit":t.uiState="normal",t.suitSelectorVisible=!!t.pendingSuitSelection&&a,console.log("ð¨ UI State updated:",{playableCards:t.playableCardIds.length,highlightedCards:t.highlightedCardIds.length,availableActions:t.availableActions,uiState:t.uiState,suitSelectorVisible:t.suitSelectorVisible})}getView(t){const e=super.getView(t);return{...e,hands:Object.fromEntries(Object.entries(e.hands).map(([a,s])=>a===t?[a,s]:[a,s.map((i,r)=>({id:`hidden-${a}-${r}`,kind:"standard",suit:"hearts",rank:"2",value:0,tags:{hidden:!0}}))]))}}}export{F as Crazy8Game};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.