防具を服に変換する

Modを作ろう

防具を服に変換するためのSSEEdit用スクリプトです。

Convert - Armor to Clothing.pas (pascal)

{
  Comvert armor to clothing.
}


unit userscript;


var
  validKeywords, invalidKeywords: TStringList;


function Initialize: integer;
begin
  validKeywords := TStringList.Create;
  validKeywords.Add('0006BBE8'); // ArmorHeavy
  validKeywords.Add('0008F95B'); // VenderItemClothing

  invalidKeywords := TStringList.Create;
  invalidKeywords.Add('0006BBD2'); // ArmorHeavy
  invalidKeywords.Add('0006BBD3'); // ArmorLight
  invalidKeywords.Add('0006C0EC'); // ArmorCuirass
  invalidKeywords.Add('0006C0ED'); // ArmorBoots
  invalidKeywords.Add('0006C0EE'); // ArmorHelmet
  invalidKeywords.Add('0006C0EF'); // ArmorGauntlets
  invalidKeywords.Add('0006BBD4'); // ArmorMaterialDaedric
  invalidKeywords.Add('0006BBD5'); // ArmorMaterialDragonplate
  invalidKeywords.Add('0006BBD6'); // ArmorMaterialDragonscale
  invalidKeywords.Add('0006BBD7'); // ArmorMaterialDwarven
  invalidKeywords.Add('0006BBD8'); // ArmorMaterialEbony
  invalidKeywords.Add('0006BBD9'); // ArmorMaterialElven
  invalidKeywords.Add('0006BBDA'); // ArmorMaterialElvenGilded
  invalidKeywords.Add('0006BBDB'); // ArmorMaterialLeather
  invalidKeywords.Add('0006BBDC'); // ArmorMaterialGrass
  invalidKeywords.Add('0006BBDD'); // ArmorMaterialHide
  invalidKeywords.Add('0006BBDE'); // ArmorMaterialScaled
  invalidKeywords.Add('0006BBDF'); // ArmorMaterialStudded
  invalidKeywords.Add('0006BBE0'); // ArmorMaterialImperialLight
  invalidKeywords.Add('0006BBE1'); // ArmorMaterialImperialStudded
  invalidKeywords.Add('0006BBE2'); // ArmorMaterialImperialHeavy
  invalidKeywords.Add('0006BBE3'); // ArmorMaterialIron
  invalidKeywords.Add('0006BBE4'); // ArmorMaterialIronBanded
  invalidKeywords.Add('0006BBE5'); // ArmorMaterialOrcish
  invalidKeywords.Add('0006BBE6'); // ArmorMaterialSteel
  invalidKeywords.Add('0006BBE7'); // ArmorMaterialSteelPlate
  invalidKeywords.Add('010009BD'); // ArmorMaterialFalmer
  invalidKeywords.Add('010009C0'); // ArmorMaterialBlades
  invalidKeywords.Add('04024100'); // DLC2ArmorMaterialBonemoldLight
  invalidKeywords.Add('04024101'); // DLC2ArmorMaterialBonemoldHeavy
  invalidKeywords.Add('04024102'); // DLC2ArmorMaterialChitinLight
  invalidKeywords.Add('04024103'); // DLC2ArmorMaterialChitinHeavy
  invalidKeywords.Add('04024104'); // DLC2ArmorMaterialNordicLight
  invalidKeywords.Add('04024105'); // DLC2ArmorMaterialNordicHeavy
  invalidKeywords.Add('04024106'); // DLC2ArmorMaterialStalhrinHeavy
  invalidKeywords.Add('04024107'); // DLC2ArmorMaterialStalhrinLight
  invalidKeywords.Add('0008F959'); // VenderItemArmor
end;


{
  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 Process(e: IInterface): integer;
var
  slotmask, i: integer;
  kwd, kwda: IInterface;
  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;

  // change to clothing
  SetElementNativeValues(e, '
BOD2\Armor Type', 2);

  // get keywords
  kwda := ElementBySignature(e, '
KWDA');

  if not Assigned(kwda) then Exit;

  // get valid keywords
  slKeywords := TStringList.Create;

  for i := Pred( ElementCount(kwda) ) downto 0 do begin
    kwd := ElementByIndex(kwda, i);
    id := IntToHex(GetNativeValue(kwd), 8);

    // remove invalid keyword
    if invalidKeywords.IndexOf(id) = -1 then begin
      slKeywords.Add(id);
    end else begin
      AddMessage( '
remove ' + GetEditValue(kwd) + ' from ' + GetElementEditValues(e, 'FULL') );
    end;
  end;

  // get slotmask
  slotmask := GetElementNativeValues(e, '
BOD2\First Person Flags');

  if slotmask and $4 <> 0 then begin
    if slKeywords.IndexOf('
000A8657') = -1 then slKeywords.Add('000A8657');
  end;

  if slotmask and $80 <> 0 then begin
    if slKeywords.IndexOf('
0010CD12') = -1 then slKeywords.Add('0010CD12');
  end;

  if slotmask and ($1 + $2) <> 0 then begin
    if slKeywords.IndexOf('
0010CD11') = -1 then slKeywords.Add('0010CD11');
  end;

  if slotmask and $1000 <> 0 then begin
    if slKeywords.IndexOf('
0010CD08') = -1 then slKeywords.Add('0010CD08');
  end;

  if slotmask and ($1 + $8) <> 0 then begin
    if slKeywords.IndexOf('
0010CD13') = -1 then slKeywords.Add('0010CD13');
  end;

  // add valid keywords
  for i := 0 to validKeywords.Count - 1 do begin
    if slKeywords.IndexOf(validKeywords[i]) = -1 then begin
      slKeywords.Add(validKeywords[i]);
    end;
  end;

  {
  for i := 0 to slKeywords.Count - 1 do begin
    AddMessage(slKeywords[i]);
  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
      kwd := ElementAssign(kwda, HighInteger, nil, False);
      SetEditValue(kwd, slKeywords[i]);
    end;

    // update keyword count
    SetElementNativeValues(e, '
KSIZ', slKeywords.Count);
  end else begin
    // remove keyword count
    RemoveElement(e, '
KSIZ');
  end;

  slKeywords.Free;
end;


function Finalize: integer;
begin
  validKeywords.Free;
  invalidKeywords.Free;
end;


end.

タイトルとURLをコピーしました