Advertisement
DieFeM

ParseTSBlueprint Test

Aug 1st, 2019
301
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 27.57 KB | None | 0 0
  1. unit ParseTSBlueprint;
  2.  
  3. // TJsonObject casts:
  4.  
  5. // S string
  6. // I Integer
  7. // L Int64
  8. // U UInt64
  9. // F Double
  10. // D TDateTime
  11. // D Utc TDateTime
  12. // B Boolean
  13. // A TJsonArray
  14. // O TJsonObject
  15.  
  16. // Castle workshop ref 00066EB6 (for powering reference)
  17.  
  18. // Automation Tools Functions
  19. {
  20.   ConstructOkCancelButtons:
  21.   A procedure which makes the standard OK and Cancel buttons on a form.
  22.  
  23.   Example usage:
  24.   ConstructOkCancelButtons(frm, pnlBottom, frm.Height - 80);
  25. }
  26. procedure ConstructOkCancelButtons(h: TObject; p: TObject; top: Integer);
  27. var
  28.   btnOk: TButton;
  29.   btnCancel: TButton;
  30. begin
  31.   btnOk := TButton.Create(h);
  32.   btnOk.Parent := p;
  33.   btnOk.Caption := 'OK';
  34.   btnOk.ModalResult := mrOk;
  35.   btnOk.Left := h.Width div 2 - btnOk.Width - 8;
  36.   btnOk.Top := top;
  37.  
  38.   btnCancel := TButton.Create(h);
  39.   btnCancel.Parent := p;
  40.   btnCancel.Caption := 'Cancel';
  41.   btnCancel.ModalResult := mrCancel;
  42.   btnCancel.Left := btnOk.Left + btnOk.Width + 16;
  43.   btnCancel.Top := btnOk.Top;
  44. end;
  45.  
  46. {
  47.   ConstructLabel:
  48.   A function which can be used to make a label.  Used to make code more compact.
  49.  
  50.   Example usage:
  51.   lbl3 := ConstructLabel(frm, pnlBottom, 65, 8, 360, 'Reference removal options:');
  52. }
  53. function ConstructLabel(h: TObject; p: TObject; top: Integer; left: Integer; width: Integer; height: Integer; s: String): TLabel;
  54. var
  55.   lb: TLabel;
  56. begin
  57.   lb := TLabel.Create(h);
  58.   lb.Parent := p;
  59.   lb.Top := top;
  60.   lb.Left := left;
  61.   lb.Width := width;
  62.   if (height > 0) then
  63.     lb.Height := height;
  64.   lb.Caption := s;
  65.  
  66.   Result := lb;
  67. end;
  68.  
  69. {
  70.   HexFormID
  71.   Gets the formID of a record as a hexadecimal string.
  72.  
  73.   This is useful for just about every time you want to deal with FormIDs.
  74.  
  75.   Example usage:
  76.   s := HexFormID(e);
  77. }
  78. function HexFormID(e: IInterface): string;
  79. begin
  80.   if ElementExists(e, 'Record Header\FormID') then
  81.     Result := IntToHex(GetLoadOrderFormID(e), 8)
  82.   else
  83.     Result := '00000000';
  84. end;
  85.  
  86. // End of Automation Tools Functions
  87.  
  88. function IsHexFormID(const AValue: string): boolean;
  89. var
  90.   regexp: TPerlRegEx;
  91. begin
  92.   regexp := TPerlRegEx.Create;
  93.   try
  94.     regexp.Subject := AValue;
  95.     regexp.RegEx := '^([A-F0-9]+)$';
  96.     Result := regexp.Match;
  97.   finally
  98.     regexp.Free;
  99.   end;
  100. end;
  101.  
  102. procedure CheckReferencedLinked(ref: IInterface; ToFile: IInterface);
  103. var
  104.   i, j: integer;
  105.   linkedRef, referenced, el: IInterface;
  106. begin
  107.   for i := Pred(ReferencedByCount(ref)) downto 0 do begin
  108.     referenced := ReferencedByIndex(ref, i);
  109.     if Signature(referenced) = 'REFR' then begin
  110.       if ElementExists(referenced, 'Linked References') then begin
  111.         el := ElementByPath(referenced, 'Linked References');
  112.         if Assigned(el) then begin
  113.           j := 0;
  114.           while j < ElementCount(el) do begin
  115.             linkedRef := ElementByIndex(el, j);
  116.             if GetElementEditValues(linkedRef, 'Keyword/Ref') = 'WorkshopStackedItemParentKEYWORD [KYWD:001C5EDD]' then begin
  117.               if GetElementEditValues(linkedRef, 'Ref') = Name(ref) then begin
  118.                 SetOverrideInitiallyDisabled(referenced, ToFile);
  119.               end;
  120.             end;
  121.             Inc(j);
  122.           end;
  123.         end;
  124.       end;
  125.     end;
  126.   end;
  127. end;
  128.  
  129. procedure SetOverrideInitiallyDisabled(ref: IInterface; ToFile: IInterface);
  130. var
  131.   sl: TStringList;
  132.   i: integer;
  133.   refOverride: IInterface;
  134. begin
  135.   sl := TStringList.Create;
  136.   ReportRequiredMasters(ref, sl, false, false);
  137.   i := 0;
  138.   while i < sl.Count do begin
  139.     AddMasterIfMissing(ToFile, sl[i]);
  140.     Inc(i);
  141.   end;
  142.   sl.Free;
  143.   refOverride := wbCopyElementToFile(ref, ToFile, False, True);
  144.   if Assigned(refOverride) then
  145.     SetFlag(ElementByPath(refOverride, 'Record Header\Record Flags'), 'Initially Disabled', true);
  146. end;
  147.  
  148. procedure ScrapAll(WorkshopRefFormID: integer; ToFile: IInterface);
  149. var
  150.   parts, references: TStringList;
  151.   filepath: string;
  152.   pi, i: integer;
  153.   ref: IInterface;
  154. begin
  155.   filepath := ScriptsPath + 'User\' + IntToStr(WorkshopRefFormID) + '.0.log';
  156.   if FileExists(filepath) then begin
  157.     references := TStringList.Create;
  158.     references.LoadFromFile(filepath);
  159.     i := 0;
  160.     while i < references.Count do begin
  161.       parts := TStringList.Create;
  162.       SplitText(references[i], parts);
  163.       if IsHexFormID(parts[0]) then begin
  164.         pi := GetPluginIndex(parts[1]);
  165.         if pi <> -1 then begin
  166.           ref := RecordByFormID(FileByIndex(pi), StrToInt64('$' + parts[0]), True);
  167.           if Assigned(ref) then begin
  168.             SetOverrideInitiallyDisabled(ref, ToFile);
  169.             CheckReferencedLinked(ref, ToFile);
  170.           end;
  171.         end;
  172.       end;
  173.       parts.Free;
  174.       Inc(i);
  175.     end;
  176.     references.Free;
  177.   end;
  178. end;
  179.  
  180. procedure SplitText(const s: String; aList: TStringList);
  181. begin
  182.   aList.Delimiter := '|';
  183.   aList.StrictDelimiter := True; // Spaces excluded from being a delimiter
  184.   aList.DelimitedText := s;
  185. end;
  186.  
  187. function GetPluginIndex(PluginName: string): integer;
  188. var
  189.   i, pi : integer;
  190. begin
  191.   pi := -1;
  192.   for i := Pred(FileCount) downto 0 do
  193.     if SameText(PluginName, GetFileName(FileByIndex(i))) then begin
  194.       pi := i;
  195.       Break;
  196.     end;
  197.   Result := pi;
  198. end;
  199.  
  200. function GetWorkshopRef(PluginIndex: integer; WorkshopID:string): IInterface;
  201. var
  202.   fid: integer;
  203.   f: IInterface;
  204. begin
  205.   f := FileByIndex(PluginIndex);
  206.   fid := StrToInt64('$' + IntToHex(GetLoadOrder(f), 2) + WorkshopID);
  207.   Result := RecordByFormID(f, fid, True);
  208. end;
  209.  
  210. procedure AddOrAssign(r: IInterface; container: string; element: string; value: string);
  211. var
  212.   el: IInterface;
  213. begin
  214.   if ElementExists(r, container) then begin
  215.     el := ElementByPath(r, container);
  216.     el := ElementAssign(el, HighInteger, nil, False);
  217.     if Assigned(el) then begin
  218.       SetElementEditValues(el, element, value);
  219.     end;
  220.   end
  221.   else begin
  222.     el := Add(r, container, True);
  223.     if Assigned(el) then begin
  224.       SetElementEditValues(ElementByIndex(el, 0), element, value);
  225.     end;
  226.   end;
  227. end;
  228.  
  229. procedure AddToPowerGrid(workshopRef: IInterface; Node1Ref: IInterface; Node2Ref: IInterface; LineRef: IInterface);
  230. var
  231.   el: IInterface;
  232. begin
  233.   if ElementExists(workshopRef, 'Power Grid') then begin
  234.     el := ElementByPath(workshopRef, 'Power Grid');
  235.     SetElementNativeValues(el, 'XWPG', GetElementNativeValues(el, 'XWPG') + 1);
  236.     el := ElementByPath(el, 'Connections');
  237.     if Assigned(el) then begin
  238.       el := ElementAssign(el, HighInteger, nil, False);
  239.       if Assigned(el) then begin
  240.         if Node1Ref <> nil then
  241.           SetElementEditValues(el, 'Node 1', Name(Node1Ref));
  242.         if Node2Ref <> nil then
  243.           SetElementEditValues(el, 'Node 2', Name(Node2Ref));
  244.         if LineRef <> nil then
  245.           SetElementEditValues(el, 'Line', Name(LineRef));
  246.       end;
  247.     end;
  248.   end
  249.   else begin
  250.     el := Add(workshopRef, 'Power Grid', True);
  251.     if Assigned(el) then begin
  252.       SetElementEditValues(el, 'XWPG', '1');
  253.       el := Add(el, 'XWPN', False);
  254.       if Assigned(el) then begin
  255.         SetElementEditValues(el, 'XWPN\Node 1', Name(Node1Ref));
  256.         SetElementEditValues(el, 'XWPN\Node 2', Name(Node2Ref));
  257.         if LineRef <> nil then
  258.           SetElementEditValues(el, 'XWPN\Line', Name(LineRef));
  259.       end;
  260.     end;
  261.   end;
  262. end;
  263.  
  264. procedure ListAVandKW(rec: IInterface ;sl :TStringList);
  265. var
  266.   j: integer;
  267.   element: IInterface;
  268. begin
  269.   element := ElementByPath(rec, 'PRPS');
  270.   if Assigned(element) then begin
  271.     j := 0;
  272.     while j < ElementCount(element) do begin
  273.       sl.Add(GetElementEditValues(ElementByIndex(element, j), 'Actor Value'));
  274.       Inc(j);
  275.     end;
  276.   end;
  277.   element := ElementByPath(rec, 'KWDA');
  278.   if Assigned(element) then begin
  279.     j := 0;
  280.     while j < ElementCount(element) do begin
  281.       sl.Add(GetEditValue(ElementByIndex(element, j)));
  282.       Inc(j);
  283.     end;
  284.   end;
  285. end;
  286.  
  287. procedure SetFlag(elem: IInterface; flagName: string; flagValue: boolean);
  288. var
  289.   sl: TStringList;
  290.   i: Integer;
  291.   f, f2: Cardinal;
  292. begin
  293.   sl := TStringList.Create;
  294.   sl.Text := FlagValues(elem);
  295.   f := GetNativeValue(elem);
  296.   for i := 0 to Pred(sl.Count) do
  297.     if SameText(sl[i], flagName) then begin
  298.       if flagValue then
  299.         f2 := f or (1 shl i)
  300.       else
  301.         f2 := f and not (1 shl i);
  302.       if f <> f2 then SetNativeValue(elem, f2);
  303.       Break;
  304.     end;
  305.   sl.Free;
  306. end;
  307.  
  308. function StripNonAlpha(const AValue: string): string;
  309. var
  310.   regexp: TPerlRegEx;
  311. begin
  312.   regexp := TPerlRegEx.Create;
  313.   try
  314.     regexp.Subject := AValue;
  315.     regexp.RegEx := '([^a-zA-Z0-9]+)';
  316.     regexp.Options := [preCaseLess];
  317.     regexp.ReplaceAll;
  318.     Result := regexp.Subject;
  319.   finally
  320.     regexp.Free;
  321.   end;
  322. end;
  323.  
  324. function GetWorkshopRefDup(workshopRef: IInterface; workshoptype: integer; ToFile: IInterface): IInterface;
  325. var
  326.   element, baseObj1, baseObj2, workshopRefDup: IInterface;
  327.   i: integer;
  328. begin
  329.   if workshoptype = 0 then begin
  330.     AddMessage('Workshop Type: Copy record for workshop ref as dual workshop.');
  331.     workshopRefDup := wbCopyElementToFile(workshopRef, ToFile, True, True);// Copy record for workshop ref as new record
  332.    
  333.     baseObj1 := LinksTo(ElementByName(workshopRef, 'NAME - Base')); // Get the workshop base object
  334.     baseObj1 := wbCopyElementToFile(baseObj1, ToFile, True, True); // Copy record for workshop base object
  335.     SetElementEditValues(baseObj1, 'EDID', GetElementEditValues(baseObj1, 'EDID') + '_' + StripNonAlpha(GetFileName(ToFile))); // Add suffix to the EDID of our copied workshop base object
  336.     baseObj2 := RecordByFormID(FileByIndex(0), StrToInt64('$0023F662'), False); // Get the base object of the invisible chest
  337.     SetElementEditValues(baseObj1, 'Model\MODL', GetElementEditValues(baseObj2, 'Model\MODL')); // Set the model of the duplicate workshop base object as a invisible chest
  338.     SetElementEditValues(workshopRefDup, 'NAME', HexFormID(baseObj1)); // Set our custom workshop base object for our duplicated workshop ref.
  339.     SetElementEditValues(workshopRefDup, 'EDID', GetElementEditValues(workshopRef, 'EDID') + '_' + StripNonAlpha(GetFileName(ToFile))); // Set the base object of the duplicate workshop as a invisible chest
  340.    
  341.     element := Add(workshopRefDup, 'Linked References', True); // Link the duplicated workshop to the actual workshop
  342.     if Assigned(element) then begin
  343.       SetElementEditValues(element, 'XLKR\Keyword/Ref', '00054BA6');
  344.       SetElementEditValues(element, 'XLKR\Ref', Name(workshopRef));
  345.     end;
  346.   end
  347.   else if workshoptype = 1 then begin
  348.     AddMessage('Workshop Type: Copy record for workshop ref as complete replacement');
  349.     workshopRefDup := wbCopyElementToFile(workshopRef, ToFile, True, True);// Copy record for workshop ref as new record
  350.     // redirect 'referenced by' workshop records
  351.     for i := Pred(ReferencedByCount(workshopRef)) downto 0 do begin
  352.       baseObj1 := ReferencedByIndex(workshopRef, i);
  353.       AddMasterIfMissing(ToFile, GetFileName(GetFile(baseObj1)));
  354.       baseObj1 := wbCopyElementToFile(baseObj1, ToFile, False, True);
  355.       CompareExchangeFormID(baseObj1, GetLoadOrderFormID(workshopRef), GetLoadOrderFormID(workshopRefDup));
  356.     end;
  357.     workshopRef := wbCopyElementToFile(workshopRef, ToFile, False, True);// Copy record for workshop ref as override
  358.     SetFlag(ElementByPath(workshopRef, 'Record Header\Record Flags'), 'Deleted', true); // Flag the workshop override as deleted
  359.   end
  360.   else if workshoptype = 2 then begin
  361.     AddMessage('Workshop Type: Override record for workshop ref');
  362.     workshopRefDup := wbCopyElementToFile(workshopRef, ToFile, False, True);// Copy record for workshop ref as override
  363.   end;
  364.   Result := workshopRefDup;
  365. end;
  366.  
  367. procedure WorkshopAllowMove(baseObj: IInterface; ref: IInterface);
  368. var
  369.   refVMAD, refScripts, refWS, refWSProperties, objVMAD, objScripts, objWS, objWSProperties, prop: IInterface;
  370.   i, j: integer;
  371.   bAllowMoveFound: boolean;
  372. begin
  373.   refVMAD := Add(ref, 'VMAD', True);
  374.   refScripts := ElementByIndex(refVMAD, 2); // Scripts
  375.   refWS := ElementAssign(refScripts, HighInteger, nil, False);
  376.   SetElementEditValues(refWS, 'scriptName', 'workshopnpcscript');
  377.   refWSProperties := ElementByIndex(refWS, 2);
  378.  
  379.   bAllowMoveFound := false;
  380.  
  381.   objVMAD := ElementByPath(baseObj, 'VMAD');
  382.   if Assigned(objVMAD) then begin
  383.     objScripts := ElementByIndex(objVMAD, 2);
  384.     if Assigned(objScripts) then begin
  385.       i := 0;
  386.       while i < ElementCount(objScripts) do begin
  387.         objWS := ElementByIndex(objScripts, i);
  388.         if GetElementEditValues(objWS, 'scriptName') = 'workshopnpcscript' then begin
  389.           objWSProperties := ElementByIndex(objWS, 2);
  390.           j := 0;
  391.           while j < ElementCount(objWSProperties) do begin
  392.             prop := ElementAssign(refWSProperties, HighInteger, ElementByIndex(objWSProperties, j), False);
  393.             if Assigned(prop) then begin
  394.               if GetElementEditValues(prop, 'propertyName') = 'bAllowMove' then begin
  395.                 SetElementEditValues(prop, 'Bool', 'True');
  396.                 bAllowMoveFound := true;
  397.               end;
  398.             end;
  399.             Inc(j);
  400.           end;
  401.           break;
  402.         end;
  403.         Inc(i);
  404.       end;
  405.     end;
  406.   end;
  407.  
  408.   if bAllowMoveFound = false then begin
  409.     prop := ElementAssign(refWSProperties, HighInteger, nil, False);
  410.     if Assigned(prop) then begin
  411.       SetElementEditValues(prop, 'propertyName', 'bAllowMove');
  412.       SetElementEditValues(prop, 'Type', 'Bool');
  413.       SetElementEditValues(prop, 'Bool', 'True');
  414.     end;
  415.   end;
  416. end;
  417.  
  418. function HasScript(rec: IInterface; script: string): boolean;
  419. var
  420.   el: IInterface;
  421.   r: boolean;
  422.   i: integer;
  423. begin
  424.   r := false;
  425.   el := ElementByPath(rec, 'VMAD');
  426.   if Assigned(el) then begin
  427.     el := ElementByIndex(el, 2); // Scripts
  428.     if Assigned(el) then begin
  429.       i := 0;
  430.       while i < ElementCount(el) do begin
  431.         if GetElementEditValues(ElementByIndex(el, i), 'scriptName') = script then begin
  432.           r := true;
  433.           break;
  434.         end;
  435.         Inc(i);
  436.       end;
  437.     end;
  438.   end;
  439.   Result := r;
  440. end;
  441.  
  442. procedure BeginImport(bppath: string; ToFile: IInterface; workshoptype: integer);
  443. var
  444.   BP, obj: TJsonObject;
  445.   form_id, reftype: string;
  446.   items: TJsonArray;
  447.   j, i, pi: integer;
  448.   element, workshopRef, workshopRefDup, wscell, ref, refA, refB, baseObj: IInterface;
  449.   sl: TStringList;
  450. begin
  451.   BP := TJsonObject.Create;
  452.   try
  453.     // parse the blueprint in the path given by the argument bppath (relative to Data)
  454.     BP.LoadFromResource(bppath);
  455.    
  456.     // Add Fallout4.esm as master beforehand because the first record copied
  457.     // could be from another file and it may contain references to records of Fallout4.esm
  458.     AddMasterIfMissing(ToFile, GetFileName(FileByIndex(0)));
  459.    
  460.     pi := GetPluginIndex(BP.O['workshop'].S['plugin']);
  461.     workshopRef := GetWorkshopRef(pi, BP.O['workshop'].S['id']);
  462.    
  463.     ScrapAll(GetLoadOrderFormID(workshopRef), ToFile);
  464.    
  465.     wscell := LinksTo(ElementByName(workshopRef, 'Cell'));
  466.     AddMasterIfMissing(ToFile, GetFileName(GetFile(wscell)));
  467.     // Copy the workshop cell as override record and store the cell's persistent group in wscell
  468.     wscell := wbCopyElementToFile(ElementByIndex(ChildGroup(wscell), 0), ToFile, True, False);
  469.    
  470.     WorkshopRefDup := GetWorkshopRefDup(workshopRef, workshoptype, ToFile);
  471.    
  472.     items := BP.A['items'];
  473.     i := 0;
  474.     while i < items.Count do begin
  475.       obj := items.O[i];
  476.       pi := GetPluginIndex(obj.S['plugin_name']);
  477.       if pi = -1 then begin
  478.         AddMessage(obj.S['plugin_name'] + ' Plugin Not Found');
  479.       end
  480.       else begin
  481.           form_id := IntToHex(GetLoadOrder(FileByIndex(pi)), 2) + obj.S['FormID'];
  482.           try
  483.             baseObj := RecordByFormID(FileByIndex(pi), StrToInt64('$' + form_id), False);
  484.            
  485.             sl := TStringList.Create;
  486.             ReportRequiredMasters(baseObj, sl, false, false);
  487.             j := 0;
  488.             while j < sl.Count do begin
  489.               AddMasterIfMissing(ToFile, sl[j]);
  490.               Inc(j);
  491.             end;
  492.             sl.Free;
  493.            
  494.             if Signature(baseObj) = 'NPC_' then reftype := 'ACHR' else reftype := 'REFR';
  495.            
  496.             ref := Add(wscell, reftype, True);
  497.             SetElementEditValues(ref, 'NAME', form_id);
  498.             SetElementEditValues(ref, 'DATA\Position\X', obj.S['posX']);
  499.             SetElementEditValues(ref, 'DATA\Position\Y', obj.S['posY']);
  500.             SetElementEditValues(ref, 'DATA\Position\Z', obj.S['posZ']);
  501.             SetElementEditValues(ref, 'DATA\Rotation\X', obj.S['rotX']);
  502.             SetElementEditValues(ref, 'DATA\Rotation\Y', obj.S['rotY']);
  503.             SetElementEditValues(ref, 'DATA\Rotation\Z', obj.S['rotZ']);
  504.            
  505.             if obj.S['Scale'] <> '1.0' then begin
  506.               element := Add(ref, 'XSCL', True);
  507.               if Assigned(element) then
  508.                 SetEditValue(element, obj.S['Scale']);
  509.             end;
  510.            
  511.             element := Add(ref, 'Linked References', True);
  512.             if Assigned(element) then begin
  513.               SetElementEditValues(element, 'XLKR\Keyword/Ref', '00054BA6');
  514.               SetElementEditValues(element, 'XLKR\Ref', Name(workshopRefDup));
  515.             end;
  516.            
  517.             if Signature(baseObj) = 'NPC_' then
  518.               if HasScript(baseObj, 'workshopnpcscript') then
  519.                 WorkshopAllowMove(baseObj, ref);
  520.            
  521.             obj.S['RefId'] := HexFormID(ref);
  522.           except
  523.             on E: Exception do
  524.               AddMessage('Error, base object not found for FormID: ' + form_id + ' (' + obj.S['name'] + ' [' + obj.S['plugin_name'] + '])');
  525.             end
  526.       end;
  527.       Inc(i);
  528.     end;
  529.    
  530.     // Start Powering Phase While
  531.     i := 0;
  532.     while i < items.Count do begin
  533.       obj := items.O[i];
  534.      
  535.       // Start if refid is not 0
  536.       if obj.S['RefId'] <> '' then begin
  537.      
  538.         refA := RecordByFormID(ToFile, StrToInt64('$' + obj.S['RefId']), True);
  539.        
  540.         // Start if Cables else Objects
  541.         // Start Cables
  542.         if obj.S['ConnectedObjects'] <> '' then begin
  543.          
  544.           sl := TStringList.Create;
  545.           SplitText(obj.S['ConnectedObjects'], sl);
  546.          
  547.           // Loop Connected Objects
  548.           j := 0;
  549.           while j < sl.Count do begin
  550.             // Start (Is Connected Object with greater Index)
  551.             if StrToInt(sl[j]) > i then begin
  552.               // Start Check object in items bounds
  553.               if StrToInt(sl[j]) < items.Count then begin
  554.                 // Start Check if connected object has a reference
  555.                 if items.O[StrToInt(sl[j])].S['RefId'] <> '' then begin
  556.                  
  557.                   // Get Connected Object Ref
  558.                   refB := RecordByFormID(ToFile, StrToInt64('$' + items.O[StrToInt(sl[j])].S['RefId']), True);
  559.                  
  560.                   // Create Spline
  561.                   ref := Add(wscell, 'REFR', True);
  562.                   SetElementEditValues(ref, 'NAME', '0001D971');
  563.                   SetElementNativeValues(ref, 'DATA\Position\X', StrToFloat(obj.S['posX']) + ((GetElementNativeValues(refB, 'DATA\Position\X') - GetElementNativeValues(refA, 'DATA\Position\X'))/2));
  564.                   SetElementNativeValues(ref, 'DATA\Position\Y', StrToFloat(obj.S['posY']) + ((GetElementNativeValues(refB, 'DATA\Position\Y') - GetElementNativeValues(refA, 'DATA\Position\Y'))/2));
  565.                   SetElementNativeValues(ref, 'DATA\Position\Z', StrToFloat(obj.S['posZ']) + ((GetElementNativeValues(refB, 'DATA\Position\Z') - GetElementNativeValues(refA, 'DATA\Position\Z'))/2));
  566.                   SetElementEditValues(ref, 'DATA\Rotation\X', '0.0');
  567.                   SetElementEditValues(ref, 'DATA\Rotation\Y', '0.0');
  568.                   SetElementEditValues(ref, 'DATA\Rotation\Z', '0.0');
  569.                  
  570.                   // Link Spline ref to workshop
  571.                   element := Add(ref, 'Linked References', True);
  572.                   if Assigned(element) then begin
  573.                     SetElementEditValues(element, 'XLKR\Keyword/Ref', '00054BA6');
  574.                     SetElementEditValues(element, 'XLKR\Ref', Name(workshopRefDup));
  575.                   end;
  576.                  
  577.                   // Set Spline Values
  578.                   element := Add(ref, 'XBSD', True);
  579.                   if Assigned(element) then begin
  580.                     // Slack
  581.                     SetEditValue(ElementByIndex(element, 0), '0.051149');
  582.                     // Thickness
  583.                     SetEditValue(ElementByIndex(element, 1), '1.500000');
  584.                     // ? Other point Relative X
  585.                     SetNativeValue(ElementByIndex(element, 2), (GetElementNativeValues(refB, 'DATA\Position\X') - GetElementNativeValues(refA, 'DATA\Position\X'))/2);
  586.                     // ? Other point Relative Y
  587.                     SetNativeValue(ElementByIndex(element, 3), (GetElementNativeValues(refB, 'DATA\Position\Y') - GetElementNativeValues(refA, 'DATA\Position\Y'))/2);
  588.                     // ? Other point Relative Z
  589.                     SetNativeValue(ElementByIndex(element, 4), (GetElementNativeValues(refB, 'DATA\Position\Z') - GetElementNativeValues(refA, 'DATA\Position\Z'))/2);
  590.                     // Detached End
  591.                     SetEditValue(ElementByIndex(element, 5), 'False');
  592.                   end;
  593.                  
  594.                   // Set Spline Connections
  595.                   AddOrAssign(ref, 'Spline Connection', 'Ref', Name(refA));
  596.                   AddOrAssign(ref, 'Spline Connection', 'Ref', Name(refB));
  597.                   AddOrAssign(refA, 'Spline Connection', 'Ref', Name(ref));
  598.                   AddOrAssign(refB, 'Spline Connection', 'Ref', Name(ref));
  599.                  
  600.                   // Setup Grid
  601.                   AddToPowerGrid(workshopRefDup, refA, refB, ref);
  602.                 // End Check if connected object has a reference
  603.                 end;
  604.               // End Check object in items bounds
  605.               end;
  606.             // End (Is Connected Object with greater Index)
  607.             end;
  608.             Inc(j);
  609.           // End Loop Connected Objects
  610.           end;
  611.           sl.Free;
  612.         // End Cables
  613.         end
  614.         // Start Objects
  615.         else begin
  616.           // Start If assigned radiator
  617.           if obj.I['isPowered'] = 1 then
  618.             AddToPowerGrid(workshopRefDup, refA, workshopRefDup, nil);
  619.         // End Objects
  620.         // End if Cables else Objects
  621.         end;
  622.        
  623.         // Give power to snapped connections
  624.         pi := GetPluginIndex(obj.S['plugin_name']);
  625.         form_id := IntToHex(GetLoadOrder(FileByIndex(pi)), 2) + obj.S['FormID'];
  626.         baseObj := RecordByFormID(FileByIndex(pi), StrToInt64('$' + form_id), False);
  627.         sl := TStringList.Create;
  628.         ListAVandKW(baseObj, sl);
  629.         if sl.IndexOf('WorkshopSnapTransmitsPower [AVIF:00000354]') > -1 then
  630.           AddToPowerGrid(workshopRefDup, refA, workshopRefDup, nil);
  631.         sl.Free;
  632.       // End if refid is not 0
  633.       end;
  634.       Inc(i);
  635.     // End Powering Phase While
  636.     end;
  637.   finally
  638.     BP.Free;
  639.   end;
  640. end;
  641.  
  642. function SelectWorkshopType(): integer;
  643. var
  644.   frm: TForm;
  645.   lbl: TLabel;
  646.   cbFiles: TComboBox;
  647. begin
  648.   frm := TForm.Create(nil);
  649.   try
  650.     frm.Caption := 'Select Workshop Type';
  651.     frm.Width := 500;
  652.     frm.Height := 160;
  653.     frm.Position := poScreenCenter;
  654.    
  655.     lbl := ConstructLabel(frm, frm, 8, 8, 284, 30, 'Workshop Type:');
  656.    
  657.     cbFiles := TComboBox.Create(frm);
  658.     cbFiles.Parent := frm;
  659.     cbFiles.Items.Add('Dual Workshop (two workshops in 1 settlement (2nd hidden), has own stats)');
  660.     cbFiles.Items.Add('Complete Replacement (redirects references, can produce incompatibilities)');
  661.     cbFiles.Items.Add('Override Record (optimal, only new game, saved game = no power)');
  662.     cbFiles.Top := lbl.Top + lbl.Height + 20;
  663.     cbFiles.Left := 8;
  664.     cbFiles.Width := 400;
  665.     cbFiles.Style := csDropDownList;
  666.     cbFiles.ItemIndex := 0;
  667.        
  668.     ConstructOkCancelButtons(frm, frm, 80);
  669.    
  670.     if frm.ShowModal = mrOk then
  671.       Result := cbFiles.ItemIndex
  672.     else
  673.       Result := -1;
  674.   finally
  675.     frm.Free;
  676.   end;
  677. end;
  678.  
  679. function CreateSelector(title: string; Blueprints: TwbFastStringList; var bppath: string): integer;
  680. var
  681.   frm: TForm;
  682.   lbl: TLabel;
  683.   cbFiles: TComboBox;
  684.   btnOk, btnCancel: TButton;
  685.   i: integer;
  686.   s: string;
  687. begin
  688.   frm := TForm.Create(nil);
  689.   try
  690.     frm.Caption := 'Select ' + title;
  691.     frm.Width := 550;
  692.     frm.Height := 170;
  693.     frm.Position := poScreenCenter;
  694.    
  695.     lbl := ConstructLabel(frm, frm, 8, 8, 284, 30, title);
  696.    
  697.     cbFiles := TComboBox.Create(frm);
  698.     cbFiles.Parent := frm;
  699.     cbFiles.Top := lbl.Top + lbl.Height + 20;
  700.     cbFiles.Left := 8;
  701.     cbFiles.Width := 500;
  702.     cbFiles.Style := csDropDownList;
  703.    
  704.     for i := 0 to Pred(Blueprints.Count) do
  705.       cbFiles.Items.Add(Blueprints[i]);
  706.    
  707.     cbFiles.ItemIndex := 0;
  708.    
  709.     ConstructOkCancelButtons(frm, frm, cbFiles.Top + 40);
  710.    
  711.     if frm.ShowModal = mrOk then begin
  712.       bppath := cbFiles.Text;
  713.       Result := 0;
  714.     end
  715.     else Result := 1;
  716.   finally
  717.     frm.Free;
  718.   end;
  719. end;
  720.  
  721. function SelectBlueprint(var bppath: string): integer;
  722. var
  723.   i: integer;
  724.   slContainers: TStringList;
  725.   Blueprints, slAssets: TwbFastStringList;
  726.   r: integer;
  727. begin
  728.   slContainers := TStringList.Create;
  729.   slAssets := TwbFastStringList.Create;
  730.   Blueprints := TwbFastStringList.Create;
  731.  
  732.   ResourceContainerList(slContainers);
  733.  
  734.   for i := 0 to Pred(slContainers.Count) do
  735.     if ExtractFileName(slContainers[i]) = '' then
  736.       ResourceList(slContainers[i], slAssets);
  737.  
  738.   slAssets.Sort;
  739.   wbRemoveDuplicateStrings(slAssets);
  740.  
  741.   for i := 0 to Pred(slAssets.Count) do
  742.     if ContainsText(slAssets[i], 'F4SE\Plugins\TransferSettlements\blueprints') then
  743.       if SameText(ExtractFileExt(slAssets[i]), '.json') then
  744.         Blueprints.Add(slAssets[i]);
  745.  
  746.   if Blueprints.Count > 0 then begin
  747.     r := CreateSelector('Blueprint', Blueprints, bppath);
  748.   end
  749.   else
  750.     r := 2;
  751.   Blueprints.Free;
  752.   slAssets.Free;
  753.   slContainers.Free;
  754.   Result := r;
  755. end;
  756.  
  757. function SelectESP(var FileName: string): integer;
  758. var
  759.   i: integer;
  760.   Plugins: TwbFastStringList;
  761.   r: integer;
  762. begin
  763.   Plugins := TwbFastStringList.Create;
  764.   Plugins.Add('<New File>');
  765.   for i := Pred(FileCount) downto 0 do
  766.     if SameText(ExtractFileExt(GetFileName(FileByIndex(i))), '.esp') then
  767.       Plugins.Add(GetFileName(FileByIndex(i)));
  768.  
  769.   r := CreateSelector('Plugin', Plugins, FileName);
  770.  
  771.   Plugins.Free;
  772.   Result := r;
  773. end;
  774.  
  775. // in the initialization it just shows a dialogue to enter the path of the blueprint
  776. // and calls BeginImport with the given path
  777. function Initialize: Integer;
  778. var
  779.   fname, s: string;
  780.   fr, r, w: integer;
  781.   f: IInterface;
  782. begin
  783.   r := SelectBlueprint(s);
  784.   if r = 0 then begin
  785.     if ResourceExists(s) then begin
  786.       w := SelectWorkshopType();
  787.       if w <> -1 then begin
  788.         fr := SelectESP(fname);
  789.         if fr = 0 then begin
  790.           if fname = '<New File>' then begin
  791.             f := AddNewFile; //Shows a dialog to create a new esp.
  792.           end
  793.           else begin
  794.             f := FileByIndex(GetPluginIndex(fname));
  795.           end;
  796.           if f <> nil then BeginImport(s, f, w) else AddMessage('Invalid File Name.');
  797.         end
  798.         else
  799.           AddMessage('Import canceled.');
  800.       end
  801.       else AddMessage('Import canceled.');
  802.     end
  803.     else
  804.       AddMessage('File ' + s + ' could not be found in the Data folder.');
  805.   end
  806.   else if r = 1 then
  807.     AddMessage('Import canceled.')
  808.   else
  809.     AddMessage('No blueprints found.');
  810.  
  811.   Result := 1;
  812. end;
  813.  
  814. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement