Join us at the Oolite Anniversary Party -- London, 7th July 2024, 1pm
More details in this thread.

Scripters cove

Discussion and information relevant to creating special missions, new ships, skins etc.

Moderators: winston, another_commander

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 »

Well, we could possibly have read-only properties for the player settings. Could also be useful to know if the music is off, on, or set to iTunes.

Other stuff, like if Oolite is being played in full screen, if growl or speech are enabled, wireframe mode, detailed(procedurally textured) planets enabled, etc.. might also be of some usefulness too.

The oxp could then use different code for different settings, I suppose.

Svengali, did you have anything specific in mind?
Hey, free OXPs: farsun v1.05 & tty v0.5! :0)
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

Frame wrote:
Svengali wrote:
Is it possible for a script to determine if a machine has shader support and if the player has enabled it?
No
We cannot access information in regard to a graphics card abilities from Oolite Java scripting
I'm afraid - expected this answer. Even if I wasn't thinking about Oolite-Class, more along the line of [[shaderEffectLevel]] or [[shadersAvailable]].
zevans wrote:
would that fix whatever it is you're trying to do?
No .-) I'm trying to avoid the creation of helper objects at all if no shader support is available. These helper objects are only there to display additional infos - via shader. And if a script could check it then it would be possible to switch between display or commsMessage.
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 »

Svengali wrote:
No .-) I'm trying to avoid the creation of helper objects at all if no shader support is available. These helper objects are only there to display additional infos - via shader. And if a script could check it then it would be possible to switch between display or commsMessage.
In that case, a read-only oolite.settings (or oolite.gameSettings) object - similar to the read-write system.info - should be what you're looking for. I think it's doable for 1.74.
Hey, free OXPs: farsun v1.05 & tty v0.5! :0)
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

Sorry Kaks, haven't seen this.
Kaks wrote:
The oxp could then use different code for different settings, I suppose.
Yupp. My 'problem' is specially that creating entities takes time and if I can avoid it...
Kaks wrote:
In that case, a read-only oolite.settings (or oolite.gameSettings) object - similar to the read-write system.info - should be what you're looking for.
This would be great (even if it wasn't a suggestion) :-)
User avatar
PhantorGorth
---- E L I T E ----
---- E L I T E ----
Posts: 647
Joined: Wed May 20, 2009 6:48 pm
Location: Somewhere off the top left of Galaxy 1 map

Post by PhantorGorth »

A fix for the arbitrary OXP loading order problem

I have been working on my own oxp (Visas.oxp) for a while now and as it is an engine oxp (injection system only with no content of it's own) I hit this rather well known issue of requiring an oxp to load after a particular one or set of the other oxps. But I think I have found a nifty way to do this. I have tested it with my visas oxp and the oxp I am using to test it with, and it works.

There is a limitation to this system and that is that it only works between oxps that are written in a particular way. It will not work with oxps that require their startUp function to be called after the startUp function of old oxps, but but I believe I have also found a way around this that will require a modification to the Oolite script loading and event system.

First here is a template that shows how to get this to work for new oxps:

Code: Select all

this.name           = "Oxp_A";
this.author         = "Author";
this.copyright      = "license";
this.description    = "Some Description";
this.version        = "1.0 alpha 1";
this.loaded         = false;

this.startUp = function()
{
	
	if (this.loaded != true)
	{
		this.loaded = true; // Must be done straight away to prevent loops and circular references.

		// For handling oxps that are written using this template:
		if (worldScripts.Oxp_B.loaded != true) worldScripts.Oxp_B.startUp(); // Calls Oxp_B.startUp as it is required to load before your Oxp_A.
		// Repeat above for each OXP that this OXP depends on.

		// Test for existence of an OXP that isn't required but effects the way this OXP works.
		if (worldScripts["Oxp_X"]) 
		{
			this.Oxp_X_Exists = true;
		}
		else
		{
			this.Oxp_X_Exists = false;
		}
		// Repeat above for other similar OXP checks.

		// Do other stuff here as required

		log(this.name + " " + this.version +" loaded."); // This goes last so the load messages appear in a sensible order.
	}

}

this.shipDied = function(whom, why)
{
	if (whom == Player)
	{
		// Do other stuff here as required

		this.loaded = false; // As this.startUp is called afterward (this.reset is deprecated).
	}

	// Do other stuff here as required
}

// Do other stuff here as required

Assuming that both Oxp_A and Oxp_B are written using the above template this then works by having Oxp_A checking if Oxp_B's startUp function has been called by checking Oxp_B's "loaded" flag and if has been called it then skips it, but if it hasn't been called it calls Oxp_B's startUp function early, before Oxp_A's code gets called, and then sets Oxp_B's "loaded" flag to "true". Now when Oolite comes to call Oxp_B's startUp function itself the "loaded" flag is now "true" so the body of the code is skipped and acts as if the startUp function wasn't called in the first place.

This now just a standard depency tree. The problem of circular references is averted because the currently executing startUp function sets the "loaded" flag to true before calling any startUp functions.

Resetting the loaded flags to "false" during shipDied functions allows the startUp functions to be called again when you restart the game.

You should also put the dependent oxps in your oxp's requires.plist. The above code may also need minor modification for when the dependent oxp is not installed.

Hopefully if everyone agrees this method should become part of Oxp development best practice.


Getting this to work for Old Oxps

Now to make this also work with old oxps we would need to change the way Oolite loads and calls functions:

Currently, as far as I can tell:
  • 1) Oolite loads (if the shift key is pressed during starting) all the javascript scripts into memory. (if you don't press shift this is just loaded from cache instead.)

    2) Then each startUp function is called in turn in some unspecified order.

    3) Later when the player dies all existing shipDied functions are called, again in some unspecified order.
