Jump to content


Photo

Custom AT-Quickchange Script?


  • Please log in to reply
11 replies to this topic

#1 johnnywatts

johnnywatts

    Guard

  • Members
  • PipPip
  • 194 posts

Posted 05 November 2016 - 05:54 AM

Hello,

 

I'm not sure if this belongs here or on the xEdit forums. It's about an xEdit tool written by Mator.

 

So I'm running the SRLE LoTD Reqtified build found right here on STEP.

 

Part of the build requires you to run AT Quickchange on Requiem's output. Which is fine, if you don't have to do it every time you change your load order or add a new mod.

 

But you do. Basically, after I update a mod or change load order, I have to run AT-Quickchange with Restore for "Head Parts", HCLF, FTST, NAM9, and "Tint Layers" from NPC Retexture Merged.esp.

 

In my case, I also have to do it again for NPC Visuals Merged.esp.

 

This is incredibly time consuming and annoying, have to setup the script the same way every single time.

 

I was hoping there was a way to edit the existing script so that Restore and the 5 records above are already pre-filled, and I just choose which esp to restore from.

 

Anyone know how to do this?


  • 0

#2 hishutup

hishutup

    Daedric Prince

  • Super Moderators
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 2,572 posts

Posted 05 November 2016 - 11:10 AM

Yeah, the script is quite limited in how usable the script is. I wish it would at least remember what I used last.

#3 Mator

Mator

    Thane

  • Mod Authors
  • PipPipPipPipPipPip
  • 474 posts

Posted 06 November 2016 - 01:58 PM

Yeah, the script is quite limited in how usable the script is. I wish it would at least remember what I used last.

Hey, I made it like years ago, and it's helped a lot of people.  >_>'

Better you have QuickChange than nothing right?

To answer the questions:
 

1. Yes it is possible to modify the script so it starts with some functions.
2. A better solution would be for me to add loading/saving of function sets.
3. You can also just make your own script which would do that.  It'd be like 3 lines of code.


  • 0

#4 dunc001

dunc001

    Thane

  • Members
  • PipPipPipPipPipPip
  • 438 posts

Posted 06 November 2016 - 03:07 PM

It'd be like three lines of code if you know what you're doing...
  • 0

#5 Mator

Mator

    Thane

  • Mod Authors
  • PipPipPipPipPipPip
  • 474 posts

Posted 06 November 2016 - 07:02 PM

It'd be like three lines of code if you know what you're doing...

It'll be three lines of code either way.  Just might take you awhile if you don't know what you're doing.  :3


Edited by Mator, 06 November 2016 - 07:03 PM.

  • 0

#6 johnnywatts

johnnywatts

    Guard

  • Members
  • PipPip
  • 194 posts

Posted 06 November 2016 - 08:32 PM

Hey, I made it like years ago, and it's helped a lot of people.  >_>'

Better you have QuickChange than nothing right?

To answer the questions:
 

1. Yes it is possible to modify the script so it starts with some functions.
2. A better solution would be for me to add loading/saving of function sets.
3. You can also just make your own script which would do that.  It'd be like 3 lines of code.

I've popped the script into Notepad++. I have no idea what is going on.


  • 0

#7 Mator

Mator

    Thane

  • Mod Authors
  • PipPipPipPipPipPip
  • 474 posts

Posted 06 November 2016 - 11:40 PM

I've popped the script into Notepad++. I have no idea what is going on.

Have you ever programmed before? If not, then that's probably the hardest approach.

I'd recommend making your own script.

Do something like this:

(note: // indicates a comment, and I added a bunch of them to explain what the script is doing and how it's doing it.
 

// all scripts must start this way
// unit <NameOfYourScript> semicolon
// you can name the script whatever you want, the default is UserScript
// this name has no affect on the script but is important if you want to use your script as a library
unit UserScript;

// this is a helper function which we're using in our script called "Restore"
// the function will restore the element in the record we input (argument "rec") at the path we input (argument "path")
// because we don't need to return anything from our function it's identified with the "procedure" keyword instead of "function"
// the arguments of the function must be specified in the form (ArgumentIdentifier: ArgumentType; ArgumentIdentifier: ArgumentType) etc., ommitting the semicolon from the last argument
// the order of the arguments is important, you must input the arguments in the same order when you call the function
// IInterface is the type which is used for all record, element, group, and file variables in xEdit scripts
// String is the type for text.  A string could hold "this is cool" or "what is going on13$?" or any other text.
// you can call this function from any other function in the script below it by typing Restore(recordValue, pathValue)
procedure Restore(rec: IInterface; path: String);
var
  mRec, element: IInterface;
begin
  // mRec is a local variable defined in the "var" section for this function
  // := is the assignment operator in pascal.  It takes the value from the left hand side and puts it into the variable on the right hand side
  // so, in this case we're taking the result of `MasterOrSelf(rec)` and putting it into the variable `mRec`
  // mRec is short for "Master Record"
  // MasterOrSelf is a function that's part of the xEdit scripting API.  You can read about it here:
  // https://www.creationkit.com/index.php?title=TES5Edit_Scripting_Functions
  // The description from that page is:
  // Function: MasterOrSelf  
  // Returns: IwbMainRecord
  //  -- This is the variable type the function outputs.  IwbMainRecord means "record".  You store this result (and any other Iwb type) in an IInterface type in scripts.
  // Arguments: record : IwbMainRecord
  //  -- This is the argument which you pass into the function (input).  In our case this is rec, which is a record.
  // Description: Returns the master record for the given record when used on override records
  //  -- This description explains what the function does.  This is what you want to do here, because in order to "Restore" a value we need to get the value from the master record first
  mRec := MasterOrSelf(rec);
 
  // our next step is to get the element from the master record at the input path
  // the path could be 'Head Parts' or 'HCLF' or whatever, we don't care what it is
  // we're going to use the function ElementByPath to get an element from mRec - the master record we just got previously - at the path input to this function
  // ElementByPath is a function that's part of the xEdit scripting API.  You can read about it here:
  // https://www.creationkit.com/index.php?title=TES5Edit_Scripting_Functions
  // The description from that page is:
  // Function: ElementByPath  
  // Returns: IwbElement
  //  -- This is the variable type the function outputs.  IwbElement means it could be a record, a group, a file, or a part of a record.  You store this result (and any other Iwb type) in an IInterface type in scripts.
  // Arguments: container : IwbContainer , path : string 
  //  -- These are the arguments which you pass into the function (input).  For this function the first argument is container, which is something that holds elements (in this case rec, which is a record).  The second argument is path, which is a string.
  // Description: Gets an element in the container by path
  element := ElementByPath(mRec, path);
  
  // our last and final step is to copy the element to our original record (rec)
  // we're going to use the function wbCopyElementToRecord for this
  // this is another xEdit scripting function
  // Function: wbCopyElementToRecord
  // Returns: IwbElement
  // Arguments: element : IwbElement , aMainRecord : IwbMainRecord , aAsNew : boolean , aDeepCopy : boolean
  // Description: Copies an element to a record. E.g. the "conditions" element on a COBJ record, or a faction from an NPC_ record. 
  // we're not going to copy it as a new record because we want to overwrite the existing element in the original record
  // we're going to deep copy the element so we get any nested values in it (in the case of an element like Tint Layers which has a bunch of nested elements and values in it)
  wbCopyElementToRecord(element, rec, false, true);
end;
 
// this function gets called for each selected record in xEdit
// you must define it exactly like this in order for xEdit to find it.
function Process(e: IInterface): Integer;
begin
  // the variable e is the record.  we need to do a few things
  // 1. get the master record and store it in a variable.
  // 2. get the element we want to copy from the master record using ElementByPath
  // 3. use wbCopyElementToRecord to copy the element from the master record to the record we're processing (e)
  // 4. repeat for each element we want to restore.  for repetition it's best to just use a function.
 
  // we're going to print the name of the record we're processing to xEdit's log
  // to do this, we're going to use the AddMessage function.
  // AddMessage is a function that's part of the xEdit scripting API.  You can read about it here:
  // https://www.creationkit.com/index.php?title=TES5Edit_Scripting_Functions
  // The description from that page is:
  // Function: AddMessage  
  //  -- This is the name of the function.  You type this in order to use the function.
  // Returns: -
  //  -- The function doesn't return anything.  That means it's a procedure.
  // Arguments: message : String
  //  -- This is the argument which you pass into the function (input).  In our case this is message, which is a string (text).
  // Description: Adds a message line into the TES5Edit output panel 
  //  -- This description explains what the function does.
  // we're also going to use the function Name to get the name of the record we're processing
  // Name is a function that's part of the xEdit scripting API.  You can read about it here:
  // https://www.creationkit.com/index.php?title=TES5Edit_Scripting_Functions
  // The description from that page is:
  // Function: Name  
  //  -- This is the name of the function.  You type this in order to use the function.
  // Returns: -
  //  -- The function doesn't return anything.  That means it's a procedure.
  // Arguments: element : IwbElement
  //  -- This is the argument which you pass into the function (input).  In our case this is element, which is any Record, Group, File, or other element (part of a record).
  // Description: Obtains the name of the element 
  //  -- This description explains what the function does.  This does what we want, which is get the name of the record.
  
  // so, in sum, we add a message to the log with the name of the record we're currently processing
  AddMessage(Name(e));
 
  // this is us calling a function we're going to make for our script to use.
  // the function needs to be defined before the Process function where we use it in order for the script to find it.
  // we're going to pass the record and the element path we want to restore into this function to have it restore the element at that path
  // single quotes indicate a string (text)
  // commas separate arguments, so the first argument is e, the second is 'Head Parts'
  Restore(e, 'Head Parts');

  // we're now going to call the function for all the other element paths we want to restore
  Restore(e, 'HCLF');
  Restore(e, 'FTST');
  Restore(e, 'NAM9');
  Restore(e, 'Tint Layers');

  // that's it.
end;
 
end.

A version with no comments:
 

unit UserScript;

procedure Restore(rec: IInterface; path: String);
var
  mRec, element: IInterface;
begin
  mRec := MasterOrSelf(rec);
  element := ElementByPath(mRec, path);
  wbCopyElementToRecord(element, rec, false, true);
end;

function Process(e: IInterface): Integer;
begin
  AddMessage(Name(e));
  
  // restore elements at paths
  Restore(e, 'Head Parts');
  Restore(e, 'HCLF');
  Restore(e, 'FTST');
  Restore(e, 'NAM9');
  Restore(e, 'Tint Layers');
end;
 
end.

  • 1

#8 hishutup

hishutup

    Daedric Prince

  • Super Moderators
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 2,572 posts

Posted 06 November 2016 - 11:48 PM

3 lines.... no probably more like 6-20 depending on how fancy(features) you want to be.



#9 Mator

Mator

    Thane

  • Mod Authors
  • PipPipPipPipPipPip
  • 474 posts

Posted 07 November 2016 - 12:00 AM

3 lines.... no probably more like 6-20 depending on how fancy(features) you want to be.

The restore function is 3 lines of executable code.  The rest of the code is just calling that function.  :P


  • 0

#10 dunc001

dunc001

    Thane

  • Members
  • PipPipPipPipPipPip
  • 438 posts

Posted 07 November 2016 - 04:31 AM

So to make use of the example script above c/p into a new script in xEdit, highlight the target records to be restored into (select all NPC records in plugin to be changed for example), Apply Script, select Restore script (or whatever you named it) - will it then give a popup asking which plugin you want to restore values from?

 

I love that you took that much time to explain the script rather than just throwing the unannotated one in, kudos for that #knowledgeispower :D

 

Also, when using the original QuickChange script does putting "" around the element name force deepcopy on that element?  I've found that to get all the subs in an element to restore correctly I need to do that, whereas single field elements (eg Male Height, etc) do not require that syntax.

 

Also for those that don't know you can Restore a single sub within an element by simply describing the path <Element>/<Sub>.


  • 0

#11 Mator

Mator

    Thane

  • Mod Authors
  • PipPipPipPipPipPip
  • 474 posts

Posted 07 November 2016 - 12:48 PM

So to make use of the example script above c/p into a new script in xEdit, highlight the target records to be restored into (select all NPC records in plugin to be changed for example), Apply Script, select Restore script (or whatever you named it)

Yes.
 

- will it then give a popup asking which plugin you want to restore values from?

No, it restores values from the master record. If you want to restore values from a specific plugin that will have to be built as well. This is why you should really just use Smash instead. :P
 

I love that you took that much time to explain the script rather than just throwing the unannotated one in, kudos for that #knowledgeispower :D

I decided to give it a try. I don't usually do annotate things that way.
 

Also, when using the original QuickChange script does putting "" around the element name force deepcopy on that element? I've found that to get all the subs in an element to restore correctly I need to do that, whereas single field elements (eg Male Height, etc) do not require that syntax.

I didn't write any code that handles "" in my script, and that is not base functionality in xEdit to my knowledge. That might be placebo effect.


Edited by Mator, 07 November 2016 - 12:48 PM.

  • 0

#12 johnnywatts

johnnywatts

    Guard

  • Members
  • PipPip
  • 194 posts

Posted 12 November 2016 - 08:16 PM

Have you ever programmed before? If not, then that's probably the hardest approach.

I'd recommend making your own script.

Do something like this:


I've never programmed anything for "normal people" before. I've only ever done R, SAS, and MATLAB scripting.

I tried to comprehend what you so graciously provided, and yeah, it just restores values from Masters, not from specific .esps. So I guess it doesn't work as is for my purposes.

I'll take a deeper look at your original QuickChange script, and try to come up with my own.

But thanks for the major effort though!
  • 0


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users