Page 63 of 118

Re: Scripters cove

Posted: Tue Feb 12, 2013 12:25 pm
by Rorschachhamster
I made this AI for my freighttrain. The idea is, that it flies to a random station and then searchs for another random station to fly to... but if I check the destination in the debug console, it's changing it constantly... so it just flies around and almost ever into empty space in something that looks like a very big circle. :?
Help! :P

Code: Select all

{
    GLOBAL = {		
	ENTER = ("randomPauseAI: 1.0 2.0");
	UPDATE = ("setStateTo: SETUP_FLIGHT");
	}; 
	
	"SETUP_FLIGHT" = {
	ENTER = ("setDesiredRangeTo: 30000000.0", setTargetToRandomStation);
	"STATION_FOUND" = (setDestinationToTarget, "setDesiredRangeTo: 30000.0", "setStateTo: HEAD_FOR_RANDOMSTATION");
	"NO_STATION_IN_RANGE" = (setCourseToPlanet, "setDesiredRangeTo: 30000.0", "setStateTo: HEAD_FOR_RANDOMSTATION");
	UPDATE = ();
	};
	
    	
    FLEEING = {
        ENTER = ("setDesiredRangeTo: 25600", performFlee); 
        "ESCORT_ATTACKED" = (setTargetToPrimaryAggressor, groupAttackTarget);
        "DESIRED_RANGE_ACHIEVED" = ("setStateTo: HEAD_FOR_RANDOMSTATION"); 
        "INCOMING_MISSILE" = (setTargetToPrimaryAggressor, groupAttackTarget, "setDesiredRangeTo: 25600", performFlee); 
        "REACHED_SAFETY" = ("setStateTo: HEAD_FOR_RANDOMSTATION"); 
        "ATTACKED" = (setTargetToPrimaryAggressor, broadcastDistressMessage, groupAttackTarget, "setDesiredRangeTo: 25600", performFlee);
        "GROUP_ATTACK_TARGET" = (setTargetToPrimaryAggressor, fightOrFleeHostiles, fightOrFleeMissile, broadcastDistressMessage, "setDesiredRangeTo: 25600", performFlee);
        "TARGET_LOST" = ("setStateTo: HEAD_FOR_RANDOMSTATION"); 
        "TARGET_DESTROYED" = ("setStateTo: HEAD_FOR_RANDOMSTATION");
        UPDATE = (); 
    }; 

    	
	"HEAD_FOR_RANDOMSTATION" = {
	ENTER = (performStop);
	"COURSE_OK" = ("setSpeedFactorTo: 0.5", performFlyToRangeFromDestination);
	"DESIRED_RANGE_ACHIEVED" = ("pauseAI: 30.0", "setStateTo: SETUP_FLIGHT");
    "INCOMING_MISSILE" = (setTargetToPrimaryAggressor, fightOrFleeHostiles, fightOrFleeMissile, "setStateTo: FLEEING");
	"ATTACKED" = (setTargetToPrimaryAggressor, fightOrFleeHostiles, fightOrFleeMissile, "setStateTo: FLEEING"); 
	"ESCORT_ATTACKED" = (setTargetToPrimaryAggressor, groupAttackTarget);
	"GROUP_ATTACK_TARGET" = (setTargetToPrimaryAggressor, fightOrFleeHostiles, fightOrFleeMissile, "setStateTo: FLEEING");
	UPDATE = ("setDesiredRangeTo: 30000.0", checkCourseToDestination, scanForHostiles, "pauseAI: 10.0");
	}; 
}
Please? :cry:

Re: Scripters cove

Posted: Tue Feb 12, 2013 1:12 pm
by Smivs
You have a loop in the AI. In "SETUP_FLIGHT" whether you find a station or not, you set the state to "HEAD_FOR_RANDOMSTATION". In this state you then "performStop" but also tell the ship to fly to range from destination, and when the desired range is achieved, you switch back to "SETUP_FLIGHT" and the whole thing starts again.
There are other issues as well, but that's probably why your ship is flying around in circles.

Re: Scripters cove

Posted: Tue Feb 12, 2013 2:16 pm
by Eric Walch
No direct relation to the problem but in the last UPDATE you must use:

Code: Select all

			setTargetToLastStation,
			"setDesiredRangeTo: 30000.0",
			setDestinationToTarget,
This to make sure you go to the last random station. Or you will go wrong after an attack.

Re: Scripters cove