Now if the following changes are made:
  • a) If during 1) Oolite checks for which oxps do not have "loaded" defined and makes a list of these oxps called say "old_Oxps" and then defines the loaded variable for these oxp with the value "true".

    b) At 2) for an oxp that is in that list, just before calling it's startUp function, Oolite checks the value of oxp.loaded and skips it if it is set to "true". If it is set to "false" then Oolite sets oxp.loaded to true and calls oxp.startUp.

    c) When the player dies set all the "loaded"s for the oxps in the list "old_Oxps" to "false".
This is exquivalent to the code I wrote in the template above except for one extra thing that needs changing in the template.

Instead of:

Code: Select all

// For handling oxps that are written using this template:
	if (worldScripts.Oxp_B.loaded != true) worldScripts.Oxp_B.startUp(); // Calls Oxp_B.startUp as it is required to load before your Oxp_A.
	// Repeat above for each OXP that this OXP depends on.
you do this:

Code: Select all

// For handling old oxps that are NOT written using this template:
	if (worldScripts.Oxp_Old.loaded != true)
	{
		worldScripts.Oxp_Old.loaded = true; // You do this as Oxp_Old can't.
		worldScripts.Oxp_Old.startUp(); // Calls Oxp_Old.startUp as it is required to load before your Oxp_A.
	}
	// Repeat above for each old OXP that this OXP depends on.
You can mix as many of these two code snippets as required. Which you use would depend on the nature of the dependent oxp. (i.e. is it built use this new template or not)

As I don't full understand the way Oolite loads the oxps and how it would work with concept of the cache, I can not be sure that the old oxps method would work. I will leave that to someone with better knowledge than I.

Even is it doesn't work the template for new oxps should make things easier for oxp developers.
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 »

Nice options. And as you write: restart is deprecated. In 1.74 all scripts are restarted from scratch so things might get easier in future. Instead of setting a true value, the script can delete its startUp handled after use. That way you are sure it can't be called again.

But as you say, it only works for scripts that are specific written for each other. To be sure a script runs as last, you also can use timers. A zero value is often enough. The rock hermit locator uses this for example as it must run as last to be sure there are no stations added after it has ran.

And in BuoyRepair the reset handler contains a timer. When you for some reason must be sure that your startup handler runs last, you can execute the code with a timer. I an almost sure that timercode is only executed after finishing of all startUp handlers.
User avatar
PhantorGorth
---- E L I T E ----
---- E L I T E ----
Posts: 647
Joined: Wed May 20, 2009 6:48 pm
Location: Somewhere off the top left of Galaxy 1 map

Post by PhantorGorth »

Eric Walch wrote:
Nice options. And as you write: restart is deprecated. In 1.74 all scripts are restarted from scratch so things might get easier in future. Instead of setting a true value, the script can delete its startUp handled after use. That way you are sure it can't be called again.
I take it that you mean setting the this.startUp = undefined. And that in 1.74 as soon as the player dies the whole JavaScript setup is reloaded from cache. So there is no need to redefine this.startUp for each oxp. Am I correct here?

If that is the case the template would become:

Code: Select all

this.name           = "Oxp_A";
this.author         = "Author";
this.copyright      = "license";
this.description    = "Some Description";
this.version        = "1.0 alpha 1";
this.loaded         = false;

