You must be logged in to post messages.
Please login or register

Modding Discussions
Moderated by Alexastor, MosheLevi, Mister SCP

Hop to:    
Welcome! You are not logged in. Please Login or Register.385 replies, Sticky
Age of Empires III Heaven » Forums » Modding Discussions » Idea: Let's start a "Better AI project"
Bottom
Topic Subject:Idea: Let's start a "Better AI project"
« Previous Page  1 ··· 12 13 14 15 16  Next Page »
murdilator
Skirmisher
posted 09-22-12 06:52 AM EDT (US)         
EDIT:

Here are links to The Beginner's Guide to AI Modification, written by me:

Part 1:

http://aoe3.heavengames.com/cgi-bin/forums/display.cgi?action=ct&f=14,38878,,10

Part 2:

http://aoe3.heavengames.com/cgi-bin/forums/display.cgi?action=ct&f=14,38885,30,100


------------------------------

Original Post (9-22-2012, 06:52 AM)

I have an idea that we can significantly improve the AOE3 AI. This will of course build from the Drauger AI. I have made a decent AI in my mod N3O Fan Patch, but it currently uses some techs that I have added to the game, so it won't work yet for an unmodified Age of Empires III. Yet I can easily remove those techs with some testing (to make sure it works) so that it can be played on an unmodified AOE3 and furthermore be a base rubric for further AI improvement.

http://aoe3.heavengames.com/downloads/showfile.php?fileid=3363

Mandorex also has an improved version of the Drauger AI:

http://aoe3.heavengames.com/downloads/showfile.php?fileid=3222


I also noticed another Drauger AI improvement uploaded for Vanilla AOE3 which makes the computer build forward bases. This would be interesting to look into, but I do say that this is quite a job for one coder. However, what I suggest is that we make it a community project to sort of build off an already improved AI and (for those who have time) fix various issues. I myself am pressed for time otherwise.


Anyone for an idea such as this!


Feel free to discuss and share your ideas! Its best if we discuss before we actually decide anything big.



best of regards to all here,




murdilator

[This message has been edited by murdilator (edited 06-23-2013 @ 10:35 AM).]

AuthorReplies:
Panmaster2014
Skirmisher
posted 10-08-18 12:51 PM EDT (US)     326 / 385       
I wonder which one is better for low-specs PCs when they all have 99 villagers, Plan or ManualGathering(?)
Assuming plans keep refreshing then they'll be slower late-game since you don't need to task once all settlers are on mills/plantations.
I wouldn't pre-order a 9900K just yet.
ylg_hke
Skirmisher
posted 10-09-18 05:44 AM EDT (US)     327 / 385       
hmm. alright, I will try ManualGathering.
BTW, ZenAI will forever send villagers to the correct RP, what brilliant AI!

Anyway, if kbLookAtAllUnitsOnMap() is cpu intensive, IMO don't run it every 5s, AI can see mother nature's stuff after the first run, so how about run it every 30-40s ?

Edit:
What does "resource allocation flip-flopping" mean exactly?

[This message has been edited by ylg_hke (edited 10-09-2018 @ 07:29 AM).]

AlistairJah
Skirmisher
posted 10-09-18 09:26 AM EDT (US)     328 / 385       
Really, the function has no noticeable impact on performance. At all. That's by the way why I thought it was just another (but a little different) version of the Japanese wonder power.

Hmm, I don't think those values are enough in an actual supremacy game... I mean, I don't know man, for treaty it definitely doesn't matter, but supremacy... But well, I can't think of a better way so
ylg_hke
Skirmisher
posted 10-09-18 09:58 PM EDT (US)     329 / 385       
I meant running kbLookAtAllUnitsOnMap every 30-40s, not running ManualGathering every 30-40s, MG should run every 5s or so.
For finding resources, 30-40s is enough, its like 9 out of 10 your opponents dare not to send their villagers to somewhere near your base to gather resources, and you can see your allies, so basically you know everything about resources near your base.

