this.GoalType = "GRENADE";
this.Version = 1;
this.DefaultPriority = 0.8;
this.MinRadius = 32;
this.RolePriorityBonus = 0.1;
this.MaxUsers_InUse(1);
this.MaxUsers_InProgress(2);

//////////////////////////////////////////////////////////////////////////

this.Schema = Schema();
//this.Schema.Facing = Validate.Vec3().Default(GetLocalFacing);
this.Schema.Stance = Validate.Enum("stand","crouch").Default("stand");
this.Schema.PrimeGrenade = Validate.IntRange(0,3).Default(1);
this.Schema.Count = Validate.IntRange(0,9).Default(0);

//////////////////////////////////////////////////////////////////////////

this.InitNewGoal = function()
{
	this.Facing = Vec3(0,0,0);
	this.TargetGoal = null;
	this.TraceInfo = {};
	this.TraceEntity = null;

	this.Schema.Check(this);
};

//////////////////////////////////////////////////////////////////////////

this.UpgradeVersion = function(Props)
{
	if(Props.Version == 1)
	{
		this.TargetGoal = Props.TargetGoal;
		this.Facing = Props.Facing;
		this.Stance = Props.Stance;
		this.PrimeGrenade = Props.PrimeGrenade;
		this.Count = Props.Count;
		this.TraceInfo = Props.TraceInfo;
		this.IgnoreDead = Props.IgnoreDead;
		this.HasEntity = this.TargetGoal!=null || this.TraceInfo && this.TraceInfo.id != -1;

		if(!this.Schema.Check(this) || (!this.TargetGoal && (!this.TraceInfo || !tableCount(this.TraceInfo))))
		{
			this.DisableGoal(true);
		}
	}
};

//////////////////////////////////////////////////////////////////////////

this.Render = function(editMode)
{
	offset2 = Vec3(0,0,64);

	if (EntityIsValid(this.TraceEntity))
	{
		entPos = GetEntPosition(this.TraceEntity);
	}

	while(this.RenderGoal)
	{
		goalBasePos = this.GetPosition();
		goalPos = goalBasePos + offset2;

		if(!this.ExtraDebugText)
		{
			this.ExtraDebugText = "";
			if(!this.TraceEntity && this.TargetGoal)
			{
				this.ExtraDebugText += format("Target: %s\n",this.TargetGoal);
			}
			else if (this.TraceEntity)
			{
				id = GetGameIdFromEntity(this.TraceEntity);
				if (!id) { id = this.TraceInfo.id; }
				this.ExtraDebugText += format("TraceEnt: %d\n", id);
			}
			this.ExtraDebugText += format("Stance: %s\n",this.Stance);
			if (this.PrimeGrenade > 1) {
				this.ExtraDebugText += format("PrimeGrenade: %d\n",this.PrimeGrenade);
			}
			if (this.Count) {
				this.ExtraDebugText += format("Count: %d\n",this.Count);
			}
			if (this.IgnoreDead) {
				this.ExtraDebugText += format("IgnoreDead: %d\n",this.IgnoreDead);
			}
		}

		if ( this.Stance == "crouch" )
		{
			stanceOffset = -20;
		}
		else
		{
			stanceOffset = 0;
		}

		this.RenderDefault();

		if(this.IsDisabled())
		{
			DrawLine(goalPos,goalBasePos,COLOR.RED,2);
		}
		else
		{
			DrawLine(goalPos,goalBasePos,COLOR.GREEN,2);
		}

		if (this.Facing)
		{
			trajectory = {};
			aimPos = goalPos + Vec3(0,0,stanceOffset);
			DrawArrow(aimPos,aimPos+this.Facing*32,COLOR.BLUE,2);
			trajectory.Velocity = Vec3(this.Facing.x * 900.0 * 1.1, this.Facing.y * 900.0 * 1.1, this.Facing.z * 650.0 * 1.1);
			trajectory.Position = aimPos;
			//trajectory.StopAtHit = true;
			trajectory.TraceBounce = false;
			trajectory.Duration = 30;
			trajectory.Interval = 0.1;

			DrawTrajectory(trajectory,COLOR.WHITE,2);
		}

		if (entPos)
		{
			DrawArrow(goalPos,entPos,COLOR.YELLOW,2);
		}
		else if (EntityIsValid(this.TraceEntity))
		{
			entPos = GetEntPosition(this.TraceEntity);
		}

		sleep(2);
	}
};

//////////////////////////////////////////////////////////////////////////

this.SaveToTable = function(SaveTable)
{
	// save the goal specific properties
	SaveTable.Facing = this.Facing;
	if (this.Stance!="stand"){ SaveTable.Stance = this.Stance; }
	SaveTable.TargetGoal = this.TargetGoal;
	SaveTable.TraceInfo = this.TraceInfo;
	SaveTable.PrimeGrenade = this.PrimeGrenade;
	if(this.IgnoreDead) { SaveTable.IgnoreDead = this.IgnoreDead; }
	if(this.Count) { SaveTable.Count = this.Count; }
};

//////////////////////////////////////////////////////////////////////////

this.Help = function()
{
	print(this.GoalType,"goal");
	print("Requires:");
	print("     targetgoal or trace or traceline - the goal that is to be grenaded or trace info,");
	print("                                        you should use traceline only if there is no entity");
	print("     facing - Direction the bot should face");
	print("Optional:");
	print("     stance - stand, crouch");
	print("     ignoredead - instruct the goal to ignore the dead flag");
	print("     prime - time in seconds the bot should prime the grenade. default 1, max 3");
	print("     count - maximum number of thrown grenades. default 0 (unlimited)");
};

//////////////////////////////////////////////////////////////////////////

this.SetProperty = function(property, value)
{
	switch(property)
	{
		case "facing":
		{
			if ( value == "clearall" || value == "clear" )
			{
				this.Facing = Vec3(0,0,0);
				print("Facing cleared");
			}
			else
			{
				playerFace = GetLocalFacing();
				this.Facing = playerFace;
				print("Facing set to",playerFace);
			}
		}
		case "stance": // crouch, stand, default stand
		{
			if(this.Schema.Stance.CheckPrintErrors(this,value))
			{
				this.Stance = value;
			}
		}
		case "prime":
		{
			this.PrimeGrenade = ToInt(value, 1);

			if ( this.PrimeGrenade > 3 )
			{
				this.PrimeGrenade = 3;
			}
		}
		case "count":
		{
			this.Count = ToInt(value, 0);
		}
		case "targetgoal":
		{
			if ( GetGoal(value) )
			{
				this.TargetGoal = value;
			}
			else
			{
				print(this.GoalType, ": goal not found" );
			}
		}
		case "trace":
		{
			if ( value == "clearall" || value == "clear" )
			{
				this.TraceInfo = null;
				this.TraceEntity = null;
			}
			else
			{
				type = Util.GetTableValue(TRACE, value);
				targetinfo = Util.ShowEntityInfo(type);
				if (tableCount(targetinfo) > 0)
				{
					// store the trace positions. this is so we can handle ETPro map scripts
					// since adding ents with the 'create' command makes ent numbers unreliable
					targetinfo.traceType = type;
					this.TraceInfo = targetinfo;
					this.TraceEntity = targetinfo.id; // for render update
				}
			}
		}
		case "traceline":
		{
			//this is used for destroyable objects which do not have entity
			info = {};
			info.eyePos = GetLocalEyePosition();
			aim = GetLocalFacing();
			tr = TraceLine( info.eyePos, info.eyePos + aim * 1000, 0, TRACE.SHOT|TRACE.FLOODFILLENT, GetGameIdFromEntity(GetLocalEntity()), false );
			if (tr.fraction < 1)
			{
				info.id = -1;
				info.endPos = tr.end + aim * 10;
				DrawDebugLine( info.eyePos, info.endPos, COLOR.GREEN, 20 );
				this.TraceInfo = info;
				this.TraceEntity = null;
			}
		}
		case "ignoredead":
		{
			i = ToBool(value);
			if ( IsNull(i) ) {
				print("ignoredead expecting bool");
				return;
			}
			this.IgnoreDead = i;
		}
		default:
		{
			print(this.GoalType, ": Invalid property:", property);
		}
	}

	this.ExtraDebugText = null;
};

//////////////////////////////////////////////////////////////////////////

this.Update = function()
{
	if ( !this.TraceInfo || !this.TraceInfo.eyePos || !this.TraceInfo.endPos )
	{
		this.Update = null;
		return;
	}

	exploded = false;

	for(;;)
	{
		sleep(1);

		if (this.HasEntity)
		{
			// give it some time to find it since some games spawn ents late
			if (!this.TraceEntity)
			{
				this.TraceEntity = Util.TraceForEntityInfo(this.TraceInfo.eyePos, this.TraceInfo.endPos, this.TraceInfo.traceType);
			}

			if ( this.TraceEntity && !EntityIsValid(this.TraceEntity) )
			{
				exploded = true;
			}
		}
		else
		{
			tr = TraceLine( this.TraceInfo.eyePos, this.TraceInfo.endPos, 0, TRACE.SHOT|TRACE.FLOODFILLENT, 0, false );
			if (tr.fraction == 1)
			{
				exploded = true;
			}
		}
		if (exploded)
		{
			triggerInfo =
			{
				Entity = this.TraceEntity,
				Activator = null,
				TagName = this.GetName() + " Exploded.",
				Action = "Exploded",
			};
			SendTrigger(triggerInfo);

			this.SetAvailable(0, false);
			this.DisableGoal(true);
			block(0);
		}
	}
};

//////////////////////////////////////////////////////////////////////////

this.HudDisplay = function(window)
{
	this.CreateGuiFromSchema(this.Schema);
};
