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();
}
}