I finally got tired of writing variants of the same code every time I need to manage CloneForms. Let's get this done, once and for all! Version 1 will support all MagicItem types, i.e. Enchantments, Ingredients, Potions and Spells. Future versions may expand this list.
Here's how it works:
- Call a Register function for the form type you want to work with. Either pass an existing form to duplicate, or start from a blank.
- Use commands which mirror OBSE's to edit the form. All relevant commands will be supported.
- Call a Finalize function which returns the fully edited form.
- Behind the scenes...
- When you finalize, Formulator checks its database for a form which matches the one you have requested. It uses string keys which fully identify the form.
- If a matching key is found, it verifies that the stored form is appropriate to the key. If everything checks out, you are returned a reference to the existing form.
- If the stored form is invalid for some reason (e.g. a mod edited it directly instead of using Formulator's interface), a new key is generated for it. If no form already exists for that key (or one exists but is also invalid, recursively) the form is filed away where it belongs. If an identical form already exists, the invalid one is placed in a recycling bin.
- If no matching key is found, Formulator checks the recycling bin. If there is an appropriate form there it is repurposed, filed, and given to you.
- Only if all of the above has failed, Formulator creates a new CloneForm, stores it in the database, and returns it to you.
API documentation:
In this document a command which starts with "form..." applies to multiple formtypes. Replace the elipsis with the type you are working with. For instance, touse the form...Finalize command on an enchantment, call formEnchantmentFinalize.The universal commands work with all form types. Each quality lists its members,and each form type lists which qualities it possesses. Some form types alsopossess unique commands.For more information about the qualities and form types, see OBSE'sdocumentation: http://obse.silverlock.org/obse_command_doc.html----------------------- Universal Commands -----------------------(nothing) form...Register sourceForm:refBegin a Formulator work session. The form sent as an argument will be the basisfor the form you wish to create, and any other form... commands sent beforeform...Finalize will modify it. If you wish to start from a completely blankform, pass form... (e.g. formSpell) which is the editorID of Formulator'sworkspace form (and should never be used in any other context). Note thatsourceForm does not have to be the same form type you are registering: if adifferent type of form is passed, any traits shared between the two types willbe duplicated and any other traits possessed by the type you are registeringwill be set to zero or null as appropriate.(finalForm:ref) form...FinalizeEnd a Formulator work session, returning a reference to a form which matches allspecifications set since the most recent form...Register. Although Formulator'sdatabase keys fully describe a form and consistency checking is performed onevery lookup, the intention is that no form returned from Formulator is everedited directly. If you wish to make further changes, the proper method is touse form...Register again.--------------------- Quality - Edible ---------------------Members: Ingredient, Potion(nothing) form...SetIsFood isFood:bool------------------------ Quality - Inventory ------------------------Members: Ingredient, Potion(nothing) form...SetGoldValue goldValue:long(nothing) form...ModGoldValue difference:float(nothing) form...SetWeight weight:float(nothing) form...ModWeight difference:float(nothing) form...SetQuestItem isQuestItem:bool-------------------- Quality - Magic --------------------Members: Ingredient, Enchantment, Potion, Spell(nothing) form...SetAutoCalc isAutoCalc:bool(nothing) form...AddEffect effectCode:longEffect code as returned by OBSE's GetMagicEffectCode.(nothing) form...AddFullEffect effectCode:long magnitude:long area:long duration:long range:shortEffect code as returned by OBSE's GetMagicEffectCode.See OBSE's list of magic effect range codes.(nothing) form...CopyNthEffectFrom fromForm:ref whichEffect:short(nothing) form...CopyAllEffectsFrom fromForm:ref(nothing) form...RemoveNthEffect whichEffect:short(nothing) form...RemoveAllEffects(nothing) form...SetNthMagnitude magnitude:long whichEffect:short(nothing) form...ModNthMagnitude difference:float whichEffect:short(nothing) form...SetNthDuration duration:long whichEffect:short(nothing) form...ModNthDuration difference:float whichEffect:short(nothing) form...SetNthArea area:long whichEffect:short(nothing) form...ModNthArea difference:float whichEffect:short(nothing) form...SetNthRange range:short whichEffect:shortSee OBSE's list of magic effect range codes.(nothing) form...SetNthAV actorValue:long whichEffect:shortsee OBSE's list of numeric actor value codes.(nothing) form...SetNthScript script:ref whichEffect:short(nothing) form...SetNthScriptName name:string whichEffect:short(nothing) form...ModNthScriptName filter:string whichEffect:shortSee OBSE's ModName for filter format.(nothing) form...SetNthScriptSchool school:long whichEffect:shortSee OBSE's list of magic school codes.(nothing) form...SetNthScriptVisual effectCode:long whichEffect:shortEffect code as returned by OBSE's GetMagicEffectCode.(nothing) form...SetNthScriptHostile isHostile:bool whichEffect:short-------------------- Quality - Named --------------------Members: Ingredient, Potion, Spell(nothing) form...SetName name:string(nothing) form...ModName filter:stringSee OBSE's ModName for filter format.(nothing) form...AppendToName toAppend:string(nothing) form...CopyNameFrom source:ref------------------------- Quality - Scriptable -------------------------Members: Ingredient, Potion(nothing) form...SetScript script:ref(nothing) form...RemoveScript--------------------- Quality - Simple ---------------------Members: Ingredient, Potion(nothing) form...SetModel modelPath:string(nothing) form...ModModel filter:stringSee OBSE's ModName for filter format.(nothing) form...CopyModelFrom source:ref(nothing) form...SetIcon iconPath:string(nothing) form...ModIcon filter:stringSee OBSE's ModName for filter format.(nothing) form...CopyIconFrom source:ref----------------------- Type - Enchantment -----------------------Member of: Magic(nothing) formEnchantmentSetCost chargeCost:long(nothing) formEnchantmentModCost difference:float(nothing) formEnchantmentSetType enchantmentType:shortSee OBSE's list of enchantment type codes.---------------------- Type - Ingredient ----------------------Member of: Edible, Inventory, Magic, Named, Scriptable, SimpleThere are no commands unique to ingredients.------------------ Type - Potion ------------------Member of: Edible, Inventory, Magic, Named, Scriptable, SimpleThere are no commands unique to potions.----------------- Type - Spell -----------------Member of: Magic, Named(nothing) formSpellSetCost magickaCost:long(nothing) formSpellModCost difference:float(nothing) formSpellSetType spellType:shortSee OBSE's list of spell type codes.(nothing) formSpellSetHostile isHostile:bool(nothing) formSpellSetExplodesWithNoTarget explodes:bool!!! The following four commands are special. OBSE v0018 has not exposed thisdata in spell records, and while Formulator supports them, there are twolimitations. First, these properties will always be zero after formSpellRegisteris called, regardless of how they are set on the duplicated form; if you wishthem to be set, you must do so explicitly. Second, Formulator's database cannotcreate keys which reflect this data. It is up to the API user to avoid creatingtwo spells which are identical in every way except the state of these forproperties. Failure to do so may yield unintended results. !!!(nothing) formSpellSetAreaIgnoresLOS ignored:bool(nothing) formSpellSetDisallowAbsorbReflect disallowed:bool(nothing) formSpellSetImmuneToSilence immune:bool(nothing) formSpellSetScriptAlwaysApplies always:bool