It seems like this should be straightforward, but maybe it's not. Full disclosure: I am not a programmer by any stretch. I just know enough to muddle my way through hobby projects, and Pascal is brand new for me as of today. So, if anything is just really terrible code, I'm open to improvements. I'm probably only going to use this script once, though, so I'm not terribly concerned about optimization, just reliable operation.
I'm writing a script for xEdit, aka SSEEDit - the tool most people use for mucking around with Skyrim and Fallout 4 mods that don't make changes to rich game assets. The goal is to dump the raw text content of the DESC property for every BOOK object in the game (vanilla + original DLC). I've gotten pretty far and have a decent understanding of what I'm doing, but I cannot for the life of me get this part to work.
I have a blacklist of strings which should be skipped when iterating through all the BOOK objects. I've tried using pos() several different ways, and it never comes back with anything other than zero.
The weird thing is, even if I can get a correct result from pos() in testing, every book is a positive match when I run my actual script. It also doesn't seem like I'm actually iterating past the first entry in the blacklist.
Here's an example of what's returned when I search for a blacklist entry:
EDID: DLC2dunFahlbtharzJournal02
looking in DLC2dunFahlbtharzJournal02
for DLC1ElderScroll...
skipped DLC2dunFahlbtharzJournal02
This shouldn't be returning 0 from pos('DLC1ElderScroll','DLC2dunFahlbtharzJournal02')...but it is.
(btw - If you have Skyrim SE, you just need SSEEdit to test this.)
Here's my complete script:
{
Dump book text
Dumps "book text" property of every vanilla book
Source for most copypasta:
https://github.com/AngryAndConflict/skyrim-utils/
}
unit UserScript;
uses mteFunctions;
// uses RegExpr;
function Initialize: integer;
var
f, group, e: IInterface;
i, j: integer;
btext,fname: String;
slItems: TStringList;
FileInfo: File_Content;
begin
AddMessage('Dumping books.....');
slItems := TStringList.Create;
// load item and perk stringlists
for i := 0 to FileCount - 1 do begin
f := FileByIndex(i);
group := GroupBySignature(f, 'BOOK');
for j := 0 to ElementCount(group) - 1 do begin
e := ElementByIndex(group, j);
slItems.Add(geev(e, 'EDID'));
// if it's a book, do things
if (isBook(e) = True) then begin
// this it the raw text content of each BOOK's DESC attribute
btext := geev(e,'DESC');
if (Length(btext) > 0) then begin
fname := ProgramPath + 'Output\' + (geev(e, 'EDID')) + '.txt';
// AddMessage('Successfully saved!');
// AddMessage(#9 + fname);
// AddMessage(#20);
// AddMessage('===ERROR=== Unable to save ' + fname + '!');
end;
end;
end;
end;
//AddMessage(btext)
end;
// check if item is book
// exclude blacklisted books and spell tomes
function isBook(item: IInterface): boolean;
var
formID,test: String;
blacklist: TStringList;
ignore: Boolean;
i,t: integer;
begin
Result := false;
ignore := false;
blacklist := TStringList.Create;
// blacklist to exclude - these are can be FormIDs or friendly names
blacklist.Add('DLC1ElderScroll');
blacklist.Add('DLC1FVBook01Falmer');
blacklist.Add('DLC1FVBook02Falmer');
blacklist.Add('DLC1FVBook03Falmer');
blacklist.Add('DLC1FVBook04Falmer');
blacklist.Add('DLC2BlackBook');
blacklist.Add('DA04ElderScroll');
blacklist.Add('ExpSpiderCrftBook');
blacklist.Add('QA');
blacklist.Add('Recipe');
formID := geev(item,'Record Header\FormID');
t := pos(blacklist(1),'Elder');
test := IntToStr(t);
AddMessage(test);
for i := 0 to (blacklist.Count - 1) do begin
if (pos(formID, blacklist(i)) >= 0) then begin
AddMessage('====' + formID + '====');
AddMessage(blacklist(i));
// AddMessage('skipped ' + formID);
ignore := true;
Result := false;
break;
end;
end;
// has Keyword excludes all spell tomes
if (Signature(item) = 'BOOK') and not (hasKeyword(item,'000937A5')) and not ignore then begin
Result := true;
end;
end;
end.{
Dump book text
Dumps "book text" property of every vanilla book
Source for most copypasta:
https://github.com/AngryAndConflict/skyrim-utils/
}
unit UserScript;
uses mteFunctions;
// uses RegExpr;
function Initialize: integer;
var
f, group, e: IInterface;
i, j: integer;
btext,fname: TString;
slItems: TStringList;
FileInfo: File_Content;
blacklist: TStringList;
begin
AddMessage('Dumping books.....');
slItems := TStringList.Create;
// load item and perk stringlists
for i := 0 to FileCount - 1 do begin
f := FileByIndex(i);
group := GroupBySignature(f, 'BOOK');
for j := 0 to ElementCount(group) - 1 do begin
e := ElementByIndex(group, j);
slItems.Add(geev(e, 'EDID'));
// if it's a book, do things
if (isBook(e) = True) then begin
// this it the raw text content of each BOOK's DESC attribute
btext := geev(e,'DESC');
if (Length(btext) > 0) then begin
fname := ProgramPath + 'Output\' + (geev(e, 'EDID')) + '.txt';
// AddMessage('Successfully saved!');
// AddMessage(#9 + fname);
// AddMessage(#20);
// AddMessage('===ERROR=== Unable to save ' + fname + '!');
end;
end;
// AddMessage('----------')
end;
end;
//AddMessage(btext)
end;
// check if item is book
// exclude blacklisted books and spell tomes
function isBook(item: IInterface): boolean;
var
formID,needle,haystack,test: TString;
blacklist: TStringList;
ignore: Boolean;
i,t,p: integer;
begin
Result := false;
ignore := false;
blacklist := TStringList.Create;
// blacklist to exclude - these are can be FormIDs or friendly names
blacklist.Add('DLC1ElderScroll');
blacklist.Add('DLC1FVBook01Falmer');
blacklist.Add('DLC1FVBook02Falmer');
blacklist.Add('DLC1FVBook03Falmer');
blacklist.Add('DLC1FVBook04Falmer');
blacklist.Add('DLC2BlackBook');
blacklist.Add('DA04ElderScroll');
blacklist.Add('ExpSpiderCrftBook');
blacklist.Add('QA');
blacklist.Add('Recipe');
formID := geev(item,'EDID');
for i := 0 to (blacklist.Count - 1) do begin
needle := blacklist[i];
haystack := formID;
// AddMessage('====' + formID + '====');
// AddMessage('looking in ' + haystack);
// AddMessage(#9 + ' for ' + needle + '...');
t := pos(haystack, needle);
test := IntToStr(t);
// AddMessage(test);
if (pos(blacklist[i], formID) >= 0) then begin
// AddMessage(blacklist[i]);
AddMessage('skipped ' + formID);
ignore := true;
break;
end;
end;
// hasKeyword excludes all spell tomes
if (not (Signature(item) = 'BOOK')) or (hasKeyword(item,'000937A5')) then begin
ignore := true;
end;
if ignore then begin
Result := false;
end;
if not ignore then begin
Result := true;
end;
end;
end.