// This script contains functionality to allow medics to revive teammates
this.Name = "REVIVE";
this.Parent = "HighLevel";
this.SkipGetPriorityWhenActive = true;
this.Debug = 0;

this.LimitToClass(CLASS.MEDIC); // weapon.syringe instead?

this.RangeForRevive = 2000;
this.RangeForNearby = 750;
this.RangeForPriority = 500;
this.CheckReviveTimer = 2; // look for closer goals every x seconds

this.Initialize = function()
{
	this.BBDelayTime = 1.25; // path failed will increase this
};

this.QueryReviveGoals = function(range, skipGoal)
{
	bestGoal = null;
	if (this.QueryGoals(Util.QueryTable,0x2086cdf0 /* REVIVE */))
	{
		closest = range + 1;
		foreach (goal in Util.QueryTable)
		{
			if (skipGoal && goal == skipGoal) {
				continue;
			}

			dist = this.Bot.DistanceTo(goal.GetPosition());
			if (dist < closest) {
				bestGoal = goal;
				closest = dist;
			}
		}
		this.GoalDistance = closest;
	}
	return bestGoal;
};

this.GetPriority = function()
{
	for(;;)
	{
		this.Priority = 0;
		if (this.Bot.HasAmmo(WEAPON.SYRINGE)) {
			this.MapGoal = this.QueryReviveGoals(this.RangeForRevive);
			if (this.MapGoal) {
				p = this.MapGoal.GetGoalPriority(this.Bot);
				if (this.GoalDistance < this.RangeForPriority) {
					//REVIVE priority is 1.0, CAPPOINT priority is 1.1
					p += 0.2;
				}
				this.Priority = p;
			}
		}

		sleep(2);
	}
};

this.Enter = function()
{
	this.TargetEntity = this.MapGoal.GetEntity();
	this.AddFinishCriteria(this.TargetEntity,"hasentflag",ENTFLAG.LIMBO);

	// cs: note: mapgoal_revive can take up to a second to remove the goal. so delay this a bit longer
	this.BBDelayTime = 1.25; // default. if interrupted for a closer revive, dont delay long.
};

this.LookForCloserReviveGoals = function()
{
	for(;;) {
		sleep(this.CheckReviveTimer);
		goal = this.QueryReviveGoals(this.RangeForRevive);
		if (!goal || goal != this.MapGoal) {
			this.Finished();
		}
	}
};

this.EvalDeliverSupplies = function()
{
	if (this.Bot.GetTarget() != null) {
		if (this.Debug) {
			this.Bot.Say("skipping deliver supplies, have target");
		}
		return false;
	}

	goal = this.QueryReviveGoals(this.RangeForNearby, this.MapGoal);
	if (this.Debug && goal) {
		this.Bot.Say("skipping deliver supplies, nearby revive");
	}

	return !goal;
};

this.Exit = function()
{
	if (this.LookForCloserReviveGoalsThread) {
		this.KillThread(this.LookForCloserReviveGoalsThread);
		this.LookForCloserReviveGoalsThread = null;
	}

	this.BlackboardDelay(this.BBDelayTime, this.MapGoal);

	// for sanity
	this.MapGoal = null;
};

this.Update = function()
{
	this.AutoFinishOnUnAvailable = true;
	if (!this.LookForCloserReviveGoalsThread) {
		this.LookForCloserReviveGoalsThread = this.ForkThread(this.LookForCloserReviveGoals);
	}

	if (this.RouteTo(this.MapGoal) != EVENT.PATH_FAILED) {
		this.KillThread(this.LookForCloserReviveGoalsThread);
		this.LookForCloserReviveGoalsThread = null;

		this.AddAimRequest(Priority.High, "position",GetEntPosition(this.TargetEntity));
		this.AddWeaponRequest(WEAPON.SYRINGE);
		this.BlockForWeaponChange(WEAPON.SYRINGE);

		this.AutoFinishOnUnAvailable = false; //REVIVE goal can be removed before signal to deliver supplies

		for (timeout = 12; timeout > 0; --timeout) { // 3 seconds
			health = Util.GetEntHealth(this.TargetEntity);
			if (health > 0) { break; }

			// position check here because some mods allow bodies to be dragged
			pos = GetEntPosition(this.TargetEntity);
			if (pos) {
				this.AddAimRequest(Priority.High, "position",pos);

				eyePos = GetEntEyePosition(this.Bot.GetGameEntity());
				heightDiff = pos.z - eyePos.z;
				if (heightDiff > 20.f) {
					this.Bot.PressButton(BTN.JUMP);
				}
				else {
					this.Bot.HoldButton(BTN.CROUCH, 1.3);
				}

				this.Bot.MoveTowards(pos);
				this.Bot.HoldButton(BTN.ATTACK1, 0.25);
			}
			else {
				this.Finished();
			}
			sleep(0.25);
		}
		this.ReleaseAimRequest();
		this.ReleaseWeaponRequest();

		if (timeout > 0) {
			if (health < 100 && this.EvalDeliverSupplies()) { //skilled medic can revive to full health
				// activate deliver supplies goal.
				this.Bot.RevivedTargetEnt = this.TargetEntity;
				signal(this.Bot.Name + "_deliversupplies");
				sleep(1);
			}
		}
		else {
			Util.ScriptDebugPrint(this.MapGoal.GetName(), "timedout");
			this.BBDelayTime = 10;
		}
	}
	else {
		Util.ScriptDebugPrint(this.MapGoal.GetName(), "pathfailed", "position " + GetEntPosition(this.TargetEntity));
		this.BBDelayTime = 10;
	}
	this.Finished();
};
