/*
This work is licensed under the Creative Commons Attribution- NonCommercial 4.0 International License. To view a copy
of this license, visit http://creativecommons.org/licenses/by-nc/4.0/ or send a letter to Creative Commons, 444 Castro
Street, Suite 900, Mountain View, California, 94041, USA.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/* ******* Portal 2 Mod by Desno365 ******* */

const DEBUG = false;

// updates variables
const CURRENT_VERSION = "r013";
var latestVersion;

// minecraft variables
const GameMode = {
	SURVIVAL: 0,
	CREATIVE: 1
};
const VEL_Y_OFFSET = -0.07840000092983246;
var isInGame = false;

// textures variables
var textureUiShowed = false;

// activity and other Android variables
var currentActivity = com.mojang.minecraftpe.MainActivity.currentMainActivity.get();
var sdcard = android.os.Environment.getExternalStorageDirectory();

// display size and density variables
var metrics = new android.util.DisplayMetrics();
currentActivity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
var displayHeight = metrics.heightPixels;
var displayWidth = metrics.widthPixels;
var deviceDensity = metrics.density;
if(displayHeight > displayWidth) // fix auto-rotation disabled bug
{
	var x = displayHeight;
	displayHeight = displayWidth;
	displayWidth = x;
}
metrics = null;

// sounds variables
const MAX_LOGARITHMIC_VOLUME = 30;

// settings for audio
var generalVolume = 1;

// change carried item variables
var previousCarriedItem = 0;
var previousSlotId = 0;

// buttons UI settings variables
const BUTTONS_SIZE_DEFAULT = 24;
var buttonsSize = BUTTONS_SIZE_DEFAULT;
var imageSize = 1;
var pixelsOffsetButtons = 0;

// general settings
var minecraftStyleForButtons = false;
var playWelcomeSoundAtStartup = true;

// map-makers settings
var indestructibleBlocks = false;
var alwaysFullHungerBar = false;
var fullHungerBarTick = 0;

// all the entities array
var entities = [];

// custom mobs array
var customMobs = [];

// player interactions variables
var velBeforeX = 0, velBeforeY = 0, velBeforeZ = 0;
var blockUnderPlayerBefore = 0;

// images in base64
var bluePortalImage = "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";
var orangePortalImage = "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";
var overlayFull = " ";
var overlayBlue = "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";
var overlayOrange = "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";
var overlayBlank = " ";

var backgroundDarkDirtPng = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABw0lEQVR4nM2WS0/CQBSFPwiPCosS0UhidOnCn+D//yW6kQgJ1RR5KS7aU50DE9wNZ9POdGZ6z7mPua2nx7s9QLna8Bef620wvsqH/GfdclWNB1n36P5ZUQbjNonReri93ANc9CuL58USOGSg79tsDMD79CVY5wq5Mn6+kF4BxYB8I8iX9zcjjn0X3LcOnSP4eckV6Mhnu/4IgElWWTyjslDfPbrd5/KxfK+xEMui9Ao0L+sFACUhw+dpNT/OB8AvQ/kwlj0fDOsf1OfWzH1degXESD4WI1ns9cCjOlb5NsVb9YMsjA2PofQKNL5eLYDDCtbJJ9V88QocMhC8xpOH854lUji9AnqJMStXcwC6xsCZKRbKfpjnQqw+pFfAK1PMZ265Z4PqhOCxJJxfHdBL7L4WfN7zPsb4IFsIFT4fBYRonhPmudd23fPN+iK8TZsfWl05HwXch265dz7yYS+/rtcf74ikkLJkVzNXFiVXoOmKZZHf+57/w6wHxHvAU/DYSq5AEwPOXCg33wC091/BvFdK76LVScV6SCG9AqeYyNenOiE9Y7Hh2SOkV8AnxNz7/WZDXcnG/fnRA7338/2udHIFfgBs9yLA5bCE1QAAAABJRU5ErkJggg==";
var divider = "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";
var playStorePng = " ";

/* credits to Designmodo for the settings icon that is licensed under the Creative Commons Attribution 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/ */
var settingsPng = " ";


// decoded images variables
var bluePortalScaled;
var orangePortalScaled;
var overlayFullScaled;
var overlayBlueScaled;
var overlayOrangeScaled;
var overlayBlankScaled;

var backgroundDarkDirtScaled;
var dividerScaled;
var settingsPngScaled;

// background of layouts
var background;

// item functions needed on load
Item.setVerticalRender = function(id)
{
	try {
		Item.setHandEquipped(id, true);
	} catch(e) { /* old version of BlockLauncher */ }
}
Item.defineItem = function(id, textureName, textureNumber, name, stackLimit)
{
	try
	{
		ModPE.setItem(id, textureName, textureNumber, name, stackLimit);
	}catch(e)
	{
		// user hasn't installed the texture pack
		if(!textureUiShowed)
			pleaseInstallTextureUI();

		ModPE.setItem(id, "skull_zombie", 0, name, stackLimit);
	}
}
Item.newArmor = function(id, iconName, iconIndex, name, texture, damageReduceAmount, maxDamage, armorType)
{
	try
	{
		//Item.defineArmor(int id, String iconName, int iconIndex, String name, String texture, int damageReduceAmount, int maxDamage, int armorType)
		Item.defineArmor(id, iconName, iconIndex, name, texture, damageReduceAmount, maxDamage, armorType);
	}catch(e)
	{
		// user hasn't installed the texture pack
		if(!textureUiShowed)
			pleaseInstallTextureUI();

		Item.defineArmor(id, "skull_zombie", 0, name, "armor/chain_2.png", damageReduceAmount, maxDamage, armorType);
	}
}

const PORTAL_GUN_ORANGE_ID = 3649;
const PORTAL_GUN_DAMAGE = 1000;
Item.defineItem(PORTAL_GUN_ORANGE_ID, "portalgunorange", 0, "PortalGun ");
Item.setMaxDamage(PORTAL_GUN_ORANGE_ID, PORTAL_GUN_DAMAGE);
Item.setVerticalRender(PORTAL_GUN_ORANGE_ID);
Item.setCategory(PORTAL_GUN_ORANGE_ID, ItemCategory.TOOL);

const PORTAL_INFORMATION_ID = 3650;
Item.defineItem(PORTAL_INFORMATION_ID, "portalinfo", 0, "§1设置(全汉化)");
Item.addShapedRecipe(PORTAL_INFORMATION_ID, 1, 0, [
	"   ",
	" w ",
	"   "], ["w", 17, 0]);
