Outils pour utilisateurs

Outils du site


simulateur

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
simulateur [2026/05/04 21:23] nanakisimulateur [2026/05/20 16:46] (Version actuelle) nanaki
Ligne 86: Ligne 86:
  
 <button onclick="resetAll()">Reset</button> <button onclick="resetAll()">Reset</button>
 +
 +<button onclick="exportBuild()">📤 Export</button>
 +<button onclick="importBuild()">📥 Import</button>
 +<button onclick="copyLink()">🔗 Lien</button>
  
 <pre id="result" class="result"></pre> <pre id="result" class="result"></pre>
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,3); let ct3 = getCTDistance(finalCT,3);
 let ct4 = getCTDistance(finalCT,4); let ct4 = getCTDistance(finalCT,4);
- 
  
  
 // ===== ESQUIVE ===== // ===== ESQUIVE =====
 +
 let checked = [...document.querySelectorAll(".skill:checked")].map(e=>e.dataset.name); let checked = [...document.querySelectorAll(".skill:checked")].map(e=>e.dataset.name);
  
-// CAC = jet CC direct +// ===== ESQUIVE CAC ===== 
-let esquiveCAC = finalCC;+// règle : meilleur entre CC et AGI (dés), puis conversion jet + protection 
 + 
 +let esquiveCAC = Math.max(ccDice, agiDice); 
 + 
 +// 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 = Math.max(esquiveA, esquiveB);+let esquiveStat;
  
-// ===== PASSIFS ===== 
- 
-// remplace complètement le calcul si passif spécifique 
 if(checked.includes("Réflexes fulgurants")){ if(checked.includes("Réflexes fulgurants")){
     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("Couverture")){
-if(checked.includes("Couverture")){+
     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, esquiveB);
 } }
  
 // conversion en jet // conversion en jet
-let esquive = esquiveStat * 2;+let esquiveTir = esquiveStat * 2
 + 
 +// protection (UNE seule fois) 
 +esquiveTir += bestProt;
  
-// bonus+// bonus passifs
 if(checked.includes("Fulgurance")) if(checked.includes("Fulgurance"))
-    esquive += 1+    esquiveTir += 1;
- +
-// bonus protection +
-esquive += bestProt;+
  
  
 // ===== ESQUIVE MAGIQUE ===== // ===== ESQUIVE MAGIQUE =====
-let esquiveFM = Math.floor(finalFM bestProt);+// 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 seuil = 6 + 6 * lvl; 
-let reussite = jetFM >= seuil ? "✅" : "❌";+    let reussite = jetFM >= seuil ? "✅" : "❌";
  
-sorts += `Niveau ${lvl} → Seuil ${seuil} | Jet ${jetFM} ${reussite}\n`;+    sorts += `Niveau ${lvl} → Seuil ${seuil} | Jet ${jetFM} ${reussite}\n`;
 } }
  
Ligne 543: Ligne 559:
  
 result.textContent = result.textContent =
-"===== STATS =====\n"++ 
 +"===== PERSONNAGE =====\n"
 +"Race : "+raceSelect.value+ 
 + 
 +"\n\n===== STATS =====\n"+
 JSON.stringify(char,null,2)+ JSON.stringify(char,null,2)+
  
-"\n\n⚔ CC : jet moyen "+ccDice+"  ("+finalCC+")"+"\n\n===== JET OFFENSIF =====\n"
-"\n🎯 CT : jet moyen "+ctDice+"  ("+finalCT+")"+"\n⚔ CC : jet moyen "+ccDice+" ("+finalCC+")"
-"\n✨ FM : jet moyen "+fmDice+"  ("+finalFM+")"++"\n🎯 CT : jet moyen "+ctDice+" ("+finalCT+")"
 +"\n✨ FM : jet moyen "+fmDice+" ("+finalFM+")"+
  
-"\n\n🛡 Esquive CAC : "+esquiveCAC+ +"\n\n===== JET DEFENSIF =====\n"
-"\n🏹 Esquive tir : "+esquive++"\n🛡 Esquive CAC : "+esquiveCAC+ 
 +"\n🏹 Esquive tir : "+esquiveTir+
 "\n✨ Esquive FM : "+esquiveFM+ "\n✨ Esquive FM : "+esquiveFM+
