Skip to content

Commit

Permalink
Implement remaining cauldron behaviors
Browse files Browse the repository at this point in the history
Potion cauldrons: will apply potion to submerged entities and will drop potion when broken
Water, milk, and soup cauldrons now support boiling, will damage submerged entities and display cool particles
  • Loading branch information
KnightMiner committed Nov 7, 2022
1 parent 0b55c9e commit 5e659fe
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/main/java/knightminer/inspirations/common/Config.java
Expand Up @@ -69,6 +69,7 @@ public class Config {
public static final BooleanSupplier cauldronCleanStickyPiston;
public static final BooleanSupplier cauldronWetSponge;
public static final BooleanSupplier cauldronWashWool;
public static final BooleanSupplier replaceVanillaCauldrons;
// contents
public static final BooleanSupplier enableCauldronMilk;
public static final BooleanSupplier enableCauldronHoney;
Expand Down Expand Up @@ -244,6 +245,7 @@ public class Config {
{
// global switch
moreCauldronBehavior = and(recipesModule, common.comment("Main disable for the cauldron, will disable most functionality").worldRestart().define("enable", true));
replaceVanillaCauldrons = and(moreCauldronBehavior, common.comment("If true, improves vanilla water cauldrons by including boiling particles, requires a block substitution on water cauldrons. More functionality coming to this option later.").worldRestart().define("replaceWaterCauldron", true));

// vanilla recipes
common.push("vanilla");
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/knightminer/inspirations/library/MiscUtil.java
Expand Up @@ -2,8 +2,10 @@

import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
Expand Down Expand Up @@ -32,6 +34,7 @@
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

@SuppressWarnings("deprecation")
public class MiscUtil {
Expand Down Expand Up @@ -366,4 +369,21 @@ public static int addColors(int newColor, int newLevels, int original, int origL
int c = origLevels + newLevels;
return divide(r, nr, c) << 16 | divide(g, ng, c) << 8 | divide(b, nb, c);
}

/**
* Adds particles
* @param type Particle type
* @param world World instance
* @param pos Block position
* @param offset Current fluid height
* @param rand Random instance
*/
public static void addParticles(ParticleOptions type, Level world, BlockPos pos, int count, double offset, Random rand) {
for (int i = 0; i < count; i++) {
double x = pos.getX() + 0.1875D + (rand.nextFloat() * 0.625D);
double y = pos.getY() + offset;
double z = pos.getZ() + 0.1875D + (rand.nextFloat() * 0.625D);
world.addParticle(type, x, y, z, 0, 0, 0);
}
}
}
Expand Up @@ -7,6 +7,8 @@
import knightminer.inspirations.library.InspirationsTags;
import knightminer.inspirations.library.MiscUtil;
import knightminer.inspirations.library.recipe.cauldron.CauldronRegistry;
import knightminer.inspirations.recipes.block.BoilingFourLayerCauldronBlock;
import knightminer.inspirations.recipes.block.BoilingThreeLayerCauldronBlock;
import knightminer.inspirations.recipes.block.DyeCauldronBlock;
import knightminer.inspirations.recipes.block.FourLayerCauldronBlock;
import knightminer.inspirations.recipes.block.PotionCauldronBlock;
Expand Down Expand Up @@ -74,6 +76,7 @@
import net.minecraft.world.level.block.LayeredCauldronBlock;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockBehaviour.Properties;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
Expand All @@ -98,6 +101,7 @@
import slimeknights.mantle.registration.adapter.RegistryAdapter;
import slimeknights.mantle.registration.object.EnumObject;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -135,6 +139,8 @@ public class InspirationsRecipes extends ModuleBase {
public static FourLayerCauldronBlock mushroomStewCauldron, beetrootSoupCauldron, rabbitStewCauldron, potatoSoupCauldron;
public static FourLayerCauldronBlock honeyCauldron, milkCauldron, suspiciousStewCauldron;
public static LayeredCauldronBlock dyeCauldron, potionCauldron;
@Nullable
private static LayeredCauldronBlock waterCauldron;

public static BlockEntityType<DyeCauldronBlockEntity> dyeCauldronEntity;
public static BlockEntityType<PotionCauldronBlockEntity> potionCauldronEntity;
Expand Down Expand Up @@ -201,22 +207,27 @@ void registerFluids(Register<Fluid> event) {
void registerBlocks(Register<Block> event) {
BlockRegistryAdapter registry = new BlockRegistryAdapter(event.getRegistry());

mushroomStewCauldron = registry.register(new FourLayerCauldronBlock(Properties.copy(Blocks.CAULDRON), MUSHROOM_STEW_CAULDRON_INTERACTIONS), "mushroom_stew_cauldron");
beetrootSoupCauldron = registry.register(new FourLayerCauldronBlock(Properties.copy(Blocks.CAULDRON), BEETROOT_SOUP_CAULDRON_INTERACTIONS), "beetroot_soup_cauldron");
rabbitStewCauldron = registry.register(new FourLayerCauldronBlock(Properties.copy(Blocks.CAULDRON), RABBIT_STEW_CAULDRON_INTERACTIONS), "rabbit_stew_cauldron");
potatoSoupCauldron = registry.register(new FourLayerCauldronBlock(Properties.copy(Blocks.CAULDRON), POTATO_SOUP_CAULDRON_INTERACTIONS), "potato_soup_cauldron");
honeyCauldron = registry.register(new FourLayerCauldronBlock(Properties.copy(Blocks.CAULDRON), HONEY_CAULDRON_INTERACTIONS), "honey_cauldron");
milkCauldron = registry.register(new FourLayerCauldronBlock(Properties.copy(Blocks.CAULDRON), MILK_CAULDRON_INTERACTIONS), "milk_cauldron");
BlockBehaviour.Properties cauldronProps = Properties.copy(Blocks.CAULDRON);
mushroomStewCauldron = registry.register(new BoilingFourLayerCauldronBlock(cauldronProps, MUSHROOM_STEW_CAULDRON_INTERACTIONS), "mushroom_stew_cauldron");
beetrootSoupCauldron = registry.register(new BoilingFourLayerCauldronBlock(cauldronProps, BEETROOT_SOUP_CAULDRON_INTERACTIONS), "beetroot_soup_cauldron");
rabbitStewCauldron = registry.register(new BoilingFourLayerCauldronBlock(cauldronProps, RABBIT_STEW_CAULDRON_INTERACTIONS), "rabbit_stew_cauldron");
potatoSoupCauldron = registry.register(new BoilingFourLayerCauldronBlock(cauldronProps, POTATO_SOUP_CAULDRON_INTERACTIONS), "potato_soup_cauldron");
honeyCauldron = registry.register(new FourLayerCauldronBlock(cauldronProps, HONEY_CAULDRON_INTERACTIONS), "honey_cauldron");
milkCauldron = registry.register(new BoilingFourLayerCauldronBlock(cauldronProps, MILK_CAULDRON_INTERACTIONS), "milk_cauldron");

mushroomStewBlock = registry.registerFluidBlock(() -> mushroomStew, Material.WATER, 0, "mushroom_stew");
beetrootSoupBlock = registry.registerFluidBlock(() -> beetrootSoup, Material.WATER, 0, "beetroot_soup");
rabbitStewBlock = registry.registerFluidBlock(() -> rabbitStew, Material.WATER, 0, "rabbit_stew");
potatoSoupBlock = registry.registerFluidBlock(() -> potatoSoup, Material.WATER, 0, "potato_soup");
honeyFluidBlock = registry.registerFluidBlock(() -> honey, Material.WATER, 0, "honey");

dyeCauldron = registry.register(new DyeCauldronBlock(Properties.copy(Blocks.CAULDRON)), "dye_cauldron");
potionCauldron = registry.register(new PotionCauldronBlock(Properties.copy(Blocks.CAULDRON)), "potion_cauldron");
suspiciousStewCauldron = registry.register(new SuspiciousStewCauldronBlock(Properties.copy(Blocks.CAULDRON)), "suspicious_stew_cauldron");
dyeCauldron = registry.register(new DyeCauldronBlock(cauldronProps), "dye_cauldron");
potionCauldron = registry.register(new PotionCauldronBlock(cauldronProps), "potion_cauldron");
suspiciousStewCauldron = registry.register(new SuspiciousStewCauldronBlock(cauldronProps), "suspicious_stew_cauldron");

if (Config.replaceVanillaCauldrons.getAsBoolean()) {
waterCauldron = registry.registerOverride(props -> new BoilingThreeLayerCauldronBlock(props, LayeredCauldronBlock.RAIN, CauldronInteraction.WATER), Blocks.WATER_CAULDRON);
}
}

@SubscribeEvent
Expand Down Expand Up @@ -629,13 +640,19 @@ void commonSetup(FMLCommonSetupEvent event) {
for (AbstractCauldronBlock cauldron : newCauldrons) {
cauldron.getStateDefinition().getPossibleStates().forEach(consumer);
}
if (waterCauldron != null) {
waterCauldron.getStateDefinition().getPossibleStates().forEach(consumer);
}
}
synchronized (PoiType.LEATHERWORKER) {
ImmutableSet.Builder<BlockState> builder = ImmutableSet.builder();
builder.addAll(PoiType.LEATHERWORKER.matchingStates);
for (AbstractCauldronBlock cauldron : newCauldrons) {
builder.addAll(cauldron.getStateDefinition().getPossibleStates());
}
if (waterCauldron != null) {
builder.addAll(waterCauldron.getStateDefinition().getPossibleStates());
}
PoiType.LEATHERWORKER.matchingStates = builder.build();
}
}
Expand Down
@@ -0,0 +1,50 @@
package knightminer.inspirations.recipes.block;

import knightminer.inspirations.Inspirations;
import knightminer.inspirations.library.InspirationsTags;
import knightminer.inspirations.library.MiscUtil;
import knightminer.inspirations.recipes.InspirationsRecipes;
import net.minecraft.core.BlockPos;
import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;

import java.util.Map;
import java.util.Random;

/** Cauldron block that has four layers and emits boiling particles when over fire */
public class BoilingFourLayerCauldronBlock extends FourLayerCauldronBlock {
public static final DamageSource DAMAGE_BOIL = new DamageSource(Inspirations.prefix("boiling")).bypassArmor();

public BoilingFourLayerCauldronBlock(Properties props, Map<Item,CauldronInteraction> interactions) {
super(props, interactions);
}

@Override
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
if (!world.isClientSide && isEntityInsideContent(state, pos, entity) && isBoiling(world, pos)) {
entity.hurt(DAMAGE_BOIL, 2.0F);
}
}

@Override
public void animateTick(BlockState state, Level level, BlockPos pos, Random rand) {
if (isBoiling(level, pos)) {
MiscUtil.addParticles(InspirationsRecipes.boilingParticle, level, pos, 2, getContentHeight(state), rand);
}
}

/** Checks if this cauldron is boiling */
public static boolean isBoiling(Level level, BlockPos pos) {
BlockState state = level.getBlockState(pos.below());
if (state.is(InspirationsTags.Blocks.CAULDRON_FIRE)) {
// if it has a lit property, use that (campfires, furnaces). Otherwise just needs to be in the tag
return !state.hasProperty(BlockStateProperties.LIT) || state.getValue(BlockStateProperties.LIT);
}
return false;
}
}
@@ -0,0 +1,48 @@
package knightminer.inspirations.recipes.block;

import knightminer.inspirations.library.MiscUtil;
import knightminer.inspirations.recipes.InspirationsRecipes;
import net.minecraft.core.BlockPos;
import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome.Precipitation;
import net.minecraft.world.level.block.LayeredCauldronBlock;
import net.minecraft.world.level.block.state.BlockState;

import java.util.Map;
import java.util.Random;
import java.util.function.Predicate;

import static knightminer.inspirations.recipes.block.BoilingFourLayerCauldronBlock.DAMAGE_BOIL;
import static knightminer.inspirations.recipes.block.BoilingFourLayerCauldronBlock.isBoiling;

/** Cauldron block that has four layers and emits boiling particles when over fire */
public class BoilingThreeLayerCauldronBlock extends LayeredCauldronBlock {
public BoilingThreeLayerCauldronBlock(Properties props, Predicate<Precipitation> fillPredicate, Map<Item,CauldronInteraction> interactions) {
super(props, fillPredicate, interactions);
}

@Override
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
if (!world.isClientSide && isEntityInsideContent(state, pos, entity)) {
if (isBoiling(world, pos)) {
entity.hurt(DAMAGE_BOIL, 2.0F);
}
if (entity.isOnFire()) {
entity.clearFire();
if (entity.mayInteract(world, pos)) {
this.handleEntityOnFireInside(state, world, pos);
}
}
}
}

@Override
public void animateTick(BlockState state, Level level, BlockPos pos, Random rand) {
if (isBoiling(level, pos)) {
MiscUtil.addParticles(InspirationsRecipes.boilingParticle, level, pos, 2, getContentHeight(state), rand);
}
}
}
Expand Up @@ -3,22 +3,87 @@
import knightminer.inspirations.recipes.InspirationsRecipes;
import knightminer.inspirations.recipes.block.entity.PotionCauldronBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.AreaEffectCloud;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.LayeredCauldronBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;

import javax.annotation.Nullable;
import java.util.List;

import static knightminer.inspirations.recipes.block.BoilingFourLayerCauldronBlock.DAMAGE_BOIL;
import static knightminer.inspirations.recipes.block.BoilingFourLayerCauldronBlock.isBoiling;

/** Cauldron that contains a data instance for the potion */
public class PotionCauldronBlock extends LayeredCauldronBlock implements EntityBlock {
public class PotionCauldronBlock extends BoilingThreeLayerCauldronBlock implements EntityBlock {
public PotionCauldronBlock(Properties props) {
super(props, precipitation -> false, InspirationsRecipes.POTION_CAULDRON_INTERACTIONS);
}

@Override
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
if (!world.isClientSide && isEntityInsideContent(state, pos, entity)) {
if (isBoiling(world, pos)) {
entity.hurt(DAMAGE_BOIL, 2.0F);
}
if (entity instanceof LivingEntity living) {
PotionCauldronBlockEntity be = InspirationsRecipes.potionCauldronEntity.getBlockEntity(world, pos);
if (be != null) {
List<MobEffectInstance> effects = be.getPotion().getEffects();
if (effects.stream().anyMatch(effect -> !living.hasEffect(effect.getEffect()))) {
for (MobEffectInstance effect : effects) {
if (effect.getEffect().isInstantenous()) {
effect.getEffect().applyInstantenousEffect(null, null, living, effect.getAmplifier(), 1.0D);
} else {
living.addEffect(new MobEffectInstance(effect));
}
}
lowerFillLevel(state, world, pos);
world.playSound(null, pos, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0f, 1.0f);
}
}
}
}
}

@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new PotionCauldronBlockEntity(pos, state);
}

@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
if (!state.is(newState.getBlock())) {
// if broken, potion!
if (!isMoving && !newState.is(BlockTags.CAULDRONS)) {
PotionCauldronBlockEntity be = InspirationsRecipes.potionCauldronEntity.getBlockEntity(level, pos);
if (be != null) {
Potion potion = be.getPotion();
int waterLevel = state.getValue(LEVEL);
AreaEffectCloud cloud = new AreaEffectCloud(level, pos.getX() + 0.5F, pos.getY() + 0.5F, pos.getZ() + 0.5F);
cloud.setRadius(0.5F * waterLevel + 0.5F);
cloud.setDuration(20 * (waterLevel + 1));
cloud.setRadiusOnUse(-0.5F);
cloud.setWaitTime(10);
cloud.setRadiusPerTick(-cloud.getRadius() / cloud.getDuration());
cloud.setPotion(potion);
for (MobEffectInstance effect : potion.getEffects()) {
cloud.addEffect(new MobEffectInstance(effect));
}
level.addFreshEntity(cloud);
level.playSound(null, pos, SoundEvents.SPLASH_POTION_BREAK, SoundSource.BLOCKS, 1.0f, 1.0f);
}
}
level.removeBlockEntity(pos);
}
}
}
Expand Up @@ -10,7 +10,7 @@
import javax.annotation.Nullable;

