package pneumaticCraft.common.entity.living;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.ai.EntityAITasks;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.item.EntityXPOrb;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryBasic;
import net.minecraft.item.ItemDye;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.client.C15PacketClientSettings;
import net.minecraft.pathfinding.PathEntity;
import net.minecraft.pathfinding.PathPoint;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.ItemInWorldManager;
import net.minecraft.stats.StatBase;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.ChunkCoordinates;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.Vec3;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.IExtendedEntityProperties;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.IFluidTank;
import org.lwjgl.opengl.GL11;
import pneumaticCraft.api.block.IPneumaticWrenchable;
import pneumaticCraft.api.client.pneumaticHelmet.IHackableEntity;
import pneumaticCraft.api.drone.IPathNavigator;
import pneumaticCraft.api.drone.IPathfindHandler;
import pneumaticCraft.api.tileentity.IManoMeasurable;
import pneumaticCraft.client.render.RenderProgressingLine;
import pneumaticCraft.common.NBTUtil;
import pneumaticCraft.common.PneumaticCraftAPIHandler;
import pneumaticCraft.common.ai.DroneAIManager;
import pneumaticCraft.common.ai.DroneAIManager.EntityAITaskEntry;
import pneumaticCraft.common.ai.DroneGoToChargingStation;
import pneumaticCraft.common.ai.DroneGoToOwner;
import pneumaticCraft.common.ai.DroneMoveHelper;
import pneumaticCraft.common.ai.EntityPathNavigateDrone;
import pneumaticCraft.common.ai.FakePlayerItemInWorldManager;
import pneumaticCraft.common.ai.IDroneBase;
import pneumaticCraft.common.block.Blockss;
import pneumaticCraft.common.config.Config;
import pneumaticCraft.common.item.ItemGPSTool;
import pneumaticCraft.common.item.ItemMachineUpgrade;
import pneumaticCraft.common.item.ItemProgrammingPuzzle;
import pneumaticCraft.common.item.Itemss;
import pneumaticCraft.common.minigun.Minigun;
import pneumaticCraft.common.network.NetworkHandler;
import pneumaticCraft.common.network.PacketSendDroneDebugEntry;
import pneumaticCraft.common.network.PacketShowWireframe;
import pneumaticCraft.common.network.PacketSyncDroneEntityProgWidgets;
import pneumaticCraft.common.progwidgets.IProgWidget;
import pneumaticCraft.common.progwidgets.ProgWidgetGoToLocation;
import pneumaticCraft.common.recipes.AmadronOffer;
import pneumaticCraft.common.recipes.AmadronOfferCustom;
import pneumaticCraft.common.tileentity.TileEntityPlasticMixer;
import pneumaticCraft.common.tileentity.TileEntityProgrammer;
import pneumaticCraft.common.util.PneumaticCraftUtils;
import pneumaticCraft.lib.NBTKeys;
import pneumaticCraft.lib.PneumaticValues;
import com.mojang.authlib.GameProfile;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
import cpw.mods.fml.relauncher.ReflectionHelper;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class EntityDrone extends EntityDroneBase implements IManoMeasurable, IInventoryHolder, IPneumaticWrenchable,
IEntityAdditionalSpawnData, IHackableEntity, IDroneBase{
private static final HashMap<String, Integer> colorMap = new HashMap<String, Integer>();
static {
colorMap.put("aureylian", 0xff69b4);
colorMap.put("loneztar", 0x00a0a0);
colorMap.put("jadedcat", 0xa020f0);
}
public boolean isChangingCurrentStack;//used when syncing up the stacks of the drone with the fake player. Without it they'll keep syncing resulting in a stackoverflow.
private IInventory inventory = new InventoryDrone("Drone Inventory", true, 0);
private final FluidTank tank = new FluidTank(Integer.MAX_VALUE);
private ItemStack[] upgradeInventory = new ItemStack[9];
private final int[] emittingRedstoneValues = new int[6];
private float propSpeed;
private static final float LASER_EXTEND_SPEED = 0.05F;
protected float currentAir; //the current held energy of the Drone;
private float volume;
private RenderProgressingLine targetLine;
private RenderProgressingLine oldTargetLine;
public List<IProgWidget> progWidgets = new ArrayList<IProgWidget>();
private DroneFakePlayer fakePlayer;
public String playerName = "Drone";
private String playerUUID;
public DroneGoToChargingStation chargeAI;
public DroneGoToOwner gotoOwnerAI;
private final DroneAIManager aiManager = new DroneAIManager(this);
private boolean firstTick = true;
public boolean naturallySpawned = true;//determines if it should drop a drone when it dies.
public boolean hasLiquidImmunity;
private double speed;
private int lifeUpgrades;
private int suffocationCounter = 40;//Drones are invincible for suffocation for this time.
private boolean isSuffocating;
private boolean disabledByHacking;
private boolean standby;//If true, the drone's propellors stop, the drone will fall down, and won't use pressure.
private Minigun minigun;
private AmadronOffer handlingOffer;
private int offerTimes;
private ItemStack usedTablet;//Tablet used to place the order.
private String buyingPlayer;
private final SortedSet<DebugEntry> debugEntries = new TreeSet<DebugEntry>();
private final Set<EntityPlayerMP> syncedPlayers = new HashSet<EntityPlayerMP>();
public EntityDrone(World world){
super(world);
setSize(0.7F, 0.35F);
ReflectionHelper.setPrivateValue(EntityLiving.class, this, new EntityPathNavigateDrone(this, world), "navigator", "field_70699_by");
ReflectionHelper.setPrivateValue(EntityLiving.class, this, new DroneMoveHelper(this), "moveHelper", "field_70765_h");
tasks.addTask(1, chargeAI = new DroneGoToChargingStation(this));
}
public EntityDrone(World world, EntityPlayer player){
this(world);
playerUUID = player.getGameProfile().getId().toString();
playerName = player.getCommandSenderName();
}
private void initializeFakePlayer(){
fakePlayer = new DroneFakePlayer((WorldServer)worldObj, new GameProfile(playerUUID != null ? UUID.fromString(playerUUID) : null, playerName), new FakePlayerItemInWorldManager(worldObj, fakePlayer, this), this);
fakePlayer.playerNetServerHandler = new NetHandlerPlayServer(MinecraftServer.getServer(), new NetworkManager(false), fakePlayer);
fakePlayer.inventory = new InventoryFakePlayer(fakePlayer);
}
@Override
protected void entityInit(){
super.entityInit();
dataWatcher.addObject(12, 0F);
dataWatcher.addObject(13, (byte)0);
dataWatcher.addObject(14, 0);
dataWatcher.addObject(15, 0);
dataWatcher.addObject(16, 0);
dataWatcher.addObject(17, "");
dataWatcher.addObject(18, 0);
dataWatcher.addObject(19, 0);
dataWatcher.addObject(20, 0);
dataWatcher.addObject(21, (byte)0);
dataWatcher.addObject(22, 0);
dataWatcher.addObject(23, (byte)0);
dataWatcher.addObject(24, (byte)0);
dataWatcher.addObjectByDataType(25, 5);
dataWatcher.addObject(26, "Main");
dataWatcher.addObject(27, 0);
}
@Override
protected void applyEntityAttributes(){
super.applyEntityAttributes();
getAttributeMap().registerAttribute(SharedMonsterAttributes.attackDamage).setBaseValue(3.0D);
getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(40F);
getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(getRange());
}
@Override
public void writeSpawnData(ByteBuf data){
ByteBufUtils.writeUTF8String(data, getFakePlayer().getCommandSenderName());
}
@Override
public void readSpawnData(ByteBuf data){
playerName = ByteBufUtils.readUTF8String(data);
}
/**
* Determines if an entity can be despawned, used on idle far away entities
*/
@Override
protected boolean canDespawn(){
return false;
}
@Override
protected float getSoundVolume(){
return 0.2F;
}
@Override
protected String getHurtSound(){
return "pneumaticcraft:drone.hurt";
}
/**
* Returns the sound this mob makes on death.
*/
@Override
protected String getDeathSound(){
return "pneumaticcraft:drone.death";
}
@Override
public void onUpdate(){
if(firstTick) {
firstTick = false;
volume = PneumaticValues.DRONE_VOLUME + getUpgrades(ItemMachineUpgrade.UPGRADE_VOLUME_DAMAGE) * PneumaticValues.VOLUME_VOLUME_UPGRADE;
hasLiquidImmunity = getUpgrades(ItemMachineUpgrade.UPGRADE_SECURITY) > 0;
if(hasLiquidImmunity) {
((EntityPathNavigateDrone)getPathNavigator()).pathThroughLiquid = true;
}
speed = 0.1 + Math.min(10, getUpgrades(ItemMachineUpgrade.UPGRADE_SPEED_DAMAGE)) * 0.01;
lifeUpgrades = getUpgrades(ItemMachineUpgrade.UPGRADE_ITEM_LIFE);
if(!worldObj.isRemote) setHasMinigun(getUpgrades(ItemMachineUpgrade.UPGRADE_ENTITY_TRACKER) > 0);
aiManager.setWidgets(progWidgets);
}
boolean enabled = !disabledByHacking && getPressure(null) > 0.01F;
if(!worldObj.isRemote) {
setAccelerating(!standby && enabled);
if(isAccelerating()) {
fallDistance = 0;
}
if(lifeUpgrades > 0) {
int interval = 10 / lifeUpgrades;
if(interval == 0 || ticksExisted % interval == 0) {
heal(1);
}
}
if(!isSuffocating) {
suffocationCounter = 40;
}
isSuffocating = false;
PathEntity path = getNavigator().getPath();
if(path != null) {
PathPoint target = path.getFinalPathPoint();
if(target != null) {
setTargetedBlock(target.xCoord, target.yCoord, target.zCoord);
} else {
setTargetedBlock(0, 0, 0);
}
} else {
setTargetedBlock(0, 0, 0);
}
if(worldObj.getTotalWorldTime() % 20 == 0) {
updateSyncedPlayers();
}
} else {
if(digLaser != null) digLaser.update();
oldLaserExtension = laserExtension;
if(getActiveProgramKey().equals("dig")) {
laserExtension = Math.min(1, laserExtension + LASER_EXTEND_SPEED);
} else {
laserExtension = Math.max(0, laserExtension - LASER_EXTEND_SPEED);
}
if(isAccelerating()) {
int x = (int)Math.floor(posX);
int y = (int)Math.floor(posY - 1);
int z = (int)Math.floor(posZ);
Block block = null;
for(int i = 0; i < 3; i++) {
block = worldObj.getBlock(x, y, z);
if(block.getMaterial() != Material.air) break;
y--;
}
if(block.getMaterial() != Material.air) {
Vec3 vec = Vec3.createVectorHelper(posY - y, 0, 0);
vec.rotateAroundY((float)(rand.nextFloat() * Math.PI * 2));
worldObj.spawnParticle("blockcrack_" + Block.getIdFromBlock(block) + "_" + worldObj.getBlockMetadata(x, y, z), posX + vec.xCoord, y + 1, posZ + vec.zCoord, vec.xCoord, 0, vec.zCoord);
}
}
}
if(hasLiquidImmunity) {
for(int x = (int)posX - 1; x <= (int)(posX + width); x++) {
for(int y = (int)posY - 1; y <= (int)(posY + height + 1); y++) {
for(int z = (int)posZ - 2; z <= (int)(posZ + width); z++) {
if(PneumaticCraftUtils.isBlockLiquid(worldObj.getBlock(x, y, z))) {
worldObj.setBlock(x, y, z, Blocks.air, 0, 2);
}
}
}
}
}
if(isAccelerating()) {
motionX *= 0.3D;
motionY *= 0.3D;
motionZ *= 0.3D;
propSpeed = Math.min(1, propSpeed + 0.04F);
addAir(null, -1);
} else {
propSpeed = Math.max(0, propSpeed - 0.04F);
}
oldPropRotation = propRotation;
propRotation += propSpeed;
if(!worldObj.isRemote && isEntityAlive()/*((FakePlayerItemInWorldManager)fakePlayer.theItemInWorldManager).isDigging()*/) {
for(int i = 0; i < 4; i++) {
getFakePlayer().theItemInWorldManager.updateBlockRemoving();
}
}
super.onUpdate();
if(hasMinigun()) getMinigun().setAttackTarget(getAttackTarget()).update(posX, posY, posZ);
if(!worldObj.isRemote && isEntityAlive()) {
if(enabled) aiManager.onUpdateTasks();
for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
if(getEmittingRedstone(d) > 0) {
if(worldObj.isAirBlock((int)Math.floor(posX + width / 2), (int)Math.floor(posY), (int)Math.floor(posZ + width / 2))) {
worldObj.setBlock((int)Math.floor(posX + width / 2), (int)Math.floor(posY), (int)Math.floor(posZ + width / 2), Blockss.droneRedstoneEmitter);
}
break;
}
}
}
}
public ChunkPosition getTargetedBlock(){
int x = dataWatcher.getWatchableObjectInt(14);
int y = dataWatcher.getWatchableObjectInt(15);
int z = dataWatcher.getWatchableObjectInt(16);
return x != 0 || y != 0 || z != 0 ? new ChunkPosition(x, y, z) : null;
}
private void setTargetedBlock(int x, int y, int z){
dataWatcher.updateObject(14, x);
dataWatcher.updateObject(15, y);
dataWatcher.updateObject(16, z);
}
@Override
public int getLaserColor(){
if(colorMap.containsKey(getCustomNameTag().toLowerCase())) {
return colorMap.get(getCustomNameTag().toLowerCase());
} else if(colorMap.containsKey(playerName.toLowerCase())) {
return colorMap.get(playerName.toLowerCase());
}
return super.getLaserColor();
}
@Override
protected ChunkPosition getDugBlock(){
int x = dataWatcher.getWatchableObjectInt(18);
int y = dataWatcher.getWatchableObjectInt(19);
int z = dataWatcher.getWatchableObjectInt(20);
return x != 0 || y != 0 || z != 0 ? new ChunkPosition(x, y, z) : null;
}
@Override
public void setDugBlock(int x, int y, int z){
dataWatcher.updateObject(18, x);
dataWatcher.updateObject(19, y);
dataWatcher.updateObject(20, z);
}
public List<EntityAITaskEntry> getRunningTasks(){
return aiManager.getRunningTasks();
}
public EntityAIBase getRunningTargetAI(){
return aiManager.getTargetAI();
}
public void setVariable(String varName, ChunkPosition pos){
aiManager.setCoordinate(varName, pos);
}
public ChunkPosition getVariable(String varName){
return aiManager.getCoordinate(varName);
}
public ItemStack getActiveProgram(){
String key = getActiveProgramKey();
if(key.equals("")) {
return null;
} else {
return ItemProgrammingPuzzle.getStackForWidgetKey(key);
}
}
private String getActiveProgramKey(){
return dataWatcher.getWatchableObjectString(17);
}
/**
* Can only be called when the drone is being debugged, so the client has a synced progWidgets array.
* @return
*/
public IProgWidget getActiveWidget(){
int index = getActiveWidgetIndex();
if(index >= 0 && index < progWidgets.size()) {
return progWidgets.get(index);
} else {
return null;
}
}
private int getActiveWidgetIndex(){
return dataWatcher.getWatchableObjectInt(27);
}
@Override
public void setActiveProgram(IProgWidget widget){
dataWatcher.updateObject(17, widget.getWidgetString());
dataWatcher.updateObject(27, progWidgets.indexOf(widget));
}
private void setAccelerating(boolean accelerating){
dataWatcher.updateObject(13, (byte)(accelerating ? 1 : 0));
}
@Override
public boolean isAccelerating(){
return dataWatcher.getWatchableObjectByte(13) == 1;
}
private void setDroneColor(int color){
dataWatcher.updateObject(22, color);
}
@Override
public int getDroneColor(){
return dataWatcher.getWatchableObjectInt(22);
}
public void setMinigunActivated(boolean activated){
dataWatcher.updateObject(23, (byte)(activated ? 1 : 0));
}
public boolean isMinigunActivated(){
return dataWatcher.getWatchableObjectByte(23) == 1;
}
public void setHasMinigun(boolean hasMinigun){
dataWatcher.updateObject(24, (byte)(hasMinigun ? 1 : 0));
}
public boolean hasMinigun(){
return dataWatcher.getWatchableObjectByte(24) == 1;
}
public int getAmmoColor(){
ItemStack ammo = dataWatcher.getWatchableObjectItemStack(25);
return ammo != null ? ammo.getItem().getColorFromItemStack(ammo, 1) : 0xFF313131;
}
public void setAmmoColor(ItemStack color){
dataWatcher.updateObject(25, color);
}
/**
* Returns true if the newer Entity AI code should be run
*/
@Override
public boolean isAIEnabled(){
return true;
}
/**
* Decrements the entity's air supply when underwater
*/
@Override
protected int decreaseAirSupply(int par1){
return -20;//make drones insta drown.
}
/**
* Moves the entity based on the specified heading. Args: strafe, forward
*/
@Override
public void moveEntityWithHeading(float par1, float par2){
if(worldObj.isRemote) {
EntityLivingBase targetEntity = getAttackTarget();
if(targetEntity != null) {
if(targetLine == null) targetLine = new RenderProgressingLine(0, -height / 2, 0, 0, 0, 0);
if(oldTargetLine == null) oldTargetLine = new RenderProgressingLine(0, -height / 2, 0, 0, 0, 0);
targetLine.endX = targetEntity.posX - posX;
targetLine.endY = targetEntity.posY + targetEntity.height / 2 - posY;
targetLine.endZ = targetEntity.posZ - posZ;
oldTargetLine.endX = targetEntity.prevPosX - prevPosX;
oldTargetLine.endY = targetEntity.prevPosY + targetEntity.height / 2 - prevPosY;
oldTargetLine.endZ = targetEntity.prevPosZ - prevPosZ;
oldTargetLine.setProgress(targetLine.getProgress());
targetLine.incProgressByDistance(0.3D);
ignoreFrustumCheck = true; //don't stop rendering the drone when it goes out of the camera frustrum, as we need to render the target lines as well.
} else {
ignoreFrustumCheck = false; //don't stop rendering the drone when it goes out of the camera frustrum, as we need to render the target lines as well.
}
}
if(ridingEntity == null && isAccelerating()) {
double d3 = motionY;
super.moveEntityWithHeading(par1, par2);
motionY = d3 * 0.60D;
} else {
super.moveEntityWithHeading(par1, par2);
}
onGround = true;//set onGround to true so AI pathfinding will keep updating.
}
/**
* Method that's being called to render anything that has to for the Drone. The matrix is already translated to the drone's position.
* @param partialTicks
*/
@Override
@SideOnly(Side.CLIENT)
public void renderExtras(double transX, double transY, double transZ, float partialTicks){
if(targetLine != null && oldTargetLine != null) {
GL11.glPushMatrix();
GL11.glScaled(1, -1, 1);
GL11.glDisable(GL11.GL_TEXTURE_2D);
//GL11.glDisable(GL11.GL_LIGHTING);
GL11.glColor4d(1, 0, 0, 1);
targetLine.renderInterpolated(oldTargetLine, partialTicks);
GL11.glColor4d(1, 1, 1, 1);
// GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glPopMatrix();
}
double x = lastTickPosX + (posX - lastTickPosX) * partialTicks;
double y = lastTickPosY + (posY - lastTickPosY) * partialTicks;
double z = lastTickPosZ + (posZ - lastTickPosZ) * partialTicks;
getMinigun().render(x, y, z, 0.6);
}
public double getRange(){
return 75;
}
@Override
public boolean interact(EntityPlayer player){
ItemStack equippedItem = player.getCurrentEquippedItem();
if(!worldObj.isRemote && equippedItem != null) {
if(equippedItem.getItem() == Itemss.GPSTool) {
ChunkPosition gpsLoc = ItemGPSTool.getGPSLocation(equippedItem);
if(gpsLoc != null) {
getNavigator().tryMoveToXYZ(gpsLoc.chunkPosX, gpsLoc.chunkPosY, gpsLoc.chunkPosZ, 0.1D);
}
} else {
int dyeIndex = TileEntityPlasticMixer.getDyeIndex(equippedItem);
if(dyeIndex >= 0) {
setDroneColor(ItemDye.field_150922_c[dyeIndex]);
equippedItem.stackSize--;
if(equippedItem.stackSize <= 0) {
player.setCurrentItemOrArmor(0, null);
}
}
}
}
return false;
}
/**
* Called when a drone is hit by a Pneumatic Wrench.
*/
@Override
public boolean rotateBlock(World world, EntityPlayer player, int x, int y, int z, ForgeDirection side){
if(!naturallySpawned) {
if(player.capabilities.isCreativeMode) naturallySpawned = true;//don't drop the drone in creative.
attackEntityFrom(DamageSource.outOfWorld, 2000.0F);
return true;
} else {
return false;
}
}
@Override
public void onDeath(DamageSource par1DamageSource){
for(int i = 0; i < inventory.getSizeInventory(); i++) {
if(inventory.getStackInSlot(i) != null) {
entityDropItem(inventory.getStackInSlot(i), 0);
inventory.setInventorySlotContents(i, null);
}
}
if(naturallySpawned) {
} else {
ItemStack drone = getDroppedStack();
if(hasCustomNameTag()) drone.setStackDisplayName(getCustomNameTag());
entityDropItem(drone, 0);
if(!worldObj.isRemote) {
EntityPlayer owner = getOwner();
if(owner != null) {
int x = (int)Math.floor(posX);
int y = (int)Math.floor(posY);
int z = (int)Math.floor(posZ);
if(hasCustomNameTag()) {
owner.addChatComponentMessage(new ChatComponentTranslation("death.drone.named", getCustomNameTag(), x, y, z));
} else {
owner.addChatComponentMessage(new ChatComponentTranslation("death.drone", x, y, z));
}
}
}
}
if(!worldObj.isRemote) ((FakePlayerItemInWorldManager)getFakePlayer().theItemInWorldManager).cancelDigging();
super.onDeath(par1DamageSource);
}
protected ItemStack getDroppedStack(){
NBTTagCompound tag = new NBTTagCompound();
writeEntityToNBT(tag);
tag.setTag("UpgradeInventory", tag.getTag("Inventory"));
tag.removeTag("Inventory");
ItemStack drone = new ItemStack(Itemss.drone);
drone.setTagCompound(tag);
return drone;
}
@Override
public void setAttackTarget(EntityLivingBase entity){
super.setAttackTarget(entity);
if(worldObj.isRemote && targetLine != null && oldTargetLine != null) {
targetLine.setProgress(0);
oldTargetLine.setProgress(0);
}
}
@Override
public float getPressure(ItemStack iStack){
return dataWatcher.getWatchableObjectFloat(12);
}
@Override
public void addAir(ItemStack iStack, int amount){
if(!worldObj.isRemote) {
currentAir += amount;
dataWatcher.updateObject(12, currentAir / volume);
}
}
@Override
public float maxPressure(ItemStack iStack){
return PneumaticValues.DRONE_MAX_PRESSURE;
}
@Override
public void printManometerMessage(EntityPlayer player, List<String> curInfo){
if(hasCustomNameTag()) curInfo.add(EnumChatFormatting.AQUA + getCustomNameTag());
curInfo.add("Owner: " + getFakePlayer().getCommandSenderName());
curInfo.add("Current pressure: " + PneumaticCraftUtils.roundNumberTo(getPressure(null), 1) + " bar.");
/*for(int i = 0; i < 9; i++) {
if(upgradeInventory[i] != null) {
player.addChatMessage("inv " + i + ": " + upgradeInventory[i].stackSize + "x " + upgradeInventory[i].getDisplayName());
}
}*/
}
@Override
public void writeEntityToNBT(NBTTagCompound tag){
super.writeEntityToNBT(tag);
TileEntityProgrammer.setWidgetsToNBT(progWidgets, tag);
tag.setBoolean("naturallySpawned", naturallySpawned);
tag.setFloat("currentAir", currentAir);
tag.setFloat("propSpeed", propSpeed);
tag.setBoolean("disabledByHacking", disabledByHacking);
tag.setBoolean("hackedByOwner", gotoOwnerAI != null);
tag.setInteger("color", getDroneColor());
tag.setBoolean("standby", standby);
tag.setFloat("volume", volume);
NBTTagCompound variableTag = new NBTTagCompound();
aiManager.writeToNBT(variableTag);
tag.setTag("variables", variableTag);
NBTTagCompound inv = new NBTTagCompound();
// Write the ItemStacks in the inventory to NBT
NBTTagList tagList = new NBTTagList();
for(int currentIndex = 0; currentIndex < inventory.getSizeInventory(); ++currentIndex) {
if(inventory.getStackInSlot(currentIndex) != null) {
NBTTagCompound tagCompound = new NBTTagCompound();
tagCompound.setByte("Slot", (byte)currentIndex);
inventory.getStackInSlot(currentIndex).writeToNBT(tagCompound);
tagList.appendTag(tagCompound);
}
}
inv.setTag("Inv", tagList);
NBTTagList upgradeList = new NBTTagList();
for(int i = 0; i < 9; i++) {
if(upgradeInventory[i] != null) {
NBTTagCompound slotEntry = new NBTTagCompound();
slotEntry.setByte("Slot", (byte)i);
upgradeInventory[i].writeToNBT(slotEntry);
upgradeList.appendTag(slotEntry);
}
}
// save content in Inventory->Items
inv.setTag("Items", upgradeList);
tag.setTag("Inventory", inv);
tank.writeToNBT(tag);
if(handlingOffer != null) {
NBTTagCompound subTag = new NBTTagCompound();
subTag.setBoolean("isCustom", handlingOffer instanceof AmadronOfferCustom);
handlingOffer.writeToNBT(subTag);
tag.setTag("amadronOffer", subTag);
tag.setInteger("offerTimes", offerTimes);
if(usedTablet != null) usedTablet.writeToNBT(subTag);
tag.setString("buyingPlayer", buyingPlayer);
}
}
@Override
public void readEntityFromNBT(NBTTagCompound tag){
super.readEntityFromNBT(tag);
progWidgets = TileEntityProgrammer.getWidgetsFromNBT(tag);
naturallySpawned = tag.getBoolean("naturallySpawned");
currentAir = tag.getFloat("currentAir");
volume = tag.getFloat("volume");
dataWatcher.updateObject(12, currentAir / volume);
propSpeed = tag.getFloat("propSpeed");
disabledByHacking = tag.getBoolean("disabledByHacking");
setGoingToOwner(tag.getBoolean("hackedByOwner"));
setDroneColor(tag.getInteger("color"));
aiManager.readFromNBT(tag.getCompoundTag("variables"));
standby = tag.getBoolean("standby");
// Read in the ItemStacks in the inventory from NBT
NBTTagCompound inv = tag.getCompoundTag("Inventory");
if(inv != null) {
NBTTagList tagList = inv.getTagList("Inv", 10);
upgradeInventory = new ItemStack[9];
NBTTagList upgradeList = inv.getTagList("Items", 10);
for(int i = 0; i < upgradeList.tagCount(); i++) {
NBTTagCompound slotEntry = upgradeList.getCompoundTagAt(i);
int j = slotEntry.getByte("Slot");
if(j >= 0 && j < 9) {
upgradeInventory[j] = ItemStack.loadItemStackFromNBT(slotEntry);
}
}
inventory = new InventoryDrone("Drone Inventory", true, 1 + getUpgrades(ItemMachineUpgrade.UPGRADE_DISPENSER_DAMAGE));
for(int i = 0; i < tagList.tagCount(); ++i) {
NBTTagCompound tagCompound = tagList.getCompoundTagAt(i);
byte slot = tagCompound.getByte("Slot");
if(slot >= 0 && slot < inventory.getSizeInventory()) {
inventory.setInventorySlotContents(slot, ItemStack.loadItemStackFromNBT(tagCompound));
}
}
}
tank.setCapacity(PneumaticValues.DRONE_TANK_SIZE * (1 + getUpgrades(ItemMachineUpgrade.UPGRADE_DISPENSER_DAMAGE)));
tank.readFromNBT(tag);
if(tag.hasKey("amadronOffer")) {
NBTTagCompound subTag = tag.getCompoundTag("amadronOffer");
if(subTag.getBoolean("isCustom")) {
handlingOffer = AmadronOffer.loadFromNBT(subTag);
} else {
handlingOffer = AmadronOfferCustom.loadFromNBT(subTag);
}
if(subTag.hasKey("id")) {
usedTablet = ItemStack.loadItemStackFromNBT(subTag);
} else {
usedTablet = null;
}
buyingPlayer = subTag.getString("buyingPlayer");
} else {
handlingOffer = null;
usedTablet = null;
buyingPlayer = null;
}
offerTimes = tag.getInteger("offerTimes");
}
/**
* This and readFromNBT are _not_ being transfered from/to the Drone item.
*/
@Override
public void writeToNBT(NBTTagCompound tag){
super.writeToNBT(tag);
if(fakePlayer != null) {
tag.setString("owner", fakePlayer.getCommandSenderName());
if(fakePlayer.getGameProfile().getId() != null) tag.setString("ownerUUID", fakePlayer.getGameProfile().getId().toString());
}
}
@Override
public void readFromNBT(NBTTagCompound tag){
super.readFromNBT(tag);
if(tag.hasKey("owner")) {
playerName = tag.getString("owner");
playerUUID = tag.hasKey("ownerUUID") ? tag.getString("ownerUUID") : null;
}
}
@Override
public int getUpgrades(int upgradeDamage){
int upgrades = 0;
for(ItemStack stack : upgradeInventory) {
if(stack != null && stack.getItem() == Itemss.machineUpgrade && stack.getItemDamage() == upgradeDamage) {
upgrades += stack.stackSize;
}
}
return upgrades;
}
@Override
public DroneFakePlayer getFakePlayer(){
if(fakePlayer == null && !worldObj.isRemote) {
initializeFakePlayer();
}
return fakePlayer;
}
public Minigun getMinigun(){
if(minigun == null) {
minigun = new MinigunDrone().setPlayer(getFakePlayer()).setWorld(worldObj).setPressurizable(this, PneumaticValues.DRONE_USAGE_ATTACK);
}
return minigun;
}
@Override
public boolean attackEntityAsMob(Entity entity){
getFakePlayer().attackTargetEntityWithCurrentItem(entity);
addAir(null, -PneumaticValues.DRONE_USAGE_ATTACK);
return true;
}
@Override
public boolean attackEntityFrom(DamageSource damageSource, float damage){
if(damageSource == DamageSource.inWall) {
isSuffocating = true;
if(suffocationCounter-- > 0 || !Config.enableDroneSuffocationDamage) {
return false;
}
}
return super.attackEntityFrom(damageSource, damage);
}
@Override
public IInventory getInventory(){
return inventory;
}
public double getSpeed(){
return speed;
}
public int getEmittingRedstone(ForgeDirection side){
return emittingRedstoneValues[side.ordinal()];
}
@Override
public void setEmittingRedstone(ForgeDirection side, int value){
if(emittingRedstoneValues[side.ordinal()] != value) {
emittingRedstoneValues[side.ordinal()] = value;
worldObj.notifyBlocksOfNeighborChange((int)Math.floor(posX + width / 2), (int)Math.floor(posY), (int)Math.floor(posZ + width / 2), Blockss.droneRedstoneEmitter);
}
}
@Override
public boolean isBlockValidPathfindBlock(int x, int y, int z){
if(worldObj.isAirBlock(x, y, z)) return true;
Block block = worldObj.getBlock(x, y, z);
if(PneumaticCraftUtils.isBlockLiquid(block)) {
return hasLiquidImmunity;
}
if(block.getBlocksMovement(worldObj, x, y, z) && block != Blocks.ladder) return true;
if(PneumaticCraftAPIHandler.getInstance().pathfindableBlocks.containsKey(block)) {
IPathfindHandler pathfindHandler = PneumaticCraftAPIHandler.getInstance().pathfindableBlocks.get(block);
return pathfindHandler == null || pathfindHandler.canPathfindThrough(worldObj, x, y, z);
} else {
return false;
}
}
@Override
public void sendWireframeToClient(int x, int y, int z){
NetworkHandler.sendToAllAround(new PacketShowWireframe(this, x, y, z), worldObj);
}
private class InventoryDrone extends InventoryBasic{
ItemStack oldStack;
public InventoryDrone(String inventoryName, boolean isNameLocalized, int slots){
super(inventoryName, isNameLocalized, slots);
}
@Override
public void setInventorySlotContents(int slot, ItemStack stack){
super.setInventorySlotContents(slot, stack);
if(slot == 0 && !isChangingCurrentStack) {
isChangingCurrentStack = true;
getFakePlayer().inventory.setInventorySlotContents(slot, stack);
isChangingCurrentStack = false;
if(oldStack != null) {
getFakePlayer().getAttributeMap().removeAttributeModifiers(oldStack.getAttributeModifiers());
}
if(stack != null) {
getFakePlayer().getAttributeMap().applyAttributeModifiers(stack.getAttributeModifiers());
}
oldStack = stack;
}
}
}
private class InventoryFakePlayer extends InventoryPlayer{
public InventoryFakePlayer(EntityPlayer par1EntityPlayer){
super(par1EntityPlayer);
}
@Override
public void setInventorySlotContents(int slot, ItemStack stack){
super.setInventorySlotContents(slot, stack);
if(slot == 0 && !isChangingCurrentStack) {
isChangingCurrentStack = true;
getInventory().setInventorySlotContents(slot, stack);
isChangingCurrentStack = false;
}
}
}
public static class DroneFakePlayer extends EntityPlayerMP{
private final IDroneBase drone;
private boolean sneaking;
public DroneFakePlayer(WorldServer world, GameProfile name, ItemInWorldManager itemManager, IDroneBase drone){
super(FMLCommonHandler.instance().getMinecraftServerInstance(), world, name, itemManager);
this.drone = drone;
}
@Override
public void addExperience(int amount){
Vec3 pos = drone.getPosition();
EntityXPOrb orb = new EntityXPOrb(drone.getWorld(), pos.xCoord, pos.yCoord, pos.zCoord, amount);
drone.getWorld().spawnEntityInWorld(orb);
}
@Override
public void setCurrentItemOrArmor(int p_70062_1_, ItemStack p_70062_2_){
if(p_70062_1_ == 0) {
inventory.setInventorySlotContents(inventory.currentItem, p_70062_2_);
} else {
inventory.armorInventory[p_70062_1_ - 1] = p_70062_2_;
}
}
@Override
public boolean canCommandSenderUseCommand(int i, String s){
return false;
}
@Override
public ChunkCoordinates getPlayerCoordinates(){
return new ChunkCoordinates(0, 0, 0);
}
@Override
public void addChatComponentMessage(IChatComponent chatmessagecomponent){}
@Override
public void addStat(StatBase par1StatBase, int par2){}
@Override
public void openGui(Object mod, int modGuiId, World world, int x, int y, int z){}
@Override
public boolean isEntityInvulnerable(){
return true;
}
@Override
public boolean canAttackPlayer(EntityPlayer player){
return false;
}
@Override
public void onDeath(DamageSource source){
return;
}
@Override
public void onUpdate(){
return;
}
@Override
public void travelToDimension(int dim){
return;
}
@Override
public void func_147100_a(C15PacketClientSettings pkt){
return;
}
@Override
public boolean isSneaking(){
return sneaking;
}
@Override
public void setSneaking(boolean sneaking){
this.sneaking = sneaking;
}
}
/**
* IHackableEntity
*/
@Override
public String getId(){
return null;
}
@Override
public boolean canHack(Entity entity, EntityPlayer player){
return isAccelerating();
}
@Override
public void addInfo(Entity entity, List<String> curInfo, EntityPlayer player){
if(playerName.equals(player.getCommandSenderName())) {
if(isGoingToOwner()) {
curInfo.add("pneumaticHelmet.hacking.result.resumeTasks");
} else {
curInfo.add("pneumaticHelmet.hacking.result.callBack");
}
} else {
curInfo.add("pneumaticHelmet.hacking.result.disable");
}
}
@Override
public void addPostHackInfo(Entity entity, List<String> curInfo, EntityPlayer player){
if(playerName.equals(player.getCommandSenderName())) {
if(isGoingToOwner()) {
curInfo.add("pneumaticHelmet.hacking.finished.calledBack");
} else {
curInfo.add("pneumaticHelmet.hacking.finished.resumedTasks");
}
} else {
curInfo.add("pneumaticHelmet.hacking.finished.disabled");
}
}
@Override
public int getHackTime(Entity entity, EntityPlayer player){
return playerName.equals(player.getCommandSenderName()) ? 20 : 100;
}
@Override
public void onHackFinished(Entity entity, EntityPlayer player){
if(!worldObj.isRemote && player.getGameProfile().equals(getFakePlayer().getGameProfile())) {
setGoingToOwner(gotoOwnerAI == null);//toggle the state
} else {
disabledByHacking = true;
}
}
@Override
public boolean afterHackTick(Entity entity){
return false;
}
private void setGoingToOwner(boolean state){
if(state && gotoOwnerAI == null) {
gotoOwnerAI = new DroneGoToOwner(this);
tasks.addTask(2, gotoOwnerAI);
dataWatcher.updateObject(21, (byte)1);
setActiveProgram(new ProgWidgetGoToLocation());
} else if(!state && gotoOwnerAI != null) {
tasks.removeTask(gotoOwnerAI);
gotoOwnerAI = null;
dataWatcher.updateObject(21, (byte)0);
}
}
private boolean isGoingToOwner(){
return dataWatcher.getWatchableObjectByte(21) == (byte)1;
}
@Override
public IFluidTank getTank(){
return tank;
}
/**
* Returns the owning player. Returns null when the player is not online.
* @return
*/
public EntityPlayer getOwner(){
return MinecraftServer.getServer().getConfigurationManager().func_152612_a(playerName);
}
public void setStandby(boolean standby){
this.standby = standby;
}
@Override
public World getWorld(){
return worldObj;
}
@Override
public Vec3 getPosition(){
return Vec3.createVectorHelper(posX, posY, posZ);
}
@Override
public void dropItem(ItemStack stack){
entityDropItem(stack, 0);
}
@Override
public List<IProgWidget> getProgWidgets(){
return progWidgets;
}
@Override
public EntityAITasks getTargetAI(){
return targetTasks;
}
@Override
public boolean isProgramApplicable(IProgWidget widget){
return true;
}
@Override
public IExtendedEntityProperties getProperty(String key){
return getExtendedProperties(key);
}
@Override
public void setProperty(String key, IExtendedEntityProperties property){
registerExtendedProperties(key, property);
}
@Override
public void setName(String string){
setCustomNameTag(string);
}
@Override
public void setCarryingEntity(Entity entity){
if(entity == null) {
if(getCarryingEntity() != null) getCarryingEntity().mountEntity(null);
} else {
entity.mountEntity(this);
}
}
@Override
public Entity getCarryingEntity(){
return riddenByEntity;
}
@Override
public boolean isAIOverriden(){
return chargeAI.isExecuting || gotoOwnerAI != null;
}
@Override
public void onItemPickupEvent(EntityItem curPickingUpEntity, int stackSize){
onItemPickup(curPickingUpEntity, stackSize);
}
@Override
public IPathNavigator getPathNavigator(){
return (IPathNavigator)getNavigator();
}
public void tryFireMinigun(EntityLivingBase target){
ItemStack ammo = getAmmo();
if(getMinigun().setAmmo(ammo).tryFireMinigun(target)) {
for(int i = 0; i < getInventory().getSizeInventory(); i++) {
if(getInventory().getStackInSlot(i) == ammo) {
getInventory().setInventorySlotContents(i, null);
}
}
}
}
public ItemStack getAmmo(){
for(int i = 0; i < getInventory().getSizeInventory(); i++) {
ItemStack stack = getInventory().getStackInSlot(i);
if(stack != null && stack.getItem() == Itemss.gunAmmo) {
return stack;
}
}
return null;
}
public void setHandlingOffer(AmadronOffer offer, int times, ItemStack usedTablet, String buyingPlayer){
handlingOffer = offer;
offerTimes = times;
this.usedTablet = usedTablet != null ? usedTablet.copy() : null;
this.buyingPlayer = buyingPlayer;
}
public AmadronOffer getHandlingOffer(){
return handlingOffer;
}
public int getOfferTimes(){
return offerTimes;
}
public ItemStack getUsedTablet(){
return usedTablet;
}
public String getBuyingPlayer(){
return buyingPlayer;
}
@Override
public void overload(){
attackEntityFrom(DamageSource.outOfWorld, 2000.0F);
}
@Override
public DroneAIManager getAIManager(){
return aiManager;
}
@Override
public void updateLabel(){
dataWatcher.updateObject(26, getAIManager() != null ? getAIManager().getLabel() : "Main");
}
public String getLabel(){
return dataWatcher.getWatchableObjectString(26);
}
public SortedSet<DebugEntry> getDebugEntries(){
return debugEntries;
}
@Override
public void addDebugEntry(String message){
addDebugEntry(message, null);
}
@Override
public void addDebugEntry(String message, ChunkPosition pos){
DebugEntry entry = new DebugEntry(message, getActiveWidgetIndex(), pos);
addDebugEntry(entry);
PacketSendDroneDebugEntry packet = new PacketSendDroneDebugEntry(entry, this);
for(EntityPlayerMP player : syncedPlayers) {
NetworkHandler.sendTo(packet, player);
}
}
public void addDebugEntry(DebugEntry entry){
if(!debugEntries.isEmpty()) {
DebugEntry previous = debugEntries.last();
if(previous.getProgWidgetId() != entry.getProgWidgetId()) {//When we've jumped to another piece
Iterator<DebugEntry> iterator = debugEntries.iterator();
while(iterator.hasNext()) {
if(iterator.next().getProgWidgetId() == entry.getProgWidgetId()) {
iterator.remove(); //Remove the data from last cycle.
}
}
}
}
debugEntries.add(entry);
}
public void trackAsDebugged(EntityPlayerMP player){
NetworkHandler.sendTo(new PacketSyncDroneEntityProgWidgets(this), player);
for(DebugEntry entry : debugEntries) {
NetworkHandler.sendTo(new PacketSendDroneDebugEntry(entry, this), player);
}
syncedPlayers.add(player);
}
public void updateSyncedPlayers(){
Iterator<EntityPlayerMP> iterator = syncedPlayers.iterator();
while(iterator.hasNext()) {
EntityPlayerMP player = iterator.next();
if(player.isDead || player.getCurrentArmor(3) == null || NBTUtil.getInteger(player.getCurrentArmor(3), NBTKeys.PNEUMATIC_HELMET_DEBUGGING_DRONE) != getEntityId()) {
iterator.remove();
}
}
}
private class MinigunDrone extends Minigun{
public MinigunDrone(){
super(true);
}
@Override
public boolean isMinigunActivated(){
return EntityDrone.this.isMinigunActivated();
}
@Override
public void setMinigunActivated(boolean activated){
EntityDrone.this.setMinigunActivated(activated);
}
@Override
public void setAmmoColorStack(ItemStack ammo){
setAmmoColor(ammo);
}
@Override
public int getAmmoColor(){
return EntityDrone.this.getAmmoColor();
}
@Override
public void playSound(String soundName, float volume, float pitch){
worldObj.playSoundAtEntity(EntityDrone.this, soundName, volume, pitch);
}
}
}