Maybe i did it wrong, but so far I haven't been able to make attackPlan work with kbLookAtAllUnitsOnMap alone.
Even getUnit, getUnitCountByLocation, kbUnitCount, they all return positive values after running kbLookAtAllUnitsOnMap.
They simply wont attack until a opponent is spotted by their units(ie: wont attack anything in unexplored-black-area, aiTaskUnitWork works though)
So if things stay this way, i dont think we need to run it every 5s.
AlistairJah
Skirmisher
posted 10-09-18 11:13 PM EDT (US)     330 / 385       
I didn't even talk about ManualGathering. What I meant was, what's even the point in reducing the frequency of kbLookAtAllUnitsOnMap, since it doesn't affect performance? And well, if you test my script, you'll see attack plans actually attack targets and locations regardless of fog/black map.
ylg_hke
Skirmisher
posted 10-10-18 00:51 AM EDT (US)     331 / 385       
According to Panmaster, ES said it is the most costly function.
If ES really said so, its impossible to be entirely wrong, maybe its not the "most", but at least should be something quite costly.

And the point is that, its very very difficult to tell how costly it is in singleplayer, I mean, AI will run just fine with 200 engage range defendplan or so in singleplayer, at least on my end, yet the game was almost unplayable with the very same setting on ESO, and everyone was green ping.
I don't have time to test just one line repeatedly on ESO, so I will just play it safe, at least for now.

Eventually I will have AI to build some single-wall-block to increase overall LOS, its fine IMO.

Regarding attackplan, you are right, your AI can attack targets in black area.
after a few tests, its all about aiPlanSetVariableVector(planID, cAttackPlanAttackPoint, 0, v). AI wont attack unexplored targets without this line, now the question is that what will happen and how costly it is without defining cAttackPlanAttackPointEngageRange.(It seems everthing related to EngageRange wont work well on ESO)
AlistairJah
Skirmisher
posted 10-10-18 01:47 AM EDT (US)     332 / 385       
Ah, yes, forgot about that... On LAN there is no problem with Zen *hmm* except when the time is about to be up. It freezes a lot once the battle begins...

EDIT:
To allow AI to make its own deck on scenario, use deck 0. Don't use the function aiHCDeckCreate(). Easier than I thought.

[This message has been edited by AlistairJah (edited 10-10-2018 @ 02:20 AM).]

ylg_hke
Skirmisher
posted 10-10-18 12:39 PM EDT (US)     333 / 385       
On LAN there is no problem with Zen
It freezes a lot once the battle begins...
==>What? I don't get it.... Do you mean its not laggy but troops tend to stand-still ?

To allow AI to make its own deck on scenario, use deck 0. Don't use the function aiHCDeckCreate()
==> Cool!, I will try it after importing ManualGathering. But since the way I handle resources is a bit different from Panmaster, I will make some changes, as well as extend it to fishing boats.
Surprisingly, I find ManualGathering is actually easier to handle, and now I have more room to improve shootHuntables, win win.

EDIT:

Hey guys, I have just found :

-kbUnitGetActionType, kbUnitGetNumberWorkers
<== they work for mother-nature units, after xsSetContextPlayer(0);

-"shrined" animals' action type = 3

[This message has been edited by ylg_hke (edited 10-11-2018 @ 01:14 AM).]

AlistairJah
Skirmisher
posted 10-11-18 01:54 AM EDT (US)     334 / 385       
The debugger works. I mean, the whole thing works. And... it's so frickin awesome

@ylg_hke > Nope, those functions are unreliable on Gaia (I even theorize that they are unreliable on Enemy Players). Tested. Try on huntables, guardians, and buildings.
ylg_hke
Skirmisher
posted 10-11-18 02:17 AM EDT (US)     335 / 385       
The debugger works.
==> teach me, LOL.

those functions are unreliable on Gaia
==> What do you mean by "unreliable" exactly? they sometimes give false values? or what?

