"""Dice rolling operations (outside of the lex/yacc roller).""" import random import numexpr rand = random.SystemRandom() def cypher_roll(difficulty=None, mods=0): """Make a Cypher System roll. Args: difficulty: the original difficulty to beat; if provided, success or failure is indicated in the results mods: eases(-) and hindrances(+) to apply to the check, as a string (e.g. '-3+1') Returns: tuple of: - the result on the d20 - the highest difficulty beaten - if the difficulty is known, if the target was beat - miscellaneous effects """ roll = rand.randint(1, 20) if roll == 1: return (roll, None, False if difficulty else None, 'a GM intrusion') effect = None if roll == 17: effect = '+1 damage' elif roll == 18: effect = '+2 damage' elif roll == 19: effect = 'a minor effect' elif roll == 20: effect = 'a MAJOR EFFECT' # if we know the difficulty, the mods would adjust the difficulty, but for the case where we don't, # and maybe just in general, it's easier to modify the difficulty that the roll beats, so we flip the logic # if incoming eases are a negative number, they should add to the difficulty the roll beats beats = (roll // 3) - (numexpr.evaluate(mods).item() if mods else 0) beats = 0 if beats < 0 else beats return (roll, beats, difficulty <= beats if difficulty else None, effect)