package blusunrize.immersiveengineering.common.blocks.metal; import blusunrize.immersiveengineering.api.IEEnums.SideConfig; import blusunrize.immersiveengineering.api.Lib; import blusunrize.immersiveengineering.api.energy.immersiveflux.FluxStorage; import blusunrize.immersiveengineering.common.Config.IEConfig; import blusunrize.immersiveengineering.common.blocks.IEBlockInterfaces.*; import blusunrize.immersiveengineering.common.blocks.TileEntityIEBase; import blusunrize.immersiveengineering.common.util.ChatUtils; import blusunrize.immersiveengineering.common.util.EnergyHelper.IEForgeEnergyWrapper; import blusunrize.immersiveengineering.common.util.EnergyHelper.IIEInternalFluxHandler; import blusunrize.immersiveengineering.common.util.Utils; import blusunrize.immersiveengineering.common.util.inventory.IIEInventory; import com.google.common.collect.Lists; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EnumCreatureType; import net.minecraft.entity.IEntityOwnable; import net.minecraft.entity.passive.EntityAnimal; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; public abstract class TileEntityTurret extends TileEntityIEBase implements ITickable, IIEInternalFluxHandler, IIEInventory, IHasDummyBlocks, ITileDrop, IDirectionalTile, IBlockBounds, IGuiTile, IEntityProof, IHammerInteraction, IHasObjProperty { public boolean dummy = false; public FluxStorage energyStorage = new FluxStorage(16000); public boolean redstoneControlInverted = false; public EnumFacing facing = EnumFacing.NORTH; public String owner; public List<String> targetList = new ArrayList<>(); public boolean whitelist = false; public boolean attackAnimals = false; public boolean attackPlayers = false; public boolean attackNeutrals = false; protected int tick = 0; protected EntityLivingBase target; public float rotationYaw; public float rotationPitch; @Override public void update() { if(dummy) return; if(target!=null) { double dX = target.posX-(getPos().getX()+.5); double dY = target.posY-(getPos().getY()+.5); double dZ = target.posZ-(getPos().getZ()+.5); double dSq = dX*dX+dY*dY+dZ*dZ; double r = getRange(); if(dSq > r*r) this.target=null; else if(worldObj.isRemote) { float facingYaw = facing==EnumFacing.NORTH?180: facing==EnumFacing.WEST?-90: facing==EnumFacing.EAST?90: 0; double yaw = (MathHelper.atan2(dX, dZ)*(180/Math.PI))-facingYaw; this.rotationPitch = (float)(Math.atan2(Math.sqrt(dZ*dZ+dX*dX), dY)*(180/Math.PI))-90; if(this.rotationYaw==0)//moving from default this.rotationYaw = (float)(yaw*.5); else this.rotationYaw = (float)yaw; } } else if(worldObj.isRemote) { this.rotationYaw*=.75; if(Math.abs(rotationYaw)<10) this.rotationYaw = 0; this.rotationPitch*=.75; if(Math.abs(rotationPitch)<10) this.rotationPitch = 0; } if(worldObj.isRemote) return; if(worldObj.getTotalWorldTime()%64==((getPos().getX()^getPos().getZ())&63)) markContainingBlockForUpdate(null); int energy = IEConfig.Machines.turret_consumption; if(worldObj.isBlockIndirectlyGettingPowered(getPos())>0^redstoneControlInverted) { if(energyStorage.extractEnergy(energy, true)==energy) { energyStorage.extractEnergy(energy, false); if(target==null||target.isDead||worldObj.getEntityByID(target.getEntityId())==null||target.getHealth() <= 0||!canSeeEntity(target)) { target = getTarget(); if(target!=null) { this.markDirty(); markContainingBlockForUpdate(null); } } //has target, Redstone control check and has power+ammo if(target!=null&&canActivate()) { tick++; int chargeup = getChargeupTicks(); if(tick==chargeup) this.activate(); else if(tick > chargeup) { if(loopActivation()) this.activate(); else if(tick==chargeup+getActiveTicks()) tick = 0; } } else tick = 0; } } else if(target!=null) target=null; } private boolean canSeeEntity(EntityLivingBase entity) { return Utils.rayTraceForFirst(new Vec3d(getPos().getX()+.5, getPos().getY()+1.375, getPos().getZ()+.5), new Vec3d(entity.posX, entity.posY+entity.getEyeHeight(), entity.posZ), worldObj, Collections.singleton(getPos().up()))==null; // return this.worldObj.rayTraceBlocks(, false, true, false)==null; } private EntityLivingBase getTarget() { double range = getRange(); List<EntityLivingBase> list = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, new AxisAlignedBB(getPos().getX()-range,getPos().getY(),getPos().getZ()-range, getPos().getX()+range,getPos().getY()+3,getPos().getZ()+range)); if(list.isEmpty()) return null; EntityLivingBase target = null; for(EntityLivingBase entity : list) { if(entity==null || entity.isDead || entity.getHealth()<=0 || !canSeeEntity(entity)) continue; //Continue if blacklist and name is in list, or whitelist and name is not in list if(whitelist ^ isListedName(targetList, entity.getName())) continue; //Same as above but for the owner of the pet, to prevent shooting wolves if(entity instanceof IEntityOwnable) { Entity entityOwner = ((IEntityOwnable)entity).getOwner(); if(entityOwner!=null&&(whitelist ^ isListedName(targetList, entityOwner.getName()))) continue; } if(entity instanceof EntityAnimal && !attackAnimals) continue; if(entity instanceof EntityPlayer && !attackPlayers) continue; if(!(entity instanceof EntityPlayer) && !(entity instanceof EntityAnimal) && !entity.isCreatureType(EnumCreatureType.MONSTER, false) && !attackNeutrals) continue; if(target==null || entity.getDistanceSq(getPos())<target.getDistanceSq(getPos())) target = entity; } return target; } private boolean isListedName(List<String> list, String name) { for(String s : list) if(s!=null && s.equalsIgnoreCase(name)) return true; return false; } protected abstract double getRange(); protected abstract boolean canActivate(); protected abstract int getChargeupTicks(); protected abstract int getActiveTicks(); protected abstract boolean loopActivation(); protected abstract void activate(); protected boolean hasOwnerRights(EntityPlayer player) { if(player.capabilities.isCreativeMode || owner==null || owner.isEmpty()) return true; return owner.equalsIgnoreCase(player.getName()); } @Override public void receiveMessageFromClient(NBTTagCompound message) { if(message.hasKey("add")) targetList.add(message.getString("add")); if(message.hasKey("remove")) targetList.remove(message.getInteger("remove")); if(message.hasKey("whitelist")) whitelist = message.getBoolean("whitelist"); if(message.hasKey("attackAnimals")) attackAnimals = message.getBoolean("attackAnimals"); if(message.hasKey("attackPlayers")) attackPlayers = message.getBoolean("attackPlayers"); if(message.hasKey("attackNeutrals")) attackNeutrals = message.getBoolean("attackNeutrals"); this.markDirty(); } @Override public void readCustomNBT(NBTTagCompound nbt, boolean descPacket) { dummy = nbt.getBoolean("dummy"); redstoneControlInverted = nbt.getBoolean("redstoneInverted"); facing = EnumFacing.getFront(nbt.getInteger("facing")); energyStorage.readFromNBT(nbt); if(nbt.hasKey("owner")) owner = nbt.getString("owner"); NBTTagList list = nbt.getTagList("targetList", 8); targetList.clear(); for(int i=0; i<list.tagCount(); i++) targetList.add(list.getStringTagAt(i)); whitelist = nbt.getBoolean("whitelist"); attackAnimals = nbt.getBoolean("attackAnimals"); attackPlayers = nbt.getBoolean("attackPlayers"); attackNeutrals = nbt.getBoolean("attackNeutrals"); target = null; if(nbt.hasKey("target")) { int targetId = nbt.getInteger("target"); Entity ent = worldObj.getEntityByID(targetId); if(ent instanceof EntityLivingBase && !ent.isDead) target = (EntityLivingBase)ent; } } @Override public void writeCustomNBT(NBTTagCompound nbt, boolean descPacket) { nbt.setBoolean("dummy", dummy); nbt.setBoolean("redstoneInverted", redstoneControlInverted); if(facing!=null) nbt.setInteger("facing", facing.ordinal()); energyStorage.writeToNBT(nbt); if(owner!=null) nbt.setString("owner", owner); NBTTagList list = new NBTTagList(); for(String s : targetList) list.appendTag(new NBTTagString(s)); nbt.setTag("targetList", list); nbt.setBoolean("whitelist",whitelist); nbt.setBoolean("attackAnimals",attackAnimals); nbt.setBoolean("attackPlayers",attackPlayers); nbt.setBoolean("attackNeutrals",attackNeutrals); if(target!=null) nbt.setInteger("target", target.getEntityId()); } @Override public float[] getBlockBounds() { if(!dummy) return null; switch(facing) { case NORTH: return new float[]{.125f,.0625f,.125f, .875f,.875f,1}; case SOUTH: return new float[]{.125f,.0625f,0, .875f,.875f,.875f}; case WEST: return new float[]{.125f,.0625f,.125f, 1,.875f,.875f}; case EAST: return new float[]{0,.0625f,.125f, .875f,.875f,.875f}; } return null; } AxisAlignedBB renderBB; @Override @SideOnly(Side.CLIENT) public AxisAlignedBB getRenderBoundingBox() { if(renderBB==null) renderBB = new AxisAlignedBB(getPos().add(-8,-8,-8),getPos().add(8,8,8)); return renderBB; } @Override public boolean hammerUseSide(EnumFacing side, EntityPlayer player, float hitX, float hitY, float hitZ) { if(dummy) { TileEntity te = worldObj.getTileEntity(getPos().offset(facing,-1)); if(te instanceof TileEntityTurret) return ((TileEntityTurret)te).hammerUseSide(side, player, hitX, hitY, hitZ); return false; } if(player.isSneaking()) { redstoneControlInverted = !redstoneControlInverted; ChatUtils.sendServerNoSpamMessages(player, new TextComponentTranslation(Lib.CHAT_INFO+"rsControl."+(redstoneControlInverted?"invertedOn":"invertedOff"))); markDirty(); this.markContainingBlockForUpdate(null); } return true; } @Override public ItemStack[] getInventory() { return new ItemStack[0]; } @Override public boolean isStackValid(int slot, ItemStack stack) { return true; } @Override public int getSlotLimit(int slot) { return 64; } @Override public void doGraphicalUpdates(int slot) { } @Override public boolean canOpenGui(EntityPlayer player) { if(hasOwnerRights(player)) return true; ChatUtils.sendServerNoSpamMessages(player, new TextComponentTranslation(Lib.CHAT_INFO+"notOwner", owner)); return false; } @Override public boolean canOpenGui() { return false; } @Override public int getGuiID() { return Lib.GUIID_Turret; } @Override public TileEntity getGuiMaster() { if(!dummy) return this; TileEntity te = worldObj.getTileEntity(getPos().down()); if(te instanceof TileEntityTurret) return te; return null; } @Override public EnumFacing getFacing() { return facing; } @Override public void setFacing(EnumFacing facing) { this.facing = facing; } @Override public int getFacingLimitation() { return 2; } @Override public boolean mirrorFacingOnPlacement(EntityLivingBase placer) { return false; } @Override public boolean canHammerRotate(EnumFacing side, float hitX, float hitY, float hitZ, EntityLivingBase entity) { return false; } @Override public boolean canRotate(EnumFacing axis) { return false; } @Override public boolean canEntityDestroy(Entity entity) { if(dummy) { TileEntity te = worldObj.getTileEntity(getPos().down()); if(te instanceof TileEntityTurret) return ((TileEntityTurret)te).canEntityDestroy(entity); } if(entity instanceof EntityPlayer) return hasOwnerRights((EntityPlayer)entity); return true; } @Override public boolean isDummy() { return dummy; } @Override public void placeDummies(BlockPos pos, IBlockState state, EnumFacing side, float hitX, float hitY, float hitZ) { worldObj.setBlockState(pos.up(), state); ((TileEntityTurret)worldObj.getTileEntity(pos.up())).dummy = true; ((TileEntityTurret)worldObj.getTileEntity(pos.up())).facing = facing; } @Override public void breakDummies(BlockPos pos, IBlockState state) { if(worldObj.getTileEntity(dummy?getPos().down():getPos().up()) instanceof TileEntityTurret) worldObj.setBlockToAir(dummy?getPos().down():getPos().up()); } @Override public ItemStack getTileDrop(EntityPlayer player, IBlockState state) { ItemStack stack = new ItemStack(state.getBlock(), 1, state.getBlock().getMetaFromState(state)); TileEntityTurret turret = this; if(dummy) { TileEntity t = worldObj.getTileEntity(getPos().down()); if(t instanceof TileEntityTurret) turret = (TileEntityTurret)t; else return stack; } NBTTagCompound tag = new NBTTagCompound(); //Only writing values when they are different from defaults if(turret.owner!=null && (player==null || !player.getName().equalsIgnoreCase(turret.owner))) tag.setString("owner", turret.owner); if(turret.targetList.size()!=1 || !isListedName(turret.targetList, turret.owner)) { NBTTagList list = new NBTTagList(); for(String s : turret.targetList) list.appendTag(new NBTTagString(s)); tag.setTag("targetList",list); } if(turret.whitelist) tag.setBoolean("whitelist",turret.whitelist); if(turret.attackAnimals) tag.setBoolean("attackAnimals",turret.attackAnimals); if(!turret.attackPlayers) tag.setBoolean("attackPlayers",turret.attackPlayers); if(turret.attackNeutrals) tag.setBoolean("attackNeutrals",turret.attackNeutrals); if(turret.redstoneControlInverted) tag.setBoolean("redstoneControlInverted",turret.redstoneControlInverted); if(!tag.hasNoTags()) stack.setTagCompound(tag); return stack; } @Override public void readOnPlacement(@Nullable EntityLivingBase placer, ItemStack stack) { if(stack.hasTagCompound()) { NBTTagCompound tag = stack.getTagCompound(); if(tag.hasKey("owner")) this.owner = tag.getString("owner"); else if(placer!=null) this.owner = placer.getName(); if(tag.hasKey("targetList")) { NBTTagList list = tag.getTagList("targetList", 8); targetList.clear(); for(int i=0; i<list.tagCount(); i++) targetList.add(list.getStringTagAt(i)); } else if(owner!=null) targetList.add(owner); if(tag.hasKey("whitelist")) whitelist = tag.getBoolean("whitelist"); if(tag.hasKey("attackAnimals")) attackAnimals = tag.getBoolean("attackAnimals"); if(tag.hasKey("attackPlayers")) attackPlayers = tag.getBoolean("attackPlayers"); if(tag.hasKey("attackNeutrals")) attackNeutrals = tag.getBoolean("attackNeutrals"); if(tag.hasKey("redstoneControlInverted")) redstoneControlInverted = tag.getBoolean("redstoneControlInverted"); } else if(placer!=null) { this.owner = placer.getName(); targetList.add(owner); } } @Nonnull @Override public FluxStorage getFluxStorage() { if(dummy) { TileEntity te = worldObj.getTileEntity(getPos().down()); if(te instanceof TileEntityTurret) return ((TileEntityTurret)te).getFluxStorage(); } return energyStorage; } @Nonnull @Override public SideConfig getEnergySideConfig(EnumFacing facing) { return !dummy?SideConfig.INPUT:SideConfig.NONE; } IEForgeEnergyWrapper[] wrappers = IEForgeEnergyWrapper.getDefaultWrapperArray(this); @Override public IEForgeEnergyWrapper getCapabilityWrapper(EnumFacing facing) { if(!dummy) return wrappers[facing==null?0:facing.ordinal()]; return null; } static ArrayList<String> displayList = Lists.newArrayList("base"); @Override public ArrayList<String> compileDisplayList() { return displayList; } }