//--------------------------------------------------------------------------
// Deconstruct Gun / Construction Tool
// Originally from Hammer Mod. Changed and redone for LuCiD MoD.
// Also Changed again and redone for Construction Mod.
// All changes made by LuCiD from LuCiD MoD & Mostlikely or JackTL from Construction Mod.

//--------------------------------------------------------------------------
// Sounds
datablock AudioProfile(ConstructionToolSwitchSound) {
	filename    = "fx/packs/packs.repairPackOn.wav";
	description = AudioClosest3d;
	preload = true;
};

datablock AudioProfile(ConstructionToolFireSound) {
	filename    = "fx/misc/downloading.wav";
	description = CloseLooping3d;
	preload = true;
};

//--------------------------------------------------------------------------
// Projectile

datablock RepairProjectileData(ConstructionToolBeam) {
	sound = ElfFireWetSound;

	beamRange      = 100;
	beamWidth      = 0.15;
	numSegments    = 20;
	texRepeat      = 0.20;
	blurFreq       = 10.0;
	blurLifetime   = 1.0;
	cutoffAngle    = 25.0;

	textures[0]   = "special/ELFLightning";
	textures[1]   = "skins/flaregreen";
};

//-------------------------------------------------------------------------
// shapebase datablocks

datablock ItemData(ConstructionTool) {
	className = Weapon;
	catagory = "Spawn Items";
	shapeFile = "weapon_shocklance.dts";
	image = ConstructionToolImage;
	mass = 1;
	elasticity = 0.2;
	friction = 0.6;
	pickupRadius = 2;
	rotate = true;
	pickUpName = "a construction tool";

	lightOnlyStatic = true;
	lightType = "PulsingLight";
	lightColor = "0 1 0 1";
	lightTime = 1200;
	lightRadius = 4;

	//computeCRC = true;
	emap = true;
};

//--------------------------------------------------------------------------
// Construction Tool

datablock ShapeBaseImageData(ConstructionToolImage) {
	shapeFile = "weapon_shocklance.dts";
	offset = "0 0 0";

	item = ConstructionTool;
	usesEnergy = true;

	minEnergy = 3;

	cutOffEnergy = 3.1;
	emap = true;

	stateName[0] = "Activate";
	stateTransitionOnTimeout[0] = "ActivateReady";
	stateTimeoutValue[0] = 0.25;
	stateSound[0] = ConstructionToolSwitchSound;

	stateName[1] = "ActivateReady";
	stateScript[1] = "onActivateReady";
	stateSpinThread[1] = Stop;
	stateTransitionOnAmmo[1] = "Ready";
	stateTransitionOnNoAmmo[1] = "ActivateReady";

	stateName[2] = "Ready";
	stateSpinThread[2] = Stop;
	stateTransitionOnNoAmmo[2] = "Deactivate";
	stateTransitionOnTriggerDown[2] = "Validate";

	stateName[3] = "Validate";
	stateTransitionOnTimeout[3] = "Validate";
	stateTimeoutValue[3] = 0.2;
	stateEnergyDrain[3] = 3;
	stateSpinThread[3] = SpinUp;
	stateScript[3] = "onValidate";
	stateIgnoreLoadedForReady[3] = true;
	stateTransitionOnLoaded[3] = "PerformAction";
	stateTransitionOnNoAmmo[3] = "Deactivate";
	stateTransitionOnTriggerUp[3] = "Deactivate";

	stateName[4] = "PerformAction";
	stateSound[4] = ConstructionToolFireSound;
	stateScript[4] = "onPerformAction";
	stateSpinThread[4] = FullSpeed;
	stateAllowImageChange[4] = false;
	stateSequence[4] = "activate";
	stateFire[4] = true;
	stateEnergyDrain[4] = 16;
	stateTimeoutValue[4] = 0.2;
	stateTransitionOnTimeOut[4] = "PerformAction";
	stateTransitionOnNoAmmo[4] = "Deactivate";
	stateTransitionOnTriggerUp[4] = "Deactivate";
	stateTransitionOnNotLoaded[4] = "Validate";

	stateName[5] = "Deactivate";
	stateScript[5] = "onDeactivate";
	stateSpinThread[5] = SpinDown;
	stateSequence[5] = "activate";
	stateDirection[5] = false;
	stateTimeoutValue[5] = 0.2;
	stateTransitionOnTimeout[5] = "ActivateReady";
};

//Phantom139: Added Weapon Mode Code Here.
function ConstructionToolImage::changeMode(%this, %obj, %key) {
   if(%obj.performing) {
      commandToClient(%obj.client, 'bottomPrint', "Construction Tool\nCannot Change Modes While Performing.", 3, 3);
      return;
   }
   switch(%key) {
      case 1:
         //Mine Modes
         %obj.constructionToolMode++;
         %obj.constructionToolMode2 = 0;
         if (%obj.constructionToolMode >= 4)
            %obj.constructionToolMode = 0;
      case 2:
         //Grenade Modes
	     %obj.constructionToolMode2++;
		 if (%obj.constructionToolMode == 0 && %obj.constructionToolMode2 == 2)
            %obj.constructionToolMode2 = 0;
         if (%obj.constructionToolMode == 1 && %obj.constructionToolMode2 == 2)
		    %obj.constructionToolMode2 = 0;
         if (%obj.constructionToolMode == 2 && %obj.constructionToolMode2 == 6)
		    %obj.constructionToolMode2 = 0;
		 if (%obj.constructionToolMode == 3 && %obj.constructionToolMode2 == 4)
			%obj.constructionToolMode2 = 0;
   }
   displayWeaponInfo(%this, %obj, %obj.constructionToolMode, %obj.constructionToolMode2, "[REPA] "@%obj.client.RotateAngle);
}
//Phantom139: End

function ConstructionToolImage::onActivate(%this,%obj,%slot) {
}

function ConstructionToolImage::onActivateReady(%this,%obj,%slot) {
	%obj.errMsgSent = false;
}

