Files
Wizardry/src/main/java/electroblob/wizardry/spell/Mine.java
T
Electroblob77 2f91573284 Block protection compat overhaul
- Unifies all block protection checks into helper methods in BlockUtils which trigger all the necessary forge events and vanilla methods
- Implements these checks in all the appropriate places and removes calls to EntityUtils#canDamageBlocks(...) where they are no longer needed
- Changes the mine spell to respect the config settings in line with the rest of the spells
- Fixes earthquake not respecting the settings at all
- Adds a separate config option for dispenser block damage and updates the description for the existing settings to reflect the changes
2020-09-23 00:57:55 +01:00

158 lines
5.6 KiB
Java

package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.item.SpellActions;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.BlockUtils;
import electroblob.wizardry.util.EntityUtils;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
public class Mine extends SpellRay {
private static final Method getSilkTouchDrop;
static {
getSilkTouchDrop = ObfuscationReflectionHelper.findMethod(Block.class, "func_180643_i", ItemStack.class, IBlockState.class);
}
public Mine(){
super("mine", SpellActions.POINT, false);
this.ignoreLivingEntities(true);
this.particleSpacing(0.5);
}
@Override
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
return false;
}
@Override
protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
// Needs to be outside because it gets run on the client-side
if(caster instanceof EntityPlayer){
if(caster.getHeldItemMainhand().getItem() instanceof ISpellCastingItem){
caster.swingArm(EnumHand.MAIN_HAND);
}else if(caster.getHeldItemOffhand().getItem() instanceof ISpellCastingItem){
caster.swingArm(EnumHand.OFF_HAND);
}
}
if(!world.isRemote){
if(BlockUtils.isBlockUnbreakable(world, pos)) return false;
// Reworked to respect the rules, but since we might break multiple blocks this is left as an optimisation
if(!EntityUtils.canDamageBlocks(caster, world)) return false;
IBlockState state = world.getBlockState(pos);
// The maximum harvest level as determined by the potency multiplier. The + 0.5f is so that
// weird float processing doesn't incorrectly round it down.
int harvestLevel = (int)((modifiers.get(SpellModifiers.POTENCY) - 1) / Constants.POTENCY_INCREASE_PER_TIER + 0.5f);
if(harvestLevel > 0) harvestLevel--; // Shifts them all down one since normally novice wands give some potency
// The >= 3 is to allow master earth wands to break anything.
if(state.getBlock().getHarvestLevel(state) <= harvestLevel || harvestLevel >= 3){
boolean flag = false;
int blastUpgradeCount = (int)((modifiers.get(WizardryItems.blast_upgrade) - 1) / Constants.RANGE_INCREASE_PER_LEVEL + 0.5f);
// Results in the following patterns:
// 0 blast upgrades: single block
// 1 blast upgrade: 3x3 without corners or edges
// 2 blast upgrades: 3x3 with corners
// 3 blast upgrades: 5x5 without corners or edges
float radius = 0.5f + 0.73f * blastUpgradeCount;
List<BlockPos> sphere = BlockUtils.getBlockSphere(pos, radius);
for(BlockPos pos1 : sphere){
if(BlockUtils.isBlockUnbreakable(world, pos1)) continue;
IBlockState state1 = world.getBlockState(pos1);
if(state1.getBlock().getHarvestLevel(state1) <= harvestLevel || harvestLevel >= 3){
if(caster instanceof EntityPlayerMP){ // Everything in here is server-side only so this is fine
boolean silkTouch = state1.getBlock().canSilkHarvest(world, pos1, state1, (EntityPlayer)caster)
&& ItemArtefact.isArtefactActive((EntityPlayer)caster, WizardryItems.charm_silk_touch);
int xp = BlockUtils.checkBlockBreakXP(caster, world, pos);
if(xp < 0) continue; // Not allowed to break the block
if(silkTouch){
flag = world.destroyBlock(pos1, false);
if(flag){
ItemStack stack = getSilkTouchDrop(state1);
if(stack != null) Block.spawnAsEntity(world, pos1, stack);
}
}else{
flag = world.destroyBlock(pos1, true);
if(flag) state1.getBlock().dropXpOnBlockBreak(world, pos1, xp);
}
}else if(BlockUtils.canBreakBlock(caster, world, pos)){
// NPCs can dig the block under the target's feet
flag = world.destroyBlock(pos1, true) || flag;
}
}
}
return flag;
}
}else{
return true;
}
return false;
}
@Override
protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){
return false;
}
@Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){
ParticleBuilder.create(Type.DUST).pos(x, y, z).time(20 + world.rand.nextInt(5)).clr(0.9f, 0.95f, 1)
.shaded(false).spawn(world);
}
private static ItemStack getSilkTouchDrop(IBlockState state){
try {
return (ItemStack)getSilkTouchDrop.invoke(state.getBlock(), state);
}catch(IllegalAccessException | InvocationTargetException e){
Wizardry.logger.error("Error while reflectively retrieving silk touch drop", e);
}
return null;
}
}