Getting AI to recall?

The place to post your WML questions and answers.

Moderator: Forum Moderators

Forum rules
  • Please use [code] BBCode tags in your posts for embedding WML snippets.
  • To keep your code readable so that others can easily help you, make sure to indent it following our conventions.
Post Reply
User avatar
Ken_Oh
Moderator Emeritus
Posts: 2178
Joined: February 6th, 2006, 4:03 am
Location: Baltimore, Maryland, USA

Getting AI to recall?

Post by Ken_Oh »

I've got this little campaign where I'd like to have some persistence to the enemy. So far I've been able to provide the same enemy leader (unit and xp) with the same recruit list for different scenarios, but can't get AI to recall.

zookeeper suggested I check to see if AI can recall by providing the player side with a recall list, deleting every unit from the recruit list and then :droid'ing myself to see if the AI recalls. Sure enough, the leader unit just goes around capping villages.

I was wondering if anyone has any thoughts on this. Am I maybe missing something? I'm also not 100% sure how to store recall lists for AI sides.

There's just one idea I have that might work, but it's far from simple.

Upon recruit a check is first done for gold. If there isn't at least enough gold past the recruit cost to make it 20 (unless the cost is already above 20) then forget it. Then a check is done of the availability of units in the recall list that are leveled up versions of that unit or the same units but with more xp. Some values are assigned to some things that give this choice a score (the less xp left to level, especially for level 1, the higher the score; the more gold the AI side has, the higher the score;etc.)...........

OK, I think I just hurt my brain thinking about the details just now. But, anyway, you get the point that things get scored, they get a chance of happening assigned, then there's a random number generated that makes the decision if it wants to substitute the unit and with which unit to put in.

Just wondering if anyone has any better ideas.
Darth Fool
Retired Developer
Posts: 2633
Joined: March 22nd, 2004, 11:22 pm
Location: An Earl's Roadstead

Post by Darth Fool »

The current AI can not recall units. It is something I intend to fix in my AI, however for now you will need to use some deep WML tricks.
Inigo Montoya
Posts: 199
Joined: November 27th, 2006, 2:29 pm
Location: Behind you

Post by Inigo Montoya »

Another quick fly-by answer...

At the end of each scenario, [store] all (surviving) enemy units. Then find some way of separating different types of unit into separate arrays.

When, in the next scenario, the AI recruits a unit, check to see if there is a stored unit of that type. If so, [kill] the newly-recruited unit and replace it with a randomly-selected unit from the array of that type. Then remove that unit from the array, and correct the AI's gold (if you really care that much)
I don't exist when you don't see me...
I don't exist when you're not here.

You bought a mask - I put it on.
You never thought to ask me if I wear it when you're gone.
User avatar
Ken_Oh
Moderator Emeritus
Posts: 2178
Joined: February 6th, 2006, 4:03 am
Location: Baltimore, Maryland, USA

Post by Ken_Oh »

Yeah, I already had the storing and putting to recall list made (that's basically what I've been doing to put dead units to the recall list).

I'd rather not make the recalling random, but intelligent to the point that the AI only recalls higher level units or the same unit type with a somewhat high xp (unless it's a unit with a recruit cost of >= 20).

I'm trying to think how to sort units in the recall list by lowest to highest max_experience minus experience and pick lowest one, but am not coming up with anything yet.

If anyone has a clue, please chime in.

EDIT: Talked it over in irc and it seems that [recall] already takes unit that is closest to leveling up. Case solved.

EDIT #2

EDIT #3 - Nevermind. I think I have it all figured out.
User avatar
Ken_Oh
Moderator Emeritus
Posts: 2178
Joined: February 6th, 2006, 4:03 am
Location: Baltimore, Maryland, USA

Post by Ken_Oh »

Bump for attention. My recall code basically comes down to this for every unit, which I include in the second scenario:

Code: Select all