function ConstructionToolImage::onValidate(%this,%obj,%slot) {
	switch (%obj.constructionToolMode) {
		case 0: // disassemble
			onValidateDisassemble(%this,%obj,%slot);
		case 1: // rotate
			onValidateRotate(%this,%obj,%slot);
		case 2: // advanced rotate
			onValidateAdvancedRotate(%this,%obj,%slot);
		case 3: // power management
			onValidatePowerManagement(%this,%obj,%slot);
	}
}

function ConstructionToolImage::onPerformAction(%this,%obj,%slot) {
	// this = ConstructionToolImage datablock
	// obj = player wielding the construction tool
	// slot = weapon slot

	if (%obj.getEnergyLevel() <= %this.cutOffEnergy) {
		if (%obj.performing > 0)
			stopPerforming(%obj);
		return;
	}

	// reset the flag that indicates an error message has been sent
	%obj.errMsgSent = false;

	switch (%obj.constructionToolMode) {
		case 0: // disassemble
			onPerformDisassemble(%this,%obj,%slot);
		case 1: // rotate
			onPerformRotate(%this,%obj,%slot);
		case 2: // advanced rotate
			onPerformAdvancedRotate(%this,%obj,%slot);
		case 3: // power management
			onPerformPowerManagement(%this,%obj,%slot);
	}
}

function ConstructionToolImage::onDeactivate(%this,%obj,%slot) {
	%obj.setImageTrigger(%slot, false);
	if (%obj.performing > 0) {
		stopPerforming(%obj);
		messageClient(%player.client, 'msgClient', '\c2Construction Tool stopped.');
	}
	%obj.errMsgSent = false;
}

function ConstructionToolImage::onMount(%this,%obj,%slot) {
	if (!$Host::TournamentMode) {
		%curWeap = ( %obj.getMountedImage($WeaponSlot) == 0 ) ? "" : %obj.getMountedImage($WeaponSlot).getName().item.pickUpName;
		BottomPrint(%obj.client, "Now using " @ %curWeap, 2, 1 );
	}
    if(%obj.client.RotateAngle $= "") {
       %obj.client.RotateAngle = 22.5;
    }
	%obj.errMsgSent = false;
	%obj.client.setWeaponsHudActive(%this.item);
	%obj.usingConstructionTool = true;
	if (!isSet(%obj.client.constructionToolMode))
		%obj.client.constructionToolMode = 0;
	if (!isSet(%obj.client.constructionToolMode2))
		%obj.client.constructionToolMode2 = 0;
    //Phantom139: Added
    %obj.hasMineModes = 1;
    %obj.hasGrenadeModes = 1;
    //Phantom139: End
	WeaponImage::onMount(%this,%obj,%slot);
}

function ConstructionToolImage::onUnmount(%data, %obj, %slot) {
	%obj.usingConstructionTool = false;
	%obj.setImageTrigger(%slot, false);
	if (%obj.performing > 0) {
		stopPerforming(%obj);
		messageClient(%player.client, 'msgClient', '\c2Construction Tool stopped.');
	}
    //Phantom139: Added
    %obj.hasMineModes = 0;
    %obj.hasGrenadeModes = 0;
    //Phantom139: End
	%obj.errMsgSent = false;
	Parent::deconstruct(%data, %obj, %slot);
	WeaponImage::onUnmount(%data, %obj, %slot);
}

function ConstructionTool::onPickup(%this, %obj, %shape, %amount) {
	// created to prevent console errors
}

// --------------------------------------------------------------------------------
// Common functions
// --------------------------------------------------------------------------------

function startPerforming(%player) {
	// %player = the player who was using the construction tool
	%initialDirection = %player.getMuzzleVector($WeaponSlot);
	%initialPosition  = %player.getMuzzlePoint($WeaponSlot);

	//else
	%performTime = 100;

	%player.performTime = %performTime;
	// Temporary (hopefully) fix
	%data = %player.performing.getDataBlock();
	%dataBlockName = %data.getName();
	if (%data.className !$= "forcefield" && %data.className !$= "gravityfield") {
		%player.constructionToolProjectile = new RepairProjectile() {
			dataBlock = ConstructionToolBeam;
			initialDirection = %initialDirection;
			initialPosition  = %initialPosition;
			sourceObject     = %player;
			sourceSlot       = $WeaponSlot;
			targetObject     = %player.performing;
		};
		MissionCleanup.add(%player.constructionToolProjectile);
	}
	%hTgt = %player.performing;
	%hTgt.beingPerformed = true;
}

function stopPerforming(%player) {
	// %player = the player who was using the construction tool
	if (%player.performing > 0) {
		if (isObject(%player.constructionToolProjectile))
			%player.constructionToolProjectile.delete();
	}
	%hTgt.beingPerformed = false;
	%player.constructionToolProjectile = 0;
	%player.performing = 0;
	%player.performTime = 0;
	%player.errMsgSent = true;
	%player.setImageTrigger($WeaponSlot, false);
	%player.setImageLoaded($WeaponSlot, false);
	%client = %player.client;
	if (%client.CampingThread)
		cancel(%client.campingThread);
	return;
}