Anyway, so far they work for all nature units on my end: huntable, berry, tree, mine, fish, whale.
===================================================
rule ReportWorkerNo
active
minInterval 2
{
int WorkerID = getUnit(cUnitTypeAbstractVillager);
int ResourceID = -1;

ResourceID = kbUnitGetTargetUnitID(WorkerID);

xsSetContextPlayer(0);
aiChat(1, "ResourceID " + ResourceID + " ResourceID Worker No " + kbUnitGetNumberWorkers(ResourceID));
}
=====================================================
rule ShrineWorker
active
minInterval 2
{
int ShrineID = getUnit(cUnitTypeAbstractShrine);
static int WorkerID = -1;
if(WorkerID < 0)
{ WorkerID = kbUnitGetWorkerID(ShrineID, 0); }
xsSetContextPlayer(0);
aiChat(1, "WorkerID " + WorkerID + " WorkerID 0 Action" + kbUnitGetActionType(WorkerID));
}
======================================================

Delete the shrine once you get the workerID, the ActionType will change accordingly.

[This message has been edited by ylg_hke (edited 10-11-2018 @ 02:18 AM).]

AlistairJah
Skirmisher
posted 10-11-18 02:36 AM EDT (US)     336 / 385       
You have to add the gadget's in hotkeys (gamey.con):
map("alt-w", "root", "AIDebugInfoToggle()")
map("alt-q", "root", "gadgetToggle(\"XSDebugger\")")
map("esc", "XSDebugger", "gadgetUnreal(\"XSDebugger\")")

You can open UI files in bin\data, if you wonder what are gadgets

Aah, you meant, use the functions while being Gaia. Will try. Also, you forgot to go back to normal context: xsSetContextPlayer(cMyID)
ylg_hke
Skirmisher
posted 10-11-18 03:09 AM EDT (US)     337 / 385       
Then..?
>start a scenario under debugger
>set AI blahblahblah
>playtest
>press esc, alt q, alt w
>nothing happens

you forgot to go back to normal context
==> didn't bother to add that line, at the time I thought it would fail anyway haha.
AlistairJah
Skirmisher
posted 10-11-18 05:22 AM EDT (US)     338 / 385       
Nothing happens? Nothing happens? Naaah, something marvelous happens. Alt+w opens the AI Debugger, as you can see in the example in my previous post (gamey.con, not cfg). Aaand of course, you have to enable AIDebug and developer in gamey.cfg (but I know you already did that, weeks ago).

[This message has been edited by AlistairJah (edited 10-11-2018 @ 06:26 AM).]

ylg_hke
Skirmisher
posted 10-11-18 08:13 AM EDT (US)     339 / 385       
ahaha, I forgot to save the file..LOL
The debugger is super cool! You should start a new thread and let other people know about it =]

EDIT:
debugger wont show AttackGoal's trainplan unless we hit alt-W twice (turn off, turn on Debugger Info)
==> Goals>AttackGoal> point at it and wait 1-2s

we can pretty much forget about fishingBoat manualGathering. Because 1 fishPlan is enough for all fishing boats, enough for fishing + whaling at the same time, we dont even need any breakdown.

The behavior of fishPlan is totally different from other foodPlan:
lets say a fishing boat is now working at fishA, if we task it to whaleA or maybe fishB, it will just go, the plan wont tell it to go back to fishA.

A small monitor rule to control the ratio of fishing and whaling will be enough, eg: task some fishing boats to gather gold when we have too many food.

[This message has been edited by ylg_hke (edited 10-12-2018 @ 03:24 AM).]

Panmaster2014
Skirmisher
posted 10-12-18 12:21 PM EDT (US)     340 / 385       
Does the debugger reveal any new information?

You should abuse aiTaskUnitTrain to get Spahi on expert difficulty to give human players a nasty surprise. Those things make imperial gendarmes look mediocre.

Fishing boats would require an extra level of filtering possibly movement type since they are classed as villagers.
Water maps aren't great unless the AI can use broadside attack and monitor mortar abilities.
ylg_hke
Skirmisher
posted 10-12-18 09:30 PM EDT (US)     341 / 385       
Does the debugger reveal any new information?
==> News to me, but not very useful: explorePlan can create child-nugget-plan, and now I know what cGatherPlanKBResourceID is, auto-generated even there is no gather goal.

You should abuse aiTaskUnitTrain to get Spahi
==> Not sure, because its way too obvious, you can't mask it, skull knight , dog soldier are different, they have their own dance. IMO obvious cheating kills mood.
But anyway, I prioritize fixing problems, and we have many, I dont bother to add these features unless troops can attack in a more uniform way and increasing troop queue size issue is fixed.

Fishing boats would require an extra level of filtering possibly movement type since they are classed as villagers.
==> hmm...since some warships can gather resource as well, maybe we should group warship & fishing boat together using AbstractFishingBoat when there's no target to attack.
AlistairJah
Skirmisher
posted 10-13-18 02:15 AM EDT (US)     342 / 385       
Yes I will make a thread about debugger. I might even remake the whole guides, as they're honestly not what a beginner would be excited about... Beginners are a little biased in practicing and immediate results than useless explanations... I will... see what's the best thing to do.
Fishing boats would require an extra level of filtering possibly movement type since they are classed as villagers.
I'm using 'AbstractFishingBoat' but movement type is a better way actually.

Regarding the debugger, I don't think it would give any new information to you. You kinda seem to know a huge part of this whole scripting thing...
ylg_hke
Skirmisher
posted 10-13-18 10:27 AM EDT (US)     343 / 385       
I'm using 'AbstractFishingBoat' but movement type is a better way actually.
==> It would be best if we could set land or water in unitQuery.
I tried kbUnitQuerySetAreaID and kbUnitQuerySetAreaGroupID. None of them work.
-1 ==> all AbstractVillager
0-3 ==> result = 0
AlistairJah
Skirmisher
posted 10-13-18 11:22 AM EDT (US)     344 / 385       
There are kbUnitGetMovementType() and cMovementTypeNone, cMovementTypeLand, cMovementTypeWater, cMovementTypeAir, cMovementTypeNonSolid
Panmaster2014
Skirmisher
posted 10-13-18 12:16 PM EDT (US)     345 / 385       
I tried kbUnitQuerySetAreaID and kbUnitQuerySetAreaGroupID. None of them work.
Confirmed.
Areas are nearly completely useless.
ylg_hke
Skirmisher
posted 10-14-18 00:13 AM EDT (US)     346 / 385       
OK kbUnitQuery is more complicated than I thought.
I tried the following query in 2 different AI files:
1: original AI
2: empty AI with a void main only

-original AI:
it gives correct counts when i = 1 & 2
it seems -1 = all abstract villager count, 1 = land, 2 = water

-empty AI with a void main only:
it works only when i = -1

I can't figure out why it works for the original AI only.

=================================================
rule QueryArea
active
minInterval 2
{
static int unitQueryID=-1;
if (unitQueryID < 0)
{
unitQueryID=kbUnitQueryCreate("miscGetUnitQuery");
}
int numberFound = -1;

for(i = -2; < 4)
{
kbUnitQueryResetResults(unitQueryID);
kbUnitQuerySetPlayerID(unitQueryID, cMyID);
kbUnitQuerySetUnitType(unitQueryID, cUnitTypeAbstractVillager);
kbUnitQuerySetState(unitQueryID, cUnitStateAlive);
kbUnitQuerySetAreaGroupID(unitQueryID, i);
numberFound=kbUnitQueryExecute(unitQueryID);

aiChat(1, "Test Villager Area " + i + " :"+ numberFound);
}
}
==================================================

BTW we have to set kbUnitQuerySetPlayerID, kbUnitQuerySetUnitType...etc again after kbUnitQueryResetResults, or it might not work.


@AlistairJah:
yea i know, but i was talking about kbUnitQuery.


EDIT:
I forgot to mention kbAreaGroupGetIDByPosition, kbAreaGetIDByPosition are also broken in the "empty AI with a void main only".
==============================================
rule QueryAreaHero
active
minInterval 2
{
static int unitQueryID=-1;
if (unitQueryID < 0)
{
unitQueryID=kbUnitQueryCreate("miscGetUnitQuery");
}
int numberFound = -1;

kbUnitQueryResetResults(unitQueryID);
kbUnitQuerySetPlayerID(unitQueryID, cMyID);
kbUnitQuerySetUnitType(unitQueryID, cUnitTypeHero);
kbUnitQuerySetState(unitQueryID, cUnitStateAlive);
numberFound=kbUnitQueryExecute(unitQueryID);

int Hero = kbUnitQueryGetResult(unitQueryID,0);
vector HeroVector = kbUnitGetPosition(Hero);
int AreaGroupID = kbAreaGroupGetIDByPosition(HeroVector);
int AreaID = kbAreaGetIDByPosition(HeroVector);

aiChat(1, "HeroVector " + HeroVector + " AreaGroupID "+ AreaGroupID + " AreaID " + AreaID);

}
==============================================

[This message has been edited by ylg_hke (edited 10-14-2018 @ 01:04 AM).]

Panmaster2014
Skirmisher
posted 10-14-18 11:05 AM EDT (US)     347 / 385       
it seems -1 = all abstract villager count, 1 = land, 2 = water
edit: I was wrong. AreaGroups are dynamic.
On Deccan:
0 = impassable
1 = Land
2 = water
On Amazonia:
0 = impassable
1 = south land
2 = north land
3 = water
4 = coast cliffs
I can't figure out why it works for the original AI only.
Definitely missing kbAreaCalculate().
I forgot to mention kbAreaGroupGetIDByPosition, kbAreaGetIDByPosition are also broken in the "empty AI with a void main only".
kbAreaCalculate() again.

[This message has been edited by Panmaster2014 (edited 10-14-2018 @ 11:34 AM).]

ylg_hke
Skirmisher
posted 10-15-18 01:06 AM EDT (US)     348 / 385       
AreaGroups are dynamic.
==> Confirmed, now we are back to square one.

Definitely missing kbAreaCalculate()
==> Yea, now they are all OK, thanks!!
AlistairJah
Skirmisher
posted 10-15-18 08:23 AM EDT (US)     349 / 385       
@ylg_hke:
You don't have to use two rules for the 'hunt towards town'. I've made my own and it's pretty neat. I think I could make it even cooler if I calculate angles, not only distances.
ylg_hke
Skirmisher
posted 10-15-18 01:34 PM EDT (US)     350 / 385       
2 rules? um..I think I have always used just 1 rule, no?
Anyway, please share your rule.

BTW, I have noticed that we can't place kbUnitQuerySetUnitType before kbUnitQuerySetPlayerID, kbUnitQuerySetState, or it will forever return 0.

I havent touched "shoot huntables" for a while, it is my latest version.
it will be further modified, because i dont use plans for gathering anymore.
==============================================