#define AI_RECALL_SPEARMAN
[event]
	name=recruit
	first_time_only=no
	[filter]
		side=2
		type=Spearman
	[/filter]
	[store_unit]
			variable=SPEARMAN_ai_recall
			[filter]
				x,y=$x1,$y1
			[/filter]
			kill=yes
		[/store_unit]
		[recall]
			type=Spearman,Swordsman,Pikeman,Javelineer,Royal Guard,Halbardier
			x,y=$x1,$y1
		[/recall]
		[if]
		[have_unit]
			x,y=$x1,$y1
		[/have_unit]
		[then]
			[gold]
				side=2
				amount=-6
			[/gold]
		[/then]
		[else]
			[unstore_unit]
				variable=SPEARMAN_ai_recall
			[/unstore_unit]
		[/else]
	[/if]
	{CLEAR_VARIABLE SPEARMAN_ai_recall}
[/event]
#enddef
It kind of works, as I've had the AI recruit xp'ed and leveled up Bowmen, Cavalrymen and Fencers. But it kind of doesn't. I put in a counter for it:

Code: Select all

#define AI_RECALL_FENCER
[event]
	name=recruit
	first_time_only=no
	[filter]
		side=2
		type=Fencer
	[/filter]
	{VARIABLE_OP count add 1}
	{DEBUG_MSG "fencer xy $x1| $y1| count $count|" }
	[store_unit]
		variable=FENCER_ai_recall
		[filter]
			x,y=$x1,$y1
		[/filter]
		kill=yes
	[/store_unit]
	[recall]
		type=Master at Arms,Duelist,Fencer
		x,y=$x1,$y1
	[/recall]
	[if]
		[have_unit]
			x,y=$x1,$y1
		[/have_unit]
		[then]
		{VARIABLE_OP count add 1}
		{DEBUG_MSG "fencer have xy $x1| $y1| count $count|"}
			[gold]
				side=2
				amount=-4
			[/gold]
		[/then]
		[else]
		{VARIABLE_OP count add 1}
		{DEBUG_MSG "fencer not have xy $x1| $y1| count $count|"}
			[unstore_unit]
				variable=FENCER_ai_recall
			[/unstore_unit]
		[/else]
	[/if]
	{VARIABLE count 0}
	{CLEAR_VARIABLE FENCER_ai_recall}
[/event]
#enddef
What happens seems random for each recall, and none of it makes any sense. It'll stay on the same x,y but the count increment goes up to anywhere between 4-8 before going to the next unit. Plus, for each x,y it sometimes displays both "have" and "not have." When it displays "have" (regardless of if it displays "have not"), then it seems to work. But other times it'll just say "have not" and then ends up with a recruit instead of a recall.

There's got to be something I'm missing here. It seem as if recruit events have a delay of some sort. The same with [recall].
Darth Fool
Retired Developer
Posts: 2633
Joined: March 22nd, 2004, 11:22 pm
Location: An Earl's Roadstead

Post by Darth Fool »

Without looking at the C++ code, it wouldn't surprise me if recalling a unit is triggering a recruit event which could be leading to a little circular logic until it exhausts the recall list. If that is the case, what is needed is some tag that lets you define whether the recruit event should include both recall/recruit events, or only one or the other.
User avatar
Ken_Oh
Moderator Emeritus
Posts: 2178
Joined: February 6th, 2006, 4:03 am
Location: Baltimore, Maryland, USA

Post by Ken_Oh »

Thanks. I think that might be it since it doesn't seem to have much problem recalling level 2 units (a Duelist wouldn't trigger the filter for Fencer).

Do you think this would do it?

Code: Select all

#define AI_RECALL_TEST
[event]
	name=prerecruit
	first_time_only=no
	[filter]
		side=2
	[/filter]
	[store_unit]
		variable=TEST_ai_recall
		[filter]
			x,y=$x1,$y1
		[/filter]
		kill=no
	[/store_unit]
[/event]
#enddef

#define AI_RECALL_DRAKE_BURNER
[event]
	name=recruit
	first_time_only=no
	[filter]
		side=2
		type=Drake Burner
		[variable]
			name=TEST_ai_recall.xp
			less_than=1
		[/variable]
	[/filter]

etc...
If not, I don't how to delay an event until just -after- a recruit, but not before the next one.

I'm having trouble telling if stuff works now that it kind of works.
Post Reply