//All tasks for deathmatch, hunters, and tasks that coincide with the current objective task live here...

//Weights for tasks that override the objective task: must be between 4300 and 4700
$AIWeightVehicleMountedEscort	= 4700;
$AIWeightReturnTurretFire		= 4675;
$AIWeightNeedItemBadly    		= 4650;
$AIWeightReturnFire        	= 4600;
$AIWeightDetectMine				= 4500;
$AIWeightTauntVictim        	= 4400;
$AIWeightNeedItem    			= 4350;
$AIWeightDestroyTurret			= 4300;

//Weights that allow the objective task to continue:  must be 3000 or less
$AIWeightFoundEnemy        	= 3000;
$AIWeightFoundItem    			= 2500;
$AIWeightFoundToughEnemy     	= 1000;
$AIWeightPatrolling        	= 2000;

//Hunters weights...
$AIHuntersWeightMustCap			= 4690;
$AIHuntersWeightShouldCap		= 4425;
$AIHuntersWeightMustEngage		= 4450;
$AIHuntersWeightShouldEngage	= 4325;
$AIHuntersWeightPickupFlag		= 4425;

//Rabbit weights...
$AIRabbitWeightDefault			= 4625;
$AIRabbitWeightNeedInv			= 4325;

//Bounty weights...
$AIBountyWeightShouldEngage	= 4325;

//-----------------------------------------------------------------------------
//AIEngageTask is responsible for anything to do with engaging an enemy

function AIEngageWhoWillWin(%client1, %client2)
{
	//assume both clients are alive - gather some info
	if (%client1.isAIControlled())
		%skill1 = %client1.getSkillLevel();
	else
		%skill1 = 0.5;

	if (%client2.isAIControlled())
		%skill2 = %client2.getSkillLevel();
	else
		%skill2 = 0.5;

	%damage1 = %client1.player.getDamagePercent();
	%damage2 = %client2.player.getDamagePercent();

	//first compare health
	%tolerance1 = 0.5 + ((%skill1 - %skill2) * 0.3);
	%tolerance2 = 0.5 + ((%skill2 - %skill1) * 0.3);
	if (%damage1 - %damage2 > %tolerance1)
		return %client2;
	else if (%damage2 - %damage1 > %tolerance2)
		return %client1;

	//health not a problem, see how the equipment compares for the two...
	%weaponry1 = AIEngageWeaponRating(%client1);
	%weaponry2 = AIEngageWeaponRating(%client2);
	%effective = 20;
	if (%weaponry1 < %effective && %weaponry2 >= %effective)
		return %client2;
	else if (%weaponry1 >= %effective && %weaponry2 < %effective)
		return %client1;

	//no other criteria for now...  return -1 to indicate a tie...
	return -1;
}

function AIEngageTask::init(%task, %client)
{
}

function AIEngageTask::assume(%task, %client)
{
	%task.setWeightFreq(9);
	%task.setMonitorFreq(9);
	%task.searching = false;
	if (isObject(%client.shouldEngage.player))
		%task.searchLocation = %client.shouldEngage.player.getWorldBoxCenter();
}

function AIEngageTask::retire(%task, %client)
{
}

