// SaveBuilding.cs
//
// This script made possible by a joint effort of DynaBlade and JackTL
//
// Functions:
//
// saveBuilding(clientId,radius,file[$],quiet[1/0])
// saveBuildingCentered(clientId,radius,file[$],quiet[1/0],centerAtMinZ[1/0])
// delBuildingWaypoint()
// loadBuilding(file[$])
// saveBuildingTimer(time in seconds,globalEcho[1/0],file[$],useMultipleFiles[1/0]) // No limit on multiple files yet. Beware
// saveBuildingTimerOn() // <-- for restarting timed saves, does not initialize like saveBuildingTimer()
// saveBuildingTimerOff()
// delDupPieces(clientId,radius,quiet[1/0]) // NOTE: There are issues with calling this function a second time before the previous call's deconstruction has finished
//
// See functions for (some) comments

if ($SaveBuilding::SaveFolder $= "")
	$SaveBuilding::SaveFolder = "Buildings/";
if ($SaveBuilding::AutoSaveFolder $= "")
	$SaveBuilding::AutoSaveFolder = "Buildings/AutoSave/";
if ($SaveBuilding::TimerDefaultTime $= "")
	$SaveBuilding::TimerDefaultTime = 5 * 60 * 1000; // 5 minutes. Saving may cause stutter on low-end servers with high number of pieces
if ($SaveBuilding::QuickDelete $= "")
	$SaveBuilding::QuickDelete = 1;


// See if we want to save the piece
function saveBuildingCheck(%obj) {
	%save = false;
	%dataBlockName = %obj.getDatablock().getName();
	switch$ (%dataBlockName) {
		case "DeployedSpine":
			%save = true;
		case "DeployedWoodSpine":
			%save = true;
		case "DeployedMSpine":
			%save = true;
		case "DeployedMSpineRing":
			%save = true;
		case "DeployedFloor":
			%save = true;
		case "DeployedWall":
			%save = true;
		case "DeployedwWall":
			%save = true;
		case "DeployedEnergizer":
			%save = true;
		case "DeployedStationInventory":
			%save = true;
		case "DeployedJumpad":
			%save = true;
		case "DeployedEscapePod":
			%save = true;
		case "TelePadDeployedBase":
			%save = true;
		case "TelePadBeam":
			%save = true;
		case "DeployedLTarget":
			%save = true;
		case "DeployedLogoProjector":
			%save = true;
		case "DeployedSwitch":
			%save = true;
		case "DeployedPulseSensor":
			%save = true;
		case "DeployedMotionSensor":
			%save = true;
		case "TurretDeployedBase":
			%save = true;
		case "TurretDeployedFloorIndoor":
			%save = true;
		case "TurretDeployedWallIndoor":
			%save = true;
		case "TurretDeployedCeilingIndoor":
			%save = true;
		case "TurretDeployedOutdoor":
			%save = true;
		case "LaserDeployed":
			%save = true;
		case "MissileRackTurretDeployed":
			%save = true;
		case "DiscTurretDeployed":
			%save = true;
		case "TurretDeployedCamera":
			%save = true;
		case "DeployedLightBase":
			%save = true;
		case "DeployedTripwire":
			%save = true;
                case "DispenserDep":
			%save = true;
                case "AudioDep":
			%save = true;
                case "EmitterDep":
			%save = true;
	}
	if (%dataBlockName $= "StationInventory" && %obj.deployed == true)
		%save = true;
	if (%dataBlockName $= "GeneratorLarge" && %obj.deployed == true)
		%save = true;
	if (%dataBlockName $= "SolarPanel" && %obj.deployed == true)
		%save = true;
	if (%dataBlockName $= "SensorMediumPulse" && %obj.deployed == true)
		%save = true;
	if (%dataBlockName $= "SensorLargePulse" && %obj.deployed == true)
		%save = true;
	if (getSubStr(%dataBlockName,0,18) $= "DeployedForceField")
		%save = true;
	if (getSubStr(%dataBlockName,0,20) $= "DeployedGravityField")
		%save = true;
	if (getSubStr(%dataBlockName,0,12) $= "DeployedTree")
		%save = true;
	if (getSubStr(%dataBlockName,0,13) $= "DeployedCrate")
		%save = true;
	if (getSubStr(%dataBlockName,0,18) $= "DeployedDecoration")
		%save = true;
	return %save;
}