// --------------------------------------------------------------------------------
// Disassemble functions
// --------------------------------------------------------------------------------
function onValidateDisassemble(%this,%obj,%slot) {
	%hGun = %obj.getMountedImage(%slot);
	// muzVec is the vector coming from the construction tool's "muzzle"
	%muzVec = %obj.getMuzzleVector(%slot);
	// muzNVec = normalized muzVec
	%muzNVec = VectorNormalize(%muzVec);
	%beamRange = ConstructionToolBeam.beamRange;
	// scale muzNVec to the range the repair beam can reach
	%muzScaled = VectorScale(%muzNVec, %beamRange);
	// muzPoint = the actual point of the gun's "muzzle"
	%muzPoint = %obj.getMuzzlePoint(%slot);
	// rangeEnd = muzzle point + length of beam
	%rangeEnd = VectorAdd(%muzPoint, %muzScaled);
	// search for just about anything that can be damaged as well as interiors
	%searchMasks = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType;
	// search for objects within the beam's range that fit the masks above
	%scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj);
	// screen out interiors
	if (%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) {
		// a target in range was found
		%hTgt = firstWord(%scanTarg);
		// can it be dissed? is it already being tooled?
		if ($ReverseDeployItem[%hTgt.getDataBlock().getName()] !$= "" && !%hTht.beingPerformed)
			%canPerform = true;
		// Only deconstruct deployed items, not base ones
		%dataBlockName = %hTgt.getDataBlock().getName();
		if (%canPerform == true && (
			%dataBlockName $= "StationInventory" ||
			%dataBlockName $= "GeneratorLarge" ||
			%dataBlockName $= "SolarPanel" ||
			%dataBlockName $= "SensorMediumPulse" ||
			%dataBlockName $= "SensorLargePulse"
			))
			if (%hTgt.deployed != true)
				%canPerform = false;
		if (%canPerform == true) {
			// yes, it's disassembleable
			if (%hTgt != %obj.performing) {
				if (isObject(%obj.performing))
					stopPerforming(%obj);
				%obj.performing = %hTgt;
				startPerforming(%obj);
			}
			// setting imageLoaded to true sends us to deconstruct state (function onPerformAction)
			%obj.setImageLoaded(%slot, true);
		}
		else {
			// there is a target in range, but it's not disable
			if (!%obj.errMsgSent) {
				messageClient(%obj.client, 'msgClient', '\c2You can\'t deconstruct that.');
				%obj.errMsgSent = true;
			}
			// if player was Disassembling something, stop the disassembling -- we're done
			if (%obj.performing > 0)
				stopPerforming(%obj);
		}
	}
	else {
		// there is no target in range
		if (!%obj.errMsgSent) {
			// send an error message only once
			messageClient(%obj.client, 'msgClient', '\c2No target to deconstruct.');
			%obj.errMsgSent = true;
		}
	}
}

function onPerformDisassemble(%this,%obj,%slot) {
	%target = %obj.performing;
	if (!%target) {
		// no target -- whoops! never mind
		stopPerforming(%obj);
		return;
	}
	if (%obj.constructionToolMode2 == 0)
		%cascade = 0;
	else
		%cascade = 1;
	%hGun = %obj.getMountedImage(%slot);
	// muzVec is the vector coming from the construction tool's "muzzle"
	%muzVec = %obj.getMuzzleVector(%slot);
	// muzNVec = normalized muzVec
	%muzNVec = VectorNormalize(%muzVec);
	%beamRange = ConstructionToolBeam.beamRange;
	// scale muzNVec to the range the repair beam can reach
	%muzScaled = VectorScale(%muzNVec, %beamRange);
	// muzPoint = the actual point of the gun's "muzzle"
	%muzPoint = %obj.getMuzzlePoint(%slot);
	// rangeEnd = muzzle point + length of beam
	%rangeEnd = VectorAdd(%muzPoint, %muzScaled);
	// search for just about anything that can be damaged as well as interiors
	%searchMasks = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType;
	// search for objects within the beam's range that fit the masks above
	%scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj);
	// screen out interiors
	if (%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) {
		// a target in range was found
		%hTgt = firstWord(%scanTarg);
		// can it be dissed? is it already being tooled?
		if ($ReverseDeployItem[%hTgt.getDataBlock().getName()] !$= "" && !%hTht.beingPerformed)
			%canPerform = true;
		// Only deconstruct deployed items, not base ones
		%dataBlockName = %hTgt.getDataBlock().getName();
		if (%canPerform == true && (
			%dataBlockName $= "StationInventory" ||
			%dataBlockName $= "GeneratorLarge" ||
			%dataBlockName $= "SolarPanel" ||
			%dataBlockName $= "SensorMediumPulse" ||
			%dataBlockName $= "SensorLargePulse"
			))
			if (%hTgt.deployed != true)
				%canPerform = false;
		if (%canPerform == true) {
			// yes, it's disassembleable
			if (%hTgt != %obj.performing) { // its not what we were originally dising
				if (isObject(%obj.performing)) {
					stopPerforming(%obj);
					%obj.performing = %hTgt;
					startPerforming(%obj);
				}
			}
			else { // continue dising
				%obj.performTime = %obj.performTime - 120;
				if (%obj.performTime < 0) { // we have a dis!
					if (%hTgt.isRemoved)
						return; // Avoid duplicate disassemblies
					if (%hTgt.team != %obj.team && !(%obj.client.isAdmin || %obj.client.isSuperAdmin)) {
						messageClient(%obj.client, 'msgClient', '\c2Deconstruction failed! Wrong team!~wfx/powered/nexus_deny.wav');
						stopPerforming(%obj);
						return;
					}
					if ($Host::OnlyOwnerDeconstruct == 1 && %hTgt.getOwner() != %obj.client && !(%obj.client.isAdmin || %obj.client.isSuperAdmin)) {
						if (isObject(%hTgt.getOwner()))
							messageClient(%obj.client, 'msgClient', '\c2Deconstruction failed! This belongs to %1!~wfx/powered/nexus_deny.wav', %hTgt.getOwner().nameBase);
						else
							messageClient(%obj.client, 'msgClient', '\c2Deconstruction failed! Not your stuff!~wfx/powered/nexus_deny.wav');
						stopPerforming(%obj);
						return;
					}
					stopPerforming(%obj);
					if (%cascade && $Host::OnlyOwnerCascade == 1 && %hTgt.getOwner() != %obj.client && !(%obj.client.isAdmin || %obj.client.isSuperAdmin))
						messageClient(%obj.client, 'msgClient', '\c2Cascade failed! Not your stuff!~wfx/powered/nexus_deny.wav');
					else {
						if ((%hTgt.getType() & $TypeMasks::StaticShapeObjectType) && %hTgt.getDamageLeftPct() < (0.25 + ((getRandom() * 0.2) - 0.1))) {
							if ($Host::InvincibleDeployables == 1 && %hTgt.getDamageLeftPct() <= 0) {
//								%hTgt.setDamageLevel(%hTgt.getDataBlock().maxDamage - 0.01);
								%hTgt.setDamageLevel(0); // Make sure we can blow it up..
							}
							%hTgt.damageFailedDecon = true;
							%hTgt.schedule(100,setDamageState,Destroyed);
							messageClient(%obj.client, 'msgClient', '\c2Deconstruction failed!~wfx/powered/nexus_deny.wav');
						}
						else {
							%hTgt.getDataBlock().disassemble(%obj, %hTgt); // Run Item Specific code.
							if (%cascade)
								cascade(%hTgt,true);
							if (%hTgt.getDataBlock().getName() $= "DeployedLTarget" && isObject(%hTgt.lMain))
								%revItem = %hTgt.lMain.getDataBlock().getName();
							else
								%revItem = %hTgt.getDataBlock().getName();
							%newPack = $ReverseDeployItem[%revItem];
							if (getWord(%newPack,0) !$= "poof") {
								%npack = new Item() {
									dataBlock = %newPack;
								};
								MissionCleanup.add(%npack);
								%npack.schedulePop();
								if (%newPack $= "ForceFieldDeployable" || %newPack $= "GravityFieldDeployable" || %newPack $= "DecorationDeployable")
									%pos = %hTgt.getWorldBoxCenter();
								else
									%pos = %hTgt.getPosition();
								%npack.setTransform(getWords(%scanTarg,1,3) SPC "0 0 1" SPC (getRandom() * ($Pi * 2)));
							}
						}
					}
				}
			}
		}
	}
	else
		stopPerforming(%obj);
}

