/*
 * Build Commands for WorldEdit
 * Copyright (C) 2013 inHaze <http://bit.ly/inHaze>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
		
importPackage(Packages.java.awt.image);			//used for map images	
importPackage(Packages.javax.imageio);
importPackage(Packages.java.io);			//saving and reading files
importPackage(Packages.org.bukkit);			//bukkit specific items
importPackage(Packages.com.sk89q.worldedit);		//rest of the worldedit stuff	
importPackage(Packages.com.sk89q.worldedit.blocks);
importPackage(Packages.com.sk89q.worldedit.patterns);
importPackage(Packages.com.sk89q.worldedit.vector);
importPackage(Packages.com.sk89q.worldedit.regions);
importPackage(Packages.com.sk89q.worldedit.regions.region);
importPackage(Packages.com.sk89q.worldedit.tools);
importPackage(Packages.com.sk89q.worldedit.tools.brushes);

var version = "1.0";
var stage = 0;
var invert = 1;
var zVec = Vector(0,0,0);
var gVec = Vector(0,0,0);
var gSize = -1;

context.getSession().setTool(player.getItemInHand(), null)
var tool = context.getSession().getBrushTool(player.getItemInHand());
var airMat = new SingleBlockPattern(new BaseBlock(0,1));		
var gMat = airMat;

tool.setSize(gSize);
tool.setFill(gMat);

var offsetVec = [];
var entityList = [];
var oreList = [];
var vecList = [];
var myKit = [];
var myShape = [];
var tools = [];
var trees = [];
var shapes = [];
var blocks = [];
var text = [];

SetObjectGroups();

var modeArg = argv.length > 1 ? argv[1] : 2;
var mode = parseMode(modeArg);		//test and return a good mode value

var brush = new Brush({		//Setup the brush - This is what runs each time it's clicked
    build : function(editSession,posB,mat,size) {
		
		try	{
			var pos = checkFlag("~") ? player.getBlockTrace(parseInt(checkFlag("~")), true) : player.getBlockTrace(200, false);
			if (pos == null) { return; }

			vecList.unshift(pos);
			
			var blackList = [6,31,32,37,38,39,30,78];	//Move the position down one if a natural block is clicked (grass, flowers, etc)
			if (parseInt(blackList.indexOf(editSession.getBlock(pos).getType())) != -1)	{
				pos = pos.add(0,-1,0);
			}
			
			gMat = ((mat.next(0,0,0).getType() == 0) && (mat.next(0,0,0).getData() == 1)) ? gMat : mat;		//set gMat if brush mat has changed
			gSize = size != -1 ? size : -1; 
			invert = pos.getY() <= player.getBlockIn().getY() ? 1 : -1;
			
			tools[mode].mySub(pos, editSession);		//run the function for the specified mode
			
			if(editSession.getBlock(player.getBlockIn().add(0,1,0)).getType() != 0)	{		//if player has been covered, find free spot
				player.findFreePosition();
			}
		}
		catch (e)	{
			//player.print(text.Red + "Error! " + text.White + String(e));
			if ((String(e)) != "ReferenceError: \"aError\" is not defined.")	{
				player.print(text.Red + "Error! " + text.White + String(e));
			}
		}
    },
	
});

if (argv.length < 2)  {
	HelpText(0);
} 
else {
	InitializeBrush();
}

//////////////////////////////////////////////////////////
//				Internal Utility Functions
//////////////////////////////////////////////////////////

function SetObjectGroups()	{

	oreList = {
		'1':  {BlockID:  16,			//Coal Ore
			chance:   100,			//Weighted probability, coal ore is considered baseline at 100, use 0 to stop an item from spawning completely
			minSize:   8,			//minimum possible vein size
			maxSize:	16,			//maximum possible vein size
			minY:	0,				//Lowest possible spawning y height
			maxY:	256				//Highest possible spawning y height
		},
		'2':  {BlockID:  15,			//Iron Ore
			chance:   60,
			minSize:   6,
			maxSize:	12,
			minY:	16,
			maxY:	256	
		},
		'3':  {BlockID:  14,			//Gold Ore
			chance:   18,
			minSize:   6,
			maxSize:	10,
			minY:	4,
			maxY:	32
		},
		'4':  {BlockID:  56,			//Diamond Ore
			chance:   16,
			minSize:   4,
			maxSize:	8,
			minY:	0,
			maxY:	16	
		},
		'5':  {BlockID:  21,			//Lapis Lazuli Ore
			chance:   14,
			minSize:   4,
			maxSize:	10,
			minY:	0,
			maxY:	32
		},
		'6':  {BlockID:  73,			//Redstone Ore
			chance:   75,
			minSize:   6,
			maxSize:	10,
			minY:	0,
			maxY:	15
		},
		'7':  {BlockID:  129,			//Emerald Ore
			chance:   .25,
			minSize:   2,
			maxSize:	45,
			minY:	0,
			maxY:	125
		},
		'8':  {BlockID:  12,			//Sand
			chance:   5,
			minSize:   6,
			maxSize:	20,
			minY:	65,
			maxY:	130
		},
		'9':  {BlockID:  13,			//Gravel
			chance:   5,
			minSize:   6,
			maxSize:	16,
			minY:	25,
			maxY:	90
		},
		'10':  {BlockID:  82,			//Clay
			chance:   5,
			minSize:   4,
			maxSize:	12,
			minY:	50,
			maxY:	110
		},
		'11':  {BlockID:  3,			//Dirt
			chance:   5,
			minSize:   4,
			maxSize:	12,
			minY:	60,
			maxY:	175
		},
		'12':  {BlockID:  45,			//Bricks - Test Item
			chance:   0,
			minSize:   10,
			maxSize:	150,
			minY:	50,
			maxY:	60
		}
	};

	trees = {
		'bush':  {
			woodBlock:  new BaseBlock(BlockID.LOG),			
			leafBlock:   new BaseBlock(BlockID.LEAVES, 4),			
			minSize:   6,
			maxChg:	0,
			leafSize: 5,
			mySub:	CreateBush
		},
		'small':  {
			woodBlock:  new BaseBlock(BlockID.LOG),			
			leafBlock:   new BaseBlock(BlockID.LEAVES, 4),			
			minSize:   6,
			maxChg:	0,
			leafSize: 5,
			mySub:	CreateSmallTree
		},
		'medium':  {
			woodBlock:  new BaseBlock(BlockID.LOG),			
			leafBlock:   new BaseBlock(BlockID.LEAVES, 4),			
			minSize:  5,
			maxChg:	8,
			branchSize:	.5,
			leafSize:	7,
			mySub:	CreateMediumTree
		},
		'large':  {
			woodBlock:  new BaseBlock(BlockID.LOG),			
			leafBlock:   new BaseBlock(BlockID.LEAVES, 4),			
			minSize:  20,
			maxChg:	8,
			branchSize:	.1,
			branchProb:	.5,
			leafSize:	7,
			mySub:	CreateLargeTree
		},
		'branched':  {
			woodBlock:  new BaseBlock(BlockID.LOG),			
			leafBlock:   new BaseBlock(BlockID.LEAVES, 4),			
			minSize:  25,
			maxChg:	1,
			branchSize1:	.3,
			branchSize2:	.15,
			branchSize3:	.1,
			branchProb1:	.7,
			branchProb2:	.7,
			branchProb3:	.7,
			leafSize:	13,
			mySub:	CreateBranchedTree
		},			
		'rainforest':  {
			woodBlock:  new BaseBlock(BlockID.LOG, 3),			
			leafBlock:   new BaseBlock(BlockID.LEAVES, 7),			
			minSize:  20,
			maxChg:	8,
			branchSize:	.15,
			branchProb:	.6,
			branchHeight: .6,
			leafSize:	12,
			mySub:	CreateRainforestTree
		},
		'palm':  {
			woodBlock:  new BaseBlock(BlockID.LOG),			
			leafBlock:   new BaseBlock(BlockID.LEAVES, 4),			
			minSize:  5,
			maxChg:	4,
			branchSize:	.5,
			leafSize:	3,
			mySub:	CreatePalmTree
		},
		'stick':  {
			woodBlock:  new BaseBlock(BlockID.LOG, 0),
			leafBlock:   new BaseBlock(BlockID.LEAVES, 4),				
			minSize:  1,
			density:	.1,
			maxChg:	3,
			mySub:	CreateStickTree
		},
		'mushroom':  {
			woodBlock:  new BaseBlock(35, 4),			
			leafBlock:   new BaseBlock(35, 14),			
			minSize:  15,
			maxChg:	40,
			leafSize:	25,
			mySub:	CreateMushroom
		},
		'spike':  {
			woodBlock:  new BaseBlock(BlockID.LOG),			
			leafBlock:   new BaseBlock(BlockID.LEAVES, 4),			
			minSize:  25,
			maxChg:	1,
			branchSize1:	.3,
			branchSize2:	.15,
			branchSize3:	.1,
			branchProb1:	.7,
			branchProb2:	.7,
			branchProb3:	.7,
			leafSize:	13,
			mySub:	CreateSpikeTree
		}		
	}
	
	shapes = {
		'PalmLeaf':  {
			offset:	Vector(0,0,0),
			angle: 0,
			shape: {
				'1': {vec: Vector(0,1,0), id: "18:4"},
				'2': {vec: Vector(0,2,0), id: "18:4"},
				'3': {vec: Vector(1,1,0), id: "18:4"},
				'4': {vec: Vector(1,2,0), id: "18:4"},
				'5': {vec: Vector(2,1,0), id: "18:4"},
				'6': {vec: Vector(3,1,0), id: "18:4"},
				'7': {vec: Vector(3,0,0), id: "18:4"},
				'8': {vec: Vector(4,0,0), id: "18:4"},
				'9': {vec: Vector(4,-1,0), id: "18:4"},
				'10': {vec: Vector(1,1,-1), id: "18:4"},
				'11': {vec: Vector(1,1,1), id: "18:4"}
			},
		},
		'Test':  {
			offset:	Vector(0,0,0),
			angle: 0,
			shape: {
				'1': {vec: Vector(0,1,0), id: "18:4"},
				'2': {vec: Vector(0,2,0), id: "18:4"},
				'3': {vec: Vector(1,1,0), id: "18:4"},
				'4': {vec: Vector(1,2,0), id: "18:4"},
				'5': {vec: Vector(2,1,0), id: "18:4"},
				'6': {vec: Vector(3,1,0), id: "18:4"},
				'7': {vec: Vector(3,0,0), id: "18:4"},
				'8': {vec: Vector(4,0,0), id: "18:4"},
				'9': {vec: Vector(4,-1,0), id: "18:4"},
				'10': {vec: Vector(1,1,-1), id: "18:4"},
				'11': {vec: Vector(1,1,1), id: "18:4"},
				'12': {vec: Vector(2,2,0), id: "5:1"},
				'13': {vec: Vector(4,1,0), id: "5:1"},
				'14': {vec: Vector(3,2,0), id: "50:1"},
				'15': {vec: Vector(5,1,0), id: "50:1"}
			},
		}		

	}

	blocks = {
		'plants':	{
			list:	{
					'0':  {block: new BaseBlock(31, 1), chance: 100, },
					'1':  {block: new BaseBlock(31, 2), chance: 100, },
					'2':  {block: new BaseBlock(37, 0), chance: 5, },
					'3':  {block: new BaseBlock(38, 0), chance: 5, },
					'4':  {block: new BaseBlock(86, 0), chance: .2, },
					'5':  {block: new BaseBlock(103, 0), chance: .2,}
			}
		},
		'ruin':	{
			list:	{
					'0':  {block: new BaseBlock(98, 0), chance: 100, },
					'1':  {block: new BaseBlock(98, 1), chance: 100, },
					'2':  {block: new BaseBlock(98, 2), chance: 100, },
					'3':  {block: new BaseBlock(98, 3), chance: 5, },
					'4':  {block: new BaseBlock(109, 0), chance: 10, },
					'5':  {block: new BaseBlock(109, 4), chance: 10, },
					'6':  {block: new BaseBlock(44, 5), chance: 5,},
					'7':  {block: new BaseBlock(44, 13), chance: 5,},
					'8':  {block: new BaseBlock(97, 2), chance: 1,}
			}
		}		
	}
	
	text = {
		'Black': "\u00A70",
		'DarkBlue': "\u00A71",
		'DarkGreen': "\u00A72",
		'DarkAqua': "\u00A73",
		'DarkRed': "\u00A74",
		'Purple': "\u00A75",
		'Gold': "\u00A76",
		'Grey': "\u00A77",
		'DarkGrey': "\u00A78",
		'Indigo': "\u00A79",
		'BrightGreen': "\u00A7a",
		'Aqua': "\u00A7b",
		'Red': "\u00A7c",
		'Pink': "\u00A7d",
		'Yellow': "\u00A7e",
		'White': "\u00A7f",
		'Random': "\u00A7k",
		'Bold': "\u00A7l",
		'Strike': "\u00A7m",
		'Underline': "\u00A7n",
		'Italics': "\u00A7o",		
		'Reset': "\u00A7r",
		'Not': "\u00AC",
		'Bar': "\u007C",
		'Arrow': "\u00BB",
	}
	
	tools = {
		'0':  {name:  "Help",			
			note:  "General, or command specific info.",			
			args:   ["command"],
			aFlags:	[""],
			keys: 	["help", "h", "?"],
			brush:	0,
			mySub:	HelpText,
		},
		'1':  {name:  "Command List(Short)",			
			note:  "List Commands - Short",			
			args:  [""],
			aFlags:	[""],
			keys:  ["list", "shortlist"],
			brush:	0,
			mySub:	CommandListShort,
		},
		'2':  {name:  "Command List(Long)",			
			note:  "List Commands - Long",			
			args:  [""],
			aFlags:	[""],
			keys:  ["commands", "command", "longlist"],
			brush:	0,
			mySub:	CommandList,
		},
		'3':  {name:  "Clear Nature",			
			note:  "Destroys and clears all natural blocks.",			
			args:  ["size"],
			aFlags:	["s"],
			keys:  ["clear", "killnature", "kill", "kn", "clearnature"],
			brush:	1,
			mySub:	ClearNature,
		},
		'4':  {name:  "Tree",			
			note:  "Creates a randomly generated tree type.",			
			args:   ["treeType", "size", "woodBlock", "leafBlock", "clump"],
			aFlags:	["", "s", "w", "l", "c"],
			keys: 	["tree"],
			brush:	1,
			mySub:	BuildTree,
		},
		'5':  {name:  "Grass Patch",			
			note:  "Creates a random patch of long grass(super bonemeal!)",			
			args:  ["size", "density"],
			aFlags:	["s", "d"],
			keys:  ["grass", "grasspatch", "bonemeal"],
			brush:	1,
			mySub:	BuildGrassPatch,
		},
		'6':  {name:  "Stick Patch",			
			note:  "Creates a random patch of blocks to random custom heights.",			
			args:  ["size", "block", "minLength,maxChg", "density"],
			aFlags:	["s", "b", "l", "d"],
			keys:  ["stickpatch", "stick"],
			brush:	1,
			mySub:	BuildStickPatch,
		},		
		'7':  {name:  "Overlay",			
			note:  "Covers all natural items to custom blocks and depths.",			
			args:  ["size", "topBlock,depth", "mid,depth", "end,depth", "all"],
			aFlags:["s", "t", "m", "e", "a"],
			keys:  ["overlay", "overlaypatch", "over"],
			brush:	1,
			mySub:	BuildOverlayPatch,
		},			
		'8':  {name:  "Spike",			
			note:  "Creates a custom spike wherever clicked.",			
			args:  ["baseSize", "block", "minLength,maxChg"],
			aFlags:["s", "b", "l"],
			keys:  ["spike", "cone"],
			brush:	1,
			mySub:	BuildSpike,
		},
		'9':  {name:  "Vine",			
			note:  "Smart custom vine brush.",			
			args:  ["size", "density", "length", "block", ],
			aFlags:["s", "d", "l", "b"],
			keys:  ["vine", "vines"],
			brush:	1,
			mySub:	BuildVines,
		},
		'10':  {name:  "Test",			
			note:  "Function Testing Area",			
			args:  [""],
			aFlags:	[""],
			keys:  ["test"],
			brush:	1,
			mySub:	BuildTest,
		},
		'11':  {name:  "Save Shape",			
			note:  "Save the current selection to shape file.",			
			args:  ["fileName", "excludeBlock"],
			aFlags:	["", "!"],
			keys:  ["save"],
			brush:	1,
			mySub:	saveShape,
		},
		'12':  {name:  "Shape",			
			note:  "Load a shape object from the selection, or shape file.",			
			args:  ["fileName", "angleLock", "excludeID", "select"],
			aFlags:["", "<", "!", "$"],
			keys:  ["shape", "load"],
			brush:	1,
			mySub:	BuildShape,
		},	
		'13':  {name:  "Line",			
			note:  "Draws a custom line in single, continous, or fixed origin mode.",			
			args:  ["mode", "size", "block", "extendCnt"],
			aFlags:	["m", "s", "b", "e"],
			keys:  ["line", "lines"],
			brush:	1,
			mySub:	BuildLine,
		},
		'14':  {name:  "Paint",			
			note:  "Attempts to paint shape objects in rapidfire mode.",			
			args:  ["fileName", "angleLock", "excludeID"],
			aFlags:["", "<", "!"],
			keys:  ["paint", "painter", "draw"],
			brush:	1,
			mySub:	BuildPaint,
		},
		'15':  {name:  "Flatten",			
			note:  "Level all terrain to a custom height.",			
			args:  ["size", "depth", "surfaceBlock"],
			aFlags:["s", "d", "b"],
			keys:  ["flatten", "flat", "level"],
			brush:	1,
			mySub:	BuildFlat,
		},	
		'16':  {name:  "Shape Kit",			
			note:  "Loads, and binds a list of custom shapes.",			
			args:  ["fileName", "angleLock", "excludeID", "select"],
			aFlags:["", "<", "!", "$"],
			keys:  ["kit","shapekit"],
			brush:	1,
			mySub:	BuildShapeKit,
		},
		'17':  {name:  "Platform",			
			note:  "Creates a custom platform, or path under your feet.",			
			args:  ["size", "block"],
			aFlags:	["s", "b"],
			keys:  ["platform", "path"],
			brush:	1,
			mySub:	BuildPlatform,
		},
		'18':  {name:  "Mirror",			
			note:  "Mirrors your current selection around a selected point.",			
			args:  ["shift", "delete"],
			aFlags:	["s", "d"],
			keys:  ["mirror"],
			brush:	1,
			mySub:	BuildMirror,
		},
		'19':  {name:  "Biome",			
			note:  "Creates a brush that paints a custom biome (multiplayer only)",			
			args:  ["biome", "size"],
			aFlags:	["", "#"],
			keys:  ["biome"],
			brush:	1,
			mySub:	BuildBiome,
		},
		'20':  {name:  "Laser",			
			note:  "Shoots a custom beam of blocks from your fingertips!",			
			args:  ["size", "depth", "aboveMat", "belowMat"],
			aFlags:	["s", "d", "a", "b"],
			keys:  ["laser", "beam"],
			brush:	1,
			mySub:	BuildLaser,
		},
		'21':  {name:  "Revolve",			
			note:  "Revolves a 2D slice selection around a center point.",			
			args:  ["count", "useBlock"],
			aFlags:	["c", "b"],
			keys:  ["revolve"],
			brush:	1,
			mySub:	BuildRevolve,
		},
		'22':  {name:  "Rotate",			
			note:  "Rotates a 3D selection to a set angle or # of increments.",			
			args:  ["items/-angleInc", "resolution", "single"],
			aFlags:	["i", "r", "s"],
			keys:  ["rotate"],
			brush:	1,
			mySub:	BuildRotate,
		},
		'23':  {name:  "Erode",			
			note:  "Erode the terrain away using a custom face setting.",			
			args:  ["size", "maxFaces", "iterations"],
			aFlags:	["s", "f", "i"],
			keys:  ["erode"],
			brush:	1,
			mySub:	BuildErode,
		},
		'24':  {name:  "Fill",			
			note:  "Fill the terrain in using a custom face setting.",			
			args:  ["size", "maxFaces", "iterations"],
			aFlags:	["s", "f", "i"],
			keys:  ["fill"],
			brush:	1,
			mySub:	BuildFill,
		},
		'25':  {name:  "Smart Wand",			
			note:  "A smarter, more user friendly selection wand.",			
			args:  [""],
			aFlags:	[""],
			keys:  ["wand"],
			brush:	1,
			mySub:	BuildWand,
		},
		'26':  {name:  "Ore Generator",			
			note:  "Generates new veins of ore based on custom settings.",			
			args:  ["size", "overBlock", "density", "region"],
			aFlags:	["s", "b", "d", "r"],
			keys:  ["ore", "ores"],
			brush:	1,
			mySub:	BuildOre,
		},
		'27':  {name:  "Fragment",			
			note:  "Creates a fragmented sphere shape.",			
			args:  ["size", "block", "density", "hollow"],
			aFlags:	["s", "b", "d", "h"],
			keys:  ["fragment", "frag"],
			brush:	1,
			mySub:	BuildFragment,
		},
		'28':  {name:  "Spawner",			
			note:  "Creates an entity mob spawner. (multiplayer only)",			
			args:  ["spawnerType"],
			aFlags:	[""],
			keys:  ["spawner", "spawn"],
			brush:	1,
			mySub:	BuildSpawner,
		},
		'29':  {name:  "Kill",			
			note:  "A special brush that kills entites. (Unstable!) (multiplayer only)",			
			args:  ["entityType", "size"],
			aFlags:	["", "s"],
			keys:  ["kill", "killer"],
			brush:	1,
			mySub:	BuildKiller,
		},
		'30':  {name:  "Pattern",			
			note:  "Replaces blocks with a custom predefined set.",			
			args:  ["blockSet", "size"],
			aFlags:	["b", "s"],
			keys:  ["pattern", "pat", "replace"],
			brush:	1,
			mySub:	BuildPattern,
		},
		'31':  {name:  "Array",			
			note:  "Arrays a selection up to 3 different directions.",			
			args:  ["totalA", "totalB", "totalC"],
			aFlags:	["a", "b", "c"],
			keys:  ["array", "stack"],
			brush:	1,
			mySub:	BuildArray,
		},
		'32':  {name:  "Map",			
			note:  "Saves a map of the area around you to a image file.",			
			args:  ["fileName", "size", "heightMap"],
			aFlags:	["", "s", "h"],
			keys:  ["map"],
			brush:	1,
			mySub:	BuildMap,
		},	
		'33':  {name:  "Flip",			
			note:  "Flips the current selection around the clicked point.",			
			args:  ["shift", "delete"],
			aFlags:	["s", "d"],
			keys:  ["flip"],
			brush:	1,
			mySub:	BuildFlip,
		},
		'34':  {name:  "Box",			
			note:  "Creates a custom sized rectangle box brush.",			
			args:  ["xSize", "ySize", "zSize", "hollow", "angled", "block", "insideBlock"],
			aFlags:	["x", "y", "z", "h", "a", "b", "i"],
			keys:  ["box", "rect", "rectangle"],
			brush:	1,
			mySub:	BuildBox,
		},
		'35':  {name:  "Ellipse",			
			note:  "Creates a custom size ellipse brush",			
			args:  ["xSize", "ySize", "zSize", "hollow", "angled", "block", "insideBlock"],
			aFlags:	["x", "y", "z", "h", "a", "b", "i"],
			keys:  ["ellipse"],
			brush:	1,
			mySub:	BuildEllipse,
		},
		'36':  {name:  "Spiral",			
			note:  "Creates a custom spiral object.",			
			args:  ["radius/-growth", "stretch", "count", "flip", "double"],
			aFlags:	["r", "s", "c", "f", "d"],
			keys:  ["spiral"],
			brush:	1,
			mySub:	BuildSpiral,
		},
		'37':  {name:  "Minesweeper",			
			note:  "Play a game of Minesweeper, Minecraft style!",			
			args:  ["xSize", "ySize", "mines", "wool", "cheat", "begginer/intermediate/expert", "hardcore"],
			aFlags:	["x", "y", "m", "w", "c", "b/i/e", "h"],
			keys:  ["minesweeper", "mine", "sweeper"],
			brush:	1,
			mySub:	BuildMineSweeper,
		},		
		
	}
	
}

function InitializeBrush()	{

	var mySession = context.remember();

	if (mode != -1)	{	//check to see if the mode exists or not
		
		if (checkFlag("?") != false )	{ 
			HelpText(1); 
			context.getSession().setTool(player.getItemInHand(), null);
			return;
		}
		
		if (tools[mode].brush == 1)	{

			var tmpStr = new Array();
			var errStr = new Array();
			switch (tools[mode].name)	{
				case "Save Shape":
					tmpStr = (text.White + text.Italics + "Click to specify shape origin point.");
					if (argv.length < 3) 	{
						var errStr = (text.Red + "Error:" + text.White + " You need to specify a file name to save under.");
						player.print(errStr);
					}
					break;
				case "Shape":
					if ((argv.length < 3) || (String(argv[2]) == "-")) 	{
						tmpStr = (text.White + text.Italics + "Click to specify selection shape origin point.");
					}
					else	{
						
						BuildShape(Vector(0,0,0), mySession)
						tool.setBrush(brush, "worldedit.brush.build");
						var errStr = "ShapeLoaded";
					}
					break;
				case "Shape Kit":
					if (argv.length < 3) 	{
						var errStr = (text.Red + "Error:" + text.White + " You need to specify a .kit file name to load.");
						player.print(errStr);
					}
					else	{
						BuildShapeKit(Vector(0,0,0), mySession)
						var errStr = "ShapeKitLoaded";
					}
					break;
				case "Biome":
					if (BuildBiome((0,0,0), mySession) == false)	{return;}
					tmpStr = (text.Red + text.Italics + "Changes won't become effective until a chunk reload.");

					break;
				case "Smart Wand":
					BuildWand(zVec, mySession);
					player.print(text.Gold + "Smart Wand" + text.White + " tool bound to " + text.Gold + ItemType.toHeldName(player.getItemInHand()) + ". " );
					return;
				default:
					tmpStr = (text.White + text.Italics + "Ready for first point.");
					break;
			}
			
			if(errStr.length < 2)	{
				tool.setBrush(brush, "worldedit.brush.build");
				player.print(text.Gold + tools[mode].name + text.White + " brush bound to " + text.Gold + ItemType.toHeldName(player.getItemInHand()) + ". " );
				if (tmpStr.length > 0) {player.print(tmpStr);}
			}
		}
		else{
			var mySession = context.remember(); 
			var pos = player.getBlockTrace(200);
			invert = pos.getY() <= player.getBlockIn().getY() ? 1 : -1;
			tools[mode].mySub(pos, mySession);
		}
	}
	else	{
		player.print(text.Red + modeArg + text.White + " mode not found. Type " + text.Gold + "/cs build list" + text.White + " for commands.");
	}


}

function loadShape(vec, session)	{

	if ((argv.length > 2) && (String(argv[2]) != "-"))	{

		var aStr = String(argv[2]).slice(String(argv[2]).length-4).toLowerCase();
		type = aStr == ".bo2" ? 2 : 1;

		if (type == 1)	{		// shape file type
			
			var fileName = argv[2];
			if (aStr == ".shp")	{fileName = String(argv[2]).slice(0, String(argv[2]).length-4).toLowerCase()};

			var file = context.getSafeFile("shapes", String(fileName) + '.shp');
			if(!file.exists()){
				player.print(text.Red + "Error! " + text.Gold + "Could not find shape file: " + text.White + text.Italics + file);
				return false;
			}
			
			var tmpStr = loadFile(fileName, 1);
			var tmpShape = parseShapeFile(tmpStr);
			player.print(text.Gold + tmpShape['TMP'].shape.length + text.White + " blocks loaded from file: " + text.Gold + fileName + ".shp");
			player.print(text.White + text.Italics + "Ready to place shape object.");
			
		}
		else if (type == 2)	{		// bo2 file type
		
			var fileName = argv[2];
			var file = context.getSafeFile("bo2s", String(fileName));
			if(!file.exists()){
				player.print(text.Red + "Error! " + text.Gold + "Could not find bo2 file: " + text.White + text.Italics + file);
				return false;
			}
			
			var tmpStr = loadFile(fileName, 2);
			var tmpShape = parseBO2File(tmpStr);
			player.print(text.Gold + tmpShape['TMP'].shape.length + text.White + " blocks loaded from file: " + text.Gold + fileName);
			player.print(text.White + text.Italics + "Ready to place shape object.");
		}
		
	}
	else {		//no file specified, use selection
		var tmpStr = saveShape(vec, session);
		var tmpShape = parseShapeFile(tmpStr);
		player.print(text.Gold + tmpShape['TMP'].shape.length + text.White +" blocks loaded from current selection.");
		player.print(text.White + text.Italics + "Ready to place shape object.");
	}
	
	myShape = tmpShape;

}

function loadShapeKit(vec, session, kitList)	{

	for (inc in kitList)	{

		fStr = kitList[inc].shapeFile;
		var aStr = String(fStr).slice(String(fStr).length-4).toLowerCase();
		type = aStr == ".bo2" ? 2 : 1;

		if (type == 1)	{		// shape file type
			
			var fileName = fStr;
			if (aStr == ".shp")	{fileName = String(fStr).slice(0, String(fStr).length-4).toLowerCase()};
			
			var file = context.getSafeFile("shapes", String(fileName) + '.shp');
			if(!file.exists()){
				player.print(text.Red + "Error! " + text.Gold + "Could not find shape file: " + text.White + text.Italics + file);
				continue;
			}
			
			var tmpStr = loadFile(fileName, 1);
			var tmpShape = parseShapeFile(tmpStr);
			player.print(text.White + "Shape file: " + text.Gold + fileName + ".shp" + text.White + " bound to " + text.Gold + ItemType.toHeldName(kitList[inc].item));
			player.giveItem(kitList[inc].item, 1);
		}
		else if (type == 2)	{		// bo2 file type
		
			var fileName = fStr;
			var file = context.getSafeFile("bo2s", String(fileName));
			if(!file.exists()){
				player.print(text.Red + "Error! " + text.Gold + "Could not find bo2 file: " + text.White + text.Italics + file);
				continue;
			}
			
			var tmpStr = loadFile(fileName, 2);
			var tmpShape = parseBO2File(tmpStr);
			player.print(text.White + "Shape file: " + text.Gold + fileName + text.White + " bound to " + text.Gold + ItemType.toHeldName(kitList[inc].item));
			player.giveItem(kitList[inc].item, 1);
		}
		
		myShape[inc] = tmpShape['TMP'];
	
	}
	player.print(text.White + text.Italics + "Finished loading shapes!"); 
	
}

function saveShape(vec, session)	{

	if ((argv.length > 2) && (String(argv[2]) != "-"))	{
		saveName = argv[2];
	}
	else	{
		if (tools[mode].name == "Save Shape")	{
			player.print(text.Red + "Error:" + text.White + " You need to specify a file name to save under.");
			return false;
		}
	}
	var ignore = checkFlag("!") ? parseBlock(checkFlag("!")) : -1;
	
	var world = context.getSession().getSelectionWorld();
	var region = context.getSession().getSelection(world);
	
	var angle = (parseInt(getDirection().rightAngle)+270) % 360;
	//var angleStr = "^" + String(angle) + "^";
	
	var mergeStr = "^" + String(angle) + "^" + "#0,0,0#|";
	var blockCnt = 0;
	
	for (var x = 0; x < region.getWidth(); x++) {
		for (var y = 0; y < region.getHeight(); y++) {
			for (var z = 0; z < region.getLength(); z++) {
				
				var tmpVec = region.getMinimumPoint().add(x, y, z);
				var block = session.getBlock(tmpVec);
				if (ignore != -1)	{
					if (block.getType() == ignore.getType())	{continue;}
				}
				var blockStr = String(block.getType()) + ":" + String(block.getData());
				var vecStr = String(tmpVec.getX()-vec.getX()) + "," + String(tmpVec.getY()-vec.getY()) + "," + String(tmpVec.getZ()-vec.getZ());
				
				mergeStr = mergeStr + (blockStr + "@" + vecStr + "|");
				blockCnt++;
			}
		}
	}
	
	mergeStr += "%";
	
	if (tools[mode].name == "Save Shape") {
		var file = context.getSafeFile("shapes", String(saveName) + '.shp');
		saveFile(saveName, mergeStr);
		player.print(text.Gold + blockCnt + text.White + " blocks saved to shape file " + text.Gold + saveName + ".shp" + text.Red + " @ " + text.White + text.Italics + file);
	}
	else	{
		return mergeStr;
	}
	//player.print(blockCnt + " totals blocks saved. [" + mergeStr.length + " total chars]");
	
}

function loadFile(fileName, type)	{
	
	if (type == 1)	{
		var file = context.getSafeFile("shapes", String(fileName) + '.shp');
	}
	else if (type == 2)	{
		var file = context.getSafeFile("bo2s", String(fileName));
	}
	else if (type == 3)	{
		var file = context.getSafeFile("shapes", String(fileName) + '.kit');
	}

	if(!file.exists()){
		return 0;
	}
	
	var buffer = new BufferedReader(new FileReader(file));
	var bufStr = new Array();

	while (line = buffer.readLine()) {
		bufStr = bufStr + line;
		if (type == 2 || type == 3)	{
			bufStr = bufStr + "\n";
		}
	}
	buffer.close();
	return bufStr;

}

function saveFile(fileName, textStr)	{

	var file = context.getSafeFile("shapes", String(fileName) + '.shp');
	
	if(!file.exists()){
		file.createNewFile();
	}
	
	buffer = new BufferedWriter(new FileWriter(file));
	buffer.write(String(textStr));
	buffer.close();
	
}

function parseShapeFile(shapeStr)	{

	var tmpShape = new Array();
	
	tmpShape = {
		'TMP':  {
			offset:	Vector(0,0,0),
			shape: []
									
		}
	}
	
		//	 |17:4@25,3,-6|
	var cnt = 0;
	var inc = 0;
	while (inc <= shapeStr.length)	{
	
		if (shapeStr.slice(inc+1, inc+2) == "%")	{
	
			break;
		}
		else if (shapeStr.slice(inc, inc+1) == "^")	{
			
			var anglePos = shapeStr.indexOf("^", inc+1);
			var angleInc = anglePos+1;
			var anglePos2 = anglePos;
			tmpShape['TMP'].angle = String(shapeStr.slice(inc+1, anglePos2));
			inc = angleInc;
		}
		else if (shapeStr.slice(inc, inc+1) == "#")	{
			
			var offsetPos = shapeStr.indexOf("#", inc+1);
			var offsetInc = offsetPos+1;
			var offsetPos2 = offsetPos;
			tmpShape['TMP'].offset = parseVector(String(shapeStr.slice(inc+1, offsetPos2)));
			inc = offsetInc;
		}
		else if (shapeStr.slice(inc, inc+1) == "|")	{

			var blockPos = shapeStr.indexOf("@", inc+1);
			var blockInc = blockPos;
			var blockPos2 = blockPos;
			var block = parseBlock(String(shapeStr.slice(inc+1, blockPos2)));
					
			var vecPos = shapeStr.indexOf("|", blockInc);
			var vecInc = vecPos+1;
			var vecPos2 = vecPos;
			var vec = parseVector(String(shapeStr.slice(blockPos+1, vecPos2)));
			
			var abc = "'" + cnt + "'";
			
			idStr = block.getType() + ":" + block.getData();
			
			tmpShape['TMP'].shape.push({vec: vec, id: idStr});
			
			inc = vecInc-1;
			cnt++;
		}
		else	{

			inc++;
		}
		

	}
	return tmpShape;
}

function parseBO2File(shapeStr)	{

	var tmpShape = new Array();
	
	tmpShape = {
		'TMP':  {
			offset:	Vector(0,0,0),
			angle: 0,
			shape: []
		}
	}
	
	var inc = shapeStr.indexOf("[DATA]");

	while (inc <= shapeStr.length)	{
		if (shapeStr.slice(inc, inc+1) == "\n")	{

			var vecPos = shapeStr.indexOf(":", inc+1);
			if (vecPos != -1)	{
			
				var vecInc = vecPos;
				var vecPos2 = vecPos;
				var vec = parseVector(String(shapeStr.slice(inc+1, vecPos2)));
				vec = Vector(vec.getX(), vec.getZ()+1, vec.getY());
				
				var blockPos = shapeStr.indexOf("\n", vecInc);
				var blockInc = blockPos+1;
				var blockPos2 = blockPos;
				
				var block = parseBlock(String(shapeStr.slice(vecPos+1, blockPos2)));
				var idStr = block.getType() + ":" + block.getData();

				tmpShape['TMP'].shape.push({vec: vec, id: idStr});
				
				inc = blockInc-1;
			}
			else 	{
				inc++
			}
		}
		else	{
			inc++;
		}
	}
	return tmpShape;
}

function parseKitFile(kitStr)	{

	var tmpKit = [];
	var inc = 0;
	kitStr = "\n" + kitStr + "\n";

	while (inc <= kitStr.length)	{
		if (kitStr.slice(inc, inc+1) == "\n")	{

			var shapePos = kitStr.indexOf(":", inc+1);
			if (shapePos != -1)	{
				var shapeInc = shapePos;
				var shapePos2 = shapePos;
				var fileStr = String(kitStr.slice(inc+1, shapePos2));

				var itemPos = kitStr.indexOf("\n", shapeInc);
				var itemInc = itemPos+1;
				var itemPos2 = itemPos;
				
				var itemID = parseInt(kitStr.slice(shapePos+1, itemPos2));
				tmpKit.push ({shapeFile: fileStr, item: itemID});

				inc = itemInc-1;
			}
			else 	{
				inc++
			}
		}
		else	{
			inc++;
		}
	}
	return tmpKit;
}

function parseBlock(blockStr)	{
	
	blockStr = blockStr.replace(".",":");
	pos = blockStr.indexOf(":");
	
	if (pos == -1)	{return new BaseBlock(parseInt(blockStr), 0);}

	id = blockStr.slice(0, pos);
	data = blockStr.slice(pos+1);

	return new BaseBlock(parseInt(id), parseInt(data));

}

function parseVector(blockStr)	{

	blockStr = blockStr.replace(/["'\(\)]/g, "");
	var pos = blockStr.indexOf(",", 0);
	var pos2 = blockStr.indexOf(",", pos+1);
	
	var x = parseInt(blockStr.slice(0, pos));
	var y = parseInt(blockStr.slice(pos+1, pos2));
	var z = parseInt(blockStr.slice(pos2+1));
	
	return Vector(x, y, z);
}

function parseBlockExtra(blockStr)	{

	pos = blockStr.indexOf(":");
	pos2 = blockStr.indexOf(",");
	var blockExtra = [];

	if ((pos != -1) && (pos2 != -1))	{
	
		blockExtra = {
			block:	new BaseBlock(parseInt(blockStr.slice(0, pos)), blockStr.slice(pos+1, pos2)),	
			extra: parseInt(blockStr.slice(pos2+1))
		}		
	}
	
	if ((pos != -1) &&  (pos2 == -1))	{
	
		blockExtra = {
			block:	new BaseBlock(parseInt(blockStr.slice(0, pos2)), blockStr.slice(pos+1)),	
			extra: 1
		}		
	}
	
	if ((pos == -1) && (pos2 == -1))	{
		blockExtra = {
			block:	new BaseBlock(parseInt(blockStr), 0),	
			extra: 1
		}
	}
	
	if ((pos == -1) && (pos2 != -1))	{
	
		blockExtra = {
			block:	new BaseBlock(parseInt(blockStr.slice(0, pos2)), 0),	
			extra: parseInt(blockStr.slice(pos2+1))
		}		
	}
	
	return blockExtra;
	
}

function parseMode(modeStr)	{

	var modeVal = -1;
	modeStr = String(modeStr).toLowerCase();
	
	for (inc in tools)	{
		for (keyInc in tools[inc].keys)	{
			if (modeStr == tools[inc].keys[keyInc])	{
				modeVal = inc;
			}
		}
	}
	return modeVal;
}

function getRandomXZVec()	{

	var rngVec = new Vector;
	var rng = Math.random();

	switch (true)	{
		case (rng > 0 && rng < .25):
			rngVec = Vector(1,0,0);
			break;
		case (rng >= .25 && rng < .5):
			rngVec = Vector(-1,0,0);
			break;
		case (rng >= .5 && rng < .75):
			rngVec = Vector(0,0,1);
			break;
		case (rng >= .75 && rng < 1):
			rngVec = Vector(0,0,-1);
			break;
	}

	return rngVec;

}

function getRandomXZSide(vec)	{

	var rngVec = new Vector;
	var rng = Math.random();
	var rng2 = Math.random();
	
	if(vec.getX() == 0)	{
		switch (true)	{
			case (rng > 0 && rng < .5):
				rngVec = Vector(rng2,0,0);
				break
			case (rng >= .5 && rng <= 1):
				rngVec = Vector(-(rng2),0,0);
				break;
			
		}
	}
	else	{
		switch (true)	{
			case (rng > 0 && rng < .5):
				rngVec = Vector(0,0,-(rng2));
				break;
			case (rng >= .5 && rng <= 1):
				rngVec = Vector(0,0,rng2);
				break;

		}
	}

	return rngVec;
}

function getListBlock(list)	{

	var tmpList = new Array();
	//var tmpObj = new Object();
	var maxBlock = 0;
	var maxChance = 0;
	var totalChance = 0;

	for (inc in list){
	
		var tmpObj = new Object();
		tmpObj.myBlock = list[inc].block;
		tmpObj.minChance = totalChance;
		tmpObj.maxChance = totalChance + list[inc].chance;
		tmpList.push(tmpObj);
		totalChance += list[inc].chance;
	}
	
	randomProb = Math.random() * totalChance;
	
	for (var inc = 0; inc < tmpList.length; inc++)	{
		if ((randomProb >= tmpList[inc].minChance) && (randomProb <= tmpList[inc].maxChance))	{
			maxBlock = tmpList[inc].myBlock;
		}
	}
	
	var rng = Math.random();
	switch (true)	{
	case (rng > 0 && rng < .25):
		maxBlock.rotate90();
		break;
	case (rng >= .25 && rng < .5):
		maxBlock.rotate90Reverse();
		break;
	case (rng >= .5 && rng < .75):
		maxBlock.flip();
		break;
	case (rng >= .75 && rng < 1):
		break;
	}

	return maxBlock;
	//var bType = new BaseBlock(oreList[maxOreID].BlockID);
	
}

function getDistance(a, b)	{

var xSize = a.getX()-b.getX();
var ySize = a.getY()-b.getY();
var zSize = a.getZ()-b.getZ();
var distance = Math.sqrt((xSize*xSize)+(ySize*ySize)+(zSize*zSize));

return distance;
}

function getDistanceVec(a, b, length) {	
	//get the vector that is the specified distance away from vec a heading to vec b
	var i = length * (1 / getDistance(a, b));

	var xi = a.getX() + ((b.getX() - a.getX()) * i);
	var yi = a.getY() + ((b.getY() - a.getY()) * i);
	var zi = a.getZ() + ((b.getZ() - a.getZ()) * i);

	var v = new Vector( xi, yi, zi );
	return v;
}

function rotateVec(origin, vec, angle)	{
	
	var s = Math.sin(angle * (Math.PI/180));
	var c = Math.cos(angle * (Math.PI/180));
	
	var dx = (vec.getX() - origin.getX()) * c - (vec.getZ() - origin.getZ()) * s;
	var dz = (vec.getX() - origin.getX()) * s + (vec.getZ() - origin.getZ()) * c;

	dx = Math.round(dx + origin.getX());
	dz = Math.round(dz + origin.getZ());
	
	return Vector(dx, vec.getY(), dz);
}

function getDirection()	{		
	//returns object with multiple player direction properties
	
	var yaw = (player.getYaw()) % 360;
    if (yaw < 0)	{
        yaw += 360;
	}
	
	var dir = new Array();
	dir.pitch = player.getPitch();
	dir.yaw = yaw;
	
	switch(true)	{

		case ((yaw > 337.5) || (yaw <= 22.5)):
			dir.text = "South [Z+]";
			dir.vec = Vector(0,0,1);
			dir.angle = 0;
			dir.rightAngle = 0;
			break;	
		case ((yaw > 22.5) && (yaw <= 67.5)):
			dir.text = "South West [X- Z+]";
			dir.vec = Vector(-1,0,1);
			dir.angle = 45;
			dir.rightAngle = yaw < 45 ? 0 : 90;
			break;
		case ((yaw > 67.5) && (yaw <= 112.5)):
			dir.text = "West [X-]";
			dir.vec = Vector(-1,0,0);
			dir.angle = 90;
			dir.rightAngle = 90;
			break;
		case ((yaw > 112.5) && (yaw <= 157.5)):
			dir.text = "North West [X- Z-]";
			dir.vec = Vector(-1,0,-1);
			dir.angle = 135;
			dir.rightAngle = yaw < 135 ? 90 : 180;
			break;
		case ((yaw > 157.5) && (yaw <= 202.5)):
			dir.text = "North [Z-]";
			dir.vec = Vector(0,0,-1);
			dir.angle = 180;
			dir.rightAngle = 180;
			break;
		case ((yaw > 202.5) && (yaw <= 247.5)):
			dir.text = "North East [X+ Z-]";
			dir.vec = Vector(1,0,-1);
			dir.angle = 225;
			dir.rightAngle = yaw < 225 ? 180 : 270;
			break;
		case ((yaw > 247.5) && (yaw <= 292.5)):
			dir.text = "East [X+]";
			dir.vec = Vector(1,0,0);
			dir.angle = 270;
			dir.rightAngle = 270;
			break;
		case ((yaw > 292.5) && (yaw <= 337.5)):
			dir.text = "South West [X+ Z+]";
			dir.vec = Vector(1,0,1);
			dir.angle = 315;
			dir.rightAngle = yaw < 315 ? 270 : 0;
			break;
	}
	
	//player.print("Direction: " + dir.text + " [" + dir.yaw.toFixed(2) + "] [" + dir.pitch.toFixed(2) + "]" );
	return dir;

}

function generateError(){

	var tmp = aError;
}

function getWorldEdit(){
	//Thanks to Nividica @ http://forum.sk89q.com/threads/i-need-to-script-schematics.8972/
	//for figuring out how to get worlddit plugin from bukkit
	
	try	{
		// Get the server singleton
		var bukkitServer = Bukkit.server;
	 
		// Get the current plugin manager
		var bukkitPluginManager = bukkitServer.getPluginManager();
	 
		// Get the world edit plugin
		var worldEditPlugin = bukkitPluginManager.getPlugin("WorldEdit");
	 
		// Access the worldedit object
		var we = worldEditPlugin.getWorldEdit();
	}
	catch (e)	{
		player.print(text.Red + "Error: " + text.White + "This feature is only available while playing on a bukkit server.");
		return false
	}
    // Return
    return we;
}

function checkFlag(flag, start)	{

	if (start == undefined) {start = 2;}

	for (var fInc in argv)	{
		if (fInc < start) {continue;}
		tmpStr = (String(argv[fInc]).slice(0, flag.length)).toLowerCase();
		if (tmpStr == String(flag).toLowerCase())	{
			var flagArg = String(argv[fInc]).slice(flag.length);
			if (flagArg.length > 0)	{
				return flagArg;
			}
			else{
				return true;
			}
		}
	}
	return false;
}

function pauseScript(timeMs)	{
    var date = new Date();
    var curDate = null;

    do {curDate = new Date(); }
    while(curDate-date < timeMs);
}

function compressArray(original) {
 
	var compressed = [];
	var copy = original.slice(0);
 
	for (var i = 0; i < original.length; i++) {
 
		var myCount = 0;	
		for (var w = 0; w < copy.length; w++) {
			if (original[i] == copy[w]) {
				myCount++;
				delete copy[w];
			}
		}
 
		if (myCount > 0) {
			var a = new Object();
			a.value = original[i];
			a.count = myCount;
			compressed.push(a);
		}
	}
 
	return compressed;
};

function getColor(r, g, b)	{

	return ((r << 16) | (g << 8) | b);

}


//////////////////////////////////////////////////////////
//				Internal Creation Functions
//////////////////////////////////////////////////////////

function CreateLeafSphere(size, yLimit, density, hollow, vec, block, session)	{
	//size, ylimit, density, hollow, vec, block, session
	
	yLimit = yLimit > 0 ? size - yLimit: -(size - Math.abs(yLimit));
	
	for (var x = 0; x <= size; x++) {
		for (var y = 0; y <= size; y++) {
			for (var z = 0; z <= size; z++) {
			
			var pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 +.5);
			var distance = getDistance(vec, pos);
			
			if (distance > size/2)	{continue;}
			if ((hollow != 0) && (distance <= (size/2 - hollow))) {continue;}

			var diff = (size/2) - ((size/2) * density);
			var pctIn = (1-((distance-((size/2) * density))/diff));
	
			if ((pctIn < Math.random()) && (density != 1))	{continue;}
				
			var adjY = (pos.getY() - (vec.getY()-(size/2)));
			if ((adjY < yLimit) || (adjY > (size) + yLimit))	{continue;}
	
			if (yLimit < 0)	{
				if (Math.abs(yLimit) > (size/2))	{
					pos = pos.add(0,Math.abs(yLimit)-(size/2)+1,0);
				}else	{
					pos = pos.add(0,-(yLimit + (size/2))+1,0);
				}
			}
			if (yLimit > 0)	{
				if (Math.abs(yLimit) > (size/2))	{
					pos = pos.add(0,-(yLimit-(size/2)),0);
				}else	{
					pos = pos.add(0,((size/2) - yLimit),0);
				}
			}
			if (yLimit == 0)	{
				pos = pos.add(0, (size/2)+1,0);
			}
			session.setBlock(pos.add(0,-.5,0), block);
			
			}
		}
	}

}

function CreateLeafClump(size, vec, block, session)	{
	
	size = Math.round(size * .5);
	
	var x = vec.getX();
	var y = vec.getY();
	var z = vec.getZ();
	
	if (invert == 1)	{
		for(var k = y; k <= y + size; k++) {
			var l = k - y;
			var i1 = size - l;

			for(var j1 = x - i1; j1 <= x + i1; ++j1) {
				var k1 = j1 - x;

				for(var l1 = z - i1; l1 <= z + i1; ++l1) {
					var i2 = l1 - z;

					if(Math.abs(k1) != i1 || Math.abs(i2) != i1 || Math.random() >= 0.5) {
						var dest = new Vector(j1,k,l1);
						session.setBlock(dest, block);
					}
				}
			}
		}
	}
	if (invert == -1)	{
		for(var k = y; k >= y - size; k--) {
			var l = k - y;
			var i1 = size - l;

			for(var j1 = x - i1; j1 <= x + i1; ++j1) {
				var k1 = j1 - x;

				for(var l1 = z - i1; l1 <= z + i1; ++l1) {
					var i2 = l1 - z;

					if(Math.abs(k1) != i1 || Math.abs(i2) != i1 || Math.random() >= 0.5) {
						var dest = new Vector(j1,k,l1);
						session.setBlock(dest, block);
					}
				}
			}
		}
	}
}

function CreateTrunk(size, height, vec, block, session)	{

	for(var y = 0; y < height; y++)	{
		CreateLeafSphere(size - (size*(y/height))+.5, 2*invert, 1, 0, vec.add(0,y*invert,0), block, session);
	}
	
}

function CreateShape(shapeObj, origin, angle, blockMat, excludeID, session)	{
	
	//var excludeID = 0;
	var shape = shapeObj.shape;
	var afterBlocks = [];
	var minVec = zVec;
	
	//blacklist are all 'attached' block dependent items that need to be set after everything else
	var blackList = [6,26,27,28,31,37,38,39,40,50,51,54,55,59,63,64,65,66,68,69,70,71,72,75,76,77,78,81,83,93,94,96,104,105,106,111,115,127,131,132,141,142,143];
	var flipList = [44,53,67,108,109,114,126,128,134,135,136];
	
	origin = origin.add(shapeObj.offset);
	for (property in shape){
		
		if (angle == 361)	{		//this is used to make 4 copies at each 90 degree increment
			for (var ang = 0; ang < 360; ang++)	{
				
				if (blockMat.next(0,0,0).getType() < 1)	{
					var block = parseBlock(shape[property].id);
				}
				else	{
					var block = blockMat.next(0,0,0);
					block = parseBlock(shape[property].id).getType() == 0 ? parseBlock(shape[property].id) : block;
				}
				if (block.getType() == excludeID)	{continue;}
				var ang = ((ang + parseInt(shapeObj.angle)) % 360);
				switch (ang)	{
				
					case 0:
						vec = origin.add(-shape[property].vec.getZ(),shape[property].vec.getY()*invert,shape[property].vec.getX());
						block.rotate90();
						break;
					case 90:
						vec = origin.add(-shape[property].vec.getX(),shape[property].vec.getY()*invert,-shape[property].vec.getZ());
						block.rotate90();
						block.rotate90();
						break;
					case 180:
						vec = origin.add(shape[property].vec.getZ(),shape[property].vec.getY()*invert,-shape[property].vec.getX());
						block.rotate90();
						block.rotate90();
						block.rotate90();
						break;
					case 270:
						vec = origin.add(shape[property].vec.getX(),shape[property].vec.getY()*invert,shape[property].vec.getZ());					
						break;
					default:
						vec = origin;
						break;
				}
				
				
				if (invert == -1)	{
					if (flipList.indexOf(block.getType()) != -1)	{
						block.flip(CuboidClipboard.FlipDirection.UP_DOWN);
					}	
				}	
				
				if (blackList.indexOf(block.getType()) != -1)	{
					var tmpObj = new Object();
					tmpObj.vec = vec;
					tmpObj.block = block;
				
					afterBlocks.push(tmpObj);
				}
				else	{
					session.setBlock(vec, block);
				}
			}
		}
		else {		//this is used for all normals rotation copies

			var endAngle = (parseInt(angle) + parseInt(shapeObj.angle)) % 360;
			
			if((shapeObj.angle == 0) || (shapeObj.angle == 180))	{
				endAngle = (endAngle + 180) % 360;
			}
			
			if (blockMat.next(0,0,0).getType() < 1)	{
				var block = parseBlock(shape[property].id);
			}
			else	{
				var block = blockMat.next(0,0,0);
				block = parseBlock(shape[property].id).getType() == 0 ? parseBlock(shape[property].id) : block;
			}
			if (block.getType() == excludeID)	{continue;}
			
			switch (endAngle)	{
				case 0:	
					vec = origin.add(-shape[property].vec.getZ(),shape[property].vec.getY()*invert,shape[property].vec.getX());
					block.rotate90();
					break;
				case 90:
					vec = origin.add(-shape[property].vec.getX(),shape[property].vec.getY()*invert,-shape[property].vec.getZ());
					block.rotate90();
					block.rotate90();
					break;
				case 180:
					vec = origin.add(shape[property].vec.getZ(),shape[property].vec.getY()*invert,-shape[property].vec.getX());
					block.rotate90();
					block.rotate90();
					block.rotate90();
					break;
				case 270:
					vec = origin.add(shape[property].vec.getX(),shape[property].vec.getY()*invert,shape[property].vec.getZ());
					break;	
				default:
					vec = origin.add(shape[property].vec.getX(),shape[property].vec.getY()*invert,shape[property].vec.getZ());
					vec = rotateVec(origin, vec, (angle-shapeObj.angle+270)%360);
					break;
			}
			
			if(minVec == zVec)	{minVec = vec;}
			
			if (invert == -1)	{
				if (flipList.indexOf(block.getType()) != -1)	{
					block.flip(CuboidClipboard.FlipDirection.UP_DOWN);
				}	
			}	
			
			if (vec != origin)	{
				if (blackList.indexOf(block.getType()) != -1)	{
					var tmpObj = new Object();
					tmpObj.vec = vec;
					tmpObj.block = block;
				
					afterBlocks.push(tmpObj);
				}
				else	{
					session.setBlock(vec, block);
				}
			}
		}
    }
	
	for (inc in afterBlocks){
		session.setBlock(afterBlocks[inc].vec, afterBlocks[inc].block);
	}
	
	if (checkFlag("$"))	{
		var selector = context.getSession().getRegionSelector(player.getWorld());
		if (selector.selectPrimary(minVec)) {
			context.getSession().dispatchCUISelection(player);
		}
		if (selector.selectSecondary(vec)) {
			context.getSession().dispatchCUISelection(player);
		}
	}

}

function CreateLine(a, b, block, session)	{

	var distance = getDistance(a, b);
	var step = .9/distance;

	for( var i = 0; i <= 1; i += step) {
			
		var xi = a.getX() + ((b.getX() - a.getX()) * i);
		var yi = a.getY() + ((b.getY() - a.getY()) * i);
		var zi = a.getZ() + ((b.getZ() - a.getZ()) * i);
		
		var vec = new Vector(xi, yi, zi);
		session.setBlock(vec, block);	
	}
}

function CreateSpike(origin, end, block, session, size)	{

	for (var x = 0; x <= size; x++) {
		for (var y = 0; y <= size; y++) {
			for (var z = 0; z <= size; z++) {
			
				pos = origin.add(x - size/2, y - size/2, z - size/2);
				distance = getDistance(origin, pos);

				if (distance > size/2)	{continue;}
				CreateLine(pos, end, block, session);
			}
		}
	}

}

function CreateSphere(size, hollow, vec, block, session)	{
	//hollow = the number of blocks thicks the "shell" should be, use 0 for solid
	
	for (var x = 0; x <= size; x++) {
		for (var y = 0; y <= size; y++) {
			for (var z = 0; z <= size; z++) {
			
				pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
				distance = getDistance(vec, pos);
				
				if (distance > size/2)	{continue;}
				if ((hollow != 0) && (distance <= (size/2 - hollow))) {continue;}

				session.setBlock(pos, block);
			
			}
		}
	}

}

//////////////////////////////////////////////////////////
//				Tree Creation Functions
//////////////////////////////////////////////////////////

function CreateBush(vec, session, size, woodBlock, leafBlock)	{
	
	//var size = checkFlag("s", 3) ? parseInt(checkFlag("s"))* (1+Math.random()*.2) : (Math.random() * (trees['bush'].maxChg)) + trees['bush'].minSize;
	//var woodBlock = checkFlag("w") ? parseBlock(checkFlag("w")) : trees['bush'].woodBlock;
	//var leafBlock = checkFlag("l") ? parseBlock(checkFlag("l")) : trees['bush'].leafBlock;
	//size = gSize != -1 ? gSize + (gSize * (1+Math.random()*.2)) : size;
	
	if (checkFlag("c", 3))
		CreateLeafClump(size, vec.add(0,1*invert,0), leafBlock, session);
	else	
		CreateLeafSphere(size, 2*invert, .95, 0, vec.add(0,1*invert,0), leafBlock, session);
	
	session.setBlock(vec.add(0,1*invert,0), woodBlock);
}

function CreateSmallTree(vec, session, size, woodBlock, leafBlock)	{

	for (var y = 1; y <= size; y++)		{
		session.setBlock(vec.add(0,y*invert,0), woodBlock);
	}
	
	if (checkFlag("c", 3))	{
		CreateLeafClump(size*.7, vec.add(0,y*invert,0), leafBlock, session);
	}
	else	{	
		CreateLeafSphere(size, (3+(size*.1))*invert , .9, 0, vec.add(0,y*invert,0), leafBlock, session);
	}
	
}

function CreateStickTree(vec, session, size, woodBlock, leafBlock)	{

	//var size = checkFlag("s") ? parseInt(checkFlag("s"))* (1+Math.random()*.2) : (Math.random() * (trees['stick'].maxChg)) + trees['stick'].minSize;
	//var woodBlock = checkFlag("w") ? parseBlock(checkFlag("w")) : trees['stick'].woodBlock;
	//var leafBlock = checkFlag("l") ? parseBlock(checkFlag("l")) : trees['stick'].leafBlock;
	//size = gSize != -1 ? gSize + (gSize * (1+Math.random()*.2)) : size;

	for (var y = 1; y <= size; y++)		{
		session.setBlock(vec.add(0,y*invert,0), woodBlock);
	}

}

function CreateMediumTree(vec, session, size, woodBlock, leafBlock)	{

	for (var y = 1; y <= size; y++)		{
		
		var randDir = getRandomXZVec();
		var sideDir = getRandomXZSide(randDir);
		var branchLength = (size*trees['medium'].branchSize) + (Math.random()*(size*trees['medium'].branchSize));
		
		for(branch = 1; branch < branchLength; branch++)	{
				var newPnt = vec.add(randDir.getX()*branch, (y*invert)+(branch/2*invert), randDir.getZ()*branch);
				var newPnt = newPnt.add(sideDir.getX()*(branch/2), 0, sideDir.getZ()*(branch/2));
				session.setBlock(newPnt, woodBlock);
		}
		session.setBlock(newPnt.add(0,1*invert,0), woodBlock);
		
		if (checkFlag("c", 3))
			CreateLeafClump(trees['medium'].leafSize/2+1, newPnt.add(0,2*invert,0), leafBlock, session);
		else
			CreateLeafSphere(trees['medium'].leafSize, 3*invert, .9, 0, newPnt.add(0,2*invert,0), leafBlock, session);

		session.setBlock(vec.add(0,y*invert,0), woodBlock);
	}
	if (checkFlag("c", 3))
		CreateLeafClump(6, vec.add(0,y*invert,0), leafBlock, session);
	else
		CreateLeafSphere(8, 4*invert, .8, 0, vec.add(0,y*invert,0), leafBlock, session);
}

function CreateLargeTree(vec, session, size, woodBlock, leafBlock)	{

	if (size < 9)	{size = 10;}

	for (var y = 1; y <= size; y++)		{
		
		if(Math.random() >= (1 - trees['large'].branchProb))	{
		
			var randDir = getRandomXZVec();
			var sideDir = getRandomXZSide(randDir);
			var branchLength = (size*trees['large'].branchSize) + (Math.random()*(size*trees['large'].branchSize));
			
			for(branch = 1; branch < branchLength; branch++)	{
					var newPnt = vec.add(randDir.getX()*branch, (y*invert)+(branch/2*invert), randDir.getZ()*branch);
					var newPnt = newPnt.add(sideDir.getX()*(branch/2), 0, sideDir.getZ()*(branch/2));
					session.setBlock(newPnt, woodBlock);
			}
			session.setBlock(newPnt.add(0,1*invert,0), woodBlock);
			
			if (checkFlag("c", 3))
				CreateLeafClump(trees['large'].leafSize/2+1, newPnt.add(0,2*invert,0), leafBlock, session);
			else
				CreateLeafSphere(trees['large'].leafSize, 3*invert, .9, 0, newPnt.add(0,2*invert,0), leafBlock, session);
				
		}
		
		session.setBlock(vec.add(0,y*invert,0), woodBlock);
	}
	
	CreateTrunk(size*.2, size * .3, vec.add(.5, 0, .5), woodBlock, session);
	
	if (checkFlag("c", 3))
		CreateLeafClump(6, vec.add(0,y*invert,0), leafBlock, session);
	else	
		CreateLeafSphere(8, 4*invert, .8, 0, vec.add(0,y*invert,0), leafBlock, session);
}

function CreateBranchedTree(vec, session, size, woodBlock, leafBlock)	{

	for (var y = 1; y <= size; y++)		{
		
		if(Math.random() >= (1 - trees['branched'].branchProb1))	{
			
			var randDir1 = getRandomXZVec();
			var sideDir1 = getRandomXZSide(randDir1);
			var branchLength1 = (size*trees['branched'].branchSize1) + (Math.random()*(size*trees['branched'].branchSize1));
			
			for(branch1 = 1; branch1 < branchLength1; branch1++)	{
				var newPnt = vec.add(randDir1.getX()*branch1, (y*invert)+(branch1/2*invert), randDir1.getZ()*branch1);
				newPnt = newPnt.add(sideDir1.getX()*(branch1), 0, sideDir1.getZ()*(branch1));
				session.setBlock(newPnt, woodBlock);
				
				if(Math.random() >= (1 - trees['branched'].branchProb2))	{

					var randDir2 = getRandomXZVec();
					var sideDir2 = getRandomXZSide(randDir2);
					var branchLength2 = (size*trees['branched'].branchSize2) + (Math.random()*(size*trees['branched'].branchSize2));
					
					for(branch2 = 1; branch2 < branchLength2; branch2++)	{
						//var newPnt = vec.add(randDir.getX()*branc1h, (y*invert)+(branch2/2*invert)), randDir.getZ()*branch1);
						var newPnt2 = newPnt.add(sideDir2.getX()*(branch2/2), 1*invert, sideDir2.getZ()*(branch2/2));
						session.setBlock(newPnt2, woodBlock);
						
					}
					session.setBlock(newPnt2.add(0,1*invert,0), woodBlock);
					if (checkFlag("c", 3))
						CreateLeafClump(trees['branched'].leafSize/2-1, newPnt2.add(0,2*invert,0), leafBlock, session);
					else	
						CreateLeafSphere(trees['branched'].leafSize, 2*invert, .9, 0, newPnt2.add(0,2*invert,0), leafBlock, session);
				}
			}
			session.setBlock(newPnt.add(0,1*invert,0), woodBlock);
			
			if (checkFlag("c", 3))
				CreateLeafClump(trees['branched'].leafSize/2-1, newPnt.add(0,2*invert,0), leafBlock, session);
			else
				CreateLeafSphere(trees['branched'].leafSize, 3*invert, .9, 0, newPnt.add(0,2*invert,0), leafBlock, session);
				
		}
		
		session.setBlock(vec.add(0,y*invert,0), woodBlock);
	}
	
	CreateTrunk(size*.3, size * .35, vec, woodBlock, session);
	if (checkFlag("c", 3))
		CreateLeafClump(6, vec.add(0,y*invert,0), leafBlock, session);
	else	
		CreateLeafSphere(8, 4*invert, .8, 0, vec.add(0,y*invert,0), leafBlock, session);
}

function CreateRainforestTree(vec, session, size, woodBlock, leafBlock)	{
	
	for (var y = 1; y <= size; y++)		{
		
		if (y > (trees['rainforest'].branchHeight * size))	{
			var randDir = getRandomXZVec();
			var sideDir = getRandomXZSide(randDir);
			var branchLength = (size*trees['rainforest'].branchSize) + (Math.random()*(size*trees['rainforest'].branchSize));
			
			if(Math.random() >= (1 - trees['rainforest'].branchProb))	{
		
				for(branch = 1; branch < branchLength; branch++)	{
					var newPnt = vec.add(randDir.getX()*branch, (y*invert)+(branch/2*invert), randDir.getZ()*branch);
					var newPnt = newPnt.add(sideDir.getX()*(branch/2), 0, sideDir.getZ()*(branch/2));
					session.setBlock(newPnt, woodBlock);
				}
				if (checkFlag("c", 3))
					CreateLeafClump(trees['rainforest'].leafSize/2, newPnt.add(0,1*invert,0), leafBlock, session);
				else
					CreateLeafSphere(trees['rainforest'].leafSize, 2*invert, .95, 0,  newPnt.add(0,1*invert,0), leafBlock, session);
			}
		}			
		session.setBlock(vec.add(0,y*invert,0), woodBlock);
	}
	
	CreateTrunk(size*.15, size * .2, vec.add(.5, 0, .5), woodBlock, session);
	
	if (checkFlag("c", 3))
		CreateLeafClump(trees['rainforest'].leafSize/2, vec.add(0,y*invert,0), leafBlock, session);
	else
		CreateLeafSphere(trees['rainforest'].leafSize, 3*invert, .9, 0,  vec.add(0,y*invert,0), leafBlock, session);

}

function CreatePalmTree(vec, session, size, woodBlock, leafBlock)	{

	var randDir = getRandomXZVec();
	var sideDir = getRandomXZSide(randDir);
	
	for (var y = 0; y < size; y++)		{
		var setVec = vec.add(randDir.getX()*y*.5, (y+1)*invert, randDir.getZ()*y*.5);
		var setVec = setVec.add(sideDir.getX()*y*.5, 0, sideDir.getZ()*y*.5);
		
		session.setBlock(setVec, woodBlock);
	}
	if (checkFlag("l"))
		CreateShape(shapes['PalmLeaf'], setVec, 361, new SingleBlockPattern(parseBlock(checkFlag("l"))), -1, session);
	else
		CreateShape(shapes['PalmLeaf'], setVec, 361, airMat, -1, session);
	session.setBlock(setVec, woodBlock);
}

function CreateSpikeTree(vec, session, size, woodBlock, leafBlock)	{

	//var size = checkFlag("s") ? parseInt(checkFlag("s"))* (1+Math.random()*.2) : (Math.random() * (trees['spike'].maxChg)) + trees['spike'].minSize;
	//var woodBlock = checkFlag("w") ? parseBlock(checkFlag("w")) : trees['spike'].woodBlock;
	//var leafBlock = checkFlag("l") ? parseBlock(checkFlag("l")) : trees['spike'].leafBlock;
	//size = gSize != -1 ? gSize + (gSize * (1+Math.random()*.2)) : size;
	
	for (var y = 1; y <= size; y++)		{
		
		if(Math.random() >= (1 - trees['spike'].branchProb1))	{
		
			var randDir1 = getRandomXZVec();
			var sideDir1 = getRandomXZSide(randDir1);
			var branchLength1 = (size*trees['spike'].branchSize1) + (Math.random()*(size*trees['spike'].branchSize1));
			
			//var maxRange = (Math.random() * 5)+.5;
			
			for(branch1 = 1; branch1 < branchLength1; branch1++)	{
				var newPnt = vec.add(randDir1.getX()*branch1, y+(branch1/2), randDir1.getZ()*branch1);
				newPnt = newPnt.add(sideDir1.getX()*(branch1), 0, sideDir1.getZ()*(branch1));
				session.setBlock(newPnt, woodBlock);

				if(Math.random() >= (1 - trees['spike'].branchProb2))	{

					var randDir2 = getRandomXZVec();
					var sideDir2 = getRandomXZSide(randDir2);
					var branchLength2 = (size*trees['spike'].branchSize2) + (Math.random()*(size*trees['spike'].branchSize2));
					
					for(branch2 = 1; branch2 < branchLength2; branch2++)	{
						//var newPnt = vec.add(randDir.getX()*branc1h, y+(branch/2), randDir.getZ()*branch1);
						var newPnt2 = newPnt.add(sideDir2.getX()*(branch2/2), 0, sideDir2.getZ()*(branch2/2));
						session.setBlock(newPnt2, woodBlock);
						
					}
					//CreateSpike(newPnt, newPnt2, trees['spike'].woodBlock, session, 2);
					
					session.setBlock(newPnt2.add(0,1,0), woodBlock);
					if (checkFlag("c", 3))
						CreateLeafClump(trees['spike'].leafSize/2-1, newPnt2.add(0,2*invert,0), leafBlock, session);
					else	
						CreateLeafSphere(trees['spike'].leafSize, 2*invert, .9, 0, newPnt2.add(0,2*invert,0), leafBlock, session);
				}
			}
			
			CreateSpike(vec.add(0,y,0), newPnt, woodBlock, session, 3);
			if (checkFlag("c", 3))
				CreateLeafClump(trees['spike'].leafSize/2-1, newPnt.add(0,2*invert,0), leafBlock, session);
			else
				CreateLeafSphere(trees['spike'].leafSize, 3*invert, .9, 0, newPnt.add(0,2*invert,0), leafBlock, session);
				
		}
		
	}
	CreateSpike(vec, vec.add(0,size,0), trees['spike'].woodBlock, session, size/10);
	
	if (checkFlag("c", 3))
		CreateLeafClump(6, vec.add(0,y*invert,0), leafBlock, session);
	else	
		CreateLeafSphere(8, 4*invert, .8, 0, vec.add(0,y*invert,0), leafBlock, session);

}

function CreateMushroom(vec, session, size, woodBlock, leafBlock)	{

	leafBlock = (gMat == airMat) ? new SingleBlockPattern(leafBlock) : gMat;

	var randDir = getRandomXZVec();
	var sideDir = getRandomXZSide(randDir);
	//var slopeMod = .3;
	
	for (var y = 0; y < size *.6; y++)		{
		
		var slopeMod = 1-(y/(size*1.1));
		var setVec = vec.add(randDir.getX()*y*slopeMod, (y+1)*invert, randDir.getZ()*y*slopeMod);
		var setVec = setVec.add(sideDir.getX()*y*slopeMod, 0, sideDir.getZ()*y*slopeMod);
		
		CreateLeafSphere(size/3, 2 , .98, 0, setVec, woodBlock, session)
	}
	var slopeMod = 0;
	
	for (var y = 0; y < size * .4; y++)		{
		
		//var slopeMod = 1-(y/size);
		var newVec = setVec.add(randDir.getX()*y*slopeMod/2, (y+1)*invert, randDir.getZ()*y*slopeMod/2);
		var newVec = newVec.add(sideDir.getX()*y*slopeMod/2, 0, sideDir.getZ()*y*slopeMod/2);
		//var newVec = setVec.add(0, (y+1)*invert, 0);
		CreateLeafSphere(size/3, 2 , .98, 0, newVec, woodBlock, session)
	}
	
	CreateLeafSphere(size, (size/2)*invert, 1, (size/8), newVec.add(0,-(size/2-size/8)*invert+1,0), leafBlock, session)
}

//////////////////////////////////////////////////////////
//				Player Tool Commands
//////////////////////////////////////////////////////////

function BuildTest(vec, session)	{

	var timeOut = context.getConfiguration().scriptTimeout;
	player.print(text.White + "Script timeout is currently set to " + text.Gold + timeOut + " (" + (timeOut/1000) + "s).");
	if (timeOut < 10000	)
		player.print(text.White + "This is a little low, I suggest increasing to at least" + text.Gold + " 10000 (10s).");

	return;
		
}

function HelpText(cmdType)  {
	
	if (cmdType != 1)	{
		var helpArg = argv.length > 2 ? argv[2] : -1;
		var helpMode = parseMode(helpArg)
	}
	else{
		var helpArg = argv.length > 1 ? argv[1] : 1;
		var helpMode = parseMode(helpArg)
	}	
	
	if (helpMode != -1)	{
		
		var keyStr = [];	
		var argStr = [];
		
		for (var keyInc in tools[helpMode].keys)	{
			keyStr = keyStr + text.Red + tools[helpMode].keys[keyInc] + text.White + "|";
		}
		for (var argInc in tools[helpMode].args)	{
			argStr = argStr + (text.White + "<");
			if (String(tools[helpMode].aFlags[argInc]).length > 0)	{
				argStr = argStr + (text.Red + tools[helpMode].aFlags[argInc] + text.Gold + text.Arrow);
			}
			argStr = argStr + (text.Red + tools[helpMode].args[argInc] + text.White + ">");
		}

		player.print("\n" + text.Gold + tools[helpMode].name + " " + text.Gold + argStr);
		player.print(text.White + text.Italics + tools[helpMode].note);
		player.print(text.White + "Keywords  |" + text.Red + keyStr );
	}
	else	{

		player.print("\n" + text.Gold + text.Italics + "Build Commands " + text.Red + "v" + version + text.White + " by inHaze \n \n");
		player.print(text.White + "Type " + text.Red + "/cs build list"  + text.White + " or " + text.Red + "/cs build commands" + text.White + " for command usage.");
		player.print(text.White + "Type " + text.Red + "/cs build ? " + text.Gold + "command" + text.White + " for detailed info on any command.");
	}
	
}

function CommandList()	{
	
	var endStr =  [];
	var strList =  [];
	
	for (inc in tools)	{
		var argStr = [];
		var comStr = [];
		for (var argInc in tools[inc].args)	{
			argStr = argStr + (text.White + "<");
			if (String(tools[inc].aFlags[argInc]).length > 0)	{
				argStr = argStr + (text.Red + tools[inc].aFlags[argInc] + text.Gold + text.Arrow);
			}
			argStr = argStr + (text.Red + tools[inc].args[argInc] + text.White + ">");
		}
	
		 comStr = comStr + (text.Gold + tools[inc].keys[0] + " \u00A7c" + argStr + "\n");
		 comStr = comStr + (text.White + text.Italics + tools[inc].note);
		 strList.push (comStr);
	}
	strList.sort();
	for (inc in strList)	{
		endStr = (endStr + strList[inc] + "\n");
	}
	player.print("\n" + text.White + "Command List - Type " + text.Red + "/cs build ? " + text.Gold + "command" + text.White + " for detailed info. \n \n");
	player.print(endStr);
	//saveFile("CommandList", endStr);
	
}

function CommandListShort()	{
	
	var names = [];
	var listStr = text.White + "[";
	
	for (inc in tools)	{
		names.push (String(tools[inc].keys[0]))
	}
	names.sort();
	for (inc in names)	{
		listStr = listStr + (text.Gold + names[inc] + text.White + " | ");
	}
	
	listStr = listStr + "]";
	player.print("\n" + text.White + "Short Command List - Use " + text.Red + "/cs build commands" + text.White + " for a full listing \n \n");
	player.print(listStr);
}

function ClearNature(vec, session)	{

	//var clearType = checkFlag("s") ? parseInt(checkFlag("s")) : 20;
	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 20;
	size = gSize != -1 ? gSize + (gSize * Math.random()*.2) : size;
	
	var blackList = [6,17,18,31,32,37,38,39,40,59,78,81,83,86,103,104,105,106,111,115,127,141,142];
	
	for (var x = 0; x <= size; x++) {
		for (var z = 0; z <= size; z++) {
			for (var y = size; y >= 0; y--) {					
				pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
				distance = getDistance(vec, pos);

				if (distance > size/2)	{continue;}
				if (blackList.indexOf(session.getBlock(pos).getType()) == -1)	{continue;}

				session.setBlock(pos, new BaseBlock(0));

			}
		}
	}

}

function BuildTree(vec, session)	{
	
	var treeType = argv.length > 2 ? String(argv[2]).toLowerCase() : "";

	typeCheck = -1;
	for (inc in trees)	{
		if (treeType == String(inc).toLowerCase())
			typeCheck = 1;
	}
	if (typeCheck == -1)	{
		var tmpStr = text.White + "[ ";
		for (inc in trees)	{tmpStr = tmpStr + text.Gold + String(inc).toLowerCase() + text.White + " | ";}
		
		player.print("\n" + text.Red + "Error: " + text.White + "Tree type " + text.Gold + treeType + text.White + " not found.");
		player.print(text.White + text.Italics + "Available tree types: \n" + tmpStr + "]");
		return;
	}
	
	var size = checkFlag("s", 3) ? parseInt(checkFlag("s", 3))* (1+Math.random()*.2) : (Math.random() * (trees[treeType].maxChg)) + trees[treeType].minSize;
	var woodBlock = checkFlag("w", 3) ? parseBlock(checkFlag("w", 3)) : trees[treeType].woodBlock;
	var leafBlock = checkFlag("l", 3) ? parseBlock(checkFlag("l", 3)) : trees[treeType].leafBlock;
	size = gSize != -1 ? gSize + (gSize * (1+Math.random()*.2)) : size;
	
	trees[treeType].mySub(vec, session, size, woodBlock, leafBlock);
	
}

function BuildShape(vec, session)	{

	if(myShape.length != 0)	{
		var mat = (gMat == airMat) ? airMat : gMat;
		var excludeID = checkFlag("!") ? parseBlock(checkFlag("!")).getType() : -1;
		
		var angle = checkFlag("<") ? parseFloat(checkFlag("<")) : getDirection().rightAngle;
		angle = checkFlag("<") == 360 ? getDirection().yaw : angle;
		
		CreateShape(myShape['TMP'], vec, angle, mat, excludeID, session);
	}
	else	{
		loadShape(vec, session);
	}

}

function BuildShapeKit(vec, session){

	if (myKit.length != 0)	{
		for (var inc in myKit)	{
			
			if (player.getItemInHand() == myKit[inc].item)	{
				var mat = ((gMat == airMat)) ? airMat : gMat;
				var excludeID = checkFlag("!") ? parseBlock(checkFlag("!")).getType() : -1;
				
				var angle = checkFlag("<") ? parseFloat(checkFlag("<")) : getDirection().rightAngle;
				angle = checkFlag("<") == 360 ? getDirection().yaw : angle;
				
				CreateShape(myShape[inc], vec, angle, mat, excludeID, session);
			}
		}
	}
	else	{
	
		var tmpKit = new Array();
		var tool = new Array();
		var fileName = String(argv[2]);

		var aStr = fileName.slice((fileName.length)-4).toLowerCase();
		if (aStr == ".kit")	{fileName = String(argv[2]).slice(0, String(argv[2]).length-4).toLowerCase()};

		var file = context.getSafeFile("shapes", String(fileName + '.kit'));
		if(!file.exists()){
			player.print(text.Red + "Error! " + text.Gold + "Could not find kit file: " + text.White + text.Italics + file);
			return false;
		}
		
		player.print(text.White + text.Italics + "Loading shapes from kit file: " + text.Gold + fileName + ".kit"); 
		var kitStr = loadFile(fileName, 3);
		tmpKit = parseKitFile(kitStr);

		for (inc in tmpKit)	{		//this is where the brushes get set to the loaded shapeKit list
			context.getSession().setTool(tmpKit[inc].item, null)
			tool[inc] = context.getSession().getBrushTool(tmpKit[inc].item);
			tool[inc].setFill(airMat);
			tool[inc].setBrush(brush, "worldedit.brush.buildShapeKit");
		}
	
		myKit = tmpKit;
		loadShapeKit(vec, session, tmpKit);

	}

}

function BuildPaint(vec, session)	{

	if(myShape.length != 0)	{
		mat = ((gMat == airMat)) ? airMat : gMat;
		excludeID = checkFlag("!") ? parseBlock(checkFlag("!")).getType() : -1;
		
		var angle = checkFlag("<") ? parseFloat(checkFlag("<")) : getDirection().rightAngle;
		angle = checkFlag("<") == 360 ? getDirection().yaw : angle;
		
		CreateShape(myShape['TMP'], vec, angle, mat, excludeID, session);
	}
	else	{
		loadShape(vec, session);
	}
	
	generateError();
}

function BuildGrassPatch(vec, session)	{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 15;
	var density = checkFlag("d") ? parseFloat(checkFlag("d")) : .25;
	size = gSize != -1 ? gSize + (gSize * Math.random()*.2) : size;
	
	var blackList = [0,6,31,32,37,38,39,40,81,106];
	var whiteList = [2,3,88];
	
	for (var x = 0; x <= size; x++) {
		for (var z = 0; z <= size; z++) {
			for (var y = size; y >= 0; y--) {					
				pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
				distance = getDistance(vec, pos);

				if (distance > size/2)	{continue;}
				if (blackList.indexOf(session.getBlock(pos).getType()) == -1)	{continue;}
				if (blackList.indexOf(session.getBlock(pos.add(0,1,0)).getType()) == -1)	{continue;}
				if (whiteList.indexOf(session.getBlock(pos.add(0,-1,0)).getType()) == -1)	{continue;}		
				if (density > Math.random())	{
				
					session.setBlock(pos, getListBlock(blocks["plants"].list));

				}
			}
		}
	}

}

function BuildStickPatch(vec, session)	{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 15;
	var density = checkFlag("d") ? parseFloat(checkFlag("d")) : .25;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) :  trees['Stick'].woodBlock;
	size = gSize != -1 ? gSize + (gSize * Math.random()*.2) : size;
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;
		
	if (checkFlag("l"))	{
		var minSize = parseBlockExtra(checkFlag("l")).block.getType();
		var maxChg = parseBlockExtra(checkFlag("l")).extra;
	}
	else	{
		var minSize = trees['Stick'].minSize;
		var maxChg = trees['Stick'].maxChg;
	}
	
	var blackList = [0,6,31,32,37,38,39,40,81,106];		//don't attach to these blocks
	//var whiteList = [2,3,88];
	
	for (var x = 0; x <= size; x++) {
		for (var z = 0; z <= size; z++) {
			for (var y = size; y >= 0; y--) {					
				pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
				distance = getDistance(vec, pos);

				if (distance > size/2)	{continue;}
				if (blackList.indexOf(session.getBlock(pos).getType()) == -1)	{continue;}
				if (blackList.indexOf(session.getBlock(pos.add(0,1*invert,0)).getType()) == -1)	{continue;}
				if (blackList.indexOf(session.getBlock(pos.add(0,-1*invert,0)).getType()) != -1)	{continue;}		
				
				if (density > Math.random())	{
					var height = (Math.random() * maxChg) + minSize;
					
					for (var inc = 0; inc < height; inc++)	{
						session.setBlock(pos.add(0,inc*invert,0), mat);
					}

				}
			}
		}
	}
}

function BuildOverlayPatch(vec, session){

	var block = [];
	var depth = [];
	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 15;
	size = gSize != -1 ? gSize : size;
	
	
	if (checkFlag("t"))	{
		block[0] = parseBlockExtra(checkFlag("t")).block; 
		depth[0] = parseBlockExtra(checkFlag("t")).extra;
	}
	else	{
		block[0] = new BaseBlock(2, 0);
		depth[0] = 0;
	}
	
	if (checkFlag("m"))	{
		block[1] = parseBlockExtra(checkFlag("m")).block;
		depth[1] = parseBlockExtra(checkFlag("m")).extra;
	}
	else	{
		block[1] = new BaseBlock(3, 0);
		depth[1] = 0;
	}
	
	if (checkFlag("e"))	{
		block[2] = parseBlockExtra(checkFlag("e")).block;
		depth[2] = parseBlockExtra(checkFlag("e")).extra;
	}
	else	{
		block[2] = new BaseBlock(1, 0);
		depth[2] = 0;
	}
	
	block[0] = (gMat == airMat) ? new SingleBlockPattern(block[0]) : gMat;
	
	if (depth[0] < 1)	{
		depth[0] = 1;
		depth[1] = 2;
		depth[2] = 3;
	}
	
	var whiteList = [0,6,17,18,31,32,37,38,39,40,78,81,83,86,106];				//The blocks allowed to be over the natural block
	var greenList = [1,2,3,12,13,14,15,16,21,24,56,73,82,87,88,110,121,129];	//List of natural blocks that should be changed
	
	for (var x = 0; x <= size; x++) {
		for (var y = 0; y <= size; y++)	{
			for (var z = 0; z <= size; z++) {
							
				pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
				distance = getDistance(vec, pos);

				if (distance > size/2)	{continue;}
				if(!checkFlag("a"))	{
					if (greenList.indexOf(session.getBlock(pos).getType()) == -1)	{continue;}
					if (whiteList.indexOf(session.getBlock(pos.add(0,1*invert,0)).getType()) == -1)	{continue;}
				}
				else	{
					if (session.getBlock(pos).getType() == 0) {continue;}
					if (session.getBlock(pos.add(0,1*invert,0)).getType() != 0) {continue;}
				}
				
				var totalDepth = depth[0] + depth[1] + depth[2];
				for (var inc = 0; inc < totalDepth; inc++)	{
					if (!checkFlag("a"))
						if (greenList.indexOf(session.getBlock(pos.add(0,(0-inc)*invert,0)).getType()) == -1)	{break;}
					if (inc < depth[0])	{
						if ((block[0].next(0,0,0).getType() == 0) && (block[0].next(0,0,0).getData() != 0))	{continue;}		//If air is used, and has a non zero data value skip it
						session.setBlock(pos.add(0,(0-inc)*invert,0), block[0]);
					
					}
					else if (inc >= depth[0] && inc < (depth[0] + depth[1])) 	{
						if ((block[1].getType() == 0) && (block[1].getData() != 0))	{continue;}
						session.setBlock(pos.add(0,(0-inc)*invert,0), block[1]);
					}
					else {
						if ((block[2].getType() == 0) && (block[2].getData() != 0))	{continue;}
						session.setBlock(pos.add(0,(0-inc)*invert,0), block[2]);
					}
				}
			}
		}
	}
}

function BuildFlat(vec, session)	{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 15;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) : new BaseBlock(2, 0);
	var depth = checkFlag("d") ? parseFloat(checkFlag("d")) : 62;
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;
	size = gSize != -1 ? gSize : size;

	
	var fillList = [0,8,9,10,11];	//fill these blocks if they are in the path

	for (var x = 0; x <= size; x++) {
		for (var y = 0; y <= size; y++)	{
			for (var z = 0; z <= size; z++) {
							
				pos = vec.add(x - size/2 + .5, parseInt(y - size/2 + .5), z - size/2 + .5);
				distance = getDistance(vec, pos);
				totalDepth = pos.getY() - depth;
				
				if (distance > size/2)	{continue;}
				if ((session.getBlock(pos).getType() == 0) && (totalDepth != 0))	{continue;}
				
				if (totalDepth > 0)	{			//Clearing Down
					for (var inc = 0; inc <= totalDepth; inc++)	{

						if (mat.next(0,0,0).getType() == 0)	{totalDepth-10;}
						if (inc == totalDepth)	{
							if (mat.next(0,0,0).getType() == 0)	{continue;}		//Skip if air is used
							session.setBlock(pos.add(0,(0-inc),0), mat);
						}
						else	{
							session.setBlock(pos.add(0,(0-inc),0), new BaseBlock(0));
						}
					}
				}
				else if (totalDepth < 0)	{		//Filling Up
					for (var inc = 0; inc >= totalDepth; inc--)	{
						if (session.getBlock(pos.add(0,(0-inc),0)).getType() == 0)	{
							session.setBlock(pos.add(0,(0-inc),0), mat);
						}

					}
				}
				
				
				else if (totalDepth == 0)	{
					session.setBlock(pos, mat)
					for (inc = 1; inc < 256; inc++)	{
						if (fillList.indexOf(session.getBlock(pos.add(0,(0-inc),0)).getType()) == -1)	{break;}
						session.setBlock(pos.add(0,(0-inc),0), mat);
						
					}
				}
			}
		}
	}
}

function BuildSpike(vec, session)	{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 8;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) : new BaseBlock(1, 0);
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;
	size = gSize != -1 ? gSize : size;
	
	if (checkFlag("l"))	{
		var minSize = parseBlockExtra(checkFlag("l")).block.getType();
		var maxChg = parseBlockExtra(checkFlag("l")).extra;
	}
	else	{
		var minSize = 50;
		var maxChg = 15;
	}

	var length = (Math.random() * maxChg) + minSize;
	var end = getDistanceVec(vec, player.getBlockIn(), length);

	CreateSpike(vec, end, mat, session, size);
	
}

function BuildVines(vec, session)	{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 12;
	var density = checkFlag("d") ? parseFloat(checkFlag("d")) : .25;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) :  new BaseBlock(BlockID.VINE, 0);
	var length = checkFlag("l") ? parseInt(checkFlag("l")) : 12;
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;
	size = gSize != -1 ? gSize : size;
	
	var rand = new java.util.Random();

	var blackList = [0,6,8,9,31,32,37,38,39,40,81,83,86,106];		//Do not place vines on these blocks

	for (var x = 0; x <= size; x++) {
		for (var y = 0; y <= size; y++)	{
			for (var z = 0; z <= size; z++) {
							
				pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
				var distance = getDistance(vec, pos);
				var curBlock = session.getBlock(pos);

				if (distance > size/2)	{continue;}
				if (Math.random() > density) {continue;}
				if (curBlock.getType() != 0) {continue;}
				
				var vines = new Array();
				vines[1] = new BaseBlock(BlockID.VINE, 8);  
				vines[2] = new BaseBlock(BlockID.VINE, 2);  
				vines[3] = new BaseBlock(BlockID.VINE, 1);  
				vines[4] = new BaseBlock(BlockID.VINE, 4); 

				var blockFaces = new Array();
				blockFaces[1] = session.getBlockType(pos.add(1,0,0));
				blockFaces[2] = session.getBlockType(pos.add(-1,0,0));
				blockFaces[3] = session.getBlockType(pos.add(0,0,1));
				blockFaces[4] = session.getBlockType(pos.add(0,0,-1));
				
				var solidSide = new Array();
				for (var inc = 1; inc <= 4; inc++) {
					
				if ((blackList.indexOf(blockFaces[inc]) != -1) || (blockFaces[inc] == mat.next(0,0,0).getType())) {continue;}
					if (blockFaces[inc] != 0) {
						solidSide.push(inc)
					}												
				}
				if ((solidSide.length >= 1)){
					randomSide = solidSide[(rand.nextInt(solidSide.length))];
					randomLength = rand.nextInt(length);
					var newVine = vines[randomSide];
					for (var extendVine = 0; extendVine <= randomLength; extendVine++) {
						if (session.getBlockType(pos.add(0,-(extendVine),0)) == 0) {
							if (mat.next(0,0,0).getType() == BlockID.VINE) {
								session.setBlock(pos.add(0,-(extendVine),0), newVine);
							}
							else {
								session.setBlock(pos.add(0,-(extendVine),0), mat);
							}
							continue;
						}
						break;
					}
				}
			}
		}
	}	
}

function BuildLine(vec, session)	{

	var lineMode = checkFlag("m") ? parseInt(checkFlag("m")) : 1;
	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 1;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) :  new BaseBlock(1);
	var extendCnt = checkFlag("e") ? parseInt(checkFlag("e")) :  0;
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;
	size = gSize != -1 ? gSize : size;	
	
	var baseVec = zVec;

	if (stage == 0) {
		player.print(text.White + text.Italics + "Origin set!");
		gVec = vec;
		stage++;
		return;
	}
	
	switch(lineMode)	{	//lineMode - 0 = Single Line; 1 = Continous; 2 = Fixed Origin.

	case 0:
		
		if (stage == 1) {
			baseVec = gVec;
			stage++;
		}
		else	{
			gVec = vec;
			player.print(text.White + text.Italics + "Origin set!");
			stage--;
		}
		break;
	case 1:
		baseVec = gVec;
		gVec = vec;
		break;
	case 2:
		baseVec = gVec;
		break;					
	}

	if((lineMode == 1) || (lineMode == 2) || (stage == 2))	{
	
		var distance = getDistance(baseVec, vec);
		var step = .9/distance;
		var extendBase = (extendCnt * step);
		
		for(var i = 0; i <= (1 + extendBase); i += step) {
				
			var xi = vec.getX() + ((baseVec.getX() - vec.getX()) * i);
			var yi = vec.getY() + ((baseVec.getY() - vec.getY()) * i);
			var zi = vec.getZ() + ((baseVec.getZ() - vec.getZ()) * i);
			var pos = new Vector(xi, yi, zi);

			if (size == 0)	{
				session.setBlock(pos, mat );
			}
			else	{
				CreateSphere(size, 1, pos, mat, session);
			}
		}
	}
	
}

function BuildPlatform(vec, session){
	
	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 3;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) :  new BaseBlock(20);
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;
	size = gSize != -1 ? gSize : size;	
	
	vec = player.getBlockIn();
	vec = vec.add(0,-1,0);
	
	for (var x = 0; x <= size; x++) {
		for (var z = 0; z <= size; z++) {
			
			pos = vec.add(x - size/2 + .5, 0, z - size/2 + .5);
			distance = getDistance(vec, pos);
			
			if (distance > size/2)	{continue;}
			session.setBlock(pos, mat);
		}
	}
}

function BuildBiome(vec, session)	{
	
	if (argv.length < 3) 	{
		player.print (text.Red + "Error:" + text.White + " You need to specify a biome type to use.");
		return false;
	}
	
	var we = getWorldEdit();
	if (we == false)	{return false;}
	
	var biome = String(argv[2]).toUpperCase();
	var size = checkFlag("#") ? parseInt(checkFlag("#")) : 7;
	size = gSize != -1 ? gSize : size;

	var biomeList = String(we.getServer().getBiomes().all());
	
	try{
		target = BiomeType(we.getServer().getBiomes().get(biome));
	}
	catch (e)	{
		player.print("\n" + text.Red + "Error: " + text.White + "Biome type " + text.Red + biome.toLowerCase() + text.White + " not found.");
		player.print(text.Gold + text.Italics + "Available Biome Types: \n" + text.White + biomeList);
		return false;
	}
	
	if (vecList.length < 1)	{
		player.print(text.Gold + biome + text.White + " biome found.");
		return;
	}
		
	for (var x = 0; x <= size; x++) {
		for (var z = 0; z <= size; z++) {
			
			pos = vec.add(x - size/2 + .5, 0, z - size/2 + .5);
			distance = getDistance(vec, pos);
			
			if (distance > size/2)	{continue;}
			
			player.getWorld().setBiome(Vector2D(pos.getX(),pos.getZ()), target);
			var yMax = session.getHighestTerrainBlock(pos.getX(),pos.getZ(), 0, 256, false);
		}
	}
	session.simulateSnow(vec, size/2);
	generateError();
}

function BuildMirror(vec, session)	{
	
	var world = context.getSession().getSelectionWorld();
	var region = context.getSession().getSelection(world);
	
	var pos = region.getMinimumPoint();
	var width = region.getWidth();
	var length = region.getLength();
	var height = region.getHeight();
	var vec2 =  player.getBlockIn();
	var dirInfo = getDirection();	

	if ((dirInfo.rightAngle == 0) || (dirInfo.rightAngle == 180))	{
		var offDir = pos.getX()-vec.getX();

		for (x = 0; x < width; x++)		{
			for (y = 0; y < height; y++)		{
				for (z = 0; z < length; z++)		{

					var tmpVec = pos.add(x, y, z);
					var offLen = (offDir + x);
					var newVec = tmpVec.add(-(offLen*2),0,0);
					var tmpBlock = session.getBlock(tmpVec);
					tmpBlock.flip(CuboidClipboard.FlipDirection.NORTH_SOUTH);
					
					if (checkFlag("d"))	{
						session.setBlock(tmpVec, airMat);
					}	
					session.setBlock(newVec, tmpBlock);
					
					if (checkFlag("s"))	{
						if((x == 0) && (y == 0) && (z == 0))	{
							var selector = context.getSession().getRegionSelector(player.getWorld());
							if (selector.selectPrimary(newVec)) {
								context.getSession().dispatchCUISelection(player);
							}
						}
						if((x == (width-1)) && (y == (height-1)) && (z == (length-1)))	{
							var selector = context.getSession().getRegionSelector(player.getWorld());
							if (selector.selectSecondary(newVec)) {
								context.getSession().dispatchCUISelection(player);
							}
						}
					}
				}
			}
		}
	}
	
	if ((dirInfo.rightAngle == 90) || (dirInfo.rightAngle == 270))	{
		var offDir = pos.getZ()-vec.getZ();

		for (x = 0; x < width; x++)		{
			for (y = 0; y < height; y++)		{
				for (z = 0; z < length; z++)		{
	
					var tmpVec = pos.add(x, y, z);
					var offLen = (offDir + z);
					var newVec = tmpVec.add(0,0,-(offLen*2));
					var tmpBlock = session.getBlock(tmpVec);
					
					tmpBlock.flip(CuboidClipboard.FlipDirection.WEST_EAST);
					
					if (checkFlag("d"))	{
						session.setBlock(tmpVec, airMat);
					}
					session.setBlock(newVec, tmpBlock);
	
					if (checkFlag("s"))	{
						if((x == 0) && (y == 0) & (z == 0))	{
							var selector = context.getSession().getRegionSelector(player.getWorld());
							if (selector.selectPrimary(newVec)) {
								context.getSession().dispatchCUISelection(player);
							}
						}
						if((x == (width-1)) && (y == (height-1)) && (z == (length-1)))	{
							var selector = context.getSession().getRegionSelector(player.getWorld());
							if (selector.selectSecondary(newVec)) {
								context.getSession().dispatchCUISelection(player);
							}
						}
					}
				}
			}
		}
	}
	

}

function BuildLaser(vec, session)	{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 1;
	var depth = checkFlag("d") ? parseInt(checkFlag("d")) :  0;
	var blockA = checkFlag("a") ? parseBlock(checkFlag("a")) :  new BaseBlock(1);
	var matB = checkFlag("b") ? parseBlock(checkFlag("b")) :  new BaseBlock(1);
	var matA = (gMat == airMat) ? new SingleBlockPattern(blockA) : gMat;
	size = gSize != -1 ? gSize : size;

	var origin = player.getBlockIn().add(0,1,0);
	var distance = getDistance(origin, vec);
	var step = .9/distance;
	var extendBeam = 1 + (depth*step);
	
	for( var i = 0; i <= extendBeam; i += step) {
		
		if (i < ((size*step) + step*2)) {continue;}
		
		var xi = origin.getX() + ((vec.getX() - origin.getX()) * i);
		var yi = origin.getY() + ((vec.getY() - origin.getY()) * i);
		var zi = origin.getZ() + ((vec.getZ() - origin.getZ()) * i);
		var pos = new Vector(xi, yi, zi);
		
		if (i <= 1)	{
			if (size == 1)	{
				session.setBlock(pos, matA);
			}
			else	{
				CreateSphere(size, 1, pos, matA, session);
			}		
		}
		else if (i > 1)	{
			if (size == 1)	{
				session.setBlock(pos, matB);
			}
			else	{
				CreateSphere(size, 1, pos, matB, session);
			}
		}

	}
}
	
function BuildRevolve(vec, session)	{

	var pointOver = checkFlag("c") ? parseInt(checkFlag("c")) : 0;
	var bTypeB = checkFlag("b") ? parseBlock(checkFlag("b")) :  new BaseBlock(0);

	var world = context.getSession().getSelectionWorld();
	var region = context.getSession().getSelection(world);

	var regionMin = new Vector(region.getMinimumPoint().getX(), region.getMinimumPoint().getY(), region.getMinimumPoint().getZ());
	var bTypeA = new BaseBlock(0);

	var pointRes = 16;

	for (var x = 0; x < region.getWidth(); x++ ) {
		for (var y = 0; y < region.getHeight(); y++ ) {
			for (var z = 0; z < region.getLength(); z++) {
				
				var pos = regionMin.add(x, y, z);
				var id = session.getBlock(pos);
				var bCheck = 0;	
				if (bTypeB.getType() != 0) {bCheck = id.getType() != bTypeB.getType() ? 1 : 0};		
																									
				if (((id.getType()) != (bTypeA.getType())) && (bCheck == 0))  		
				{			
					var radZ = Math.abs(vec.getZ()-pos.getZ());	
					var radX = Math.abs(vec.getX()-pos.getX());
					var radius = radX > radZ ? radX : radZ;	
					
					var points = pointOver != 0 ? pointOver : (pointRes * radius);
					var slice = 2 * Math.PI / points;
					
					for (var i = 0; i < (points); i++)
					{
						var angle = (slice * i);
						var newX = (radius * Math.cos(angle));
						var newY = (radius * Math.sin(angle));
						var newZ = (pos.getY() - vec.getY());
						var pt = vec.add(newX, newZ, newY);	

						session.setBlock(pt, id);
					}
				}			
			}
		}
	}
}

function BuildRotate(vec, session)	{
	
	var angleArg = checkFlag("i") ? parseInt(checkFlag("i")) : 8;
	var resolution = checkFlag("r") ? parseInt(checkFlag("r")) : 4;
	var singleMode = checkFlag("s") ? true : false;

	var world = context.getSession().getSelectionWorld();
	var region = context.getSession().getSelection(world);

	angleArg = angleArg == 0 ? 8 : angleArg;
	angleStep = angleArg < 0 ? Math.abs(angleArg) : (360/angleArg);

	var step = 1 / resolution;
	
	for (var x = 0; x < region.getWidth(); x += step) {
		for (var z = 0; z < region.getLength(); z += step) {
			for (var y = 0; y < region.getHeight(); y += 1) {
				
				var tmpVec = region.getMinimumPoint().add(x, y, z);
				
				var block = session.getBlock(tmpVec);
				if (block.getType() == BlockID.AIR)	{continue;}
				
				var angle = angleStep;				
				while (angle < 360)	{
					
					var newVec = Vector(rotateVec(vec, tmpVec, angle));
					var oldVec = Vector(rotateVec(vec, newVec, -angle));
					
					if (session.getBlock(oldVec).getType() == block.getType() && session.getBlock(newVec).getType() != block.getType())	{

						session.setBlock(newVec, block);
					}
					
					if (singleMode) {angle = 360;}
					angle += angleStep;
				}	
			}
		}
	}
}

function BuildErode(vec, session)	{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 8;
	var maxFaces = checkFlag("f") ? parseInt(checkFlag("f")) :  3;
	var strength = checkFlag("i") ? parseInt(checkFlag("i")) :  1;
	size = gSize != -1 ? gSize : size;	
	maxFaces = (gMat == airMat) ? maxFaces : gMat.next(zVec).getType();
	
	if (size == 0)	{size = 4;}
	var blocks = [];
	
	for (iteration = 1; iteration <= strength; iteration++)	{
		
		var blockTotal = 0;			
		var blockCnt = 0;			
		var blockFaces = new Array(6);
		
		for (var x = 0; x <= size; x++) {
			for (var y = 0; y <= size; y++) {
				for (var z = 0; z <= size; z++) {					
					pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
					distance = getDistance(vec, pos);
					if (distance > size/2)	{continue;}
					
					var curBlock = session.getBlock(pos);
					
					var blockCnt = 0;
					var blockFaces = [];
					
					blockFaces[1] = session.getBlockType(pos.add(1,0,0));
					blockFaces[2] = session.getBlockType(pos.add(-1,0,0));
					blockFaces[3] = session.getBlockType(pos.add(0,1,0));
					blockFaces[4] = session.getBlockType(pos.add(0,-1,0));
					blockFaces[5] = session.getBlockType(pos.add(0,0,1));
					blockFaces[6] = session.getBlockType(pos.add(0,0,-1));	
					
					for (var inc = 1; inc <= 6; inc++) {
						if((blockFaces[inc]) == 0) {blockCnt++;}												
					}
					
					if (blockCnt >= maxFaces) {
						blocks[blockTotal] = BlockID.AIR;
					}
					else {
						blocks[blockTotal] = curBlock.getType();
					}
					blockTotal++;

				}
			}
		}
		
		var setBlockTotal = 0;
		for (var x = 0; x <= size; x++) {
			for (var y = 0; y <= size; y++) {
				for (var z = 0; z <= size; z++) {				
					pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
					distance = getDistance(vec, pos);
					if (distance > size/2)	{continue;}
					
					var ID = blocks[setBlockTotal];

					session.setBlock(pos, new BaseBlock(ID));
					setBlockTotal++;

				}
			}
		}
	}

}

function BuildFill(vec, session)	{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 8;
	var maxFaces = checkFlag("f") ? parseInt(checkFlag("f")) :  3;
	var strength = checkFlag("i") ? parseInt(checkFlag("i")) :  1;
	size = gSize != -1 ? gSize : size;	
	maxFaces = (gMat == airMat) ? maxFaces : gMat.next(zVec).getType();
	
	if (size == 0)	{size = 4;}
	var blocks = [];
	
	for (iteration = 1; iteration <= strength; iteration++)	{
		
		var blockTotal = 0;			
		var blockCnt = 0;			
		var blockFaces = new Array(6);
		
		for (var x = 0; x <= size; x++) {
			for (var y = 0; y <= size; y++) {
				for (var z = 0; z <= size; z++) {					
					pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
					distance = getDistance(vec, pos);
					if (distance > size/2)	{continue;}
					
					var curBlock = session.getBlock(pos);
					if (curBlock.getType() != BlockID.AIR) {
						blocks[blockTotal] = curBlock.getType();
						blockTotal++;
						continue;
					}
					
					var blockCnt = 0;
					var blockFaces = [];
					
					blockFaces[1] = session.getBlockType(pos.add(1,0,0));
					blockFaces[2] = session.getBlockType(pos.add(-1,0,0));
					blockFaces[3] = session.getBlockType(pos.add(0,1,0));
					blockFaces[4] = session.getBlockType(pos.add(0,-1,0));
					blockFaces[5] = session.getBlockType(pos.add(0,0,1));
					blockFaces[6] = session.getBlockType(pos.add(0,0,-1));	
					
					var newArray = compressArray(blockFaces);
					
					var maxFace = new Object()
					
					for (var lpC = 1; lpC <= 6; lpC++) {
						
						if(blockFaces[lpC] != 0) {blockCnt++;}												
					}
					
					for (q in newArray) {
						if (newArray[q].value != 0) {
							if (typeof maxFace.value === "undefined") {
								maxFace = newArray[q];
							}							
							if (newArray[q].count > maxFace.count) {
								maxFace = newArray[q];
							}
						}
					}
						
					if (blockCnt >= maxFaces){
						if (typeof maxFace.value === "undefined") {
							blocks[blockTotal] = BlockID.STONE
						}
						else {
							blocks[blockTotal] = maxFace.value
						}
					}	
					else {
						blocks[blockTotal] = curBlock.getType();
					}
					blockTotal++;

				}
			}
		}
		
		var setBlockTotal = 0;
		for (var x = 0; x <= size; x++) {
			for (var y = 0; y <= size; y++) {
				for (var z = 0; z <= size; z++) {				
					pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
					distance = getDistance(vec, pos);
					if (distance > size/2)	{continue;}
					
					var ID = blocks[setBlockTotal];

					session.setBlock(pos, new BaseBlock(ID));
					setBlockTotal++;

				}
			}
		}
	}



}

function BuildWand(vec, session)	{
	
	var wandTool = new DoubleActionTraceTool({
		canUse : function(player) {
			return player.hasPermission("worldedit.tool.wand");
		},
		actPrimary : function(server,config,player,session) {
			var vec = player.getBlockIn()
			if (vec == null) { return; }
			var selector = session.getRegionSelector(player.getWorld());
			if (selector.selectSecondary(vec)) {
				session.dispatchCUISelection(player);
			}
			return;
		},
		actSecondary : function(server,config,player,session) {
			
			var vec = checkFlag("~") ? player.getBlockTrace(parseInt(checkFlag("~")), true) : player.getBlockTrace(200, false);
			if (vec == null) { return; }

			var selector = session.getRegionSelector(player.getWorld());
			var setVec = selector.isDefined() ? selector.getPrimaryPosition(): zVec.toBlockVector();
			
			if (setVec.equals(vec.toBlockVector()))	{
				selector.clear();
				session.dispatchCUISelection(player);
				player.print(text.White + text.Italics + "Selection cleared.");
				return;
			}

			if (selector.selectPrimary(vec)) {
				session.dispatchCUISelection(player);
			}
			return;

		},	
	});
	
	context.getSession().setTool(player.getItemInHand(), wandTool);

}

function BuildOre(vec, session)		{

	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 20;
	var density = checkFlag("d") ? parseInt(checkFlag("d")) : 100;
	var overBlockID = checkFlag("b") ? parseBlock(checkFlag("b")).getType() :  BlockID.STONE;
	var origin = vec.add(0 - size/2 + .5, 0 - size/2 + .5, 0 - size/2 + .5);

	var width = size;
	var height = size;
	var length = size;
	var area = width * height * length;
	
	if(checkFlag("r"))	{
		var world = context.getSession().getSelectionWorld();
		var region = context.getSession().getSelection(world);
	
		var width = Math.abs(region.getMaximumPoint().getX() - region.getMinimumPoint().getX());
		var height = Math.abs(region.getMinimumPoint().getY() - region.getMaximumPoint().getY());
		var length = Math.abs(region.getMinimumPoint().getZ() - region.getMaximumPoint().getZ());
		var area = width * height * length;
		var origin = new Vector(
				region.getMinimumPoint().getX(),
				region.getMinimumPoint().getY(),
				region.getMinimumPoint().getZ()
				);
		
	}
	
	var oreTotal = 0;
	for (var oInc in oreList)	{
		oreTotal++;
	}
	
	var rand = new java.util.Random(); 	
	var densityStep = 300;
	var maxVeinSize = 12;
	var veinCount = 0;
	var oreCount = 0;

	var maxPoints = (area / densityStep) * (density / 100);

	for ( var pointStep = 0; pointStep < maxPoints; pointStep++) {
			
		randPnt = origin.add(rand.nextInt(width), rand.nextInt(height), rand.nextInt(length));
		randPnt2 = randPnt.add(rand.nextInt(maxVeinSize)*2-maxVeinSize, rand.nextInt(maxVeinSize)*2-maxVeinSize, rand.nextInt(maxVeinSize)*2-maxVeinSize);

		if (session.getBlock(randPnt).getType() != overBlockID)	{continue;}
		var distance = getDistance(randPnt, randPnt2);
		
		var testOre = [];
		var maxOreID = 0;
		var maxOreChance = 0;
		var chanceMax = 0;

		for (var findOre = 1; findOre <= oreTotal; findOre++)	{
			
			if (randPnt.getY() <= 0)	{ continue; }
			
			if ((oreList[findOre].minY <= randPnt.getY()) && (oreList[findOre].maxY >= randPnt.getY())) {
				
				var tmpOre = new Object();
				tmpOre.myOreID = findOre;
				
				tmpOre.minChance = chanceMax;
				tmpOre.maxChance = chanceMax + oreList[findOre].chance;
				testOre.push(tmpOre);
				chanceMax += oreList[findOre].chance;
			}
		}
		
		if(testOre.length <= 0)	{ continue; }
		randomProb = Math.random() * chanceMax;

		for (var getOre = 0; getOre < testOre.length; getOre++)	{
			if ((randomProb >= testOre[getOre].minChance) && (randomProb <= testOre[getOre].maxChance))	{
				maxOreID = testOre[getOre].myOreID;
			}
		}
		
		var bType = new BaseBlock(oreList[maxOreID].BlockID);
		
		var step = .9/distance;
		var newLength = (rand.nextInt(oreList[maxOreID].maxSize - oreList[maxOreID].minSize) + oreList[maxOreID].minSize);
		var chgCount = 0;
		
		for( var i = 0; i <= 1; i += step ) {
			
			if (chgCount >= newLength)	{break;}
			
			var distance = getDistance(randPnt, randPnt2);
			var step = .9/distance;

			for( var i = 0; i <= 1; i += step) {
					
				var xi = randPnt.getX() + ((randPnt2.getX() - randPnt.getX()) * i);
				var yi = randPnt.getY() + ((randPnt2.getY() - randPnt.getY()) * i);
				var zi = randPnt.getZ() + ((randPnt2.getZ() - randPnt.getZ()) * i);
								
				var vecA = new Vector(xi, yi, zi);
				if(vecA.getY() <= 0)	{ continue; }
				
				if (session.getBlock(vecA).getType() == overBlockID)	{
					session.setBlock(vecA, bType);	
					chgCount++;
					oreCount++;	
				}
			}
			
			
		}
		veinCount++;
		
	}
}

function BuildFragment(vec, session)	{
	
	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 7;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) : new BaseBlock(1);
	var density = checkFlag("d") ? parseFloat(checkFlag("d")) : .75;
	var hollow = checkFlag("h") ? parseInt(checkFlag("h")) : 0;

	size = gSize != -1 ? gSize + (gSize * Math.random()*.2) : size;
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;	
	
	CreateLeafSphere(size, size, density, hollow, vec.add(0,-(size/2),0), mat, session);

}

function BuildSpawner(vec, session)	{

	var entityList = [
		"bat", "chicken", "cow", "pig", "sheep", "squid", "villager", "enderman", "pigzombie", "blaze",
		"creeper", "ghast", "silverfish", "wither", "slime", "lavaslime", "spider", "cavespider", "witch",
		"zombie", "ozelot", "wolf", "villagergolem", "snowman", "enderdragon", "witherboss", "giant", "boat",
		"minecart", "mushroomcow", "endercrystal", "item", "xporb", "arrow", "snowball", "fireball", "smallfireball"
	]

	var type = argv.length > 2 ? String(argv[2]).toLowerCase() : "-";
	entityList.sort();
	
	for (inc in entityList)	{
		
		if(type == "all")
			session.setBlock(vec.add(0,parseInt(inc)+1,0), MobSpawnerBlock(entityList[inc].toLowerCase()));
		
		if(entityList[inc].toLowerCase() == type)	{
			session.setBlock(vec.add(0,1,0), MobSpawnerBlock(entityList[inc].toLowerCase()));
			return;
		}
	}
	
	if (type != "all")	{
		player.print("\n" + text.Red + "Error: " + text.White + "Entity type " + text.Gold + type + text.White + " not found.");
		player.print(text.Gold + text.Italics + "Available Entity Types: \n" + text.White + "[" + entityList + "]");
	}	

}

function BuildKiller(vec, session)	{

	var entityType = argv.length > 2 ? String(argv[2]).toLowerCase() : false;
	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 7;
	size = gSize != -1 ? gSize : size;
	
	var pos1 = Vector(vec.getX()-size/2, vec.getY()-size/2, vec.getZ()-size/2);
	var pos2 = Vector(vec.getX()+size/2, vec.getY()+size/2, vec.getZ()+size/2);
	var region = new CuboidRegion(pos1, pos2);
		
	/* Entity killing - unstable
	
	var entities = player.getWorld().getEntities(region);
	for (var entity in entities) {
		var tmp2 = entities[entity].getPosition().position;
		var tmp3 = entities[entity].getClass().getType();
		player.print("Entity Killed @ " + String(tmp2) + String(tmp3));
		
		for (sube in  entities[entity])	
			//player.print(sube);

	}
	player.getWorld().killEntities(entities);
	*/
	
	/* Entity Spawning
	    public LocalEntity[] pasteEntities(Vector pos) {
        LocalEntity[] entities = new LocalEntity[this.entities.size()];
        for (int i = 0; i < this.entities.size(); ++i) {
            CopiedEntity copied = this.entities.get(i);
            if (copied.entity.spawn(copied.entity.getPosition().setPosition(copied.relativePosition.add(pos)))) {
                entities[i] = copied.entity;
            }
        }
        return entities;
    }
	
	
	*/
	
	/* Alt killing method - unstable
	
	var entities = player.getWorld().getWorld().getLivingEntities();
	
	var cnt = 0;
	for (var inc = 0; inc < entities.size(); inc++) {
		var entity = entities.get(inc);
		var type = String(entity.getType()).toLowerCase();
		var loc = entity.getLocation();
		var pos = new Vector(parseInt(loc.getX()), parseInt(loc.getY()), parseInt(loc.getZ()));
		
		//player.print("what the hell?!" + entity + type + pos);
		if (region.contains(pos))	{
			player.print("inside");
			if (!(entityType) || (type == entityType))	{
				entity.remove();
			}
		}
		//player.print("any luck?");
		
	}
	*/

}

function BuildPattern(vec, session)	{

	if (argv.length < 3) 	{
		player.print (text.Red + "Error:" + text.White + " You need to specify a pattern type to use.");
		return false;
	}

	var blockList = String(argv[2]).toLowerCase();
	var size = checkFlag("s") ? parseInt(checkFlag("s")) : 10;
	blockList = blockList == "-" ? "ruin" : blockList;
	size = gSize != -1 ? gSize : size;
	
	if (blocks[blockList] == undefined)	{
		player.print(text.Red + "Error:" + text.White + " Pattern type " + text.Gold + blockList + text.White + " not found.");
		return;
	}
	
	var blackList = [0,6,31,32,37,38,39,40,81,106];
	
	for (var x = 0; x <= size; x++) {
		for (var y = 0; y <= size; y++) {
			for (var z = 0; z <= size; z++) {					
				pos = vec.add(x - size/2 + .5, y - size/2 + .5, z - size/2 + .5);
				distance = getDistance(vec, pos);

				if (distance > size/2)	{continue;}
				
				if (blackList.indexOf(session.getBlock(pos).getType()) != -1)	{continue;}
					
				session.setBlock(pos, getListBlock(blocks[blockList].list));
				//session.setBlock(pos, getListBlock(blocks["Plants"].list));


			}
		}
	}

}