Item.setCategory(PORTAL_INFORMATION_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(PORTAL_INFORMATION_ID, 1);

// portal guns variables
var blueBullet;
var blueBulletLaunched = false;
var orangeBullet;
var orangeBulletLaunched = false;
var portalWithUseItem = false;
var bluePortal = null;
var bluePortalCreated = false;
var orangePortal = null;
var orangePortalCreated = false;

var ENTITIES_SUPPORT_DEFAULT = android.os.Build.VERSION.SDK_INT <= 15 ? false : true; // 15 = ICS
var entitiesSupportForPortals = ENTITIES_SUPPORT_DEFAULT;

var overlayImageView;
var showingOverlayID = 0;
const OVERLAY_FULL = 1;
const OVERLAY_BLUE = 2;
const OVERLAY_ORANGE = 3;
const OVERLAY_BLANK = 4;

// portal guns picking variables
var pgIsPickingEnabled = false;
var isPortalGunPicking = false;
var pgPickButtonFalse;
var pgPickButtonTrue;
var pgDropButtonFalse;
var pgDropButtonTrue;
var pgEntity = null;
var pgIsBlock = false;
var pgBlockId;
var pgBlockData;

const PORTAL_GUN_BLUE_ID = 3651;
Item.defineItem(PORTAL_GUN_BLUE_ID, "portalgunblue", 0, "传送枪");
Item.setMaxDamage(PORTAL_GUN_BLUE_ID, PORTAL_GUN_DAMAGE);
Item.addShapedRecipe(PORTAL_GUN_BLUE_ID, 1, 0, [
	"f f",
	" d ",
	"f f"], ["f", 265, 0, "d", 264, 0]);
Item.setVerticalRender(PORTAL_GUN_BLUE_ID);
Item.setCategory(PORTAL_GUN_BLUE_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(PORTAL_GUN_BLUE_ID, 1);

const PORTAL_GUN_GOLD_ID = 3652;
const PORTAL_GUN_GOLD_DAMAGE = 500;
Item.defineItem(PORTAL_GUN_GOLD_ID, "portalgungold", 0, "传送枪金");
Item.setMaxDamage(PORTAL_GUN_GOLD_ID, PORTAL_GUN_GOLD_DAMAGE);
Item.addShapedRecipe(PORTAL_GUN_GOLD_ID, 1, 0, [
	"f f",
	" g ",
	"f f"], ["f", 265, 0, "g", 266, 0]);
Item.setVerticalRender(PORTAL_GUN_GOLD_ID);
Item.setCategory(PORTAL_GUN_GOLD_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(PORTAL_GUN_GOLD_ID, 1);

const PORTAL_GUN_IRON_ID = 3653;
const PORTAL_GUN_IRON_DAMAGE = 250;
Item.defineItem(PORTAL_GUN_IRON_ID, "portalguniron", 0, "传送枪铁");
Item.setMaxDamage(PORTAL_GUN_IRON_ID, PORTAL_GUN_IRON_DAMAGE);
Item.addShapedRecipe(PORTAL_GUN_IRON_ID, 1, 0, [
	"fff",
	"f f",
	"fff"], ["f", 265, 0]);
Item.setVerticalRender(PORTAL_GUN_IRON_ID);
Item.setCategory(PORTAL_GUN_IRON_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(PORTAL_GUN_IRON_ID, 1);

const PORTAL_GUN_LAVA_ID = 3654;
const PORTAL_GUN_LAVA_DAMAGE = 200;
Item.defineItem(PORTAL_GUN_LAVA_ID, "portalgunlava", 0, "传送枪熔岩");
Item.setMaxDamage(PORTAL_GUN_LAVA_ID, PORTAL_GUN_LAVA_DAMAGE);
Item.addShapedRecipe(PORTAL_GUN_LAVA_ID, 1, 0, [
	"f f",
	" a ",
	"f f"], ["f", 265, 0, "a", 259, 0]);
Item.setVerticalRender(PORTAL_GUN_LAVA_ID);
Item.setCategory(PORTAL_GUN_LAVA_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(PORTAL_GUN_LAVA_ID, 1);

const PORTAL_GUN_WOOD_AND_STONE_ID = 3655;
const PORTAL_GUN_WOOD_AND_STONE_DAMAGE = 100;
Item.defineItem(PORTAL_GUN_WOOD_AND_STONE_ID, "portalgunwoodandstone", 0, "传送枪木&石");
Item.setMaxDamage(PORTAL_GUN_WOOD_AND_STONE_ID, PORTAL_GUN_WOOD_AND_STONE_DAMAGE);
Item.addShapedRecipe(PORTAL_GUN_WOOD_AND_STONE_ID, 1, 0, [
	"sws",
	"s s",
	"sws"], ["s", 98, 0, "w", 17, 0]);
Item.setVerticalRender(PORTAL_GUN_WOOD_AND_STONE_ID);
Item.setCategory(PORTAL_GUN_WOOD_AND_STONE_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(PORTAL_GUN_WOOD_AND_STONE_ID, 1);

var isGravityGunPicking = false;
var ggShootButtonFalse;
var ggShootButtonTrue;
var ggDropButtonFalse;
var ggDropButtonTrue;
var ggEntity = null;
var ggIsBlock = false;
var ggBlockId;
var ggBlockData;
var ggShotBlocksToBePlaced = [];
const GRAVITY_GUN_ID = 3656;
const GRAVITY_GUN_MAX_DAMAGE = 400;
Item.defineItem(GRAVITY_GUN_ID, "gravitygun", 0, "重力枪");
Item.setMaxDamage(GRAVITY_GUN_ID, GRAVITY_GUN_MAX_DAMAGE);
Item.addShapedRecipe(GRAVITY_GUN_ID, 1, 0, [
	"frf",
	"r r",
	"frf"], ["f", 265, 0, "r", 331, 0]);
Item.setVerticalRender(GRAVITY_GUN_ID);
Item.setCategory(GRAVITY_GUN_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(GRAVITY_GUN_ID, 1);

const ID_TURRET_OPTIONS = 3657;
Item.defineItem(ID_TURRET_OPTIONS, "turretoptions", 0, "炮塔选项");
Item.setCategory(ID_TURRET_OPTIONS, ItemCategory.TOOL);
Player.addItemCreativeInv(ID_TURRET_OPTIONS, 1);

var turretsDefective = [];
const ID_TURRET_DEFECTIVE = 3666;
Item.defineItem(ID_TURRET_DEFECTIVE, "turretdefective", 0, "炮塔故障");
Item.setCategory(ID_TURRET_DEFECTIVE, ItemCategory.TOOL);
Player.addItemCreativeInv(ID_TURRET_DEFECTIVE, 1);

var turrets = [];
var areTurretsSinging = false;
var turretSoundPlayer;
var turretsSongCountdown = 0;
var turretsSongX;
var turretsSongY;
var turretsSongZ;
const ID_TURRET = 3658;
Item.defineItem(ID_TURRET, "turret", 0, "炮塔");
Item.setCategory(ID_TURRET, ItemCategory.TOOL);
Player.addItemCreativeInv(ID_TURRET, 1);

const LONG_FALL_BOOT_ID = 3659;
Item.defineItem(LONG_FALL_BOOT_ID, "longfallboot", 0, "长落靴");
Item.addShapedRecipe(LONG_FALL_BOOT_ID, 1, 0, [
	"   ",
	"f f",
	"r r"], ["f", 265, 0, "r", 331, 0]);

var isFalling = false;
const LONG_FALL_BOOTS_ID = 3660;
const LONG_FALL_BOOTS_MAX_DAMAGE = 1500;
Item.newArmor(LONG_FALL_BOOTS_ID, "longfallboots", 0, "Long Fall Boots", "armor/longfallboots.png", 1, LONG_FALL_BOOTS_MAX_DAMAGE, ArmorType.boots);
Item.addShapedRecipe(LONG_FALL_BOOTS_ID, 1, 0, [
	"   ",
	"   ",
	"l l"], ["l", LONG_FALL_BOOT_ID, 0,]);

const MAX_LOGARITHMIC_VOLUME_RADIO = 25;
var radioPlayer = new android.media.MediaPlayer();
var isRadioPlaying = false;
var radioCountdown = 0;
var radioX;
var radioY;
var radioZ;
const RADIO_ID = 3661;
Item.defineItem(RADIO_ID, "portalradio", 0, "孔径射电");
Item.addShapedRecipe(RADIO_ID, 1, 0, [
	"   ",
	"iii",
	"iri"], ["i", 265, 0, "r", 331, 0]); // i = iron; r = redstone;
Item.setCategory(RADIO_ID, ItemCategory.MATERIAL);
Player.addItemCreativeInv(RADIO_ID, 1);

const STILL_ALIVE_DISC_ID = 3662;
Item.defineItem(STILL_ALIVE_DISC_ID, "discstillalive", 0, "§4勇敢爱(Mi2)光盘");
Item.setCategory(STILL_ALIVE_DISC_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(STILL_ALIVE_DISC_ID, 1);

const WANT_YOU_GONE_DISC_ID = 3663;
Item.defineItem(WANT_YOU_GONE_DISC_ID, "discwantyougone", 0, "§6我的天空(南征北战)光盘");
Item.setCategory(WANT_YOU_GONE_DISC_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(WANT_YOU_GONE_DISC_ID, 1);

const CARA_MIA_ADDIO_DISC_ID = 3664;
Item.defineItem(CARA_MIA_ADDIO_DISC_ID, "disccaramiaaddio", 0, "§3千本樱(初音未来)光盘");
Item.setCategory(CARA_MIA_ADDIO_DISC_ID, ItemCategory.TOOL);
Player.addItemCreativeInv(CARA_MIA_ADDIO_DISC_ID, 1);

const JUMPER_ITEM_ID = 3665;
Item.defineItem(JUMPER_ITEM_ID, "jumperitem", 0, "空中弹射板");
Item.setCategory(JUMPER_ITEM_ID, ItemCategory.MATERIAL);
Player.addItemCreativeInv(JUMPER_ITEM_ID, 1);


//########################################################################################################################################################
// Blocks
//########################################################################################################################################################

// block functions needed on load
Block.newBlock = function(id, name, textureNames, sourceId, opaque, renderType)
{
	try
	{
		Block.defineBlock(id, name, textureNames, sourceId, opaque, renderType);
	} catch(e)
	{
		// user hasn't installed the texture pack
		if(!textureUiShowed)
			pleaseInstallTextureUI();

		Block.defineBlock(id, name, "enchanting_table_top", sourceId, opaque, renderType);
	}
}
Block.newPortal = function(id, name, textureName, xMin, yMin, zMin, xMax, yMax, zMax)
{
	Block.newBlock(id, name, textureName, 0, false, 0);
	Block.setShape(id, xMin, yMin, zMin, xMax, yMax, zMax);
	Block.setDestroyTime(id, 3);
	Block.setRenderLayer(id, 4); // recently changed from 3 to 4
	Block.setLightLevel(id, 3);
	Block.setLightOpacity(id, 0);
	Block.setExplosionResistance(id, 30);
}

// Type 1
//orange z min down
const ORANGE_Z_MIN_D = 200;
Block.newPortal(ORANGE_Z_MIN_D, "Orange portal z-min-d", "portalorangedown", 0, 0, 1/16, 1, 1, 1/16);

//orange z min up
const ORANGE_Z_MIN_U = 201;
Block.newPortal(ORANGE_Z_MIN_U, "Orange portal z-min-up", "portalorangeup", 0, 0, 1/16, 1, 1, 1/16)


// Type 2
//orange z max down
const ORANGE_Z_MAX_D = 202;
Block.newPortal(ORANGE_Z_MAX_D, "Orange portal z-max-d", "portalorangedown", 0, 0, 15/16, 1, 1, 15/16);

//orange z max up
const ORANGE_Z_MAX_U = 203;
Block.newPortal(ORANGE_Z_MAX_U, "Orange portal z-max-up", "portalorangeup", 0, 0, 15/16, 1, 1, 15/16);


// Type 3
//orange y min down
const ORANGE_Y_MIN_D = 204;
Block.newPortal(ORANGE_Y_MIN_D, "Orange portal y-min-d", "portalorangedown", 0, 1/16, 0, 1, 1/16, 1);

//orange y min up
const ORANGE_Y_MIN_U = 205;
Block.newPortal(ORANGE_Y_MIN_U, "Orange portal y-min-up", "portalorangeup", 0, 1/16, 0, 1, 1/16, 1);


// Type 4
//orange y max down
const ORANGE_Y_MAX_D = 206;
Block.newPortal(ORANGE_Y_MAX_D, "Orange portal y-max-d", "portalorangedown", 0, 15/16, 0, 1, 15/16, 1);

//orange y max up
const ORANGE_Y_MAX_U = 207;
Block.newPortal(ORANGE_Y_MAX_U, "Orange portal y-max-up", "portalorangeup", 0, 15/16, 0, 1, 15/16, 1);


// Type 5
//orange x min down
const ORANGE_X_MIN_D = 208;
Block.newPortal(ORANGE_X_MIN_D, "Orange portal x-min-d", "portalorangedown", 1/16, 0, 0, 1/16, 1, 1);

//orange x min up
const ORANGE_X_MIN_U = 209;
Block.newPortal(ORANGE_X_MIN_U, "Orange portal x-min-up", "portalorangeup", 1/16, 0, 0, 1/16, 1, 1);


// Type 6
//orange x max down
const ORANGE_X_MAX_D = 210;
Block.newPortal(ORANGE_X_MAX_D, "Orange portal x-max-d", "portalorangedown", 15/16, 0, 0, 15/16, 1, 1);

//orange x max up
const ORANGE_X_MAX_U = 211;
Block.newPortal(ORANGE_X_MAX_U, "Orange portal x-max-up", "portalorangeup", 15/16, 0, 0, 15/16, 1, 1);


// Type 1
//blue z min down
const BLUE_Z_MIN_D = 212;
Block.newPortal(BLUE_Z_MIN_D, "Blue portal z-min-d", "portalbluedown", 0, 0, 1/16, 1, 1, 1/16);

//blue z min up
const BLUE_Z_MIN_U = 213;
Block.newPortal(BLUE_Z_MIN_U, "Blue portal z-min-up", "portalblueup", 0, 0, 1/16, 1, 1, 1/16);


// Type 2
//blue z max down
const BLUE_Z_MAX_D = 214;
Block.newPortal(BLUE_Z_MAX_D, "Blue portal z-max-d", "portalbluedown", 0, 0, 15/16, 1, 1, 15/16);

//blue z max up
const BLUE_Z_MAX_U = 215;
Block.newPortal(BLUE_Z_MAX_U, "Blue portal z-max-up", "portalblueup", 0, 0, 15/16, 1, 1, 15/16);


// Type 3
//blue y min down
const BLUE_Y_MIN_D = 216;
Block.newPortal(BLUE_Y_MIN_D, "Blue portal y-min-d", "portalbluedown", 0, 1/16, 0, 1, 1/16, 1);

//blue y min up
const BLUE_Y_MIN_U = 217;
Block.newPortal(BLUE_Y_MIN_U, "Blue portal y-min-up", "portalblueup", 0, 1/16, 0, 1, 1/16, 1);


// Type 4
//blue y max down
const BLUE_Y_MAX_D = 218;
Block.newPortal(BLUE_Y_MAX_D, "Blue portal y-max-d", "portalbluedown", 0, 15/16, 0, 1, 15/16, 1);

//blue y max up
const BLUE_Y_MAX_U = 219;
Block.newPortal(BLUE_Y_MAX_U, "Blue portal y-max-up", "portalblueup", 0, 15/16, 0, 1, 15/16, 1);


// Type 5
//blue x min down
const BLUE_X_MIN_D = 220;
Block.newPortal(BLUE_X_MIN_D, "Blue portal x-min-d", "portalbluedown", 1/16, 0, 0, 1/16, 1, 1);

//blue x min up
const BLUE_X_MIN_U = 221;
Block.newPortal(BLUE_X_MIN_U, "Blue portal x-min-up", "portalblueup", 1/16, 0, 0, 1/16, 1, 1);


// Type 6
//blue x max down
const BLUE_X_MAX_D = 222;
Block.newPortal(BLUE_X_MAX_D, "Blue portal x-max-d", "portalbluedown", 15/16, 0, 0, 15/16, 1, 1);

//blue x max up
const BLUE_X_MAX_U = 223;
Block.newPortal(BLUE_X_MAX_U, "Blue portal x-max-up", "portalblueup", 15/16, 0, 0, 15/16, 1, 1);



// jukebox
const MAX_LOGARITHMIC_VOLUME_JUKEBOX = 65;
var nowPlayingMessage = "";
var currentColor = 0;
var jukeboxes = [];
const JUKEBOX_ID = 84;
Block.defineBlock(JUKEBOX_ID, "§5唱片机", [["jukebox_side", 0], ["jukebox_top", 0], ["jukebox_side", 0], ["jukebox_side", 0], ["jukebox_side", 0], ["jukebox_side", 0]], 17);
Block.setDestroyTime(JUKEBOX_ID, 2);
Block.setExplosionResistance(JUKEBOX_ID, 30);
Item.setCategory(JUKEBOX_ID, ItemCategory.MATERIAL);
Player.addItemCreativeInv(JUKEBOX_ID, 1);

// jumper
const JUMPER_DIRECTION_ID = 224;
Block.newBlock(JUMPER_DIRECTION_ID, "跨接方向", "jumperdirection", 0, false);
Block.setDestroyTime(JUMPER_DIRECTION_ID, 1);
Block.setLightOpacity(JUMPER_DIRECTION_ID, 0.01);
Block.setShape(JUMPER_DIRECTION_ID, 0, 0, 0, 1, 1/16, 1);

const JUMPER_ID = 225;
Block.newBlock(JUMPER_ID, "跳线", "jumper", 0, false);
Block.setDestroyTime(JUMPER_ID, 1);
Block.setLightOpacity(JUMPER_ID, 0.01);
Block.setShape(JUMPER_ID, 0, 0, 0, 1, 1/16, 1);

// radio
const PORTAL_RADIO_A = 226;
Block.newBlock(PORTAL_RADIO_A, "Portal Radio", [["radiotop", 0], ["radiotop", 0], ["radioside", 0], ["radioside", 0], ["radiodisplay", 0], ["radioside", 0]], 0, false, 0);
Block.setDestroyTime(PORTAL_RADIO_A, 1);
Block.setShape(PORTAL_RADIO_A, 5/16, 0, 0, 11/16, 10/16, 1);
Block.setLightOpacity(PORTAL_RADIO_A, 0.01);
Block.setExplosionResistance(PORTAL_RADIO_A, 30);
const PORTAL_RADIO_B = 227;
Block.newBlock(PORTAL_RADIO_B, "Portal Radio", [["radiotop", 0], ["radiotop", 0], ["radiodisplay", 0], ["radioside", 0], ["radioside", 0], ["radioside", 0]], 0, false, 0);
Block.setDestroyTime(PORTAL_RADIO_B, 1);
Block.setShape(PORTAL_RADIO_B, 0, 0, 5/16, 1, 10/16, 11/16);
Block.setLightOpacity(PORTAL_RADIO_B, 0.01);
Block.setExplosionResistance(PORTAL_RADIO_B, 30);
const PORTAL_RADIO_C = 228;
Block.newBlock(PORTAL_RADIO_C, "Portal Radio", [["radiotop", 0], ["radiotop", 0], ["radioside", 0], ["radioside", 0], ["radioside", 0], ["radiodisplay", 0]], 0, false, 0);
Block.setDestroyTime(PORTAL_RADIO_C, 1);
Block.setShape(PORTAL_RADIO_C, 5/16, 0, 0, 11/16, 10/16, 1);
Block.setLightOpacity(PORTAL_RADIO_C, 0.01);
Block.setExplosionResistance(PORTAL_RADIO_C, 30);
const PORTAL_RADIO_D = 229;
Block.newBlock(PORTAL_RADIO_D, "Portal Radio", [["radiotop", 0], ["radiotop", 0], ["radioside", 0], ["radiodisplay", 0], ["radioside", 0], ["radioside", 0]], 0, false, 0);
Block.setDestroyTime(PORTAL_RADIO_D, 1);
Block.setShape(PORTAL_RADIO_D, 0, 0, 5/16, 1, 10/16, 11/16);
Block.setLightOpacity(PORTAL_RADIO_D, 0.01);
Block.setExplosionResistance(PORTAL_RADIO_D, 30);

// blue gel
const REPULSION_GEL_ID = 230;
Block.newBlock(REPULSION_GEL_ID, "排斥凝胶块", [["wool", 3]]);
Block.setDestroyTime(REPULSION_GEL_ID, 1);
Item.setCategory(REPULSION_GEL_ID, ItemCategory.MATERIAL);
Player.addItemCreativeInv(REPULSION_GEL_ID, 1);

// orange gel
const SPEED_MULTIPLIER_MIN = 1.35;
const SPEED_MULTIPLIER_MAX = 1.65;
var speedMultiplier = SPEED_MULTIPLIER_MIN;
const PROPULSION_GEL_ID = 231;
Block.newBlock(PROPULSION_GEL_ID, "推进凝胶块", [["wool", 1]]);
Block.setDestroyTime(PROPULSION_GEL_ID, 1);
Item.setCategory(PROPULSION_GEL_ID, ItemCategory.MATERIAL);
Player.addItemCreativeInv(PROPULSION_GEL_ID, 1);

// cubes
const CUBE_NORMAL_ID = 232;
Block.newBlock(CUBE_NORMAL_ID, "立方体", "cubenormal");
Block.setDestroyTime(CUBE_NORMAL_ID, 1);
Item.setCategory(CUBE_NORMAL_ID, ItemCategory.MATERIAL);
Player.addItemCreativeInv(CUBE_NORMAL_ID, 1);

const CUBE_COMPANION_ID = 233;
Block.newBlock(CUBE_COMPANION_ID, "同伴立方体", "cubecompanion");
Block.setDestroyTime(CUBE_COMPANION_ID, 1);
Item.setCategory(CUBE_COMPANION_ID, ItemCategory.MATERIAL);
Player.addItemCreativeInv(CUBE_COMPANION_ID, 1);


// blacklist variables
var pickBuggedBlocksBlacklist = [7, 26, 52, 54, 59, 61, 62, 63, 64, 68, 71, 83, 90, 96, 104, 105, 106, 111, 115, 141, 142, 207, ORANGE_Z_MIN_D, ORANGE_Z_MIN_U, ORANGE_Z_MAX_D, ORANGE_Z_MAX_U, ORANGE_Y_MIN_D, ORANGE_Y_MIN_U, ORANGE_Y_MAX_D, ORANGE_Y_MAX_U, ORANGE_X_MIN_D, ORANGE_X_MIN_U, ORANGE_X_MAX_D, ORANGE_X_MAX_U, BLUE_Z_MIN_D, BLUE_Z_MIN_U, BLUE_Z_MAX_D, BLUE_Z_MAX_U, BLUE_Y_MIN_D, BLUE_Y_MIN_U, BLUE_Y_MAX_D, BLUE_Y_MAX_U, BLUE_X_MIN_D, BLUE_X_MIN_U, BLUE_X_MAX_D, BLUE_X_MAX_U];
var pickBlocksBlacklist = [REPULSION_GEL_ID, PROPULSION_GEL_ID, JUMPER_ID, JUMPER_DIRECTION_ID];


//########################################################################################################################################################
// Hooks
//########################################################################################################################################################

function selectLevelHook()
{
	// reset custom mobs array
	customMobs = [];

	loadCustomMobs();
}

function newLevel()
{
	isInGame = true;

	// things to do when the world is completely loaded
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			new android.os.Handler().postDelayed(new java.lang.Runnable(
			{
				run: function()
				{
					if(isInGame)
					{
						loadPortalsAndDeleteThem();
					}
				}
			}), 500);
		}
	}));

	loadMapOptions();

	var bSizeTest = ModPE.readData("pref_portal_buttons_size");
	if(bSizeTest != "" && bSizeTest != null && bSizeTest != undefined)
		buttonsSize = parseFloat(bSizeTest);

	var imageSizeTest = ModPE.readData("pref_portal_image_buttons_size");
	if(imageSizeTest != "" && imageSizeTest != null && imageSizeTest != undefined)
		imageSize = parseFloat(imageSizeTest);

	var mButtonsTest = ModPE.readData("pref_portal_y_offset");
	if(mButtonsTest != "" && mButtonsTest != null && mButtonsTest != undefined)
		pixelsOffsetButtons = parseFloat(mButtonsTest);

	var generalVolumeTest = ModPE.readData("pref_portal_general_volume");
	if(generalVolumeTest != "" && generalVolumeTest != null && generalVolumeTest != undefined)
		generalVolume = parseFloat(generalVolumeTest);
	if(generalVolume < 0 || generalVolume > 1)
		generalVolume = 1;

	// load saved boolean settings
	// getSavedBoolean(name, defaultValue, debug);
	minecraftStyleForButtons = getSavedBoolean("pref_portal_buttons_style", false);
	playWelcomeSoundAtStartup = getSavedBoolean("pref_portal_welcome_sound", true);
	entitiesSupportForPortals = getSavedBoolean("pref_portal_entities_support", ENTITIES_SUPPORT_DEFAULT);

	new java.lang.Thread(new java.lang.Runnable()
	{
		run: function()
		{
			updateLatestVersionMod();
			if(latestVersion != CURRENT_VERSION && latestVersion != undefined)
				updateAvailableUI();
			else
			{
				if(latestVersion != undefined) // if == undefined there was an error
				{
					currentActivity.runOnUiThread(new java.lang.Runnable() {
						run: function() {
							android.widget.Toast.makeText(currentActivity, new android.text.Html.fromHtml("<b>Portal Mod</b>: You have the latest version."), 0).show();
						}
					});
				}
			}
		}
	}).start();

	clientMessage("§fP§9O§fRTAL M§cO§fD " + CURRENT_VERSION + " by Desno365.");

	if(playWelcomeSoundAtStartup)
		Sound.playFromFileName("game-entry1.mp3");
}

function leaveGame()
{
	isInGame = false;

	previousCarriedItem = 0;
	previousSlotId = 0;

	// player interactions
	velBeforeX = 0;
	velBeforeY = 0;
	velBeforeZ = 0;
	blockUnderPlayerBefore = 0;

	// entities container
	entities = [];

	// save custom mobs
	saveCustomMobs();

	// settings only for maps
	indestructibleBlocks = false;

	// stop sounds
	try {
		sound1.reset();
	} catch(e) {}
	try {
		sound2.reset();
	} catch(e) {}
	try {
		sound3.reset();
	} catch(e) {}

	// info item
	removeInfoItemUI();

	// Portal Gun
	removePortalGunUI();
	pgIsPickingEnabled = false;
	blueBulletLaunched = false;
	orangeBulletLaunched = false;

	// Gravity Gun
	removeGravityGunUI();
	ggShotBlocksToBePlaced = [];

	// radio
	stopRadioMusic();

	// orange gel
	speedMultiplier = SPEED_MULTIPLIER_MIN;

	// jukebox
	for(var i in jukeboxes)
		jukeboxes[i].player.reset();
	jukeboxes = [];
	nowPlayingMessage = "";
	currentColor = 0;

	// turrets
	turrets = [];
	turretsStopSinging();
	turretsDefective = [];
}

function useItem(x, y, z, itemId, blockId, side, itemDamage)
{
	x = Math.floor(x);
	y = Math.floor(y);
	z = Math.floor(z);
	//clientMessage(Block.getRenderType(blockId)); // TODO fizzler

	//clientMessage("x " + x + " y " + y + " z " + z);

	if(itemId == PORTAL_INFORMATION_ID)
	{
		infoPortalMod();
		preventDefault();
		return;
	}

	// PortalGun Wood & Stone
	if(itemId == PORTAL_GUN_WOOD_AND_STONE_ID)
	{
		var random = Math.floor((Math.random() * 3) + 1);
		Sound.playFromFileName("portals/portal_open" + random + ".mp3");

		var placeX = x, placeY = y, placeZ = z;
		// get correct block
		switch(side)
		{
			case 0: // down
			{
				placeY--;
				break;
			}
			case 1: // up
			{
				placeY++;
				break;
			}
			case 2:
			{
				placeZ--;
				break;
			}
			case 3:
			{
				placeZ++;
				break;
			}
			case 4:
			{
				placeX--;
				break;
			}
			case 5:
			{
				placeX++;
				break;
			}
		}

		if(portalWithUseItem)
		{
			setPortalOrange(placeX, placeY, placeZ);
			portalWithUseItem = false;
		} else
		{
			setPortalBlue(placeX, placeY, placeZ);
			portalWithUseItem = true;
		}
		if(Level.getGameMode() == GameMode.SURVIVAL)
			Player.damageCarriedItem();
	}

	// PortalGun picking
	if(pgIsPickingEnabled && isItemPortalGun(itemId) && !isPortalGunPicking)
	{
		if(canBlockBePicked(blockId))
		{
			pickBlockPortalGun(blockId, Level.getData(x, y, z));
			Level.setTile(Math.floor(x), Math.floor(y), Math.floor(z), 0);

			// prevent radio bug
			if(blockId == PORTAL_RADIO_A || blockId == PORTAL_RADIO_B || blockId == PORTAL_RADIO_C || blockId == PORTAL_RADIO_D)
				stopRadioMusic();

			// prevent jukebox bug
			if(blockId == JUKEBOX_ID)
			{
				var checkBlockJukebox = getJukeboxObjectFromXYZ(x, y, z);
				if(checkBlockJukebox != -1)
					checkBlockJukebox.stopJukebox();
			}
		} else
		{
			Sound.playFromFileName("gravitygun/fail.ogg");
			ModPE.showTipMessage("这个方块不能被选中");
		}
		return;
	}

	// GravityGun
	if(itemId == GRAVITY_GUN_ID && !isGravityGunPicking)
	{
		if(canBlockBePicked(blockId))
		{
			pickBlockGravityGun(blockId, Level.getData(x, y, z));
			Level.setTile(Math.floor(x), Math.floor(y), Math.floor(z), 0);

			// prevent radio bug
			if(blockId == PORTAL_RADIO_A || blockId == PORTAL_RADIO_B || blockId == PORTAL_RADIO_C || blockId == PORTAL_RADIO_D)
				stopRadioMusic();

			// prevent jukebox bug
			if(blockId == JUKEBOX_ID)
			{
				var checkBlockJukebox = getJukeboxObjectFromXYZ(x, y, z);
				if(checkBlockJukebox != -1)
					checkBlockJukebox.stopJukebox();
			}
		} else
		{
			Sound.playFromFileName("gravitygun/fail.ogg");
			ModPE.showTipMessage("This block can't be picked");
		}
		return;
	}

	// jumper
	if(itemId == JUMPER_ITEM_ID)
	{
		if(side == 0 || side == 1)
		{
			var angle = normalizeAngle(Entity.getYaw(Player.getEntity()));

			var y1 = y;
			if(side == 1)
				y1++;
			if(side == 0)
				y1--;
			var x2 = x;
			var z2 = z;

			if((angle >= 0 && angle < 45) || (angle >= 315 && angle <= 360))
			{
				z2++;
			}
			if(angle >= 45 && angle < 135)
			{
				x2--;
			}
			if(angle >= 135 && angle < 225)
			{
				z2--;
			}
			if(angle >= 225 && angle < 315)
			{
				x2++;
			}

			Level.setTile(x, y1, z, JUMPER_ID);
			if(Level.getTile(x2, y1, z2) == 0)
			{
				// also the jumper direction can be placed
				Level.setTile(x2, y1, z2, JUMPER_DIRECTION_ID);
			}

			if(Level.getGameMode() == GameMode.SURVIVAL)
				Player.decreaseByOneCarriedItem();
		}
	}

	// radio
	if(blockId == PORTAL_RADIO_A || blockId == PORTAL_RADIO_B || blockId == PORTAL_RADIO_C || blockId == PORTAL_RADIO_D)
	{
		preventDefault();
		if(isRadioPlaying && Math.floor(radioX) == Math.floor(x) && Math.floor(radioY) == Math.floor(y) && Math.floor(radioZ) == Math.floor(z))
		{
			stopRadioMusic();
		} else
		{
			isRadioPlaying = true;
			radioX = Math.floor(x) + 0.5;
			radioY = Math.floor(y);
			radioZ = Math.floor(z) + 0.5;

			startRadioMusic();
		}
	} else
	{
		if(itemId == RADIO_ID)
		{
			var angle = normalizeAngle(Entity.getYaw(Player.getEntity()));
			if((angle >= 0 && angle < 45) || (angle >= 315 && angle <= 360))
			{
				Level.placeBlockFromItem(x, y, z, side, 227);
			}
			if(angle >= 45 && angle < 135)
			{
				Level.placeBlockFromItem(x, y, z, side, 228);
			}
			if(angle >= 135 && angle < 225)
			{
				Level.placeBlockFromItem(x, y, z, side, 229);
			}
			if(angle >= 225 && angle < 315)
			{
				Level.placeBlockFromItem(x, y, z, side, 226);
			}
		}
	}

	// jukebox
	if(blockId == JUKEBOX_ID)
	{
		preventDefault();

		// is block a playing jukebox?
		var checkBlockJukebox = getJukeboxObjectFromXYZ(x, y, z);
		if(checkBlockJukebox != -1)
		{
			checkBlockJukebox.stopJukebox();
			return;
		}

		//is the player carrying a disc?
		if(itemId == STILL_ALIVE_DISC_ID || itemId == WANT_YOU_GONE_DISC_ID || itemId == CARA_MIA_ADDIO_DISC_ID)
		{
			//jukebox: start playing
			try
			{
				jukeboxes.push(new JukeboxClass(Math.floor(x) + 0.5, Math.floor(y), Math.floor(z) + 0.5, itemId));
				if(Level.getGameMode() == GameMode.SURVIVAL)
					Player.decreaseByOneCarriedItem();
			}
			catch(err)
			{
				ModPE.showTipMessage("Portal Mod: Music files not installed!");
				clientMessage(err);
			}
		}
	}

	// turrets
	if(itemId == ID_TURRET && Level.getTile(x, y + 1, z) == 0 && Level.getTile(x, y + 2, z) == 0)
	{
		ModPE.showTipMessage("Hit the turret with \"Turret Options\" to make it aggressive.");

		spawnTurret(x, y, z);

		// turrets[turrets.length - 1] is the latest spawned turret

		if(turrets[turrets.length - 1].isThereTurretAtDistance(1))
		{
			if(turrets[turrets.length - 1].isThereTurretAtDistance(2))
			{
				if(turrets[turrets.length - 1].isThereTurretAtDistance(3))
				{
					turrets[turrets.length - 1].playSound("portal-music/portal_turret_song.mp3");
					ModPE.showTipMessage("Singing...");
					turretsSongX = Entity.getX(turrets[turrets.length - 1].entity);
					turretsSongY = Entity.getY(turrets[turrets.length - 1].entity);
					turretsSongZ = Entity.getZ(turrets[turrets.length - 1].entity);
					areTurretsSinging = true;
				}
			}
		}

		if(turrets.length >= 20)
			ModPE.showTipMessage("§cWARNING§f: So many turrets can slow down your device");

		if(Level.getGameMode() == GameMode.SURVIVAL)
			Player.decreaseByOneCarriedItem();
	}

	// defective turrets
	if(itemId == ID_TURRET_DEFECTIVE && Level.getTile(x, y + 1, z) == 0 && Level.getTile(x, y + 2, z) == 0)
	{
		ModPE.showTipMessage("Hit the turret with \"Turret Options\" to make it aggressive.");

		spawnTurretDefective(x, y, z);

		// turretsDefective[turretsDefective.length - 1] is the latest spawned turret

		var random = Math.floor((Math.random() * 16) + 1);
		turretsDefective[turretsDefective.length - 1].playSound("portal-sounds/turrets_defective/turret_defective_spawn_" + random + ".wav");

		if(turretsDefective.length >= 20)
			ModPE.showTipMessage("§cWARNING§f: So many turrets can slow down your device");

		if(Level.getGameMode() == GameMode.SURVIVAL)
			Player.decreaseByOneCarriedItem();
	}
}

function destroyBlock(x, y, z)
{
	if(indestructibleBlocks && Level.getGameMode() == GameMode.SURVIVAL)
	{
		ModPE.showTipMessage("You can't break blocks in this world");
		preventDefault();
		return;
	}

	x = Math.floor(x);
	y = Math.floor(y);
	z = Math.floor(z);
	var tile = Level.getTile(x, y, z);

	// radio
	if(isRadioPlaying)
	{
		if(x == Math.floor(radioX) && y == Math.floor(radioY) && z == Math.floor(radioZ))
		{
			stopRadioMusic();
		}
	}

	// radio
	if(tile == PORTAL_RADIO_A || tile == PORTAL_RADIO_B || tile == PORTAL_RADIO_C || tile == PORTAL_RADIO_D)
	{
		preventDefault();
		Level.setTile(x, y, z, 0);
		Level.dropItem(x + 0.5, y + 1, z + 0.5, 0, RADIO_ID, 1, 0);
	}

	// portals
	if(orangePortalCreated)
	{
		if(x == orangePortal.x1 && y == orangePortal.y1 && z == orangePortal.z1)
		{
			preventDefault();
			orangePortalCreated = false;
			updateOverlay();
			Level.setTile(orangePortal.x1, orangePortal.y1, orangePortal.z1, 0);
			Level.setTile(orangePortal.x2, orangePortal.y2, orangePortal.z2, 0);
			savePortalsToDelete();
		}
		if(x == orangePortal.x2 && y == orangePortal.y2 && z == orangePortal.z2)
		{
			preventDefault();
			orangePortalCreated = false;
			updateOverlay();
			Level.setTile(orangePortal.x1, orangePortal.y1, orangePortal.z1, 0);
			Level.setTile(orangePortal.x2, orangePortal.y2, orangePortal.z2, 0);
			savePortalsToDelete();
		}
	}
	if(bluePortalCreated)
	{
		if(x == bluePortal.x1 && y == bluePortal.y1 && z == bluePortal.z1)
		{
			preventDefault();
			bluePortalCreated = false;
			updateOverlay();
			Level.setTile(bluePortal.x1, bluePortal.y1, bluePortal.z1, 0);
			Level.setTile(bluePortal.x2, bluePortal.y2, bluePortal.z2, 0);
			savePortalsToDelete();
		}
		if(x == bluePortal.x2 && y == bluePortal.y2 && z == bluePortal.z2)
		{
			preventDefault();
			bluePortalCreated = false;
			updateOverlay();
			Level.setTile(bluePortal.x1, bluePortal.y1, bluePortal.z1, 0);
			Level.setTile(bluePortal.x2, bluePortal.y2, bluePortal.z2, 0);
			savePortalsToDelete();
		}
	}

	// jumper
	if(tile == JUMPER_ID)
	{
		//
		preventDefault();
		Level.setTile(x, y, z, 0);
		Level.dropItem(x + 0.5, y + 1, z + 0.5, 0, JUMPER_ITEM_ID, 1, 0);
	}
	if(tile == JUMPER_DIRECTION_ID)
	{
		//
		preventDefault();
		Level.setTile(x, y, z, 0);
	}

	// jukebox
	if(tile == JUKEBOX_ID)
	{
		var checkBlockJukebox = getJukeboxObjectFromXYZ(x, y, z);
		if(checkBlockJukebox != -1)
			checkBlockJukebox.stopJukebox();
	}
}

function attackHook(attacker, victim)
{
	if(attacker == Player.getEntity())
	{
		var itemId = Player.getCarriedItem();

		// GravityGun
		if(itemId == GRAVITY_GUN_ID && !isGravityGunPicking)
		{
			// for turrets
			turretsLoop:
			for(var i in turrets)
			{
				if(victim == turrets[i].entity)
				{
					var random = Math.floor((Math.random() * 10) + 1);
					turrets[i].playSound("portal-sounds/turrets/turret_pickup_" + random + ".mp3");

					if(areTurretsSinging)
						turretsStopSinging();
					break turretsLoop;
				}
			}

			// for defective turrets
			turretsDefectiveLoop:
			for(var i in turretsDefective)
			{
				if(victim == turretsDefective[i].entity)
				{
					var random = Math.floor((Math.random() * 4) + 1);
					turretsDefective[i].playSound("portal-sounds/turrets_defective/turret_defective_pickup_" + random + ".wav");
					break turretsDefectiveLoop;
				}
			}

			preventDefault();

			// pick the entity
			pickEntityGravityGun(victim);
			return;
		}

		// PortalGun
		if(isItemPortalGun(itemId) && !isPortalGunPicking && pgIsPickingEnabled)
		{
			// for turrets
			turretsLoop:
			for(var i in turrets)
			{
				if(victim == turrets[i].entity)
				{
					var random = Math.floor((Math.random() * 10) + 1);
					turrets[i].playSound("portal-sounds/turrets/turret_pickup_" + random + ".mp3");

					if(areTurretsSinging)
						turretsStopSinging();
					break turretsLoop;
				}
			}

			// for defective turrets
			turretsDefectiveLoop:
			for(var i in turretsDefective)
			{
				if(victim == turretsDefective[i].entity)
				{
					var random = Math.floor((Math.random() * 4) + 1);
					turretsDefective[i].playSound("portal-sounds/turrets_defective/turret_defective_pickup_" + random + ".wav");
					break turretsDefectiveLoop;
				}
			}

			preventDefault();

			// pick the entity
			pickEntityPortalGun(victim);
			return;
		}

		// turrets options, normal turrets
		for(var i in turrets)
		{
			if(victim == turrets[i].entity)
			{
				if(Player.getCarriedItem() == ID_TURRET_OPTIONS)
				{
					turretOptionsUI(i);
				} else
				{
					if(isItemPortalGun(Player.getCarriedItem()))
						ModPE.showTipMessage("Use \"pick\" to kill a turret");
					else
						if(Player.getCarriedItem() != GRAVITY_GUN_ID)
							ModPE.showTipMessage("Only gravity can kill a turret");
				}
				preventDefault();
				return;
			}
		}

		// turrets options, defective turrets
		for(var i in turretsDefective)
		{
			if(victim == turretsDefective[i].entity)
			{
				if(Player.getCarriedItem() == ID_TURRET_OPTIONS)
				{
					turretDefectiveOptionsUI(i);
				} else
				{
					if(isItemPortalGun(Player.getCarriedItem()))
						ModPE.showTipMessage("Use \"pick\" to kill a turret");
					else
						if(Player.getCarriedItem() != GRAVITY_GUN_ID)
							ModPE.showTipMessage("Only gravity can kill a turret");
				}
				preventDefault();
				return;
			}
		}
	}
}

function deathHook(murderer, victim)
{
	// custom mobs
	var index = findPositionInCustomMobs(victim);
	if(index != -1)
		customMobs.splice(index, 1);

	// GravityGun
	if(victim == ggEntity)
	{
		if(isGravityGunPicking)
		{
			isGravityGunPicking = false;
			ggEntity = null;
			updateEnabledGravityGunButtons();
		}
	}

	// PortalGun
	if(victim == pgEntity)
	{
		if(isPortalGunPicking)
		{
			isPortalGunPicking = false;
			pgEntity = null;
			updateDropButtonPortalGun();
		}
	}

	// turrets
	for(var i in turrets)
	{
		if(victim == turrets[i].entity)
		{
			if(murderer != -1 && murderer != Player.getEntity())
			{
				restoreTurretFromOldTurretObject(Entity.getX(turrets[i].entity), Entity.getY(turrets[i].entity), Entity.getZ(turrets[i].entity), turrets[i]);

				if(Entity.getEntityTypeId(murderer) == EntityType.ZOMBIE || Entity.getEntityTypeId(murderer) == EntityType.ZOMBIE_VILLAGER)
					Entity.remove(murderer);
			} else
			{
				var random = Math.floor((Math.random() * 9) + 1);
				turrets[i].playSound("portal-sounds/turrets/turret_disabled_" + random + ".mp3");

				if(areTurretsSinging)
					turretsStopSinging();
			}

			turrets.splice(i, 1);
		}
	}

	// defective turrets
	for(var i in turretsDefective)
	{
		if(victim == turretsDefective[i].entity)
		{
			if(murderer != -1 && murderer != Player.getEntity())
			{
				restoreTurretDefectiveFromOldTurretObject(Entity.getX(turretsDefective[i].entity), Entity.getY(turretsDefective[i].entity), Entity.getZ(turretsDefective[i].entity), turretsDefective[i]);

				if(Entity.getEntityTypeId(murderer) == EntityType.ZOMBIE || Entity.getEntityTypeId(murderer) == EntityType.ZOMBIE_VILLAGER)
					Entity.remove(murderer);
			} else
			{
				var random = Math.floor((Math.random() * 7) + 1);
				turretsDefective[i].playSound("portal-sounds/turrets_defective/turret_defective_disabled_" + random + ".wav");
			}

			turretsDefective.splice(i, 1);
		}
	}
}

function entityAddedHook(entity)
{
	// custom mobs
	customMobRespawnerCheck(entity);

	// to prevent the death of turrets by zombies
	if(Entity.getEntityTypeId(entity) == EntityType.ZOMBIE_VILLAGER && (turrets.length > 0 || turretsDefective.length > 0))
	{
		Entity.remove(entity);
		return;
	}

	// needed for mobs support for portal and jumper
	var entityId = Entity.getEntityTypeId(entity);
	if(entityId != 0 && entityId != EntityType.ARROW && entityId != EntityType.EGG && entityId != EntityType.EXPERIENCE_ORB && entityId != EntityType.EXPERIENCE_POTION && entityId != EntityType.FIREBALL && entityId != EntityType.FISHING_HOOK && entityId != EntityType.LIGHTNING_BOLT && entityId != EntityType.PAINTING && entityId != EntityType.PAINTING && entityId != EntityType.SMALL_FIREBALL && entityId != EntityType.SNOWBALL && entityId != EntityType.THROWN_POTION)
		entities.push(entity);

	// debug entities size
	if(DEBUG)
	{
		var array = [];
		for(var i in entities)
		{
			if(array[Entity.getEntityTypeId(entities[i])] == null)
				array[Entity.getEntityTypeId(entities[i])] = 0;
			array[Entity.getEntityTypeId(entities[i])]++;
		}
		clientMessage("entities " + array.toString());
	}
}

function entityRemovedHook(entity)
{
	removeThisEntityFromContainer:
	for(var i in entities)
	{
		if(entities[i] == entity)
		{
			entities.splice(i, 1);
			break removeThisEntityFromContainer;
		}
	}

	// GravityGun
	if(entity == ggEntity)
	{
		if(isGravityGunPicking)
		{
			isGravityGunPicking = false;
			ggEntity = null;
			updateEnabledGravityGunButtons();
		}
	}

	// PortalGun
	if(entity == pgEntity)
	{
		if(isPortalGunPicking)
		{
			isPortalGunPicking = false;
			pgEntity = null;
			updateDropButtonPortalGun();
		}
	}
}

function changeCarriedItemHook(currentItem, previousItem) // not really an hook
{
	// remove gravity gun UI
	if(previousItem == GRAVITY_GUN_ID)
	{
		//
		removeGravityGunUI();
	}

	// remove portal gun UI
	if(isItemPortalGun(previousItem) && !isItemPortalGun(currentItem))
	{
		//
		removePortalGunUI();
	}

	// remove gravity gun UI
	if(previousItem == PORTAL_INFORMATION_ID)
	{
		//
		removeInfoItemUI();
	}

	switch(currentItem)
	{
		case GRAVITY_GUN_ID:
		{
			initializeAndShowGravityGunUI();
			break;
		}

		case PORTAL_GUN_BLUE_ID:
		case PORTAL_GUN_GOLD_ID:
		case PORTAL_GUN_IRON_ID:
		case PORTAL_GUN_LAVA_ID:
		case PORTAL_GUN_ORANGE_ID:
		{
			if(!isItemPortalGun(previousItem))
				showPortalGunUI();
			if(!((previousItem == PORTAL_GUN_BLUE_ID && currentItem == PORTAL_GUN_ORANGE_ID) || (previousItem == PORTAL_GUN_ORANGE_ID && currentItem == PORTAL_GUN_BLUE_ID)))
				Sound.playFromFileName("portalgun/portalgun_powerup1.mp3");
			break;
		}

		case PORTAL_GUN_WOOD_AND_STONE_ID:
		{
			ModPE.showTipMessage("点击放置一个传送门");
			break;
		}

		case ID_TURRET_OPTIONS:
		{
			ModPE.showTipMessage("Hit a turret to display options.");
			break;
		}

		case PORTAL_INFORMATION_ID:
		{
			displayInfoItemUI();
			break;
		}
	}
}

function jumpHook() // not really an hook
{
	// repulsion gel block
	if(blockUnderPlayerBefore == REPULSION_GEL_ID)
	{
		makeBounceSound();
	}

	// long fall boots
	if(isFalling)
	{
		// player is spamming the jump button causing bugs
		Entity.setVelY(Player.getEntity(), -3);
	}
}

function modTick()
{
	var blockUnderPlayer = Level.getTile(Math.floor(Player.getX()), Math.floor(Player.getY()) - 2, Math.floor(Player.getZ()))

	var flatBlockUnderPlayer = Level.getTile(Math.floor(Player.getX()), Math.floor(Player.getY()) - 1, Math.floor(Player.getZ()))

	ModTickFunctions.alwaysFullHungerBarOption();

	ModTickFunctions.checkChangedCarriedItem();

	ModTickFunctions.checkJumpHook();

	ModTickFunctions.portals();

	ModTickFunctions.portalGunBullets();

	ModTickFunctions.portalGunPicking(); // portal gun picking entities

	ModTickFunctions.gravityGun(); // gravity gun picking entities

	ModTickFunctions.placeShotBlocks(); // gravity gun picking entities

	ModTickFunctions.gelBlue(blockUnderPlayer);

	ModTickFunctions.gelOrange(blockUnderPlayer);

	ModTickFunctions.jukebox();

	ModTickFunctions.jumper(flatBlockUnderPlayer);

	ModTickFunctions.longFallBoots(blockUnderPlayer);

	ModTickFunctions.radio();

	ModTickFunctions.turretsAI();

	ModTickFunctions.turretsSong();

	// player interactions
	velBeforeX = Entity.getVelX(Player.getEntity());
	velBeforeY = Entity.getVelY(Player.getEntity()); // used also for the blue gel
	velBeforeZ = Entity.getVelZ(Player.getEntity());
	blockUnderPlayerBefore = blockUnderPlayer;
}

var ModTickFunctions = {

	alwaysFullHungerBarOption: function()
	{
		if(alwaysFullHungerBar)
		{
			fullHungerBarTick++;

			if(fullHungerBarTick >= 50)
			{
				if(Level.getGameMode() == GameMode.SURVIVAL)
					Entity.addEffect(Player.getEntity(), MobEffect.saturation, 1, 19, false, false);
				fullHungerBarTick = 0;
			}
		}
	},

	checkChangedCarriedItem: function()
	{
		if(Player.getCarriedItem() != previousCarriedItem)
			changeCarriedItemHook(Player.getCarriedItem(), previousCarriedItem);
		else
		{
			// switching between items with same id but different damage for example
			if(Player.getSelectedSlotId() != previousSlotId)
			{
				changeCarriedItemHook(previousCarriedItem, previousCarriedItem);
			}
		}
		previousCarriedItem = Player.getCarriedItem();
		previousSlotId = Player.getSelectedSlotId();
	},

	checkJumpHook: function()
	{
		if(Entity.getVelY(Player.getEntity()) > VEL_Y_OFFSET && velBeforeY == VEL_Y_OFFSET)
		{
			jumpHook();
		}
	},

	portals: function()
	{
		// player is in portal?
		if(bluePortalCreated && orangePortalCreated)
		{
			if(orangePortal.type == 4)
				entityIsInPortalOrange(Player.getEntity(), Player.getX(), Player.getY(), Player.getZ());
			else
				entityIsInPortalOrange(Player.getEntity(), Player.getX(), Player.getY() - 1, Player.getZ());

			if(bluePortal.type == 4)
				entityIsInPortalBlue(Player.getEntity(), Player.getX(), Player.getY(), Player.getZ());
			else
				entityIsInPortalBlue(Player.getEntity(), Player.getX(), Player.getY() - 1, Player.getZ());

			if(entitiesSupportForPortals)
			{
				for(var i in entities)
				{
					entityIsInPortalOrange(entities[i], Entity.getX(entities[i]), Entity.getY(entities[i]) + 0.1, Entity.getZ(entities[i]));
					entityIsInPortalBlue(entities[i], Entity.getX(entities[i]), Entity.getY(entities[i]) + 0.1, Entity.getZ(entities[i]));
				}
			}
		}
	},

	portalGunBullets: function()
	{
		if(blueBulletLaunched)
		{
			var xArrow = Entity.getX(blueBullet.entity);
			var yArrow = Entity.getY(blueBullet.entity);
			var zArrow = Entity.getZ(blueBullet.entity);
			if(blueBullet.previousX == xArrow && blueBullet.previousY == yArrow && blueBullet.previousZ == zArrow)
			{
				setPortalBlue(Math.floor(xArrow), Math.floor(yArrow), Math.floor(zArrow));

				Entity.remove(blueBullet.entity);
				blueBullet = null;
				blueBulletLaunched = false;
			} else
			{
				if(xArrow == 0 && yArrow == 0 && zArrow == 0)
				{
					// the blueBullet hit an entity
					Sound.playFromFileName("portals/portal_invalid_surface.mp3", blueBullet.previousX, blueBullet.previousY, blueBullet.previousZ);

					Entity.remove(blueBullet.entity);
					blueBullet = null;
					blueBulletLaunched = false;
				} else
				{
					blueBullet.previousX = xArrow;
					blueBullet.previousY = yArrow;
					blueBullet.previousZ = zArrow;
				}
			}
		}

		if(orangeBulletLaunched)
		{
			var xArrow = Entity.getX(orangeBullet.entity);
			var yArrow = Entity.getY(orangeBullet.entity);
			var zArrow = Entity.getZ(orangeBullet.entity);
			if(orangeBullet.previousX == xArrow && orangeBullet.previousY == yArrow && orangeBullet.previousZ == zArrow)
			{
				setPortalOrange(Math.floor(xArrow), Math.floor(yArrow), Math.floor(zArrow));

				Entity.remove(orangeBullet.entity);
				orangeBullet = null;
				orangeBulletLaunched = false;
			} else
			{
				if(xArrow == 0 && yArrow == 0 && zArrow == 0)
				{
					// the orangeBullet hit an entity
					Sound.playFromFileName("portals/portal_invalid_surface.mp3", orangeBullet.previousX, orangeBullet.previousY, orangeBullet.previousZ);

					Entity.remove(orangeBullet.entity);
					orangeBullet = null;
					orangeBulletLaunched = false;
				} else
				{
					orangeBullet.previousX = xArrow;
					orangeBullet.previousY = yArrow;
					orangeBullet.previousZ = zArrow;
				}
			}
		}
	},

	portalGunPicking: function()
	{
		if(isPortalGunPicking)
		{
			if(pgIsBlock)
			{
				var dir = getDirection(Entity.getYaw(Player.getEntity()), Entity.getPitch(Player.getEntity()));
				if(pgEntity != null)
					Entity.remove(pgEntity);
				pgEntity = Level.dropItem(Player.getX() + (dir.x * 2), Player.getY() + (dir.y * 2.5), Player.getZ() + (dir.z * 2), 0, pgBlockId, 1, pgBlockData);
			} else
			{
				var dir = getDirection(Entity.getYaw(Player.getEntity()), Entity.getPitch(Player.getEntity()));
				if(Player.getX() + (dir.x * 3) - Entity.getX(pgEntity) > 0.5 ||  Player.getX() + (dir.x * 3) - Entity.getX(pgEntity) < -0.5 || Player.getY () + (dir.y * 3) - Entity.getY (pgEntity) > 0.5 ||  Player.getY () + (dir.y * 3) - Entity.getY (pgEntity) < -0.5 || Player.getZ () + (dir.z * 3) - Entity.getZ (pgEntity) > 0.5 ||  Player.getZ () + (dir.z * 3) - Entity.getZ (pgEntity) < -0.5)
				{
					Entity.setVelX(pgEntity, (Player.getX() + (dir.x * 3) - Entity.getX(pgEntity)) / 5)
					Entity.setVelY(pgEntity, (Player.getY() + (dir.y * 3) - Entity.getY(pgEntity)) / 5);
					Entity.setVelZ(pgEntity, (Player.getZ() + (dir.z * 3) - Entity.getZ(pgEntity)) / 5);
				} else
				{
					Entity.setVelX(pgEntity, 0);
					Entity.setVelY(pgEntity, 0);
					Entity.setVelZ(pgEntity, 0);
				}
			}
		}
	},

	gravityGun: function()
	{
		if(isGravityGunPicking)
		{
			if(ggIsBlock)
			{
				var dir = getDirection(Entity.getYaw(Player.getEntity()), Entity.getPitch(Player.getEntity()));
				if(ggEntity != null)
					Entity.remove(ggEntity);
				ggEntity = Level.dropItem(Player.getX() + (dir.x * 2), Player.getY() + (dir.y * 2.5), Player.getZ() + (dir.z * 2), 0, ggBlockId, 1, ggBlockData);
			} else
			{
				var dir = getDirection(Entity.getYaw(Player.getEntity()), Entity.getPitch(Player.getEntity()));
				if(Player.getX() + (dir.x * 3) - Entity.getX(ggEntity) > 0.5 ||  Player.getX() + (dir.x * 3) - Entity.getX(ggEntity) < -0.5 || Player.getY () + (dir.y * 3) - Entity.getY (ggEntity) > 0.5 ||  Player.getY () + (dir.y * 3) - Entity.getY (ggEntity) < -0.5 || Player.getZ () + (dir.z * 3) - Entity.getZ (ggEntity) > 0.5 ||  Player.getZ () + (dir.z * 3) - Entity.getZ (ggEntity) < -0.5)
				{
					Entity.setVelX(ggEntity, (Player.getX() + (dir.x * 3) - Entity.getX(ggEntity)) / 5)
					Entity.setVelY(ggEntity, (Player.getY() + (dir.y * 3) - Entity.getY(ggEntity)) / 5);
					Entity.setVelZ(ggEntity, (Player.getZ() + (dir.z * 3) - Entity.getZ(ggEntity)) / 5);
				} else
				{
					Entity.setVelX(ggEntity, 0);
					Entity.setVelY(ggEntity, 0);
					Entity.setVelZ(ggEntity, 0);
				}
			}
		}
	},

	placeShotBlocks: function()
	{
		for(var i in ggShotBlocksToBePlaced)
		{
			var entity = ggShotBlocksToBePlaced[i].entity;
			if(Entity.getX(entity) == ggShotBlocksToBePlaced[i].previousX && Entity.getY(entity) == ggShotBlocksToBePlaced[i].previousY && Entity.getZ(entity) == ggShotBlocksToBePlaced[i].previousZ)
			{
				if(!(Entity.getX(entity) == 0 && Entity.getY(entity) == 0 && Entity.getZ(entity) == 0)) // is entity already removed
				{
					Level.setTile(Math.floor(Entity.getX(entity)), Math.floor(Entity.getY(entity)), Math.floor(Entity.getZ(entity)), ggShotBlocksToBePlaced[i].id, ggShotBlocksToBePlaced[i].data);
					Entity.remove(entity);
				}
				ggShotBlocksToBePlaced.splice(i, 1);
			} else
			{
				ggShotBlocksToBePlaced[i].previousX = Entity.getX(entity);
				ggShotBlocksToBePlaced[i].previousY = Entity.getY(entity);
				ggShotBlocksToBePlaced[i].previousZ = Entity.getZ(entity);
			}
		}
	},

	gelBlue: function(blockUnderPlayer)
	{
		if(blockUnderPlayer == REPULSION_GEL_ID)
		{
			if(velBeforeY < -0.666) // Satan confirmed!
			{
				Entity.setVelY(Player.getEntity(), -velBeforeY);
				makeBounceSound();
			}

			Entity.addEffect(Player.getEntity(), MobEffect.jump, 2, 5, false, false);
		}
	},

	gelOrange: function(blockUnderPlayer)
	{
		if(blockUnderPlayer == PROPULSION_GEL_ID)
		{
			currentActivity.runOnUiThread(new java.lang.Runnable(
			{
				run: function()
				{
					new android.os.Handler().postDelayed(new java.lang.Runnable(
					{
						run: function()
						{
							if(isInGame)
							{
								Entity.setVelX(Player.getEntity(), Entity.getVelX(Player.getEntity()) * speedMultiplier);
								Entity.setVelZ(Player.getEntity(), Entity.getVelZ(Player.getEntity()) * speedMultiplier);
									
								if(speedMultiplier < SPEED_MULTIPLIER_MAX)
									speedMultiplier = speedMultiplier + 0.025;
							}
						}
					}), ((speedMultiplier - SPEED_MULTIPLIER_MIN) * 1000));
				}
			}));
		}else
		{
			if(speedMultiplier != SPEED_MULTIPLIER_MIN)
				speedMultiplier = SPEED_MULTIPLIER_MIN;
		}
	},

	jukebox: function()
	{
		for(var i in jukeboxes)
		{
			jukeboxes[i].countdown++;
			if(jukeboxes[i].countdown >= 10)
			{
				jukeboxes[i].countdown = 0;
				var distancePJ = Math.sqrt( (Math.pow(jukeboxes[i].x - Player.getX(), 2)) + (Math.pow(jukeboxes[i].y - Player.getY(), 2)) + (Math.pow(jukeboxes[i].z - Player.getZ(), 2) ));
				if(distancePJ > MAX_LOGARITHMIC_VOLUME_JUKEBOX)
				{
					jukeboxes[i].player.setVolume(0.0, 0.0);
				}
				else
				{
					var volume = 1 - (Math.log(distancePJ) / Math.log(MAX_LOGARITHMIC_VOLUME_JUKEBOX));
					jukeboxes[i].player.setVolume(volume * generalVolume, volume * generalVolume);
				}
			}
		}
	},

	jumper: function(flatBlockUnderPlayer)
	{
		if(flatBlockUnderPlayer == JUMPER_ID)
		{
			var angle = getAngleOfNearBlockId(Math.floor(Player.getX()), Math.floor(Player.getY()) - 1, Math.floor(Player.getZ()), JUMPER_DIRECTION_ID);
			if(angle == null)
				angle = getYaw();

			makeJumperJump(angle);
		}
		if(flatBlockUnderPlayer == JUMPER_DIRECTION_ID && blockUnderPlayerBefore != JUMPER_ID)
		{
			var angle = getAngleOfNearBlockId(Math.floor(Player.getX()), Math.floor(Player.getY()) - 1, Math.floor(Player.getZ()), JUMPER_ID);
			if(angle == null)
				angle = getYaw();
			else
				angle += 180;

			makeJumperJump(angle);
		}
	},

	longFallBoots: function(blockUnderPlayer)
	{
		if(Player.getArmorSlot(3) == LONG_FALL_BOOTS_ID)
		{
			// player will hit the ground soon
			if(isFalling && blockUnderPlayer > 0)
			{
				if(Entity.getVelY(Player.getEntity()) == VEL_Y_OFFSET)
				{
					// STOP Long Fall Boots
					isFalling = false;

					if(Level.getGameMode() == GameMode.SURVIVAL)
					{
						// Entity.removeEffect(entity, id) doesn't remove particles of the effect https://github.com/zhuowei/MCPELauncher/issues/241
						//Entity.removeEffect(Player.getEntity(), MobEffect.jump);
						Entity.removeAllEffects(Player.getEntity());
					}

					makeLongFallBootsSound();
				}
			}

			// player is falling
			if(Entity.getVelY(Player.getEntity()) <= -0.5)
			{
				// START Long Fall Boots
				isFalling = true;

				if(Level.getGameMode() == GameMode.SURVIVAL)
					Entity.addEffect(Player.getEntity(), MobEffect.jump, 999999, 254, false, false);
			}
		} else
		{
			if(isFalling)
			{
				// STOP Long Fall Boots
				isFalling = false;

				if(Level.getGameMode() == GameMode.SURVIVAL)
				{
					// Entity.removeEffect(entity, id) doesn't remove particles of the effect https://github.com/zhuowei/MCPELauncher/issues/241
					//Entity.removeEffect(Player.getEntity(), MobEffect.jump);
					Entity.removeAllEffects(Player.getEntity());
				}
			}
		}
	},

	radio: function()
	{
		if(isRadioPlaying)
		{
			radioCountdown++;
			if(radioCountdown >= 10)
			{
				radioCountdown = 0;
				var distancePR = Math.sqrt( (Math.pow(radioX - Player.getX(), 2)) + (Math.pow(radioY - Player.getY(), 2)) + (Math.pow(radioZ - Player.getZ(), 2) ));
				if(distancePR > MAX_LOGARITHMIC_VOLUME_RADIO)
				{
					stopRadioMusic();
				}else
				{
					var radioVolume = 1 - (Math.log(distancePR) / Math.log(MAX_LOGARITHMIC_VOLUME_RADIO));
					radioPlayer.setVolume(radioVolume * generalVolume, radioVolume * generalVolume);
				}
			}
		}
	},

	turretsAI: function()
	{
		// normal turrets
		for(var i in turrets)
		{
			turrets[i].artificialIntelligence();
		}

		// defective turrets
		for(var i in turretsDefective)
		{
			turretsDefective[i].artificialIntelligence();
		}
	},

	turretsSong: function()
	{
		if(areTurretsSinging)
		{
			turretsSongCountdown++;
			if(turretsSongCountdown >= 10)
			{
				turretsSongCountdown = 0;
				var distance = Math.sqrt( (Math.pow(turretsSongX - Player.getX(), 2)) + (Math.pow(turretsSongY - Player.getY(), 2)) + (Math.pow(turretsSongZ - Player.getZ(), 2) ));
				if(distance > MAX_LOGARITHMIC_VOLUME_JUKEBOX)
				{
					turretSoundPlayer.setVolume(0.0, 0.0);
				}else
				{
					var volume = 1 - (Math.log(distance) / Math.log(MAX_LOGARITHMIC_VOLUME_JUKEBOX));
					turretSoundPlayer.setVolume(volume * generalVolume, volume * generalVolume);
				}
			}
		}
	}
};


//########################################################################################################################################################
// Added functions (No GUI and No render)
//########################################################################################################################################################

//########## PORTAL GUN GENERAL functions ##########
function isItemPortalGun(itemId)
{
	//
	return (itemId == PORTAL_GUN_BLUE_ID || itemId == PORTAL_GUN_GOLD_ID || itemId == PORTAL_GUN_IRON_ID || itemId == PORTAL_GUN_LAVA_ID || itemId == PORTAL_GUN_ORANGE_ID);
}

function showPortalGunUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layoutLeft = new android.widget.LinearLayout(currentActivity);
				layoutLeft.setOrientation(android.widget.LinearLayout.VERTICAL);

				var blueImage = scaleImageToSize(bluePortalScaled, bluePortalScaled.getWidth() * 0.166 * imageSize, bluePortalScaled.getHeight() * 0.166 * imageSize, true);
				var blueImageView = new android.widget.ImageView(currentActivity);
				blueImageView.setImageBitmap(blueImage);
				blueImageView.setOnClickListener(new android.view.View.OnClickListener(
				{
					onClick: function()
					{
						if(blueBulletLaunched)
						{
							blueBulletLaunched = false;
							Entity.remove(blueBullet.entity);
							blueBullet = null;
						}
						shootBluePortal();
					}
				}));
				layoutLeft.addView(blueImageView);
				setMarginsLinearLayout(blueImageView, 0, 0, 0, MARGIN_HORIZONTAL_SMALL);

				// PICK BUTTONS
				if(minecraftStyleForButtons)
				{
					pgPickButtonFalse = MinecraftButton(buttonsSize);
					pgPickButtonFalse.setText("发射蓝色传送门");
				} else
				{
					pgPickButtonFalse = defaultColoredMinecraftButton("发射蓝色传送门", "#FF929292");
				}
				pgPickButtonFalse.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						if(minecraftStyleForButtons)
							ModPE.showTipMessage("Pick enabled");
						setPickEnabledPortalGun(true);
					}
				});
				pgPickButtonFalse.setSoundEffectsEnabled(false);

				if(minecraftStyleForButtons)
				{
					pgPickButtonTrue = MinecraftButton(buttonsSize);
					pgPickButtonTrue.setText("发射蓝色传送门");
				} else
				{
					pgPickButtonTrue = defaultColoredMinecraftButton("发射蓝色传送门", "#FFFFFFFF");
				}
				pgPickButtonTrue.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						if(minecraftStyleForButtons)
							ModPE.showTipMessage("Pick disabled");
						setPickEnabledPortalGun(false);
					}
				});
				pgPickButtonTrue.setSoundEffectsEnabled(false);

				layoutLeft.addView(pgPickButtonFalse);
				layoutLeft.addView(pgPickButtonTrue);
				pgPickButtonTrue.setVisibility(android.view.View.GONE);

				popupPortalGunPick = new android.widget.PopupWindow(layoutLeft, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
				popupPortalGunPick.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
				popupPortalGunPick.showAtLocation(currentActivity.getWindow().getDecorView(), android.view.Gravity.LEFT | android.view.Gravity.CENTER, 0, pixelsOffsetButtons);

				setPickEnabledPortalGun(pgIsPickingEnabled); // restore previous status of pick
				// PICK BUTTONS - END



				// OVERLAY IMAGE
				displayOverlay();
				// OVERLAY IMAGE - END



				var layoutRight = new android.widget.LinearLayout(currentActivity);
				layoutRight.setOrientation(android.widget.LinearLayout.VERTICAL);

				var orangeImage = scaleImageToSize(orangePortalScaled, orangePortalScaled.getWidth() * 0.166 * imageSize, orangePortalScaled.getHeight() * 0.166 * imageSize, true);
				var orangeImageView = new android.widget.ImageView(currentActivity);
				orangeImageView.setImageBitmap(orangeImage);
				orangeImageView.setOnClickListener(new android.view.View.OnClickListener(
				{
					onClick: function()
					{
						if(orangeBulletLaunched)
						{
							orangeBulletLaunched = false;
							Entity.remove(orangeBullet.entity);
							orangeBullet = null;
						}
						shootOrangePortal();
					}
				}));
				layoutRight.addView(orangeImageView);
				setMarginsLinearLayout(orangeImageView, 0, 0, 0, MARGIN_HORIZONTAL_SMALL);

				// DROP BUTTONS
				if(minecraftStyleForButtons)
				{
					pgDropButtonFalse = MinecraftButton(buttonsSize, false);
					pgDropButtonFalse.setText("发射黄色传送门");
				} else
				{
					pgDropButtonFalse = defaultColoredMinecraftButton("发射黄色传送门", "#FF929292");
				}
				pgDropButtonFalse.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						Sound.playFromFileName("gravitygun/fail.ogg");
						ModPE.showTipMessage("你没有选择任何实体。");
					}
				});
				pgDropButtonFalse.setSoundEffectsEnabled(false);

				if(minecraftStyleForButtons)
				{
					pgDropButtonTrue = MinecraftButton(buttonsSize, false);
					pgDropButtonTrue.setText("发射黄色传送门");
				} else
				{
					pgDropButtonTrue = defaultColoredMinecraftButton("发射黄色传送门", "#FFFFFFFF");
				}
				pgDropButtonTrue.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						dropPortalGun();
					}
				});
				pgDropButtonTrue.setSoundEffectsEnabled(false);

				layoutRight.addView(pgDropButtonFalse);
				layoutRight.addView(pgDropButtonTrue);
				pgDropButtonTrue.setVisibility(android.view.View.GONE);

				popupPortalGunDrop = new android.widget.PopupWindow(layoutRight, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
				popupPortalGunDrop.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
				popupPortalGunDrop.showAtLocation(currentActivity.getWindow().getDecorView(), android.view.Gravity.RIGHT | android.view.Gravity.CENTER, 0, pixelsOffsetButtons);
				// DROP BUTTONS - END
			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function shootBluePortal()
{
	Sound.playFromFileName("portalgun/portalgun_shoot_red1.mp3");

	var gunShootDir = getDirection(getYaw(), getPitch());
	var bullet = Level.spawnMob(Player.getX() + (gunShootDir.x * 2), Player.getY() + (gunShootDir.y * 2.5), Player.getZ() + (gunShootDir.z * 2), 80);
	var speed = getPortalGunBulletSpeed(Player.getCarriedItem());
	Entity.setVelX(bullet, gunShootDir.x * speed);
	Entity.setVelY(bullet, gunShootDir.y * speed);
	Entity.setVelZ(bullet, gunShootDir.z * speed);
	if(Player.getCarriedItem() == PORTAL_GUN_LAVA_ID)
		Entity.setFireTicks(bullet, 100);
	//Entity.setRenderType(bullet, 18);
	
	if(Level.getGameMode() == GameMode.SURVIVAL)
		Player.damageCarriedItem();

	changeCarriedPortalGunColorToBlue(); // change the carried item if necessary

	blueBullet = new EntityClass(bullet);
	blueBulletLaunched = true;
}

function shootOrangePortal()
{
	Sound.playFromFileName("portalgun/portalgun_shoot_blue1.mp3");

	var gunShootDir = getDirection(getYaw(), getPitch());
	var bullet = Level.spawnMob(Player.getX() + (gunShootDir.x * 2), Player.getY() + (gunShootDir.y * 2.5), Player.getZ() + (gunShootDir.z * 2), 80);
	var speed = getPortalGunBulletSpeed(Player.getCarriedItem());
	Entity.setVelX(bullet, gunShootDir.x * speed);
	Entity.setVelY(bullet, gunShootDir.y * speed);
	Entity.setVelZ(bullet, gunShootDir.z * speed);
	if(Player.getCarriedItem() == PORTAL_GUN_LAVA_ID)
		Entity.setFireTicks(bullet, 100);
	//Entity.setRenderType(bullet, 18);
	
	if(Level.getGameMode() == GameMode.SURVIVAL)
		Player.damageCarriedItem();

	changeCarriedPortalGunColorToOrange(); // change the carried item if necessary

	orangeBullet = new EntityClass(bullet);
	orangeBulletLaunched = true;
}

function getPortalGunBulletSpeed(portalGun)
{
	if(portalGun == PORTAL_GUN_BLUE_ID || portalGun == PORTAL_GUN_ORANGE_ID)
		return 3;
	if(portalGun == PORTAL_GUN_GOLD_ID)
		return 1.8;
	if(portalGun == PORTAL_GUN_IRON_ID)
		return 1.2;
	if(portalGun == PORTAL_GUN_LAVA_ID)
		return 1.2;
}

function changeCarriedPortalGunColorToBlue()
{
	if(Player.getCarriedItem() == PORTAL_GUN_ORANGE_ID)
	{
		Entity.setCarriedItem(Player.getEntity(), PORTAL_GUN_BLUE_ID,  Player.getCarriedItemCount(), Player.getCarriedItemData());
	}
}

function changeCarriedPortalGunColorToOrange()
{
	if(Player.getCarriedItem() == PORTAL_GUN_BLUE_ID)
	{
		Entity.setCarriedItem(Player.getEntity(), PORTAL_GUN_ORANGE_ID,  Player.getCarriedItemCount(), Player.getCarriedItemData());
	}
}

function removePortalGunUI()
{
	isPortalGunPicking = false;
	pgEntity = null;
	showingOverlayID = 0;
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				popupPortalGunPick.dismiss();
				popupPortalGunDrop.dismiss();
				popupOverlay.dismiss();
			} catch(err) { /* Portal Gun not in hand */ }
		}
	}));
}
//########## PORTAL GUN GENERAL functions - END ##########


