From e312e3d854a89d41ce231a7ea054c435272ad862 Mon Sep 17 00:00:00 2001 From: WayofTime Date: Thu, 26 Nov 2020 13:32:56 -0500 Subject: [PATCH] Ritual reimplementation Reimplemented the following rituals: - Resonance of the Faceted Crystal - Crack of the Fractured Crystal - Reap of the Harvest Moon --- changelog.txt | 9 + .../java/wayoftime/bloodmagic/BloodMagic.java | 2 + .../common/data/GeneratorLanguage.java | 3 + .../common/item/ItemSentientScythe.java | 8 +- .../bloodmagic/ritual/ModRituals.java | 26 +++ .../harvest/HarvestHandlerPlantable.java | 152 +++++++++++++ .../ritual/harvest/HarvestHandlerStem.java | 72 ++++++ .../ritual/harvest/HarvestHandlerTall.java | 59 +++++ .../ritual/harvest/HarvestRegistry.java | 125 ++++++++++ .../ritual/harvest/IHarvestHandler.java | 39 ++++ .../ritual/types/RitualCrystalHarvest.java | 104 +++++++++ .../ritual/types/RitualCrystalSplit.java | 215 ++++++++++++++++++ .../ritual/types/RitualHarvest.java | 145 ++++++++++++ 13 files changed, 955 insertions(+), 4 deletions(-) create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/ModRituals.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerPlantable.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerStem.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerTall.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestRegistry.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/harvest/IHarvestHandler.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/types/RitualCrystalHarvest.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/types/RitualCrystalSplit.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/types/RitualHarvest.java diff --git a/changelog.txt b/changelog.txt index 27fe43e3..9360baf7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,15 @@ Version 3.0.1 ------------------------------------------------------ +Reimplemented the following rituals: + - Resonance of the Faceted Crystal + - Crack of the Fractured Crystal + - Reap of the Harvest Moon + +------------------------------------------------------ +Version 3.0.1 +------------------------------------------------------ + - Reimplemented the Incense Altar with all appropriate blocks. - Added guide entries for the Incense Altar and Blood Altar. Other misc entries added, too. - Fixed a server-related crash on the client on the Sigil of the Green Grove. diff --git a/src/main/java/wayoftime/bloodmagic/BloodMagic.java b/src/main/java/wayoftime/bloodmagic/BloodMagic.java index 5783c983..d9d6dfd2 100644 --- a/src/main/java/wayoftime/bloodmagic/BloodMagic.java +++ b/src/main/java/wayoftime/bloodmagic/BloodMagic.java @@ -55,6 +55,7 @@ import wayoftime.bloodmagic.impl.BloodMagicAPI; import wayoftime.bloodmagic.impl.BloodMagicCorePlugin; import wayoftime.bloodmagic.network.BloodMagicPacketHandler; import wayoftime.bloodmagic.potion.BloodMagicPotions; +import wayoftime.bloodmagic.ritual.ModRituals; import wayoftime.bloodmagic.ritual.RitualManager; import wayoftime.bloodmagic.structures.ModDungeons; import wayoftime.bloodmagic.tile.TileAlchemicalReactionChamber; @@ -163,6 +164,7 @@ public class BloodMagic OrbRegistry.tierMap.put(BloodMagicItems.ORB_MASTER.get().getTier(), new ItemStack(BloodMagicItems.MASTER_BLOOD_ORB.get())); BloodMagicCorePlugin.INSTANCE.register(BloodMagicAPI.INSTANCE); RITUAL_MANAGER.discover(); + ModRituals.initHarvestHandlers(); } public void registerTileEntityTypes(RegistryEvent.Register> event) diff --git a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java index 3ffc4aa2..ea83f623 100644 --- a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java +++ b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java @@ -159,6 +159,9 @@ public class GeneratorLanguage extends LanguageProvider add("ritual.bloodmagic.upgradeRemoveRitual", "Sound of the Cleansing Soul"); add("ritual.bloodmagic.armourEvolveRitual", "Ritual of Living Evolution"); add("ritual.bloodmagic.animalGrowthRitual", "Ritual of the Shepherd"); + add("ritual.bloodmagic.crystalHarvestRitual", "Crack of the Fractured Crystal"); + add("ritual.bloodmagic.forsakenSoulRitual", "Gathering of the Forsaken Souls"); + add("ritual.bloodmagic.crystalSplitRitual", "Resonance of the Faceted Crystal"); add("ritual.bloodmagic.cobblestoneRitual", "Le Vulcanos Frigius"); add("ritual.bloodmagic.placerRitual", "The Filler"); diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ItemSentientScythe.java b/src/main/java/wayoftime/bloodmagic/common/item/ItemSentientScythe.java index ee04af67..e6d3810d 100644 --- a/src/main/java/wayoftime/bloodmagic/common/item/ItemSentientScythe.java +++ b/src/main/java/wayoftime/bloodmagic/common/item/ItemSentientScythe.java @@ -62,7 +62,7 @@ public class ItemSentientScythe extends HoeItem implements IDemonWillWeapon, IMu { public static int[] soulBracket = new int[] { 16, 60, 200, 400, 1000 }; public static double[] defaultDamageAdded = new double[] { 0.5, 1, 1.5, 2, 2.5 }; - public static double[] destructiveDamageAdded = new double[] { 2, 3, 4, 5, 6 }; + public static double[] destructiveDamageAdded = new double[] { 1, 1.5, 2, 2.5, 3 }; public static double[] vengefulDamageAdded = new double[] { 0, 0.5, 1, 1.5, 2 }; public static double[] steadfastDamageAdded = new double[] { 0, 0.5, 1, 1.5, 2 }; public static double[] defaultDigSpeedAdded = new double[] { 1, 1.5, 2, 3, 4 }; @@ -296,8 +296,6 @@ public class ItemSentientScythe extends HoeItem implements IDemonWillWeapon, IMu continue; } - if (!net.minecraftforge.common.ForgeHooks.onPlayerAttackTarget(attacker, targetEntity)) - continue; if (targetEntity.canBeAttackedWithItem()) { if (!targetEntity.hitByEntity(attacker)) @@ -447,6 +445,8 @@ public class ItemSentientScythe extends HoeItem implements IDemonWillWeapon, IMu int k = (int) ((double) f5 * 0.5D); ((ServerWorld) attacker.world).spawnParticle(ParticleTypes.DAMAGE_INDICATOR, targetEntity.getPosX(), targetEntity.getPosYHeight(0.5D), targetEntity.getPosZ(), k, 0.1D, 0.0D, 0.1D, 0.2D); } + + applyEffectToEntity(type, willBracket, (LivingEntity) targetEntity, attacker); } } else @@ -506,7 +506,7 @@ public class ItemSentientScythe extends HoeItem implements IDemonWillWeapon, IMu if (!target.isAlive()) { float absorption = attacker.getAbsorptionAmount(); - attacker.addPotionEffect(new EffectInstance(Effects.ABSORPTION, absorptionTime[willBracket], 127)); + attacker.addPotionEffect(new EffectInstance(Effects.ABSORPTION, absorptionTime[willBracket], 127, true, false)); attacker.setAbsorptionAmount((float) Math.min(absorption + target.getMaxHealth() * 0.05f, maxAbsorptionHearts)); } break; diff --git a/src/main/java/wayoftime/bloodmagic/ritual/ModRituals.java b/src/main/java/wayoftime/bloodmagic/ritual/ModRituals.java new file mode 100644 index 00000000..e3421d7d --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/ModRituals.java @@ -0,0 +1,26 @@ +package wayoftime.bloodmagic.ritual; + +import net.minecraft.block.Blocks; +import wayoftime.bloodmagic.ritual.harvest.HarvestHandlerPlantable; +import wayoftime.bloodmagic.ritual.harvest.HarvestHandlerStem; +import wayoftime.bloodmagic.ritual.harvest.HarvestHandlerTall; +import wayoftime.bloodmagic.ritual.harvest.HarvestRegistry; + +public class ModRituals +{ + public static void initHarvestHandlers() + { + HarvestRegistry.registerRangeAmplifier(Blocks.DIAMOND_BLOCK.getDefaultState(), 15); + HarvestRegistry.registerRangeAmplifier(Blocks.GOLD_BLOCK.getDefaultState(), 10); + HarvestRegistry.registerRangeAmplifier(Blocks.IRON_BLOCK.getDefaultState(), 6); + + HarvestRegistry.registerHandler(new HarvestHandlerPlantable()); + HarvestRegistry.registerHandler(new HarvestHandlerTall()); + HarvestRegistry.registerHandler(new HarvestHandlerStem()); + } +// +// public static void initCuttingFluids() { +// CrushingRegistry.registerCuttingFluid(new CrushingHandlerCuttingFluid(ItemCuttingFluid.FluidType.BASIC.getStack(), 250, 0.5)); +// CrushingRegistry.registerCuttingFluid(new CrushingHandlerCuttingFluid(ItemCuttingFluid.FluidType.EXPLOSIVE.getStack(), 25, 0.05)); +// } +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerPlantable.java b/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerPlantable.java new file mode 100644 index 00000000..444ba07f --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerPlantable.java @@ -0,0 +1,152 @@ +package wayoftime.bloodmagic.ritual.harvest; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.CropsBlock; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameters; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.registries.ForgeRegistries; +import wayoftime.bloodmagic.util.BMLog; + +/** + * Harvest handler for standard plantable crops such as Wheat, Potatoes, and + * Netherwart.
+ * Register a new crop for this handler with + * {@link HarvestRegistry#registerStandardCrop(Block, int)} + */ + +public class HarvestHandlerPlantable implements IHarvestHandler +{ + private static final ItemStack mockHoe = new ItemStack(Items.DIAMOND_HOE, 1); + + public HarvestHandlerPlantable() + { + HarvestRegistry.registerStandardCrop(Blocks.CARROTS, 7); + HarvestRegistry.registerStandardCrop(Blocks.WHEAT, 7); + HarvestRegistry.registerStandardCrop(Blocks.POTATOES, 7); + HarvestRegistry.registerStandardCrop(Blocks.BEETROOTS, 3); + HarvestRegistry.registerStandardCrop(Blocks.NETHER_WART, 3); + + addThirdPartyCrop("actuallyadditions", "blockFlax", 7); + addThirdPartyCrop("actuallyadditions", "blockCanola", 7); + addThirdPartyCrop("actuallyadditions", "blockRice", 7); + + addThirdPartyCrop("extrautils2", "redorchid", 6); + addThirdPartyCrop("extrautils2", "enderlily", 7); + + addThirdPartyCrop("roots", "moonglow", 7); + addThirdPartyCrop("roots", "terra_moss", 7); + addThirdPartyCrop("roots", "pereskia", 7); + addThirdPartyCrop("roots", "wildroot", 7); + addThirdPartyCrop("roots", "aubergine", 7); + addThirdPartyCrop("roots", "spirit_herb", 7); + + addPamCrops(); + } + + @Override + public boolean harvest(World world, BlockPos pos, BlockState state, List drops) + { +// NonNullList blockDrops = NonNullList.create(); +// state.getBlock().getDrops(blockDrops, world, pos, state, 0); + boolean foundSeed = false; + LootContext.Builder lootBuilder = new LootContext.Builder((ServerWorld) world); + Vector3d blockCenter = new Vector3d(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); + List blockDrops = state.getDrops(lootBuilder.withParameter(LootParameters.field_237457_g_, blockCenter).withParameter(LootParameters.TOOL, mockHoe)); + +// System.out.println("Size of list: " + blockDrops.size()); + + for (ItemStack stack : blockDrops) + { + if (stack.isEmpty()) + continue; + + // This hurts my soul. + if (stack.getItem() instanceof BlockItem && ((BlockItem) stack.getItem()).getBlock() == state.getBlock()) + { + stack.shrink(1); + foundSeed = true; + break; + } + } + +// System.out.println("Found seed: " + foundSeed); + + if (foundSeed) + { + world.setBlockState(pos, state.getBlock().getDefaultState()); + world.playEvent(2001, pos, Block.getStateId(state)); + for (ItemStack stack : blockDrops) + { + if (stack.isEmpty()) + continue; + + drops.add(stack); + } + + return true; + } + + return false; + } + + @Override + public boolean test(World world, BlockPos pos, BlockState state) + { +// state.hasProperty(null); + return HarvestRegistry.getStandardCrops().containsKey(state.getBlock()) && state.getBlock() instanceof CropsBlock && ((CropsBlock) state.getBlock()).isMaxAge(state); +// return HarvestRegistry.getStandardCrops().containsKey(state.getBlock()) && state.getBlock().getMetaFromState(state) == HarvestRegistry.getStandardCrops().get(state.getBlock()); + } + + private static void addThirdPartyCrop(String modid, String regName, int matureMeta) + { + if (!ModList.get().isLoaded(modid)) + return; + + Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(modid, regName)); + if (block != null && block != Blocks.AIR) + HarvestRegistry.registerStandardCrop(block, matureMeta); + } + + private static void addPamCrops() + { + if (!ModList.get().isLoaded("harvestcraft")) + return; + + try + { + Class pamRegistry = Class.forName("com.pam.harvestcraft.blocks.CropRegistry"); + Field names = pamRegistry.getDeclaredField("cropNames"); + Method getCrop = pamRegistry.getMethod("getCrop", String.class); + for (String name : (String[]) names.get(null)) + { + CropsBlock crop = (CropsBlock) getCrop.invoke(null, name); + HarvestRegistry.registerStandardCrop(crop, crop.getMaxAge()); + } + } catch (ClassNotFoundException e) + { + BMLog.DEFAULT.error("HarvestCraft integration cancelled; unable to find registry class"); + } catch (NoSuchMethodException | NoSuchFieldException e) + { + BMLog.DEFAULT.error("HarvestCraft integration cancelled; unable to find crop name mapper"); + } catch (IllegalAccessException | InvocationTargetException e) + { + BMLog.DEFAULT.error("HarvestCraft integration cancelled; crop name lookup broke"); + } + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerStem.java b/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerStem.java new file mode 100644 index 00000000..e2d876b8 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerStem.java @@ -0,0 +1,72 @@ +package wayoftime.bloodmagic.ritual.harvest; + +import java.util.Collection; +import java.util.List; + +import net.minecraft.block.AttachedStemBlock; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameters; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; + +/** + * Harvest handler for crops with stems such as Pumpkins and Melons. Rotation + * based crop blocks are a good reason to use this (see pumpkins).
+ * Register a new crop for this handler with + * {@link HarvestRegistry#registerStemCrop(BlockState, BlockState)} + */ +public class HarvestHandlerStem implements IHarvestHandler +{ + private static final ItemStack mockHoe = new ItemStack(Items.DIAMOND_HOE, 1); + + public HarvestHandlerStem() + { + for (int i = 0; i < 4; i++) + { + Direction facing = Direction.byHorizontalIndex(i); + HarvestRegistry.registerStemCrop(Blocks.PUMPKIN.getDefaultState(), Blocks.ATTACHED_PUMPKIN_STEM.getDefaultState().with(AttachedStemBlock.FACING, facing)); + HarvestRegistry.registerStemCrop(Blocks.MELON.getDefaultState(), Blocks.ATTACHED_MELON_STEM.getDefaultState().with(AttachedStemBlock.FACING, facing)); + } + } + + @Override + public boolean harvest(World world, BlockPos pos, BlockState state, List drops) + { + Direction cropDir = state.get(AttachedStemBlock.FACING); + + if (cropDir != Direction.UP) + { + BlockPos cropPos = pos.offset(cropDir); + BlockState probableCrop = world.getBlockState(cropPos); + Collection registeredCrops = HarvestRegistry.getStemCrops().get(state); + + for (BlockState registeredCrop : registeredCrops) + { + if (registeredCrop == probableCrop) + { + LootContext.Builder lootBuilder = new LootContext.Builder((ServerWorld) world); + Vector3d blockCenter = new Vector3d(cropPos.getX() + 0.5, cropPos.getY() + 0.5, cropPos.getZ() + 0.5); + List blockDrops = registeredCrop.getDrops(lootBuilder.withParameter(LootParameters.field_237457_g_, blockCenter).withParameter(LootParameters.TOOL, mockHoe)); + drops.addAll(blockDrops); + world.destroyBlock(cropPos, false); + return true; + } + } + } + + return false; + } + + @Override + public boolean test(World world, BlockPos pos, BlockState state) + { + return HarvestRegistry.getStemCrops().containsKey(state); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerTall.java b/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerTall.java new file mode 100644 index 00000000..4ca53ce8 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestHandlerTall.java @@ -0,0 +1,59 @@ +package wayoftime.bloodmagic.ritual.harvest; + +import java.util.List; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.CactusBlock; +import net.minecraft.block.SugarCaneBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameters; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; + +/** + * Harvest handler for crops that grow vertically such as Sugar Cane and Cactus. + *
+ * Register a new crop for this handler with + * {@link HarvestRegistry#registerTallCrop(BlockState)} + */ +public class HarvestHandlerTall implements IHarvestHandler +{ + private static final ItemStack mockHoe = new ItemStack(Items.DIAMOND_HOE, 1); + + public HarvestHandlerTall() + { + for (int i = 0; i < 15; i++) + { + HarvestRegistry.registerTallCrop(Blocks.SUGAR_CANE.getDefaultState().with(SugarCaneBlock.AGE, i)); + HarvestRegistry.registerTallCrop(Blocks.CACTUS.getDefaultState().with(CactusBlock.AGE, i)); + } + } + + @Override + public boolean harvest(World world, BlockPos pos, BlockState state, List drops) + { + BlockState up = world.getBlockState(pos.up()); + if (up.getBlock() == state.getBlock()) + { + LootContext.Builder lootBuilder = new LootContext.Builder((ServerWorld) world); + Vector3d blockCenter = new Vector3d(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); + List blockDrops = state.getDrops(lootBuilder.withParameter(LootParameters.field_237457_g_, blockCenter).withParameter(LootParameters.TOOL, mockHoe)); + drops.addAll(blockDrops); + world.destroyBlock(pos.up(), false); + return true; + } + + return false; + } + + @Override + public boolean test(World world, BlockPos pos, BlockState state) + { + return HarvestRegistry.getTallCrops().contains(state); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestRegistry.java b/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestRegistry.java new file mode 100644 index 00000000..c4738256 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/harvest/HarvestRegistry.java @@ -0,0 +1,125 @@ +package wayoftime.bloodmagic.ritual.harvest; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; + +import net.minecraft.block.AttachedStemBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.StemBlock; + +public class HarvestRegistry +{ + + private static final List HARVEST_HANDLERS = Lists.newArrayList(); + private static final Map STANDARD_CROPS = Maps.newHashMap(); + private static final Set TALL_CROPS = Sets.newHashSet(); + private static final Multimap STEM_CROPS = ArrayListMultimap.create(); + private static final Map AMPLIFIERS = Maps.newHashMap(); + + /** + * Registers a handler for the Harvest Ritual to call. + * + * @param handler - The custom handler to register + */ + public static void registerHandler(IHarvestHandler handler) + { + if (!HARVEST_HANDLERS.contains(handler)) + HARVEST_HANDLERS.add(handler); + } + + /** + * Registers a standard crop (IE: Wheat, Carrots, Potatoes, Netherwart, etc) for + * the {@link WayofTime.bloodmagic.ritual.harvest.HarvestHandlerPlantable} + * handler to handle. + * + * @param crop - The crop block to handle. + * @param matureMeta - The meta value at which the crop is considered mature and + * ready to be harvested. + */ + public static void registerStandardCrop(Block crop, int matureMeta) + { + if (!STANDARD_CROPS.containsKey(crop)) + STANDARD_CROPS.put(crop, matureMeta); + } + + /** + * Registers a tall crop (Sugar Cane and Cactus) for the + * {@link WayofTime.bloodmagic.ritual.harvest.HarvestHandlerTall} handler to + * handle. + * + * @param crop - The crop block to handle. + */ + public static void registerTallCrop(BlockState crop) + { + if (!TALL_CROPS.contains(crop)) + TALL_CROPS.add(crop); + } + + /** + * Registers a stem crop (Melon and Pumpkin) for the + * {@link WayofTime.bloodmagic.ritual.harvest.HarvestHandlerStem} handler to + * handle. + *

+ * Use {@link net.minecraftforge.oredict.OreDictionary#WILDCARD_VALUE} to accept + * any meta for the crop block. + *

+ * The Stem must be instanceof {@link StemBlock} + * + * @param crop - The crop block to handle. + * @param stem - The stem of the crop + */ + public static void registerStemCrop(BlockState crop, BlockState stem) + { + if (!STEM_CROPS.containsKey(crop) && stem.getBlock() instanceof AttachedStemBlock) + STEM_CROPS.put(stem, crop); + } + + /** + * Registers a range amplifier for the Harvest Ritual. + * + * @param block - The block for the amplifier. + * @param range - The range the amplifier provides. + */ + public static void registerRangeAmplifier(BlockState block, int range) + { + if (!AMPLIFIERS.containsKey(block)) + AMPLIFIERS.put(block, range); + } + + public static List getHarvestHandlers() + { + return ImmutableList.copyOf(HARVEST_HANDLERS); + } + + public static Map getStandardCrops() + { + return ImmutableMap.copyOf(STANDARD_CROPS); + } + + public static Set getTallCrops() + { + return ImmutableSet.copyOf(TALL_CROPS); + } + + public static Multimap getStemCrops() + { + return ImmutableMultimap.copyOf(STEM_CROPS); + } + + public static Map getAmplifiers() + { + return ImmutableMap.copyOf(AMPLIFIERS); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/harvest/IHarvestHandler.java b/src/main/java/wayoftime/bloodmagic/ritual/harvest/IHarvestHandler.java new file mode 100644 index 00000000..82313dd5 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/harvest/IHarvestHandler.java @@ -0,0 +1,39 @@ +package wayoftime.bloodmagic.ritual.harvest; + +import java.util.List; + +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +/** + * Used to define a HarvestHandler for the Harvest Ritual. + */ +public interface IHarvestHandler +{ + + /** + * Called whenever the Harvest Ritual attempts to harvest a block.
+ * Use this to break the block and plant a new one.
+ * Add the items to be dropped to the drops list.
+ * + * @param world - The world + * @param pos - The position of the {@link BlockState} being checked + * @param state - The {@link BlockState} being checked + * @param drops - The items to be dropped + * @return If the block was successfully harvested. + */ + boolean harvest(World world, BlockPos pos, BlockState state, List drops); + + /** + * Tests to see if the block is valid for harvest. + * + * @param world The world + * @param pos The position in the world of the {@link BlockState} being + * checked + * @param state The {@link BlockState} being checked + * @return if this block is valid for harvest. + */ + boolean test(World world, BlockPos pos, BlockState state); +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualCrystalHarvest.java b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualCrystalHarvest.java new file mode 100644 index 00000000..1a8add72 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualCrystalHarvest.java @@ -0,0 +1,104 @@ +package wayoftime.bloodmagic.ritual.types; + +import java.util.function.Consumer; + +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.ritual.AreaDescriptor; +import wayoftime.bloodmagic.ritual.EnumRuneType; +import wayoftime.bloodmagic.ritual.IMasterRitualStone; +import wayoftime.bloodmagic.ritual.Ritual; +import wayoftime.bloodmagic.ritual.RitualComponent; +import wayoftime.bloodmagic.ritual.RitualRegister; +import wayoftime.bloodmagic.tile.TileDemonCrystal; + +@RitualRegister("crystal_harvest") +public class RitualCrystalHarvest extends Ritual +{ + public static final String CRYSTAL_RANGE = "crystal"; + + public RitualCrystalHarvest() + { + super("ritualCrystalHarvest", 0, 40000, "ritual." + BloodMagic.MODID + ".crystalHarvestRitual"); + addBlockRange(CRYSTAL_RANGE, new AreaDescriptor.Rectangle(new BlockPos(-3, 2, -3), 7, 5, 7)); + + setMaximumVolumeAndDistanceOfRange(CRYSTAL_RANGE, 250, 5, 7); + } + + @Override + public void performRitual(IMasterRitualStone masterRitualStone) + { + World world = masterRitualStone.getWorldObj(); + int currentEssence = masterRitualStone.getOwnerNetwork().getCurrentEssence(); + BlockPos pos = masterRitualStone.getBlockPos(); + + if (currentEssence < getRefreshCost()) + { + masterRitualStone.getOwnerNetwork().causeNausea(); + return; + } + + int maxEffects = 1; + int totalEffects = 0; + + AreaDescriptor crystalRange = masterRitualStone.getBlockRange(CRYSTAL_RANGE); + + crystalRange.resetIterator(); + while (crystalRange.hasNext()) + { + BlockPos nextPos = crystalRange.next().add(pos); + TileEntity tile = world.getTileEntity(nextPos); + if (tile instanceof TileDemonCrystal) + { + TileDemonCrystal demonCrystal = (TileDemonCrystal) tile; + if (demonCrystal.dropSingleCrystal()) + { + BlockState state = world.getBlockState(nextPos); + world.notifyBlockUpdate(nextPos, state, state, 3); + totalEffects++; + if (totalEffects >= maxEffects) + { + break; + } + } + } + } + + masterRitualStone.getOwnerNetwork().syphon(masterRitualStone.ticket(getRefreshCost() * totalEffects)); + } + + @Override + public int getRefreshTime() + { + return 25; + } + + @Override + public int getRefreshCost() + { + return 50; + } + + @Override + public void gatherComponents(Consumer components) + { + addCornerRunes(components, 1, 0, EnumRuneType.AIR); + addParallelRunes(components, 1, 1, EnumRuneType.DUSK); + addParallelRunes(components, 1, -1, EnumRuneType.FIRE); + addParallelRunes(components, 2, -1, EnumRuneType.FIRE); + addParallelRunes(components, 3, -1, EnumRuneType.FIRE); + addOffsetRunes(components, 3, 1, -1, EnumRuneType.FIRE); + addCornerRunes(components, 3, -1, EnumRuneType.EARTH); + addCornerRunes(components, 3, 0, EnumRuneType.EARTH); + addOffsetRunes(components, 3, 2, 0, EnumRuneType.DUSK); + } + + @Override + public Ritual getNewCopy() + { + return new RitualCrystalHarvest(); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualCrystalSplit.java b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualCrystalSplit.java new file mode 100644 index 00000000..9e399aae --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualCrystalSplit.java @@ -0,0 +1,215 @@ +package wayoftime.bloodmagic.ritual.types; + +import java.util.function.Consumer; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.api.compat.EnumDemonWillType; +import wayoftime.bloodmagic.common.block.BloodMagicBlocks; +import wayoftime.bloodmagic.ritual.EnumRuneType; +import wayoftime.bloodmagic.ritual.IMasterRitualStone; +import wayoftime.bloodmagic.ritual.Ritual; +import wayoftime.bloodmagic.ritual.RitualComponent; +import wayoftime.bloodmagic.ritual.RitualRegister; +import wayoftime.bloodmagic.tile.TileDemonCrystal; + +@RitualRegister("crystal_split") +public class RitualCrystalSplit extends Ritual +{ + public RitualCrystalSplit() + { + super("ritualCrystalSplit", 0, 20000, "ritual." + BloodMagic.MODID + ".crystalSplitRitual"); + } + + @Override + public void performRitual(IMasterRitualStone masterRitualStone) + { + World world = masterRitualStone.getWorldObj(); + int currentEssence = masterRitualStone.getOwnerNetwork().getCurrentEssence(); + + if (currentEssence < getRefreshCost()) + { + masterRitualStone.getOwnerNetwork().causeNausea(); + return; + } + + BlockPos pos = masterRitualStone.getBlockPos(); + Direction direction = masterRitualStone.getDirection(); + BlockPos rawPos = pos.up(2); + + TileEntity tile = world.getTileEntity(rawPos); + if (!(tile instanceof TileDemonCrystal) || ((TileDemonCrystal) tile).getWillType() != EnumDemonWillType.DEFAULT) + { + return; + } + + BlockState rawState = world.getBlockState(rawPos); + + TileDemonCrystal rawTile = (TileDemonCrystal) tile; + if (rawTile.getCrystalCount() >= 5) + { + BlockPos vengefulPos = pos.offset(rotateFacing(Direction.NORTH, direction)).up(); + BlockPos corrosivePos = pos.offset(rotateFacing(Direction.EAST, direction)).up(); + BlockPos steadfastPos = pos.offset(rotateFacing(Direction.SOUTH, direction)).up(); + BlockPos destructivePos = pos.offset(rotateFacing(Direction.WEST, direction)).up(); + + int vengefulCrystals = 0; + int corrosiveCrystals = 0; + int steadfastCrystals = 0; + int destructiveCrystals = 0; + + tile = world.getTileEntity(vengefulPos); + if (tile instanceof TileDemonCrystal && ((TileDemonCrystal) tile).getWillType() == EnumDemonWillType.VENGEFUL && ((TileDemonCrystal) tile).getCrystalCount() < 7) + { + vengefulCrystals = ((TileDemonCrystal) tile).getCrystalCount(); + } else if (!(tile instanceof TileDemonCrystal) && world.isAirBlock(vengefulPos)) + { + // #donothing, no point setting the crystal to 0 again + } else + { + return; + } + + tile = world.getTileEntity(corrosivePos); + if (tile instanceof TileDemonCrystal && ((TileDemonCrystal) tile).getWillType() == EnumDemonWillType.CORROSIVE && ((TileDemonCrystal) tile).getCrystalCount() < 7) + { + corrosiveCrystals = ((TileDemonCrystal) tile).getCrystalCount(); + } else if (!(tile instanceof TileDemonCrystal) && world.isAirBlock(corrosivePos)) + { + + } else + { + return; + } + + tile = world.getTileEntity(steadfastPos); + if (tile instanceof TileDemonCrystal && ((TileDemonCrystal) tile).getWillType() == EnumDemonWillType.STEADFAST && ((TileDemonCrystal) tile).getCrystalCount() < 7) + { + steadfastCrystals = ((TileDemonCrystal) tile).getCrystalCount(); + } else if (!(tile instanceof TileDemonCrystal) && world.isAirBlock(steadfastPos)) + { + + } else + { + return; + } + + tile = world.getTileEntity(destructivePos); + if (tile instanceof TileDemonCrystal && ((TileDemonCrystal) tile).getWillType() == EnumDemonWillType.DESTRUCTIVE && ((TileDemonCrystal) tile).getCrystalCount() < 7) + { + destructiveCrystals = ((TileDemonCrystal) tile).getCrystalCount(); + } else if (!(tile instanceof TileDemonCrystal) && world.isAirBlock(destructivePos)) + { + + } else + { + return; + } + + rawTile.setCrystalCount(rawTile.getCrystalCount() - 4); + + growCrystal(world, vengefulPos, EnumDemonWillType.VENGEFUL, vengefulCrystals); + growCrystal(world, corrosivePos, EnumDemonWillType.CORROSIVE, corrosiveCrystals); + growCrystal(world, steadfastPos, EnumDemonWillType.STEADFAST, steadfastCrystals); + growCrystal(world, destructivePos, EnumDemonWillType.DESTRUCTIVE, destructiveCrystals); + rawTile.markDirty(); + world.notifyBlockUpdate(rawPos, rawState, rawState, 3); + } + } + + public Direction rotateFacing(Direction facing, Direction rotation) + { + switch (rotation) + { + case EAST: + return facing.rotateY(); + case SOUTH: + return facing.rotateY().rotateY(); + case WEST: + return facing.rotateYCCW(); + case NORTH: + default: + return facing; + } + } + + public void growCrystal(World world, BlockPos pos, EnumDemonWillType type, int currentCrystalCount) + { + if (currentCrystalCount <= 0) + { + BlockState state; + switch (type) + { + case CORROSIVE: + state = BloodMagicBlocks.CORROSIVE_CRYSTAL_BLOCK.get().getDefaultState(); + break; + case DEFAULT: + state = BloodMagicBlocks.RAW_CRYSTAL_BLOCK.get().getDefaultState(); + break; + case DESTRUCTIVE: + state = BloodMagicBlocks.DESTRUCTIVE_CRYSTAL_BLOCK.get().getDefaultState(); + break; + case STEADFAST: + state = BloodMagicBlocks.STEADFAST_CRYSTAL_BLOCK.get().getDefaultState(); + break; + case VENGEFUL: + state = BloodMagicBlocks.VENGEFUL_CRYSTAL_BLOCK.get().getDefaultState(); + break; + default: + state = BloodMagicBlocks.RAW_CRYSTAL_BLOCK.get().getDefaultState(); + } + world.setBlockState(pos, state, 3); + } else + { + TileDemonCrystal tile = (TileDemonCrystal) world.getTileEntity(pos); + tile.setCrystalCount(currentCrystalCount + 1); + tile.markDirty(); + BlockState state = world.getBlockState(pos); + world.notifyBlockUpdate(pos, state, state, 3); + } + } + + @Override + public int getRefreshTime() + { + return 20; + } + + @Override + public int getRefreshCost() + { + return 1000; + } + + @Override + public void gatherComponents(Consumer components) + { + addRune(components, 0, 0, -1, EnumRuneType.FIRE); + addRune(components, 1, 0, 0, EnumRuneType.EARTH); + addRune(components, 0, 0, 1, EnumRuneType.WATER); + addRune(components, -1, 0, 0, EnumRuneType.AIR); + + this.addOffsetRunes(components, 1, 2, -1, EnumRuneType.DUSK); + this.addCornerRunes(components, 1, 0, EnumRuneType.BLANK); + this.addParallelRunes(components, 2, 0, EnumRuneType.DUSK); + } + + @Override + public Ritual getNewCopy() + { + return new RitualCrystalSplit(); + } + + @Override + public ITextComponent[] provideInformationOfRitualToPlayer(PlayerEntity player) + { + return new ITextComponent[] { new TranslationTextComponent(this.getTranslationKey() + ".info") }; + } +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualHarvest.java b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualHarvest.java new file mode 100644 index 00000000..1ac4433e --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualHarvest.java @@ -0,0 +1,145 @@ +package wayoftime.bloodmagic.ritual.types; + +import java.util.List; +import java.util.function.Consumer; + +import com.google.common.collect.Lists; + +import net.minecraft.block.BlockState; +import net.minecraft.inventory.InventoryHelper; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.ritual.AreaDescriptor; +import wayoftime.bloodmagic.ritual.EnumRuneType; +import wayoftime.bloodmagic.ritual.IMasterRitualStone; +import wayoftime.bloodmagic.ritual.Ritual; +import wayoftime.bloodmagic.ritual.RitualComponent; +import wayoftime.bloodmagic.ritual.RitualRegister; +import wayoftime.bloodmagic.ritual.harvest.HarvestRegistry; +import wayoftime.bloodmagic.ritual.harvest.IHarvestHandler; + +/** + * This ritual uses registered {@link IHarvestHandler}'s to harvest blocks. + *

+ * To register a new Handler for this ritual use + * {@link HarvestRegistry#registerHandler(IHarvestHandler)} + *

+ * This ritual includes a way to change the range based on what block is above + * the MasterRitualStone. You can use + * {@link HarvestRegistry#registerRangeAmplifier(BlockState, int)} to register a + * new amplifier. + */ +@RitualRegister("harvest") +public class RitualHarvest extends Ritual +{ + public static final String HARVEST_RANGE = "harvestRange"; + + public RitualHarvest() + { + super("ritualHarvest", 0, 20000, "ritual." + BloodMagic.MODID + ".harvestRitual"); + addBlockRange(HARVEST_RANGE, new AreaDescriptor.Rectangle(new BlockPos(-4, 1, -4), 9, 5, 9)); + setMaximumVolumeAndDistanceOfRange(HARVEST_RANGE, 0, 15, 15); + } + + @Override + public void performRitual(IMasterRitualStone masterRitualStone) + { + World world = masterRitualStone.getWorldObj(); + BlockPos pos = masterRitualStone.getBlockPos(); + + if (masterRitualStone.getOwnerNetwork().getCurrentEssence() < getRefreshCost()) + { + masterRitualStone.getOwnerNetwork().causeNausea(); + return; + } + + int harvested = 0; + + AreaDescriptor harvestArea = masterRitualStone.getBlockRange(HARVEST_RANGE); + + harvestArea.resetIterator(); + while (harvestArea.hasNext()) + { + BlockPos nextPos = harvestArea.next().add(pos); + if (harvestBlock(world, nextPos, masterRitualStone.getBlockPos())) + { + harvested++; + } + } + + masterRitualStone.getOwnerNetwork().syphon(masterRitualStone.ticket(getRefreshCost() * harvested)); + } + + @Override + public int getRefreshCost() + { + return 20; + } + + @Override + public int getRefreshTime() + { + return 5; + } + + @Override + public void gatherComponents(Consumer components) + { + addCornerRunes(components, 1, 0, EnumRuneType.DUSK); + addParallelRunes(components, 2, 0, EnumRuneType.EARTH); + addOffsetRunes(components, 3, 1, 0, EnumRuneType.EARTH); + addOffsetRunes(components, 3, 2, 0, EnumRuneType.WATER); + } + + @Override + public Ritual getNewCopy() + { + return new RitualHarvest(); + } + + public static boolean harvestBlock(World world, BlockPos cropPos, BlockPos controllerPos) + { + BlockState harvestState = world.getBlockState(cropPos); + TileEntity potentialInventory = world.getTileEntity(controllerPos.up()); + IItemHandler itemHandler = null; + if (potentialInventory != null && potentialInventory.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.DOWN).isPresent()) + itemHandler = potentialInventory.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.DOWN).resolve().get(); + + for (IHarvestHandler handler : HarvestRegistry.getHarvestHandlers()) + { + if (handler.test(world, cropPos, harvestState)) + { + List drops = Lists.newArrayList(); + if (handler.harvest(world, cropPos, harvestState, drops)) + { + for (ItemStack stack : drops) + { + if (stack.isEmpty()) + continue; + + // TODO I wrote this, but didn't actually think about whether it should be a + // thing. Remove the true if we want to keep it + if (itemHandler == null || true) + InventoryHelper.spawnItemStack(world, cropPos.getX(), cropPos.getY(), cropPos.getZ(), stack); + else + { + ItemStack remainder = ItemHandlerHelper.insertItemStacked(itemHandler, stack, false); + if (!remainder.isEmpty()) + InventoryHelper.spawnItemStack(world, cropPos.getX(), cropPos.getY(), cropPos.getZ(), remainder); + } + } + return true; + } + } + } + + return false; + } +}