diff --git a/CHANGELOG.md b/CHANGELOG.md index 1be5e139fb..98467f9e20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - Added Simulate, which causes the next pattern drawn to be simulated (to check for mishaps) rather than executed ([#1194](https://github.com/FallingColors/HexMod/pull/1194)) @Robotgiggle - Added the `hex_unbreakable` tag for blocks that should be immune to Break Block regardless of the configured mining tier ([#1186](https://github.com/FallingColors/HexMod/pull/1186)) @Robotgiggle @slava110 - Added a new Ancient Cypher hex that impulses nearby items towards the caster ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid +- Added a recipe to copy a spellbook's contents into another blank spellbook using dragon's breath ([#1231](https://github.com/FallingColors/HexMod/pull/1231)) @Robotgiggle +- Added a recipe to fully erase a spellbook's contents using soul sand ([#1231](https://github.com/FallingColors/HexMod/pull/1231)) @Robotgiggle ### Changed @@ -26,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - Fixed Entity Iota comparison to use `equals` on entity IDs instead of reference equality ([#1101](https://github.com/FallingColors/HexMod/pull/1101)) @IridescentVoid - Corrected field names of the codec for Pattern Iotas and add a graceful fallback for upgrading ([#1120](https://github.com/FallingColors/HexMod/pull/1120), [#1131](https://github.com/FallingColors/HexMod/pull/1131), [#1140](https://github.com/FallingColors/HexMod/pull/1140)) @Master-Bw3 @IridescentVoid +- Fixed the iota-holder sealing recipe also consuming anything else placed into the crafting grid ([#1231](https://github.com/FallingColors/HexMod/pull/1231)) @Robotgiggle ### Internal diff --git a/Common/src/generated/resources/data/hexcasting/recipe/dynamiccopy_spellbook.json b/Common/src/generated/resources/data/hexcasting/recipe/dynamiccopy_spellbook.json new file mode 100644 index 0000000000..9b052f3500 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/dynamiccopy_spellbook.json @@ -0,0 +1,4 @@ +{ + "type": "hexcasting:copy_spellbook", + "category": "misc" +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/recipe/dynamicerase_spellbook.json b/Common/src/generated/resources/data/hexcasting/recipe/dynamicerase_spellbook.json new file mode 100644 index 0000000000..3612273f79 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/recipe/dynamicerase_spellbook.json @@ -0,0 +1,4 @@ +{ + "type": "hexcasting:erase_spellbook", + "category": "misc" +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/tags/item/spellbook_copy_materials.json b/Common/src/generated/resources/data/hexcasting/tags/item/spellbook_copy_materials.json new file mode 100644 index 0000000000..1c508bfd3d --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/tags/item/spellbook_copy_materials.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:dragon_breath" + ] +} \ No newline at end of file diff --git a/Common/src/generated/resources/data/hexcasting/tags/item/spellbook_erase_materials.json b/Common/src/generated/resources/data/hexcasting/tags/item/spellbook_erase_materials.json new file mode 100644 index 0000000000..355a91fd01 --- /dev/null +++ b/Common/src/generated/resources/data/hexcasting/tags/item/spellbook_erase_materials.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:soul_sand" + ] +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexTags.java b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexTags.java index 8230034ac1..073f9f4e2f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/mod/HexTags.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/mod/HexTags.java @@ -19,6 +19,8 @@ public static final class Items { public static final TagKey PHIAL_BASE = create("phial_base"); public static final TagKey GRANTS_ROOT_ADVANCEMENT = create("grants_root_advancement"); public static final TagKey SEAL_MATERIALS = create("seal_materials"); + public static final TagKey SPELLBOOK_COPY_MATERIALS = create("spellbook_copy_materials"); + public static final TagKey SPELLBOOK_ERASE_MATERIALS = create("spellbook_erase_materials"); public static final TagKey IMPETI = create("impeti"); public static final TagKey DIRECTRICES = create("directrices"); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/CopySpellbookRecipe.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/CopySpellbookRecipe.java new file mode 100644 index 0000000000..b3627c739b --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/CopySpellbookRecipe.java @@ -0,0 +1,95 @@ +package at.petrak.hexcasting.common.recipe; + +import at.petrak.hexcasting.api.mod.HexTags; +import at.petrak.hexcasting.common.lib.HexDataComponents; +import at.petrak.hexcasting.common.lib.HexItems; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.NonNullList; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.*; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +public class CopySpellbookRecipe extends CustomRecipe { + public static final SimpleCraftingRecipeSerializer SERIALIZER = + new SimpleCraftingRecipeSerializer<>(CopySpellbookRecipe::new); + + public CopySpellbookRecipe(CraftingBookCategory category) { + super(category); + } + + @Override + public boolean canCraftInDimensions(int width, int height) { + return width * height >= 2; + } + + @Override + public boolean matches(CraftingInput container, Level level) { + boolean foundCopyMaterial = false; + boolean foundOriginal = false; + boolean foundBlank = false; + + for (int i = 0; i < container.size(); i++) { + var stack = container.getItem(i); + if (stack.is(HexTags.Items.SPELLBOOK_COPY_MATERIALS)) { + if (foundCopyMaterial) return false; + foundCopyMaterial = true; + } else if (stack.is(HexItems.SPELLBOOK.get())) { + if (stack.has(HexDataComponents.SPELLBOOK_PAGES.get())) { + if (foundOriginal) return false; + foundOriginal = true; + } else { + if (foundBlank) return false; + foundBlank = true; + } + } else { + return false; + } + } + + return foundCopyMaterial && foundOriginal && foundBlank; + } + + @Override + public @NotNull ItemStack assemble(CraftingInput inv, HolderLookup.RegistryLookup.@NotNull Provider registryProvider) { + ItemStack output = ItemStack.EMPTY; + Integer variant = null; + for (int i = 0; i < inv.size(); i++) { + var stack = inv.getItem(i); + if (stack.is(HexItems.SPELLBOOK.get())) { + if (stack.has(HexDataComponents.SPELLBOOK_PAGES.get())) { + output = stack.copyWithCount(1); + } else { + variant = stack.get(HexDataComponents.ITEM_VARIANT.get()); + } + } + } + if (variant != null && output != ItemStack.EMPTY) { + output.set(HexDataComponents.ITEM_VARIANT.get(), variant); + } + return output; + } + + @Override + public @NotNull NonNullList getRemainingItems(@NotNull CraftingInput craftingInput) { + NonNullList remainingItems = NonNullList.withSize(craftingInput.size(), ItemStack.EMPTY); + + for(int i = 0; i < remainingItems.size(); ++i) { + ItemStack stack = craftingInput.getItem(i); + if (stack.getItem().hasCraftingRemainingItem()) { + remainingItems.set(i, new ItemStack(stack.getItem().getCraftingRemainingItem())); + } else if (stack.is(HexItems.SPELLBOOK.get()) && stack.get(HexDataComponents.SPELLBOOK_PAGES.get()) != null) { + remainingItems.set(i, stack.copyWithCount(1)); + } + } + + return remainingItems; + } + + @Override + public @NotNull RecipeSerializer getSerializer() { + return SERIALIZER; + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/EraseSpellbookRecipe.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/EraseSpellbookRecipe.java new file mode 100644 index 0000000000..6b3ff7078c --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/EraseSpellbookRecipe.java @@ -0,0 +1,68 @@ +package at.petrak.hexcasting.common.recipe; + +import at.petrak.hexcasting.api.mod.HexTags; +import at.petrak.hexcasting.common.lib.HexDataComponents; +import at.petrak.hexcasting.common.lib.HexItems; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.*; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +public class EraseSpellbookRecipe extends CustomRecipe { + public static final SimpleCraftingRecipeSerializer SERIALIZER = + new SimpleCraftingRecipeSerializer<>(EraseSpellbookRecipe::new); + + public EraseSpellbookRecipe(CraftingBookCategory category) { + super(category); + } + + @Override + public boolean canCraftInDimensions(int width, int height) { + return width * height >= 2; + } + + @Override + public boolean matches(CraftingInput container, Level level) { + boolean foundEraseMaterial = false; + boolean foundSpellbook = false; + + for (int i = 0; i < container.size(); i++) { + var stack = container.getItem(i); + if (stack.is(HexTags.Items.SPELLBOOK_ERASE_MATERIALS)) { + if (foundEraseMaterial) return false; + foundEraseMaterial = true; + } else if (stack.is(HexItems.SPELLBOOK.get()) && stack.has(HexDataComponents.SPELLBOOK_PAGES.get())) { + if (foundSpellbook) return false; + foundSpellbook = true; + } else { + return false; + } + } + + return foundEraseMaterial && foundSpellbook; + } + + @Override + public @NotNull ItemStack assemble(CraftingInput inv, HolderLookup.RegistryLookup.@NotNull Provider registryProvider) { + for (int i = 0; i < inv.size(); i++) { + var stack = inv.getItem(i); + if (stack.is(HexItems.SPELLBOOK.get()) && stack.has(HexDataComponents.SPELLBOOK_PAGES.get())) { + var output = new ItemStack(HexItems.SPELLBOOK.get(), 1); + var variant = stack.get(HexDataComponents.ITEM_VARIANT.get()); + if (variant != null) { + output.set(HexDataComponents.ITEM_VARIANT.get(), variant); + } + return output; + } + } + return ItemStack.EMPTY; + } + + @Override + public @NotNull RecipeSerializer getSerializer() { + return SERIALIZER; + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/HexRecipeStuffRegistry.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/HexRecipeStuffRegistry.java index 1e1c26aa86..dddd680fcb 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/HexRecipeStuffRegistry.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/HexRecipeStuffRegistry.java @@ -30,6 +30,10 @@ public static void register() { "seal_focus", () -> SealThingsRecipe.FOCUS_SERIALIZER); public static final Supplier> SEAL_SPELLBOOK = REGISTER_SERIALIZER.register( "seal_spellbook", () -> SealThingsRecipe.SPELLBOOK_SERIALIZER); + public static final Supplier> COPY_SPELLBOOK = REGISTER_SERIALIZER.register( + "copy_spellbook", () -> CopySpellbookRecipe.SERIALIZER); + public static final Supplier> ERASE_SPELLBOOK = REGISTER_SERIALIZER.register( + "erase_spellbook", () -> EraseSpellbookRecipe.SERIALIZER); public static Supplier> BRAINSWEEP_TYPE = REGISTER_RECIPE_TYPE.register("brainsweep", () -> new RecipeType() { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealThingsRecipe.java b/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealThingsRecipe.java index 315fadb540..911f92c08c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealThingsRecipe.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/recipe/SealThingsRecipe.java @@ -35,7 +35,7 @@ public boolean canCraftInDimensions(int width, int height) { @Override public boolean matches(CraftingInput container, Level level) { - boolean foundComb = false; + boolean foundSealant = false; boolean foundSealee = false; for (int i = 0; i < container.size(); i++) { @@ -44,12 +44,14 @@ public boolean matches(CraftingInput container, Level level) { if (foundSealee) return false; foundSealee = true; } else if (stack.is(HexTags.Items.SEAL_MATERIALS)) { - if (foundComb) return false; - foundComb = true; + if (foundSealant) return false; + foundSealant = true; + } else { + return false; } } - return foundComb && foundSealee; + return foundSealant && foundSealee; } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java index 74471a67e3..e0ae5be927 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/recipe/HexplatRecipes.java @@ -9,6 +9,8 @@ import at.petrak.hexcasting.common.items.pigment.ItemPridePigment; import at.petrak.hexcasting.common.lib.HexBlocks; import at.petrak.hexcasting.common.lib.HexItems; +import at.petrak.hexcasting.common.recipe.CopySpellbookRecipe; +import at.petrak.hexcasting.common.recipe.EraseSpellbookRecipe; import at.petrak.hexcasting.common.recipe.SealThingsRecipe; import at.petrak.hexcasting.common.recipe.ingredient.brainsweep.EntityTypeIngredient; import at.petrak.hexcasting.common.recipe.ingredient.brainsweep.VillagerIngredient; @@ -87,6 +89,8 @@ public HexplatRecipes(PackOutput output, CompletableFuture