//########## PORTAL GUN OVERLAY functions ##########
function displayOverlay()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			/*var correctOverlayImage = getOverlayFromID(getCurrentOverlayID());
			var overlayImage = scaleImageToSize(correctOverlayImage, correctOverlayImage.getWidth() * 0.5, correctOverlayImage.getHeight() * 0.5, true);*/
			overlayImageView = new android.widget.ImageView(currentActivity);
			showingOverlayID = 0;
			updateOverlay();
			//overlayImageView.setImageBitmap(overlayImage);

			popupOverlay = new android.widget.PopupWindow(overlayImageView, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
			popupOverlay.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
			popupOverlay.setOutsideTouchable(false);
			popupOverlay.setFocusable(false);
			popupOverlay.setTouchable(false);
			popupOverlay.showAtLocation(currentActivity.getWindow().getDecorView(), android.view.Gravity.CENTER | android.view.Gravity.CENTER, 0, 0);
		}
	}));
}

function updateOverlay()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				var overlayID = getCurrentOverlayID();
				if(showingOverlayID != overlayID)
				{
					var correctOverlayImage = getOverlayFromID(overlayID);
					var overlayImage = scaleImageToSize(correctOverlayImage, correctOverlayImage.getWidth() * 0.5, correctOverlayImage.getHeight() * 0.5, true);
					overlayImageView.setImageBitmap(overlayImage);

					showingOverlayID = overlayID;
				}
			} catch (e) { }
		}
	}));
}

function getCurrentOverlayID()
{
	if(bluePortalCreated && orangePortalCreated)
	{
		return OVERLAY_FULL;
	} else
	{
		if(bluePortalCreated)
			return OVERLAY_BLUE;
		if(orangePortalCreated)
			return OVERLAY_ORANGE;

		return OVERLAY_BLANK;
	}
}

function getOverlayFromID(id)
{
	switch(id)
	{
		case OVERLAY_FULL:
		{
			return overlayFullScaled;
		}
		case OVERLAY_BLUE:
		{
			return overlayBlueScaled;
		}
		case OVERLAY_ORANGE:
		{
			return overlayOrangeScaled;
		}
		case OVERLAY_BLANK:
		{
			return overlayBlankScaled;
		}
	}
}
//########## PORTAL GUN OVERLAY functions - END ##########


//########## PORTAL GUN PICK & DROP functions ##########
function setPickEnabledPortalGun(enable)
{
	if(enable)
	{
		pgIsPickingEnabled = true;
		pgPickButtonFalse.setVisibility(android.view.View.GONE);
		pgPickButtonTrue.setVisibility(android.view.View.VISIBLE);
	} else
	{
		pgIsPickingEnabled = false;
		pgPickButtonFalse.setVisibility(android.view.View.VISIBLE);
		pgPickButtonTrue.setVisibility(android.view.View.GONE);
	}
}

function pickBlockPortalGun(id, data)
{
	if(!isPortalGunPicking)
	{
		pgIsBlock = true;
		pgBlockId = id;
		pgBlockData = data;

		pickWithPortalGun();
	}
}

function pickEntityPortalGun(entity)
{
	if(!isPortalGunPicking)
	{
		pgIsBlock = false;
		pgEntity = entity;
		
		pickWithPortalGun();
	}
}

function pickWithPortalGun()
{
	if(!isPortalGunPicking)
	{		
		isPortalGunPicking = true;
		updateDropButtonPortalGun();
		if(Level.getGameMode() == GameMode.SURVIVAL)
			Player.damageCarriedItem();
		Sound.playFromFileName("gravitygun/pickup.ogg");
	}
}

function updateDropButtonPortalGun()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			if(isPortalGunPicking)
			{
				pgDropButtonFalse.setVisibility(android.view.View.GONE);
				pgDropButtonTrue.setVisibility(android.view.View.VISIBLE);
			} else
			{
				pgDropButtonFalse.setVisibility(android.view.View.VISIBLE);
				pgDropButtonTrue.setVisibility(android.view.View.GONE);
			}
		}
	}));
}

function dropPortalGun()
{
	if(pgIsBlock)
	{
		var dir = getDirection(Entity.getYaw(Player.getEntity()), Entity.getPitch(Player.getEntity()));
		var x = Player.getX() + (dir.x * 2);
		var y = Player.getY() + (dir.y * 2.5);
		var z = Player.getZ() + (dir.z * 2);
		if(Level.getTile(Math.floor(x), Math.floor(y), Math.floor(z)) == 0)
		{
			isPortalGunPicking = false;
			Sound.playFromFileName("gravitygun/drop.ogg");
			updateDropButtonPortalGun();

			Level.setTileNotInAir(x, y, z, pgBlockId, pgBlockData);
			Entity.remove(pgEntity);
			pgEntity = null;
		} else
		{
			Sound.playFromFileName("gravitygun/fail.ogg");
			ModPE.showTipMessage("There is another block in this position.");
		}
	} else
	{
		isPortalGunPicking = false;
		Sound.playFromFileName("gravitygun/drop.ogg");
		updateDropButtonPortalGun();
		pgEntity = null;
	}
}
//########## PORTAL GUN PICK & DROP functions - END ##########


//########## PORTAL functions ##########
// WARNING: the following code is crap, I wrote it when I was 16 but now I'm too lazy to rewrite it. Sorry!
function entityIsInPortalOrange(entity, x, y, z)
{
	if(Math.floor(x) == orangePortal.x1 && Math.floor(y) == orangePortal.y1 && Math.floor(z) == orangePortal.z1 || Math.floor(x) == orangePortal.x2 && Math.floor(y) == orangePortal.y2 && Math.floor(z) == orangePortal.z2)
	{
		var random = Math.floor((Math.random() * 2) + 1);
		Sound.playFromFileName("portals/portal_exit" + random + ".mp3", x, y, z);

		if(orangePortal.type == 2)
		{
			if(bluePortal.type == 2)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 - 1);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelZ(entity, -Entity.getVelZ(entity));
			}
			if(bluePortal.type == 1)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 1);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));
			}
			if(bluePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelY(entity, 0.6);
				Entity.setVelZ(entity, -0.4);	
			}
			if(bluePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 - 0.05, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, 0);
				Entity.setVelY(entity, -0.15);
				Entity.setVelZ(entity, 0);
			}
			if(bluePortal.type == 5)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelZ(entity, -Entity.getVelX(entity));
			}
			if(bluePortal.type == 6)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 - 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelZ(entity));
				Entity.setVelZ(entity, Entity.getVelX(entity));
			}
		}else

		if(orangePortal.type == 1)
		{
			if(bluePortal.type == 2)
			{	
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 - 1);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));
			}
			if(bluePortal.type == 1)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 1);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelZ(entity, -Entity.getVelZ(entity));
			}
			if(bluePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelY(entity, 0.6);
				Entity.setVelZ(entity, -0.4);	
			}
			if(bluePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 - 0.05, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, 0);
				Entity.setVelY(entity, -0.15);
				Entity.setVelZ(entity, 0);	
			}
			if(bluePortal.type == 5)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelZ(entity));
				Entity.setVelZ(entity, Entity.getVelX(entity));
			}
			if(bluePortal.type == 6)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 - 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelZ(entity, -Entity.getVelX(entity));
			}
		}else

		if(orangePortal.type == 3)
		{
			if(bluePortal.type == 2)
			{
				Entity.setRot(entity, 180, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 - 1);
				if(entity == Player.getEntity())
					Entity.setVelZ(entity, velBeforeY);
				else
					Entity.setVelZ(entity, -0.2);
				Entity.setVelY(entity, 0);
			}
			if(bluePortal.type == 1)
			{
				Entity.setRot(entity, 360, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 1);
				if(entity == Player.getEntity())
					Entity.setVelZ(entity, -velBeforeY);
				else
					Entity.setVelZ(entity, 0.2);
				Entity.setVelY(entity, 0);
			}
			if(bluePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				if(entity == Player.getEntity())
					Entity.setVelY(entity, -velBeforeY);
				else
					Entity.setVelY(entity, 0.5);
			}
			if(bluePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 - 0.05, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				if(entity == Player.getEntity())
					Entity.setVelY(entity, Entity.getVelY(velBeforeY) - 0.15);
				else
					Entity.setVelY(entity, 0);
				Entity.setVelZ(entity, Entity.getVelZ(entity));	
			}
			if(bluePortal.type == 5)
			{
				Entity.setRot(entity, 270, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				if(entity == Player.getEntity())
					Entity.setVelX(entity, -velBeforeY);
				else
					Entity.setVelX(entity, 0.2);
				Entity.setVelY(entity, 0);
			}
			if(bluePortal.type == 6)
			{
				Entity.setRot(entity, 450, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 - 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				if(entity == Player.getEntity())
					Entity.setVelX(entity, velBeforeY);
				else
					Entity.setVelX(entity, -0.2);
				Entity.setVelY(entity, 0);
			}
		}else

		if(orangePortal.type == 4)
		{
			if(bluePortal.type == 2)
			{
				Entity.setRot(entity, 180, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 - 1);
				Entity.setVelZ(entity, -0.2);
			}
			if(bluePortal.type == 1)
			{
				Entity.setRot(entity, 360, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 1);
				Entity.setVelZ(entity, 0.2);
			}
			if(bluePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelY(entity, 0.5);
				Entity.setVelZ(entity, Entity.getVelZ(entity));	
			}
			if(bluePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 - 0.05, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelY(entity, Entity.getVelY(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));	
			}
			if(bluePortal.type == 5)
			{
				Entity.setRot(entity, 270, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, 0.2);
			}
			if(bluePortal.type == 6)
			{
				Entity.setRot(entity, 450, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 - 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, -0.2);
			}
		}else

		if(orangePortal.type == 5)
		{
			if(bluePortal.type == 2)
			{	
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 - 1);
				Entity.setVelX(entity, -Entity.getVelZ(entity));
				Entity.setVelZ(entity, Entity.getVelX(entity));
			}
			if(bluePortal.type == 1)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 1);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelZ(entity, -Entity.getVelX(entity));
			}
			if(bluePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelY(entity, 0.6);
				Entity.setVelZ(entity, -0.4);	
			}
			if(bluePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 - 0.05, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, 0);
				Entity.setVelY(entity, -0.15);
				Entity.setVelZ(entity, 0);	
			}
			if(bluePortal.type == 5)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelZ(entity, -Entity.getVelZ(entity));
			}
			if(bluePortal.type == 6)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 - 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));
			}
		}else

		if(orangePortal.type == 6)
		{
			if(bluePortal.type == 2)
			{	
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 - 1);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelZ(entity, -Entity.getVelX(entity));
			}
			if(bluePortal.type == 1)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 1);
				Entity.setVelX(entity, -Entity.getVelZ(entity));
				Entity.setVelZ(entity, Entity.getVelX(entity));
			}
			if(bluePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelY(entity, 0.6);
				Entity.setVelZ(entity, -0.4);	
			}
			if(bluePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 0.5, bluePortal.y1 - 0.05, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, 0);
				Entity.setVelY(entity, -0.15);
				Entity.setVelZ(entity, 0);
			}
			if(bluePortal.type == 5)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 + 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));
			}
			if(bluePortal.type == 6)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, bluePortal.x1 - 1, bluePortal.y1 + 2, bluePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelZ(entity, -Entity.getVelZ(entity));
			}
		}
	}
}

function entityIsInPortalBlue(entity, x, y, z)
{
	if(Math.floor(x) == bluePortal.x1 && Math.floor(y) == bluePortal.y1 && Math.floor(z) == bluePortal.z1 || Math.floor(x) == bluePortal.x2 && Math.floor(y) == bluePortal.y2 && Math.floor(z) == bluePortal.z2)
	{
		var random = Math.floor((Math.random() * 2) + 1);
		Sound.playFromFileName("portals/portal_exit" + random + ".mp3", x, y, z);

		if(bluePortal.type == 2)
		{
			if(orangePortal.type == 2)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 - 1);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelZ(entity, -Entity.getVelZ(entity));
			}
			if(orangePortal.type == 1)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 1);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));
			}
			if(orangePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelY(entity, 0.6);
				Entity.setVelZ(entity, -0.4);	
			}
			if(orangePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 - 0.05, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, 0);
				Entity.setVelY(entity, -0.15);
				Entity.setVelZ(entity, 0);
			}
			if(orangePortal.type == 5)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelZ(entity, -Entity.getVelX(entity));
			}
			if(orangePortal.type == 6)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 - 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelZ(entity));
				Entity.setVelZ(entity, Entity.getVelX(entity));
			}
		}else

		if(bluePortal.type == 1)
		{
			if(orangePortal.type == 2)
			{	
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 - 1);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));
			}
			if(orangePortal.type == 1)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 1);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelZ(entity, -Entity.getVelZ(entity));
			}
			if(orangePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelY(entity, 0.6);
				Entity.setVelZ(entity, -0.4);	
			}
			if(orangePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 - 0.05, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, 0);
				Entity.setVelY(entity, -0.15);
				Entity.setVelZ(entity, 0);	
			}
			if(orangePortal.type == 5)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelZ(entity));
				Entity.setVelZ(entity, Entity.getVelX(entity));
			}
			if(orangePortal.type == 6)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 - 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelZ(entity, -Entity.getVelX(entity));
			}
		}else

		if(bluePortal.type == 3)
		{
			if(orangePortal.type == 2)
			{
				Entity.setRot(entity, 180, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 - 1);
				if(entity == Player.getEntity())
					Entity.setVelZ(entity, velBeforeY);
				else
					Entity.setVelZ(entity, -0.2);
				Entity.setVelY(entity, 0);
			}
			if(orangePortal.type == 1)
			{
				Entity.setRot(entity, 360, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 1);
				if(entity == Player.getEntity())
					Entity.setVelZ(entity, -velBeforeY);
				else
					Entity.setVelZ(entity, 0.2);
				Entity.setVelY(entity, 0);
			}
			if(orangePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				if(entity == Player.getEntity())
					Entity.setVelY(entity, -velBeforeY);
				else
					Entity.setVelY(entity, 0.5);
			}
			if(orangePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 - 0.05, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				if(entity == Player.getEntity())
					Entity.setVelY(entity, Entity.getVelY(velBeforeY) - 0.15);
				else
					Entity.setVelY(entity, 0);
				Entity.setVelZ(entity, Entity.getVelZ(entity));	
			}
			if(orangePortal.type == 5)
			{
				Entity.setRot(entity, 270, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				if(entity == Player.getEntity())
					Entity.setVelX(entity, -velBeforeY);
				else
					Entity.setVelX(entity, 0.2);
				Entity.setVelY(entity, 0);
			}
			if(orangePortal.type == 6)
			{
				Entity.setRot(entity, 450, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 - 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				if(entity == Player.getEntity())
					Entity.setVelX(entity, velBeforeY);
				else
					Entity.setVelX(entity, -0.2);
				Entity.setVelY(entity, 0);
			}
		}else

		if(bluePortal.type == 4)
		{
			if(orangePortal.type == 2)
			{
				Entity.setRot(entity, 180, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 - 1);
				Entity.setVelZ(entity, -0.2);
			}
			if(orangePortal.type == 1)
			{
				Entity.setRot(entity, 360, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 1);
				Entity.setVelZ(entity, 0.2);
			}
			if(orangePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelY(entity, 0.5);
				Entity.setVelZ(entity, Entity.getVelZ(entity));	
			}
			if(orangePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 - 0.05, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelY(entity, Entity.getVelY(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));	
			}
			if(orangePortal.type == 5)
			{
				Entity.setRot(entity, 270, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, 0.2);
			}
			if(orangePortal.type == 6)
			{
				Entity.setRot(entity, 450, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 - 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, -0.2);
			}
		}else

		if(bluePortal.type == 5)
		{
			if(orangePortal.type == 2)
			{	
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 - 1);
				Entity.setVelX(entity, -Entity.getVelZ(entity));
				Entity.setVelZ(entity, Entity.getVelX(entity));
			}
			if(orangePortal.type == 1)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 1);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelZ(entity, -Entity.getVelX(entity));
			}
			if(orangePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelY(entity, 0.6);
				Entity.setVelZ(entity, -0.4);	
			}
			if(orangePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 - 0.05, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, 0);
				Entity.setVelY(entity, -0.15);
				Entity.setVelZ(entity, 0);	
			}
			if(orangePortal.type == 5)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelZ(entity, -Entity.getVelZ(entity));
			}
			if(orangePortal.type == 6)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 - 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));
			}
		}else

		if(bluePortal.type == 6)
		{
			if(orangePortal.type == 2)
			{	
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 - 1);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelZ(entity, -Entity.getVelX(entity));
			}
			if(orangePortal.type == 1)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 90, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 1);
				Entity.setVelX(entity, -Entity.getVelZ(entity));
				Entity.setVelZ(entity, Entity.getVelX(entity));
			}
			if(orangePortal.type == 3)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelZ(entity));
				Entity.setVelY(entity, 0.6);
				Entity.setVelZ(entity, -0.4);	
			}
			if(orangePortal.type == 4)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 270, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 0.5, orangePortal.y1 - 0.05, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, 0);
				Entity.setVelY(entity, -0.15);
				Entity.setVelZ(entity, 0);
			}
			if(orangePortal.type == 5)
			{
				Entity.setRot(entity, Entity.getYaw(entity), Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 + 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, Entity.getVelX(entity));
				Entity.setVelZ(entity, Entity.getVelZ(entity));
			}
			if(orangePortal.type == 6)
			{
				Entity.setRot(entity, Entity.getYaw(entity) + 180, Entity.getPitch(entity));
				Entity.setPosition(entity, orangePortal.x1 - 1, orangePortal.y1 + 2, orangePortal.z1 + 0.5);
				Entity.setVelX(entity, -Entity.getVelX(entity));
				Entity.setVelZ(entity, -Entity.getVelZ(entity));
			}
		}
	}
}

function setPortalOrange(x, y ,z)
{
	var pX = Player.getX();
	var pY = Player.getY();
	var pZ = Player.getZ();

	if(Level.getTile(x, y ,z) != 0)
	{
		Sound.playFromFileName("portals/portal_invalid_surface.mp3", x, y, z);
	}else
	{
		//ARROW
		if(Level.getTile(x + 1, y, z) == 0 && Level.getTile(x - 1, y, z) == 0 && Level.getTile(x, y, z + 1) == 0 && Level.getTile(x, y, z - 1) == 0)
		{
			if(Level.getTile(x, y - 1, z) != 0)
			{
				Level.setTile(x, y, z, ORANGE_Y_MIN_U);
				Level.setTile(x, y, z + 1, ORANGE_Y_MIN_D);
				savePortalAndDeleteOrange(x, y, z, x, y, z+1, 3);
				return;
			}else
			if(Level.getTile(x, y + 1, z) != 0)
			{
				Level.setTile(x, y, z, ORANGE_Y_MAX_U);
				Level.setTile(x, y, z + 1, ORANGE_Y_MAX_D);
				savePortalAndDeleteOrange(x, y, z, x, y, z+1, 4);
				return;
			}
		}else
		{
			if(Level.getTile(x + 1, y, z) != 0 && Level.getTile(x - 1, y, z) == 0 && Level.getTile(x, y, z + 1) == 0 && Level.getTile(x, y, z - 1) == 0)
			{

				if(Level.getTile(x, y + 1, z) == 0)
				{
					Level.setTile(x, y, z, ORANGE_X_MAX_D, 0);
					Level.setTile(x, y + 1, z, ORANGE_X_MAX_U, 0);
					savePortalAndDeleteOrange(x, y, z, x, y+1, z, 6);
					return;
				}else
				{
					if(Level.getTile(x, y - 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_X_MAX_U, 0);
						Level.setTile(x, y - 1, z, ORANGE_X_MAX_D, 0);
						savePortalAndDeleteOrange(x, y, z, x, y-1, z, 6);
						return;
					}
				}
			}
			if(Level.getTile(x, y, z + 1) != 0 && Level.getTile(x, y, z - 1) == 0 && Level.getTile(x + 1, y, z) == 0 && Level.getTile(x - 1, y, z) == 0)
			{

				if(Level.getTile(x, y + 1, z) == 0)
				{
					Level.setTile(x, y, z, ORANGE_Z_MAX_D, 0);
					Level.setTile(x, y + 1, z, ORANGE_Z_MAX_U, 0);
					savePortalAndDeleteOrange(x, y, z, x, y+1, z, 2);
					return;
				}else
				{
					if(Level.getTile(x, y - 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_Z_MAX_U, 0);
						Level.setTile(x, y - 1, z, ORANGE_Z_MAX_D, 0);
						savePortalAndDeleteOrange(x, y, z, x, y-1, z, 2);
						return;
					}
				}
			}
			if(Level.getTile(x - 1, y, z) != 0 && Level.getTile(x + 1, y, z) == 0 && Level.getTile(x, y, z + 1) == 0 && Level.getTile(x, y, z - 1) == 0)
			{

				if(Level.getTile(x, y + 1, z) == 0)
				{
					Level.setTile(x, y, z, ORANGE_X_MIN_D, 0);
					Level.setTile(x, y + 1, z, ORANGE_X_MIN_U, 0);
					savePortalAndDeleteOrange(x, y, z, x, y+1, z, 5);
					return;
				}else
				{
					if(Level.getTile(x, y - 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_X_MIN_U, 0);
						Level.setTile(x, y - 1, z, ORANGE_X_MIN_D, 0);
						savePortalAndDeleteOrange(x, y, z, x, y-1, z, 5);
						return;
					}
				}
			}
			if(Level.getTile(x, y, z - 1) != 0 && Level.getTile(x, y, z + 1) == 0 && Level.getTile(x + 1, y, z) == 0 && Level.getTile(x - 1, y, z) == 0)
			{

				if(Level.getTile(x, y + 1, z) == 0)
				{
					Level.setTile(x, y, z, ORANGE_Z_MIN_D, 0);
					Level.setTile(x, y + 1, z, ORANGE_Z_MIN_U, 0);
					savePortalAndDeleteOrange(x, y, z, x, y+1, z, 1);
					return;
				}else
				{
					if(Level.getTile(x, y - 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_Z_MIN_U, 0);
						Level.setTile(x, y - 1, z, ORANGE_Z_MIN_D, 0);
						savePortalAndDeleteOrange(x, y, z, x, y-1, z, 1);
						return;
					}
				}
			}
			if(pX < x && pZ < z)
			{
				if(Math.abs(pX - x) > Math.abs(pZ - z))
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_X_MAX_D, 0);
						Level.setTile(x, y + 1, z, ORANGE_X_MAX_U, 0);
						savePortalAndDeleteOrange(x, y, z, x, y+1, z, 6);
					return;
					} else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, ORANGE_X_MAX_U, 0);
							Level.setTile(x, y - 1, z, ORANGE_X_MAX_D, 0);
							savePortalAndDeleteOrange(x, y, z, x, y-1, z, 6);
							return;
						}
					}
				}else
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_Z_MAX_D, 0);
						Level.setTile(x, y + 1, z, ORANGE_Z_MAX_U, 0);
						savePortalAndDeleteOrange(x, y, z, x, y+1, z, 2);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, ORANGE_Z_MAX_U, 0);
							Level.setTile(x, y - 1, z, ORANGE_Z_MAX_D, 0);
							savePortalAndDeleteOrange(x, y, z, x, y-1, z, 2);
							return;
						}
					}
				}
			}
			if(pX < x && pZ >= z)
			{
				if(Math.abs(pX - x) > Math.abs(pZ - z))
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_X_MAX_D, 0);
						Level.setTile(x, y + 1, z, ORANGE_X_MAX_U, 0);
						savePortalAndDeleteOrange(x, y, z, x, y+1, z, 6);
					return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, ORANGE_X_MAX_U, 0);
							Level.setTile(x, y - 1, z, ORANGE_X_MAX_D, 0);
							savePortalAndDeleteOrange(x, y, z, x, y-1, z, 6);
							return;
						}
					}
				}else
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_Z_MIN_D, 0);
						Level.setTile(x, y + 1, z, ORANGE_Z_MIN_U, 0);
						savePortalAndDeleteOrange(x, y, z, x, y+1, z, 1);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, ORANGE_Z_MIN_U, 0);
							Level.setTile(x, y - 1, z, ORANGE_Z_MIN_D, 0);
							savePortalAndDeleteOrange(x, y, z, x, y-1, z, 1);
							return;
						}
					}
				}
			}
			if(pX >= x && pZ >= z)
			{
				if(Math.abs(pX - x) > Math.abs(pZ - z))
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_X_MIN_D, 0);
						Level.setTile(x, y + 1, z, ORANGE_X_MIN_U, 0);
						savePortalAndDeleteOrange(x, y, z, x, y+1, z, 5);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, ORANGE_X_MIN_U, 0);
							Level.setTile(x, y - 1, z, ORANGE_X_MIN_D, 0);
							savePortalAndDeleteOrange(x, y, z, x, y-1, z, 5);
							return;
						}
					}
				}else
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_Z_MIN_D, 0);
						Level.setTile(x, y + 1, z, ORANGE_Z_MIN_U, 0);
						savePortalAndDeleteOrange(x, y, z, x, y+1, z, 1);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, ORANGE_Z_MIN_U, 0);
							Level.setTile(x, y - 1, z, ORANGE_Z_MIN_D, 0);
							savePortalAndDeleteOrange(x, y, z, x, y-1, z, 1);
							return;
						}
					}
				}
			}
			if(pX >= x && pZ < z)
			{
				if(Math.abs(pX - x) > Math.abs(pZ - z))
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_X_MIN_D, 0);
						Level.setTile(x, y + 1, z, ORANGE_X_MIN_U, 0);
						savePortalAndDeleteOrange(x, y, z, x, y+1, z, 5);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, ORANGE_X_MIN_U, 0);
							Level.setTile(x, y - 1, z, ORANGE_X_MIN_D, 0);
							savePortalAndDeleteOrange(x, y, z, x, y-1, z, 5);
							return;
						}
					}
				}else
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, ORANGE_Z_MAX_D, 0);
						Level.setTile(x, y + 1, z, ORANGE_Z_MAX_U, 0);
						savePortalAndDeleteOrange(x, y, z, x, y+1, z, 2);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, ORANGE_Z_MAX_U, 0);
							Level.setTile(x, y - 1, z, ORANGE_Z_MAX_D, 0);
							savePortalAndDeleteOrange(x, y, z, x, y-1, z, 2);
							return;
						}
					}
				}
			}
		}
	}
}

function setPortalBlue(x, y ,z)
{
	var pX = Player.getX();
	var pY = Player.getY();
	var pZ = Player.getZ();

	if(Level.getTile(x, y ,z) != 0)
	{
		Sound.playFromFileName("portals/portal_invalid_surface.mp3", x, y, z);
	}else
	{
		//ARROW
		if(Level.getTile(x + 1, y, z) == 0 && Level.getTile(x - 1, y, z) == 0 && Level.getTile(x, y, z + 1) == 0 && Level.getTile(x, y, z - 1) == 0)
		{
			if(Level.getTile(x, y - 1, z) != 0)
			{
				Level.setTile(x, y, z, BLUE_Y_MIN_U);
				Level.setTile(x, y, z + 1, BLUE_Y_MIN_D);
				savePortalAndDeleteBlue(x, y, z, x, y, z+1, 3);
			return;
			}else
			if(Level.getTile(x, y + 1, z) != 0)
			{
				Level.setTile(x, y, z, BLUE_Y_MAX_U);
				Level.setTile(x, y, z + 1, BLUE_Y_MAX_D);
				savePortalAndDeleteBlue(x, y, z, x, y, z+1, 4);
				return;
			}
		}else
		{
			if(Level.getTile(x + 1, y, z) != 0 && Level.getTile(x - 1, y, z) == 0 && Level.getTile(x, y, z + 1) == 0 && Level.getTile(x, y, z - 1) == 0)
			{

				if(Level.getTile(x, y + 1, z) == 0)
				{
					Level.setTile(x, y, z, BLUE_X_MAX_D, 0);
					Level.setTile(x, y + 1, z, BLUE_X_MAX_U, 0);
					savePortalAndDeleteBlue(x, y, z, x, y+1, z, 6);
					return;
				}else
				{
					if(Level.getTile(x, y - 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_X_MAX_U, 0);
						Level.setTile(x, y - 1, z, BLUE_X_MAX_D, 0);
						savePortalAndDeleteBlue(x, y, z, x, y-1, z, 6);
						return;
					}
				}
			}
			if(Level.getTile(x, y, z + 1) != 0 && Level.getTile(x, y, z - 1) == 0 && Level.getTile(x + 1, y, z) == 0 && Level.getTile(x - 1, y, z) == 0)
			{

				if(Level.getTile(x, y + 1, z) == 0)
				{
					Level.setTile(x, y, z, BLUE_Z_MAX_D, 0);
					Level.setTile(x, y + 1, z, BLUE_Z_MAX_U, 0);
					savePortalAndDeleteBlue(x, y, z, x, y+1, z, 2);
					return;
				}else
				{
					if(Level.getTile(x, y - 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_Z_MAX_U, 0);
						Level.setTile(x, y - 1, z, BLUE_Z_MAX_D, 0);
						savePortalAndDeleteBlue(x, y, z, x, y-1, z, 2);
						return;
					}
				}
			}
			if(Level.getTile(x - 1, y, z) != 0 && Level.getTile(x + 1, y, z) == 0 && Level.getTile(x, y, z + 1) == 0 && Level.getTile(x, y, z - 1) == 0)
			{

				if(Level.getTile(x, y + 1, z) == 0)
				{
					Level.setTile(x, y, z, BLUE_X_MIN_D, 0);
					Level.setTile(x, y + 1, z, BLUE_X_MIN_U, 0);
					savePortalAndDeleteBlue(x, y, z, x, y+1, z, 5);
					return;
				}else
				{
					if(Level.getTile(x, y - 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_X_MIN_U, 0);
						Level.setTile(x, y - 1, z, BLUE_X_MIN_D, 0);
						savePortalAndDeleteBlue(x, y, z, x, y-1, z, 5);
						return;
					}
				}
			}
			if(Level.getTile(x, y, z - 1) != 0 && Level.getTile(x, y, z + 1) == 0 && Level.getTile(x + 1, y, z) == 0 && Level.getTile(x - 1, y, z) == 0)
			{

				if(Level.getTile(x, y + 1, z) == 0)
				{
					Level.setTile(x, y, z, BLUE_Z_MIN_D, 0);
					Level.setTile(x, y + 1, z, BLUE_Z_MIN_U, 0);
					savePortalAndDeleteBlue(x, y, z, x, y+1, z, 1);
					return;
				}else
				{
					if(Level.getTile(x, y - 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_Z_MIN_U, 0);
						Level.setTile(x, y - 1, z, BLUE_Z_MIN_D, 0);
						savePortalAndDeleteBlue(x, y, z, x, y-1, z, 1);
						return;
					}
				}
			}
			if(pX < x && pZ < z)
			{
				if(Math.abs(pX - x) > Math.abs(pZ - z))
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_X_MAX_D, 0);
						Level.setTile(x, y + 1, z, BLUE_X_MAX_U, 0);
						savePortalAndDeleteBlue(x, y, z, x, y+1, z, 6);
					return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, BLUE_X_MAX_U, 0);
							Level.setTile(x, y - 1, z, BLUE_X_MAX_D, 0);
							savePortalAndDeleteBlue(x, y, z, x, y-1, z, 6);
							return;
						}
					}
				}else
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_Z_MAX_D, 0);
						Level.setTile(x, y + 1, z, BLUE_Z_MAX_U, 0);
						savePortalAndDeleteBlue(x, y, z, x, y+1, z, 2);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, BLUE_Z_MAX_U, 0);
							Level.setTile(x, y - 1, z, BLUE_Z_MAX_D, 0);
							savePortalAndDeleteBlue(x, y, z, x, y-1, z, 2);
							return;
						}
					}
				}
			}
			if(pX < x && pZ >= z)
			{
				if(Math.abs(pX - x) > Math.abs(pZ - z))
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_X_MAX_D, 0);
						Level.setTile(x, y + 1, z, BLUE_X_MAX_U, 0);
						savePortalAndDeleteBlue(x, y, z, x, y+1, z, 6);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, BLUE_X_MAX_U, 0);
							Level.setTile(x, y - 1, z, BLUE_X_MAX_D, 0);
							savePortalAndDeleteBlue(x, y, z, x, y-1, z, 6);
							return;
						}
					}
				}else
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_Z_MIN_D, 0);
						Level.setTile(x, y + 1, z, BLUE_Z_MIN_U, 0);
						savePortalAndDeleteBlue(x, y, z, x, y+1, z, 1);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, BLUE_Z_MIN_U, 0);
							Level.setTile(x, y - 1, z, BLUE_Z_MIN_D, 0);
							savePortalAndDeleteBlue(x, y, z, x, y-1, z, 1);
							return;
						}
					}
				}
			}
			if(pX >= x && pZ >= z)
			{
				if(Math.abs(pX - x) > Math.abs(pZ - z))
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_X_MIN_D, 0);
						Level.setTile(x, y + 1, z, BLUE_X_MIN_U, 0);
						savePortalAndDeleteBlue(x, y, z, x, y+1, z, 5);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, BLUE_X_MIN_U, 0);
							Level.setTile(x, y - 1, z, BLUE_X_MIN_D, 0);
							savePortalAndDeleteBlue(x, y, z, x, y-1, z, 5);
							return;
						}
					}
				}else
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_Z_MIN_D, 0);
						Level.setTile(x, y + 1, z, BLUE_Z_MIN_U, 0);
						savePortalAndDeleteBlue(x, y, z, x, y+1, z, 1);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, BLUE_Z_MIN_U, 0);
							Level.setTile(x, y - 1, z, BLUE_Z_MIN_D, 0);
							savePortalAndDeleteBlue(x, y, z, x, y-1, z, 1);
							return;
						}
					}
				}
			}
			if(pX >= x && pZ < z)
			{
				if(Math.abs(pX - x) > Math.abs(pZ - z))
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_X_MIN_D, 0);
						Level.setTile(x, y + 1, z, BLUE_X_MIN_U, 0);
						savePortalAndDeleteBlue(x, y, z, x, y+1, z, 5);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, BLUE_X_MIN_U, 0);
							Level.setTile(x, y - 1, z, BLUE_X_MIN_D, 0);
							savePortalAndDeleteBlue(x, y, z, x, y-1, z, 5);
							return;
						}
					}
				}else
				{

					if(Level.getTile(x, y + 1, z) == 0)
					{
						Level.setTile(x, y, z, BLUE_Z_MAX_D, 0);
						Level.setTile(x, y + 1, z, BLUE_Z_MAX_U, 0);
						savePortalAndDeleteBlue(x, y, z, x, y+1, z, 2);
						return;
					}else
					{
						if(Level.getTile(x, y - 1, z) == 0)
						{
							Level.setTile(x, y, z, BLUE_Z_MAX_U, 0);
							Level.setTile(x, y - 1, z, BLUE_Z_MAX_D, 0);
							savePortalAndDeleteBlue(x, y, z, x, y-1, z, 2);
							return;
						}
					}
				}
			}
		}
	}
}
// END CRAP

function savePortalAndDeleteOrange(x1, y1, z1, x2, y2, z2, type)
{
	deleteOrangePortal();
	orangePortal = new PortalClass(Math.floor(x1), Math.floor(y1), Math.floor(z1), Math.floor(x2), Math.floor(y2), Math.floor(z2), type);
	orangePortalCreated = true;
	updateOverlay();
	savePortalsToDelete();
}

function savePortalAndDeleteBlue(x1, y1, z1, x2, y2, z2, type)
{
	deleteBluePortal();
	bluePortal = new PortalClass(Math.floor(x1), Math.floor(y1), Math.floor(z1), Math.floor(x2), Math.floor(y2), Math.floor(z2), type);
	bluePortalCreated = true;
	updateOverlay();
	savePortalsToDelete();
}

function deleteBluePortal()
{
	if(bluePortal != null)
	{
		Level.setTile(bluePortal.x1, bluePortal.y1, bluePortal.z1, 0);
		Level.setTile(bluePortal.x2, bluePortal.y2, bluePortal.z2, 0);
	}
	bluePortalCreated = false;
}

function deleteOrangePortal()
{
	if(orangePortal != null)
	{
		Level.setTile(orangePortal.x1, orangePortal.y1, orangePortal.z1, 0);
		Level.setTile(orangePortal.x2, orangePortal.y2, orangePortal.z2, 0);
	}
	orangePortalCreated = false;
}

function loadPortalsAndDeleteThem()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				var loadFile = java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod/portals.dat");
				if(loadFile.exists())
				{
					// load streams
					var streamInput = new java.io.FileInputStream(loadFile);
					var streamReader = new java.io.InputStreamReader(streamInput);

					var properties = new java.util.Properties();
					properties.load(streamReader);

					orangePortalCreated = stringToBoolean(properties.getProperty("orange", "0"));
					if(orangePortalCreated)
					{
						var x1 = parseInt(properties.getProperty("orange_x_1"));
						var y1 = parseInt(properties.getProperty("orange_y_1"));
						var z1 = parseInt(properties.getProperty("orange_z_1"));
						var x2 = parseInt(properties.getProperty("orange_x_2"));
						var y2 = parseInt(properties.getProperty("orange_y_2"));
						var z2 = parseInt(properties.getProperty("orange_z_2"));
						orangePortal = new PortalClass(x1, y1, z1, x2, y2, z2, null);
						deleteOrangePortal();
					}

					bluePortalCreated = stringToBoolean(properties.getProperty("blue", "0"));
					if(bluePortalCreated)
					{
						var x1 = parseInt(properties.getProperty("blue_x_1"));
						var y1 = parseInt(properties.getProperty("blue_y_1"));
						var z1 = parseInt(properties.getProperty("blue_z_1"));
						var x2 = parseInt(properties.getProperty("blue_x_2"));
						var y2 = parseInt(properties.getProperty("blue_y_2"));
						var z2 = parseInt(properties.getProperty("blue_z_2"));
						bluePortal = new PortalClass(x1, y1, z1, x2, y2, z2, null);
						deleteBluePortal();
					}

					// close streams
					streamReader.close();
					streamInput.close();
				}
			}catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	}));
}

function savePortalsToDelete()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				// create folders
				var saveFolder = new java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod");
				saveFolder.mkdirs();

				// create file
				var saveFile = new java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod/portals.dat");
				if(saveFile.exists())
					saveFile.delete();
				saveFile.createNewFile();

				// load streams
				var streamOutput = new java.io.FileOutputStream(saveFile);
				var streamWriter = new java.io.OutputStreamWriter(streamOutput);
				
				var properties = new java.util.Properties();

				properties.setProperty("orange", String(orangePortalCreated));
				if(orangePortalCreated)
				{
					properties.setProperty("orange_x_1", orangePortal.x1);
					properties.setProperty("orange_y_1", orangePortal.y1);
					properties.setProperty("orange_z_1", orangePortal.z1);
					properties.setProperty("orange_x_2", orangePortal.x2);
					properties.setProperty("orange_y_2", orangePortal.y2);
					properties.setProperty("orange_z_2", orangePortal.z2);
				}

				properties.setProperty("blue", String(bluePortalCreated));
				if(bluePortalCreated)
				{
					properties.setProperty("blue_x_1", bluePortal.x1);
					properties.setProperty("blue_y_1", bluePortal.y1);
					properties.setProperty("blue_z_1", bluePortal.z1);
					properties.setProperty("blue_x_2", bluePortal.x2);
					properties.setProperty("blue_y_2", bluePortal.y2);
					properties.setProperty("blue_z_2", bluePortal.z2);
				}

				properties.store(streamWriter, "Portal 2 Mod by Desno365");
				streamWriter.close();
				streamOutput.close();
			}catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	}));
}
//########## PORTAL functions - END ##########


//########## PORTAL GUN & GRAVITY GUN functions ##########
function canBlockBePicked(blockId)
{
	//
	return (pickBlocksBlacklist.indexOf(blockId) == -1 && pickBuggedBlocksBlacklist.indexOf(blockId) == -1);
}
//########## PORTAL GUN & GRAVITY GUN functions - END ##########


//########## GRAVITY GUN functions ##########
function initializeAndShowGravityGunUI()
{
	Sound.playFromFileName("gravitygun/equip.ogg");

	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				// SHOOT BUTTONS
				var layoutShoot = new android.widget.LinearLayout(currentActivity);
				layoutShoot.setOrientation(android.widget.LinearLayout.VERTICAL);

				if(minecraftStyleForButtons)
				{
					ggShootButtonFalse = MinecraftButton(buttonsSize, false);
					ggShootButtonFalse.setText("发射方块或实体");
				} else
				{
					ggShootButtonFalse = defaultColoredMinecraftButton("发射方块或实体", "#FF929292");
				}
				ggShootButtonFalse.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						Sound.playFromFileName("gravitygun/fail.ogg");
						ModPE.showTipMessage("§4你没有选择任何实体或方块。");
					}
				});
				ggShootButtonFalse.setSoundEffectsEnabled(false);

				if(minecraftStyleForButtons)
				{
					ggShootButtonTrue = MinecraftButton(buttonsSize, false);
					ggShootButtonTrue.setText("发射方块或实体");
				} else
				{
					ggShootButtonTrue = defaultColoredMinecraftButton("发射方块或实体", "#FFFFFFFF");
				}
				ggShootButtonTrue.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						shootGravityGun();
					}
				});
				ggShootButtonTrue.setSoundEffectsEnabled(false);

				layoutShoot.addView(ggShootButtonFalse);
				layoutShoot.addView(ggShootButtonTrue);
				ggShootButtonTrue.setVisibility(android.view.View.GONE);

				popupGravityGunShoot = new android.widget.PopupWindow(layoutShoot, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
				popupGravityGunShoot.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
				popupGravityGunShoot.showAtLocation(currentActivity.getWindow().getDecorView(), android.view.Gravity.LEFT | android.view.Gravity.CENTER, 0, pixelsOffsetButtons);
				// SHOOT BUTTONS - END


				// DROP BUTTONS
				var layoutDrop = new android.widget.LinearLayout(currentActivity);
				layoutDrop.setOrientation(android.widget.LinearLayout.VERTICAL);

				if(minecraftStyleForButtons)
				{
					ggDropButtonFalse = MinecraftButton(buttonsSize, false);
					ggDropButtonFalse.setText("放置在脚下");
				} else
				{
					ggDropButtonFalse = defaultColoredMinecraftButton("放置在脚下", "#FF929292");
				}
				ggDropButtonFalse.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						Sound.playFromFileName("gravitygun/fail.ogg");
						ModPE.showTipMessage("§4你没有选择任何实体或方块。");
					}
				});
				ggDropButtonFalse.setSoundEffectsEnabled(false);

				if(minecraftStyleForButtons)
				{
					ggDropButtonTrue = MinecraftButton(buttonsSize, false);
					ggDropButtonTrue.setText("放置在脚下");
				} else
				{
					ggDropButtonTrue = defaultColoredMinecraftButton("放置在脚下", "#FFFFFFFF");
				}
				ggDropButtonTrue.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						dropGravityGun();
					}
				});
				ggDropButtonTrue.setSoundEffectsEnabled(false);

				layoutDrop.addView(ggDropButtonFalse);
				layoutDrop.addView(ggDropButtonTrue);
				ggDropButtonTrue.setVisibility(android.view.View.GONE);

				popupGravityGunDrop = new android.widget.PopupWindow(layoutDrop, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
				popupGravityGunDrop.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
				popupGravityGunDrop.showAtLocation(currentActivity.getWindow().getDecorView(), android.view.Gravity.RIGHT | android.view.Gravity.CENTER, 0, pixelsOffsetButtons);
				// DROP BUTTONS - END
			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function shootGravityGun()
{
	isGravityGunPicking = false;

	Sound.playFromFileName("gravitygun/fire.ogg");

	if(ggIsBlock)
	{
		var dir = getDirection(Entity.getYaw(Player.getEntity()), Entity.getPitch(Player.getEntity()));
		Entity.setVelX(ggEntity, dir.x * 1.5);
		Entity.setVelY(ggEntity, dir.y * 1.5);
		Entity.setVelZ(ggEntity, dir.z * 1.5);

		ggShotBlocksToBePlaced.push(new DroppedItemClass(ggEntity, ggBlockId, ggBlockData));
	} else
	{
		var dir = getDirection(Entity.getYaw(Player.getEntity()), Entity.getPitch(Player.getEntity()));
		Entity.setVelX(ggEntity, dir.x * 3.3);
		Entity.setVelY(ggEntity, dir.y * 3.3);
		Entity.setVelZ(ggEntity, dir.z * 3.3);

		turretsLoop:
		for(var i in turrets)
		{
			if(turrets[i].entity == ggEntity)
			{
				var random = Math.floor((Math.random() * 8) + 1);
				turrets[i].playSound("portal-sounds/turrets/turret_launched_" + random + ".mp3");
				break turretsLoop;
			}
		}
	}

	ggEntity = null;
	updateEnabledGravityGunButtons();
}

function dropGravityGun()
{
	if(ggIsBlock)
	{
		var dir = getDirection(Entity.getYaw(Player.getEntity()), Entity.getPitch(Player.getEntity()));
		var x = Player.getX() + (dir.x * 2);
		var y = Player.getY() + (dir.y * 2.5);
		var z = Player.getZ() + (dir.z * 2);
		if(Level.getTile(Math.floor(x), Math.floor(y), Math.floor(z)) == 0)
		{
			isGravityGunPicking = false;
			Sound.playFromFileName("gravitygun/drop.ogg");
			updateEnabledGravityGunButtons();

			Level.setTileNotInAir(x, y, z, ggBlockId, ggBlockData);
			Entity.remove(ggEntity);
			ggEntity = null;
		} else
		{
			Sound.playFromFileName("gravitygun/fail.ogg");
			ModPE.showTipMessage("There is another block in this position.");
		}
	} else
	{
		isGravityGunPicking = false;
		Sound.playFromFileName("gravitygun/drop.ogg");
		updateEnabledGravityGunButtons();
		ggEntity = null;
	}
}

function updateEnabledGravityGunButtons()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			if(isGravityGunPicking)
			{
				ggShootButtonFalse.setVisibility(android.view.View.GONE);
				ggShootButtonTrue.setVisibility(android.view.View.VISIBLE);

				ggDropButtonFalse.setVisibility(android.view.View.GONE);
				ggDropButtonTrue.setVisibility(android.view.View.VISIBLE);
			} else
			{
				ggShootButtonFalse.setVisibility(android.view.View.VISIBLE);
				ggShootButtonTrue.setVisibility(android.view.View.GONE);

				ggDropButtonFalse.setVisibility(android.view.View.VISIBLE);
				ggDropButtonTrue.setVisibility(android.view.View.GONE);
			}
		}
	}));
}

function pickBlockGravityGun(id, data)
{
	if(!isGravityGunPicking)
	{
		ggIsBlock = true;
		ggBlockId = id;
		ggBlockData = data;

		pickWithGravityGun();
	}
}

function pickEntityGravityGun(entity)
{
	if(!isGravityGunPicking)
	{
		ggIsBlock = false;
		ggEntity = entity;
		
		pickWithGravityGun();
	}
}

function pickWithGravityGun()
{
	if(!isGravityGunPicking)
	{		
		isGravityGunPicking = true;
		updateEnabledGravityGunButtons();
		if(Level.getGameMode() == GameMode.SURVIVAL)
			Player.damageCarriedItem();
		Sound.playFromFileName("gravitygun/pickup.ogg");
	}
}

function removeGravityGunUI()
{
	isGravityGunPicking = false;
	ggEntity = null;
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				popupGravityGunShoot.dismiss();
				popupGravityGunDrop.dismiss();
			} catch(err) { /* Gravity Gun not in hand */ }
		}
	}));
}
//########## GRAVITY GUN functions - END ##########


//########## LONG FALl BOOTS functions ##########
function makeLongFallBootsSound()
{
	var random = Math.floor((Math.random() * 2) + 1);
	Sound.playFromFileName("long_fall_boots/futureshoes" + random + ".mp3");
}
//########## LONG FALl BOOTS functions - END ##########


