Relationship between 'Role' and AI

General discussion for players of Oolite.

Moderators: winston, another_commander

User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Smivs wrote:
I had a quick look at the wiki section you referenced. Should I be adding pauses between the scans, or are multiple updates the best way to go?
When you only look at your ship, you need no pauses, however, scans are commands that are relative time consuming. And when there are to many ships all busy scanning your fps rate will strongly drop, so adding a 5 to 10 second pause will improve total game performance.

I remember random-hits that was also doing an extreme amount scans per second with the result of a strong fps drop on entering such a system. After removing 99% of the scans, the fps problems were gone without any noticeable bad effect of ships not being found. Galactic navy has a similar problem when entering a setcom system. I once reduced all those scans in my private version with a strong performance boots in such systems.
I've obviously still got a lot to learn!
The quickest way to understand things is to enable AI logging for a certain ship. In order to do so, you must use the console, target a ship and type: player.ship.target.reportAIMessages = true (or short: PS.target.reportAIMessages = true). From than on all AI activity for that ship is logged, allowing you to see the command flow. It often flows different than one would expect.

Or alternatively you can switch the reportAIMessages on in the spawn actions of a ship script you are experimenting with.
Last edited by Eric Walch on Tue Oct 19, 2010 1:41 pm, edited 2 times in total.
User avatar
Smivs
Retired Assassin
Retired Assassin
Posts: 8408
Joined: Tue Feb 09, 2010 11:31 am
Location: Lost in space
Contact:

Post by Smivs »

Thanks again...this is all interesting stuff!
I think I'm right in trying these scans to achieve my goal. Just scanning for Offenders will be a bit pointless in Anarchies, the scan for Hostiles is possibly redundant but may as well be included if it's doing no harm and the scan for Pirates sort of covers the Anarchies.
I'll try

Code: Select all

UPDATE = (setCourseToPlanet, "setDesiredRangeTo: 50000.0", checkCourseToDestination, scanForOffenders, "pauseAI: 10.0" scanForHostiles, "pauseAI: 10.0" "scanForNearestShipWithPrimaryRole: pirate", "pauseAI: 10.0");
and see how I get on. :)

Edit:- I think I need to add commas (,) after the pauses.
Commander Smivs, the friendliest Gourd this side of Riedquat.
Switeck
---- E L I T E ----
---- E L I T E ----
Posts: 2411
Joined: Mon May 31, 2010 11:11 pm

Post by Switeck »

And I'll be scanning for stuff to loot/scoop in my modified trader-crossed-with-scavenger ai. :lol:
User avatar
maik
Wiki Wizard
Wiki Wizard
Posts: 2026
Joined: Wed Mar 10, 2010 12:30 pm
Location: Ljubljana, Slovenia (mainly industrial, feudal, TL12)

Post by maik »

Eric Walch wrote:
Galactic navy has a similar problem when entering a setcom system. I once reduced all those scans in my private version with a strong performance boots in such systems.
Do you know if Nemoricus is still around to fix this? Or could you upload your improved version?
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Smivs wrote:
Edit:- I think I need to add commas (,) after the pauses.
Please try doing some AI logging to get a feeling of the order of code execution. e.g. "pauseAI" does not interrupt the current code but only sets the interval for the next UPDATE execution. Doing 3 in one line has no effect as only the last will be valid. And you still do 3 scans in one command-line. For doing 3 different scans, you need 3 different stated, each doing a scan.

However, as you said, scanning for offenders will not work in anarchies and scanning for hostiles only will find ships that are already in an attack mode to that ship. And for ships with a hunter role its unlikely that there are such ships. Leaving only the scan for pirates as useful in anarchies.
User avatar
Smivs
Retired Assassin
Retired Assassin
Posts: 8408
Joined: Tue Feb 09, 2010 11:31 am
Location: Lost in space
Contact:

Post by Smivs »

