Home » MODDING HQ 1.13 » v1.13 Coding Talk » Learning how the tactical AI works
Learning how the tactical AI works[message #274168]
|
Tue, 22 February 2011 07:54
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
Hey all,
Newbie here, I'm trying to play with the AI a bit.
I've found
\Jagged Alliance 2 v1.13 - Source code [1.0.0.2085]\Build\TacticalAI\DecideAction.cpp
, which returns actions for each soldiers such as "AI_ACTION_FLANK_LEFT", "AI_ACTION_SEEK_OPPONENT" and "AI_ACTION_TAKE_COVER".
However, I can't seem to find where these actions are defined. I've seen the actions names in "AIUtils.cpp" and "AI.h", but this is not where they are defined...
A pointer would be appreciated as my sanity is slowly fading ![Smile](images/smiley_icons/icon_smile.gif)
Also, how does one build the exe to be able to see the "debugmsg" ?
Cheers!
[Updated on: Tue, 22 February 2011 19:02] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
|
Re: Learning how the AI works[message #274195]
|
Tue, 22 February 2011 15:30 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
Thanks Rowa for the link and tips.
My understanding of the code above is that it sets the action of the soldier to be either AI_ACTION_FLANK_LEFT, AI_ACTION_FLANK_RIGHT or AI_ACTION_SEEK_NOISE.
What I meant to say is : Where is the behaviour of a soldier whose action is set to,say, "AI_ACTION_SEEK_NOISE" defined? Something that would look like "move toward sound source, stopping near obstacles that could provide cover, and keeping enough APs for an interrupt".
Cheers!
[Updated on: Tue, 22 February 2011 15:33] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
|
|
|
Re: Learning how the AI works[message #274253]
|
Tue, 22 February 2011 20:03 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
Here's where I am so far in trying to understand what is going on when someone is supposed to go and take cover..
Question: Is InternalGetNewSoldierPath where the actual moving occurs? I'm at a loss (again)
Cheers!
FIRST:
DecideAction (from DecideAction.CPP) returns an action, but it also sets parameters for that action. Example with AI_ACTION_TAKE_COVER, where sBestCover is probably the coordinate of the best cover available...
pSoldier->aiData.usActionData = sBestCover;
return(AI_ACTION_TAKE_COVER);
SECOND:
ExecuteAction (from AIMain.cpp) tries to execute this action.
All the "movement orders" will call the NewDest method (from AIUtils.cpp) to set a new pSoldier->pathing.sDestination based on pSoldier->aiData.usActionData
THIRD:
NewDest
-sets pSoldier->usUIMovementMode (sometimes using AIUtils's DetermineMovementMode() method)
-calls pSoldier->EVENT_InternalGetNewSoldierPath( usGridNo, pSoldier->usUIMovementMode , FALSE, pSoldier->flags.fNoAPToFinishMove );
SOLDIERTYPE::EVENT_InternalGetNewSoldierPath is located in "Soldier control.cpp"
[Updated on: Tue, 22 February 2011 21:24] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
|
Re: Learning how the AI works[message #274337]
|
Wed, 23 February 2011 17:34 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
BunsUnfortuantly I cannot help you with the code, but my observation is that AI orders seem to updated, or generated, everytime it reaches a tile. This seems to be the reason behind the AI running in circles and wasting all APs for moving for and back between two adjecting tiles.
You can see this quite frequently when an enemy soldiers is standing behind a row of windows. He will often switch for and back between two windows until having spent all APs. Another very typical situation is an enemy who already has been shooting (means he can see his foe) but then suddenly advances a few tiles only to then run back beyond the tile he had started his movement from.
My guess would be that these orders are not executed (or generated?) en bloc, in the way of "move to tile 114 112 and then take cover", but step by step: "Take cover by moving to tile 114 112" and when the AI has reached this tile a new order is generated, which can include to move back to the tile it just came from.
Yup, I have the feeling that's why the AI will move back and forth all the time, I still have to find the code for this though.
This shows how far we are from an AI that coordinates multiple soldiers... Individual soldiers dont even know what they'll do 10 APs from now..
[Updated on: Wed, 23 February 2011 17:40] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
Re: Learning how the AI works[message #274338]
|
Wed, 23 February 2011 17:36 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
Just learned about the "Source Insight" program. Allowed me to generate to the following "relation graphs", might be interesting.
WinMain --> HandledWinMain --> InitializeStandardGamingPlatform --> InitializeGame --> GameScreens --> MainGameScreenHandle --> ExecuteOverhead --> HandleSoldierAI
And then:
HandleSoldierAI calls
1) TurnBasedHandleNPCAI which calls 1a) DecideAction and 1b) ExecuteAction
2) RTHandleAI , which calls 2a) RTDecideAction and 2b) ExecuteAction
DecideAction, ExecuteAction and (eventually) RTDecideAction are where it's at.
Maybe adding an action "Move to cover AND shoot" would be the way to go.
I'll try to figure out how to compile a "debug" version, to see which of the many "move" orders are being used when the AI is stuck on a window...
[Updated on: Wed, 23 February 2011 17:38] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
|
Re: Learning how the AI works[message #274360]
|
Wed, 23 February 2011 21:13 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
Buns
Just received my teacher's comment for my master -- looks like I can't procrastinate anymore today.
I'd love to see if I can implement that.
I'm slowly becoming functional. I've installed Visual Studio 2010, and I compiled the "solution" for the latest SVN downloaded with Tortoise.
It runs and the file is called JA2-ENG-DEBUG.EXE. So I assume I compiled the WIN32 DEBUG and not the WIN32 RELEASE version by default, which is great.
Question to coders: When I start JA2-ENG-DEBUG.EXE, it creates a file named AIDEBUG.TXT ("AI DEBUG") in the JA2 program files folder. For some reason it remains empty of text when I play the game. Any reason why?
(some meat that help to answer):
I manually added some text to the AIDEBUG.TXT file and that file was removed (probably by the InitAI method, partially shown below)
I guess this means that "#ifdef JA2TESTVERSION" (from InitAI) is true but "#ifdef DEBUGDECISIONS" (from DecideAction) isnt. I'll dig a bit further to understand what #ifdef means...
here's the code for the DebugAI method, which is called a lot by the DecideAction, but only if "#ifdef DEBUGDECISIONS" is true... any idea how to set it on?
void DebugAI( STR szOutput )
{
#ifdef DEBUGDECISIONS
// Send regular debug msg AND AI debug message
FILE * DebugFile;
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, szOutput );
if ((DebugFile = fopen( "aidebug.txt", "a+t" )) != NULL)
{
fputs( szOutput, DebugFile );
fputs( "
", DebugFile );
fclose( DebugFile );
}
else {ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Debug: AIDEBUG.TXT = NULL" );} // SIMON
#endif
}
Here's the beginning of the InitAI method:
BOOLEAN InitAI( void )
{
#ifdef JA2TESTVERSION
FILE * DebugFile;
#endif
#ifdef _DEBUG
if (gfDisplayCoverValues)
{
//memset( gsCoverValue, 0x7F, sizeof( INT16 ) * WORLD_MAX );
}
#endif
//If we are not loading a saved game ( if we are, this has already been called )
if( !( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
{
//init the panic system
InitPanicSystem();
}
#ifdef JA2TESTVERSION
// Clear the AI debug txt file to prevent it from getting huge
if ((DebugFile = fopen( "aidebug.txt", "w" )) != NULL)
{
fputs( "
", DebugFile );
fclose( DebugFile );
}
#endif
some code in the DecideAction method:
#ifdef DEBUGDECISIONS
sprintf( tempstr,"DecideAction: selected action %d, actionData %d
",bAction,pSoldier->aiData.usActionData);
DebugAI( tempstr );
#endif
[Updated on: Wed, 23 February 2011 21:23] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
Re: Learning how the AI works[message #274361]
|
Wed, 23 February 2011 21:27 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
JMich |
![](/images/ranks/first_sergeant.png) |
Messages:546
Registered:January 2011 Location: Greece |
|
|
the part that says is false, so anything between that and #endif will not be processed. You will have to #define DEBUGDECISIONS = 1 for any debugdecisions blocks to be processed.
Also, the Tactical AI is quite complex, and you will see that it is being referenced in many places. In DecideAction.cpp we have 4 routines to decide what action the unit (and it is unit, wheter civilian, monster, bloodcat, soldier or in some cases pcs), 1 for each of the alert status (stati?).
For the part of "do this, and then do that", take a look at the function INT8 DecideActionSchedule( SOLDIERTYPE * pSoldier ) in decideaction.cpp, the one for going through closed doors.
Since you are using VS, run the game by pressing F5, which is the debug mode of VS, and run the game in window. This will allow you to set breakpoints that will stop the execution when a breakpoint is reached, but before it's calculated. For example, if you set a breakpoint at INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) the execution will stop once the function is to be called, which will allow you to see the value of and if you want to see what this soldier will do, you can set more breakpoints.
P.S. in VS, if you hover your mouse over any declarations, it will tell you its definition and whether it has a value defined or not.
P.P.S. I usually lurk in irc if you think I can help you more, but I am not yet that confident of my ability to understand code.
Report message to a moderator
|
First Sergeant
|
|
|
|
Re: Learning how the AI works[message #274363]
|
Wed, 23 February 2011 21:42 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
JMich.
Great stuff- thanks
By the way, I tried uncommenting #define DEBUGDECISIONS like I said in my previous post, and now I get these errors when compiling.
Bugger.
>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(146): error C2065: 'sGridno' : undeclared identifier
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(344): error C2664: 'sprintf' : cannot convert parameter 1 from 'STR16' to 'char *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(345): error C3861: 'AIPopMessage': identifier not found
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(434): error C2664: 'sprintf' : cannot convert parameter 1 from 'STR16' to 'char *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(435): error C3861: 'AIPopMessage': identifier not found
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(498): error C2664: 'sprintf' : cannot convert parameter 1 from 'STR16' to 'char *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(499): error C3861: 'AIPopMessage': identifier not found
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(544): error C3861: 'AIPopMessage': identifier not found
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(591): error C3861: 'AINumMessage': identifier not found
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(601): error C3861: 'AINumMessage': identifier not found
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(617): error C3861: 'AINumMessage': identifier not found
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(618): error C3861: 'AINumMessage': identifier not found
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(755): error C2664: 'sprintf' : cannot convert parameter 1 from 'STR16' to 'char *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>d:\documents and settings\temp\desktop\downloadsvn\build\tacticalai\movement.cpp(756): error C3861: 'AIPopMessage': identifier not found
1> Medical.cpp
[Updated on: Wed, 23 February 2011 21:48] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
Re: Learning how the AI works[message #274364]
|
Wed, 23 February 2011 21:57 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
Just to make my current objectives clear. At this stage, I'd be very happy if I could just get the following to work:
1) Decisions are written to aidebug.txt
2) Create a decision where the unit moves 1 square right then stop for the rest of the turn. If it cannot go right, then go left/north/south...
This would probably require using "Schedule" which I am very glad was mentionned above
edit: Also, is anyone aware oh how the "pSoldiers" are chosen? Are they simply played one after the other, always in the same order (say, by increasing ID#?)
edit2 : Running debugging mode using F5 doesnt work because
"\Build\ext\vfs\build\...... \lib\vs2010\debug\VFS.lib is an unrecognized or unsupported binary format"
[Updated on: Wed, 23 February 2011 22:42] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
Re: Learning how the AI works[message #274380]
|
Thu, 24 February 2011 01:22 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
hey all!
Again, working on the v1.13 code, only difference is that I: uncommented #define DEBUGDECISIONS in builddefine.h . It didnt compile, so I did the following
I tried the following solution:
1) replace AIPopMessage(str16) by DebugAI(str)
2) commenting out AINumMessage and AINameMessage
Now it compiles, but when I start or load a game it crashes.
Damn it
Original code (snipped from various .cpp files)
void DebugAI( STR szOutput )
{
#ifdef DEBUGDECISIONS
// Send regular debug msg AND AI debug message
FILE * DebugFile;
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, szOutput );
if ((DebugFile = fopen( "aidebug.txt", "a+t" )) != NULL)
{
fputs( szOutput, DebugFile );
fputs( "
", DebugFile );
fclose( DebugFile );
}
else {ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Debug: AIDEBUG.TXT = NULL" );} // SIMON
#endif
}
void AIPopMessage ( STR16 str )
{
DebugAI(str);
}
#ifdef DEBUGDECISIONS
STR16 tempstr;
#endif
#ifdef DEBUGDECISIONS
sprintf(tempstr,"%s- GETTING CLOSER to PANIC TRIGGER at grid %d (Trigger at %d)",pSoldier->name ,pSoldier->aiData.usActionData,sPanicTriggerGridNo);
AIPopMessage(tempstr);
#endif
This code gets an error where sprintf refuses to convert a STR16 string to CHAR.. or something to that effect. Could that simply because STR16 can't fit the whole text??
Anyway, I tried replacing STR16 by STR and skipping AIPopMessage (which takes a STR16 and outputs a STR to DebugAI) and it seems to work now...
#ifdef DEBUGDECISIONS
STR tempstr;
sprintf(tempstr,"%s- GETTING CLOSER to PANIC TRIGGER at grid %d (Trigger at %d)",pSoldier->name ,pSoldier->aiData.usActionData,sPanicTriggerGridNo);
DebugAI(tempstr);
#endif
Thing is, I will need to replace this in a lot of the CPP files, so I want to get your input as to whether or not this will work...
Also, I get an error for the following method (located in AIUtils)"1>c:\svn_ja2\build\tacticalai\movement.cpp(595): error C3861: 'AINumMessage': identifier not found"
void AINumMessage(const STR8 str, INT32 num)
{
STR tempstr;
sprintf( tempstr,"%s %d", str, num);
DebugAI(tempstr);
}
which is called in the following fashion in Movement.cpp :
#ifdef DEBUGDECISIONS
AINumMessage("Found a spot! ubDirection = ",ubDirection + 1);
#endif
[Updated on: Thu, 24 February 2011 04:20] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
|
Re: Learning how the AI works[message #274486]
|
Thu, 24 February 2011 23:41 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
JMich |
![](/images/ranks/first_sergeant.png) |
Messages:546
Registered:January 2011 Location: Greece |
|
|
to get F5 (Start Debugging) to work in VS2010, right click on project ja2, click properties, and then select Configuration Properties->General. The first field is called "Output Directory", which is where the executable will be built. Set this to your JA2 testing directory, for example "C:\JA2\Debug build\".
Then go to Configuration Properties->Debugging and set the "Working Directory" to the directory you set before. These 2 directories mean that any time you build your solution, you will built it in the directory it should go (instead of copying it afterwards) and you can also use F5 (Start Debugging) to run your build, whether it's a debug build or not. Do this with a version you can compile (eg svn version without any changes) and it should work. It is possible that I forgot a change, if so I will look at it again tomorrow, after I have managed to sleep.
I am also trying to see what needs to be changed so the code can compile with Define Debugdecisions but it is quite a mess, will update if I manage to compile it.
Report message to a moderator
|
First Sergeant
|
|
|
|
Re: Learning how the AI works[message #274502]
|
Fri, 25 February 2011 06:02 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
JMichto get F5 (Start Debugging) to work in VS2010, right click on project ja2, click properties, and then select Configuration Properties->General. The first field is called "Output Directory", which is where the executable will be built. Set this to your JA2 testing directory, for example "C:\JA2\Debug build\".
Then go to Configuration Properties->Debugging and set the "Working Directory" to the directory you set before. These 2 directories mean that any time you build your solution, you will built it in the directory it should go (instead of copying it afterwards) and you can also use F5 (Start Debugging) to run your build, whether it's a debug build or not. Do this with a version you can compile (eg svn version without any changes) and it should work. It is possible that I forgot a change, if so I will look at it again tomorrow, after I have managed to sleep.
I am also trying to see what needs to be changed so the code can compile with Define Debugdecisions but it is quite a mess, will update if I manage to compile it.
Re: starting debbugging.
Thanks for the tip, here's how I was doing so far:
1) I copied the .PDB , the .ILK and the .EXE files that compiled to my JA2 folder
2) Run JA2 in windowed mode. To do that, edit JA2.INI and set windowed to =1
3) In VS2010, Debug-->Attach process, then look at the output from "Debug".
Re:Compiling with Define DebugDecisions, I found the following things:
1) Do I need to replace all the "STR16 tempstr;" lines by "STR tempstr;" lines in all the .cpp files?
2) I added the following 3 lines to AI.h:
void AIPopMessage ( STR str );
void AINumMessage(const STR str, INT num);
void AINameMessage(SOLDIERTYPE * pSoldier,const STR8 str,INT32 num);
3) In AIUtils, I replaced the input of AIPopMessage, AINumMessage and AINameMessage from "STR16 str" to "STR str".
4) I forgot which CPP file, but one of the call has a type and asks for "sGridno" (type instead of "sGridNo")
5) In CreatureDecideAction, one of the "AINumMessage" wants to refer to "sClosestFriend" which doesnt exist...
Now I compile, but with warnings.
JA2 will crash when in the tactical screen, because tempstr isnt initialized...
Report message to a moderator
|
Private 1st Class
|
|
|
Re: Learning how the AI works[message #274504]
|
Fri, 25 February 2011 06:09 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
Tais STR tempstr = ""; ?
warning is gone.. thanks!
Now I get the following errors when going to the tactical screen:
First-chance exception at 0x010fe72e in JA2_EN_Debug.exe: 0xC0000005: Access violation writing location 0x0119ff46.
Unhandled exception at 0x010fe72e in JA2_EN_Debug.exe: 0xC0000005: Access violation writing location 0x0119ff46.
one in output.c, the other in sprintf.c
This will have to go on the back burner for a while, just thought I'd report on my "progress"
thanks everyone for helping.
[Updated on: Fri, 25 February 2011 06:15] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
Re: Learning how the AI works[message #274511]
|
Fri, 25 February 2011 09:05 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
JMich |
![](/images/ranks/first_sergeant.png) |
Messages:546
Registered:January 2011 Location: Greece |
|
|
CreatureDecideAction.cpp 774
ChangepSoldier->name,sClosestFriend,pSoldier->aiData.usActionData); topSoldier->name,pSoldier->aiData.sCallerGridNo,pSoldier->aiData.usActionData); since the closest friend is actually the one that is calling the soldier.
Now, for the cannot covnert parameter 1 from str to char * sprintf(char *, format, parameter value) requires a character array to insert the text, but the tempstr (or whatever else is used) is a string type, thus it cannot be used. The possibilities are either to use a char array for sprintf and then convert it to str, or have the DebugAI and the AI___Message routines use a char array. Not sure how to do either of these things.
P.S.1 I found it easier to change the AIPopMessage routine tovoid AIPopMessage ( STR16 str )
{
STR tempstr;
sprintf( tempstr, "%s", str);
DebugAI(tempstr);
}
P.S.2 Reviewing the above piece of code, it seems that sprintf can take a string type as output, but only if using string type as input? no idea exactly what's going on.
P.S.3 Anyone has any idea what the ExtMen is, as it's an undefined identifier, used for example in CreatureDecideAction.cpp, line 1360 (or thereabout). It appears to be a struct, but no idea of what/why/where.
Report message to a moderator
|
First Sergeant
|
|
|
|
Re: Learning how the AI works[message #275347]
|
Tue, 08 March 2011 17:26 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
Buns |
![](/images/ranks/first_sergeant.png) |
Messages:655
Registered:September 2010 |
|
|
From observing the AI, including milita, a bit more closer, and without looking into the code, I think I can name some major problems in its behaviour:
Investigating Sounds
The AI is drilled to investigate suspicious sounds. That makes sense when you sneek into a facility at night, but doesn't make much sense in a shoot-out at daylight. The main problems comes from soldiers not being able to differentiate between an unidentified sound (movement, you throwing a rock) and a shot.
While the first one indeed should trigger a "soldier comes looking"-behaviour, the second one would mean a "contact" that should trigger a different behaviour. The AI is able to identify the tile the sound originated from. This means in case of a shot the AI would be able to identify the tile where an opponent would be sitting and should be acting accordingly.
Latest Sound Rules
It seems the AI only reacts to the latest sound, when having heard a couple of them. When you have several mercs placed all over the map, the AI during its turn will approach the last one of them who had been shooting during your turn. In case another mercs gets an interrupt and shoots, all soldiers with APs left will change direction and move to that tile.
It would make more sense if the AI would be able to "remember" all shots you had fired during your turn, and then each soldier would approach the closest of those contacts assuming an opponent who had just been shooting out of a tile to still be there.
We are no Borg
It doesn't seem that all soldiers are able to see what one soldier sees. Even when one AI soldier has visible contact to an opponent others behave as if they don't know the opponent is there. A typical example is when one soldier is shooting at an opponent from the corner of a building, and a second soldier is around the corner without seeing the opponent. That second soldier during his turn will round the corner, run past his comrad (to investigate the sound he heard, of course), then he sees the opponent and tries to get back to the corner.
This dramatically dumbs down the AI; just imagine one of your mercs would see an enemy but you would be moving the others as if you wouldn't know of that enemy! No chance. When calculating orders and pathfinding during the AI turn, all opponents sighted by that side should be taken into account.
No Blind Shooting
I had once claimed that the AI never is shooting blindly (means on "greyed out enemies"). This is not correct: I had closely observed this during my ongoing campaign and there indeed had been two occasions (in 35 battles!) when the AI had been shooting "surpressive fire" - once of that on my vehicles. OK, in my mod most enemies are armed with bolt-action or semi-automatic rifles, but in larger armies there are usually four or five with SMGs and two or three with LMGs. And there also is no reason to limit blind shooting to autofire.
This basically is the same problem as described above: the AI should take all sightings of that side into account when creating orders for a soldiers. If there is a sighting within range, and the soldier is in a suitable position he might start shooting, even when not having visible contact himself. This would also solve the scope-problem: when the soldier has a scope on his rifle he would then see the enemy while raising the weapon for blind-shooting.
Randomized Movement
It seems large parts of AI movement is by random. You can see it very clearly with militia in tactical combat, because it shows you all their movements, not only that of the ones you see yourself, and not only those that are somewhat involved into combat.
For example, you have militias that move couched despite being far away from anything dangerous, others suddenly get up and start walking around even though in line of fire of the enemy. Most notably is the "running of 8s", which can happen within range of the enemy, but also far away from the frontline. It seems this random behaviour can kick in anytime an AI enters a tile, which can result in the AI wasting all APs for running fore and back between two tiles indentically in coverage and line of fire.
When you have your next defensive battle with militias, just leave the last three or so enemies to them and don't shoot them yourself. You would be surprised how long it can take for 32 militias to kill 3 enemies they know of. After that you wouldn't be surprised why the AI usually has no chance of killing one of your mercs with 32 soldiers.
Report message to a moderator
|
First Sergeant
|
|
|
Re: Learning how the AI works[message #275355]
|
Tue, 08 March 2011 17:47 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
JMich |
![](/images/ranks/first_sergeant.png) |
Messages:546
Registered:January 2011 Location: Greece |
|
|
// THE FOUR (4) POSSIBLE ALERT STATUSES ARE:
// GREEN - No one seen, no suspicious noise heard, go about regular duties
// YELLOW - Suspicious noise was heard personally or radioed in by buddy
// RED - Either saw opponents in person, or definite contact had been radioed
// BLACK - Currently has one or more opponents in sight How the AI reacts depends on what state the soldier is currently in. If the soldier is on green and hears a noise, he will (usually) move to investigate, if he is on yellow he has a chance (25% to 65%, depending on orders and attitude) of radioing the noise, if on red he will turn towards the noise and go prone. There is also the "Most Important Noise", which I'm not sure if it's the closest, or the loudest, or if it can tell the difference between a footstep, an explosion, a scream and a shot.
On the borg mentality, there is a chance (again depending on orders and attitudes) that if the soldier knows some enemy positions that his allies do not, he will radio the contact, but how often do we let the enemy enough time to radio in? Usually, only if there are 5+ soldiers, and we cannot kill them all in 1 turn. Same thing also explains the suppression and blind shooting (or lack of).
Finally, the movement mode of the soldiers depends once again on orders and attitude, a cunning soldier for example is more propable to move crouched than an aggressive one. Also, whenever the situation changes (enemy sighted, noise heard, better cover in view), the merc (pc/militia/soldier/civilian) has to reevaluate his/her options, and decide again whether he/she should continue or do something else. This is the reason for the back and forth, since the soldier moves around the corner, sees your pc and has no cover. Best cover is behind the corner, so he/she moves back to cover. Next turn, the soldier again has an idea of where your merc is, but no definite answer, so if he/she goes to look, the same thing will happen.
Hope this helps clarify a few things, and I will suggest you take a look at the code as well, the comments make it easy enough to understand.
Report message to a moderator
|
First Sergeant
|
|
|
Re: Learning how the AI works[message #275367]
|
Tue, 08 March 2011 19:39 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
Buns |
![](/images/ranks/first_sergeant.png) |
Messages:655
Registered:September 2010 |
|
|
Quote:Hope this helps clarify a few things, and I will suggest you take a look at the code as well, the comments make it easy enough to understand. You are of course right, I should have looked into the code before posting, but ATM I don't have the intention to start coding the tactical AI myself, and wished to limit myself to experiences what actually happens in battle.
JMichHow the AI reacts depends on what state the soldier is currently in. If the soldier is on green and hears a noise, he will (usually) move to investigate, if he is on yellow he has a chance (25% to 65%, depending on orders and attitude) of radioing the noise, if on red he will turn towards the noise and go prone. There is also the "Most Important Noise", which I'm not sure if it's the closest, or the loudest, or if it can tell the difference between a footstep, an explosion, a scream and a shot. This includes some problematic things, I think:
- The AI being required to radio doesn't do it any good: the soldier can either radio or fight (If I see that right radioing costs a lot of APs; at least both enemies and militia often don't do much else than going couched after radioing).
This is a classical dilemma, because whatever he does is wrong. When he radios he can't do anything about the enemies in his sight. So he will be shot the next turn, and whether the guys he radioed will do anything better out of the situation is another question - not to mention that the mercs probably will move on after killing that poor fellow.
When he decides to fight instead he might be able to pin you down, but unless it is a 1:1 situation or other soldiers by chance are close enough to help, he would be left alone and easy prey for your cooperativly working team.
Apart from that, the animation of radioing goes on my nerves.
So this is something I would suggest to skip: When one enemy sees you, all would know of your position (100%). You would either need to shoot him (in this case the enemy would be blind again) or move out of his sight.
Giving the enemy a certain % of what to do next is problematic too: it is difficult to define a suitable behaviour in each situation for the AI at all. Saying that in between 35% to 75% of all cases he wouldn't do even that, do something else or nothing at all means that besides the JA2 enemies already already are dumb AI, they are even coded to behave extra stupied/wrong.
Report message to a moderator
|
First Sergeant
|
|
|
Re: Learning how the AI works[message #275369]
|
Tue, 08 March 2011 20:13 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
JMich |
![](/images/ranks/first_sergeant.png) |
Messages:546
Registered:January 2011 Location: Greece |
|
|
BunsSo this is something I would suggest to skip: When one enemy sees you, all would know of your position (100%). You would either need to shoot him (in this case the enemy would be blind again) or move out of his sight. If when any soldier sees you, all have seen you, that means that all raise their alarm level, and sneaking is harder (if not impossible) to do. Think of what would happen in Alma, you kill the first soldier, and since he has seen you, panic button is pushed, and Sergeant Krott is killed. You have to kill the enemy quietly and without letting him notify to be able to save him and get the Rocket Rifle.BunsGiving the enemy a certain % of what to do next is problematic too: it is difficult to define a suitable behaviour in each situation for the AI at all. Saying that in between 35% to 75% of all cases he wouldn't do even that, do something else or nothing at all means that besides the JA2 enemies already already are dumb AI, they are even coded to behave extra stupied/wrong. If soldier.orders->Guard OR soldier.orders->Stationary
then chance = 50
else chance = 25
If soldier.attitude.defensive chance = chance + 15
If random(100) < chance
then radio
else investigate
P.S. the reason I mention the code is because it is easy to read, and usually understand, even though one may not know C++. I haven't used C in more than 8 years, and the only usage I did was an introductory university course, but I still find the code easy to follow. And after all, the more people reading the code, the more people making suggestions to the code.
Report message to a moderator
|
First Sergeant
|
|
|
Re: Learning how the AI works[message #275408]
|
Wed, 09 March 2011 14:51 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
Buns |
![](/images/ranks/first_sergeant.png) |
Messages:655
Registered:September 2010 |
|
|
JMichIf when any soldier sees you, all have seen you, that means that all raise their alarm level, and sneaking is harder (if not impossible) to do. Think of what would happen in Alma, you kill the first soldier, and since he has seen you, panic button is pushed, and Sergeant Krott is killed. This would apply when the soldier sees me during his turn:
(a)
My turn: Soldiers sees me, I see soldier. Soldier gets killed (silenced).
Next AI turn: No more soldier sees me, no alarm, all stay on green alert status
(b)
My turn: Soldiers sees me, I see soldier. Soldier not is killed (missed shot).
Next AI turn: Soldier still sees me; now all enemies know of the position of that merc. They would switch to red alert status and start approaching my position. One will blow up Sergeant Krott.
(c)
My turn: Soldiers sees me, I see soldier. Soldier is killed silenced but had been able to shoot himself before.
Next AI turn: No more soldier sees me, but a shot by a friend had been heard. This would set the others to yellow alert status with the result that they would come looking. Sergeant Krott may live on, for now.
(d)
My turn: Soldiers sees me, I see soldier. Soldier is killed by an unsurpressed shot.
Next AI turn: No more soldier sees me, but a shot by an enemy had been heard. This would set them to red alert and make them approach the concact. Sergeant Krott is blown up.
So removing the need to radio contacts would not make it impossible to sneak into Alma unnoticed, even when an enemy has seen you. You only have to make sure he doesn't survive your turn, and that no one hears you killing him. It's basically as difficult, or easy, as it is now.
But you see it yourself: the major problem is that the AI is coded with keeping in mind to make those special situations possible. This is fine for all those that do nothing but sneaking around at night. All others rather have a WTF?-experience in battle.
Another example: I just had a monster battle with lots of mercs and masses of enemies. The battlefield was stretching from the NW corner of the map to about the center with the enemy getting reinforcements all the time.
On the very western edge of the map six of my mercs had a shootout with a good dozend of enemies; both sides sitting behind rocks. This means the enemy had visible contact to those mercs, was behind suitable cover, and in a position the AI found acceptable for shooting with the weapons it had. This went on for several turns.
In the center two other squads were fighting it out with other enemies. One of these two squads managed to move around the SE flank of those enemies and opened fire at the south-easternmost enemies. The next thing that happened was that the enemies in the NW, those behind the rocks (in range of their opponents, and with visible contact) suddenly all got up and started walking to the SE. Needless to say that none survived the next turn.
A typical example how the AI primarly tries to do investigate new sounds, even when already involved in combat with opponents much closer than any new sound.
Report message to a moderator
|
First Sergeant
|
|
|
|
Re: Learning how the AI works[message #275417]
|
Wed, 09 March 2011 17:34 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
Buns |
![](/images/ranks/first_sergeant.png) |
Messages:655
Registered:September 2010 |
|
|
JMichHowever the AI does require quite some time to be able to understand what they do, and why. That's for sure. I was more or less throwing around ideas what could be done about the AI and what seems to be going wrong (in game); last but not least to keep this important discussion going.
The final goal would be to have the AI acting as reasonable as the player moves his mercs. This does not mean that I would consider it possible having any refined tactics working for the enemy, but that the AI shows a more reasonable reaction to contacts.
From my gaming experience I would consider the following things either as not covered by the code, or not properly working/broken, or being given the wrong priority:
- The "lemming-behaviour", i.e. soldiers neatly moving one by one on a tile where they will be shot.
- The inability to give closer contacts a higher priority.
- The requirement to establish personal visual contact to (already known) enemies in order to shoot or move into a proper position
- The "self-pinning", means going prone when being shot at and remain in that position even when not being able to return fire and being on a tile with no coverage
- The usage of wrong stances/movings as a result of randomization and/or pre-defined attitude
- The "forming of unions", means the gathering around certain (pointless) tiles in large numbers
- The direct rushing to a tile where opponents had been shooting from, instead of moving to a tile from where they could open fire on the suspected opponent.
- The waisting of APs for pointless, often looping, movement.
Report message to a moderator
|
First Sergeant
|
|
|
|
|
|
|
|
Re: Learning how the AI works[message #277368]
|
Wed, 06 April 2011 10:39 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
JMich |
![](/images/ranks/first_sergeant.png) |
Messages:546
Registered:January 2011 Location: Greece |
|
|
Welcome back MorgluM
Unfortunately, work and a few other projects kept me occupied, especially since I do doubt that I would use the DebugAI for debugging.
So far, it seems to me much better to use VS's debugger, especially since it does allow to change values on the fly, and thus test a bit better the AI routines. Also, while I do know how to read and modify code, I doubt I am able to understand why the DebugAI routines do not work .
I do hope you will make more sense out of the AI code than I currently do, and should you want to chat a bit more, do pop over to the IRC channel. Remember though that I am a european living at GMT +2, so don't be surprised if I'm not responding.
Report message to a moderator
|
First Sergeant
|
|
|
Semi-Success , and question re: working directory[message #277418]
|
Thu, 07 April 2011 15:26 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
MorgluM |
![](/images/ranks/private_1stclass.png) |
Messages:24
Registered:March 2004 Location: Qu |
|
|
1: Semi-Success
I managed to get JA2 to compile and run (for some time) with DEBUGDECISIONS. It posts the AI decision in aidebug.txt (most important noise heard at grid #XX, soldier #XX moving to gridno YY, Soldier ZZ offering to surrender etc...) and works fine, until, I believe, the AI tries to attack. Then, it crashes somewhere in output.c (a file related to the sprintf function, which is used to create the string that is printed to the aidebug.txt file).
Basically, I started definining tempstr as char tempstr [250]="";
2: I can't link VS2010 to JA2 the way JMich described here:
JMichto get F5 (Start Debugging) to work in VS2010, right click on project ja2, click properties, and then select Configuration Properties->General. The first field is called "Output Directory", which is where the executable will be built. Set this to your JA2 testing directory, for example "C:\JA2\Debug build\".
Then go to Configuration Properties->Debugging and set the "Working Directory" to the directory you set before. These 2 directories mean that any time you build your solution, you will built it in the directory it should go (instead of copying it afterwards) and you can also use F5 (Start Debugging) to run your build, whether it's a debug build or not.
Here is what I see when I go to the properties of the JA2 project. Nothing for "General":
Selecting Properties of the project
No "General" tab
However, when I select the properties of a part of the project, say TacticalAI, then I can see General/Working directory:
TacticalAI properties has a general tab
Any tip would be greatly appreciated
[Updated on: Thu, 07 April 2011 15:27] by Moderator Report message to a moderator
|
Private 1st Class
|
|
|
Re: Semi-Success , and question re: working directory[message #277425]
|
Thu, 07 April 2011 16:29 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
JMich |
![](/images/ranks/first_sergeant.png) |
Messages:546
Registered:January 2011 Location: Greece |
|
|
MorgluM
2: I can't link VS2010 to JA2 the way JMich described here:
JMichto get F5 (Start Debugging) to work in VS2010, right click on project ja2, click properties, and then select Configuration Properties->General. The first field is called "Output Directory", which is where the executable will be built. Set this to your JA2 testing directory, for example "C:\JA2\Debug build\".
Then go to Configuration Properties->Debugging and set the "Working Directory" to the directory you set before. These 2 directories mean that any time you build your solution, you will built it in the directory it should go (instead of copying it afterwards) and you can also use F5 (Start Debugging) to run your build, whether it's a debug build or not.
Here is what I see when I go to the properties of the JA2 project. Nothing for "General":
Selecting Properties of the project
No "General" tab
However, when I select the properties of a part of the project, say TacticalAI, then I can see General/Working directory:
TacticalAI properties has a general tab
Any tip would be greatly appreciated
You are right-clicking on Solution JA2, not project JA2. You will also have to set JA2 project as the one to start when debugging.
See here
Report message to a moderator
|
First Sergeant
|
|
|
|
Goto Forum:
Current Time: Mon Feb 10 20:28:10 GMT+2 2025
Total time taken to generate the page: 0.04219 seconds
|