// Liste des monstres du jeu let monsters = [ { id: 1, name: 'Chatacabra', image: 'img/Chatacabra.jpg' }, { id: 2, name: 'Quematrice', image: 'img/Quematrice.jpg' }, { id: 3, name: 'Lala Barina', image: 'img/Lala_Barina.jpg' }, { id: 4, name: 'Congalala', image: 'img/Congalala.jpg' }, { id: 5, name: 'Balahara', image: 'img/Balahara.jpg' }, { id: 6, name: 'Doshaguma', image: 'img/Doshaguma.jpg' }, { id: 7, name: 'Uth Duna', image: 'img/Uth_Duna.jpg' }, { id: 8, name: 'Rompopolo', image: 'img/Rompopolo.jpg' }, { id: 9, name: 'Rey Dau', image: 'img/Rey_Dau.jpg' }, { id: 10, name: 'Nerscylla', image: 'img/Nerscylla.jpg' }, { id: 11, name: 'Hirabami', image: 'img/Hirabami.jpg' }, { id: 12, name: 'Ajarakan', image: 'img/Ajarakan.jpg' }, { id: 13, name: 'Nu Udra', image: 'img/Nu_Udra.jpg' }, { id: 14, name: 'Doshaguma Gardien', image: 'img/Doshaguma_Gardien.jpg' }, { id: 15, name: 'Rathalos Gardien', image: 'img/Rathalos_Gardien.jpg' }, { id: 16, name: 'Jin Dahaad', image: 'img/Jin_Dahaad.jpg' }, { id: 17, name: 'Odogaron Désastre Gardien', image: 'img/Odogaron_Desastre_Gardien.jpg' }, { id: 18, name: 'Xu Wu', image: 'img/Xu_Wu.jpg' }, { id: 19, name: 'Arkveld Gardien', image: 'img/Arkveld_Gardien.jpg' }, { id: 20, name: 'Zoh Shia', image: 'img/Zoh_Shia.jpg' }, { id: 21, name: 'Yian Kut-Ku', image: 'img/Yian_Kut-Ku.jpg' }, { id: 22, name: 'Gypceros', image: 'img/Gypceros.jpg' }, { id: 23, name: 'Rathian', image: 'img/Rathian.jpg' }, { id: 24, name: 'Anjanath Tonnerre Gardien', image: 'img/Anjanath_Tonnerre_Gardien.jpg' }, { id: 25, name: 'Rathalos', image: 'img/Rathalos.jpg' }, { id: 26, name: 'Gravios', image: 'img/Gravios.jpg' }, { id: 27, name: 'Blangonga', image: 'img/Blangonga.jpg' }, { id: 28, name: 'Gore Malaga', image: 'img/Gore_Malaga.jpg' }, { id: 29, name: 'Arkveld', image: 'img/Arkveld.jpg' } ]; let quests = [ { id: 1, monsterId: 1, crownType: 'small', playerName: 'Hunter123', playerId: 'MHW-1234', date: new Date().toISOString() }, { id: 2, monsterId: 1, crownType: 'large', playerName: 'DragonSlayer', playerId: 'MHW-5678', date: new Date().toISOString() }, { id: 3, monsterId: 2, crownType: 'small', playerName: 'ThunderLord', playerId: 'MHW-9012', date: new Date().toISOString() } ]; let announcements = [ { id: 1, text: "Bienvenue sur le site de partage de quêtes à couronnes pour Monster Hunter Wilds!", active: true } ]; // Éléments DOM const monsterListEl = document.getElementById('monsterList'); const modalMonsterNameEl = document.getElementById('modalMonsterName'); const questListEl = document.getElementById('questList'); const addQuestBtn = document.getElementById('addQuestBtn'); const addQuestForm = document.getElementById('addQuestForm'); const crownFilterEls = document.querySelectorAll('input[name="crownFilter"]'); const announcementAreaEl = document.getElementById('announcementArea'); const confirmDeleteBtn = document.getElementById('confirmDeleteBtn'); const monsterSearchEl = document.getElementById('monsterSearch'); const clearSearchBtn = document.getElementById('clearSearchBtn'); // Variables globales let currentMonsterId = null; let currentQuestToDelete = null; // Modales Bootstrap const questListModal = new bootstrap.Modal(document.getElementById('questListModal')); const addQuestModal = new bootstrap.Modal(document.getElementById('addQuestModal')); const deleteQuestModal = new bootstrap.Modal(document.getElementById('deleteQuestModal')); // Initialisation document.addEventListener('DOMContentLoaded', () => { loadData(); renderMonsterList(); setupMonsterSearchSelect(); displayAnnouncements(); // Événements addQuestBtn.addEventListener('click', () => { resetMonsterSearchSelect(); addQuestModal.show(); }); addQuestForm.addEventListener('submit', handleAddQuest); crownFilterEls.forEach(radio => { radio.addEventListener('change', filterQuests); }); confirmDeleteBtn.addEventListener('click', handleDeleteQuest); // Événements pour la recherche monsterSearchEl.addEventListener('input', searchMonsters); clearSearchBtn.addEventListener('click', clearSearch); // Initialiser le sélecteur de monstre avec recherche initMonsterSearchSelect(); }); // Fonctions de chargement et sauvegarde des données function loadData() { // Essayer de charger depuis localStorage s'il y a des données const storedQuests = localStorage.getItem('mhw_quests'); const storedAnnouncements = localStorage.getItem('mhw_announcements'); if (storedQuests) quests = JSON.parse(storedQuests); if (storedAnnouncements) announcements = JSON.parse(storedAnnouncements); } function saveData() { localStorage.setItem('mhw_quests', JSON.stringify(quests)); console.log('Données sauvegardées'); } // Affichage des annonces function displayAnnouncements() { const activeAnnouncements = announcements.filter(a => a.active); if (activeAnnouncements.length > 0) { announcementAreaEl.innerHTML = activeAnnouncements.map(a => `