this.startUp = function()
{
	
	if (this.startUp)
	{
		this.startUp = undefined // Must be done straight away to prevent loops. It doesn't stop this function from working.

		// For handling oxps that are written using this template:
		if (worldScripts.Oxp_B.startUp) worldScripts.Oxp_B.startUp(); // Calls Oxp_B.startUp as it is required to load before your Oxp_A.
		// Repeat above for each OXP that this OXP depends on.

		// For handling old oxps that are NOT written using this template:
		if (worldScripts.Oxp_Old.startUp)
		{
			worldScripts.Oxp_Old.startUp(); // Calls Oxp_Old.startUp as it is required to load before your Oxp_A.
			worldScripts.Oxp_Old.startUp = undefined; // You do this as Oxp_Old can't.
		}
		// Repeat above for each old OXP that this OXP depends on.

		// Test for existence of an OXP that isn't required but effects the way this OXP works.
		if (worldScripts["Oxp_X"]) 
		{
			this.Oxp_X_Exists = true;
		}
		else
		{
			this.Oxp_X_Exists = false;
		}
		// Repeat above for other similar OXP checks.

		// Do other stuff here as required

		log(this.name + " " + this.version +" loaded."); // This goes last so the load messages appear the sensible order.
	}

}

// Do other stuff here as required
This is much simpler and works for old oxps out of the box and still works if the dependent oxp is not installed. The only downside is that it won't work prior to Oolite version 1.74.

I will work on a combined version that works for both and post it here.
Eric Walch wrote:
But as you say, it only works for scripts that are specific written for each other. To be sure a script runs as last, you also can use timers. A zero value is often enough. The rock hermit locator uses this for example as it must run as last to be sure there are no stations added after it has ran.

And in BuoyRepair the reset handler contains a timer. When you for some reason must be sure that your startup handler runs last, you can execute the code with a timer. I an almost sure that timercode is only executed after finishing of all startUp handlers.
I am aware of the timer method but I find that rather inelegant.
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 »

I think he means

Code: Select all

delete this.startUp;
On restart / reload all scripts are reloaded from scratch, so any deleted this.startUp function will be back there, ready to be deleted again.
Hey, free OXPs: farsun v1.05 & tty v0.5! :0)
User avatar
PhantorGorth
---- E L I T E ----
---- E L I T E ----
Posts: 647
Joined: Wed May 20, 2009 6:48 pm
Location: Somewhere off the top left of Galaxy 1 map

Post by PhantorGorth »

Kaks wrote:
I think he means

Code: Select all

delete this.startUp;
Kaks you are right but I thought that both ways are identical.

Here is the version using delete instead:

Code: Select all

this.name           = "Oxp_A"; 
this.author         = "Author"; 
this.copyright      = "license"; 
this.description    = "Some Description"; 
this.version        = "1.0 alpha 1"; 

this.startUp = function() 
{

      delete this.startUp; // Must be done straight away to prevent loops. It doesn't stop this function from working. 

      // For handling oxps that are written using this template: 
      if (worldScripts.Oxp_B.startUp) worldScripts.Oxp_B.startUp(); // Calls Oxp_B.startUp as it is required to load before your Oxp_A. 
      // Repeat above for each OXP that this OXP depends on. 

      // For handling old oxps that are NOT written using this template: 
      if (worldScripts.Oxp_Old.startUp) 
      { 
         worldScripts.Oxp_Old.startUp(); // Calls Oxp_Old.startUp as it is required to load before your Oxp_A. 
         delete worldScripts.Oxp_Old.startUp; // You do this as Oxp_Old can't. 
      } 
      // Repeat above for each old OXP that this OXP depends on. 

      // Test for existence of an OXP that isn't required but effects the way this OXP works. 
      if (worldScripts["Oxp_X"]) 
      { 
         this.Oxp_X_Exists = true; 
      } 
      else 
      { 
         this.Oxp_X_Exists = false; 
      } 
      // Repeat above for other similar OXP checks. 

      // Do other stuff here as required 

      log(this.name + " " + this.version +" loaded."); // This goes last so the load messages appear the sensible order. 

} 

// Do other stuff here as required
I also dropped the if (this.startUp) and this.loaded = false as there are obviously redundant.
Kaks wrote:
On restart / reload all scripts are reloaded from scratch, so any deleted this.startUp function will be back there, ready to be deleted again.
That's what I thought.
User avatar
JensAyton
Grand Admiral Emeritus
Grand Admiral Emeritus
Posts: 6657
Joined: Sat Apr 02, 2005 2:43 pm
Location: Sweden
Contact:

Post by JensAyton »

