[schema]
    identifier="re ^[a-zA-Z0-9_ ]+$"
    identifierlist="re ^([a-zA-Z0-9_ ]+,)*[a-zA-Z0-9_ ]+$"
    # slash-separated filenames
    path="re ^([a-zA-Z0-9_\-.+]+/)*[a-zA-Z0-9_\-.+]+(~(TC|RC|PAL|FL|GS|CS|CROP|SCALE|BL|O|R|G|B|NOP|RIGHT)\(.*\))*$"
    #TODO: imagepath, remove imagepathfunctions from path
    # comma-separated paths
    pathlist="re ^(([a-zA-Z0-9_\-.+]+/)*[a-zA-Z0-9_\-.+]+(~(TC|RC|PAL|FL|GS|CS|CROP|SCALE|BL|O|R|G|B|NOP|RIGHT)\(.*\))*,)*([a-zA-Z0-9_\-.+]+/)*[a-zA-Z0-9_\-.+]+(~(TC|RC|PAL|FL|GS|CS|CROP|SCALE|BL|O|R|G|B|NOP|RIGHT)\(.*\))*$"
    #TODO: imagepathlist, same as above
    [root]
        # All possible root elements
        _about="repeated about"
        _advanced_preference="repeated advanced_preference"
        _ais="required ais"
        _binary_path="repeated binary_path"
        _campaign="repeated campaign"
        _fonts="optional fonts"
        _game_config="optional game_config"
        _help="optional help"
        _hotkey="repeated hotkey"
        _lua="repeated lua"
        _terrain_type="repeated terrain_type"
        _terrain_graphics="repeated terrain_graphics"
        _textdomain="repeated textdomain"
        _theme="repeated theme"
        _units="optional units"
    [/root]

    [about]
        [description]
            text="_ A section of the credits
-title is the title of this section
-text is displayed before the entries"
        [/description]
        _entry="repeated entry"

        text="optional tstring"
        title="optional tstring"
    [/about]
    [about-campaign:about]
        [description]
            text="_ -images is a list of the background images for the credits"
        [/description]
        images="optional string" #TODO: should be a list of paths
    [/about-campaign:about]
    about_preference_type="enum boolean,int"
    [advanced_preference]
        [description]
            text="_ The interface for an advanced preference