${a.text}

`).join(''); announcementAreaEl.classList.remove('d-none'); } else { announcementAreaEl.classList.add('d-none'); } } // Rendu de la liste des monstres function renderMonsterList(filteredMonsters = null) { const monstersToRender = filteredMonsters || monsters; if (monstersToRender.length === 0) { monsterListEl.innerHTML = `

Aucun monstre disponible pour le moment.

`; return; } monsterListEl.innerHTML = monstersToRender.map(monster => { const smallCrownCount = quests.filter(q => q.monsterId === monster.id && q.crownType === 'small').length; const largeCrownCount = quests.filter(q => q.monsterId === monster.id && q.crownType === 'large').length; return `
${monster.name}
${monster.name}
👑 ${smallCrownCount} 👑 ${largeCrownCount}
`; }).join(''); // Ajouter les écouteurs d'événements après avoir rendu la liste document.querySelectorAll('.monster-card').forEach(card => { card.addEventListener('click', () => { const monsterId = parseInt(card.dataset.monsterId); showQuestsForMonster(monsterId); }); }); } // Recherche de monstres sur la page principale function searchMonsters() { const searchTerm = monsterSearchEl.value.trim().toLowerCase(); if (searchTerm === '') { // Si la recherche est vide, afficher tous les monstres renderMonsterList(); return; } // Filtrer les monstres qui correspondent à la recherche const filteredMonsters = monsters.filter(monster => monster.name.toLowerCase().includes(searchTerm) ); // Afficher un message si aucun monstre ne correspond if (filteredMonsters.length === 0) { monsterListEl.innerHTML = `

Aucun monstre ne correspond à votre recherche "${monsterSearchEl.value}".

`; return; } renderMonsterList(filteredMonsters); } // Effacer la recherche function clearSearch() { monsterSearchEl.value = ''; renderMonsterList(); } // Afficher les quêtes pour un monstre spécifique function showQuestsForMonster(monsterId) { currentMonsterId = monsterId; const monster = monsters.find(m => m.id === monsterId); if (!monster) return; modalMonsterNameEl.textContent = monster.name; // Réinitialiser le filtre document.getElementById('filterAll').checked = true; // Afficher toutes les quêtes pour ce monstre renderQuestList(monsterId); // Afficher la modale questListModal.show(); } // Rendu de la liste des quêtes function renderQuestList(monsterId, filter = 'all') { let monsterQuests = quests.filter(q => q.monsterId === monsterId); if (filter !== 'all') { monsterQuests = monsterQuests.filter(q => q.crownType === filter); } if (monsterQuests.length === 0) { questListEl.innerHTML = `

Aucune quête disponible pour ce monstre avec ce filtre.

`; return; } questListEl.innerHTML = monsterQuests.map(quest => { const monster = monsters.find(m => m.id === quest.monsterId); const crownClass = quest.crownType === 'small' ? 'small-crown' : 'large-crown'; const crownText = quest.crownType === 'small' ? 'Petite couronne' : 'Grande couronne'; const questDate = new Date(quest.date); const daysDiff = Math.floor((new Date() - questDate) / (1000 * 60 * 60 * 24)); const freshness = daysDiff <= 1 ? 'Aujourd\'hui' : daysDiff <= 2 ? 'Hier' : `Il y a ${daysDiff} jours`; return `
👑 ${crownText} pour ${monster.name}

Proposée par: ${quest.playerName} (ID: ${quest.playerId})

Ajoutée: ${freshness}

