Jump to content


  • Content Count

  • Joined

  • Last visited

About Malonn

  • Rank
  • Birthday 01/29/1979

Profile Information

  • Gender
  • Location
    : The US of A

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Okay. I got out of the holding pattern, updated and fixed the script, and it is confirmed working. Here it is for anyone interested: {Designed to change dialog formIDs unique to a plugin to free master file formIDs and then rename the associated MP3 and Lip files accordingly. This script is written for merging from ONE plugin (load order index '01') to a master (load order index '00'). It does not take into account multiple plugins.} unit UserScript; var voice_files: TStringDynArray; formidstart: Cardinal; function Initialize: integer; var TDirectory: TDirectory; voices_root: string; begin formidstart := $00000001; //Path to sound files to be renamed voices_root := 'C:\Users\MaLonn\Downloads\Sound\Voice\Unofficial Oblivion Patch.esp\'; //Create array of sound files and path voice_files := TDirectory.GetFiles(voices_root, '*.*', soAllDirectories); end; function Process(e: IInterface): integer; var oldid, newid: cardinal; j: integer; s, x, old_name, new_name: string; begin oldid := GetLoadOrderFormID(e); //Ensure the load order index (8 bits) of formID are '01', i.e. not the master. if (oldid shr 24) and $FF = $01 then begin //Zero out load order index 8 bits and replace with '00' newid := (oldid and $00FFFFFF) + ($00 shl 24); //Check for free formID in master to assign while Assigned(RecordByFormID(FileByLoadOrder(0), formidstart, True)) do Inc(formidstart); //Begin loop through sound files array for j := 0 to Length(voice_files) - 1 do begin s := voice_files[j]; //If the formID is present, proceed if Pos(IntToHex64(newid, 8), s) > 0 then begin //Replace old formID with new/free formID x := StringReplace(s, IntToHex64(newid, 8), IntToHex64(formidstart, 8), [rfReplaceAll, rfIgnoreCase]); //For message printing... old_name := StringReplace(s, ExtractFilePath(s), '', [rfReplaceAll, rfIgnoreCase]); new_name := StringReplace(x, ExtractFilePath(s), '', [rfReplaceAll, rfIgnoreCase]); AddMessage(Format('Replacing "%s" with "%s"', [for_print, new_name])); //Delphi function to rename a file RenameFile(s, x) end; end; //Change referenced records to the new/free formID while ReferencedByCount(e) > 0 do CompareExchangeFormID(ReferencedByIndex(e, 0), oldid, formidstart); SetLoadOrderFormID(e, formidstart); Inc(formidstart); end; end; end. If anyone wants to use it, make note of the opening comment. This is written for specific use. Also, the script posted in this post is the working one. Earlier posts were WIP. Another question for you, zilav: in the header (HEDR) section of a plugin there is "NextObjectID". Is that necessary to be updated in the mod I'm merging into? xEdit changes it when manually changing formIDs, but I couldn't find a function that seemed to deal with it. Finally, I'll close by saying thank you, zilav! I'm continuing to write more scripts to aid in tasks with xEdit.
  2. I'm just wondering if anyone knows of a fix outside of the UOP for the Trespasses stat being broken. I noticed it's optional in the Patch, and hoped maybe there was an OBSE plugin that fixed it? I checked MenuQue and EngineBugFixes, but neither of those seem (document) to have fixed it.
  3. Well I answered my question through investigation. It was a stupid question (again--there'll be more), but "UOPRetroactive354" and "UOPRetroactive355" do have the script changes made via direct record edit. I've found that 90% (or more maybe--exact numbers are not known) of the new quests with the UOP have direct record edits. Would you say I'm not thorough enough, Arthmoor? That all quests have direct record edits? I know that almost all of them run once and then call "stopquest" as the last line. I thought I had found several that did of have the edits. But maybe I just didn't look in the right place. Also, Arthmoor: I'm going to investigate this, but I like asking (stupid) questions. Is there new DIAL/INFO records in the patch with corresponding audio? I don't know if the patch team found audio that wasn't used and they restored it? That's more an "uncut" type job, but I like asking questions. Now, will Arthmoor respond... or do I just have to find out for myself...
  4. Gotcha, Arthmoor. Thanks for your patience with that question. It was stupid, but I ask stupid questions sometimes. I've noticed a LOT of the UOP quests and corresponding scripts are for adding to an existing save. This makes them unnecessary for what I'm doing. But this leads me to the following follow-up questions: Quests "UOPRetroactive354" and "UOPRetroactive355", are the changes in the scripts needed or are they also made via direct record editing? 90% (or more) of the new quests and quest scripts have direct record edits that make the scripts superfluous. Perhaps that number could be 100% but in my modding there were some changes I found in scripts that I could not track down in records. I completely understand you have to make the mod for existing saves; I'm not knocking the UOP by a long shot. But I'm working some "magic" here and superfluous records have to go.
  5. Okay, good to know, but on a new game a record edit should work, right? And the (very stupid question) positions in the script are correct? I'm doing some "stuff" and know I will not be adding the UOP to an existing save. Can I make the record changes and the fix will exist?
  6. Question regarding a fix: "UOPFaregylDoorFix", it aligns the door, but shouldn't that be done via manual record correction, not script? What is the point of this quest/script?
  7. Gotcha, zilav. Thanks again for the help. I'm in a holding pattern for now, but when the time comes to run this script, I may have more questions.
  8. I did not even try RenameFile (yet). The script is untested and I was going to play with that function during the testing process. It's on my list of things to do, however. Good catch (!) with the global "formidstart" and those functions. But, this is a personal script and is designed to be run with two plugins only--master (00) and plugin (01). Plugin is being groomed to merge into master, so it's okay. That's the only way it's designed to work and I'll make a comment at the start of the script to remind me of this if time passes between uses (and I forget) Question about that last line: aren't "DIAL" records recorded and named, thus need to be renamed as well? I confess, I'm ignorant in regards to this topic.
  9. Okay, zilav, I took a couple hours today and implemented your advice into the script I acquired. Untested as of this writing, but it looks right to my novice eye. I would very much appreciate it if you could scan it over and provide any needed feedback. unit UserScript; var voice_files: TStringDynArray; formidstart: Cardinal; function Initialize: integer; var TDirectory: TDirectory; voices_root: string; begin formidstart := $00001000; voices_root := 'C:\Users\MaLonn\Downloads\Knights\sound\voice\knights.esp\'; voice_files := TDirectory.GetFiles(voices_root, '*.*', soAllDirectories); end; function Process(e: IInterface): integer; var oldid, newid: cardinal; j, k: integer; freeid, s, x, zx, new_name: string; begin oldid := GetLoadOrderFormID(e); newid := (oldid and $00FFFFFF) + ($00 shl 24); AddMessage('Current file ID: ' + IntToHex64(newid)); while Assigned(RecordByFormID(GetFile(e), formidstart, True)) do Inc(formidstart); for j := 0 to Length(voice_files) - 1 do begin s := voice_files[j]; k := Pos(IntToHex64(newid), s); if k > 0 then begin x := StringReplace(s, newid, IntToHex64(formidstart), [rfReplaceAll, rfIgnoreCase]); AddMessage (x); zx := ExtractFilePath(s); AddMessage (zx); new_name := StringReplace(x, zx, '', [rfReplaceAll, rfIgnoreCase]); AddMessage(new_name); ShellExecute( TForm(frmMain).Handle, // parent window handle, use 0 for none 'open', // verb 'cmd.exe', // application '/C ren "' + s + '" "' + new_name + '"' , ' ', // working directory SW_HIDE // window mode ); end; end; SetLoadOrderFormID(e, formidstart); exit; end; end. I can't thank you enough for your patience and help. Holding a noob's hand can be annoying at times.
  10. CS, eh? That's cool. I'm learning Python as well. I focus my attention on 3.x, not 2.x, but it's a fun language, and easy to catch on to. I like that it doesn't require compiling like C# and C++ (etc.). I believe I read that it's probably the most popular language in the world right now.
  11. Thanks for the tips, zilav! I will implement them and update the script. I've been playing with the scripting functions (remember, the script posted above is not mine, I got it from someone else) and find it easy enough to learn. I just have no familiarity with Pascal, so going is slow. Googling, etc. Prior to this, I've never even looked at a script for xEdit. So, it'll take a minute to catch on. If I have questions, I will post back. Thanks again!
  12. I'm learning, and enjoying learning. That xEdit documentation is quite helpful. But I can't quite seem to figure out what the '$' symbol does? What in God's name is the purpose of that? From the supplied change LO script: NewLoadOrder := StrToInt64('$' + s); The script calls a GUI, gets user input (which is in the form of a string), the above line takes that string and converts it to an integer. NP. But what's the '$' doing? I Googled for a minute or 5 but couldn't find a reference to that.
  13. First off, thanks for the help, zilav. The script I posted is not mine, but I was told (I haven't "figured it out" for myself yet--I'm not familiar with the scripting language) that it checks the plugin for available FormIDs, renumbers those IDs appropriately (as in the "Change FormID" xEdit function), and finally takes those new IDs and renames the lip and mp3 (? I think, right?) accordingly. I just want the script to get the appropriate FormID from the plugin, copy the rest of the name from the lip/mp3 file, substitute correct FormID in the string, then rename the lip/mp3 file. All of the FormID changing has been done already. Now, I just need to rename lip/mp3 files. Direct scripting assistance is always welcome, but I don't mind going it alone and trying to learn the scripting language. If that's the route I take, I'm curious if there's information to assist in learning the language? If not, I'll just study existing scripts and post here with questions. Thanks again. EDIT: Through the Github page, I found this. As of this writing I haven't seen how much information it contains, but it's a start. Anything else is more than welcome.
  14. If I wanted to write a script for xEdit, is there a place with documentation to assist in the process? I actually have a script, but I need to modify it some. Do I just need to figure it out on my own, or is there someplace I can get some help? { Comment } unit UserScript; const FormIDStart = $00050000; FormIDLast = $00950000; function Process(e: IInterface): integer; var TDirectory: TDirectory; FORMID, FORMID2: cardinal; fileiwb, check: IInterface; i, j, k: integer; files: TStringDynArray; aFolder, q, s, t, m, x, zx, after, temp: string; begin aFolder := 'c:\OblivionLM\Data\sound\voice\Desert_AlikR.esp\'; fileiwb := FileByIndex(0); FORMID := GetLoadOrderFormID(e); AddMessage (IntToHex64(FORMID, 8)); q := (IntToHex64(FORMID, 8)); q := Copy(q, 3, 8); q := '00' + q; AddMessage (q); for i := FormIDStart to FormIDLast do begin check := RecordByFormID(fileiwb, i, True); if not Assigned(check) then begin AddMessage (IntToHex64(i, 8)); m := (IntToHex64(i, 8)); files := TDirectory.GetFiles(aFolder, '*.*', soAllDirectories); for j := 0 to Pred(Length(files)) do begin s := files[j]; k := Pos(q, s); if k > 0 then begin AddMessage (s); x := StringReplace( S, q, m, [ rfReplaceAll, rfIgnoreCase ]); AddMessage (x); zx := ExtractFilePath(s); AddMessage (zx); after := StringReplace(x, zx, '', [rfReplaceAll, rfIgnoreCase]); AddMessage (after); ShellExecute( TForm(frmMain).Handle, // parent window handle, use 0 for none 'open', // verb 'cmd.exe', // application '/C ren "' + s + '" "' + after + '"' , ' ', // working directory SW_HIDE // window mode ); end; end; SetLoadOrderFormID(e, i); exit; end; end; end; end. I believe this changes FormIDs within the plugin. I don't need that. I just need it to read the FormID associated with LIP files, and change the LIP files to match. I can be persistent, so should be able to figure this out, but help is always welcome.

Support us on Patreon!

  • Create New...