simulateur
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 | ||
| simulateur [2026/05/04 21:23] – nanaki | simulateur [2026/05/20 16:46] (Version actuelle) – nanaki | ||
|---|---|---|---|
| Ligne 86: | Ligne 86: | ||
| <button onclick=" | <button onclick=" | ||
| + | |||
| + | <button onclick=" | ||
| + | <button onclick=" | ||
| + | <button onclick=" | ||
| <pre id=" | <pre id=" | ||
| Ligne 467: | Ligne 471: | ||
| let ctDice = char.ct * 2; | let ctDice = char.ct * 2; | ||
| let fmDice = char.fm * 2; | let fmDice = char.fm * 2; | ||
| + | let agiDice = char.agi * 2; | ||
| // ===== VALEURS FINALES ===== | // ===== VALEURS FINALES ===== | ||
| Ligne 472: | Ligne 477: | ||
| let finalCT = ctDice + bestDex; | let finalCT = ctDice + bestDex; | ||
| let finalFM = fmDice + bestDex; | let finalFM = fmDice + bestDex; | ||
| + | |||
| // ===== CT DISTANCE ===== | // ===== CT DISTANCE ===== | ||
| Ligne 483: | Ligne 489: | ||
| let ct3 = getCTDistance(finalCT, | let ct3 = getCTDistance(finalCT, | ||
| let ct4 = getCTDistance(finalCT, | let ct4 = getCTDistance(finalCT, | ||
| - | |||
| // ===== ESQUIVE ===== | // ===== ESQUIVE ===== | ||
| + | |||
| let checked = [...document.querySelectorAll(" | let checked = [...document.querySelectorAll(" | ||
| - | // CAC = jet CC direct | + | // ===== ESQUIVE |
| - | let esquiveCAC = finalCC; | + | // règle : meilleur entre CC et AGI (dés), puis conversion jet + protection |
| + | |||
| + | let esquiveCAC = Math.max(ccDice, | ||
| + | |||
| + | // conversion en jet + protection | ||
| + | esquiveCAC = esquiveCAC + bestProt; | ||
| // ===== ESQUIVE TIR ===== | // ===== ESQUIVE TIR ===== | ||
| + | // règle : | ||
| + | // max entre : | ||
| + | // (3/4 CC + 1/4 AGI) | ||
| + | // (1/4 CC + 3/4 AGI) | ||
| + | // arrondi inférieur → dés → ×2 → + protection | ||
| - | // calcul des 2 formules en dés | ||
| let esquiveA = Math.floor(char.cc * 0.75 + char.agi * 0.25); | let esquiveA = Math.floor(char.cc * 0.75 + char.agi * 0.25); | ||
| let esquiveB = Math.floor(char.cc * 0.25 + char.agi * 0.75); | let esquiveB = Math.floor(char.cc * 0.25 + char.agi * 0.75); | ||
| - | // choix du meilleur | + | // passifs qui remplacent le calcul |
| - | let esquiveStat | + | let esquiveStat; |
| - | // ===== PASSIFS ===== | ||
| - | |||
| - | // remplace complètement le calcul si passif spécifique | ||
| if(checked.includes(" | if(checked.includes(" | ||
| esquiveStat = Math.floor(char.agi * 0.85 + char.cc * 0.15); | esquiveStat = Math.floor(char.agi * 0.85 + char.cc * 0.15); | ||
| } | } | ||
| - | + | else if(checked.includes(" | |
| - | if(checked.includes(" | + | |
| esquiveStat = Math.floor(char.cc * 0.85 + char.agi * 0.15); | esquiveStat = Math.floor(char.cc * 0.85 + char.agi * 0.15); | ||
| + | } | ||
| + | else{ | ||
| + | esquiveStat = Math.max(esquiveA, | ||
| } | } | ||
| // conversion en jet | // conversion en jet | ||
| - | let esquive | + | let esquiveTir |
| + | |||
| + | // protection (UNE seule fois) | ||
| + | esquiveTir += bestProt; | ||
| - | // bonus | + | // bonus passifs |
| if(checked.includes(" | if(checked.includes(" | ||
| - | | + | |
| - | + | ||
| - | // bonus protection | + | |
| - | esquive += bestProt; | + | |
| // ===== ESQUIVE MAGIQUE ===== | // ===== ESQUIVE MAGIQUE ===== | ||
| - | let esquiveFM = Math.floor(finalFM | + | // règle : FM en jet + protection |
| + | let esquiveFM = fmDice + bestProt; | ||
| // ===== MAGIE ===== | // ===== MAGIE ===== | ||
| Ligne 532: | Ligne 548: | ||
| let sorts = ""; | let sorts = ""; | ||
| for(let lvl=1; lvl<=5; lvl++){ | for(let lvl=1; lvl<=5; lvl++){ | ||
| - | let seuil = 6 + 6 * lvl; | + | |
| - | let reussite = jetFM >= seuil ? " | + | let reussite = jetFM >= seuil ? " |
| - | sorts += `Niveau ${lvl} → Seuil ${seuil} | Jet ${jetFM} ${reussite}\n`; | + | |
| } | } | ||
| Ligne 543: | Ligne 559: | ||
| result.textContent = | result.textContent = | ||
| - | "===== STATS =====\n" | + | |
| + | "===== PERSONNAGE =====\n" | ||
| + | "Race : " | ||
| + | |||
| + | "\n\n===== STATS =====\n" | ||
| JSON.stringify(char, | JSON.stringify(char, | ||
| - | " | + | "\n\n===== JET OFFENSIF =====\n" |
| - | " | + | "\n⚔ CC : jet moyen " |
| - | "\n✨ FM : jet moyen " | + | " |
| + | "\n✨ FM : jet moyen " | ||
| - | " | + | "\n\n===== JET DEFENSIF =====\n" |
| - | " | + | "\n🛡 Esquive CAC : " |
| + | " | ||
| "\n✨ Esquive FM : " | "\n✨ Esquive FM : " | ||
| - | " | ||
| - | " | + | "\n\n===== JET DISTANCE =====\n" |
| + | "\n🎯 CT distances :"+ | ||
| "\n1 case : "+ct1+ | "\n1 case : "+ct1+ | ||
| "\n2 cases : "+ct2+ | "\n2 cases : "+ct2+ | ||
| Ligne 588: | Ligne 610: | ||
| }); | }); | ||
| - | // ===== SORTS ACTIFS ===== | ||
| Ligne 646: | Ligne 667: | ||
| updateCost(); | updateCost(); | ||
| })); | })); | ||
| + | |||
| // ===== INIT ===== | // ===== INIT ===== | ||
| Ligne 651: | Ligne 673: | ||
| calculate(); | calculate(); | ||
| calculatePush(); | 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; | ||
| + | }); | ||
| + | |||
| + | // passifs | ||
| + | document.querySelectorAll(" | ||
| + | data.skills.push(s.dataset.name); | ||
| + | }); | ||
| + | |||
| + | // sorts | ||
| + | document.querySelectorAll(" | ||
| + | data.spells.push({ | ||
| + | dex: +s.dataset.dex, | ||
| + | prot: +s.dataset.prot | ||
| + | }); | ||
| + | }); | ||
| + | |||
| + | return data; | ||
| + | } | ||
| + | |||
| + | // ===================================== | ||
| + | // APPLY BUILD | ||
| + | // ===================================== | ||
| + | |||
| + | function applyBuild(data){ | ||
| + | |||
| + | // race | ||
| + | raceSelect.value = data.race || " | ||
| + | |||
| + | // recharge équipements race | ||
| + | resetSlots(); | ||
| + | fillEquip(); | ||
| + | |||
| + | // stats | ||
| + | for(let s in costTable){ | ||
| + | document.getElementById(s).value = | ||
| + | data.stats? | ||
| + | } | ||
| + | | ||
| + | // équipements | ||
| + | Object.entries(slots).forEach(([k, | ||
| + | s.value = data.equip? | ||
| + | }); | ||
| + | |||
| + | // refresh affichage bonus équipements | ||
| + | Object.entries(slots).forEach(([k, | ||
| + | displayStats(s, | ||
| + | }); | ||
| + | | ||
| + | |||
| + | // passifs | ||
| + | document.querySelectorAll(" | ||
| + | s.checked = | ||
| + | data.skills? | ||
| + | }); | ||
| + | |||
| + | // sorts | ||
| + | document.querySelectorAll(" | ||
| + | |||
| + | s.checked = data.spells? | ||
| + | sp.dex == +s.dataset.dex && | ||
| + | sp.prot == +s.dataset.prot | ||
| + | ); | ||
| + | |||
| + | }); | ||
| + | |||
| + | displayBase(); | ||
| + | checkLimit(); | ||
| + | autoCalculate(); | ||
| + | } | ||
| + | |||
| + | // ===================================== | ||
| + | // EXPORT | ||
| + | // ===================================== | ||
| + | |||
| + | function exportBuild(){ | ||
| + | |||
| + | let data = getBuildData(); | ||
| + | |||
| + | let code = encodeBuild(data); | ||
| + | |||
| + | prompt(" | ||
| + | } | ||
| + | |||
| + | // ===================================== | ||
| + | // 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(" | ||
| + | |||
| + | } | ||
| + | |||
| + | })(); | ||
| </ | </ | ||
| </ | </ | ||
| </ | </ | ||
simulateur.1777922608.txt.gz · Dernière modification : 2026/05/04 21:23 de nanaki