function AIEngageTask::weight(%task, %client)
{
   %player = %client.player;
	if (!isObject(%player))
		return;

   %clientPos = %player.getWorldBoxCenter();
   %currentTarget = %client.shouldEngage;
	if (!AIClientIsAlive(%currentTarget))
		%currentTarget = %client.getEngageTarget();
   %client.shouldEngage = -1;
	%mustEngage = false;
	%tougherEnemy = false;

	//first, make sure we actually can engage
	if (AIEngageOutOfAmmo(%client))
	{
		%client.shouldEngage = -1;
		%task.setWeight(0);
		return;
	}

	//see if anyone has fired on us recently...
   %losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel());
   if (AIClientIsAlive(%client.lastDamageClient, %losTimeout) && getSimTime() - %client.lastDamageTime < %losTimeout)
   {
      //see if we should turn on the new attacker
      if (AIClientIsAlive(%currentTarget))
      {
         %targPos = %currentTarget.player.getWorldBoxCenter();
         %curTargDist = %client.getPathDistance(%targPos);
      
         %newTargPos = %client.lastDamageClient.player.getWorldBoxCenter();
         %newTargDist = %client.getPathDistance(%newTargPos);
      
         //see if the new targ is no more than 30 m further
         if (%newTargDist > 0 && %newTargDist < %curTargDist + 30)
         {
            %client.shouldEngage = %client.lastDamageClient;
				%mustEngage = true;
         }
      }
      else
      {
         %client.shouldEngage = %client.lastDamageClient;
			%mustEngage = true;
      }
   }

   //no one has fired at us recently, see if we're near an enemy
   else
   {
		%result = AIFindClosestEnemy(%client, 100, %losTimeout);
      %closestEnemy = getWord(%result, 0);
      %closestdist = getWord(%result, 1);
      if (%closestEnemy > 0)
      {
         //see if we're right on top of them
         %targPos = %closestEnemy.player.getWorldBoxCenter();
         %dist = %client.getPathDistance(%targPos);
         
         if (%dist > 0 && %dist < 20)
         {
            %client.shouldEngage = %closestEnemy;
				%mustEngage = true;
         }
         
         //else choose them only if we're not already attacking someone
         else if (%currentTarget <= 0)
         {
            %client.shouldEngage = %closestEnemy;
				%mustEngage = false;

				//Make sure the odds are not overwhelmingly in favor of the enemy...
				if (AIEngageWhoWillWin(%client, %closestEnemy) == %closestEnemy)
					%tougherEnemy = true;
         }
      }
   }
   
   //if we still haven't found a new target, keep fighting the old one
   if (%client.shouldEngage <= 0)
   {
      if (AIClientIsAlive(%currentTarget))
		{
			//see if we still have sight of the current target
			%hasLOS = %client.hasLOSToClient(%currentTarget);
			%losTime = %client.getClientLOSTime(%currentTarget);
			if (%hasLOS || %losTime < %losTimeout)
		      %client.shouldEngage = %currentTarget;
			else
				%client.shouldEngage = -1;
		}
      else
			%client.shouldEngage = -1;
		%mustEngage = false;
   }

   //finally, set the weight
	if (%client.shouldEngage > 0)
	{
		if (%mustEngage)
		   %task.setWeight($AIWeightReturnFire);
		else if (%tougherEnemy)
		   %task.setWeight($AIWeightFoundToughEnemy);
		else
		   %task.setWeight($AIWeightFoundEnemy);
	}
	else
	   %task.setWeight(0);
}

function AIEngageTask::monitor(%task, %client)
{
	if (!AIClientIsAlive(%client.shouldEngage))
	{
		%client.stop();
		%client.clearStep();
		%client.setEngageTarget(-1);
		return;
	}

	%hasLOS = %client.hasLOSToClient(%client.shouldEngage);
	%losTime = %client.getClientLOSTime(%client.shouldEngage);
	//%detectLocation = %client.getDetectLocation(%client.shouldEngage);
	%detectPeriod = %client.getDetectPeriod();

	//if we can see the target, engage...
	if (%hasLOS || %losTime < %detectPeriod)
	{
		%client.stepEngage(%client.shouldEngage);
		%task.searching = false;
		%task.searchLocation = %client.shouldEngage.player.getWorldBoxCenter();
	}

	//else if we haven't for approx 5 sec...  move to the last known location
	else
	{
		//clear the engage target
		%client.setEngageTarget(-1);

		if (! %task.searching)
		{
			%dist = VectorDist(%client.player.getWorldBoxCenter(), %task.searchLocation);
			if (%dist < 4)
			{
				%client.stepIdle(%task.searchLocation);
				%task.searching = true;
			}
			else
				%client.stepMove(%task.searchLocation, 4.0);
		}
	}
}

//-----------------------------------------------------------------------------
//AIPickupItemTask is responsible for anything to do with picking up an item

function AIPickupItemTask::init(%task, %client)
{
}

function AIPickupItemTask::assume(%task, %client)
{
	%task.setWeightFreq(10);
	%task.setMonitorFreq(10);

	%task.pickUpItem = -1;
}

function AIPickupItemTask::retire(%task, %client)
{
}