rule ShootHuntable
inactive
minInterval 3
{
int d1 = -1;
int d2 = -1;

if(gShootHuntable != -1)
{
if((kbUnitGetHealth(gPreyID) < 0.6) || (kbUnitGetHealth(gHunterID) < 0.1) || ((xsGetTime() - gHunterTimer) >= 40000) )
{
aiPlanDestroy(gShootHuntable);
gShootHuntable = -1;
gHunterID = -1;
xsSetRuleMinIntervalSelf(3);
return;
}
else
{
d1 = distance(kbUnitGetPosition(gHunterID), gMilitaryMainBase);
d2 = distance(kbUnitGetPosition(gPreyID), gMilitaryMainBase);

if((d1 - d2) > 5)
{
aiTaskUnitWork(gHunterID, gPreyID);
aiTaskUnitWork(gHunterID, gPreyID);
aiTaskUnitWork(gHunterID, gPreyID);
aiTaskUnitWork(gHunterID, gPreyID);
aiTaskUnitWork(gHunterID, gPreyID);
gHunterID = -1;
return;
}
else
{ return; }
}
}

int PreyCount = -1;
int WoundedPreyCount = 0;
int PreyOrder = -1;
int PreyID = -1;
vector PreyLocation = cInvalidVector;
int d3 = -1;

int HunterCount = -1;
int HunterOrder = -1;
int HunterID = -1;
vector HunterLocation = cInvalidVector;

PreyCount = getUnitCountByLocation(cUnitTypeHuntable, cPlayerRelationEnemy, cUnitStateAlive, gMilitaryMainBase, 140.0);

for (PreyOrder = 5; < PreyCount)
{
PreyID = getUnitByLocationSorted(cUnitTypeHuntable, cPlayerRelationEnemy, cUnitStateAlive, gMilitaryMainBase, 140, PreyOrder);
if (kbUnitGetHealth(PreyID) < 0.6)
{
WoundedPreyCount = WoundedPreyCount + 1;
continue;
}

PreyLocation = kbUnitGetPosition(PreyID);
if(getUnitByLocationSorted(cUnitTypeTownCenter, cPlayerRelationAny, cUnitStateAlive, PreyLocation, 30, 0) >= 0)
{ continue; }

d3 = distance(PreyLocation, kbUnitGetPosition(gPreyID));
if(d3 < 15)
{ continue; }
else
{ break; }
}

if(xsGetTime() > 600000)
{
if( (PreyCount < 10) || ( (PreyCount - WoundedPreyCount) < 3 ) )
{
aiChat(1, "Turning off ShootHuntable");
xsDisableSelf();
return;
}
}

HunterLocation = PreyLocation + ((xsVectorNormalize(PreyLocation - gMilitaryMainBase)) * 20) ;

if(d3 < 45)
{ HunterID = gHunterIDBackup; }
else
{
HunterCount = getUnitCountByLocation(gEconUnit, cMyID, cUnitStateAlive, PreyLocation, 140);
for (HunterOrder = 0; < HunterCount)
{
HunterID = getUnitByLocationSorted(gEconUnit, cMyID, cUnitStateAlive, PreyLocation, 140, HunterOrder);
if(aiPlanGetType(kbUnitGetPlanID(HunterID)) != cPlanGather)
{ continue; }
else
{ break; }
}
}

if(gShootHuntable < 0)
{
gShootHuntable = aiPlanCreate("Hunter", cPlanAttack);
aiPlanSetVariableInt(gShootHuntable, cAttackPlanPlayerID, 0, 0);
aiPlanSetNumberVariableValues(gShootHuntable, cAttackPlanTargetTypeID, 1, true);
aiPlanSetVariableInt(gShootHuntable, cAttackPlanTargetTypeID, 0, cUnitTypeHuntable);
aiPlanSetVariableVector(gShootHuntable, cAttackPlanGatherPoint, 0, HunterLocation);
aiPlanSetVariableFloat(gShootHuntable, cAttackPlanGatherDistance, 0, 5.0);
aiPlanSetVariableInt(gShootHuntable, cAttackPlanRefreshFrequency, 0, 10);
aiPlanSetDesiredPriority(gShootHuntable, 99);
aiPlanAddUnitType(gShootHuntable, gEconUnit, 1, 1, 1);
aiPlanAddUnit(gShootHuntable, HunterID);
aiPlanSetInitialPosition(gShootHuntable, HunterLocation);
aiPlanSetActive(gShootHuntable, true);

gPreyID = PreyID;
gHunterID = HunterID;
gHunterIDBackup = HunterID;
gHunterTimer = xsGetTime();
xsSetRuleMinIntervalSelf(1);
}
}
==============================================

[This message has been edited by ylg_hke (edited 10-15-2018 @ 01:46 PM).]

« Previous Page  1 ··· 12 13 14 15 16  Next Page »
You must be logged in to post messages.
Please login or register

Hop to:    

Age of Empires III Heaven | HeavenGames