diff --git a/data/schema/ai/_main.cfg b/data/schema/ai/_main.cfg index 56ddd4f8ff7c..08d92b855534 100644 --- a/data/schema/ai/_main.cfg +++ b/data/schema/ai/_main.cfg @@ -51,4 +51,5 @@ {./recruitment.cfg} {./goal.cfg} {./stage.cfg} + {./modify.cfg} [/tag] diff --git a/data/schema/ai/aspect_complex.cfg b/data/schema/ai/aspect_complex.cfg index 28959df6f2e9..687c22e1f5ee 100644 --- a/data/schema/ai/aspect_complex.cfg +++ b/data/schema/ai/aspect_complex.cfg @@ -120,21 +120,23 @@ max=infinite {AI_ASPECT_INVALIDATE} [if] - {AI_ASPECT_FILTER_STANDARD} + # Check for composite first so that you can have a composite_aspect with id=attacks + {AI_ASPECT_FILTER_COMPOSITE} + {AI_ASPECT_FILTER_DEFAULT} [then] - {AI_ASPECT_SWITCH $ai/standard_aspect} + {AI_ASPECT_SWITCH $ai/composite_aspect} [/then] [elseif] - {AI_ASPECT_FILTER_COMPOSITE} - {AI_ASPECT_FILTER_DEFAULT} + # Check for attacks next so that you can't have standard_aspect with id=attacks + {AI_ASPECT_FILTER_ATTACKS} [then] - {AI_ASPECT_SWITCH $ai/composite_aspect} + super="$ai/facet~attacks" [/then] [/elseif] [elseif] - {AI_ASPECT_FILTER_ATTACKS} + {AI_ASPECT_FILTER_STANDARD} [then] - super="$ai/facet~attacks" + {AI_ASPECT_SWITCH $ai/standard_aspect} [/then] [/elseif] [elseif] diff --git a/data/schema/ai/modify.cfg b/data/schema/ai/modify.cfg new file mode 100644 index 000000000000..bfb80c0baa2e --- /dev/null +++ b/data/schema/ai/modify.cfg @@ -0,0 +1,146 @@ + +#define AI_MODIFY_MATCH_ASPECT ASPECT TYPE + [elseif] + glob_on_path=aspect[{ASPECT}] + [then] + [tag] + name="aspect" + [if] + # This is the best way we have to proscribe a particular value: + # If it's any other value, the tag must not contain what it's supposed to. + id={ASPECT} + [or] + {AI_FILTER_KEY_MISSING id} + [/or] + [then] + super="$ai/$component" + {AI_ASPECT_INVALIDATE} + [if] + {AI_ASPECT_FILTER_COMPOSITE} + {AI_ASPECT_FILTER_DEFAULT} + [then] + super="$ai/composite_aspect~{TYPE}" + [/then] + [elseif] + # Check for attacks next so that you can't have standard_aspect with id=attacks + {AI_ASPECT_FILTER_ATTACKS} + [then] + super="$ai/facet~attacks" + [/then] + [/elseif] + [elseif] + {AI_ASPECT_FILTER_STANDARD} + [then] + super="$ai/standard_aspect~{TYPE}" + [/then] + [/elseif] + [elseif] + {AI_ASPECT_FILTER_LUA} + [then] + super="$ai/facet~lua" + [/then] + [/elseif] + # TODO: Somehow give an error for any other combination + [/if] + [/then] + [/if] + [/tag] + [/then] + [/elseif] + [elseif] + glob_on_path=aspect[{ASPECT}]*.facet[*] + # Glob isn't good enough to verify that these are really just a chain of facets + # Combined with the regex type validation on path though, it should be good enough + [then] + [tag] + name="facet" + super="$ai/facet~{TYPE}" + [/tag] + [/then] + [/elseif] +#enddef + +[tag] + name="modify_ai" + super="$filter_side" + {SIMPLE_KEY action ai_modify_action} + {SIMPLE_KEY path ai_modify_path} + [if] + action=delete + [or] + action=try_delete + [/or] + # Nothing extra for deleting components + [elseif] + glob_on_path=goal[*] + [then] + [tag] + name="goal" + super="$ai/goal" + [/tag] + [/then] + [/elseif] + [elseif] + glob_on_path=stage[*].candidate_action[*] + [then] + [tag] + name="candidate_action" + super="$ai/$candidate_action" + [/tag] + [/then] + [/elseif] + [elseif] + glob_on_path=stage[*] + [then] + [tag] + name="stage" + super="$ai/stage" + [/tag] + [/then] + [/elseif] + # Recruitment jobs before aspects because some could also be matched by the facet globs + [elseif] + glob_on_path=aspect[recruitment_instructions]*.recruit[*] + [then] + [tag] + name="recruit" + super="$ai/$recruit" + [/tag] + [/then] + [/elseif] + [elseif] + glob_on_path=aspect[recruitment_instructions]*.limit[*] + [then] + [tag] + name="limit" + super="$ai/$recruit_limit" + [/tag] + [/then] + [/elseif] + # Okay, now the hard part. Basically need two entries for every possible type of aspect! + {AI_MODIFY_MATCH_ASPECT aggression real} + {AI_MODIFY_MATCH_ASPECT caution real} + {AI_MODIFY_MATCH_ASPECT leader_aggression real} + {AI_MODIFY_MATCH_ASPECT scout_village_targeting real} + {AI_MODIFY_MATCH_ASPECT village_value real} + {AI_MODIFY_MATCH_ASPECT recruitment_diversity real} + {AI_MODIFY_MATCH_ASPECT leader_ignores_keep bool} + {AI_MODIFY_MATCH_ASPECT passive_leader bool} + {AI_MODIFY_MATCH_ASPECT passive_leader_shares_keep bool} + {AI_MODIFY_MATCH_ASPECT simple_targeting bool} + {AI_MODIFY_MATCH_ASPECT support_villages bool} + {AI_MODIFY_MATCH_ASPECT villages_per_scout int} + {AI_MODIFY_MATCH_ASPECT attack_depth int} + {AI_MODIFY_MATCH_ASPECT recruitment_randomness int} + {AI_MODIFY_MATCH_ASPECT grouping ai_grouping} + {AI_MODIFY_MATCH_ASPECT advancements string_list} + {AI_MODIFY_MATCH_ASPECT recruitment_more string_list} + {AI_MODIFY_MATCH_ASPECT recruitment_pattern string_list} + {AI_MODIFY_MATCH_ASPECT avoid avoid} + {AI_MODIFY_MATCH_ASPECT leader_goal leader_goal} + {AI_MODIFY_MATCH_ASPECT recruitment_instructions recruitment_instructions} + {AI_MODIFY_MATCH_ASPECT recruitment_save_gold recruitment_save_gold} + {AI_MODIFY_MATCH_ASPECT attacks attacks} + [/if] +[/tag] + \ No newline at end of file diff --git a/data/schema/game_config.cfg b/data/schema/game_config.cfg index 25c2bf0fe2af..e2dcdfab8807 100644 --- a/data/schema/game_config.cfg +++ b/data/schema/game_config.cfg @@ -182,6 +182,26 @@ name="ai_ca_formula_type" value="movement|attack" [/type] + [type] + name="ai_modify_action" + value="add|change|(try_)?delete" + [/type] + [type] + name="ai_modify_path" + # This only does some very basic validation and accepts quite a few invalid values. + # For example, only aspect[recruitment_instructions] can have a .recruit or .limit suffix. + [union] + [type] + value="aspect\[([a-zA-Z0-9_]+|\*)?\](\.facet\[([a-zA-Z0-9_]+|\*)?\])*(\.(recruit|limit)\[([a-zA-Z0-9_]+|\*)?\])?" + [/type] + [type] + value="goal\[([a-zA-Z0-9_]+|\*)?\]" + [/type] + [type] + value="stage\[([a-zA-Z0-9_]+|\*)?\](\.candidate_action\[([a-zA-Z0-9_]+|\*)?\])?" + [/type] + [/union] + [/type] [tag] name="root" min=1