Home   Help Search Login Register  

Author Topic: Scripting: Advanced AI skill improvement  (Read 12835 times)

0 Members and 2 Guests are viewing this topic.

Komuna

  • Guest
Re:Scripting: Advanced AI skill improvement
« Reply #15 on: 03 Nov 2003, 14:16:37 »
I have to say though, that it also lags as a lot of nearestObject calls have to be done
to get a reasonable faithful terrain representation. I don't think this is really a problem
because we don't have to actually "monitor" the terrain all the time as it is mastly static.
One can make once in a while a sample of the terrain surrounding our group, store the
result, and access it from memory.In principle, monitoring the enemy is not too difficult, but it can also put some nosty strain on the CPU, because
unlike to terrain sampling it must be done regularly. Also, we not only need the positions
but also the strength/type/ability.I would say that the obstacle checker is also solved theoretically. It should best be combined with the
elevation checker to give a terrain sampler.

Checking terrain obstacles with nearestObject?!?! WOW! :wow: Such script must be a jewel! Didn't think it was possible... :hmm:

This weekend I had been testing a few Waypoint types. Indeed, "SCRIPTED" type WP allows you to call scripts with several usefull arguments; however, it would be too complicated in what concerns to behaviour randomness. So, I'll still defend my "safe-positions" theory, which allows the AI to cover and move through safe paths, "chosen" by themselves... (As "Choice" is something we can't apply to AI, I had it in quotes ;)).

For my surprise, this weekend I've seen the AI acting stealthily!!! They organized two groups each; one covered the right side of the base (Machine Gunner laid behind a bush; GL crouched next the base walls and 2 meters away from the MG; RFLman crouched behind a tree) and the other covered the entrance. I was :wow:. And it happened with no scripting, just a "Guard" waypoint and "stealth" behaviour - this last is the one that forces the AI to get covered.
Unfoutunately, at the next attempt (retry), they started again acting like fools; again and again.

So, as you can see, there's alot (maybe too much) randomness in the AI's behaviour. Scripting the AI would 'kill' such randomness; besides, if dependent on WP's, the AI would always cross the same path or maybe two different paths, being too predictable.

Now, the solutions surely dwells on the terrain/obstacles script, which - if it works with bushes and trees - will allow the AI to cover at the nearest "obstacle".
« Last Edit: 03 Nov 2003, 15:13:40 by Komuna »

Offline Spinor

  • Members
  • *
  • I'm a llama!
    • The chain of command
Re:Scripting: Advanced AI skill improvement
« Reply #16 on: 03 Nov 2003, 16:09:11 »
Quote
Spinor, could you please post this script?! This is EXACTLY what I have been wanting to be able to do for so long!
I'd love to see this! I can think of so much to do with this!
Quote
Checking terrain obstacles with nearestObject?!?! WOW!  Such script must be a jewel! Didn't think it was
possible...
Mind you, it is a bad workaround so its far from perfect and as I mentioned it puts
quite some workload on the CPU. As I don't have internet at home at the moment, it's
a little difficult to put the script up. In any case, my script is not originally intended to
determine each single object but to determine the general category of a map grid.

Anyway, here's a snippet (untested) to scan an area of size _dx * _dy around
the position [_x0,_y0]. All objects found are stored in the arrays _objs (containing all
proper objects belonging to an actual object class, e.g. buildings), _roads, _bushes
(probably also containing rocks) , _trees and _forests

;---------------------------
;center of scan area
_x0 = 5000
_y0 = 5000

;scan area size
_dx = 200
_dy = 200

;step size for nearestObject calls
_incr = 5

_objs=[]
_roads=[]
_bushes= []
_trees=[]
_forests[]


_x = _x0 - _dx/2
_y = _y0 - _dy/2

#LoopX
?!(_x < _x0 + _dx/2): goto "EndLoopX"

   #LoopY
   ?!(_y < _y0 + _dy/2): goto "EndLoopY"

       _object = nearestObject[_x,_y,0]

       ;object analysis----------------
       ;if object is of known class type (== of class "All"), it is not a road/bush/tree/forest
       ?("All" countType [_object] == 1): _objs = _objs + [_object]; goto "EndAnalysis"
       _z = (getPos _object) select 2
       ?_z < 0.2: _roads = _roads + [_object]; goto "EndAnalysis"
       ?_z < 3: _bushes = _bushes + [_object]; goto "EndAnalysis"
       ?_z < 12: _trees = _trees + [_object]; goto "EndAnalysis"
       _forests = _forests + [_object]
       ;---------------------------
       #EndAnalysis

       _y = _y + _incr
   goto "LoopY"

   #EndLoopY

   _x = _x + _incr