Again, thanks for your help (and patience!). I should have read your previous reply more carefully. I think I understand that element now (at last :roll: ).
So, (next question), is it OK to include a series of updates? Would this work?

Code: Select all

{
	GLOBAL =
	{
		ENTER = ("setStateTo: HEAD_FOR_WITCHPOINT");
	};
	"HEAD_FOR_PLANET" =
	{
		ENTER = (setCourseToPlanet, "setDesiredRangeTo: 50000.0", checkCourseToDestination);
		"COURSE_OK" = (setSpeedToCruiseSpeed, performFlyToRangeFromDestination);
		"WAYPOINT_SET" = ("setAITo: cbhgotoWaypointAI.plist");
		"DOCKING_REQUESTED" = ("setAITo: receiveDockingAI.plist");
		"DESIRED_RANGE_ACHIEVED" = ("setStateTo: HEAD_FOR_WITCHPOINT");
		"ACCEPT_DISTRESS_CALL" = (setTargetToFoundTarget, "setAITo: cbhinterceptAI.plist");
		"OFFENCE_COMMITTED" = (setTargetToFoundTarget, "setAITo: cbhinterceptAI.plist");
           "TARGET_FOUND" = (setTargetToFoundTarget, checkTargetLegalStatus);
	        "TARGET_MINOR_OFFENDER" = ("setAITo: cbhinterceptAI.plist");
	        "TARGET_OFFENDER" = ("setAITo: cbhinterceptAI.plist");
	        "TARGET_FUGITIVE" = ("setAITo: cbhinterceptAI.plist");
		"INCOMING_MISSILE" = (setTargetToFoundTarget, "setAITo: cbhdelayedReactToAttackAI.plist");
		ATTACKED = (setTargetToPrimaryAggressor, "setAITo: cbhinterceptAI.plist");
		RESTARTED = (checkAegis);
		UPDATE = (setCourseToPlanet, "setDesiredRangeTo: 50000.0", checkCourseToDestination, scanForOffenders, "pauseAI: 10.0");
      UPDATE = ("scanForNearestShipWithPrimaryRole: pirate", "pauseAI: 10.0")
	};
One problem I (and probably others ) have is the lack of guidance on the Wiki. If you don't know this stuff the only way to learn seems to be to have a go using trial and error and to pick the brains of the people who do know, like your good self.
I'm not complaining...a detailed tutorial would be a massive bit of work and I can see why there isn't one.
Commander Smivs, the friendliest Gourd this side of Riedquat.
another_commander
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 6645
Joined: Wed Feb 28, 2007 7:54 am

Post by another_commander »

I think the best possible tutorial is already included in Oolite: Have a look at the built-in AI files in Resources and see how they work. You already know how a pirate behaves, so try to see how it is done and "follow" the AI as it runs. Look at the patrol AIs, the Constrictor AI etc. and see how it all comes together. The console trick with player.ship.target.reportAIMessages = true that Eric mentioned earlier can be of great help while you do this.
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Or when you want the fastest way of analysing a ship with AI, add it to the system with the line:

Code: Select all

system.addShips('pirate', 1, player.ship.position, 10000)[0].reportAIMessages = true
(replace pirate with your role). It adds a ship in your surroundings and immediately starts logging this ship. This way you almost get the whole AI log from start. You only miss the log of first GLOBAL state, but it will be faster than targeting first. On the mac I can easy switch logging on/off in the inspector with a checkbox, but targeting first takes time, so for following just added ships I sometimes use this way of adding.

The best manual for AI is the C-code itself. That is the source I used. At that time I hardly understood C itself but it was still a good help in understanding things. (wiki documentation was not available back than).
One other very important thing is the difference between messages that are immediately reacted upon and the messages that are put on hold for execution on the next update. On the AI page I tried to consistently use boldface for the first group of messages.
User avatar
Smivs
Retired Assassin
Retired Assassin
Posts: 8408
Joined: Tue Feb 09, 2010 11:31 am
Location: Lost in space
Contact:

Post by Smivs »

Thanks A_C. In fact that is more or less what I'm doing, and yes, you can learn a lot that way. What I'm finding now is that it doesn't help you to find out what doesn't work. Or at least it does, but not necessarily why something doesn't work.
You might argue that I shouldn't be trying to do something without knowing how to do it, but how else do you learn? All knowledge is gained from an initial position of ignorance, and while I clearly am still developing an understanding of this, my knowledge is not yet complete.
Which is one of the reasons Oolite is such an important part of my life...as well as being a truly great game, developing OXPs is one of the few stimulating and 'educational' things I get to do these days, and of course the community is second to none. :)
Commander Smivs, the friendliest Gourd this side of Riedquat.
User avatar
Kaks
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 3009
Joined: Mon Jan 21, 2008 11:41 pm
Location: The Big Smoke

