brouillon7
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 | ||
| brouillon7 [2026/04/22 20:07] – nanaki | brouillon7 [2026/05/04 21:25] (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: | ||
| + | </ | ||
| + | </ | ||
| - | table { border-collapse: | + | < |
| - | td, th { border: 1px solid #ccc; padding: 5px; } | + | |
| - | th { background: #f2f2f2; } | + | |
| - | .offensif { background: #ffe5e5; } | + | < |
| - | .defensif { background: #e5f0ff; } | + | |
| - | .malediction { background: #f3e5ff; } | + | |
| - | .controls { margin-bottom:10px; } | + | <div class=" |
| - | </style> | + | Race : |
| + | <select id=" | ||
| + | < | ||
| + | <pre id=" | ||
| + | </div> | ||
| - | <div class=" | + | <div class=" |
| + | < | ||
| + | <div id=" | ||
| + | <div id=" | ||
| + | </div> | ||
| - | Points : <span id="points">0</ | + | <div class=" |
| + | < | ||
| + | Tête <select id=" | ||
| + | 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 class=" | ||
| + | < | ||
| + | <div id=" | ||
| + | </ | ||
| + | |||
| + | <div class=" | ||
| + | < | ||
| + | <div id=" | ||
| + | <div id=" | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | <!-- ================= POUSSEE ================= --> | ||
| + | <div class=" | ||
| + | < | ||
| - | <br>< | + | Force assaillant |
| + | Renforcement <select id=" | ||
| - | Recherche : | + | Endurance |
| - | <input type="text" id="search" | + | Agilité < |
| - | Filtre effet : | + | PV actuels |
| - | <select | + | |
| - | <option value="all"> | + | |
| - | < | + | |
| - | <option value=" | + | |
| - | <option value=" | + | |
| - | </select> | + | |
| - | Filtre type : | + | Instabilité |
| - | <select id="filterType"> | + | Stabilité <select id=" |
| - | <option value=" | + | |
| - | <option value=" | + | |
| - | <option value=" | + | |
| - | <option value=" | + | |
| - | <option value=" | + | |
| - | </ | + | |
| + | <pre id=" | ||
| </ | </ | ||
| - | <table id="skills"> | + | <button onclick="resetAll()"> |
| - | <thead> | + | <pre id=" |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | < | + | |
| - | </ | + | |
| - | </thead> | + | |
| - | <tbody> | + | <script> |
| - | <!-- NIVEAU 1 --> | + | // ===== RACES ===== |
| + | const races = { | ||
| + | Elfe: | ||
| + | Nain: | ||
| + | Géant: | ||
| + | Olympien: | ||
| + | HS: | ||
| + | }; | ||
| - | <tr class=" | + | // ===== COST ===== |
| - | < | + | const costTable = { |
| - | < | + | a: |
| - | </tr> | + | cc: |
| + | f: | ||
| + | agi: | ||
| + | m: | ||
| + | fm: | ||
| + | p: | ||
| + | pv:[4,2,1], | ||
| + | pm: | ||
| + | mvt: | ||
| + | r: | ||
| + | rm: | ||
| + | }; | ||
| - | <tr class=" | + | // ===== PASSIFS ===== |
| - | < | + | const skills = [ |
| - | < | + | {name:"Fulgurance",desc:"+1 toucher au cac + 1 esquive tous les 5 mouvements"}, |
| - | </tr> | + | {name:"Couverture",desc:"85% CC / 15% AGI"}, |
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | ]; | ||
| - | <tr class=" | + | // ===== SORTS ===== |
| - | < | + | const spells |
| - | < | + | {name:"Peau de granit", |
| - | </tr> | + | {name:"Coup précis",dex:2,prot:0}, |
| - | <tr class="malediction" | + | {name:"Maladresse",dex:-2, |
| - | < | + | {name:"Vulnérabilité", |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="defensif" | + | {name:"Puissance de la nature", |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="defensif" | + | {name:"Aide", |
| - | < | + | {name:"Malchance",dex:-4,prot:0}, |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="defensif" | + | {name:"Fatigue", |
| - | < | + | {name:"Réflexes accrus", |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="malediction" | + | {name:"Bénédiction", |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="malediction" | + | {name:"Puissance du lutin capricieux",dex:-4,prot:-4}, |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="malediction" | + | {name:"Exténuation", |
| - | < | + | {name:"Sauvegarde", |
| - | < | + | {name:"Guigne", |
| - | </tr> | + | {name:"Virtuose", |
| + | ]; | ||
| - | <!-- NIVEAU 2 --> | ||
| - | <tr class=" | ||
| - | < | ||
| - | < | ||
| - | </tr> | ||
| - | <tr class=" | + | const equipments |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class=" | + | /* ================= COMMUNS ================= */ |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="offensif" | + | {name:"Arc", |
| - | < | + | {name:"Armure matelassée", |
| - | < | + | {name:"Bâton de marche", |
| - | </tr> | + | {name:"Bottes de marche",race:"all", |
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| - | <tr class=" | + | /* ===== NOUVEAUX COMMUNS ===== */ |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="offensif" | + | {name:"Torche",race:"all", |
| - | < | + | {name:"Hache de jet", |
| - | < | + | {name:"Pierre Noire",race:"all", |
| - | </tr> | + | {name:" |
| - | <!-- NIVEAU 3 --> | + | /* ================= ELFES ================= */ |
| - | <tr class="defensif" | + | {name:"Bâton du Pèlerin",race:"all",slot:"weapon", |
| - | < | + | {name:"Bottes Tâlroval",race:"all", |
| - | < | + | {name:" |
| - | </tr> | + | {name:" |
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| - | <tr class="malediction" | + | // spécifique elfe |
| - | < | + | {name:"Arc Elfique",race:"Elfe",slot:"weapon2h",stats:{ct:2,cc:-1}}, |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class=" | + | /* ================= NAINS ================= */ |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <!-- NIVEAU | + | {name:" |
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| - | <tr class="defensif" | + | // spécifiques nains |
| - | < | + | {name:"Bâton d' |
| - | < | + | {name:"Hache runique",race:"Nain", |
| - | </tr> | + | |
| - | <tr class=" | + | /* ================= GÉANTS ================= */ |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="offensif" | + | {name:"Bouclier Clipeus", |
| - | < | + | {name:" |
| - | < | + | {name:" |
| - | </tr> | + | {name:"Bâton de shaman", |
| + | {name:"Javelot lourd", | ||
| + | {name:"Broigne",race:"all", | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| - | <tr class="offensif" | + | // spécifique géant |
| - | < | + | {name:"Peau de granit manifiée",race:"Géant",slot:"body",stats:{m:1, |
| - | < | + | |
| - | </tr> | + | |
| - | <!-- NIVEAU 5 --> | + | /* ================= HS ================= */ |
| - | <tr class="malediction" | + | {name:"Bâton de sage",race:"all",slot:"weapon2h", |
| - | < | + | {name:"Orbe de mana",race:"all", |
| - | < | + | {name:" |
| - | </tr> | + | {name:" |
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| - | <tr class="defensif" | + | // spécifiques HS |
| - | < | + | {name:"Manteau de feuillage",race:"HS",slot:"body", |
| - | < | + | {name:"Bottes griffues",race:"HS", |
| - | </tr> | + | |
| - | <tr class=" | + | /* ================= OLYMPIENS ================= */ |
| - | < | + | |
| - | < | + | |
| - | </tr> | + | |
| - | <tr class="defensif" | + | {name:"Armure hoplitique",race:"all",slot:"body", |
| - | < | + | {name:"Bouclier Ancile",race:"all", |
| - | < | + | {name:" |
| - | </tr> | + | {name:" |
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| - | </tbody> | + | // spécifique olympien |
| - | </table> | + | {name:" |
| - | < | + | /* ================= ANNEAUX ================= */ |
| - | let max = 15; | + | {name:" |
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| + | {name:" | ||
| - | document.querySelectorAll(".skill").forEach(cb=>{ | + | ]; |
| - | cb.addEventListener("change", ()=>{ | + | |
| - | let total = document.querySelectorAll(".skill: | + | |
| - | if(total | + | // ===== INIT ===== |
| - | points.innerText | + | const raceSelect = document.getElementById("race"); |
| + | const statsDiv = document.getElementById(" | ||
| + | const baseDiv = document.getElementById("baseStats"); | ||
| + | |||
| + | for(let r in races){ | ||
| + | raceSelect.innerHTML += `<option>${r}</ | ||
| + | } | ||
| + | |||
| + | // stats UI | ||
| + | for(let s in costTable){ | ||
| + | statsDiv.innerHTML += ` | ||
| + | <div class=" | ||
| + | < | ||
| + | <input type=" | ||
| + | </ | ||
| + | } | ||
| + | |||
| + | // passifs | ||
| + | skills.forEach(s=> | ||
| + | document.getElementById("skills").innerHTML += ` | ||
| + | <label> | ||
| + | <input type=" | ||
| + | < | ||
| + | <span class=" | ||
| + | </ | ||
| }); | }); | ||
| + | |||
| + | |||
| + | // affichage sorts | ||
| + | spells.forEach(s=> | ||
| + | document.getElementById(" | ||
| + | < | ||
| + | <input type=" | ||
| + | < | ||
| + | <span class=" | ||
| + | </ | ||
| }); | }); | ||
| - | function | + | // base stats |
| - | let e = filterEffect.value; | + | function |
| - | let t = filterType.value; | + | baseDiv.textContent |
| - | let s = search.value.toLowerCase(); | + | } |
| + | raceSelect.addEventListener(" | ||
| + | displayBase(); | ||
| - | document.querySelectorAll("#skills tbody tr" | + | // ===== COST ===== |
| - | let txt = r.innerText.toLowerCase(); | + | function calcCost(b, |
| - | let ok = (e==" | + | let total=0, |
| - | && | + | for(let i=1; |
| - | && txt.includes(s); | + | if(i===1) last=b; |
| - | r.style.display | + | else if(i<=3) last+=m1; |
| + | else last+=m2; | ||
| + | total+=last; | ||
| + | } | ||
| + | return total; | ||
| + | } | ||
| + | |||
| + | function updateCost(){ | ||
| + | let total=0; | ||
| + | for(let s in costTable){ | ||
| + | let v=+document.getElementById(s).value||0; | ||
| + | let [b, | ||
| + | total+=calcCost(b, | ||
| + | } | ||
| + | document.getElementById("cost").innerHTML=" | ||
| + | } | ||
| + | |||
| + | // ===== SLOTS ===== | ||
| + | const slots = { | ||
| + | head: | ||
| + | leftHand: | ||
| + | }; | ||
| + | |||
| + | function resetSlots(){ | ||
| + | Object.values(slots).forEach(s=>s.innerHTML="< | ||
| + | } | ||
| + | |||
| + | function fillEquip(){ | ||
| + | let r=raceSelect.value; | ||
| + | |||
| + | equipments.forEach((e,i)=>{ | ||
| + | if(e.race!=="all"&& | ||
| + | |||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot==="body") body.innerHTML+=`< | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot===" | ||
| + | if(e.slot==="ring") ring.innerHTML+=`< | ||
| }); | }); | ||
| } | } | ||
| - | filterEffect.onchange | + | raceSelect.addEventListener(" |
| - | filterType.onchange = filter; | + | resetSlots(); |
| - | search.oninput = filter; | + | fillEquip(); |
| + | autoCalculate(); | ||
| + | }); | ||
| - | </ | + | resetSlots(); |
| + | fillEquip(); | ||
| + | // ===== BONUS ===== | ||
| + | function displayStats(select, | ||
| + | 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; | ||
| + | } | ||
| + | |||
| + | const slotToStatId = { | ||
| + | head:" | ||
| + | neck:" | ||
| + | cape:" | ||
| + | rightHand:" | ||
| + | leftHand:" | ||
| + | body:" | ||
| + | ring:" | ||
| + | feet:" | ||
| + | }; | ||
| + | |||
| + | Object.entries(slots).forEach(([k, | ||
| + | s.addEventListener(" | ||
| + | displayStats(s, | ||
| + | checkLimit(); | ||
| + | autoCalculate(); | ||
| + | }); | ||
| + | }); | ||
| + | |||
| + | // ===== LIMIT ===== | ||
| + | function checkLimit(){ | ||
| + | let count=0; | ||
| + | Object.entries(slots).forEach(([k, | ||
| + | if(k!==" | ||
| + | }); | ||
| + | |||
| + | if(count> | ||
| + | limitWarn.innerText=" | ||
| + | Object.entries(slots).forEach(([k, | ||
| + | if(k!==" | ||
| + | }); | ||
| + | }else{ | ||
| + | limitWarn.innerText=""; | ||
| + | Object.values(slots).forEach(s=> | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // ===== CALCUL ===== | ||
| + | |||
| + | function calculate(){ | ||
| + | |||
| + | let activeSpells = [...document.querySelectorAll(" | ||
| + | |||
| + | let bestDex = 0; | ||
| + | let bestProt = 0; | ||
| + | |||
| + | activeSpells.forEach(s=> | ||
| + | let d = +s.dataset.dex; | ||
| + | let p = +s.dataset.prot; | ||
| + | |||
| + | if(Math.abs(d) > Math.abs(bestDex)) bestDex = 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; | ||
| + | |||
| + | // ===== VALEURS FINALES ===== | ||
| + | let finalCC = ccDice + bestDex; | ||
| + | let finalCT = ctDice + bestDex; | ||
| + | let finalFM = fmDice + bestDex; | ||
| + | |||
| + | // ===== CT DISTANCE ===== | ||
| + | function getCTDistance(baseCT, | ||
| + | if(distance <= 2) return baseCT; | ||
| + | return baseCT - (distance - 2) * 3; | ||
| + | } | ||
| + | |||
| + | let ct1 = getCTDistance(finalCT, | ||
| + | let ct2 = getCTDistance(finalCT, | ||
| + | let ct3 = getCTDistance(finalCT, | ||
| + | let ct4 = getCTDistance(finalCT, | ||
| + | |||
| + | |||
| + | |||
| + | // ===== ESQUIVE ===== | ||
| + | let checked = [...document.querySelectorAll(" | ||
| + | |||
| + | // CAC = jet CC direct | ||
| + | let esquiveCAC = finalCC; | ||
| + | |||
| + | // ===== ESQUIVE TIR ===== | ||
| + | |||
| + | // calcul des 2 formules en dés | ||
| + | let esquiveA = Math.floor(char.cc * 0.75 + char.agi * 0.25); | ||
| + | let esquiveB = Math.floor(char.cc * 0.25 + char.agi * 0.75); | ||
| + | |||
| + | // choix du meilleur | ||
| + | let esquiveStat = Math.max(esquiveA, | ||
| + | |||
| + | // ===== PASSIFS ===== | ||
| + | |||
| + | // remplace complètement le calcul si passif spécifique | ||
| + | if(checked.includes(" | ||
| + | esquiveStat = Math.floor(char.agi * 0.85 + char.cc * 0.15); | ||
| + | } | ||
| + | |||
| + | if(checked.includes(" | ||
| + | esquiveStat = Math.floor(char.cc * 0.85 + char.agi * 0.15); | ||
| + | } | ||
| + | |||
| + | // conversion en jet | ||
| + | let esquive = esquiveStat * 2; | ||
| + | |||
| + | // bonus | ||
| + | if(checked.includes(" | ||
| + | esquive += 1; | ||
| + | |||
| + | // bonus protection | ||
| + | esquive += bestProt; | ||
| + | |||
| + | |||
| + | // ===== ESQUIVE MAGIQUE ===== | ||
| + | let esquiveFM = Math.floor(finalFM + bestProt); | ||
| + | |||
| + | |||
| + | // ===== MAGIE ===== | ||
| + | let jetFM = finalFM; | ||
| + | |||
| + | let sorts = ""; | ||
| + | for(let lvl=1; lvl<=5; lvl++){ | ||
| + | let seuil = 6 + 6 * lvl; | ||
| + | let reussite = jetFM >= seuil ? " | ||
| + | |||
| + | sorts += `Niveau ${lvl} → Seuil ${seuil} | Jet ${jetFM} ${reussite}\n`; | ||
| + | } | ||
| + | |||
| + | // ===== AFFICHAGE ===== | ||
| + | document.getElementById(" | ||
| + | "Bonus actifs → Dex: " | ||
| + | |||
| + | result.textContent = | ||
| + | "===== STATS =====\n" | ||
| + | JSON.stringify(char, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | "\n✨ FM : jet moyen " | ||
| + | |||
| + | " | ||
| + | " | ||
| + | "\n✨ Esquive FM : " | ||
| + | " | ||
| + | |||
| + | " | ||
| + | "\n1 case : "+ct1+ | ||
| + | "\n2 cases : "+ct2+ | ||
| + | "\n3 cases : "+ct3+ | ||
| + | "\n4 cases : "+ct4+ | ||
| + | |||
| + | " | ||
| + | "Jet FM : " | ||
| + | sorts; | ||
| + | } | ||
| + | |||
| + | |||
| + | // ===== AUTO ===== | ||
| + | function autoCalculate(){ | ||
| + | updateCost(); | ||
| + | calculate(); | ||
| + | } | ||
| + | |||
| + | // events stats | ||
| + | document.querySelectorAll("# | ||
| + | i.addEventListener(" | ||
| + | }); | ||
| + | |||
| + | document.querySelectorAll(" | ||
| + | s.addEventListener(" | ||
| + | }); | ||
| + | |||
| + | |||
| + | // passifs | ||
| + | document.querySelectorAll(" | ||
| + | s.addEventListener(" | ||
| + | }); | ||
| + | |||
| + | // ===== SORTS ACTIFS ===== | ||
| + | |||
| + | |||
| + | // ===== 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(); | ||
| + | |||
| + | </ | ||
| + | </ | ||
| </ | </ | ||
brouillon7.1776881233.txt.gz · Dernière modification : 2026/04/22 20:07 de nanaki
