This document describes API changes in 1.7 Beta 4.

Armor/Device Criteria for Ship Classes

Starting in API 33 you can specify armor and device criteria on a ship class to restrict the set of items that can be installed. For example:

<ShipClass unid="..."
   ...
   armorCriteria="a +Rasiermesser"
   deviceCriteria="d +Rasiermesser"
   ...
   />
...
</ShipClass>

The above example specifies that the ship class can only install Rasiermesser items. This is useful for specialized ship classes or for creating separate, non-compatible ship types.

By default, the error when trying to install a non-compatible item is generic: The device is not compatible with your ship. If you wish to customize this message, you may add Language elements to ship class. The following IDs are supported:

  • rpg.cannotInstallArmorBecauseNotCompatible: Defaults to This armor segment is not compatible with your ship.
  • rpg.cannotInstallDeviceBecauseNotCompatible: Defaults to This device is not compatible with your ship.
  • rpg.noCompatibleDeviceInCargo: This message shows up when you have an appropriate device type, but not a compatible one. For example, you may have a drive upgrade to install, but it is not compatible. The default uses a switch statement on (@ gData 'category) to pick a message of the form: You do not have any compatible {device type} in your cargo hold.

Trade & Prices

Dynamic Prices

The recommended way for setting prices is with <Trade> directives on a station type. In general, a trade directive defines a price adjustment for some set of items. For example:

<Trade ...>
   <Sell criteria="w +commonwealth;" priceAdj="110"/>
</Trade>

This directive says to sell commonwealth weapons at 110% of the base price.

It is currently possible to set prices dynamically through a <GetGlobalPlayerPriceAdj> event. This event is called on every price computation to get an additional price adjustment.

Since this is a global event, it is most useful for altering prices globally. For example, having a certain military rank might entitle you to discounts on ammo on all commonwealth stations.

API 33 introduces a local way to set dynamic prices, when the station itself can define the price adjustment. To do this, we set price adjustment to variable and define the <GetPlayerPriceAdj> event.

For example, imagine a station which sets its prices based on the last time a freighter docked with it. If it's been a long time since a freighter delivered goods, everything is more expensive.

We start by setting the <Trade> directive.

<Trade ...>
   <Sell criteria="*" priceAdj="variable"/>
</Trade>

The keyword variable indicates that the price adjustment needs to be computed by calling the <GetPlayerPriceAdj> event:

<Events>
   <GetPlayerPriceAdj>
      (block ()
         ; We get the following variables as input:
         ;
         ; gSource: The object providing the service.
         ; gItem: The item whose price we need to compute.
         ; aService: The service being provided

         ; We should return a price adjustment.
         )
   </GetPlayerPriceAdj>
</Events>

The only advantage of <GetPlayerPriceAdj> over <GetGlobalPlayerPriceAdj> is that it only gets called for the station providing the service. This is slightly more efficient and also requires fewer tests.

Buy/Sell Events

Sometimes it is useful to know when the player bought or sold items. For example, the Commonwealth penalizes you if you sell slaves. Prior to API 33, the rpgBuyItems and rpgSellItems calls were hard-coded to handle slave sales and Black Market promotions.

API 33 introduces a generic system for implementing this. We start by introducing a new function:

(objRecordBuyItem buyerObj sellerObj item [currency] price)

This function handles the actual transaction of moving money from the buyer to the seller. Previously, this required separate calls to objCharge and objCredit, plus we had to manually call plyRecordBuyItem to keep track of stats (e.g., total goods sold by player).

The objRecordBuyItem handles all of the above internally. In addition, it calls one of two events:

If the player is buying:

<OnGlobalPlayerBoughtItem>
   ; gItem is the item being bought (could have a count > 1)
   ; aSellerObj is the object selling (usually the station)
   ; aCurrency is the currency being used
   ; aPrice is the total price paid for gItem
</OnGlobalPlayerBoughtItem>

If the player is selling:

<OnGlobalPlayerSoldItem>
   ; gItem is the item being sold
   ; aBuyerObj is the object buying
   ; aCurrency is the currency being used
   ; aPrice is the total price received for gItem
</OnGlobalPlayerSoldItem>

Miscellaneous

  • relativisticSpeed= now takes an actual speed value (before it only took true or false).
  • Added frequency property for items, which returns either common, uncommon, rare, veryRare, or notRandom.

Part II Extensions

The Vault of the Galaxy (Part II) is a radically different adventure that shares almost nothing in common with Part I. Many older extensions will fail to work with it, so we've decided to omit older extensions from the list when creating a Part II game. Here's how to get an extension to work with Part II:

API 33 adds a way for adventures to exclude extensions older than a certain API level. For example, Part II has the following definition:

<TranscendenceAdventure unid="..."
   name="Domina & Oracus II: The Vault of the Galaxy"
   ...
   extensionAPIVersion="33"
   >
...

The extensionAPIVersion= parameter specifies the minimum API version required for a compatible extension. Thus if you've created an extension compatible with Part II, make sure it is API 33 or above.

The Stars of the Pilgrim and Eternity Port will continue to support a minimum API of 0, meaning all extensions will work.

In addition, Part II requires an extension to have an explicit extends= parameter in order to be included.

The extends= parameter specifies the list of adventure or library UNIDs that the given extension is compatible with. For example, extends="0x00200000" specifies that the extension is compatible with Part I (and only Part I).

Here are a few guidelines for setting the extends= parameter:

  • In general, your extension should extend a specific major library, like Human Space Vol 01 (0x00100000), which is used by both Part I and Eternity Port.
  • Part II's library is Ancient Races Vol 01 (0x00310000). You should extend this library if you want to be compatible with any adventure set in the galaxy of the Ancient Races.
  • In the future, we'll implement optional library references, which will allow extensions to adapt themselves to either Part I or Part II (and thus work on both).
  • Utility extensions which do not require a specific major library could require the RPG Library (0x00010000) which is used by both Part I and Part II.
the_shrike on 12/21/2016 7:34 AM:

Any chance of a no-omni/only-omni restriction? Mass and power consumption would also be cool.

nms on 12/23/2016 1:55 AM:

I think you can do those things with a <CanInstallItem> event.

the_shrike on 12/24/2016 6:40 PM:

Yeah, I highly doubt API0 stuff is going to work in the modern SOTP.

nms on 1/5/2017 4:39 AM:

Well, the Constellation has a <CanRemoveItem> event, which works properly.

assumedpseudonym on 1/28/2017 10:59 PM:

 …And it better continue working properly. It was my first major bug find, heh; I was about ready to start tearing hair out (and not necessarily mine) trying to figure out why it wasn’t working back in my earliest days as a modder.