| <!DOCTYPE html> |
| <html lang="ar" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>لعبة سكرو - Skru Card Game</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap'); |
| |
| body { |
| font-family: 'Tajawal', sans-serif; |
| background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); |
| min-height: 100vh; |
| } |
| |
| .card { |
| width: 80px; |
| height: 120px; |
| border-radius: 8px; |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
| transition: all 0.3s ease; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| font-weight: bold; |
| position: relative; |
| cursor: pointer; |
| user-select: none; |
| } |
| |
| .card:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1); |
| } |
| |
| .card-back { |
| background: linear-gradient(45deg, #8e2de2, #4a00e0); |
| color: white; |
| background-size: 200% 200%; |
| animation: gradient 3s ease infinite; |
| } |
| |
| .card-front { |
| background: white; |
| color: #333; |
| } |
| |
| .player-area { |
| transition: all 0.3s ease; |
| position: relative; |
| } |
| |
| .player-area.active { |
| border: 3px solid #4CAF50; |
| box-shadow: 0 0 15px rgba(76, 175, 80, 0.5); |
| } |
| |
| .player-area.active::after { |
| content: "اللاعب الحالي"; |
| position: absolute; |
| top: -15px; |
| right: 50%; |
| transform: translateX(50%); |
| background: #4CAF50; |
| color: white; |
| padding: 2px 10px; |
| border-radius: 20px; |
| font-size: 12px; |
| font-weight: bold; |
| } |
| |
| .special-card { |
| background: linear-gradient(45deg, #ff416c, #ff4b2b); |
| color: white; |
| background-size: 200% 200%; |
| animation: gradient 3s ease infinite; |
| } |
| |
| .thief-card { |
| background: linear-gradient(45deg, #000000, #434343); |
| color: white; |
| } |
| |
| .action-card { |
| background: linear-gradient(45deg, #00b09b, #96c93d); |
| color: white; |
| } |
| |
| .modal { |
| transition: all 0.3s ease; |
| } |
| |
| .modal.show { |
| opacity: 1; |
| pointer-events: auto; |
| } |
| |
| @keyframes gradient { |
| 0% { |
| background-position: 0% 50%; |
| } |
| 50% { |
| background-position: 100% 50%; |
| } |
| 100% { |
| background-position: 0% 50%; |
| } |
| } |
| |
| .card-icon { |
| font-size: 24px; |
| margin-bottom: 5px; |
| } |
| |
| .card-value { |
| font-size: 28px; |
| font-weight: bold; |
| } |
| |
| .card-special { |
| font-size: 14px; |
| text-align: center; |
| padding: 0 5px; |
| } |
| |
| .highlight { |
| animation: pulse 1.5s infinite; |
| } |
| |
| @keyframes pulse { |
| 0% { |
| box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.7); |
| } |
| 70% { |
| box-shadow: 0 0 0 10px rgba(76, 175, 80, 0); |
| } |
| 100% { |
| box-shadow: 0 0 0 0 rgba(76, 175, 80, 0); |
| } |
| } |
| |
| .penalty-badge { |
| position: absolute; |
| top: -8px; |
| right: -8px; |
| background: #ff5722; |
| color: white; |
| border-radius: 50%; |
| width: 25px; |
| height: 25px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| font-size: 12px; |
| font-weight: bold; |
| animation: bounce 0.5s alternate infinite; |
| } |
| |
| @keyframes bounce { |
| from { |
| transform: translateY(0); |
| } |
| to { |
| transform: translateY(-5px); |
| } |
| } |
| |
| .winner-crown { |
| position: absolute; |
| top: -15px; |
| left: 50%; |
| transform: translateX(-50%); |
| color: gold; |
| font-size: 24px; |
| text-shadow: 0 0 3px rgba(0,0,0,0.5); |
| } |
| </style> |
| </head> |
| <body class="text-gray-800"> |
| <div class="container mx-auto px-4 py-8"> |
| <header class="text-center mb-8"> |
| <h1 class="text-4xl font-bold text-indigo-800 mb-2">لعبة سكرو</h1> |
| <p class="text-lg text-gray-600">اللعبة التي تتحدى ذكاءك وتركيزك!</p> |
| </header> |
| |
| |
| <div id="mode-selection" class="bg-white rounded-lg shadow-lg p-6 mb-8"> |
| <h2 class="text-2xl font-bold mb-4 text-center text-indigo-700">اختر نمط اللعبة</h2> |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| <div class="mode-option bg-indigo-50 hover:bg-indigo-100 rounded-lg p-4 cursor-pointer transition flex flex-col items-center" data-mode="general"> |
| <div class="w-12 h-12 bg-gradient-to-r from-purple-500 to-pink-500 rounded-full flex items-center justify-center text-white mb-2"> |
| <i class="fas fa-star"></i> |
| </div> |
| <h3 class="font-bold text-lg text-indigo-800">سكرو العامة</h3> |
| <p class="text-gray-600 text-sm text-center">يمكن اللعبة واضافة جميع الاوراق</p> |
| </div> |
| <div class="mode-option bg-indigo-50 hover:bg-indigo-100 rounded-lg p-4 cursor-pointer transition flex flex-col items-center" data-mode="classic"> |
| <div class="w-12 h-12 bg-gradient-to-r from-blue-500 to-teal-400 rounded-full flex items-center justify-center text-white mb-2"> |
| <i class="fas fa-history"></i> |
| </div> |
| <h3 class="font-bold text-lg text-indigo-800">سكرو كلاسيك</h3> |
| <p class="text-gray-600 text-sm text-center">جميع الاوراق ما عدا كرت الحرامي وكرتين بينج وبونج</p> |
| </div> |
| <div class="mode-option bg-indigo-50 hover:bg-indigo-100 rounded-lg p-4 cursor-pointer transition flex flex-col items-center" data-mode="thief"> |
| <div class="w-12 h-12 bg-gradient-to-r from-gray-700 to-gray-900 rounded-full flex items-center justify-center text-white mb-2"> |
| <i class="fas fa-user-ninja"></i> |
| </div> |
| <h3 class="font-bold text-lg text-indigo-800">سكرو الحرامي</h3> |
| <p class="text-gray-600 text-sm text-center">جميع الاوراق ما عدا كرت بينج وبونج</p> |
| </div> |
| <div class="mode-option bg-indigo-50 hover:bg-indigo-100 rounded-lg p-4 cursor-pointer transition flex flex-col items-center" data-mode="duos"> |
| <div class="w-12 h-12 bg-gradient-to-r from-green-500 to-green-700 rounded-full flex items-center justify-center text-white mb-2"> |
| <i class="fas fa-users"></i> |
| </div> |
| <h3 class="font-bold text-lg text-indigo-800">سكرو الثنائيات</h3> |
| <p class="text-gray-600 text-sm text-center">جميع الاوراق ما عدا كرت الحرامي</p> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="player-setup" class="bg-white rounded-lg shadow-lg p-6 mb-8 hidden"> |
| <h2 class="text-2xl font-bold mb-4 text-center text-indigo-700">إعداد اللاعبين</h2> |
| <div class="mb-4"> |
| <label class="block text-gray-700 mb-2">عدد اللاعبين (2-6)</label> |
| <input type="number" min="2" max="6" value="4" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
| </div> |
| <div id="player-names" class="space-y-3"> |
| |
| </div> |
| <button id="start-game" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-2 px-4 rounded-md mt-4 transition transform hover:scale-105"> |
| <i class="fas fa-play mr-2"></i> بدء اللعبة |
| </button> |
| </div> |
| |
| |
| <div id="game-board" class="hidden"> |
| |
| <div class="flex flex-col md:flex-row justify-between items-center mb-6 gap-4"> |
| <div class="bg-white rounded-lg shadow px-4 py-2 flex items-center gap-4"> |
| <div> |
| <span class="font-bold">الجولة:</span> <span id="round-number" class="text-indigo-600 font-bold">1</span> |
| </div> |
| <div> |
| <span class="font-bold">النمط:</span> <span id="game-mode" class="text-indigo-600 font-bold">سكرو العامة</span> |
| </div> |
| <div> |
| <span class="font-bold">اللاعب الحالي:</span> <span id="current-player" class="text-green-600 font-bold"></span> |
| </div> |
| </div> |
| <div class="flex gap-2"> |
| <button id="rules-button" class="bg-yellow-500 hover:bg-yellow-600 text-white px-4 py-2 rounded-lg transition flex items-center"> |
| <i class="fas fa-info-circle mr-2"></i> القواعد |
| </button> |
| <button id="end-game" class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg transition flex items-center"> |
| <i class="fas fa-stop mr-2"></i> إنهاء اللعبة |
| </button> |
| </div> |
| </div> |
| |
| |
| <div class="relative mb-16 bg-indigo-50 rounded-xl p-6 shadow-inner"> |
| |
| <div class="absolute left-1/2 transform -translate-x-1/2 -top-8"> |
| <div id="draw-pile" class="card card-back flex flex-col items-center justify-center cursor-pointer hover:shadow-lg"> |
| <i class="fas fa-layer-group text-2xl"></i> |
| <span class="text-xs mt-1">السحب</span> |
| <span id="draw-count" class="text-xs mt-1">0</span> |
| </div> |
| </div> |
| |
| |
| <div class="flex justify-center"> |
| <div id="discard-pile" class="card card-front mx-2"> |
| |
| </div> |
| </div> |
| |
| |
| <div class="absolute right-0 -top-8 bg-white rounded-lg shadow px-4 py-2 text-center flex items-center gap-2"> |
| <div id="round-info" class="font-bold text-indigo-700">الجولة الأولى: النظر إلى أول كرتين على اليمين</div> |
| <div id="round-warning" class="text-xs text-red-500 hidden bg-red-100 px-2 py-1 rounded-full"> |
| <i class="fas fa-exclamation-triangle mr-1"></i> تحذير: +10 عند مخالفة قواعد الجولة |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="players-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> |
| |
| </div> |
| |
| |
| <div id="player-actions" class="bg-white rounded-lg shadow-lg p-4 mt-8 hidden"> |
| <h3 class="font-bold mb-4 text-center text-lg text-indigo-700">اختياراتك</h3> |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> |
| <button id="draw-from-pile" class="bg-blue-500 hover:bg-blue-600 text-white py-3 px-4 rounded-lg transition transform hover:scale-105 flex flex-col items-center"> |
| <i class="fas fa-draw-polygon text-xl mb-1"></i> |
| <span>سحب من ميدان الكروت</span> |
| </button> |
| <button id="draw-from-discard" class="bg-green-500 hover:bg-green-600 text-white py-3 px-4 rounded-lg transition transform hover:scale-105 flex flex-col items-center"> |
| <i class="fas fa-hand-paper text-xl mb-1"></i> |
| <span>سحب من الأرض</span> |
| </button> |
| <button id="play-similar" class="bg-purple-500 hover:bg-purple-600 text-white py-3 px-4 rounded-lg transition transform hover:scale-105 flex flex-col items-center"> |
| <i class="fas fa-exchange-alt text-xl mb-1"></i> |
| <span>التخلص من كرت مشابه</span> |
| </button> |
| </div> |
| <div class="mt-6 text-center"> |
| <button id="declare-skru" class="bg-red-500 hover:bg-red-600 text-white py-3 px-8 rounded-lg font-bold transition transform hover:scale-105 flex items-center justify-center mx-auto"> |
| <i class="fas fa-flag mr-2"></i> سكرو! |
| </button> |
| <p class="text-xs text-gray-500 mt-2">عند إعلان "سكرو"، سيتم احتساب النقاط بعد انتهاء الجولة</p> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="card-selection-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 opacity-0 pointer-events-none modal"> |
| <div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-md"> |
| <h3 class="font-bold text-xl mb-4 text-center text-indigo-700" id="selection-title">اختر كرت</h3> |
| <div id="selectable-cards" class="flex flex-wrap justify-center gap-3 mb-6"> |
| |
| </div> |
| <div class="flex justify-center gap-4"> |
| <button id="confirm-selection" class="bg-green-500 hover:bg-green-600 text-white px-6 py-2 rounded-lg transition flex items-center"> |
| <i class="fas fa-check mr-2"></i> تأكيد |
| </button> |
| <button id="cancel-selection" class="bg-gray-500 hover:bg-gray-600 text-white px-6 py-2 rounded-lg transition flex items-center"> |
| <i class="fas fa-times mr-2"></i> إلغاء |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="player-selection-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 opacity-0 pointer-events-none modal"> |
| <div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-md"> |
| <h3 class="font-bold text-xl mb-4 text-center text-indigo-700" id="player-selection-title">اختر لاعب</h3> |
| <div id="selectable-players" class="space-y-3 mb-6"> |
| |
| </div> |
| <div class="flex justify-center gap-4"> |
| <button id="confirm-player" class="bg-green-500 hover:bg-green-600 text-white px-6 py-2 rounded-lg transition flex items-center"> |
| <i class="fas fa-check mr-2"></i> تأكيد |
| </button> |
| <button id="cancel-player" class="bg-gray-500 hover:bg-gray-600 text-white px-6 py-2 rounded-lg transition flex items-center"> |
| <i class="fas fa-times mr-2"></i> إلغاء |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="card-view-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 opacity-0 pointer-events-none modal"> |
| <div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-md"> |
| <h3 class="font-bold text-xl mb-4 text-center text-indigo-700" id="card-view-title">عرض الكرت</h3> |
| <div id="viewed-card" class="flex justify-center mb-6"> |
| |
| </div> |
| <div class="flex justify-center"> |
| <button id="close-view" class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-lg transition flex items-center"> |
| <i class="fas fa-check mr-2"></i> موافق |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="game-over-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 opacity-0 pointer-events-none modal"> |
| <div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-md"> |
| <h3 class="font-bold text-2xl mb-6 text-center text-indigo-800">نتيجة اللعبة</h3> |
| <div id="game-results" class="mb-6 space-y-4 max-h-96 overflow-y-auto"> |
| |
| </div> |
| <div class="flex justify-center gap-4"> |
| <button id="play-again" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg font-bold transition flex items-center"> |
| <i class="fas fa-redo mr-2"></i> لعب مرة أخرى |
| </button> |
| <button id="new-game" class="bg-gray-600 hover:bg-gray-700 text-white px-6 py-2 rounded-lg font-bold transition flex items-center"> |
| <i class="fas fa-plus mr-2"></i> لعبة جديدة |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="rules-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 opacity-0 pointer-events-none modal"> |
| <div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-2xl max-h-[80vh] overflow-y-auto"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="font-bold text-xl text-indigo-800">قواعد لعبة سكرو</h3> |
| <button id="close-rules" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| |
| <div class="space-y-4"> |
| <div class="bg-blue-50 p-4 rounded-lg"> |
| <h4 class="font-bold text-lg text-blue-800">هدف اللعبة:</h4> |
| <p>الحصول على أقل عدد من الأرقام في نهاية الجولة.</p> |
| </div> |
| |
| <div class="bg-green-50 p-4 rounded-lg"> |
| <h4 class="font-bold text-lg text-green-800">بداية اللعبة:</h4> |
| <ul class="list-disc list-inside space-y-1"> |
| <li>كل لاعب يحصل على 4 كروت غير مكشوفة</li> |
| <li>يتم وضع ميدان للكروت في المنتصف</li> |
| <li>اللاعبون يسحبون بالترتيب من اليمين إلى اليسار</li> |
| </ul> |
| </div> |
| |
| <div class="bg-purple-50 p-4 rounded-lg"> |
| <h4 class="font-bold text-lg text-purple-800">طرق اللعب:</h4> |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-3"> |
| <div class="bg-white p-3 rounded border border-purple-200"> |
| <h5 class="font-bold text-purple-700">سكرو العامة</h5> |
| <p class="text-sm">يمكن اللعبة واضافة جميع الاوراق</p> |
| </div> |
| <div class="bg-white p-3 rounded border border-purple-200"> |
| <h5 class="font-bold text-purple-700">سكرو كلاسيك</h5> |
| <p class="text-sm">جميع الاوراق ما عدا كرت الحرامي وكرتين بينج وبونج</p> |
| </div> |
| <div class="bg-white p-3 rounded border border-purple-200"> |
| <h5 class="font-bold text-purple-700">سكرو الحرامي</h5> |
| <p class="text-sm">جميع الاوراق ما عدا كرت بينج وبونج</p> |
| </div> |
| <div class="bg-white p-3 rounded border border-purple-200"> |
| <h5 class="font-bold text-purple-700">سكرو الثنائيات</h5> |
| <p class="text-sm">جميع الاوراق ما عدا كرت الحرامي</p> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-yellow-50 p-4 rounded-lg"> |
| <h4 class="font-bold text-lg text-yellow-800">خيارات اللاعب:</h4> |
| <ol class="list-decimal list-inside space-y-2"> |
| <li class="font-medium">سحب من ميدان الكروت ثم الاحتفاظ به أو التخلص منه</li> |
| <li class="font-medium">سحب من الأرض آخر كرت تركه اللاعب السابق</li> |
| <li class="font-medium">التخلص من كرت يشابه آخر كرت في الأرض</li> |
| </ol> |
| <div class="mt-2 bg-red-50 p-2 rounded text-red-600 text-sm flex items-start"> |
| <i class="fas fa-exclamation-circle mt-1 mr-2"></i> |
| <span>⛔️ تحذير: إذا لم يكن الكرت مشابهاً يعود إليه كرته + الكرت الآخر</span> |
| </div> |
| </div> |
| |
| <div class="bg-indigo-50 p-4 rounded-lg"> |
| <h4 class="font-bold text-lg text-indigo-800">جولات اللعبة:</h4> |
| <div class="space-y-3"> |
| <div class="bg-white p-3 rounded border border-indigo-200"> |
| <h5 class="font-bold text-indigo-700">الجولة الأولى</h5> |
| <p class="text-sm">ينظر الجميع إلى أول كرتين على اليمين فقط</p> |
| <div class="mt-1 bg-red-50 p-1 rounded text-red-600 text-xs"> |
| ⛔️ تحذير: +10 عند النظر إلى أكثر من كرتين أو تبديل الكروت |
| </div> |
| </div> |
| <div class="bg-white p-3 rounded border border-indigo-200"> |
| <h5 class="font-bold text-indigo-700">الجولة الثانية (الصامتة)</h5> |
| <p class="text-sm">لا يجوز الكلام خلال هذه الجولة</p> |
| <div class="mt-1 bg-red-50 p-1 rounded text-red-600 text-xs"> |
| ⛔️ تحذير: +10 عند الكلام |
| </div> |
| </div> |
| <div class="bg-white p-3 rounded border border-indigo-200"> |
| <h5 class="font-bold text-indigo-700">الجولة الثالثة</h5> |
| <p class="text-sm">لا يستطيع أي لاعب النظر إلى كروته</p> |
| <div class="mt-1 bg-red-50 p-1 rounded text-red-600 text-xs"> |
| ⛔️ تحذير: +10 عند النظر إلى أي كرت |
| </div> |
| </div> |
| <div class="bg-white p-3 rounded border border-indigo-200"> |
| <h5 class="font-bold text-indigo-700">الجولة الرابعة</h5> |
| <p class="text-sm">جولة الدبل: مجموع ما تحصل عليه بعد انتهاء الجولة × 2</p> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-pink-50 p-4 rounded-lg"> |
| <h4 class="font-bold text-lg text-pink-800">مهام الكروت الخاصة:</h4> |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-3"> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">7 أو 8</h5> |
| <p class="text-xs">تنظر في كرت واحد فقط من كروتك</p> |
| </div> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">9 أو 10</h5> |
| <p class="text-xs">تنظر في كرت واحد فقط من أحد اللاعبين</p> |
| </div> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">البصرة</h5> |
| <p class="text-xs">تستطيع التخلص من كرت من كروتك باختيارك</p> |
| </div> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">خذ وهات</h5> |
| <p class="text-xs">تستبدل كرت من أحد اللاعبين بكرت من عندك دون النظر</p> |
| </div> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">خذ بس</h5> |
| <p class="text-xs">تستطيع إعطاء كرت من كروتك لأحد اللاعبين</p> |
| </div> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">دائر ما يدور</h5> |
| <p class="text-xs">تنظر في كرت واحد من كل لاعب أو كرتين من أوراقك</p> |
| </div> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">عجب ما عجب</h5> |
| <p class="text-xs">مثل خذ وهات ولكن مع خيار الاستبدال مع لاعب آخر</p> |
| </div> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">الحرامي</h5> |
| <p class="text-xs">لا يمكن التخلص منه ويقوم بسرقة نقاط الخصم</p> |
| </div> |
| <div class="bg-white p-2 rounded border border-pink-200"> |
| <h5 class="font-bold text-pink-700 text-sm">بونج/بينج</h5> |
| <p class="text-xs">تمنع فريق الخصم من اللعب في الجولة التالية</p> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-teal-50 p-4 rounded-lg"> |
| <h4 class="font-bold text-lg text-teal-800">نهاية اللعبة:</h4> |
| <p class="text-sm">عندما يقول لاعب "سكرو"، يكمل الجميع حتى يعود دوره ثم تكشف الكروت. اللاعب الأقل عدداً هو الفائز، وقد يكون هناك أكثر من فائز. الخاسر هو من لديه أكبر مجموع أرقام.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <button id="help-button" class="fixed bottom-6 left-6 bg-indigo-600 text-white w-14 h-14 rounded-full shadow-lg flex items-center justify-center hover:bg-indigo-700 transition z-40 transform hover:scale-110"> |
| <i class="fas fa-question text-2xl"></i> |
| </button> |
| |
| |
| <button id="sound-toggle" class="fixed bottom-6 right-6 bg-gray-600 text-white w-14 h-14 rounded-full shadow-lg flex items-center justify-center hover:bg-gray-700 transition z-40 transform hover:scale-110"> |
| <i class="fas fa-volume-up text-2xl"></i> |
| </button> |
| </div> |
|
|
| <script> |
| |
| const gameState = { |
| mode: null, |
| players: [], |
| currentPlayerIndex: 0, |
| round: 1, |
| drawPile: [], |
| discardPile: [], |
| gameStarted: false, |
| skruDeclared: false, |
| skruPlayer: null, |
| soundEnabled: true, |
| specialCards: { |
| thief: { name: 'الحرامي', type: 'thief', penalty: 10 }, |
| bing: { name: 'بينج', type: 'action', penalty: 10 }, |
| bong: { name: 'بونج', type: 'action', penalty: 10 }, |
| basra: { name: 'البصرة', type: 'action' }, |
| takeAndGive: { name: 'خذ وهات', type: 'action' }, |
| takeOnly: { name: 'خذ بس', type: 'action' }, |
| lookAround: { name: 'دائر ما يدور', type: 'action' }, |
| likeOrNot: { name: 'عجب ما عجب', type: 'action' } |
| }, |
| cardActions: { |
| 7: { name: 'انظر إلى كرت واحد من كروتك', type: 'view-self' }, |
| 8: { name: 'انظر إلى كرت واحد من كروتك', type: 'view-self' }, |
| 9: { name: 'انظر إلى كرت واحد من لاعب آخر', type: 'view-other' }, |
| 10: { name: 'انظر إلى كرت واحد من لاعب آخر', type: 'view-other' } |
| } |
| }; |
| |
| |
| const modeSelection = document.getElementById('mode-selection'); |
| const playerSetup = document.getElementById('player-setup'); |
| const gameBoard = document.getElementById('game-board'); |
| const playersContainer = document.getElementById('players-container'); |
| const playerActions = document.getElementById('player-actions'); |
| const drawPile = document.getElementById('draw-pile'); |
| const discardPile = document.getElementById('discard-pile'); |
| const roundNumber = document.getElementById('round-number'); |
| const gameMode = document.getElementById('game-mode'); |
| const currentPlayer = document.getElementById('current-player'); |
| const roundInfo = document.getElementById('round-info'); |
| const roundWarning = document.getElementById('round-warning'); |
| const cardSelectionModal = document.getElementById('card-selection-modal'); |
| const selectionTitle = document.getElementById('selection-title'); |
| const selectableCards = document.getElementById('selectable-cards'); |
| const playerSelectionModal = document.getElementById('player-selection-modal'); |
| const playerSelectionTitle = document.getElementById('player-selection-title'); |
| const selectablePlayers = document.getElementById('selectable-players'); |
| const cardViewModal = document.getElementById('card-view-modal'); |
| const cardViewTitle = document.getElementById('card-view-title'); |
| const viewedCard = document.getElementById('viewed-card'); |
| const gameOverModal = document.getElementById('game-over-modal'); |
| const gameResults = document.getElementById('game-results'); |
| const rulesModal = document.getElementById('rules-modal'); |
| const helpButton = document.getElementById('help-button'); |
| const soundToggle = document.getElementById('sound-toggle'); |
| const drawCount = document.getElementById('draw-count'); |
| |
| |
| const startGameBtn = document.getElementById('start-game'); |
| const endGameBtn = document.getElementById('end-game'); |
| const drawFromPileBtn = document.getElementById('draw-from-pile'); |
| const drawFromDiscardBtn = document.getElementById('draw-from-discard'); |
| const playSimilarBtn = document.getElementById('play-similar'); |
| const declareSkruBtn = document.getElementById('declare-skru'); |
| const confirmSelectionBtn = document.getElementById('confirm-selection'); |
| const cancelSelectionBtn = document.getElementById('cancel-selection'); |
| const confirmPlayerBtn = document.getElementById('confirm-player'); |
| const cancelPlayerBtn = document.getElementById('cancel-player'); |
| const closeViewBtn = document.getElementById('close-view'); |
| const playAgainBtn = document.getElementById('play-again'); |
| const newGameBtn = document.getElementById('new-game'); |
| const closeRulesBtn = document.getElementById('close-rules'); |
| const rulesButton = document.getElementById('rules-button'); |
| |
| |
| const drawSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-unlock-game-notification-253.mp3'); |
| const discardSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-quick-jump-arcade-game-239.mp3'); |
| const skruSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-winning-chimes-2015.mp3'); |
| const errorSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-software-interface-remove-notification-257.mp3'); |
| const specialSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-magic-ping-utility-notification-308.mp3'); |
| const winSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-achievement-bell-600.mp3'); |
| const loseSound = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-sad-game-over-trombone-471.mp3'); |
| |
| |
| document.querySelectorAll('.mode-option').forEach(option => { |
| option.addEventListener('click', () => { |
| gameState.mode = option.dataset.mode; |
| modeSelection.classList.add('hidden'); |
| playerSetup.classList.remove('hidden'); |
| |
| |
| let modeText = ''; |
| switch(gameState.mode) { |
| case 'general': modeText = 'سكرو العامة'; break; |
| case 'classic': modeText = 'سكرو كلاسيك'; break; |
| case 'thief': modeText = 'سكرو الحرامي'; break; |
| case 'duos': modeText = 'سكرو الثنائيات'; break; |
| } |
| gameMode.textContent = modeText; |
| |
| |
| const playerCount = document.querySelector('#player-setup input').value; |
| setupPlayerInputs(playerCount); |
| }); |
| }); |
| |
| document.querySelector('#player-setup input').addEventListener('input', (e) => { |
| setupPlayerInputs(e.target.value); |
| }); |
| |
| startGameBtn.addEventListener('click', startGame); |
| endGameBtn.addEventListener('click', endGame); |
| drawFromPileBtn.addEventListener('click', drawFromPile); |
| drawFromDiscardBtn.addEventListener('click', drawFromDiscard); |
| playSimilarBtn.addEventListener('click', playSimilarCard); |
| declareSkruBtn.addEventListener('click', declareSkru); |
| confirmSelectionBtn.addEventListener('click', confirmCardSelection); |
| cancelSelectionBtn.addEventListener('click', cancelCardSelection); |
| confirmPlayerBtn.addEventListener('click', confirmPlayerSelection); |
| cancelPlayerBtn.addEventListener('click', cancelPlayerSelection); |
| closeViewBtn.addEventListener('click', closeCardView); |
| playAgainBtn.addEventListener('click', resetGame); |
| newGameBtn.addEventListener('click', newGame); |
| helpButton.addEventListener('click', showRules); |
| closeRulesBtn.addEventListener('click', hideRules); |
| rulesButton.addEventListener('click', showRules); |
| soundToggle.addEventListener('click', toggleSound); |
| |
| |
| function setupPlayerInputs(count) { |
| const playerNames = document.getElementById('player-names'); |
| playerNames.innerHTML = ''; |
| |
| for (let i = 0; i < count; i++) { |
| const div = document.createElement('div'); |
| div.className = 'flex items-center'; |
| div.innerHTML = ` |
| <span class="bg-indigo-100 text-indigo-800 px-3 py-2 rounded-l-md flex items-center justify-center w-24"> |
| <i class="fas fa-user mr-2"></i> لاعب ${i+1} |
| </span> |
| <input type="text" class="flex-1 px-3 py-2 border border-gray-300 rounded-r-md focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="اسم اللاعب" required> |
| `; |
| playerNames.appendChild(div); |
| } |
| } |
| |
| function startGame() { |
| |
| const inputs = document.querySelectorAll('#player-setup input'); |
| gameState.players = []; |
| |
| inputs.forEach(input => { |
| if (input.type === 'text' && input.value.trim() !== '') { |
| gameState.players.push({ |
| name: input.value.trim(), |
| cards: [], |
| points: 0, |
| isActive: false, |
| penalties: 0 |
| }); |
| } |
| }); |
| |
| if (gameState.players.length < 2) { |
| alert('يجب إدخال اسماء لاثنين من اللاعبين على الأقل'); |
| return; |
| } |
| |
| playerSetup.classList.add('hidden'); |
| gameBoard.classList.remove('hidden'); |
| |
| |
| initializeGame(); |
| } |
| |
| function initializeGame() { |
| |
| gameState.round = 1; |
| gameState.skruDeclared = false; |
| gameState.skruPlayer = null; |
| gameState.gameStarted = true; |
| |
| |
| gameState.drawPile = createDeck(); |
| |
| |
| shuffleDeck(gameState.drawPile); |
| |
| |
| gameState.players.forEach(player => { |
| player.cards = []; |
| for (let i = 0; i < 4; i++) { |
| player.cards.push({ |
| value: gameState.drawPile.pop(), |
| isFaceUp: false |
| }); |
| } |
| }); |
| |
| |
| gameState.discardPile = [gameState.drawPile.pop()]; |
| |
| |
| gameState.currentPlayerIndex = 0; |
| gameState.players[0].isActive = true; |
| |
| |
| updateGameBoard(); |
| updateRoundInfo(); |
| |
| |
| playerActions.classList.remove('hidden'); |
| |
| |
| playSound(specialSound); |
| } |
| |
| function createDeck() { |
| const deck = []; |
| |
| |
| for (let i = 1; i <= 10; i++) { |
| |
| for (let j = 0; j < 4; j++) { |
| deck.push(i); |
| } |
| } |
| |
| |
| switch(gameState.mode) { |
| case 'general': |
| deck.push(gameState.specialCards.thief); |
| deck.push(gameState.specialCards.bing); |
| deck.push(gameState.specialCards.bong); |
| deck.push(gameState.specialCards.basra); |
| deck.push(gameState.specialCards.takeAndGive); |
| deck.push(gameState.specialCards.takeOnly); |
| deck.push(gameState.specialCards.lookAround); |
| deck.push(gameState.specialCards.likeOrNot); |
| break; |
| |
| case 'classic': |
| deck.push(gameState.specialCards.basra); |
| deck.push(gameState.specialCards.takeAndGive); |
| deck.push(gameState.specialCards.takeOnly); |
| deck.push(gameState.specialCards.lookAround); |
| deck.push(gameState.specialCards.likeOrNot); |
| break; |
| |
| case 'thief': |
| deck.push(gameState.specialCards.thief); |
| deck.push(gameState.specialCards.basra); |
| deck.push(gameState.specialCards.takeAndGive); |
| deck.push(gameState.specialCards.takeOnly); |
| deck.push(gameState.specialCards.lookAround); |
| deck.push(gameState.specialCards.likeOrNot); |
| break; |
| |
| case 'duos': |
| deck.push(gameState.specialCards.bing); |
| deck.push(gameState.specialCards.bong); |
| deck.push(gameState.specialCards.basra); |
| deck.push(gameState.specialCards.takeAndGive); |
| deck.push(gameState.specialCards.takeOnly); |
| deck.push(gameState.specialCards.lookAround); |
| deck.push(gameState.specialCards.likeOrNot); |
| break; |
| } |
| |
| return deck; |
| } |
| |
| function shuffleDeck(deck) { |
| for (let i = deck.length - 1; i > 0; i--) { |
| const j = Math.floor(Math.random() * (i + 1)); |
| [deck[i], deck[j]] = [deck[j], deck[i]]; |
| } |
| } |
| |
| function updateGameBoard() { |
| |
| playersContainer.innerHTML = ''; |
| |
| gameState.players.forEach((player, index) => { |
| const playerDiv = document.createElement('div'); |
| playerDiv.className = `player-area bg-white rounded-lg shadow p-4 ${player.isActive ? 'active' : ''}`; |
| |
| const playerName = document.createElement('h3'); |
| playerName.className = 'font-bold text-lg text-center mb-2 relative'; |
| playerName.textContent = player.name; |
| |
| if (player.penalties > 0) { |
| const penaltyBadge = document.createElement('div'); |
| penaltyBadge.className = 'penalty-badge'; |
| penaltyBadge.textContent = `+${player.penalties}`; |
| playerName.appendChild(penaltyBadge); |
| } |
| |
| const playerCards = document.createElement('div'); |
| playerCards.className = 'flex justify-center gap-2'; |
| |
| player.cards.forEach((card, cardIndex) => { |
| const cardDiv = document.createElement('div'); |
| cardDiv.className = `card ${card.isFaceUp ? 'card-front' : 'card-back'}`; |
| cardDiv.dataset.playerIndex = index; |
| cardDiv.dataset.cardIndex = cardIndex; |
| |
| if (card.isFaceUp) { |
| if (typeof card.value === 'object') { |
| |
| cardDiv.innerHTML = ` |
| <div class="card-icon">${getCardIcon(card.value)}</div> |
| <div class="card-special">${card.value.name}</div> |
| `; |
| |
| if (card.value.type === 'thief') { |
| cardDiv.classList.add('thief-card'); |
| } else { |
| cardDiv.classList.add('action-card'); |
| } |
| } else { |
| |
| if (card.value >= 7 && card.value <= 10) { |
| cardDiv.classList.add('action-card'); |
| } |
| cardDiv.innerHTML = ` |
| <div class="card-value">${card.value}</div> |
| `; |
| } |
| } |
| |
| |
| if (gameState.round === 1 || (card.isFaceUp && typeof card.value === 'number' && card.value >= 7 && card.value <= 10)) { |
| cardDiv.addEventListener('click', () => handleCardClick(index, cardIndex)); |
| } |
| |
| playerCards.appendChild(cardDiv); |
| }); |
| |
| const playerPoints = document.createElement('div'); |
| playerPoints.className = 'text-center mt-2 text-gray-600'; |
| playerPoints.textContent = `النقاط: ${player.points}`; |
| |
| playerDiv.appendChild(playerName); |
| playerDiv.appendChild(playerCards); |
| playerDiv.appendChild(playerPoints); |
| playersContainer.appendChild(playerDiv); |
| }); |
| |
| |
| discardPile.innerHTML = ''; |
| if (gameState.discardPile.length > 0) { |
| const lastCard = gameState.discardPile[gameState.discardPile.length - 1]; |
| const cardDiv = document.createElement('div'); |
| cardDiv.className = 'card card-front'; |
| |
| if (typeof lastCard === 'object') { |
| |
| cardDiv.innerHTML = ` |
| <div class="card-icon">${getCardIcon(lastCard)}</div> |
| <div class="card-special">${lastCard.name}</div> |
| `; |
| |
| if (lastCard.type === 'thief') { |
| cardDiv.classList.add('thief-card'); |
| } else { |
| cardDiv.classList.add('action-card'); |
| } |
| } else { |
| |
| if (lastCard >= 7 && lastCard <= 10) { |
| cardDiv.classList.add('action-card'); |
| } |
| cardDiv.innerHTML = ` |
| <div class="card-value">${lastCard}</div> |
| `; |
| } |
| |
| discardPile.appendChild(cardDiv); |
| } |
| |
| |
| drawCount.textContent = gameState.drawPile.length; |
| |
| |
| roundNumber.textContent = gameState.round; |
| |
| |
| currentPlayer.textContent = gameState.players[gameState.currentPlayerIndex].name; |
| } |
| |
| function getCardIcon(card) { |
| if (typeof card === 'number') { |
| return card; |
| } |
| |
| switch(card.name) { |
| case 'الحرامي': return '<i class="fas fa-user-ninja"></i>'; |
| case 'بينج': return '<i class="fas fa-ban"></i>'; |
| case 'بونج': return '<i class="fas fa-ban"></i>'; |
| case 'البصرة': return '<i class="fas fa-trash-alt"></i>'; |
| case 'خذ وهات': return '<i class="fas fa-exchange-alt"></i>'; |
| case 'خذ بس': return '<i class="fas fa-hand-holding"></i>'; |
| case 'دائر ما يدور': return '<i class="fas fa-eye"></i>'; |
| case 'عجب ما عجب': return '<i class="fas fa-random"></i>'; |
| default: return card.value || '?'; |
| } |
| } |
| |
| function handleCardClick(playerIndex, cardIndex) { |
| const player = gameState.players[playerIndex]; |
| const card = player.cards[cardIndex]; |
| |
| |
| if (gameState.round === 1 && cardIndex < 2) { |
| viewCard(card, `كرت ${player.name}`); |
| } |
| |
| |
| if (card.isFaceUp && typeof card.value === 'number' && card.value >= 7 && card.value <= 10) { |
| useActionCard(playerIndex, cardIndex); |
| } |
| } |
| |
| function useActionCard(playerIndex, cardIndex) { |
| const player = gameState.players[playerIndex]; |
| const card = player.cards[cardIndex]; |
| |
| if (playerIndex !== gameState.currentPlayerIndex) { |
| alert('ليس دورك لاستخدام هذا الكرت!'); |
| return; |
| } |
| |
| const action = gameState.cardActions[card.value]; |
| |
| switch(action.type) { |
| case 'view-self': |
| |
| const options = player.cards |
| .filter((c, i) => !c.isFaceUp && i !== cardIndex) |
| .map((c, i) => ({ index: i, value: c.value })); |
| |
| if (options.length === 0) { |
| alert('لا توجد كروت مخفية لديك!'); |
| return; |
| } |
| |
| showCardSelectionModal( |
| options, |
| `اختر كرتاً من كروتك لرؤيته (باستخدام كرت ${card.value})`, |
| false |
| ); |
| |
| |
| selectableCards.dataset.actionCardIndex = cardIndex; |
| selectableCards.dataset.actionPlayerIndex = playerIndex; |
| break; |
| |
| case 'view-other': |
| |
| showPlayerSelectionModal( |
| `اختر لاعباً لرؤية أحد كروته (باستخدام كرت ${card.value})`, |
| playerIndex |
| ); |
| |
| |
| selectablePlayers.dataset.actionCardIndex = cardIndex; |
| selectablePlayers.dataset.actionPlayerIndex = playerIndex; |
| break; |
| } |
| } |
| |
| function viewCard(card, title) { |
| cardViewTitle.textContent = title; |
| viewedCard.innerHTML = ''; |
| |
| const cardDiv = document.createElement('div'); |
| cardDiv.className = 'card card-front'; |
| |
| if (typeof card.value === 'object') { |
| |
| cardDiv.innerHTML = ` |
| <div class="card-icon">${getCardIcon(card.value)}</div> |
| <div class="card-special">${card.value.name}</div> |
| `; |
| |
| if (card.value.type === 'thief') { |
| cardDiv.classList.add('thief-card'); |
| } else { |
| cardDiv.classList.add('action-card'); |
| } |
| } else { |
| |
| if (card.value >= 7 && card.value <= 10) { |
| cardDiv.classList.add('action-card'); |
| } |
| cardDiv.innerHTML = ` |
| <div class="card-value">${card.value}</div> |
| `; |
| } |
| |
| viewedCard.appendChild(cardDiv); |
| |
| |
| cardViewModal.classList.remove('opacity-0', 'pointer-events-none'); |
| cardViewModal.classList.add('opacity-100'); |
| |
| playSound(specialSound); |
| } |
| |
| function updateRoundInfo() { |
| let info = ''; |
| let warning = false; |
| |
| switch(gameState.round) { |
| case 1: |
| info = 'الجولة الأولى: النظر إلى أول كرتين على اليمين فقط'; |
| warning = true; |
| break; |
| case 2: |
| info = 'الجولة الثانية: الجولة الصامتة - ممنوع الكلام'; |
| warning = true; |
| break; |
| case 3: |
| info = 'الجولة الثالثة: لا يمكن النظر إلى أي كرت من كروتك'; |
| warning = true; |
| break; |
| case 4: |
| info = 'الجولة الرابعة: جولة الدبل - النقاط × 2'; |
| break; |
| default: |
| info = `الجولة ${gameState.round}`; |
| } |
| |
| roundInfo.textContent = info; |
| |
| if (warning) { |
| roundWarning.classList.remove('hidden'); |
| } else { |
| roundWarning.classList.add('hidden'); |
| } |
| } |
| |
| function drawFromPile() { |
| if (gameState.drawPile.length === 0) { |
| alert('لا توجد كروت متبقية في ميدان السحب!'); |
| playSound(errorSound); |
| return; |
| } |
| |
| const drawnCard = gameState.drawPile.pop(); |
| const currentPlayer = gameState.players[gameState.currentPlayerIndex]; |
| |
| |
| if (gameState.mode !== 'classic' && typeof drawnCard === 'object' && drawnCard.type === 'thief') { |
| |
| currentPlayer.cards.push({ |
| value: drawnCard, |
| isFaceUp: true |
| }); |
| |
| alert(`لقد سحبت كرت ${drawnCard.name}! يجب عليك الاحتفاظ به ولا يمكنك التخلص منه.`); |
| updateGameBoard(); |
| playSound(specialSound); |
| return; |
| } |
| |
| |
| showCardSelectionModal([{ |
| value: drawnCard, |
| isFaceUp: true |
| }], 'ماذا تريد أن تفعل بهذا الكرت؟', true); |
| |
| playSound(drawSound); |
| } |
| |
| function drawFromDiscard() { |
| if (gameState.discardPile.length === 0) { |
| alert('لا توجد كروت في الأرض!'); |
| playSound(errorSound); |
| return; |
| } |
| |
| const drawnCard = gameState.discardPile.pop(); |
| const currentPlayer = gameState.players[gameState.currentPlayerIndex]; |
| |
| |
| currentPlayer.cards.push({ |
| value: drawnCard, |
| isFaceUp: true |
| }); |
| |
| |
| checkForSimilarCards(); |
| |
| updateGameBoard(); |
| playSound(drawSound); |
| } |
| |
| function playSimilarCard() { |
| const currentPlayer = gameState.players[gameState.currentPlayerIndex]; |
| const lastDiscard = gameState.discardPile[gameState.discardPile.length - 1]; |
| |
| |
| const similarCards = currentPlayer.cards.filter(card => |
| card.isFaceUp && ( |
| (typeof card.value === 'number' && typeof lastDiscard === 'number' && card.value === lastDiscard) || |
| (typeof card.value === 'object' && typeof lastDiscard === 'object' && card.value.name === lastDiscard.name) |
| ) |
| ); |
| |
| if (similarCards.length === 0) { |
| alert('ليس لديك أي كرت مشابه لآخر كرت في الأرض!'); |
| playSound(errorSound); |
| return; |
| } |
| |
| |
| showCardSelectionModal(similarCards, 'اختر كرت للتخلص منه:'); |
| } |
| |
| function declareSkru() { |
| if (confirm('هل أنت متأكد أنك تريد إعلان "سكرو"؟')) { |
| gameState.skruDeclared = true; |
| gameState.skruPlayer = gameState.currentPlayerIndex; |
| |
| |
| nextPlayer(); |
| |
| |
| playerActions.classList.add('hidden'); |
| |
| alert(`أعلن ${gameState.players[gameState.skruPlayer].name} "سكرو"! سيتم احتساب النقاط بعد انتهاء الجولة.`); |
| playSound(skruSound); |
| } |
| } |
| |
| function checkForSimilarCards() { |
| const currentPlayer = gameState.players[gameState.currentPlayerIndex]; |
| const lastDiscard = gameState.discardPile[gameState.discardPile.length - 1]; |
| |
| |
| const hasSimilar = currentPlayer.cards.some(card => |
| card.isFaceUp && ( |
| (typeof card.value === 'number' && typeof lastDiscard === 'number' && card.value === lastDiscard) || |
| (typeof card.value === 'object' && typeof lastDiscard === 'object' && card.value.name === lastDiscard.name) |
| ) |
| ); |
| |
| if (hasSimilar) { |
| if (confirm('لديك كرت مشابه لآخر كرت في الأرض، هل تريد التخلص منه؟')) { |
| playSimilarCard(); |
| } |
| } |
| } |
| |
| function nextPlayer() { |
| |
| gameState.players[gameState.currentPlayerIndex].isActive = false; |
| |
| |
| gameState.currentPlayerIndex = (gameState.currentPlayerIndex + 1) % gameState.players.length; |
| |
| |
| if (gameState.currentPlayerIndex === 0 && !gameState.skruDeclared) { |
| gameState.round++; |
| updateRoundInfo(); |
| |
| |
| applyRoundRules(); |
| } |
| |
| |
| if (gameState.skruDeclared && gameState.currentPlayerIndex === gameState.skruPlayer) { |
| endGame(); |
| return; |
| } |
| |
| |
| gameState.players[gameState.currentPlayerIndex].isActive = true; |
| |
| |
| updateGameBoard(); |
| |
| |
| playerActions.classList.remove('hidden'); |
| } |
| |
| function applyRoundRules() { |
| |
| switch(gameState.round) { |
| case 1: |
| gameState.players.forEach(player => { |
| |
| if (player.cards.length >= 1) player.cards[0].isFaceUp = true; |
| if (player.cards.length >= 2) player.cards[1].isFaceUp = true; |
| }); |
| break; |
| |
| case 2: |
| break; |
| |
| case 3: |
| gameState.players.forEach(player => { |
| player.cards.forEach(card => { |
| card.isFaceUp = false; |
| }); |
| }); |
| break; |
| |
| case 4: |
| break; |
| } |
| } |
| |
| function showCardSelectionModal(cards, message, showKeepOption = false) { |
| selectableCards.innerHTML = ''; |
| selectionTitle.textContent = message; |
| |
| |
| cards.forEach((card, index) => { |
| const cardDiv = document.createElement('div'); |
| cardDiv.className = `card ${card.isFaceUp ? 'card-front' : 'card-back'} cursor-pointer`; |
| cardDiv.dataset.cardIndex = index; |
| |
| if (card.isFaceUp) { |
| if (typeof card.value === 'object') { |
| |
| cardDiv.innerHTML = ` |
| <div class="card-icon">${getCardIcon(card.value)}</div> |
| <div class="card-special">${card.value.name}</div> |
| `; |
| |
| if (card.value.type === 'thief') { |
| cardDiv.classList.add('thief-card'); |
| } else { |
| cardDiv.classList.add('action-card'); |
| } |
| } else { |
| |
| if (card.value >= 7 && card.value <= 10) { |
| cardDiv.classList.add('action-card'); |
| } |
| function showPlayerSelectionModal(message, excludePlayerIndex) { |
| selectablePlayers.innerHTML = ''; |
| playerSelectionTitle.textContent = message; |
| |
| |
| gameState.players.forEach((player, index) => { |
| if (index !== excludePlayerIndex) { |
| const playerDiv = document.createElement('div'); |
| playerDiv.className = 'bg-gray-100 hover:bg-gray-200 p-3 rounded-lg cursor-pointer flex items-center justify-between'; |
| playerDiv.dataset.playerIndex = index; |
| |
| playerDiv.innerHTML = ` |
| <span class="font-medium">${player.name}</span> |
| <span class="text-sm text-gray-500">${player.cards.length} كروت</span> |
| `; |
| |
| playerDiv.addEventListener('click', () => { |
| |
| document.querySelectorAll('#selectable-players > div').forEach(p => { |
| p.classList.remove('bg-blue-100', 'border', 'border-blue-300'); |
| }); |
| playerDiv.classList.add('bg-blue-100', 'border', 'border-blue-300'); |
| }); |
| |
| selectablePlayers.appendChild(playerDiv); |
| } |
| }); |
| |
| |
| playerSelectionModal.classList.remove('opacity-0', 'pointer-events-none'); |
| playerSelectionModal.classList.add('opacity-100'); |
| } |
| |
| function hideCardSelectionModal() { |
| cardSelectionModal.classList.remove('opacity-100'); |
| cardSelectionModal.classList.add('opacity-0', 'pointer-events-none'); |
| } |
| |
| function hidePlayerSelectionModal() { |
| playerSelectionModal.classList.remove('opacity-100'); |
| playerSelectionModal.classList.add('opacity-0', 'pointer-events-none'); |
| } |
| |
| function confirmCardSelection() { |
| const selectedCard = document.querySelector('#selectable-cards .card.ring-4'); |
| if (!selectedCard) { |
| alert('الرجاء اختيار كرت أولاً'); |
| playSound(errorSound); |
| return; |
| } |
| |
| const cardIndex = selectedCard.dataset.cardIndex; |
| const currentPlayer = gameState.players[gameState.currentPlayerIndex]; |
| const lastDiscard = gameState.discardPile[gameState.discardPile.length - 1]; |
| |
| |
| if (selectableCards.dataset.actionCardIndex !== undefined) { |
| const actionCardIndex = selectableCards.dataset.actionCardIndex; |
| const actionPlayerIndex = selectableCards.dataset.actionPlayerIndex; |
| const actionPlayer = gameState.players[actionPlayerIndex]; |
| const actionCard = actionPlayer.cards[actionCardIndex]; |
| |
| |
| const selectedCardObj = currentPlayer.cards[cardIndex]; |
| viewCard(selectedCardObj, `كرت ${currentPlayer.name}`); |
| |
| |
| actionPlayer.cards.splice(actionCardIndex, 1); |
| |
| |
| gameState.discardPile.push(actionCard.value); |
| |
| |
| delete selectableCards.dataset.actionCardIndex; |
| delete selectableCards.dataset.actionPlayerIndex; |
| |
| |
| hideCardSelectionModal(); |
| updateGameBoard(); |
| nextPlayer(); |
| return; |
| } |
| |
| |
| |
| const selectedCardObj = currentPlayer.cards.find(card => |
| card.isFaceUp && ( |
| (typeof card.value === 'number' && typeof lastDiscard === 'number' && card.value === lastDiscard) || |
| (typeof card.value === 'object' && typeof lastDiscard === 'object' && card.value.name === lastDiscard.name) |
| ) |
| ); |
| |
| if (!selectedCardObj) { |
| alert('خطأ: الكرت المحدد غير موجود!'); |
| playSound(errorSound); |
| return; |
| } |
| |
| |
| const cardIndexInHand = currentPlayer.cards.indexOf(selectedCardObj); |
| if (cardIndexInHand !== -1) { |
| currentPlayer.cards.splice(cardIndexInHand, 1); |
| } |
| |
| |
| gameState.discardPile.push(selectedCardObj.value); |
| |
| |
| hideCardSelectionModal(); |
| updateGameBoard(); |
| nextPlayer(); |
| playSound(discardSound); |
| } |
| |
| function confirmPlayerSelection() { |
| const selectedPlayer = document.querySelector('#selectable-players > div.bg-blue-100'); |
| if (!selectedPlayer) { |
| alert('الرجاء اختيار لاعب أولاً'); |
| playSound(errorSound); |
| return; |
| } |
| |
| const playerIndex = selectedPlayer.dataset.playerIndex; |
| const selectedPlayerObj = gameState.players[playerIndex]; |
| |
| |
| if (selectablePlayers.dataset.actionCardIndex !== undefined) { |
| const actionCardIndex = selectablePlayers.dataset.actionCardIndex; |
| const actionPlayerIndex = selectablePlayers.dataset.actionPlayerIndex; |
| const actionPlayer = gameState.players[actionPlayerIndex]; |
| const actionCard = actionPlayer.cards[actionCardIndex]; |
| |
| |
| const faceDownCards = selectedPlayerObj.cards.filter(card => !card.isFaceUp); |
| |
| if (faceDownCards.length === 0) { |
| alert('لا توجد كروت مخفية لدى هذا اللاعب!'); |
| playSound(errorSound); |
| return; |
| } |
| |
| |
| const randomIndex = Math.floor(Math.random() * faceDownCards.length); |
| const viewedCard = faceDownCards[randomIndex]; |
| |
| |
| viewCard(viewedCard, `كرت ${selectedPlayerObj.name}`); |
| |
| |
| actionPlayer.cards.splice(actionCardIndex, 1); |
| |
| |
| gameState.discardPile.push(actionCard.value); |
| |
| |
| delete selectablePlayers.dataset.actionCardIndex; |
| delete selectablePlayers.dataset.actionPlayerIndex; |
| |
| |
| hidePlayerSelectionModal(); |
| updateGameBoard(); |
| nextPlayer(); |
| return; |
| } |
| } |
| |
| function cancelCardSelection() { |
| hideCardSelectionModal(); |
| } |
| |
| function cancelPlayerSelection() { |
| hidePlayerSelectionModal(); |
| } |
| |
| function closeCardView() { |
| cardViewModal.classList.remove('opacity-100'); |
| cardViewModal.classList.add('opacity-0', 'pointer-events-none'); |
| } |
| |
| function calculateScores() { |
| |
| gameState.players.forEach(player => { |
| let score = 0; |
| |
| player.cards.forEach(card => { |
| if (typeof card.value === 'number') { |
| score += card.value; |
| } else if (typeof card.value === 'object' && card.value.penalty) { |
| score += card.value.penalty; |
| } |
| }); |
| |
| |
| score += player.penalties; |
| |
| |
| if (gameState.round === 4) { |
| score *= 2; |
| } |
| |
| player.points += score; |
| }); |
| } |
| |
| function endGame() { |
| |
| calculateScores(); |
| |
| |
| const scores = gameState.players.map(player => player.points); |
| const minScore = Math.min(...scores); |
| const maxScore = Math.max(...scores); |
| |
| |
| gameResults.innerHTML = ''; |
| |
| |
| const sortedPlayers = [...gameState.players].sort((a, b) => a.points - b.points); |
| |
| sortedPlayers.forEach((player, index) => { |
| const playerDiv = document.createElement('div'); |
| playerDiv.className = `mb-3 p-4 rounded-lg flex justify-between items-center ${ |
| player.points === minScore ? 'bg-green-100 text-green-800 border border-green-200' : |
| player.points === maxScore ? 'bg-red-100 text-red-800 border border-red-200' : 'bg-gray-100 border border-gray-200' |
| }`; |
| |
| playerDiv.innerHTML = ` |
| <div class="flex items-center gap-3"> |
| ${player.points === minScore ? '<div class="winner-crown">👑</div>' : ''} |
| <span class="font-bold">${player.name}</span> |
| </div> |
| <span class="font-bold ${player.points === minScore ? 'text-green-600' : player.points === maxScore ? 'text-red-600' : 'text-gray-600'}"> |
| ${player.points} نقطة |
| </span> |
| `; |
| |
| gameResults.appendChild(playerDiv); |
| }); |
| |
| |
| gameOverModal.classList.remove('opacity-0', 'pointer-events-none'); |
| gameOverModal.classList.add('opacity-100'); |
| |
| |
| playSound(winSound); |
| } |
| |
| function resetGame() { |
| |
| gameOverModal.classList.remove('opacity-100'); |
| gameOverModal.classList.add('opacity-0', 'pointer-events-none'); |
| |
| |
| initializeGame(); |
| } |
| |
| function newGame() { |
| |
| gameOverModal.classList.remove('opacity-100'); |
| gameOverModal.classList.add('opacity-0', 'pointer-events-none'); |
| |
| |
| gameBoard.classList.add('hidden'); |
| |
| |
| modeSelection.classList.remove('hidden'); |
| } |
| |
| function showRules() { |
| rulesModal.classList.remove('opacity-0', 'pointer-events-none'); |
| rulesModal.classList.add('opacity-100'); |
| } |
| |
| function hideRules() { |
| rulesModal.classList.remove('opacity-100'); |
| rulesModal.classList.add('opacity-0', 'pointer-events-none'); |
| } |
| |
| function toggleSound() { |
| gameState.soundEnabled = !gameState.soundEnabled; |
| |
| if (gameState.soundEnabled) { |
| soundToggle.innerHTML = '<i class="fas fa-volume-up text-2xl"></i>'; |
| } else { |
| soundToggle.innerHTML = '<i class="fas fa-volume-mute text-2xl"></i>'; |
| } |
| } |
| |
| function playSound(sound) { |
| if (gameState.soundEnabled) { |
| sound.currentTime = 0; |
| sound.play().catch(e => console.log('Sound playback prevented:', e)); |
| } |
| } |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=V-Booking/f" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |