#!/usr/bin/env python import random from itertools import chain, combinations # For the sake of determining hits (not crits, which auto-hit), we assume # an enemy with AC 10 and a character with no attack bonus. The idea being # that your attack bonus and enemy AC scale up at approximately the same # rate (AC14 common at low levels, AC17 common at higher levels, etc). # All attack rolls have a ternary result: None for miss, False for hit, # and True for crit. def d(sides): return random.choice(range(sides)) + 1 def attack(ac=10, crit=20): roll = d(20) if roll < ac: return None if roll < crit: return False return True def advantage(**kwargs): # None < False < True return max([attack(**kwargs), attack(**kwargs)]) def reroll(sides, trigger=0): roll = d(sides) if roll <= trigger: roll = d(sides) return roll def damage(count=1, sides=6, trigger=0): return sum([reroll(sides, trigger) for _ in xrange(count)]) def round(weapon_die_count, weapon_die_sides, savage=False, great=False, reckless=False, improved=False, brutal=False, brutal2=False, brutal3=False, improved2=False): attack_roll = advantage if reckless else attack crit = attack_roll(crit=20-sum([improved, improved2])) if crit == None: return 0 count = weapon_die_count if crit: count *= 2 count += sum([savage, brutal, brutal2, brutal3]) return damage(count, weapon_die_sides, 2 if great else 0) def validate(savage=False, great=False, reckless=False, improved=False, brutal=False, brutal2=False, brutal3=False, improved2=False): if brutal and not reckless: return False if brutal2 and not brutal: return False if brutal3 and not brutal2: return False if improved and not great: return False if improved2 and not improved: return False if improved2 and any([brutal, brutal2, brutal3]): return False return True vars = [ 'savage', # Adds one extra damage die on crits, level 1 half-orc 'great', # Rerolls 1s and 2s on damage dice, level 1 fighter 'reckless', # Gives advantage on attacks, level 2 barbarian 'improved', # Crits on 19 & 20, level 3 fighter (champion) 'brutal', # Adds one extra damage die on crits, level 9 barb (berzerker) 'brutal2', # Adds one extra damage die on crits, level 13 barb 'brutal3', # Adds one extra damage die on crits, level 17 barb 'improved2', # Crits on 18, level 15 fighter (champion) (precludes brutal) ] def __main__(): for combo in chain.from_iterable(combinations(vars, s) for s in range(len(vars)+1)): abilities = {x: True for x in combo} if validate(**abilities): print ', '.join(sorted(abilities.keys())), ':' axe = sum([round(1, 12, **abilities) for _ in xrange(10000)]) / 10000.0 print ' Greataxe:', axe, 'damage per attack' sword = sum([round(2, 6, **abilities) for _ in xrange(10000)]) / 10000.0 print ' Greatsword:', sword, 'damage per attack' if __name__ == '__main__': __main__()
Run
Reset
Share
Import
Link
Embed
Language▼
English
中文
Python Fiddle
Python Cloud IDE
Follow @python_fiddle
Browser Version Not Supported
Due to Python Fiddle's reliance on advanced JavaScript techniques, older browsers might have problems running it correctly. Please download the latest version of your favourite browser.
Chrome 10+
Firefox 4+
Safari 5+
IE 10+
Let me try anyway!
url:
Go
Python Snippet
Stackoverflow Question