// This function saves a building and its position in the map
function saveBuilding(%cl,%rad,%file,%quiet,%isAutoSave) {
	if (%quiet == true) {
		$SaveBuilding::Quiet = true;
	}
	else {
		$SaveBuilding::Quiet = false; // Overwrite
	}
	%origCl = %cl;
	if (!isObject(%cl)) {
		if (isObject(nameToID(LocalClientConnection))) {
			%cl = nameToID(LocalClientConnection);
		}
		else {
			if ($CurrentClientId) {
				%cl = $CurrentClientId;
			}
		}
	}
	if (%rad < 1) {
		%rad = 100000;
	}
	%buildingCount = 0;
	if (%file $= "" || %file $= "0") {
		for(%found = true; %found; %buildingCount++ ) {
			%suffix = %buildingCount;
			while (strLen(%suffix) < 5) %suffix = "0" @ %suffix;
			if (%isAutoSave)
				%file = $SaveBuilding::AutoSaveFolder @ $MissionName @ "-" @ %suffix @ ".cs";
			else
				%file = $SaveBuilding::SaveFolder @ %cl.nameBase @ "-" @ $MissionName @ "-" @ %suffix @ ".cs";
			%found = isFile(%file);
		}
	}
	else {
		if (%isAutoSave)
			%file = $SaveBuilding::AutoSaveFolder @ %file;
		else
			%file = $SaveBuilding::SaveFolder @ %file;
	}
	if (isObject(%cl.getControlObject())) {
		%pos = %cl.getControlObject().getPosition();
	}
	if (!%pos) {
		%pos = "0 0 0";
	}
	if (%isAutoSave && (%origCl $= "" || %origCl $= "0"))
		%pos = "0 0 0";
	new fileObject("Building");
	if (!$SaveBuilding::Quiet) {
		warn("Saving to file: \"" @ %file @ "\"");
	}
	Building.openForWrite(%file);
	Building.writeLine("// CONSTRUCTION MOD SAVE FILE");
	Building.writeLine("// Saved by \"" @ getField(%cl.nameBase,0) @ "\"");
	Building.writeLine("// Created in mission \"" @ $MissionName @ "\"");
	Building.writeLine("// Construction " @ $ModVersion);
	Building.writeLine("");

	$SaveBuilding::Saved = 0;
	$SaveBuilding::Skipped = 0;
	initContainerRadiusSearch(%pos,%rad,$TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType);
	while((%obj = containerSearchNext()) != 0) {
		%cmp = writeBuildingComponent(%obj);
		if (%cmp !$= "") {
			Building.writeLine(%cmp);
		}
	}

	if (!$SaveBuilding::Quiet) {
		warn("Saved to file: \"" @ %file @ "\"");
		warn("Saved pieces: " @ $SaveBuilding::Saved);
		warn("Skipped pieces: " @ $SaveBuilding::Skipped);
	}

	$SaveBuilding::LastFile = %file;

	Building.close();
	Building.delete();
	return %file;
}