-"\n🏹 Esquive tir : "+esquive+" ("+esquiveStat+" dés)" 
  
-"\n\n🎯 CT distances :"++"\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(); calculate(); calculatePush(); updateCost(); calculate(); calculatePush();
 })); }));
 +
  
 // ===== 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,s])=>{
 +        data.equip[k] = s.value;
 +    });
 +
 +    // passifs
 +    document.querySelectorAll(".skill:checked").forEach(s=>{
 +        data.skills.push(s.dataset.name);
 +    });
 +
 +    // sorts
 +    document.querySelectorAll(".spell:checked").forEach(s=>{
 +        data.spells.push({
 +            dex: +s.dataset.dex,
 +            prot: +s.dataset.prot
 +        });
 +    });
 +
 +    return data;
 +}
 +
 +// =====================================
 +// APPLY BUILD
 +// =====================================
 +
 +function applyBuild(data){
 +
 +    // race
 +    raceSelect.value = data.race || "Elfe";
 +
 +    // recharge équipements race
 +    resetSlots();
 +    fillEquip();
 +
 +    // stats
 +    for(let s in costTable){
 +        document.getElementById(s).value =
 +            data.stats?.[s] || 0;
 +    }
 +    
 +    // équipements
 +    Object.entries(slots).forEach(([k,s])=>{
 +        s.value = data.equip?.[k] || "";
 +    });
 +
 +    // refresh affichage bonus équipements
 +    Object.entries(slots).forEach(([k,s])=>{
 +        displayStats(s, slotToStatId[k]);
 +    });
 +    
 +
 +    // passifs
 +    document.querySelectorAll(".skill").forEach(s=>{
 +        s.checked =
 +            data.skills?.includes(s.dataset.name);
 +    });
 +
 +    // sorts
 +    document.querySelectorAll(".spell").forEach(s=>{
 +
 +        s.checked = data.spells?.some(sp =>
 +            sp.dex == +s.dataset.dex &&
 +            sp.prot == +s.dataset.prot
 +        );
 +
 +    });
 +
 +    displayBase();
 +    checkLimit();
 +    autoCalculate();
 +}
 +
 +// =====================================
 +// EXPORT
 +// =====================================
 +
 +function exportBuild(){
 +
 +    let data = getBuildData();
 +
 +    let code = encodeBuild(data);
 +
 +    prompt("Copie ton build :", code);
 +}
 +
 +// =====================================
 +// IMPORT
 +// =====================================
 +
 +function importBuild(codeInput){
 +
 +    let code = codeInput;
 +
 +    if(!code){
 +        code = prompt("Colle le code du build :");
 +    }
 +
 +    if(!code) return;
 +
 +    try{
 +
 +        code = code.trim();
 +
 +        let data = decodeBuild(code);
 +
 +        applyBuild(data);
 +
 +        alert("✅ Build importé");
 +
 +    }catch(e){
 +
 +        console.log(e);
 +
 +        alert("❌ Code invalide");
 +    }
 +}
 +
 +// =====================================
 +// LIEN PARTAGE
 +// =====================================
 +
 +function copyLink(){
 +
 +    let data = getBuildData();
 +
 +    let code = encodeBuild(data);
 +
 +    let url =
 +        window.location.origin +
 +        window.location.pathname +
 +        "?id=simulateur&build=" + code;
 +
 +    navigator.clipboard.writeText(url).then(()=>{
 +
 +        alert("🔗 Lien copié !");
 +
 +    }).catch(()=>{
 +
 +        prompt("Copie ce lien :", url);
 +
 +    });
 +}
 +
 +// =====================================
 +// AUTO LOAD URL
 +// =====================================
 +
 +(function(){
 +
 +    try{
 +
 +        let params =
 +            new URLSearchParams(window.location.search);
 +
 +        let code = params.get("build");
 +
 +        if(!code) return;
 +
 +        let data = decodeBuild(code);
 +
 +        applyBuild(data);
 +
 +        console.log("✅ Build URL chargé");
 +
 +    }catch(e){
 +
 +        console.log("Erreur chargement URL", e);
 +
 +    }
 +
 +})();
  
 </script> </script>
 </body> </body>
 </html> </html>
simulateur.1777922608.txt.gz · Dernière modification : 2026/05/04 21:23 de nanaki