{ Remove incorrect armor keyword. } unit userscript; //uses mteFunctions; { mteFunctions https://github.com/matortheeternal/mteFunctions/blob/master/LICENSE } { ElementByIP: Element by Indexed Path This is a function to help with getting at elements that are inside lists. It allows you to use an "indexed path" to get at these elements that would otherwise be inaccessible without multiple lines of code. Example usage: element0 := ElementByIP(e, 'Conditions\[0]\CTDA - \Function'); element1 := ElementByIP(e, 'Conditions\[1]\CTDA - \Function'); } function ElementByIP(e: IInterface; ip: string): IInterface; var i, index: integer; path: TStringList; begin // replace forward slashes with backslashes ip := StringReplace(ip, '/', '\', [rfReplaceAll]); // prepare path stringlist delimited by backslashes path := TStringList.Create; path.Delimiter := '\'; path.StrictDelimiter := true; path.DelimitedText := ip; // traverse path for i := 0 to Pred(path.count) do begin if Pos('[', path[i]) > 0 then begin index := StrToInt(GetTextIn(path[i], '[', ']')); e := ElementByIndex(e, index); end else e := ElementByPath(e, path[i]); end; // set result Result := e; end; { GetTextIn: Returns a substring of @str between characters @open and @close. Example usage: s := 'Hello [test] world'; AddMessage(GetTextIn(s, '[', ']')); // prints 'test' } function GetTextIn(str: string; open, close: char): string; var i, openIndex: integer; bOpen: boolean; begin Result := ''; bOpen := false; for i := 1 to Length(str) do begin if not bOpen and (GetChar(str, i) = open) then begin openIndex := i; bOpen := true; end; if bOpen and (GetChar(str, i) = close) then begin Result := CopyFromTo(str, openIndex + 1, i - 1); break; end; end; end; { GetChar: Gets a character in a string and returns it. Example usage: s := '1234'; AddMessage(GetChar(s, 3)); //'3' } function GetChar(const s: string; n: integer): char; begin Result := Copy(s, n, 1); end; { CopyFromTo: A copy function that allows you to copy from one position to another. This function is a better copy function, in my opinion. Example usage: s := 'Hi. I'm a cool guy.'; s := CopyFromTo(s, Pos('a', s), Pos('g', s)); AddMessage(s); //'a cool g' } function CopyFromTo(s: string; p1: integer; p2: integer): string; begin Result := ''; if p1 > p2 then exit; Result := Copy(s, p1, p2 - p1 + 1); end; function IsValidArmorKeyword(e: IInterface; slotmask: integer): boolean; var i: integer; s: string; begin Result := True; s := IntToHex(GetNativeValue(e), 8); if s = '0006C0EC' then begin // ArmorCuirass if slotmask and $4 = 0 then begin Result := False; end; end; if s = '0006C0ED' then begin // ArmorBoots if slotmask and $80 = 0 then begin Result := False; end; end; if s = '0006C0EE' then begin // ArmorHelm if slotmask and ($1 + $1000) = 0 then begin Result := False; end; end; if s = '0006C0EF' then begin // ArmorGauntlets if slotmask and $8 = 0 then begin Result := False; end; end; if s = '000965B2' then begin // ArmorShield if slotmask and $200 = 0 then begin Result := False; end; end; end; function Process(e: IInterface): integer; var slotmask, i, j, p: integer; kwd, kwda, keyword: IInterface; ev, id: string; slKeywords: TStringList; begin // abort if this element is not an armor if Signature(e) <> 'ARMO' then Exit; // abort if this element is clothing if GetElementNativeValues(e, 'BOD2\Armor Type') = 2 then Exit; // get keywords kwda := ElementBySignature(e, 'KWDA'); if not Assigned(kwda) then Exit; // get slotmaks slotmask := GetElementNativeValues(e, 'BOD2\First Person Flags'); // remove all incorrect keywords // (does not work) { for i := Pred( ElementCount(kwda) ) downto 0 do begin if not IsValidArmorKeyword( ElementByIndex(kwda, i), slotmask) then begin AddMessage( 'remove ' + GetEditValue( ElementByIndex(kwda, i) ) + ' from ' + GetElementEditValues(e, 'FULL') ); RemoveByIndex(kwda, i, True); end; end; } // get valid keywords slKeywords := TStringList.Create; j := 0; for i := Pred( ElementCount(kwda) ) downto 0 do begin kwd := ElementByIndex(kwda, i); if IsValidArmorKeyword(kwd, slotmask) then begin ev := GetEditValue(kwd); p := Pos(':', ev); id := Copy(ev, p + 1, 8); //AddMessage(id); slKeywords.Add(id); end else begin AddMessage( 'remove ' + GetEditValue(kwd) + ' from ' + GetElementEditValues(e, 'FULL') ); end; end; // remove keywords RemoveElement(e, 'KWDA'); // rebuild keywords if slKeywords.Count > 0 then begin // first one Add(e, 'KWDA', True); SetEditValue(ElementByIP(e, 'KWDA\[0]'), slKeywords[0]); // second one kwda := ElementBySignature(e, 'KWDA'); for i := 1 to slKeywords.Count - 1 do begin keyword := ElementAssign(kwda, HighInteger, nil, False); SetEditValue(keyword, slKeywords[i]); end; // update keyword count SetElementNativeValues(e, 'KSIZ', slKeywords.Count); end else begin // remove keyword count RemoveElement(e, 'KSIZ'); end; slKeywords.Free; end; end.