Post by Kaks »

Smivs wrote:
Again, thanks for your help (and patience!). I should have read your previous reply more carefully. I think I understand that element now (at last :roll: ).
So, (next question), is it OK to include a series of updates? Would this work?

Code: Select all

{
	GLOBAL =
	{
		ENTER = ("setStateTo: HEAD_FOR_WITCHPOINT");
	};
	"HEAD_FOR_PLANET" =
	{
		ENTER = (setCourseToPlanet, "setDesiredRangeTo: 50000.0", checkCourseToDestination);
		"COURSE_OK" = (setSpeedToCruiseSpeed, performFlyToRangeFromDestination);
		"WAYPOINT_SET" = ("setAITo: cbhgotoWaypointAI.plist");
		"DOCKING_REQUESTED" = ("setAITo: receiveDockingAI.plist");
		"DESIRED_RANGE_ACHIEVED" = ("setStateTo: HEAD_FOR_WITCHPOINT");
		"ACCEPT_DISTRESS_CALL" = (setTargetToFoundTarget, "setAITo: cbhinterceptAI.plist");
		"OFFENCE_COMMITTED" = (setTargetToFoundTarget, "setAITo: cbhinterceptAI.plist");
           "TARGET_FOUND" = (setTargetToFoundTarget, checkTargetLegalStatus);
	        "TARGET_MINOR_OFFENDER" = ("setAITo: cbhinterceptAI.plist");
	        "TARGET_OFFENDER" = ("setAITo: cbhinterceptAI.plist");
	        "TARGET_FUGITIVE" = ("setAITo: cbhinterceptAI.plist");
		"INCOMING_MISSILE" = (setTargetToFoundTarget, "setAITo: cbhdelayedReactToAttackAI.plist");
		ATTACKED = (setTargetToPrimaryAggressor, "setAITo: cbhinterceptAI.plist");
		RESTARTED = (checkAegis);
		UPDATE = (setCourseToPlanet, "setDesiredRangeTo: 50000.0", checkCourseToDestination, scanForOffenders, "pauseAI: 10.0");
      UPDATE = ("scanForNearestShipWithPrimaryRole: pirate", "pauseAI: 10.0")
	};

Sorry, but your question doesn't err... compute... every few seconds the AI executes the instructions inside UPDATE, for the state it's in.

The ai is a state machine: if you are inside the state HEAD_FOR_PLANET, it will follow the update instructions found inside that state. If you are in the state SCAN_FOR_OFFENDERS, it will follow the UPDATE instructions found inside that other state.

By the way did you see this wiki page, and clicked on the state machine link? I believe it does say there that the UPDATE message is sent periodically to each ai when Oolite is running.

The whole point of programming the AI is to give the npc a set of simple to follow rules: the 'example' you wrote above doesn't quite seem simple to follow... how is the AI supposed to figure out which UPDATE is the 'right' one it should use?


Edit: to answer your question more fully: the AI is only expecting one set of instructions per UPDATE cycle per state: as a result it'll only use one update sequence - the one it finds first.

And that's exactly how any state machine is supposed to work. If you need a different UPDATE sequence, you define a new state with the new UPDATE etc, and switch to that other state.

Hope this helps too... :P
Hey, free OXPs: farsun v1.05 & tty v0.5! :0)
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Kaks wrote:
Edit: to answer your question more fully: the AI is only expecting one set of instructions per UPDATE cycle per state: as a result it'll only use one update sequence - the one it finds first.
Comment to edit: The UPDATE is a key in a plist and there can only be one unique key. So, when you define two keys with the same name, the computer already will remove the duplicate. In case of the mac, the operating system itself will already remove one of the two UPDATE lines while loading the file and Oolite itself will never know there were two UPDATES in one directory.

AI handling works just a bit different than most people think because of the mix of delayed and immediate reactions. Therefor logging is a good tool to get a feeling of program-flow. The documentation itself can also use an update. I wrote a big part of it at a time I didn't understand things as good as I do now.
But to do it right, one should start from scratch. At the moment I don't see me making time for that in the near future.
User avatar
Smivs
Retired Assassin
Retired Assassin
Posts: 8408
Joined: Tue Feb 09, 2010 11:31 am
Location: Lost in space
Contact:

Post by Smivs »

Hi again. I'd concluded that that wasn't working by trial and error, but thanks anyway. These AIs are fiendish thing, aren't they?
I think I'm close to my aim now. My AI is heavily based on the route1patrol AI as you know, and this has both outbound and inbound elements, so what I'm trying now is simply checking for offenders on the way out (Head for witchpoint) and checking for pirates on the return 'Head for Planet' run. This covers all the bases, keeps thing simple with minimal changes to the 'base' AI, and hopedully will do pretty much what I want. I'll keep you posted.
Commander Smivs, the friendliest Gourd this side of Riedquat.
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Post by Commander McLane »

Another solution would be to move the whole scanning business into a ship script. Then you would only insert the call for execution of the ship script into the AI.

In the ship script itself, which is written in JS, you can have your ship perform all sorts of much more sophisticated scans than in the AI itself. For instance it is possible to perform multiple scans. So the script could scan for offenders first (and as a side effect this would work in anarchies as well). If nothing turns up, the script could scan for pirates. If this scan returns nothing again, you could scan for something else altogether. You can continue this until one of the scans finds something (then you would cancel the rest of the scans and have your ship react to the target found), or all scans are performed.

The possibilities fpr AI programming are becoming virtually limitless, as soon as you combine the AI itself with a ship script.
User avatar
Smivs
Retired Assassin
Retired Assassin
Posts: 8408
Joined: Tue Feb 09, 2010 11:31 am
Location: Lost in space
Contact:

Post by Smivs »

Commander McLane wrote:
Another solution would be to move the whole scanning business into a ship script.
This would be the ideal solution, I agree, except for one thing. I know less about JS than I know about these AIs! I can see I'm going to have to learn, but starting from scratch as I will be it will take some time.
For now the modified Route1patrol AI seems to be working OK and will probably have to do.
It's not a desperately serious issue, as I mentioned earlier. The Contractor itself (as a player ship) is fine, and the ultra-rare Pirate NPCs are also OK as they use the standard Pirate AI, it's just that with the current release of Contractor the Bounty Hunter NPC version isn't as 'dedicated' as I'd like to tracking down and attacking offenders. Early tests with the new AI suggest that this is a notable improvement over the original so I'll probably go with that.
Having said that, if any JS jockey out there would like to contribute, I'd certainly be interested.
Commander Smivs, the friendliest Gourd this side of Riedquat.
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Post by Commander McLane »

Smivs wrote:
Having said that, if any JS jockey out there would like to contribute, I'd certainly be interested.
PM me what you have so far. I'll be glad to help out.
Post Reply