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:03] 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 485: Ligne 491:
  
  
 +// ===== ESQUIVE =====
  
-// ===== ESQUIVE ===== 
-let agiDice = char.agi * 2; 
 let checked = [...document.querySelectorAll(".skill:checked")].map(e=>e.dataset.name); let checked = [...document.querySelectorAll(".skill:checked")].map(e=>e.dataset.name);
  
-let esquive1 ccDice*0.75 + agiDice*0.25; +// ===== ESQUIVE CAC ===== 
-let esquive2 ccDice*0.25 agiDice*0.75;+// règle : meilleur entre CC et AGI (dés), puis conversion jet protection
  
-let esquive Math.floor(Math.max(esquive1esquive2)); +let esquiveCAC = Math.max(ccDiceagiDice);
-let esquiveCAC = esquive;+
  
-if(checked.includes("Réflexes fulgurants")) +// conversion en jet + protection 
-esquive Math.floor(agiDice*0.85 ccDice*0.15);+esquiveCAC esquiveCAC bestProt;
  
-if(checked.includes("Couverture")) 
-esquive = Math.floor(ccDice*0.85 + agiDice*0.15); 
  
 +// ===== 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
 +
 +let esquiveA = Math.floor(char.cc * 0.75 + char.agi * 0.25);
 +let esquiveB = Math.floor(char.cc * 0.25 + char.agi * 0.75);
 +
 +// passifs qui remplacent le calcul
 +let esquiveStat;
 +
 +if(checked.includes("Réflexes fulgurants")){
 +    esquiveStat = Math.floor(char.agi * 0.85 + char.cc * 0.15);
 +}
 +else if(checked.includes("Couverture")){
 +    esquiveStat = Math.floor(char.cc * 0.85 + char.agi * 0.15);
 +}
 +else{
 +    esquiveStat = Math.max(esquiveA, esquiveB);
 +}
 +
 +// conversion en jet
 +let esquiveTir = esquiveStat * 2;
 +
 +// protection (UNE seule fois)
 +esquiveTir += bestProt;
 +
 +// 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 517: 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 528: 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\n🎯 CT distances :"++"\n\n===== JET DISTANCE =====\n"
 +"\n🎯 CT distances :"+
 "\n1 case : "+ct1+ "\n1 case : "+ct1+
 "\n2 cases : "+ct2+ "\n2 cases : "+ct2+
Ligne 572: Ligne 610:
 }); });
  
-// ===== SORTS ACTIFS ===== 
  
  
Ligne 630: Ligne 667:
 updateCost(); calculate(); calculatePush(); updateCost(); calculate(); calculatePush();
 })); }));
 +
  
 // ===== INIT ===== // ===== INIT =====
Ligne 635: 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.1777921428.txt.gz · Dernière modification : 2026/05/04 21:03 de nanaki