Scripting the AI....

Moderators: rbodleyscott, Slitherine Core, Gothic Labs

parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Scripting the AI....

Post by parmenio »

Apologies for the open-ended topic and for the fact that I'm most likely to be re-asking questions already asked before.

I now have an application written that reverses the scenario - tiles, objects, sides and height data (it's undergoing extensive testing and a bit of polishing at the moment). It would be possible, I guess, to simply use AI_Masterplan() as-is as a simple method of remaking scenarios for playing from the other side.

However, I'd prefer if possible to be a little bit more ambitious.

I'm assuming from what I've read here that other than assigning teams, there's not much point in using the editor to configure the AI (and I know that AI_Masterplan re-assigns the teams anyway)

First questions are around SetTeamActivationStage()
Is the definition of stages simply up to the Scenario Designer or do the stage numbers used have some pre-defined meaning.

SetTeamActivationStage() calls SetTeamData() using an "index" of 2.
Other indexes I've seen are 0 (which seems to be used for co-ordinates) and 1 (don't know what that's for).
Are there other pre-defined index values?
Are there index values available to the Scenario Designer to store his/her own user-defined team data?

Thanks in advance.
rbodleyscott
Field of Glory 2
Field of Glory 2
Posts: 28294
Joined: Sun Dec 04, 2005 6:25 pm

Re: Scripting the AI....

Post by rbodleyscott »

parmenio wrote:First questions are around SetTeamActivationStage()
Is the definition of stages simply up to the Scenario Designer or do the stage numbers used have some pre-defined meaning.
The stage numbers have no predefined meanings - look at any of the scenario scripts that don't use AI_Masterplan() for examples of its use. We just used it as a tool to allow the AI for each team to switch to new instructions after certain scripted conditions are met.
SetTeamActivationStage() calls SetTeamData() using an "index" of 2.
Other indexes I've seen are 0 (which seems to be used for co-ordinates) and 1 (don't know what that's for).
I must admit that I have not explored this issue in detail. Index 0 appear to be used to specify which predefined waypoint is the teams current destination.
We did not make use of these waypoints in the AI for Pike and Shot, but specified the coordinates directly in our AI scripts.
If you do want to use them, they can be defined in the editor or alternatively in scripts using SetAIPoint(id, x, y);

Index 1 also has something to do with team movement but I am not sure what.

This is what Pip said when I asked previously:
PipFromSlitherine wrote:Data 0 is generally used for movement control, and is the only data affected by the code itself (it's set to -1 when maps are loaded and created). The others are only used in the scripts, and so you can check out their current use by doing a search on Get/SetTeamData. Obviously you can alter these uses to suit your (one assumes nefarious) purposes :)
Are there other pre-defined index values?
No.
Are there index values available to the Scenario Designer to store his/her own user-defined team data?
The index range is [0,3], so that just leaves index 3 for you to use (if you don't want to risk a clash).
Richard Bodley Scott

Image
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

Thanks for the reply.
rbodleyscott wrote:The index range is [0,3], so that just leaves index 3 for you to use (if you don't want to risk a clash).
Is it possible to store an array in that index? I'm sure I read something similar for something else - campaign variables or maybe universalvars?

A couple of questions round team aggressions values, if I may....

These are the possible values I've collected so far:

2 = Should the team stick together when it is moving?
4 = Should the team units try and avoid the enemy?
8 = Should the team ignore the enemy when they have a destination?
16 = Should the team seek out enemies if it has no destination or target given?
32 = Should the team try and work around enemies using the threat map?
64 = Should we all stay in our foxholes?
128 = Should team's non-light troops ignore light troops (unless they are very close)?
256 = Should team try to ignore non-light enemy foot (unless they are very close)?
512 = Should team try to ignore enemy mounted (unless they are very close)?
1024 = Should light troops team bug out?
2048 = Should team try to ignore enemy artillery (unless we are close enough to possibly charge them?

I have a couple of queries round the items in bold.
Based on the comments (which are lifted from the AI_GetTeam functions), does that mean if set 128 for a team other than non-light, the setting will be ignored?
Similar for 1024, will only light troops "bug out" if that aggression value is set?

Last query on this, I've no found reference to Bit 0 (i.e. a value of 1) being used anywhere, is that correct?
rbodleyscott
Field of Glory 2
Field of Glory 2
Posts: 28294
Joined: Sun Dec 04, 2005 6:25 pm

Re: Scripting the AI....

Post by rbodleyscott »

parmenio wrote:Thanks for the reply.
rbodleyscott wrote:The index range is [0,3], so that just leaves index 3 for you to use (if you don't want to risk a clash).
Is it possible to store an array in that index? I'm sure I read something similar for something else - campaign variables or maybe universalvars?
Not sure why you would want to do that, it only has 8 elements. You can specify up to 64 Universal Arrays with 8 elements each. (Though of course the existing scripts are already using some, but not close to the limit.)
128 = Should team's non-light troops ignore light troops (unless they are very close)?
1024 = Should light troops team bug out?

I have a couple of queries round the items in bold.
Based on the comments (which are lifted from the AI_GetTeam functions), does that mean if set 128 for a team other than non-light, the setting will be ignored?
Well yes. The idea is that if you have a team including some light and some non-lights, the non-lights will try to avoid being distracted by enemy light troops but the lights won't.
Similar for 1024, will only light troops "bug out" if that aggression value is set?
Yes
Last query on this, I've no found reference to Bit 0 (i.e. a value of 1) being used anywhere, is that correct?
Probably, but I wouldn't risk using it just in case it is used in some arcane way by the engine.
Richard Bodley Scott

Image
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

Thanks for the info.
rbodleyscott wrote:Not sure why you would want to do that, it only has 8 elements. You can specify up to 64 Universal Arrays with 8 elements each. (Though of course the existing scripts are already using some, but not close to the limit.)
Only that if you store a reference to an array in that index, you've got many more possible entries available (up to the size of the array).
rbodleyscott
Field of Glory 2
Field of Glory 2
Posts: 28294
Joined: Sun Dec 04, 2005 6:25 pm

Re: Scripting the AI....

Post by rbodleyscott »

parmenio wrote:Thanks for the info.
rbodleyscott wrote:Not sure why you would want to do that, it only has 8 elements. You can specify up to 64 Universal Arrays with 8 elements each. (Though of course the existing scripts are already using some, but not close to the limit.)
Only that if you store a reference to an array in that index, you've got many more possible entries available (up to the size of the array).
If you want an array of 8 more data items per team you can just make 8 Universal Arrays called (for example)

"TeamArray0"
"TeamArray1"
"TeamArray2"
"TeamArray3"
"TeamArray4"
"TeamArray5"
"TeamArray6"
"TeamArray7"

then reference them directly from the Team numbers using StartWorkString(), PrintWorkStringLiteral() and PrintWorkStringInt() to concatenate the reference names.

So you don't actually need to store references to the arrays in the TeamData.

Out of curiosity, why do you need so many data elements for each team?
Richard Bodley Scott

Image
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

rbodleyscott wrote:If you want an array of 8 more data items per team you can just make 8 Universal Arrays called (for example)

"TeamArray0"
"TeamArray1"
"TeamArray2"
"TeamArray3"
"TeamArray4"
"TeamArray5"
"TeamArray6"
"TeamArray7"

then reference them directly from the Team numbers using StartWorkString(), PrintWorkStringLiteral() and PrintWorkStringInt() to concatenate the reference names.

So you don't actually need to store references to the arrays in the TeamData.
Thanks - that was what I'd seen before.
Out of curiosity, why do you need so many data elements for each team?
Well actually at the moment, I don't know that I do :D
... I'm just trying to get a feel for the boundaries of the engine.
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

What's the maximum number of local variables I can declare in a CSCRIPT FUNCTION?
rbodleyscott
Field of Glory 2
Field of Glory 2
Posts: 28294
Joined: Sun Dec 04, 2005 6:25 pm

Re: Scripting the AI....

Post by rbodleyscott »

parmenio wrote:What's the maximum number of local variables I can declare in a CSCRIPT FUNCTION?
Autodeploy() is at the maximum - it appears to be 32. I had to get round it for that function by turning parts of it into separate functions.
Richard Bodley Scott

Image
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

rbodleyscott wrote:Autodeploy() is at the maximum - it appears to be 32.


I managed to hit it pretty much straight away as I was trying to do the following to make my AI scripts more readable:

Code: Select all

    int TRUE;
    int FALSE;
    int PARLIAMENT;
    int ROYALISTS;
    int HORSE_DRAGOONS;
    int HORSE_CAVALIERS;
    int PIKE_COLUMN_1;
    int PIKE_COLUMN_2;
    int PIKE_COLUMN_3;
    int PIKE_COLUMN_4;

    int STICK_TOGETHER;
    int AVOID_ENEMY;
    int IGNORE_ENEMY;
    int SEEK_AND_DESTROY;
    int WORK_AROUND;
    int STAY_PUT;
    int NON_LIGHT_IGNORE_LIGHT;
    int IGNORE_NON_LIGHT;
    int IGNORE_MOUNTED;
    int LIGHT_BUG_OUT;
    int IGNORE_ARTILLERY;

    TRUE = 1;
    FALSE = 0;

    PARLIAMENT = 0;
    ROYALISTS = 1;

    HORSE_DRAGOONS = 0;
    HORSE_CAVALIERS = 1;
    PIKE_COLUMN_1 = 2;
    PIKE_COLUMN_2 = 3;
    PIKE_COLUMN_3 = 4;
    PIKE_COLUMN_4 = 5;

    STICK_TOGETHER = 2;
    AVOID_ENEMY = 4;
    IGNORE_ENEMY = 8;
    SEEK_AND_DESTROY = 16;
    WORK_AROUND = 32;
    STAY_PUT = 64;
    NON_LIGHT_IGNORE_LIGHT = 128;
    IGNORE_NON_LIGHT = 256;
    IGNORE_MOUNTED = 512;
    LIGHT_BUG_OUT = 1024;
    IGNORE_ARTILLERY  = 2048;
I had to get round it for that function by turning parts of it into separate functions.
I did consider that - luckily to begin with I have a bunch of unused declarations which I've just deleted.
rbodleyscott
Field of Glory 2
Field of Glory 2
Posts: 28294
Joined: Sun Dec 04, 2005 6:25 pm

Re: Scripting the AI....

Post by rbodleyscott »

What you really want is definable constants for those AI values. Sadly the engine does not currently support those.

(Unless Pip has sneakily added them in without me noticing.)
Richard Bodley Scott

Image
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

rbodleyscott wrote:What you really want is definable constants for those AI values. Sadly the engine does not currently support those.

(Unless Pip has sneakily added them in without me noticing.)
Yes - the above was the closest I could get to #define or a const declaration.
pipfromslitherine
Site Admin
Site Admin
Posts: 9872
Joined: Wed Mar 23, 2005 10:35 pm

Re: Scripting the AI....

Post by pipfromslitherine »

I will look at whether it is practical to add something like that, although you could get the same effect perhaps by using a file and loading in the values - then you could get (what I assume you want) different values per campaign with the same scripting?

Cheers

Pip
follow me on Twitter here
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

pipfromslitherine wrote:I will look at whether it is practical to add something like that, although you could get the same effect perhaps by using a file and loading in the values - then you could get (what I assume you want) different values per campaign with the same scripting?
Pip - are you saying that the scripting API supports opening up custom files and reading data out of them?
rbodleyscott
Field of Glory 2
Field of Glory 2
Posts: 28294
Joined: Sun Dec 04, 2005 6:25 pm

Re: Scripting the AI....

Post by rbodleyscott »

parmenio wrote:
pipfromslitherine wrote:I will look at whether it is practical to add something like that, although you could get the same effect perhaps by using a file and loading in the values - then you could get (what I assume you want) different values per campaign with the same scripting?
Pip - are you saying that the scripting API supports opening up custom files and reading data out of them?
It certainly does.

//open a parser file for reading. Prefix with a # to force reading from the CORE game folder. Otherwise reads from the current campaign. Assumes a .TXT extension. Returns 0 if fails, otherwise a fileID which is used when reading data from the file. You MUST close the file when you are done.
FromFileOpen(filename)

//close the given parser file.
FromFileClose(fileID)

//returns 1 if the given chunk is present in the file. Returns 0 if the chunk is not present
FromFileFindChunk(fileID, chunk)

//returns 1 if the given tag is present in the chunk in the file. chunk ="" means global chunk. Returns 0 if the tag is not present
FromFileFindTag(fileID, chunk, tag)

//read and return a signed integer value from the denoted parser file. If chunk is an empty string uses the global chunk. Always returns 0 if the tag does not exist.
FromFileGetValue(fileID, chunk, tag)

//read a string from the given tag. If chunk is an empty string uses the global chunk. The string is placed in the 1st working string, or in the zero-based workingString[index] if included. Returns 1 if the tag exists, zero if not
FromFileGetString(fileID, chunk, tag, [index])

//reads in a number of numeric data elements from a tag. E.g. TAG 1 2 3 4. These are placed in the first work array. If chunk is an empty string uses the global chunk. count is the max number to be read. The function returns the actual number of data elements read.
FromFileGetData(fileID, chunk, tag, count)

//returns the number of chunks in the file, not including the global chunk
FromFileChunkCount(fileID)

//copies the name of the chunk into the 1st working string, or in the zero-based workingString[index] if included. Returns 1 if successful
FromFileChunkName(fileID, index, [stringIndex])

(See GetRandomArmyList() and GetRegion() in MapGenerate2.BSF in /data/battle/Scripts for examples on use. This uses the existing ArmyList.txt file but there is nothing to stop you from setting up files that are entirely new to the game).
Richard Bodley Scott

Image
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

rbodleyscott wrote:It certainly does.

....................

(See GetRandomArmyList() and GetRegion() in MapGenerate2.BSF in /data/battle/Scripts for examples on use. This uses the existing ArmyList.txt file but there is nothing to stop you from setting up files that are entirely new to the game).
Thanks - I'll take a look.
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

Is there an API function that gives you the name of the scenario currently being played?
rbodleyscott
Field of Glory 2
Field of Glory 2
Posts: 28294
Joined: Sun Dec 04, 2005 6:25 pm

Re: Scripting the AI....

Post by rbodleyscott »

parmenio wrote:Is there an API function that gives you the name of the scenario currently being played?
Pip will correct me if I am wrong, but I don't think so. I agree it would be useful.
Richard Bodley Scott

Image
parmenio
Senior Corporal - Destroyer
Senior Corporal - Destroyer
Posts: 105
Joined: Sun Jan 10, 2010 5:41 pm

Re: Scripting the AI....

Post by parmenio »

rbodleyscott wrote:Pip will correct me if I am wrong, but I don't think so. I agree it would be useful.
I'm presuming I can do something like....

Code: Select all

// CAMPAIGN.TXT
VAR BreakPoint1
VAR BreakPoint2
VAR ScenarioName

Code: Select all

// Some .BSF file
SetCampaignVar("ScenarioName", "Stratton");
..............
..............
if (GetCampaignVar("ScenarioName" ==  "Stratton")
{
}
rbodleyscott
Field of Glory 2
Field of Glory 2
Posts: 28294
Joined: Sun Dec 04, 2005 6:25 pm

Re: Scripting the AI....

Post by rbodleyscott »

parmenio wrote:
rbodleyscott wrote:Pip will correct me if I am wrong, but I don't think so. I agree it would be useful.
I'm presuming I can do something like....

Code: Select all

// CAMPAIGN.TXT
VAR BreakPoint1
VAR BreakPoint2
VAR ScenarioName

Code: Select all

// Some .BSF file
SetCampaignVar("ScenarioName", "Stratton");
..............
..............
if (GetCampaignVar("ScenarioName" ==  "Stratton")
{
}
No, because Campaign variables are Ints.

As a matter of interest, what are you hoping to do using the scenario name? Surely anything that applies to a specific scenario can be put in the scenario script?

If you want to put something in the generic scripts of your campaign, to apply only to certain scenarios, you can use

TryToCallScenarioFunction(function, [value, ...]);

to look in the scenario script to see if there is a custom version of a function.

This has been done in P&S, for example, in StandardVictoryConditions() in MoreScenarioTools.BSF, to allow the function to access special victory conditions e.g. in the Nordlingen and Lostwithiel scripts.
Richard Bodley Scott

Image
Post Reply

Return to “Scenario Design”