diff --git a/dependencies.gradle b/dependencies.gradle index 7cb201253..33d9e076e 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -43,13 +43,14 @@ final def mod_dependencies = [ 'lemonlib-306926:2639879' : [project.debug_arcane_world], 'arcane-world-302852:2972860' : [project.debug_arcane_world], 'astralsorcery-sorcery-241721:3044416' : [project.debug_astral], - 'baubles-227083:2518667' : [project.debug_blood_arsenal, project.debug_astral, project.debug_botania, project.debug_botania_tweaks, project.debug_botanic_additions, project.debug_essentialcraft_4, project.debug_extra_botany, project.debug_thaum], + 'baubles-227083:2518667' : [project.debug_blood_arsenal, project.debug_astral, project.debug_bewitchment, project.debug_botania, project.debug_botania_tweaks, project.debug_botanic_additions, project.debug_essentialcraft_4, project.debug_extra_botany, project.debug_thaum], 'the-aurorian-352137:4981736' : [project.debug_aurorian], 'avaritia_1_10-261348:3143349' : [project.debug_avaritia], 'atum-2-59621:3116599' : [project.debug_atum], 'better-with-addons-268326:2899407' : [project.debug_better_with_addons], 'bwm-core-294335:2624990' : [project.debug_better_with_addons, project.debug_better_with_mods], 'bwm-suite-246760:3289033' : [project.debug_better_with_addons, project.debug_better_with_mods], + 'bewitchment-legacy-285439:6379256' : [project.debug_bewitchment], 'blood-arsenal-228823:2904183' : [project.debug_blood_arsenal], 'blood-magic-224791:2822288' : [project.debug_blood_arsenal, project.debug_blood_magic], 'guide-api-228832:2645992' : [project.debug_blood_arsenal, project.debug_blood_magic, project.debug_woot], @@ -103,7 +104,7 @@ final def mod_dependencies = [ 'pyrotech-306676:4956838' : [project.debug_pyrotech], 'random-things-59816:2905241' : [project.debug_random_things], 'mystical_world-282940:3460961' : [project.debug_roots], - 'patchouli-306770:3162874' : [project.debug_roots, project.debug_natures_aura, project.debug_prodigytech], + 'patchouli-306770:3162874' : [project.debug_bewitchment, project.debug_roots, project.debug_natures_aura, project.debug_prodigytech], 'prodigytech-297414:2769520' : [project.debug_prodigytech], 'roots-246183:3905074' : [project.debug_roots], 'rustic-256141:3107974' : [project.debug_rustic], diff --git a/examples/postInit/bewitchment.groovy b/examples/postInit/bewitchment.groovy new file mode 100644 index 000000000..bf5e34422 --- /dev/null +++ b/examples/postInit/bewitchment.groovy @@ -0,0 +1,223 @@ + +// Auto generated groovyscript example file +// MODS_LOADED: bewitchment + +log.info 'mod \'bewitchment\' detected, running script' + +// Altar Upgrades: +// Controls the valid upgrades placed atop the Witches' Altar, a multiblock that gain Magic Power from nearby plants and +// logs based on their uniqueness. The upgrades modify the amount gained per second and the maximum Magic Power the Altar +// can hold. + +mods.bewitchment.altar_upgrade.remove(blockstate('bewitchment:goblet')) +mods.bewitchment.altar_upgrade.remove(item('bewitchment:garnet')) +mods.bewitchment.altar_upgrade.removeByType(com.bewitchment.api.registry.AltarUpgrade.Type.WAND) +// mods.bewitchment.altar_upgrade.removeAll() + +mods.bewitchment.altar_upgrade.recipeBuilder() + .cup() + .predicate(blockstate('minecraft:clay')) + .gain(-10) + .multiplier(500) + .register() + +mods.bewitchment.altar_upgrade.recipeBuilder() + .pentacle() + .predicate(item('minecraft:gold_ingot')) + .gain(1000) + .register() + +mods.bewitchment.altar_upgrade.recipeBuilder() + .sword() + .predicate(blockstate('minecraft:gold_block')) + .multiplier(50) + .register() + +mods.bewitchment.altar_upgrade.recipeBuilder() + .wand() + .predicate(item('minecraft:iron_ingot')) + .multiplier(0.5) + .register() + + +// Athame Loot: +// When killing a mob with the Athame in the main hand, drops a random amount between `0` and `stackSize + lootingLevel` of +// each item that the entity passes the predicate of. + +mods.bewitchment.athame_loot.removeByOutput(item('bewitchment:spectral_dust')) +// mods.bewitchment.athame_loot.removeAll() + +mods.bewitchment.athame_loot.add(entity('minecraft:pig'), item('minecraft:gold_ingot')) +mods.bewitchment.athame_loot.add(entity('minecraft:cow'), item('minecraft:clay') * 5, item('minecraft:iron_sword')) + +// Witches' Cauldron Brew: +// After throwing a `bewitchment:mandrake_root` in the Witches' Cauldron while Magic Power is provided, all items thrown in +// will add their potion effects when extracted via a `minecraft:glass_bottle`. Each fill of the Cauldron can create 3 +// bottles. An ingredient can also refund an itemstack. + +mods.bewitchment.brew.removeByInput(item('bewitchment:dragons_blood_resin')) +mods.bewitchment.brew.removeByOutput(item('minecraft:bowl')) +mods.bewitchment.brew.removeByPotion(potion('minecraft:instant_health')) +// mods.bewitchment.brew.removeAll() + +mods.bewitchment.brew.recipeBuilder() + .input(ore('netherStar')) + .outputCheck(item('minecraft:nether_star')) + .effect(new PotionEffect(potion('minecraft:strength'), 1800, 3)) + .output(item('bewitchment:catechu_brown')) + .register() + +mods.bewitchment.brew.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .effect(new PotionEffect(potion('minecraft:instant_health'), 1, 3)) + .output(item('minecraft:clay')) + .register() + +mods.bewitchment.brew.recipeBuilder() + .input(item('minecraft:deadbush')) + .effect(new PotionEffect(potion('minecraft:resistance'), 1800, 3)) + .register() + + +// Witches' Cauldron: +// Converts up to 10 input ingredients into up to 3 output itemstacks in the Witches' Cauldron while Magic Power is +// provided. + +mods.bewitchment.cauldron.remove(resource('bewitchment:catechu_brown')) +mods.bewitchment.cauldron.removeByInput(item('bewitchment:tongue_of_dog')) +mods.bewitchment.cauldron.removeByOutput(item('bewitchment:iron_gall_ink')) +// mods.bewitchment.cauldron.removeAll() + +mods.bewitchment.cauldron.recipeBuilder() + .input(ore('logWood')) + .input(item('minecraft:deadbush')) + .input(item('minecraft:dye', 3)) + .output(item('bewitchment:catechu_brown')) + .register() + + +// Curses: +// Allows applying curses to a player to cause unique effects in the Brazier with a `bewitchment:taglock` targeting the +// desired player. + +mods.bewitchment.curse.remove(resource('bewitchment:berserker')) +mods.bewitchment.curse.removeByInput(item('minecraft:blaze_rod')) +// mods.bewitchment.curse.removeAll() + +// Distillery: +// Converts up to 6 input ingredients into up to 6 output itemstacks in the Distillery at the cost of 1 Magic Power per +// tick. Takes 10 seconds. + +mods.bewitchment.distillery.remove(resource('bewitchment:bottled_frostfire')) +mods.bewitchment.distillery.removeByInput(item('bewitchment:perpetual_ice')) +mods.bewitchment.distillery.removeByOutput(item('bewitchment:demonic_elixir')) +// mods.bewitchment.distillery.removeAll() + +mods.bewitchment.distillery.recipeBuilder() + .input(item('minecraft:glass_bottle')) + .input(item('minecraft:snow')) + .input(item('bewitchment:cleansing_balm')) + .input(item('bewitchment:fiery_unguent')) + .output(item('bewitchment:bottled_frostfire')) + .output(item('bewitchment:empty_jar') * 2) + .register() + + +// Fortune: +// Modifies potential Fortunes, with a random one being selected from the list when interacting with a Crystal Ball. Some +// amount of time will pass before the Fortune occurs, whereupon a customizable effect will happen. + +mods.bewitchment.fortune.remove(resource('bewitchment:cornucopia')) +// mods.bewitchment.fortune.removeAll() + +// Frostfire: +// Converts an input ingredient into an output itemstack once a second while inside a Frostfire block. + +mods.bewitchment.frostfire.removeByInput(item('minecraft:iron_ore')) +// mods.bewitchment.frostfire.removeByOutput(item('bewitchment:cold_iron_ingot')) +// mods.bewitchment.frostfire.removeAll() + +mods.bewitchment.frostfire.recipeBuilder() + .input(item('minecraft:water_bucket')) + .output(item('minecraft:ice')) + .register() + + +// Incense: +// Converts up to 8 input ingredients in the Brazier when activated by a Flint and Steel for any number of potion effects +// that apply whenever a player wakes up nearby. + +mods.bewitchment.incense.removeByInput(item('bewitchment:essence_of_vitality')) +mods.bewitchment.incense.removeByPotion(potion('minecraft:haste')) +// mods.bewitchment.incense.removeAll() + +mods.bewitchment.incense.recipeBuilder() + .input(item('minecraft:clay'), item('minecraft:gold_ingot') * 5, item('minecraft:iron_ingot')) + .potion(potion('minecraft:strength'), potion('minecraft:resistance')) + .time(10000) + .register() + + +// Oven: +// Converts an input itemstack into an output itemstack, with the ability to have a chance to produce an optional +// itemstack, and if producing the optional itemstack will consume a `bewitchment:empty_jar`. Requires furnace fuel to run +// and takes 10 seconds per recipe. + +mods.bewitchment.oven.removeByInput(item('minecraft:sapling')) +mods.bewitchment.oven.removeByOutput(item('bewitchment:tallow')) +mods.bewitchment.oven.removeByOutput(item('bewitchment:garlic_grilled')) +// mods.bewitchment.oven.removeAll() + +mods.bewitchment.oven.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) + .requiresJar(false) + .byproduct(item('minecraft:gold_nugget')) + .byproductChance(0.2f) + .register() + + +// Pets: +// Sets what animals are valid for summoning via the `FortuneMeetPet` effect. + +mods.bewitchment.pet.remove(entity('minecraft:ocelot')) +// mods.bewitchment.pet.removeAll() + +mods.bewitchment.pet.add(entity('minecraft:cow')) + +// Rituals: +// Converts up to 10 input ingredients into a ritual. The ritual can output up to 5 items, can require specific small, +// medium, and large circle sizes, can require a specific type for each circle, can require a specific entity nearby as a +// sacrifice, can set the time the ritual takes, and can set the Magic Power consumed to start and run the ritual. + +mods.bewitchment.ritual.removeByInput(item('minecraft:poisonous_potato')) +mods.bewitchment.ritual.removeByOutput(item('bewitchment:purifying_earth')) +// mods.bewitchment.ritual.removeAll() + + + +// Sigils: +// Converts up to 25 itemstacks into a single output itemstack. + +mods.bewitchment.sigil.remove(resource('bewitchment:mending')) +mods.bewitchment.sigil.removeByInput(item('bewitchment:bottle_of_blood')) +mods.bewitchment.sigil.removeByOutput(item('bewitchment:sigil_disorientation')) +// mods.bewitchment.sigil.removeAll() + + + +// Spinning Wheel: +// Converts up to 4 itemstacks into up to 2 output itemstacks in the Spinning Wheel at the cost of 1 Magic Power per tick. +// Takes 10 seconds. + +mods.bewitchment.spinning_wheel.remove(resource('bewitchment:cobweb')) +mods.bewitchment.spinning_wheel.removeByInput(item('minecraft:string')) +mods.bewitchment.spinning_wheel.removeByOutput(item('bewitchment:spirit_string')) +// mods.bewitchment.spinning_wheel.removeAll() + +mods.bewitchment.spinning_wheel.recipeBuilder() + .input(item('minecraft:string'), item('minecraft:string'), item('minecraft:string'), item('minecraft:string')) + .output(item('minecraft:gold_ingot') * 4, item('minecraft:web')) + .register() + + diff --git a/examples/postInit/botania.groovy b/examples/postInit/botania.groovy index 12aa14770..7f9e61f2c 100644 --- a/examples/postInit/botania.groovy +++ b/examples/postInit/botania.groovy @@ -2,7 +2,6 @@ // Auto generated groovyscript example file // MODS_LOADED: botania -import net.minecraft.potion.PotionEffect import net.minecraft.util.text.TextFormatting log.info 'mod \'botania\' detected, running script' diff --git a/examples/postInit/industrialforegoing.groovy b/examples/postInit/industrialforegoing.groovy index c1f8fd595..e5d4200eb 100644 --- a/examples/postInit/industrialforegoing.groovy +++ b/examples/postInit/industrialforegoing.groovy @@ -2,8 +2,6 @@ // Auto generated groovyscript example file // MODS_LOADED: industrialforegoing -import net.minecraft.potion.PotionEffect - log.info 'mod \'industrialforegoing\' detected, running script' // Bioreactor: diff --git a/examples/postInit/rustic.groovy b/examples/postInit/rustic.groovy index 2312d3aa9..1e65ddc8c 100644 --- a/examples/postInit/rustic.groovy +++ b/examples/postInit/rustic.groovy @@ -2,8 +2,6 @@ // Auto generated groovyscript example file // MODS_LOADED: rustic -import net.minecraft.potion.PotionEffect - log.info 'mod \'rustic\' detected, running script' // Alchemy Condenser: diff --git a/gradle.properties b/gradle.properties index 10ffb67fd..6c810e277 100644 --- a/gradle.properties +++ b/gradle.properties @@ -37,6 +37,7 @@ debug_better_with_addons = false debug_better_with_everything = false debug_better_with_mods = false debug_betweenlands = false +debug_bewitchment = false debug_blood_arsenal = false debug_blood_magic = false debug_botania = false @@ -57,7 +58,7 @@ debug_extended_crafting = false debug_extra_botany = false debug_extra_utilities_2 = false -debug_factory_tech = true +debug_factory_tech = false debug_forestry = false debug_future_mc = false @@ -275,6 +276,7 @@ curseForgeRelations = req:mixin-booter;\ opt:atum;\ opt:avaritia-1-10;\ opt:better-with-addons;\ + opt:bewitchment;\ opt:blood-arsenal;\ opt:blood-magic;\ opt:botania;\ diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java index e32c4df48..1aa0a5fb9 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -18,6 +18,7 @@ import com.cleanroommc.groovyscript.compat.mods.betterwithaddons.BetterWithAddons; import com.cleanroommc.groovyscript.compat.mods.betterwithmods.BetterWithMods; import com.cleanroommc.groovyscript.compat.mods.betweenlands.Betweenlands; +import com.cleanroommc.groovyscript.compat.mods.bewitchment.Bewitchment; import com.cleanroommc.groovyscript.compat.mods.bloodarsenal.BloodArsenal; import com.cleanroommc.groovyscript.compat.mods.bloodmagic.BloodMagic; import com.cleanroommc.groovyscript.compat.mods.botania.Botania; @@ -107,6 +108,7 @@ public class ModSupport { public static final GroovyContainer BETTER_WITH_ADDONS = new InternalModContainer<>("betterwithaddons", "Better With Addons", BetterWithAddons::new); public static final GroovyContainer BETTER_WITH_MODS = new InternalModContainer<>("betterwithmods", "Better With Mods", BetterWithMods::new); public static final GroovyContainer BETWEENLANDS = new InternalModContainer<>("thebetweenlands", "The Betweenlands", Betweenlands::new, "betweenlands"); + public static final GroovyContainer BEWITCHMENT = new InternalModContainer<>("bewitchment", "Bewitchment", Bewitchment::new); public static final GroovyContainer BLOOD_ARSENAL = new InternalModContainer<>("bloodarsenal", "Blood Arsenal", BloodArsenal::new); public static final GroovyContainer BLOOD_MAGIC = new InternalModContainer<>("bloodmagic", "Blood Magic: Alchemical Wizardry", BloodMagic::new, "bm"); public static final GroovyContainer BOTANIA = new InternalModContainer<>("botania", "Botania", Botania::new); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/appliedenergistics2/Inscriber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/appliedenergistics2/Inscriber.java index 8a9d7b064..087d99a0d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/appliedenergistics2/Inscriber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/appliedenergistics2/Inscriber.java @@ -7,6 +7,7 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.documentation.annotations.*; import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.EnumHelper; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; @@ -82,7 +83,7 @@ public RecipeBuilder type(InscriberProcessType type) { @RecipeBuilderMethodDescription public RecipeBuilder type(String type) { - this.type = InscriberProcessType.valueOf(type.toUpperCase(Locale.ROOT)); + this.type = EnumHelper.valueOfNullable(InscriberProcessType.class, type, false); return this; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/AltarUpgrades.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/AltarUpgrades.java new file mode 100644 index 000000000..f98381189 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/AltarUpgrades.java @@ -0,0 +1,293 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.BewitchmentAPI; +import com.bewitchment.api.registry.AltarUpgrade; +import com.bewitchment.common.block.tile.entity.TileEntityPlacedItem; +import com.bewitchment.registry.ModObjects; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.Alias; +import com.cleanroommc.groovyscript.helper.EnumHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import net.minecraft.block.state.BlockWorldState; +import net.minecraft.block.state.IBlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.function.Predicate; + +@RegistryDescription(category = RegistryDescription.Category.ENTRIES, admonition = { + @Admonition("groovyscript.wiki.bewitchment.altar_upgrade.note0"), + @Admonition("groovyscript.wiki.bewitchment.altar_upgrade.note1") +}) +public class AltarUpgrades extends VirtualizedRegistry, AltarUpgrade>> { + + public AltarUpgrades() { + super(Alias.generateOf("AltarUpgrade")); + } + + public static Map, AltarUpgrade> getRegistry() { + return BewitchmentAPI.ALTAR_UPGRADES; + } + + @Override + public void onReload() { + var recipes = getRegistry(); + removeScripted().forEach(x -> recipes.remove(x.getKey(), x.getValue())); + restoreFromBackup().forEach(x -> recipes.put(x.getKey(), x.getValue())); + } + + @RecipeBuilderDescription(example = { + @Example(".cup().predicate(blockstate('minecraft:clay')).gain(-10).multiplier(500)"), + @Example(".pentacle().predicate(item('minecraft:gold_ingot')).gain(1000)"), + @Example(".sword().predicate(blockstate('minecraft:gold_block')).multiplier(50)"), + @Example(".wand().predicate(item('minecraft:iron_ingot')).multiplier(0.5)"), + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addCup(IBlockState state, int gain, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.CUP).predicate(state).gain(gain).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addCup(IIngredient stack, int gain, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.CUP).predicate(stack).gain(gain).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addCup(Predicate predicate, int gain, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.CUP).predicate(predicate).gain(gain).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addPentacle(IBlockState state, int gain) { + return recipeBuilder().type(AltarUpgrade.Type.PENTACLE).predicate(state).gain(gain).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addPentacle(IIngredient stack, int gain) { + return recipeBuilder().type(AltarUpgrade.Type.PENTACLE).predicate(stack).gain(gain).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addPentacle(Predicate predicate, int gain) { + return recipeBuilder().type(AltarUpgrade.Type.PENTACLE).predicate(predicate).gain(gain).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addSword(IBlockState state, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.SWORD).predicate(state).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addSword(IIngredient stack, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.SWORD).predicate(stack).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addSword(Predicate predicate, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.SWORD).predicate(predicate).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addWand(IBlockState state, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.WAND).predicate(state).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addWand(IIngredient stack, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.WAND).predicate(stack).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public AltarUpgrade addWand(Predicate predicate, double multiplier) { + return recipeBuilder().type(AltarUpgrade.Type.WAND).predicate(predicate).multiplier(multiplier).register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean add(Predicate state, AltarUpgrade upgrade) { + getRegistry().put(state, upgrade); + doAddScripted(Pair.of(state, upgrade)); + return true; + } + + @MethodDescription + public boolean remove(BlockWorldState state) { + return getRegistry().entrySet().removeIf(entry -> entry.getKey().test(state) && doAddBackup(entry)); + } + + @MethodDescription(example = @Example("item('bewitchment:garnet')")) + public boolean remove(ItemStack stack) { + var placedItem = new TileEntityPlacedItem(); + placedItem.getInventories()[0].insertItem(0, stack, false); + //noinspection DataFlowIssue + return remove(new BlockWorldState(null, null, false) { + + @Override + public @NotNull IBlockState getBlockState() { + return ModObjects.placed_item.getDefaultState(); + } + + @Override + public TileEntity getTileEntity() { + return placedItem; + } + }); + } + + @MethodDescription(example = @Example("blockstate('bewitchment:goblet')")) + public boolean remove(IBlockState state) { + //noinspection DataFlowIssue + return remove(new BlockWorldState(null, null, false) { + + @Override + public @NotNull IBlockState getBlockState() { + return state; + } + + @Override + public TileEntity getTileEntity() { + return null; + } + }); + } + + @MethodDescription(example = @Example("com.bewitchment.api.registry.AltarUpgrade.Type.WAND")) + public void removeByType(AltarUpgrade.Type type) { + getRegistry().entrySet().removeIf(x -> x.getValue().type == type && doAddBackup(x)); + } + + @MethodDescription(priority = 2000, example = @Example(commented = true)) + public void removeAll() { + getRegistry().entrySet().removeIf(this::doAddBackup); + } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(not = "null")) + private Predicate predicate; + @Property(comp = @Comp(not = "null")) + private AltarUpgrade.Type type; + @Property(comp = @Comp(unique = "groovyscript.wiki.bewitchment.altar_upgrade.gain.required")) + private int gain; + @Property(comp = @Comp(unique = "groovyscript.wiki.bewitchment.altar_upgrade.multiplier.required")) + private double multiplier; + + @RecipeBuilderMethodDescription + public RecipeBuilder predicate(Predicate predicate) { + this.predicate = predicate; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder predicate(IBlockState state) { + return predicate(s -> s.getBlockState().equals(state)); + } + + @RecipeBuilderMethodDescription + public RecipeBuilder predicate(IIngredient stack) { + return predicate(state -> { + if (state.getBlockState().getBlock() == ModObjects.placed_item && state.getTileEntity() instanceof TileEntityPlacedItem placed) { + return stack.test(placed.getInventories()[0].getStackInSlot(0)); + } + return false; + }); + } + + @RecipeBuilderMethodDescription(field = "type") + public RecipeBuilder cup() { + return type(AltarUpgrade.Type.CUP); + } + + @RecipeBuilderMethodDescription(field = "type") + public RecipeBuilder pentacle() { + return type(AltarUpgrade.Type.PENTACLE); + } + + @RecipeBuilderMethodDescription(field = "type") + public RecipeBuilder sword() { + return type(AltarUpgrade.Type.SWORD); + } + + @RecipeBuilderMethodDescription(field = "type") + public RecipeBuilder wand() { + return type(AltarUpgrade.Type.WAND); + } + + @RecipeBuilderMethodDescription(priority = 1002) + public RecipeBuilder type(String type) { + return type(EnumHelper.valueOfNullable(AltarUpgrade.Type.class, type, false)); + } + + @RecipeBuilderMethodDescription(priority = 1001) + public RecipeBuilder type(AltarUpgrade.Type type) { + this.type = type; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder gain(int gain) { + this.gain = gain; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder multiplier(double multiplier) { + this.multiplier = multiplier; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Altar Upgrade"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + /** + * What the types are used for is set in {@link com.bewitchment.common.block.tile.entity.TileEntityWitchesAltar#scan} + */ + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg); + validateFluids(msg); + msg.add(predicate == null, "predicate cannot be null, but it was null"); + if (type == null) { + msg.add("type cannot be null, but it was null"); + } else { + switch (type) { + case PENTACLE -> msg.add(multiplier != 0, "multiplier was used for the type {}, has no use for that type", type); + case SWORD, WAND -> msg.add(gain != 0, "gain was used for the type {}, has no use for that type", type); + } + // gain and/or multipliers can be negative, so we can only check for unused stats. + //switch (type) { + // case CUP -> msg.add(gain <= 0 && multiplier <= 0, "either gain or multiplier must be greater than 0 with the type {}, but gain was {} and multiplier was {}", type, gain, multiplier); + // case PENTACLE -> msg.add(gain <= 0, "gain must be greater than 0 with the type {}, but it was {}", type, gain); + // case SWORD, WAND -> msg.add(multiplier <= 0, "multiplier must be greater than 0 with the type {}, but it was {}", type, multiplier); + //} + } + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable AltarUpgrade register() { + if (!validate()) return null; + var upgrade = new AltarUpgrade(type, gain, multiplier); + ModSupport.BEWITCHMENT.get().altarUpgrade.add(predicate, upgrade); + return upgrade; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/AthameLoot.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/AthameLoot.java new file mode 100644 index 000000000..fe0ec1c61 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/AthameLoot.java @@ -0,0 +1,89 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.BewitchmentAPI; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.Example; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription; +import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import com.google.common.collect.ImmutableList; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.registry.EntityEntry; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.Collection; +import java.util.Map; +import java.util.function.Predicate; + +@RegistryDescription(category = RegistryDescription.Category.ENTRIES) +public class AthameLoot extends VirtualizedRegistry, Collection>> { + + public static Map, Collection> getRegistry() { + return BewitchmentAPI.ATHAME_LOOT; + } + + @Override + public void onReload() { + var recipes = getRegistry(); + removeScripted().forEach(x -> recipes.remove(x.getKey(), x.getValue())); + restoreFromBackup().forEach(x -> recipes.put(x.getKey(), x.getValue())); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("entity('minecraft:pig'), item('minecraft:gold_ingot')")) + public boolean add(EntityEntry entity, ItemStack stack) { + return add(e -> entity.getEntityClass().isInstance(e), stack); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("entity('minecraft:cow'), item('minecraft:clay') * 5, item('minecraft:iron_sword')")) + public boolean add(EntityEntry entity, ItemStack... stacks) { + return add(e -> entity.getEntityClass().isInstance(e), stacks); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean add(EntityEntry entity, Collection stacks) { + return add(e -> entity.getEntityClass().isInstance(e), stacks); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean add(Class entity, ItemStack stack) { + return add(entity::isInstance, stack); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean add(Class entity, ItemStack... stacks) { + return add(entity::isInstance, stacks); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean add(Class entity, Collection stacks) { + return add(entity::isInstance, stacks); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean add(Predicate predicate, ItemStack stack) { + return add(predicate, ImmutableList.of(stack)); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean add(Predicate predicate, ItemStack... stacks) { + return add(predicate, ImmutableList.copyOf(stacks)); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean add(Predicate predicate, Collection stacks) { + getRegistry().put(predicate, stacks); + doAddScripted(Pair.of(predicate, stacks)); + return true; + } + + @MethodDescription(example = @Example("item('bewitchment:spectral_dust')")) + public boolean removeByOutput(IIngredient output) { + return getRegistry().entrySet().removeIf(recipe -> recipe.getValue().stream().anyMatch(output) && doAddBackup(recipe)); + } + + @MethodDescription(priority = 2000, example = @Example(commented = true)) + public void removeAll() { + getRegistry().entrySet().removeIf(this::doAddBackup); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Bewitchment.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Bewitchment.java new file mode 100644 index 000000000..354f1f280 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Bewitchment.java @@ -0,0 +1,21 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; + +public class Bewitchment extends GroovyPropertyContainer { + + public final AltarUpgrades altarUpgrade = new AltarUpgrades(); + public final AthameLoot athameLoot = new AthameLoot(); + public final Brew brew = new Brew(); + public final Cauldron cauldron = new Cauldron(); + public final Curse curse = new Curse(); + public final Distillery distillery = new Distillery(); + public final Fortune fortune = new Fortune(); + public final Frostfire frostfire = new Frostfire(); + public final Incense incense = new Incense(); + public final Oven oven = new Oven(); + public final Pet pet = new Pet(); + public final Ritual ritual = new Ritual(); + public final Sigil sigil = new Sigil(); + public final SpinningWheel spinningWheel = new SpinningWheel(); +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Brew.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Brew.java new file mode 100644 index 000000000..08f78373b --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Brew.java @@ -0,0 +1,128 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.function.Predicate; + +@RegistryDescription(admonition = { + @Admonition(value = "groovyscript.wiki.bewitchment.brew.note0", type = Admonition.Type.INFO), + @Admonition(value = "groovyscript.wiki.bewitchment.brew.note1", type = Admonition.Type.INFO), + @Admonition(value = "groovyscript.wiki.bewitchment.cauldron.magic_power_note", type = Admonition.Type.INFO), +}) +public class Brew extends ForgeRegistryWrapper { + + public Brew() { + super(GameRegistry.findRegistry(com.bewitchment.api.registry.Brew.class)); + } + + @RecipeBuilderDescription(example = { + @Example(".input(ore('netherStar')).outputCheck(item('minecraft:nether_star')).effect(new PotionEffect(potion('minecraft:strength'), 1800, 3)).output(item('bewitchment:catechu_brown'))"), + @Example(".input(item('minecraft:gold_ingot')).effect(new PotionEffect(potion('minecraft:instant_health'), 1, 3)).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:deadbush')).effect(new PotionEffect(potion('minecraft:resistance'), 1800, 3))") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(example = @Example("item('bewitchment:dragons_blood_resin')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (Arrays.stream(recipe.input.getMatchingStacks()).anyMatch(input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example("item('minecraft:bowl')")) + public void removeByOutput(IIngredient output) { + getRegistry().forEach(recipe -> { + if (output.test(recipe.output)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example("potion('minecraft:instant_health')")) + public void removeByPotion(Potion potion) { + getRegistry().forEach(recipe -> { + if (recipe.effect.getPotion().equals(potion)) { + remove(recipe); + } + }); + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(gte = 0, lte = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(not = "null")) + private PotionEffect effect; + @Property + private Predicate outputCheck; + + @RecipeBuilderMethodDescription + public RecipeBuilder effect(PotionEffect effect) { + this.effect = effect; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder outputCheck(IIngredient outputCheck) { + // while IIngredient does implement Predicate, making this method redundant, + // having it be explicit makes documentation clearer. + this.outputCheck = outputCheck; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder outputCheck(Predicate outputCheck) { + this.outputCheck = outputCheck; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Cauldron Brew Recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_brew_recipe_"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 1); + validateFluids(msg); + validateName(); + msg.add(effect == null, "effect must not be null, but it was null"); + msg.add(outputCheck != null && output.isEmpty(), "outputCheck was defined, yet output did not have an entry"); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable com.bewitchment.api.registry.Brew register() { + if (!validate()) return null; + com.bewitchment.api.registry.Brew recipe = new com.bewitchment.api.registry.Brew(super.name, input.get(0).toMcIngredient(), outputCheck, output.getOrEmpty(0), effect); + ModSupport.BEWITCHMENT.get().brew.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Cauldron.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Cauldron.java new file mode 100644 index 000000000..fd2ccbb2c --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Cauldron.java @@ -0,0 +1,101 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.registry.CauldronRecipe; +import com.bewitchment.registry.ModObjects; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.Ingredient; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@RegistryDescription(admonition = { + @Admonition(value = "groovyscript.wiki.bewitchment.cauldron.note0", type = Admonition.Type.INFO), + @Admonition(value = "groovyscript.wiki.bewitchment.cauldron.magic_power_note", type = Admonition.Type.INFO) +}, override = @MethodOverride(method = @MethodDescription(method = "remove(Lnet/minecraft/util/ResourceLocation;)V", example = @Example("resource('bewitchment:catechu_brown')")))) +public class Cauldron extends ForgeRegistryWrapper { + + public Cauldron() { + super(GameRegistry.findRegistry(CauldronRecipe.class)); + } + + @RecipeBuilderDescription(example = @Example(".input(ore('logWood')).input(item('minecraft:deadbush')).input(item('minecraft:dye', 3)).output(item('bewitchment:catechu_brown'))")) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(example = @Example("item('bewitchment:tongue_of_dog')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (recipe.input.stream().map(Ingredient::getMatchingStacks).flatMap(Arrays::stream).anyMatch(input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example("item('bewitchment:iron_gall_ink')")) + public void removeByOutput(IIngredient output) { + getRegistry().forEach(recipe -> { + if (recipe.output.stream().anyMatch(output)) { + remove(recipe); + } + }); + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(gte = 1, lte = 10)) + @Property(property = "output", comp = @Comp(gte = 1, lte = 3)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Cauldron Recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_cauldron_recipe_"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 10, 1, 3); + validateFluids(msg); + validateName(); + + var ash = new ItemStack(ModObjects.wood_ash); + msg.add(input.stream().anyMatch(x -> x.test(ash)), "inputs contained 'bewitchment:wood_ash', which clears the Witches' Cauldron"); + + if (!input.isEmpty()) { + var slot = input.get(0); + var root = new ItemStack(ModObjects.mandrake_root); + var sand = new ItemStack(ModObjects.dimensional_sand); + msg.add(slot.test(root), "the first input stack matched 'bewitchment:mandrake_root', which causes a Brew to be made instead"); + msg.add(slot.test(sand), "the first input stack matched 'bewitchment:dimensional_sand', which causes the Cauldron to teleport the player"); + } + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable CauldronRecipe register() { + if (!validate()) return null; + List inputs = input.stream().map(IIngredient::toMcIngredient).collect(Collectors.toList()); + CauldronRecipe recipe = new CauldronRecipe(super.name, inputs, output); + ModSupport.BEWITCHMENT.get().cauldron.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Curse.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Curse.java new file mode 100644 index 000000000..9518e471c --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Curse.java @@ -0,0 +1,29 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.Example; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodOverride; +import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.item.crafting.Ingredient; +import net.minecraftforge.fml.common.registry.GameRegistry; + +import java.util.Arrays; + +@RegistryDescription(category = RegistryDescription.Category.ENTRIES, override = @MethodOverride(method = @MethodDescription(method = "remove(Lnet/minecraft/util/ResourceLocation;)V", example = @Example("resource('bewitchment:berserker')")))) +public class Curse extends ForgeRegistryWrapper { + + public Curse() { + super(GameRegistry.findRegistry(com.bewitchment.api.registry.Curse.class)); + } + + @MethodDescription(example = @Example("item('minecraft:blaze_rod')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (recipe.input != null && recipe.input.stream().map(Ingredient::getMatchingStacks).flatMap(Arrays::stream).anyMatch(input)) { + remove(recipe); + } + }); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Distillery.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Distillery.java new file mode 100644 index 000000000..017fa36bf --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Distillery.java @@ -0,0 +1,85 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.registry.DistilleryRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.item.crafting.Ingredient; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@RegistryDescription(override = @MethodOverride(method = @MethodDescription(method = "remove(Lnet/minecraft/util/ResourceLocation;)V", example = @Example("resource('bewitchment:bottled_frostfire')")))) +public class Distillery extends ForgeRegistryWrapper { + + public Distillery() { + super(GameRegistry.findRegistry(DistilleryRecipe.class)); + } + + @RecipeBuilderDescription(example = @Example(".input(item('minecraft:glass_bottle')).input(item('minecraft:snow')).input(item('bewitchment:cleansing_balm')).input(item('bewitchment:fiery_unguent')).output(item('bewitchment:bottled_frostfire')).output(item('bewitchment:empty_jar') * 2)")) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(example = @Example("item('bewitchment:perpetual_ice')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (recipe.input.stream().map(Ingredient::getMatchingStacks).flatMap(Arrays::stream).anyMatch(input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example("item('bewitchment:demonic_elixir')")) + public void removeByOutput(IIngredient output) { + getRegistry().forEach(recipe -> { + if (recipe.output.stream().anyMatch(output)) { + remove(recipe); + } + }); + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(gte = 1, lte = 6)) + @Property(property = "output", comp = @Comp(gte = 1, lte = 6)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Distillery Recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_distillery_recipe_"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 6, 1, 6); + validateFluids(msg); + validateName(); + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable DistilleryRecipe register() { + if (!validate()) return null; + List inputs = input.stream().map(IIngredient::toMcIngredient).collect(Collectors.toList()); + DistilleryRecipe recipe = new DistilleryRecipe(super.name, inputs, output); + ModSupport.BEWITCHMENT.get().distillery.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Fortune.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Fortune.java new file mode 100644 index 000000000..2296a158d --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Fortune.java @@ -0,0 +1,16 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.cleanroommc.groovyscript.api.documentation.annotations.Example; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodOverride; +import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraftforge.fml.common.registry.GameRegistry; + +@RegistryDescription(category = RegistryDescription.Category.ENTRIES, override = @MethodOverride(method = @MethodDescription(method = "remove(Lnet/minecraft/util/ResourceLocation;)V", example = @Example("resource('bewitchment:cornucopia')")))) +public class Fortune extends ForgeRegistryWrapper { + + public Fortune() { + super(GameRegistry.findRegistry(com.bewitchment.api.registry.Fortune.class)); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Frostfire.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Frostfire.java new file mode 100644 index 000000000..d42ac9fe1 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Frostfire.java @@ -0,0 +1,84 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.registry.FrostfireRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; + +@RegistryDescription +public class Frostfire extends ForgeRegistryWrapper { + + public Frostfire() { + super(GameRegistry.findRegistry(FrostfireRecipe.class)); + } + + @RecipeBuilderDescription(example = @Example(".input(item('minecraft:water_bucket')).output(item('minecraft:ice'))")) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(example = @Example("item('minecraft:iron_ore')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (Arrays.stream(recipe.input.getMatchingStacks()).anyMatch(input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example(value = "item('bewitchment:cold_iron_ingot')", commented = true)) + public void removeByOutput(IIngredient output) { + getRegistry().forEach(recipe -> { + if (output.test(recipe.output)) { + remove(recipe); + } + }); + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Frostfire recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_frostfire_"; + } + + /** + * {@link com.bewitchment.common.block.tile.entity.TileEntityFrostfire TileEntityFrostfire} does {@code shrink(1)} + */ + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + validateName(); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable FrostfireRecipe register() { + if (!validate()) return null; + FrostfireRecipe recipe = new FrostfireRecipe(super.name, input.get(0).toMcIngredient(), output.get(0)); + ModSupport.BEWITCHMENT.get().frostfire.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Incense.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Incense.java new file mode 100644 index 000000000..82604a762 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Incense.java @@ -0,0 +1,115 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.potion.Potion; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +@RegistryDescription +public class Incense extends ForgeRegistryWrapper { + + public Incense() { + super(GameRegistry.findRegistry(com.bewitchment.api.registry.Incense.class)); + } + + @RecipeBuilderDescription(example = @Example(".input(item('minecraft:clay'), item('minecraft:gold_ingot') * 5, item('minecraft:iron_ingot')).potion(potion('minecraft:strength'), potion('minecraft:resistance')).time(10000)")) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(example = @Example("item('bewitchment:essence_of_vitality')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (recipe.input.stream().map(Ingredient::getMatchingStacks).flatMap(Arrays::stream).anyMatch(input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example("potion('minecraft:haste')")) + public void removeByPotion(Potion potion) { + getRegistry().forEach(recipe -> { + if (recipe.effects != null && recipe.effects.stream().anyMatch(potion::equals)) { + remove(recipe); + } + }); + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(gte = 1, lte = 8)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gte = 1)) + private final List potion = new ArrayList<>(); + @Property(comp = @Comp(gte = 1)) + private int time; + + @RecipeBuilderMethodDescription + public RecipeBuilder potion(Potion potion) { + this.potion.add(potion); + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder potion(Potion... potions) { + for (var potion : potions) { + potion(potion); + } + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder potion(Collection potions) { + for (var potion : potions) { + potion(potion); + } + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Incense Recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_incense_recipe_"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 8, 0, 0); + validateFluids(msg); + validateCustom(msg, potion, 1, Integer.MAX_VALUE, "potion"); + msg.add(time <= 0, "time must be greater than 0, got {}", time); + validateName(); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable com.bewitchment.api.registry.Incense register() { + if (!validate()) return null; + var recipe = new com.bewitchment.api.registry.Incense(super.name, input.stream().map(IIngredient::toMcIngredient).collect(Collectors.toList()), potion, time); + ModSupport.BEWITCHMENT.get().incense.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Oven.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Oven.java new file mode 100644 index 000000000..a8bbb53e9 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Oven.java @@ -0,0 +1,112 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.registry.OvenRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +@RegistryDescription +public class Oven extends ForgeRegistryWrapper { + + public Oven() { + super(GameRegistry.findRegistry(OvenRecipe.class)); + } + + @RecipeBuilderDescription(example = @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond')).requiresJar(false).byproduct(item('minecraft:gold_nugget')).byproductChance(0.2f)")) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(example = @Example("item('minecraft:sapling')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (input.test(recipe.input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = { + @Example("item('bewitchment:garlic_grilled')"), @Example("item('bewitchment:tallow')") + }) + public void removeByOutput(IIngredient output) { + getRegistry().forEach(recipe -> { + if (output.test(recipe.output) || output.test(recipe.byproduct)) { + remove(recipe); + } + }); + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(defaultValue = "ItemStack.EMPTY", comp = @Comp(not = "null")) + private ItemStack byproduct = ItemStack.EMPTY; + @Property(comp = @Comp(gte = 0)) + private float byproductChance; + @Property + private boolean requiresJar; + + @RecipeBuilderMethodDescription + public RecipeBuilder byproduct(ItemStack byproduct) { + this.byproduct = byproduct; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder byproductChance(float byproductChance) { + this.byproductChance = byproductChance; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder requiresJar(boolean requiresJar) { + this.requiresJar = requiresJar; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Oven Recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_oven_recipe_"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + msg.add(byproduct == null, "byproduct must not be null, but it was null"); + msg.add(byproductChance < 0, "byproductChance must be greater than or equal to 0, yet it was {}", byproductChance); + validateName(); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable OvenRecipe register() { + if (!validate()) return null; + OvenRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new OvenRecipe(super.name, stack, output.get(0), byproduct, byproductChance, requiresJar); + ModSupport.BEWITCHMENT.get().oven.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Pet.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Pet.java new file mode 100644 index 000000000..e8c0aaef7 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Pet.java @@ -0,0 +1,23 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.BewitchmentAPI; +import com.cleanroommc.groovyscript.api.documentation.annotations.Example; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodOverride; +import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraftforge.fml.common.registry.EntityEntry; + +import java.util.Collection; + +@RegistryDescription(category = RegistryDescription.Category.ENTRIES, override = @MethodOverride(method = { + @MethodDescription(method = "add", type = MethodDescription.Type.ADDITION, description = "groovyscript.wiki.add_to_list", example = @Example("entity('minecraft:cow')")), + @MethodDescription(method = "remove", description = "groovyscript.wiki.remove_from_list", example = @Example("entity('minecraft:ocelot')")) +})) +public class Pet extends StandardListRegistry { + + @Override + public Collection getRecipes() { + return BewitchmentAPI.VALID_PETS; + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Ritual.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Ritual.java new file mode 100644 index 000000000..aea08e641 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Ritual.java @@ -0,0 +1,183 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.crafting.Ingredient; +import net.minecraftforge.fml.common.registry.EntityEntry; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@RegistryDescription(admonition = @Admonition("groovyscript.wiki.bewitchment.ritual.note0")) +public class Ritual extends ForgeRegistryWrapper { + + public Ritual() { + super(GameRegistry.findRegistry(com.bewitchment.api.registry.Ritual.class)); + } + + @MethodDescription(example = @Example("item('minecraft:poisonous_potato')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (recipe.input.stream().map(Ingredient::getMatchingStacks).flatMap(Arrays::stream).anyMatch(input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example("item('bewitchment:purifying_earth')")) + public void removeByOutput(IIngredient output) { + getRegistry().forEach(recipe -> { + if (recipe.output != null && recipe.output.stream().anyMatch(output)) { + remove(recipe); + } + }); + } + + @RecipeBuilderDescription(example = { +// @Example(".input(ore('logWood')).input(item('minecraft:deadbush')).input(item('minecraft:dye', 3)).output(item('bewitchment:catechu_brown'))") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + //WitchesRitual.NONE; + //WitchesRitual.GOLDEN; + //WitchesRitual.RITUAL; + //WitchesRitual.FIERY; + //WitchesRitual.PHASING; + //WitchesRitual.ANY; + + public enum ChalkType { + NONE, // No chalk + GOLDEN, // Golden chalk + RITUAL, // Ritual Chalk (The standard white chalk) + FIERY, // Fiery/Infernal chalk + PHASING, // Phasing/Otherwhere chalk + ANY, // No matter what chalk + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(gte = 1, lte = 10)) + @Property(property = "output", comp = @Comp(gte = 0, lte = 5)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property + private Predicate sacrifice; + @Property(defaultValue = "true") + private boolean canBePerformedRemotely = true; + @Property(comp = @Comp(gt = 0)) + private int time; + @Property(comp = @Comp(gt = 0)) + private int startingPower; + @Property(comp = @Comp(gt = 0)) + private int runningPower; + @Property(comp = @Comp(gt = 0)) + private int small; + @Property + private int medium; + @Property + private int big; + + @RecipeBuilderMethodDescription + public RecipeBuilder sacrifice(EntityEntry sacrifice) { + this.sacrifice = x -> sacrifice.getEntityClass().equals(x.getClass()); + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder sacrifice(Predicate sacrifice) { + this.sacrifice = sacrifice; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder canBePerformedRemotely(boolean canBePerformedRemotely) { + this.canBePerformedRemotely = canBePerformedRemotely; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder startingPower(int startingPower) { + this.startingPower = startingPower; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder runningPower(int runningPower) { + this.runningPower = runningPower; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder small(int small) { + this.small = small; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder medium(int medium) { + this.medium = medium; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder big(int big) { + this.big = big; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Ritual Recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_ritual_"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 10, 0, 5); + validateFluids(msg); + validateName(); + msg.add(time <= 0, "time must be greater than 0, yet it was {}", time); + msg.add(startingPower <= 0, "startingPower must be greater than 0, yet it was {}", startingPower); + msg.add(runningPower <= 0, "runningPower must be greater than 0, yet it was {}", runningPower); + msg.add(small == 0, "small must not be equal to 0 (representing the golden circle), yet it was"); + msg.add(medium == 0, "medium must not be equal to 0 (representing the golden circle), yet it was"); + msg.add(big == 0, "big must not be equal to 0 (representing the golden circle), yet it was"); + msg.add(small <= 0, "small must be greater than 0, yet it was {}", small); + msg.add(medium < 0 && big > 0, "medium cannot be less than 0 while big is greater than 0, yet medium was {} and big was {}", medium, big); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable com.bewitchment.api.registry.Ritual register() { + if (!validate()) return null; + var inputs = input.stream().map(IIngredient::toMcIngredient).collect(Collectors.toList()); + var outputs = output.isEmpty() ? null : output; + var recipe = new com.bewitchment.api.registry.Ritual(super.name, inputs, sacrifice, outputs, canBePerformedRemotely, time, startingPower, runningPower, small, medium, big); + ModSupport.BEWITCHMENT.get().ritual.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Sigil.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Sigil.java new file mode 100644 index 000000000..77e17dd28 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/Sigil.java @@ -0,0 +1,80 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.registry.SigilRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.item.crafting.Ingredient; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@RegistryDescription(override = @MethodOverride(method = @MethodDescription(method = "remove(Lnet/minecraft/util/ResourceLocation;)V", example = @Example("resource('bewitchment:mending')")))) +public class Sigil extends ForgeRegistryWrapper { + + public Sigil() { + super(GameRegistry.findRegistry(SigilRecipe.class)); + } + + @RecipeBuilderDescription + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(example = @Example("item('bewitchment:bottle_of_blood')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (recipe.input.stream().map(Ingredient::getMatchingStacks).flatMap(Arrays::stream).anyMatch(input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example("item('bewitchment:sigil_disorientation')")) + public void removeByOutput(IIngredient output) { + getRegistry().forEach(recipe -> { + if (output.test(recipe.output)) { + remove(recipe); + } + }); + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(eq = 25)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Sigil Recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_sigil_recipe_"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 25, 25, 1, 1); + validateFluids(msg); + validateName(); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable SigilRecipe register() { + // TODO make grid-based recipe? + List inputs = input.stream().map(IIngredient::toMcIngredient).collect(Collectors.toList()); + SigilRecipe recipe = new SigilRecipe(super.name, inputs, output.get(0)); + ModSupport.BEWITCHMENT.get().sigil.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/SpinningWheel.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/SpinningWheel.java new file mode 100644 index 000000000..2a3c800a3 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bewitchment/SpinningWheel.java @@ -0,0 +1,85 @@ +package com.cleanroommc.groovyscript.compat.mods.bewitchment; + +import com.bewitchment.api.registry.SpinningWheelRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; +import net.minecraft.item.crafting.Ingredient; +import net.minecraftforge.fml.common.registry.GameRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@RegistryDescription(override = @MethodOverride(method = @MethodDescription(method = "remove(Lnet/minecraft/util/ResourceLocation;)V", example = @Example("resource('bewitchment:cobweb')")))) +public class SpinningWheel extends ForgeRegistryWrapper { + + public SpinningWheel() { + super(GameRegistry.findRegistry(SpinningWheelRecipe.class)); + } + + @RecipeBuilderDescription(example = @Example(".input(item('minecraft:string'), item('minecraft:string'), item('minecraft:string'), item('minecraft:string')).output(item('minecraft:gold_ingot') * 4, item('minecraft:web'))")) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @MethodDescription(example = @Example("item('minecraft:string')")) + public void removeByInput(IIngredient input) { + getRegistry().forEach(recipe -> { + if (recipe.input.stream().map(Ingredient::getMatchingStacks).flatMap(Arrays::stream).anyMatch(input)) { + remove(recipe); + } + }); + } + + @MethodDescription(example = @Example("item('bewitchment:spirit_string')")) + public void removeByOutput(IIngredient output) { + getRegistry().forEach(recipe -> { + if (recipe.output.stream().anyMatch(output)) { + remove(recipe); + } + }); + } + + @Property(property = "name") + @Property(property = "input", comp = @Comp(gte = 1, lte = 4)) + @Property(property = "output", comp = @Comp(gte = 1, lte = 2)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Bewitchment Spinning Wheel Recipe"; + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_spinning_wheel_recipe_"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 4, 1, 2); + validateFluids(msg); + validateName(); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable SpinningWheelRecipe register() { + if (!validate()) return null; + List inputs = input.stream().map(IIngredient::toMcIngredient).collect(Collectors.toList()); + SpinningWheelRecipe recipe = new SpinningWheelRecipe(super.name, inputs, output); + ModSupport.BEWITCHMENT.get().spinningWheel.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Brew.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Brew.java index 7275d75d4..2d1c44d4b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Brew.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Brew.java @@ -20,7 +20,7 @@ ) public class Brew extends VirtualizedRegistry { - @RecipeBuilderDescription(example = @Example(value = ".key('groovy_example_brew').name('Groovy Brew').color(0x00FFFF).cost(100).effect(new PotionEffect(potion('minecraft:strength'), 1800, 3), new PotionEffect(potion('minecraft:speed'), 1800, 2), new PotionEffect(potion('minecraft:weakness'), 3600, 1)).incense(true).bloodPendant(true)", imports = "net.minecraft.potion.PotionEffect")) + @RecipeBuilderDescription(example = @Example(".key('groovy_example_brew').name('Groovy Brew').color(0x00FFFF).cost(100).effect(new PotionEffect(potion('minecraft:strength'), 1800, 3), new PotionEffect(potion('minecraft:speed'), 1800, 2), new PotionEffect(potion('minecraft:weakness'), 3600, 1)).incense(true).bloodPendant(true)")) public BrewBuilder brewBuilder() { return new BrewBuilder(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/industrialforegoing/Straw.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/industrialforegoing/Straw.java index b78364b2f..865640554 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/industrialforegoing/Straw.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/industrialforegoing/Straw.java @@ -22,7 +22,7 @@ public Straw() { super(IFRegistries.STRAW_HANDLER_REGISTRY); } - @RecipeBuilderDescription(example = @Example(value = ".fluidInput(fluid('if.pink_slime')).effect(new PotionEffect(potion('minecraft:strength'), 1800, 3))", imports = "net.minecraft.potion.PotionEffect")) + @RecipeBuilderDescription(example = @Example(".fluidInput(fluid('if.pink_slime')).effect(new PotionEffect(potion('minecraft:strength'), 1800, 3))")) public RecipeBuilder recipeBuilder() { return new RecipeBuilder(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/inspirations/Cauldron.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/inspirations/Cauldron.java index b3ba92e62..2ac912e32 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/inspirations/Cauldron.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/inspirations/Cauldron.java @@ -5,6 +5,7 @@ import com.cleanroommc.groovyscript.api.documentation.annotations.*; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.core.mixin.inspirations.InspirationsRegistryAccessor; +import com.cleanroommc.groovyscript.helper.EnumHelper; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.StandardListRegistry; import knightminer.inspirations.library.InspirationsRegistry; @@ -223,7 +224,7 @@ public RecipeBuilder type(RecipeType type) { @RecipeBuilderMethodDescription public RecipeBuilder type(String type) { - return type(RecipeType.valueOf(type.toUpperCase(Locale.ROOT))); + return type(EnumHelper.valueOfNullable(RecipeType.class, type, false)); } @RecipeBuilderMethodDescription(field = "type") diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/rustic/Alchemy.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/rustic/Alchemy.java index 9680e3988..f571d357d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/rustic/Alchemy.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/rustic/Alchemy.java @@ -33,7 +33,7 @@ public Collection getRecipes() { @RecipeBuilderDescription(example = { @Example(".input(item('minecraft:stone'), item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4).time(20)"), - @Example(value = ".input(item('minecraft:stone'), item('minecraft:gold_ingot'), item('minecraft:diamond')).bottle(item('minecraft:torch')).advanced().effect(new PotionEffect(potion('minecraft:night_vision'), 3600, 1))", imports = "net.minecraft.potion.PotionEffect"), + @Example(".input(item('minecraft:stone'), item('minecraft:gold_ingot'), item('minecraft:diamond')).bottle(item('minecraft:torch')).advanced().effect(new PotionEffect(potion('minecraft:night_vision'), 3600, 1))"), @Example(".input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone')).modifier(item('minecraft:clay')).fluidInput(fluid('lava') * 500).advanced().output(item('minecraft:diamond'))"), @Example(".input(item('minecraft:cobblestone'), item('minecraft:cobblestone')).fluidInput(fluid('lava') * 25).bottle(item('minecraft:bucket')).output(item('minecraft:lava_bucket'))") }) diff --git a/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java b/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java index a5c96587b..a5097341a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java +++ b/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java @@ -11,6 +11,7 @@ import com.cleanroommc.groovyscript.documentation.helper.descriptor.DescriptorHelper; import com.cleanroommc.groovyscript.documentation.helper.descriptor.MethodAnnotation; import com.cleanroommc.groovyscript.documentation.linkgenerator.LinkGeneratorHooks; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.client.resources.I18n; import org.apache.commons.lang3.text.WordUtils; @@ -274,9 +275,13 @@ public String documentMethods(List> methods, StringBuilder out = new StringBuilder(); List exampleLines = new ArrayList<>(); List annotations = new ArrayList<>(); + Set describedMethods = new ObjectOpenHashSet<>(); for (MethodAnnotation method : methods) { - out.append(methodDescription(method)); + // only add the method description if it is the first for the targeted method + if (describedMethods.add(method.method())) { + out.append(methodDescription(method)); + } if (method.annotation().example().length > 0 && Arrays.stream(method.annotation().example()).anyMatch(x -> !x.value().isEmpty())) { exampleLines.addAll(Arrays.stream(method.annotation().example()).flatMap(example -> Stream.of(methodExample(method.method(), example.value()))).collect(Collectors.toList())); } else if (method.method().getParameterTypes().length == 0) { diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/GroovyScriptCodeConverter.java b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/GroovyScriptCodeConverter.java index ea2d6fd15..0b9fef324 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/GroovyScriptCodeConverter.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/GroovyScriptCodeConverter.java @@ -18,6 +18,7 @@ import net.minecraft.world.DimensionType; import net.minecraft.world.biome.Biome; import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.registry.EntityEntry; import net.minecraftforge.fml.common.registry.VillagerRegistry; import net.minecraftforge.registries.IForgeRegistryEntry; @@ -173,6 +174,10 @@ public static String asGroovyCode(Entity entity, boolean colored) { return formatResourceLocation("entity", EntityList.getKey(entity), colored); } + public static String asGroovyCode(EntityEntry entity, boolean colored) { + return formatForgeRegistryImpl("entity", entity, colored); + } + public static String asGroovyCode(CreativeTabs tab, boolean colored) { return formatGenericHandler("creativeTab", ((CreativeTabsAccessor) tab).getTabLabel2(), colored); } diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java index a56a486a5..2a56b6223 100644 --- a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java +++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java @@ -82,6 +82,7 @@ public GroovyScriptSandbox() { "net.minecraft.item.ItemStack", "net.minecraft.nbt.NBTTagCompound", "net.minecraft.nbt.NBTTagList", + "net.minecraft.potion.PotionEffect", "net.minecraft.tileentity.TileEntity", "net.minecraft.util.math.BlockPos", "net.minecraft.util.DamageSource", diff --git a/src/main/resources/assets/groovyscript/lang/en_us.lang b/src/main/resources/assets/groovyscript/lang/en_us.lang index a26101856..5de3e8921 100644 --- a/src/main/resources/assets/groovyscript/lang/en_us.lang +++ b/src/main/resources/assets/groovyscript/lang/en_us.lang @@ -80,7 +80,6 @@ groovyscript.wiki.not_fully_documented=This compat is not fully documented. Some groovyscript.wiki.add_to_list=Add the given recipe to the recipe list groovyscript.wiki.remove_from_list=Removes the given recipe from the recipe list - groovyscript.wiki.requires=Requires %s. groovyscript.wiki.default=(Default `%s`). @@ -790,6 +789,88 @@ groovyscript.wiki.thebetweenlands.steeping_pot.removeAcceptedItem=Removes the gi groovyscript.wiki.thebetweenlands.steeping_pot.removeAllAcceptedItem=Removes all entries from the accepted item list for the Silk Bundle +# Bewitchment +groovyscript.wiki.bewitchment.altar_upgrade.title=Altar Upgrades +groovyscript.wiki.bewitchment.altar_upgrade.description=Controls the valid upgrades placed atop the Witches' Altar, a multiblock that gain Magic Power from nearby plants and logs based on their uniqueness. The upgrades modify the amount gained per second and the maximum Magic Power the Altar can hold. +groovyscript.wiki.bewitchment.altar_upgrade.note0=Magic Power is increased once a second, with the multipliers stacking on top of the base regeneration rate of 8. +groovyscript.wiki.bewitchment.altar_upgrade.note1=The Max Magic Power increase provided by wands is multiplied by 64. +groovyscript.wiki.bewitchment.altar_upgrade.add=Register a new Altar Upgrade in the form `state`, `upgrade` +groovyscript.wiki.bewitchment.altar_upgrade.addCup=Adds the given entry as a cup upgrade in the format `condition`, `gain`, `multiplier` +groovyscript.wiki.bewitchment.altar_upgrade.addPentacle=Adds the given entry as a pentacle upgrade in the format `condition`, `gain` +groovyscript.wiki.bewitchment.altar_upgrade.addSword=Adds the given entry as a sword upgrade in the format `condition`, `multiplier` +groovyscript.wiki.bewitchment.altar_upgrade.addWand=Adds the given entry as a wand upgrade in the format `condition`, `multiplier` +groovyscript.wiki.bewitchment.altar_upgrade.gain.value=Sets the gain value, which is used for cups and pentacles +groovyscript.wiki.bewitchment.altar_upgrade.multiplier.value=Sets the multiplier value, which is used for cups, swords, and wands +groovyscript.wiki.bewitchment.altar_upgrade.predicate.value=Sets the predicate used to check if the block/item matches +groovyscript.wiki.bewitchment.altar_upgrade.type.value=Sets the type of Altar Upgrade being created +groovyscript.wiki.bewitchment.altar_upgrade.gain.required=only if the type is cup or pentacle +groovyscript.wiki.bewitchment.altar_upgrade.multiplier.required=only if the type is cup, sword, or wand +groovyscript.wiki.bewitchment.altar_upgrade.remove=Removes the given Altar Upgrade entry +groovyscript.wiki.bewitchment.altar_upgrade.removeByType=Removes all Altar Upgrades of the given type + +groovyscript.wiki.bewitchment.athame_loot.title=Athame Loot +groovyscript.wiki.bewitchment.athame_loot.description=When killing a mob with the Athame in the main hand, drops a random amount between `0` and `stackSize + lootingLevel` of each item that the entity passes the predicate of. +groovyscript.wiki.bewitchment.athame_loot.add=Register a new Athame Loot entry in the format `entity`, `stacks` + +groovyscript.wiki.bewitchment.brew.title=Witches' Cauldron Brew +groovyscript.wiki.bewitchment.brew.description=After throwing a `bewitchment:mandrake_root` in the Witches' Cauldron while Magic Power is provided, all items thrown in will add their potion effects when extracted via a `minecraft:glass_bottle`. Each fill of the Cauldron can create 3 bottles. An ingredient can also refund an itemstack. +groovyscript.wiki.bewitchment.brew.note0=In addition to any potion effects granted, if the items included in the potion contain specific items the output potion will have additional effects - `bewitchment:ravens_feather` will cause the potion to not create particles, `minecraft:gunpowder` will cause the potion to be a splash potion, `bewitchment:owlets_wing` will cause the potion to be a lingering potion, `minecraft:glowstone` will increase the potency up to a max of 2, and `minecraft:redstone` will increase the duration up to a max of 3. +groovyscript.wiki.bewitchment.brew.note1=Bewitchment has a pair of events that are fired - `WitchesCauldronEvent.CreatePotionEvent` and `WitchesCauldronEvent.PotionCreatedEvent`. Both can be cancelled. The first allows modifying the player creating the potions, the maximum potency of the potions to a max of 3, the base level of potency from 1 to 2, and how many bottles can be made from the Cauldron. The latter allows modifying the player creating the potions, the amount of bottles made, and the ItemStack created. This event is used when the player is wearing Alchemist equipment or when pledged to the demon Leonard. +groovyscript.wiki.bewitchment.brew.effect.value=Sets the potion effect the brew provides +groovyscript.wiki.bewitchment.brew.outputCheck.value=Sets the check for if the output itemstack is granted +groovyscript.wiki.bewitchment.brew.removeByPotion=Removes all recipes providing the given potion effect + +groovyscript.wiki.bewitchment.cauldron.title=Witches' Cauldron +groovyscript.wiki.bewitchment.cauldron.description=Converts up to 10 input ingredients into up to 3 output itemstacks in the Witches' Cauldron while Magic Power is provided. +groovyscript.wiki.bewitchment.cauldron.magic_power_note=Magic Power is consumed at a rate of `16 * {itemCount - 1}` every second and each time an item is added to the Cauldron. +groovyscript.wiki.bewitchment.cauldron.note0=Some items cannot be used in the Witches' Cauldron due to conflicts with other effects - `bewitchment:wood_ash` cannot be used anywhere, while `bewitchment:mandrake_root` and `bewitchment:dimensional_sand` cannot be used as the first item. + +groovyscript.wiki.bewitchment.curse.title=Curses +groovyscript.wiki.bewitchment.curse.description=Allows applying curses to a player to cause unique effects in the Brazier with a `bewitchment:taglock` targeting the desired player. + +groovyscript.wiki.bewitchment.distillery.title=Distillery +groovyscript.wiki.bewitchment.distillery.description=Converts up to 6 input ingredients into up to 6 output itemstacks in the Distillery at the cost of 1 Magic Power per tick. Takes 10 seconds. + +groovyscript.wiki.bewitchment.fortune.title=Fortune +groovyscript.wiki.bewitchment.fortune.description=Modifies potential Fortunes, with a random one being selected from the list when interacting with a Crystal Ball. Some amount of time will pass before the Fortune occurs, whereupon a customizable effect will happen. + +groovyscript.wiki.bewitchment.frostfire.title=Frostfire +groovyscript.wiki.bewitchment.frostfire.description=Converts an input ingredient into an output itemstack once a second while inside a Frostfire block + +groovyscript.wiki.bewitchment.incense.title=Incense +groovyscript.wiki.bewitchment.incense.description=Converts up to 8 input ingredients in the Brazier when activated by a Flint and Steel for any number of potion effects that apply whenever a player wakes up nearby. +groovyscript.wiki.bewitchment.incense.removeByPotion=Removes all recipes providing the given potion effect +groovyscript.wiki.bewitchment.incense.potion.value=Sets the potion effects provided upon waking up while the Incense is active +groovyscript.wiki.bewitchment.incense.time.value=Sets the time the Brazier will remain active before being extinguished in seconds + +groovyscript.wiki.bewitchment.oven.title=Oven +groovyscript.wiki.bewitchment.oven.description=Converts an input itemstack into an output itemstack, with the ability to have a chance to produce an optional itemstack, and if producing the optional itemstack will consume a `bewitchment:empty_jar`. Requires furnace fuel to run and takes 10 seconds per recipe. +groovyscript.wiki.bewitchment.oven.byproduct.value=Sets the byproduct itemstack +groovyscript.wiki.bewitchment.oven.byproductChance.value=Sets the chance the byproduct will be created +groovyscript.wiki.bewitchment.oven.requiresJar.value=Sets if the recipe must consume a jar in order to produce the byproduct + +groovyscript.wiki.bewitchment.pet.title=Pets +groovyscript.wiki.bewitchment.pet.description=Sets what animals are valid for summoning via the `FortuneMeetPet` effect + +groovyscript.wiki.bewitchment.ritual.title=Rituals +groovyscript.wiki.bewitchment.ritual.description=Converts up to 10 input ingredients into a ritual. The ritual can output up to 5 items, can require specific small, medium, and large circle sizes, can require a specific type for each circle, can require a specific entity nearby as a sacrifice, can set the time the ritual takes, and can set the Magic Power consumed to start and run the ritual. +groovyscript.wiki.bewitchment.ritual.note0=Due to the complexity of custom rituals, only the basic item output rituals can be constructed with the Recipe Builder. To create your own custom rituals, extend the class `com.bewitchment.api.registry.Ritual` and add it via `mods.bewitchment.ritual.add(Ritual)`. +groovyscript.wiki.bewitchment.ritual.sacrifice.value=Sets what entities are valid sacrifices, if any +groovyscript.wiki.bewitchment.ritual.canBePerformedRemotely.value=Sets if the ritual can be activated via a Waystone instead of immediately +groovyscript.wiki.bewitchment.ritual.time.value=Sets the time in ticks the ritual takes to complete +groovyscript.wiki.bewitchment.ritual.startingPower.value=Sets the starting Magic Power consumed by the ritual +groovyscript.wiki.bewitchment.ritual.runningPower.value=Sets the Magic Power consumed every tick +groovyscript.wiki.bewitchment.ritual.small.value=Sets the type of chalk used for the small circle +groovyscript.wiki.bewitchment.ritual.medium.value=Sets the type of chalk used for the medium circle +groovyscript.wiki.bewitchment.ritual.big.value=Sets the type of chalk used for the big circle + +groovyscript.wiki.bewitchment.sigil.title=Sigils +groovyscript.wiki.bewitchment.sigil.description=Converts up to 25 itemstacks into a single output itemstack + +groovyscript.wiki.bewitchment.spinning_wheel.title=Spinning Wheel +groovyscript.wiki.bewitchment.spinning_wheel.description=Converts up to 4 itemstacks into up to 2 output itemstacks in the Spinning Wheel at the cost of 1 Magic Power per tick. Takes 10 seconds. + + # Blood Arsenal groovyscript.wiki.bloodarsenal.sanguine_infusion.title=Sanguine Infusion groovyscript.wiki.bloodarsenal.sanguine_infusion.description=Converts an input infusion itemstack and up to 8 input surrounding itemstacks into an output itemstack, consuming Life Essence from the network to do so when the Infusion de Sanguine Ritual is activated. Alternatively, instead of consuming an infusion item, adds or upgrades a modifier to the given stasis tool, with the ability to increase the quantity of inputs consumed based on level.