/src/psrd/feats.py

https://github.com/devonjones/PSRD-Parser · Python · 153 lines · 138 code · 15 blank · 0 comment · 29 complexity · af4a5ef6d547845b18203a1d9e12e68b MD5 · raw file

  1. import os
  2. import json
  3. import re
  4. from BeautifulSoup import BeautifulSoup
  5. from psrd.rules import write_rules
  6. from psrd.files import char_replace
  7. from psrd.universal import parse_universal
  8. from psrd.sections import ability_pass, is_anonymous_section, has_subsections, entity_pass, find_section, quote_pass
  9. def adjust_core_pass(struct, filename):
  10. first = 3
  11. second = 6
  12. if filename in ('advancedFeats.html', 'ultimateMagicFeats.html'):
  13. first = 2
  14. elif struct['source'] == 'Occult Adventures':
  15. first = 1
  16. fdesc = struct['sections'][first]
  17. special = fdesc['sections'][second - 2]
  18. table = special['sections'][0]
  19. del special['sections']
  20. fdesc['sections'].insert(second - 1, table)
  21. feats = fdesc['sections'][second:]
  22. del fdesc['sections'][second:]
  23. sections = struct['sections']
  24. struct = sections.pop(0)
  25. struct['sections'] = sections
  26. return struct, feats
  27. def adjust_ultimate_combat_pass(struct):
  28. first = 3
  29. second = 6
  30. table = struct['sections'][2]['sections'][0]
  31. fdesc = struct['sections'][first]
  32. fdesc['sections'].insert(second - 1, table)
  33. del struct['sections'][2]
  34. feats = fdesc['sections'][second:]
  35. del fdesc['sections'][second:]
  36. sections = struct['sections']
  37. struct = sections.pop(0)
  38. struct['sections'] = sections
  39. p = find_section(struct, name="Prerequisites", section_type='section')
  40. p['name'] = 'Prerequisite'
  41. return struct, feats
  42. def adjust_advanced_class_guide_pass(struct):
  43. feats = struct['sections'][1]['sections'][5:]
  44. del struct['sections'][1]['sections'][5:]
  45. return struct, feats
  46. def adjust_ultimate_campaign_pass(struct):
  47. feats = struct['sections'][2]['sections']
  48. del struct['sections'][2]
  49. return struct, feats
  50. def adjust_mythic_adventures_pass(struct):
  51. feats = struct['sections'][2:]
  52. del struct['sections'][2:]
  53. return struct, feats
  54. def adjust_feat_structure_pass(struct, filename):
  55. feats = []
  56. if filename in ('feats.html', 'advancedFeats.html', 'ultimateMagicFeats.html'):
  57. if struct['source'] == 'Advanced Class Guide':
  58. struct, feats = adjust_advanced_class_guide_pass(struct)
  59. else:
  60. struct, feats = adjust_core_pass(struct, filename)
  61. elif filename in ('monsterFeats.html'):
  62. feats = struct['sections']
  63. del struct['sections']
  64. elif filename in ('ultimateCombatFeats.html'):
  65. struct, feats = adjust_ultimate_combat_pass(struct)
  66. elif filename in ('storyFeats.html'):
  67. struct, feats = adjust_ultimate_campaign_pass(struct)
  68. elif filename in ('mythicFeats.html'):
  69. struct, feats = adjust_mythic_adventures_pass(struct)
  70. return struct, feats
  71. def section_naming_pass(feat):
  72. p = find_section(feat, name="Prerequisite", section_type='section')
  73. if p != None:
  74. p['name'] = 'Prerequisites'
  75. b = find_section(feat, name="Benefit", section_type='section')
  76. if b != None:
  77. b['name'] = 'Benefits'
  78. p = find_section(feat, name="Prerequisites", section_type='section')
  79. if p != None:
  80. soup = BeautifulSoup(p['text'])
  81. p['description'] = ''.join(soup.findAll(text=True))
  82. del p['text']
  83. return feat
  84. def prerequisite_pass(feat):
  85. p = find_section(feat, name="Prerequisites", section_type='section')
  86. if p != None:
  87. prereq = p['description']
  88. if prereq.endswith("."):
  89. prereq = prereq[:-1]
  90. if prereq.find(";") > -1:
  91. parts = prereq.split(";")
  92. else:
  93. parts = prereq.strip().split(", ")
  94. feat['prerequisites'] = [part.strip() for part in parts]
  95. def feat_pass(feat):
  96. feat['type'] = 'feat'
  97. name = feat['name']
  98. m = re.search('(.*)\s*\((.*)\)', name)
  99. if m:
  100. newname = m.group(1).strip()
  101. types = m.group(2).split(", ")
  102. feat['name'] = newname
  103. feat['feat_types'] = types
  104. if not feat.has_key('text') and not feat.has_key('description'):
  105. for section in feat['sections']:
  106. if is_anonymous_section(section) and not has_subsections(section):
  107. feat['text'] = section['text']
  108. feat['sections'].remove(section)
  109. if feat.has_key('text') and not feat.has_key('description'):
  110. soup = BeautifulSoup(feat['text'])
  111. feat['description'] = ''.join(soup.findAll(text=True))
  112. del feat['text']
  113. def monster_feat_pass(feat):
  114. types = feat.setdefault('feat_types', [])
  115. types.append("Monster")
  116. def parse_feats(filename, output, book):
  117. struct = parse_universal(filename, output, book)
  118. struct = quote_pass(struct)
  119. struct = entity_pass(struct)
  120. rules, feats = adjust_feat_structure_pass(struct, os.path.basename(filename))
  121. for feat in feats:
  122. feat_pass(feat)
  123. ability_pass(feat)
  124. section_naming_pass(feat)
  125. prerequisite_pass(feat)
  126. if rules['name'] == 'Monster Feats':
  127. monster_feat_pass(feat)
  128. for feat in feats:
  129. print "%s: %s" %(feat['source'], feat['name'])
  130. filename = create_feat_filename(output, book, feat)
  131. fp = open(filename, 'w')
  132. json.dump(feat, fp, indent=4)
  133. fp.close()
  134. if rules:
  135. write_rules(output, rules, book, "feats")
  136. def create_feat_filename(output, book, feat):
  137. title = char_replace(book) + "/feats/" + char_replace(feat['name'])
  138. return os.path.abspath(output + "/" + title + ".json")