/*
"Sky Grenades"
By Michael 'MaNiAc' Turitzin <miket@inside3d.com>

Place the following functions above W_FireGrenade (but below GrenadeExplode).
The GrenadeTouch function (at the bottom of this file) has been changed and
you need to either make the necessary additions or replace it with the one I
have included.
*/

void() GrenadeTouch;

void() GrenadePositionThink =
{

//NOTE: Much of this is a copy of W_FireGrenade.  I had to make a new grenade
//because using a null model for the old one would screw up its bouncing when
//the model was changed back, and, if the grenade was left in its original
//position or placed in the void, it would still make the "splash" sound when
//it hit something.

        local entity missile;

        missile = spawn ();
        missile.owner = self.owner;
        missile.movetype = MOVETYPE_BOUNCE;
        missile.solid = SOLID_BBOX;
        missile.classname = "grenade";
        missile.velocity = self.movedir;
        missile.avelocity = '300 300 300';
        missile.angles = vectoangles(missile.velocity);
        missile.touch = GrenadeTouch;

        missile.think = GrenadeExplode;
        missile.nextthink = self.attack_finished;

        setmodel (missile, "progs/grenade.mdl");
        setsize (missile, '0 0 0', '0 0 0');     
        setorigin (missile, self.oldorigin);

        remove (self);
};

void() FindNewGrenadePosition =
{
        local float checks, maxchecks, del, contents, realtime, maxtime;
        local vector pos, newvel, lastinsolid;

        maxtime = self.nextthink - time; //find time until grenade will explode
        del = 0.05; //delay time between checks(seems to be the maximum acceptable)
        maxchecks = ceil(maxtime/del); //max number before grenade would blow up
                                       //anyway
        checks = 0;
        pos = self.origin;
        newvel = self.velocity; //I can use this because bouncing velocity is
                                //not changed until after the touch function is called
        do
        {
                newvel_z = newvel_z - cvar("sv_gravity")*del; //account for
                                                              //gravity
                pos = pos + newvel*del; //measure where grenade should now be
                                        //each time increment
                contents = pointcontents (pos);
                if (contents == CONTENT_SOLID)
                        lastinsolid = pos; //record this to make grenade explode
                                           //even if it never enters the level again
                checks = checks + 1;
        } while (((contents == CONTENT_SKY) ||
                  (contents == CONTENT_SOLID)) &&
                  (checks < maxchecks));

        realtime = checks*del; //find time the grenade will "take" to fall
        traceline (pos, pos - newvel*0.2, TRUE, self); //trace to see if grenade
                                                       //has fallen out of sky (and not the ceiling)
        if (trace_fraction < 1)
                trace_endpos = trace_endpos + normalize(newvel); //move endpos
                                                                 //forward so it is
                                                                 //not on a wall
        if ((contents != CONTENT_SKY) &&
            (contents != CONTENT_SOLID) &&
            (pointcontents(trace_endpos) == CONTENT_SKY))
        {
                setmodel (self, string_null);
                self.movetype = MOVETYPE_NONE;
                self.movedir = newvel; //store new velocity
                self.oldorigin = pos; //store new position
                self.attack_finished = self.nextthink; //store nextthink
                self.nextthink = time + realtime; //time when grenade should
                                                  //fall from sky
                self.think = GrenadePositionThink;
        }
        else
        {
                if (lastinsolid) //the grenade will explode where it was last
                                 //in a solid (usually either way out in the
                                 //void or right above a ceiling)
                {
                        setmodel (self, string_null);
                        self.movetype = MOVETYPE_NONE;
                        setorigin (self, lastinsolid);
                }
                else
                        remove (self); //remove if all else fails (this should
                                       //theoretically never happen)
        }
};

void() GrenadeTouch =
{

//MaNiAc START
        if (pointcontents (self.origin) == CONTENT_SKY)
        {
                FindNewGrenadePosition ();
                return;
        }
//MaNiAc END

	if (other.takedamage == DAMAGE_AIM)
	{
		GrenadeExplode();
		return;
	}
	sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);	// bounce sound
	if (self.velocity == '0 0 0')
		self.avelocity = '0 0 0';
};


