Una forma de conseguirlo de forma bastante sencilla es a través de la simulación: no obtendrás el porcentaje exacto hasta el segundo decimal, pero puedes acercarte mucho a él. A continuación he introducido un código R que simulará las tiradas que estás haciendo y escupirá la probabilidad de que tu aliado muera.
# Creating a hundred thousand sets of your three rolls to hit
roll.1 <- sample(1:20, replace = TRUE, 100000)
roll.2 <- sample(1:20, replace = TRUE, 100000)
roll.3 <- sample(1:20, replace = TRUE, 100000)
# Creating a hundred thousand sets of three damage rolls
damage.1 <- replicate(100000, (sample(1:6, 1) + sample(1:6, 1) + 2))
damage.2 <- replicate(100000, (sample(1:6, 1) + sample(1:6, 1) + 2))
damage.3 <- replicate(100000, (sample(1:6, 1) + sample(1:6, 1) + 2))
# Here we calculate the damage of each roll. Essentially this line is saying
# "Apply the full damage if the hit roll was 13 or more (13 + 4 = 17), and
# apply half the damage if the roll was 12." Applying zero damage when the roll
# was less than 12 is implicit here.
hurt.1 <- ((roll.1 >= 13) * damage.1 + floor((roll.1 == 12) * damage.1 * .5))
hurt.2 <- ((roll.2 >= 13) * damage.2 + floor((roll.2 == 12) * damage.2 * .5))
hurt.3 <- ((roll.3 >= 13) * damage.3 + floor((roll.3 == 12) * damage.3 * .5))
# Now we just subtract the total damage from the health
health <- 20 - (hurt.1 + hurt.2 + hurt.3)
# And this gives the percentage of the time you'd kill your ally.
sum(health <= 0)/1000000
Cuando ejecuto esto, obtengo consistentemente entre 16.8% y 17.2%. Así que tienes un 17% de posibilidades de matar a tu aliado con este hechizo.
Si te interesa, el siguiente código también calcula la probabilidad exacta utilizando el método descrito en la respuesta de Micah. Resulta que la probabilidad exacta es del 16,99735%.
# Get a vector of the probability to hit 0, 1, 2, and 3 times. Since you can
# only kill him if you get 2 hits or more, we only need the latter 2 probabilities
hit.times <- (dbinom(0:3, 3, 9/20))
# We'll be making extensive use of R's `outer` function, which gives us all
# combinations of adding or multiplying various numbers - useful for dice
# rolling
damage.prob <- table(outer(1:6, 1:6, FUN = "+") + 2)/36
damage.prob <- data.frame(damage.prob)
colnames(damage.prob) <- c("Damage", "Prob")
damage.prob$Damage <- as.numeric(as.character(damage.prob$Damage))
# Since we'll be multiplying by the probability to hit each number of times
# later, we just use 8/9 as the probability to get full damage, and 1/9 as
# the probability of half damage.
damage.prob.full <- data.frame("Damage" = damage.prob$Damage, "Prob" = damage.prob$Prob * 8/9)
damage.prob.half <- data.frame("Damage" = damage.prob$Damage * .5, "Prob" = damage.prob$Prob * 1/9)
# Rounding down the half damage
damage.prob.half$Damage <- floor(damage.prob.half$Damage)
damage.prob.half <- aggregate(damage.prob.half$Prob, by = list(damage.prob.half$Damage), FUN = sum)
colnames(damage.prob.half) <- c("Damage", "Prob")
damage.prob.total <- merge(damage.prob.full, damage.prob.half, by = "Damage", all.x = TRUE, all.y = TRUE)
damage.prob.total$Prob <- rowSums(cbind(damage.prob.total$Prob.x, damage.prob.total$Prob.y), na.rm=TRUE)
# Below I'm multiplying out all the damage probabilities for 2 and 3 hits, then
# summing the probabilities of getting each damage total that equals 20 or more.
damage.2 <- outer(damage.prob.total$Damage, damage.prob.total$Damage, FUN = '+')
prob.kill.2 <- sum(outer(damage.prob.total$Prob, damage.prob.total$Prob)[damage.2 >= 20])
damage.3 <- outer(outer(damage.prob.total$Damage, damage.prob.total$Damage, FUN = "+"), damage.prob.total$Damage, FUN = "+")
prob.kill.3 <- outer(outer(damage.prob.total$Prob, damage.prob.total$Prob), damage.prob.total$Prob)[damage.3 >= 20]
# Now we just multiply the probability of killing with 2 hits by the probability
# of hitting twice, and the same for 3 hits. Adding that together we get the
# answer.
sum(prob.kill.2)*hit.times[3] + sum(prob.kill.3)*hit.times[4]