// --------------------------------------------------------------------------------
// Rotate functions
// --------------------------------------------------------------------------------

function onValidateRotate(%this,%obj,%slot) {
	%hGun = %obj.getMountedImage(%slot);
	// muzVec is the vector coming from the construction tool's "muzzle"
	%muzVec = %obj.getMuzzleVector(%slot);
	// muzNVec = normalized muzVec
	%muzNVec = VectorNormalize(%muzVec);
	%beamRange = ConstructionToolBeam.beamRange;
	// scale muzNVec to the range the repair beam can reach
	%muzScaled = VectorScale(%muzNVec, %beamRange);
	// muzPoint = the actual point of the gun's "muzzle"
	%muzPoint = %obj.getMuzzlePoint(%slot);
	// rangeEnd = muzzle point + length of beam
	%rangeEnd = VectorAdd(%muzPoint, %muzScaled);
	// search for just about anything that can be damaged as well as interiors
	%searchMasks = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType;
	// search for objects within the beam's range that fit the masks above
	%scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj);
	// screen out interiors
	if (%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) {
		// a target in range was found
		%hTgt = firstWord(%scanTarg);
		// can it be rotated? is it already being tooled?
		if ($ReverseDeployItem[%hTgt.getDataBlock().getName()] !$= "" && !%hTht.beingPerformed)
			%canPerform = true;
		// Only rotate deployed items, not base ones
		%dataBlockName = %hTgt.getDataBlock().getName();
		if (%dataBlockName $= "DeployedLTarget" && !isObject(%hTgt.lMain))
			%canPerform = false;
		if (%canPerform == true && (
			%dataBlockName $= "StationInventory" ||
			%dataBlockName $= "GeneratorLarge" ||
			%dataBlockName $= "SolarPanel" ||
			%dataBlockName $= "SensorMediumPulse" ||
			%dataBlockName $= "SensorLargePulse"
			))
			if (%hTgt.deployed != true)
				%canPerform = false;
		if (%canPerform == true) {
			// yes, it's rotatable
			if (%hTgt != %obj.performing) {
				if (isObject(%obj.performing))
					stopPerforming(%obj);
				%obj.performing = %hTgt;
				startPerforming(%obj);
			}
			// setting imageLoaded to true sends us to rotate state (function onPerformAction)
			%obj.setImageLoaded(%slot, true);
		}
		else {
			// there is a target in range, but it's not rotatable
			if (!%obj.errMsgSent) {
				messageClient(%obj.client, 'msgClient', '\c2You can\'t rotate that.');
				%obj.errMsgSent = true;
			}
			// if player was rotating something, stop the rotating -- we're done
			if (%obj.performing > 0)
				stopPerforming(%obj);
		}
	}
	else {
		// there is no target in range
		if (!%obj.errMsgSent) {
			// send an error message only once
			messageClient(%obj.client, 'msgClient', '\c2No target to rotate.');
			%obj.errMsgSent = true;
		}
	}
}

function onPerformRotate(%this,%obj,%slot) {
	%target = %obj.performing;
	if (!%target) {
		// no target -- whoops! never mind
		stopPerforming(%obj);
		return;
	}
	if (%obj.constructionToolMode2 == 0)
		%rotVal = 1;
	else
		%rotVal = -1;
	%hGun = %obj.getMountedImage(%slot);
	// muzVec is the vector coming from the construction tool's "muzzle"
	%muzVec = %obj.getMuzzleVector(%slot);
	// muzNVec = normalized muzVec
	%muzNVec = VectorNormalize(%muzVec);
	%beamRange = ConstructionToolBeam.beamRange;
	// scale muzNVec to the range the repair beam can reach
	%muzScaled = VectorScale(%muzNVec, %beamRange);
	// muzPoint = the actual point of the gun's "muzzle"
	%muzPoint = %obj.getMuzzlePoint(%slot);
	// rangeEnd = muzzle point + length of beam
	%rangeEnd = VectorAdd(%muzPoint, %muzScaled);
	// search for just about anything that can be damaged as well as interiors
	%searchMasks = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType;
	// search for objects within the beam's range that fit the masks above
	%scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj);
	// screen out interiors
	if (%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) {
		// a target in range was found
		%hTgt = firstWord(%scanTarg);
		// can it be rotated? is it already being tooled?
		if ($ReverseDeployItem[%hTgt.getDataBlock().getName()] !$= "" && !%hTht.beingPerformed)
			%canPerform = true;
		// Only rotate deployed items, not base ones
		%dataBlockName = %hTgt.getDataBlock().getName();
		if (%dataBlockName $= "DeployedLTarget" && !isObject(%hTgt.lMain))
			%canPerform = false;
		if (%canPerform == true && (
			%dataBlockName $= "StationInventory" ||
			%dataBlockName $= "GeneratorLarge" ||
			%dataBlockName $= "SolarPanel" ||
			%dataBlockName $= "SensorMediumPulse" ||
			%dataBlockName $= "SensorLargePulse"
			))
			if (%hTgt.deployed != true)
				%canPerform = false;
		if (%canPerform == true) {
			// yes, it's rotatable
			if (%hTgt != %obj.performing) { // its not what we were originally rotating
				if (isObject(%obj.performing)) {
					stopPerforming(%obj);
					%obj.performing = %hTgt;
					startPerforming(%obj);
				}
			}
			else { // continue rotating
				%obj.performTime = %obj.performTime - 120;
				if (%obj.performTime < 0) { // we have a rot!
					if (%hTgt.team != %obj.team && !(%obj.client.isAdmin || %obj.client.isSuperAdmin)) {
						messageClient(%obj.client, 'msgClient', '\c2Rotate failed! Wrong team!~wfx/powered/nexus_deny.wav');
						stopPerforming(%obj);
						return;
					}
					if ($Host::OnlyOwnerRotate == 1 && %hTgt.getOwner() != %obj.client && !(%obj.client.isAdmin || %obj.client.isSuperAdmin)) {
						messageClient(%obj.client, 'msgClient', '\c2Rotate failed! Not your stuff!~wfx/powered/nexus_deny.wav');
						stopPerforming(%obj);
						return;
					}
                    //
                    if(%obj.client.RotateAngle $= "" || %obj.client.RotateAngle == 0) {
                       %obj.client.RotateAngle = $Pi / 8;
                       %angle = ($Pi/8)*%rotVal;
                    }
                    else {
                       %angle = (%obj.client.RotateAngle * ($Pi / 180)) * %rotVal;
                    }
                    //
					stopPerforming(%obj);
					%obj = firstWord(%scanTarg);
					%vec1 = posFromRaycast(%scanTarg);
					%vec2 = normalFromRaycast(%scanTarg);
					pullObject(%obj,%vec1,%vec2,%angle,"0 0 0");
				}
			}
		}
	}
	else
		stopPerforming(%obj);
}

// --------------------------------------------------------------------------------
// Advanced rotate functions
// --------------------------------------------------------------------------------

function onValidateAdvancedRotate(%this,%obj,%slot) {
	%m2 = %obj.constructionToolMode2;
	if (%m2 == 2 || %m2 == 3 || %m2 == 4 || %m2 == 5) {
		%obj.setImageLoaded(%slot, true);
		return;
	}

	%hGun = %obj.getMountedImage(%slot);
	// muzVec is the vector coming from the construction tool's "muzzle"
	%muzVec = %obj.getMuzzleVector(%slot);
	// muzNVec = normalized muzVec
	%muzNVec = VectorNormalize(%muzVec);
	%beamRange = ConstructionToolBeam.beamRange;
	// scale muzNVec to the range the repair beam can reach
	%muzScaled = VectorScale(%muzNVec, %beamRange);
	// muzPoint = the actual point of the gun's "muzzle"
	%muzPoint = %obj.getMuzzlePoint(%slot);
	// rangeEnd = muzzle point + length of beam
	%rangeEnd = VectorAdd(%muzPoint, %muzScaled);
	// search for just about anything that can be damaged as well as interiors
	%searchMasks = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType;
	// search for objects within the beam's range that fit the masks above
	%scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj);
	// screen out interiors
	if (%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) {
		// a target in range was found
		%hTgt = firstWord(%scanTarg);
		// can it be selected? is it already being tooled?
		if ($ReverseDeployItem[%hTgt.getDataBlock().getName()] !$= "" && !%hTht.beingPerformed)
			%canPerform = true;
		// Only select deployed items, not base ones
		%dataBlockName = %hTgt.getDataBlock().getName();
		if (%dataBlockName $= "DeployedLTarget" && !isObject(%hTgt.lMain))
			%canPerform = false;
		if (%canPerform == true && (
			%dataBlockName $= "StationInventory" ||
			%dataBlockName $= "GeneratorLarge" ||
			%dataBlockName $= "SolarPanel" ||
			%dataBlockName $= "SensorMediumPulse" ||
			%dataBlockName $= "SensorLargePulse"
			))
			if (%hTgt.deployed != true)
				%canPerform = false;
		if (!$Host::AllowUnderground) {
			if (%dataBlockName $= "TelePadDeployedBase")
					%canPerform = false;
		}
		if (%canPerform == true) {
			// yes, it's selectable
			if (%hTgt != %obj.performing) {
				if (isObject(%obj.performing))
					stopPerforming(%obj);
				%obj.performing = %hTgt;
				startPerforming(%obj);
			}
			// setting imageLoaded to true sends us to select state (function onPerformAction)
			%obj.setImageLoaded(%slot, true);
		}
		else {
			// there is a target in range, but it's not selectable
			if (!%obj.errMsgSent) {
				messageClient(%obj.client, 'msgClient', '\c2You can\'t select/rotate that.');
				%obj.errMsgSent = true;
			}
			// if player was selecting something, stop the selecting -- we're done
			if (%obj.performing > 0)
				stopPerforming(%obj);
		}
	}
	else {
		// there is no target in range
		if (!%obj.errMsgSent) {
			// send an error message only once
			messageClient(%obj.client, 'msgClient', '\c2No target to select/rotate.');
			%obj.errMsgSent = true;
		}
	}
}

