#textdomain wesnoth-ai #define HOME_GUARDIAN X Y # Meant to be used as a suffix to a unit-generating macro call. # The previously-generated unit will treat (X,Y) as its home. [+unit] [ai] [vars] home_loc="loc({X},{Y})" [/vars] [/ai] [/unit] #enddef [test] id=guardians name= _ "Guardians" next_scenario=micro_ai_test map_data="{/multiplayer/maps/4p_Paths_of_Daggers.map}" {DEFAULT_SCHEDULE} turns=-1 victory_when_enemies_defeated=no [side] side=1 controller=human id=Kraa name= _ "Kraa" unrenamable=yes type=Gryphon x,y=3,5 team_name=gryphons user_team_name=_"Gryphons" recruit=Gryphon persistent=no gold=200 [/side] # Guardians [side] side=2 type=Orcish Leader id=Another Bad Orc name= _ "Another Bad Orc" x,y=33,24 canrecruit=yes recruit=Orcish Archer,Orcish Grunt persistent=no gold=30 [ai] [modify_ai] side=1 action=add # wmllint: unbalanced-on path=stage[main_loop].candidate_action[] # wmllint: unbalanced-off [candidate_action] engine=fai name=go_home id=go_home type=movement # wmlindent: start ignoring evaluation="if( (null != me.vars.home_loc), {AI_CA_MOVE_TO_TARGETS_SCORE}+10, 0)" action="if( (me.loc != me.vars.home_loc), move(me.loc, next_hop(me.loc, me.vars.home_loc)), move(me.loc, me.loc)#do not move this turn#)" # wmlindent: stop ignoring [/candidate_action] [/modify_ai] [/ai] [/side] # Put all the units and markers out there [event] name=prestart {VARIABLE scenario_name guardians} {PLACE_IMAGE "scenery/signpost.png" 1 6} {SET_LABEL 1 6 _"End Scenario"} # A couple gryphons {GENERIC_UNIT 1 Gryphon 4 6} {GENERIC_UNIT 1 Gryphon 5 4} # The normal guardians [unit] type=Dwarvish Guardsman side=2 id=guardian1 name= _ "Guardian 1" x,y=12,1 ai_special=guardian [variables] label="ai_special=guardian" [/variables] [/unit] [unit] type=Dwarvish Guardsman side=2 id=guardian2 name= _ "Guardian 2" x,y=15,1 ai_special=guardian [variables] label="ai_special=guardian" [/variables] [/unit] # The cowards [unit] type=Giant Rat side=2 id=coward1 name= _ "Coward 1" x,y=14,21 [modifications] {TRAIT_QUICK} [/modifications] [variables] label="coward r=5" [/variables] [/unit] [micro_ai] side=2 ai_type=coward action=add id=coward1 distance=5 [/micro_ai] [unit] type=Giant Rat side=2 id=coward2 name= _ "Coward 2" x,y=16,21 [modifications] {TRAIT_QUICK} [/modifications] [variables] label="coward r=5 s=24 5" [/variables] [/unit] [micro_ai] side=2 ai_type=coward action=add id=coward2 distance=5 seek_x,seek_y=24,5 [/micro_ai] [unit] type=Giant Rat side=2 id=coward3 name= _ "Coward 3" x,y=18,21 [modifications] {TRAIT_QUICK} [/modifications] [variables] label=" coward r=5 s=24,5 a=24,15" [/variables] [/unit] [micro_ai] side=2 ai_type=coward action=add id=coward3 distance=5 seek_x,seek_y=24,5 avoid_x,avoid_y=24,15 [/micro_ai] [unit] type=Giant Rat side=2 id=coward4 name= _ "Coward 4" x,y=12,21 [modifications] {TRAIT_QUICK} [/modifications] [variables] label="coward r=5 s=32,--" [/variables] [/unit] [micro_ai] side=2 ai_type=coward action=add id=coward4 distance=4 seek_x=32 [/micro_ai] {SET_LABEL 15 19 _"Move gryphons here to see different coward reactions"} {PLACE_IMAGE "items/gohere.png" 13 20} {PLACE_IMAGE "items/gohere.png" 17 20} # The return guardians [unit] type=Troll side=2 id=return1 name= _ "Return Guardian 1" x,y=20,2 [variables] label="return 20,2" [/variables] [/unit] [micro_ai] side=2 ai_type=return_guardian action=add id=return1 return_x,return_y=20,2 [/micro_ai] [unit] type=Troll Whelp side=2 id=return2 name= _ "Return Guardian 2" x,y=21,9 [variables] label="return 21,9" [/variables] [/unit] [micro_ai] side=2 ai_type=return_guardian action=add id=return2 return_x,return_y=21,9 [/micro_ai] # The home guards [unit] type=Troll Whelp side=2 id=home1 name= _ "Home Guard 1" x,y=19,2 [variables] label="home 19,2" [/variables] [/unit] {HOME_GUARDIAN 19 2} [unit] type=Troll side=2 id=home 2 name= _ "Home Guard 2" x,y=21,10 [variables] label="home 21,10" [/variables] [/unit] {HOME_GUARDIAN 21 10} # The stationed guardians [unit] type=Skeleton Archer side=2 id=stationed1 name= _ "Stationed Guardian 1" x,y=1,12 [variables] label=" stationed r=4 s=2,14 g=3,13" [/variables] [/unit] [micro_ai] side=2 ai_type=stationed_guardian action=add id=stationed1 distance=4 station_x,station_y=2,14 guard_x,guard_y=3,13 [/micro_ai] [unit] type=Skeleton side=2 id=stationed2 name= _ "Stationed Guardian 2" x,y=6,14 [variables] label=" stationed r=4 s=4,14 g=7,13" [/variables] [/unit] [micro_ai] side=2 ai_type=stationed_guardian action=add id=stationed2 distance=4 station_x,station_y=4,14 guard_x,guard_y=3,13 [/micro_ai] # Zone guardians [unit] type=Troll side=2 id=zone1 name= _ "Gate Keeper" x,y=5,25 [modifications] {TRAIT_STRONG} [/modifications] [variables] label="Zone Guard" [/variables] [/unit] [micro_ai] side=2 ai_type=zone_guardian action=add id=zone1 [filter_location] x=4,5,6,7,5 y=24,24,24,24,25 [/filter_location] [/micro_ai] [unit] type=Dwarvish Guardsman side=2 id=zone2 name= _ "Home Keeper" x,y=2,27 [modifications] {TRAIT_STRONG} [/modifications] [variables] label="Zone Guard with separate attack Zone" [/variables] [/unit] [micro_ai] side=2 ai_type=zone_guardian action=add id=zone2 [filter_location] x=1,2,3,2 y=27,27,27,26 [/filter_location] [filter_location_enemy] x,y=1-4,24-27 [/filter_location_enemy] [/micro_ai] [unit] type=Naga Fighter side=2 id=zone3 name= _ "Water Guardian" x,y=29,8 [variables] label="Zone Guard" [/variables] [/unit] [micro_ai] side=2 ai_type=zone_guardian action=add id=zone3 [filter_location] x,y=22-31,4-11 # This is intentionally chosen to extend past the lake terrain=W* [/filter_location] station_x,station_y=32,8 [/micro_ai] {SET_LABEL 3 13 _"Guarded Location"} {SET_LABEL 2 14 _"Station 1"} {SET_LABEL 4 14 _"Station 2"} # Set initial label for each units [store_unit] [filter] side=2 [/filter] variable=tmp_units kill=no [/store_unit] {FOREACH tmp_units i} {SET_LABEL $tmp_units[$i].x $tmp_units[$i].y $tmp_units[$i].variables.label} {NEXT i} {CLEAR_VARIABLE tmp_units} # The right-click menu items [set_menu_item] id=m01_guardian description= _ "Standard WML Guardian" image=units/dwarves/guard.png~CROP(28,24,24,24) [show_if] {VARIABLE_CONDITIONAL scenario_name equals guardians} [/show_if] [command] {MESSAGE narrator "portraits/dwarves/transparent/guard.png" _"Standard WML Guardian" _"This is the built-in WML guardian coded using 'ai_special=guardian'. These guardians attack if there is an enemy within their movement range, otherwise they do nothing (except maybe retreating to a village for healing)."} [/command] [/set_menu_item] [set_menu_item] id=m02_return description= _ "Return Guardian" image=units/trolls/grunt.png~CROP(31,7,24,24) [show_if] {VARIABLE_CONDITIONAL scenario_name equals guardians} [/show_if] [command] {MESSAGE narrator "portraits/trolls/transparent/troll.png" _"Return Guardian" _"A 'return guardian' is a variation of the standard Wesnoth guardian. It has an assigned guard position (GP) to which it returns after attacks on approaching enemies: - If at GP with no enemy in reach, do nothing. - If at GP with enemy in reach, leave attack to default AI (note that this may include not attacking if the enemy is deemed too strong). - If not at GP, return there, no matter whether an enemy is in reach or not. - If enemies are blocking your way back, do your best to get there anyway. - If you end up next to an enemy on the way back, attack after the move."} [/command] [/set_menu_item] [set_menu_item] id=m03_home description= _ "Home Guard" image=units/trolls/grunt.png~CROP(31,7,24,24) [show_if] {VARIABLE_CONDITIONAL scenario_name equals guardians} [/show_if] [command] {MESSAGE narrator "portraits/trolls/transparent/troll.png" _"Home Guard" _"A 'home guard' is a variant on the 'guardian' AI special. With this variant, the unit has an assigned 'home' location, and will return there if not involved in combat and if not going to a village, whether for healing or to capture it this turn. (By contrast, the standard guardian AI will cause the unit to stay where it last attacked.) This differs from 'return guardian' in that a home guard will press the attack, possibly getting drawn quite far from 'home', rather than returning after each attack. (It can also be lured away by a string of closely-placed villages, but that is something a map builder can control.) This also demonstrates how to combine candidate actions from Formula AI and Lua AI in one side. The home guard is written in Formula AI, while the return and stationed guardians and the cowards are written in Lua AI. In addition the non-guardian units of the side follow the default AI behavior."} [/command] [/set_menu_item] [set_menu_item] id=m04_stationed description= _ "Stationed Guardian" image=units/undead-skeletal/archer.png~CROP(24,16,24,24) [show_if] {VARIABLE_CONDITIONAL scenario_name equals guardians} [/show_if] [command] {MESSAGE narrator "portraits/undead/transparent/archer.png" _"Stationed Guardian" _"A 'stationed guardian' is another variation of the standard Wesnoth guardian with a somewhat more complex behavior than that of the 'return guardian'. Two positions are defined for it, a 'station' and a 'guarded location', as well as a 'distance'. The behavior is as follows: - If no enemy is within 'distance' of the guard's current position, do nothing. - Otherwise: If an enemy is within 'distance' of the guard, but not also within the same distance of the guarded location and the station (all of this simultaneously), move the guard in the direction of the station. - Otherwise: - Pick the enemy unit that is closest to the guarded location. - If we can reach it, pick the adjacent hex with the highest defense rating and attack from there. - If not in reach, move toward this unit."} [/command] [/set_menu_item] [set_menu_item] id=m05_coward description= _ "Coward" image=units/monsters/giant-rat.png~CROP(30,30,24,24) [show_if] {VARIABLE_CONDITIONAL scenario_name equals guardians} [/show_if] [command] {MESSAGE narrator "units/monsters/giant-rat.png" _"Coward" _"Cowards are units that, like guardians, sit around doing nothing until an enemy comes into range. Unlike guardians, however, they run away once enemies approach. Applications might be wild animals, unarmed civilians getting in the way of a battle, etc. The coward macro can be called with two optional locations, 'seek' and 'avoid': - If neither is given, the coward retreats to the position farthest away from the approaching enemies. - If 'seek' is given, it preferentially goes toward that location (but getting away from enemies takes priority). - If 'avoid' is given, it in addition tries to avoid that location (with both maximizing distance from enemies and going toward 'seek' taking priority). - Both 'seek' and 'avoid' may consist of only one coordinate ('x' or 'y'), in which case not a single hex, but a line of hexes is sought or avoided."} [/command] [/set_menu_item] [set_menu_item] id=m06_zone description= _ "Zone Guardian" image=units/nagas/fighter.png~CROP(25,19,24,24) [show_if] {VARIABLE_CONDITIONAL scenario_name equals guardians} [/show_if] [command] {MESSAGE narrator "units/monsters/water-serpent.png" _"Zone Guardian" _"A zone guardian is a unit that, as the name says, guards a zone. It moves randomly inside this zone until an enemy enters it (or a separately defined enemy zone, see below). Applications might be the defense of a castle or a nesting area. The zone macro can be called with an optional enemy zone: - If not specified, the zone guard attacks any enemy coming inside its guard zone. - Otherwise, it attacks any enemy entering the enemy zone and once there are no more enemies, it goes back to patrol in its basic zone."} [/command] [/set_menu_item] [/event] [event] name=start {STORE_UNIT_VAR id=Kraa profile profile} {MESSAGE Kraa "$profile~FL()~RIGHT()" "" _"Kraahhh!!!!"} {MESSAGE (Another Bad Orc) "" "" _"They there! We them get!"} # wmllint: unbalanced-on {MESSAGE Kraa "$profile~FL()~RIGHT()" "" _"Gryphons of the High Plains, look at all these enemies. They don't behave normally. Most of them don't move at all unless we get close. Let's check out how they react to us. Note to the player: the right-click context menu provides information about each of the units' behavior. Another note: Most of the Guardian AIs are coded as Micro AIs. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the Micro AI wiki page at http://wiki.wesnoth.org/Micro_AIs for more information."} # wmllint: unbalanced-off {CLEAR_VARIABLE profile} [objectives] summary= _ "Move the Gryphons around to explore how the guardians react" [objective] description= _ "Defeat all enemy units" condition=win [/objective] [objective] description= _ "Move Kraa to the signpost" condition=win [/objective] [objective] description= _ "Death of Kraa" condition=lose [/objective] [note] description= _ "Check out the right-click menu options for information on each guardian type" [/note] [/objectives] [/event] # Reset the label for moving units [event] name=moveto first_time_only=no [filter] side=2 [/filter] {REMOVE_LABEL $x2 $y2} {SET_LABEL $x1 $y1 $unit.variables.label} [/event] # The events finishing the scenario [event] name=die first_time_only=no [if] [not] [have_unit] side=2 [/have_unit] [/not] [then] [kill] id=$unit.id [/kill] [fire_event] name=end_scenario [/fire_event] [/then] [/if] [/event] [event] name=moveto [filter] id=Kraa x,y=1,6 [/filter] [fire_event] name=end_scenario [/fire_event] [/event] [event] name=end_scenario {MESSAGE Kraa "" "" _"Gryphons of the High Plains, it is time to return to said plains. Follow me."} [endlevel] result=victory bonus=no carryover_percentage=0 carryover_report=no linger_mode=no [/endlevel] [/event] [/test]