diff --git a/ChroniquesOubliees/ReadMe.md b/ChroniquesOubliees/ReadMe.md index 1469e7225b..be1fbf397b 100644 --- a/ChroniquesOubliees/ReadMe.md +++ b/ChroniquesOubliees/ReadMe.md @@ -9,9 +9,17 @@ Cette feuilles de personnage inclue quelques jets et règles optionnelles. Le jeu complet, des suppléments et des téléchargements gratuits sont disponibles sur le site de l'éditeur [Black Book Editions](http://www.black-book-editions.fr/catalogue.php?id=13). # Version courante -3.3 [Screenshot](co_v3.jpg) +3.4 [Screenshot](co_v3.jpg) # Notes de version +## v3.4 (2020-08-06) +* Utilisation des modificateurs dans les options d'attaque + * avantage et désavantage + * attaque automatique et sans dégâts + * dégâts temporaires + * un peu de logique sur les dés de dégâts +* Des options d'attaque communes à toutes les attaques (attaque de groupe, attaque risquée, attaque assurée,... ) + ## v3.3 (20020-06-19) * Ajout d'options pour les attaques (pour l'instant utilisées par le script) diff --git a/ChroniquesOubliees/co.html b/ChroniquesOubliees/co.html index a047ff8a63..02191a8112 100644 --- a/ChroniquesOubliees/co.html +++ b/ChroniquesOubliees/co.html @@ -1,5 +1,5 @@
- + @@ -329,7 +329,7 @@ - + Malus @@ -427,8 +427,17 @@
+ + + + + + + + +
- @@ -489,7 +498,7 @@ - + Options d'attaque
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + Attaque en puissance + + + en attaque et + + + + d6 DM +
+ + + + Attaque assurée + + +5 en attaque et DM divisés par 2 +
+ + + Attaque risquée + + +2 en attaque au contact et -4 en DEF +
+ + + Attaque non léthale + + -2 en attaque si arme non adaptée +
+
@@ -941,8 +1007,17 @@
+ + + + + + + + + {{/desc}} {{#attaque}} + {{^attaqueautomatique}} {{#rollWasCrit() attaque}} {{/rollWasCrit() attaque}} @@ -1068,9 +1207,23 @@ + {{#poudre}} + + + + + {{/poudre}} + {{/attaqueautomatique}} + {{#attaqueautomatique}} + + {{/attaqueautomatique}} {{#degats}} - +
- @@ -992,7 +1067,7 @@ - + Options d'attaque
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ Attaque de groupe : + + + +
+ + + Attaque en puissance + + en attaque et + + + + d6 DM +
+ + + Attaque assurée + + +5 en attaque et DM divisés par 2 +
+ + + + Attaque risquée + + +2 en attaque au contact mais la DEF passe de à pour 1 tour +
+ + + Attaque non léthale + + -2 en attaque si arme non adaptée +
+
@@ -1056,6 +1194,7 @@
Critique !
Jet {{attaque}} contre DEF
+ Dé de poudre + + {{poudre}} +
Réussite automatique
Dégâts Dégâts {{#dmtemp}}temp.{{/dmtemp}} {{degats}} {{#rollWasCrit() attaque}} @@ -1237,12 +1390,88 @@ enleveAttaqueVisible('repeating_armes'); enleveAttaqueVisible('repeating_pnjatk'); } + if (verfdp < 3.4) { + appliqueModificateurs34('armes'); + appliqueModificateurs34('pnjatk'); + getAttrs(['pnj_def'], function(values) { + var def = parseInt(values.pnj_def); + if (isNaN(def) || def == 10) return; + setAttrs({ + defense_si_attaque_risquee: def - 4 + }); + }); + } setAttrs({ - version: 3.3 + version: 3.4 }); }); }); + function appliqueModificateurs34(section) { + getSectionIDs('repeating_' + section, function(idArray) { + idArray.forEach(function(id) { + var prefix = 'repeating_' + section + '_' + id + '_'; + getAttrs([prefix + 'armemodificateurs'], function(values) { + var modifs = values[prefix + 'armemodificateurs'].split(','); + var attrs = {}; + var nbDes = 1; //Nombre de dés pour l'attaque + var plusFort = true; + modifs.forEach(function(m) { + switch (m.trim()) { + case 'tempDmg': + attrs[prefix + 'armedmtemp'] = 1; + return; + case 'pasDeDmg': + attrs[prefix + 'armedegats'] = '{{degats=}}'; + return; + case 'poudre': + attrs[prefix + 'armepoudre'] = '{{poudre=[[1d20]]}}'; + return; + case 'auto': + attrs[prefix + 'armereussiteauto'] = '{{attaqueautomatique=1}}'; + return; + case 'reroll1': + attrs[prefix + 'armedmrollmod'] = attrs[prefix + 'armedmrollmod'] || ''; + attrs[prefix + 'armedmrollmod'] += 'r1'; + return; + case 'explodeMax': + attrs[prefix + 'armedmrollmod'] = attrs[prefix + 'armedmrollmod'] || ''; + attrs[prefix + 'armedmrollmod'] += '!'; + return; + case 'avantage': + case 'm2d20': + if (plusFort) nbDes++; + else if (nbDes <= 1) { + plusFort = true; + nbDes = 2; + } else nbDes--; + return; + case 'desavantage': + case 'désavantage': + if (plusFort) { + if (nbDes > 1) nbDes--; + else { + plusFort = false; + nbDes = 2; + } + } else nbDes++; + return; + case 'avecd12': + attrs[prefix + 'armeattde'] = '12'; + return; + } + }); + if (nbDes > 1) { + attrs[prefix + 'armeattnbde'] = nbDes; + if (plusFort) attrs[prefix + 'armeattrollmod'] = 'kh1'; + else attrs[prefix + 'armeattrollmod'] = 'kl1'; + } + setAttrs(attrs); + }); + }); + }); + } + function enleveAttaqueVisible(attr) { getSectionIDs(attr, function(idArray) { var toSet = {}; @@ -1599,7 +1828,8 @@ bonus = Math.floor((parseInt(values.DEXTERITE) - 10) / 2); if (!isNaN(bonus)) defense += bonus; setAttrs({ - DEFDIV: new_def - defense + DEFDIV: new_def - defense, + defense_si_attaque_risquee: new_def - 4, }); }); }); @@ -2100,12 +2330,13 @@ getAttrs(['DEFARMURE', 'DEFARMUREON'], function(values) { var def = parseInt(values.DEFARMURE); if (isNaN(def)) return; - if (eventinfo.previousValue > 0) { - if (def === 0 && values.DEFARMUREON) setAttrs({ + var armureOn = parseInt(values.DEFARMUREON); + if (eventinfo.previousValue > 0 && eventinfo.previousValue != def) { + if (def === 0 && armureOn) setAttrs({ DEFARMUREON: 0 }); - } else { - if (def > 0 && !values.DEFARMUREON) setAttrs({ + } else { //comprend aussi le cas où previousValue == def, car c'est le cas si l'attribut n'a encore jamais été modifié + if (def > 0 && !armureOn) setAttrs({ DEFARMUREON: 1 }); } @@ -2115,12 +2346,13 @@ getAttrs(['DEFBOUCLIER', 'DEFBOUCLIERON'], function(values) { var def = parseInt(values.DEFBOUCLIER); if (isNaN(def)) return; - if (eventinfo.previousValue > 0) { - if (def === 0 && values.DEFBOUCLIERON) setAttrs({ + var bouclierOn = parseInt(values.DEFBOUCLIERON); + if (eventinfo.previousValue > 0 && eventinfo.previousValue != def) { + if (def === 0 && bouclierOn) setAttrs({ DEFBOUCLIERON: 0 }); } else { - if (def > 0 && !values.DEFBOUCLIERON) setAttrs({ + if (def > 0 && !bouclierOn) setAttrs({ DEFBOUCLIERON: 1 }); } @@ -2130,12 +2362,13 @@ getAttrs(['casque_rd', 'casque_on'], function(values) { var rd = parseInt(values.casque_rd); if (isNaN(rd)) return; - if (eventinfo.previousValue > 0) { - if (rd === 0 && values.casque_on) setAttrs({ + var casqueOn = parseInt(values.casque_on); + if (eventinfo.previousValue > 0 && eventinfo.previousValue != rd) { + if (rd === 0 && casqueOn) setAttrs({ casque_on: 0 }); } else { - if (rd > 0 && !values.casque_on) setAttrs({ + if (rd > 0 && !casqueOn) setAttrs({ casque_on: 1 }); } @@ -2204,4 +2437,283 @@ }); }); + //Les options d'attaque + on('change:attaque_en_puissance', function(eventinfo) { + getAttrs(['attaque_en_puissance'], function(values) { + var bonus = parseInt(values.attaque_en_puissance); + if (isNaN(bonus) || bonus < 1) { + setAttrs({ + attaque_en_puissance: 1 + }); + return; + } + setAttrs({ + malus_attaque_en_puissance: -5 * bonus + }); + }); + }); + + on('change:attaque_en_puissance_check change:attaque_en_puissance change:attaque_de_groupe', function(eventinfo) { + getAttrs(['attaque_en_puissance_check', 'attaque_en_puissance', 'attaque_assuree_check', 'attaque_de_groupe'], function(values) { + var attrs = {}; + var bonus = 0; + var attaque_en_puissance = parseInt(values.attaque_en_puissance_check) * parseInt(values.attaque_en_puissance); + var attaque_assuree = parseInt(values.attaque_assuree_check); + if (!isNaN(attaque_en_puissance) && attaque_en_puissance > 0) { + bonus -= 5 * attaque_en_puissance; + attrs.bonus_dm_option = '[[' + attaque_en_puissance + 'd6]]'; + if (attaque_assuree) attrs.attaque_assuree_check = 0; + } else { + attrs.bonus_dm_option = ''; + if (attaque_assuree) bonus += 5; + } + var attaque_groupe = parseInt(values.attaque_de_groupe); + if (isNaN(attaque_groupe) || attaque_groupe < 1) { + attaque_groupe = 1; + attrs.attaque_groupe = 1; + } + if (attaque_groupe == 1) { + attrs.message_attaque_de_groupe = 'attaquant par jet'; + } else { + var bg = (attaque_groupe - 1) * 2; + attrs.message_attaque_de_groupe = 'attaquants par jet (+' + bg + ' en attaque, DM x2 si attaque > DEF + 5, et x3 si critique)'; + bonus += bg; + } + attrs.bonus_attaque_option = bonus; + setAttrs(attrs); + }); + }); + + on('change:attaque_assuree_check', function(eventinfo) { + getAttrs(['attaque_en_puissance_check', 'attaque_en_puissance', 'attaque_assuree_check', 'attaque_de_groupe'], function(values) { + var attrs = {}; + var bonus = 0; + var attaque_en_puissance = parseInt(values.attaque_en_puissance_check) * parseInt(values.attaque_en_puissance); + var attaque_assuree = parseInt(values.attaque_assuree_check); + if (attaque_assuree) { + bonus += 5; + attrs.division_attaque_assuree = '/2'; + if (isNaN(attaque_en_puissance) || attaque_en_puissance > 0) + attrs.attaque_en_puissance_check = 0; + } else { + attrs.division_attaque_assuree = ''; + if (!isNaN(attaque_en_puissance) && attaque_en_puissance > 0) + bonus -= 5 * attaque_en_puissance; + } + var attaque_groupe = parseInt(values.attaque_de_groupe); + if (attaque_groupe > 1) { + bonus += (attaque_groupe - 1) * 2; + } + attrs.bonus_attaque_option = bonus; + setAttrs(attrs); + }); + }); + + on('change:attaque_risquee_check change:attaque_dm_temp_check', function(eventinfo) { + getAttrs(['attaque_risquee_check', 'attaque_dm_temp_check'], function(values) { + var attaque_risquee = parseInt(values.attaque_risquee_check); + var attaque_non_lethale = parseInt(values.attaque_dm_temp_check); + var updateArmes = function(section) { + getSectionIDs('repeating_' + section, function(idArray) { + idArray.forEach(function(id) { + var prefix = 'repeating_' + section + '_' + id + '_'; + getAttrs([prefix + 'armeportee', prefix + 'armemodificateurs'], function(values) { + var portee = values[prefix + 'armeportee']; + var modifs = values[prefix + 'armemodificateurs'].split(','); + var bonus = 0; + if (attaque_non_lethale) bonus = -2; + var attrs = {}; + var dmTemp = attaque_non_lethale; + modifs.forEach(function(m) { + switch (m.trim()) { + case 'tempDmg': + dmTemp = true; + if (attaque_non_lethale) bonus = 0; + return; + case 'choc': + if (attaque_non_lethale) bonus = 0; + return; + } + }); + if (dmTemp) attrs[prefix + 'armedmtemp'] = 1; + else attrs[prefix + 'armedmtemp'] = ''; + if (attaque_risquee && !portee) { + attrs[prefix + 'armebonusoption'] = bonus + 2; + } else { + attrs[prefix + 'armebonusoption'] = bonus; + } + setAttrs(attrs); + }); + }); + }); + }; + updateArmes('armes'); + updateArmes('pnjatk'); + }); + }); + + const DEGATSPJ = '{{degats=[[(@{armedmnbde}d@{armedmde}@{armedmrollmod}+[[@{armedmcar}]]+@{armedmdiv})@{division_attaque_assuree}]]}}'; + + //Du coup, mise à jour aussi quand on change les attaques + on('change:repeating_armes:armeportee change:repeating_armes:armemodificateurs', function(eventinfo) { + getAttrs(['attaque_risquee_check', 'attaque_dm_temp_check', 'repeating_armes_armeportee', 'repeating_armes_armemodificateurs'], function(values) { + var attaque_risquee = parseInt(values.attaque_risquee_check); + var attaque_non_lethale = parseInt(values.attaque_dm_temp_check); + var portee = values.repeating_armes_armeportee; + var modifs = values.repeating_armes_armemodificateurs.split(','); + var bonus = 0; + if (attaque_non_lethale) bonus = -2; + var attrs = {}; + var dmTemp = attaque_non_lethale; + var nbDes = 1; //Nombre de dés pour l'attaque + var plusFort = true; + attrs.repeating_armes_armedegats = DEGATSPJ; + attrs.repeating_armes_armepoudre = '{{poudre=}}'; + attrs.repeating_armes_armereussiteauto = '{{attaqueautomatique=}}'; + attrs.repeating_armes_armedmrollmod = ''; + attrs.repeating_armes_armeattde = '@{ETATDE}'; + modifs.forEach(function(m) { + switch (m.trim()) { + case 'tempDmg': + dmTemp = true; + if (attaque_non_lethale) bonus = 0; + return; + case 'choc': + if (attaque_non_lethale) bonus = 0; + return; + case 'pasDeDmg': + attrs.repeating_armes_armedegats = '{{degats=}}'; + return; + case 'poudre': + attrs.repeating_armes_armepoudre = '{{poudre=[[1d20]]}}'; + return; + case 'auto': + attrs.repeating_armes_armereussiteauto = '{{attaqueautomatique=1}}'; + return; + case 'reroll1': + attrs.repeating_armes_armedmrollmod += 'r1'; + return; + case 'explodeMax': + attrs.repeating_armes_armedmrollmod += '!'; + return; + case 'avantage': + case 'm2d20': + if (plusFort) nbDes++; + else if (nbDes <= 1) { + plusFort = true; + nbDes = 2; + } else nbDes--; + return; + case 'desavantage': + case 'désavantage': + if (plusFort) { + if (nbDes > 1) nbDes--; + else { + plusFort = false; + nbDes = 2; + } + } else nbDes++; + return; + case 'avecd12': + attrs.repeating_armes_armeattde = '12'; + return; + } + }); + if (dmTemp) attrs.repeating_armes_armedmtemp = 1; + else attrs.repeating_armes_armedmtemp = ''; + if (attaque_risquee && !portee) { + attrs.repeating_armes_armebonusoption = bonus + 2; + } else { + attrs.repeating_armes_armebonusoption = bonus; + } + attrs.repeating_armes_armeattnbde = nbDes; + if (nbDes > 1) { + if (plusFort) attrs.repeating_armes_armeattrollmod = 'kh1'; + else attrs.repeating_armes_armeattrollmod = 'kl1'; + } else attrs.repeating_armes_armeattrollmod = ''; + setAttrs(attrs); + }); + }); + + const DEGATSPNJ = '{{degats=[[(@{armedmnbde}d@{armedmde}@{armedmrollmod}+@{armedm})@{division_attaque_assuree}]]}}'; + + on('change:repeating_pnjatk:armeportee change:repeating_pnjatk:armemodificateurs', function(eventinfo) { + getAttrs(['attaque_risquee_check', 'attaque_dm_temp_check', 'repeating_pnjatk_armeportee', 'repeating_pnjatk_armemodificateurs'], function(values) { + var attaque_risquee = parseInt(values.attaque_risquee_check); + var attaque_non_lethale = parseInt(values.attaque_dm_temp_check); + var portee = values.repeating_pnjatk_armeportee; + var modifs = values.repeating_pnjatk_armemodificateurs.split(','); + var bonus = 0; + if (attaque_non_lethale) bonus = -2; + var attrs = {}; + var dmTemp = attaque_non_lethale; + var nbDes = 1; //Nombre de dés pour l'attaque + var plusFort = true; + attrs.repeating_pnjatk_armedegats = DEGATSPNJ; + attrs.repeating_pnjatk_armepoudre = '{{poudre=}}'; + attrs.repeating_pnjatk_armereussiteauto = '{{attaqueautomatique=}}'; + attrs.repeating_pnjatk_armedmrollmod = ''; + attrs.repeating_pnjatk_armeattde = '@{ETATDE}'; + modifs.forEach(function(m) { + switch (m.trim()) { + case 'tempDmg': + dmTemp = true; + if (attaque_non_lethale) bonus = 0; + return; + case 'choc': + if (attaque_non_lethale) bonus = 0; + return; + case 'pasDeDmg': + attrs.repeating_pnjatk_armedegats = '{{degats=}}'; + return; + case 'poudre': + attrs.repeating_pnjatk_armepoudre = '{{poudre=[[1d20]]}}'; + return; + case 'auto': + attrs.repeating_pnjatk_armereussiteauto = '{{attaqueautomatique=1}}'; + return; + case 'reroll1': + attrs.repeating_pnjatk_armedmrollmod += 'r1'; + return; + case 'explodeMax': + attrs.repeating_pnjatk_armedmrollmod += '!'; + return; + case 'avantage': + case 'm2d20': + if (plusFort) nbDes++; + else if (nbDes <= 1) { + plusFort = true; + nbDes = 2; + } else nbDes--; + return; + case 'desavantage': + case 'désavantage': + if (plusFort) { + if (nbDes > 1) nbDes--; + else { + plusFort = false; + nbDes = 2; + } + } else nbDes++; + return; + case 'avecd12': + attrs.repeating_pnjatk_armeattde = '12'; + return; + } + }); + if (dmTemp) attrs.repeating_pnjatk_armedmtemp = 1; + else attrs.repeating_pnjatk_armedmtemp = ''; + if (attaque_risquee && !portee) { + attrs.repeating_pnjatk_armebonusoption = bonus + 2; + } else { + attrs.repeating_pnjatk_armebonusoption = bonus; + } + attrs.repeating_pnjatk_armeattnbde = nbDes; + if (nbDes > 1) { + if (plusFort) attrs.repeating_pnjatk_armeattrollmod = 'kh1'; + else attrs.repeating_pnjatk_armeattrollmod = 'kl1'; + } else attrs.repeating_pnjatk_armeattrollmod = ''; + setAttrs(attrs); + }); + }); diff --git a/ChroniquesOubliees/sheet.json b/ChroniquesOubliees/sheet.json index 78a878ca12..57ae782c8c 100644 --- a/ChroniquesOubliees/sheet.json +++ b/ChroniquesOubliees/sheet.json @@ -4,7 +4,7 @@ "authors": "Natha, Ulti", "roll20userid": "75857, 1794854", "preview": "co_v3.jpg", - "instructions": "Feuille de Personnage (avec jets) pour [Chroniques Oubliées Fantasy](http://www.black-book-editions.fr/catalogue.php?id=13). Chroniques Oubliées Fantasy est un jeu de rôle médiéval-fantastique complet basé sur le système d20/OGL 3.5. Feuille version 3.3 (19/06/2020). [Lisez-moi](https://github.com/Roll20/roll20-character-sheets/blob/master/ChroniquesOubliees/ReadMe.md).", + "instructions": "Feuille de Personnage (avec jets) pour [Chroniques Oubliées Fantasy](http://www.black-book-editions.fr/catalogue.php?id=13). Chroniques Oubliées Fantasy est un jeu de rôle médiéval-fantastique complet basé sur le système d20/OGL 3.5. Feuille version 3.4 (06/08/2020). [Lisez-moi](https://github.com/Roll20/roll20-character-sheets/blob/master/ChroniquesOubliees/ReadMe.md).", "useroptions": [ { "attribute": "option_pc",