function AIPickupItemTask::weight(%task, %client)
{
	//if we're already picking up an item, make sure it's still valid, then keep the weight the same...
	if (%task.pickupItem > 0)
	{
		if (isObject(%task.pickupItem) && !%task.pickupItem.isHidden() && AICouldUseItem(%client, %task.pickupItem))
			return;
		else
			%task.pickupItem = -1;
	}

	//otherwise, search for objects
   //first, see if we can pick up health
	%player = %client.player;
	if (!isObject(%player))
		return;

	%damage = %player.getDamagePercent();
	%healthRad = %damage * 100;
	%closestHealth = -1;
	%closestHealthDist = %healthRad;
	%closestHealthLOS = false;
	%closestItem = -1;
	%closestItemDist = 32767;
	%closestItemLOS = false;

	//loop through the item list, looking for things to pick up
	%itemCount = $AIItemSet.getCount();
	for (%i = 0; %i < %itemCount; %i++)
	{
		%item = $AIItemSet.getObject(%i);
		if (!%item.isHidden())
		{
         %dist = %client.getPathDistance(%item.getWorldBoxCenter());
			if (((%item.getDataBlock().getName() $= "RepairKit" || %item.getDataBlock().getName() $= "RepairPatch") ||
                                                            (%item.isCorpse && %item.getInventory("RepairKit") > 0)) &&
                                                            %player.getInventory("RepairKit") <= 0 && %damage > 0.3)
			{
				if (%dist > 0 && %dist < %closestHealthDist)
				{
					%closestHealth = %item;
					%closestHealthDist = %dist;

					//check for LOS
				   %mask = $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType;
				   %closestHealthLOS = !containerRayCast(%client.player.getWorldBoxCenter(), %item.getWorldBoxCenter(), %mask, 0);
				}
			}
			else
			{
				//only pick up stuff within 35m
				if (%dist < 35)
				{
					if (AICouldUseItem(%client, %item))
					{
						if (%dist < %closestItemDist)
						{
							%closestItem = %item;
							%closestItemDist = %dist;

							//check for LOS
						   %mask = $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType;
						   %closestItemLOS = !containerRayCast(%client.player.getWorldBoxCenter(), %item.getWorldBoxCenter(), %mask, 0);
						}
					}
				}
			}
		}
	}

	//now set the weight
	if (%closestHealth > 0)
	{
		//only choose an item if it's at least 25 m closer than health...
		//and we're not engageing someone or not that badly in need
	   %currentTarget = %client.getEngageTarget();
		if (%closestItem > 0 && %closetItemDist < %closestHealthDist - 25 && (%damage < 0.6 || %currentTarget <= 0) && %closestItemLOS)
		{
			%task.pickupItem = %closestItem;
         if (AIEngageWeaponRating(%client) < 20)
				%task.setWeight($AIWeightNeedItemBadly);
			else if (%closestItemDist < 10 && %closestItemLOS)
				%task.setWeight($AIWeightNeedItem);
			else if (%closestItemLOS)
				%task.setWeight($AIWeightFoundItem);
			else
				%task.setWeight(0);
		}
		else
		{
			if (%damage > 0.8)
			{
				%task.pickupItem = %closestHealth;
				%task.setWeight($AIWeightNeedItemBadly);
			}
			else if (%closestHealthLOS)
			{
				%task.pickupItem = %closestHealth;
				%task.setWeight($AIWeightNeedItem);
			}
			else
				%task.setWeight(0);
		}
	}
	else if (%closestItem > 0)
	{
		%task.pickupItem = %closestItem;
      if (AIEngageWeaponRating(%client) < 20)
			%task.setWeight($AIWeightNeedItemBadly);
		else if (%closestItemDist < 10 && %closestItemLOS)
			%task.setWeight($AIWeightNeedItem);
		else if (%closestItemLOS)
			%task.setWeight($AIWeightFoundItem);
		else
			%task.setWeight(0);
	}
	else
		%task.setWeight(0);
}

function AIPickupItemTask::monitor(%task, %client)
{
	//move to the pickup location
	if (isObject(%task.pickupItem))
	   %client.stepMove(%task.pickupItem.getWorldBoxCenter(), 0.25);

	//this call works in conjunction with AIEngageTask
	%client.setEngageTarget(%client.shouldEngage);
}

