6
\$\begingroup\$

VtM5 has many quirks that make their calculation of probabilities really hard. But ignoring hunger dice, how can I calculate the distribution of success of a given pool considering that each pair of 10's counts as two successes (a regular success is just d10>5).

So 10,1 is just one success, but 10,10 is four.

\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

Turns out it is simpler than I thought, but I must use a function:

function: roll ROLL:s  {
 result: (ROLL > 5) + ((ROLL = 10)/2)*2
}

I just sum every success and for every pair of 10's I add 2 successes.

\$\endgroup\$
1
\$\begingroup\$

With hunger dice

When applied to a number, the i@n operator extracts the ith digit, starting from the left/most significant. This allows AnyDice to have some capability of handling multivariate distributions.

Step 1: raw roll

In this case, we first want to know the number of hunger botches, successes, normal crits, and hunger crits. We can do this using custom dice:

NORMAL: d{10000:5, 10100:4, 10010:1}
BESTIAL: d{11000:1, 10000:4, 10100:4, 10001:1}

The digits are as follows:

  1. A placeholder to ensure we have exactly five digits.
  2. Hunger botches.
  3. Successes.
  4. Normal crits.
  5. Hunger crits.

We can use the d operator to roll multiple dice of each type, and + to sum the two types. For example, three normal and two bestial dice would be

3dNORMAL + 2dBESTIAL

Step 2: final score

Now we want to convert the raw roll into a final score. We use the @ operator to extract the number of each type of face, and then apply the V5 rules.

function: vampire ROLL:n {
 HUNGER_BOTCHES: 2@ROLL
 SUCCESSES: 3@ROLL
 CRITS: 4@ROLL
 HUNGER_CRITS: 5@ROLL
 TOTAL_CRITS: CRITS + HUNGER_CRITS
 SUCCESSES: SUCCESSES + TOTAL_CRITS + 2 * (TOTAL_CRITS / 2)
 if (TOTAL_CRITS >= 2) {
  if (HUNGER_CRITS > 0) {
   WIN_TYPE: 2
  } else {
   WIN_TYPE: 1
  }
 } else {
  WIN_TYPE: 0
 }
 if (HUNGER_BOTCHES > 0) {
  LOSS_TYPE: 1
 } else {
  LOSS_TYPE: 0
 }
 result: 1000 + SUCCESSES * 100 + WIN_TYPE * 10 + LOSS_TYPE
}

output [vampire 3dNORMAL + 2dBESTIAL]

At the very end, we put the result into five digits:

  1. A placeholder to ensure we have exactly five digits.
  2. Tens place of the number of successes in case we need it.
  3. Ones place of the number of successes.
  4. Win type: normal (0), crit (1), or messy crit (2).
  5. Loss type: normal (0) or bestial failure (1).

You can run this script here.

Icepool

My own Icepool Python package supports non-integer outcomes, allowing the different components to be expressed directly using vectors and strings.

from icepool import Die, vectorize

normal_die = Die({vectorize(0, 0, 0, 0): 5, # failure
                  vectorize(0, 1, 0, 0): 4, # success
                  vectorize(0, 0, 1, 0): 1, # crit
                 })
hunger_die = Die({vectorize(1, 0, 0, 0): 1, # bestial failure
                  vectorize(0, 0, 0, 0): 4, # failure
                  vectorize(0, 1, 0, 0): 4, # success
                  vectorize(0, 0, 0, 1): 1, # messy crit
                 })

total = 3 @ normal_die + 2 @ hunger_die

def vampire(hunger_botch, success, crit, hunger_crit):
    total_crit = crit + hunger_crit
    success += total_crit + 2 * (total_crit // 2)
    if total_crit >= 2:
        if hunger_crit > 0:
            win_type = 'messy'
        else:
            win_type = 'crit'
    else:
        win_type = ''
    loss_type = 'bestial' if hunger_botch > 0 else ''
    return success, win_type, loss_type

result = total.map(vampire)
output(result)

You can run this script here.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .