package pneumaticCraft.common.tileentity; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.ChunkPosition; import net.minecraft.world.WorldServer; import net.minecraftforge.common.util.FakePlayerFactory; import pneumaticCraft.common.ai.StringFilterEntitySelector; import pneumaticCraft.common.block.Blockss; import pneumaticCraft.common.item.ItemMachineUpgrade; import pneumaticCraft.common.item.Itemss; import pneumaticCraft.common.minigun.Minigun; import pneumaticCraft.common.network.DescSynced; import pneumaticCraft.common.network.GuiSynced; import pneumaticCraft.common.util.PneumaticCraftUtils; import com.mojang.authlib.GameProfile; public class TileEntitySentryTurret extends TileEntityBase implements IRedstoneControlled, ISidedInventory, IGUITextFieldSensitive{ private final ItemStack[] inventory = new ItemStack[8]; @GuiSynced private String entityFilter = ""; @GuiSynced private int redstoneMode; @DescSynced private int range; @DescSynced private boolean activated; @DescSynced private ItemStack minigunColorStack; private Minigun minigun; @DescSynced private int targetEntityId = -1; @DescSynced private boolean sweeping; private final SentryTurretEntitySelector entitySelector = new SentryTurretEntitySelector(); public TileEntitySentryTurret(){ setUpgradeSlots(0, 1, 2, 3); } @Override public void updateEntity(){ super.updateEntity(); if(!worldObj.isRemote) { range = 16 + Math.min(16, getUpgrades(ItemMachineUpgrade.UPGRADE_RANGE)); if(getMinigun().getAttackTarget() == null && redstoneAllows()) { getMinigun().setSweeping(true); if(worldObj.getTotalWorldTime() % 20 == 0) { List<EntityLivingBase> entities = worldObj.selectEntitiesWithinAABB(EntityLivingBase.class, getTargetingBoundingBox(), entitySelector); if(entities.size() > 0) { Collections.sort(entities, new TargetSorter()); getMinigun().setAttackTarget(entities.get(0)); targetEntityId = entities.get(0).getEntityId(); } } } else { getMinigun().setSweeping(false); } EntityLivingBase target = getMinigun().getAttackTarget(); if(target != null) { if(!redstoneAllows() || !entitySelector.isEntityApplicable(target)) { getMinigun().setAttackTarget(null); targetEntityId = -1; } else { if(worldObj.getTotalWorldTime() % 5 == 0) { getFakePlayer().setPosition(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5); //Make sure the knockback has the right direction. boolean usedAmmo = getMinigun().tryFireMinigun(target); if(usedAmmo) { for(int i = 4; i < inventory.length; i++) { if(inventory[i] != null) { setInventorySlotContents(i, null); break; } } } } } } } getMinigun().update(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5); } private boolean canSeeEntity(Entity entity){ Vec3 entityVec = Vec3.createVectorHelper(entity.posX + entity.width / 2, entity.posY + entity.height / 2, entity.posZ + entity.width / 2); Vec3 tileVec = Vec3.createVectorHelper(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5); MovingObjectPosition trace = worldObj.rayTraceBlocks(entityVec, tileVec); return trace != null && trace.blockX == xCoord && trace.blockY == yCoord && trace.blockZ == zCoord; } private AxisAlignedBB getTargetingBoundingBox(){ return AxisAlignedBB.getBoundingBox(xCoord - range, yCoord - range, zCoord - range, xCoord + range + 1, yCoord + range + 1, zCoord + range + 1); } @Override protected void onFirstServerUpdate(){ super.onFirstServerUpdate(); updateAmmo(); } @Override public void onDescUpdate(){ super.onDescUpdate(); Entity entity = worldObj.getEntityByID(targetEntityId); if(entity instanceof EntityLivingBase) { getMinigun().setAttackTarget((EntityLivingBase)entity); } else { getMinigun().setAttackTarget(null); } } public Minigun getMinigun(){ if(minigun == null) { minigun = new MinigunSentryTurret(); minigun.setWorld(worldObj); if(worldObj != null && !worldObj.isRemote) { minigun.setPlayer(getFakePlayer()); } } return minigun; } private EntityPlayer getFakePlayer(){ return FakePlayerFactory.get((WorldServer)worldObj, new GameProfile(null, "Sentry Turret")); } @Override public void writeToNBT(NBTTagCompound tag){ super.writeToNBT(tag); writeInventoryToNBT(tag, inventory); tag.setByte("redstoneMode", (byte)redstoneMode); tag.setString("entityFilter", entityFilter); } @Override public void readFromNBT(NBTTagCompound tag){ super.readFromNBT(tag); readInventoryFromNBT(tag, inventory); redstoneMode = tag.getByte("redstoneMode"); setText(0, tag.getString("entityFilter")); } @Override public boolean redstoneAllows(){ if(redstoneMode == 3) return true; return super.redstoneAllows(); } @Override public int getRedstoneMode(){ return redstoneMode; } @Override public void handleGUIButtonPress(int buttonID, EntityPlayer player){ if(buttonID == 0) { redstoneMode++; if(redstoneMode > 2) redstoneMode = 0; } } /* * ---------------IInventory--------------------- */ /** * Returns the name of the inventory. */ @Override public String getInventoryName(){ return Blockss.sentryTurret.getUnlocalizedName(); } /** * Returns the number of slots in the inventory. */ @Override public int getSizeInventory(){ return inventory.length; } /** * Returns the stack in slot i */ @Override public ItemStack getStackInSlot(int par1){ return inventory[par1]; } @Override public ItemStack decrStackSize(int slot, int amount){ ItemStack itemStack = getStackInSlot(slot); if(itemStack != null) { if(itemStack.stackSize <= amount) { setInventorySlotContents(slot, null); } else { itemStack = itemStack.splitStack(amount); if(itemStack.stackSize == 0) { setInventorySlotContents(slot, null); } } } return itemStack; } @Override public ItemStack getStackInSlotOnClosing(int slot){ ItemStack itemStack = getStackInSlot(slot); if(itemStack != null) { setInventorySlotContents(slot, null); } return itemStack; } @Override public void setInventorySlotContents(int slot, ItemStack itemStack){ inventory[slot] = itemStack; if(itemStack != null && itemStack.stackSize > getInventoryStackLimit()) { itemStack.stackSize = getInventoryStackLimit(); } if(slot >= 4) { updateAmmo(); } } private void updateAmmo(){ ItemStack ammo = null; for(int i = 4; i < inventory.length; i++) { if(inventory[i] != null) { ammo = inventory[i]; break; } } getMinigun().setAmmo(ammo); } @Override public boolean isItemValidForSlot(int slot, ItemStack stack){ if(slot < 4) { return stack != null && stack.getItem() == Itemss.machineUpgrade; } else { return stack != null && stack.getItem() == Itemss.gunAmmo; } } @Override public boolean hasCustomInventoryName(){ return false; } @Override public int getInventoryStackLimit(){ return 64; } @Override public boolean isUseableByPlayer(EntityPlayer p_70300_1_){ return isGuiUseableByPlayer(p_70300_1_); } @Override public void openInventory(){} @Override public void closeInventory(){} @Override public int[] getAccessibleSlotsFromSide(int p_94128_1_){ return new int[]{0, 1, 2, 3, 4, 5, 6, 7}; } @Override public boolean canInsertItem(int slot, ItemStack stack, int side){ return isItemValidForSlot(slot, stack); } @Override public boolean canExtractItem(int slot, ItemStack stack, int side){ return true; } private class MinigunSentryTurret extends Minigun{ public MinigunSentryTurret(){ super(true); } @Override public boolean isMinigunActivated(){ return activated; } @Override public void setMinigunActivated(boolean activated){ TileEntitySentryTurret.this.activated = activated; } @Override public void setAmmoColorStack(ItemStack ammo){ minigunColorStack = ammo; } @Override public int getAmmoColor(){ return getAmmoColor(minigunColorStack); } @Override public void playSound(String soundName, float volume, float pitch){ worldObj.playSoundEffect(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, soundName, volume, pitch); } @Override public void setSweeping(boolean sweeping){ TileEntitySentryTurret.this.sweeping = sweeping; } @Override public boolean isSweeping(){ return sweeping; } } private class TargetSorter implements Comparator<Entity>{ private final ChunkPosition pos; public TargetSorter(){ pos = new ChunkPosition(xCoord, yCoord, zCoord); } @Override public int compare(Entity arg0, Entity arg1){ double dist1 = PneumaticCraftUtils.distBetween(pos, arg0.posX, arg0.posY, arg0.posZ); double dist2 = PneumaticCraftUtils.distBetween(pos, arg1.posX, arg1.posY, arg1.posZ); return Double.compare(dist1, dist2); } } private class SentryTurretEntitySelector extends StringFilterEntitySelector{ @Override public boolean isEntityApplicable(Entity entity){ if(entity instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer)entity; if(player.capabilities.isCreativeMode || isExcludedBySecurityStations(player)) return false; } return super.isEntityApplicable(entity) && inRange(entity) && canSeeEntity(entity); } private boolean inRange(Entity entity){ return PneumaticCraftUtils.distBetween(new ChunkPosition(xCoord, yCoord, zCoord), entity.posX, entity.posY, entity.posZ) <= range; } private boolean isExcludedBySecurityStations(EntityPlayer player){ Iterator<TileEntitySecurityStation> iterator = PneumaticCraftUtils.getSecurityStations(worldObj, xCoord, yCoord, zCoord, false).iterator(); if(iterator.hasNext()) { //When there are Security Stations, all stations need to be allowing the player. while(iterator.hasNext()) { if(!iterator.next().doesAllowPlayer(player)) return false; } return true; } else { return false; //When there are no Security Stations at all, the player isn't automatically 'allowed to live'. } } } @Override public void setText(int textFieldID, String text){ entityFilter = text; entitySelector.setFilter(text); if(minigun != null) minigun.setAttackTarget(null); } @Override public String getText(int textFieldID){ return entityFilter; } @Override public AxisAlignedBB getRenderBoundingBox(){ return getTargetingBoundingBox(); } }