diff --git a/data/schema/ai/_main.cfg b/data/schema/ai/_main.cfg new file mode 100644 index 000000000000..b734d85c40c8 --- /dev/null +++ b/data/schema/ai/_main.cfg @@ -0,0 +1,53 @@ + +#define AI_ASPECT_FILTERS + {SIMPLE_KEY turns range_list} + {SIMPLE_KEY time_of_day string_list} +#enddef + +#define AI_ASPECT_INVALIDATE + {SIMPLE_KEY invalidate_on_* bool} +#enddef + +[tag] + name="ais" + min=1 + [tag] + name="ai" + max=infinite + super="$ai" + {REQUIRED_KEY id string} + {SIMPLE_KEY name t_string} + {SIMPLE_KEY description t_string} + {DEFAULT_KEY hidden bool no} + [/tag] + [tag] + name="default_config" + min=1 + [link] + name="$ai/aspect" + [/link] + [/tag] +[/tag] + +[tag] + name="$ai" + max=0 + {SIMPLE_KEY ai_algorithm string} + [tag] + name="$component" + {SIMPLE_KEY id string} + {SIMPLE_KEY name string} + {SIMPLE_KEY engine ai_engine} + [/tag] + [tag] + name="$generic_lua_component" + engine=lua + {SIMPLE_KEY code string} + {DATA_TAG args 0 1} + [/tag] + {./engine.cfg} + {./aspect_complex.cfg} + {./aspect_simple.cfg} + {./goal.cfg} + {./stage.cfg} +[/tag] diff --git a/data/schema/ai/aspect_complex.cfg b/data/schema/ai/aspect_complex.cfg new file mode 100644 index 000000000000..643619eaa0a3 --- /dev/null +++ b/data/schema/ai/aspect_complex.cfg @@ -0,0 +1,293 @@ + +#define AI_ASPECT_FILTER_STANDARD + engine=cpp + name=standard_aspect + [or] + engine= + name=standard_aspect + [/or] +#enddef + +#define AI_ASPECT_FILTER_COMPOSITE + engine=cpp + name=composite_aspect + [or] + engine= + name=composite_aspect + [/or] +#enddef + +#define AI_ASPECT_FILTER_DEFAULT + [or] + engine=cpp + name= + [/or] +#enddef + +#define AI_ASPECT_FILTER_ATTACKS + engine=cpp + name=ai_default_rca::aspect_attacks + id=attacks + [or] + engine= + name=ai_default_rca::aspect_attacks + id=attacks + [/or] + [or] + engine=cpp + name= + id=attacks + [/or] + [or] + engine= + name= + id=attacks + [/or] +#enddef + +#define AI_ASPECT_FILTER_LUA + engine=lua + name=lua_aspect + [or] + engine=lua + name= + [/or] + [or] + engine= + name=lua_aspect + [/or] +#enddef + +#define AI_ASPECT_SWITCH BASE + [switch] + key=id + [case] + value=aggression,caution,leader_aggression,leader_value,scout_village_targeting,village_value,recruitment_diversity + super="{BASE}~real" + [/case] + [case] + value=leader_ignores_keep,passive_leader,passive_leader_shares_keep,simple_targeting,support_villages + super="{BASE}~bool" + [/case] + [case] + value=villages_per_scout,attack_depth,recruitment_randomness + super="{BASE}~int" + [/case] + [case] + value=grouping + super="{BASE}~ai_grouping" + [/case] + [case] + value=advancements,recruitment_more,recruitment_pattern + super="{BASE}~string_list" + [/case] + [case] + value=avoid + super="{BASE}~avoid" + [/case] + [case] + value=leader_goal + super="{BASE}~leader_goal" + [/case] + [case] + value=recruitment_instructions + super="{BASE}~recruitment_instructions" + [/case] + [case] + value=recruitment_save_gold + super="{BASE}~recruitment_save_gold" + [/case] + [/switch] +#enddef + +[tag] + name="aspect" + super="$ai/$component" + {AI_ASPECT_INVALIDATE} + [if] + {AI_ASPECT_FILTER_STANDARD} + [then] + {AI_ASPECT_SWITCH $ai/standard_aspect} + [/then] + [elseif] + {AI_ASPECT_FILTER_COMPOSITE} + {AI_ASPECT_FILTER_DEFAULT} + [then] + {AI_ASPECT_SWITCH $ai/composite_aspect} + [/then] + [/elseif] + [elseif] + {AI_ASPECT_FILTER_ATTACKS} + [then] + super="$ai/facet~attacks" + [/then] + [/elseif] + [elseif] + {AI_ASPECT_FILTER_LUA} + [then] + super="$ai/facet~lua" + [/then] + [/elseif] + # TODO: Somehow give an error for any other combination + [/if] +[/tag] + +[tag] + name="$facet_base" + super="$ai/$component" + {AI_ASPECT_INVALIDATE} + {AI_ASPECT_FILTERS} +[/tag] + +[tag] + name="facet~lua" + super="$ai/$generic_lua_component" + {SIMPLE_KEY value string} +[/tag] + +#define AI_ASPECT NAME VALUE + [tag] + # This defines the valid content of an aspect with name=standard_aspect + # and the specified ID + name="standard_aspect~{NAME}" + {VALUE} + [/tag] + [tag] + # This defines the valid content of an aspect with name=composite_aspect + # and the specified ID + name="composite_aspect~{NAME}" + [tag] + name="facet" + max=infinite + super="$ai/facet~{NAME}" + [/tag] + [tag] + name="default" + super="$ai/facet~{NAME}" + [/tag] + [/tag] +#enddef + +#define AI_FACET NAME VALUE + {AI_ASPECT {NAME} {VALUE}} + [tag] + name="facet~{NAME}" + super="$ai/$facet_base" + [if] + {AI_ASPECT_FILTER_STANDARD} + {AI_ASPECT_FILTER_DEFAULT} + [then] + super="$ai/standard_aspect~{NAME}" + [/then] + [elseif] + {AI_ASPECT_FILTER_COMPOSITE} + [then] + super="$ai/composite_aspect~{NAME}" + [/then] + [/elseif] + [elseif] + {AI_ASPECT_FILTER_LUA} + [then] + super="$ai/facet~lua" + [/then] + [/elseif] + [else] + # This required key is just a hack to get an error here. + # It's not actually valid. + {REQUIRED_KEY invalid_engine_name_combo_in_aspect bool} + [/else] + [/if] + [/tag] +#enddef + +#define AI_FACET_SCALAR TYPE + {AI_FACET {TYPE} {SIMPLE_KEY value {TYPE}}} +#enddef + +#define AI_FACET_TAG TAG CONTENTS + {AI_FACET {TAG} ( + [tag] + name="value" + {CONTENTS} + [/tag] + )} +#enddef + +{AI_FACET_SCALAR real} +{AI_FACET_SCALAR int} +{AI_FACET_SCALAR bool} +{AI_FACET_SCALAR string_list} +{AI_FACET_SCALAR ai_grouping} +{AI_FACET avoid {FILTER_TAG value location ()}} + +{AI_FACET_TAG leader_goal ( + {SIMPLE_KEY x int} + {SIMPLE_KEY y int} + {SIMPLE_KEY max_risk real} + {SIMPLE_KEY auto_remove bool} +)} + +{AI_FACET_TAG recruitment_save_gold ( + {SIMPLE_KEY active int} + {SIMPLE_KEY begin real} + {SIMPLE_KEY end real} + {SIMPLE_KEY spend_all_gold int} + {SIMPLE_KEY save_on_negative_income bool} +)} + +{AI_FACET_TAG recruitment_instructions ( + [tag] + name="recruit" + max=infinite + super="$ai/$recruit" + [/tag] + [tag] + name="total" + max=infinite + super="$ai/$recruit_base" + [/tag] + [tag] + name="pattern" + max=infinite + super="$ai/$recruit_base" + [/tag] + [tag] + name="limit" + max=infinite + super="$ai/$recruit_limit" + [/tag] +)} + +{AI_ASPECT attacks ( + {FILTER_TAG filter_own unit ()} + {FILTER_TAG filter_enemy unit ()} +)} + +[tag] + name="facet~attacks" + super="$ai/$facet_base" + [if] + {AI_ASPECT_FILTER_ATTACKS} + {AI_ASPECT_FILTER_DEFAULT} + [then] + super="$ai/standard_aspect~attacks" + [/then] + [elseif] + {AI_ASPECT_FILTER_COMPOSITE} + [then] + super="$ai/composite_aspect~attacks" + [/then] + [/elseif] + [elseif] + {AI_ASPECT_FILTER_LUA} + [then] + super="$ai/facet~lua" + [/then] + [/elseif] + [else] + # This required key is just a hack to get an error here. + # It's not actually valid. + {REQUIRED_KEY invalid_engine_name_combo_in_aspect bool} + [/else] + [/if] +[/tag] diff --git a/data/schema/ai/aspect_simple.cfg b/data/schema/ai/aspect_simple.cfg new file mode 100644 index 000000000000..bc6ca32839a5 --- /dev/null +++ b/data/schema/ai/aspect_simple.cfg @@ -0,0 +1,71 @@ + +#define AI_ASPECT_KEY NAME TYPE + {SIMPLE_KEY {NAME} {TYPE}} + [tag] + name={NAME} + {SIMPLE_KEY value {TYPE}} + {SIMPLE_KEY id string} + {SIMPLE_KEY engine string} + {AI_ASPECT_FILTERS} + {AI_ASPECT_INVALIDATE} + [/tag] +#enddef + +#define AI_ASPECT_TAG NAME CONTENTS + [tag] + name={NAME} + [if] + [value] + [/value] + [then] + {SIMPLE_KEY id string} + {SIMPLE_KEY engine string} + {AI_ASPECT_FILTERS} + {AI_ASPECT_INVALIDATE} + [tag] + name="value" + {CONTENTS} + [/tag] + [/then] + [else] + {CONTENTS} + [/else] + [/if] + [/tag] +#enddef + +# Filter keys for simple aspects +{AI_ASPECT_FILTERS} +{SIMPLE_KEY engine string} +# Simple scalar aspects +{AI_ASPECT_KEY aggression real} +{AI_ASPECT_KEY caution real} +{AI_ASPECT_KEY grouping ai_grouping} +{AI_ASPECT_KEY leader_aggression real} +{AI_ASPECT_KEY leader_ignores_keep bool} +{AI_ASPECT_KEY leader_value real} +{AI_ASPECT_KEY passive_leader bool} +{AI_ASPECT_KEY passive_leader_shares_keep bool} +{AI_ASPECT_KEY recruitment_diversity real} +{AI_ASPECT_KEY recruitment_randomness int} +{AI_ASPECT_KEY scout_village_targeting real} +{AI_ASPECT_KEY simple_targeting bool} +{AI_ASPECT_KEY support_villages bool} +{AI_ASPECT_KEY village_value real} +{AI_ASPECT_KEY villages_per_scout int} +{AI_ASPECT_KEY attack_depth int} +{AI_ASPECT_KEY advancements string_list} +{AI_ASPECT_KEY recruitment_more string_list} +{AI_ASPECT_KEY recruitment_pattern string_list} + +# Simple non-scalar aspects +{AI_ASPECT_TAG leader_goal super="$ai/standard_aspect~leader_goal/value"} +{AI_ASPECT_TAG recruitment_instructions super="$ai/standard_aspect~recruitment_instructions/value"} +{AI_ASPECT_TAG recruitment_save_gold super="$ai/standard_aspect~recruitment_save_gold/value"} +{AI_ASPECT_TAG avoid super="$ai/standard_aspect~avoid/value"} + +# Attacks is nice in that it doesn't have the doubly-simplified form! +[tag] + name="attacks" + super="$ai/standard_aspect~attacks" +[/tag] diff --git a/data/schema/ai/engine.cfg b/data/schema/ai/engine.cfg new file mode 100644 index 000000000000..aac034f27236 --- /dev/null +++ b/data/schema/ai/engine.cfg @@ -0,0 +1,26 @@ + +[tag] + name="engine" + super="$ai/$component" + [switch] + key=engine + [case] + value=fai + # TODO: FIll this in (which is difficult since it's not documented) + # I think some kind of variables tag is permitted here? + [tag] + name="function" + max=infinite + {SIMPLE_KEY name string} + {SIMPLE_KEY inputs string_list} + {SIMPLE_KEY formula formula} + {SIMPLE_KEY precondition formula} + [/tag] + [/case] + [case] + value=lua + super="$ai/$generic_lua_component" + [/case] + # Nothing special for cpp engine so just leave it out + [/switch] +[/tag] diff --git a/data/schema/ai/goal.cfg b/data/schema/ai/goal.cfg new file mode 100644 index 000000000000..0162e36cf3aa --- /dev/null +++ b/data/schema/ai/goal.cfg @@ -0,0 +1,52 @@ + +[tag] + name="goal" + super="$component" + {SIMPLE_KEY value real} + [if] + engine=lua + [else] + [switch] + key=name + [case] + value=target,target_unit + {FILTER_TAG criteria unit ()} + [/case] + [case] + value=target_location + {FILTER_TAG criteria location ()} + [/case] + [case] + value=protect_unit,protect_my_unit + {FILTER_TAG criteria unit ()} + {SIMPLE_KEY protect_radius int} + [/case] + [case] + value=protect_location + {FILTER_TAG criteria location ()} + {SIMPLE_KEY protect_radius int} + [/case] + [/switch] + [/else] + [/if] +[/tag] + +# Deprecated versions +{FILTER_TAG target unit ( + deprecated=yes + {SIMPLE_KEY value real} +)} +{FILTER_TAG target_location location ( + deprecated=yes + {SIMPLE_KEY value real} +)} +{FILTER_TAG protect_unit unit ( + deprecated=yes + {SIMPLE_KEY value real} + {SIMPLE_KEY protect_radius int} +)} +{FILTER_TAG protect_location location ( + deprecated=yes + {SIMPLE_KEY value real} + {SIMPLE_KEY protect_radius int} +)} diff --git a/data/schema/ai/recruitment.cfg b/data/schema/ai/recruitment.cfg new file mode 100644 index 000000000000..29b0f387e217 --- /dev/null +++ b/data/schema/ai/recruitment.cfg @@ -0,0 +1,24 @@ + +[tag] + name="$recruit_base" + super="$ai/$component" + {SIMPLE_KEY type string} + {SIMPLE_KEY number int} + {SIMPLE_KEY importance int} + {SIMPLE_KEY leader_id string} + {SIMPLE_KEY blocker bool} +[/tag] + +[tag] + name="$recruit" + super="$ai/$recruit_base" + {SIMPLE_KEY total bool} + {SIMPLE_KEY pattern bool} +[/tag] + +[tag] + name="$recruit_limit" + super="$ai/$component" + {SIMPLE_KEY type string} + {SIMPLE_KEY max int} +[/tag] diff --git a/data/schema/ai/stage.cfg b/data/schema/ai/stage.cfg new file mode 100644 index 000000000000..31f4b9bb77be --- /dev/null +++ b/data/schema/ai/stage.cfg @@ -0,0 +1,73 @@ + +[tag] + name="stage" + super="$ai/$component" + [switch] + key=engine + [else] + # TODO: This should really be a case that also matches if the key is absent + #value=cpp + [if] + name=ai_default_rca::candidate_action_evaluation_loop + [then] + [tag] + name="candidate_action" + super="$ai/$candidate_action" + max=infinite + [/tag] + [/then] + # TODO: Somehow give an error if name is present with any other value + [/if] + [/else] + [case] + value=lua + super="$ai/$generic_lua_component" + [/case] + [case] + value=fai + [switch] + key=name + [case] + value=side_formulas + {SIMPLE_KEY move formula} + [/case] + [case] + value=unit_formulas + [/case] + # TODO: Somehow give an error if name has any other value + [/switch] + [/case] + [/switch] +[/tag] + +[tag] + name="$candidate_action" + super="$ai/$component" + [switch] + key=engine + [case] + value=lua + {SIMPLE_KEY max_score int} + {SIMPLE_KEY location string} + {SIMPLE_KEY evaluation string} + {SIMPLE_KEY execution string} + [/case] + [case] + value=cpp + {SIMPLE_KEY score int} + {SIMPLE_KEY max_score int} + [/case] + [case] + value=fai + {SIMPLE_KEY type ai_ca_formula_type} + {SIMPLE_KEY evaluation formula} + {SIMPLE_KEY action formula} + [tag] + name="filter" + {SIMPLE_KEY me formula} + {SIMPLE_KEY target formula} + [/tag] + # TODO: Filters, variables + [/case] + [/switch] +[/tag] \ No newline at end of file diff --git a/data/schema/core/addons.cfg b/data/schema/core/addons.cfg index ca1e1b75affa..2ab556603fd0 100644 --- a/data/schema/core/addons.cfg +++ b/data/schema/core/addons.cfg @@ -78,7 +78,7 @@ [tag] name="ai" max=infinite - super="$ai" + super="ais/ai" [/tag] {DEFAULT_KEY allow_player bool yes} diff --git a/data/schema/core/ai.cfg b/data/schema/core/ai.cfg deleted file mode 100644 index bc5e55d91040..000000000000 --- a/data/schema/core/ai.cfg +++ /dev/null @@ -1,28 +0,0 @@ - -[tag] - name="ais" - min=1 - [tag] - name="ai" - max=infinite - super="$ai" - {REQUIRED_KEY id string} - {SIMPLE_KEY name t_string} - {SIMPLE_KEY description t_string} - [/tag] - [tag] - name="default_config" - min=1 - any_tag=yes - {ANY_KEY string} - [/tag] -[/tag] - -[tag] - name="$ai" - max=0 - # TODO: Encode all the aspects and such properly - # This requires some switch work, so putting it off - any_tag=yes - {ANY_KEY string} -[/tag] diff --git a/data/schema/game_config.cfg b/data/schema/game_config.cfg index 25b6bb09ae02..25c2bf0fe2af 100644 --- a/data/schema/game_config.cfg +++ b/data/schema/game_config.cfg @@ -170,11 +170,24 @@ name="effect_set_special_mode" value="append|replace" [/type] + [type] + name="ai_grouping" + value="offensive|defensive|no" + [/type] + [type] + name="ai_engine" + value="cpp|lua|fai" + [/type] + [type] + name="ai_ca_formula_type" + value="movement|attack" + [/type] [tag] name="root" min=1 {./filters} {./core} + {./ai} {./units} {./terrain} {./editor}