function BuildArray(vec, session)	{

	var world = context.getSession().getSelectionWorld();
	var region = context.getSession().getSelection(world);

	var cnt1 = checkFlag("a") ? parseInt(checkFlag("a")) : 0;
	var cnt2 = checkFlag("b") ? parseInt(checkFlag("b")) : 0;
	var cnt3 = checkFlag("c") ? parseInt(checkFlag("c")) : 0;

	var copyAir = false;

	switch(stage)	{

		case 0:
		case 1:
			offsetVec[0] = vec;
			offsetVec[1] = vec;	
			offsetVec[2] = vec;	
			offsetVec[3] = vec;	
			player.print(text.White + "Origin point #1 set to [" + vec.getX() + ", " + vec.getY() + ", " + vec.getZ() + "]");
			player.print(text.Gold + text.Italics + "Ready for offset point #1.");
			stage = 2;
			break;
			
		case 2:
			offsetVec[1] = vec.add(-(offsetVec[0].getX()), -(offsetVec[0].getY()), -(offsetVec[0].getZ()));
			var pStr1 = (text.White + "Offset point #1 set to [" + vec.getX() + ", " + vec.getY() + ", " + vec.getZ() + "]\n")
			var pStr2 = (text.White + "Point #1 Offset Total: [" + offsetVec[1].getX() + ", " + offsetVec[1].getY() + ", " + offsetVec[1].getZ() + "]")
			player.print(pStr1 + pStr2);
			if (cnt2 == 0)	{
				stage = 7;
				break;
			}
			player.print(text.Gold + text.Italics + "Ready for origin point #2.");
			stage++;
			break;				
		case 3:
			offsetVec[0] = vec;
			player.print(text.White + "Origin point #2 set to [" + vec.getX() + ", " + vec.getY() + ", " + vec.getZ() + "]");
			player.print(text.Gold + text.Italics + "Ready for offset point #2.");
			stage++;
			break;		

		case 4:
			offsetVec[2] = vec.add(-(offsetVec[0].getX()), -(offsetVec[0].getY()), -(offsetVec[0].getZ()));
			var pStr1 = (text.White + "Offset point #2 set to [" + vec.getX() + ", " + vec.getY() + ", " + vec.getZ() + "]\n")
			var pStr2 = (text.White + "Point #2 Offset Total: [" + offsetVec[2].getX() + ", " + offsetVec[2].getY() + ", " + offsetVec[2].getZ() + "]")
			player.print(pStr1 + pStr2);
			if (cnt3 == 0)	{
				stage = 7;
				break;
			}
			player.print(text.Gold + text.Italics + "Ready for origin point #3.");
			stage++;
			break;				
		case 5:
			offsetVec[0] = vec;
			player.print(text.White + "Origin point #3 set to [" + vec.getX() + ", " + vec.getY() + ", " + vec.getZ() + "]");
			player.print(text.Gold + text.Italics + "Ready for offset point #3.");
			stage++;
			break;	

		case 6:
			offsetVec[3] = vec.add(-(offsetVec[0].getX()), -(offsetVec[0].getY()), -(offsetVec[0].getZ()));
			var pStr1 = (text.White + "Offset point #3 set to [" + vec.getX() + ", " + vec.getY() + ", " + vec.getZ() + "]\n")
			var pStr2 = (text.White + "Point #3 Offset Total: [" + offsetVec[3].getX() + ", " + offsetVec[3].getY() + ", " + offsetVec[3].getZ() + "]")
			player.print(pStr1 + pStr2);
			stage++;
			break;
	}

	if (stage == 10)	{
	
		var min = region.getMinimumPoint();
		var max = region.getMaximumPoint();

		var minX = min.getBlockX();
		var minY = min.getBlockY();
		var minZ = min.getBlockZ();
		var maxX = max.getBlockX();
		var maxY = max.getBlockY();
		var maxZ = max.getBlockZ();
		
		var setPos = new Vector;
		var setPos2 = new Vector;
		
		for (var x = minX; x <= maxX; ++x) {
			for (var z = minZ; z <= maxZ; ++z) {
				for (var y = minY; y <= maxY; ++y) {
				
					var block = session.getBlock(new Vector(x, y, z));
					if (!block.isAir() || copyAir) {
						for (var i = 0; i <= cnt1; ++i) {
							setPos = Vector(x + offsetVec[1].getX() * i, y + offsetVec[1].getY() * i, z + offsetVec[1].getZ() * i);

							for (var j = 0; j <= cnt2; ++j) {
								setPos2 = Vector(setPos.add(offsetVec[2].getX() * j, offsetVec[2].getY() * j, offsetVec[2].getZ() * j));
								for (var k = 0; k <= cnt3; ++k) {
									setPos3 = Vector(setPos2.add(offsetVec[3].getX() * k, offsetVec[3].getY() * k, offsetVec[3].getZ() * k));
								
									session.setBlock(setPos3, block);
								}
								session.setBlock(setPos2, block);
							}
						}
					}
				}
			}
		}
		player.print(text.White + "Array complete!");
		stage = 0;
	}
	
	if (stage == 7)	{
		player.print(text.Gold + text.Italics + "Everything is set!" + text.White + text.Italics + " Click once more to perform the array stack!");
		stage = 10;
	}

}

function BuildMap(vec, session)	{

 	if (argv.length > 2)	{
		var fileStr = String(argv[2]).toLowerCase();
	}
	else {		//no file specified
		player.print(text.Red + "Error: " + text.White + "You must specify a filename to save to.");
		return false;
	} 

	var size = checkFlag("s", 3) ? parseInt(checkFlag("s")) : 256;
	var img = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
	var file = context.getSafeFile("shapes", String(fileStr) + '.png');

	if(!file.exists()){
		file.createNewFile();
	}
	
	blockColors = {			//RGB values for blocks
		1: Vector(85,85,85),		//stone
		2: Vector(0,225,0),			//grass
		9: Vector(0,0,255),			//water
		12: Vector(228,216,174),	//sand
		13: Vector(120,120,120),	//gravel
		17: Vector(165,103,53),		//wood
		18: Vector(76,150,24),		//leaves
		31: Vector(0,170,0),		//long grass
		37: Vector(255,248,56),		//yellow flower
		78: Vector(230,255,255),	//snow layer
		79: Vector(145,255,227),	//ice
		106: Vector(25,70,5),		//vines
	}
	
	vec = player.getBlockIn();

	for (var x = 0; x < size; x++) {
		for (var z = 0; z < size; z++) {
		
			pos = vec.add(x - size/2 + .5, 0, z - size/2 + .5);
			var yMax = session.getHighestTerrainBlock(pos.getX(),pos.getZ(), 0, 256, false);

			for (var y = yMax; y < 256; y++) {
				
				var topVec = Vector(pos.getX(), y, pos.getZ());
				if(session.getBlockType(topVec.add(0,1,0)) == 0)	{
					var topID = session.getBlockType(topVec);
					break;
				}
			}
			
			
			clr = getColor(0,0,0);
			if (checkFlag("h", 3) == false)	{
				for(inc in blockColors)	{
					if(inc == topID)	{
						clr = getColor(blockColors[inc].getX(), blockColors[inc].getY(), blockColors[inc].getZ());
						break
					}
				}
			}
			else	{
				var modb = 1;
				for(inc in blockColors)	{
					if(inc == topID)	{
						r = blockColors[inc].getX()-(y/modb) < 0 ? 0 : blockColors[inc].getX()-(y/modb);
						g = blockColors[inc].getY()-(y/modb) < 0 ? 0 : blockColors[inc].getY()-(y/modb);
						b = blockColors[inc].getZ()-(y/modb) < 0 ? 0 : blockColors[inc].getZ()-(y/modb);
						clr = getColor(r, g, b);
						break
					}
				}
				//clr = getColor(y,y,y);
			}
			
			
			
			img.setRGB(x, z, clr);
		}		
	}
	
	ImageIO.write(img, "png", file);
	player.print(text.White + "Map image successfully saved to:\n" + text.Gold + file);

}