PhantorGorth wrote:
1) Oolite loads (if the shift key is pressed during starting) all the javascript scripts into memory. (if you don't press shift this is just loaded from cache instead.)
This isn’t quite true, but it’s also not relevant. The compiled scripts Oolite caches are effectively a processed version of the text in the script file. The cache doesn’t affect script behaviour in any way, so it’s best not to think about it.

Eric is correct in that timers can’t fire between different scripts’ startup timers. Of course, timers are still limited in that they don’t allow for dependency chains.
User avatar
PhantorGorth
---- E L I T E ----
---- E L I T E ----
Posts: 647
Joined: Wed May 20, 2009 6:48 pm
Location: Somewhere off the top left of Galaxy 1 map

Post by PhantorGorth »

Ahruman wrote:
This isn’t quite true, but it’s also not relevant. The compiled scripts Oolite caches are effectively a processed version of the text in the script file. The cache doesn’t affect script behaviour in any way, so it’s best not to think about it.
That's useful to know. I wasn't 100% sure of the mechanism. I was mostly concern about it for my suggestion for getting my original dependency mechanism to work for dependencies on old oxps but with the changes that are coming with 1.74 that suggestion is now irrelevant.

I now have a method that works for newly written oxps for pre version 1.74 and a method that works for new and old oxps in 1.74. All I need to do is put them together for oxp that are compatible in both sets of versions. For dependencies on old oxps in pre 1.74 you would have to depend on other methods such as the timer method.
Eric is correct in that timers can’t fire between different scripts’ startup timers. Of course, timers are still limited in that they don’t allow for dependency chains.
That's why I find the method less elegant.
User avatar
snork
---- E L I T E ----
---- E L I T E ----
Posts: 551
Joined: Sat Jan 30, 2010 4:21 am
Location: northern Germany

Post by snork »

hej,
list-reading is still new to me and I need help to learn if I understood this correctly/ all wrong. :?

So I wanted a prettier but not uber ship and found me a suitable OXP containing two ships, mostly faithful to the Cobra 3 they are modded from.
Now I only ever see the one of them. Looking into the shipyard.plist I see :shock: ... this
<key>price</key>
<integer>470000</integer>

...

<key>techlevel</key>
<integer>10</integer>
...

<key>chance</key>
<real>0.0001</real>
Now, does this mean, that
- every 10,000th TL>=10 shipyard I visit will offer this ship ? (on average)
or
- every 10,000th ship I see offered at TL>=10 shipyards will be such ship ? So, maybe every ~400th or 500th TL>=10 shipyard ?

Leading to the next question : How many TL>=10 systems are there, at all ? I would think certainly no 10,000, but if my 2nd interpretation idea is correct, then there may actually be 1 or even 2 ships of these available in all Ooniverse ?
wiki wrote:
The difference between the local tech level and the ship’s tech level also factor into this.
Should this raise my hopes ? Significantly, I mean ?

In the end, what this means to me, if I ever find it, expensive as it is, I must buy it. :?

[stubborn-mode] And no, I do not want to"hack" / "cheat". If the author planned it this way - fine. Will only make it more special, should I really ever see it. [/stubborn-mode]
User avatar
Lestradae
---- E L I T E ----
---- E L I T E ----
Posts: 3095
Joined: Tue Apr 17, 2007 10:30 pm
Location: Vienna, Austria

..

Post by Lestradae »

How do I translate the legacy "Spawn *role* *number*" into a java script?

I tried "system.legacy_spawn" as a logical option, but to no avail.

So how to spawn something with a java script?

Help is much appreciated.
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Re: ..

Post by Svengali »

Lestradae wrote:
How do I translate the legacy "Spawn *role* *number*" into a java script?

Code: Select all

targetShip.spawn("role",number);
or
targetShip.spawnOne("role");
targetShip has to be a valid Entity. So if you're using it in a ship-script you can simply use this.ship.spawn("role",number);
http://wiki.alioth.net/index.php/Oolite ... ence:_Ship tells you more about it...
Last edited by Svengali on Tue Feb 23, 2010 3:47 pm, edited 1 time in total.
User avatar
Cmd. Cheyd
---- E L I T E ----
---- E L I T E ----
Posts: 934
Joined: Tue Dec 16, 2008 2:52 pm
Location: Deep Horizon Industries Manufacturing & Research Site somewhere in G8...

Post by Cmd. Cheyd »

1.73.4 Code
Specific Example :

Code: Select all

 system.legacy_addShipsWithinRadius('pirate',Num_Pirates,'abs',player.ship.position,25600);

For Trunk See:

http://wiki.alioth.net/index.php/Oolite ... m#addShips
Post Reply