`; }).join(''); // Ajouter les écouteurs d'événements pour les boutons de suppression document.querySelectorAll('.quest-delete-btn').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const questId = parseInt(btn.dataset.questId); showDeleteConfirmation(questId); }); }); } // Filtrer les quêtes function filterQuests() { const filterValue = document.querySelector('input[name="crownFilter"]:checked').value; renderQuestList(currentMonsterId, filterValue); } // Afficher la confirmation de suppression function showDeleteConfirmation(questId) { currentQuestToDelete = questId; deleteQuestModal.show(); } // Gérer la suppression d'une quête function handleDeleteQuest() { if (currentQuestToDelete === null) return; // Trouver l'index de la quête à supprimer const questIndex = quests.findIndex(q => q.id === currentQuestToDelete); if (questIndex === -1) return; // Mémoriser le monsterId pour mettre à jour l'affichage const monsterId = quests[questIndex].monsterId; // Supprimer la quête quests.splice(questIndex, 1); // Sauvegarder les données saveData(); // Mettre à jour l'affichage renderMonsterList(); // Si la modale des quêtes est ouverte, mettre à jour son contenu if (currentMonsterId === monsterId) { renderQuestList(currentMonsterId); } // Fermer la modale de confirmation deleteQuestModal.hide(); // Réinitialiser currentQuestToDelete = null; } // Préparer le HTML pour le sélecteur de monstre avec recherche function setupMonsterSearchSelect() { // Récupérer le conteneur du formulaire const monsterFieldContainer = document.querySelector('.mb-3:has(#monsterSelect)'); if (!monsterFieldContainer) return; // Remplacer le contenu par notre nouveau sélecteur monsterFieldContainer.innerHTML = `
🔍
Veuillez sélectionner un monstre
`; // Ajouter les styles CSS nécessaires s'ils n'existent pas déjà if (!document.getElementById('monster-search-styles')) { const styleEl = document.createElement('style'); styleEl.id = 'monster-search-styles'; styleEl.textContent = ` /* Styles pour le select searchable personnalisé */ .monster-search-container { position: relative; } .monster-search-results { position: absolute; width: 100%; max-height: 250px; overflow-y: auto; background-color: var(--mh-light-bg); border: 1px solid var(--mh-accent); border-radius: 0.375rem; z-index: 1050; margin-top: 2px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); } .monster-search-item { padding: 8px 12px; cursor: pointer; border-bottom: 1px solid rgba(255, 255, 255, 0.1); color: var(--mh-light); } .monster-search-item:hover, .monster-search-item.active { background-color: var(--mh-dark); } .monster-search-item:last-child { border-bottom: none; } .selected-monster { font-weight: bold; color: var(--mh-accent); } .monster-search-no-results { padding: 10px; text-align: center; color: var(--mh-light); font-style: italic; } `; document.head.appendChild(styleEl); } } // Initialiser le sélecteur de monstre avec recherche function initMonsterSearchSelect() { const searchInput = document.getElementById('monsterSearchSelect'); const searchResults = document.getElementById('monsterSearchResults'); const hiddenInput = document.getElementById('selectedMonsterId'); if (!searchInput || !searchResults || !hiddenInput) return; // Événement pour l'input de recherche searchInput.addEventListener('input', function() { const searchTerm = this.value.trim().toLowerCase(); // Filtrer les monstres qui correspondent à la recherche const filteredMonsters = monsters.filter(monster => monster.name.toLowerCase().includes(searchTerm) ); // Afficher les résultats renderSearchResults(filteredMonsters, searchResults); // Montrer les résultats si l'input a du contenu if (searchTerm.length > 0) { searchResults.classList.remove('d-none'); } else if (!hiddenInput.value) { // Cacher seulement si aucun monstre n'est déjà sélectionné searchResults.classList.add('d-none'); } }); // Événement pour le focus sur l'input searchInput.addEventListener('focus', function() { const searchTerm = this.value.trim().toLowerCase(); // Si l'input a du contenu ou si un monstre est déjà sélectionné, montrer les résultats if (searchTerm.length > 0 || hiddenInput.value) { // Filtrer les monstres qui correspondent à la recherche const filteredMonsters = searchTerm.length > 0 ? monsters.filter(monster => monster.name.toLowerCase().includes(searchTerm)) : monsters; // Afficher les résultats renderSearchResults(filteredMonsters, searchResults); searchResults.classList.remove('d-none'); } }); // Fermer les résultats lors d'un clic à l'extérieur document.addEventListener('click', function(e) { if (!searchInput?.contains(e.target) && !searchResults?.contains(e.target)) { searchResults?.classList.add('d-none'); } }); // Navigation avec les flèches du clavier searchInput.addEventListener('keydown', function(e) { if (searchResults.classList.contains('d-none')) return; const items = searchResults.querySelectorAll('.monster-search-item'); const activeItem = searchResults.querySelector('.monster-search-item.active'); switch(e.key) { case 'ArrowDown': e.preventDefault(); if (!activeItem) { items[0]?.classList.add('active'); ensureVisible(items[0], searchResults); } else { const nextItem = activeItem.nextElementSibling; if (nextItem) { activeItem.classList.remove('active'); nextItem.classList.add('active'); ensureVisible(nextItem, searchResults); } } break; case 'ArrowUp': e.preventDefault(); if (activeItem) { const prevItem = activeItem.previousElementSibling; if (prevItem) { activeItem.classList.remove('active'); prevItem.classList.add('active'); ensureVisible(prevItem, searchResults); } } break; case 'Enter': e.preventDefault(); if (activeItem) { const monsterId = activeItem.dataset.monsterId; selectMonster(monsterId, searchInput, hiddenInput, searchResults); } break; case 'Escape': e.preventDefault(); searchResults.classList.add('d-none'); break; } }); } // S'assurer que l'élément actif est visible dans la liste déroulante function ensureVisible(element, container) { if (!element || !container) return; const containerRect = container.getBoundingClientRect(); const elementRect = element.getBoundingClientRect(); if (elementRect.bottom > containerRect.bottom) { container.scrollTop += elementRect.bottom - containerRect.bottom; } else if (elementRect.top < containerRect.top) { container.scrollTop -= containerRect.top - elementRect.top; } } // Afficher les résultats de recherche pour le sélecteur de monstre function renderSearchResults(results, container) { if (!container) return; if (results.length === 0) { container.innerHTML = '
Aucun monstre trouvé
'; return; } container.innerHTML = results.map(monster => `
${monster.name}
` ).join(''); // Ajouter les écouteurs d'événements pour les éléments de la liste container.querySelectorAll('.monster-search-item').forEach(item => { item.addEventListener('click', function() { const monsterId = this.dataset.monsterId; const searchInput = document.getElementById('monsterSearchSelect'); const hiddenInput = document.getElementById('selectedMonsterId'); const searchResults = document.getElementById('monsterSearchResults'); selectMonster(monsterId, searchInput, hiddenInput, searchResults); }); }); } // Sélectionner un monstre dans le sélecteur function selectMonster(monsterId, searchInput, hiddenInput, searchResults) { const monster = monsters.find(m => m.id == monsterId); if (monster) { searchInput.value = monster.name; hiddenInput.value = monster.id; searchInput.classList.add('selected-monster'); searchResults.classList.add('d-none'); } } // Réinitialiser le sélecteur de monstre function resetMonsterSearchSelect() { const searchInput = document.getElementById('monsterSearchSelect'); const hiddenInput = document.getElementById('selectedMonsterId'); const searchResults = document.getElementById('monsterSearchResults'); if (searchInput) { searchInput.value = ''; searchInput.classList.remove('selected-monster'); } if (hiddenInput) { hiddenInput.value = ''; } if (searchResults) { searchResults.classList.add('d-none'); } } // Gérer l'ajout d'une quête function handleAddQuest(e) { e.preventDefault(); const monsterId = parseInt(document.getElementById('selectedMonsterId')?.value); const crownType = document.querySelector('input[name="crownType"]:checked')?.value; const playerName = document.getElementById('playerName')?.value.trim(); const playerId = document.getElementById('playerId')?.value.trim(); if (!monsterId || !crownType || !playerName || !playerId) { alert('Veuillez remplir tous les champs requis'); return; } // Générer un ID unique pour la nouvelle quête const newQuestId = quests.length > 0 ? Math.max(...quests.map(q => q.id)) + 1 : 1; // Créer la nouvelle quête const newQuest = { id: newQuestId, monsterId, crownType, playerName, playerId, date: new Date().toISOString() }; // Ajouter la quête à la liste quests.push(newQuest); // Sauvegarder les données saveData(); // Mettre à jour l'affichage renderMonsterList(); // Réinitialiser le formulaire et fermer la modale addQuestForm.reset(); resetMonsterSearchSelect(); addQuestModal.hide(); // Si la modale des quêtes est ouverte, mettre à jour son contenu if (currentMonsterId === monsterId) { renderQuestList(currentMonsterId); } } // Nettoyer les quêtes de plus de 7 jours (à appeler depuis l'admin) function cleanOldQuests() { const sevenDaysAgo = new Date(); sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7); const oldQuestsCount = quests.filter(q => new Date(q.date) < sevenDaysAgo).length; quests = quests.filter(q => new Date(q.date) >= sevenDaysAgo); saveData(); renderMonsterList(); return oldQuestsCount; }