diff --git a/ESMify_Plugins.pas b/ESMify_Plugins.pas index 4d9f0e6..5257779 100644 --- a/ESMify_Plugins.pas +++ b/ESMify_Plugins.pas @@ -17,6 +17,8 @@ unit ESMify_Plugins; var refsChecked, recordsCounted, flaggedCount, persLocSkipped: integer; pluginShown: boolean; + hardcodedStatForms: TStringList; + dragonCZMarker, dragonLZMarker: IwbMainRecord; function IsReferencedByNonLocation(rec: IwbMainRecord): boolean; var @@ -179,18 +181,77 @@ begin end; end; -function Initialize: integer; +function IsSameCellPackage(package: IwbMainRecord): boolean; +var + packageLoc, packageType: string; + refCell, linkedRefKeyword, linkedRef: IwbMainRecord; begin - AddMessage('All done.'); + packageLoc := GetElementEditValues(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Type'); + + if packageLoc <> '' then begin + + if (packageLoc = 'Near editor location') or (packageLoc = 'Near self') then begin + //AddMessage(' Skipping editor location actor: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')'); + continue; + end + else if (packageLoc = 'In cell') then begin + refCell := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Cell')); + if Assigned(refCell) then begin + if SameRecord(refCell, LinksTo(ElementByPath(e, 'Cell'))) then continue; + end; + end + else if (packageLoc = 'Near linked reference') then begin + linkedRefKeyword := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Keyword')); + if not IsLinkedRefRemote(e, linkedRefKeyword) then continue; + end + else if (packageLoc = 'Near reference') then begin + if InSameCell(e, LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Reference'))) then continue; + end; + + end + else begin + packageLoc := GetElementEditValues(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Type'); + + if (packageLoc = 'Linked Reference') then begin + linkedRefKeyword := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Reference')); + if not IsLinkedRefRemote(e, linkedRefKeyword) then continue; + end + else if (packageLoc = 'Specific Reference') then begin + linkedRef := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Reference')); + if InSameCell(e, linkedRef) then continue; + end; + end; +end; + +function Initialize: integer; +var dobj: IwbMainRecord; +begin + AddMessage('ESMify Plugins is starting...'); + + hardcodedStatForms := TStringList.Create; + hardcodedStatForms.Add($5); // DivineMarker + hardcodedStatForms.Add($6); // TempleMarker + hardcodedStatForms.Add($10); // MapMarker + hardcodedStatForms.Add($12); // HorseMarker + hardcodedStatForms.Add($15); // MultiBoundMarker + hardcodedStatForms.Add($1F); // RoomMarker + hardcodedStatForms.Add($34); // XMarkerHeading + hardcodedStatForms.Add($3B); // XMarker + + // DLZM and DCZM Default Objects. + // For simplicity sake, I assume they are unchanged, which is true in 99.999% cases. + // If you ever find a mod, changing these objects, I will update this to retrieve actual values. + hardcodedStatForms.Add($138C0); // DragonMarker + hardcodedStatForms.Add($3DF55); // DragonMarkerCrashStrip end; function Process(e: IInterface): integer; var currentPlugin: IwbFile; - baseRefRecord, package, refCell, actorLocation, linkedRef, linkedRefKeyword: IwbMainRecord; + baseRefRecord, package, actorLocation: IwbMainRecord; packages: IwbElement; i, baseID, packageCount, typeId: integer; - sig, baseSig, packageLoc, packageType: string; + sig, baseSig: string; isREFR, isACHR, skip: boolean; begin if not pluginShown then begin @@ -240,18 +301,43 @@ begin end; if isREFR then begin - // Water, texture sets, and markers always get flagged by CK - - baseID := FormID(baseRefRecord); - if (baseID = $3B) or (baseID = $4) or (baseID = $34) or (baseID = $1F) or (baseID = $15) or (baseID = $12) or (baseID = $10) or (baseID = $6) or (baseID = $5) or (baseID = $138C0) or (baseID = $3DF55) then begin - MarkPersistent(e); - exit; - end; - + // Certain types of references are always flagged as persistent by the CK. See DavidJCobb's post: + // https://discord.com/channels/535508975626747927/535530099475480596/1129026688077013084 + baseSig := Signature(baseRefRecord); - if (baseSig = 'TXST') or ((baseSig = 'ACTI') and ElementExists(baseRefRecord, 'WNAM')) then begin + + if baseSig = 'TXST' then begin + // Flag texture sets MarkPersistent(e); exit; + end + else if baseSig = 'STAT' then begin + // Flag hardcoded static forms (markers) + if hardcodedStatForms.indexOf(FormID(baseRefRecord)) > -1 then begin + MarkPersistent(e); + exit; + end; + end + else if baseSig = 'ACTI' then begin + // Flag water activators + if ElementExists(baseRefRecord, 'WNAM')) then begin + MarkPersistent(e); + exit; + end; + end + else if baseSig = 'LIGH' then begin + // Flag Never Fades lights + if (GetElementNativeValues(e, 'Record Header\Record Flags\Never Fades') > 0) then begin + MarkPersistent(e); + exit; + end; + end + else if baseSig = 'DOOR' then begin + // Flag PrisonMarker refs and any doors with teleport data + if (FormID(baseRefRecord) = $4) or (ElementExists(e, 'XTEL')) then begin // PrisonMarker + MarkPersistent(e); + exit; + end; end; end; @@ -267,9 +353,16 @@ begin // This NPC uses Persistent Location, should work fine if the location was assigned correctly if ElementExists(e, 'XLCN') then begin actorLocation := LinksTo(ElementByPath(e, 'XLCN')); + + // CK flags refs with the PersistAll location + if FormID(actorLocation) = $216A7 then begin // PersistAll + MarkPersistent(e); + exit; + end; + if ReferencedByCount(actorLocation) > 1 then begin Inc(persLocSkipped); - //AddMessage(' Skipping actor with Persistent Location: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')'); + AddMessage(' Skipping actor with Persistent Location: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')'); exit; end; end; @@ -285,8 +378,8 @@ begin if packageCount = 0 then exit; + // Scan packages and try to determine if their range extends beyond the NPC's starting cell. skip := true; - for i := 0 to Pred(packageCount) do begin package := LinksTo(ElementByIndex(packages, i)); @@ -295,48 +388,14 @@ begin continue; end; - packageLoc := GetElementEditValues(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Type'); - - if packageLoc <> '' then begin - - if (packageLoc = 'Near editor location') or (packageLoc = 'Near self') then begin - //AddMessage(' Skipping editor location actor: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')'); - continue; - end - else if (packageLoc = 'In cell') then begin - refCell := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Cell')); - if Assigned(refCell) then begin - if SameRecord(refCell, LinksTo(ElementByPath(e, 'Cell'))) then continue; - end; - end - else if (packageLoc = 'Near linked reference') then begin - linkedRefKeyword := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Keyword')); - if not IsLinkedRefRemote(e, linkedRefKeyword) then continue; - end - else if (packageLoc = 'Near reference') then begin - if InSameCell(e, LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Reference'))) then continue; - end; - - end - else begin - packageLoc := GetElementEditValues(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Type'); - - if (packageLoc = 'Linked Reference') then begin - linkedRefKeyword := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Reference')); - if not IsLinkedRefRemote(e, linkedRefKeyword) then continue; - end - else if (packageLoc = 'Specific Reference') then begin - linkedRef := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Reference')); - if InSameCell(e, linkedRef) then continue; - end; - end; + if (IsSameCellPackage(package)) then continue; skip := false; - + break; end; if skip then begin - //AddMessage(' Skipping actor, staying in one cell: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')'); + AddMessage(' Skipping actor, staying in the same cell: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')'); exit; end; @@ -346,6 +405,7 @@ end; function Finalize: integer; begin + hardcodedStatForms.Clear; AddMessage('All done.'); end;