//########## CUSTOM MOBS functions ##########
function saveCustomMobs()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				// create folders
				var saveFolder = new java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod");
				saveFolder.mkdirs();

				// create file
				var saveFile = new java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod/mobs.dat");
				if(saveFile.exists())
					saveFile.delete();
				saveFile.createNewFile();

				// load streams
				var streamOutput = new java.io.FileOutputStream(saveFile);
				var streamWriter = new java.io.OutputStreamWriter(streamOutput);
				
				var properties = new java.util.Properties();

				properties.setProperty("number_of_mobs", String(customMobs.length));
				for(var i in customMobs)
				{
					properties.setProperty("mob_" + i + "_id", String(customMobs[i].entity));
					properties.setProperty("mob_" + i + "_string_id", String(customMobs[i].stringId));

					// custom properties
					properties.setProperty("mob_" + i + "_custom_properties", String(customMobs[i].getPropertiesNameArray().toString()));
					for(var j in customMobs[i].customProperties)
					{
						var propertyName = customMobs[i].customProperties[j].propertyName;
						var propertyType = customMobs[i].customProperties[j].propertyType;
						var value;
						eval("value = customMobs[i]." + propertyName + ";");

						properties.setProperty("mob_" + i + "_" + propertyName, String(value));
						properties.setProperty("mob_" + i + "_" + propertyName + "_type", String(propertyType));
					}
				}

				// save and close
				properties.store(streamWriter, "Portal 2 Mod by Desno365");
				streamWriter.close();
				streamOutput.close();
			}catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	}));
}

function loadCustomMobs()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				var loadFile = java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod/mobs.dat");
				if(loadFile.exists())
				{
					// load streams
					var streamInput = new java.io.FileInputStream(loadFile);
					var streamReader = new java.io.InputStreamReader(streamInput);

					var properties = new java.util.Properties();
					properties.load(streamReader);

					var numberOfMobs = parseInt(properties.getProperty("number_of_mobs", "0"));
					for(var i = 0; i < numberOfMobs; i++)
					{
						customMobs[i] = new CustomMobClass(parseFloat(properties.getProperty("mob_" + i + "_id", "0")));
						customMobs[i].stringId = String(properties.getProperty("mob_" + i + "_string_id", "0"));

						// custom properties
						var customPropertiesArray = stringToArray(properties.getProperty("mob_" + i + "_custom_properties", "null"));
						if(customPropertiesArray.length > 0 && customPropertiesArray[0] != "null")
						{
							for(var j in customPropertiesArray)
							{
								var propertyName = customPropertiesArray[j];
								var propertyType = String(properties.getProperty("mob_" + i + "_" + propertyName + "_type", "null"));
								if(propertyType != "null")
								{
									var propertyValue;
									var propertyValueString = String(properties.getProperty("mob_" + i + "_" + propertyName, "null"));
									if(propertyType == "bool")
										propertyValue = stringToBoolean(propertyValueString);
									if(propertyType == "int")
										propertyValue = parseInt(propertyValueString);
									if(propertyType == "float")
										propertyValue = parseFloat(propertyValueString);
									if(propertyType == "string")
										propertyValue = propertyValueString;

									eval("customMobs[i]." + propertyName + " = propertyValue;");
								}
							}
						}
					}

					// close streams
					streamReader.close();
					streamInput.close();
				}
			}catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	}));
}

function customMobRespawnerCheck(entity)
{
	var index = findPositionInCustomMobs(entity);
	if(index != -1) // if true a custom mob has just been added
	{
		// get old mobs position and remove it from world
		var x = Entity.getX(entity);
		var y = Entity.getY(entity);
		var z = Entity.getZ(entity);
		Entity.remove(customMobs[index].entity);

		// spawn new turrets
		if(customMobs[index].stringId == "turret")
		{
			restoreTurretFromOldTurretObject(x, y, z, customMobs[index]);
		}
		if(customMobs[index].stringId == "turret-defective")
		{
			restoreTurretDefectiveFromOldTurretObject(x, y, z, customMobs[index]);
		}

		// remove old mob from custom mobs
		customMobs.splice(index, 1);
	}
}

function findPositionInCustomMobs(entity)
{
	for(var i in customMobs)
	{
		if(customMobs[i].entity == entity)
		{
			return i;
		}
	}
	return -1;
}

function addToCustomMobs(customMobObject)
{
	// add an object that must be a subclass of CustomMobClass to the custom mobs array
	customMobs.push(customMobObject);
	saveCustomMobs();
}

function CustomMobClass(entity)
{
	this.entity = entity;
	this.stringId = "";
	this.x = 0;
	this.y = 0;
	this.z = 0;
	this.customProperties = [];

	this.updatePosition = function()
	{
		var x = Entity.getX(this.entity);
		var y = Entity.getY(this.entity);
		var z = Entity.getZ(this.entity);

		if(x != 0 && y != 0 && z != 0)
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}
	}

	this.getPropertiesNameArray = function()
	{
		var array = [];
		for(var i in this.customProperties)
		{
			array.push(this.customProperties[i].propertyName);
		}
		return array;
	}
}
//########## CUSTOM MOBS functions - END ##########


//########## TURRETS functions ##########
function spawnTurret(x, y, z)
{
	x = Math.floor(x);
	y = Math.floor(y);
	z = Math.floor(z);

	var turret = Level.spawnMob(x + 0.5, y + 1.6, z + 0.5, EntityType.VILLAGER, "mob/turret.png");
	Entity.setHealth(turret, 1);
	Entity.setRenderType(turret, TurretRenderType.renderType);
	Entity.setCollisionSize(turret, 8/16, 16/16);
	Entity.addEffect(turret, MobEffect.movementSlowdown, 999999, 126, false, true);

	turrets.push(new TurretClass(turret));
	turrets[turrets.length - 1].x = Entity.getX(turret);
	turrets[turrets.length - 1].y = Entity.getY(turret);
	turrets[turrets.length - 1].z = Entity.getZ(turret);

	addToCustomMobs(turrets[turrets.length - 1]);
}

function spawnTurretDefective(x, y, z)
{
	x = Math.floor(x);
	y = Math.floor(y);
	z = Math.floor(z);

	var turret = Level.spawnMob(x + 0.5, y + 1.6, z + 0.5, EntityType.VILLAGER, "mob/turretdefective.png");
	Entity.setHealth(turret, 1);
	Entity.setRenderType(turret, TurretRenderType.renderType);
	Entity.setCollisionSize(turret, 8/16, 16/16);
	Entity.addEffect(turret, MobEffect.movementSlowdown, 999999, 126, false, true);

	turretsDefective.push(new TurretDefectiveClass(turret));
	turretsDefective[turretsDefective.length - 1].x = Entity.getX(turret);
	turretsDefective[turretsDefective.length - 1].y = Entity.getY(turret);
	turretsDefective[turretsDefective.length - 1].z = Entity.getZ(turret);

	addToCustomMobs(turretsDefective[turretsDefective.length - 1]);
}

function restoreTurretFromOldTurretObject(x, y, z, oldTurret)
{
	spawnTurret(x, y, z);
	turrets[turrets.length - 1].countdownToAttack = oldTurret.countdownToAttack;
	turrets[turrets.length - 1].aggressive = oldTurret.aggressive;
	if(turrets[turrets.length - 1].aggressive)
	{
		if(turrets[turrets.length - 1].shouldShoot())
			Entity.setRenderType(turrets[turrets.length - 1].entity, TurretShooting2RenderType.renderType);
		else
			Entity.setRenderType(turrets[turrets.length - 1].entity, TurretLaserRenderType.renderType);
	}
}

function restoreTurretDefectiveFromOldTurretObject(x, y, z, oldTurret)
{
	spawnTurretDefective(x, y, z);
	turretsDefective[turretsDefective.length - 1].countdownToAttack = oldTurret.countdownToAttack;
	turretsDefective[turretsDefective.length - 1].aggressive = oldTurret.aggressive;
	if(turretsDefective[turretsDefective.length - 1].aggressive)
	{
		if(turretsDefective[turretsDefective.length - 1].shouldShoot())
			Entity.setRenderType(turretsDefective[turretsDefective.length - 1].entity, TurretShooting2RenderType.renderType);
		else
			Entity.setRenderType(turretsDefective[turretsDefective.length - 1].entity, TurretLaserRenderType.renderType);
	}
}

function TurretClass(turret)
{
	var turretObject = new CustomMobClass(turret);
	turretObject.stringId = "turret";

	turretObject.customProperties = [{propertyName: "aggressive", propertyType:"bool"}, {propertyName: "countdownToAttack", propertyType:"int"}];

	turretObject.aggressive = false;
	turretObject.countdownToAttack = 0;

	turretObject.artificialIntelligence = function()
	{
		//Entity.setRot(this.entity, 0, 0);

		if(this.aggressive)
		{
			if(this.shouldShoot())
			{
				this.countdownToAttack++;
				if(this.countdownToAttack == 1)
				{
					Entity.setRenderType(this.entity, TurretShooting1RenderType.renderType);
					var random = Math.floor((Math.random() * 9) + 1);
					this.playSound("portal-sounds/turrets/turret_active_" + random + ".mp3");
				}
				if(this.countdownToAttack == 10)
					Entity.setRenderType(this.entity, TurretShooting2RenderType.renderType);
				if(this.countdownToAttack % 15 == 0 && this.countdownToAttack >= 30)
					this.shoot(Player.getEntity());
			}else
			{
				if(this.countdownToAttack != 0)
				{
					if(this.countdownToAttack == 1)
					{
						Entity.setRenderType(this.entity, TurretLaserRenderType.renderType);
						this.countdownToAttack = 0;
						var random = Math.floor((Math.random() * 3) + 1);
						this.playSound("portal-sounds/turrets/turret_search_" + random + ".mp3");
					}else
					{
						Entity.setRenderType(this.entity, TurretShooting1RenderType.renderType);
						if(this.countdownToAttack > 10)
							this.countdownToAttack = 10;
						this.countdownToAttack--;
					}
				}
			}
		}else
		{
			if(this.countdownToAttack != 0)
				this.countdownToAttack = 0;
		}
	}

	turretObject.shouldShoot = function()
	{
		//
		return checkProximity(Player.getEntity(), this.entity, 10, 3);
	}

	turretObject.shoot = function(victim)
	{
		var shotYaw = Math.atan2((Entity.getZ(this.entity) - Entity.getZ(victim)), (Entity.getX(this.entity) - Entity.getX(victim)));
		var turretShot = getDirection((java.lang.Math.toDegrees(shotYaw) - 90), 0);
		Level.playSoundEnt(this.entity, "random.bow", 1000, 0);

		if(Level.getGameMode() == GameMode.SURVIVAL)
		{
			var bullet = Level.spawnMob(Entity.getX(this.entity) + (-turretShot.x * 1.1), Entity.getY(this.entity) + 1, Entity.getZ(this.entity) + (-turretShot.z * 1.1), 80);

			// fix bouncing bullets
			var skelly = Level.spawnMob(Entity.getX(this.entity) + (-turretShot.x * 1.1), Entity.getY(this.entity) + 1, Entity.getZ(this.entity) + (-turretShot.z * 1.1), 34);
			Entity.setRenderType(skelly, 4); // dropped item render
			Entity.rideAnimal(skelly, bullet);
			Entity.remove(skelly);
		} else
		{
			var bullet = Level.spawnMob(Entity.getX(this.entity) + (-turretShot.x * 1.1), Entity.getY(this.entity) + 1, Entity.getZ(this.entity) + (-turretShot.z * 1.1), 81);
		}

		Entity.setVelX(bullet, -turretShot.x * 1.8);
		Entity.setVelY(bullet, turretShot.y * 1.8);
		Entity.setVelZ(bullet, -turretShot.z * 1.8);
	}

	turretObject.isThereTurretAtDistance = function(distance)
	{
		distance = Math.floor(distance);
		for(var i in turrets)
		{
			if((Math.floor(Entity.getY(this.entity))) == (Math.floor(Entity.getY(turrets[i].entity))))
			{
				if((Math.floor(Entity.getX(this.entity)) - distance) == (Math.floor(Entity.getX(turrets[i].entity))))
					if((Math.floor(Entity.getZ(this.entity))) == (Math.floor(Entity.getZ(turrets[i].entity))))
						return true;

				if((Math.floor(Entity.getX(this.entity)) + distance) == (Math.floor(Entity.getX(turrets[i].entity))))
					if((Math.floor(Entity.getZ(this.entity))) == (Math.floor(Entity.getZ(turrets[i].entity))))
						return true;

				if((Math.floor(Entity.getZ(this.entity)) - distance) == (Math.floor(Entity.getZ(turrets[i].entity))))
					if((Math.floor(Entity.getX(this.entity))) == (Math.floor(Entity.getX(turrets[i].entity))))
						return true;

				if((Math.floor(Entity.getZ(this.entity)) + distance) == (Math.floor(Entity.getZ(turrets[i].entity))))
					if((Math.floor(Entity.getX(this.entity))) == (Math.floor(Entity.getX(turrets[i].entity))))
						return true;
			}
		}
		return false;
	}

	turretObject.playSound = function(fileName)
	{
		if(areTurretsSinging)
			turretsStopSinging();


		var volume = 1.0;

		// change volume based on distance from source
		var distance = Math.sqrt( Math.pow(Entity.getX(this.entity) - Player.getX(), 2) + Math.pow(Entity.getY(this.entity) - Player.getY(), 2) + Math.pow(Entity.getZ(this.entity) - Player.getZ(), 2) );
		if(distance > MAX_LOGARITHMIC_VOLUME)
			volume = 0.0;
		else
		{
			volume = 1 - (Math.log(distance) / Math.log(MAX_LOGARITHMIC_VOLUME));
		}

		// apply general volume
		volume = volume * generalVolume;

		// play sound
		try
		{
			if(turretSoundPlayer == null)
				turretSoundPlayer = new android.media.MediaPlayer();
			turretSoundPlayer.reset();
			turretSoundPlayer.setDataSource(sdcard + "/games/com.mojang/" + fileName);
			turretSoundPlayer.setVolume(volume, volume);
			turretSoundPlayer.prepare();
			turretSoundPlayer.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener()
			{
				onCompletion: function(mp)
				{
					turretSoundPlayer.release();
					turretSoundPlayer = null;
					turretsStopSinging();
				}
			});
			turretSoundPlayer.start();
		} catch(err)
		{
			ModPE.showTipMessage(getLogText() + "Sounds not installed!");
			ModPE.log(getLogText() + "Error while playing a turret sound: " + err);
		}
	}

	return turretObject;
}

function TurretDefectiveClass(turret)
{
	var turretObject = new TurretClass(turret);
	turretObject.stringId = "turret-defective";

	turretObject.artificialIntelligence = function()
	{
		//Entity.setRot(this.entity, 0, 0);

		if(this.aggressive)
		{
			if(checkProximity(Player.getEntity(), this.entity, 8, 3))
			{
				this.countdownToAttack++;
				if(this.countdownToAttack == 1)
				{
					Entity.setRenderType(this.entity, TurretShooting1RenderType.renderType);
				}
				if(this.countdownToAttack == 10)
				{
					Entity.setRenderType(this.entity, TurretShooting2RenderType.renderType);
					this.shoot();
				}
			}else
			{
				if(this.countdownToAttack != 0)
				{
					if(this.countdownToAttack == 1)
					{
						Entity.setRenderType(this.entity, TurretLaserRenderType.renderType);
						this.countdownToAttack = 0;
					}else
					{
						Entity.setRenderType(this.entity, TurretShooting1RenderType.renderType);
						if(this.countdownToAttack > 10)
							this.countdownToAttack = 10;
						this.countdownToAttack--;
					}
				}
			}
		}else
		{
			if(this.countdownToAttack != 0)
				this.countdownToAttack = 0;
		}
	}

	turretObject.shouldShoot = function()
	{
		//
		return checkProximity(Player.getEntity(), this.entity, 8, 3);
	}

	turretObject.shoot = function()
	{
		var volume = 1.0;

		// change volume based on distance from source
		var distance = Math.sqrt( Math.pow(Entity.getX(this.entity) - Player.getX(), 2) + Math.pow(Entity.getY(this.entity) - Player.getY(), 2) + Math.pow(Entity.getZ(this.entity) - Player.getZ(), 2) );
		if(distance > MAX_LOGARITHMIC_VOLUME)
			volume = 0.0;
		else
		{
			volume = 1 - (Math.log(distance) / Math.log(MAX_LOGARITHMIC_VOLUME));
		}

		// apply general volume
		volume = volume * generalVolume;

		// play shooting sound
		try
		{
			var random = Math.floor((Math.random() * 5) + 1);

			var soundPlayer = new android.media.MediaPlayer();
			soundPlayer.reset();
			soundPlayer.setDataSource(sdcard + "/games/com.mojang/portal-sounds/turrets_defective/turret_defective_shoot_" + random + ".wav");
			soundPlayer.setVolume(volume, volume);
			soundPlayer.prepare();
			soundPlayer.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener()
			{
				onCompletion: function(mp)
				{
					var random = Math.floor((Math.random() * 20) + 1);

					mp.reset();
					mp.setDataSource(sdcard + "/games/com.mojang/portal-sounds/turrets_defective/turret_defective_after_shoot_" + random + ".wav");
					mp.setVolume(volume, volume);
					mp.prepare();
					mp.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener()
					{
						onCompletion: function(mp)
						{
							mp.release();
							mp = null;
						}
					});
					mp.start();
				}
			});
			soundPlayer.start();
		} catch(err)
		{
			ModPE.showTipMessage(getLogText() + "Sounds not installed!");
			ModPE.log(getLogText() + "Error while playing a turret sound: " + err);
		}
	}

	return turretObject;
}

function checkProximity(entity1, entity2, distanceXZ, distanceY)
{
	if(!(Math.abs(Entity.getX(entity1) - Entity.getX(entity2)) <= distanceXZ))
		return false;
	if(!(Math.abs(Entity.getY(entity1) - Entity.getY(entity2)) <= distanceY))
		return false;
	if(!(Math.abs(Entity.getZ(entity1) - Entity.getZ(entity2)) <= distanceXZ))
		return false;
	return true;
}

function turretsStopSinging()
{
	areTurretsSinging = false;
	try
	{
		turretSoundPlayer.reset();
	} catch(e) { }
}
//########## TURRETS functions - END ##########


//########## RADIO functions ##########
function startRadioMusic()
{
	try
	{
		radioPlayer.reset();
		radioPlayer.setDataSource(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/portal-sounds/radio/looping_radio_mix.mp3");
		radioPlayer.prepare();
		radioPlayer.setLooping(true);
		radioPlayer.setVolume(1.0 * generalVolume, 1.0 * generalVolume);
		radioPlayer.start();
	} catch(err)
	{
		ModPE.showTipMessage(getLogText() + "Sounds not installed!");
		ModPE.log(getLogText() + "Error in startRadioMusic: " + err);
		stopRadioMusic();
	}
}

function stopRadioMusic()
{
	isRadioPlaying = false;
	radioX = 0;
	radioY = 0;
	radioZ = 0;
	radioCountdown = 0;
	try
	{
		radioPlayer.reset();
	} catch(err) { }
}
//########## RADIO functions - END ##########


//########## JUKEBOX functions ##########
function JukeboxClass(x, y, z, disc)
{
	this.x = x;
	this.y = y;
	this.z = z;
	this.countdown = 0;
	this.disc = disc;

	this.player = new android.media.MediaPlayer();
	this.player.reset();
	this.player.setDataSource(sdcard + "/games/com.mojang/portal-music/" + getFileNameFromDiscId(disc));
	this.player.prepare();
	this.player.setVolume(1.0 * generalVolume, 1.0 * generalVolume);
	this.player.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener()
	{
		onCompletion: function()
		{
			var jukebox = getJukeboxObjectFromXYZ(x, y, z);
			if(jukebox != -1)
				jukebox.stopJukebox();
		}
	});
	this.player.start();

	nowPlayingMessage = "正在播放: " + Item.getName(disc, 0, false);
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			for(var ms = 0; ms < 17; ms++) // executed 17 times, 16 different colors, the last one to stop the effect
			{
				if(ms < 16)
				{
					new android.os.Handler().postDelayed(new java.lang.Runnable(
					{
						run: function()
						{
							ModPE.showTipMessage("§" + currentColor.toString(16) + nowPlayingMessage);
							if(currentColor == 15)
								currentColor = 0;
							else
								currentColor++;
						}
					}), ms * 250 + 1);
				} else
				{
					new android.os.Handler().postDelayed(new java.lang.Runnable(
					{
						run: function()
						{
							ModPE.showTipMessage(" ");
							currentColor = 0;
						}
					}), ms * 250 + 1);
				}
			}
		}
	}));


	this.stopJukebox = function()
	{
		this.ejectDisc();
		this.player.reset();
		jukeboxes.splice(jukeboxes.indexOf(this), 1);
	}

	this.ejectDisc = function()
	{
		Level.dropItem(this.x, this.y + 1, this.z, 0, this.disc, 1, 0);
	}
}

function getJukeboxObjectFromXYZ(x, y, z)
{
	for(var i in jukeboxes)
		if(Math.floor(jukeboxes[i].x) == Math.floor(x) && Math.floor(jukeboxes[i].y) == Math.floor(y) && Math.floor(jukeboxes[i].z) == Math.floor(z))
			return jukeboxes[i];
	return -1;
}

function getFileNameFromDiscId(discId)
{
	switch(discId)
	{
		case STILL_ALIVE_DISC_ID:
		{
			return "portal_still_alive.mp3";
		}
		case WANT_YOU_GONE_DISC_ID:
		{
			return "portal_want_you_gone.mp3";
		}
		case CARA_MIA_ADDIO_DISC_ID:
		{
			return "portal_turret_song.mp3";
		}
		default:
		{
			throw "Not A Disc";
		}
	}
}
//########## JUKEBOX functions - END ##########


//########## BLUE GEL functions ##########
function makeBounceSound()
{
	var random = Math.floor((Math.random() * 2) + 1);
	Sound.playFromFileName("gelblue/player_bounce_jump_paint_0" + random + ".mp3");
}
//########## BLUE GEL functions - END ##########


//########## JUMPER functions ##########
function makeJumperJump(angle)
{
	var random = Math.floor((Math.random() * 3) + 4);
	Sound.playFromFileName("jumper/alyx_gun_fire" + random + ".mp3");

	var jumperDir = getDirection(angle, 0);
	Entity.setVelX(Player.getEntity(), jumperDir.x * 1.8);
	Entity.setVelY(Player.getEntity(), 1.27); // cos(45) * 1.8
	Entity.setVelZ(Player.getEntity(), jumperDir.z * 1.8);
}
//########## JUMPER functions - END ##########


//########## MAP OPTIONS functions ##########
function saveMapOptions()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				// create folders
				var saveFolder = new java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod");
				saveFolder.mkdirs();

				// create file
				var saveFile = new java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod/portal-mod-options.dat");
				if(saveFile.exists())
					saveFile.delete();
				saveFile.createNewFile();

				// load streams
				var streamOutput = new java.io.FileOutputStream(saveFile);
				var streamWriter = new java.io.OutputStreamWriter(streamOutput);
				
				var properties = new java.util.Properties();

				properties.setProperty("indestructible_blocks", String(indestructibleBlocks));
				properties.setProperty("full_hunger_bar", String(alwaysFullHungerBar));
				properties.setProperty("pick_blacklist", pickBlocksBlacklist.toString());

				properties.store(streamWriter, "Portal 2 Mod by Desno365");
				streamWriter.close();
				streamOutput.close();
			}catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	}));
}

function loadMapOptions()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try
			{
				var loadFile = java.io.File(new android.os.Environment.getExternalStorageDirectory() + "/games/com.mojang/minecraftWorlds/" + Level.getWorldDir() + "/portal-mod/portal-mod-options.dat");
				if(loadFile.exists())
				{
					// load streams
					var streamInput = new java.io.FileInputStream(loadFile);
					var streamReader = new java.io.InputStreamReader(streamInput);

					var properties = new java.util.Properties();
					properties.load(streamReader);

					indestructibleBlocks = stringToBoolean(properties.getProperty("indestructible_blocks", "0"));
					alwaysFullHungerBar = stringToBoolean(properties.getProperty("full_hunger_bar", "0"));
					pickBlocksBlacklist = stringToIntArray(properties.getProperty("pick_blacklist", "" + REPULSION_GEL_ID + ", " + PROPULSION_GEL_ID + ", " + JUMPER_ID + ", " + JUMPER_DIRECTION_ID));

					// close streams
					streamReader.close();
					streamInput.close();
				}
			}catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	}));
}
//########## MAP OPTIONS functions - END ##########


//########## SOUND functions ##########
var sound1;
var sound2;
var sound3;

var Sound = {

	playFromFileName: function(fileName, x, y, z)
	{
		var volume = 1.0;

		// change volume based on distance from source
		if(!(x == null || y == null || z == null))
		{
			var distance = Math.sqrt( Math.pow(x - Player.getX(), 2) + Math.pow(y - Player.getY(), 2) + Math.pow(z - Player.getZ(), 2) );
			if(distance > MAX_LOGARITHMIC_VOLUME)
				volume = 0.0;
			else
			{
				volume = 1 - (Math.log(distance) / Math.log(MAX_LOGARITHMIC_VOLUME));
			}
		}

		// apply general volume
		volume = volume * generalVolume;

		// play sound
		try
		{
			if(sound1 == null)
			{
				if(DEBUG)
					clientMessage("sound 1");

				if(sound1 == null)
					sound1 = new android.media.MediaPlayer();
				sound1.reset();
				sound1.setDataSource(sdcard + "/games/com.mojang/portal-sounds/" + fileName);
				sound1.setVolume(volume, volume);
				sound1.prepare();
				sound1.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener()
				{
					onCompletion: function(mp)
					{
						if(DEBUG)
							clientMessage("sound 1 finish");
						sound1.release();
						sound1 = null;
					}
				});
				sound1.start();
				return 1; // END
			}
			if(sound2 == null)
			{
				if(DEBUG)
					clientMessage("sound 2");

				if(sound2 == null)
					sound2 = new android.media.MediaPlayer();
				sound2.reset();
				sound2.setDataSource(sdcard + "/games/com.mojang/portal-sounds/" + fileName);
				sound2.setVolume(volume, volume);
				sound2.prepare();
				sound2.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener()
				{
					onCompletion: function(mp)
					{
						if(DEBUG)
							clientMessage("sound 2 finish");
						sound2.release();
						sound2 = null;
					}
				});
				sound2.start();
				return 2; // END
			}
			if(sound3 == null)
			{
				if(DEBUG)
					clientMessage("sound 3");

				if(sound3 == null)
					sound3 = new android.media.MediaPlayer();
				sound3.reset();
				sound3.setDataSource(sdcard + "/games/com.mojang/portal-sounds/" + fileName);
				sound3.setVolume(volume, volume);
				sound3.prepare();
				sound3.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener()
				{
					onCompletion: function(mp)
					{
						if(DEBUG)
							clientMessage("sound 3 finish");
						sound3.release();
						sound3 = null;
					}
				});
				sound3.start();
				return 3; // END
			} else
			{
				if(DEBUG)
					clientMessage("sound 1 all");

				if(sound1 == null)
					sound1 = new android.media.MediaPlayer();
				sound1.reset();
				sound1.setDataSource(sdcard + "/games/com.mojang/portal-sounds/" + fileName);
				sound1.setVolume(volume, volume);
				sound1.prepare();
				sound1.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener()
				{
					onCompletion: function(mp)
					{
						if(DEBUG)
							clientMessage("sound 1 all finish");
						sound1.release();
						sound1 = null;
					}
				});
				sound1.start();
				return 1; // END
			}
		} catch(err)
		{
			ModPE.showTipMessage(getLogText() + "Sounds not installed!");
			ModPE.log(getLogText() + "Error in playSoundFromFile: " + err);
		}
	}
};
//########## SOUND functions - END ##########

//########## INFO ITEM functions ##########
function displayInfoItemUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var settingsImage = new android.widget.ImageView(currentActivity);
				settingsImage.setImageBitmap(settingsPngScaled);
				settingsImage.setOnClickListener(new android.view.View.OnClickListener(
				{
					onClick: function()
					{
						infoPortalMod();
					}
				}));

				popupSettingsImage = new android.widget.PopupWindow(settingsImage, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
				popupSettingsImage.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
				popupSettingsImage.showAtLocation(currentActivity.getWindow().getDecorView(), android.view.Gravity.LEFT | android.view.Gravity.CENTER, convertDpToPixel(4), 0);



				var tipText = basicMinecraftTextView(getRandomTip(), 14);
				tipText.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function(v)
					{
						v.setText(new android.text.Html.fromHtml(getRandomTip()));
						return false;
					}
				});
				tipText.setMovementMethod(android.text.method.LinkMovementMethod.getInstance());
				tipText.setLinkTextColor(android.graphics.Color.parseColor("#FFFBFF97"));
				tipText.setGravity(android.view.Gravity.LEFT);
				tipText.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				tipText.setPadding(convertDpToPixel(4), convertDpToPixel(4), convertDpToPixel(4), convertDpToPixel(4));
				tipText.setLayoutParams(new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT));

				popupTip = new android.widget.PopupWindow(tipText, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
				popupTip.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
				popupTip.showAtLocation(currentActivity.getWindow().getDecorView(), android.view.Gravity.RIGHT | android.view.Gravity.CENTER, 0, -64 * deviceDensity);
			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function getRandomTip()
{
	var cal = java.util.Calendar.getInstance();
	var day = cal.get(java.util.Calendar.DAY_OF_MONTH);
	var month = cal.get(java.util.Calendar.MONTH);
	if(day == 3 && month == java.util.Calendar.JULY)
	{
		return "Happy birthday, Desno365!";
	}
	if(day == 31 && month == java.util.Calendar.OCTOBER)
	{
		return "Keep calm and scary on.";
	}
	if(day == 25 && month == java.util.Calendar.DECEMBER)
	{
		return "Merry Christmas!";
	}
	if(day == 1 && month == java.util.Calendar.JANUARY)
	{
		return "Happy new year!";
	}

	var random = Math.floor((Math.random() * 15) + 1);
	switch(random)
	{
		case 1:
		{
			return "你曾经尝试过 <a href=\"http://ichun.us/mods/portalgun/\">mod网站</a> 和 Minecraft PC by 葫芦侠?";
		}
		case 2:
		{
			return "按照@ desno365在推特";
		}
		case 3:
		{
			return "好的话给我葫芦和关注哦";
		}
		case 4:
		{
			return "4个炮塔在一排。";
		}
		case 5:
		{
			return "我没有缺陷！";
		}
		case 6:
		{
			return "空间!!";
		}
		case 7:
		{
			return "你还在那里吗？";
		}
		case 8:
		{
			return "不要做柠檬水！";
		}
		case 9:
		{
			return "有人在那里吗？";
		}
		case 10:
		{
			return "一组包含自己的集合吗？";
		}
		case 11:
		{
			return "<a href=\"http://www.thinkwithportals.com/\">此mod网站</a>";
		}
		case 12:
		{
			return "蛋糕是一个谎言。";
		}
		case 13:
		{
			return "作者.名称 = \"葫芦侠\"; 作者.昵称 = \"葫芦侠\";";
		}
		case 14:
		{
			return "如果你想警告你这个国防部的未来，不要听。";
		}
		case 15:
		{
			return "这是一个很长的时间…";
		}
	}
}

function removeInfoItemUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable(
	{
		run: function()
		{
			try {
				popupSettingsImage.dismiss();
			} catch(e) {}
			try {
				popupTip.dismiss();
			} catch(e) {}
		}
	}));
}
//########## INFO ITEM functions - END ##########


//########## PLAYER functions ##########
Player.damageCarriedItem = function()
{
	var maxDamage;
	if(Player.getCarriedItem() == GRAVITY_GUN_ID)
		maxDamage = GRAVITY_GUN_MAX_DAMAGE;
	if(Player.getCarriedItem() == PORTAL_GUN_ORANGE_ID || Player.getCarriedItem() == PORTAL_GUN_BLUE_ID)
		maxDamage = PORTAL_GUN_DAMAGE;
	if(Player.getCarriedItem() == PORTAL_GUN_GOLD_ID)
		maxDamage = PORTAL_GUN_GOLD_DAMAGE;
	if(Player.getCarriedItem() == PORTAL_GUN_IRON_ID)
		maxDamage = PORTAL_GUN_IRON_DAMAGE;
	if(Player.getCarriedItem() == PORTAL_GUN_LAVA_ID)
		maxDamage = PORTAL_GUN_LAVA_DAMAGE;
	if(Player.getCarriedItem() == PORTAL_GUN_WOOD_AND_STONE_ID)
		maxDamage = PORTAL_GUN_WOOD_AND_STONE_DAMAGE;

	if(Player.getCarriedItemData() < maxDamage)
		Entity.setCarriedItem(Player.getEntity(), Player.getCarriedItem(), Player.getCarriedItemCount(), Player.getCarriedItemData() + 1);
	else
	{
		Level.playSoundEnt(Player.getEntity(), "random.break", 100, 0);
		/*if(Player.getCarriedItemCount() == 1)
			Player.clearInventorySlot(Player.getSelectedSlotId()); // crashes in 0.12.1
		else*/
		Entity.setCarriedItem(Player.getEntity(), Player.getCarriedItem(), Player.getCarriedItemCount() - 1, 0);
	}
}

Player.decreaseByOneCarriedItem = function()
{
	/*if(Player.getCarriedItemCount() == 1)
		Player.clearInventorySlot(Player.getSelectedSlotId()); // crashes on 0.12.1
	else*/
	Entity.setCarriedItem(Player.getEntity(), Player.getCarriedItem(), Player.getCarriedItemCount() - 1, 0);
}
//########## PLAYER functions - END ##########


//########## LEVEL functions ##########
Level.setTileNotInAir = function(x, y, z, id, data)
{
	x = Math.floor(x);
	y = Math.floor(y);
	z = Math.floor(z);

	notInAir:
	for(var i = y; i > 0; i--)
	{
		if(Level.getTile(x, i - 1, z) > 0)
		{
			y = i;
			break notInAir;
		}
	}

	Level.setTile(x, y, z, id, data);
}

Level.placeBlockFromItem = function(x, y, z, side, blockId, canBePlacedOnAir)
{
	if(canBePlacedOnAir == null)
		canBePlacedOnAir = false; // must be placed on a block

	var canBePlaced = true;

	switch(side)
	{
		case 0: // down
		{
			y--;
			if(canBePlacedOnAir || Level.getTile(x, y - 1, z) == 0)
				canBePlaced = false;
			break;
		}
		case 1: // up
		{
			y++;
			break;
		}
		case 2:
		{
			z--;
			if(canBePlacedOnAir || Level.getTile(x, y - 1, z) == 0)
				canBePlaced = false;
			break;
		}
		case 3:
		{
			z++;
			if(canBePlacedOnAir || Level.getTile(x, y - 1, z) == 0)
				canBePlaced = false;
			break;
		}
		case 4:
		{
			x--;
			if(canBePlacedOnAir || Level.getTile(x, y - 1, z) == 0)
				canBePlaced = false;
			break;
		}
		case 5:
		{
			x++;
			if(canBePlacedOnAir || Level.getTile(x, y - 1, z) == 0)
				canBePlaced = false;
			break;
		}
	}
	if(canBePlaced)
	{
		Level.setTile(x, y, z, blockId);
		if(Level.getGameMode() == GameMode.SURVIVAL)
			Player.decreaseByOneCarriedItem();
	}
}
//########## LEVEL functions - END ##########


//########## INTERNET functions ##########
function updateLatestVersionMod()
{
	try
	{
		// download content
		var url = new java.net.URL("https://raw.githubusercontent.com/Desno365/MCPE-scripts/master/portalMOD-version");
		var connection = url.openConnection();
 
		// get content
		inputStream = connection.getInputStream();
 
		// read result
		var loadedVersion = "";
		var bufferedVersionReader = new java.io.BufferedReader(new java.io.InputStreamReader(inputStream));
		var rowVersion = "";
		while((rowVersion = bufferedVersionReader.readLine()) != null)
		{
			loadedVersion += rowVersion;
		}
		latestVersion = loadedVersion.split(" ")[0];
 
		// close what needs to be closed
		bufferedVersionReader.close();
		inputStream.close();
	} catch(err)
	{
		clientMessage("Portal Mod: Can't check for updates, please check your Internet connection.");
		ModPE.log(getLogText() + "updateLatestVersionMod(): caught an error: " + err);
	}
}
//########## INTERNET functions - END ##########


//########## DIRECTION functions ##########
function vector3d(x, y, z)
{
	this.x = x;
	this.y = y;
	this.z = z;
}

function getDirection(yaw, pitch)
{
	var direction = new vector3d(0, 0, 0);
	direction.y = -Math.sin(java.lang.Math.toRadians(pitch));
	direction.x = -Math.sin(java.lang.Math.toRadians(yaw)) * Math.cos(java.lang.Math.toRadians(pitch));
	direction.z = Math.cos(java.lang.Math.toRadians(yaw)) * Math.cos(java.lang.Math.toRadians(pitch));
	return direction;
}
//########## DIRECTION functions - END ##########


//########## IMAGE functions ##########
function createImages()
{
	var bluePortalDecoded = decodeImageFromBase64(bluePortalImage);
	bluePortalScaled = scaleImageToDensity(bluePortalDecoded, true);
	bluePortalImage = null;

	var orangePortalDecoded = decodeImageFromBase64(orangePortalImage);
	orangePortalScaled = scaleImageToDensity(orangePortalDecoded, true);
	orangePortalImage = null;

	var overlayDecoded = decodeImageFromBase64(overlayFull);
	overlayFullScaled = scaleImageToDensity(overlayDecoded);
	overlayFull = null;

	var overlayBlueDecoded = decodeImageFromBase64(overlayBlue);
	overlayBlueScaled = scaleImageToDensity(overlayBlueDecoded);
	overlayBlue = null;

	var overlayOrangeDecoded = decodeImageFromBase64(overlayOrange);
	overlayOrangeScaled = scaleImageToDensity(overlayOrangeDecoded);
	overlayOrange = null;

	var overlayBlankDecoded = decodeImageFromBase64(overlayBlank);
	overlayBlankScaled = scaleImageToDensity(overlayBlankDecoded);
	overlayBlank = null;


	var backgroundDarkDirtDecoded = decodeImageFromBase64(backgroundDarkDirtPng);
	backgroundDarkDirtScaled = scaleImageToDensity(backgroundDarkDirtDecoded);
	background = new android.graphics.drawable.BitmapDrawable(backgroundDarkDirtScaled);
	background.setTileModeXY(android.graphics.Shader.TileMode.REPEAT, android.graphics.Shader.TileMode.REPEAT);
	backgroundDarkDirtPng = null;

	var dividerDecoded = decodeImageFromBase64(divider);
	dividerScaled = scaleImageToSize(dividerDecoded, dividerDecoded.getWidth() * deviceDensity * 0.5, dividerDecoded.getHeight() * deviceDensity * 0.5, true);
	divider = null;

	var settingsPngDecoded = decodeImageFromBase64(settingsPng);
	settingsPngScaled = scaleImageToSize(settingsPngDecoded, settingsPngDecoded.getWidth() * deviceDensity * 0.3, settingsPngDecoded.getHeight() * deviceDensity * 0.3, true);
	settingsPng = null;

	var playStorePngDecoded = decodeImageFromBase64(playStorePng);
	playStorePngScaled = scaleImageToSize(playStorePngDecoded, playStorePngDecoded.getWidth() * (deviceDensity / 3), playStorePngDecoded.getHeight() * (deviceDensity / 3), true);
	playStorePng = null;
}

function decodeImageFromBase64(base64String)
{
	if(base64String != null)
	{
		var byteArray = android.util.Base64.decode(base64String, 0);
		return android.graphics.BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
	}else
	{
		throw getLogText() + "decodeImageFromBase64 has found a null string.";
	}
}

function scaleImageToDensity(image, filter)
{
	if(filter == null)
		filter = false;
	return scaleImageToSize(image, Math.round(image.getWidth() * deviceDensity), Math.round(image.getHeight() * deviceDensity), filter);
}

function scaleImageToSize(image, width, height, filter)
{
	if(filter == null)
		filter = false;
	return android.graphics.Bitmap.createScaledBitmap(image, Math.round(width), Math.round(height), filter);
}
//########## IMAGE functions - END ##########


//########## FILE functions ##########
function deleteFile(path)
{
	var file = new java.io.File(path);

	if(file.isDirectory())
	{
		var directoryFiles = file.listFiles();
		for(var i in directoryFiles)
		{
			deleteFile(directoryFiles[i].getAbsolutePath());
		}
		file.delete();
	}

	if(file.isFile())
		file.delete();
}

function doesFileExist(path)
{
	var file = new java.io.File(path);
	return file.exists();
}

function isFileEmpty(path)
{
	var file = new java.io.File(path);
	if(file.length() > 0)
		return false;
	else
		return true;
}

function writeFileFromByteArray(byteArray, path)
{
	var file = new java.io.File(path);
	if(file.exists())
		file.delete();
	file.createNewFile();
	var stream = new java.io.FileOutputStream(file);
	stream.write(byteArray);
	stream.close();
	byteArray = null;
}
//########## FILE functions - END ##########


//########## UTILS OF UIs functions ##########
function convertDpToPixel(dp)
{
	//
	return Math.round(dp * deviceDensity);
}

function basicMinecraftTextView(text, textSize) // TextView with just the Minecraft font
{
	var textview = new android.widget.TextView(currentActivity);
	textview.setText(new android.text.Html.fromHtml(text));
	if(textSize != null)
		textview.setTextSize(textSize);
	MinecraftButtonLibrary.addMinecraftStyleToTextView(textview);

	return textview;
}

function defaultColoredMinecraftButton(text, colorString)
{
	var padding = convertDpToPixel(4);

	var bg = android.graphics.drawable.GradientDrawable();
	bg.setColor(android.graphics.Color.TRANSPARENT);
	bg.setShape(android.graphics.drawable.GradientDrawable.RECTANGLE);
	bg.setStroke(convertDpToPixel(1), android.graphics.Color.parseColor(colorString));

	var coloredButton = basicMinecraftTextView(text, buttonsSize);
	coloredButton.setGravity(android.view.Gravity.CENTER);
	coloredButton.setTextColor(android.graphics.Color.parseColor(colorString));
	coloredButton.setBackgroundDrawable(bg);
	coloredButton.setPadding(padding, padding, padding, padding);
	coloredButton.setLayoutParams(new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT));

	return coloredButton;
}
//########## UTILS OF UIs functions - END ##########


//########## MISC functions ##########
function getLogText()
{
	//
	return("Portal Mod: ");
}

function stringToBoolean(string)
{
	if(typeof string != "string")
		string = String(string);
	switch(string.toLowerCase())
	{
		case "true":
		case "yes":
		case "1":
			return true;
		case "false":
		case "no":
		case "0":
		case null:
			return false;
		default:
			return Boolean(string);
	}
}

function stringToArray(string)
{
	string = String(string);
	string = string.replace(/ /g, "");

	var stringArray = string.split(",");

	return stringArray;
}

function stringToIntArray(string)
{
	string = String(string);
	string = string.replace(/ /g, "");

	var stringArray = string.split(",");
	var intArray = [];

	for(var i in stringArray)
	{
		var value = parseInt(stringArray[i]);
		if(value > 0)
			intArray.push(value);
	}

	return intArray;
}

function getSavedBoolean(name, defaultValue, debug)
{
	var savedDataTest = ModPE.readData(name);
	debug = debug || false;

	// debug code
	if(DEBUG)
	{
		var debugTest;

		if(typeof savedDataTest == "boolean")
		{
			clientMessage(name + " is bool");
			debugTest = savedDataTest;
		} else
		{
			if(typeof savedDataTest == "string")
			{
				clientMessage(name + " is string");
				debugTest = stringToBoolean(savedDataTest);
			} else
			{
				clientMessage(name + " is " + typeof savedDataTest);
			}
		}

		clientMessage(name + ": " + debugTest);

		if(typeof debugTest == "boolean")
		{
			if(debugTest)
				clientMessage(name + " true");
			else
				clientMessage(name + " false");
		} else
		{
			clientMessage(name + ", something really wrong here!");
		}
	}

	// return the saved boolean
	if(typeof savedDataTest == "boolean")
	{
		return savedDataTest;
	} else
	{
		if(typeof savedDataTest == "string")
		{
			if(savedDataTest != "" && savedDataTest != null && savedDataTest != undefined)
			{
				return stringToBoolean(savedDataTest);
			} else
			{
				// this setting has never been saved.
				if(typeof defaultValue == "boolean")
					return defaultValue;
				else
					return stringToBoolean(defaultValue)
			}
		} else
		{
			clientMessage("Error in getSavedBoolean() for " + name);
			return false;
		}
	}
}

function normalizeAngle(angle)
{
	var newAngle = angle;
	while (newAngle < 0) newAngle += 360;
	while (newAngle > 360) newAngle -= 360;
	return newAngle;
}

function getAngleOfNearBlockId(x, y, z, blockId)
{
	x = Math.floor(x);
	y = Math.floor(y);
	z = Math.floor(z);

	if(Level.getTile(x + 1, y, z) == blockId)
		return 270;
	if(Level.getTile(x, y, z + 1) == blockId)
		return 0;
	if(Level.getTile(x - 1, y, z) == blockId)
		return 90;
	if(Level.getTile(x, y, z - 1) == blockId)
		return 180;

	return null;
}

function DroppedItemClass(entity, id, data)
{
	this.entity = entity;
	this.id = id;
	this.data = data;
	this.previousX = 0;
	this.previousY = 0;
	this.previousZ = 0;
}

function EntityClass(entity)
{
	this.entity = entity;
	this.previousX = 0;
	this.previousY = 0;
	this.previousZ = 0;
}

function PortalClass(x1, y1, z1, x2, y2, z2, type)
{
	this.x1 = Math.floor(x1);
	this.y1 = Math.floor(y1);
	this.z1 = Math.floor(z1);
	this.x2 = Math.floor(x2);
	this.y2 = Math.floor(y2);
	this.z2 = Math.floor(z2);
	this.type = type;
}
//########## MISC functions - END ##########


//########################################################################################################################################################
// Utils of popup's UI functions
//########################################################################################################################################################

const MARGIN_HORIZONTAL_BIG = 16;
const MARGIN_HORIZONTAL_SMALL = 4;

function setMarginsLinearLayout(view, left, top, right, bottom)
{
	var originalParams = view.getLayoutParams();
	var newParams = new android.widget.LinearLayout.LayoutParams(originalParams);
	newParams.setMargins(convertDpToPixel(left), convertDpToPixel(top), convertDpToPixel(right), convertDpToPixel(bottom));
	view.setLayoutParams(newParams);
}

function dividerText()
{
	var dividerText = new android.widget.TextView(currentActivity);
	dividerText.setText(" ");
	return dividerText;
}

function portalDivider()
{
	var dividerImage = new android.widget.ImageView(currentActivity); 			 
 	dividerImage.setImageBitmap(dividerScaled);
 	dividerImage.setAdjustViewBounds(true);
 	return dividerImage;
}

function defaultContentTextView(text) // TextView for contents (basicMinecraftTextView with little changes)
{
	var textview = basicMinecraftTextView(text, 12);
	textview.setTextColor(android.graphics.Color.parseColor(MinecraftButtonLibrary.defaultButtonTextColor));

	return textview;
}

function defaultSubTitle(subtitle) // TextView with Minecraft background
{
	var padding = convertDpToPixel(8);

	var bg = android.graphics.drawable.GradientDrawable();
	bg.setColor(android.graphics.Color.parseColor("#FF736A6F"));
	bg.setShape(android.graphics.drawable.GradientDrawable.RECTANGLE);
	bg.setStroke(convertDpToPixel(2), android.graphics.Color.parseColor("#FF93898B"));

	var title = basicMinecraftTextView(subtitle, 16);
	title.setTextColor(android.graphics.Color.WHITE);
	title.setBackgroundDrawable(bg);
	title.setPadding(padding, padding, padding, padding);

	return title;
}

function defaultLayout(title)
{
	var layout = new android.widget.LinearLayout(currentActivity);
	layout.setOrientation(android.widget.LinearLayout.VERTICAL);
	var padding = convertDpToPixel(8);
	layout.setPadding(padding, padding, padding, padding);
	layout.setBackgroundDrawable(background);

	var titleTextView = basicMinecraftTextView(title, 18);
	titleTextView.setTextColor(android.graphics.Color.WHITE);
	titleTextView.setGravity(android.view.Gravity.CENTER);
	layout.addView(titleTextView);
	setMarginsLinearLayout(titleTextView, 0, 4, 0, 4);

	var divider = new android.view.View(currentActivity);
	divider.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.parseColor("#958681")));
	divider.setLayoutParams(new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, convertDpToPixel(1)));
	layout.addView(divider);
	setMarginsLinearLayout(divider, 0, 8, 0, 8);

	return layout;
}

function defaultPopup(layout)
{
	var scroll = new android.widget.ScrollView(currentActivity);
	scroll.addView(layout);

	var popup = new android.app.Dialog(currentActivity);
	popup.requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
	popup.setContentView(scroll);

	return popup;
}

function showImmersivePopup(popup)
{
	//Set the dialog to not focusable (makes navigation ignore us adding the window)
	// http://stackoverflow.com/questions/22794049/how-to-maintain-the-immersive-mode-in-dialogs
	popup.getWindow().setFlags(android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

	//Show the dialog!
	popup.show();

	//Set the dialog to immersive
	popup.getWindow().getDecorView().setSystemUiVisibility(currentActivity.getWindow().getDecorView().getSystemUiVisibility());

	//Clear the not focusable flag from the window
	popup.getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}


//########################################################################################################################################################
// Popup's UI functions
//########################################################################################################################################################

function infoPortalMod()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout = defaultLayout("P<font color=#1E90FF>O</font>RTAL 2 M<font color=#FFA500>O</font>D");

				var text = defaultContentTextView("欢迎来到传送枪mod");
				layout.addView(text);
				setMarginsLinearLayout(text, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_BIG);

				var informationButton = MinecraftButton();
				informationButton.setText("询问处");
				informationButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						informationUI();
						popup.dismiss();
					}
				});
				layout.addView(informationButton);
				setMarginsLinearLayout(informationButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var settingsButton = MinecraftButton();
				settingsButton.setText("设置");
				settingsButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						settingsUI();
						popup.dismiss();
					}
				});
				layout.addView(settingsButton);
				setMarginsLinearLayout(settingsButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				layout.addView(portalDivider());


				var updatesButton = MinecraftButton();
				updatesButton.setText("检查更新");
				updatesButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						if(latestVersion == CURRENT_VERSION || latestVersion == undefined || latestVersion == " ")
						{
							latestVersionUI();
							popup.dismiss();
						} else
						{
							updateAvailableUI();
						}
					}
				});
				layout.addView(updatesButton);
				setMarginsLinearLayout(updatesButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var modThreadButton = MinecraftButton();
				modThreadButton.setText("访问官网");
				modThreadButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						visitThread();
						popup.dismiss();
					}
				});
				layout.addView(modThreadButton);
				setMarginsLinearLayout(modThreadButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var supportButton = MinecraftButton();
				supportButton.setText("支持开发者");
				supportButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						supportUI();
						popup.dismiss();
					}
				});
				layout.addView(supportButton);
				setMarginsLinearLayout(supportButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				layout.addView(portalDivider());


				var exitButton = MinecraftButton();
				exitButton.setText("关闭");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function informationUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout = defaultLayout("询问处");

				var informationText1 = new android.widget.TextView(currentActivity);
				informationText1.setText(new android.text.Html.fromHtml("<b>§4传送枪:</b>" +
					"<br>-<i>§4传送枪</i>: §4子弹速度：40块/秒，可使用" + PORTAL_GUN_DAMAGE + " times." +
					"<br>-<i>§4传送枪金</i>: §4子弹速度：30块/秒，可使用" + PORTAL_GUN_GOLD_DAMAGE + " times." +
					"<br>-<i>§4传送枪铁</i>: §4子弹速度：20块/秒，可使用" + PORTAL_GUN_IRON_DAMAGE + " times." +
					"<br>-<i>§4传送枪熔岩</i>: §4子弹速度：20块/秒，可使用" + PORTAL_GUN_LAVA_DAMAGE + " times." +
					"<br>-<i>§4传送枪木&石</i>: §4在一个块上点击放置一个传送门。可使用" + PORTAL_GUN_WOOD_AND_STONE_DAMAGE + " times."));
				layout.addView(informationText1);

				layout.addView(portalDivider());

				var informationText2 = new android.widget.TextView(currentActivity);
				informationText2.setText(new android.text.Html.fromHtml("<b>§4其他项目:</b>" +
					"<br>-<i>§4重力枪</i>: §4打一个暴徒与这个项目来挑选它，然后你可以把它带到任何地方或射击它。" +
					"<br>-<i>§4炮塔</i>:§4 产生一个炮塔。" +
					"<br>-<i>§4炮塔故障</i>:§4 产生一个有缺陷的炮塔。" +
					"<br>-<i>§4炮塔选项</i>: §4使用此项来显示选项图形用户界面。" +
					"<br>-<i>§4长靴</i>: §4当你从高处摔下来时，这些靴子会对你造成伤害。" +
					"<br>-<i>§4空中弹射板</i>: §4当你走上这一块，他会做出强有力的跳跃。" + 
					"<br>-<i>§4点唱机</i>: §4用一个光盘点击这个块，它将开始播放选定的歌曲。" +
					'<br>-<i>§4mod电台</i>: §4当你点击这个“无线电波”的时候，它就会停下来，当你从收音机里走的时候，它会停下来（20个街区）。' +
					"<br>-<i>§4立方体</i>: §4立方体。没有做任何特殊的事情。" +
					"<br>-<i>§4同伴立方体</i>: §4同伴立方体。没有做任何特殊的事情。但它爱你。" +
					"<br>-<i>§4排斥凝胶块</i>: §4当玩家站在这座他更强大的跳跃，当他落在它，他将拒绝在空气速度比以前少一点。" +
					"<br>-<i>§4推进凝胶块</i>: §4当你走在这些方块上时，他的加速度将增加。" +
					"<br>如果你想更好的解释如何凝胶工作表 <a href=\"http://youtu.be/32DaEaODKyI\">this YouTube video</a>"));
				informationText2.setMovementMethod(android.text.method.LinkMovementMethod.getInstance());
				layout.addView(informationText2);

				layout.addView(portalDivider());
				
				var informationText3 = new android.widget.TextView(currentActivity);
				informationText3.setText(new android.text.Html.fromHtml("<b>§4提示和技巧:</b>" +
					"<br>-<i>Turrets</i>: §44台一排，他们开始唱\"千本樱(初音未来)\"."));
				layout.addView(informationText3);


				layout.addView(portalDivider());


				var backButton = MinecraftButton();
				backButton.setText("返回");
				backButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						infoPortalMod();
						popup.dismiss();
					}
				});
				layout.addView(backButton);
				setMarginsLinearLayout(backButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var exitButton = MinecraftButton();
				exitButton.setText("关闭");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function settingsUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout = defaultLayout("设置");

				var settingsButton = MinecraftButton();
				settingsButton.setText("一般设置");
				settingsButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						settingsGeneralUI();
						popup.dismiss();
					}
				});
				layout.addView(settingsButton);
				setMarginsLinearLayout(settingsButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var mapMakersSettingsButton = MinecraftButton();
				mapMakersSettingsButton.setText("地图制作者设置");
				mapMakersSettingsButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						settingsMapMakersUI();
						popup.dismiss();
					}
				});
				layout.addView(mapMakersSettingsButton);
				setMarginsLinearLayout(mapMakersSettingsButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				layout.addView(portalDivider());


				var backButton = MinecraftButton();
				backButton.setText("返回");
				backButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						infoPortalMod();
						popup.dismiss();
					}
				});
				layout.addView(backButton);
				setMarginsLinearLayout(backButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);
				
				var exitButton = MinecraftButton();
				exitButton.setText("关闭");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function settingsGeneralUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout;
				layout = defaultLayout("一般设置");

				var padding = convertDpToPixel(8);


				var title = defaultSubTitle("按钮");
				layout.addView(title);

				layout.addView(dividerText());


				var sizeText = new android.widget.TextView(currentActivity);
				sizeText.setText("选择文本按钮的首选大小(默认值 " + BUTTONS_SIZE_DEFAULT + ")");
				sizeText.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				sizeText.setPadding(padding, 0, padding, 0);
				layout.addView(sizeText);

				var sizeChooser = new android.widget.SeekBar(currentActivity);
				sizeChooser.setMax(30);
				sizeChooser.setProgress(buttonsSize - 10);
				sizeChooser.setOnSeekBarChangeListener(new android.widget.SeekBar.OnSeekBarChangeListener()
				{
					onProgressChanged: function()
					{
						buttonsSize = sizeChooser.getProgress() + 10;
						sizeText1.setText("大小: " + buttonsSize + "/" + (sizeChooser.getMax() + 10));
					},
					onStopTrackingTouch: function()
					{
						ModPE.saveData("pref_portal_buttons_size", buttonsSize);
					}
				});
				sizeChooser.setPadding(padding * 2, 0, padding * 2, 0);
				layout.addView(sizeChooser);

				var sizeText1 = new android.widget.TextView(currentActivity);
				sizeText1.setText("Size: " + buttonsSize + "/" + (sizeChooser.getMax() + 10));
				sizeText1.setTextColor(android.graphics.Color.parseColor("#FFC0C0C0"));
				sizeText1.setPadding(padding * 2, 0, padding * 2, 0);
				layout.addView(sizeText1);

				layout.addView(dividerText());


				var imageButtonsSizeText = new android.widget.TextView(currentActivity);
				imageButtonsSizeText.setText("选择mod按钮的首选大小 (默认值 10)");
				imageButtonsSizeText.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				imageButtonsSizeText.setPadding(padding, 0, padding, 0);
				layout.addView(imageButtonsSizeText);

				var imageButtonsSizeChooser = new android.widget.SeekBar(currentActivity);
				imageButtonsSizeChooser.setMax(19);
				imageButtonsSizeChooser.setProgress((imageSize * 10));
				imageButtonsSizeChooser.setOnSeekBarChangeListener(new android.widget.SeekBar.OnSeekBarChangeListener()
				{
					onProgressChanged: function()
					{
						imageSize = (imageButtonsSizeChooser.getProgress() + 1) / 10;
						imageButtonsSizeText1.setText("大小: " + (imageButtonsSizeChooser.getProgress() + 1) + "/" + (imageButtonsSizeChooser.getMax() + 1));
					},
					onStopTrackingTouch: function()
					{
						//clientMessage("size " + imageSize);
						ModPE.saveData("pref_portal_buttons_image_ buttons_size", imageSize);
					}
				});
				imageButtonsSizeChooser.setPadding(padding * 2, 0, padding * 2, 0);
				layout.addView(imageButtonsSizeChooser);

				var imageButtonsSizeText1 = new android.widget.TextView(currentActivity);
				imageButtonsSizeText1.setText("Size: " + (imageSize * 10) + "/" + (imageButtonsSizeChooser.getMax() + 1));
				imageButtonsSizeText1.setTextColor(android.graphics.Color.parseColor("#FFC0C0C0"));
				imageButtonsSizeText1.setPadding(padding * 2, 0, padding * 2, 0);
				layout.addView(imageButtonsSizeText1);

				layout.addView(dividerText());


				var moveButtonsText = new android.widget.TextView(currentActivity);
				moveButtonsText.setText("选择按钮的偏移值 (默认值 0)");
				moveButtonsText.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				moveButtonsText.setPadding(padding, 0, padding, 0);
				layout.addView(moveButtonsText);

				var maxY = (displayHeight / 4 * 3);
				if(maxY % 2 != 0)
					maxY--;
				var moveButtonsChooser = new android.widget.SeekBar(currentActivity);
				moveButtonsChooser.setMax(maxY);
				moveButtonsChooser.setProgress((-pixelsOffsetButtons) + (maxY / 2));
				moveButtonsChooser.setOnSeekBarChangeListener(new android.widget.SeekBar.OnSeekBarChangeListener()
				{
					onProgressChanged: function()
					{
						pixelsOffsetButtons = -(moveButtonsChooser.getProgress() - (maxY / 2));
						moveButtonsText1.setText("位置: " + (-pixelsOffsetButtons) + " 像素");
					},
					onStopTrackingTouch: function()
					{
						ModPE.saveData("pref_portal_y_offset", pixelsOffsetButtons);
					}
				});
				moveButtonsChooser.setPadding(padding * 2, 0, padding * 2, 0);
				layout.addView(moveButtonsChooser);

				var moveButtonsText1 = new android.widget.TextView(currentActivity);
				moveButtonsText1.setText("Y position: " + (-pixelsOffsetButtons) + " pixels");
				moveButtonsText1.setTextColor(android.graphics.Color.parseColor("#FFC0C0C0"));
				moveButtonsText1.setPadding(padding * 2, 0, padding * 2, 0);
				layout.addView(moveButtonsText1);

				layout.addView(dividerText());


				var switchButtonsStyle = new android.widget.Switch(currentActivity);
				switchButtonsStyle.setChecked(minecraftStyleForButtons);
				switchButtonsStyle.setText("使文本按钮成为Minecraft风格");
				switchButtonsStyle.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				switchButtonsStyle.setOnCheckedChangeListener(new android.widget.CompoundButton.OnCheckedChangeListener()
				{
					onCheckedChanged: function()
					{
						minecraftStyleForButtons = !minecraftStyleForButtons;
						ModPE.saveData("pref_portal_buttons_style", minecraftStyleForButtons);
					}
				});
				switchButtonsStyle.setPadding(padding, 0, padding, 0);
				layout.addView(switchButtonsStyle);

				layout.addView(dividerText());



				var title = defaultSubTitle("mod特色");
				layout.addView(title);

				layout.addView(dividerText());


				var switchEntitiesSupportPortals = new android.widget.Switch(currentActivity);
				switchEntitiesSupportPortals.setChecked(entitiesSupportForPortals);
				switchEntitiesSupportPortals.setText("对于mod的暴徒和实体的支持 (会导致非常旧的设备滞后)");
				switchEntitiesSupportPortals.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				switchEntitiesSupportPortals.setOnCheckedChangeListener(new android.widget.CompoundButton.OnCheckedChangeListener()
				{
					onCheckedChanged: function()
					{
						entitiesSupportForPortals = !entitiesSupportForPortals;
						ModPE.saveData("pref_portal_entities_support", entitiesSupportForPortals);
					}
				});
				switchEntitiesSupportPortals.setPadding(padding, 0, padding, 0);
				layout.addView(switchEntitiesSupportPortals);

				layout.addView(dividerText());



				var title = defaultSubTitle("音频");
				layout.addView(title);

				layout.addView(dividerText());


				var audioText = new android.widget.TextView(currentActivity);
				audioText.setText("设置mod的音量 (默认值 " + 10 + ")");
				audioText.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				audioText.setPadding(padding, 0, padding, 0);
				layout.addView(audioText);

				var audioChooser = new android.widget.SeekBar(currentActivity);
				audioChooser.setMax(10);
				audioChooser.setProgress(generalVolume * 10);
				audioChooser.setOnSeekBarChangeListener(new android.widget.SeekBar.OnSeekBarChangeListener()
				{
					onProgressChanged: function()
					{
						generalVolume = audioChooser.getProgress() / 10;
						audioText1.setText("大小: " + audioChooser.getProgress() + "/" + audioChooser.getMax());
					},
					onStopTrackingTouch: function()
					{
						ModPE.saveData("pref_portal_general_volume", generalVolume);
					}
				});
				audioChooser.setPadding(padding * 2, 0, padding * 2, 0);
				layout.addView(audioChooser);

				var audioText1 = new android.widget.TextView(currentActivity);
				audioText1.setText("Volume: " + (generalVolume * 10) + "/" + audioChooser.getMax());
				audioText1.setTextColor(android.graphics.Color.parseColor("#FFC0C0C0"));
				audioText1.setPadding(padding * 2, 0, padding * 2, 0);
				layout.addView(audioText1);

				layout.addView(dividerText());


				var switchWelcomeSound = new android.widget.Switch(currentActivity);
				switchWelcomeSound.setChecked(playWelcomeSoundAtStartup);
				switchWelcomeSound.setText("在启动时播放受欢迎的声音");
				switchWelcomeSound.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				switchWelcomeSound.setOnCheckedChangeListener(new android.widget.CompoundButton.OnCheckedChangeListener()
				{
					onCheckedChanged: function()
					{
						playWelcomeSoundAtStartup = !playWelcomeSoundAtStartup;
						ModPE.saveData("pref_portal_welcome_sound", playWelcomeSoundAtStartup);
					}
				});
				switchWelcomeSound.setPadding(padding, 0, padding, 0);
				layout.addView(switchWelcomeSound);

				layout.addView(dividerText());



				var backButton = MinecraftButton();
				backButton.setText("返回");
				backButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						settingsUI();
						popup.dismiss();
					}
				});
				layout.addView(backButton);
				setMarginsLinearLayout(backButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var exitButton = MinecraftButton();
				exitButton.setText("关闭");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function settingsMapMakersUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout;
				layout = defaultLayout("地图制作者设置");

				var padding = convertDpToPixel(8);


				var text = defaultContentTextView("你在这里改变的每一个选项都保存在你正在玩的地图的文件夹中，你可以在网上分享这个地图，每个人都会得到你选择的选项。");
				layout.addView(text);
				setMarginsLinearLayout(text, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_BIG);


				var title = defaultSubTitle("世界相互作用");
				layout.addView(title);

				layout.addView(dividerText());


				var switchButtonsStyle = new android.widget.Switch(currentActivity);
				switchButtonsStyle.setChecked(indestructibleBlocks);
				switchButtonsStyle.setText("在生存里坚不可摧的方块");
				switchButtonsStyle.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				switchButtonsStyle.setOnCheckedChangeListener(new android.widget.CompoundButton.OnCheckedChangeListener()
				{
					onCheckedChanged: function()
					{
						indestructibleBlocks = !indestructibleBlocks;
						saveMapOptions();
					}
				});
				switchButtonsStyle.setPadding(padding, 0, padding, 0);
				layout.addView(switchButtonsStyle);

				layout.addView(dividerText());


				var switchFullHungerBar = new android.widget.Switch(currentActivity);
				switchFullHungerBar.setChecked(alwaysFullHungerBar);
				switchFullHungerBar.setText("生存不会饥饿");
				switchFullHungerBar.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				switchFullHungerBar.setOnCheckedChangeListener(new android.widget.CompoundButton.OnCheckedChangeListener()
				{
					onCheckedChanged: function()
					{
						alwaysFullHungerBar = !alwaysFullHungerBar;
						fullHungerBarTick = 50;
						saveMapOptions();
					}
				});
				switchFullHungerBar.setPadding(padding, 0, padding, 0);
				layout.addView(switchFullHungerBar);

				layout.addView(dividerText());



				var title = defaultSubTitle("孔径实验室选项");
				layout.addView(title);

				layout.addView(dividerText());

				var apertureLabEquipmentButton = MinecraftButton();
				apertureLabEquipmentButton.setText("获得孔径实验室设备");
				apertureLabEquipmentButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						if(Level.getGameMode() == GameMode.SURVIVAL)
						{
							Player.addItemInventory(JUKEBOX_ID, 4, 0);
							Player.addItemInventory(STILL_ALIVE_DISC_ID, 2, 0);
							Player.addItemInventory(CARA_MIA_ADDIO_DISC_ID, 2, 0);
							Player.addItemInventory(WANT_YOU_GONE_DISC_ID, 2, 0);
							Player.addItemInventory(JUMPER_ITEM_ID, 64, 0);
							Player.addItemInventory(ID_TURRET_OPTIONS, 1, 0);
							Player.addItemInventory(ID_TURRET, 64, 0);
							Player.addItemInventory(ID_TURRET_DEFECTIVE, 64, 0);
							Player.addItemInventory(RADIO_ID, 64, 0);
							Player.addItemInventory(REPULSION_GEL_ID, 64, 0);
							Player.addItemInventory(PROPULSION_GEL_ID, 64, 0);
							Player.addItemInventory(CUBE_NORMAL_ID, 64, 0);
							Player.addItemInventory(CUBE_COMPANION_ID, 64, 0);
							Player.addItemInventory(LONG_FALL_BOOTS_ID, 1, 0);
							Player.addItemInventory(PORTAL_GUN_BLUE_ID, 1, 0);
							Player.addItemInventory(GRAVITY_GUN_ID, 1, 0);
							android.widget.Toast.makeText(currentActivity,"Equipment added to the inventory.",0).show();
						} else
						{
							android.widget.Toast.makeText(currentActivity,"The equipment is useful only when playing in survival",0).show();
						}
					}
				});
				layout.addView(apertureLabEquipmentButton);
				setMarginsLinearLayout(apertureLabEquipmentButton, MARGIN_HORIZONTAL_BIG, 0, MARGIN_HORIZONTAL_BIG, 0);

				layout.addView(dividerText());



				var title = defaultSubTitle("选黑名单");
				layout.addView(title);

				layout.addView(dividerText());


				var pickBlacklistText = new android.widget.TextView(currentActivity);
				pickBlacklistText.setText("类型，玩家不能与gravitygun或portalgun跳块的ID (默认值: " + REPULSION_GEL_ID + ", " + PROPULSION_GEL_ID + ", " + JUMPER_ID + ", " + JUMPER_DIRECTION_ID + ")");
				pickBlacklistText.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				pickBlacklistText.setPadding(padding, 0, padding, 0);
				layout.addView(pickBlacklistText);

				var layoutH = new android.widget.LinearLayout(currentActivity);
				layoutH.setOrientation(android.widget.LinearLayout.HORIZONTAL);
				layoutH.setPadding(padding * 2, 0, padding * 2, 0);

				var inputText1 = new android.widget.EditText(currentActivity);
				inputText1.setHint("Example: " + REPULSION_GEL_ID + ", " + PROPULSION_GEL_ID + ", " + JUMPER_ID + ", " + JUMPER_DIRECTION_ID);
				inputText1.setText(pickBlocksBlacklist.toString());
				inputText1.setLayoutParams(new android.widget.LinearLayout.LayoutParams(0, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 7));
				layoutH.addView(inputText1);

				var button1 = MinecraftButton();
				button1.setText("保存");
				button1.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						pickBlocksBlacklist = stringToIntArray(String(inputText1.getText()));
						saveMapOptions();
						android.widget.Toast.makeText(currentActivity, new android.text.Html.fromHtml("Saved blacklist " + pickBlocksBlacklist.toString()), 1).show();
					}
				});
				button1.setLayoutParams(new android.widget.LinearLayout.LayoutParams(0, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 3));
				layoutH.addView(button1);

				layout.addView(layoutH);

				layout.addView(dividerText());



				var backButton = MinecraftButton();
				backButton.setText("返回");
				backButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						settingsUI();
						popup.dismiss();
					}
				});
				layout.addView(backButton);
				setMarginsLinearLayout(backButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var exitButton = MinecraftButton();
				exitButton.setText("关闭");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function latestVersionUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout;
				layout = defaultLayout("最新的版本");

				var updatesText = defaultContentTextView("你有最新版本的传送枪mod<br><br>" +
					"下载的应用程序收到更新通知和得到我的插件的最新消息。");
				layout.addView(updatesText);
				setMarginsLinearLayout(updatesText, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_BIG);

				var playStoreView = new android.widget.ImageView(currentActivity);
				playStoreView.setImageBitmap(playStorePngScaled);
				playStoreView.setOnClickListener(new android.view.View.OnClickListener(
				{
					onClick: function()
					{
						try
						{
							//play store installed
							currentActivity.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse("market://details?id=" + "com.desno365.mods")));
						} catch (err)
						{
							//play store not installed
							currentActivity.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse("http://play.google.com/store/apps/details?id=" + "com.desno365.mods")));
						}
					}
				}));
				layout.addView(playStoreView);
				setMarginsLinearLayout(playStoreView, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_BIG);



				var backButton = MinecraftButton();
				backButton.setText("返回");
				backButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						infoPortalMod();
						popup.dismiss();
					}
				});
				layout.addView(backButton);
				setMarginsLinearLayout(backButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var exitButton = MinecraftButton();
				exitButton.setText("Close");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function updateAvailableUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout;
				layout = defaultLayout("Portal Mod: new version");

				var updatesText = defaultContentTextView("New version available, you have the " + CURRENT_VERSION + " version and the latest version is " + latestVersion + ".<br>" +
					"You can find a download link on Desno365's website (press the button to visit it).");
				layout.addView(updatesText);
				setMarginsLinearLayout(updatesText, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var threadButton = MinecraftButton();
				threadButton.setText("Visit website");
				threadButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						var intentBrowser = new android.content.Intent(currentActivity);
						intentBrowser.setAction(android.content.Intent.ACTION_VIEW);
						intentBrowser.setData(android.net.Uri.parse("http://desno365.github.io/minecraft/portal2-mod/"));
						currentActivity.startActivity(intentBrowser);
						popup.dismiss();
					}
				});
				layout.addView(threadButton);
				setMarginsLinearLayout(threadButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_BIG);

				var exitButton = MinecraftButton();
				exitButton.setText("Close");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				popup.setCanceledOnTouchOutside(false);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function visitThread()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var intentBrowser = new android.content.Intent(currentActivity);
				intentBrowser.setAction(android.content.Intent.ACTION_VIEW);
				intentBrowser.setData(android.net.Uri.parse("http://www.minecraftforum.net/forums/minecraft-pocket-edition/mcpe-mods-tools/2097326-mod-beta-portal-2-mod-portal-gun-r010-by-desno365"));
				currentActivity.startActivity(intentBrowser);
			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function supportUI()
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout;
				layout = defaultLayout("Support me");

				var text = defaultContentTextView("这个mod是葫芦侠给你带来的 :)<br>谢谢使用.");
				layout.addView(text);
				setMarginsLinearLayout(text, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var button1 = MinecraftButton();
				button1.setText("葫芦侠不玩推特");
				button1.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						var intentBrowser = new android.content.Intent(currentActivity);
						intentBrowser.setAction(android.content.Intent.ACTION_VIEW);
						intentBrowser.setData(android.net.Uri.parse("https://twitter.com/desno365"));
						currentActivity.startActivity(intentBrowser);
						popup.dismiss();
					}
				});
				layout.addView(button1);
				setMarginsLinearLayout(button1, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var button2 = MinecraftButton();
				button2.setText("订阅我的YouTube频道");
				button2.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						var intentBrowser = new android.content.Intent(currentActivity);
						intentBrowser.setAction(android.content.Intent.ACTION_VIEW);
						intentBrowser.setData(android.net.Uri.parse("http://www.youtube.com/channel/UCJQL47nQnsijcaN_7pMsjCQ/videos"));
						currentActivity.startActivity(intentBrowser);
						popup.dismiss();
					}
				});
				layout.addView(button2);
				setMarginsLinearLayout(button2, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_BIG);


				var backButton = MinecraftButton();
				backButton.setText("返回");
				backButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						infoPortalMod();
						popup.dismiss();
					}
				});
				layout.addView(backButton);
				setMarginsLinearLayout(backButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				var exitButton = MinecraftButton();
				exitButton.setText("关闭");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
				clientMessage("Maybe GUI is not supported for your device.");
			}
		}
	});
}

