This record describes API changes in 1.8 Alpha 4.

Armor

<OnArmorConsumePower>

This event allows you to override armor power consumption. The event will get called whenever the armor needs to consume power. Callers should return the amount of power to consume (in 1/10th of a MW).

<CanBeInstalled> and <CanBeRemoved>

Armor now gets these two events. They are the same as the existing events for devices.

HP Bonus per Charge

Use the hpBonusPerCharge= parameter on armor to allow armor to gain HP with each charge. This is similar to the parameter for shields.

Devices

Fire Arc on Point Defense

Point defense devices (<AutoDefenseDevice>) now support a fire arc. Use minFireArc= and maxFireArc= to define a fire arc.

For completeness, you can also specify omnidirectional="true", but this is not required.

Non-Empty Device Slots

In API 39 you can define a device slot that cannot be empty. For example, you could define a ship class with a build-in cargo hold device and specify that the cargo hold device cannot be removed unless it is replaced by another cargo hold device.

Use cannotBeEmpty="true" on a device slot.

Intro Events

Types now have special events for dealing with the intro.

<OnGlobalIntroStarted>

This event fires when the intro starts.

<OnGlobalIntroCommand>

This event allows a type to handle an intro command. aCommand is the command the user entered.

Items

  • You can now specify maxCharges= at an item level to limit the number of charges on an item. This allows us to specify different values for initial charges vs. maximum charges.

Names

In API 39 you can separate random station names with a comma as well as a semicolon.

Shared Item Criteria

It's very common for <Trade> descriptors to use the same criteria across different types. For example, most friendly Commonwealth stations will sell items that match the criteria *NU -illegal; -ID; -notForSale;.

In API 39, you can define a shared criteria and give it an ID. Once defined, you can use that criteria by ID. The advantages of this are relatively obvious.

Defining a Shared Item Criteria

You can define a shared item criteria in an <AttributeDesc> element on any type:

<Type ...>
   <AttributeDesc>
      <ItemAttribute id="myCriteria" criteria="*NU -illegal"/>
   </AttributeDesc>
</Type>

The above defines a shared criteria called myCriteria. This name is globally accessible, and the behavior of duplicate names is undefined (no guarantees about which criteria will win).

We recommend that you add appropriate namespace prefixes to your IDs so they do not conflict. For example, many of the shared criteria in the core game are prefixed with core. (as in core.fusionFuel).

Using a Shared Criteria

You can use a shared criteria anywhere that an item criteria is expected (including in TLisp functions). For example:

...
<Trade>
   <Sell criteria="{myCriteria}" priceAdj="100"/>
</Trade>
...

The shared criteria name must be surrounded by braces, and it must be the only token in the criteria. You cannot currently mix a reference to a shared criteria with other criteria syntax.

Criteria Labels

In some cases, such as trade elements, we need a human-readable description of a criteria. In those cases, you can use the criteriaLabel= parameter to specify the label. For example, criteria labels are used in the galactic map to show shortages and gluts of certain items in each system.

You may also add a label= parameter to specify that items that match the criteria should be labeled as such in the item list UI. This was already possible in previous APIs.

Trading Directives

In API 39 you can specify that a station or ship produces or consumes a certain set of items. This directive is used to determine whether a given system has a shortage or surplus of a given item. Shortages cause prices to go up and surpluses cause them to go down.

The following trade directives are now available:

...
<Trade>
   <ConsumeTrade criteria="..." impact="5"/>
   <ProduceTrade criteria="..." impact="10"/>
   <BalanceTrade criteria="..." impact="5"/>
</Trade>

The ConsumeTrade directive indicates that the object increase the price of the given items. The price increases by 1% for each point of impact. For example, a Commonwealth metropolis might consume food and thus increase the price of food in that system.

The ProduceTrade directive indicates that the object decreases the price of the given items. The price decreases by 1% for each point of impact. For example, an agricultural colony might produce food and thus decrease the price in the system.

The BalanceTrade directive works to resolve shortages or surpluses in a given system. We add up all the impact contributions for a given item criteria for all objects in the system. The BalanceTrade directive will reduce the shortage or surplus up to its number of impact points.

For example, if a system has an agricultural colony that produces 20 impact points of food, then the price of food in the system will drop by 20%. If the same system has an object with a BalanceTrade directive, the price of food will increase by the specific impact value. Conversely, if a system has a shortage of food, the BalanceTrade directive will decrease the price of food.

BalanceTrade is mostly used for trading stations like Korolov, which would naturally take advantage of a disparity in price and thus reduce it.

In practice, however, you can also use this to make sure that a set-piece system has reasonable prices. For example, if you have a system which always spawns a dozen agricultural colonies, you might want to add an extra object with a large BalanceTrade directive to make sure the prices don't drop too much.

Topology

Node State

In previous versions nodes on the map were invisible until the player visited them. In API 39 you can control the visibility. Use the initialState= attribute for a <Node>. The possible values are:

  • unknown: The node is unknown to the player at the beginning of the game. This is the default.
  • positionKnown: The position/existence of the node is known, but the type or even name is unknown. The player will see a generic star at that point on the map.
  • known: The node will be displayed on the map with a correct star image and name.

<NodeDistanceTable>

You can use a <NodeDistanceTable> in a topology processor to choose different results depending on a node's distance to one or more nodes. For example:

<TopologyProcessor criteria="+newBeyond">
   <FillNodes>
      <System>
         <NodeDistanceTable distanceTo="+nodeID:SE">
            <System distance="1-2"   level="2"/>
            <System distance="2-3"   level="3"/>
            <System                  level="4"/>
         </NodeDistanceTable>
      </System>
   </FillNodes>
