Advertisement
Guest User

Untitled

a guest
Jul 1st, 2015
194
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.63 KB | None | 0 0
  1. #!/usr/bin/env python
  2. """oldskool.py
  3.  
  4. Generate character stats using old school methods.
  5. """
  6.  
  7.  
  8. # I wanted to quickly generate some old school character stats. And I
  9. # wanted to express each method as tersely as possible in python.
  10. # As it turns out, this is pretty simple to do as one-liners, aside
  11. # from the differences in whether the player is allowed to reorder the
  12. # stats or not.
  13.  
  14.  
  15. from collections import OrderedDict
  16. from random import randint
  17.  
  18.  
  19. ATTRIBUTES = ("Strength",
  20. "Intelligence",
  21. "Wisdom",
  22. "Dexterity",
  23. "Constitution",
  24. "Charisma")
  25.  
  26. PALADIN = {"Strength": 12, "Intelligence": 9, "Wisdom": 13, "Constitution": 9,
  27. "Charisma": 17}
  28. RANGER = {"Strength": 13, "Intelligence": 13, "Wisdom": 14, "Constitution": 14}
  29. ILLUSIONIST = {"Intelligence": 15, "Dexterity": 16, "Constitution": 9,
  30. "Charisma": 17}
  31. MONK = {"Strength": 15, "Wisdom": 15, "Dexterity": 15, "Constitution": 11}
  32.  
  33.  
  34. def d6(num=1):
  35. """Roll a d6, num times."""
  36. return sum([randint(1, 6) for x in xrange(num)])
  37.  
  38.  
  39. def evaluate(attrs):
  40. """Evaluate a list of scores to see if it is really bad or not."""
  41. # Handle (in this case) OrderedDict data:
  42. if isinstance(attrs, dict):
  43. scores = attrs.values()
  44. elif len(attrs) == 6:
  45. scores = attrs
  46. else:
  47. raise TypeError("Too many scores!")
  48.  
  49. # Really good.
  50. if scores.count(18) + scores.count(17) > 2 or sum(scores) / 6 > 14:
  51. print "%s\n%s" % (u'\U0001F63B', score_string(attrs))
  52. # Really bad.
  53. elif sum(scores) < 48 or max(scores) < 14 or sum(scores) / 6 < 10:
  54. print "%s\n%s" % (u'\U0001F4A9', score_string(attrs))
  55. # Okay.
  56. else:
  57. print "%s\n%s" % (u'\U0001F352', score_string(attrs))
  58.  
  59.  
  60. def score_string(attrs):
  61. """Nicely represent scores of different types."""
  62. if isinstance(attrs, dict):
  63. result = ["%s: %s" % (key, attrs[key]) for key in attrs]
  64. else:
  65. result = [str(attr) for attr in attrs]
  66. return "\n".join(result)
  67.  
  68.  
  69. def method_zero():
  70. """Basic D&D / AD&D 2e Method I.
  71.  
  72. Roll 3d6 in order. Deal with it.
  73.  
  74. "Iron Man" method.
  75. """
  76. return OrderedDict((attr, d6(3)) for attr in ATTRIBUTES)
  77.  
  78.  
  79. def method_one():
  80. """AD&D 1e method I.
  81.  
  82. All scores are recorded and arranged in the order the player
  83. desires. 4d6 are rolled, and the lowest die (or one of the lower) is
  84. discarded.
  85. """
  86. return [sum(sorted([d6() for x in xrange(4)])[1:]) for y in xrange(6)]
  87.  
  88.  
  89. def method_two():
  90. """AD&D 1e method II.
  91.  
  92. All scores are recorded and arranged as in Method I. 3d6 are rolled
  93. 12 times and the highest 6 scores are retained.
  94. """
  95. return sorted([d6(3) for x in xrange(12)])[6:]
  96.  
  97.  
  98. def method_three():
  99. """AD&D 1e method III.
  100.  
  101. Scores rolled are according to each ability category, in order,
  102. STRENGTH, INTELLIGENCE, WISDOM, DEXTERITY, CONSTITUTION, CHARISMA.
  103. 3d6 are rolled 6 times for each ability and the highest score in
  104. each category is retained for that category.
  105. """
  106. return OrderedDict((attr, max((d6(3) for x in xrange(6)))) for attr in
  107. ATTRIBUTES)
  108.  
  109.  
  110. def method_four():
  111. """AD&D 1e method IV.
  112.  
  113. 3d6 are rolled sufficient times to generate the 6 ability scores, in
  114. order, for 12 characters. The player then selects the single set of
  115. scores which he or she finds most desirable and these scores are
  116. noted on the character record sheet.
  117. """
  118. return [method_zero() for x in xrange(12)]
  119.  
  120.  
  121. def rolls_for_a_class(c_class, method):
  122. """Return num of rolls it takes for stats elibible for paladinhood"""
  123. is_eligible = False
  124. ctr = 1
  125. while not is_eligible:
  126. is_eligible = meets_minimums(method(), c_class)
  127. ctr += 1
  128.  
  129. return ctr
  130.  
  131.  
  132. def percentage_of_class(c_class, method, trials=1000000):
  133. return [meets_minimums(method(), c_class) for _ in
  134. xrange(trials)].count(True) / float(trials) * 100
  135.  
  136.  
  137. def meets_minimums(stats, required):
  138. """Return bool whether a set of stats meet minimums."""
  139. result = True
  140. # Stats rolled are in order.
  141. if isinstance(stats, dict) and isinstance(required, dict):
  142. for stat in required:
  143. if stats[stat] < required[stat]:
  144. result = False
  145. break
  146. # Stats are unordered.
  147. elif isinstance(required, dict):
  148. sorted_requirements = sorted(required.values())
  149. sorted_requirements.reverse()
  150. sorted_stats = sorted(stats)
  151.  
  152. for requirement in sorted_requirements:
  153. if sorted_stats.pop() < requirement:
  154. result = False
  155. break
  156.  
  157. else:
  158. raise AttributeError("Incorrect required type.")
  159.  
  160. return result
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement