package icbm.zhapin.jiqi; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import calclavia.lib.TileEntityUniversalRunnable; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import icbm.api.IItemFrequency; import icbm.api.RadarRegistry; import icbm.core.MainBase; import icbm.zhapin.ICBMExplosion; import icbm.zhapin.daodan.EMissile; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.ChatComponentText; import net.minecraft.world.ChunkCoordIntPair; import net.minecraftforge.common.ForgeChunkManager; import net.minecraftforge.common.util.ForgeDirection; import universalelectricity.core.electricity.ElectricityPack; import universalelectricity.core.vector.Vector2; import universalelectricity.core.vector.Vector3; import universalelectricity.prefab.block.BlockAdvanced; import universalelectricity.prefab.implement.IRedstoneProvider; import universalelectricity.prefab.multiblock.IMultiBlock; public class TRadarTower extends TileEntityUniversalRunnable implements IRedstoneProvider, IMultiBlock, IPeripheral { public static final int MAX_BIAN_JING = 500; public float rotation; public int alarmRadius; public int safetyRadius; private List missilesInRange; public List entitiesInRange; public List tileEntitiesInRange; public boolean emitAll; private ForgeChunkManager.Ticket ticket; public double wattsForDisplay; public TRadarTower() { this.rotation = 0.0f; this.alarmRadius = 100; this.safetyRadius = 50; this.missilesInRange = new ArrayList<>(); this.entitiesInRange = new ArrayList<>(); this.tileEntitiesInRange = new ArrayList<>(); this.emitAll = true; RadarRegistry.register(this); } @Override public void initiate() { if (this.worldObj != null) { this.worldObj.notifyBlocksOfNeighborChange( this.xCoord, this.yCoord, this.zCoord, this.worldObj.getBlock(this.xCoord, this.yCoord, this.zCoord) ); } if (this.ticket == null) { this.ticket = ForgeChunkManager.requestTicket( (Object) ICBMExplosion.instance, this.worldObj, ForgeChunkManager.Type.NORMAL ); if (this.ticket != null) { this.ticket.getModData(); } } ForgeChunkManager.forceChunk( this.ticket, new ChunkCoordIntPair(this.xCoord >> 4, this.zCoord >> 4) ); } @Override public void updateEntity() { super.updateEntity(); try { if (!this.worldObj.isRemote) { this.wattsForDisplay = super.wattsReceived; if (super.ticks % 40L == 0L) { this.worldObj.markBlockForUpdate( this.xCoord, this.yCoord, this.zCoord ); } } if (!this.isDisabled()) { if (this.canRun()) { this.rotation += 0.05f; if (this.rotation > 360.0f) { this.rotation = 0.0f; } if (!this.worldObj.isRemote) { super.wattsReceived = Math.max( super.wattsReceived - this.getRequest().getWatts(), 0.0 ); } final int prevShuMu = this.entitiesInRange.size(); this.doScan(); if (prevShuMu != this.entitiesInRange.size()) { this.worldObj.notifyBlocksOfNeighborChange( this.xCoord, this.yCoord, this.zCoord, this.getBlockType() ); } } else { if (this.entitiesInRange.size() > 0) { this.worldObj.notifyBlocksOfNeighborChange( this.xCoord, this.yCoord, this.zCoord, this.getBlockType() ); } this.entitiesInRange.clear(); this.tileEntitiesInRange.clear(); } } if (super.ticks % 40L == 0L) { this.worldObj.notifyBlocksOfNeighborChange( this.xCoord, this.yCoord, this.zCoord, this.getBlockType() ); } } catch (final Exception e) { e.printStackTrace(); } } private void doScan() { this.missilesInRange.clear(); this.entitiesInRange.clear(); this.tileEntitiesInRange.clear(); final List entities = RadarRegistry.getEntitiesWithinRadius(new Vector3(this).toVector2(), 500); for (final Entity entity : entities) { if (entity instanceof EMissile) { if (((EMissile) entity).flyingTicks <= -1) { continue; } if (!this.entitiesInRange.contains(entity)) { this.entitiesInRange.add(entity); } if (!this.isWeiXianDaoDan((EMissile) entity)) { continue; } this.missilesInRange.add((EMissile) entity); } else { this.entitiesInRange.add(entity); } } final List players = this.worldObj.getEntitiesWithinAABB( (Class) EntityPlayer.class, AxisAlignedBB.getBoundingBox( (double) (this.xCoord - 500), (double) (this.yCoord - 500), (double) (this.zCoord - 500), (double) (this.xCoord + 500), (double) (this.yCoord + 500), (double) (this.zCoord + 500) ) ); for (final EntityPlayer player : players) { if (player != null) { boolean youHuoLuan = false; for (int i = 0; i < player.inventory.getSizeInventory(); ++i) { final ItemStack itemStack = player.inventory.getStackInSlot(i); if (itemStack != null && itemStack.getItem() instanceof IItemFrequency) { youHuoLuan = true; break; } } if (youHuoLuan) { continue; } this.entitiesInRange.add(player); } } for (final TileEntity jiQi : RadarRegistry.getTileEntitiesInArea( new Vector2(this.xCoord - 500, this.zCoord - 500), new Vector2(this.xCoord + 500, this.zCoord + 500) )) { if (jiQi instanceof TRadarTower) { if (((TRadarTower) jiQi).isDisabled() || ((TRadarTower) jiQi).prevWatts <= 0.0) { continue; } this.tileEntitiesInRange.add(jiQi); } else { this.tileEntitiesInRange.add(jiQi); } } } public boolean isWeiXianDaoDan(final EMissile daoDan) { return daoDan != null && daoDan.target != null && Vector2.distance( new Vector3(daoDan).toVector2(), new Vector2(this.xCoord, this.zCoord) ) < this.alarmRadius && Vector2.distance( daoDan.target.toVector2(), new Vector2(this.xCoord, this.zCoord) ) < this.safetyRadius; } @Override public Packet getDescriptionPacket() { NBTTagCompound nbt = new NBTTagCompound(); nbt.setDouble("wattsReceived", super.wattsReceived); nbt.setDouble("wattsForDisplay", this.wattsForDisplay); nbt.setInteger("disabledTicks", this.disabledTicks); nbt.setInteger("safetyRadius", this.safetyRadius); nbt.setInteger("alarmRadius", this.alarmRadius); return new S35PacketUpdateTileEntity( this.xCoord, this.yCoord, this.zCoord, this.getBlockMetadata(), nbt ); } @Override public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { NBTTagCompound nbt = pkt.func_148857_g(); super.wattsReceived = nbt.getDouble("wattsReceived"); this.wattsForDisplay = nbt.getDouble("wattsForDisplay"); this.disabledTicks = nbt.getInteger("disabledTicks"); this.safetyRadius = nbt.getInteger("safetyRadius"); this.alarmRadius = nbt.getInteger("alarmRadius"); } @Override public boolean isPoweringTo(final ForgeDirection side) { if ((super.prevWatts > 0.0 || super.wattsReceived > 0.0) && this.missilesInRange.size() > 0) { if (this.emitAll) { return true; } // This detects which direction a missile is coming from, and emits // redstone on the other side. for (final EMissile missile : this.missilesInRange) { final Vector2 position = new Vector3(missile).toVector2(); ForgeDirection missileSide = ForgeDirection.UNKNOWN; double closest = -1.0; for (int i = 2; i < 6; ++i) { final double dist = Vector2.distance( position, new Vector2( this.xCoord + ForgeDirection.getOrientation(i).offsetX, this.zCoord + ForgeDirection.getOrientation(i).offsetZ ) ); if (dist < closest || closest < 0.0) { missileSide = ForgeDirection.getOrientation(i); closest = dist; } } if (missileSide.getOpposite() == side) { return true; } } } return false; } @Override public boolean isIndirectlyPoweringTo(final ForgeDirection side) { return this.isPoweringTo(side); } @Override public void readFromNBT(final NBTTagCompound nbt) { super.readFromNBT(nbt); this.safetyRadius = nbt.getInteger("safetyRadius"); this.alarmRadius = nbt.getInteger("alarmRadius"); this.emitAll = nbt.getBoolean("emitAll"); } @Override public void writeToNBT(final NBTTagCompound par1NBTTagCompound) { super.writeToNBT(par1NBTTagCompound); par1NBTTagCompound.setInteger("safetyRadius", this.safetyRadius); par1NBTTagCompound.setInteger("alarmRadius", this.alarmRadius); par1NBTTagCompound.setBoolean("emitAll", this.emitAll); } @Override public void onDestroy(final TileEntity callingBlock) { this.worldObj.setBlock(this.xCoord, this.yCoord, this.zCoord, Blocks.air, 0, 3); this.worldObj.setBlock( this.xCoord, this.yCoord + 1, this.zCoord, Blocks.air, 0, 3 ); this.worldObj.setBlock( this.xCoord + 1, this.yCoord + 1, this.zCoord, Blocks.air, 0, 3 ); this.worldObj.setBlock( this.xCoord - 1, this.yCoord + 1, this.zCoord, Blocks.air, 0, 3 ); this.worldObj.setBlock( this.xCoord, this.yCoord + 1, this.zCoord + 1, Blocks.air, 0, 3 ); this.worldObj.setBlock( this.xCoord, this.yCoord + 1, this.zCoord - 1, Blocks.air, 0, 3 ); this.worldObj.setBlock( this.xCoord + 1, this.yCoord + 1, this.zCoord + 1, Blocks.air, 0, 3 ); this.worldObj.setBlock( this.xCoord - 1, this.yCoord + 1, this.zCoord - 1, Blocks.air, 0, 3 ); this.worldObj.setBlock( this.xCoord + 1, this.yCoord + 1, this.zCoord - 1, Blocks.air, 0, 3 ); this.worldObj.setBlock( this.xCoord - 1, this.yCoord + 1, this.zCoord + 1, Blocks.air, 0, 3 ); } @Override public boolean onActivated(final EntityPlayer entityPlayer) { if (entityPlayer.inventory.getCurrentItem() != null && ((BlockAdvanced) this.getBlockType()) .isUsableWrench( entityPlayer, entityPlayer.inventory.getCurrentItem(), this.xCoord, this.yCoord, this.zCoord )) { if (!this.worldObj.isRemote) { this.emitAll = !this.emitAll; entityPlayer.addChatMessage(new ChatComponentText( "Radar redstone all side emission: " + this.emitAll )); } return true; } entityPlayer.openGui( (Object) ICBMExplosion.instance, 3, this.worldObj, this.xCoord, this.yCoord, this.zCoord ); return true; } @Override public void onCreate(final Vector3 position) { MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(0.0, 1.0, 0.0), position), new Vector3(this) ); MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(1.0, 1.0, 0.0), position), new Vector3(this) ); MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(-1.0, 1.0, 0.0), position), new Vector3(this) ); MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(0.0, 1.0, 1.0), position), new Vector3(this) ); MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(0.0, 1.0, -1.0), position), new Vector3(this) ); MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(1.0, 1.0, -1.0), position), new Vector3(this) ); MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(-1.0, 1.0, 1.0), position), new Vector3(this) ); MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(1.0, 1.0, 1.0), position), new Vector3(this) ); MainBase.bJia.makeFakeBlock( this.worldObj, Vector3.add(new Vector3(-1.0, 1.0, -1.0), position), new Vector3(this) ); } public boolean canRun() { if (this.worldObj.isRemote) { return this.wattsForDisplay >= this.getRequest().getWatts(); } else { return super.wattsReceived >= this.getRequest().getWatts(); } } @Override public String getType() { return "ICBMRadar"; } @Override public String[] getMethodNames() { return new String[] { "getEntities", "getBlocks" }; } @Override public Object[] callMethod( final IComputerAccess computer, ILuaContext ctx, final int method, final Object[] arguments ) throws LuaException { if (super.wattsReceived < this.getRequest().getWatts()) { throw new LuaException("Radar has insufficient electricity!"); } final HashMap returnArray = new HashMap<>(); int count = 0; switch (method) { case 0: { final List entities = RadarRegistry.getEntitiesWithinRadius( new Vector3(this).toVector2(), this.alarmRadius ); for (final Entity entity : entities) { // TODO: completely retarded lua API returnArray.put("x_" + count, entity.posX); returnArray.put("y_" + count, entity.posY); returnArray.put("z_" + count, entity.posZ); ++count; } return new Object[] { returnArray }; } case 1: { for (final TileEntity jiQi : RadarRegistry.getTileEntitiesInArea( new Vector2(this.xCoord - 500, this.zCoord - 500), new Vector2(this.xCoord + 500, this.zCoord + 500) )) { returnArray.put("x_" + count, (double) jiQi.xCoord); returnArray.put("y_" + count, (double) jiQi.yCoord); returnArray.put("z_" + count, (double) jiQi.zCoord); ++count; } return new Object[] { returnArray }; } default: { throw new LuaException("Invalid ICBM Radar Function."); } } } @Override public void invalidate() { ForgeChunkManager.releaseTicket(this.ticket); RadarRegistry.unregister(this); super.invalidate(); } @Override public void attach(final IComputerAccess computer) {} @Override public void detach(final IComputerAccess computer) {} @Override public ElectricityPack getRequest() { return new ElectricityPack(15.0 / this.getVoltage(), this.getVoltage()); } @Override public AxisAlignedBB getRenderBoundingBox() { return TileEntity.INFINITE_EXTENT_AABB; } @Override public boolean equals(IPeripheral other) { return this == other; } }