Files
roll20-character-sheets/Naruto JDR/sheet.js
T
Rosko79 a0caaf4c5c Update sheet.js
correction bug calcul D'xp
2025-04-26 17:26:55 +02:00

344 lines
12 KiB
JavaScript

// ==============================
// === TABLES XP ===============
// ==============================
const xpSkillTable = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
const xpBaseCosts = [0, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 90, 100];
// ==============================
// === 1. COMPÉTENCES COMMUNES =
// ==============================
const commonSkills = {
armessimples: "arm", camouflage: "nin", cac: "tai", esquive: "tai",
gensou: "gen", henge: "nin", kawarimi: "gen", mental: "esp",
parade: "arm", physique: "cor", survie: "nin", vigilance: "nin"
};
for (const skill in commonSkills) {
const baseAttr = commonSkills[skill];
on(`change:scmp_${skill} change:${baseAttr} sheet:opened`, () => {
getAttrs([`scmp_${skill}`, baseAttr], values => {
const base = parseInt(values[baseAttr]) || 0;
const mod = parseInt(values[`scmp_${skill}`]) || 0;
setAttrs({ [`stcmp_${skill}`]: base + mod });
});
});
}
// =========================================
// === 2. XP DES CARACTÉRISTIQUES (base) ===
// =========================================
const baseAttrs = ['cor', 'esp', 'arm', 'tai', 'nin', 'gen', 'lign'];
baseAttrs.forEach(attr => {
on(`change:${attr}`, () => {
getAttrs([attr], values => {
let score = parseInt(values[attr]) || 1;
score = Math.min(score, xpBaseCosts.length - 1);
const cost = xpBaseCosts.slice(1, score).reduce((a, b) => a + b, 0);
setAttrs({ [`xp_${attr}`]: cost });
});
});
});
// ===========================================
// === 3. CALCUL DU CHAKRA TOTAL & RESTANT ===
// ===========================================
on("change:cor change:esp change:chakra_colossal change:chakra_endurci change:chakra_imperieux sheet:opened", () => {
getAttrs(["cor", "esp", "chakra_colossal", "chakra_endurci", "chakra_imperieux", "chakra_restant"], values => {
const toInt = v => parseInt(v) || 0;
const totalChakra =
(toInt(values.cor) * 50) +
(toInt(values.esp) * 50) +
(toInt(values.chakra_colossal) * 100) +
(toInt(values.chakra_endurci) * 50) +
(toInt(values.chakra_imperieux) * 50);
const actuel = parseInt(values.chakra_restant);
const restant = isNaN(actuel) || actuel === 0 ? totalChakra : actuel;
setAttrs({
chakra: totalChakra,
chakra_restant: restant
});
});
});
// ===============================
// === 4. STATS SECONDAIRES =====
// ===============================
on("change:cor change:esp change:arm change:tai change:nin change:gen change:chakra change:chakra_endurci change:chakra_imperieux change:chakra_fulgurant change:stcmp_physique sheet:opened", () => {
getAttrs([
"cor", "esp", "arm", "tai", "nin", "gen", "chakra", "chakra_endurci",
"chakra_imperieux", "chakra_fulgurant", "stcmp_physique"
], values => {
const toInt = v => parseInt(values[v]) || 0;
const cor = toInt("cor");
const esp = toInt("esp");
const arm = toInt("arm");
const tai = toInt("tai");
const controle = cor + esp;
let spe = 1;
if (controle >= 5 && controle <= 9) spe = 2;
else if (controle >= 10 && controle <= 13) spe = 4;
else if (controle >= 14 && controle <= 19) spe = 6;
else if (controle >= 20) spe = 9;
const initiative = toInt("stcmp_physique") + (toInt("chakra_fulgurant") * 2);
const vigueur = cor + 2 + toInt("chakra_endurci");
const caractere = esp + 2 + toInt("chakra_imperieux");
const regen = Math.floor(toInt("chakra") * (spe * 0.01));
const interceptions_arm = Math.floor(arm / 2);
const interceptions_tai = Math.floor(tai / 2);
setAttrs({
controle,
specialisation_chakra: spe,
initiative,
vigueur,
caractere,
regen,
interceptions_arm,
interceptions_tai
});
});
});
on("change:cor change:esp change:chakra_colossal change:chakra_endurci change:chakra_imperieux change:bonus_chakra sheet:opened", () => {
getAttrs(["cor", "esp", "chakra_colossal", "chakra_endurci", "chakra_imperieux", "chakra_restant", "bonus_chakra"], values => {
const toInt = v => parseInt(v) || 0;
const totalChakra =
(toInt(values.cor) * 50) +
(toInt(values.esp) * 50) +
(toInt(values.chakra_colossal) * 100) +
(toInt(values.chakra_endurci) * 50) +
(toInt(values.chakra_imperieux) * 50) +
toInt(values.bonus_chakra); // Bonus manuel
const actuel = parseInt(values.chakra_restant);
const restant = isNaN(actuel) || actuel === 0 ? totalChakra : actuel;
setAttrs({
chakra: totalChakra,
chakra_restant: restant
});
});
});
on("change:cor change:esp change:chakra_colossal change:chakra_endurci change:chakra_imperieux change:bonus_chakra sheet:opened", () => {
getAttrs(["cor", "esp", "chakra_colossal", "chakra_endurci", "chakra_imperieux", "chakra_restant", "bonus_chakra"], values => {
const toInt = v => parseInt(v) || 0;
const totalChakra =
(toInt(values.cor) * 50) +
(toInt(values.esp) * 50) +
(toInt(values.chakra_colossal) * 100) +
(toInt(values.chakra_endurci) * 50) +
(toInt(values.chakra_imperieux) * 50) +
toInt(values.bonus_chakra); // Bonus manuel
const actuel = parseInt(values.chakra_restant);
const restant = isNaN(actuel) || actuel === 0 ? totalChakra : actuel;
setAttrs({
chakra: totalChakra,
chakra_restant: restant
});
});
});
on("change:cor change:esp change:arm change:tai change:nin change:gen change:chakra change:chakra_endurci change:chakra_imperieux change:chakra_fulgurant change:stcmp_physique change:bonus_vigueur change:bonus_caractere sheet:opened", () => {
getAttrs([
"cor", "esp", "arm", "tai", "nin", "gen", "chakra", "chakra_endurci",
"chakra_imperieux", "chakra_fulgurant", "stcmp_physique",
"bonus_vigueur", "bonus_caractere"
], values => {
const toInt = v => parseInt(values[v]) || 0;
const cor = toInt("cor");
const esp = toInt("esp");
const arm = toInt("arm");
const tai = toInt("tai");
const controle = cor + esp;
let spe = 1;
if (controle >= 5 && controle <= 9) spe = 2;
else if (controle >= 10 && controle <= 13) spe = 4;
else if (controle >= 14 && controle <= 19) spe = 6;
else if (controle >= 20) spe = 9;
const initiative = toInt("stcmp_physique") + (toInt("chakra_fulgurant") * 2);
const vigueur = cor + 2 + toInt("chakra_endurci") + toInt("bonus_vigueur");
const caractere = esp + 2 + toInt("chakra_imperieux") + toInt("bonus_caractere");
const regen = Math.floor(toInt("chakra") * (spe * 0.01));
const interceptions_arm = Math.floor(arm / 2);
const interceptions_tai = Math.floor(tai / 2);
setAttrs({
controle,
specialisation_chakra: spe,
initiative,
vigueur,
caractere,
regen,
interceptions_arm,
interceptions_tai
});
});
});
// ===============================
// === 5. DÉGÂTS ================
// ===============================
on("change:cor change:arm change:tai change:gen change:nin change:chakra_acere change:chakra_explosif change:bonus_degats_gen change:bonus_degats_nin change:degats_tai_bonus change:degats_arm_bonus sheet:opened", () => {
getAttrs([
"cor", "arm", "tai", "gen", "nin",
"chakra_acere", "chakra_explosif",
"bonus_degats_gen", "bonus_degats_nin",
"degats_tai_bonus", "degats_arm_bonus"
], values => {
const toInt = v => parseInt(values[v]) || 0;
const baseArm = toInt("cor") + toInt("arm") + (toInt("chakra_acere") * 2);
const baseTai = toInt("cor") + toInt("tai") + (toInt("chakra_explosif") * 2);
const baseGen = toInt("gen") + 1;
const baseNin = toInt("nin") + 1;
setAttrs({
degats_arm_base: baseArm,
degats_tai_base: baseTai,
degats_gen_base: baseGen,
degats_nin_base: baseNin,
degats_arm: baseArm + toInt("degats_arm_bonus"),
degats_tai: baseTai + toInt("degats_tai_bonus"),
degats_gen: baseGen + toInt("bonus_degats_gen"),
degats_nin: baseNin + toInt("bonus_degats_nin")
});
});
});
// ============================================
// === 6. XP COMPÉTENCES COMMUNES ============
// ============================================
Object.keys(commonSkills).forEach(skill => {
on(`change:scmp_${skill}`, () => {
getAttrs([`scmp_${skill}`], values => {
const score = Math.min(parseInt(values[`scmp_${skill}`]) || 1, xpSkillTable.length);
const xp = xpSkillTable.slice(1, score).reduce((a, b) => a + b, 0);
setAttrs({ [`xp_scmp_${skill}`]: xp });
});
});
});
// ==============================================
// === 7. XP DES COMPÉTENCES SPÉCIFIQUES (REP) ===
// ==============================================
on("change:repeating_cmpspe:scmps change:repeating_cmpspe:nom_cmps", function (eventInfo) {
const rowId = eventInfo.sourceAttribute.split("_")[2];
getAttrs([`repeating_cmpspe_${rowId}_nom_cmps`, `repeating_cmpspe_${rowId}_scmps`], function (values) {
const attrBase = values[`repeating_cmpspe_${rowId}_nom_cmps`];
const mod = parseInt(values[`repeating_cmpspe_${rowId}_scmps`]) || 0;
getAttrs([attrBase], function (baseValues) {
const base = parseInt(baseValues[attrBase]) || 0;
const total = base + mod;
const xp = mod > 1 ? xpSkillTable.slice(1, mod).reduce((a, b) => a + b, 0) : 0;
setAttrs({
[`repeating_cmpspe_${rowId}_stcmps`]: total,
[`repeating_cmpspe_${rowId}_xp_cmps`]: xp
});
});
});
});
// =========================================
// === 8. XP TOTALE UTILISÉE & RESTANTE ====
// =========================================
function calculateTotalXP() {
getSectionIDs("repeating_cmpspe", ids => {
const attrs = ["xp_total", ...baseAttrs.map(a => `xp_${a}`), ...Object.keys(commonSkills).map(s => `xp_scmp_${s}`)];
ids.forEach(id => attrs.push(`repeating_cmpspe_${id}_xp_cmps`));
getAttrs(attrs, values => {
let totalXP = 0;
baseAttrs.forEach(attr => totalXP += parseInt(values[`xp_${attr}`]) || 0);
Object.keys(commonSkills).forEach(skill => totalXP += parseInt(values[`xp_scmp_${skill}`]) || 0);
ids.forEach(id => totalXP += parseInt(values[`repeating_cmpspe_${id}_xp_cmps`]) || 0);
const total = parseInt(values.xp_total) || 0;
setAttrs({
xp_utilisee: totalXP,
xp_restante: total - totalXP
});
});
});
}
on("change:xp_total sheet:opened", calculateTotalXP);
baseAttrs.forEach(attr => on(`change:xp_${attr}`, calculateTotalXP));
Object.keys(commonSkills).forEach(skill => on(`change:xp_scmp_${skill}`, calculateTotalXP));
on("change:repeating_cmpspe:xp_cmps", calculateTotalXP);
// ===============================
// === LOGO DU VILLAGE ======
// ===============================
on("change:village sheet:opened", () => {
getAttrs(["village"], values => {
const logoURL = values.village || "";
setAttrs({ village_logo: logoURL });
});
});
// =====================================
// === 10. VALIDATION SPÉ CHAKRA =======
// =====================================
on("change:chakra_acere change:chakra_colossal change:chakra_endurci change:chakra_explosif change:chakra_fulgurant change:chakra_hereditaire change:chakra_imperieux change:chakra_inepuisable change:chakra_puissant change:chakra_remanent change:specialisation_chakra", () => {
const chakraAttrs = [
"chakra_acere", "chakra_colossal", "chakra_endurci", "chakra_explosif",
"chakra_fulgurant", "chakra_hereditaire", "chakra_imperieux", "chakra_inepuisable",
"chakra_puissant", "chakra_remanent", "specialisation_chakra"
];
getAttrs(chakraAttrs, values => {
const toInt = v => parseInt(values[v]) || 0;
const total =
toInt("chakra_acere") + toInt("chakra_colossal") + toInt("chakra_endurci") +
toInt("chakra_explosif") + toInt("chakra_fulgurant") + toInt("chakra_hereditaire") +
toInt("chakra_imperieux") + toInt("chakra_inepuisable") +
toInt("chakra_puissant") + toInt("chakra_remanent");
const max = toInt("specialisation_chakra");
setAttrs({ chakra_specialisation_total: total });
if (total > max) {
setTimeout(() => {
alert(`⚠️ Vous avez dépassé la limite de spécialisations (${max}). Veuillez ajuster vos points.`);
}, 50);
}
const fields = chakraAttrs.slice(0, -1); // sans specialisation_chakra
fields.forEach(name => {
const input = document.querySelector(`input[name="attr_${name}"]`);
if (input) {
input.classList.toggle("over-limit", total > max);
}
});
});
});
on("change:prenom", () => {
getAttrs(["prenom"], values => {
const nom = values.prenom || "";
setAttrs({ character_name: nom });
});
});