From 06faa916c31703702c457d99fbd0f29d0361c737 Mon Sep 17 00:00:00 2001 From: WayofTime Date: Thu, 26 Nov 2020 15:21:03 -0500 Subject: [PATCH] Added more rituals Includes the Green Grove, Regen, Animal Growth, and a fix to the Feathered Knife ritual so that it... doesn't cause the damage animation. --- changelog.txt | 2 + .../bloodmagic/api/IBloodMagicAPI.java | 61 ++-- .../bloodmagic/api/IBloodMagicBlacklist.java | 61 ++++ .../bloodmagic/impl/BloodMagicAPI.java | 23 +- .../bloodmagic/impl/BloodMagicBlacklist.java | 125 +++++++ .../network/BloodMagicPacketHandler.java | 1 + .../network/SetClientHealthPacket.java | 48 +++ .../bloodmagic/potion/BMPotionUtils.java | 78 ++++ .../bloodmagic/potion/BloodMagicPotions.java | 4 + .../ritual/types/RitualAnimalGrowth.java | 258 +++++++++++++ .../ritual/types/RitualFeatheredKnife.java | 21 +- .../ritual/types/RitualGreenGrove.java | 345 ++++++++++++++++++ .../ritual/types/RitualRegeneration.java | 214 +++++++++++ .../java/wayoftime/bloodmagic/util/Utils.java | 140 +++++++ .../util/handler/event/GenericHandler.java | 29 +- 15 files changed, 1365 insertions(+), 45 deletions(-) create mode 100644 src/main/java/wayoftime/bloodmagic/api/IBloodMagicBlacklist.java create mode 100644 src/main/java/wayoftime/bloodmagic/impl/BloodMagicBlacklist.java create mode 100644 src/main/java/wayoftime/bloodmagic/network/SetClientHealthPacket.java create mode 100644 src/main/java/wayoftime/bloodmagic/potion/BMPotionUtils.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/types/RitualAnimalGrowth.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/types/RitualGreenGrove.java create mode 100644 src/main/java/wayoftime/bloodmagic/ritual/types/RitualRegeneration.java diff --git a/changelog.txt b/changelog.txt index 9360baf7..f7202627 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,8 @@ Reimplemented the following rituals: - Resonance of the Faceted Crystal - Crack of the Fractured Crystal - Reap of the Harvest Moon + - Ritual of the Shepherd + - Ritual of the Green Grove ------------------------------------------------------ Version 3.0.1 diff --git a/src/main/java/wayoftime/bloodmagic/api/IBloodMagicAPI.java b/src/main/java/wayoftime/bloodmagic/api/IBloodMagicAPI.java index f252309d..d0f85ddb 100644 --- a/src/main/java/wayoftime/bloodmagic/api/IBloodMagicAPI.java +++ b/src/main/java/wayoftime/bloodmagic/api/IBloodMagicAPI.java @@ -1,13 +1,14 @@ package wayoftime.bloodmagic.api; +import java.util.function.Predicate; + import javax.annotation.Nonnull; +import org.apache.logging.log4j.LogManager; + import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.LazyValue; -import org.apache.logging.log4j.LogManager; - -import java.util.function.Predicate; /** * The main interface between a plugin and Blood Magic's internals. @@ -16,29 +17,36 @@ import java.util.function.Predicate; * Magic. More advanced integration is out of the scope of this API and are * considered "addons". * - * Use INSTANCE to get an instance of the API without actually implementing anything + * Use INSTANCE to get an instance of the API without actually implementing + * anything */ public interface IBloodMagicAPI { - LazyValue INSTANCE = new LazyValue<>(() -> - { + LazyValue INSTANCE = new LazyValue<>(() -> { try { return (IBloodMagicAPI) Class.forName("wayoftime.bloodmagic.impl.BloodMagicAPI").getDeclaredField("INSTANCE").get(null); - } - catch (ReflectiveOperationException e) + } catch (ReflectiveOperationException e) { LogManager.getLogger().warn("Unable to find BloodMagicAPI, using a dummy instance instead..."); - return new IBloodMagicAPI() {}; + return new IBloodMagicAPI() + { + }; } }); -// /** -// * Retrieves the instance of the blacklist. -// * -// * @return the active {@link IBloodMagicBlacklist} instance -// */ -// @Nonnull -// IBloodMagicBlacklist getBlacklist(); + + /** + * Retrieves the instance of the blacklist. + * + * @return the active {@link IBloodMagicBlacklist} instance + */ + @Nonnull + default IBloodMagicBlacklist getBlacklist() + { + return new IBloodMagicBlacklist() + { + }; + }; /** * Retrieves the instance of the value manager. @@ -48,7 +56,9 @@ public interface IBloodMagicAPI @Nonnull default IBloodMagicValueManager getValueManager() { - return new IBloodMagicValueManager() {}; + return new IBloodMagicValueManager() + { + }; } /** @@ -67,7 +77,9 @@ public interface IBloodMagicAPI * @param state The state to register * @param componentType The type of Blood Altar component to register as. */ - default void registerAltarComponent(@Nonnull BlockState state, @Nonnull String componentType) {} + default void registerAltarComponent(@Nonnull BlockState state, @Nonnull String componentType) + { + } /** * Removes a {@link BlockState} from the component mappings @@ -85,7 +97,9 @@ public interface IBloodMagicAPI * @param state The state to unregister * @param componentType The type of Blood Altar component to unregister from. */ - default void unregisterAltarComponent(@Nonnull BlockState state, @Nonnull String componentType) {} + default void unregisterAltarComponent(@Nonnull BlockState state, @Nonnull String componentType) + { + } /** * Registers a {@link Predicate} for tranquility handling @@ -101,11 +115,14 @@ public interface IBloodMagicAPI *
  • LAVA
  • * * - * @param predicate Predicate to be used for the handler (goes to ITranquilityHandler) + * @param predicate Predicate to be used for the handler (goes to + * ITranquilityHandler) * @param tranquilityType Tranquility type that the handler holds - * @param value The amount of tranquility that the handler has + * @param value The amount of tranquility that the handler has */ - default void registerTranquilityHandler(Predicate predicate, String tranquilityType, double value) {} + default void registerTranquilityHandler(Predicate predicate, String tranquilityType, double value) + { + } /** * Gets the total Will that a Player contains diff --git a/src/main/java/wayoftime/bloodmagic/api/IBloodMagicBlacklist.java b/src/main/java/wayoftime/bloodmagic/api/IBloodMagicBlacklist.java new file mode 100644 index 00000000..57ac89b2 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/api/IBloodMagicBlacklist.java @@ -0,0 +1,61 @@ +package wayoftime.bloodmagic.api; + +import javax.annotation.Nonnull; + +import net.minecraft.block.BlockState; +import net.minecraft.util.ResourceLocation; + +/** + * Allows blacklisting of various objects from different Blood Magic systems. + */ +public interface IBloodMagicBlacklist +{ + + /** + * Blacklists a given {@link BlockState} from being teleposed. + * + * @param state The {@link BlockState} to blacklist. + */ + default void addTeleposer(@Nonnull BlockState state) + { + }; + + /** + * Blacklists a {@link net.minecraft.entity.Entity} from being teleposed based + * on the given registry name. + * + * @param entityId The registry name to blacklist. + */ + default void addTeleposer(@Nonnull ResourceLocation entityId) + { + }; + + /** + * Blacklists a given {@link BlockState} from being transposed. + * + * @param state The {@link BlockState} to blacklist. + */ + default void addTransposition(@Nonnull BlockState state) + { + }; + + /** + * Blacklists a given {@link BlockState} from being accelerated by the growth + * enhancement ritual and sigil. + * + * @param state The {@link BlockState} to blacklist. + */ + default void addGreenGrove(@Nonnull BlockState state) + { + }; + + /** + * Blacklists a {@link net.minecraft.entity.Entity} from being sacrificed via + * the Well of Suffering ritual. + * + * @param entityId The registry name to blacklist. + */ + default void addWellOfSuffering(@Nonnull ResourceLocation entityId) + { + }; +} diff --git a/src/main/java/wayoftime/bloodmagic/impl/BloodMagicAPI.java b/src/main/java/wayoftime/bloodmagic/impl/BloodMagicAPI.java index fe0d975a..2b4b1143 100644 --- a/src/main/java/wayoftime/bloodmagic/impl/BloodMagicAPI.java +++ b/src/main/java/wayoftime/bloodmagic/impl/BloodMagicAPI.java @@ -24,25 +24,25 @@ public class BloodMagicAPI implements IBloodMagicAPI public static final BloodMagicAPI INSTANCE = new BloodMagicAPI(); -// private final BloodMagicBlacklist blacklist; + private final BloodMagicBlacklist blacklist; private final BloodMagicRecipeRegistrar recipeRegistrar; private final BloodMagicValueManager valueManager; private final Multimap altarComponents; public BloodMagicAPI() { -// this.blacklist = new BloodMagicBlacklist(); + this.blacklist = new BloodMagicBlacklist(); this.recipeRegistrar = new BloodMagicRecipeRegistrar(); this.valueManager = new BloodMagicValueManager(); this.altarComponents = ArrayListMultimap.create(); } -// @Nonnull -// @Override -// public BloodMagicBlacklist getBlacklist() -// { -// return blacklist; -// } + @Nonnull + @Override + public BloodMagicBlacklist getBlacklist() + { + return blacklist; + } @Nonnull public BloodMagicRecipeRegistrar getRecipeRegistrar() @@ -91,9 +91,10 @@ public class BloodMagicAPI implements IBloodMagicAPI if (type != null) { - IncenseTranquilityRegistry.registerTranquilityHandler((world, pos, block, state) -> blockState.test(state) ? new TranquilityStack(type, value) : null); - } - else + IncenseTranquilityRegistry.registerTranquilityHandler((world, pos, block, state) -> blockState.test(state) + ? new TranquilityStack(type, value) + : null); + } else { BMLog.API.warn("Invalid Tranquility type: {}.", tranquilityType); } diff --git a/src/main/java/wayoftime/bloodmagic/impl/BloodMagicBlacklist.java b/src/main/java/wayoftime/bloodmagic/impl/BloodMagicBlacklist.java new file mode 100644 index 00000000..e9d5d81b --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/impl/BloodMagicBlacklist.java @@ -0,0 +1,125 @@ +package wayoftime.bloodmagic.impl; + +import java.util.Set; + +import javax.annotation.Nonnull; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.ResourceLocation; +import wayoftime.bloodmagic.api.IBloodMagicBlacklist; +import wayoftime.bloodmagic.util.BMLog; + +public class BloodMagicBlacklist implements IBloodMagicBlacklist +{ + + private final Set teleposer; + private final Set teleposerEntities; + private final Set transposition; + private final Set greenGrove; + private final Set sacrifice; + + public BloodMagicBlacklist() + { + this.teleposer = Sets.newHashSet(); + this.teleposerEntities = Sets.newHashSet(); + this.transposition = Sets.newHashSet(); + this.greenGrove = Sets.newHashSet(); + this.sacrifice = Sets.newHashSet(); + } + + @Override + public void addTeleposer(@Nonnull BlockState state) + { + if (!teleposer.contains(state)) + { + BMLog.API_VERBOSE.info("Blacklist: Added {} to the Teleposer blacklist.", state); + teleposer.add(state); + } + } + + public void addTeleposer(@Nonnull Block block) + { + for (BlockState state : block.getStateContainer().getValidStates()) addTeleposer(state); + } + + @Override + public void addTeleposer(@Nonnull ResourceLocation entityId) + { + if (!teleposerEntities.contains(entityId)) + { + BMLog.API_VERBOSE.info("Blacklist: Added {} to the Teleposer blacklist.", entityId); + teleposerEntities.add(entityId); + } + } + + @Override + public void addTransposition(@Nonnull BlockState state) + { + if (!transposition.contains(state)) + { + BMLog.API_VERBOSE.info("Blacklist: Added {} to the Transposition blacklist.", state); + transposition.add(state); + } + } + + public void addTransposition(@Nonnull Block block) + { + for (BlockState state : block.getStateContainer().getValidStates()) addTransposition(state); + } + + @Override + public void addGreenGrove(@Nonnull BlockState state) + { + if (!greenGrove.contains(state)) + { + BMLog.API_VERBOSE.info("Blacklist: Added {} to the Green Grove blacklist.", state); + greenGrove.add(state); + } + } + + public void addGreenGrove(@Nonnull Block block) + { + for (BlockState state : block.getStateContainer().getValidStates()) addGreenGrove(state); + } + + @Override + public void addWellOfSuffering(@Nonnull ResourceLocation entityId) + { + if (!sacrifice.contains(entityId)) + { + BMLog.API_VERBOSE.info("Blacklist: Added {} to the Well of Suffering blacklist.", entityId); + sacrifice.add(entityId); + } + } + + // Internal use getters + + public Set getTeleposer() + { + return ImmutableSet.copyOf(teleposer); + } + + public Set getTeleposerEntities() + { + return ImmutableSet.copyOf(teleposerEntities); + } + + public Set getTransposition() + { + return ImmutableSet.copyOf(transposition); + } + + public Set getGreenGrove() + { + return ImmutableSet.copyOf(greenGrove); + } + + public Set getSacrifice() + { + return ImmutableSet.copyOf(sacrifice); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/network/BloodMagicPacketHandler.java b/src/main/java/wayoftime/bloodmagic/network/BloodMagicPacketHandler.java index 7bba855b..089ae21d 100644 --- a/src/main/java/wayoftime/bloodmagic/network/BloodMagicPacketHandler.java +++ b/src/main/java/wayoftime/bloodmagic/network/BloodMagicPacketHandler.java @@ -16,6 +16,7 @@ public class BloodMagicPacketHandler extends BasePacketHandler registerServerToClient(ChatUtil.PacketNoSpamChat.class, ChatUtil.PacketNoSpamChat::encode, ChatUtil.PacketNoSpamChat::decode, ChatUtil.PacketNoSpamChat::handle); registerServerToClient(ARCTanksPacket.class, ARCTanksPacket::encode, ARCTanksPacket::decode, ARCTanksPacket::handle); registerServerToClient(DemonAuraClientPacket.class, DemonAuraClientPacket::encode, DemonAuraClientPacket::decode, DemonAuraClientPacket::handle); + registerServerToClient(SetClientHealthPacket.class, SetClientHealthPacket::encode, SetClientHealthPacket::decode, SetClientHealthPacket::handle); // INSTANCE.registerMessage(id, messageType, encoder, decoder, messageConsumer); // INSTANCE.registerMessage(ChatUtil.PacketNoSpamChat.Handler.class, ChatUtil.PacketNoSpamChat.class, 0, Side.CLIENT); // INSTANCE.registerMessage(ItemRouterButtonPacketProcessor.class, ItemRouterButtonPacketProcessor.class, 1, Side.SERVER); diff --git a/src/main/java/wayoftime/bloodmagic/network/SetClientHealthPacket.java b/src/main/java/wayoftime/bloodmagic/network/SetClientHealthPacket.java new file mode 100644 index 00000000..d89345dc --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/network/SetClientHealthPacket.java @@ -0,0 +1,48 @@ +package wayoftime.bloodmagic.network; + +import java.util.function.Supplier; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class SetClientHealthPacket +{ + public float health; + + public SetClientHealthPacket() + { + + } + + public SetClientHealthPacket(float health) + { + this.health = health; + } + + public static void encode(SetClientHealthPacket pkt, PacketBuffer buf) + { + buf.writeFloat(pkt.health); + } + + public static SetClientHealthPacket decode(PacketBuffer buf) + { + SetClientHealthPacket pkt = new SetClientHealthPacket(buf.readFloat()); + + return pkt; + } + + public static void handle(SetClientHealthPacket message, Supplier context) + { + context.get().enqueueWork(() -> updateClientHealth(message.health)); + context.get().setPacketHandled(true); + } + + @OnlyIn(Dist.CLIENT) + public static void updateClientHealth(float health) + { + Minecraft.getInstance().player.setHealth(health); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/potion/BMPotionUtils.java b/src/main/java/wayoftime/bloodmagic/potion/BMPotionUtils.java new file mode 100644 index 00000000..94df642c --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/potion/BMPotionUtils.java @@ -0,0 +1,78 @@ +package wayoftime.bloodmagic.potion; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.IGrowable; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import wayoftime.bloodmagic.impl.BloodMagicAPI; +import wayoftime.bloodmagic.util.DamageSourceBloodMagic; + +public class BMPotionUtils +{ + public static Random rand = new Random(); + + public static double damageMobAndGrowSurroundingPlants(LivingEntity entity, int horizontalRadius, int verticalRadius, double damageRatio, int maxPlantsGrown) + { + World world = entity.getEntityWorld(); + if (world.isRemote) + { + return 0; + } + + if (!entity.isAlive()) + { + return 0; + } + + double incurredDamage = 0; + + List growList = new ArrayList<>(); + + for (int i = 0; i < maxPlantsGrown; i++) + { + BlockPos blockPos = entity.getPosition().add(rand.nextInt(horizontalRadius * 2 + 1) - horizontalRadius, rand.nextInt(verticalRadius * 2 + 1) - verticalRadius, rand.nextInt(horizontalRadius * 2 + 1) - horizontalRadius); + BlockState state = world.getBlockState(blockPos); + + if (!BloodMagicAPI.INSTANCE.getBlacklist().getGreenGrove().contains(state)) + { + if (state.getBlock() instanceof IGrowable) + { + growList.add(blockPos); + } + } + } + + for (BlockPos blockPos : growList) + { + Block block = world.getBlockState(blockPos).getBlock(); +// if (world.rand.nextInt(50) == 0) + { + BlockState preBlockState = world.getBlockState(blockPos); + for (int n = 0; n < 10; n++) + block.randomTick(world.getBlockState(blockPos), (ServerWorld) world, blockPos, world.rand); + + BlockState newState = world.getBlockState(blockPos); + if (!newState.equals(preBlockState)) + { + world.playEvent(2005, blockPos, 0); + incurredDamage += damageRatio; + } + } + } + + if (incurredDamage > 0) + { + entity.attackEntityFrom(DamageSourceBloodMagic.INSTANCE, (float) incurredDamage); + } + + return incurredDamage; + } + +} diff --git a/src/main/java/wayoftime/bloodmagic/potion/BloodMagicPotions.java b/src/main/java/wayoftime/bloodmagic/potion/BloodMagicPotions.java index 3f449a97..eafe2fe7 100644 --- a/src/main/java/wayoftime/bloodmagic/potion/BloodMagicPotions.java +++ b/src/main/java/wayoftime/bloodmagic/potion/BloodMagicPotions.java @@ -10,6 +10,8 @@ public class BloodMagicPotions public static final Effect SOUL_SNARE = new PotionSoulSnare(); public static final Effect FIRE_FUSE = new PotionFireFuse(); public static final Effect SOUL_FRAY = new PotionBloodMagic(EffectType.HARMFUL, 0xFFFFFFFF); + public static final Effect PLANT_LEECH = new PotionBloodMagic(EffectType.HARMFUL, 0x00FF00FF); + public static final Effect SACRIFICIAL_LAMB = new PotionBloodMagic(EffectType.HARMFUL, 0xFFFFFF); public static void registerPotions(RegistryEvent.Register evt) { @@ -17,5 +19,7 @@ public class BloodMagicPotions reg.register(SOUL_SNARE.setRegistryName("soulsnare")); reg.register(FIRE_FUSE.setRegistryName("firefuse")); reg.register(SOUL_FRAY.setRegistryName("soulfray")); + reg.register(PLANT_LEECH.setRegistryName("plantleech")); + reg.register(SACRIFICIAL_LAMB.setRegistryName("sacrificiallamb")); } } diff --git a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualAnimalGrowth.java b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualAnimalGrowth.java new file mode 100644 index 00000000..3a6aea63 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualAnimalGrowth.java @@ -0,0 +1,258 @@ +package wayoftime.bloodmagic.ritual.types; + +import java.util.List; +import java.util.function.Consumer; + +import net.minecraft.entity.passive.AnimalEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.EffectInstance; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; +import net.minecraftforge.items.IItemHandler; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.api.compat.EnumDemonWillType; +import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; +import wayoftime.bloodmagic.potion.BloodMagicPotions; +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.util.Utils; + +@RitualRegister("animal_growth") +public class RitualAnimalGrowth extends Ritual +{ + public static final double rawWillDrain = 0.05; + public static final double vengefulWillDrain = 0.02; + public static final double steadfastWillDrain = 0.1; + public static final double destructiveWillDrain = 1; + + public static final String GROWTH_RANGE = "growing"; + public static final String CHEST_RANGE = "chest"; + public static int defaultRefreshTime = 20; + public int refreshTime = 20; + + public RitualAnimalGrowth() + { + super("ritualAnimalGrowth", 0, 10000, "ritual." + BloodMagic.MODID + ".animalGrowthRitual"); + addBlockRange(GROWTH_RANGE, new AreaDescriptor.Rectangle(new BlockPos(-2, 1, -2), 5, 2, 5)); + addBlockRange(CHEST_RANGE, new AreaDescriptor.Rectangle(new BlockPos(0, 1, 0), 1)); + + setMaximumVolumeAndDistanceOfRange(GROWTH_RANGE, 0, 7, 7); + setMaximumVolumeAndDistanceOfRange(CHEST_RANGE, 1, 3, 3); + } + + @Override + public void performRitual(IMasterRitualStone masterRitualStone) + { + World world = masterRitualStone.getWorldObj(); + int currentEssence = masterRitualStone.getOwnerNetwork().getCurrentEssence(); + + if (currentEssence < getRefreshCost()) + { + masterRitualStone.getOwnerNetwork().causeNausea(); + return; + } + + int maxGrowths = currentEssence / getRefreshCost(); + int totalGrowths = 0; + BlockPos pos = masterRitualStone.getBlockPos(); + + AreaDescriptor chestRange = masterRitualStone.getBlockRange(CHEST_RANGE); + TileEntity chest = world.getTileEntity(chestRange.getContainedPositions(pos).get(0)); + IItemHandler itemHandler = null; + if (chest != null) + { + itemHandler = Utils.getInventory(chest, null); + } + + List willConfig = masterRitualStone.getActiveWillConfig(); + + double rawWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.DEFAULT, willConfig); + double steadfastWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.STEADFAST, willConfig); + double corrosiveWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.CORROSIVE, willConfig); + double destructiveWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.DESTRUCTIVE, willConfig); + double vengefulWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.VENGEFUL, willConfig); + + refreshTime = getRefreshTimeForRawWill(rawWill); + + boolean consumeRawWill = rawWill >= rawWillDrain && refreshTime != defaultRefreshTime; + + double vengefulDrain = 0; + double steadfastDrain = 0; + double destructiveDrain = 0; + + boolean decreaseBreedTimer = vengefulWill >= vengefulWillDrain; + boolean breedAnimals = steadfastWill >= steadfastWillDrain && itemHandler != null; + boolean kamikaze = destructiveWill >= destructiveWillDrain; + + AreaDescriptor growingRange = masterRitualStone.getBlockRange(GROWTH_RANGE); + AxisAlignedBB axis = growingRange.getAABB(masterRitualStone.getBlockPos()); + List animalList = world.getEntitiesWithinAABB(AnimalEntity.class, axis); + + boolean performedEffect = false; + + for (AnimalEntity animal : animalList) + { + if (animal.getGrowingAge() < 0) + { + animal.addGrowth(5); + totalGrowths++; + performedEffect = true; + } else if (animal.getGrowingAge() > 0) + { + if (decreaseBreedTimer) + { + if (vengefulWill >= vengefulWillDrain) + { + animal.setGrowingAge(Math.max(0, animal.getGrowingAge() - getBreedingDecreaseForWill(vengefulWill))); + vengefulDrain += vengefulWillDrain; + vengefulWill -= vengefulWillDrain; + performedEffect = true; + } else + { + decreaseBreedTimer = false; + } + } + } else + { + if (kamikaze) + { + if (destructiveWill >= destructiveWillDrain) + { + if (!animal.isPotionActive(BloodMagicPotions.SACRIFICIAL_LAMB)) + { + animal.addPotionEffect(new EffectInstance(BloodMagicPotions.SACRIFICIAL_LAMB, 1200)); + destructiveDrain += destructiveWillDrain; + destructiveWill -= destructiveWillDrain; + performedEffect = true; + } + } else + { + kamikaze = false; + } + } + + if (breedAnimals) + { + if (steadfastWill >= steadfastWillDrain) + { + if (!animal.isInLove()) + { + for (int slot = 0; slot < itemHandler.getSlots(); slot++) + { + ItemStack foodStack = itemHandler.getStackInSlot(slot); + if (foodStack != null && animal.isBreedingItem(foodStack) && itemHandler.extractItem(slot, 1, true) != null) + { + animal.setInLove(null); + itemHandler.extractItem(slot, 1, false); + steadfastDrain += steadfastWillDrain; + steadfastWill -= steadfastWillDrain; + performedEffect = true; + break; + } + } + } + } else + { + breedAnimals = false; + } + } + } + + if (totalGrowths >= maxGrowths) + { + break; + } + } + + if (performedEffect && consumeRawWill) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.DEFAULT, rawWillDrain, true); + } + + if (vengefulDrain > 0) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.VENGEFUL, vengefulDrain, true); + } + + if (steadfastDrain > 0) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.STEADFAST, steadfastDrain, true); + } + + if (destructiveDrain > 0) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.DESTRUCTIVE, destructiveDrain, true); + } + + masterRitualStone.getOwnerNetwork().syphon(masterRitualStone.ticket(totalGrowths * getRefreshCost())); + } + + @Override + public int getRefreshCost() + { + return 2; + } + + @Override + public void gatherComponents(Consumer components) + { + + addParallelRunes(components, 2, 0, EnumRuneType.DUSK); + addParallelRunes(components, 1, 0, EnumRuneType.WATER); + components.accept(new RitualComponent(new BlockPos(1, 0, 2), EnumRuneType.EARTH)); + components.accept(new RitualComponent(new BlockPos(1, 0, -2), EnumRuneType.EARTH)); + components.accept(new RitualComponent(new BlockPos(-1, 0, 2), EnumRuneType.EARTH)); + components.accept(new RitualComponent(new BlockPos(-1, 0, -2), EnumRuneType.EARTH)); + components.accept(new RitualComponent(new BlockPos(2, 0, 1), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(2, 0, -1), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(-2, 0, 1), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(-2, 0, -1), EnumRuneType.AIR)); + } + + @Override + public Ritual getNewCopy() + { + return new RitualAnimalGrowth(); + } + + @Override + public ITextComponent[] provideInformationOfRitualToPlayer(PlayerEntity player) + { + return new ITextComponent[] { new TranslationTextComponent(this.getTranslationKey() + ".info"), + new TranslationTextComponent(this.getTranslationKey() + ".default.info"), + new TranslationTextComponent(this.getTranslationKey() + ".corrosive.info"), + new TranslationTextComponent(this.getTranslationKey() + ".steadfast.info"), + new TranslationTextComponent(this.getTranslationKey() + ".destructive.info"), + new TranslationTextComponent(this.getTranslationKey() + ".vengeful.info") }; + } + + public int getBreedingDecreaseForWill(double vengefulWill) + { + return (int) (10 + vengefulWill / 5); + } + + public int getRefreshTimeForRawWill(double rawWill) + { + if (rawWill >= rawWillDrain) + { + return (int) Math.max(defaultRefreshTime - rawWill / 10, 1); + } + + return defaultRefreshTime; + } + + @Override + public int getRefreshTime() + { + return refreshTime; + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualFeatheredKnife.java b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualFeatheredKnife.java index b2fd9885..9f2a7734 100644 --- a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualFeatheredKnife.java +++ b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualFeatheredKnife.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.function.Consumer; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.potion.EffectInstance; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.AxisAlignedBB; @@ -14,7 +15,9 @@ import net.minecraft.world.World; import wayoftime.bloodmagic.BloodMagic; import wayoftime.bloodmagic.ConfigHandler; import wayoftime.bloodmagic.altar.IBloodAltar; +import wayoftime.bloodmagic.api.compat.EnumDemonWillType; import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; +import wayoftime.bloodmagic.network.SetClientHealthPacket; import wayoftime.bloodmagic.potion.BloodMagicPotions; import wayoftime.bloodmagic.ritual.AreaDescriptor; import wayoftime.bloodmagic.ritual.EnumRuneType; @@ -23,7 +26,6 @@ import wayoftime.bloodmagic.ritual.Ritual; import wayoftime.bloodmagic.ritual.RitualComponent; import wayoftime.bloodmagic.ritual.RitualRegister; import wayoftime.bloodmagic.util.helper.PlayerSacrificeHelper; -import wayoftime.bloodmagic.api.compat.EnumDemonWillType; @RitualRegister("feathered_knife") public class RitualFeatheredKnife extends Ritual @@ -54,6 +56,10 @@ public class RitualFeatheredKnife extends Ritual public void performRitual(IMasterRitualStone masterRitualStone) { World world = masterRitualStone.getWorldObj(); +// if (world.isRemote) +// { +// return; +// } int currentEssence = masterRitualStone.getOwnerNetwork().getCurrentEssence(); if (currentEssence < getRefreshCost()) @@ -118,8 +124,7 @@ public class RitualFeatheredKnife extends Ritual { float healthThreshold = steadfastWill >= steadfastWillThreshold ? 0.7f : 0.3f; - if (vengefulWill >= vengefulWillThreshold - && !player.getGameProfile().getId().equals(masterRitualStone.getOwner())) + if (vengefulWill >= vengefulWillThreshold && !player.getGameProfile().getId().equals(masterRitualStone.getOwner())) { healthThreshold = 0.1f; } @@ -130,8 +135,7 @@ public class RitualFeatheredKnife extends Ritual float sacrificedHealth = 1; double lpModifier = 1; - if ((health / player.getMaxHealth() > healthThreshold) - && (!useIncense || !player.isPotionActive(BloodMagicPotions.SOUL_FRAY))) + if ((health / player.getMaxHealth() > healthThreshold) && (!useIncense || !player.isPotionActive(BloodMagicPotions.SOUL_FRAY))) { if (useIncense) { @@ -169,9 +173,9 @@ public class RitualFeatheredKnife extends Ritual // } player.setHealth(health - sacrificedHealth); + BloodMagic.packetHandler.sendTo(new SetClientHealthPacket(health - sacrificedHealth), (ServerPlayerEntity) player); - tileAltar.sacrificialDaggerCall((int) (ConfigHandler.values.sacrificialDaggerConversion * lpModifier - * sacrificedHealth), false); + tileAltar.sacrificialDaggerCall((int) (ConfigHandler.values.sacrificialDaggerConversion * lpModifier * sacrificedHealth), false); totalEffects++; @@ -229,8 +233,7 @@ public class RitualFeatheredKnife extends Ritual @Override public ITextComponent[] provideInformationOfRitualToPlayer(PlayerEntity player) { - return new ITextComponent[] - { new TranslationTextComponent(this.getTranslationKey() + ".info"), + return new ITextComponent[] { new TranslationTextComponent(this.getTranslationKey() + ".info"), new TranslationTextComponent(this.getTranslationKey() + ".default.info"), new TranslationTextComponent(this.getTranslationKey() + ".corrosive.info"), new TranslationTextComponent(this.getTranslationKey() + ".steadfast.info"), diff --git a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualGreenGrove.java b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualGreenGrove.java new file mode 100644 index 00000000..a8d67d12 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualGreenGrove.java @@ -0,0 +1,345 @@ +package wayoftime.bloodmagic.ritual.types; + +import java.util.List; +import java.util.Random; +import java.util.function.Consumer; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.CactusBlock; +import net.minecraft.block.FarmlandBlock; +import net.minecraft.block.IGrowable; +import net.minecraft.block.SugarCaneBlock; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.potion.EffectInstance; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.api.compat.EnumDemonWillType; +import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; +import wayoftime.bloodmagic.impl.BloodMagicAPI; +import wayoftime.bloodmagic.potion.BloodMagicPotions; +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.util.Utils; +import wayoftime.bloodmagic.will.DemonWillHolder; + +@RitualRegister("green_grove") +public class RitualGreenGrove extends Ritual +{ + public static final String GROW_RANGE = "growing"; + public static final String LEECH_RANGE = "leech"; + public static final String HYDRATE_RANGE = "hydrate"; + + public static double corrosiveWillDrain = 0.2; + public static double rawWillDrain = 0.05; + public static double vengefulWillDrain = 0.05; + public static double steadfastWillDrain = 0.05; + public static int defaultRefreshTime = 20; + public static double defaultGrowthChance = 0.3; + public static BlockState farmlandState = Blocks.FARMLAND.getDefaultState().with(FarmlandBlock.MOISTURE, 7); + public int refreshTime = 20; + + public RitualGreenGrove() + { + super("ritualGreenGrove", 0, 5000, "ritual." + BloodMagic.MODID + ".greenGroveRitual"); + addBlockRange(GROW_RANGE, new AreaDescriptor.Rectangle(new BlockPos(-1, 2, -1), 3, 1, 3)); + addBlockRange(LEECH_RANGE, new AreaDescriptor.Rectangle(new BlockPos(0, 0, 0), 1)); + addBlockRange(HYDRATE_RANGE, new AreaDescriptor.Rectangle(new BlockPos(0, 0, 0), 1)); + setMaximumVolumeAndDistanceOfRange(GROW_RANGE, 81, 4, 4); + setMaximumVolumeAndDistanceOfRange(LEECH_RANGE, 0, 15, 15); + setMaximumVolumeAndDistanceOfRange(HYDRATE_RANGE, 0, 15, 15); + } + + @Override + public void performRitual(IMasterRitualStone masterRitualStone) + { + World world = masterRitualStone.getWorldObj(); + if (!(world instanceof ServerWorld)) + { + return; + } + + ServerWorld serverWorld = (ServerWorld) world; + BlockPos pos = masterRitualStone.getBlockPos(); + int currentEssence = masterRitualStone.getOwnerNetwork().getCurrentEssence(); + + if (currentEssence < getRefreshCost()) + { + masterRitualStone.getOwnerNetwork().causeNausea(); + return; + } + + int maxGrowths = currentEssence / getRefreshCost(); + int totalGrowths = 0; + + List willConfig = masterRitualStone.getActiveWillConfig(); + + DemonWillHolder holder = WorldDemonWillHandler.getWillHolder(world, pos); + double corrosiveWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.CORROSIVE, willConfig); + double rawWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.DEFAULT, willConfig); + double steadfastWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.STEADFAST, willConfig); + double vengefulWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.VENGEFUL, willConfig); + + refreshTime = getRefreshTimeForRawWill(rawWill); + double growthChance = getPlantGrowthChanceForWill(vengefulWill); + + boolean consumeRawWill = rawWill >= rawWillDrain && refreshTime != defaultRefreshTime; + boolean consumeVengefulWill = vengefulWill >= vengefulWillDrain && growthChance != defaultGrowthChance; + + double rawDrain = 0; + double vengefulDrain = 0; + + AreaDescriptor growingRange = masterRitualStone.getBlockRange(GROW_RANGE); + + int maxGrowthVolume = getMaxVolumeForRange(GROW_RANGE, willConfig, holder); + if (!growingRange.isWithinRange(getMaxVerticalRadiusForRange(GROW_RANGE, willConfig, holder), getMaxHorizontalRadiusForRange(GROW_RANGE, willConfig, holder)) || (maxGrowthVolume != 0 && growingRange.getVolume() > maxGrowthVolume)) + { + return; + } + + for (BlockPos newPos : growingRange.getContainedPositions(pos)) + { + BlockState state = world.getBlockState(newPos); + + if (!BloodMagicAPI.INSTANCE.getBlacklist().getGreenGrove().contains(state)) + { + boolean flag = state.getBlock() instanceof IGrowable || state.getBlock() instanceof CactusBlock || state.getBlock() instanceof SugarCaneBlock; + if (flag) + { + if (world.rand.nextDouble() < growthChance) + { + state.getBlock().randomTick(state, serverWorld, newPos, new Random()); + BlockState newState = world.getBlockState(newPos); + if (!newState.equals(state)) + { + world.playEvent(2005, newPos, 0); + totalGrowths++; + if (consumeRawWill) + { + rawWill -= rawWillDrain; + rawDrain += rawWillDrain; + } + + if (consumeVengefulWill) + { + vengefulWill -= vengefulWillDrain; + vengefulDrain += vengefulWillDrain; + } + } + } + } + } + + if (totalGrowths >= maxGrowths || (consumeRawWill && rawWill < rawWillDrain) || (consumeVengefulWill && vengefulWill < vengefulWillDrain)) + { + break; + } + } + + if (rawDrain > 0) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.DEFAULT, rawDrain, true); + } + + if (vengefulDrain > 0) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.VENGEFUL, vengefulDrain, true); + } + + AreaDescriptor hydrateRange = masterRitualStone.getBlockRange(HYDRATE_RANGE); + + double steadfastDrain = 0; + if (steadfastWill > steadfastWillDrain) + { + AxisAlignedBB aabb = hydrateRange.getAABB(pos); + steadfastDrain += steadfastWillDrain * Utils.plantSeedsInArea(world, aabb, 2, 1); + steadfastWill -= steadfastDrain; + + for (BlockPos newPos : hydrateRange.getContainedPositions(pos)) + { + if (steadfastWill < steadfastWillDrain) + { + break; + } + + BlockState state = world.getBlockState(newPos); + Block block = state.getBlock(); + + boolean hydratedBlock = false; + if (block == Blocks.DIRT || block == Blocks.GRASS) + { + world.setBlockState(newPos, farmlandState); + hydratedBlock = true; + } else if (block == Blocks.FARMLAND) + { + int meta = state.get(FarmlandBlock.MOISTURE); + if (meta < 7) + { + world.setBlockState(newPos, farmlandState); + hydratedBlock = true; + } + } + + if (hydratedBlock) + { + steadfastWill -= steadfastWillDrain; + steadfastDrain += steadfastWillDrain; + } + } + } + + if (steadfastDrain > 0) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.STEADFAST, steadfastDrain, true); + } + + double corrosiveDrain = 0; + if (corrosiveWill > corrosiveWillDrain) + { + AreaDescriptor leechRange = masterRitualStone.getBlockRange(LEECH_RANGE); + AxisAlignedBB mobArea = leechRange.getAABB(pos); + List entityList = world.getEntitiesWithinAABB(LivingEntity.class, mobArea); + for (LivingEntity entityLiving : entityList) + { + if (corrosiveWill < corrosiveWillDrain) + { + break; + } + + if (entityLiving instanceof PlayerEntity) + { + continue; + } + + if (entityLiving.isPotionActive(BloodMagicPotions.PLANT_LEECH) || !entityLiving.isPotionApplicable(new EffectInstance(BloodMagicPotions.PLANT_LEECH))) + { + continue; + } + + entityLiving.addPotionEffect(new EffectInstance(BloodMagicPotions.PLANT_LEECH, 200, 0)); + + corrosiveWill -= corrosiveWillDrain; + corrosiveDrain += corrosiveWillDrain; + } + + if (corrosiveDrain > 0) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.CORROSIVE, corrosiveDrain, true); + } + } + + masterRitualStone.getOwnerNetwork().syphon(masterRitualStone.ticket(totalGrowths * getRefreshCost())); + } + + public double getPlantGrowthChanceForWill(double will) + { + if (will > 0) + { + return 0.3 + will / 200; + } + + return defaultGrowthChance; + } + + public int getRefreshTimeForRawWill(double rawWill) + { + if (rawWill > 0) + { + return 10; + } + + return defaultRefreshTime; + } + + @Override + public int getRefreshTime() + { + return refreshTime; + } + + @Override + public int getMaxVolumeForRange(String range, List activeTypes, DemonWillHolder holder) + { + if (GROW_RANGE.equals(range) && activeTypes.contains(EnumDemonWillType.DESTRUCTIVE)) + { + double destructiveWill = holder.getWill(EnumDemonWillType.DESTRUCTIVE); + if (destructiveWill > 0) + { + return 81 + (int) Math.pow(destructiveWill / 4, 1.5); + } + } + + return volumeRangeMap.get(range); + } + + @Override + public int getMaxVerticalRadiusForRange(String range, List activeTypes, DemonWillHolder holder) + { + if (GROW_RANGE.equals(range) && activeTypes.contains(EnumDemonWillType.DESTRUCTIVE)) + { + double destructiveWill = holder.getWill(EnumDemonWillType.DESTRUCTIVE); + if (destructiveWill > 0) + { + return (int) (4 + destructiveWill / 10d); + } + } + + return verticalRangeMap.get(range); + } + + @Override + public int getMaxHorizontalRadiusForRange(String range, List activeTypes, DemonWillHolder holder) + { + if (GROW_RANGE.equals(range) && activeTypes.contains(EnumDemonWillType.DESTRUCTIVE)) + { + double destructiveWill = holder.getWill(EnumDemonWillType.DESTRUCTIVE); + if (destructiveWill > 0) + { + return (int) (4 + destructiveWill / 10d); + } + } + + return horizontalRangeMap.get(range); + } + + @Override + public int getRefreshCost() + { + return 20; // TODO: Need to find a way to balance this + } + + @Override + public void gatherComponents(Consumer components) + { + addCornerRunes(components, 1, 0, EnumRuneType.EARTH); + addParallelRunes(components, 1, 0, EnumRuneType.WATER); + } + + @Override + public ITextComponent[] provideInformationOfRitualToPlayer(PlayerEntity player) + { + return new ITextComponent[] { new TranslationTextComponent(this.getTranslationKey() + ".info"), + new TranslationTextComponent(this.getTranslationKey() + ".default.info"), + new TranslationTextComponent(this.getTranslationKey() + ".corrosive.info"), + new TranslationTextComponent(this.getTranslationKey() + ".steadfast.info"), + new TranslationTextComponent(this.getTranslationKey() + ".destructive.info"), + new TranslationTextComponent(this.getTranslationKey() + ".vengeful.info") }; + } + + @Override + public Ritual getNewCopy() + { + return new RitualGreenGrove(); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualRegeneration.java b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualRegeneration.java new file mode 100644 index 00000000..d83cdb44 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualRegeneration.java @@ -0,0 +1,214 @@ +package wayoftime.bloodmagic.ritual.types; + +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.potion.EffectInstance; +import net.minecraft.potion.Effects; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.api.compat.EnumDemonWillType; +import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; +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.util.DamageSourceBloodMagic; +import wayoftime.bloodmagic.util.Utils; + +@RitualRegister("regeneration") +public class RitualRegeneration extends Ritual +{ + public static final String HEAL_RANGE = "heal"; + public static final String VAMPIRE_RANGE = "vampire"; + + public static final int SACRIFICE_AMOUNT = 100; + + public static final double corrosiveWillDrain = 0.04; + + public RitualRegeneration() + { + super("ritualRegeneration", 0, 25000, "ritual." + BloodMagic.MODID + ".regenerationRitual"); + addBlockRange(HEAL_RANGE, new AreaDescriptor.Rectangle(new BlockPos(-15, -15, -15), 31)); + addBlockRange(VAMPIRE_RANGE, new AreaDescriptor.Rectangle(new BlockPos(-15, -15, -15), 31)); + + setMaximumVolumeAndDistanceOfRange(HEAL_RANGE, 0, 20, 20); + setMaximumVolumeAndDistanceOfRange(VAMPIRE_RANGE, 0, 20, 20); + } + + @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(); + + int maxEffects = currentEssence / getRefreshCost(); + int totalEffects = 0; + + int totalCost = 0; + + List willConfig = masterRitualStone.getActiveWillConfig(); + + double rawWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.DEFAULT, willConfig); + double steadfastWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.STEADFAST, willConfig); + double corrosiveWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.CORROSIVE, willConfig); + double destructiveWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.DESTRUCTIVE, willConfig); + double vengefulWill = this.getWillRespectingConfig(world, pos, EnumDemonWillType.VENGEFUL, willConfig); + + double vengefulDrain = 0; + double steadfastDrain = 0; + double destructiveDrain = 0; + double corrosiveDrain = 0; + + boolean syphonHealth = corrosiveWill >= corrosiveWillDrain; + boolean applyAbsorption = false; + float absorptionRate = 1; + int maxAbsorption = 20; + + AreaDescriptor healArea = masterRitualStone.getBlockRange(HEAL_RANGE); + AxisAlignedBB healRange = healArea.getAABB(pos); + + AreaDescriptor damageArea = masterRitualStone.getBlockRange(VAMPIRE_RANGE); + AxisAlignedBB damageRange = damageArea.getAABB(pos); + + List entities = world.getEntitiesWithinAABB(LivingEntity.class, healRange); + List players = world.getEntitiesWithinAABB(PlayerEntity.class, healRange); + List damagedEntities = world.getEntitiesWithinAABB(LivingEntity.class, damageRange); + + if (syphonHealth) + { + for (PlayerEntity player : players) + { + if (player.getHealth() <= player.getMaxHealth() - 1) + { + float syphonedHealthAmount = getSyphonAmountForWill(corrosiveWill); + Collections.shuffle(damagedEntities); + for (LivingEntity damagedEntity : damagedEntities) + { + if (damagedEntity instanceof PlayerEntity) + { + continue; + } + + float currentHealth = damagedEntity.getHealth(); + + damagedEntity.attackEntityFrom(DamageSourceBloodMagic.INSTANCE, Math.min(player.getMaxHealth() - player.getHealth(), syphonedHealthAmount)); + + float healthDifference = currentHealth - damagedEntity.getHealth(); + if (healthDifference > 0) + { + corrosiveDrain += corrosiveWillDrain; + corrosiveWill -= corrosiveWillDrain; + player.heal(healthDifference); + } + + break; + } + } + } + } + + for (LivingEntity entity : entities) + { + float health = entity.getHealth(); + if (health <= entity.getMaxHealth() - 1) + { + if (entity.isPotionApplicable(new EffectInstance(Effects.REGENERATION))) + { + if (entity instanceof PlayerEntity) + { + totalCost += getRefreshCost(); + currentEssence -= getRefreshCost(); + } else + { + totalCost += getRefreshCost() / 10; + currentEssence -= getRefreshCost() / 10; + } + + entity.addPotionEffect(new EffectInstance(Effects.REGENERATION, 50, 0, false, false)); + + totalEffects++; + + if (totalEffects >= maxEffects) + { + break; + } + } + } + if (applyAbsorption && entity instanceof PlayerEntity) + { + if (applyAbsorption) + { + float added = Utils.addAbsorptionToMaximum(entity, absorptionRate, maxAbsorption, 1000); + } + } + } + + if (corrosiveDrain > 0) + { + WorldDemonWillHandler.drainWill(world, pos, EnumDemonWillType.CORROSIVE, corrosiveDrain, true); + } + + masterRitualStone.getOwnerNetwork().syphon(masterRitualStone.ticket(totalCost)); + } + + @Override + public int getRefreshTime() + { + return 50; + } + + @Override + public int getRefreshCost() + { + return SACRIFICE_AMOUNT; + } + + @Override + public void gatherComponents(Consumer components) + { + components.accept(new RitualComponent(new BlockPos(4, 0, 0), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(5, 0, -1), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(5, 0, 1), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(-4, 0, 0), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(-5, 0, -1), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(-5, 0, 1), EnumRuneType.AIR)); + components.accept(new RitualComponent(new BlockPos(0, 0, 4), EnumRuneType.FIRE)); + components.accept(new RitualComponent(new BlockPos(1, 0, 5), EnumRuneType.FIRE)); + components.accept(new RitualComponent(new BlockPos(-1, 0, 5), EnumRuneType.FIRE)); + components.accept(new RitualComponent(new BlockPos(0, 0, -4), EnumRuneType.FIRE)); + components.accept(new RitualComponent(new BlockPos(1, 0, -5), EnumRuneType.FIRE)); + components.accept(new RitualComponent(new BlockPos(-1, 0, -5), EnumRuneType.FIRE)); + addOffsetRunes(components, 3, 5, 0, EnumRuneType.WATER); + addCornerRunes(components, 3, 0, EnumRuneType.DUSK); + addOffsetRunes(components, 4, 5, 0, EnumRuneType.EARTH); + addOffsetRunes(components, 4, 5, -1, EnumRuneType.EARTH); + addCornerRunes(components, 5, 0, EnumRuneType.EARTH); + } + + @Override + public Ritual getNewCopy() + { + return new RitualRegeneration(); + } + + public float getSyphonAmountForWill(double corrosiveWill) + { + return 1; + } +} diff --git a/src/main/java/wayoftime/bloodmagic/util/Utils.java b/src/main/java/wayoftime/bloodmagic/util/Utils.java index 799470f4..1a665309 100644 --- a/src/main/java/wayoftime/bloodmagic/util/Utils.java +++ b/src/main/java/wayoftime/bloodmagic/util/Utils.java @@ -1,5 +1,6 @@ package wayoftime.bloodmagic.util; +import java.util.List; import java.util.Locale; import javax.annotation.Nullable; @@ -14,21 +15,27 @@ import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.potion.EffectInstance; import net.minecraft.potion.Effects; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.common.IPlantable; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.IFluidBlock; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.wrapper.InvWrapper; import net.minecraftforge.items.wrapper.PlayerMainInvWrapper; +import net.minecraftforge.items.wrapper.SidedInvWrapper; import wayoftime.bloodmagic.api.compat.IDemonWillViewer; import wayoftime.bloodmagic.tile.TileInventory; @@ -483,4 +490,137 @@ public class Utils return 100; } + + public static int plantSeedsInArea(World world, AxisAlignedBB aabb, int horizontalRadius, int verticalRadius) + { + int placedBlocks = 0; + List itemEntities = world.getEntitiesWithinAABB(ItemEntity.class, aabb); + + for (ItemEntity itemEntity : itemEntities) + { + placedBlocks += plantEntityItem(itemEntity, horizontalRadius, verticalRadius); + } + + return placedBlocks; + } + + public static int plantItemStack(World world, BlockPos centralPos, ItemStack stack, int horizontalRadius, int verticalRadius) + { + if (stack.isEmpty()) + { + return 0; + } + + Item item = stack.getItem(); + if (!(item instanceof IPlantable)) + { + return 0; + } + + int planted = 0; + + for (int hR = 0; hR <= horizontalRadius; hR++) + { + for (int vR = 0; vR <= verticalRadius; vR++) + { + for (int i = -hR; i <= hR; i++) + { + for (int k = -hR; k <= hR; k++) + { + for (int j = -vR; j <= vR; j += 2 * vR + (vR > 0 ? 0 : 1)) + { + if (!(Math.abs(i) == hR || Math.abs(k) == hR)) + { + continue; + } + + BlockPos newPos = centralPos.add(i, j, k); + if (world.isAirBlock(newPos)) + { + BlockPos offsetPos = newPos.offset(Direction.DOWN); + BlockState state = world.getBlockState(offsetPos); + if (state.getBlock().canSustainPlant(state, world, offsetPos, Direction.UP, (IPlantable) item)) + { + BlockState plantState = ((IPlantable) item).getPlant(world, newPos); + world.setBlockState(newPos, plantState, 3); +// Block. + world.playEvent(2001, newPos, Block.getStateId(plantState)); + stack.shrink(1); + planted++; + if (stack.isEmpty() || stack.getCount() <= 0) + { + return planted; + } + } + } + } + } + } + } + } + + return planted; + } + + public static int plantEntityItem(ItemEntity itemEntity, int horizontalRadius, int verticalRadius) + { + if (itemEntity == null || !itemEntity.isAlive()) + { + return 0; + } + + World world = itemEntity.getEntityWorld(); + BlockPos pos = itemEntity.getPosition(); + ItemStack stack = itemEntity.getItem(); + + int planted = plantItemStack(world, pos, stack, horizontalRadius, verticalRadius); + + if (stack.isEmpty()) + { + itemEntity.remove(); + } + + return planted; + } + + @Nullable + public static IItemHandler getInventory(TileEntity tile, @Nullable Direction facing) + { + if (facing == null) + facing = Direction.DOWN; + + IItemHandler itemHandler = null; + + if (tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing).isPresent()) + itemHandler = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing).resolve().get(); + else if (tile instanceof ISidedInventory) + itemHandler = ((ISidedInventory) tile).getSlotsForFace(facing).length != 0 + ? new SidedInvWrapper((ISidedInventory) tile, facing) + : null; + else if (tile instanceof IInventory) + itemHandler = new InvWrapper((IInventory) tile); + + return itemHandler; + } + + public static float addAbsorptionToMaximum(LivingEntity entity, float added, int maximum, int duration) + { + float currentAmount = entity.getAbsorptionAmount(); + added = Math.min(maximum - currentAmount, added); + + if (added <= 0) + { + return 0; + } + + if (duration > 0) + { + int potionLevel = (int) ((currentAmount + added) / 4); + entity.addPotionEffect(new EffectInstance(Effects.ABSORPTION, duration, potionLevel, true, false)); + } + + entity.setAbsorptionAmount(currentAmount + added); + + return added; + } } diff --git a/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java b/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java index 653c15b9..c8b52550 100644 --- a/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java +++ b/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java @@ -4,6 +4,7 @@ import java.util.Map.Entry; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.EquipmentSlotType; @@ -12,6 +13,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.Tags; import net.minecraftforge.common.ToolType; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerXpEvent; import net.minecraftforge.event.world.BlockEvent.BlockToolInteractEvent; @@ -20,15 +22,17 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import wayoftime.bloodmagic.BloodMagic; import wayoftime.bloodmagic.common.block.BloodMagicBlocks; +import wayoftime.bloodmagic.common.item.BloodOrb; +import wayoftime.bloodmagic.common.item.IBindable; +import wayoftime.bloodmagic.common.item.IBloodOrb; import wayoftime.bloodmagic.common.item.ItemExperienceBook; import wayoftime.bloodmagic.core.data.Binding; import wayoftime.bloodmagic.core.data.SoulNetwork; import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; import wayoftime.bloodmagic.event.ItemBindEvent; -import wayoftime.bloodmagic.common.item.IBindable; import wayoftime.bloodmagic.network.DemonAuraClientPacket; -import wayoftime.bloodmagic.common.item.BloodOrb; -import wayoftime.bloodmagic.common.item.IBloodOrb; +import wayoftime.bloodmagic.potion.BMPotionUtils; +import wayoftime.bloodmagic.potion.BloodMagicPotions; import wayoftime.bloodmagic.util.helper.BindableHelper; import wayoftime.bloodmagic.util.helper.NetworkHelper; import wayoftime.bloodmagic.util.helper.PlayerHelper; @@ -162,4 +166,23 @@ public class GenericHandler } } } + + // Handles sending the client the Demon Will Aura updates + @SubscribeEvent + public void onLivingUpdate(LivingUpdateEvent event) + { + if (!event.getEntityLiving().getEntityWorld().isRemote) + { + LivingEntity entity = event.getEntityLiving(); + if (entity.isPotionActive(BloodMagicPotions.PLANT_LEECH)) + { + int amplifier = entity.getActivePotionEffect(BloodMagicPotions.PLANT_LEECH).getAmplifier(); + int timeRemaining = entity.getActivePotionEffect(BloodMagicPotions.PLANT_LEECH).getDuration(); + if (timeRemaining % 10 == 0) + { + BMPotionUtils.damageMobAndGrowSurroundingPlants(entity, 2 + amplifier, 1, 0.5 * 3 / (amplifier + 3), 25 * (1 + amplifier)); + } + } + } + } }