-field identifies the preference
-name is the user-visible name
-type indicates the type of setting, only if is an int do min, max and step have meaning"
        [/description]
        default="optional string"
        description="optional tstring"
        field="required identifier"
        name="required tstring"
        type="required about_preference_type"

        min="optional integer"
        max="optional integer"
        step="optional integer"
    [/advanced_preference]
    [ai]
        _aspect="repeated aspect"
        _stage="repeated stage"

        description="required string" #maybe tstring?
        id="required identifier"
        version="required integer"
    [/ai]
    [ais]
        _ai="repeated ai"
        _default_config="required default_config"
    [/ais]
    [binary_path]
        path="required path"
    [/binary_path]
    [campaign]
        _about="repeated about-campaign"

        abbrev="required identifier"
        define="required identifier" #TODO: maybe require it to be uppercase?
        description="required tstring"
        difficulties="required string" #TODO: should be a list of identifiers, same maybe as above
        difficulty_descriptions="required string" #TODO: this one's especially complicated
        extra_defines="optional string" #TODO: should be a list of identifiers, maybe uppercase?
        first_scenario="required identifier"
        icon="optional path"
        id="required string"
        image="optional path"
        name="required tstring"
        rank="required integer"
    [/campaign]
    [entry]
        [description]
            text="_ An entry for the credits"
        [/description]
        comment="optional string"
        email="optional string"
        ircuser="optional string"
        name="required string"
        wikiuser="optional string"
    [/entry]
    [female:unit_type]
        id="forbidden identifier"
        inherit="optional boolean"
    [/female:unit_type]
    [font]
        codepoints="required string" #TODO: should be a list of integers
        name="required path"
    [/font]
    [fonts]
        _font="repeated font"

        order="required string" #TODO: should be a list of paths
    [/fonts]
    # this is a list of path:integer
    flag_image_type="re ^((([a-zA-Z0-9_\-.+]+/)*[a-zA-Z0-9_\-.+]+):[0-9]+,)*(([a-zA-Z0-9_\-.+]+/)*[a-zA-Z0-9_\-.+]+):[0-9]+$"
    hexlist="re ^([0-9a-f]{6},)*[0-9a-f]{6}$"
    [game_config]
        _color_palette="repeated color_palette"
        _color_range="repeated color_range"
        _server="repeated server"

        # Maybe these aren't required...
        ally_ball_image="required path"
        base_income="optional integer"
        buttons_x="optional integer"
        buttons_y="optional integer"
        buttons_padding="optional integer"
        cross_image="required path"
        default_defeat_music="required pathlist"
        default_victory_music="required pathlist"
        #defense_color_scale="
        ellipsis_image="required path"
        enemy_ball_image="required path"
        energy_image="required path"
        flag_icon_image="required path"
        flag_image="required flag_image_type"
        flag_rgb="optional identifier"
        footprint_prefix="required pathlist"
        footprint_teleport_enter="required path"
        footprint_teleport_exit="required path"
        grid_image="required path"
        hp_bar_scaling="required float"
        icon="required path"
        kill_experience="optional integer"
        level_image="required path"
        lobby_music="required path" #maybe list
        lobby_refresh="optional integer"
        logo="required path"
        logo_x="required integer"
        logo_y="required integer"
        moved_ball_image="required path"
        observer_image="required path"
        partmoved_ball_image="required path"
        poison_amount="optional integer"
        recall_cost="optional integer"
        red_green_scale="optional hexlist"
        red_green_scale_text="optional hexlist"
        rest_heal_amount="optional integer"
        terrain_mask_image="required path"
        tip_padding="required integer"
        tip_width="required integer"
        tip_x="required integer"
        title="required pathlist"
        title_music="required path" #maybe list
        tod_bright_image="required path"
        unmoved_ball_image="required path"
        unreachable_image="required path"
        village_income="optional integer"
        #wesnothd_name=
        xp_bar_scaling="required float"
    [/game_config]
    [help]
        _section="repeated section"
        _topic="repeated topic"
        _toplevel="required toplevel"
    [/help]
    [hotkey]
        alt="optional boolean"
        cmd="optional boolean"
        command="required identifier"
        ctrl="optional boolean"
        key="required string"
        shift="optional boolean"
    [/hotkey]
    [lua]
        code="required string"
    [/lua]
    [male:unit_type]
        id="forbidden identifier"
        inherit="optional boolean"
    [/male:unit_type]
    [movetype]
        _defense="required defense"
        _movement_costs="required movement_costs"
        _resistance="required resistance"

        flies="optional boolean"
        name="required identifier"
    [/movetype]
    [partialresolution]
        _add="optional add"
        _change="repeated change"
        _remove="repeated remove"

        height="required integer"
        id="required identifier"
        inherits="required identifier"
        width="required integer"
    [/partialresolution]
    side_of_screen="enum both,left,right"
    [portrait]
        image="required path"
        mirror="optional boolean"
        side="required side_of_screen"
        size="required integer"
    [/portrait]
    [race]
        _trait="repeated trait"

        description="optional tstring"
        female_name="optional tstring"
        female_names="optional tstring"
        id="required identifier"
        ignore_global_traits="optional boolean"
        male_name="optional tstring"
        male_names="optional tstring"
        markov_chain_size="optional integer"
        name="optional tstring"
        num_traits="optional integer" # FIXME: are we sure this is optional?
        plural_name="optional tstring"
    [/race]
    [resolution]
        _label="repeated label-theme"
        _main_map="optional main_map"
        _main_map_border="optional map_map_border"
        _menu="repeated menu"
        _mini_map="optional mini_map"
        _panel="repeated panel"
        #_replay
        #_screen
        _status="optional status"

        height="required integer"
        id="optional identifier"
        inherits="optional identifier"
        width="required integer"
    [/resolution]
    sort_topics_type="enum yes,no,generated,"
    [section]
        generator="optional identifier"
        id="required identifier"
        sections_generator="optional identifier"
        sort_sections="optional boolean"
        sort_topics="optional sort_topics_type"
        title="required tstring"
        topics="optional string" # TODO: list of identifiers
    [/section]
    #[terrain_graphics]
    #    #subtags here
    #
    #    map="optional string"
    #    no_flag="optional string"
    #    probability="
    #[/terrain_graphics]
    [textdomain]
        name="required string"
        path="optional path" # required for UMC, implicit for mainline
    [/textdomain]
    [theme]
        _partialresolution="repeated partialresolution"
        _resolution="repeated resolution"

        name="required string"
    [/theme]
    [topic]
        generator="optional string" #TODO: maybe a special kind of identifier
        id="required string" #TODO: see above
        text="optional tstring"
        title="required tstring"
    [/topic]
    [toplevel]
        sections="required string" #TODO: should be list of identifiers
        topics="required string" #TODO: see above
    [/toplevel]
    [units]
        _movetype="repeated movetype"
        _race="repeated race"
        _trait="repeated trait"
        _unit_type="repeated unit_type"
    [/units]
    alignments="enum chaotic,neutral,lawful"
    [unit_type]
        _abilities="optional abilities"
        _advancement="repeated advancement"
        _animation="repeated animation"
        #.*_anim
        [element]
            freq="repeated"
            match="re ^[a-z_]+_anim$"
            name="animation"
        [/element]
        _attack="repeated attack"
        _death="repeated animation"
        _defend="repeated animation"
        _defense="optional defense"
        _female="optional female"
        _male="optional male"
        _movement_costs="optional movement_costs"
        _portrait="repeated portrait"
        _resistance="optional resistance"
        _trait="repeated trait"
        _variation="repeated variation"

        #TODO: make [base_unit] do its job
        advances_to="optional identifierlist" #should be required
        alignment="optional alignments" # required
        cost="optional integer" # required
        description="optional tstring"
        die_sound="optional pathlist"
        do_not_list="optional boolean"
        ellipse="optional path"
        experience="optional integer" # required
        flag_rgb="optional string" # list of integers
        gender="optional string" # enum male,female
        halo="optional string" # should be animlist: list of imagepaths with animation length
        hide_help="optional boolean"
        hitpoints="optional integer" # required
        id="required identifier"
        ignore_race_traits="optional boolean"
        image="optional path" # required
        level="optional integer" # required
        movement="optional integer" # required
        movement_type="optional identifier" # required
        name="optional tstring" # required
        profile="optional path"
        race="optional identifier" # required
        undead_variation="optional identifier"
        usage="optional identifier" # required
        zoc="optional boolean"
    [/unit_type]
    [variation:unit_type]
        id="forbidden identifier"
        inherit="optional boolean"
        variation_name="required identifier"
    [/variation:unit_type]
[/schema]

## Things that still need to be converted, in a similar format.
## Note that this is derived from the old wmlgrammar, which was incomplete
#
## Attempt to keep everything alphabetically ordered
#[abilities]
#    [ 'heals', 'hides', 'illuminates', 'leadership', 'regenerate', { 'resistance' : 'resistance-ability' }, 'skirmisher', 'teleport', { re.compile('\w+') : 'ability-dummy' }, ]
#    []
#[/abilities]
#[ability-dummy]
#    [], #TODO: the filters and adjacent_description
#    [ 'affect_allies', 'affect_enemies', 'affect_self', 'cumulative', 'description', 'description_inactive', 'female_name', 'female_name_inactive', 'id', 'name', 'name_inactive', ]
#[/ability-dummy]
#[add]
#    'resolution'
#    []
#[/add]
#[advancement]
#    [ 'effect', ]
#    [ 'description', 'id', 'image', 'max_times', 'require_amla', 'strict_amla', ]
#[/advancement]
#[animation]
#    #TODO: add filter, filter_second
#    [ 'filter_attack', 'filter_second_attack', # Filters
#        { 'else' : 'else-animation' }, 'frame',
#{ re.compile('\w+_frame') : 'frame' },
#{ 'if' : 'if-animation' }, ], # The contents
#    [ 'apply_to', 'direction', 'frequency', 'hits', 'swing', 'terrain', 'value', # Filters
#        re.compile('(\w+_)?alpha'), re.compile('(\w+_)?blend_with'), re.compile('(\w+_)?blend_ratio'), re.compile('(\w+_)?halo'), re.compile('(\w+_)?halo_mod'), re.compile('(\w+_)?halo_x'), re.compile('(\w+_)?halo_y'), re.compile('(\w+_)?image_mod'), re.compile('(\w+_)?layer'), re.compile('(\w+_)?offset'), re.compile('(\w+_)?start_time'), re.compile('(\w+_)?submerge'), re.compile('(\w+_)?x'), re.compile('(\w+_)?y'), ] # Frame data, got them from the wiki, I'm assuming these are all valid
#[/animation]
#[attack]
#    [ 'specials', ]
#    [ 'attack_weight', 'damage', 'defense_weight', 'description', 'icon', 'movement_used', 'name', 'number', 'range', 'type', ]
#[/attack]
#[attacks]
#    TagPlus('special-dummy', ([], [ 'add', 'backstab', 'cumulative', 'multiply', 'value', ]) ),
#[/attacks]
#[berserk]
#    TagPlus('special-dummy', ([], [ 'value', ]) ),
#[/berserk]
#[chance_to_hit]
#    TagPlus('special-dummy', ([], [ 'add', 'backstab', 'cumulative', 'multiply', 'value', ]) ),
#[/chance_to_hit]
#[change]
#    []
#    [ 'font_size', 'id', 'image', 'items', 'rect', 'ref', ] #TODO: unfinished
#[/change]
#[color_palette]
#    []
#    [ 'ellipse_red', 'flag_green', 'magenta', ]
#[/color_palette]
#[color_range]
#    []
#    [ 'id', 'name', 'rgb', ]
#[/color_range]
#[damage]
#    TagPlus('special-dummy', ([], [ 'add', 'backstab', 'cumulative', 'multiply', 'value', ]) ),
#[/damage]
#[death]
#    'animation',
#[/death]
#[defend]
#    'animation',
#[/defend]
#[defense]
#    'movement_costs',
#[/defense]
#[drains]
#    'special-dummy',
#[/drains]
#[editor_tool_hint]
#    'gold-theme',
#[/editor_tool_hint]
#[effect]
#    [ 'defense', 'movement_costs', 'resistance', ], #TODO: point tags to where they should go (specials, contents of filter_attack,
#{ set_specials : specials }, abilities)
#    [ 'apply_to', 'times', 'unit_type', re.compile("\w+"), ]
#[/effect]
#[else-animation]
#    'animation',
#[/else-animation]
#[filter_attack]
#    []
#    [ 'name', 'range', 'special', 'type', ]
#[/filter_attack]
#[filter_second_attack]
#    'filter_attack',
#[/filter_second_attack]
#[filter_weapon]
#    'filter_attack',
#[/filter_weapon]
#[firststrike]
#    'special-dummy',
#[/firststrike]
#[frame]
#    []
#    [ 'alpha', 'begin', 'blend_color', 'blend_ratio', 'duration', 'end', 'halo', 'halo_mod', 'halo_x', 'halo_y', 'image', 'image_diagonal', 'image_mod', 'layer', 'offset', 'sound', 'submerge', 'text', 'text_color', 'x', 'y', ]
#[/frame]
#[gold-theme]
#    []
#    [ 'font_rgb', 'font_size', 'id', 'prefix', 'prefix_literal', 'rect', 'ref', 'xanchor', 'yanchor', ]
#[/gold-theme]
#[heals]
#    TagPlus('ability-dummy', ([], [ 'poison', 'value', ]) ),
#[/heals]
#[hides]
#    TagPlus('ability-dummy', ([], [ 'alert', ]) ),
#[/hides]
#[if-animation]
#    'animation',
#[/if-animation]
#[income]
#    'gold-theme',
#[/income]
#[illuminates]
#    TagPlus('ability-dummy', ([], [ 'max_value', 'value', ]) ),
#[/illuminates]
#[image]
#    []
#    [ 'base', 'center', 'layer', 'name', ]
#[/image]
#[label-theme]
#    []
#    [ 'font_rgb', 'font_size', 'icon', 'id', 'image', 'text', 'rect', 'ref', 'xanchor', 'yanchor', ]
#[/label-theme]
#[leadership]
#    TagPlus('ability-dummy', ([], [ 'value', ]) ),
#[/leadership]
#[main_map]
#    []
#    'panel'
#[/main_map]
#[main_map_border]
#    []
#    [ 'background_image', 'border_image_bottom_even', 'border_image_bottom_odd', 'border_image_left', 'border_image_right', 'border_image_top_even', 'border_image_top_odd', 'border_size', 'corner_image_bottom_left', 'corner_image_bottom_right_even', 'corner_image_bottom_right_odd', 'corner_image_top_left','corner_image_top_right_even',  'corner_image_top_right_odd', 'tile_image', ]
#[/main_map_border]
#[menu]
#    []
#    [ 'auto_tooltip', 'id', 'image', 'is_context_menu', 'items', 'title', 'title2', 'tooltip', 'type', 'rect', 'ref', 'xanchor', 'yanchor', ]
#[/menu]
#[mini_map]
#    []
#    'panel'
#[/mini_map]
#[movement_costs]
#    []
#    [ re.compile('\w+'), ]
#[/movement_costs]
#[num_units]
#    'gold-theme',
#[/num_units]
#[observers]
#    'gold-theme',
#[/observers]
#[panel]
#    []
#    [ 'id', 'image', 'rect', 'ref', 'xanchor', 'yanchor', ]
#[/panel]
#[plague]
#    TagPlus('special-dummy', ( [], [ 'type', ] ) ),
#[/plague]
#[poison]
#    'special-dummy',
#[/poison]
#[position]
#    'gold-theme',
#[/position]
#[regenerate]
#    TagPlus('ability-dummy', ([], [ 'poison', 'value', ]) ),
#[/regenerate]
#[remove]
#    []
#    [ 'id', ]
#[/remove]
#[replay]
#    'partialresolution'
#    []
#[/replay]
#[report_clock]
#    'gold-theme',
#[/report_clock]
#[report_countdown]
#    'gold-theme',
#[/report_countdown]
#[resistance-ability]
#    TagPlus('ability-dummy', ([], [ 'active_on', 'add', 'apply_to', 'max_value', 'multiply', 'value', ]) ),
#[/resistance-ability]
#[resistance]
#    []
#    [ re.compile('\w+'), ]
#[/resistance]
#[screen]
#    []
#    [ 'id', 'rect' ]
#[/screen]
#[server]
#    []
#    [ 'address', 'name', ]
#[/server]
#[side_playing]
#    []
#    [ 'id', 'rect', 'ref', 'xanchor', 'yanchor', ]
#[/side_playing]
#[skirmisher]
#    'ability-dummy',
#[/skirmisher]
#[slow]
#    'special-dummy',
#[/slow]
#[special-dummy]
#    [] #TODO: filters
#    [ 'active_on', 'apply_to', 'description', 'description_inactive', 'id', 'name', 'name_inactive', ]
#[/special-dummy]
#[specials]
#    [ 'attacks', 'berserk', 'chance_to_hit', 'damage', 'drains', 'firststrike', 'plague', 'poison', 'slow', 'petrifies', 'swarm', { re.compile('\w+') : 'special-dummy' }, ]
##TODO: add the rest of them
#    []
#[/specials]
#[status]
#    [ 'editor_tool_hint', { 'gold' : 'gold-theme' }, 'income', 'num_units', 'observers', 'panel', 'position', 'report_clock', 'report_countdown', 'side_playing',
#{ 'terrain' : 'terrain-theme' }, 'time_of_day', 'turn', 'unit_abilities', 'unit_advancement_options', 'unit_alignment', 'unit_amla', 'unit_hp', 'unit_image', 'unit_level', 'unit_moves', 'unit_name', 'unit_race', 'unit_side', 'unit_status', 'unit_traits',
#{ 'unit_type' : 'unit_type-theme' } , 'unit_weapons', 'unit_xp', 'upkeep', 'villages', ]
#    []
#[/status]
#[petrifies]
#    'special-dummy',
#[/petrifies]
#[swarm]
#    TagPlus('special-dummy', ([], ['swarm_attacks_min', 'swarm_attacks_max',]) ),
#[/swarm]
#[teleport]
#    'ability-dummy',
#[/teleport]
#[terrain_type]
#    []
#    [ 'aliasof', 'default_base', 'def_alias', 'description', 'editor_group', 'editor_image', 'gives_income', 'heals', 'hidden', 'id', 'light', 'mvt_alias', 'name', 'recruit_from', 'recruit_onto', 'string', 'submerge', 'symbol_image', 'unit_height_adjust', ]
#[/terrain_type]
#[terrain-theme]
#    'gold-theme',
#[/terrain-theme]
#[tile]
#    [ 'image', ]
#    [ 'no_flag', 'pos', 'set_flag', 'type', 'x', 'y', ]
#[/tile]
#[time_of_day]
#    'side_playing',
#[/time_of_day]
#[trait]
#    [ 'effect', ]
#    [ 'availability', 'description', 'female_name', 'id', 'male_name', 'name', ]
#[/trait]
#[turn]
#    'gold-theme',
#[/turn]
#[unit_abilities]
#    'gold-theme',
#[/unit_abilities]
#[unit_advancement_options]
#    'gold-theme',
#[/unit_advancement_options]
#[unit_alignment]
#    'gold-theme',
#[/unit_alignment]
#[unit_amla]
#    'gold-theme',
#[/unit_amla]
#[unit_hp]
#    'gold-theme',
#[/unit_hp]
#[unit_image]
#    'gold-theme',
#[/unit_image]
#[unit_level]
#    'gold-theme',
#[/unit_level]
#[unit_moves]
#    'gold-theme',
#[/unit_moves]
#[unit_name]
#    'gold-theme',
#[/unit_name]
#[unit_race]
#    'gold-theme',
#[/unit_race]
#[unit_side]
#    'gold-theme',
#[/unit_side]
#[unit_status]
#    'gold-theme',
#[/unit_status]
#[unit_traits]
#    'gold-theme',
#[/unit_traits]
#[unit_type-theme]
#    'gold-theme',
#[/unit_type-theme]
#[unit_weapons]
#    'gold-theme',
#[/unit_weapons]
#[unit_xp]
#    'gold-theme',
#[/unit_xp]
#[villages]
#    'gold-theme',
#[/villages]
#[upkeep]
#    'gold-theme',
#[/upkeep]
