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
TGHC
---- E L I T E ----
---- E L I T E ----
Posts: 2157
Joined: Mon Jan 31, 2005 4:16 pm
Location: Berkshire, UK

Post by TGHC »

WD Svengali, Eric Walsh is also doing a fine job updating old OXP's, so I guess you need to pm each other, to avoid duplication, or alternatively publish a list of candidate OXP's, and who is working on them, it may encourage others to join in, I would if I could, but I don't know how to.
The Grey Haired Commander has spoken!
OK so I'm a PC user - "you know whats scary? Out of billions of sperm I was the fastest"
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

TGHC wrote:
WD Svengali, Eric Walsh is also doing a fine job updating old OXP's, so I guess you need to pm each other, to avoid duplication, or alternatively publish a list of candidate OXP's, and who is working on them, it may encourage others to join in, I would if I could, but I don't know how to.
You COULD join too. As a experienced senior member you know which OXP is abandoned and which is not. You can send this list to me and I'll contact Eric.

The next step:

Code: Select all

// Checks if the licence for a special equipment is expired. If so it removes the equipment and returns "expired" else "ok"
function CheckLicence(licencetilldate, specialdevice)
{
	if (clock.days >= parseInt(licencetilldate))
	{
		player.removeEquipment(specialdevice);
		player.commsMessage("The licence for your "+specialdevice.slice(3,specialdevice.length)+" is expired. Buy a new one at your local dealer.");
		return ("expired");
	}
	else
	{
		return ("ok");
	}
}
It is called by:

Code: Select all

if (CheckLicence(missionVariables.hyperradio_last, "EQ_HYPER_RADIO") == "ok")
	{ do something }
else
	{ do something }
But before the time has to be set:

Code: Select all

missionVariables.hyperradio_last = String(Math.floor(20 + (clock.days)));
User avatar
TGHC
---- E L I T E ----
---- E L I T E ----
Posts: 2157
Joined: Mon Jan 31, 2005 4:16 pm
Location: Berkshire, UK

Post by TGHC »

I'll have a go at it, there are at first glance about 160 OXP's on the Wiki.
It's my Financial year end tomorrow so just a bit stuffed with time at the moment but will get on with it PDQ
The Grey Haired Commander has spoken!
OK so I'm a PC user - "you know whats scary? Out of billions of sperm I was the fastest"
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 »

Svengali wrote:
And a second thing. Yesterday I've tested to split the hyperradio.OXP into two OXPs. One with a function library and one with the ingame-used things. It works fine - so maybe we should also make a general OXP-Function-Library that can be used by all scripters. That would be a great improvement for scripting new OXPs.
Yes, that is also one of the advantages of JS: you can define functions. And functions that are very useful for general use can be collected into one big library. This way not everybody needs to re-invent the wheel, but just can call a useful function from this library.

I think it is important to have several good examples of scripting to start learning it. It will help if the first larger JS script will see daylight. In the past I mastered (and forgotten) a lot of program languages. I remember that only the start is difficult, but one needs examples in one place. Now they are scattered throughout this board.
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

Eric Walch wrote:
Yes, that is also one of the advantages of JS: you can define functions. And functions that are very useful for general use can be collected into one big library. This way not everybody needs to re-invent the wheel, but just can call a useful function from this library.

I think it is important to have several good examples of scripting to start learning it. It will help if the first larger JS script will see daylight. In the past I mastered (and forgotten) a lot of program languages. I remember that only the start is difficult, but one needs examples in one place. Now they are scattered throughout this board.
So here is the place for them. Lets collect these sweeties and I'll build up a function-lib, put it on a server and if it's getting bigger it will be placed on the WIKI. So if you've got an code-snippet that is generally usable (and working) post it here.

Code: Select all

	// This returns a random number in the range of min-max or -1
	function GetRandomA(min, max)
	{
		if(min > max) { return(-1); }
		if(min == max) { return( min );	}
		let r = parseInt( Math.random() * (max+1));
		return(r + min <= max ? r + min : r);
	}
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 »

I mentioned this in a private message, but: any function declared with the “function foo()” syntax which is not inside another function is global, that is, it is seen by all scripts. I strongly recommend placing such functions inside an object, which will act as a namespace. For example:

Code: Select all

SvengaliMathFuntions =
{
    GetRandomA: function(min, max)
    {
        // same code as above
    }
}
This can be used by other scripts like so:

Code: Select all

this.SMF = SvengaliMathsFunctions
this.randomValue = SMF.GetRandomA(1, 5)
Actually, thinking about it, it would probably be better to do it like this:

Code: Select all

// Library script
this.name = "svengali_math_functions_v1"
this.GetRandomA = function(min, max)
{
    // Same code as above
}

Code: Select all

// Client script
this.SMF = worldScripts["svengali_math_functions_v1"]
this.GetRandomA = SMF.GetRandomA
this.randomValue = GetRandomA(1, 5)
Why is this better? Well, I hope to be able to trick the JS library into putting global declarations into the current script object instead of the global object, in which case the first method will stop working.

Note also the _v1 suffix. If more than one script has the same name, only one will be findable, so new versions need to have new names. A simple way to be backwards-compatible would be for the new version to include scripts which transclude functions into the old namespace. Er, so to speak. :-)

Code: Select all

// svengali_math_functions_v2.js
this.name = "svengali_math_functions_v2"
this.GetRandomA = function(min, max)
{
    // Same code as above
}

this.DoSomethingElse = function()
{
    // Whatever, a new function
}

Code: Select all