function BuildFlip(vec, session)	{

	var world = context.getSession().getSelectionWorld();
	var region = context.getSession().getSelection(world);
	
	var pos = region.getMinimumPoint();
	var width = region.getWidth();
	var length = region.getLength();
	var height = region.getHeight();
	var vec2 =  player.getBlockIn();
	var dirInfo = getDirection();	

	if ((dirInfo.rightAngle == 0) || (dirInfo.rightAngle == 180))	{
		var offDir = pos.getX()-vec.getX();
		for (x = 0; x < width; x++)		{
			for (y = 0; y < height; y++)		{
				for (z = 0; z < length; z++)		{
					
					var tmpVec = pos.add(x,y,z);
					var tmpBlock = session.getBlock(tmpVec);
					var offLen = Math.abs(offDir + x);
					
					if ((tmpVec.getX()+width/2) <= vec.getX())
						var newVec = Vector(vec.getX()+y,vec.getY()+offLen,pos.getZ()+z);
					if ((tmpVec.getX()+width/2) > vec.getX())
						var newVec = Vector(vec.getX()-y,vec.getY()+offLen,pos.getZ()+z);
									
					if (checkFlag("d"))	{
						session.setBlock(tmpVec, airMat);
					}					
					session.setBlock(newVec, tmpBlock);
					
					if (checkFlag("s"))	{
						if((x == 0) && (y == 0) & (z == 0))	{
							var selector = context.getSession().getRegionSelector(player.getWorld());
							if (selector.selectPrimary(newVec)) {
								context.getSession().dispatchCUISelection(player);
							}
						}
						if((x == (width-1)) && (y == (height-1)) && (z == (length-1)))	{
							var selector = context.getSession().getRegionSelector(player.getWorld());
							if (selector.selectSecondary(newVec)) {
								context.getSession().dispatchCUISelection(player);
							}
						}
					}
				}
			}
		}
		return true;
	}
	
	if ((dirInfo.rightAngle == 90) || (dirInfo.rightAngle == 270))	{
		var offDir = pos.getZ()-vec.getZ();
		for (x = 0; x < width; x++)		{
			for (y = 0; y < height; y++)		{
				for (z = 0; z < length; z++)		{
				
					var tmpVec = pos.add(x,y,z);
					var tmpBlock = session.getBlock(tmpVec);
					var offLen = Math.abs(offDir + z);
					
					if ((pos.getZ()+length/2) <= vec.getZ())
						var newVec = Vector(pos.getX()+x,vec.getY()+offLen,vec.getZ()+y);
					if ((pos.getZ()+length/2) > vec.getZ())
						var newVec = Vector(pos.getX()+x,vec.getY()+offLen,vec.getZ()-y);
					
					
					//if(tmpBlock.getType() == BlockID.AIR)	{continue}	
					if (checkFlag("d"))	{
						session.setBlock(tmpVec, airMat);
					}					
					session.setBlock(newVec, tmpBlock);

					if (checkFlag("s"))	{
						if((x == 0) && (y == 0) & (z == 0))	{
							var selector = context.getSession().getRegionSelector(player.getWorld());
							if (selector.selectPrimary(newVec)) {
								context.getSession().dispatchCUISelection(player);
							}
						}
						if((x == (width-1)) && (y == (height-1)) && (z == (length-1)))	{
							var selector = context.getSession().getRegionSelector(player.getWorld());
							if (selector.selectSecondary(newVec)) {
								context.getSession().dispatchCUISelection(player);
							}
						}
					}
				}
			}
		}
		return true;	
	}




}

function BuildBox(vec, session)	{

	var xSize = checkFlag("x") ? parseInt(checkFlag("x")) : 20;
	var ySize = checkFlag("y") ? parseInt(checkFlag("y")) : 10;
	var zSize = checkFlag("z") ? parseInt(checkFlag("z")) : 5;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) :  new BaseBlock(20);
	var insideBlock = checkFlag("i") ? parseBlock(checkFlag("i")) :  false;
	var hollow = checkFlag("h") ? parseInt(checkFlag("h")) : false;
	var angled = checkFlag("a") ? true : false;	
	
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;

	var dirInfo = getDirection();	

	if (!angled)	{
		if ((dirInfo.rightAngle == 0) || (dirInfo.rightAngle == 180))	{
			var tmpSize = xSize;
			xSize = zSize;
			zSize = tmpSize;
		}
	}
	
	var step = angled ? .7 : 1;
	for (var x = 0; x < xSize; x += step) {
		for (var y = 0; y < ySize; y += step) {
			for (var z = 0; z < zSize; z += step) {
				
				 if (hollow)	{
					if (((x >= hollow) && (x < xSize-hollow)) && ((y >= hollow) && (y < ySize-hollow)) && ((z >= hollow) && (z < zSize-hollow)))	{
						if(!insideBlock) {continue;}
						
						var pt = vec.add((x-xSize/2), (y*invert+invert), (z-zSize/2));
						if (angled) {pt = rotateVec(vec, pt, dirInfo.yaw);}
						
						session.setBlock(pt, insideBlock);
						continue;
						
					}
				 }
		
				var pt = vec.add((x-xSize/2), (y*invert+invert), (z-zSize/2));
				if (angled) {pt = rotateVec(vec, pt, dirInfo.yaw);}
		
				session.setBlock(pt, mat);
			}
		}
	}
}

function BuildEllipse(vec, session)	{

	var xSize = checkFlag("x") ? parseInt(checkFlag("x")) : 16;
	var ySize = checkFlag("y") ? parseInt(checkFlag("y")) : 8;
	var zSize = checkFlag("z") ? parseInt(checkFlag("z")) : 48;
	var block = checkFlag("b") ? parseBlock(checkFlag("b")) :  new BaseBlock(20);
	var insideBlock = checkFlag("i") ? parseBlock(checkFlag("i")) :  false;
	var hollow = checkFlag("h") ? true : false;
	var angled = checkFlag("a") ? true : false;
	
	var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;
	var dirInfo = getDirection();

	function lengthSq(x, y, z) {return (x * x) + (y * y) + (z * z);}
	
	var xOff = ['1', '-1', '1', '1', '-1', '1', '-1', '-1'];
	var yOff = ['1', '1', '-1', '1', '-1', '-1', '1', '-1'];
	var zOff = ['1', '1', '1', '-1', '1', '-1', '-1', '-1'];

	radiusX = xSize/2 + 0.5;
	radiusY = ySize/2 + 0.5;
	radiusZ = zSize/2 + 0.5;

	var invRadiusX = 1 / radiusX;
	var invRadiusY = 1 / radiusY;
	var invRadiusZ = 1 / radiusZ;

	var ceilRadiusX = Math.ceil(radiusX);
	var ceilRadiusY = Math.ceil(radiusY);
	var ceilRadiusZ = Math.ceil(radiusZ);
	
	var step = angled ? .7 : 1;
	var nextXn = 0;
	forX: for (var x = 0; x <= ceilRadiusX; x += step) {
		var xn = nextXn;
		nextXn = (x + 1) * invRadiusX;
		var nextYn = 0;
		forY: for (var y = 0; y <= ceilRadiusY; y += step) {
			var yn = nextYn;
			nextYn = (y + 1) * invRadiusY;
			var nextZn = 0;
			forZ: for (var z = 0; z <= ceilRadiusZ; z += step) {
				var zn = nextZn;
				nextZn = (z + 1) * invRadiusZ;

				var distanceSq = lengthSq(xn, yn, zn);
				if (distanceSq > 1) {
					if (z == 0) {
						if (y == 0) {
							break forX;
						}
						break forY;
					}
					break forZ;
				}

				if (hollow) {
					if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) {
						if (insideBlock)	{
							for (var dirLoop = 0; dirLoop <= 7 ; dirLoop++)	{
							
								var setPnt = vec.add(x * xOff[dirLoop], y * yOff[dirLoop], z * zOff[dirLoop]);
								if (angled) {setPnt = rotateVec(vec, setPnt, dirInfo.yaw);}
								session.setBlock(setPnt, insideBlock);
							}
							
						}
						continue;
					}
				}
				
				
				for (var dirLoop = 0; dirLoop <= 7 ; dirLoop++)	{

					var setPnt = vec.add(x * xOff[dirLoop], y * yOff[dirLoop], z * zOff[dirLoop]);
					if (angled) {setPnt = rotateVec(vec, setPnt, dirInfo.yaw);}
					session.setBlock(setPnt, mat);
					
				}
			}
		}
	}




}

