0 of 0

File information

Last updated

Original upload

Created by

lalolalo9

Uploaded by

lalolalo9

Virus scan

Safe to use

Tags for this mod

About this mod

Uniques are now craftable.

Permissions and credits
Hi all


Long gone are the days where we go to the deadfire wiki page to see what the debugnames are for the uniques we want in our builds. Now they are all craftable ingame. Hurray!


Big thanks for Noqn for providing Apotheosis, the modding tool for Pillars of Eternity II Deadfire


Installation is easy just place the mod folder in your override folder. If it doesn't exist create one.
PillarsOfEternityII_Data/override/MODFOLDERHERE

For the curious people of people who have unique items from other mods and want also those uniques to be craftable.

Use following UserScripts in Apotheosis program and save it.

Get Apotheosis here https://gitlab.com/noqn/apotheosis/-/tree/main

Follow instructions.
Then create a new script in Apotheosis
Paste below script and run it.
Restart POEII
Enjoy!

int count = 0;
string[] debugnames = { "" } ;
string[] debugnamesID = { "" } ;
// Creates a new recipe category called uniques
if (TryCreateGameData<RecipeCategory>("Lalolalo9_Unique_Crafting", out var Lalolalo9_Unique_CraftingCat))
{
  if (Lalolalo9_Unique_CraftingCat.TryGetComponent(out RecipeCategoryComponent rcc))
  {
    var stringindex = rcc.DisplayName.AppendStringTableEntry("Uniques");
    rcc.DisplayName = stringindex;
  }
}
else
{
  // If the catergory already exist assing Lalolalo9_Unique_CraftingCat var to it.
  if(TryGetGameData<RecipeCategory>("Lalolalo9_Unique_Crafting", out Lalolalo9_Unique_CraftingCat))
    { 
    }
}
// Starts adding all unique to a new list because creating new gamedataobjects while looping through it throws errors
foreach (var equipitemGDO in GameData.OfType<EquippableGameData>())
{
  // If the item does not have an itemcomponent return
  if (!TryGetGameData(equipitemGDO.DebugName, out _, out ItemComponent itemC))
  {
    return;
  }
  // Check the name of the item, if its empty chnaces are it does not exist in game
  // Tip adding a + "" converts most objects in the game to string especially useful if working with enumerators like FilterTypes in Itemcomponent
  var itemdisplayname = itemC.DisplayName.GetStringTableText() + "";
  // We only want unique items and not quest related and items with names that are not empty
  if (itemC.IsUnique == true && (itemC.FilterType  + "") != "Quest" && (itemC.DisplayName.GetStringTableText() + "") != "")
  {
    
    // Recipe order in crafitn GUI are not alfabethic or anything, I found out that they are sorted according to when each items was made.
    // This step makes the debugnames uniform and when we will sort it the items will be grouped nicely in crafting window
    if (equipitemGDO.TryGetComponent(out EquippableComponent EquipCDOPreSorted))
        {
            // counting how many items are eligible
            count = count + 1;
            // preparation to assing correct debugnames so the lsit is nicely sorted
            string filtertype = itemC.FilterType + "a";
            string DebugNameToAdd = "Default";
            string EquipTypeSubstituted = (EquipCDOPreSorted.EquipmentType + "").Replace("SmallShield","ShieldS").Replace("MediumShield","ShieldM").Replace("LargeShield","ShieldL");
            if(EquipCDOPreSorted.EquipmentType != 0)
            {
              DebugNameToAdd = filtertype.FirstOrDefault() + "" + EquipTypeSubstituted + "_" + equipitemGDO.DebugName;
            }
            else
            {
              DebugNameToAdd = filtertype.FirstOrDefault() + "" + EquipCDOPreSorted.EquipmentSlot + "_" + equipitemGDO.DebugName;
            }
        // Adding items to the array
        debugnames = debugnames.Concat(new string[] { DebugNameToAdd }).ToArray();
        debugnamesID = debugnamesID.Concat(new string[] { equipitemGDO.DebugName }).ToArray();
        }
  }
}
// Sorts the list of debugnames based on the new debugnames
Array.Sort(debugnames, debugnamesID);
// Now we are making the RecipeData items
for (int i = 1; i < count ; i++)
{
  // We check if the item can be created, if it exist which I doubt this will run
  if (TryCreateGameData<RecipeData>("LalRecipe"+debugnames[i], out var createdRecipe))
  {
    // We want the recipe component so we can modify it
    if (createdRecipe.TryGetComponent(out RecipeComponent recipeComponent))
    {
      // We want the item which we are adding a recipe to
      // Actually all these step may be put together and using try create gamedata as the latest would be best to prevent any unneccesary objects created
      if (TryGetGameData<ItemGameData>(debugnamesID[i], out var itemde))
      {
        // Adding the item to the output list of our recipe component
        RecipeProduct itemtoAdd =  RecipeProduct.Default with { ItemID = itemde.ID};  
        recipeComponent.Output = recipeComponent.Output.Add(itemtoAdd);
        // Here we need the name again of our string so we can assign it as the recipe name in our overview
        if (itemde.TryGetComponent(out EquippableComponent EquipCDO))
        {
          if (itemde.TryGetComponent(out ItemComponent itemCDO))
          {
            string NameToAdd = "Default";
            // Some replacement to make in game a little bit more readable
            string EquipTypeSubstitutedGUI = (EquipCDO.EquipmentType + "").Replace("SmallShield","ShieldS").Replace("MediumShield","ShieldM").Replace("LargeShield","ShieldL");
            string EquipSlotSubstitutedGUI = (EquipCDO.EquipmentSlot + "").Replace("GrimoireOrTrinket","GrimTrin").Replace("RingAnyHand","Ring");
           
            if(EquipCDO.EquipmentType != 0)
            {
              NameToAdd = EquipTypeSubstitutedGUI + " " + itemCDO.DisplayName.GetStringTableText();
            }
            else
            {
              NameToAdd = EquipSlotSubstitutedGUI + " " + itemCDO.DisplayName.GetStringTableText();
            }
            // Assigning the name to the recipe component 
            var stringindex = recipeComponent.DisplayName.AppendStringTableEntry(NameToAdd);
            recipeComponent.DisplayName = stringindex;
          }
        }
      }
      // Setting the category and cost
      recipeComponent.Category = Lalolalo9_Unique_CraftingCat.ID;
      recipeComponent.Cost = 100;
    }
  }
}