Download index.html from V-Booking/f: direct link, hf CLI and curl.
- Browser
- Download file 77.5 kB
-
https://huggingface.co/spaces/V-Booking/f/resolve/main/index.html
- Command line
-
hf download hf://spaces/V-Booking/f/index.html
-
curl -L -o index.html https://huggingface.co/spaces/V-Booking/f/resolve/main/index.html
77.5 kB
| <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> | |
| <!-- Game Mode Selection --> | |
| <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> | |
| <!-- Player Setup --> | |
| <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"> | |
| <!-- Player name inputs will be added here --> | |
| </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> | |
| <!-- Game Board --> | |
| <div id="game-board" class="hidden"> | |
| <!-- Game Info --> | |
| <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> | |
| <!-- Center Area --> | |
| <div class="relative mb-16 bg-indigo-50 rounded-xl p-6 shadow-inner"> | |
| <!-- Draw Pile --> | |
| <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> | |
| <!-- Discard Pile --> | |
| <div class="flex justify-center"> | |
| <div id="discard-pile" class="card card-front mx-2"> | |
| <!-- Cards will be placed here --> | |
| </div> | |
| </div> | |
| <!-- Current Round Info --> | |
| <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> | |
| <!-- Players Area --> | |
| <div id="players-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> | |
| <!-- Player areas will be added here --> | |
| </div> | |
| <!-- Current Player Actions --> | |
| <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> | |
| <!-- Card Selection Modal --> | |
| <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"> | |
| <!-- Cards will be added here --> | |
| </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> | |
| <!-- Player Selection Modal --> | |
| <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"> | |
| <!-- Players will be added here --> | |
| </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> | |
| <!-- Card View Modal --> | |
| <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"> | |
| <!-- Card will be shown here --> | |
| </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> | |
| <!-- Game Over Modal --> | |
| <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"> | |
| <!-- Results will be added here --> | |
| </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> | |
| <!-- Rules Modal --> | |
| <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> | |
| <!-- Help Button --> | |
| <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> | |
| <!-- Sound Toggle --> | |
| <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> | |
| // Game State | |
| 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' } | |
| } | |
| }; | |
| // DOM Elements | |
| 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'); | |
| // Buttons | |
| 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'); | |
| // Audio Elements | |
| 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'); | |
| // Event Listeners | |
| document.querySelectorAll('.mode-option').forEach(option => { | |
| option.addEventListener('click', () => { | |
| gameState.mode = option.dataset.mode; | |
| modeSelection.classList.add('hidden'); | |
| playerSetup.classList.remove('hidden'); | |
| // Set game mode display text | |
| let modeText = ''; | |
| switch(gameState.mode) { | |
| case 'general': modeText = 'سكرو العامة'; break; | |
| case 'classic': modeText = 'سكرو كلاسيك'; break; | |
| case 'thief': modeText = 'سكرو الحرامي'; break; | |
| case 'duos': modeText = 'سكرو الثنائيات'; break; | |
| } | |
| gameMode.textContent = modeText; | |
| // Setup player name inputs | |
| 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); | |
| // Initialize | |
| 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() { | |
| // Get player names | |
| 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'); | |
| // Initialize game | |
| initializeGame(); | |
| } | |
| function initializeGame() { | |
| // Reset game state | |
| gameState.round = 1; | |
| gameState.skruDeclared = false; | |
| gameState.skruPlayer = null; | |
| gameState.gameStarted = true; | |
| // Create deck based on game mode | |
| gameState.drawPile = createDeck(); | |
| // Shuffle deck | |
| shuffleDeck(gameState.drawPile); | |
| // Deal cards to players (4 each) | |
| gameState.players.forEach(player => { | |
| player.cards = []; | |
| for (let i = 0; i < 4; i++) { | |
| player.cards.push({ | |
| value: gameState.drawPile.pop(), | |
| isFaceUp: false | |
| }); | |
| } | |
| }); | |
| // Set first card in discard pile | |
| gameState.discardPile = [gameState.drawPile.pop()]; | |
| // Set first player | |
| gameState.currentPlayerIndex = 0; | |
| gameState.players[0].isActive = true; | |
| // Update UI | |
| updateGameBoard(); | |
| updateRoundInfo(); | |
| // Show actions for current player | |
| playerActions.classList.remove('hidden'); | |
| // Play sound | |
| playSound(specialSound); | |
| } | |
| function createDeck() { | |
| const deck = []; | |
| // Regular cards (1-10) | |
| for (let i = 1; i <= 10; i++) { | |
| // Add 4 copies of each number | |
| for (let j = 0; j < 4; j++) { | |
| deck.push(i); | |
| } | |
| } | |
| // Special cards based on game mode | |
| switch(gameState.mode) { | |
| case 'general': // All special cards | |
| 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': // All except thief, bing, 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 'thief': // All except bing, bong | |
| 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': // All except 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; | |
| } | |
| 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() { | |
| // Update players display | |
| 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') { | |
| // Special card | |
| 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 { | |
| // Number card | |
| if (card.value >= 7 && card.value <= 10) { | |
| cardDiv.classList.add('action-card'); | |
| } | |
| cardDiv.innerHTML = ` | |
| <div class="card-value">${card.value}</div> | |
| `; | |
| } | |
| } | |
| // Add click event for viewing cards in certain rounds | |
| 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); | |
| }); | |
| // Update discard pile | |
| 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') { | |
| // Special card | |
| 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 { | |
| // Number card | |
| if (lastCard >= 7 && lastCard <= 10) { | |
| cardDiv.classList.add('action-card'); | |
| } | |
| cardDiv.innerHTML = ` | |
| <div class="card-value">${lastCard}</div> | |
| `; | |
| } | |
| discardPile.appendChild(cardDiv); | |
| } | |
| // Update draw pile count | |
| drawCount.textContent = gameState.drawPile.length; | |
| // Update round number | |
| roundNumber.textContent = gameState.round; | |
| // Update current player name | |
| 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]; | |
| // In round 1, players can view their first two cards | |
| if (gameState.round === 1 && cardIndex < 2) { | |
| viewCard(card, `كرت ${player.name}`); | |
| } | |
| // For action cards (7-10) | |
| 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': | |
| // Player can view one of their own cards | |
| 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 | |
| ); | |
| // Store the action card info for later use | |
| selectableCards.dataset.actionCardIndex = cardIndex; | |
| selectableCards.dataset.actionPlayerIndex = playerIndex; | |
| break; | |
| case 'view-other': | |
| // Player can view one card from another player | |
| showPlayerSelectionModal( | |
| `اختر لاعباً لرؤية أحد كروته (باستخدام كرت ${card.value})`, | |
| playerIndex | |
| ); | |
| // Store the action card info for later use | |
| 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') { | |
| // Special card | |
| 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 { | |
| // Number card | |
| if (card.value >= 7 && card.value <= 10) { | |
| cardDiv.classList.add('action-card'); | |
| } | |
| cardDiv.innerHTML = ` | |
| <div class="card-value">${card.value}</div> | |
| `; | |
| } | |
| viewedCard.appendChild(cardDiv); | |
| // Show modal | |
| 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]; | |
| // Check if drawn card is the thief in certain modes | |
| if (gameState.mode !== 'classic' && typeof drawnCard === 'object' && drawnCard.type === 'thief') { | |
| // Player must keep the thief card | |
| currentPlayer.cards.push({ | |
| value: drawnCard, | |
| isFaceUp: true | |
| }); | |
| alert(`لقد سحبت كرت ${drawnCard.name}! يجب عليك الاحتفاظ به ولا يمكنك التخلص منه.`); | |
| updateGameBoard(); | |
| playSound(specialSound); | |
| return; | |
| } | |
| // Show card selection modal to choose whether to keep or discard | |
| 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]; | |
| // Player must keep the card from discard | |
| currentPlayer.cards.push({ | |
| value: drawnCard, | |
| isFaceUp: true | |
| }); | |
| // Check if player can play a similar card immediately | |
| checkForSimilarCards(); | |
| updateGameBoard(); | |
| playSound(drawSound); | |
| } | |
| function playSimilarCard() { | |
| const currentPlayer = gameState.players[gameState.currentPlayerIndex]; | |
| const lastDiscard = gameState.discardPile[gameState.discardPile.length - 1]; | |
| // Find cards that match the last discarded card | |
| 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; | |
| } | |
| // Show card selection to choose which similar card to play | |
| showCardSelectionModal(similarCards, 'اختر كرت للتخلص منه:'); | |
| } | |
| function declareSkru() { | |
| if (confirm('هل أنت متأكد أنك تريد إعلان "سكرو"؟')) { | |
| gameState.skruDeclared = true; | |
| gameState.skruPlayer = gameState.currentPlayerIndex; | |
| // Current player skips their turn | |
| nextPlayer(); | |
| // Hide actions for current player | |
| 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]; | |
| // Check if player has any cards that match the last discarded card | |
| 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() { | |
| // Deactivate current player | |
| gameState.players[gameState.currentPlayerIndex].isActive = false; | |
| // Move to next player | |
| gameState.currentPlayerIndex = (gameState.currentPlayerIndex + 1) % gameState.players.length; | |
| // Check if we've completed a full round | |
| if (gameState.currentPlayerIndex === 0 && !gameState.skruDeclared) { | |
| gameState.round++; | |
| updateRoundInfo(); | |
| // Check for round-specific rules | |
| applyRoundRules(); | |
| } | |
| // Check if game should end (after skru) | |
| if (gameState.skruDeclared && gameState.currentPlayerIndex === gameState.skruPlayer) { | |
| endGame(); | |
| return; | |
| } | |
| // Activate next player | |
| gameState.players[gameState.currentPlayerIndex].isActive = true; | |
| // Update UI | |
| updateGameBoard(); | |
| // Show actions for current player | |
| playerActions.classList.remove('hidden'); | |
| } | |
| function applyRoundRules() { | |
| // Apply rules specific to each round | |
| switch(gameState.round) { | |
| case 1: // First round - players can look at first two cards on the right | |
| gameState.players.forEach(player => { | |
| // Reveal first two cards | |
| if (player.cards.length >= 1) player.cards[0].isFaceUp = true; | |
| if (player.cards.length >= 2) player.cards[1].isFaceUp = true; | |
| }); | |
| break; | |
| case 2: // Silent round - no talking (handled by UI warning) | |
| break; | |
| case 3: // No looking round - all cards face down | |
| gameState.players.forEach(player => { | |
| player.cards.forEach(card => { | |
| card.isFaceUp = false; | |
| }); | |
| }); | |
| break; | |
| case 4: // Double points round (handled at scoring) | |
| break; | |
| } | |
| } | |
| function showCardSelectionModal(cards, message, showKeepOption = false) { | |
| selectableCards.innerHTML = ''; | |
| selectionTitle.textContent = message; | |
| // Add cards | |
| 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') { | |
| // Special card | |
| 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 { | |
| // Number card | |
| if (card.value >= 7 && card.value <= 10) { | |
| cardDiv.classList.add('action-card'); | |
| } | |
| function showPlayerSelectionModal(message, excludePlayerIndex) { | |
| selectablePlayers.innerHTML = ''; | |
| playerSelectionTitle.textContent = message; | |
| // Add players | |
| 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', () => { | |
| // Toggle selection | |
| 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); | |
| } | |
| }); | |
| // Show modal | |
| 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]; | |
| // Check if this is an action card selection | |
| 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]; | |
| // View the selected card | |
| const selectedCardObj = currentPlayer.cards[cardIndex]; | |
| viewCard(selectedCardObj, `كرت ${currentPlayer.name}`); | |
| // Remove the action card from player's hand | |
| actionPlayer.cards.splice(actionCardIndex, 1); | |
| // Add action card to discard pile | |
| gameState.discardPile.push(actionCard.value); | |
| // Clear stored data | |
| delete selectableCards.dataset.actionCardIndex; | |
| delete selectableCards.dataset.actionPlayerIndex; | |
| // Hide modal and continue | |
| hideCardSelectionModal(); | |
| updateGameBoard(); | |
| nextPlayer(); | |
| return; | |
| } | |
| // Normal card selection for playing similar card | |
| // Get the actual card from player's hand that matches the last discard | |
| 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; | |
| } | |
| // Remove card from player's hand | |
| const cardIndexInHand = currentPlayer.cards.indexOf(selectedCardObj); | |
| if (cardIndexInHand !== -1) { | |
| currentPlayer.cards.splice(cardIndexInHand, 1); | |
| } | |
| // Add card to discard pile | |
| gameState.discardPile.push(selectedCardObj.value); | |
| // Hide modal and continue | |
| 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]; | |
| // Check if this is for an action card | |
| 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]; | |
| // Get a random face-down card from the selected player | |
| const faceDownCards = selectedPlayerObj.cards.filter(card => !card.isFaceUp); | |
| if (faceDownCards.length === 0) { | |
| alert('لا توجد كروت مخفية لدى هذا اللاعب!'); | |
| playSound(errorSound); | |
| return; | |
| } | |
| // Select a random face-down card | |
| const randomIndex = Math.floor(Math.random() * faceDownCards.length); | |
| const viewedCard = faceDownCards[randomIndex]; | |
| // View the card | |
| viewCard(viewedCard, `كرت ${selectedPlayerObj.name}`); | |
| // Remove the action card from player's hand | |
| actionPlayer.cards.splice(actionCardIndex, 1); | |
| // Add action card to discard pile | |
| gameState.discardPile.push(actionCard.value); | |
| // Clear stored data | |
| delete selectablePlayers.dataset.actionCardIndex; | |
| delete selectablePlayers.dataset.actionPlayerIndex; | |
| // Hide modal and continue | |
| 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() { | |
| // Calculate scores for each player | |
| 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; | |
| } | |
| }); | |
| // Add any penalties | |
| score += player.penalties; | |
| // Double points in round 4 | |
| if (gameState.round === 4) { | |
| score *= 2; | |
| } | |
| player.points += score; | |
| }); | |
| } | |
| function endGame() { | |
| // Calculate scores | |
| calculateScores(); | |
| // Determine winners and losers | |
| const scores = gameState.players.map(player => player.points); | |
| const minScore = Math.min(...scores); | |
| const maxScore = Math.max(...scores); | |
| // Display results | |
| gameResults.innerHTML = ''; | |
| // Sort players by score (ascending) | |
| 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); | |
| }); | |
| // Show game over modal | |
| gameOverModal.classList.remove('opacity-0', 'pointer-events-none'); | |
| gameOverModal.classList.add('opacity-100'); | |
| // Play sound | |
| playSound(winSound); | |
| } | |
| function resetGame() { | |
| // Hide game over modal | |
| gameOverModal.classList.remove('opacity-100'); | |
| gameOverModal.classList.add('opacity-0', 'pointer-events-none'); | |
| // Reset game with same players and mode | |
| initializeGame(); | |
| } | |
| function newGame() { | |
| // Hide game over modal | |
| gameOverModal.classList.remove('opacity-100'); | |
| gameOverModal.classList.add('opacity-0', 'pointer-events-none'); | |
| // Hide game board | |
| gameBoard.classList.add('hidden'); | |
| // Show mode selection | |
| 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> |