function onPerformAdvancedRotate(%this,%obj,%slot) {
	// Account for lag, and make gun a bit less trigger happy
	%m2 = %obj.constructionToolMode2;
	if (%m2 == 2 || %m2 == 3 || %m2 == 4 || %m2 == 5) {
		if (getSimTime() < (%obj.constructionToolTime + 500))
			return;
	}
	else {
		if (getSimTime() < (%obj.constructionToolTime + 500) && %obj.performTime < 0)
			return;
	}
	%obj.constructionToolTime = getSimTime();

	// Load rotation list
	%list = %obj.rotList;

	// Validate list
	%size = getWordCount(%list);
	for(%id = 0; %id < %size; %id++) {
		if (!isObject(getWord(%list,%id)))
		%badIDs = %badIDs SPC %id;
	}
	%list = listDel(%list,trim(%badIDs));

	if (!%list) // Is there a rotation list?
		%list = %obj; // Set player as center.

	// Save list
	%obj.rotList = %list;

	if (%obj.rotSpeed == 0) // So players can rotate without specifically setting rotSpeed
		%obj.rotSpeed = 1;

	if (%obj.constructionToolMode2 == 2) {
		%obj.rotSpeed++;
		if (%obj.rotSpeed > 3)
			%obj.rotSpeed = -3;
		if (%obj.rotSpeed == 0)
			%obj.rotSpeed = 1;
		%mod = lev(%obj.rotSpeed) * 5 * mPow(3,mAbs(%obj.rotSpeed) -1);
		bottomPrint(%obj.client,"Rotation speed set to:" SPC %mod SPC " degrees per tick",2,1);
		return;
	}
	else if(%obj.constructionToolMode2 == 3) {
		%angle =lev(%obj.rotSpeed) * 5 * mPow(3,mAbs(%obj.rotSpeed) -1) / 180 * $Pi;
		%mod = lev(%obj.rotSpeed) * 5 * mPow(3,mAbs(%obj.rotSpeed) -1);
		rotateSection(getWord(%list,0),%list,"0 0 1" SPC %angle);
		%obj.constructionToolTime = %obj.constructionToolTime + (getWordCount(%list) * 100);
		bottomPrint(%obj.client,getWordCount(%list) SPC "objects rotated" SPC %mod SPC " degrees (wait " @ mFloor((%obj.constructionToolTime - getSimTime()) / 1000) @ " seconds)",2,1);
		return;
	}
	else if(%obj.constructionToolMode2 == 4) {
		for(%id = 0; %id < getWordCount(%list); %id++) {
			%obj = getWord(%list,%id);
			%obj.startFade(400,%id * 100,0);
			if (isObject(%obj.lMain))
				%obj.lMain.startFade(400,%id * 100,0);
		}
		bottomPrint(%obj.client,getWordCount(%list) SPC "objects selected including the rotation center",2,1);
		return;
	}
	else if(%obj.constructionToolMode2 == 5) {
		%list = "";
		%obj.rotList = %list;
		bottomPrint(%obj.client,"All objects removed from rotation list - player set as rotation center",2,1);
		return;
	}

	%target = %obj.performing;
	if (!%target) {
		// no target -- whoops! never mind
		stopPerforming(%obj);
		return;
	}
	%hGun = %obj.getMountedImage(%slot);
	// muzVec is the vector coming from the construction tool's "muzzle"
	%muzVec = %obj.getMuzzleVector(%slot);
	// muzNVec = normalized muzVec
	%muzNVec = VectorNormalize(%muzVec);
	%beamRange = ConstructionToolBeam.beamRange;
	// scale muzNVec to the range the repair beam can reach
	%muzScaled = VectorScale(%muzNVec, %beamRange);
	// muzPoint = the actual point of the gun's "muzzle"
	%muzPoint = %obj.getMuzzlePoint(%slot);
	// rangeEnd = muzzle point + length of beam
	%rangeEnd = VectorAdd(%muzPoint, %muzScaled);
	// search for just about anything that can be damaged as well as interiors
	%searchMasks = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType;
	// search for objects within the beam's range that fit the masks above
	%scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj);
	// screen out interiors
	if (%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) {
		// a target in range was found
		%hTgt = firstWord(%scanTarg);
		// can it be selected? is it already being tooled?
		if ($ReverseDeployItem[%hTgt.getDataBlock().getName()] !$= "" && !%hTht.beingPerformed)
			%canPerform = true;
		// Only select deployed items, not base ones
		%dataBlockName = %hTgt.getDataBlock().getName();
		if (%dataBlockName $= "DeployedLTarget" && !isObject(%hTgt.lMain))
			%canPerform = false;
		if (%canPerform == true && (
			%dataBlockName $= "StationInventory" ||
			%dataBlockName $= "GeneratorLarge" ||
			%dataBlockName $= "SolarPanel" ||
			%dataBlockName $= "SensorMediumPulse" ||
			%dataBlockName $= "SensorLargePulse"
			))
			if (%hTgt.deployed != true)
				%canPerform = false;
		if (!$Host::AllowUnderground) {
			if (%dataBlockName $= "TelePadDeployedBase")
					%canPerform = false;
		}
		if (%canPerform == true) {
			// yes, it's selectable
			if (%hTgt != %obj.performing) { // its not what we were originally selecting
				if (isObject(%obj.performing)) {
					stopPerforming(%obj);
					%obj.performing = %hTgt;
					startPerforming(%obj);
				}
			}
			else { // continue selecting
				%obj.performTime = %obj.performTime - 120;
				if (%obj.performTime < 0) { // we have a select!
					if (%hTgt.team != %obj.team && !(%obj.client.isAdmin || %obj.client.isSuperAdmin)) {
						messageClient(%obj.client, 'msgClient', '\c2Select failed! Wrong team!~wfx/powered/nexus_deny.wav');
						stopPerforming(%obj);
						return;
					}
					if ($Host::OnlyOwnerRotate == 1 && %hTgt.getOwner() != %obj.client && !(%obj.client.isAdmin || %obj.client.isSuperAdmin)) {
						messageClient(%obj.client, 'msgClient', '\c2Select failed! Not your stuff!~wfx/powered/nexus_deny.wav');
						stopPerforming(%obj);
						return;
					}
					if (%obj.constructionToolMode2 == 0) {
						if (%hTgt ==  getWord(%list,0)) { // Is it already the center?
							%list = listReplace(%list,%obj,0); // Replace player as center
							bottomPrint(%obj.client,"Object deselected as center",2,1);
						}
						else {
							// Remove it from the list if it was in the list to start with.
							%loc = findWord(%list,%hTgt);
							if (%loc !$= "")
								%list = listDel(%list,%loc);
							%list = listReplace(%list,%hTgt,0); // Replace player as center
							bottomPrint(%obj.client,"Object selected as center",2,1);
						}
						%hTgt.startFade(400,%id * 100,0);
						if (isObject(%hTgt.lMain))
							%hTgt.lMain.startFade(400,%id * 100,0);
					}
					else if (%obj.constructionToolMode2 == 1) {
						if (%hTgt ==  getWord(%list,0))
							bottomPrint(%obj.client,"Object is already center of rotation",2,1);
						else {
							%loc = findWord(%list,%hTgt);
							if (%loc !$= "") { // Is it already in the list?
								%list = listDel(%list,%loc);
								bottomPrint(%obj.client,"Object deselected",2,1);
							}
							else {
								%tempList = %list;
								%list = %tempList SPC %hTgt;
								bottomPrint(%obj.client,"Object Selected",2,1);
							}
						}
						%hTgt.startFade(400,%id * 100,0);
						if (isObject(%hTgt.lMain))
							%hTgt.lMain.startFade(400,%id * 100,0);
					}
				}
			}
		}
	}
	else
		stopPerforming(%obj);
	%obj.rotList = %list;
}

