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
263 lines
9.4 KiB
Java
263 lines
9.4 KiB
Java
package electroblob.wizardry.block;
|
|
|
|
import electroblob.wizardry.tileentity.TileEntityStatue;
|
|
import electroblob.wizardry.util.BlockUtils;
|
|
import net.minecraft.block.Block;
|
|
import net.minecraft.block.ITileEntityProvider;
|
|
import net.minecraft.block.SoundType;
|
|
import net.minecraft.block.material.Material;
|
|
import net.minecraft.block.state.IBlockState;
|
|
import net.minecraft.entity.EntityLiving;
|
|
import net.minecraft.entity.EntityLivingBase;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
import net.minecraft.util.BlockRenderLayer;
|
|
import net.minecraft.util.EnumBlockRenderType;
|
|
import net.minecraft.util.EnumFacing;
|
|
import net.minecraft.util.math.AxisAlignedBB;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraft.world.IBlockAccess;
|
|
import net.minecraft.world.World;
|
|
import net.minecraftforge.fml.relauncher.Side;
|
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
|
|
|
import javax.annotation.Nullable;
|
|
import java.util.Random;
|
|
|
|
public class BlockStatue extends Block implements ITileEntityProvider {
|
|
|
|
private boolean isIce;
|
|
|
|
/** The NBT tag name for storing the petrified flag (used for rendering) in the target's tag compound. */
|
|
public static final String PETRIFIED_NBT_KEY = "petrified";
|
|
/** The NBT tag name for storing the frozen flag (used for rendering) in the target's tag compound. */
|
|
public static final String FROZEN_NBT_KEY = "frozen";
|
|
|
|
public BlockStatue(Material material){
|
|
super(material);
|
|
this.isIce = material == Material.ICE;
|
|
if(this.isIce){
|
|
this.setDefaultSlipperiness(0.98f);
|
|
this.setSoundType(SoundType.GLASS);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
|
|
// Not a good idea to call getBlockBoundsMinX() or whatever from in here, since this method changes those!
|
|
if(!this.isIce){
|
|
|
|
if(world.getTileEntity(pos) instanceof TileEntityStatue){
|
|
|
|
TileEntityStatue statue = (TileEntityStatue)world.getTileEntity(pos);
|
|
|
|
if(statue.creature != null){
|
|
|
|
// Block bounds are set to match the width and height of the entity, clamped to within 1 block.
|
|
return new AxisAlignedBB((float)Math.max(0.5 - statue.creature.width / 2, 0), 0,
|
|
(float)Math.max(0.5 - statue.creature.width / 2, 0),
|
|
(float)Math.min(0.5 + statue.creature.width / 2, 1),
|
|
// This checks if the block is the top one and if so reduces its height so the top lines up
|
|
// with
|
|
// the top of the entity model.
|
|
statue.position == statue.parts
|
|
? (float)Math.min(statue.creature.height - statue.parts + 1, 1)
|
|
: 1,
|
|
(float)Math.min(0.5 + statue.creature.width / 2, 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
return FULL_BLOCK_AABB;
|
|
}
|
|
|
|
// getCollisionBoundingBox eventually calls getBoundingBox anyway, and since I want the collision box and the block
|
|
// outline to be the same here, I've removed that getCollisionBoundingBox entirely.
|
|
|
|
// The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block
|
|
// connections (fences, glass panes, etc.)...
|
|
@Override
|
|
public boolean isFullCube(IBlockState state){
|
|
return false;
|
|
}
|
|
|
|
// ...this one isn't used much but has something to do with redstone...
|
|
@Override
|
|
public boolean isBlockNormalCube(IBlockState state){
|
|
return false;
|
|
}
|
|
|
|
// ... this one is for most other game logic...
|
|
@Override
|
|
public boolean isNormalCube(IBlockState state){
|
|
return false;
|
|
}
|
|
|
|
// Forge version of the above method. I still need to override both though because vanilla uses the other one.
|
|
@Override
|
|
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
|
|
return false;
|
|
}
|
|
|
|
// ... and this one is for rendering.
|
|
@Override
|
|
public boolean isOpaqueCube(IBlockState state){
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public BlockRenderLayer getRenderLayer(){
|
|
return this.isIce ? BlockRenderLayer.TRANSLUCENT : BlockRenderLayer.SOLID;
|
|
}
|
|
|
|
@Override
|
|
public EnumBlockRenderType getRenderType(IBlockState state){
|
|
return this.isIce ? EnumBlockRenderType.MODEL : EnumBlockRenderType.ENTITYBLOCK_ANIMATED;
|
|
}
|
|
|
|
@Override
|
|
public boolean hasTileEntity(IBlockState state){
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public TileEntity createNewTileEntity(World world, int metadata){
|
|
return new TileEntityStatue(this.isIce);
|
|
}
|
|
|
|
@Override
|
|
public int quantityDropped(Random random){
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void breakBlock(World world, BlockPos pos, IBlockState state){
|
|
|
|
if(!world.isRemote){
|
|
|
|
TileEntityStatue tileentity = (TileEntityStatue)world.getTileEntity(pos);
|
|
|
|
if(tileentity != null){
|
|
if(tileentity.parts == 2){
|
|
if(tileentity.position == 2){
|
|
world.destroyBlock(pos.down(), false);
|
|
}else{
|
|
world.destroyBlock(pos.up(), false);
|
|
}
|
|
}else if(tileentity.parts == 3){
|
|
if(tileentity.position == 3){
|
|
world.destroyBlock(pos.down(), false);
|
|
world.destroyBlock(pos.down(2), false);
|
|
}else if(tileentity.position == 2){
|
|
world.destroyBlock(pos.down(), false);
|
|
world.destroyBlock(pos.up(), false);
|
|
}else{
|
|
world.destroyBlock(pos.up(), false);
|
|
world.destroyBlock(pos.up(2), false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is only when position == 1 because world.destroyBlock calls this function for the other blocks.
|
|
if(tileentity != null && tileentity.position == 1 && tileentity.creature != null){
|
|
tileentity.creature.getEntityData().removeTag(BlockStatue.PETRIFIED_NBT_KEY);
|
|
tileentity.creature.isDead = false;
|
|
world.spawnEntity(tileentity.creature);
|
|
}
|
|
}
|
|
|
|
super.breakBlock(world, pos, state);
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
@SideOnly(Side.CLIENT)
|
|
@Override
|
|
public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos,
|
|
EnumFacing side){
|
|
|
|
IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side));
|
|
Block block = iblockstate.getBlock();
|
|
|
|
return this.isIce && block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side);
|
|
}
|
|
|
|
/**
|
|
* Turns the given entity into a statue. The type of statue depends on the block instance this method was invoked on.
|
|
* @param target The entity to turn into a statue.
|
|
* @param caster The entity that caused it, or null if it was not caused by an entity
|
|
* @param duration The time for which the entity should remain a statue. For petrified creatures, this is the minimum
|
|
* time it can stay as a statue.
|
|
* @return True if the entity was successfully turned into a statue, false if not (i.e. something was in the way).
|
|
*/
|
|
// Making this an instance method means it works equally well for both types of statue
|
|
public boolean convertToStatue(EntityLiving target, @Nullable EntityLivingBase caster, int duration){
|
|
|
|
if(target.deathTime > 0) return false;
|
|
|
|
BlockPos pos = new BlockPos(target);
|
|
World world = target.world;
|
|
|
|
target.hurtTime = 0; // Stops the entity looking red while frozen and the resulting z-fighting
|
|
target.extinguish();
|
|
|
|
// Short mobs such as spiders and pigs
|
|
if((target.height < 1.2 || target.isChild()) && BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canPlaceBlock(caster, world, pos)){
|
|
|
|
world.setBlockState(pos, this.getDefaultState());
|
|
if(world.getTileEntity(pos) instanceof TileEntityStatue){
|
|
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 1);
|
|
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
|
|
}
|
|
|
|
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
|
target.setDead();
|
|
return true;
|
|
}
|
|
// Normal sized mobs like zombies and skeletons
|
|
else if(target.height < 2.5 && BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canBlockBeReplaced(world, pos.up())
|
|
&& BlockUtils.canPlaceBlock(caster, world, pos) && BlockUtils.canPlaceBlock(caster, world, pos.up())){
|
|
|
|
world.setBlockState(pos, this.getDefaultState());
|
|
if(world.getTileEntity(pos) instanceof TileEntityStatue){
|
|
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 2);
|
|
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
|
|
}
|
|
|
|
world.setBlockState(pos.up(), this.getDefaultState());
|
|
if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){
|
|
((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 2);
|
|
}
|
|
|
|
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
|
target.setDead();
|
|
return true;
|
|
}
|
|
// Tall mobs like endermen
|
|
else if(BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canBlockBeReplaced(world, pos.up()) && BlockUtils.canBlockBeReplaced(world, pos.up(2))
|
|
&& BlockUtils.canPlaceBlock(caster, world, pos) && BlockUtils.canPlaceBlock(caster, world, pos.up()) && BlockUtils.canPlaceBlock(caster, world, pos.up(2))){
|
|
|
|
world.setBlockState(pos, this.getDefaultState());
|
|
if(world.getTileEntity(pos) instanceof TileEntityStatue){
|
|
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 3);
|
|
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
|
|
}
|
|
|
|
world.setBlockState(pos.up(), this.getDefaultState());
|
|
if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){
|
|
((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 3);
|
|
}
|
|
|
|
world.setBlockState(pos.up(2), this.getDefaultState());
|
|
if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){
|
|
((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(target, 3, 3);
|
|
}
|
|
|
|
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
|
target.setDead();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|