Custom properties on design types give us a structured, standardized way of getting information from objects, items, types, etc. But properties are intended to be purely functional. That is, asking for the value of a property should have no side effects, and even setting the value of a property should have no side-effects other than changing the property value.

There are currently two ways to create custom code on types:

  • Events: It is very common for a design type to define custom events, such as <OrderRaidTransport>, which implements some change on the target object. There are a couple of limitations to events: First, they are not self-documenting. There is no way to obtain a list of custom events. Second, they accept parameters via global variables (usually, gData).
  • Global Function: Another very common approach is to create a global function like, korGiveReward. The problem with this technique is that global functions are global, which means they all require a prefix (kor) or some other namespace disambiguation. Another problem is that you cannot override or inherit global functions.

Proposal

This record proposes an equivalent system for methods: custom functions that have side-effects. Imagine something like:

<StationType unid="&stDefenseNetwork;">
   <Events>
      <Method id="LaunchDefenses">
         (lambda (targetObj)
            (block ()
               ...
               )
            )
      </Method>
   </Events>
</StationType>

We invoke the above method with a new function:

(obj! stationObj 'LaunchDefenses targetObj)

Types of Methods

We support the following method types:

<Procedure>

A <Procedure> event can be invoked on either a type (e.g., a station type UNID) or an instance (e.g., a station object).

gType is the type being invoked.

As with properties, we can inherit methods from a base class.

Procedures can be invoked either with (typ! ...) or (obj! ...).

<Method>

A <Method> event can be invoked on an instance (e.g., a station object).

gType is the type of the object that we're invoking.
gSource (or gItem) is the instance that we're invoking.

Methods are invoked with (obj! ...) or (itm! ...) or (msn! ...). If you try to invoke a method with (typ! ...) you will get a runtime error.

Functions

We add the following functions to invoke methods:

  • (typ! unid event [param1, [param2, ..]])
  • (obj! obj event [param1, [param2, ..]])
  • (obj! obj item event [param1, [param2, ..]])
  • (ovr! obj overlayID event [param1, [param2, ..]])
  • (msn! missionObj event [param1, [param2, ..]])

Events

Note that the above design can supersede the original concept of events. There really is no difference between code defined in a <Method ...> and code defined as an event.

Thus we allow for any existing event to be implemented as a method or procedure. For example:

...
<Events>
   <Method id="OnObjDestroyed">
      (lambda (objDestroyed destroyCtx)
         ...
         )
   </Method>
</Events>

This will require us to define all engine-specific events in a table, which will then serve as documentation for all engine events.