</TopologyProcessor>

The above code looks at all systems with the newBeyond attribute and computes their distance to node SE (Starton Eridani). Systems that are 1 or 2 gates away are marked as level 2. Those 2 to 3 gates away are marked as level 3. Any system farther than that is marked as level 4.

If multiple distance elements match (1-2 and 2-3 overlap at distance 2) then we pick one at random.

Random Names for Systems

You can add a <Names> element to a <System> element in a <SystemMap> to assign a random name.

Random Topologies

In API 39 we've enhanced the method for creating random topologies. Use the <Random> element inside a <SystemMap> as follows:

<SystemMap ...>
   ...
   <Random id="MyRandomArea"
         networkType=   "path"
         count=         "5-10"
         minSeparation= "60"
         >
      <NodeTemplate attributes="specialRegion, enemyRegion"/>

      <Area>
          <Line from="0,0"     to="100,100"  radius="100"/>
          <Line from="100,100" to="200,0"    radius="100"/>
      </Area>
   </Random>
   ...
</SystemMap>

The above code works as follows:

  1. The <Area> section defines the area on the map where we create the random nodes. We define two thick lines (100 units wide), one from 0,0 to 100,100 and the other from 100,100 to 200,0.
  2. We randomly create between 5 and 10 nodes (as specified by count=) and place them randomly somewhere in the well-defined area. minSeparation= means that we try to keep every node at least 60 units away from another node. [This is a best-effort, not a guarantee.]
  3. We use the definitions in <NodeTemplate> to create the nodes. (In general, though, it is easier to use topology processors later to define the system.)
  4. The networkType= parameter controls how we connect the nodes with stargates. The following types are supported:
    1. path: Connect each node via the shortest path.
    2. tree: Starting at one node, connect as many nodes as possible along a Delaunay network.
    3. web: Connect all nodes in a full Delaunay network.

<MapEffect>

You can add a map effect at a <SystemMap> level:

<SystemMap unid="...">
   ...
   <MapEffect>
      <Group xOffset="..." yOffset="...">
         {one or more effects}
      </Group>

      <Group xOffset="..." yOffset="...">
         {one or more effects}
      </Group>

      ...
   </MapEffect>
   ...
</SystemMap>

In previous versions you could attach a map effect to a node on the map. Now you can define effects at the map level.

Use a <Group> element to specify a position for the effect (using xOffset= and yOffset=). Coordinates are Cartesian, with the origin at the center of the map.

You may have any number of elements under the <MapEffect> element, but there can be only one <MapEffect> element.

Treasure Value

In the current API you can specify generate items whose total average value equals some specified number. For example:

<Items>
   <Group value="1000">
      <RandomItem criteria="m L:1"/>
   </Group>
</Items>

The above item table will generate random items that match the criteria (level 1 missiles) until the total average value (over multiple runs) equals 1000 credits.

You may also specify different values for different system levels:

<Items>
   <Group levelValue="500, 1000, 2000, 3000, 4000">
      <RandomItem criteria="m L:1"/>
   </Group>
</Items>

The above table specifies that we should generate 500 credits worth of items at level 1, 1,000 at level 2, etc.

Starting in API 39 you will also be able to specify these values relative to a standard treasure table curve. For example:

<Items>
   <Group value="standard">
      <RandomItem criteria="m L:1"/>
   </Group>
</Items>

This table specifies that the value of items should be based on the system level. This is similar to the levalValue= table above, except that we use the standard treasure values.

You can specify a specific level (overriding the system level):

<Items>
   <Group value="standard:level=3">
      <RandomItem criteria="m L:1"/>
   </Group>
</Items>

Or you can specify a multiplier for the standard value:

<Items>
   <Group value="standard:x=1.5">
      <RandomItem criteria="m L:1"/>
   </Group>
</Items>

The above specifies that we should generate items equal to 1.5 of the standard treasure value for the current system level. You can also combine them a specific level with a multiplier:

<Items>
   <Group value="standard:level=3:x=1.5">
      <RandomItem criteria="m L:1"/>
   </Group>
</Items>

The standard treasure values are as follows (in credits):

LEVEL     VALUE
1           750
2         1,000
3         1,500
4         2,000
5         4,000
6         8,000
7        16,000
8        32,000
9        64,000
10      128,000
11      256,000
12      512,000
13    1,000,000
14    1,800,000
15    3,500,000
16    6,000,000
17   10,000,000
18   15,000,000
19   22,500,000
20   32,500,000
21   50,000,000
22   75,000,000
23  120,000,000
24  180,000,000
25  240,000,000

Effects

  • Added emitWidth= parameter to <ParticleSystem>.
  • Added style="blackHole" to <Orb> to paint orbs where the center is all black (instead of all white).
  • <Shockwave> effect now supports multiple (sequential) shockwaves. Use waveCount=, waveInterval=, and waveLifetime= to control.
  • Thruster effects use bringToFront= and sendToBack= to control how they are painted relative to the ship image. You can now use a special syntax to specify angle ranges. E.g.: bringToFront="angles:0-60, angles:120-180"

Optional Libraries and Types

In API 39 an extension can optionally depend on a library:

<Library unid="&unidCorporateHierarchyVol01;" optional="true"/>

The above reference loads the Corporate Hierarchy library (which comes with Corporate Command) if it exists. If not, it does not load it.

You can use this functionality in combination with extends= and excludes= on a type. This allows you to conditionally define types depending on whether a library (or extension) is loaded or not.

See also: https://ministry.kronosaur.com/record.hexm?id=75908

TLisp