function turretOptionsUI(i)
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout;
				layout = defaultLayout("Turret options");

				var padding = convertDpToPixel(8);



				var switchAggressive = new android.widget.Switch(currentActivity);
				switchAggressive.setChecked(turrets[i].aggressive);
				switchAggressive.setText("Aggressive turret");
				switchAggressive.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				switchAggressive.setOnCheckedChangeListener(new android.widget.CompoundButton.OnCheckedChangeListener()
				{
					onCheckedChanged: function()
					{
						new android.os.Handler().postDelayed(new java.lang.Runnable(
						{
							run: function()
							{
								if(isInGame)
								{
									try
									{
										turrets[i].aggressive = !turrets[i].aggressive;
										Entity.setRenderType(turrets[i].entity, TurretRenderType.renderType);
										
										saveCustomMobs();
									} catch(e) {}
								}
							}
						}), 800);

						new android.os.Handler().postDelayed(new java.lang.Runnable(
						{
							run: function()
							{
								popup.dismiss();
							}
						}), 300);
					}
				});
				switchAggressive.setPadding(padding, 0, padding, 0);
				MinecraftButtonLibrary.addMinecraftStyleToTextView(switchAggressive);
				layout.addView(switchAggressive);

				layout.addView(dividerText());


				var removeButton = MinecraftButton(null, null, "#FF0000");
				removeButton.setText("Remove turret");
				removeButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						Entity.remove(turrets[i].entity);

						var random = Math.floor((Math.random() * 9) + 1);
						turrets[i].playSound("portal-sounds/turrets/turret_disabled_" + random + ".mp3");

						customMobs.splice(findPositionInCustomMobs(turrets[i].entity), 1);
						turrets.splice(i, 1);

						saveCustomMobs();
						
						if(areTurretsSinging)
							turretsStopSinging();

						popup.dismiss();
					}
				});
				layout.addView(removeButton);
				setMarginsLinearLayout(removeButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				layout.addView(dividerText());



				var exitButton = MinecraftButton();
				exitButton.setText("Close");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

function turretDefectiveOptionsUI(i)
{
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout;
				layout = defaultLayout("Turret options");

				var padding = convertDpToPixel(8);



				var switchAggressive = new android.widget.Switch(currentActivity);
				switchAggressive.setChecked(turretsDefective[i].aggressive);
				switchAggressive.setText("Aggressive turret");
				switchAggressive.setTextColor(android.graphics.Color.parseColor("#FFFFFFFF"));
				switchAggressive.setOnCheckedChangeListener(new android.widget.CompoundButton.OnCheckedChangeListener()
				{
					onCheckedChanged: function()
					{
						new android.os.Handler().postDelayed(new java.lang.Runnable(
						{
							run: function()
							{
								if(isInGame)
								{
									try
									{
										turretsDefective[i].aggressive = !turretsDefective[i].aggressive;
										Entity.setRenderType(turretsDefective[i].entity, TurretRenderType.renderType);
										
										saveCustomMobs();
									} catch(e) { }
								}
							}
						}), 800);

						new android.os.Handler().postDelayed(new java.lang.Runnable(
						{
							run: function()
							{
								popup.dismiss();
							}
						}), 300);
					}
				});
				switchAggressive.setPadding(padding, 0, padding, 0);
				MinecraftButtonLibrary.addMinecraftStyleToTextView(switchAggressive);
				layout.addView(switchAggressive);

				layout.addView(dividerText());


				var removeButton = MinecraftButton(null, null, "#FF0000");
				removeButton.setText("Remove turret");
				removeButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						Entity.remove(turretsDefective[i].entity);

						var random = Math.floor((Math.random() * 7) + 1);
						turretsDefective[i].playSound("portal-sounds/turrets_defective/turret_defective_disabled_" + random + ".wav");

						customMobs.splice(findPositionInCustomMobs(turretsDefective[i].entity), 1);
						turretsDefective.splice(i, 1);
						
						saveCustomMobs();

						popup.dismiss();
					}
				});
				layout.addView(removeButton);
				setMarginsLinearLayout(removeButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);

				layout.addView(dividerText());



				var exitButton = MinecraftButton();
				exitButton.setText("Close");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						popup.dismiss();
					}
				});
				layout.addView(exitButton);
				setMarginsLinearLayout(exitButton, 0, MARGIN_HORIZONTAL_SMALL, 0, MARGIN_HORIZONTAL_SMALL);


				var popup = defaultPopup(layout);
				showImmersivePopup(popup);

			} catch(err)
			{
				clientMessage("Error: " + err);
			}
		}
	});
}

// No Minecraft Layout because this UI can be showed at startup
function pleaseInstallTextureUI()
{
	textureUiShowed = true;
	currentActivity.runOnUiThread(new java.lang.Runnable()
	{
		run: function()
		{
			try
			{
				var layout = new android.widget.LinearLayout(currentActivity);
				var padding = convertDpToPixel(8);
				layout.setPadding(padding, padding, padding, padding);
				layout.setOrientation(android.widget.LinearLayout.VERTICAL);

				var scroll = new android.widget.ScrollView(currentActivity);
				scroll.addView(layout);

				var popup = new android.app.Dialog(currentActivity);
				popup.setContentView(scroll);
				popup.setTitle(new android.text.Html.fromHtml("Texture not installed"));
				popup.setCanceledOnTouchOutside(false);

				var text = new android.widget.TextView(currentActivity);
				text.setText(new android.text.Html.fromHtml("Seems that you haven't installed the Portal 2 Mod texture pack.<br><br>Please install the Texture Pack of the mod and <b>restart BlockLauncher</b> to enjoy all the features of the Portal 2 Mod."));
				layout.addView(text);

				layout.addView(dividerText());

				var exitButton = new android.widget.Button(currentActivity);
				exitButton.setText("OK");
				exitButton.setOnClickListener(new android.view.View.OnClickListener()
				{
					onClick: function()
					{
						textureUiShowed = false;
						popup.dismiss();
					}
				});
				layout.addView(exitButton);


				showImmersivePopup(popup);

			} catch(err)
			{
				print("Error: " + err);
			}
		}
	});
}


//########################################################################################################################################################
// Render
//########################################################################################################################################################

function addTurretRenderType(renderer)
{
	var model = renderer.getModel();

	var head = model.getPart("head");
	var body = model.getPart("body");
	var rArm = model.getPart("rightArm");
	var lArm = model.getPart("leftArm");
	var rLeg = model.getPart("rightLeg");
	var lLeg = model.getPart("leftLeg");

	var yOffset = 6;

	head.clear();

	body.clear();
	body.setTextureOffset(25,15);
	body.addBox(0,0 + yOffset,0,3,11,6);
	body.setTextureOffset(54,0);	
	body.addBox(-1,1 + yOffset,1,1,9,4);
	body.setTextureOffset(54,0);	
	body.addBox(3,1 + yOffset,1,1,9,4);
	body.setTextureOffset(44,30);	
	body.addBox(1,5 + yOffset,-0.5,1,1,1);

	// leg
	body.setTextureOffset(49,17);
	body.addBox(3,10 + yOffset,3,1,2,1);
	body.setTextureOffset(49,17);
	body.addBox(3,12 + yOffset,0,1,1,4);
	body.setTextureOffset(25,21);
	body.addBox(2.5,12 + yOffset,-3,2,1,3);
	body.setTextureOffset(49,17);
	body.addBox(3,13 + yOffset,-3,1,6,1);

	// leg
	body.setTextureOffset(49,17);
	body.addBox(-1,10 + yOffset,3,1,2,1);
	body.setTextureOffset(49,17);
	body.addBox(-1,12 + yOffset,0,1,1,4);
	body.setTextureOffset(25,21);
	body.addBox(-1.5,12 + yOffset,-3,2,1,3);
	body.setTextureOffset(49,17);
	body.addBox(-1,13 + yOffset,-3,1,6,1);

	// arm
	body.setTextureOffset(49,17);
	body.addBox(1,11 + yOffset,5,1,1,5);
	body.setTextureOffset(25,21);
	body.addBox(0.5,10 + yOffset,6,2,1,4);
	body.setTextureOffset(49,17);
	body.addBox(1,11 + yOffset,9,1,8,1);

	lLeg.clear();
	rLeg.clear();
	rArm.clear();
	lArm.clear();
}
var TurretRenderType = Renderer.createHumanoidRenderer();
addTurretRenderType(TurretRenderType);

function addTurretLaserRenderType(renderer)
{
	var model = renderer.getModel();

	var head = model.getPart("head");
	var body = model.getPart("body");
	var rArm = model.getPart("rightArm");
	var lArm = model.getPart("leftArm");
	var rLeg = model.getPart("rightLeg");
	var lLeg = model.getPart("leftLeg");

	var yOffset = 6;

	head.clear();

	body.clear();
	body.setTextureOffset(25,15);
	body.addBox(0,0 + yOffset,0,3,11,6);
	body.setTextureOffset(54,0);	
	body.addBox(-1,1 + yOffset,1,1,9,4);
	body.setTextureOffset(54,0);	
	body.addBox(3,1 + yOffset,1,1,9,4);
	for(var i = 0; i < 160; i++)
	{
		body.setTextureOffset(44,30);	
		body.addBox(1,5 + yOffset,0 - i,1,1,1);
	}

	// leg
	body.setTextureOffset(49,17);
	body.addBox(3,10 + yOffset,3,1,2,1);
	body.setTextureOffset(49,17);
	body.addBox(3,12 + yOffset,0,1,1,4);
	body.setTextureOffset(25,21);
	body.addBox(2.5,12 + yOffset,-3,2,1,3);
	body.setTextureOffset(49,17);
	body.addBox(3,13 + yOffset,-3,1,6,1);

	// leg
	body.setTextureOffset(49,17);
	body.addBox(-1,10 + yOffset,3,1,2,1);
	body.setTextureOffset(49,17);
	body.addBox(-1,12 + yOffset,0,1,1,4);
	body.setTextureOffset(25,21);
	body.addBox(-1.5,12 + yOffset,-3,2,1,3);
	body.setTextureOffset(49,17);
	body.addBox(-1,13 + yOffset,-3,1,6,1);

	// arm
	body.setTextureOffset(49,17);
	body.addBox(1,11 + yOffset,5,1,1,5);
	body.setTextureOffset(25,21);
	body.addBox(0.5,10 + yOffset,6,2,1,4);
	body.setTextureOffset(49,17);
	body.addBox(1,11 + yOffset,9,1,8,1);

	lLeg.clear();
	rLeg.clear();
	rArm.clear();
	lArm.clear();
}
var TurretLaserRenderType = Renderer.createHumanoidRenderer();
addTurretLaserRenderType(TurretLaserRenderType);

function addTurretShooting1RenderType(renderer)
{
	var model = renderer.getModel();

	var head = model.getPart("head");
	var body = model.getPart("body");
	var rArm = model.getPart("rightArm");
	var lArm = model.getPart("leftArm");
	var rLeg = model.getPart("rightLeg");
	var lLeg = model.getPart("leftLeg");

	var yOffset = 6;

	head.clear();

	body.clear();
	body.setTextureOffset(25,15);
	body.addBox(0,0 + yOffset,0,3,11,6);

	body.setTextureOffset(49,17);
	body.addBox(-1,4 + yOffset,2,1,1,2);
	body.setTextureOffset(49,17);
	body.addBox(3,4 + yOffset,2,1,1,2);
	body.setTextureOffset(51,19);
	body.addBox(-1,6 + yOffset,2,1,1,2);
	body.setTextureOffset(51,19);
	body.addBox(3,6 + yOffset,2,1,1,2);

	body.setTextureOffset(54,0);	
	body.addBox(-2,1 + yOffset,1,1,9,4);
	body.setTextureOffset(54,0);	
	body.addBox(4,1 + yOffset,1,1,9,4);
	body.setTextureOffset(44,30);	
	body.addBox(1,5 + yOffset,-0.5,1,1,1);

	// leg
	body.setTextureOffset(49,17);
	body.addBox(3,10 + yOffset,3,1,2,1);
	body.setTextureOffset(49,17);
	body.addBox(3,12 + yOffset,0,1,1,4);
	body.setTextureOffset(25,21);
	body.addBox(2.5,12 + yOffset,-3,2,1,3);
	body.setTextureOffset(49,17);
	body.addBox(3,13 + yOffset,-3,1,6,1);

	// leg
	body.setTextureOffset(49,17);
	body.addBox(-1,10 + yOffset,3,1,2,1);
	body.setTextureOffset(49,17);
	body.addBox(-1,12 + yOffset,0,1,1,4);
	body.setTextureOffset(25,21);
	body.addBox(-1.5,12 + yOffset,-3,2,1,3);
	body.setTextureOffset(49,17);
	body.addBox(-1,13 + yOffset,-3,1,6,1);

	// arm
	body.setTextureOffset(49,17);
	body.addBox(1,11 + yOffset,5,1,1,5);
	body.setTextureOffset(25,21);
	body.addBox(0.5,10 + yOffset,6,2,1,4);
	body.setTextureOffset(49,17);
	body.addBox(1,11 + yOffset,9,1,8,1);

	lLeg.clear();
	rLeg.clear();
	rArm.clear();
	lArm.clear();
}
var TurretShooting1RenderType = Renderer.createHumanoidRenderer();
addTurretShooting1RenderType(TurretShooting1RenderType);

function addTurretShooting2RenderType(renderer)
{
	var model = renderer.getModel();

	var head = model.getPart("head");
	var body = model.getPart("body");
	var rArm = model.getPart("rightArm");
	var lArm = model.getPart("leftArm");
	var rLeg = model.getPart("rightLeg");
	var lLeg = model.getPart("leftLeg");

	var yOffset = 6;

	head.clear();

	body.clear();
	body.setTextureOffset(25,15);
	body.addBox(0,0 + yOffset,0,3,11,6);

	body.setTextureOffset(49,17);
	body.addBox(-2,4 + yOffset,2,2,1,2);
	body.setTextureOffset(49,17);
	body.addBox(3,4 + yOffset,2,2,1,2);
	body.setTextureOffset(51,19);
	body.addBox(-2,6 + yOffset,2,2,1,2);
	body.setTextureOffset(51,19);
	body.addBox(3,6 + yOffset,2,2,1,2);

	body.setTextureOffset(54,0);	
	body.addBox(-3,1 + yOffset,1,1,9,4);
	body.setTextureOffset(54,0);	
	body.addBox(5,1 + yOffset,1,1,9,4);
	body.setTextureOffset(44,30);	
	body.addBox(1,5 + yOffset,-0.5,1,1,1);

	// leg
	body.setTextureOffset(49,17);
	body.addBox(3,10 + yOffset,3,1,2,1);
	body.setTextureOffset(49,17);
	body.addBox(3,12 + yOffset,0,1,1,4);
	body.setTextureOffset(25,21);
	body.addBox(2.5,12 + yOffset,-3,2,1,3);
	body.setTextureOffset(49,17);
	body.addBox(3,13 + yOffset,-3,1,6,1);

	// leg
	body.setTextureOffset(49,17);
	body.addBox(-1,10 + yOffset,3,1,2,1);
	body.setTextureOffset(49,17);
	body.addBox(-1,12 + yOffset,0,1,1,4);
	body.setTextureOffset(25,21);
	body.addBox(-1.5,12 + yOffset,-3,2,1,3);
	body.setTextureOffset(49,17);
	body.addBox(-1,13 + yOffset,-3,1,6,1);

	// arm
	body.setTextureOffset(49,17);
	body.addBox(1,11 + yOffset,5,1,1,5);
	body.setTextureOffset(25,21);
	body.addBox(0.5,10 + yOffset,6,2,1,4);
	body.setTextureOffset(49,17);
	body.addBox(1,11 + yOffset,9,1,8,1);

	lLeg.clear();
	rLeg.clear();
	rArm.clear();
	lArm.clear();
}
var TurretShooting2RenderType = Renderer.createHumanoidRenderer();
addTurretShooting2RenderType(TurretShooting2RenderType);


//########################################################################################################################################################
// Sounds installation
//########################################################################################################################################################

