Ce qu'il faut faire, c'est écrire une fonction pour "geler" vos jets de touche, et l'appeler récursivement pour chaque attaque (infructueuse), quelque chose comme cet exemple de base :
ATK: 1d20 \ attack roll: use 1@2d20 for advantage or 2@2d20 for disadvantage \
HIT: +0 \ bonus to attack roll \
AC: 8 \ target AC: attack hits if ATK + HIT >= AC \
CRIT: 20 \ minimum attack roll to crit \
DMG: 1d4 \ damage rolled on successful hit \
BONUS: 1d6 \ bonus damage on first hit \
function: attack ROLL:n {
\ return the number of times damage is applied on an attack roll of ROLL \
if ROLL <= 1 { result: 0 } \ natural 1 is always a miss \
if ROLL >= CRIT { result: 2 } \ critical hit deals damage damage twice \
result: ROLL + HIT >= AC
}
function: multiattack N:n times {
result: [roll [attack ATK] to multiattack N times]
}
function: roll FIRSTHIT:n to multiattack N:n times {
if N <= 0 {
result: 0
}
if FIRSTHIT > 0 {
DAMAGE: FIRSTHIT d (DMG + BONUS)
loop I over {2..N} {
DAMAGE: DAMAGE + [attack ATK] d DMG
}
result: DAMAGE
} else {
result: [roll [attack ATK] to multiattack N-1 times]
}
}
output [multiattack 3 times]
Les principaux [multiattack N:n times]
appelle simplement la fonction d'aide [roll FIRSTHIT:n to multiattack N:n times]
. Le premier argument ( FIRSTHIT
) à la fonction d'aide est donnée par [attack ATK]
qui renvoie le nombre de fois où les dégâts doivent être appliqués pour ce jet d'attaque (c'est-à-dire 0 pour un échec, 1 pour un succès et 2 pour un coup critique).
Puisque cet argument est marqué comme numérique (avec la mention :n
) dans la définition de la fonction, AnyDice appelle en interne la fonction d'aide avec chaque valeur de retour possible de [attack ATK]
et pondère ses résultats en fonction de la probabilité des résultats. Cela signifie que, même si le résultat de [attack ATK]
est un dé (biaisé), dans la fonction d'aide sa valeur est "gelée" comme FIRSTHIT
qui est un nombre fixe et peut donc être utilisé, par exemple, dans le cadre d'un projet de recherche. if
les conditionnels. (Voir la section "Fonctions" de la documentation d'AnyDice pour plus de détails).
La fonction d'aide elle-même vérifie simplement si l'attaque touche (c'est-à-dire si FIRSTHIT > 0
) et, si c'est le cas, applique les dégâts de cette attaque (plus le bonus, le cas échéant) et de toutes les attaques restantes (sans le bonus). En revanche, si l'attaque est ratée, la fonction d'aide s'appelle récursivement avec un nouveau jet d'attaque et avec un nombre d'attaques restantes réduit d'une unité.
Ps. L'expression FIRSTHIT d (DMG + BONUS)
peut être discutée : elle lance simplement les dégâts normaux et les dégâts bonus. FIRSTHIT
et additionne les résultats. (D'autre part, FIRSTHIT * (DMG + BONUS)
Le résultat est obtenu en lançant une fois les dégâts normaux et les dégâts bonus, et en les multipliant par FIRSTHIT
.) Ainsi, si FIRSTHIT
est égal à 2, les dégâts (y compris les éventuels bonus d'attaque sournoise ou autres) sont calculés deux fois, comme le précisent les règles du 5e pour les coups critiques. De même, à l'intérieur de la boucle, l'expression [attack ATK] d DMG
donne le résultat du roulement DMG
soit zéro, soit une, soit deux fois, selon les probabilités données par l'équation. [attack ATK]
rouleau.
En fait, tout le code à l'intérieur du if FIRSTHIT > 0
bloc conditionnel pourrait être remplacée avec l'expression suivante :
result: FIRSTHIT d (DMG + BONUS) + (N-1) d ([attack ATK] d DMG)
Ici, (N-1) d ([attack ATK] d DMG)
donne le résultat de l'exécution N-1
les jets d'attaque, chaque attaque infligeant DMG
dommages [attack ATK]
fois.
Il convient également de noter qu'AnyDice ne permet normalement d'imbriquer les appels de fonction qu'à 10 niveaux de profondeur (dont un est utilisé par la fonction wrapper dans cet exemple, et un par la fonction [attack ATK]
appel). Si vous souhaitez prendre en charge les multi-attaques avec plus de 8 jets d'attaque successifs, vous devez augmenter la limite de récursivité, par exemple de la manière suivante :
set "maximum function depth" to 999
Cependant, pour faire fonctionner une récursion aussi profonde en un temps raisonnable, il est nécessaire de essentiel pour s'assurer que la fonction d'aide ne s'appelle que sur un valeur spécifique de ses paramètres non fixes (par exemple, dans le cas présent, lorsque FIRSTHIT
est égal à zéro). S'il peut récurer sur deux entrées possibles ou plus, le nombre de séquences différentes d'appels récursifs qu'AnyDice doit vérifier augmentera de façon exponentielle avec la profondeur de récursion.
C'est la raison pour laquelle le code ci-dessus utilise l'option résultat de [attack ATK]
(qui ne peut être que 0, 1 ou 2) comme paramètre de la fonction d'aide, au lieu de transmettre le jet d'attaque ATK
(qui peut aller de 1 à 20) directement en tant que paramètre. Alors que le faire de cette façon fonctionnera correctement pour un petit nombre d'attaques, mais il deviendra très lent très rapidement à mesure que la profondeur de récursion augmentera.
En fait, nous pourrions optimiser un peu plus le code en pré-calculant les résultats de [attack ATK]
et les assigner à un dé personnalisé global. Cela permettrait d'accélérer légèrement le code et d'économiser un niveau d'imbrication de fonctions.
Notez également que le code ci-dessus suppose que le bonus de dégâts sera toujours appliqué au premier coup réussi, qu'il s'agisse d'un critérium ou non. Ceci est probablement optimal dans la plupart des situations pratiques, mais en principe, un joueur avec un nombre suffisamment important d'attaques restantes et un changement de hit et/ou de crit suffisamment élevé pourrait Il est préférable de garder son attaque sournoise pour plus tard s'il obtient une touche précoce non critique, en supposant qu'il obtiendra probablement une touche critique (ou au moins une autre touche normale) plus tard. Modélisation de ces stratégies avancées es possible dans AnyDice (généralement aussi par récursion), mais plus compliqué.