Market Script Interface

From Elite Wiki

Overview

This OXP aims to help OXP developers integrate their market scripts with other OXP's without conflict. The difficulty faced previously is that, if one OXP uses planetinfo.plist to define a market script, no other OXP can define their own market script for the same location. There is no way to integrate the two market scripts - one will win the battle of coming in last when Oolite loads and merges all the planetinfo data, and one will lose, and there is no way to know which one it will be.

The Market Script Interface provides a simple way for OXP's to register their market script callbacks, and each one will be called in turn, with the "goodCommodity" being passed from one script to the next for updating. All conflicts might not be able to be avoided (for instance, if one OXP decides to zero out the quantity of a commodity, and another one making it max out), but this OXP at least provides a way to allow both to co-exist, and potentially any remaining conflict issues can be resolved by careful coding.

Please note: This system will not make one OXP compatible with another if both OXP are completely rewriting values. In those instances, the OXP that runs last will be the one that gets the final say on the values being changed. There is still plenty of scope for incompatibilities. What this system does do, however, is allow OXP's that are only mildly adjusting values (for instance, boosting a value by a percentage) to work with each other without breaking the other.

Usage

How you make use of this utility will depend on where you are currently defining your market script.

trade-goods.plist equivalent

If you want to control existing commodities at the commodity level, you would normally use the "market_script" property in the trade-goods.plist file. If this is preferred, use the following method:

In your startUp script, add this:

 this.startUp = function() {
   var msi = worldScripts.MarketScriptInterface_Main;
   msi.$addMarketInterface("tradegoods_general", "_my_updateGeneralCommodityDef", this.name);
 }

Then create a function in your worldScript file (the function must exist in a worldscript).

 this._my_updateGeneralCommodityDef = function(goodDefinition, station, systemID) {
   // perform functions on the "goodDefinition" object as required
   // note: you need to check whether systemID or station are available
   // if the systemID is available but station is null - this is a system-level change
   // if the station is not null, this is a station level change
   // if neither the station or systemID is defined, this is a global change.
   // note: the station and systemID may not be available to use - take care when referencing them
   if (!systemID && !station) {
       ... do things to commodity at commodity level ...
   }
   // then return the updated object in the return call
   return goodDefinition;
 }

planetinfo.plist equivalent

If you want to control commodities at a system level, you would normally use the "market_script" property on the system in the planetinfo.plist file. If this is preferred, use the following method:

In your startuUp script, add this:

 this.startUp = function() {
   var msi = worldScripts.MarketScriptInterface_Main;
   msi.$addMarketInterface("system_local", "_my_updateLocalCommodityDef", this.name);
 }

Then create a function in your worldScript file (the function must exist in a worldscript).

 this._my_updateLocalCommodityDef = function(goodDefinition, station, systemID) {
   // perform functions on the "goodDefinition" object as required
   // note: the station and systemID may not be available to use - take care when referencing them
   // if you only want your changes to apply to particular systems, you need to include a check for that system before making changes
   if (systemID && !station && systemID == x && galaxyNumber == xx) {
       ... do things to commodity definition...
   }
   // then return the updated object in the return call
   return goodDefinition;
 }

shipdata.plist equivalent

If you want to control commodities at a station level, you would normally use the "market_script" property on the station in the shipdata.plist file. If this is preferred, use the following method:

In your shipdata.plist file (or shipdata-overrides.plist) add this:

 {
   "my_station_def" = {
       market_script = "msi_station_market.js"; // it must refer to this specific script
   };
 }

Then, in your startUp script, add this:

 this.startUp = function() {
   var msi = worldScripts.MarketScriptInterface_Main;
   msi.$addMarketInterface("station_local", "_my_updateLocalCommodityDef", this.name);
 }

Then create a function in your worldScript file (the function must exist in a worldscript).

 this._my_updateLocalCommodityDef = function(goodDefinition, station, systemID) {
   // perform functions on the "goodDefinition" object as required
   // note: the station and systemID may not be available to use - take care when referencing them
   if (station && station.dataKey == "my_station_key") { // use whatever parameters are appropriate for identifying your station
       .. do things to commodity at a station level ...
   }
   // then return the updated object in the return call
   return goodDefinition;
 }

Although there is usually not as much market script conflict at the station level, this method will allow multiple callers to make adjustments relatively cleanly.

Adding new commodities

If you are creating a new commodity, and want to make use of this system, you need to do the following:

In your trade-goods.plist file, add the following to the new commodity definition:

 {
   "coffee" = {
       ... various settings...
       market_script = "msi_tradegoods_market.js"; // it must refer to this specific script
   };
 }

You can then follow the instructions above for interfacing at the commodity level. However, remember that the script will be called for every commodity, not just your new one. So remember to check for your commodity key before adjusting prices.

For example:

 if (goodDefinition.key == "coffee") {
     ... do things to the price/quantity ...
 }
 return goodDefinition;

Setting priority

It is possible to prioritize where your script will be called if there are more than one script to run. In your code to register your callback, you can specify a priority:

 // this setting will call your script before any others 
 msi.$addMarketInterface("system_local", "_my_updateLocalCommodityDef", this.name, "highest");
 // this setting will call your script after all others 
 msi.$addMarketInterface("system_local", "_my_updateLocalCommodityDef", this.name, "lowest");

Anything without a specific priority is considered "normal" priority, and will be executed between the highest and lowest priority items.

There is no way to control the priority if more than one script specifies the same priority. So, if two scripts set the "highest" priority, there is no way to predict which one will be run first.

General Information

The market_script property of the "universal" section of planetinfo.plist will only engage if there is no market_script defined at the system level. Because we are specifying a market script for every system in every galaxy, it will never get called. If you want your script to act in a universal way, use the system-level facility provided by this interface.

Market scripts defined through the "interstellar space" section of planetinfo.plist do not function. Individual station market scripts can be defined, however.

Important Note

This system will likely break any OXP that currently defines a market script at the universal level, or potentially at the system level. Station-level markets should be unaffected. The OXP will need to be made compatible before the desired market changes are observed.

Compatible OXPs

The following OXP's are compatible with Market Script Interface. Ensure the latest versions of these OXP's are installed to maintain functionality.

Download

Download MarketScriptInterface_1.1.oxz v1.0 (downloaded 0 times).

License

This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 4.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/

Version History

1.1

  • Better handling of saved data, ensuring it is available as early as possible.
  • Added try/catch block when executing callbacks, for better protection if any callback fails.
  • Extra documentation around normal priority items.

1.0

  • Initial release.

Quick Facts

Levelindicator0.png
0-{{{2}}}

Minimum Oolite versionCPU usage lowMemory usage lowGPU usage lowisAPIisDocumented

Version Released License Features Category Author(s) Feedback
1.1 2023-11-20 CC BY-NC-SA 4.0 Market Scripts Misc OXPs‏‎ phkb Oolite BB

Gameplay and Balance indicator

Tag-colour-green.png