function writeBuildingComponent(%obj) {
	%dataBlockName = %obj.getDatablock().getName();
	%save = false;
	%save = saveBuildingCheck(%obj);
	if (%save == true) {
		if (%dataBlockName $= "DeployedMSpineRing") // Handled by DeployedMSpine
			return;
		if (%dataBlockName $= "TelePadBeam") // Handled by TelePadDeployedBase
			return;
		if (%dataBlockName $= "DeployedLTarget") // Handled by parent object
			return;
		if (!$SaveBuilding::Quiet)
			echo("Saving: " @ %obj @ " Name: " @ %dataBlockName);
		%buildingPiece = "%building = new (" @ %obj.getClassName() @ ") () {";
		%buildingPiece = %buildingPiece @ "datablock = \"" @ %dataBlockName @ "\";";
		if (%obj.position !$= "") %buildingPiece = %buildingPiece @ "position = \"" @ %obj.position @ "\";";
		if (%obj.rotation !$= "") %buildingPiece = %buildingPiece @ "rotation = \"" @ %obj.rotation @ "\";";
		if (%obj.realScale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %obj.realScale @ "\";";
		else {if (%obj.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %obj.scale @ "\";";}
		if (%obj.team !$= "") %buildingPiece = %buildingPiece @ "team = \"" @ %obj.team @ "\";";
		if (%obj.ownerGUID !$= "") %buildingPiece = %buildingPiece @ "ownerGUID = \"" @ %obj.ownerGUID @ "\";";
		if (%obj.needsFit) %buildingPiece = %buildingPiece @ "needsfit = \"" @ %obj.needsFit @ "\";";
		if (%obj.grounded) %buildingPiece = %buildingPiece @ "grounded = \"" @ %obj.grounded @ "\";";
		if (%obj.deployed !$= "") %buildingPiece = %buildingPiece @ "deployed = \"" @ %obj.deployed @ "\";";
		if (%obj.impulse !$= "") %buildingPiece = %buildingPiece @ "impulse = \"" @ %obj.impulse @ "\";";
		if (%obj.velocityMod !$= "") %buildingPiece = %buildingPiece @ "velocityMod = \"" @ %obj.velocityMod @ "\";";
		if (%obj.gravityMod !$= "") %buildingPiece = %buildingPiece @ "gravityMod = \"" @ %obj.gravityMod @ "\";";
		if (%obj.appliedForce !$= "") %buildingPiece = %buildingPiece @ "appliedForce = \"" @ %obj.appliedForce @ "\";";
		if (%obj.powerFreq !$= "") %buildingPiece = %buildingPiece @ "powerFreq = \"" @ %obj.powerFreq @ "\";";
		if (%obj.isSwitchedOff !$= "") %buildingPiece = %buildingPiece @ "isSwitchedOff = \"" @ %obj.isSwitchedOff @ "\";";
		if (%obj.switchRadius !$= "") %buildingPiece = %buildingPiece @ "switchRadius = \"" @ %obj.switchRadius @ "\";";
		if (%obj.holoBlock !$= "") %buildingPiece = %buildingPiece @ "holoBlock = \"" @ %obj.holoBlock @ "\";";
		if (%obj.noSlow !$= "") %buildingPiece = %buildingPiece @ "noSlow = \"" @ %obj.noSlow @ "\";";
		if (%obj.static !$= "") %buildingPiece = %buildingPiece @ "static = \"" @ %obj.static @ "\";";
		if (%obj.timed !$= "") %buildingPiece = %buildingPiece @ "timed = \"" @ %obj.timed @ "\";";
		if (%obj.beamRange !$= "") %buildingPiece = %buildingPiece @ "beamRange = \"" @ %obj.beamRange @ "\";";
		if (%obj.tripMode !$= "") %buildingPiece = %buildingPiece @ "tripMode = \"" @ %obj.tripMode @ "\";";
		if (%obj.fieldMode !$= "") %buildingPiece = %buildingPiece @ "fieldMode = \"" @ %obj.fieldMode @ "\";";
		if (%dataBlockName $= "TelePadDeployedBase") {
			if (%obj.frequency !$= "") %buildingPiece = %buildingPiece @ "frequency = \"" @ %obj.frequency @ "\";";
			if (%obj.teleMode !$= "") %buildingPiece = %buildingPiece @ "teleMode = \"" @ %obj.teleMode @ "\";";
		}
		if (%obj.getType() & $TypeMasks::TurretObjectType) {
			if (%obj.isSeeker !$= "") %buildingPiece = %buildingPiece @ "isSeeker = \"" @ %obj.isSeeker @ "\";";
			%barrel = %obj.getMountedImage(0);
			if (%barrel > 0)
				%buildingPiece = %buildingPiece @ "initialBarrel = \"" @ %barrel.getName() @ "\";";
		}
		%buildingPiece = %buildingPiece @ "};";
		if (%obj.getTarget() != -1) %buildingPiece = %buildingPiece @ "setTargetSensorGroup(%building.getTarget()," @ mAbs(%obj.team) @ ");";
		%buildingPiece = %buildingPiece @ "addToDeployGroup(%building);";
		if (%obj.noSlow !$= "") %buildingPiece = %buildingPiece @ "%building.pzone.delete();%building.pzone = \"\";";
		if (%dataBlockName $= "DeployedEnergizer" || %dataBlockName $= "DeployedStationInventory" || %dataBlockName $= "StationInventory"
		|| %dataBlockName $= "TurretDeployedFloorIndoor" || %dataBlockName $= "TurretDeployedWallIndoor" || %dataBlockName $= "TurretDeployedCeilingIndoor"
		|| %dataBlockName $= "TurretDeployedOutdoor" || %dataBlockName $= "DeployedPulseSensor"
		|| %dataBlockName $= "LaserDeployed" || %dataBlockName $= "MissileRackTurretDeployed" || %dataBlockName $= "DiscTurretDeployed") {
			%buildingPiece = %buildingPiece @ "%building.deploy();";
			if (%dataBlockName $= "StationInventory")
				%buildingPiece = %buildingPiece @ "adjustTrigger(%building);";
		}
		if (%obj.getDatablock().rechargeRate > 0 && !%obj.getDatablock().needsPower) %buildingPiece = %buildingPiece @ "%building.setSelfPowered();";
		if (%obj.getType() & $TypeMasks::TurretObjectType)
			%buildingPiece = %buildingPiece @ "%building.setRechargeRate(%building.getDatablock().rechargeRate);";
		if (%obj.getDataBlock().className $= "Generator" || %obj.getDataBlock().className $= "Switch") {
			if (%obj.isSwitchedOff)
				%buildingPiece = %buildingPiece @ "setTargetName(%building.target,addTaggedString(\"Disabled Frequency\" SPC %building.powerFreq));";
			else
				%buildingPiece = %buildingPiece @ "setTargetName(%building.target,addTaggedString(\"Frequency\" SPC %building.powerFreq));";
			if (%dataBlockName $= "DeployedSwitch")
				%buildingPiece = %buildingPiece @ "setTargetSkin(%building.target,'" @ getTaggedString(getTargetSkin(%obj.target)) @ "');";
				if (!%obj.isSwitchedOff)
					%buildingPiece = %buildingPiece @ "%building.playThread($AmbientThread,\"ambient\");";
			else {
				if (%obj.isSwitchedOff)
					// nb: doubles no. of power switches done, when loading switched off gens
					%buildingPiece = %buildingPiece @ "%building.lastState = \"\";%building.getDataBlock().losePower(%building);";
			}
		}
		$SaveBuilding::Saved++;
// Ugly, but it works. May be cleaned up later.
		if (isObject(%obj.lTarget)) { // We assume none of the later saved sub-objects need decon targets, could make this a subroutine
			%target = %obj.lTarget;
			%targetDataBlock = %target.getDatablock().getName();
			if (!$SaveBuilding::Quiet)
				echo("Saving: " @ %target @ " Name: " @ %targetDataBlock);
			%buildingPiece = %buildingPiece @ "%target = new StaticShape() {";
			%buildingPiece = %buildingPiece @ "datablock = \"" @ %targetDataBlock @ "\";";
			if (%target.position !$= "") %buildingPiece = %buildingPiece @ "position = \"" @ %target.position @ "\";";
			if (%target.rotation !$= "") %buildingPiece = %buildingPiece @ "rotation = \"" @ %target.rotation @ "\";";
			if (%target.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %target.scale @ "\";";
			if (%target.team) %buildingPiece = %buildingPiece @ "team = \"" @ %target.team @ "\";";
			%buildingPiece = %buildingPiece @ "lMain = %building;";
			%buildingPiece = %buildingPiece @ "};";
			%buildingPiece = %buildingPiece @ "%building.lTarget = %target;";
			%buildingPiece = %buildingPiece @ "addToDeployGroup(%target);";
			if (%target.getDatablock().rechargeRate > 0 && !%target.getDatablock().needsPower) %buildingPiece = %buildingPiece @ "%building.setSelfPowered();";
		}
		if (%dataBlockName $= "DeployedMSpine") {
			%left = %obj.left;
			%right = %obj.right;
			if (isObject(%left)) {
				%leftDataBlock = %left.getDatablock().getName();
				if (!$SaveBuilding::Quiet)
					echo("Saving: " @ %left @ " Name: " @ %leftDataBlock);
				%buildingPiece = %buildingPiece @ "%left = new StaticShape() {";
				%buildingPiece = %buildingPiece @ "datablock = \"" @ %leftDataBlock @ "\";";
				if (%left.position !$= "") %buildingPiece = %buildingPiece @ "position = \"" @ %left.position @ "\";";
				if (%left.rotation !$= "") %buildingPiece = %buildingPiece @ "rotation = \"" @ %left.rotation @ "\";";
				if (%left.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %left.scale @ "\";";
				if (%left.team) %buildingPiece = %buildingPiece @ "team = \"" @ %left.team @ "\";";
				if (%left.needsFit) %buildingPiece = %buildingPiece @ "needsfit = \"" @ %left.needsFit @ "\";";
				%buildingPiece = %buildingPiece @ "};";
				%buildingPiece = %buildingPiece @ "%building.left = %left;";
				%buildingPiece = %buildingPiece @ "addToDeployGroup(%left);";
				if (%left.getDatablock().rechargeRate > 0 && !%left.getDatablock().needsPower) %buildingPiece = %buildingPiece @ "%building.setSelfPowered();";
				$SaveBuilding::Saved++;
			}
			if (isObject(%right)) {
				%rightDataBlock = %right.getDatablock().getName();
				if (!$SaveBuilding::Quiet)
					echo("Saving: " @ %right @ " Name: " @ %rightDataBlock);
				%buildingPiece = %buildingPiece @ "%right = new StaticShape() {";
				%buildingPiece = %buildingPiece @ "datablock = \"" @ %rightDataBlock @ "\";";
				if (%right.position !$= "") %buildingPiece = %buildingPiece @ "position = \"" @ %right.position @ "\";";
				if (%right.rotation !$= "") %buildingPiece = %buildingPiece @ "rotation = \"" @ %right.rotation @ "\";";
				if (%right.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %right.scale @ "\";";
				if (%right.team) %buildingPiece = %buildingPiece @ "team = \"" @ %right.team @ "\";";
				if (%right.needsFit) %buildingPiece = %buildingPiece @ "needsfit = \"" @ %right.needsFit @ "\";";
				%buildingPiece = %buildingPiece @ "};";
				%buildingPiece = %buildingPiece @ "%building.right = %right;";
				%buildingPiece = %buildingPiece @ "addToDeployGroup(%right);";
				if (%right.getDatablock().rechargeRate > 0 && !%right.getDatablock().needsPower) %buildingPiece = %buildingPiece @ "%building.setSelfPowered();";
				$SaveBuilding::Saved++;
			}
		}
		else if (%dataBlockName $= "TelePadDeployedBase") {
			%beam = %obj.beam;
			if (isObject(%beam)) {
				%beamDataBlock = %beam.getDatablock().getName();
				if (!$SaveBuilding::Quiet)
					echo("Saving: " @ %beam @ " Name: " @ %beamDataBlock);
				%buildingPiece = %buildingPiece @ "%beam = new StaticShape() {";
				%buildingPiece = %buildingPiece @ "datablock = \"" @ %beamDataBlock @ "\";";
				if (%beam.position !$= "") %buildingPiece = %buildingPiece @ "position = \"" @ %beam.position @ "\";";
				if (%beam.rotation !$= "") %buildingPiece = %buildingPiece @ "rotation = \"" @ %beam.rotation @ "\";";
				if (%beam.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %beam.scale @ "\";";
				%buildingPiece = %buildingPiece @ "};";
				%buildingPiece = %buildingPiece @ "%building.beam = %beam;";
				%buildingPiece = %buildingPiece @ "%beam.playThread(0,\"ambient\");";
				%buildingPiece = %buildingPiece @ "%beam.setThreadDir(0,true);";
				%buildingPiece = %buildingPiece @ "%beam.flashThreadDir = true;";
				%buildingPiece = %buildingPiece @ "setTargetName(%building.target,addTaggedString(\"Frequency\" SPC %building.frequency));";
			}
		}
		else if (%dataBlockName $= "DeployedLogoProjector") {
			%holo = %obj.holo;
			if (isObject(%holo)) {
				%holoDataBlock = %holo.getDatablock().getName();
				if (!$SaveBuilding::Quiet)
					echo("Saving: " @ %holo @ " Name: " @ %holoDataBlock);
				%buildingPiece = %buildingPiece @ "%holo = new StaticShape() {";
				%buildingPiece = %buildingPiece @ "datablock = \"" @ %holoDataBlock @ "\";";
				if (%holo.position !$= "") %buildingPiece = %buildingPiece @ "position = \"" @ %holo.position @ "\";";
				if (%holo.rotation !$= "") %buildingPiece = %buildingPiece @ "rotation = \"" @ %holo.rotation @ "\";";
				if (%holo.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %holo.scale @ "\";";
				%buildingPiece = %buildingPiece @ "};";
				%buildingPiece = %buildingPiece @ "%building.holo = %holo;";
				%buildingPiece = %buildingPiece @ "%holo.projector = %building;";
			}
		}
		else if (%dataBlockName $= "DeployedLightBase") {
			%light = %obj.light;
			if (isObject(%light)) {
				%lightDataBlock = %light.getDatablock().getName();
				if (!$SaveBuilding::Quiet)
					echo("Saving: " @ %light @ " Name: " @ %lightDataBlock);
				%buildingPiece = %buildingPiece @ "%light = new Item() {";
				%buildingPiece = %buildingPiece @ "datablock = \"" @ %lightDataBlock @ "\";";
				%buildingPiece = %buildingPiece @ "static = true;";
				%buildingPiece = %buildingPiece @ "};";
				%buildingPiece = %buildingPiece @ "%building.light = %light;";
				%buildingPiece = %buildingPiece @ "%light.lightBase = %building;";
				%buildingPiece = %buildingPiece @ "adjustLight(%building);";
			}
		}
		else if (%dataBlockName $= "DeployedTripwire") {
			%tripField = %obj.tripField;
			if (isObject(%tripField)) {
				%tripFieldDataBlock = %tripField.getDatablock().getName();
				if (!$SaveBuilding::Quiet)
					echo("Saving: " @ %tripField @ " Name: " @ %tripFieldDataBlock);
				%buildingPiece = %buildingPiece @ "%tripField = new ForceFieldBare() {";
				%buildingPiece = %buildingPiece @ "datablock = \"" @ %tripFieldDataBlock @ "\";";
				if (%tripField.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %tripField.scale @ "\";";
				%buildingPiece = %buildingPiece @ "};";
				%buildingPiece = %buildingPiece @ "%building.tripField = %tripField;";
				%buildingPiece = %buildingPiece @ "%tripField.pzone.delete();%building.pzone = \"\";";
			}
			%tripTrigger = %obj.tripTrigger;
			if (isObject(%tripTrigger)) {
				%tripTriggerDataBlock = %tripTrigger.getDatablock().getName();
				if (!$SaveBuilding::Quiet)
					echo("Saving: " @ %tripTrigger @ " Name: " @ %tripTriggerDataBlock);
				%buildingPiece = %buildingPiece @ "%tripTrigger = new Trigger() {";
				%buildingPiece = %buildingPiece @ "datablock = \"" @ %tripTriggerDataBlock @ "\";";
				if (%tripTrigger.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %tripTrigger.scale @ "\";";
				if (%tripTrigger.polyhedron !$= "") %buildingPiece = %buildingPiece @ "polyhedron = \"" @ %tripTrigger.polyhedron @ "\";";
				%buildingPiece = %buildingPiece @ "};";
				%buildingPiece = %buildingPiece @ "%building.tripTrigger = %tripTrigger;";
				%buildingPiece = %buildingPiece @ "%tripTrigger.baseObj = %building;";
			}
			%buildingPiece = %buildingPiece @ "setTargetName(%building.target,addTaggedString(\"Frequency\" SPC %building.powerFreq));";
			%buildingPiece = %buildingPiece @ "%building.deploy();";
			%buildingPiece = %buildingPiece @ "adjustTripwire(%building);";
		}
		else if (%dataBlockName $= "DeployedEscapePod") {
			%buildingPiece = %buildingPiece @ "adjustEscapePod(%building);";
			%buildingPiece = %buildingPiece @ "escapePodLoop(%building);";
		}
	}
	else {
		if (!$SaveBuilding::Quiet) {
//			warn("Skipping: " @ %obj @ " Name: " @ %dataBlockName);
		}
		%buildingPiece = "";
		$SaveBuilding::Skipped++;
	}

	return %buildingPiece;
}

// This function saves a building and relocates it to the center of the 'map'
// Optional switch to put center at lowest part of building
//
// NB: Position of objects (such as support beams) is their attachment point,
// not their actual center. This may give some 'strange' results when centering
// small buildings

function saveBuildingCentered(%cl,%rad,%file,%quiet,%centerAtMinZ) {
	if (%quiet == true) {
		$SaveBuilding::Quiet = true;
	}
	else {
		$SaveBuilding::Quiet = false; // Overwrite
	}
	if (!isObject(%cl)) {
		if (isObject(nameToID(LocalClientConnection))) {
			%cl = nameToID(LocalClientConnection);
		}
		else {
			if ($CurrentClientId) {
				%cl = $CurrentClientId;
			}
		}
	}
	if (%rad < 1) {
		%rad = 100000;
	}
	%buildingCount = 0;
	if (%file $= "") {
		for(%found = true; %found; %buildingCount++ ) {
			%suffix = %buildingCount;
			while (strLen(%suffix) < 5) %suffix = "0" @ %suffix;
			%file = $SaveBuilding::SaveFolder @ %cl.nameBase @ "-" @ $MissionName @ "-" @ %suffix @ ".cs";
			%found = isFile(%file);
		}
	}
	else {
		%file = $SaveBuilding::SaveFolder @ %file;
	}

	if (isObject(%cl.getControlObject())) {
		%pos = %cl.getControlObject().getPosition();
	}
	if (!%pos) {
		%pos = "0 0 0";
	}
	new fileObject("Building");
	if (!$SaveBuilding::Quiet) {
		warn("Saving to file: \"" @ %file @ "\"");
	}
	Building.openForWrite(%file);
	Building.writeLine("// CONSTRUCTION MOD SAVE FILE");
	Building.writeLine("// This building was saved by \"" @ getField(%cl.nameBase,0) @ "\"");
	Building.writeLine("// This building was created in mission \"" @ $MissionName @ "\"");
	Building.writeLine("");

	$SaveBuilding::Saved = 0;
	$SaveBuilding::Skipped = 0;
	$SaveBuilding::MaxX = 0;
	$SaveBuilding::MaxY = 0;
	$SaveBuilding::MaxZ = 0;
	$SaveBuilding::MinX = 0;
	$SaveBuilding::MinY = 0;
	$SaveBuilding::MinZ = 0;

	%firstObj = true;
	initContainerRadiusSearch(%pos,%rad,$TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType);
	while((%obj = containerSearchNext()) != 0) {
		%compPos = checkBuildingComponentCentered(%obj);
		if (%compPos) {
			%x = getWord(%compPos,0);
			%y = getWord(%compPos,1);
			%z = getWord(%compPos,2);
			if (%x > $SaveBuilding::MaxX || %firstObj) {$SaveBuilding::MaxX = %x;}
			if (%y > $SaveBuilding::MaxY || %firstObj) {$SaveBuilding::MaxY = %y;}
			if (%z > $SaveBuilding::MaxZ || %firstObj) {$SaveBuilding::MaxZ = %z;}
			if (%x < $SaveBuilding::MinX || %firstObj) {$SaveBuilding::MinX = %x;}
			if (%y < $SaveBuilding::MinY || %firstObj) {$SaveBuilding::MinY = %y;}
			if (%z < $SaveBuilding::MinZ || %firstObj) {$SaveBuilding::MinZ = %z;}
			%firstObj = false;
		}
	}

	$SaveBuilding::SizeX = $SaveBuilding::MaxX - $SaveBuilding::MinX;
	$SaveBuilding::SizeY = $SaveBuilding::MaxY - $SaveBuilding::MinY;
	$SaveBuilding::SizeZ = $SaveBuilding::MaxZ - $SaveBuilding::MinZ;

	$SaveBuilding::CenterX = $SaveBuilding::MinX + ($SaveBuilding::SizeX / 2);
	$SaveBuilding::CenterY = $SaveBuilding::MinY + ($SaveBuilding::SizeY / 2);
	if (!%centerAtMinZ) {$SaveBuilding::CenterZ = $SaveBuilding::MinZ + ($SaveBuilding::SizeZ / 2);}
	else {$SaveBuilding::CenterZ = $SaveBuilding::MinZ;}

	if (isObject($SaveBuilding::TestWaypoint))
		$SaveBuilding::TestWaypoint.delete();
	$SaveBuilding::TestWaypoint = new WayPoint(SaveBuildingWaypoint) {
		position = $SaveBuilding::CenterX SPC $SaveBuilding::CenterY SPC $SaveBuilding::CenterZ;
		rotation = "1 0 0 0";
		scale = "1 1 1";
		dataBlock = "WayPointMarker";
		team = 0;
		name = "Saved Building Center";
	};
	MissionCleanup.add($SaveBuilding::TestWaypoint);

	initContainerRadiusSearch(%pos,%rad,$TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType);
	while((%obj = containerSearchNext()) != 0) {
		%cmp = writeBuildingComponentCentered(%obj);
		if (%cmp !$= "") {
			Building.writeLine(%cmp);
		}
	}

	if (!$SaveBuilding::Quiet) {
		warn("Saved to file: \"" @ %file @ "\"");
		warn("Saved pieces: " @ $SaveBuilding::Saved);
		warn("Skipped pieces: " @ $SaveBuilding::Skipped);
	}

	$SaveBuilding::LastFile = %file;

	Building.close();
	Building.delete();
	return %file;
}

function checkBuildingComponentCentered(%obj) {
	%save = false;
	%save = saveBuildingCheck(%obj);
	if (%save == true) {
		%pos = %obj.position;
		%x = getWord(%pos,0);
		%y = getWord(%pos,1);
		%z = getWord(%pos,2);
		%obj.saveBuilding = true;
		return %x SPC %y SPC %z;
	}
	else {
		%obj.saveBuilding = false;
		return;
	}
}

function writeBuildingComponentCentered(%obj) {
	%dataBlockName = %obj.getDatablock().getName();
	%save = false;
	%save = saveBuildingCheck(%obj);
	if (%save == true) {
		if (!$SaveBuilding::Quiet)
			echo("Saving: " @ %obj @ " Name: " @ %dataBlockName);
		%buildingPiece = "%building = new (" @ %obj.getClassName() @ ") () {";
		%buildingPiece = %buildingPiece @ "datablock = \"" @ %dataBlockName @ "\";";
		%pos = %obj.position;
		%x = getWord(%pos,0)-$SaveBuilding::CenterX;
		%y = getWord(%pos,1)-$SaveBuilding::CenterY;
		%z = getWord(%pos,2)-$SaveBuilding::CenterZ;
		%savePos = %x SPC %y SPC %z;
		if (%obj.position !$= "") %buildingPiece = %buildingPiece @ "position = \"" @ %savePos @ "\";";
		if (%obj.rotation !$= "") %buildingPiece = %buildingPiece @ "rotation = \"" @ %obj.rotation @ "\";";
		if (%obj.realScale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %obj.realScale @ "\";";
		else {if (%obj.scale !$= "") %buildingPiece = %buildingPiece @ "scale = \"" @ %obj.scale @ "\";";}
		if (%obj.impulse !$= "") %buildingPiece = %buildingPiece @ "impulse = \"" @ %obj.impulse @ "\";";
		if (%obj.frequency !$= "") %buildingPiece = %buildingPiece @ "frequency = \"" @ %obj.frequency @ "\";";
		%buildingPiece = %buildingPiece @ "};";
		$SaveBuilding::Saved++;
	}
	else {
		if (!$SaveBuilding::Quiet) {
//			warn("Skipping: " @ %obj @ " Name: " @ %dataBlockName);
		}
		%buildingPiece = "";
		$SaveBuilding::Skipped++;
	}

	return %buildingPiece;
}

function delBuildingWaypoint() {
	if (isObject($SaveBuilding::TestWaypoint))
		$SaveBuilding::TestWaypoint.delete();
}

function loadBuilding(%file) {
	compile($SaveBuilding::SaveFolder @ %file); // Just in case it bombs out
	exec($SaveBuilding::SaveFolder @ %file);
}

function saveBuildingTimer(%timeInSeconds,%globalEcho,%file,%useMultipleFiles,%isScheduled,%threadCount) {
	if (!%isScheduled) {
		$SaveBuilding::TimerCount++;
		$SaveBuilding::TimerTime = %timeInSeconds * 1000;
		if ($SaveBuilding::TimerTime < 1)
			$SaveBuilding::TimerTime = $SaveBuilding::TimerDefaultTime;
		$SaveBuilding::TimerFile = %file;
		if ($SaveBuilding::TimerFile $= "" || $SaveBuilding::TimerFile $= "0")
			$SaveBuilding::TimerFile = "SaveBuildingTimer.cs";
		if (%useMultipleFiles)
			$SaveBuilding::TimerFile = "";
		$SaveBuilding::TimerGlobalChatEcho = %globalEcho;
		$SaveBuilding::TimerEnabled = true;
		%threadCount = $SaveBuilding::TimerCount;
	}
	if ($SaveBuilding::TimerEnabled == true && $SaveBuilding::TimerCount == %threadCount && isObject("MissionCleanup/Deployables")) {
		%file = saveBuilding(0,0,$SaveBuilding::TimerFile,true,true);
		%timeToNextSave = mFloatLength($SaveBuilding::TimerTime / 60 / 1000,2);
		%timeToNextSaveMinutes = mFloor(%timeToNextSave);
		%timeToNextSaveSeconds = mFloor((%timeToNextSave - %timeToNextSaveMinutes) * 60);
		%timeToNextSave = %timeToNextSaveMinutes @ "m, " @ %timeToNextSaveSeconds @ "s";
		%filespec = "\"" @ %file @ "\"";
		if ($SaveBuilding::TimerFile $= "")
			%filespec = %filespec @ " (using multiple files)";
		warn("-SaveBuildingTimer- Saved to: " @ %filespec @ " - Timer: " @ %timeToNextSave);
		if ($SaveBuilding::TimerGlobalChatEcho)
			MessageAll('msgClient',"\c2Buildings saved. Next save in " @ %timeToNextSave);
		if ($SaveBuilding::TimerTime > 0) // Extra safety
			schedule($SaveBuilding::TimerTime,0,saveBuildingTimer,0,0,0,0,true,%threadCount);
	}
	else {
		warn("-SaveBuildingTimer- Thread " @ %threadCount @ " disabled. Last active thread: " @ $SaveBuilding::TimerCount);
	}
}

// NB: This function does not setup default parameters
function saveBuildingTimerOn() {
	if ($SaveBuilding::TimerTime < 1) {
		$SaveBuilding::TimerTime = $SaveBuilding::TimerDefaultTime;
	}
	$SaveBuilding::TimerCount++;
	$SaveBuilding::TimerEnabled = true;
	saveBuildingTimer(0,0,0,0,true,$SaveBuilding::TimerCount);
}

function saveBuildingTimerOff() {
	$SaveBuilding::TimerEnabled = false;
}

function delDupPieces(%cl,%rad,%quiet) {
	%randomTime = 10000;
	if (%quiet == true) {
		$SaveBuilding::Quiet = true;
	}
	else {
		$SaveBuilding::Quiet = false; // Overwrite
	}
	if (!isObject(%cl)) {
		if (isObject(nameToID(LocalClientConnection))) {
			%cl = nameToID(LocalClientConnection);
		}
		else {
			if ($CurrentClientId) {
				%cl = $CurrentClientId;
			}
		}
	}
	if (%rad < 1) {
		%rad = 100000;
	}
	if (isObject(%cl.getControlObject())) {
		%pos = %cl.getControlObject().getPosition();
	}
	if (!%pos) {
		%pos = "0 0 0";
	}
	%oldChk = "";
	initContainerRadiusSearch(%pos,%rad,$TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType);
	while((%obj = containerSearchNext()) != 0) {
		%dataBlockName = %obj.getDatablock().getName();
		%save = saveBuildingCheck(%obj);
		if (%save) {
			// Round down a bit
			%objPos = mFloatLength(getWord(%obj.getPosition(),0),2) SPC mFloatLength(getWord(%obj.getPosition(),1),2) SPC mFloatLength(getWord(%obj.getPosition(),2),2);
			%objRot = mFloatLength(getWord(%obj.rotation,0),2) SPC mFloatLength(getWord(%obj.rotation,1),2) SPC mFloatLength(getWord(%obj.rotation,2),2) SPC mFloatLength(getWord(%obj.rotation,3),2);
			if (%obj.realScale)
				%objScale = %obj.realScale;
			else
				%objScale = %obj.scale;
			if (%dataBlockName $= "DeployedFloor" || %dataBlockName $= "DeployedwWall")
				// This doesn't handle all wWalls, but it helps
				%chk = %dataBlockName SPC %objPos SPC %objScale;
			else
				%chk = %dataBlockName SPC %objPos SPC %objRot SPC %objScale;
			if (%chk $= %oldChk) {
				%deleted++;
				if (!$SaveBuilding::Quiet && %dataBlockName !$= "DeployedMSpineRing")
					warn("Deleting: " @ %oldObj @ " Name: " @ %dataBlockName);
				// from inventoryHud.cs, modified
				%random = getRandom() * %randomTime;
				// Not the best way of doing this..
				if ($SaveBuilding::QuickDelete == true) {
					// Handle special cases
					if (%dataBlockName $= "DeployedMSpine") {
						if (isObject(%oldObj.left)) {
							if (!$SaveBuilding::Quiet)
								warn("Deleting: " @ %oldObj.left @ " Name: " @ %oldObj.left.getDatablock().getName());
							%deleted++;
							remDSurface(%oldObj.left);
							%oldObj.left.delete();
						}
						if (isObject(%oldObj.right)) {
							if (!$SaveBuilding::Quiet)
								warn("Deleting: " @ %oldObj.right @ " Name: " @ %oldObj.right.getDatablock().getName());
							%deleted++;
							remDSurface(%oldObj.right);
							%oldObj.right.delete();
						}
						remDSurface(%oldObj);
						%oldObj.delete();
					}
					else if (%dataBlockName $= "DeployedEscapePod") {
						if (isObject(%oldObj.lTarget)) {
							if (!$SaveBuilding::Quiet)
								warn("Deleting: " @ %oldObj.lTarget @ " Name: " @ %oldObj.lTarget.getDatablock().getName());
							%deleted++;
							remDSurface(%oldObj.lTarget);
							%oldObj.lTarget.delete();
						}
						if (isObject(%oldObj.podVehicle)) {
							if (!$SaveBuilding::Quiet)
								warn("Deleting: " @ %oldObj.podVehicle @ " Name: " @ %oldObj.podVehicle.getDatablock().getName());
							%deleted++;
							%oldObj.podVehicle.delete();
						}
						%oldObj.delete();
					}
					else if (%dataBlockName $= "DeployedMSpineRing") {
						// Nil. Handled by DeployedMSpine
						%deleted--;
					}
					else if (%dataBlockName $= "TelePadBeam") {
						// Nil. Handled by TelePadDeployedBase
						%deleted--;
					}
					else if (%dataBlockName $= "DeployedLTarget") {
						// Nil. Handled by parent object
						%deleted--;
					}
					else {
						if (%oldObj.beam)
							%oldObj.beam.delete();
						if (%oldObj.pzone)
							%oldObj.pzone.delete();
						if (%oldObj.trigger)
							%oldObj.trigger.delete();
						if (%oldObj.lTarget)
							%oldObj.lTarget.delete();
						if (%oldObj.holo)
							%oldObj.holo.delete();
						if (%oldObj.light)
							%oldObj.light.delete();
						if (%oldObj.tripField)
							%oldObj.tripField.delete();
						if (%oldObj.tripTrigger)
							%oldObj.tripTrigger.delete();
						remDSurface(%oldObj);
						%oldObj.delete();
					}
				}
				else {
					// Handle special cases
					if (%dataBlockName $= "DeployedMSpineRing") {
							// Nil. Handled by DeployedMSpine
					}
					else if (%dataBlockName $= "TelePadBeam") {
						// Nil. Handled by TelePadDeployedBase
					}
					else if (%dataBlockName $= "DeployedLTarget") {
						// Nil. Handled by parent object
					}
					else {
						%oldObj.getDataBlock().schedule(%random,"disassemble",0, %oldObj); // Run Item Specific code.
					}
				}
			}
			else {
				%checked++;
//				if (!$SaveBuilding::Quiet)
//					echo("Checking: " @ %obj @ " Name: " @ %dataBlockName);
			}
			%oldChk = %chk;
			%oldObj = %obj;
		}
		else {
			%skipped++;
//			if (!$SaveBuilding::Quiet)
//				warn("Skipping: " @ %obj @ " Name: " @ %dataBlockName);
		}
	}

	if (!$SaveBuilding::Quiet) {
		warn("Checked pieces: " @ %checked);
		warn("Skipped pieces: " @ %skipped);
		warn("Deleted pieces: " @ %deleted);
	}
	return %randomTime;
}

function updateDeployedCount() {
	Game.clearDeployableMaxes();
	%group = nameToID("MissionCleanup/Deployables");
	%count = %group.getCount();
	for(%i=0;%i<%count;%i++) {
		%obj = %group.getObject(%i);
		%revItem = $ReverseDeployItem[%obj.getDataBlock().getName()];
		if (getWord(%revItem,0) $= "poof")
			%revItem = getWord(%revItem,1);
		if (%revItem !$= "")
			$TeamDeployedCount[%obj.team,%revItem]++;
	}
}