//-----------------------------------------------------------------------------
//AIUseInventoryTask will cause them to use an inv station if they're low
//on ammo.  This task should be used only for DM and Hunters - most objectives
//have their own logic for when to use an inv station...

function AIUseInventoryTask::init(%task, %client)
{
}

function AIUseInventoryTask::assume(%task, %client)
{
	%task.setWeightFreq(15);
	%task.setMonitorFreq(5);

	//mark the current time for the buy inventory state machine
	%task.buyInvTime = getSimTime();
}

function AIUseInventoryTask::retire(%task, %client)
{
	//reset the state machine time stamp...
	%task.buyInvTime = getSimTime();
}

function AIUseInventoryTask::weight(%task, %client)
{
   //first, see if we can pick up health
	%player = %client.player;
	if (!isObject(%player))
		return;

	%damage = %player.getDamagePercent();
	%weaponry = AIEngageWeaponRating(%client);

   //if there's an inv station, and we haven't used an inv station since we
   //spawned, the bot should use an inv once regardless
   if (%client.spawnUseInv)
   {
      //see if we're already heading there
      if (%client.buyInvTime != %task.buyInvTime)
      {
	      //see if there's an inventory we can use
         %result = AIFindClosestInventory(%client, false);
         %closestInv = getWord(%result, 0);
	      if (isObject(%closestInv))
         {
            %task.setWeight($AIWeightNeedItem);
            return;
         }
         else
            %client.spawnUseInv = false;
      }
      else
      {
         %task.setWeight($AIWeightNeedItem);
         return;
      }
   }

	//first, see if we need equipment or health
	if (%damage < 0.3 && %weaponry >= 40)
	{
		%task.setWeight(0);
		return;
	}

	//don't use inv stations if we're not that badly damaged, and we're in the middle of a fight
	if (%damage < 0.6 && %client.getEngageTarget() > 0 && !AIEngageOutOfAmmo(%client))
	{
		%task.setWeight(0);
		return;
	}

	//if we're already buying, continue
	if (%task.buyInvTime == %client.buyInvTime)
	{
		//set the weight - if our damage is above 0.8 or our we're out of ammo
		if (%damage > 0.8 || AIEngageOutOfAmmo(%client))
			%task.setWeight($AIWeightNeedItemBadly);
		else
			%task.setWeight($AIWeightNeedItem);
		return;
	}

	//we need to search for an inv station near us...
	%result = AIFindClosestInventory(%client, false);
	%closestInv = getWord(%result, 0);
	%closestDist = getWord(%result, 1);

	//only use inv stations if we're right near them...  patrolTask will get us nearer if required
	if (%closestDist > 35)
	{
		%task.setWeight(0);
		return;
	}

	//set the weight...
	%task.closestInv = %closestInv;
	if (%damage > 0.8 || AIEngageOutOfAmmo(%client))
		%task.setWeight($AIWeightNeedItemBadly);
	else if (%closestDist < 20 && (AIEngageWeaponRating(%client) <= 30 || %damage > 0.4))
		%task.setWeight($AIWeightNeedItem);
	else if (%hasLOS)
		%task.setWeight($AIWeightFoundItem);
	else
		%task.setWeight(0);
}

function AIUseInventoryTask::monitor(%task, %client)
{
	//make sure we still need equipment
	%player = %client.player;
	if (!isObject(%player))
		return;

	%damage = %player.getDamagePercent();
	%weaponry = AIEngageWeaponRating(%client);
	if (%damage < 0.3 && %weaponry >= 40 && !%client.spawnUseInv)
	{
		%task.buyInvTime = getSimTime();
		return;
	}

	//pick a random set based on armor...
	%randNum = getRandom();
	if (%randNum < 0.4)
		%buySet = "LightEnergyDefault MediumEnergySet HeavyEnergySet";
	else if (%randNum < 0.6)
		%buySet = "LightShieldSet MediumShieldSet HeavyShieldSet"; 
	else if (%randNum < 0.8)
		%buySet = "LightEnergyELF MediumRepairSet HeavyAmmoSet";
   else
      %buySet = "LightEnergySniper MediumEnergySet HeavyEnergySet";

	//process the inv buying state machine
   %result = AIBuyInventory(%client, "", %buySet, %task.buyInvTime);

   //if we succeeded, reset the spawn flag
   if (%result $= "Finished")
      %client.spawnUseInv = false;

   //if we succeeded or failed, reset the state machine...
	if (%result !$= "InProgress")
		%task.buyInvTime = getSimTime();


	//this call works in conjunction with AIEngageTask
	%client.setEngageTarget(%client.shouldEngage);
}

//-----------------------------------------------------------------------------
//AITauntCorpseTask is should happen only after an enemy is freshly killed

function AITauntCorpseTask::init(%task, %client)
{
}

function AITauntCorpseTask::assume(%task, %client)
{
	%task.setWeightFreq(11);
	%task.setMonitorFreq(11);
}

function AITauntCorpseTask::retire(%task, %client)
{
}

function AITauntCorpseTask::weight(%task, %client)
{
   %task.corpse = %client.getVictimCorpse();
   if (%task.corpse > 0 && getSimTime() - %client.getVictimTime() < 15000)
	{
		//see if we're already taunting, and if it's time to stop
		if ((%task.tauntTime > %client.getVictimTime()) && (getSimTime() - %task.tauntTime > 5000))
			%task.corpse = -1;
		else
		{
			//if the corpse is within 50m, taunt
         %distToCorpse = %client.getPathDistance(%task.corpse.getWorldBoxCenter());
			if (%dist < 0 || %distToCorpse > 50)
				%task.corpse = -1;
		}
	}
	else
		%task.corpse = -1;

	//set the weight
	if (%task.corpse > 0)
	{
		//don't taunt someone if there's an enemy right near by...
		%result = AIFindClosestEnemy(%client, 40, 15000);
      %closestEnemy = getWord(%result, 0);
      %closestdist = getWord(%result, 1);
      if (%closestEnemy > 0)
			%task.setWeight(0);
		else
			%task.setWeight($AIWeightTauntVictim);
	}
	else
		%task.setWeight(0);
}

$AITauntChat[0] = "gbl.aww";
$AITauntChat[1] = "gbl.brag";
$AITauntChat[2] = "gbl.obnoxious";
$AITauntChat[3] = "gbl.sarcasm";
$AITauntChat[4] = "gbl.when";
function AITauntCorpseTask::monitor(%task, %client)
{
	//make sure we still have a corpse, and are not fighting anyone
	if (%client.getEngageTarget() <= 0 && %task.corpse > 0 && isObject(%task.corpse))
	{
      %clientPos = %client.player.getWorldBoxCenter();
		%corpsePos = %task.corpse.getWorldBoxCenter();
		%distToCorpse = VectorDist(%clientPos, %corpsePos);
		if (%distToCorpse < 2.0)
		{
			//start the taunt!
			if (%task.tauntTime < %client.getVictimTime())
			{
				%task.tauntTime = getSimTime();
				%client.stop();

				if (getRandom() > 0.2)
				{
					//pick the sound and taunt cels
					%sound = $AITauntChat[mFloor(getRandom() * 3.99)];
					%minCel = 2;
					%maxCel = 8;
				   schedule(250, %client, "AIPlayAnimSound", %client, %corpsePos, %sound, %minCel, %maxCel, 0);
				}
				//say 'bye'  :)
				else
				   schedule(250, %client, "AIPlayAnimSound", %client, %corpsePos, "gbl.bye", 2, 2, 0);
			}
		}
		else
			%client.stepMove(%task.corpse.getWorldBoxCenter(), 1.75);
	}
}

//-----------------------------------------------------------------------------
//AIPatrolTask used to wander around the map (DM and Hunters mainly) looking for something to do...

function AIPatrolTask::init(%task, %client)
{
}

function AIPatrolTask::assume(%task, %client)
{
	%task.setWeightFreq(13);
	%task.setMonitorFreq(13);
	%task.findLocation = true;
	%task.patrolLocation = "0 0 0";
	%task.idleing = false;
	%task.idleEndTime = 0;
}

function AIPatrolTask::retire(%task, %client)
{
}

function AIPatrolTask::weight(%task, %client)
{
	%task.setWeight($AIWeightPatrolling);
}

function AIPatrolTask::monitor(%task, %client)
{
	//this call works in conjunction with AIEngageTask
	%client.setEngageTarget(%client.shouldEngage);

	//see if we're close enough to our patrol point
	if (%task.idleing)
	{
		if (getSimTime() > %task.idleEndTime)
		{
			%task.findLocation = true;
			%task.idleing = false;
		}
	}

	//see if we need to find a place to go...
	else if (%task.findLocation)
	{
		//first, see if we're in need of either health, or ammo
		//note: normally, I'd be tempted to put this kind of "looking for health" code
		//into the AIPickupItemTask, however, that task will be used in CTF, where you
		//don't want people on AIDefendLocation to leave their post to hunt for health, etc...
		//AIPickupItemTask only deals with items within a 30m radius around the bot.
		//AIPatrolTask will move the bot to the vicinity of an item, then AIPickUpItemTask
		//will finish the job...
		%foundItemLocation = false;
		%damage = %client.player.getDamagePercent();
		if (%damage > 0.7)
		{
			//search for a health kit
			%closestHealth = AIFindSafeItem(%client, "Health");
			if (%closestHealth > 0)
			{
				%task.patrolLocation = %closestHealth.getWorldBoxCenter();
				%foundItemLocation = true;
			}
		}
		else if (AIEngageOutOfAmmo(%client))
		{
			//search for a Ammo or a weapon...
			%closestItem = AIFindSafeItem(%client, "Ammo");
			if (%closestItem > 0)
			{
				%task.patrolLocation = %closestItem.getWorldBoxCenter();
				%foundItemLocation = true;
			}
		}

		//now see if we don't really have good equipment...
		if (!%foundItemLocation && AIEngageWeaponRating(%client) < 20)
		{
			//search for any useful item
			%closestItem = AIFindSafeItem(%client, "Any");
			if (%closestItem > 0)
			{
				%task.patrolLocation = %closestItem.getWorldBoxCenter();
				%foundItemLocation = true;
			}
		}
		//choose a randomish location only if we're not in need of health or ammo
		if (!%foundItemLocation)
		{
			//find a random item/inventory in the map, and pick a spawn point near it...
			%pickGraphNode = false;
			%chooseSet = 0;
			if ($AIInvStationSet.getCount() > 0)
				%chooseSet = $AIInvStationSet;
			else if ($AIWeaponSet.getCount() > 0)
				%chooseSet = $AIWeaponSet;
			else if ($AIItemSet.getCount() > 0)
				%chooseSet = $AIItemSet;

			if (!%chooseSet)
				%pickGraphNode = true;

			//here we pick whether we choose a random map point, or a point based on an item...
			if (getRandom() < 0.3)
				%pickGraphNode = true;

			//here we decide whether we should choose a player location...  a bit of a cheat but
			//it's scaled by the bot skill level
			%pickPlayerLocation = false;
			%skill = %client.getSkillLevel();
			if (%skill < 1.0)
				%skill = %skill / 2.0;
			if (getRandom() < (%skill * %skill) && ClientGroup.getCount() > 1)
			{
				//find a random client
				%count = ClientGroup.getCount();
				%index = (getRandom() * (%count - 0.1));
				%cl = ClientGroup.getObject(%index);
				if (%cl != %client && AIClientIsAlive(%cl))
				{
					%task.patrolLocation = %cl.player.getWorldBoxCenter();
					%pickGraphNode = false;
					%pickPlayerLocation = true;
				}
			}
			
			if (!%pickGraphNode && !%pickPlayerLocation)
			{
				%itemCount = %chooseSet.getCount();
				%item = %chooseSet.getObject(getRandom() * (%itemCount - 0.1));
		      %nodeIndex = navGraph.randNode(%item.getWorldBoxCenter(), 10, true, true);
				if (%nodeIndex <= 0)
					%pickGraphNode = true;
				else
					%task.patrolLocation = navGraph.randNodeLoc(%nodeIndex);
			}

			//see if we failed above or have to pick just a random spot on the graph - use the spawn points...
			if (%pickGraphNode)
			{
			   %task.patrolLocation = Game.pickPlayerSpawn(%client, true);
				if (%task.patrolLocation == -1)
				{
					%client.stepIdle(%client.player.getWorldBoxCenter());
					return;
				}
			}
		}

		//now that we have a new location - move towards it
		%task.findLocation = false;
		%client.stepMove(%task.patrolLocation, 8.0);
	}

	//else we're on patrol - see if we're close to our destination
	else
	{
		%client.stepMove(%task.patrolLocation, 8.0);
		%distToDest = %client.getPathDistance(%task.patrolLocation);
		if (%distToDest > 0 && %distToDest < 10)
		{
			%task.idleing = true;
			%task.idleEndTime = 4000 + getSimTime() + (getRandom() * 6000);
			%client.stepIdle(%client.player.getWorldBoxCenter());
		}
	}
}

