2f91573284
- 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
158 lines
5.6 KiB
Java
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;
|
|
}
|
|
|
|
}
|