// --------------------------------------------------------------------------------
// Power management functions
// --------------------------------------------------------------------------------

function onValidatePowerManagement(%this,%obj,%slot) {

	%m2 = %obj.constructionToolMode2;
	if (%m2 == 1 || %m2 == 2) {
		%obj.setImageLoaded(%slot, true);
		return;
	}

	%hGun = %obj.getMountedImage(%slot);
	// muzVec is the vector coming from the construction tool's "muzzle"
	%muzVec = %obj.getMuzzleVector(%slot);
	// muzNVec = normalized muzVec
	%muzNVec = VectorNormalize(%muzVec);
	%beamRange = ConstructionToolBeam.beamRange;
	// scale muzNVec to the range the repair beam can reach
	%muzScaled = VectorScale(%muzNVec, %beamRange);
	// muzPoint = the actual point of the gun's "muzzle"
	%muzPoint = %obj.getMuzzlePoint(%slot);
	// rangeEnd = muzzle point + length of beam
	%rangeEnd = VectorAdd(%muzPoint, %muzScaled);
	// search for just about anything that can be damaged as well as interiors
	%searchMasks = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType;
	// search for objects within the beam's range that fit the masks above
	%scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj);
	// screen out interiors
	if (%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) {
		// a target in range was found
		%hTgt = firstWord(%scanTarg);
		// can it be used? is it already being tooled?
		if ($ReverseDeployItem[%hTgt.getDataBlock().getName()] !$= "" && !%hTht.beingPerformed)
			%canPerform = true;
		// Only use deployed items, not base ones
		%dataBlockName = %hTgt.getDataBlock().getName();
		if (%dataBlockName $= "DeployedLTarget" && !isObject(%hTgt.lMain))
			%canPerform = false;
		if (%canPerform == true && (
			%dataBlockName $= "StationInventory" ||
			%dataBlockName $= "GeneratorLarge" ||
			%dataBlockName $= "SolarPanel" ||
			%dataBlockName $= "SensorMediumPulse" ||
			%dataBlockName $= "SensorLargePulse"
			))
			if (%hTgt.deployed != true)
				%canPerform = false;
		if (%canPerform == true) {
			// yes, it's usable
			if (%hTgt != %obj.performing) {
				if (isObject(%obj.performing))
					stopPerforming(%obj);
				%obj.performing = %hTgt;
				startPerforming(%obj);
			}
			// setting imageLoaded to true sends us to use state (function onPerformAction)
			%obj.setImageLoaded(%slot, true);
		}
		else {
			// there is a target in range, but it's not usable
			if (!%obj.errMsgSent) {
				messageClient(%obj.client, 'msgClient', '\c2You can\'t use that.');
				%obj.errMsgSent = true;
			}
			// if player was using something, stop it -- we're done
			if (%obj.performing > 0)
				stopPerforming(%obj);
		}
	}
	else {
		// there is no target in range
		if (!%obj.errMsgSent) {
			// send an error message only once
			messageClient(%obj.client, 'msgClient', '\c2No target to use.');
			%obj.errMsgSent = true;
		}
	}
}