function BuildSpiral(vec, session)	{

	var radius = checkFlag("r") ? parseInt(checkFlag("r")) : 10;
	var compress = checkFlag("s") ? parseInt(checkFlag("s")) : 8;
	var coilCnt = checkFlag("c") ? parseInt(checkFlag("c")) : 3;
	var dFlag = checkFlag("d") ? true : false;
	var hFlag = checkFlag("f") ? true : false;

	//var mat = (gMat == airMat) ? new SingleBlockPattern(block) : gMat;
	radius = gSize != -1 ? gSize : radius;
	compress = compress == 0 ? 1 : compress;

	var origin = vec;
	var cb = context.getSession().getClipboard();
	cb.copy(session);

	if(radius <= 0)	{
		
		radius = radius * .1;
		var increment = .01;
		var maxAngle = Math.PI * 2 * coilCnt;
		var gap = Math.abs(radius);

		for (var angle = 0; angle <= maxAngle; angle = angle + increment)
		{
			var newX = (angle * gap * Math.cos(angle));
			var newY = (angle * gap * Math.sin(angle));
			var newZ = (angle/(compress/10))
			
			if (hFlag) {
				var pt = origin.add(newX, newY*invert, newZ);
				if (dFlag)  {
					var pt2 = origin.add((-newX), (-newY*invert), newZ);
				}
			}
			else {
				var pt = origin.add(newX, newZ*invert, newY);
				if (dFlag)  {
					var pt2 = origin.add((-newX), (newZ*invert), (-newY));
				}
			}
			cb.paste(session, pt, true);
			
			if (dFlag)  {
				cb.paste(session, pt2, true);
			}
		}
	}
	else	{
	
		var points = 256;
		var slice = 2 * Math.PI / points;
		var pt;
		var loopCnt = 0;
		for (var i = 0; i < (points * coilCnt); i++)	{

			var angle = slice * i;

			var newX = (radius * Math.cos(angle));
			var newY = (radius * Math.sin(angle));
			var newZ = (i/(compress*2));
			
			if (hFlag) {
				var pt = origin.add(newX, newY*invert, newZ);
				if (dFlag)  {
					var pt2 = origin.add(-newX, (-newY*invert), newZ);
				}
			}
			else	{
				var pt = origin.add(newX, newZ*invert, newY);
				if (dFlag)  {
					var pt2 = origin.add(-newX, newZ*invert, -newY);
				}
			}
			cb.paste(session, pt, true);
			
			if (dFlag)  {
				cb.paste(session, pt2, true);
			}
		}	
	}
	
}

function BuildMineSweeper(vec, session)	{

	var xSize = checkFlag("x") ? parseInt(checkFlag("x")) : 24;
	var zSize = checkFlag("y") ? parseInt(checkFlag("y")) : 12;
	var mineTotal = checkFlag("m") ? parseInt(checkFlag("m")) : 40;
	
	if (checkFlag("b"))	{
		xSize = 9;
		zSize = 9;
		mineTotal = 10;
	}
	if (checkFlag("i"))	{
		xSize = 16;
		zSize = 16;
		mineTotal = 40;
	}
	if (checkFlag("e"))	{
		xSize = 16;
		zSize = 30;
		mineTotal = 99;
	}
	
//		-x+y|0x+y|+x+y			Offset reference
//		-x0y|####|+x0y
//		-x-y|0x-y|+x-y

	offsetList = {			//Helpful when checking around a block
		1: Vector(-1,0,1),
		2: Vector(-1,0,0),
		3: Vector(-1,0,-1),
		4: Vector(0,0,1),
		5: Vector(0,0,-1),
		6: Vector(1,0,1),
		7: Vector(1,0,0),
		8: Vector(1,0,-1)
	};
		
	mineBlocks = {			//Block set for # of mines in the area
		0: new BaseBlock(BlockID.STONE, 0),			//No mines
		1: new BaseBlock(BlockID.COAL_ORE, 0),		//One mine	
		2: new BaseBlock(BlockID.IRON_ORE, 0),		//Two mines...
		3: new BaseBlock(BlockID.GOLD_ORE, 0),
		4: new BaseBlock(BlockID.LAPIS_LAZULI_ORE, 0),	
		5: new BaseBlock(BlockID.REDSTONE_ORE, 0),
		6: new BaseBlock(BlockID.DIAMOND_ORE, 0),
		7: new BaseBlock(BlockID.EMERALD_ORE, 0),
		8: new BaseBlock(BlockID.OBSIDIAN, 0),
		9: new BaseBlock(46, 0),				//Mine Block
		10: new BaseBlock(42, 0),				//Surface Block
		11: new BaseBlock(98, 0),				//Wall Base Block
		12: new BaseBlock(139, 0),				//Wall Block
		13: new BaseBlock(123, 0)				//Flag Marker
	};
	
	if (checkFlag("w"))	{
		mineBlocks = {			//Alt Wool block set for # of mines in the area
			0: new BaseBlock(35, 0),
			1: new BaseBlock(35, 3),
			2: new BaseBlock(35, 5),
			3: new BaseBlock(35, 6),
			4: new BaseBlock(35, 11),	
			5: new BaseBlock(35, 14),
			6: new BaseBlock(35, 9),
			7: new BaseBlock(35, 13),
			8: new BaseBlock(35, 7),
			9: new BaseBlock(35, 15),
			10: new BaseBlock(42, 0),
			11: new BaseBlock(98, 0),
			12: new BaseBlock(139, 0),	
			13: new BaseBlock(19, 0)	
		};
	}
	var fieldMin = vec.add(-xSize/2, 0, -zSize/2);
	var startTime = new Date();

	if (checkFlag("c"))
		mineBlocks[10] = new BaseBlock(20, 0);
	
	var mines = [];
	
	var arrayWidth = xSize;
	var arrayHeight = zSize;
	
	var mines = new Array(xSize)				//array to hold mine positions
	for (var x = 0; x < xSize; x++) {
		mines[x] = new Array(zSize);
		for (var z = 0; z < zSize; z++) {
			mines[x][z] = 0;
		}
	}
	
	var legendPos = vec.add(xSize/2+4, 1, -4);
	for(var inc = 0; inc < 9; inc++)	{
		session.setBlock(legendPos.add(0,0,inc), mineBlocks[inc]);
	}
	session.setBlock(legendPos.add(0,0,-1), mineBlocks[13]);
	session.setBlock(legendPos.add(0,0,9), mineBlocks[9]);
	
	for (x = -1; x < xSize+1; x++)	{					//Creating the base minefield
		for (z = -1; z < zSize+1; z++)	{
			var pos = vec.add(x - xSize/2, 0, z - zSize/2);
			session.setBlock(pos.add(0,-2,0), mineBlocks[11]);
			for(var y = 1; y < 11; y++)	{ session.setBlock(pos.add(0,y,0), new BaseBlock(0)); }		//clear some space above
			
			if((x == -1) || (x == xSize) || (z == -1) || (z == zSize))	{		//Walls and perimeter
				session.setBlock(pos, mineBlocks[11]);							//Underground stone brick layers
				session.setBlock(pos.add(0,-1,0), mineBlocks[11]);
				
				if((x == parseInt(xSize/2)) || (z == parseInt(zSize/2))) { continue; }
				
				if ((xSize%2) == 1)	{
					if (x == xSize/2) { continue; }
				}
				else	{
					if (x == xSize/2) { continue; }
					if (x+1 == xSize/2) { continue; }
				}
				
				if ((zSize%2) == 1)	{
					if (z == zSize/2) { continue; }
				}
				else	{
					if (z == zSize/2) { continue; }
					if (z+1 == zSize/2) { continue; }
				}
				
				
				
				session.setBlock(pos.add(0,1,0), mineBlocks[12]);
			}	
			else	{															//Center Area
				session.setBlock(pos, mineBlocks[10]);
			}
			
		}
	}
	
	var missCnt = 0;
	for (m = 0; m < mineTotal; m += 0)	{			//Setting the mines
	
		var x = parseInt(Math.random()*xSize);
		var z = parseInt(Math.random()*zSize);
		
		//player.print("x@" + x + "| z@" + z);
		
		var pos = fieldMin.add(x, 0, z);
		//var pos = vec.add(parseInt(x - size/2), 0, parseInt(z - size/2));
		//player.print("pos@" + pos);
		
		
		missCnt++;
		if (mines[x][z] == 0)	{			
			session.setBlock(pos.add(0,-1,0), mineBlocks[9]);
			//player.print("mine set @" + pos + mineBlocks[9]);
			mines[x][z] = 1;
			m++;
			missCnt = 0;
		}
		
		if(missCnt > 1000)	{
			player.print("I couldn't find anymore spots to put mines!");
			player.print("I found room for a total of " + m + " mines.");
			m = mineTotal;
			missCnt = 0;
		}
	}

	player.print(text.Gold + "Finished creating minefield!");
	player.print(text.Gold + mineTotal + text.White + " mines set in a " + text.Gold + xSize + " x " + zSize + text.White + " area - " + text.Gold + (m/(xSize*zSize)*100).toFixed(1) + text.White + "% density.");
	
	for (x = 0; x < xSize; x++)	{					//Setting color blocks
		for (z = 0; z < zSize; z++)	{
			
			pos = vec.add(x - xSize/2, -1, z - zSize/2);
			
			//if (session.getBlock(pos) == mineBlocks[10])	{
			
			if (mines[x][z] == 0)	{
			
				var areaMines = 0;
				
				for (px = -1; px <= 1; px++)	{					//Looping thru neighbor blocks
					for (pz = -1; pz <= 1; pz++)	{
						posX = x + px;
						posZ = z + pz;
						
						if((posX < 0) || (posX >= xSize) || (posZ < 0) || (posZ >= zSize)	)	{continue;}
						
						if (mines[posX][posZ] == 1)
							areaMines++;
					
					
					}
				}
				
				session.setBlock(pos, mineBlocks[areaMines]);
		
			}
		
		}
	}

	var sweeperTool = new DoubleActionTraceTool({			//Creating the sweeper tool
		canUse : function(player) {
			return player.hasPermission("worldedit.tool.wand");
		},
		actSecondary : function(server,config,player,session) {			// ###### Left Click - Clear Block
		
			try {
				var vec = player.getBlockTrace(200, false);
				if (vec == null) { return; }
				
				var es = session.createEditSession(player);
				
				if (es.getBlock(vec).equals(mineBlocks[10]))	{			//check if the surface block was clicked
					var es = session.createEditSession(player);
					var testBlock = es.getBlock(vec.add(0,-1,0));
					es.setBlock(vec.add(0,0,0), testBlock);				
					
					if (testBlock.equals(mineBlocks[0]))	{			//if mine count is zero attempt to expand area
						
						var expandList = [];
						var expandSide = [];
						
						expandList.push(vec.add(0,-1,0)); 
						
						for (var inc = 0;  inc < expandList.length; inc++)	{
							
							for(var side in offsetList)	{		//check all the sides for more open areas, if found push them to be checked also
								if (es.getBlock(expandList[inc].add(offsetList[side])).equals(mineBlocks[0]) && es.getBlock(expandList[inc].add(offsetList[side].add(0,1,0))).equals(mineBlocks[10]))	{
									if (String(expandList).indexOf(String(expandList[inc].add(offsetList[side]))) == -1)	{
										expandList.push(expandList[inc].add(offsetList[side])); 
									}								
								}
							}
							
							if(inc > 500000)	{			//check to see if the expanding gets too far out of control
								player.print("inc over 500,000!");
								player.print("length=" + expandList.length);
								session.remember(es);
								return;
							}
							
							es.setBlock(expandList[inc].add(0,1,0), mineBlocks[0]);
							
							for(var side in offsetList)	{		//open up all the blocks around clear area
								if (es.getBlock(expandList[inc].add(offsetList[side].add(0,1,0))).equals(mineBlocks[10]))
									expandSide.push(expandList[inc].add(offsetList[side].add(0,1,0)));
							}
						}
						
						for (var inc in expandSide) {
							es.setBlock(expandSide[inc], es.getBlock(expandSide[inc].add(0,-1,0)));
						}
					}
				}
				
				else{													//check if a numbered block was clicked
					var tCnt = 0;
					for (var tInc = 1; tInc < 10; tInc++)	{
						if (es.getBlock(vec).equals(mineBlocks[tInc]))		
							tCnt = tInc;
					
					}
				}
				
				if (tCnt > 0)	{				//if a numbered block was found
					
					var flagCnt = 0;
					
					for (var side in offsetList)	{		//open up all the blocks around clear area
						if (es.getBlock(vec.add(offsetList[side])).equals(mineBlocks[13]))
							flagCnt++;
					
					}
					
					if(flagCnt >= tCnt)	{
						for(var side in offsetList)	{		//open up all the blocks around clear area
							
							if (!es.getBlock(vec.add(offsetList[side])).equals(mineBlocks[13]))		{
								es.setBlock(vec.add(offsetList[side]), es.getBlock(vec.add(offsetList[side].add(0,-1,0))));
							}
							
							var testVec = vec.add(offsetList[side].add(0,-1,0));
							var testBlock = es.getBlock(testVec);			
							
							if (testBlock.equals(mineBlocks[0]))	{			//if mine count is zero attempt to expand area
								
								var expandList = [];
								var expandSide = [];
								
								expandList.push(testVec); 
								
								for (var inc = 0;  inc < expandList.length; inc++)	{									
									
									for(var side in offsetList)	{		//check all the sides for more open areas, if found push them to be checked also
										if (es.getBlock(expandList[inc].add(offsetList[side])).equals(mineBlocks[0]) && es.getBlock(expandList[inc].add(offsetList[side].add(0,1,0))).equals(mineBlocks[10]))	{
											if (String(expandList).indexOf(String(expandList[inc].add(offsetList[side]))) == -1)	{
												expandList.push(expandList[inc].add(offsetList[side])); 
											}								
										}
									}
									
									if(inc > 500000)	{			//check to see if the expanding gets too far out of control
										player.print("inc over 500,000!");
										player.print("length=" + expandList.length);
										return;
									}
									
									for(var side in offsetList)	{		//open up all the blocks around clear area
										if (es.getBlock(expandList[inc].add(offsetList[side].add(0,1,0))).equals(mineBlocks[10]))
											expandSide.push(expandList[inc].add(offsetList[side].add(0,1,0)));
									}

								}
								
								for (var inc in expandSide) {
									es.setBlock(expandSide[inc], es.getBlock(expandSide[inc].add(0,-1,0)));
								
								}
							}							
						}
					}
				}
				
				var tntList = [];
				var leftCnt = 0;	//surface block count
				//var fCnt = 0;	//flag count
				for (var x = 0; x < xSize; x++)	{					//Checking for TNT or game win
					for (var z = 0; z < zSize; z++)	{
						var pos = fieldMin.add(x, 0, z);
						
						if (es.getBlock(pos).equals(mineBlocks[10]))	{ leftCnt++; }
						if (es.getBlock(pos).equals(mineBlocks[13]))	{ leftCnt++; }
						
						if (es.getBlock(pos).equals(mineBlocks[9]))	{					//TNT was hit
							for (var xT = 0; xT < xSize; xT++)	{					
								for (var zT = 0; zT < zSize; zT++)	{
									var posT = fieldMin.add(xT, -1, zT);
									if (es.getBlock(posT).equals(mineBlocks[9]))	{
										es.setBlock(posT.add(0,1,0), mineBlocks[9]);
										if (checkFlag("h"))	
											es.setBlock(posT.add(0,0,0), new BaseBlock(76));
									}
									
								}
							}
							
							player.print("\n" + text.Red + text.Bold + "BOOOOOOM!!!!" + text.White + " You hit TNT, and are now dead. Better luck next time!");
							session.setTool(player.getItemInHand(), null)
							return;
						}
					}
				}	
				
				if(leftCnt == mineTotal)	{
				
					var totalTime = (new Date() - startTime)/1000;
					player.print("\n" + text.Gold + text.Bold + "-------- You Win!! --------");
					player.print(text.White + "You cleared " + text.Gold + mineTotal + text.White + " mines from a " + text.Gold + xSize + " x " + zSize + text.White + " area in " + text.Gold + totalTime.toFixed(1) + text.White + " secs!");
					
					var diamonds = new BaseItemStack(264, 1);
					for (var xT = 0; xT < xSize; xT++)	{					
						for (var zT = 0; zT < zSize; zT++)	{
							var posT = fieldMin.add(xT, -1, zT);
							if (es.getBlock(posT).equals(mineBlocks[9]))	{
								es.setBlock(posT.add(0,1,0), mineBlocks[9]);
								player.getWorld().dropItem(posT.add(0,30,0), diamonds, 1);
							}
							
						}
					}
					
					session.setTool(player.getItemInHand(), null)
					return;

				}
				
			}
			catch (e)	{
				player.print("error=" + e);
			}
			
			return;
		},
		
		actPrimary : function(server,config,player,session) {			// ###### Right Click - Set Marker
			
			try {
				var vec = player.getBlockTrace(200, false);
				if (vec == null) { return; }
				var es = session.createEditSession(player);
				
				if (es.getBlock(vec).equals(mineBlocks[10]))	{			//Set Flag
					es.setBlock(vec.add(0,0,0), mineBlocks[13]);
				}
				else if (es.getBlock(vec).equals(mineBlocks[13]))	{		//Remove Flag
					es.setBlock(vec.add(0,0,0), mineBlocks[10]);
				}
				else	{
					
					var flagCnt = 0;
					for (var x = 0; x < xSize; x++)	{					//Checking for flags
						for (var z = 0; z < zSize; z++)	{
							var pos = fieldMin.add(x, 0, z);
							
							if (es.getBlock(pos).equals(mineBlocks[13]))	{ flagCnt++; }
							
						}
					}
					var totalTime = (new Date() - startTime)/1000;
					player.print(text.White + "Mines Left: " + text.Gold + (mineTotal-flagCnt) + text.White + "  Current Time: " + text.Gold + totalTime.toFixed(1) + text.White + " secs.");
				
				}
				
			}
			catch (e)	{
				player.print("error=" + e);
			
			}				
				
			return;

		},	
	});
	
	context.getSession().setTool(player.getItemInHand(), sweeperTool);
	
}