Posted: Tue Feb 12, 2013 2:42 pm
by Rorschachhamster
Thank you.

I'm still trying to understand this - performStop deletes the set destination? :?: (Would make sense, now that I think about it... :? )
Because it is thought to loop, after arriving at the destination, to get a new target station. The thing is, it almost always finds a station, says debug console... and if not, it is supposed to fly to the planet and then pick another station (at least the system station should always be in this 3000000 range...)

@eric - Hmm, I had setTargetToLastStation somewhere in, before trying to do it another way... :roll: :lol: Oh, and would the planet check as station to setTargetToLastStation?
I'll make that the main station for now... could make proplems if there is no other station near it... :|

I'll try it. Be right back! :wink:

Re: Scripters cove

Posted: Wed Feb 13, 2013 7:21 pm
by Rorschachhamster
Sorry for the double post, but I can't get it right. I have changed it now and it seems to do what I want .... only it doesn't.
This is what the AI logs:

Code: Select all

19:51:59.088 [ai.takeAction]: Traction Engine 401 to take action setTargetToLastStation
19:51:59.088 [ai.takeAction]: Traction Engine 401 to take action setDesiredRangeTo: 30000.0
19:51:59.088 [ai.takeAction]: Traction Engine 401 to take action setDestinationToTarget
19:51:59.088 [ai.takeAction]: Traction Engine 401 to take action checkCourseToDestination
19:51:59.089 [ai.takeAction]: Traction Engine 401 to take action scanForHostiles
19:51:59.089 [ai.message.receive]: AI Freighttrain_AIs.plist for Traction Engine 401 in state 'HEAD_FOR_RANDOMSTATION' receives message 'NOTHING_FOUND'. Context: handling deferred message, stack depth: 0
19:51:59.089 [ai.message.receive]: AI Freighttrain_AIs.plist for Traction Engine 401 in state 'HEAD_FOR_RANDOMSTATION' receives message 'COURSE_OK'. Context: handling deferred message, stack depth: 0
19:51:59.089 [ai.takeAction]: Traction Engine 401 to take action setSpeedFactorTo: 0.5
19:51:59.089 [ai.takeAction]: Traction Engine 401 to take action setDesiredRangeTo: 30000.0
19:51:59.089 [ai.takeAction]: Traction Engine 401 to take action performFlyToRangeFromDestination
19:51:59.089 [ai.takeAction]: Traction Engine 401 to take action pauseAI: 10.0
...and repeat.

"NOTHING_FOUND" is from scanForHostiles? Because if I look at the target in the debug console it shows always some station or another. But... it doesn't go there. Does a ship not fly in a straight line towards it's destination? And "Course_OK" comes from the checkCourseToDestination, so it should work, as the target is a station, it sets the target as destination and performFlyToRangeFromDestination fires, too? :shock: :? :roll: :evil: :x :cry: :lol:
Because if I check the destination in the debug console it changes constantly and is not the target station. Wich could be perfectly normal. For all I know. :wink:
So a little help, please?

Re: Scripters cove

Posted: Wed Feb 13, 2013 8:37 pm
by GGShinobi
Sorry Rohrschachhamster, but I can't help you on this. :(

I've got some problem of my own, or rather some strange behaviour I want to report.

Since subentities can't be restored selectively but only all together / at once, in order to simulate the repair of only a single subentity with my External Repair System (ERS), I wrote a function which destroys all subentites that have not been repaired by the ERS after I called player.ship.restoreSubEntities(). Or at least it ought to do this (it does now in my updated version), but it didn't work properly and it took me some time to find out why.

Here is the original code:

Code: Select all

this.$setupSubentities = function() {
  var damagedSubents = $getDamagedSubentsAsString();
  $showDebugInfo("damagedSubents: " + damagedSubents, 1);

  for (var x in player.ship.subEntities) {
    var subentity = player.ship.subEntities[x];
    $showDebugInfo("setting up subEnt(" + x + "): " + subentity, 1);
    // if subentity is marked as damaged, remove it / damage it again (it might just have been restored by "restoreSubentities()")
    if (damagedSubents.indexOf("" + subentity) > -1) {
      $showDebugInfo("removing damaged subentity(" + x + "): " + subentity, 1);
      player.ship.subEntities[x].remove(true); // true: suppress death event
    } else {
      // subentity is operational => prepare subentity for ERS by setting up "subentity died" functions
      $showDebugInfo("preparing subentity for ERS repairs(" + x + "): " + subentity, 1);
      // remember original shipDied() in order to be able to start it later:
      player.ship.subEntities[x].script._shipDiedOld = player.ship.subEntities[x].script.shipDied;
      player.ship.subEntities[x].script.shipDied = function(whom, why) {
        worldScripts["GGIndustries_ERS_MainScript.js"].$notifyERS(this.ship, why); // let ERS know that subentity has been destroyed
        if (this._shipDiedOld) {
          this._shipDiedOld(whom, why);
        }
      }
    }
  }
}
The part which ought to remove all subentities that are known to be damaged didn't work. Only some of the subentities where removed, but approximately half of it was skipped. :!: Through many experiments I came to the conclusion that the reason for this is that the for-loop

