# How to calculate Vampire the Masquerade 5 odds on anydice?

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.

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.

## 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.