IsharaMeradin Posted August 23, 2016 Share Posted August 23, 2016 I'm trying to figure out how to write a script for xEdit. I've been through the tutorial by mator (found via google as a link here). I can get the scripts as explained to work in xEdit. But I'm still clueless on how to achieve what I want. I have no experience with Pascal. I want to run a script that will automatically locate every COBJ record in every active plugin, get its BNAM - Workbench Keyword, and get each Items\Item\CNTO - Item\Item. Depending upon the BNAM value, I want to add each of the Items to an existing FormID List as an override in a patch plugin if and only if they are not already on said FormID List. Some examples: EditorID: RecipeIronIngot BNAM: CraftingSmelter [KYWD:000A5CCE] Items\Item\CNTO - Item\Item: OreIron "Iron Ore" [MISC:00071CF3] Add: OreIron "Iron Ore" [MISC:00071CF3] to FormID List: SmelterItemList as override in MyMod_Patch plugin EditorID: RecipeWeaponOrcishWarAxe BNAM: CraftingSmithingForge [KYWD:00088105] Items\Item\CNTO - Item\Item: IngotIron "Iron Ingot" [MISC:0005ACE4] Items\Item\CNTO - Item\Item: IngotOrichalcum "Orichalcum Ingot" [MISC:0005AD99] Items\Item\CNTO - Item\Item: LeatherStrips "Leather Strips" [MISC:000800E4] Add: IngotIron "Iron Ingot" [MISC:0005ACE4] Add: IngotOrichalcum "Orichalcum Ingot" [MISC:0005AD99] Add: LeatherStrips "Leather Strips" [MISC:000800E4] to FormList: SmithingItemList as override in MyMod_Patch plugin I learn best with working examples and explanations of how it works. If anyone can point me in the right direction or show a working example with other records that I could possibly adapt to my needs, that would be great. Thank you. I do know that I can achieve what I want to a degree with Papyrus but it includes a long series of GetFormFromFile calls and the script(s) would have to be updated every time a new mod is added for compatibility. With an xEdit script users could simply run it and a patch is made for all of their currently active mods. Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 24, 2016 Author Share Posted August 24, 2016 With a lot of trial and error, I finally managed to get a script that will display the information I need to work with. { Prints out the FULL name, workbench keyword, quantity of ingredients and their names } unit userscript; uses mteFunctions; const s = 'COBJ'; function Process(e: IInterface): integer; var bn, itms, itm, sig, item: IInterface; edid: string; i, c, tempi: integer; begin sig := geev(e, 'Signature'); if sig = s then bn := geev(e, 'BNAM'); AddMessage(''); AddMessage(Name(e)); AddMessage(' BNAM - Workbench Keyword: '+bn); itms := ElementByName(e, 'Items'); for i := 0 to Pred(ElementCount(itms)) do begin itm := ElementByIndex(itms, i); item := LinksTo(ElementByPath(itm, 'CNTO - Item\Item')); edid := geev(item, 'EDID'); tempi := i + 1; AddMessage(' Ingredient #'+FloatToStr(tempi)+' '+edid); end; end; end. Sample result RecipeIngotSteel [COBJ:000A30E4] BNAM - Workbench Keyword: Ingredient #1 OreCorundum Ingredient #2 OreIron Haven't figured out yet how to call up the formlist that I want to add the ingredient items to. Nor how to create overrides for said formlists. Nor how to actually add the items to the lists. At least part of the battle is over. Any input on how to proceed would be nice. Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 24, 2016 Author Share Posted August 24, 2016 All my mish-mash attempts are going nowhere fast. I occasionally get something that runs without error but it doesn't do anything. So I'm thinking it might be better to just see about a script that will put all COBJ records into a single FLST and use GetWorkbenchKeyword, GetNumIngredients & GetNthIngredient in-game to assign the ingredients to formlists specific to the given workbench. But that is actually the part I'm having trouble with, the tutorial didn't go over creating a patch file, adding records and adding new entries to those records. I'm going to take a needed break from this part of the project and hope that in the meantime someone might be able to explain what I need to do. Link to comment Share on other sites More sharing options...
zilav Posted August 24, 2016 Share Posted August 24, 2016 So you have some mod with new FLST records for each crafting type, and want to make a patch that will override them and include all appropriate components used in all loaded plugins, right? Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 24, 2016 Author Share Posted August 24, 2016 So you have some mod with new FLST records for each crafting type, and want to make a patch that will override them and include all appropriate components used in all loaded plugins, right? In a nutshell, yes. Link to comment Share on other sites More sharing options...
zilav Posted August 25, 2016 Share Posted August 25, 2016 In a nutshell, yes. I created TheCraft.esm with a pair of FLSTs to override as a test case. Script will create a new patch plugin (or update the existing one), set their names at the top of script. Also populate slCraftingIndex with pairs KeywordEditorID=FLSTEditorID so all components from workbenches with that keyword will end up in corresponding FLST https://drive.google.com/file/d/0B4rR0C-Bcx_JdHlhb0FFWjAyQUE/view?usp=sharing Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 25, 2016 Author Share Posted August 25, 2016 This works. Thank you. I discovered I could add additional slCraftingIndex pairs to cover DLC if present (Hearthfires specifically). As a result the sawn log gets added to the formlist. This item is handled differently by the game (stored in its own container and put into the player for crafting then returned). I don't want to break that functionality. What would I need to add to prevent that specific item from being added? This is the specific item that needs blocked: BYOHMaterialLog "Sawn Log" [MISC:0100300E] I'm assuming that some sort of check added within the ProcessRecipe procedure would do the trick. I'll attempt something and see what I get. Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 25, 2016 Author Share Posted August 25, 2016 I managed to get the specific item blocked. Might not be the best solution. If you have a better method, please share. Modified ProcessRecipe procedure: procedure ProcessRecipe(e: IInterface); var i: integer; items, item, comp: IInterface; kwd, comp_edid: string; begin // workbench keyword EditorID kwd := EditorID(LinksTo(ElementBySignature(e, 'BNAM'))); // skip workbenches with unknown keyword if slCraftIndex.IndexOfName(kwd) = -1 then Exit; // iterate over components items := ElementByName(e, 'Items'); for i := 0 to Pred(ElementCount(items)) do begin item := ElementByIndex(items, i); comp := LinksTo(ElementByPath(item, 'CNTO\Item')); //added comp_edid check to avoid getting sawn logs stored comp_edid := GetElementEditValues(comp,'EDID'); if comp_edid = 'BYOHMaterialLog' then else if Assigned(comp) then AddComponentToList(slCraftIndex.Values[kwd], comp); end; end; gotta love how 2-space tabs get converted into lots of space tabs on the forum Link to comment Share on other sites More sharing options...
zilav Posted August 25, 2016 Share Posted August 25, 2016 Just add a new line if EditorID(comp) = 'somename' then Exit; as a first line in AddComponentToList(). Shorter and doesn't need a new variable. You can also load crafting index from a text file if you wish so. Remove slCraftingIndex.Add() lines and add this one instead slCraftingIndex.LoadFromFile(ProgramPath + 'Edit Scripts\anyname.txt'); The file should be located in the Edit Scripts folder and has the same format as individual lines KeywordEditorID1=FLSTEditorID1 KeywordEditorID2=FLSTEditorID2 ... Can include any number of pairs here to cover most popular crafting mods too. Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 25, 2016 Author Share Posted August 25, 2016 Switched to using a text file for the pairs. Can I still use // inside the text file to make comments? Would be helpful to be able to make notes about the various pair groups. Link to comment Share on other sites More sharing options...
zilav Posted August 25, 2016 Share Posted August 25, 2016 Add this after LoadFromFile for i := Pred(slCraftIndex.Count) downto 0 do if Copy(slCraftIndex[i], 1, 2) = '//' then slCraftIndex.Delete(i); Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 29, 2016 Author Share Posted August 29, 2016 Before I go butchering what is already working How do I add in ability to go through the furniture (FURN) objects and put them into formlists based upon which workbench keyword they have in their keyword list? I'm assuming it will be a similar approach with a keyword / formlist pair along with a separate process function. And for another part of the mod that I've not gotten to re-building yet, I want to put all arrows in one list (minus bound arrow and practice arrow) and all bolts in another list. I'm okay with an ammo EDID / formlist pair as well if that ends up being necessary. While the pair files end up being almost as long as a series of GetFormFromFIle calls, they do allow for greater compatibility by allowing the end user to tweak them to include mods they might have that I may not be aware of. Much better than instructing them on how to edit the PSC file(s) and re-compile them. I've gotten this far... (not in the working file just here in this post) In the Initialize function: // only COBJ records g := GroupBySignature(f, 'COBJ'); if not Assigned(g) then Continue; would it or could it be changed to: // only COBJ, FURN, and AMMO records g := GroupBySignature(f, 'COBJ'); gr := GroupBySignature(f, 'FURN'); gro := GroupBySignature(f, 'AMMO'); if not (Assigned(g) or Assigned(gr) or Assigned(gro)) then Continue; if (Assigned(g) then //use existing remainder if (Assigned(gr) then //duplicate remainder and slightly modify by changing message displayed, the function called and maybe integer used if (Assigned(gro) then //duplicate remainder and slightly modify by changing message displayed, the function called and maybe integer used Link to comment Share on other sites More sharing options...
zilav Posted August 29, 2016 Share Posted August 29, 2016 I modified my original script so add your own changes back http://pastebin.com/raw/AtwqZHhr Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 29, 2016 Author Share Posted August 29, 2016 I modified my original script so add your own changes back http://pastebin.com/raw/AtwqZHhr Thank you. Just making sure I understand. // determine arrow or bolt by 'bolt' word in the name if Pos('bolt', LowerCase(GetElementEditValues(e, 'FULL'))) <> 0 then list := 'BoltList' else list := 'ArrowList'; The 'BoltList' and 'ArrowList' are where I put the EDID for the form lists that I will be using, correct? Link to comment Share on other sites More sharing options...
zilav Posted August 30, 2016 Share Posted August 30, 2016 The 'BoltList' and 'ArrowList' are where I put the EDID for the form lists that I will be using, correct? Yes. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now