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

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()
{
	while(1)
	{
		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()
{
	while(1) {
		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, 32.f) != EVENT.PATH_FAILED ) {
		this.KillThread(this.LookForCloserReviveGoalsThread);
		this.LookForCloserReviveGoalsThread = null;

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

		this.AutoFinishOnUnAvailable = false; //REVIVE goal can be removed before signal to deliver supplies
		health = 0;
		for (timeout = 12; timeout > 0; timeout -= 1) { // 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();
};