goto "LoopX"
#EndLoopX
;--------------------------------

If the snippet works as expected it should put all the objects, bushes, etc. into their
respective arrays. Armed with these you should be able to do all kinds of stunts,
e.g. determine the closest cover for a given unit, an analysis of good cover areas, etc.

The method is not foolproof and is bound to give some false results sometimes, e.g.
misinterpreting a tree for a bush, etc. The z-values used (0.2,3,12) are not perfect,
a little finetuning maybe required.

With the numbers given, the snippet will have to perform (200/5) * (200/5) = 1600 nearestObject
calls to scan an area of 200m * 200m.

The object analysis can be extended to determine the type of buildings, etc. through the
use of typeOf,countType. Another neat command is buildingPos. If used properly
one can determine whether a building is enterable and if yes, how many building
positions it has.






Komuna

  • Guest
Re:Scripting: Advanced AI skill improvement
« Reply #17 on: 03 Nov 2003, 17:26:47 »
Hmm... That script uses the nearestObject command in a different way, and if you're right, Spinor, then our AI problem is solved... Thing will be alot easier...

WOW! Thanks alot mate!

Offline Doolittle

  • Contributing Member
  • **
  • _this select 0
Re:Scripting: Advanced AI skill improvement
« Reply #18 on: 03 Nov 2003, 21:34:13 »
Yeah but don't forget the part about having to run it 1,600 times.

What about telling AI to be Stealthy, like you said...but then keep telling them that every 5 seconds or so.  Maybe each time you give the command they run for cover...but then come out after they find cover.  This might keep them in cover.

Doolittle

Offline General Barron

  • Former Staff
  • ****
  • Semper Fi!
Re:Scripting: Advanced AI skill improvement
« Reply #19 on: 03 Nov 2003, 22:55:18 »
Quote
_object = nearestObject[_x,_y,0]

A couple Q's here. First, why are you passing 3 parameters to nearestObject. Doesn't it only take 2? And second, what is the "0"? Is that what I think it is? Does that make it return the nearestobject of any type?!?! How come I never knew this?!

Quote
?("All" countType [_object] == 1): _objs = _objs + [_object]; goto "EndAnalysis"

Could you explain this line? How could the object not fall under the "any" class? Doesn't everything fall under the any class?
HANDSIGNALS COMMAND SYSTEM-- A realistic squad-control modification for OFP
kexp.org-- The best radio station in the world, right here at home! Listen to John Richards!

Unnamed

  • Guest
Re:Scripting: Advanced AI skill improvement
« Reply #20 on: 04 Nov 2003, 03:32:28 »
Quote
Yeah but don't forget the part about having to run it 1,600 times.

You dont have to, just run it for area's of interest or when something happens.

Quote
First, why are you passing 3 parameters to nearestObject. Doesn't it only take 2?

You only need to pass the XYZ coordinates of the position you want to search from, if no type class is provided I it gets any of them.

Quote
How could the object not fall under the "any" class? Doesn't everything fall under the any class?

If you use the typeof command. Roads,bushes,trees and forests do not return a type. So I guess "ALL" is all CfgVehicle types or something like?

Offline General Barron

  • Former Staff
  • ****
  • Semper Fi!
Re:Scripting: Advanced AI skill improvement
« Reply #21 on: 04 Nov 2003, 09:15:53 »
Quote
You only need to pass the XYZ coordinates of the position you want to search from, if no type class is provided I it gets any of them.

Wow! News to me. And good news at that! Excuse me now; I have to go play.....
HANDSIGNALS COMMAND SYSTEM-- A realistic squad-control modification for OFP
kexp.org-- The best radio station in the world, right here at home! Listen to John Richards!

Komuna

  • Guest
Re:Scripting: Advanced AI skill improvement
« Reply #22 on: 04 Nov 2003, 15:04:16 »
Incredible... :wow: nearestObject's main syntax requires two arguments:

nearestObject [[x,y,z],"Type"]

or

nearestObject [object, "Type"]

However, and that's really amasing to me, nearestObject works by giving a position and ignore the type:

nearestObject [x,y,z]


So, you can detect anything and everything...!
Now, that's the problem... We don't want to detect either roads or marks... So, we'll have to do a few tricks.

Roads, like most of the buildings are at level 0m according to the groud level. But they don't return any class name; besides, nearestBuilding solves us the building detection problem, and so, every objects between level 1 and -1 shall be ignored.

