Jump to content

Scripting for xEdit


IsharaMeradin

Recommended Posts

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

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

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

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

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

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

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

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   :P

Link to comment
Share on other sites

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

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

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

Before I go butchering what is already working   :P

 

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

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...