I've come up with a design for a feature I call "Dynamic Types" and I'd love some feedback:
The goal of Dymanic Types is to allow an extension to create new types at runtime. For example, this might allow a mod to create a weapon with random properties. As with Betel's suggestion, the way this works is by providing an XML string that describes the type (using all the normal syntax, including embedded code) and adding it as a new type at runtime.
To implement this, I propose the following:
TEMPLATE TYPE
Imagine syntax like this:
Code: Select all
<TemplateType UNID="&itRandomWeapon;">
<StaticData>
<Template><![CDATA[
<ItemType
name="%itemName%"
...
>
<Weapon
damage="%itemDamage%"
...
>
%itemEffect%
</Weapon>
</ItemType>
]]></Template>
</StaticData>
<Events>
<OnEval><![CDATA[
(subst (typGetStaticData &itRandomWeapon; "Template")
{
itemName : (random '("Arguil cannon" "Brodian lancer" "Catapon weapon"))
itemDamage : (random '("damage='laser:3d6'" "damage='particle:1d8'"))
itemEffect : (random '(
"<Effect><Beam beamType='laser' primaryColor='255, 255, 0'/></Effect>"
"<Effect><Beam beamType='laser' primaryColor='0, 255, 255'/></Effect>"
))
}
)
]]></OnEval>
</Events>
</TemplateType>
Doing this at game creation time has a few advantages:
1. You can use the UNID (&itRandomWeapon;) in any other type (e.g., ship classes) as if it were a normal type.
2. I think you can specify an existing UNID (e.g., &itLaserCannon;) which will cause the dynamic type to override the existing one. [there might be roadblocks I haven't thought about.]
3. You can generate types (such as SystemMap) that are only used at game-creation time.
[A few notes of the above: First notice that I use the CDATA syntax. That's just standard XML syntax so that we don't have to escape all the angle-brackets (that works in today's XML parser). Second, notice the subst command takes a struct of key/value pairs--this makes the syntax easier, IMHO, and is something that I think I will add in 1.08.]
DYNAMIC TYPE FUNCTIONS
I think the above handles 80% of the use-case, and if people agree, the above might be all I get done in 1.08. But another possible use case is to create types in the middle of the game. For example, imagine that a quest needs to generate a weapon based on an item that the player brings.
We can add the following functions to help:
(unvCreateType UNID string) -> True/Nil
This function takes an UNID (see below) and a string. The string is just some well-formed XML string that could be generated using the subst technique above. If successful, this will register a new type associated with the given UNID. You can then use the UNID in any function that accepts it (e.g., itmCreate).
The type that you create will be persisted with the game.
There are a few limitations:
1. The UNID must be unused (thus, you cannot override a type using this technique, even one that was previously created with the function)
2. The kinds of types that you can create is more limited. E.g., you cannot create a SystemType with this technique.
To help generate UNIDs, we need a new functions:
(unvDynamicUNID string) -> UNID
This function works as follows: If "string" has not yet been bound, it generates a new UNID (from the 0xF??????? space) and associates the string with it. If the string has already been bound, it just returns the UNID for that string.
You can now use this function to create new types without having to worry about UNIDs. For example, you can do something like:
(unvCreateType
(unvDynamicUNID "myNewAmazingWeapon")
XMLforNewWeapon
)
and then:
(itmCreate (unvDynamicUNID "myNewAmazingWeapon") 1)
I'd love to hear feedback on this design. As I said, I'm leaning towards implementing template types for 1.08 and leaving the dynamic type functions for later, but I'm happy to hear counter-arguments.