// svengali_math_functions_v1.js
this.name = "svengali_math_functions_v1"
this.v2 = worldScripts["svengali_math_functions_v2"]

this.GetRandomA = v2.GetRandomA // Transclude function from v1

delete this.v2
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

Ahruman wrote:
SvengaliMathFuntions =
Hehe, that sounds nice...
But it is not my intention to get my very own library. I'm thinking of:

Code: Select all

this.name           = "functionlib";
this.author         = "Oolite BB";
this.copyright      = "Creative Commons 2.0";
this.description    = "OXP Function Library";
this.version        = "1.00";
We are a community and only we all together can make the world a little bit better.
Ahruman wrote:
Well, I hope to be able to trick the JS library into putting global declarations into the current script object instead of the global object...
Does it mean that a script object can declare methods, functions, maybe even classes? I think I didn't get the point.
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 »

As it is, script object methods are declared using the somewhat weird syntax this.method = function(parameters) { code }. I’d like to be able to use the syntax function method(parameters) { code }, partly because it strikes me as simpler, and partly because I don’t like the fact that global declarations are the default; that sort of makes sense in a web context, but not so much in Oolite.

JavaScript 2 will add support for classes, but I don’t intend to use them in the scripting interface. The prototype-based approach is good for customizing ships and such. On the other hand, classes provide a good way to structure code, and making them available for OXP scripts to use internally would be good.
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

Ahruman wrote:
...any function declared with the “function foo()” syntax which is not inside another function is global, that is, it is seen by all scripts.
That's the intention of this function library. A collection of useful things like the random number generator. Maybe the first snippets are a little bit too specific for the library.
Ahruman wrote:
I strongly recommend placing such functions inside an object, which will act as a namespace.
I agree that we should use the naming conventions that are already there for the legacy-scripting (unique names). Even if it would lead to some more code. That prevents us from getting trouble. And declaring an object is done within a few lines of code.
Ahruman wrote:
Well, I hope to be able to trick the JS library into putting global declarations into the current script object instead of the global object...
But does the 'normal' global declaration work too?
Ahruman wrote:
...because I don’t like the fact that global declarations are the default;
I think JS is running in an sandbox. So this couldn't be a real problem. Or do you think about conflicts between JS-OXPs? Maybe double declarations or changed methods/properties...
User avatar
LittleBear
---- E L I T E ----
---- E L I T E ----
Posts: 2868
Joined: Tue Apr 04, 2006 7:02 pm
Location: On a survey mission for GalCop. Ship: Cobra Corvette: Hidden Dragon Rated: Deadly.

Post by LittleBear »

Does 1.70 replace a dead ship with a new one of the same role, in the same way as replacing when witching out? If so could we have a "dieWithoutReplacing" as you don't really want a mission ship respawned.
OXPS : The Assassins Guild, Asteroid Storm, The Bank of the Black Monks, Random Hits, The Galactic Almanac, Renegade Pirates can be downloaded from the Elite Wiki here.
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 »

As a result of playing with several scripts over the past week I wrote a page in the wiki how in my opinion a legacy script could get largely improved in speed performance.

Most scriptwriters are no programmers and just copy methods they see in other scripts. Over the past week I rearranged 3 old mission scripts according to these rules and re-uploaded them. Compared with the old flat structure, evaluation of this nested structure will probably use less then 10 percent of the original evaluation time.

The file is linked from the script.plist page and also from the index pages.

Structured_Legacy_Scripts

Any comment on this is welcome as this is only one opinion on writing.

With this document in hand I also looked at my own UPS courier and also there nested some conditions deeper to minimise the checks at idle time.
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

Very good work, Eric. :D

Easy to understand - even for non-native english speakers.
I think you should add a link to your MOP, because any new mission-script should include your mission_offering check.
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 »

even for non-native english speakers.
Hmm.. as non-native English speaker I am not capable of creating such text as I than would not understand it myself. Or not.

I was afraid it was to complex written, on the other hand it is only mend for scripters and from those I may expect a certain knowledge that they understand it.
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

Eric Walch wrote:
I was afraid it was to complex written, on the other hand it is only mend for scripters
and from those I may expect a certain knowledge that they understand it.
I don't think that it is to complex. Your article gives us some background information that is very useful to understand what Oolite is doing. So it helps every scripter to understand why and how Oolite reacts. I know that it's only the first step in understanding, but it's a good motivation to start this process.
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Post by Svengali »

Ok. Forget my last posts about the function lib.
Ahruman wrote:
...to trick the JS library into putting global declarations into the current script object...
After reading some more docs this was the result (without using literals). Would this work after lowering the top-level?
Library:

Code: Select all

this.name           = "BBFL";	// Is this already a 'namespace'-object?
this.author         = "Oolite BB";
this.copyright      = "Creative Commons 2.0";
this.description    = "OXP Function Library";
this.version        = "1.00";
// Declare an empty object as namespace AND global
var BBFL_Math = {};
    // Then declare the members (methods, properties) as public
    BBFL_Math.GetRandomA = function(min, max)
    {
           // code
    }
    BBFL_Math.DeclareNextMember = function(x, y, z)
    {
          // code
    }
// Then the next namespace, maybe Vector or...
var BBFL_Vector = {};...
I've used a prefix (BBFL_) for all lib-objects, so it's clear for an scripter that this is related to this Function Library.
This could be used in the client script:

Code: Select all

BBFL_Math.GetRandomA(1, 7);
Ahruman, you have suggested to use a suffix (_v1, _v2,...). I like this idea to be backward compatible, but is this really necessary. There is already a this.version = "1.00". So maybe a check for the correct version could (and should) be realised.
Post Reply