function onPerformPowerManagement(%this,%obj,%slot) {
	// Account for lag, and make gun a bit less trigger happy
	%m2 = %obj.constructionToolMode2;
	if (%m2 == 1 || %m2 == 2) {
		if (getSimTime() < (%obj.constructionToolTime + 500))
			return;
	}
	else {
		if (getSimTime() < (%obj.constructionToolTime + 500) && %obj.performTime < 0)
			return;
	}
	%obj.constructionToolTime = getSimTime();

	if (%obj.constructionToolMode2 == 1) {
		%obj.powerFreq++;
		if (%obj.powerFreq > upperPowerFreq(%obj))
			%obj.powerFreq = 1;
		displayPowerFreq(%obj);
		return;
	}
	else if (%obj.constructionToolMode2 == 2) {
		%obj.powerFreq--;
		if (%obj.powerFreq < 1)
			%obj.powerFreq = upperPowerFreq(%obj);
		displayPowerFreq(%obj);
		return;
	}

	%target = %obj.performing;
	if (!%target) {
		// no target -- whoops! never mind
		stopPerforming(%obj);
		return;
	}

	%hGun = %obj.getMountedImage(%slot);
	// muzVec is the vector coming from the construction tool's "muzzle"
	%muzVec = %obj.getMuzzleVector(%slot);
	// muzNVec = normalized muzVec
	%muzNVec = VectorNormalize(%muzVec);
	%beamRange = ConstructionToolBeam.beamRange;
	// scale muzNVec to the range the repair beam can reach
	%muzScaled = VectorScale(%muzNVec, %beamRange);
	// muzPoint = the actual point of the gun's "muzzle"
	%muzPoint = %obj.getMuzzlePoint(%slot);
	// rangeEnd = muzzle point + length of beam
	%rangeEnd = VectorAdd(%muzPoint, %muzScaled);
	// search for just about anything that can be damaged as well as interiors
	%searchMasks = $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType;
	// search for objects within the beam's range that fit the masks above
	%scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj);
	// screen out interiors
	if (%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) {
		// a target in range was found
		%hTgt = firstWord(%scanTarg);
		// can it be used? is it already being tooled?
		if ($ReverseDeployItem[%hTgt.getDataBlock().getName()] !$= "" && !%hTht.beingPerformed)
			%canPerform = true;
		// Only use deployed items, not base ones
		%dataBlockName = %hTgt.getDataBlock().getName();
		if (%dataBlockName $= "DeployedLTarget" && !isObject(%hTgt.lMain))
			%canPerform = false;
		if (%canPerform == true && (
			%dataBlockName $= "StationInventory" ||
			%dataBlockName $= "GeneratorLarge" ||
			%dataBlockName $= "SolarPanel" ||
			%dataBlockName $= "SensorMediumPulse" ||
			%dataBlockName $= "SensorLargePulse"
			))
			if (%hTgt.deployed != true)
				%canPerform = false;
		if (%canPerform == true) {
			// yes, it's usable
			if (%hTgt != %obj.performing) { // its not what we were originally using
				if (isObject(%obj.performing)) {
					stopPerforming(%obj);
					%obj.performing = %hTgt;
					startPerforming(%obj);
				}
			}
			else { // continue using
				%obj.performTime = %obj.performTime - 120;
				if (%obj.performTime < 0) { // we have a use!
					if (%hTgt.team != %obj.team && !(%obj.client.isAdmin || %obj.client.isSuperAdmin)) {
						messageClient(%obj.client, 'msgClient', '\c2Use failed! Wrong team!~wfx/powered/nexus_deny.wav');
						stopPerforming(%obj);
						return;
					}
					if ($Host::OnlyOwnerDeconstruct == 1 && %hTgt.getOwner() != %obj.client && !(%obj.client.isAdmin || %obj.client.isSuperAdmin)) {
						if (isObject(%hTgt.getOwner()))
							messageClient(%obj.client, 'msgClient', '\c2Use failed! This belongs to %1!~wfx/powered/nexus_deny.wav', %hTgt.getOwner().nameBase);
						else
							messageClient(%obj.client, 'msgClient', '\c2Use failed! Not your stuff!~wfx/powered/nexus_deny.wav');
						stopPerforming(%obj);
						return;
					}
					if (%obj.constructionToolMode2 == 0) {
						if (%hTgt.getDataBlock().className !$= "Generator") {
							messageClient(%obj.client, 'msgClient', '\c2Use failed! Not a generator!~wfx/powered/nexus_deny.wav');
							stopPerforming(%obj);
							return;
						}
						else {
							%r = toggleGenerator(%hTgt);
							%r1 = firstWord(%r);
							%r2 = getTaggedString(getWord(%r,1));
							%r3 = getWord(%r,2);
							if (%r1 == -2)
								messageClient(%obj.client, 'msgClient', '\c2Use failed! %1 is damaged!~wfx/powered/nexus_deny.wav',%r2);
							else if (%r1 == -3)
								messageClient(%obj.client, 'msgClient', '\c2Must wait %1 seconds before toggling power state.',mCeil(%r3/1000));
							else if (%r1 == 1)
								messageClient(%obj.client, 'msgClient', '\c2%1 switched off.',%r2);
							else if (%r1 == 2)
								messageClient(%obj.client, 'msgClient', '\c2%1 switched on.',%r2);
							stopPerforming(%obj);
							return;
						}
					}
					if (%obj.constructionToolMode2 == 3) {
//						if (%hTgt.powerFreq !$= "" || %hTgt.getDataBlock().needsPower) {
							%numLines = 1;
							if (%hTgt.powerFreq !$= "")
								%msg = "Power frequency is " @ %hTgt.powerFreq @ ", power is " @ (%hTgt.isPowered() ? ((%hTgt.powerCount > 0) ? (%hTgt.powerCount) : "On") : "OFF");
							else
								%msg = "Item does not have power frequency set";
							if (%hTgt.getOwner().nameBase !$= "") {
								%numLines++;
								%msg = %msg @ "\nThis belongs to " @ %hTgt.getOwner().nameBase;
                                                        }
                                                        if (%obj.client.isAdmin || %obj.client.isSuperAdmin) {
                                                                %numLines++;
                                                                %msg = %msg @ "\n [Owner Clientid]:" SPC %hTgt.getOwner() SPC "[Object id]:" SPC %htgt;
							}
							bottomPrint(%obj.client,%msg,2,%numLines);
							stopPerforming(%obj);
//						}
					}
				}
			}
		}
	}
	else
		stopPerforming(%obj);
	%obj.rotList = %list;
}