var SoundsInstaller = {
	sounds:
	{
		version: 1,
		soundArray: [
			// { fileName: "" },
			// { fileName: "", fileDirectory: "" },

			{
				fileName: "game-entry1.mp3"
			},
			{
				fileName: "player_bounce_jump_paint_01.mp3",
				fileDirectory: "gelblue"
			},
			{
				fileName: "player_bounce_jump_paint_02.mp3",
				fileDirectory: "gelblue"
			},
			{
				fileName: "drop.ogg",
				fileDirectory: "gravitygun"
			},
			{
				fileName: "equip.ogg",
				fileDirectory: "gravitygun"
			},
			{
				fileName: "fail.ogg",
				fileDirectory: "gravitygun"
			},
			{
				fileName: "fire.ogg",
				fileDirectory: "gravitygun"
			},
			{
				fileName: "pickup.ogg",
				fileDirectory: "gravitygun"
			},
			{
				fileName: "alyx_gun_fire4.mp3",
				fileDirectory: "jumper"
			},
			{
				fileName: "alyx_gun_fire5.mp3",
				fileDirectory: "jumper"
			},
			{
				fileName: "alyx_gun_fire6.mp3",
				fileDirectory: "jumper"
			},
			{
				fileName: "futureshoes1.mp3",
				fileDirectory: "long_fall_boots"
			},
			{
				fileName: "futureshoes2.mp3",
				fileDirectory: "long_fall_boots"
			},
			{
				fileName: "portalgun_powerup1.mp3",
				fileDirectory: "portalgun"
			},
			{
				fileName: "portalgun_shoot_blue1.mp3",
				fileDirectory: "portalgun"
			},
			{
				fileName: "portalgun_shoot_red1.mp3",
				fileDirectory: "portalgun"
			},
			{
				fileName: "portal_exit1.mp3",
				fileDirectory: "portals"
			},
			{
				fileName: "portal_exit2.mp3",
				fileDirectory: "portals"
			},
			{
				fileName: "portal_invalid_surface.mp3",
				fileDirectory: "portals"
			},
			{
				fileName: "portal_open1.mp3",
				fileDirectory: "portals"
			},
			{
				fileName: "portal_open2.mp3",
				fileDirectory: "portals"
			},
			{
				fileName: "portal_open3.mp3",
				fileDirectory: "portals"
			},
			{
				fileName: "looping_radio_mix.mp3",
				fileDirectory: "radio"
			},
			{
				fileName: "turret_active_1.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_active_2.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_active_3.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_active_4.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_active_5.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_active_6.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_active_7.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_active_8.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_active_9.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_1.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_2.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_3.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_4.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_5.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_6.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_7.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_8.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_disabled_9.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_launched_1.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_launched_2.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_launched_3.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_launched_4.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_launched_5.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_launched_6.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_launched_7.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_launched_8.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_1.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_2.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_3.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_4.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_5.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_6.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_7.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_8.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_9.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_pickup_10.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_search_1.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_search_2.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_search_3.mp3",
				fileDirectory: "turrets"
			},
			{
				fileName: "turret_defective_after_shoot_1.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_2.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_3.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_4.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_5.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_6.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_7.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_8.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_9.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_10.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_11.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_12.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_13.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_14.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_15.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_16.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_17.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_18.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_19.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_after_shoot_20.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_disabled_1.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_disabled_2.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_disabled_3.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_disabled_4.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_disabled_5.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_disabled_6.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_disabled_7.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_pickup_1.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_pickup_2.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_pickup_3.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_pickup_4.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_shoot_1.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_shoot_2.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_shoot_3.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_shoot_4.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_shoot_5.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_1.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_2.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_3.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_4.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_5.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_6.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_7.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_8.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_9.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_10.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_11.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_12.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_13.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_14.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_15.wav",
				fileDirectory: "turrets_defective"
			},
			{
				fileName: "turret_defective_spawn_16.wav",
				fileDirectory: "turrets_defective"
			},
		]
	},

	progressDialog: null,

	versionFileName: "version.txt",


	checkAtStartup: function()
	{
		ModPE.log(getLogText() + "checkAtStartup(): started check.");

		if(SoundsInstaller.needsInstallation())
		{
			if(DEBUG)
				print("Portal 2 Debug: checkAtStartup(): sounds NOT correctly installed!");

			SoundsInstaller.installUI();
		} else
		{
			if(DEBUG)
				print("Portal 2 Debug: checkAtStartup(): sounds correctly installed.");
			ModPE.log(getLogText() + "checkAtStartup(): sounds correctly installed.");
		}
	},


	needsInstallation: function()
	{
		if(doesFileExist(sdcard + "/games/com.mojang/portal-sounds/" + SoundsInstaller.versionFileName))
		{
			var versionOfSounds = SoundsInstaller.getInstalledVersion();
			ModPE.log(getLogText() + "needsInstallation(): version file found, version: " + versionOfSounds);

			// check version
			if(versionOfSounds == SoundsInstaller.sounds.version)
			{
				ModPE.log(getLogText() + "needsInstallation(): version of the file matches saved version.");
				return !SoundsInstaller.areSoundsPresent();
			} else
			{
				ModPE.log(getLogText() + "needsInstallation(): version of the file is different than saved version.");
				return true;
			}
		} else
		{
			ModPE.log(getLogText() + "needsInstallation(): version file not found.");
			return true;
		}
	},

	getInstalledVersion: function()
	{
		var versionFile = new java.io.File(sdcard + "/games/com.mojang/portal-sounds/" + SoundsInstaller.versionFileName);
		if(versionFile.exists())
		{
			var loadedVersion = "";
			var streamVersionInput = new java.io.FileInputStream(versionFile);
			var bufferedVersionReader = new java.io.BufferedReader(new java.io.InputStreamReader(streamVersionInput));
			var rowVersion = "";
			while((rowVersion = bufferedVersionReader.readLine()) != null)
			{
				loadedVersion += rowVersion;
			}
			var loadedVersion = loadedVersion.split(" ");
			bufferedVersionReader.close();

			ModPE.log(getLogText() + "getInstalledVersion(): text on the version file: " + loadedVersion);
			return parseInt(loadedVersion);
		} else
		{
			print("Bug found: remember that getInstalledVersion() should be used only when version file exists.");
			return -1;
		}
	},

	areSoundsPresent: function()
	{
		var arrayOfMissingSounds = SoundsInstaller.checkMissingSounds();

		if(arrayOfMissingSounds.length == 0)
		{
			// yeah, all sounds needed have been found
			ModPE.log(getLogText() + "areSoundsPresent(): all sounds present.");
			return true;
		} else
		{
			// not correctly installed :(
			ModPE.log(getLogText() + "areSoundsPresent(): some sounds are missing.");
			ModPE.log(getLogText() + "areSoundsPresent(): missing: " + arrayOfMissingSounds.toString());
			return false;
		}
	},

	checkMissingSounds: function()
	{
		var tmpPath = sdcard + "/games/com.mojang/portal-sounds/";
		var arrayOfErrors = [];
		for(var i in SoundsInstaller.sounds.soundArray)
		{
			if(SoundsInstaller.sounds.soundArray[i].fileDirectory == undefined || SoundsInstaller.sounds.soundArray[i].fileDirectory == null)
			{
				// file is inside the general sound folder
				if(!doesFileExist(tmpPath + SoundsInstaller.sounds.soundArray[i].fileName))
				{
					if(arrayOfErrors.indexOf(SoundsInstaller.sounds.soundArray[i].fileName) == -1)
						arrayOfErrors.push(SoundsInstaller.sounds.soundArray[i].fileName);
				} else
				{
					// file exists, maybe is empty?
					if(isFileEmpty(tmpPath + SoundsInstaller.sounds.soundArray[i].fileName))
					{
						if(arrayOfErrors.indexOf(SoundsInstaller.sounds.soundArray[i].fileName) == -1)
							arrayOfErrors.push(SoundsInstaller.sounds.soundArray[i].fileName);
					}
				}
			} else
			{
				// file is inside another folder
				if(!doesFileExist(tmpPath + SoundsInstaller.sounds.soundArray[i].fileDirectory + "/" + SoundsInstaller.sounds.soundArray[i].fileName))
				{
					if(arrayOfErrors.indexOf(SoundsInstaller.sounds.soundArray[i].fileName) == -1)
						arrayOfErrors.push(SoundsInstaller.sounds.soundArray[i].fileName);
				} else
				{
					// file exists, maybe is empty?
					if(isFileEmpty(tmpPath + SoundsInstaller.sounds.soundArray[i].fileDirectory + "/" + SoundsInstaller.sounds.soundArray[i].fileName))
					{
						if(arrayOfErrors.indexOf(SoundsInstaller.sounds.soundArray[i].fileName) == -1)
							arrayOfErrors.push(SoundsInstaller.sounds.soundArray[i].fileName);
					}
				}
			}
		}

		return arrayOfErrors;
	},


	installUI: function()
	{
		currentActivity.runOnUiThread(new java.lang.Runnable()
		{
			run: function()
			{
				try
				{
					ModPE.log(getLogText() + "installUI(): displayed installation for sounds UI.");

					var layout = new android.widget.LinearLayout(currentActivity);
					layout.setOrientation(android.widget.LinearLayout.VERTICAL);
					var padding = convertDpToPixel(8);
					layout.setPadding(padding, padding, padding, padding);

					var scroll = new android.widget.ScrollView(currentActivity);
					scroll.addView(layout);

					var popup = new android.app.AlertDialog.Builder(currentActivity);
					popup.setView(scroll);
					popup.setTitle("Download sounds?");

					var helpTextInstallation = new android.widget.TextView(currentActivity);
					helpTextInstallation.setText(android.text.Html.fromHtml("<br>Would you like to download and install Portal 2 Mod sounds now?<br><br>" +
						"A total of approximately 3 MB of data will be saved on your internal storage.<br>" +
						"The installation may take up to one minute.<br><br>" +
						"An active Internet connection is needed to install sounds.<br>"));
					layout.addView(helpTextInstallation);

					popup.setPositiveButton("Install", new android.content.DialogInterface.OnClickListener()
					{
						onClick: function(viewarg)
						{
							SoundsInstaller.installingUI();
							ModPE.log(getLogText() + "installUI(): Sounds installation started by the user.");
						}
					});

					popup.setNegativeButton("Cancel", new android.content.DialogInterface.OnClickListener()
					{
						onClick: function(viewarg)
						{
							android.widget.Toast.makeText(currentActivity, new android.text.Html.fromHtml("<b>Portal 2</b>: Some features may not work properly without sounds."), android.widget.Toast.LENGTH_LONG).show();
							ModPE.log(getLogText() + "installUI(): Sounds installation canceled.");
						}
					});


					var alertDialog = popup.create();
					alertDialog.setCanceledOnTouchOutside(false);
					alertDialog.show();

				} catch(err)
				{
					print("Error: " + err);
				}
			}
		});
	},

	installingUI: function()
	{
		currentActivity.runOnUiThread(new java.lang.Runnable()
		{
			run: function()
			{
				try
				{
					SoundsInstaller.progressDialog = new android.app.ProgressDialog(currentActivity);
					SoundsInstaller.progressDialog.setTitle("Downloading...");
					SoundsInstaller.progressDialog.setMessage("Downloading sound 1 of " + SoundsInstaller.sounds.soundArray.length);
					SoundsInstaller.progressDialog.setProgressStyle(android.app.ProgressDialog.STYLE_HORIZONTAL);
					SoundsInstaller.progressDialog.setCancelable(false);
					SoundsInstaller.progressDialog.setCanceledOnTouchOutside(false);
					SoundsInstaller.progressDialog.setIndeterminate(false);
					SoundsInstaller.progressDialog.setMax(SoundsInstaller.sounds.soundArray.length);
					SoundsInstaller.progressDialog.setProgress(0);
					SoundsInstaller.progressDialog.show();

					SoundsInstaller.install();
				} catch(err)
				{
					print("Error: " + err);
				}
			}
		});
	},

	install: function()
	{
		new java.lang.Thread(new java.lang.Runnable()
		{
			run: function()
			{
				var githubUrl = "https://raw.githubusercontent.com/DesnoSoftware/Portal-Mod-sounds-installer/master/version" + SoundsInstaller.sounds.version + "/portal-sounds/";
				var tmpPath = sdcard + "/games/com.mojang/portal-sounds/";

				deleteFile(tmpPath); //delete previous files if present

				// creates directories
				new java.io.File(tmpPath).mkdirs();
				new java.io.File(tmpPath + "gelblue/").mkdirs();
				new java.io.File(tmpPath + "gravitygun/").mkdirs();
				new java.io.File(tmpPath + "jumper/").mkdirs();
				new java.io.File(tmpPath + "long_fall_boots/").mkdirs();
				new java.io.File(tmpPath + "portalgun/").mkdirs();
				new java.io.File(tmpPath + "portals/").mkdirs();
				new java.io.File(tmpPath + "radio/").mkdirs();
				new java.io.File(tmpPath + "turrets/").mkdirs();
				new java.io.File(tmpPath + "turrets_defective/").mkdirs();

				for(var i in SoundsInstaller.sounds.soundArray)
				{
					// display progress
					currentActivity.runOnUiThread(new java.lang.Runnable()
					{
						run: function()
						{
							var progress = parseInt(i) + 1;
							SoundsInstaller.progressDialog.setMessage("Downloading sound " + (progress) + " of " + SoundsInstaller.sounds.soundArray.length);
							SoundsInstaller.progressDialog.setProgress(progress);

						}
					});

					// save file on the sdcard
					if(SoundsInstaller.sounds.soundArray[i].fileDirectory == undefined || SoundsInstaller.sounds.soundArray[i].fileDirectory == null)
					{
						// file is inside the general sound folder
						//writeFileFromByteArray(android.util.Base64.decode(SoundsInstaller.sounds.soundArray[i].file, 0), tmpPath + SoundsInstaller.sounds.soundArray[i].fileName);
						SoundsInstaller.downloadFile(githubUrl + SoundsInstaller.sounds.soundArray[i].fileName, tmpPath + SoundsInstaller.sounds.soundArray[i].fileName);
					} else
					{
						// file is inside another folder
						//writeFileFromByteArray(android.util.Base64.decode(SoundsInstaller.sounds.soundArray[i].file, 0), tmpPath + SoundsInstaller.sounds.soundArray[i].fileDirectory + "/" + SoundsInstaller.sounds.soundArray[i].fileName);
						SoundsInstaller.downloadFile(githubUrl + SoundsInstaller.sounds.soundArray[i].fileDirectory + "/" + SoundsInstaller.sounds.soundArray[i].fileName, tmpPath + SoundsInstaller.sounds.soundArray[i].fileDirectory + "/" + SoundsInstaller.sounds.soundArray[i].fileName);
					}
				}

				var nomediaFile = new java.io.File(sdcard + "/games/com.mojang/portal-sounds/.nomedia");
				if(!nomediaFile.exists())
					nomediaFile.createNewFile();

				// put file version
				SoundsInstaller.saveFileWithVersion();

				// END INSTALLATION
				SoundsInstaller.onFinishInstallation();
			}
		}).start();
	},


	downloadFile: function(url, savePath)
	{
		try
		{
			// download content
			var url = new java.net.URL(url);
			var connection = url.openConnection();

			// create file
			var file = new java.io.File(savePath);
			if(file.exists())
				file.delete();
			file.createNewFile();
	 
			// get content
			inputStream = connection.getInputStream();

			// write to file
			var outputStream = new java.io.FileOutputStream(file);
			var read = 0;
			var bytes = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 1024);
			while ((read = inputStream.read(bytes)) != -1) {
				outputStream.write(bytes, 0, read);
			}
	 
			// close what needs to be closed
			outputStream.close();
		} catch(err)
		{
			ModPE.log(getLogText() + "downloadFile(): caught an error: " + err);
		}
	},


	onFinishInstallation: function()
	{
		SoundsInstaller.progressDialog.dismiss();

		ModPE.log(getLogText() + "Finished sounds installation. Re-checking sounds...");

		var notSuccess = SoundsInstaller.needsInstallation();
		if(notSuccess)
		{
			currentActivity.runOnUiThread(new java.lang.Runnable()
			{
				run: function()
				{
					android.widget.Toast.makeText(currentActivity, new android.text.Html.fromHtml("<b>Portal 2</b>: An error has happened during installation, so sounds aren't correctly installed, please check your Internet connection and try again."), android.widget.Toast.LENGTH_LONG).show();
				}
			});
			ModPE.log(getLogText() + "Sounds HAVEN'T been correctly installed!");
		} else
		{
			currentActivity.runOnUiThread(new java.lang.Runnable()
			{
				run: function()
				{
					android.widget.Toast.makeText(currentActivity, new android.text.Html.fromHtml("<b>Portal 2</b>: Congratulations, sounds are now correctly installed. You can start playing with the <i>传送门mod葫芦侠汉化</i>."), android.widget.Toast.LENGTH_LONG).show();
				}
			});
			ModPE.log(getLogText() + "Sounds have been correctly installed. Very good.");
		}

		removeSoundsInstaller();
	},

	saveFileWithVersion: function()
	{
		var versionSaveFile = new java.io.File(sdcard + "/games/com.mojang/portal-sounds/" + SoundsInstaller.versionFileName);
		if(versionSaveFile.exists())
			versionSaveFile.delete();
		versionSaveFile.createNewFile();

		var streamOutputVersion = new java.io.FileOutputStream(versionSaveFile);
		var streamWriterVersion = new java.io.OutputStreamWriter(streamOutputVersion);

		streamWriterVersion.append(SoundsInstaller.sounds.version + " Is anyone there?");
		streamWriterVersion.close();
		streamOutputVersion.close();
	}
};

function removeSoundsInstaller()
{
	// this should allow the GC to free the memory that all the sounds were using
	SoundsInstaller = null;
}


//########################################################################################################################################################
// Things to do at startup
//########################################################################################################################################################

// check sounds
SoundsInstaller.checkAtStartup();

// create images from base64
new java.lang.Thread(new java.lang.Runnable()
{
	run: function()
	{
		try
		{
			createImages();
		} catch(e)
		{
			print("Error " + e);
		}
	}
}).start();


//########################################################################################################################################################
// MINECRAFT BUTTON LIBRARY
//########################################################################################################################################################

// Library version: 1.2.4
// Made by Dennis Motta, also known as Desno365
// https://github.com/Desno365/Minecraft-Button-Library

/*
	The MIT License (MIT)

	Copyright (c) 2015 Dennis Motta 

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.
*/

var MinecraftButtonLibrary = {};

// Customization
// These are the default values of the library, you can change them to make the buttons look how you want to.
MinecraftButtonLibrary.defaultButtonPadding = 8;
MinecraftButtonLibrary.defaultButtonTextSize = 16;
MinecraftButtonLibrary.defaultButtonTextLineSpacing = 4;
MinecraftButtonLibrary.defaultButtonTextColor = "#FFDDDDDD";
MinecraftButtonLibrary.defaultButtonTextPressedColor = "#FFFBFF97";
MinecraftButtonLibrary.defaultButtonTextShadowColor = "#FF292929";

// Variables
MinecraftButtonLibrary.Resources = {};
MinecraftButtonLibrary.ProcessedResources = {};

MinecraftButtonLibrary.context = com.mojang.minecraftpe.MainActivity.currentMainActivity.get();
MinecraftButtonLibrary.metrics = new android.util.DisplayMetrics();
MinecraftButtonLibrary.context.getWindowManager().getDefaultDisplay().getMetrics(MinecraftButtonLibrary.metrics);
MinecraftButtonLibrary.sdcard = new android.os.Environment.getExternalStorageDirectory();
MinecraftButtonLibrary.LOG_TAG = "Minecraft Button Library ";

MinecraftButtonLibrary.ProcessedResources.font = null;
MinecraftButtonLibrary.ProcessedResources.mcNormalNineDrawable = null;
MinecraftButtonLibrary.ProcessedResources.mcPressedNineDrawable = null;

//########################################################################################################################################################
// LIBRARY
//########################################################################################################################################################

// MinecraftButton(int textSize, bool enableSound, string customTextColor)
// set an argument null if you want to use the default value
function MinecraftButton(textSize, enableSound, customTextColor)
{
	if(textSize == null)
		textSize = MinecraftButtonLibrary.defaultButtonTextSize;
	if(enableSound == null)
		enableSound = true;
	if(customTextColor == null)
		customTextColor = MinecraftButtonLibrary.defaultButtonTextColor;

	var button = new android.widget.Button(MinecraftButtonLibrary.context);
	button.setTextSize(textSize);
	button.setOnTouchListener(new android.view.View.OnTouchListener()
	{
		onTouch: function(v, motionEvent)
		{
			MinecraftButtonLibrary.onTouch(v, motionEvent, enableSound, customTextColor);
			return false;
		}
	});
	if (android.os.Build.VERSION.SDK_INT >= 14)
		button.setAllCaps(false);
	MinecraftButtonLibrary.setButtonBackground(button, MinecraftButtonLibrary.ProcessedResources.mcNormalNineDrawable);
	button.setTag(false); // is pressed?
	button.setSoundEffectsEnabled(false);
	button.setGravity(android.view.Gravity.CENTER);
	button.setTextColor(android.graphics.Color.parseColor(customTextColor));
	button.setPadding(MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding));
	MinecraftButtonLibrary.addMinecraftStyleToTextView(button);

	return button;
}

// ######### BUTTON UTILS functions #########
MinecraftButtonLibrary.addMinecraftStyleToTextView = function(textview)
{
	// works also for subclasses of TextView
	// you must set the text size before calling this function!

	textview.setTypeface(MinecraftButtonLibrary.ProcessedResources.font);
	textview.setPaintFlags(textview.getPaintFlags() | android.graphics.Paint.SUBPIXEL_TEXT_FLAG);
	textview.setLineSpacing(MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonTextLineSpacing), 1);
	if (android.os.Build.VERSION.SDK_INT >= 19) // KitKat
		textview.setShadowLayer(1, Math.round((textview.getLineHeight() - MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonTextLineSpacing)) / 8), Math.round((textview.getLineHeight() - MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonTextLineSpacing)) / 8), android.graphics.Color.parseColor(MinecraftButtonLibrary.defaultButtonTextShadowColor));
	else
		textview.setShadowLayer(0.0001, Math.round((textview.getLineHeight() - MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonTextLineSpacing)) / 8), Math.round((textview.getLineHeight() - MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonTextLineSpacing)) / 8), android.graphics.Color.parseColor(MinecraftButtonLibrary.defaultButtonTextShadowColor));
}

MinecraftButtonLibrary.setButtonBackground = function(button, background)
{
	if (android.os.Build.VERSION.SDK_INT >= 16)
		button.setBackground(background);
	else
		button.setBackgroundDrawable(background);
}

MinecraftButtonLibrary.convertDpToPixel = function(dp)
{
	var density = MinecraftButtonLibrary.metrics.density;

	return (dp * density);
}

MinecraftButtonLibrary.onTouch = function(v, motionEvent, enableSound, customTextColor)
{
	var action = motionEvent.getActionMasked();
	if(action == android.view.MotionEvent.ACTION_DOWN)
	{
		// button pressed
		MinecraftButtonLibrary.changeToPressedState(v);
	}
	if(action == android.view.MotionEvent.ACTION_CANCEL || action == android.view.MotionEvent.ACTION_UP)
	{
		// button released
		MinecraftButtonLibrary.changeToNormalState(v, customTextColor);
		
		var rect = new android.graphics.Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
		if(rect.contains(v.getLeft() + motionEvent.getX(), v.getTop() + motionEvent.getY())) // detect if the event happens inside the view
		{
			// onClick will run soon

			// play sound
			if(enableSound)
				Level.playSoundEnt(Player.getEntity(), "random.click", 100, 0);
		}
	}
	if(action == android.view.MotionEvent.ACTION_MOVE)
	{
		var rect = new android.graphics.Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
		if(rect.contains(v.getLeft() + motionEvent.getX(), v.getTop() + motionEvent.getY())) // detect if the event happens inside the view
		{
			// pointer inside the view
			if(v.getTag() == false)
			{
				// restore pressed state
				v.setTag(true); // is pressed?

				MinecraftButtonLibrary.changeToPressedState(v);
			}
		} else
		{
			// pointer outside the view
			if(v.getTag() == true)
			{
				// restore pressed state
				v.setTag(false); // is pressed?

				MinecraftButtonLibrary.changeToNormalState(v, customTextColor);
			}
		}
	}
}

MinecraftButtonLibrary.changeToNormalState = function(button, customTextColor)
{
	MinecraftButtonLibrary.setButtonBackground(button, MinecraftButtonLibrary.ProcessedResources.mcNormalNineDrawable);
	button.setTextColor(android.graphics.Color.parseColor(customTextColor));
	// reset pressed padding
	button.setPadding(MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding));
}

MinecraftButtonLibrary.changeToPressedState = function(button)
{
	MinecraftButtonLibrary.setButtonBackground(button, MinecraftButtonLibrary.ProcessedResources.mcPressedNineDrawable);
	button.setTextColor(android.graphics.Color.parseColor(MinecraftButtonLibrary.defaultButtonTextPressedColor));
	// make the effect of a pressed button with padding
	button.setPadding(MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding) + MinecraftButtonLibrary.convertDpToPixel(2), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding), MinecraftButtonLibrary.convertDpToPixel(MinecraftButtonLibrary.defaultButtonPadding) - MinecraftButtonLibrary.convertDpToPixel(2));
}
// ######### END - BUTTON UTILS functions #########


// ######### CREATE NINE PATCH functions #########
MinecraftButtonLibrary.createNinePatchDrawables = function()
{
	var mcButtonNormalBitmap = MinecraftButtonLibrary.getMinecraftButtonBitmap();
	var mcButtonPressedBitmap = MinecraftButtonLibrary.getMinecraftButtonPressedBitmap();

	var mcNormalNinePatch = new android.graphics.NinePatch(mcButtonNormalBitmap, mcButtonNormalBitmap.getNinePatchChunk(), null);
	var mcPressedNinePatch = new android.graphics.NinePatch(mcButtonPressedBitmap, mcButtonPressedBitmap.getNinePatchChunk(), null);

	// here is used a deprecated method that doesn't deals with density
	//noinspection deprecation
	MinecraftButtonLibrary.ProcessedResources.mcNormalNineDrawable = new android.graphics.drawable.NinePatchDrawable(mcNormalNinePatch);
	MinecraftButtonLibrary.ProcessedResources.mcNormalNineDrawable.setFilterBitmap(false);
	//noinspection deprecation
	MinecraftButtonLibrary.ProcessedResources.mcPressedNineDrawable = new android.graphics.drawable.NinePatchDrawable(mcPressedNinePatch);
	MinecraftButtonLibrary.ProcessedResources.mcPressedNineDrawable.setFilterBitmap(false);
}

MinecraftButtonLibrary.getMinecraftButtonBitmap = function()
{
	var density = MinecraftButtonLibrary.metrics.density;

	if(density < 1)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", ldpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStateNormalLDPI);
	}
	if(density >= 1 && density < 1.5)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", mdpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStateNormalMDPI);
	}
	if(density >= 1.5 && density < 2)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", hdpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStateNormalHDPI);
	}
	if(density >= 2 && density < 2.5)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", xhdpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStateNormalXHDPI);
	}
	if(density >= 2.5)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", xxhdpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStateNormalXXHDPI);
	}

	ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Error: " + density + ", xhdpi");
	return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStateNormalXHDPI);
}

MinecraftButtonLibrary.getMinecraftButtonPressedBitmap = function()
{
	var density = MinecraftButtonLibrary.metrics.density;

	if(density < 1)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", ldpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStatePressedLDPI);
	}
	if(density >= 1 && density < 1.5)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", mdpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStatePressedMDPI);
	}
	if(density >= 1.5 && density < 2)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", hdpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStatePressedHDPI);
	}
	if(density >= 2 && density < 2.5)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", xhdpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStatePressedXHDPI);
	}
	if(density >= 2.5)
	{
		ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Density: " + density + ", xxhdpi");
		return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStatePressedXXHDPI);
	}

	ModPE.log(MinecraftButtonLibrary.LOG_TAG + "Error: " + density + ", xhdpi");
	return MinecraftButtonLibrary.decodeImageFromBase64(MinecraftButtonLibrary.Resources.minecraftButtonStatePressedXHDPI);
}

MinecraftButtonLibrary.decodeImageFromBase64 = function(base64String)
{
	var byteArray = android.util.Base64.decode(base64String, 0);
	return android.graphics.BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
}
// ######### END - CREATE NINE PATCH functions #########


// ######### CREATE TYPEFACE functions #########
MinecraftButtonLibrary.createTypeface = function()
{
	MinecraftButtonLibrary.writeFileFromByteArray(android.util.Base64.decode(MinecraftButtonLibrary.Resources.base64Font, 0), MinecraftButtonLibrary.sdcard + "/minecraft.ttf");
	MinecraftButtonLibrary.ProcessedResources.font = android.graphics.Typeface.createFromFile(MinecraftButtonLibrary.sdcard + "/minecraft.ttf");
	MinecraftButtonLibrary.deleteFile(MinecraftButtonLibrary.sdcard + "/minecraft.ttf");
}

MinecraftButtonLibrary.writeFileFromByteArray = function(byteArray, path)
{
	var file = new java.io.File(path);
	if(file.exists())
		file.delete();
	file.createNewFile();
	var stream = new java.io.FileOutputStream(file);
	stream.write(byteArray);
	stream.close();
	byteArray = null;
}
// ######### END - CREATE TYPEFACE functions #########


// ######### UTILS functions #########
MinecraftButtonLibrary.removeResources = function()
{
	MinecraftButtonLibrary.Resources.minecraftButtonStateNormalLDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStateNormalMDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStateNormalHDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStateNormalXHDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStateNormalXXHDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStatePressedLDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStatePressedMDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStatePressedHDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStatePressedXHDPI = null;
	MinecraftButtonLibrary.Resources.minecraftButtonStatePressedXXHDPI = null;

	MinecraftButtonLibrary.Resources.base64Font = null;
}

MinecraftButtonLibrary.deleteFile = function(path)
{
	var file = new java.io.File(path);

	if(file.isDirectory())
	{
		var directoryFiles = file.listFiles();
		for(var i in directoryFiles)
		{
			deleteFile(directoryFiles[i].getAbsolutePath());
		}
		file.delete();
	}

	if(file.isFile())
		file.delete();
}
// ######### END - UTILS functions #########


//########################################################################################################################################################
// RESOURCES IN BASE64
//########################################################################################################################################################

// backgrounds
MinecraftButtonLibrary.Resources.minecraftButtonStateNormalLDPI = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAACAAAAAgAAAAMAAAACMAAAAAAAAAEAAAAHAAAAAgAAAAf/vLGr/7yxqwAAAAH/vLGr/5WGgQAAAAH/cmVnAAAAAf8oJyoMgs1WAAAASUlEQVQY02Pcs3H1fwY8gAmf5NYtexhYGBgYGG5evYZVwfZDh/GbwPD/PwEFjIwEFBByJAPDfwaWbVv2MGw7eIiBgRFuLrIdDADq5BFxvezsVAAAAABJRU5ErkJggg==";
MinecraftButtonLibrary.Resources.minecraftButtonStateNormalMDPI = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAAEAAAABAAAAAYAAAAEMAAAAAAAAAIAAAAOAAAABAAAAA7/vLGr/7yxqwAAAAH/vLGr/5WGgQAAAAH/cmVnAAAAAf8oJyqdu2NqAAAAT0lEQVQ4y2Pcs3H1fwYKABMDhYCFXI1bt+yhsgtuXr1Gksbthw4PcBgw/P8/0C5gZKSOCwbeAPLDgIFasbANmqa3HTwEDV2M4MYVDdRxAQBscxGJWBLxyQAAAABJRU5ErkJggg==";
MinecraftButtonLibrary.Resources.minecraftButtonStateNormalHDPI = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAAGAAAABgAAAAkAAAAGMAAAAAAAAAMAAAAVAAAABgAAABX/vLGr/7yxqwAAAAH/vLGr/5WGgQAAAAH/cmVnAAAAAf8oJyqPt1DfAAAAV0lEQVRIx2Pcs3H1fwYaAiYGGgOaW8BCC0O3btkzXIPo5tVrVDF0+6HDo6mIAPj/fzSICABGxmEURKMWDFAqYhhWGW0bUu2z7eAhpMyCMxcRk9OGURABAH/ZEZn4HdB3AAAAAElFTkSuQmCC";
MinecraftButtonLibrary.Resources.minecraftButtonStateNormalXHDPI = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAAIAAAACAAAAAwAAAAIMAAAAAAAAAQAAAAcAAAACAAAABz/vLGr/7yxqwAAAAH/vLGr/5WGgQAAAAH/cmVnAAAAAf8oJypkuTlTAAAAZUlEQVRYw2Pcs3H1f4YBBEwMAwxGHcBCbwu3btkzGgWDPA3cvHqNphZuP3R4NApGeDnA8P//aBSM9DTAyDgaBaMOGHXASC8HGEbrgsGWBrahtdO3HTyEVnYTLNxJrQxGo2BwOQAAWckRqcYME3kAAAAASUVORK5CYII=";
MinecraftButtonLibrary.Resources.minecraftButtonStateNormalXXHDPI = "iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAAMAAAADAAAABIAAAAMMAAAAAAAAAYAAAAqAAAADAAAACr/vLGr/7yxqwAAAAH/vLGr/5WGgQAAAAH/cmVnAAAAAf8oJypAoV45AAAAg0lEQVRo3u3ZwQmAMAyF4UTcfxFPgtZLL9YZFJwmTtCDINQ0/5sgHzxCQzXPk4njDOI8AABEB4xeBl2XTIUAAAi1he7z+tWgWzmoEAAAvIVaxowKAQDAFmoZVSoEAAAAAAAAAIj7FhIuMgAA+txCqfL3lPZSuYxen1JfnWRUCACAHgEPIUcRyZ0dVsEAAAAASUVORK5CYII=";
MinecraftButtonLibrary.Resources.minecraftButtonStatePressedLDPI = "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAACAAAAAgAAAAIAAAADMAAAAAAAAAEAAAAHAAAAAQAAAAb/KCcqAAAAAf9yZWcAAAABAAAAAQAAAAEAAAABAAAAAQAAAAGZYAV4AAAAb0lEQVQY012OQQqDMBRE34Scwp1QsHgHs7CbGnv9UjzNuIjRxuHD/wzzhq/nMBrKIIENAhA5TUQwS0pUiZIFeK8zEVSAQy5Vpxdq3k3HdYbLq2xTRwBht2T9QxJxSRP588I2d9kmPvqO7ftryb+9AxX7IG5YZYu3AAAAAElFTkSuQmCC";
MinecraftButtonLibrary.Resources.minecraftButtonStatePressedMDPI = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAAEAAAABAAAAAQAAAAGMAAAAAAAAAIAAAAOAAAAAgAAAAz/KCcqAAAAAf9yZWcAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEDO+tuAAAAkklEQVQ4y62SwQrCMAyGvwyfwpswcOwd7EEvbu71Zfg08ZIgi10ZtLm0CSn5/r+R4ToqAGwPRCy3gqV+mdMNgI7KOPnIKaVsgw/WUH++7s0IZCsxhP5Myfa184CgVf5cyJvTgiDarUYixV/wQrtfUC1rjiRim1pPMNlOz8vDSPTQQ++rJ+gvZwA+77WseSevJvgCGagihHTV1j0AAAAASUVORK5CYII=";
MinecraftButtonLibrary.Resources.minecraftButtonStatePressedHDPI = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAAGAAAABgAAAAYAAAAJMAAAAAAAAAMAAAAVAAAAAwAAABL/KCcqAAAAAf9yZWcAAAABAAAAAQAAAAEAAAABAAAAAQAAAAGqizz1AAAAl0lEQVRIx92VwQqAIAyGXfQU3YKg6B3yUJe0Xj+ip1k3+QOHGXhoO+l0Ch/flIZ+ZBMiPjREkIcFSOPE2ymMK1M4il9QIwtnbbIAqbCwZ91mXYgoLoUQ/NQrWavMIiMYQqJHadVUIJK6iAEXZTUaLihrNOY8WyRcBM+7AkQOfh+/L4CLPx+KtQoQdW0TJtdx5tnyIv9/RDcytSKUL7bTXAAAAABJRU5ErkJggg==";
MinecraftButtonLibrary.Resources.minecraftButtonStatePressedXHDPI = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAAIAAAACAAAAAgAAAAMMAAAAAAAAAQAAAAcAAAABAAAABj/KCcqAAAAAf9yZWcAAAABAAAAAQAAAAEAAAABAAAAAQAAAAHs/TEDAAAAqUlEQVRYw+2WwQqAIAyGXfQU3YKg6B3yUJe0Xj+ip1ln/8AhBnrYbroxhe/frzSNM5sg4ktDBHkogDRueLsE68YUDr1Ai5CdtUkNEDkL9fuxKoLqNEDxMRaCv0aR1E8R1OcDRphrEp0gzTgUQQ0akMydQROU9RZggSKo7y1gzptzSRMEf0pFUF4DDv7p/txAE/zrgdhPEZTXwNB3wcZz3XlznphXBMUv8AJ9bSKkEsE9twAAAABJRU5ErkJggg==";
MinecraftButtonLibrary.Resources.minecraftButtonStatePressedXXHDPI = "iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGG5wT2wAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAADYHRhkAAAAVG5wVGMAAgIJIAAAACgAAAAAAAALAAAACwAAAAsAAAARMAAAAAAAAAYAAAAqAAAABgAAACT/KCcqAAAAAf9yZWcAAAABAAAAAQAAAAEAAAABAAAAAQAAAAGV/cSjAAAAzElEQVRo3u2ZQQrCMBBFM9JTuBMEi3cwC93Y6vVFPM14gfzFQIpMfLNMJk0ffD5/WptPZy/Nii0XM9EvDoh2tbHWS3N9V5IXAAD8O8CkbGWptcsFymw8+Jz744qEAABgUBeyWFQJluvw1OVeJAQAAKNmoRLMMBZOQ31CFRICAID8LhQdpVy4UyzbRCcydQAJAQDAqBOZ+7bZJupOJr5+IyEAAMjuQov497Q+b8Kd/Ccvqu5FQgAAkN2Fjod9c+Pzem+bbTr1IyEAAEheX2f8IsSeFAnbAAAAAElFTkSuQmCC";

// font
MinecraftButtonLibrary.Resources.base64Font = " ";

//########################################################################################################################################################
// START CREATION OF RESOURCES
//########################################################################################################################################################

new java.lang.Thread(new java.lang.Runnable()
{
	run: function()
	{
		try
		{
			MinecraftButtonLibrary.createNinePatchDrawables();
			MinecraftButtonLibrary.createTypeface();

			MinecraftButtonLibrary.removeResources();
		} catch(e)
		{
			print("Error " + e);
		}
	}
}).start();

