diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java index dae2eef7..b26402b3 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/IceSpell.java @@ -22,7 +22,9 @@ import net.minecraft.entity.LivingEntity; import net.minecraft.entity.TntEntity; import net.minecraft.entity.Entity.RemovalReason; import net.minecraft.particle.ParticleTypes; +import net.minecraft.state.property.Properties; import net.minecraft.tag.BlockTags; +import net.minecraft.tag.FluidTags; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -33,7 +35,7 @@ public class IceSpell extends AbstractSpell { .build(); private final int rad = 3; - private final Shape effect_range = new Sphere(false, rad); + private final Shape outerRange = new Sphere(false, rad); protected IceSpell(SpellType type, SpellTraits traits) { super(type, traits); @@ -43,17 +45,34 @@ public class IceSpell extends AbstractSpell { public boolean tick(Caster source, Situation situation) { LivingEntity owner = source.getMaster(); - PosHelper.getAllInRegionMutable(source.getOrigin(), effect_range) - .forEach(i -> { - if (source.canModifyAt(i) && applyBlockSingle(owner, source.getWorld(), i)) { - ParticleUtils.spawnParticle(source.getWorld(), ParticleTypes.SPLASH, new Vec3d( - i.getX() + source.getWorld().random.nextFloat(), - i.getY() + 1, - i.getZ() + source.getWorld().random.nextFloat()), Vec3d.ZERO); - } - }); + boolean submerged = source.getEntity().isSubmergedInWater() || source.getEntity().isSubmergedIn(FluidTags.LAVA); - return applyEntities(source.getMaster(), source.getWorld(), source.getOriginVector()); + long blocksAffected = PosHelper.getAllInRegionMutable(source.getOrigin(), outerRange).filter(i -> { + if (source.canModifyAt(i) && applyBlockSingle(owner, source.getWorld(), i, situation)) { + + if (submerged & source.getOrigin().isWithinDistance(i, rad - 1)) { + BlockState state = source.getWorld().getBlockState(i); + if (state.isIn(BlockTags.ICE) || state.isOf(Blocks.OBSIDIAN)) { + source.getWorld().setBlockState(i, Blocks.AIR.getDefaultState(), Block.NOTIFY_NEIGHBORS); + } else if (!state.getFluidState().isEmpty()) { + source.getWorld().setBlockState(i, state.with(Properties.WATERLOGGED, false), Block.NOTIFY_NEIGHBORS); + } + } + + ParticleUtils.spawnParticle(source.getWorld(), ParticleTypes.SPLASH, new Vec3d( + i.getX() + source.getWorld().random.nextFloat(), + i.getY() + 1, + i.getZ() + source.getWorld().random.nextFloat()), Vec3d.ZERO); + + return true; + } + + return false; + }).count(); + + source.subtractEnergyCost(Math.min(10, blocksAffected)); + + return applyEntities(source.getMaster(), source.getWorld(), source.getOriginVector()) && situation == Situation.PROJECTILE; } protected boolean applyEntities(LivingEntity owner, World world, Vec3d pos) { @@ -73,17 +92,19 @@ public class IceSpell extends AbstractSpell { return true; } - private boolean applyBlockSingle(Entity owner, World world, BlockPos pos) { + private boolean applyBlockSingle(Entity owner, World world, BlockPos pos, Situation situation) { BlockState state = world.getBlockState(pos); - if (StateMaps.ICE_AFFECTED.convert(world, pos)) { + if ((situation == Situation.PROJECTILE + && StateMaps.SNOW_PILED.convert(world, pos)) + || StateMaps.ICE_AFFECTED.convert(world, pos)) { return true; } if (world.isTopSolid(pos, owner) || state.isOf(Blocks.SNOW) || state.isIn(BlockTags.LEAVES)) { - incrementIce(world, pos.up()); + addSnowLayer(world, pos.up()); return true; } @@ -103,7 +124,7 @@ public class IceSpell extends AbstractSpell { ); } - private static void incrementIce(World world, BlockPos pos) { + private static void addSnowLayer(World world, BlockPos pos) { BlockState state = world.getBlockState(pos); Block id = state.getBlock(); diff --git a/src/main/java/com/minelittlepony/unicopia/block/state/StateMapping.java b/src/main/java/com/minelittlepony/unicopia/block/state/StateMapping.java index f462b22f..a154bef0 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/state/StateMapping.java +++ b/src/main/java/com/minelittlepony/unicopia/block/state/StateMapping.java @@ -10,36 +10,39 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.Material; -import net.minecraft.block.SnowBlock; +import net.minecraft.state.property.IntProperty; import net.minecraft.state.property.Property; import net.minecraft.tag.Tag; import net.minecraft.world.World; interface StateMapping extends Predicate, BiFunction { - static StateMapping incrementSnow() { - return build( - isOf(Blocks.SNOW), - (w, s) -> { - s = s.cycle(SnowBlock.LAYERS); - if (s.get(SnowBlock.LAYERS) >= 7) { - return Blocks.SNOW_BLOCK.getDefaultState(); - } - - return s; - }); - } static Predicate isOf(Block block) { return s -> s.isOf(block); } - static StateMapping replaceMaterial(Material mat, Block block) { - return build(isOf(mat), block); - } static Predicate isOf(Material mat) { return s -> s.getMaterial() == mat; } + static StateMapping cycleProperty(Block block, IntProperty property, int stopAt) { + if (stopAt < 0) { + return build( + isOf(block), + (w, s) -> s.cycle(property) + ); + } + + return build( + isOf(block).and(state -> state.get(property) < stopAt), + (w, s) -> s.get(property) >= stopAt ? s : s.cycle(property) + ); + } + + static StateMapping replaceMaterial(Material mat, Block block) { + return build(isOf(mat), block); + } + static StateMapping removeBlock(Predicate mapper) { return build( mapper, @@ -133,8 +136,8 @@ interface StateMapping extends Predicate, BiFunction REGISTRY = Registries.createSimple(new Identifier("unicopia", "state_map")); + public static final BlockStateConverter SNOW_PILED = register("snow_piled", new BlockStateMap.Builder() + .add(StateMapping.cycleProperty(Blocks.SNOW, SnowBlock.LAYERS, 7))); + public static final BlockStateConverter ICE_AFFECTED = register("ice", new BlockStateMap.Builder() .replaceMaterial(Material.WATER, Blocks.ICE) .replaceMaterial(Material.LAVA, Blocks.OBSIDIAN) - .add(StateMapping.incrementSnow()) + .add(StateMapping.cycleProperty(Blocks.SNOW, SnowBlock.LAYERS, 7)) .replaceBlock(Blocks.FIRE, Blocks.AIR) .setProperty(Blocks.REDSTONE_WIRE, RedstoneWireBlock.POWER, 0)); - public static final ReversableBlockStateConverter MOSS_AFFECTED = register("moss", new ReversableBlockStateMap.Builder() - .replaceBlock(Blocks.MOSSY_COBBLESTONE, Blocks.COBBLESTONE) - .replaceBlock(Blocks.MOSSY_COBBLESTONE_SLAB, Blocks.COBBLESTONE_SLAB) - .replaceBlock(Blocks.MOSSY_COBBLESTONE_STAIRS, Blocks.COBBLESTONE_STAIRS) - .replaceBlock(Blocks.MOSSY_COBBLESTONE_WALL, Blocks.COBBLESTONE_WALL) - .replaceBlock(Blocks.MOSSY_STONE_BRICK_SLAB, Blocks.STONE_BRICK_SLAB) - .replaceBlock(Blocks.MOSSY_STONE_BRICK_STAIRS, Blocks.STONE_BRICK_STAIRS) - .replaceBlock(Blocks.MOSSY_STONE_BRICK_WALL, Blocks.MOSSY_STONE_BRICK_WALL) - .replaceBlock(Blocks.MOSSY_STONE_BRICKS, Blocks.STONE_BRICKS) - .replaceBlock(Blocks.INFESTED_MOSSY_STONE_BRICKS, Blocks.INFESTED_STONE_BRICKS)); - public static final BlockStateConverter SILVERFISH_AFFECTED = register("infestation", new BlockStateMap.Builder() .replaceBlock(Blocks.CHISELED_STONE_BRICKS, Blocks.INFESTED_CHISELED_STONE_BRICKS) .replaceBlock(Blocks.COBBLESTONE, Blocks.INFESTED_COBBLESTONE)