Code: Select all

  for (var x in player.ship.subEntities) {
doesn't grant access to all members of player.ship.subEntities because the line

Code: Select all

player.ship.subEntities[x].remove(true);
changes the array so that player.ship.subEntities[x] varies over the loop-iterations. So, for instance, let's say there are seven subentities marked as damaged of a total of 8 subentites, what happens is that player.ship.subentites[0] to player.ship.subEntities[4] still return a subEntity, but player.ship.subEntites[5] does not because the array has already been shrinked by "subEntites[x].remove()". Therefore, approximately half of the subEntites which ought to get removed will stay alive.

:idea: My quick workaround for this is to only mark the subEntities for removal as long as I'm inside the for-loop, and to remove them after I left it. That way it works!

Here is the working version:

Code: Select all

this.$setupSubentities = function() {
  var damagedSubents = $getDamagedSubentsAsString();
  $showDebugInfo("damagedSubents: " + damagedSubents, 1);

  var subents2Remove = new Array();
  for (var x in player.ship.subEntities) {
    var subentity = player.ship.subEntities[x];
    $showDebugInfo("setting up subEnt(" + x + "): " + subentity, 1);
    // if subentity is marked as damaged, remove it / damage it again (it might just have been restored by "restoreSubentities()")
    if (damagedSubents.indexOf("" + subentity) > -1) {
      $showDebugInfo("removing damaged subentity(" + x + "): " + subentity, 1);
      // player.ship.subEntities[x].remove(true); // true: suppress death event // can't do it immediately because this will change player.ship.subEntities, preventing access to all
      subents2Remove.push(player.ship.subEntities[x]);
    } else {
      // subentity is operational => prepare subentity for ERS by setting up "subentity died" functions
      $showDebugInfo("preparing subentity for ERS repairs(" + x + "): " + subentity, 1);
      // remember original shipDied() in order to be able to start it later:
      player.ship.subEntities[x].script._shipDiedOld = player.ship.subEntities[x].script.shipDied;
      player.ship.subEntities[x].script.shipDied = function(whom, why) {
        worldScripts["GGIndustries_ERS_MainScript.js"].$notifyERS(this.ship, why); // let ERS know that subentity has been destroyed
        if (this._shipDiedOld) {
          this._shipDiedOld(whom, why);
        }
      }
    }
  }

  // remove damaged subEntities:
  for (var x in subents2Remove) {
    $showDebugInfo("subents2Remove(" + x + "): " + subents2Remove[x], 1);
    subents2Remove[x].remove(true); // true: suppress death event
  }
}
Is this behaviour of subEntities.remove() intentional? It sure makes sense, but for writers of OXP's which think they can remove all subEnts in a single for-loop this might come quite unexpected (as it was for me). :roll: :?:

Re: Scripters cove

Posted: Wed Feb 13, 2013 8:43 pm
by cim
GGShinobi wrote:
Is this behaviour of subEntities.remove() intentional? It sure makes sense, but for writers of OXP's which think they can remove all subEnts in a single for-loop this might come quite unexpected (as it was for me). :roll: :?:
As a general rule, removing elements from the array you're currently iterating over is a bad idea. In some cases you can do it safely by iterating backwards over the array.

Re: Scripters cove

Posted: Wed Feb 13, 2013 8:53 pm
by GGShinobi
cim wrote:
GGShinobi wrote:
Is this behaviour of subEntities.remove() intentional? It sure makes sense, but for writers of OXP's which think they can remove all subEnts in a single for-loop this might come quite unexpected (as it was for me). :roll: :?:
As a general rule, removing elements from the array you're currently iterating over is a bad idea. In some cases you can do it safely by iterating backwards over the array.
Ooooh!!! :mrgreen: And I already wondered why Solonar iterated backwards when deactivating all turrets in his Turret Toggler!! :idea: :oops:

And I also thought that "remove()" was a function of the subEntity, not of the array ship.subEntities... well! :roll:

Hey, this was my 222th post! Cool number! :mrgreen:

Re: Scripters cove

Posted: Wed Feb 13, 2013 9:30 pm
by cim
GGShinobi wrote:
And I also thought that "remove()" was a function of the subEntity, not of the array ship.subEntities... well! :roll:
It is a function of the subentity. However, the next time you query the array, the subentity, having been removed, is no longer in it, as removing the subentity requires removing it from the ship's list of subentities.

Re: Scripters cove

Posted: Wed Feb 13, 2013 9:44 pm
by GGShinobi
cim wrote:
GGShinobi wrote:
And I also thought that "remove()" was a function of the subEntity, not of the array ship.subEntities... well! :roll:
It is a function of the subentity. However, the next time you query the array, the subentity, having been removed, is no longer in it, as removing the subentity requires removing it from the ship's list of subentities.
I see! Makes perfect sense! Thanks again, cim! :mrgreen:

Re: Scripters cove

Posted: Thu Feb 14, 2013 4:00 am
by Wildeblood
Similarly with system.allShips which is an array, you can't use system.allShips[x] instead of a pointer to a particular ship, because as ships are being continually added and removed from the system the position of a particular ship in the array continually changes.

Re: Scripters cove

Posted: Fri Feb 15, 2013 2:01 am
by GGShinobi
Wildeblood wrote:
Similarly with system.allShips which is an array, you can't use system.allShips[x] instead of a pointer to a particular ship, because as ships are being continually added and removed from the system the position of a particular ship in the array continually changes.
Thanks Wildeblood! Good to know!

Re: Scripters cove

Posted: Sun Feb 17, 2013 11:22 am
by Rorschachhamster
Is there an easy way to get an ship to orbit the main planet again and again with a considerable speed? :|

I tried a framecallback with a "vector correction", but it looks shaky from up close:

Code: Select all

this.OrbitSatellite = function(delta)
	{
     var targetVector = system.mainPlanet.position.subtract(this.ship.position).direction();
     this.ship.orientation = targetVector.rotationTo([0, 1, 0]);	
	}
Oh, and I still argue with my freighttrains AI, but it is rather stubborn to do it's own thing :wink:

Re: Scripters cove

Posted: Sun Feb 17, 2013 11:48 am
by Eric Walch
A year ago I wrote a small orbiter script. Not with frameCallbacks, but just with AI:

Code: Select all

{
    GLOBAL = {ENTER = ("setStateTo: ORBIT_PLANET");
    };
    ORBIT_PLANET = {
        "COURSE_OK" = ("setSpeedFactorTo: 0.65", performFlyToRangeFromDestination);
        "WAYPOINT_SET" = ("setAITo: gotoWaypointAI.plist");
        "TARGET_FOUND" = (setTargetToFoundTarget, "setAITo: traderInterceptAI.plist", fightOrFleeHostiles);
        "INCOMING_MISSILE" = ("setAITo: traderInterceptAI.plist", "setStateTo: INCOMING_MISSILE", "randomPauseAI: 0.5 2.0"); 
        ATTACKED = ("setAITo: traderInterceptAI.plist", fightOrFleeHostiles);
        UPDATE = ("sendScriptMessage: newOrbitPoint", "setDesiredRangeTo: 500.0",
            setDestinationFromCoordinates, checkCourseToDestination, "pauseAI: 10");
    }; 
}
And than in the ship script:

Code: Select all

this.newOrbitPoint = function ()
{
    var v = this.ship.position.add(this.ship.heading.multiply(10000));
    v = v.subtract(system.mainPlanet.position).direction().multiply(2.5 * system.mainPlanet.radius);
    this.ship.savedCoordinates = system.mainPlanet.position.add(v);
}
But it is long ago, So I'm not sure if it indeed works as intended or that it needed adjustments.

In this case for an orbiting ship, that does try to avoid obstacles.

Re: Scripters cove

Posted: Sun Feb 17, 2013 11:51 am
by Rorschachhamster
Eric Walch wrote:
But it is long ago, So I'm not sure if it indeed works as intended or that it needed adjustments.
Thanks, I'll just try it, and we'll see... :D :wink: