brouillon3
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| brouillon3 [2026/04/21 17:22] – nanaki | brouillon3 [2026/05/12 13:53] (Version actuelle) – nanaki | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| + | Voici un simulateur en version beta, n' | ||
| + | |||
| + | |||
| < | < | ||
| + | < | ||
| + | <meta charset=" | ||
| + | < | ||
| < | < | ||
| - | body { font-family: | + | body { |
| + | | ||
| + | background:# | ||
| + | color:# | ||
| + | padding: | ||
| + | } | ||
| + | h1,h2 { color: | ||
| + | .box { border:1px solid gold; padding: | ||
| + | select { margin:3px; max-width: | ||
| + | input { margin:3px; width:60px; } | ||
| + | .statLine { display: | ||
| + | .result { background:# | ||
| + | .small { font-size: | ||
| + | </ | ||
| + | </ | ||
| - | .controls { display: | + | < |
| - | #pointsBox { font-weight: | + | < |
| - | table { width:100%; border-collapse: | + | <div class=" |
| - | th, td { border:1px solid #ccc; padding: | + | Race : |
| - | th { background:# | + | <select id=" |
| - | tr: | + | < |
| + | <pre id=" | ||
| + | </ | ||
| - | .offensif { background:# | + | <div class=" |
| - | .defensif { background:# | + | < |
| - | .utilitaire { background:# | + | <div id=" |
| + | <div id=" | ||
| + | </ | ||
| - | .lvl { padding:2px 6px; border-radius: | + | <div class=" |
| - | .lvl-1 { background:# | + | < |
| - | .lvl-2 { background:#cce5ff; } | + | Tête <select id=" |
| - | </style> | + | Cou <select id=" |
| + | Dos <select id=" | ||
| + | Main droite <select id=" | ||
| + | Main gauche <select id=" | ||
| + | Corps <select id=" | ||
| + | Anneau <select id=" | ||
| + | Pieds <select id=" | ||
| + | <div id=" | ||
| + | </div> | ||
| - | < | + | < |
| - | Points utilisés : <span id="points">0</span> / 15 | + | <h3> |
| + | < | ||
| </ | </ | ||
| - | <div class=" | + | <div class=" |
| - | <select id=" | + | <h3>Sorts actifs</ |
| - | <option value="Toutes">Toutes</option> | + | <div id="spells"></ |
| - | <option value="Communs">Communs</option> | + | <div id=" |
| - | </select> | + | </div> |
| - | <select id=" | ||
| - | <option value=" | ||
| - | <option value=" | ||
| - | <option value=" | ||
| - | <option value=" | ||
| - | </ | ||
| - | <input type=" | ||
| - | </ | ||
| - | <table id=" | + | <!-- ================= POUSSEE ================= --> |
| - | < | + | <div class="box"> |
| - | < | + | <h3>Simulateur de poussée</h3> |
| - | <th onclick=" | + | |
| - | <th onclick=" | + | |
| - | <th onclick=" | + | |
| - | <th onclick=" | + | |
| - | < | + | |
| - | <th onclick="sortTable(5)"> | + | |
| - | </tr> | + | |
| - | </thead> | + | |
| - | <tbody> | + | Force assaillant |
| + | Renforcement <select id=" | ||
| - | <tr class="Communs offensif" | + | Endurance |
| - | <td>< | + | Agilité |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="Communs offensif" | + | PV actuels |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="Communs utilitaire" | + | Instabilité |
| - | <td><input type="checkbox" | + | Stabilité |
| - | <td>Communs</td> | + | |
| - | <td>Arcane ajustée</td> | + | |
| - | <td>Sort</td> | + | |
| - | <td>Avantage au toucher</td> | + | |
| - | <td>< | + | |
| - | </tr> | + | |
| - | </tbody> | + | <pre id=" |
| - | </table> | + | </div> |
| + | |||
| + | <button onclick=" | ||
| + | |||
| + | <button onclick=" | ||
| + | <button onclick=" | ||
| + | <button onclick=" | ||
| + | |||
| + | <pre id=" | ||
| < | < | ||
| - | const maxPoints = 15; | ||
| - | const raceFilter | + | // ===== RACES ===== |
| - | const typeFilter | + | const races = { |
| - | const search | + | Elfe: |
| - | const rows = document.querySelectorAll("# | + | Nain: |
| - | const checkboxes | + | Géant: |
| - | const pointsDisplay | + | Olympien: |
| + | HS: | ||
| + | }; | ||
| - | function updatePoints(e){ | + | // ===== COST ===== |
| - | let total = 0; | + | const costTable |
| + | a: | ||
| + | cc: | ||
| + | f: | ||
| + | agi: | ||
| + | m: | ||
| + | fm: | ||
| + | p: | ||
| + | pv: | ||
| + | pm: | ||
| + | mvt: | ||
| + | r: | ||
| + | rm: | ||
| + | }; | ||
| - | checkboxes.forEach(cb | + | // ===== PASSIFS ===== |
| - | | + | const skills = [ |
| - | }); | + | {name:" |
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | ]; | ||
| - | if(total > maxPoints){ | + | // ===== SORTS ===== |
| - | | + | const spells |
| - | | + | {name:" |
| - | } | + | {name:" |
| - | pointsDisplay.textContent = total; | + | {name:" |
| + | {name:" | ||
| - | if(total >= maxPoints){ | + | {name:" |
| - | | + | |
| - | | + | {name:" |
| - | }); | + | {name:" |
| - | } else { | + | |
| - | | + | {name:" |
| - | } | + | {name:" |
| + | |||
| + | {name:" | ||
| + | |||
| + | {name:" | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | ]; | ||
| + | |||
| + | |||
| + | |||
| + | const equipments | ||
| + | |||
| + | /* ================= COMMUNS ================= */ | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | /* ===== NOUVEAUX COMMUNS ===== */ | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | /* ================= ELFES ================= */ | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | // spécifique elfe | ||
| + | {name:" | ||
| + | |||
| + | /* ================= NAINS ================= */ | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | // spécifiques nains | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | /* ================= GÉANTS ================= */ | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | // spécifique géant | ||
| + | {name:" | ||
| + | |||
| + | /* ================= HS ================= */ | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | // spécifiques HS | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | /* ================= OLYMPIENS ================= */ | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | // spécifique olympien | ||
| + | {name:" | ||
| + | |||
| + | /* ================= ANNEAUX ================= */ | ||
| + | |||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | |||
| + | ]; | ||
| + | |||
| + | |||
| + | // ===== INIT ===== | ||
| + | const raceSelect = document.getElementById(" | ||
| + | const statsDiv | ||
| + | const baseDiv | ||
| + | |||
| + | for(let r in races){ | ||
| + | raceSelect.innerHTML += `< | ||
| } | } | ||
| - | checkboxes.forEach(cb => { | + | // stats UI |
| - | cb.addEventListener("change", updatePoints); | + | for(let s in costTable){ |
| + | statsDiv.innerHTML += ` | ||
| + | <div class=" | ||
| + | < | ||
| + | <input type=" | ||
| + | </ | ||
| + | } | ||
| + | |||
| + | // passifs | ||
| + | skills.forEach(s=>{ | ||
| + | document.getElementById("skills").innerHTML += ` | ||
| + | < | ||
| + | <input type=" | ||
| + | < | ||
| + | <span class=" | ||
| + | </ | ||
| }); | }); | ||
| - | function filter(){ | ||
| - | const term = search.value.toLowerCase(); | ||
| - | rows.forEach(row=>{ | + | // affichage sorts |
| - | const raceOk = raceFilter.value==="Toutes" | + | spells.forEach(s=>{ |
| - | const typeOk | + | document.getElementById(" |
| - | const textOk = row.innerText.toLowerCase().includes(term); | + | < |
| + | <input type=" | ||
| + | < | ||
| + | <span class=" | ||
| + | </ | ||
| + | }); | ||
| - | row.style.display = (raceOk && typeOk && textOk) ? "" | + | // base stats |
| - | }); | + | function displayBase(){ |
| + | baseDiv.textContent = JSON.stringify(races[raceSelect.value], | ||
| } | } | ||
| + | raceSelect.addEventListener(" | ||
| + | displayBase(); | ||
| - | raceFilter.onchange | + | // ===== COST ===== |
| - | typeFilter.onchange | + | function calcCost(b, |
| - | search.oninput | + | let total=0, |
| + | for(let i=1;i< | ||
| + | if(i===1) last=b; | ||
| + | else if(i<=3) last+=m1; | ||
| + | else last+=m2; | ||
| + | total+=last; | ||
| + | } | ||
| + | return total; | ||
| + | } | ||
| - | function | + | function |
| - | const tbody = document.querySelector("# | + | let total=0; |
| - | const rowsArr | + | for(let s in costTable){ |
| + | let v=+document.getElementById(s).value||0; | ||
| + | let [b,m1,m2]=costTable[s]; | ||
| + | total+=calcCost(b, | ||
| + | } | ||
| + | document.getElementById(" | ||
| + | } | ||
| - | rowsArr.sort((a, | + | // ===== SLOTS ===== |
| - | | + | const slots = { |
| - | | + | head: |
| - | | + | leftHand:leftHand, |
| - | )); | + | }; |
| - | rowsArr.forEach(r=>tbody.appendChild(r)); | + | function resetSlots(){ |
| + | Object.values(slots).forEach(s=>s.innerHTML="< | ||
| } | } | ||
| - | </ | ||
| - | </ | + | function fillEquip(){ |
| + | let r=raceSelect.value; | ||
| + | equipments.forEach((e, | ||
| + | if(e.race!==" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | }); | ||
| + | } | ||
| + | raceSelect.addEventListener(" | ||
| + | resetSlots(); | ||
| + | fillEquip(); | ||
| + | autoCalculate(); | ||
| + | }); | ||
| - | < | + | resetSlots(); |
| + | fillEquip(); | ||
| - | < | + | // ===== BONUS ===== |
| - | table { width:100%; border-collapse: | + | function displayStats(select, |
| - | th, td { border:1px solid #ccc; padding:6px; } | + | let v=select.value; |
| + | let el=document.getElementById(id); | ||
| + | if(v==="" | ||
| + | let e=equipments[v]; | ||
| + | let txt=""; | ||
| + | for(let s in e.stats){ | ||
| + | let val=e.stats[s]; | ||
| + | txt+=val> | ||
| + | } | ||
| + | el.innerHTML=txt; | ||
| + | } | ||
| - | tr[data-effect="offensif"] { background:#ffe5e5; } | + | const slotToStatId |
| - | tr[data-effect="defensif"] { background:#e5f0ff; } | + | head:"headStats", |
| - | tr[data-effect="malediction"] { background:# | + | neck:" |
| + | cape:"capeStats", | ||
| + | rightHand:" | ||
| + | leftHand:"leftStats", | ||
| + | body:" | ||
| + | ring:" | ||
| + | feet:" | ||
| + | }; | ||
| - | th { background:# | + | Object.entries(slots).forEach(([k, |
| - | </ | + | s.addEventListener(" |
| + | displayStats(s, | ||
| + | checkLimit(); | ||
| + | autoCalculate(); | ||
| + | }); | ||
| + | }); | ||
| - | <table> | + | // ===== LIMIT ===== |
| + | function checkLimit(){ | ||
| + | let count=0; | ||
| + | Object.entries(slots).forEach(([k, | ||
| + | if(k!==" | ||
| + | }); | ||
| - | <thead> | + | if(count>=3){ |
| - | <tr> | + | limitWarn.innerText=" |
| - | < | + | Object.entries(slots).forEach(([k, |
| - | < | + | if(k!==" |
| - | < | + | }); |
| - | < | + | }else{ |
| - | < | + | limitWarn.innerText=""; |
| - | < | + | Object.values(slots).forEach(s=>s.disabled=false); |
| - | </tr> | + | } |
| - | </ | + | } |
| - | < | + | // ===== CALCUL ===== |
| - | <!-- 🔥 OFFENSIF --> | + | function calculate(){ |
| - | <tr class=" | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | <td>6 PM</ | + | |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <!-- 🛡 DÉFENSIF --> | + | let activeSpells |
| - | <tr class="Communs" | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | <td>5 PM</ | + | |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <!-- ☠️ MALÉDICTION --> | + | let bestDex = 0; |
| - | <tr class=" | + | let bestProt |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | <td>6 PM</ | + | |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | </tbody> | + | activeSpells.forEach(s=>{ |
| + | let d = +s.dataset.dex; | ||
| + | let p = +s.dataset.prot; | ||
| - | </table> | + | if(Math.abs(d) |
| + | if(Math.abs(p) > Math.abs(bestProt)) bestProt = p; | ||
| + | }); | ||
| - | </ | + | let char={...races[raceSelect.value]}; |
| + | // stats investies | ||
| + | for(let s in costTable){ | ||
| + | let v=+document.getElementById(s).value||0; | ||
| + | char[s]=(char[s]||0)+v; | ||
| + | } | ||
| + | // equip | ||
| + | Object.values(slots).forEach(sel=> | ||
| + | if(sel.value==="" | ||
| + | let e=equipments[sel.value]; | ||
| + | for(let s in e.stats){ | ||
| + | char[s]=(char[s]||0)+e.stats[s]; | ||
| + | } | ||
| + | }); | ||
| - | < | + | // ===== DÉS ===== |
| + | let ccDice = char.cc * 2; | ||
| + | let ctDice = char.ct * 2; | ||
| + | let fmDice = char.fm * 2; | ||
| + | let agiDice = char.agi * 2; | ||
| - | < | + | // ===== VALEURS FINALES ===== |
| - | body { font-family: | + | let finalCC = ccDice + bestDex; |
| + | let finalCT = ctDice + bestDex; | ||
| + | let finalFM = fmDice + bestDex; | ||
| - | .controls { display: | ||
| - | # | + | // ===== CT DISTANCE ===== |
| + | function getCTDistance(baseCT, | ||
| + | if(distance <= 2) return baseCT; | ||
| + | return baseCT - (distance | ||
| + | } | ||
| - | table { width:100%; border-collapse: | + | let ct1 = getCTDistance(finalCT, |
| - | th, td { border:1px solid #ccc; padding: | + | let ct2 = getCTDistance(finalCT,2); |
| - | th { background:# | + | let ct3 = getCTDistance(finalCT, |
| - | tr: | + | let ct4 = getCTDistance(finalCT,4); |
| - | .offensif { background:# | ||
| - | .defensif { background:# | ||
| - | .utilitaire { background:# | ||
| - | .malediction { background:# | ||
| - | .lvl { padding:2px 6px; border-radius: | + | // ===== ESQUIVE ===== |
| - | .lvl-1 { background:# | + | |
| - | .lvl-2 { background:# | + | |
| - | </style> | + | let checked = [...document.querySelectorAll(" |
| - | <div id=" | + | // ===== ESQUIVE CAC ===== |
| - | Points utilisés : <span id=" | + | // règle : meilleur entre CC et AGI (dés), puis conversion jet + protection |
| - | </div> | + | |
| - | <div class=" | + | let esquiveCAC |
| - | <select id=" | + | // conversion en jet + protection |
| - | <option value=" | + | esquiveCAC |
| - | <option value=" | + | |
| - | </ | + | |
| - | <select id=" | ||
| - | <option value=" | ||
| - | <option value=" | ||
| - | <option value=" | ||
| - | <option value=" | ||
| - | </ | ||
| - | <select id=" | + | // ===== ESQUIVE TIR ===== |
| - | <option value=" | + | // règle : |
| - | <option value=" | + | // max entre : |
| - | <option value=" | + | // (3/4 CC + 1/4 AGI) |
| - | <option value=" | + | // (1/4 CC + 3/4 AGI) |
| - | </select> | + | // arrondi inférieur → dés → ×2 → + protection |
| - | <input type=" | + | let esquiveA |
| + | let esquiveB | ||
| - | </div> | + | // passifs qui remplacent le calcul |
| + | let esquiveStat; | ||
| - | <table id="table"> | + | if(checked.includes("Réflexes fulgurants")){ |
| - | < | + | |
| - | <tr> | + | } |
| - | < | + | else if(checked.includes(" |
| - | < | + | |
| - | < | + | } |
| - | < | + | else{ |
| - | < | + | |
| - | < | + | } |
| - | </tr> | + | |
| - | </ | + | |
| - | < | + | // conversion en jet |
| + | let esquiveTir = esquiveStat * 2; | ||
| - | <!-- SORTS AJOUTES --> | + | // protection (UNE seule fois) |
| + | esquiveTir += bestProt; | ||
| - | <tr class=" | + | // bonus passifs |
| - | < | + | if(checked.includes("Fulgurance")) |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class=" | ||
| - | < | ||
| - | < | ||
| - | < | ||
| - | < | ||
| - | < | ||
| - | < | ||
| - | </tr> | ||
| - | <tr class=" | + | // ===== ESQUIVE MAGIQUE ===== |
| - | < | + | // règle : FM en jet + protection |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | </ | + | let esquiveFM = fmDice + bestProt; |
| - | </ | + | |
| - | < | + | // ===== MAGIE ===== |
| - | const maxPoints | + | let jetFM = finalFM; |
| - | const raceFilter | + | let sorts = ""; |
| - | const typeFilter | + | for(let lvl=1; lvl<=5; lvl++){ |
| - | const effectFilter | + | let seuil = 6 + 6 * lvl; |
| - | const search = document.getElementById(" | + | let reussite |
| - | const rows = document.querySelectorAll("# | + | |
| - | const checkboxes | + | |
| - | const pointsDisplay = document.getElementById("points"); | + | |
| - | function updatePoints(e){ | + | sorts += `Niveau ${lvl} → Seuil ${seuil} | Jet ${jetFM} ${reussite}\n`; |
| - | let total = 0; | + | } |
| - | checkboxes.forEach(cb | + | // ===== AFFICHAGE ===== |
| - | if(cb.checked) total++; | + | document.getElementById(" |
| - | }); | + | "Bonus actifs → Dex: "+bestDex+" | Protection: " |
| - | if(total > maxPoints){ | + | result.textContent |
| - | e.target.checked | + | |
| - | return; | + | |
| - | } | + | |
| - | pointsDisplay.textContent | + | "===== PERSONNAGE =====\n" |
| + | "Race : " | ||
| - | if(total >= maxPoints){ | + | " |
| - | | + | JSON.stringify(char, |
| - | if(!cb.checked) | + | |
| + | "\n\n===== JET OFFENSIF =====\n" | ||
| + | "\n⚔ CC : jet moyen " | ||
| + | " | ||
| + | "\n✨ FM : jet moyen " | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | "\n✨ Esquive FM : " | ||
| + | |||
| + | " | ||
| + | " | ||
| + | "\n1 case : " | ||
| + | "\n2 cases : " | ||
| + | "\n3 cases : " | ||
| + | "\n4 cases : " | ||
| + | |||
| + | " | ||
| + | "Jet FM : " | ||
| + | sorts; | ||
| + | } | ||
| + | |||
| + | |||
| + | // ===== AUTO ===== | ||
| + | function autoCalculate(){ | ||
| + | updateCost(); | ||
| + | calculate(); | ||
| + | } | ||
| + | |||
| + | // events stats | ||
| + | document.querySelectorAll("# | ||
| + | i.addEventListener(" | ||
| + | }); | ||
| + | |||
| + | document.querySelectorAll(" | ||
| + | s.addEventListener(" | ||
| + | }); | ||
| + | |||
| + | |||
| + | // passifs | ||
| + | document.querySelectorAll(" | ||
| + | s.addEventListener(" | ||
| + | }); | ||
| + | |||
| + | |||
| + | |||
| + | // ===== RESET ===== | ||
| + | function resetAll(){ | ||
| + | |||
| + | document.querySelectorAll("# | ||
| + | document.querySelectorAll(" | ||
| + | |||
| + | Object.values(slots).forEach(s=> | ||
| + | s.value=""; | ||
| + | s.disabled=false; | ||
| + | }); | ||
| + | |||
| + | document.querySelectorAll(" | ||
| + | |||
| + | resetSlots(); | ||
| + | fillEquip(); | ||
| + | displayBase(); | ||
| + | checkLimit(); | ||
| + | autoCalculate(); | ||
| + | } | ||
| + | |||
| + | // init | ||
| + | autoCalculate(); | ||
| + | |||
| + | |||
| + | |||
| + | // ===== POUSSEE ===== | ||
| + | function calculatePush(){ | ||
| + | |||
| + | let F=+pushF.value; | ||
| + | let buff=+pushBuff.value; | ||
| + | |||
| + | let E=+pushE.value; | ||
| + | let agi=+pushAgi.value; | ||
| + | let pv=+pushPV.value; | ||
| + | |||
| + | let instability=+pushDebuff.value; | ||
| + | let stability=+pushStab.value; | ||
| + | |||
| + | let attaque=F+buff; | ||
| + | let defense=Math.max(E+4, | ||
| + | |||
| + | pushResult.textContent= | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | |||
| + | // ===== EVENTS ===== | ||
| + | document.querySelectorAll(" | ||
| + | updateCost(); | ||
| + | })); | ||
| + | |||
| + | document.querySelectorAll(" | ||
| + | updateCost(); | ||
| + | })); | ||
| + | |||
| + | |||
| + | // ===== INIT ===== | ||
| + | updateCost(); | ||
| + | calculate(); | ||
| + | calculatePush(); | ||
| + | |||
| + | |||
| + | // ===================================== | ||
| + | // ENCODE / DECODE | ||
| + | // ===================================== | ||
| + | |||
| + | function encodeBuild(data){ | ||
| + | return encodeURIComponent(JSON.stringify(data)); | ||
| + | } | ||
| + | |||
| + | function decodeBuild(code){ | ||
| + | return JSON.parse(decodeURIComponent(code)); | ||
| + | } | ||
| + | |||
| + | // ===================================== | ||
| + | // BUILD DATA | ||
| + | // ===================================== | ||
| + | |||
| + | function getBuildData(){ | ||
| + | |||
| + | let data = { | ||
| + | race: raceSelect.value, | ||
| + | stats: {}, | ||
| + | equip: {}, | ||
| + | skills: [], | ||
| + | spells: [] | ||
| + | }; | ||
| + | |||
| + | // stats | ||
| + | for(let s in costTable){ | ||
| + | data.stats[s] = +document.getElementById(s).value || 0; | ||
| + | } | ||
| + | |||
| + | // équipements | ||
| + | Object.entries(slots).forEach(([k, | ||
| + | data.equip[k] = s.value; | ||
| }); | }); | ||
| - | } else { | + | |
| - | | + | |
| - | } | + | document.querySelectorAll(" |
| + | data.skills.push(s.dataset.name); | ||
| + | }); | ||
| + | |||
| + | // sorts | ||
| + | document.querySelectorAll(" | ||
| + | data.spells.push({ | ||
| + | dex: +s.dataset.dex, | ||
| + | prot: +s.dataset.prot | ||
| + | }); | ||
| + | }); | ||
| + | |||
| + | return data; | ||
| } | } | ||
| - | checkboxes.forEach(cb | + | // ===================================== |
| + | // APPLY BUILD | ||
| + | // ===================================== | ||
| - | function | + | function |
| - | const term = search.value.toLowerCase(); | + | |
| - | rows.forEach(row=>{ | + | // race |
| + | raceSelect.value = data.race || " | ||
| - | | + | |
| - | | + | resetSlots(); |
| - | const effectOk = effectFilter.value===" | + | |
| - | const textOk = row.innerText.toLowerCase().includes(term); | + | |
| - | | + | |
| - | }); | + | for(let s in costTable){ |
| + | document.getElementById(s).value = | ||
| + | data.stats? | ||
| + | } | ||
| + | |||
| + | // équipements | ||
| + | Object.entries(slots).forEach(([k, | ||
| + | s.value = data.equip?.[k] || "" | ||
| + | }); | ||
| + | |||
| + | // passifs | ||
| + | document.querySelectorAll(".skill").forEach(s=> | ||
| + | s.checked = | ||
| + | data.skills? | ||
| + | }); | ||
| + | |||
| + | // sorts | ||
| + | document.querySelectorAll(" | ||
| + | |||
| + | s.checked = data.spells? | ||
| + | sp.dex == +s.dataset.dex && | ||
| + | sp.prot == +s.dataset.prot | ||
| + | ); | ||
| + | |||
| + | }); | ||
| + | |||
| + | displayBase(); | ||
| + | checkLimit(); | ||
| + | autoCalculate(); | ||
| } | } | ||
| - | raceFilter.onchange | + | // ===================================== |
| - | typeFilter.onchange | + | // EXPORT |
| - | effectFilter.onchange | + | // ===================================== |
| - | search.oninput | + | |
| - | function | + | function |
| - | const tbody = document.querySelector("# | + | |
| - | const rowsArr = Array.from(tbody.rows); | + | |
| - | rowsArr.sort((a, | + | let data = getBuildData(); |
| - | rowsArr.forEach(r=> | + | let code = encodeBuild(data); |
| + | |||
| + | prompt(" | ||
| } | } | ||
| - | </ | ||
| - | </html> | + | // ===================================== |
| + | // IMPORT | ||
| + | // ===================================== | ||
| + | function importBuild(codeInput){ | ||
| + | |||
| + | let code = codeInput; | ||
| + | |||
| + | if(!code){ | ||
| + | code = prompt(" | ||
| + | } | ||
| + | |||
| + | if(!code) return; | ||
| + | |||
| + | try{ | ||
| + | |||
| + | code = code.trim(); | ||
| + | |||
| + | let data = decodeBuild(code); | ||
| + | |||
| + | applyBuild(data); | ||
| + | |||
| + | alert(" | ||
| + | |||
| + | }catch(e){ | ||
| + | |||
| + | console.log(e); | ||
| + | |||
| + | alert(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // ===================================== | ||
| + | // LIEN PARTAGE | ||
| + | // ===================================== | ||
| + | |||
| + | function copyLink(){ | ||
| + | |||
| + | let data = getBuildData(); | ||
| + | |||
| + | let code = encodeBuild(data); | ||
| + | |||
| + | let url = | ||
| + | window.location.origin + | ||
| + | window.location.pathname + | ||
| + | "? | ||
| + | |||
| + | navigator.clipboard.writeText(url).then(()=> | ||
| + | |||
| + | alert(" | ||
| + | |||
| + | }).catch(()=> | ||
| + | |||
| + | prompt(" | ||
| + | |||
| + | }); | ||
| + | } | ||
| + | |||
| + | // ===================================== | ||
| + | // AUTO LOAD URL | ||
| + | // ===================================== | ||
| + | |||
| + | (function(){ | ||
| + | |||
| + | try{ | ||
| + | |||
| + | let params = | ||
| + | new URLSearchParams(window.location.search); | ||
| + | |||
| + | let code = params.get(" | ||
| + | |||
| + | if(!code) return; | ||
| + | |||
| + | let data = decodeBuild(code); | ||
| + | |||
| + | applyBuild(data); | ||
| + | |||
| + | console.log(" | ||
| + | |||
| + | }catch(e){ | ||
| + | |||
| + | console.log(" | ||
| + | |||
| + | } | ||
| + | |||
| + | })(); | ||
| + | |||
| + | </ | ||
| + | </ | ||
| + | </ | ||
brouillon3.1776784931.txt.gz · Dernière modification : 2026/04/21 17:22 de nanaki
