Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- """oldskool.py
- Generate character stats using old school methods.
- """
- # I wanted to quickly generate some old school character stats. And I
- # wanted to express each method as tersely as possible in python.
- # As it turns out, this is pretty simple to do as one-liners, aside
- # from the differences in whether the player is allowed to reorder the
- # stats or not.
- from collections import OrderedDict
- from random import randint
- ATTRIBUTES = ("Strength",
- "Intelligence",
- "Wisdom",
- "Dexterity",
- "Constitution",
- "Charisma")
- PALADIN = {"Strength": 12, "Intelligence": 9, "Wisdom": 13, "Constitution": 9,
- "Charisma": 17}
- RANGER = {"Strength": 13, "Intelligence": 13, "Wisdom": 14, "Constitution": 14}
- ILLUSIONIST = {"Intelligence": 15, "Dexterity": 16, "Constitution": 9,
- "Charisma": 17}
- MONK = {"Strength": 15, "Wisdom": 15, "Dexterity": 15, "Constitution": 11}
- def d6(num=1):
- """Roll a d6, num times."""
- return sum([randint(1, 6) for x in xrange(num)])
- def evaluate(attrs):
- """Evaluate a list of scores to see if it is really bad or not."""
- # Handle (in this case) OrderedDict data:
- if isinstance(attrs, dict):
- scores = attrs.values()
- elif len(attrs) == 6:
- scores = attrs
- else:
- raise TypeError("Too many scores!")
- # Really good.
- if scores.count(18) + scores.count(17) > 2 or sum(scores) / 6 > 14:
- print "%s\n%s" % (u'\U0001F63B', score_string(attrs))
- # Really bad.
- elif sum(scores) < 48 or max(scores) < 14 or sum(scores) / 6 < 10:
- print "%s\n%s" % (u'\U0001F4A9', score_string(attrs))
- # Okay.
- else:
- print "%s\n%s" % (u'\U0001F352', score_string(attrs))
- def score_string(attrs):
- """Nicely represent scores of different types."""
- if isinstance(attrs, dict):
- result = ["%s: %s" % (key, attrs[key]) for key in attrs]
- else:
- result = [str(attr) for attr in attrs]
- return "\n".join(result)
- def method_zero():
- """Basic D&D / AD&D 2e Method I.
- Roll 3d6 in order. Deal with it.
- "Iron Man" method.
- """
- return OrderedDict((attr, d6(3)) for attr in ATTRIBUTES)
- def method_one():
- """AD&D 1e method I.
- All scores are recorded and arranged in the order the player
- desires. 4d6 are rolled, and the lowest die (or one of the lower) is
- discarded.
- """
- return [sum(sorted([d6() for x in xrange(4)])[1:]) for y in xrange(6)]
- def method_two():
- """AD&D 1e method II.
- All scores are recorded and arranged as in Method I. 3d6 are rolled
- 12 times and the highest 6 scores are retained.
- """
- return sorted([d6(3) for x in xrange(12)])[6:]
- def method_three():
- """AD&D 1e method III.
- Scores rolled are according to each ability category, in order,
- STRENGTH, INTELLIGENCE, WISDOM, DEXTERITY, CONSTITUTION, CHARISMA.
- 3d6 are rolled 6 times for each ability and the highest score in
- each category is retained for that category.
- """
- return OrderedDict((attr, max((d6(3) for x in xrange(6)))) for attr in
- ATTRIBUTES)
- def method_four():
- """AD&D 1e method IV.
- 3d6 are rolled sufficient times to generate the 6 ability scores, in
- order, for 12 characters. The player then selects the single set of
- scores which he or she finds most desirable and these scores are
- noted on the character record sheet.
- """
- return [method_zero() for x in xrange(12)]
- def rolls_for_a_class(c_class, method):
- """Return num of rolls it takes for stats elibible for paladinhood"""
- is_eligible = False
- ctr = 1
- while not is_eligible:
- is_eligible = meets_minimums(method(), c_class)
- ctr += 1
- return ctr
- def percentage_of_class(c_class, method, trials=1000000):
- return [meets_minimums(method(), c_class) for _ in
- xrange(trials)].count(True) / float(trials) * 100
- def meets_minimums(stats, required):
- """Return bool whether a set of stats meet minimums."""
- result = True
- # Stats rolled are in order.
- if isinstance(stats, dict) and isinstance(required, dict):
- for stat in required:
- if stats[stat] < required[stat]:
- result = False
- break
- # Stats are unordered.
- elif isinstance(required, dict):
- sorted_requirements = sorted(required.values())
- sorted_requirements.reverse()
- sorted_stats = sorted(stats)
- for requirement in sorted_requirements:
- if sorted_stats.pop() < requirement:
- result = False
- break
- else:
- raise AttributeError("Incorrect required type.")
- return result
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement