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.