//-----------------------------------------------------------------------------
//AIEngageTurretTask is responsible for returning turret fire...

function AIEngageTurretTask::init(%task, %client)
{
}

function AIEngageTurretTask::assume(%task, %client)
{
	%task.setWeightFreq(4);
	%task.setMonitorFreq(4);
}

function AIEngageTurretTask::retire(%task, %client)
{
	%client.engageTurret = -1;
	%client.setEngagetarget(-1);
}

function AIEngageTurretTask::weight(%task, %client)
{
	//see if we're still fighting a turret
	%elapsedTime = getSimTime() - %task.startAttackTime;
	if (isObject(%task.engageTurret) && %task.engageTurret.getDataBlock().getClassName() $= "TurretData")
	{
		if (%task.engageTurret == %client.lastdamageTurret)
		{
			if (%task.engageTurret.isEnabled() && getSimTime() - %client.lastDamageTurretTime < 5000)
				%task.setWeight($AIWeightReturnTurretFire);
			else
				%task.setWeight($AIWeightDestroyTurret);
		}
		else if (AIClientIsAlive(%client, %elapsedTime))
		{
			//if another turret is shooting us, disable this one first...
			if (isObject(%client.lastDamageTurret) && %client.lastDamageTurret.getDataBlock().getClassName() $= "TurretData")
			{
				if (%task.engageTurret.isEnabled())
					%task.setWeight($AIWeightReturnTurretFire);
				else
				{
					//see if we need to switch to the new turret
					if (%client.lastDamageTurret.isEnabled() && %client.lastDamageTurretTime < 5000)
					{
						%task.engageTurret = %client.lastDamageTurret;
						%task.attackInitted = false;
						%task.setWeight($AIWeightDestroyTurret);
					}

					else
						%task.setWeight($AIWeightReturnTurretFire);
				}
			}
			else
			{
				if (%task.engageTurret.isEnabled() && getSimTime() - %client.lastDamageTurretTime < 5000)
					%task.setWeight($AIWeightReturnTurretFire);
				else
					%task.setWeight($AIWeightDestroyTurret);
			}
		}

		//else we died since - clear out the vars
		else
		{
			%task.engageTurret = -1;
			%task.setWeight(0);
		}
	}

	//else see if we have a new target
	else if (isObject(%client.lastDamageTurret) && %client.lastDamageTurret.getDataBlock().getClassName() $= "TurretData")
	{
		%task.engageTurret = %client.lastDamageTurret;
		%task.attackInitted = false;

		if (%client.lastDamageTurret.isEnabled() && %client.lastDamageTurretTime < 5000)
			%task.setWeight($AIWeightReturnTurretFire);
		else
			%task.setWeight($AIWeightDestroyTurret);
	}

	//else no turret to attack...  (later, do a query to find turrets before they attack)
	else
	{
		%task.engageTurret = -1;
		%task.setWeight(0);
	}

}