/** Cauldron that contains suspicious stew effects */
public class SuspiciousStewCauldronBlock extends FourLayerCauldronBlock implements EntityBlock {
public class SuspiciousStewCauldronBlock extends BoilingFourLayerCauldronBlock implements EntityBlock {
public SuspiciousStewCauldronBlock(Properties props) {
super(props, InspirationsRecipes.SUSPICIOUS_STEW_CAULDRON_INTERACTIONS);
}
Expand Down
@@ -1,6 +1,5 @@
package knightminer.inspirations.recipes.cauldron;

import knightminer.inspirations.library.InspirationsTags;
import knightminer.inspirations.library.MiscUtil;
import knightminer.inspirations.recipes.block.FourLayerCauldronBlock;
import net.minecraft.core.BlockPos;
Expand All @@ -18,6 +17,8 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.IntegerProperty;

import static knightminer.inspirations.recipes.block.BoilingFourLayerCauldronBlock.isBoiling;

/** Transforms a cauldron into another cauldron */
public record TransformCauldronInteraction(boolean requireFire, int needed, IntegerProperty oldProp, FourLayerCauldronBlock block, SoundEvent sound) implements CauldronInteraction {
public TransformCauldronInteraction(boolean requireFire, int needed, IntegerProperty oldProp, FourLayerCauldronBlock block) {
Expand All @@ -32,7 +33,7 @@ public static int scaleAmountNeeded(int needed) {

@Override
public InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand pHand, ItemStack stack) {
if (requireFire && !level.getBlockState(pos.below()).is(InspirationsTags.Blocks.CAULDRON_FIRE)) {
if (requireFire && !isBoiling(level, pos)) {
return InteractionResult.PASS;
}
if (!level.isClientSide) {
Expand Down
@@ -1,6 +1,5 @@
package knightminer.inspirations.recipes.cauldron.potion;

import knightminer.inspirations.library.InspirationsTags;
import knightminer.inspirations.library.MiscUtil;
import knightminer.inspirations.recipes.InspirationsRecipes;
import knightminer.inspirations.recipes.block.entity.PotionCauldronBlockEntity;
Expand Down Expand Up @@ -30,6 +29,7 @@
import java.util.Map;
import java.util.function.Function;

import static knightminer.inspirations.recipes.block.BoilingFourLayerCauldronBlock.isBoiling;
import static net.minecraft.world.level.block.LayeredCauldronBlock.LEVEL;

/** Cauldron interaction for brewing in a cauldron */
Expand All @@ -44,7 +44,7 @@ public BrewingCauldronInteraction(@Nullable Potion fixedInput) {
@Override
public InteractionResult interact(BlockState oldState, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack) {
// cauldron needs to be above fire
if (level.getBlockState(pos.below()).is(InspirationsTags.Blocks.CAULDRON_FIRE)) {
if (isBoiling(level, pos)) {
// if given a fixed input, use that
PotionCauldronBlockEntity cauldron = null;
Potion oldPotion = this.fixedInput;
Expand Down

0 comments on commit 5e659fe

Please sign in to comment.