package mcjty.rftools.items.shapecard; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import mcjty.lib.varia.Coordinate; import mcjty.lib.varia.GlobalCoordinate; import mcjty.lib.varia.Logging; import mcjty.rftools.RFTools; import mcjty.rftools.blocks.spaceprojector.BuilderTileEntity; import mcjty.rftools.blocks.spaceprojector.SpaceProjectorConfiguration; import net.minecraft.block.Block; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.IIcon; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import net.minecraftforge.oredict.OreDictionary; import org.lwjgl.input.Keyboard; import java.util.*; public class ShapeCardItem extends Item { public static final int CARD_UNKNOWN = -2; // Not known yet public static final int CARD_SPACE = -1; // Not a shape card but a space card instead public static final int CARD_SHAPE = 0; public static final int CARD_VOID = 1; public static final int CARD_QUARRY = 2; public static final int CARD_QUARRY_SILK = 3; public static final int CARD_QUARRY_FORTUNE = 4; public static final int CARD_QUARRY_CLEAR = 5; public static final int CARD_QUARRY_CLEAR_SILK = 6; public static final int CARD_QUARRY_CLEAR_FORTUNE = 7; public static final int MAXIMUM_COUNT = 50000000; private final IIcon[] icons = new IIcon[8]; public enum Shape { SHAPE_BOX(0, "Box"), SHAPE_TOPDOME(1, "Top Dome"), SHAPE_BOTTOMDOME(2, "Bottom Dome"), SHAPE_SPHERE(3, "Sphere"), SHAPE_CYLINDER(4, "Cylinder"), SHAPE_CAPPEDCYLINDER(5, "Capped Cylinder"), SHAPE_PRISM(6, "Prism"), SHAPE_TORUS(7, "Torus"), SHAPE_SOLIDBOX(100, "Solid Box"), SHAPE_SOLIDSPHERE(103, "Solid Sphere"), SHAPE_SOLIDCYLINDER(104, "Solid Cylinder"), SHAPE_SOLIDTORUS(107, "Solid Torus"); private final int index; private final String description; private static Map<Integer,Shape> shapes; private static Map<String,Shape> shapesByDescription; static { shapesByDescription = new HashMap<String, Shape>(); shapes = new HashMap<Integer, Shape>(); for (Shape shape : values()) { shapes.put(shape.getIndex(), shape); shapesByDescription.put(shape.getDescription(), shape); } } // Return the hollow version of the shape. public Shape makeHollow() { switch (this) { case SHAPE_SOLIDBOX: return SHAPE_BOX; case SHAPE_SOLIDSPHERE: return SHAPE_SPHERE; case SHAPE_SOLIDCYLINDER: return SHAPE_CAPPEDCYLINDER; case SHAPE_SOLIDTORUS: return SHAPE_TORUS; } return this; } Shape(int index, String description) { this.index = index; this.description = description; } public int getIndex() { return index; } public String getDescription() { return description; } public static Shape getShape(int index) { return shapes.get(index); } public static Shape getShape(String description) { return shapesByDescription.get(description); } } public static final int MODE_NONE = 0; public static final int MODE_CORNER1 = 1; public static final int MODE_CORNER2 = 2; public ShapeCardItem() { setMaxStackSize(1); setHasSubtypes(true); setMaxDamage(0); } @Override public int getMaxItemUseDuration(ItemStack stack) { return 1; } @Override public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float sx, float sy, float sz) { if (!world.isRemote) { int mode = getMode(stack); if (mode == MODE_NONE) { if (player.isSneaking()) { if (world.getTileEntity(x, y, z) instanceof BuilderTileEntity) { setCurrentBlock(stack, new GlobalCoordinate(new Coordinate(x, y, z), world.provider.dimensionId)); Logging.message(player, EnumChatFormatting.GREEN + "Now select the first corner"); setMode(stack, MODE_CORNER1); setCorner1(stack, null); } else { Logging.message(player, EnumChatFormatting.RED + "You can only do this on a builder!"); } } else { return false; } } else if (mode == MODE_CORNER1) { GlobalCoordinate currentBlock = getCurrentBlock(stack); if (currentBlock.getDimension() != world.provider.dimensionId) { Logging.message(player, EnumChatFormatting.RED + "The Builder is in another dimension!"); } else if (currentBlock.getCoordinate().equals(new Coordinate(x, y, z))) { Logging.message(player, EnumChatFormatting.RED + "Cleared area selection mode!"); setMode(stack, MODE_NONE); } else { Logging.message(player, EnumChatFormatting.GREEN + "Now select the second corner"); setMode(stack, MODE_CORNER2); setCorner1(stack, new Coordinate(x, y, z)); } } else { GlobalCoordinate currentBlock = getCurrentBlock(stack); if (currentBlock.getDimension() != world.provider.dimensionId) { Logging.message(player, EnumChatFormatting.RED + "The Builder is in another dimension!"); } else if (currentBlock.getCoordinate().equals(new Coordinate(x, y, z))) { Logging.message(player, EnumChatFormatting.RED + "Cleared area selection mode!"); setMode(stack, MODE_NONE); } else { NBTTagCompound tag = stack.getTagCompound(); if (tag == null) { tag = new NBTTagCompound(); stack.setTagCompound(tag); } Coordinate c1 = getCorner1(stack); if (c1 == null) { Logging.message(player, EnumChatFormatting.RED + "Cleared area selection mode!"); setMode(stack, MODE_NONE); } else { Logging.message(player, EnumChatFormatting.GREEN + "New settings copied to the shape card!"); System.out.println("currentBlock = " + currentBlock.getCoordinate()); System.out.println("corner1 = " + c1); System.out.println("corner2 = " + x + ", " + y + ", " + z); // Coordinate center = new Coordinate((int) ((c1.getX() + x) / 2.0f + .55f), (int) ((c1.getY() + y) / 2.0f + .55f), (int) ((c1.getZ() + z) / 2.0f + .55f)); Coordinate center = new Coordinate((int) Math.ceil((c1.getX() + x) / 2.0f), (int) Math.ceil((c1.getY() + y) / 2.0f), (int) Math.ceil((c1.getZ() + z) / 2.0f)); System.out.println("center = " + center); tag.setInteger("dimX", Math.abs(c1.getX() - x) + 1); tag.setInteger("dimY", Math.abs(c1.getY() - y) + 1); tag.setInteger("dimZ", Math.abs(c1.getZ() - z) + 1); tag.setInteger("offsetX", center.getX() - currentBlock.getCoordinate().getX()); tag.setInteger("offsetY", center.getY() - currentBlock.getCoordinate().getY()); tag.setInteger("offsetZ", center.getZ() - currentBlock.getCoordinate().getZ()); setMode(stack, MODE_NONE); setCorner1(stack, null); } } } } return true; } public static void setCorner1(ItemStack itemStack, Coordinate corner) { NBTTagCompound tagCompound = itemStack.getTagCompound(); if (tagCompound == null) { tagCompound = new NBTTagCompound(); itemStack.setTagCompound(tagCompound); } if (corner == null) { tagCompound.removeTag("corner1x"); tagCompound.removeTag("corner1y"); tagCompound.removeTag("corner1z"); } else { tagCompound.setInteger("corner1x", corner.getX()); tagCompound.setInteger("corner1y", corner.getY()); tagCompound.setInteger("corner1z", corner.getZ()); } } public static Coordinate getCorner1(ItemStack stack1) { NBTTagCompound tagCompound = stack1.getTagCompound(); if (tagCompound == null) { return null; } if (!tagCompound.hasKey("corner1x")) { return null; } return new Coordinate(tagCompound.getInteger("corner1x"), tagCompound.getInteger("corner1y"), tagCompound.getInteger("corner1z")); } public static int getMode(ItemStack itemStack) { NBTTagCompound tagCompound = itemStack.getTagCompound(); if (tagCompound != null) { return tagCompound.getInteger("mode"); } else { return MODE_NONE; } } public static void setMode(ItemStack itemStack, int mode) { NBTTagCompound tagCompound = itemStack.getTagCompound(); if (tagCompound == null) { tagCompound = new NBTTagCompound(); itemStack.setTagCompound(tagCompound); } tagCompound.setInteger("mode", mode); } public static void setCurrentBlock(ItemStack itemStack, GlobalCoordinate c) { NBTTagCompound tagCompound = itemStack.getTagCompound(); if (tagCompound == null) { tagCompound = new NBTTagCompound(); itemStack.setTagCompound(tagCompound); } if (c == null) { tagCompound.removeTag("selectedX"); tagCompound.removeTag("selectedY"); tagCompound.removeTag("selectedZ"); tagCompound.removeTag("selectedDim"); } else { tagCompound.setInteger("selectedX", c.getCoordinate().getX()); tagCompound.setInteger("selectedY", c.getCoordinate().getY()); tagCompound.setInteger("selectedZ", c.getCoordinate().getZ()); tagCompound.setInteger("selectedDim", c.getDimension()); } } public static GlobalCoordinate getCurrentBlock(ItemStack itemStack) { NBTTagCompound tagCompound = itemStack.getTagCompound(); if (tagCompound != null && tagCompound.hasKey("selectedX")) { int x = tagCompound.getInteger("selectedX"); int y = tagCompound.getInteger("selectedY"); int z = tagCompound.getInteger("selectedZ"); int dim = tagCompound.getInteger("selectedDim"); return new GlobalCoordinate(new Coordinate(x, y, z), dim); } return null; } @SideOnly(Side.CLIENT) @Override public void addInformation(ItemStack itemStack, EntityPlayer player, List list, boolean whatIsThis) { super.addInformation(itemStack, player, list, whatIsThis); int type = itemStack.getItemDamage(); if (!SpaceProjectorConfiguration.shapeCardAllowed) { list.add(EnumChatFormatting.RED + "Disabled in config!"); } else if (type != CARD_SHAPE) { if (!SpaceProjectorConfiguration.quarryAllowed) { list.add(EnumChatFormatting.RED + "Disabled in config!"); } else if (isClearingQuarry(type)) { if (!SpaceProjectorConfiguration.clearingQuarryAllowed) { list.add(EnumChatFormatting.RED + "Disabled in config!"); } } } Shape shape = getShape(itemStack); list.add(EnumChatFormatting.GREEN + "Shape " + shape.getDescription()); list.add(EnumChatFormatting.GREEN + "Dimension " + getDimension(itemStack)); list.add(EnumChatFormatting.GREEN + "Offset " + getOffset(itemStack)); if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) { list.add(EnumChatFormatting.YELLOW + "Sneak right click on builder to start mark mode"); list.add(EnumChatFormatting.YELLOW + "Then right click to mark two corners of wanted area"); switch (type) { case CARD_VOID: list.add(EnumChatFormatting.WHITE + "This item will cause the builder to void"); list.add(EnumChatFormatting.WHITE + "all blocks in the configured space."); list.add(EnumChatFormatting.GREEN + "Max area: " + SpaceProjectorConfiguration.maxBuilderDimension + "x" + Math.min(256, SpaceProjectorConfiguration.maxBuilderDimension) + "x" + SpaceProjectorConfiguration.maxBuilderDimension); list.add(EnumChatFormatting.GREEN + "Base cost: " + (int)(SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.voidShapeCardFactor) + " RF/t per block"); list.add(EnumChatFormatting.GREEN + "(final cost depends on infusion level and block hardness)"); break; case CARD_SHAPE: list.add(EnumChatFormatting.WHITE + "This item can be configured as a shape. You"); list.add(EnumChatFormatting.WHITE + "can then use it in the shield projector to make"); list.add(EnumChatFormatting.WHITE + "a shield of that shape or in the builder to"); list.add(EnumChatFormatting.WHITE + "actually build the shape"); list.add(EnumChatFormatting.GREEN + "Max area: " + SpaceProjectorConfiguration.maxBuilderDimension + "x" + Math.min(256, SpaceProjectorConfiguration.maxBuilderDimension) + "x" + SpaceProjectorConfiguration.maxBuilderDimension); list.add(EnumChatFormatting.GREEN + "Base cost: " + SpaceProjectorConfiguration.builderRfPerOperation + " RF/t per block"); list.add(EnumChatFormatting.GREEN + "(final cost depends on infusion level)"); break; case CARD_QUARRY_SILK: list.add(EnumChatFormatting.WHITE + "This item will cause the builder to quarry"); list.add(EnumChatFormatting.WHITE + "all blocks in the configured space and replace"); list.add(EnumChatFormatting.WHITE + "them with dirt."); list.add(EnumChatFormatting.WHITE + "Blocks are harvested with silk touch"); list.add(EnumChatFormatting.GREEN + "Max area: " + SpaceProjectorConfiguration.maxBuilderDimension + "x" + Math.min(256, SpaceProjectorConfiguration.maxBuilderDimension) + "x" + SpaceProjectorConfiguration.maxBuilderDimension); list.add(EnumChatFormatting.GREEN + "Base cost: " + (int)(SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.silkquarryShapeCardFactor) + " RF/t per block"); list.add(EnumChatFormatting.GREEN + "(final cost depends on infusion level and block hardness)"); break; case CARD_QUARRY_CLEAR_SILK: list.add(EnumChatFormatting.WHITE + "This item will cause the builder to quarry"); list.add(EnumChatFormatting.WHITE + "all blocks in the configured space."); list.add(EnumChatFormatting.WHITE + "Blocks are harvested with silk touch"); list.add(EnumChatFormatting.GREEN + "Max area: " + SpaceProjectorConfiguration.maxBuilderDimension + "x" + Math.min(256, SpaceProjectorConfiguration.maxBuilderDimension) + "x" + SpaceProjectorConfiguration.maxBuilderDimension); list.add(EnumChatFormatting.GREEN + "Base cost: " + (int)(SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.silkquarryShapeCardFactor) + " RF/t per block"); list.add(EnumChatFormatting.GREEN + "(final cost depends on infusion level and block hardness)"); break; case CARD_QUARRY_FORTUNE: list.add(EnumChatFormatting.WHITE + "This item will cause the builder to quarry"); list.add(EnumChatFormatting.WHITE + "all blocks in the configured space and replace"); list.add(EnumChatFormatting.WHITE + "them with dirt."); list.add(EnumChatFormatting.WHITE + "Blocks are harvested with fortune"); list.add(EnumChatFormatting.GREEN + "Max area: " + SpaceProjectorConfiguration.maxBuilderDimension + "x" + Math.min(256, SpaceProjectorConfiguration.maxBuilderDimension) + "x" + SpaceProjectorConfiguration.maxBuilderDimension); list.add(EnumChatFormatting.GREEN + "Base cost: " + (int)(SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.fortunequarryShapeCardFactor) + " RF/t per block"); list.add(EnumChatFormatting.GREEN + "(final cost depends on infusion level and block hardness)"); break; case CARD_QUARRY_CLEAR_FORTUNE: list.add(EnumChatFormatting.WHITE + "This item will cause the builder to quarry"); list.add(EnumChatFormatting.WHITE + "all blocks in the configured space."); list.add(EnumChatFormatting.WHITE + "Blocks are harvested with fortune"); list.add(EnumChatFormatting.GREEN + "Max area: " + SpaceProjectorConfiguration.maxBuilderDimension + "x" + Math.min(256, SpaceProjectorConfiguration.maxBuilderDimension) + "x" + SpaceProjectorConfiguration.maxBuilderDimension); list.add(EnumChatFormatting.GREEN + "Base cost: " + (int)(SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.fortunequarryShapeCardFactor) + " RF/t per block"); list.add(EnumChatFormatting.GREEN + "(final cost depends on infusion level and block hardness)"); break; case CARD_QUARRY: list.add(EnumChatFormatting.WHITE + "This item will cause the builder to quarry"); list.add(EnumChatFormatting.WHITE + "all blocks in the configured space and replace"); list.add(EnumChatFormatting.WHITE + "them with dirt."); list.add(EnumChatFormatting.GREEN + "Max area: " + SpaceProjectorConfiguration.maxBuilderDimension + "x" + Math.min(256, SpaceProjectorConfiguration.maxBuilderDimension) + "x" + SpaceProjectorConfiguration.maxBuilderDimension); list.add(EnumChatFormatting.GREEN + "Base cost: " + SpaceProjectorConfiguration.builderRfPerQuarry + " RF/t per block"); list.add(EnumChatFormatting.GREEN + "(final cost depends on infusion level and block hardness)"); break; case CARD_QUARRY_CLEAR: list.add(EnumChatFormatting.WHITE + "This item will cause the builder to quarry"); list.add(EnumChatFormatting.WHITE + "all blocks in the configured space"); list.add(EnumChatFormatting.GREEN + "Max area: " + SpaceProjectorConfiguration.maxBuilderDimension + "x" + Math.min(256, SpaceProjectorConfiguration.maxBuilderDimension) + "x" + SpaceProjectorConfiguration.maxBuilderDimension); list.add(EnumChatFormatting.GREEN + "Base cost: " + SpaceProjectorConfiguration.builderRfPerQuarry + " RF/t per block"); list.add(EnumChatFormatting.GREEN + "(final cost depends on infusion level and block hardness)"); break; } } else { list.add(EnumChatFormatting.WHITE + RFTools.SHIFT_MESSAGE); } } /** * Return true if the card is a normal card (not a quarry or void card) * @param stack * @return */ public static boolean isNormalShapeCard(ItemStack stack) { return stack.getItemDamage() == CARD_SHAPE; } public static boolean isClearingQuarry(int type) { return type == CARD_QUARRY_CLEAR || type == CARD_QUARRY_CLEAR_FORTUNE || type == CARD_QUARRY_CLEAR_SILK; } public static boolean isQuarry(int type) { return type == CARD_QUARRY_CLEAR || type == CARD_QUARRY_CLEAR_FORTUNE || type == CARD_QUARRY_CLEAR_SILK || type == CARD_QUARRY || type == CARD_QUARRY_FORTUNE || type == CARD_QUARRY_SILK; } private static void addBlocks(Set<Block> blocks, Block block, boolean oredict) { blocks.add(block); if (oredict) { int[] iDs = OreDictionary.getOreIDs(new ItemStack(block)); for (int id : iDs) { String oreName = OreDictionary.getOreName(id); ArrayList<ItemStack> ores = OreDictionary.getOres(oreName); for (ItemStack ore : ores) { if (ore.getItem() instanceof ItemBlock) { blocks.add(((ItemBlock)ore.getItem()).field_150939_a); } } } } } public static Set<Block> getVoidedBlocks(ItemStack stack) { Set<Block> blocks = new HashSet<Block>(); boolean oredict = isOreDictionary(stack); if (isVoiding(stack, "stone")) { addBlocks(blocks, Blocks.stone, oredict); } if (isVoiding(stack, "cobble")) { addBlocks(blocks, Blocks.cobblestone, oredict); } if (isVoiding(stack, "dirt")) { addBlocks(blocks, Blocks.dirt, oredict); } if (isVoiding(stack, "sand")) { addBlocks(blocks, Blocks.sand, oredict); } if (isVoiding(stack, "gravel")) { addBlocks(blocks, Blocks.gravel, oredict); } if (isVoiding(stack, "netherrack")) { addBlocks(blocks, Blocks.netherrack, oredict); } return blocks; } public static boolean isOreDictionary(ItemStack stack) { NBTTagCompound tagCompound = stack.getTagCompound(); if (tagCompound == null) { return false; } return tagCompound.getBoolean("oredict"); } public static boolean isVoiding(ItemStack stack, String material) { NBTTagCompound tagCompound = stack.getTagCompound(); if (tagCompound == null) { return false; } return tagCompound.getBoolean("void" + material); } public static Shape getShape(ItemStack stack) { NBTTagCompound tagCompound = stack.getTagCompound(); if (tagCompound == null) { return Shape.SHAPE_BOX; } int shape = tagCompound.getInteger("shape"); Shape s = Shape.getShape(shape); if (s == null) { return Shape.SHAPE_BOX; } return s; } public static void setShape(ItemStack stack, Shape shape) { NBTTagCompound tagCompound = stack.getTagCompound(); if (tagCompound == null) { tagCompound = new NBTTagCompound(); stack.setTagCompound(tagCompound); } tagCompound.setInteger("shape", shape.getIndex()); } public static Coordinate getDimension(ItemStack stack) { NBTTagCompound tagCompound = stack.getTagCompound(); if (tagCompound == null) { return new Coordinate(5, 5, 5); } if (!tagCompound.hasKey("dimX")) { return new Coordinate(5, 5, 5); } int dimX = tagCompound.getInteger("dimX"); int dimY = tagCompound.getInteger("dimY"); int dimZ = tagCompound.getInteger("dimZ"); return new Coordinate(dimX, clampDimension(dimY, 256), dimZ); } public static Coordinate getClampedDimension(ItemStack stack, int maximum) { NBTTagCompound tagCompound = stack.getTagCompound(); if (tagCompound == null) { return new Coordinate(5, 5, 5); } int dimX = tagCompound.getInteger("dimX"); int dimY = tagCompound.getInteger("dimY"); int dimZ = tagCompound.getInteger("dimZ"); return new Coordinate(clampDimension(dimX, maximum), clampDimension(dimY, maximum), clampDimension(dimZ, maximum)); } private static int clampDimension(int o, int maximum) { if (o > maximum) { o = maximum; } else if (o < 0) { o = 0; } return o; } public static Coordinate getOffset(ItemStack stack) { NBTTagCompound tagCompound = stack.getTagCompound(); if (tagCompound == null) { return new Coordinate(0, 0, 0); } int offsetX = tagCompound.getInteger("offsetX"); int offsetY = tagCompound.getInteger("offsetY"); int offsetZ = tagCompound.getInteger("offsetZ"); return new Coordinate(offsetX, offsetY, offsetZ); } public static Coordinate getClampedOffset(ItemStack stack, int maximum) { NBTTagCompound tagCompound = stack.getTagCompound(); if (tagCompound == null) { return new Coordinate(0, 0, 0); } int offsetX = tagCompound.getInteger("offsetX"); int offsetY = tagCompound.getInteger("offsetY"); int offsetZ = tagCompound.getInteger("offsetZ"); return new Coordinate(clampOffset(offsetX, maximum), clampOffset(offsetY, maximum), clampOffset(offsetZ, maximum)); } private static int clampOffset(int o, int maximum) { if (o < -maximum) { o = -maximum; } else if (o > maximum) { o = maximum; } return o; } @Override public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { if (world.isRemote) { player.openGui(RFTools.instance, RFTools.GUI_SHAPECARD, player.worldObj, (int) player.posX, (int) player.posY, (int) player.posZ); return stack; } return stack; } public static Coordinate getMinCorner(Coordinate thisCoord, Coordinate dimension, Coordinate offset) { int xCoord = thisCoord.getX(); int yCoord = thisCoord.getY(); int zCoord = thisCoord.getZ(); int dx = dimension.getX(); int dy = dimension.getY(); int dz = dimension.getZ(); return new Coordinate(xCoord - dx/2 + offset.getX(), yCoord - dy/2 + offset.getY(), zCoord - dz/2 + offset.getZ()); } public static Coordinate getMaxCorner(Coordinate thisCoord, Coordinate dimension, Coordinate offset) { int dx = dimension.getX(); int dy = dimension.getY(); int dz = dimension.getZ(); Coordinate minCorner = getMinCorner(thisCoord, dimension, offset); return new Coordinate(minCorner.getX() + dx, minCorner.getY() + dy, minCorner.getZ() + dz); } public static int countBlocks(Shape shape, Coordinate dimension) { final int[] cnt = {0}; Coordinate offset = new Coordinate(0, 128, 0); Coordinate clamped = new Coordinate(Math.min(dimension.getX(), 512), Math.min(dimension.getY(), 256), Math.min(dimension.getZ(), 512)); composeShape(shape, null, new Coordinate(0, 0, 0), clamped, offset, new AbstractCollection<Coordinate>() { @Override public Iterator<Coordinate> iterator() { return null; } @Override public boolean add(Coordinate coordinate) { cnt[0]++; return true; } @Override public int size() { return 0; } }, MAXIMUM_COUNT+1, false, null); return cnt[0]; } public static boolean xInChunk(int x, ChunkCoordIntPair chunk) { if (chunk == null) { return true; } else { return chunk.chunkXPos == (x>>4); } } public static boolean zInChunk(int z, ChunkCoordIntPair chunk) { if (chunk == null) { return true; } else { return chunk.chunkZPos == (z>>4); } } public static void composeShape(Shape shape, World worldObj, Coordinate thisCoord, Coordinate dimension, Coordinate offset, Collection<Coordinate> blocks, int maxSize, boolean forquarry, ChunkCoordIntPair chunk) { switch (shape) { case SHAPE_BOX: composeBox(worldObj, thisCoord, dimension, offset, blocks, maxSize, false, forquarry, chunk); break; case SHAPE_SOLIDBOX: composeBox(worldObj, thisCoord, dimension, offset, blocks, maxSize, true, forquarry, chunk); break; case SHAPE_TOPDOME: composeSphere(worldObj, thisCoord, dimension, offset, blocks, maxSize, 1, false, forquarry, chunk); break; case SHAPE_BOTTOMDOME: composeSphere(worldObj, thisCoord, dimension, offset, blocks, maxSize, -1, false, forquarry, chunk); break; case SHAPE_SPHERE: composeSphere(worldObj, thisCoord, dimension, offset, blocks, maxSize, 0, false, forquarry, chunk); break; case SHAPE_SOLIDSPHERE: composeSphere(worldObj, thisCoord, dimension, offset, blocks, maxSize, 0, true, forquarry, chunk); break; case SHAPE_CYLINDER: composeCylinder(worldObj, thisCoord, dimension, offset, blocks, maxSize, false, false, forquarry, chunk); break; case SHAPE_SOLIDCYLINDER: composeCylinder(worldObj, thisCoord, dimension, offset, blocks, maxSize, true, true, forquarry, chunk); break; case SHAPE_CAPPEDCYLINDER: composeCylinder(worldObj, thisCoord, dimension, offset, blocks, maxSize, true, false, forquarry, chunk); break; case SHAPE_PRISM: composePrism(worldObj, thisCoord, dimension, offset, blocks, maxSize, forquarry, chunk); break; case SHAPE_TORUS: composeTorus(worldObj, thisCoord, dimension, offset, blocks, maxSize, false, forquarry, chunk); break; case SHAPE_SOLIDTORUS: composeTorus(worldObj, thisCoord, dimension, offset, blocks, maxSize, true, forquarry, chunk); break; } } private static void placeBlockIfPossible(World worldObj, Collection<Coordinate> blocks, int maxSize, int x, int y, int z, boolean forquarry) { if (worldObj == null) { blocks.add(new Coordinate(x, y, z)); return; } if (forquarry) { if (worldObj.isAirBlock(x, y, z)) { return; } blocks.add(new Coordinate(x, y, z)); } else { if (BuilderTileEntity.isEmptyOrReplacable(worldObj, x, y, z) && blocks.size() < maxSize - 1) { blocks.add(new Coordinate(x, y, z)); } } } private static void composeSphere(World worldObj, Coordinate thisCoord, Coordinate dimension, Coordinate offset, Collection<Coordinate> blocks, int maxSize, int side, boolean solid, boolean forquarry, ChunkCoordIntPair chunk) { int xCoord = thisCoord.getX(); int yCoord = thisCoord.getY(); int zCoord = thisCoord.getZ(); int dx = dimension.getX(); int dy = dimension.getY(); int dz = dimension.getZ(); float centerx; float centery; float centerz; if (SpaceProjectorConfiguration.oldSphereCylinderShape) { centerx = xCoord + offset.getX() + 0.5f; centery = yCoord + offset.getY() + 0.5f; centerz = zCoord + offset.getZ() + 0.5f; } else { centerx = xCoord + offset.getX() + ((dx % 2 != 0) ? 0.0f : -.5f); centery = yCoord + offset.getY() + ((dy % 2 != 0) ? 0.0f : -.5f); centerz = zCoord + offset.getZ() + ((dz % 2 != 0) ? 0.0f : -.5f); } Coordinate tl = new Coordinate(xCoord - dx/2 + offset.getX(), yCoord - dy/2 + offset.getY(), zCoord - dz/2 + offset.getZ()); float dx2; float dy2; float dz2; int davg; if (SpaceProjectorConfiguration.oldSphereCylinderShape) { dx2 = dx == 0 ? .5f : (dx * dx) / 4.0f; dy2 = dy == 0 ? .5f : (dy * dy) / 4.0f; dz2 = dz == 0 ? .5f : (dz * dz) / 4.0f; davg = (dx + dy + dz) / 3; } else { // float factor = 2.0f; float factor = 1.8f; dx2 = dx == 0 ? .5f : ((dx + factor) * (dx + factor)) / 4.0f; dy2 = dy == 0 ? .5f : ((dy + factor) * (dy + factor)) / 4.0f; dz2 = dz == 0 ? .5f : ((dz + factor) * (dz + factor)) / 4.0f; davg = (int) ((dx + dy + dz + factor * 3) / 3); } for (int ox = 0 ; ox < dx ; ox++) { int x = tl.getX() + ox; if (xInChunk(x, chunk)) { for (int oz = 0 ; oz < dz ; oz++) { int z = tl.getZ() + oz; if (zInChunk(z, chunk)) { for (int oy = 0; oy < dy; oy++) { int y = tl.getY() + oy; if (y >= 0 && y < 255) { if (side == 0 || (side == 1 && y >= yCoord + offset.getY()) || (side == -1 && y <= yCoord + offset.getY())) { if (isInside3D(centerx, centery, centerz, x, y, z, dx2, dy2, dz2, davg) == 1) { int cnt; if (solid) { cnt = 0; } else { cnt = isInside3D(centerx, centery, centerz, x - 1, y, z, dx2, dy2, dz2, davg); cnt += isInside3D(centerx, centery, centerz, x + 1, y, z, dx2, dy2, dz2, davg); cnt += isInside3D(centerx, centery, centerz, x, y - 1, z, dx2, dy2, dz2, davg); cnt += isInside3D(centerx, centery, centerz, x, y + 1, z, dx2, dy2, dz2, davg); cnt += isInside3D(centerx, centery, centerz, x, y, z - 1, dx2, dy2, dz2, davg); cnt += isInside3D(centerx, centery, centerz, x, y, z + 1, dx2, dy2, dz2, davg); } if (cnt != 6) { placeBlockIfPossible(worldObj, blocks, maxSize, x, y, z, forquarry); } } } } } } } } } } private static float squaredDistance3D(float cx, float cy, float cz, float x1, float y1, float z1, float dx2, float dy2, float dz2) { return (x1-cx) * (x1-cx) / dx2 + (y1-cy) * (y1-cy) / dy2 + (z1-cz) * (z1-cz) / dz2; } private static float squaredDistance2D(float cx, float cz, float x1, float z1, float dx2, float dz2) { return (x1-cx) * (x1-cx) / dx2 + (z1-cz) * (z1-cz) / dz2; } private static int isInside2D(float centerx, float centerz, int x, int z, float dx2, float dz2, int davg) { double distance = Math.sqrt(squaredDistance2D(centerx, centerz, x, z, dx2, dz2)); return ((int) (distance * (davg / 2 + 1))) <= (davg / 2 - 1) ? 1 : 0; } private static int isInside3D(float centerx, float centery, float centerz, int x, int y, int z, float dx2, float dy2, float dz2, int davg) { double distance = Math.sqrt(squaredDistance3D(centerx, centery, centerz, x, y, z, dx2, dy2, dz2)); return ((int) (distance * (davg / 2 + 1))) <= (davg / 2 - 1) ? 1 : 0; } private static void composeCylinder(World worldObj, Coordinate thisCoord, Coordinate dimension, Coordinate offset, Collection<Coordinate> blocks, int maxSize, boolean capped, boolean solid, boolean forquarry, ChunkCoordIntPair chunk) { int xCoord = thisCoord.getX(); int yCoord = thisCoord.getY(); int zCoord = thisCoord.getZ(); int dx = dimension.getX(); int dy = dimension.getY(); int dz = dimension.getZ(); float centerx; float centerz; if (SpaceProjectorConfiguration.oldSphereCylinderShape) { centerx = xCoord + offset.getX() + 0.5f; centerz = zCoord + offset.getZ() + 0.5f; } else { centerx = xCoord + offset.getX() + ((dx % 2 != 0) ? 0.0f : -.5f); centerz = zCoord + offset.getZ() + ((dz % 2 != 0) ? 0.0f : -.5f); } Coordinate tl = new Coordinate(xCoord - dx/2 + offset.getX(), yCoord - dy/2 + offset.getY(), zCoord - dz/2 + offset.getZ()); float dx2; float dz2; int davg; if (SpaceProjectorConfiguration.oldSphereCylinderShape) { dx2 = dx == 0 ? .5f : (dx * dx) / 4.0f; dz2 = dz == 0 ? .5f : (dz * dz) / 4.0f; davg = (dx + dz) / 2; } else { float factor = 1.7f; dx2 = dx == 0 ? .5f : ((dx + factor) * (dx + factor)) / 4.0f; dz2 = dz == 0 ? .5f : ((dz + factor) * (dz + factor)) / 4.0f; davg = (int) ((dx + dz + factor * 2) / 2); } for (int ox = 0 ; ox < dx ; ox++) { int x = tl.getX() + ox; if (xInChunk(x, chunk)) { for (int oz = 0; oz < dz; oz++) { int z = tl.getZ() + oz; if (zInChunk(z, chunk)) { for (int oy = 0; oy < dy; oy++) { int y = tl.getY() + oy; if (y >= 0 && y < 255) { if (isInside2D(centerx, centerz, x, z, dx2, dz2, davg) == 1) { int cnt; if (solid) { cnt = 0; } else { cnt = isInside2D(centerx, centerz, x - 1, z, dx2, dz2, davg); cnt += isInside2D(centerx, centerz, x + 1, z, dx2, dz2, davg); cnt += isInside2D(centerx, centerz, x, z - 1, dx2, dz2, davg); cnt += isInside2D(centerx, centerz, x, z + 1, dx2, dz2, davg); } if (cnt != 4 || (capped && (oy == 0 || oy == dy - 1))) { placeBlockIfPossible(worldObj, blocks, maxSize, x, y, z, forquarry); } } } } } } } } } private static void composeBox(World worldObj, Coordinate thisCoord, Coordinate dimension, Coordinate offset, Collection<Coordinate> blocks, int maxSize, boolean solid, boolean forquarry, ChunkCoordIntPair chunk) { int xCoord = thisCoord.getX(); int yCoord = thisCoord.getY(); int zCoord = thisCoord.getZ(); int dx = dimension.getX(); int dy = dimension.getY(); int dz = dimension.getZ(); Coordinate tl = new Coordinate(xCoord - dx/2 + offset.getX(), yCoord - dy/2 + offset.getY(), zCoord - dz/2 + offset.getZ()); for (int ox = 0 ; ox < dx ; ox++) { int x = tl.getX() + ox; if (xInChunk(x, chunk)) { for (int oz = 0 ; oz < dz ; oz++) { int z = tl.getZ() + oz; if (zInChunk(z, chunk)) { for (int oy = 0; oy < dy; oy++) { int y = tl.getY() + oy; if (y >= 0 && y < 255) { if (solid || ox == 0 || oy == 0 || oz == 0 || ox == (dx - 1) || oy == (dy - 1) || oz == (dz - 1)) { placeBlockIfPossible(worldObj, blocks, maxSize, x, y, z, forquarry); } } } } } } } } private static void composePrism(World worldObj, Coordinate thisCoord, Coordinate dimension, Coordinate offset, Collection<Coordinate> blocks, int maxSize, boolean forquarry, ChunkCoordIntPair chunk) { int xCoord = thisCoord.getX(); int yCoord = thisCoord.getY(); int zCoord = thisCoord.getZ(); int dx = dimension.getX(); int dy = dimension.getY(); int dz = dimension.getZ(); Coordinate tl = new Coordinate(xCoord - dx/2 + offset.getX(), yCoord - dy/2 + offset.getY(), zCoord - dz/2 + offset.getZ()); for (int oy = 0 ; oy < dy ; oy++) { int y = tl.getY() + oy; if (y >= 0 && y < 255) { int yoffset = oy; for (int ox = 0 ; ox < dx ; ox++) { if (ox >= yoffset && ox < dx-yoffset) { int x = tl.getX() + ox; if (xInChunk(x, chunk)) { for (int oz = yoffset; oz < dz - yoffset; oz++) { int z = tl.getZ() + oz; if (zInChunk(z, chunk)) { if (ox == yoffset || oy == 0 || oz == yoffset || ox == (dx - yoffset - 1) || oz == (dz - yoffset - 1)) { placeBlockIfPossible(worldObj, blocks, maxSize, x, y, z, forquarry); } } } } } } } } } private static int isInsideTorus(float centerx, float centery, float centerz, int x, int y, int z, float bigRadius, float smallRadius) { double rr = bigRadius - Math.sqrt((x-centerx)*(x-centerx) + (z-centerz)*(z-centerz)); double f = rr*rr + (y-centery) * (y-centery) - smallRadius * smallRadius; if (f < 0) { return 1; } else { return 0; } } private static void composeTorus(World worldObj, Coordinate thisCoord, Coordinate dimension, Coordinate offset, Collection<Coordinate> blocks, int maxSize, boolean solid, boolean forquarry, ChunkCoordIntPair chunk) { int xCoord = thisCoord.getX(); int yCoord = thisCoord.getY(); int zCoord = thisCoord.getZ(); int dx = dimension.getX(); int dy = dimension.getY(); int dz = dimension.getZ(); float centerx = xCoord + offset.getX(); float centery = yCoord + offset.getY(); float centerz = zCoord + offset.getZ(); Coordinate tl = new Coordinate(xCoord - dx/2 + offset.getX(), yCoord - dy/2 + offset.getY(), zCoord - dz/2 + offset.getZ()); float smallRadius = (dy-2)/2.0f; float bigRadius = (dx-2)/2.0f - smallRadius; for (int ox = 0 ; ox < dx ; ox++) { int x = tl.getX() + ox; if (xInChunk(x, chunk)) { for (int oz = 0 ; oz < dz ; oz++) { int z = tl.getZ() + oz; if (zInChunk(z, chunk)) { for (int oy = 0; oy < dy; oy++) { int y = tl.getY() + oy; if (y >= 0 && y < 255) { if (isInsideTorus(centerx, centery, centerz, x, y, z, bigRadius, smallRadius) == 1) { int cnt; if (solid) { cnt = 0; } else { cnt = isInsideTorus(centerx, centery, centerz, x - 1, y, z, bigRadius, smallRadius); cnt += isInsideTorus(centerx, centery, centerz, x + 1, y, z, bigRadius, smallRadius); cnt += isInsideTorus(centerx, centery, centerz, x, y, z - 1, bigRadius, smallRadius); cnt += isInsideTorus(centerx, centery, centerz, x, y, z + 1, bigRadius, smallRadius); cnt += isInsideTorus(centerx, centery, centerz, x, y - 1, z, bigRadius, smallRadius); cnt += isInsideTorus(centerx, centery, centerz, x, y + 1, z, bigRadius, smallRadius); } if (cnt != 6) { placeBlockIfPossible(worldObj, blocks, maxSize, x, y, z, forquarry); } } } } } } } } } @Override public void registerIcons(IIconRegister iconRegister) { icons[CARD_SHAPE] = iconRegister.registerIcon(RFTools.MODID + ":shapeCardItem"); icons[CARD_VOID] = iconRegister.registerIcon(RFTools.MODID + ":shapeCardVoidItem"); icons[CARD_QUARRY] = iconRegister.registerIcon(RFTools.MODID + ":shapeCardQuarryItem"); icons[CARD_QUARRY_SILK] = iconRegister.registerIcon(RFTools.MODID + ":shapeCardSilkItem"); icons[CARD_QUARRY_FORTUNE] = iconRegister.registerIcon(RFTools.MODID + ":shapeCardFortuneItem"); icons[CARD_QUARRY_CLEAR] = iconRegister.registerIcon(RFTools.MODID + ":shapeCardCQuarryItem"); icons[CARD_QUARRY_CLEAR_SILK] = iconRegister.registerIcon(RFTools.MODID + ":shapeCardCSilkItem"); icons[CARD_QUARRY_CLEAR_FORTUNE] = iconRegister.registerIcon(RFTools.MODID + ":shapeCardCFortuneItem"); } @SideOnly(Side.CLIENT) @Override public IIcon getIconIndex(ItemStack stack) { int damage = stack.getItemDamage(); return icons[damage]; } @Override public String getUnlocalizedName(ItemStack itemStack) { if (itemStack.getItemDamage() == 0) { return super.getUnlocalizedName(itemStack); } else { return super.getUnlocalizedName(itemStack) + itemStack.getItemDamage(); } } @Override public void getSubItems(Item item, CreativeTabs creativeTabs, List list) { for (int i = 0 ; i < icons.length ; i++) { list.add(new ItemStack(this, 1, i)); } } }