function AIEngageTurretTask::monitor(%task, %client)
{
	if (isObject(%task.engageTurret) && %task.engageTurret.getDataBlock().getClassName() $= "TurretData")
	{
		//set the AI to fire at the turret
		%client.setEngageTarget(-1);
		%client.setTargetObject(%task.engageTurret);

		%clientPos = %client.player.getWorldBoxCenter();
		%turretPos = %task.engageTurret.getWorldBoxCenter();

		//control the movement - first, hide, then wait, then attack
		if (!%task.attackInitted)
		{
			%task.attackInitted = true;
			%task.startAttackTime = getSimTime();
			%task.hideLocation = %client.getHideLocation(%turretPos, 40.0, %clientPos, 4.0); 
			%client.stepMove(%task.hideLocation, 2.0);
		}
		else if (getSimTime() - %task.startAttackTime > 5000)
		{
			%client.stepMove(%task.engageTurret.getWorldBoxCenter(), 8.0);
		}
	}
}

//-----------------------------------------------------------------------------
//AIAvoidMineTask is responsible for detecting/destroying enemy mines...

function AIDetectMineTask::init(%task, %client)
{
}

function AIDetectMineTask::assume(%task, %client)
{
	%task.setWeightFreq(7);
	%task.setMonitorFreq(7);
}

function AIDetectMineTask::retire(%task, %client)
{
	%task.engageMine = -1;
	%task.attackInitted = false;
   %client.setTargetObject(-1);
}

function AIDetectMineTask::weight(%task, %client)
{
	//crappy hack, but they need the proper weapon before they can destroy a mine...
	%player = %client.player;
	if (!isObject(%player))
		return;

   %hasPlasma = (%player.getInventory("Plasma") > 0) && (%player.getInventory("PlasmaAmmo") > 0);
   %hasDisc = (%player.getInventory("Disc") > 0) && (%player.getInventory("DiscAmmo") > 0);

	if (!%hasPlasma && !%hasDisc)
	{
		%task.setWeight(0);
		return;
	}

	//if we're already attacking a mine, 
	if (%task.engageMine > 0 && isObject(%task.engageMine))
	{
		%task.setWeight($AIWeightDetectMine);
		return;
	}
	//see if we're within the viscinity of a new (enemy) mine
	%task.engageMine = -1;
	%closestMine = -1;
	%closestDist = 15;	//initialize so only mines within 15 m will be detected...
	%mineCount = $AIDeployedMineSet.getCount();
	for (%i = 0; %i < %mineCount; %i++)
	{
		%mine = $AIDeployedMineSet.getObject(%i);
		%mineTeam = %mine.sourceObject.team;

		%minePos = %mine.getWorldBoxCenter();
		%clPos = %client.player.getWorldBoxCenter();

		//see if the mine is the closest...
		%mineDist = VectorDist(%minePos, %clPos);
		if (%mineDist < %closestDist)
		{
			//now see if we're more or less heading towards the mine...
			%clVelocity = %client.player.getVelocity();
			%clVelocity = getWord(%clVelocity, 0) SPC getWord(%clVelocity, 1) SPC "0";
			%mineVector = VectorSub(%minePos, %clPos);
			%mineVector = getWord(%mineVector, 0) SPC getWord(%mineVector, 1) SPC "0";
			if (VectorLen(%clVelocity) > 2.0 && VectorLen(%mineVector > 2.0))
			{
				%clNormal = VectorNormalize(%clVelocity);
				%mineNormal = VectorNormalize(%mineVector);
				if (VectorDot(%clNormal, %mineNormal) > 0.3)
				{
					%closestMine = %mine;
					%closestDist = %mineDist;
				}
			}
		}
	}

	//see if we found a mine to attack
	if (%closestMine > 0)
	{
		%task.engageMine = %closestMine;
		%task.attackInitted = false;
		%task.setWeight($AIWeightDetectMine);
	}
	else
		%task.setWeight(0);
}

function AIDetectMineTask::monitor(%task, %client)
{
	if (%task.engageMine > 0 && isObject(%task.engageMine))
	{
		if (!%task.attackInitted)
		{
			%task.attackInitted = true;
		   %client.stepRangeObject(%task.engageMine, "DefaultRepairBeam", 6, 12);
			%client.setEngageTarget(-1);
			%client.setTargetObject(-1);
		}

      else if (%client.getStepStatus() $= "Finished")
		{
			%client.stop();
         %client.setTargetObject(%task.engageMine);
		}
	}
}

//-----------------------------------------------------------------------------
