def _parse_spell(spell_source, default, spell_list): spell = copy.copy(default) m = re.match("(.*) \((.*)\)", spell_source) count = 1 if m: spell["name"] = m.groups()[0] notes = [s.strip() for s in split(m.groups()[1])] while len(notes) > 0: note = notes.pop(0) if note.startswith("DC "): dc = note[3:] dc_notes = None if dc.find(";"): parts = split(dc, char=";") dc = parts.pop(0) dc_notes = parts dc = int(dc) spell["dc"] = {"value": dc} if dc_notes: spell["dc"]["notes"] = dc_notes elif note.isdigit(): count = int(note) else: spell["notes"] = note else: spell["name"] = spell_source if spell["name"].endswith("D"): spell["name"] = spell["name"][:-1] spell["domain"] = True if spell["name"].endswith("M"): spell["name"] = spell["name"][:-1] spell["mythic"] = True for i in range(count): spell_list["spells"].append(spell)
def _handle_saves(statblock, token, data): content = " ".join([l.strip() for l in data["lines"]]) saves = statblock.setdefault("saves", {}) parts = [s.strip() for s in split(content, char=";")] saves_source = [s.strip() for s in split(parts.pop(0))] modifiers = ";".join(parts) for save in saves_source: m = re.match("^(.*) ([-+]?\d+)$", save) if m: name, value = m.groups() name = name.lower() value = int(value) if name == "ref": name = "reflex" elif name == "fort": name = "fortitude" saves[name] = create("save", name=name, value=value) add_situational_modifiers(saves[name], modifiers) continue m = re.match("^(.*) ([-+]?\d+) \((.*)\)$", save) if m: name, value, specific_modifiers = m.groups() name = name.lower() value = int(value) if name == "ref": name = "reflex" elif name == "fort": name = "fortitude" saves[name] = create("save", name=name, value=int(m.groups()[1])) add_situational_modifiers(saves[name], modifiers) add_situational_modifiers(saves[name], specific_modifiers, value) continue raise Exception("Don't know how to parse saves: %s" % content)
def _handle_list_intern(statblock, token, data): lines = data['lines'] content = " ".join([line.strip() for line in lines]) fields = split(content, ";") if len(fields) > 1: raise Exception("; not yet supported in %s: %s" % (token, json.dumps(content))) parts = [create(object_type, name=part.strip()) for part in split(content)] name_token = token.lower().replace(" ", "_") statblock[name_token] = parts
def _handle_skills(statblock, token, data): lines = data['lines'] content = " ".join([line.strip() for line in lines]).split(";") skills_line = content.pop(0) skills = {} for skill_line in split(skills_line): skill_line = skill_line.strip() name = None bonus = None m = re.match("^([A-Za-z ]*) ([+-]?[0-9]+)$", skill_line) if m: name = m.groups()[0] skill_name = name.lower().replace(" ", "_") bonus = int(m.groups()[1]) skills[skill_name] = create("skill", value=bonus, name=name) continue m = re.match("^([A-Za-z ]*) \((.*?)\) ([+-]?[0-9]+)$", skill_line) if m: name = m.groups()[0] skill_name = name.lower().replace(" ", "_") subtype = m.groups()[1] bonus = int(m.groups()[2]) subtype = subtype.replace(", and ", ", ").replace(" or ", ", ") for st in subtype.split(","): skills["%s_%s" % (skill_name, st.strip().replace(" ", "_"))] = create( "skill", value=bonus, name=name, subskill=st.strip()) continue m = re.match("^([A-Za-z ]*) ([+-]?[0-9]+) \((.*?)\)$", skill_line) if m: name = m.groups()[0] skill_name = name.lower().replace(" ", "_") bonus = int(m.groups()[1]) skill = create("skill", value=bonus, name=name) skills[skill_name] = skill modifiers = m.groups()[2] add_situational_modifiers(skill, modifiers, bonus) continue for line in content: if line.strip().startswith("Racial Modifiers "): line = line.replace("Racial Modifiers ", "") bonuses = split(line) for bonus in bonuses: m = re.match("([+-]?[0-9]+) (.*)", bonus.strip()) if m: b = int(m.groups()[0]) skill_name = m.groups()[1] skill = skills.setdefault(skill_name, create("skill", name=name)) add_modifier(skill, create_modifier("racial", value=b)) else: raise Exception("Can't parse: %s" % line) else: raise Exception("Unknown skill subsection: %s" % line) statblock["skills"] = skills
def _handle_weapons(statblock, token, data): content = " ".join([d.strip() for d in data["lines"]]) section = statblock.setdefault(token, []) if content.find(" or "): content.replace(" or ", "`") for weapon_set_source in split(content, char="`"): weapon_set_source = weapon_set_source.replace("`", " or ") weapon_set = [] section.append(weapon_set) for weapon in split(weapon_set_source): weapon = weapon.strip() m = re.match("(\d+) (.*) ([0-9/+-]+) \((.*)\)", weapon) if m: count = int(m.groups()[0]) name = m.groups()[1] if name.endswith("s"): name = name to_hit = m.groups()[2] damage = m.groups()[3] w = _generate_weapon(name, to_hit, damage) w["count"] = count weapon_set.append(w) continue m = re.match("(.*) ([0-9/+-]+) \((.*)\)", weapon) if m: name = m.groups()[0] to_hit = m.groups()[1] damage = m.groups()[2] w = _generate_weapon(name, to_hit, damage) weapon_set.append(w) continue m = re.match("(.*) ([0-9/+-]+)", weapon) if m: name = m.groups()[0] to_hit = m.groups()[1] w = _generate_weapon(name, to_hit) weapon_set.append(w) continue m = re.match("(.*) ([0-9/+-]+)", weapon) if m: name = m.groups()[0] to_hit = m.groups()[1] w = _generate_weapon(name, to_hit) weapon_set.append(w) continue m = re.match("(.*) \((.*)\)", weapon) if m: name = m.groups()[0] damage = m.groups()[1] w = _generate_weapon(name, "", damage) weapon_set.append(w) continue raise Exception("Don't know how to parse weapon: %s" % json.dumps(weapon))
def _handle_list_intern(statblock, token, data): lines = data['lines'] content = " ".join([line.strip() for line in lines]) fields = split(content, ";") if len(fields) > 1: raise Exception("; not yet supported in %s: %s" % (token, json.dumps(content))) parts = [ create(object_type, name=part.strip()) for part in split(content) ] name_token = token.lower().replace(" ", "_") statblock[name_token] = parts
def _handle_languages(statblock, token, data): lines = data['lines'] content = " ".join([line.strip() for line in lines]) fields = split(content, ";") languages = split(fields[0]) final = [] for language in languages: final.append(create("language", name=language.strip())) if len(fields) > 1: others = split(fields[1]) for other in others: final.append(create("language", "other", name=other.strip())) elif len(fields) > 2: raise Exception("I don't know how to handle this language list: %s" % json.dumps(content)) statblock["languages"] = final
def _handle_cl(section, lines): line = lines.pop(0) m = re.match("\((CL .*?)\)", line) if m: cl = m.groups()[0] pieces = split(cl, char=";") for piece in pieces: piece = piece.strip() m = re.match("CL (\d+)[snrt][tdh]", piece) if m: section["caster_level"] = create("caster_level", value=int(m.groups()[0])) continue m = re.match("(\d+)% spell failure", piece) if m: section["spell_failure"] = create("spell_failure", value=int(m.groups()[0])) continue m = re.match("concentration ([+-]?\d+)", piece) if m: section["concentration"] = create("concentration", value=int(m.groups()[0])) continue section["notes"] = line parts = line.split(")") parts.pop(0) line = ")".join(parts).strip() if line == "": return lines else: lines.insert(0, line) return lines raise Exception("Spell block has unexpected format: %s" % line)
def _handle_spell_notes(section, lines): retlines = [] for line in lines: append = True for s in [ "Thassilonian Specialization", "Thassilonian Specialist", "Opposition Schools", "Prohibited Schools ", "D ", "Domain ", "Domains ", "Patron ", "Bloodline ", "Mystery ", "M " ]: if line.startswith(s): if s not in ["D ", "M "]: data = line[len(s):].strip() key = s.lower().strip() if data.find(",") > -1: data = [d.strip() for d in split(data)] if s == "Domain ": key = "domains" data = [data] if s == "Thassilonian Specialist": key = "thassilonian specialization" section[key] = data append = False if append: retlines.append(line) return retlines
def _handle_attack(statblock, token, data): lines = data['lines'] content = " ".join([line.strip() for line in lines]) fields = [field.strip() for field in split(content, char=";")] for field in fields: m = re.match("(.*?) ([+-]?[0-9]+) \((.*?)\)", field) if m: name = m.groups()[0] name, subtype, abbrev = _get_attack_fields(name) bonus = int(m.groups()[1]) modifiers = m.groups()[2] section = create( "attack", subtype, name=name, value=bonus, abbrev=abbrev) add_situational_modifiers(section, modifiers, bonus) statblock[name] = section continue m = re.match("(.*?) ([+-]?[0-9]+)", field) if m: name = m.groups()[0] name, subtype, abbrev = _get_attack_fields(name) bonus = int(m.groups()[1]) statblock[name] = create( "attack", subtype, name=name, value=bonus, abbrev=abbrev) m = re.match("(.*?) -", field) if m: name = m.groups()[0] name, subtype, abbrev = _get_attack_fields(name) statblock[name] = create( "attack", subtype, name=name, value=None, abbrev=abbrev)
def _handle_cl(section, lines): line = lines.pop(0) m = re.match("\((CL .*?)\)", line) if m: cl = m.groups()[0] pieces = split(cl, char=";") for piece in pieces: piece = piece.strip() m = re.match("CL (\d+)[snrt][tdh]", piece) if m: section["caster_level"] = create( "caster_level", value=int(m.groups()[0])) continue m = re.match("(\d+)% spell failure", piece) if m: section["spell_failure"] = create( "spell_failure", value=int(m.groups()[0])) continue m = re.match("concentration ([+-]?\d+)", piece) if m: section["concentration"] = create( "concentration", value=int(m.groups()[0])) continue section["notes"] = line parts = line.split(")") parts.pop(0) line = ")".join(parts).strip() if line == "": return lines else: lines.insert(0, line) return lines raise Exception("Spell block has unexpected format: %s" % line)
def _handle_gear(statblock, token, data): lines = data['lines'] content = " ".join([line.strip() for line in lines]) gear = statblock.setdefault("gear", {}) items = split(content) subgear = gear.setdefault(token, []) for item in items: subgear.append(create("gear", name=item.strip()))
def _split_spell_fields(lines): retlines = [] for line in lines: if line.find(";") > -1: parts = split(line, char=";") for part in parts: retlines.append(part.strip()) else: retlines.append(line) return retlines
def _handle_ac(statblock, token, data): content = " ".join([l.strip() for l in data["lines"]]) parts = split(content, char=";") ac = statblock.setdefault("ac", {}) ac_part = parts.pop(0) try: _handle_ac_components(ac, ac_part) except Exception, e: sys.stderr.write("%s\n" % json.dumps(content, indent=2)) raise e
def _handle_defensive_abilities(statblock, data): abilities = [s.strip() for s in split(data[20:])] da_s = statblock.setdefault("defensive abilities", {}) for ability in abilities: m = re.match("^(.*) ([-+]?\d+)$", ability) if m: name = m.groups()[0] bonus = int(m.groups()[1]) da_s["name"] = create("defensive_ability", name=name, value=bonus) else: da_s["name"] = create("defensive_ability", name=ability)
def _handle_senses(statblock, parts): retlines = [] while len(parts) > 0: part = parts.pop() if part.strip().startswith("Senses "): content = part[7:] sections = [p.strip() for p in split(content)] statblock["senses"] = [create("sense", name=s) for s in sections] else: retlines.append(part) return retlines
def add_situational_modifiers(statblock, modifiers, bonus=0): for modifier in split(modifiers): m = re.match("([+-]?[0-9]+) (.*)", modifier.strip()) if m: value = int(m.groups()[0]) - bonus situation = m.groups()[1] add_modifier(statblock, create_modifier( subtype="situational", value=value, situation=situation)) else: add_modifier(statblock, create_modifier( subtype="situational", situation=modifier))
def _handle_hp(statblock, token, data): content = " ".join([l.strip() for l in data["lines"]]) parts = [s.strip() for s in split(content, char=";")] hp_source = parts.pop(0) hp = statblock.setdefault("hit_points", create("hit_points")) hp_source = hp_source.replace(" each", "") m = re.match("(\d+) \((.*)\)", hp_source) if m: hit_points, hit_dice = m.groups() hp["value"] = int(hit_points) m = re.match("(\d+) HD; ([0-9d+]+)([-+]\d+)", hit_dice) if m: hd, dice, plus = m.groups() hp["hit_dice"] = create("hit_dice", value=int(hd)) hp["dice"] = dice hp["plus"] = create("hp_plus", value=int(plus)) else: m = re.match("([0-9]+)d([0-9]+)([-+]\d+)", hit_dice) if m: count, d_type, plus = m.groups() hp["hit_dice"] = create("hit_dice", value=int(count)) hp["dice"] = "%sd%s" % (count, d_type) hp["plus"] = create("hp_plus", value=int(plus)) else: m = re.match("([0-9]+)d([0-9]+)", hit_dice) if m: count, d_type = m.groups() hp["hit_dice"] = create("hit_dice", value=int(count)) hp["dice"] = "%sd%s" % (count, d_type) else: raise Exception( "Don't know how to parse hit dice: %s" % json.dumps(content)) else: raise Exception( "Don't know how to parse hp: %s" % json.dumps(content)) if len(parts) > 0: healing = [h.strip() for h in split(parts.pop(0))] _handle_healing(hp, healing) if len(parts) > 0: raise Exception( "Don't know how to parse hp line: %s" % json.dumps(content))
def _parse_ac_modifiers(pieces): parts = [p.strip() for p in split(pieces)] results = {} for part in parts: m = re.match("^([-+]?\d+) (.*)", part) if m: bonus = int(m.groups()[0]) name = m.groups()[1] results[name] = bonus continue raise Exception("Don't know how to parse: %s" % pieces) return results
def _handle_hp(statblock, token, data): content = " ".join([l.strip() for l in data["lines"]]) parts = [s.strip() for s in split(content, char=";")] hp_source = parts.pop(0) hp = statblock.setdefault("hit_points", create("hit_points")) hp_source = hp_source.replace(" each", "") m = re.match("(\d+) \((.*)\)", hp_source) if m: hit_points, hit_dice = m.groups() hp["value"] = int(hit_points) m = re.match("(\d+) HD; ([0-9d+]+)([-+]\d+)", hit_dice) if m: hd, dice, plus = m.groups() hp["hit_dice"] = create("hit_dice", value=int(hd)) hp["dice"] = dice hp["plus"] = create("hp_plus", value=int(plus)) else: m = re.match("([0-9]+)d([0-9]+)([-+]\d+)", hit_dice) if m: count, d_type, plus = m.groups() hp["hit_dice"] = create("hit_dice", value=int(count)) hp["dice"] = "%sd%s" % (count, d_type) hp["plus"] = create("hp_plus", value=int(plus)) else: m = re.match("([0-9]+)d([0-9]+)", hit_dice) if m: count, d_type = m.groups() hp["hit_dice"] = create("hit_dice", value=int(count)) hp["dice"] = "%sd%s" % (count, d_type) else: raise Exception("Don't know how to parse hit dice: %s" % json.dumps(content)) else: raise Exception("Don't know how to parse hp: %s" % json.dumps(content)) if len(parts) > 0: healing = [h.strip() for h in split(parts.pop(0))] _handle_healing(hp, healing) if len(parts) > 0: raise Exception("Don't know how to parse hp line: %s" % json.dumps(content))
def _handle_space(statblock, token, data): content = " ".join([d.strip() for d in data["lines"]]) space = content if content.find(";"): parts = split(space, char=";") space = parts.pop(0) for part in parts: part = part.strip() if part.startswith("Reach "): statblock["reach"] = part[6:] else: raise Exception("Space token not recognized: %" % content) statblock["space"] = space
def add_situational_modifiers(statblock, modifiers, bonus=0): for modifier in split(modifiers): m = re.match("([+-]?[0-9]+) (.*)", modifier.strip()) if m: value = int(m.groups()[0]) - bonus situation = m.groups()[1] add_modifier( statblock, create_modifier(subtype="situational", value=value, situation=situation)) else: add_modifier( statblock, create_modifier(subtype="situational", situation=modifier))
def parse_senses(lines): retlines = [] for statblock in yield_statblocks(lines, retlines): source = statblock.setdefault("source", {}) basics = statblock.setdefault("basics", {}) senses_source = source.setdefault("senses", {}) content = " ".join([sense.strip() for sense in senses_source.get("lines", [])]) if content != "": parts = [part.strip() for part in split(content, ";")] parts = _handle_initiative(basics, parts) parts = _handle_senses(basics, parts) parts = _handle_perception(statblock, parts) if len(parts) > 0: raise Exception("Senses line contains unknown parts: %s" % content) del source["senses"] return retlines
def _parse_alignment(statblock, data): content = " ".join([l.strip() for l in data["lines"]]) if content.find("(") > -1: content, subtypes = content.split("(") subtypes = subtypes[:-1] statblock["creature_subtypes"] = [s.strip() for s in split(subtypes)] parts = content.split() align = parts.pop(0) if not validate_alignment(align): raise Exception("Don't recognize alignment: %s" % align) statblock["alignment"] = create("alignment", value=align) statblock["size"] = create_size(parts.pop(0)) creature_type = " ".join(parts) if not validate_creature_type(creature_type): raise Exception("Creature Type unrecognized: %s" % creature_type) statblock["creature_type"] = creature_type
def _add_spells(line, section, level=None, freq=None, freq_period=None): parts = line.split("-") parts.pop(0) spells = [s.strip() for s in split("-".join(parts))] spell = create("spell") spell_list = create("spell_list", spells=[]) if level != None: spell_list["level"] = level spell["level"] = level if freq: spell_list["frequency"] = freq if freq_period: spell_list["frequency period"] = freq_period for spell_source in spells: _parse_spell(spell_source, spell, spell_list) section["spell_lists"].append(spell_list)
def _handle_defenses(statblock, token, data): content = " ".join([l.strip() for l in data["lines"]]) chunks = [s.strip() for s in split(content, char=";")] for da in chunks: if da.startswith("Defensive Abilities "): _handle_defensive_abilities(statblock, da) elif da.startswith("DR "): _handle_dr(statblock, da) elif da.startswith("Immune "): handle_list("immune")(statblock, "immune", {"lines": [da[7:]]}) elif da.startswith("Resist "): _handle_resist(statblock, da) elif da.startswith("SR "): _handle_sr(statblock, da) else: raise Exception("I don't recognize this defense: %s" % json.dumps(da))
def _parse_armor(ac, line): parts = [l.strip() for l in split(line)] ac["base"] = { "value": int(parts.pop(0)), "name": "base", "type": "armor_class"} while len(parts) > 0: p = parts.pop() if p.startswith("touch"): ac["touch"] = { "value": int(p.replace("touch", "")), "name": "touch", "type": "armor_class"} elif p.startswith("flat-footed"): ac["flat-footed"] = { "value": int(p.replace("flat-footed", "")), "name": "flat-footed", "type": "armor_class"} else: raise Exception("I don't know how to parse armor: %s" % line)
def _handle_resist(statblock, data): resists = [s.strip() for s in split(data[7:])] for resist in resists: m = re.match("(.*) (\d+) \((.*)\)", resist) if m: name, value, notes = m.groups() resist_section = statblock.setdefault("resistances", []) resist_section.append( create("resistance", name=name, value=int(value), notes=notes)) continue m = re.match("(.*) (\d+)", resist) if m: name, value = m.groups() resist_section = statblock.setdefault("resistances", []) resist_section.append( create("resistance", name=name, value=int(value))) continue raise Exception("Don't know how to parse resist: %s" % data)
def _handle_resist(statblock, data): resists = [s.strip() for s in split(data[7:])] for resist in resists: m = re.match("(.*) (\d+) \((.*)\)", resist) if m: name, value, notes = m.groups() resist_section = statblock.setdefault("resistances", []) resist_section.append(create( "resistance", name=name, value=int(value), notes=notes)) continue m = re.match("(.*) (\d+)", resist) if m: name, value = m.groups() resist_section = statblock.setdefault("resistances", []) resist_section.append(create( "resistance", name=name, value=int(value))) continue raise Exception("Don't know how to parse resist: %s" % data)
def parse_senses(lines): retlines = [] for statblock in yield_statblocks(lines, retlines): source = statblock.setdefault("source", {}) basics = statblock.setdefault("basics", {}) senses_source = source.setdefault("senses", {}) content = " ".join( [sense.strip() for sense in senses_source.get("lines", [])]) if content != "": parts = [part.strip() for part in split(content, ";")] parts = _handle_initiative(basics, parts) parts = _handle_senses(basics, parts) parts = _handle_perception(statblock, parts) if len(parts) > 0: raise Exception("Senses line contains unknown parts: %s" % content) del source["senses"] return retlines
def _handle_sr(statblock, data): sr_s = [s.strip() for s in split(data[3:])] for sr in sr_s: m = re.match("(\d+) \((.*)\)", sr) if m: value, notes = m.groups() sr_section = statblock.setdefault("spell_resistances", []) sr_section.append(create( "spell_resistance", value=int(value), notes=notes)) continue m = re.match("(\d+) (.*)", sr) if m: value, notes = m.groups() sr_section = statblock.setdefault("spell_resistances", []) sr_section.append(create( "spell_resistance", value=int(value), notes=notes)) continue resist_section = statblock.setdefault("spell_resistances", []) resist_section.append(create("spell_resistance", value=int(sr)))
def _handle_sr(statblock, data): sr_s = [s.strip() for s in split(data[3:])] for sr in sr_s: m = re.match("(\d+) \((.*)\)", sr) if m: value, notes = m.groups() sr_section = statblock.setdefault("spell_resistances", []) sr_section.append( create("spell_resistance", value=int(value), notes=notes)) continue m = re.match("(\d+) (.*)", sr) if m: value, notes = m.groups() sr_section = statblock.setdefault("spell_resistances", []) sr_section.append( create("spell_resistance", value=int(value), notes=notes)) continue resist_section = statblock.setdefault("spell_resistances", []) resist_section.append(create("spell_resistance", value=int(sr)))
def _parse_classes(creature, parts): class_parts = [] while parts[-1][0].isdigit(): class_parts.insert(0, parts.pop()) if len(class_parts) > 0: class_parts.insert(0, parts.pop()) if parts[-1] == "of": class_parts.insert(0, parts.pop()) class_parts.insert(0, parts.pop()) class_source = " ".join(class_parts) classes = [s.strip() for s in split(class_source, char="/")] cc = None for pc_class in classes: m = re.match("^(.*) (\d+)$", pc_class) if m: name, value = m.groups() cc = creature.setdefault("classes", []) cc.append(create("class", name=name, value=int(value))) else: raise Exception("I don't recognize class: %s" % pc_class)
def _handle_spell_notes(section, lines): retlines = [] for line in lines: append = True for s in ["Thassilonian Specialization", "Thassilonian Specialist", "Opposition Schools", "Prohibited Schools ", "D ", "Domain ", "Domains ", "Patron ", "Bloodline ", "Mystery ", "M "]: if line.startswith(s): if s not in ["D ", "M "]: data = line[len(s):].strip() key = s.lower().strip() if data.find(",") > -1: data = [d.strip() for d in split(data)] if s == "Domain ": key = "domains" data = [data] if s == "Thassilonian Specialist": key = "thassilonian specialization" section[key] = data append = False if append: retlines.append(line) return retlines
def _parse_armor(ac, line): parts = [l.strip() for l in split(line)] ac["base"] = { "value": int(parts.pop(0)), "name": "base", "type": "armor_class" } while len(parts) > 0: p = parts.pop() if p.startswith("touch"): ac["touch"] = { "value": int(p.replace("touch", "")), "name": "touch", "type": "armor_class" } elif p.startswith("flat-footed"): ac["flat-footed"] = { "value": int(p.replace("flat-footed", "")), "name": "flat-footed", "type": "armor_class" } else: raise Exception("I don't know how to parse armor: %s" % line)
def _handle_attributes(statblock, token, data): lines = data['lines'] content = " ".join([line.strip() for line in lines]) for field in split(content): field = field.strip() m = re.match("^([A-Za-z]+) ([-0-9]+)$", field) if m: stat = m.groups()[0] stat, abbrev = _get_attribute_name(stat) value = m.groups()[1] if value == "-": value = None else: value = int(value) mod = "%s_mod" % abbrev mod_value = None if value: mod_value = int(value - 10) / 2 statblock[abbrev] = create( "attribute", name=stat, value=value, abbrev=abbrev, mod=create( "attribute_modifier", name=mod, value=mod_value)) else: raise Exception("Cannot parse Attributes: %s" % json.dumps(content))
def _handle_speed(statblock, token, data): content = " ".join([d.strip() for d in data["lines"]]) statblock["speed"] = [ create("movement", name=c.strip()) for c in split(content) ]
def _handle_speed(statblock, token, data): content = " ".join([d.strip() for d in data["lines"]]) statblock["speed"] = [create("movement", name=c.strip()) for c in split(content)]