Marks (a strange invisible thing I've detected in the islands, usualy called "stopa_l" or "stopa_p" - not sure, though) are at the same level of buildings (between 1 and -1). Therefore, they can easily be ignored, by calling their z-value.

Bushes, rocks and trees have usualy a z-value higher than 2m. These are easy to define (mainly trees, which are 8~20m tall - while bushes and rocks have the same level :().


In conclusion:

wood/desert land combat - nearestObject (ignore <1 z-values)
urban combat - nearestBuilding

Storing the buildings settings into an array, regarding each type - [width, length, number of inner positions] - is a good way of making the AI to walk along them and explore them.
« Last Edit: 05 Nov 2003, 10:39:34 by Komuna »

Offline Spinor

  • Members
  • *
  • I'm a llama!
    • The chain of command
Re:Scripting: Advanced AI skill improvement
« Reply #23 on: 04 Nov 2003, 16:57:24 »
Quote
Yeah but don't forget the part about having to run it 1,600 times.

What about telling AI to be Stealthy, like you said...but then keep telling them that every 5 seconds or so.  Maybe each
time you give the command they run for cover...but then come out after they find cover.  This might keep them in
cover.
Like unnamed said, its not necessary to do it continually. An even better solution
is to run this "terrain scanning" in the background with a low priority (put large
waiting times within the loops).
Anyway, for simple things like "Take cover" I would also try your suggestion of using
"Stealth" mode first. If we want to write our own AI that is able to "intelligently" use
terrain features, a proper analysis of the terrain is necessary, though.

Quote
If you use the typeof command. Roads,bushes,trees and forests do not return a type. So I guess "ALL" is all
CfgVehicle types or something like?
Yes, "All" covers all vehicle classes, but roads/bushes/trees/forests do not belong to any class.

Quote
Now, that's the problem... We don't want to detect either roads or marks... So, we'll have to do a few tricks.

Roads, like most of the buildings are at level 0m according to the groud level. But they don't return any class name;
besides, nearestBuilding solves us the building detection problem, and so, every objects between level 1 and -1 shall
be ignored.

Marks (a strange invisible thing I've detected in the islands, usualy called "stopa_l" or "stopa_p" - not sure, though)
are at the same level of buildings (between 1 and -1). Therefore, they can easily be ignored, by calling their z-value.

Bushes, rocks and trees have usualy a z-value higher than 2m. These are easy to define (mainly trees, which are 8~20m
tall - while bushes and rocks have the same level ).
I haven't noticed the marks yet. Any idea what they are for?

One clarification about buildings. nearestBuilding only returns enterable buildings.
To capture "fake" buildings you need to check for the "Buildings" class of a given
object. If needed, with countType and typeOf you can determine subclasses
or the exact type of building.

I found that forests objects (i.e. not single trees, but a section of a forest patch) have the
highest z-value of about 22 meters.

Another trick to differentiate between types is to use getDir. E.g. roads mostly have a
non-zero direction (naturally), whereas trees and bushes have zero direction. I'm not sure
about rocks.

Komuna

  • Guest
Re:Scripting: Advanced AI skill improvement
« Reply #24 on: 05 Nov 2003, 10:36:58 »
I've finished editing the first version of Spinor's script. It looks really nice, but I'll have to implement a few more features. It detects 65% to 100% of the objects in a given area. It ignores classed objects - AI units, buildings and other structures - and stores every detected object in a proper array:

roads for unclassed objects with less than 0.2m. Note: stopa_@ usualy have the same height of roads, but they're class-named as "Marks". I can't figure out what they are.

rock_bush for bushes and rocks. I can't distinguish them through scripting.

trees for trees with more than 6.5m and less than 12.5m.

forest for forest sections with more than 12.5m. There are a few trees with 25m (!!!) and which will be considered forest. There's nothing we can do... yet.

I've fully tested this first version. Kedgety's/Gunslinger's editor update doesn't cause any conflicts with the script. The script doesn't cause any lag in my old Buddy (400MHz), though it takes 20 seconds to finish looping in an area of 500x500m2. Scanning an area of 100x100m2 is basically instantaneous - my old buddy takes 0.5~1 seconds to finish scanning.

The mission sample contains a trigger with the size of the area to be scanned; therefore, every objects within that area shall be detected, except when they're too close of each other - in this case, only a few will be detected. It also contains a JPEG with a sample of the monitoring grid (made with flag poles).

In a further version I'll implement an area angle setting, which allows the script to work exactly like a trigger. Besides, the conditions I use (which are quite large) will be writen in a function which will be called by the script everytime it is required.


Note: Looks like I'm having problems in attaching the zip-file. I'll be able to do it in a few hours (about 1:30pm GMT). See ya!

#Edit

I've just forgot the following:

This script looks like solved. It shall be used only in open area combat. For the urban combats, we shall make a new script which consists in:

Detect buildings included in an array of classes (which can be modified by the editor through a variable!). The class names array should consist in a group of arrays (arrays within array) containing the settings of each building type: ["Class Name", length, width, number of positions (for open build')]. With such array we'll be able, as I've said, to have an AI unit to explore it and positionate at it's corners.

Then, after the "urban combat terrain monitor", we must make a script returning the terrain elevation gradient between the enemies and the surrounding area. With such script, tha AI will be able to decide which position is better for attacking the enemy.
Unlike the medieval ages, where whoever had the mountains, would have advantage; with powder, the highest positions are the best targets! A depresion is an excellent positon for hiding from the enemy, while a hill is the best position for guarding an area.

After that script, then, we'll start to make the great "AI units interaction script", consisting on the unit's behaviour according the terrain settings and the enemy. And after that we'll have to make the "Inter-Group interaction script" - which I believe there are already some good samples - and the "Intra-group interaction script".


Awaiting for the mission sample... (1:30pm GMT)

#Edit2

EhEh! Geometry writen test went bad... ::) :-\ So, I got out later... It's now 1:40pm

Here's the sample (not big deal, though, Spinor...)

Code: [Select]
;Original script by Spinor
;Improvements and modifications by MorMel (Komuna at OFPEC)

;[position - array[x,y], scanning area - array[length,width], angle - integer, step - integer] exec "TerrainChecker.sqs"

;center of scan area
_i = (_this select 0) select 0
_j = (_this select 0) select 1

;scan area (divided by two)
_l = ((_this select 1) select 0) / 2
_w = ((_this select 1) select 1) / 2

;angle of the area shape
;Note: this feature hasn't been coded, yet.
_ang = _this select 2

;step size
_incr = _this select 3

_objs=[]

_x = _i - _l

#X

_y = _j - _w

#Y

IF (({(format["%1",typeOf _x] != "")||(isNull _x)||(_x in _objs)} count [nearestObject [_x,_y,3]]) == 0) THEN {_objs = _objs + [nearestObject [_x,_y,3]]}

_y = _y + _incr

? _y <= _j + _w : Goto "Y"

_x = _x + _incr

? _x <= _i + _l : Goto "X"

_roads=[]
_rock_bush=[]
_trees=[]
_forest=[]

{IF (position _x select 2 < 0.2) THEN {_roads=_roads+[_x]} ELSE {IF (position _x select 2 < 6.5) THEN {_rock_bush=_rock_bush+[_x]} ELSE {IF (position _x select 2 < 15) THEN {_trees=_trees+[_x]} ELSE {_forest=_forest+[_x]}}}} forEach _objs

hint format ["total: %1\nroads: %2\nrocks&bushes: %3\ntrees: %4\nforests: %5",count _objs, count _roads, count _rock_bush, count _trees, count _forest]

exit
« Last Edit: 05 Nov 2003, 14:59:36 by Komuna »

Offline Spinor

  • Members
  • *
  • I'm a llama!
    • The chain of command
Re:Scripting: Advanced AI skill improvement
« Reply #25 on: 05 Nov 2003, 13:16:45 »
Sounds excellent, Komuna  :)

Quote
rock_bush for bushes and rocks. I can't distinguish them through scripting.
Have you tried getDir yet? I could imagine most rocks are rotated somehow.

Quote
orest for forest sections with more than 12.5m. There are a few trees with 25m (!!!) and which will be considered
forest. There's nothing we can do... yet.
One way to distinguish between them is to check for nearby forests. Forests always come in patches
and a typical patch consists of about 20 forest objects or so, which are placed very regularly.
So, if you have an assumed forest object, check if another one is close by (30-40m). If yes,
make it a forest, if no, a tree.

Quote
The mission sample contains a trigger with the size of the area to be scanned;
One Q here: Why do you need a trigger? The trigger does not catch map objects, only vehicles/units.
The obstacle monitor should work fine without a trigger.

Quote
It shall be used only in open area combat. For the urban combats, we shall make a new
script
In the end, I would suggest a single script, that unifies both. Otherwise, you have to
externally check if a map section is urban or open area. Mixed terrain even complicates
this.

Komuna

  • Guest
Re:Scripting: Advanced AI skill improvement
« Reply #26 on: 05 Nov 2003, 14:53:16 »
One Q here: Why do you need a trigger? The trigger does not catch map objects, only vehicles/units.

EhEh! I use the trigger just for reference! It only activates the script and gives the editor an idea of the area to be scanned... Nothing special, indeed.

Quote
In the end, I would suggest a single script, that unifies both. Otherwise, you have to
externally check if a map section is urban or open area. Mixed terrain even complicates
this.

Mix them? Might be a solution, but I was thinking that each script type would be configured by the editor according to the area's nature - urban or open.

But that's not a problem. First we make all the required script's. Then we mix them, create some extra scripts and delete the one's we don't need.

#Edit

Code: [Select]
IF (({(format["%1",typeOf _x] != "")||(isNull _x)||(_x in _objs)} count [nearestObject [_x,_y,3]]) == 0) THEN {_objs = _objs + [nearestObject [_x,_y,3]]}
You might be wondering why I use such a complex condition (instead of calling nearestObject everytime I need to check a cond).

The answer is simple: calling nearestObject several times will increase the game lag (Wo! Imagine in my 400MHz) and, due to OFP bugs, it might also detect a diferent obj each time use call it...

Note: the "Angle" feature ahsn't been coded yet. Maybe tomorrow I'll have that finished, as long with the building detector.
« Last Edit: 05 Nov 2003, 14:58:15 by Komuna »

Offline Spinor

  • Members
  • *
  • I'm a llama!
    • The chain of command
Re:Scripting: Advanced AI skill improvement
« Reply #27 on: 05 Nov 2003, 15:20:09 »
Quote
Mix them? Might be a solution, but I was thinking that each script type would be configured by the editor according
to the area's nature - urban or open.
Yup, that should work nicely. Sorry, I have to admit that I view most of this stuff in combination
with the Command Engine and in that case everything is so dynamic (when AI is included, even
more) that it is impossible for the mission-designer to assign a specific area.

Offline KTottE

  • Former Staff
  • ****
Re:Scripting: Advanced AI skill improvement
« Reply #28 on: 05 Nov 2003, 20:17:19 »
Perhaps we should use this tread as a development place for this?
I.E post updates on scripts and such, so that we can all work to create one bad-ass system.

Because I'm very willing to help out :)

edit

Or in other words:

Post your bloody scripts so I can help out ;D

edit 2

Ok, I've tested this some, apparently it takes forever to scan an entire island (12800 x 12800), it doesn't lag while doing it (not noticable in the test-mission) but it takes bloody ages.
A 512 x 512 area took 35 ingame seconds for me to scan (440 objects in total), so if you plan on using this you need a good way of breaking it down.

I suppose one could just scan a smaller area around each AI group leader, 256 x 256 gives the AI enough room to manouver in, and doesn't take that long to scan.
« Last Edit: 06 Nov 2003, 10:55:26 by KTottE »
"Life is not a journey to the grave with the intention of arriving safely in a pretty and well preserved body, but rather to skid in broadside, thoroughly used up, totally worn out, and loudly proclaiming 'WOW What a Ride!'"

Komuna

  • Guest
Re:Scripting: Advanced AI skill improvement
« Reply #29 on: 06 Nov 2003, 13:35:10 »
I suppose one could just scan a smaller area around each AI group leader, 256 x 256 gives the AI enough room to manouver in, and doesn't take that long to scan.

Indeed.

The "Advanced AI skill improvement" is far from being finished. This script I've edited is just a very small part of a big scripting process. So, finding a solution for reducing the scanning time is not reliable, yet.

In this way, we shall wait for the other scripts and only then find a solution according to the whole scripts-set conditions.


P.S.: I've been a little lazy and, yesterday, instead of studing physics or coding the scripts - as I had promissed - I prefered to shoot down a few thunderbolts with the SU25BM... Sorry! :o ;D

#Edit

You might be wondering why I use such a complex condition (instead of calling nearestObject everytime I need to check a cond).

Well. Why didn't I store the nearest object into a variable, then?
That's what I forgot to explain: everytime I stored the nearest object into a variable, the stored value was a bug: the well known "fdeeee :sdbsgh - something I can't remember". This value doesn't mean anything, it works like a null value. So, storing it into the objects array would be usefull... I could try storing the initial value into an array for testing the condition (_temp = [nearestObject [_x,_y,3]]), but I though such thing wasn't needed, so... I made that condition.
« Last Edit: 06 Nov 2003, 13:54:13 by Komuna »