This document describes API changes for 1.7 Alpha 2.
Scalable Items
Scalable items are items with a variable level. The level can be set at runtime and the properties of the item (e.g., hit points) change depending on the level. The item type defines whether or not an item is scalable and how its properties change with level.
Defining Scalable Item Types
To define a scalable item, simply set the level parameter to a range of levels:
<ItemType unid="..."
level="3-8"
...
</ItemType>
The above XML defines an item type that can be scaled from level 3 to level 8. By default the item is created at level 3, but can be set to any level between 3 and 8.
Items cannot be scaled above level 25 nor below level 1.
Setting an Item's Level
Once an item type has been defined as scalable, you can set the level of an individual item in the following ways:
- Use
(itmSetProperty ...)
or(objSetItemProperty ...)
to set thelevel
of an item. Obviously, this method will only work for scalable items and within the level range defined by the item type. - Add
level="..."
to an<Armor>
or<ArmorSegment>
element in a<ShipClass>
.
Armor Items
In armor items, the following properties scale:
- Hit Points scale proportionally to standard scale. Imagine a scalable level 5 armor with 120 hit points. The standard hit points for level 5 armor is 100, so this armor is 20% more than standard. When we scale up, we maintain that proportion. Thus at level 6, the armor has 135 hp + 20% = 162 hit points.
- Damage Adjustment scales to the level. Imagine a scalable level 5 armor with +50% bonus to blast damage. At level 6, the armor will still have +50% bonus to blast damage. Remember, though, that damage resistance is already relative to level, so the armor will have higher blast resistance at level 6 (but still only +50% relative to standard).
- Default immunities are applied for the level. For example, armor scaled to level 6 becomes immune to blinding attacks, even if not originally immune. Armor is immune to radiation at level 7, EMP at level 9, and device damage at level 11. NOTE: If the armor has explicit immunities, those are inherited when scaling up, but there is no (current) way to force higher-level armor to not be immune.
- Regeneration and decay scale proportionally to hit points. That is, when scaling from level 5 to level 6, regeneration (or decay) improves according to the standard scale for hit points. If standard level 6 armor has 30% more hit points than standard level 5 armor, then the armor will regenerate 30% more.
- Prices scale proportionally to standard scale. If standard level 6 armor costs twice as much as level 5 armor, then the armor will double in price when scaled to level 6. The same applies to repair cost and install cost.
Drive Devices
Drives do not normally scale with levels, so we need to explicitly define the scaling parameters. We implement a <Scaling>
element to defined different properties at different levels:
<ItemType unid="..."
level="1-5"
...
>
<DriveDevice>
<Scaling>
<Stage level="1" maxSpeed="20" thrust="100" powerUse="100"/>
<Stage level="3" maxSpeed="25" thrust="200" powerUse="200"/>
</Scaling>
</DriveDevice>
</ItemType>
In the above example we've defined a drive device that scales from level 1 to 5. The scaling parameters define the properties: for a given level, we use the properties defined by the entry for that level. For example, when scaled to level 3, we use the properties defined for the level="3" stage (maxSpeed="25", etc.).
If no stage matches exactly, we interpolate linearly between the stages above and below. For example, for level 2, we interpolate between the properties for level 1 and level 3.
If there is no stage above, then we simply copy the previous stage. In the example above, levels 4 and 5 are identical to level 3. It is an error to not have a stage below, however. A scalable item that starts at level n must always define a stage of level n.
Like other scalable devices, prices scale with weapon prices.
Cargo Holds
Cargo expansion devices have explicit scaling parameters just like drives:
<ItemType unid="..."
level="1-5"
...
>
<DriveDevice>
<Scaling>
<Stage level="1" cargoSpace="50"/>
<Stage level="3" cargoSpace="100"/>
</Scaling>
</DriveDevice>
</ItemType>
Reactor Devices
Reactors scale along a standard power scale:
- Power Output scales along the standard power scale, proportionally to initial power. For example, if a given scalable reactor outputs one-half of normal power for its level, then it will continue to output one-half of normal power for all scaled levels.
- Fuel Capacity scales proportionally to power output scaling.
- Prices scale along the weapon price scale.
Weapon Devices
The following weapon properties scale:
- Damage scales along the standard damage scale.
- Prices scale along the weapon price scale.
Other Item Improvements
Drives Can Enhance Maneuverability
Drive devices can now enhance ship maneuverability:
<ItemType ...
...
<DriveDevice
...
maxRotationRate="6.0"
rotationAccel="2.0"
rotationStopAccel="9.0"
/>
</ItemType>
When installed and enabled, the device will increase rotation rate and rotation acceleration up to the level defined (unless already higher).
Device Properties
API 30 adds the following properties to device items. They can be access using objGetItemProperty
and objSetItemProperty
:
'capacitor
: For devices that need to charge up.'temperature
: For weapons that overheat.
Ships
Initial Data
For consistency with stations, a <ShipClass>
can now have an <InitialData>
element, which is used to initialize object data when a ship is created.
If there is an <InitialData>
element in a ship table (e.g., the definition of a station's guards) then the two elements are merged. Data in the ship table will override the ship class only if it has the same ID.
Hero Images
The large ship image shown for player ships is defined in the <PlayerSettings>
element. For consistency with stations, we also allow a <ShipClass>
to have a <HeroImage>
element to define it.
The <HeroImage>
, if it exists, overrides the image in <PlayerSettings>
.
Dock Screen Customization
API 30 allows a player ship class to customize the look of the dock screen elements. The <PlayerSettings>
element can have a <DockScreenDisplay>
element, which specifies images and colors to use for the dock screen. The <DockScreenDisplay>
element has the following attributes:
backgroundImage
: The UNID for the background image to use. It should be 1280×528 pixels in size. The default is&rsDefaultDockScreenBkgnd;
.contentMask
: The UNID for the mask used to paint images. It should be 1280×528 pixels in size. The default is&rsDefaultDockScreenMask;
.textBackgroundColor
: The RGB color of the background area behind normal text.textColor
: The RGB color of normal text in dock screen.titleTextBackgroundColor
: The RGB color of the background behind the title.titleTextColor
: The RGB color of title and header text.
<OnPlayerLeftShip> Event
This event is raised on a ship when the player switches to another ship. gSource
is the old ship; aNewShip
is the ship object that we are switching to.
<OnPlayerEnteredShip> Event
This event is raised on a ship when the player switches to it. gSource
is the new ship; aOldShip
is the previous ship (which could be Nil
).
This event is also called when the game is first created.
<OnDataTransfer> Event
When changing ships, we move any stored data ((objSetData ...)
) from the old ship to the new ship. This handles some older code which stored things like fleet rank on the ship object.
The <OnDataTransfer>
event allows ship classes to prevent this automatic data move. Classes may returns a struct, in which each element represents a data attribute. The value can be set to ignore
to prevent data from being transferred. If the value is copy
, then we proceed with the copy (as normal).
For example:
<OnDataTransfer>
{
myData1: 'ignore
myData2: 'copy
}
</OnDataTransfer>
Imagine that the above event is placed on ship B. When the player switches from ship A to ship B, we call <OnDataTransfer>
on ship B to decide which data to move from ship A.
myData1
is not moved from ship A to ship B, which means we do not overwrite the data on ship B.
But myData2
is copied from ship A to ship B.
Any data on ship A that is not mentioned in the struct above is copied by default.
Fuel Properties
API 30 adds two new properties to manage fuel:
(objGetProperty shipObj 'fuelLeft) -> Fuel left (in standard fuel rod units)
(objGetProperty shipObj 'maxFuel) -> Fuel capacity (in standard fuel rod units)
The fuelLeft
property is settable (and automatically adjusts to stay within the max fuel limit).
Other Properties
- Added
'powerUse
, which returns the number of kilowatts currently being consumed. Compare against'power
to determine the percent of reactor capacity being used.
Missiles
sysFindObject
API 30 now honors the directives in sysFindObject
for projectiles. In all cases, this
only works when combined with the m
directive, which selects projectiles.
- The
H
directive includes only projectiles fired by the source object. - The
A
directive includes only active projectiles. It excludes any projectile that is dead but painting its fade-out animation. - The
X
directive includes only projectiles whose target is the source object.
Particle Effect Weapons
There's a new parameter for particle effect weapons:
minDamage="..."
When a ship is hit with particles, we always do at least the minimum damage, regardless of how many particles actually hit.
Properties
In API 30 we now support the lifeLeft
property for projectile, which is the number of ticks left before the projectile expires. This property can be modified with objSetProperty
.
Dock Screens
Armor/Device Management Screens
Armor and device management screens are implemented with an item selector control, specified with, for example, type="armorSelector"
. Previously, the set of items show in a selector depended on the type. For example, type="armorSelector"
was hard-coded to show armor segments and shields.
Starting in API 30, we honor the list=
parameter in <ListOptions>
to control the set of items shown in a selector. For backwards compatibility, screens prior to API 30 will continue to ignore the list
parameter.
We've also introduced a new type: type="deviceSelector"
, which makes fewer assumptions about the types of devices to show. For example, it allows mixing weapons and misc devices (though not armor).
API 30 adds the following parameters to <ListOptions>
to control behavior of selectors:
- Added
slotName
parameter in<ListOptions>
to set label for empty slots (defaults to "device slot"). - Added
noEmptySlots
parameter to<ListOptions>
to omit any empty slots.
Markers
Starting in API 30 you can make markers visible by setting the style property. This is mostly useful for debugging. For example:
...
(setq markerObj (sysCreateMarker "my marker" pos &svPlayer;))
(objSetProperty markerObj 'style 'smallCross)
The above will draw the marker as a small, yellow cross. Currently, smallCross
is the only supported style. Setting the style to nil
will make the marker invisible again.
Galactic Map
Station Information
In 1.7 Alpha 2 the galactic map shows summary information for each known station. The summary information is designed to remind the player of the key features of each station (refueling, installing, etc.). By default, this information is generated based on <Trade>
definitions.
Individual stations may override this summary information by adding specific <Language>
entries:
- core.mapDescMain: The simplest case is where you want to add a service that is not covered in the
<Trade>
description. The text for this entry is prepended to any other autogenerated descriptions.
Example:
<Language>
<Text id="core.mapDescMain">
"Microsaur training"
</Text>
</Language>
<Trade>
service to generate a description. You can add a parameter: noDescription="true"
to specify that a particular trade entry should not generate a description. For example:<Trade>
<Buy ... noDescription="true"/>
</Trade>
<StationType>
state. That is, we do not have access to the gSource
object when generating the text in core.mapDesc
.This could be a problem if your station changes services based on some runtime state. For example, imagine a station that sells ships, but only if NPC ships are docked. We want to add an if-statement that checks to see if there are any ships before returning the service.
The
core.mapDescCustom
language entry is used exactly for this purpose. You may use the gSource
variable inside it to check whatever station state you need and then generate appropriate text.The language entry will be invoked when you leave the system, so that it is up to date if you ask for information in a different system.
- core.mapDescAbandonedCustom: This element is the same are
core.mapDescCustom
, but is invoked only if the station is abandoned.
Other Enhancements
- Added
lightYearsPerPixel=
to<SystemMap>
type. This value can be a floating point number. It is used only to show a scale when displaying a topology map.
Effects
- The
<Ray>
effect now accepts theblendMode
parameter. - The
<Ray>
effect'sanimateOpacity
parameter has been renamed toanimate
. It now supports two values:fade
(which was the only value supported byanimateOpacity
) andflicker
, which causes the ray to flicker through various sizes and intensities (similar to theflicker
animation for<Orb>
).
TransLISP
struct Function
The struct
function is used to construct structures; it is analogous to list
. The function supports the following syntax:
(struct nil) -> nil
(struct 'a 1) -> { a:1 }
(struct 'a 1 'b 2) -> { a:1 b:2 }
(struct (list 'a 1)) -> { a:1 }
(struct (list 'a 1) (list 'b 2)) -> { a:1 b:2 }
(struct { a:1 }) -> { a:1 }
(struct { a:1 } { b:2} ) -> { a:1 b:2 }
Support for doubles in data increment functions
Functions which increment opaque data now support doubles. For example:
(objIncData gSource 'myVar 1.2)
The above will properly increment by 1.2, whereas before, it would truncate to 1.
Type Timer Events
API 30 adds functions to add timers on arbitrary types. The events get called in any system (unlike object timers). The new functions are:
(typeAddTimerEvent unid delay event)
(typAddRecurringTimerEvent unid interval event)
(typCancelTimerEvent unid event)
Other Changes
objGetOverlays
now accepts a criteria as a second parameter (optionally).- Added
scrGetScreen
function to return current dock screen. - Added
scrAddMinorAction
to add a minor action to a dock pane. - Added
join
function to easily concatenate a list of strings.
Is there any chance that you might add support for optional libraries in this version?
Will this let me have an armor that shows up throughout its level band: Eg. Armor A has a level band of 1-4, I go to a shop and find segments of armor A that are level 1, 2 and 4...or would it generate them all at Level 1 and make me need to set up some other way of doing that?
@the_shrike: Not currently. It will only show up as the lowest level band. But it's a good idea and we need to think of how to support what you're suggesting.
If damage is the only (performance affecting) property of weapons that scales, scaling weapons won't be very good.
As you upgrade to higher level weapons, you expect DPS to increase by some multiplier. But you also expect to gain a damage type tier every 3 levels. So when you don't, you expect extra damage, and when you do, you expect a smaller (maybe negative) damage change.
In some cases it might be logical for a weapon to be upgradable to a better damage type, probably at specified levels. In others it might not. But either way, the damage increase should take into account whether there's a damage type improvement.