Exemple #1
0
void G_RunMissile( gentity_t *ent ) {
	vector3		origin, groundSpot;
	trace_t		tr;
	int			passent;
	qboolean	isKnockedSaber = qfalse;

	if ( ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF) ) {
		isKnockedSaber = qtrue;
		ent->s.pos.trType = TR_GRAVITY;
	}

	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, &origin );

	// if this missile bounced off an invulnerability sphere
	if ( ent->target_ent ) {
		passent = ent->target_ent->s.number;
	}
	else {
		// ignore interactions with the missile owner
		if ( (ent->r.svFlags&SVF_OWNERNOTSHARED)
			&& (ent->s.eFlags&EF_JETPACK_ACTIVE) ) {//A vehicle missile that should be solid to its owner
			//I don't care about hitting my owner
			passent = ent->s.number;
		}
		else {
			passent = ent->r.ownerNum;
		}
	}
	// trace a line from the previous position to the current position
	if ( d_projectileGhoul2Collision.integer ) {
		trap->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &origin, passent, ent->clipmask, qfalse, G2TRFLAG_DOGHOULTRACE | G2TRFLAG_GETSURFINDEX | G2TRFLAG_THICK | G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );

		if ( tr.fraction != 1.0f && tr.entityNum < ENTITYNUM_WORLD ) {
			gentity_t *g2Hit = &g_entities[tr.entityNum];

			if ( g2Hit->inuse && g2Hit->client && g2Hit->ghoul2 ) { //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
				g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags;
				g2Hit->client->g2LastSurfaceTime = level.time;
			}

			if ( g2Hit->ghoul2 ) {
				tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
			}

			//Raz: Portals!
			if ( g2Hit->s.eType == ET_SPECIAL && g2Hit->s.userInt1 ) {
				if ( g2Hit->touch ) {
					g2Hit->touch( g2Hit, ent, &tr );
				}
				JPLua::Entity_CallFunction( g2Hit, JPLua::JPLUA_ENTITY_TOUCH, (intptr_t)ent, (intptr_t)&tr );
				goto passthrough;
			}
		}
	}
	else {
		trap->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &origin, passent, ent->clipmask, qfalse, 0, 0 );
	}

	if ( tr.startsolid || tr.allsolid ) {
		// make sure the tr.entityNum is set to the entity we're stuck in
		trap->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &ent->r.currentOrigin, passent, ent->clipmask, qfalse, 0, 0 );
		tr.fraction = 0;
	}
	else {
		VectorCopy( &tr.endpos, &ent->r.currentOrigin );
	}

	if ( ent->passThroughNum && tr.entityNum == (ent->passThroughNum - 1) ) {
		VectorCopy( &origin, &ent->r.currentOrigin );
		trap->LinkEntity( (sharedEntity_t *)ent );
		goto passthrough;
	}

	trap->LinkEntity( (sharedEntity_t *)ent );

	if ( ent->s.weapon == G2_MODEL_PART && !ent->bounceCount ) {
		vector3 lowerOrg;
		trace_t trG;

		VectorCopy( &ent->r.currentOrigin, &lowerOrg );
		lowerOrg.z -= 1;
		trap->Trace( &trG, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &lowerOrg, passent, ent->clipmask, qfalse, 0, 0 );

		VectorCopy( &trG.endpos, &groundSpot );

		if ( !trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD ) {
			ent->s.groundEntityNum = trG.entityNum;
		}
		else {
			ent->s.groundEntityNum = ENTITYNUM_NONE;
		}
	}

	if ( ent->parent && ent->parent->client && ent->parent->client->hook && ent->parent->client->hook == ent
		&& (ent->parent->client->ps.duelInProgress
		|| BG_SaberInSpecial( ent->parent->client->ps.saberMove )
		|| !(japp_allowHook.integer & (1 << level.gametype))
		|| ent->parent->client->pers.adminData.isSlept
		|| g_entities[tr.entityNum].client) )
	{
		// not allowed to have hook out
		Weapon_HookFree( ent );
		return;
	}

	if ( tr.fraction != 1 ) {
		// never explode or bounce on sky
		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
			// If grapple, reset owner
			//	if ( ent->parent && ent->parent->client && ent->parent->client->hook == ent )
			//		ent->parent->client->hook = NULL;
			if ( ent->parent && ent->parent->client && ent->parent->client->hook && ent->parent->client->hook == ent ) {
				Weapon_HookFree( ent->parent->client->hook );
			}

			if ( (ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber ) {
				G_RunThink( ent );
				return;
			}
			else if ( ent->s.weapon != G2_MODEL_PART ) {
				G_FreeEntity( ent );
				return;
			}
		}

		if ( ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
			(tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC) ) { //player or NPC, try making a mark on him
			//copy current pos to s.origin, and current projected traj to origin2
			VectorCopy( &ent->r.currentOrigin, &ent->s.origin );
			BG_EvaluateTrajectory( &ent->s.pos, level.time, &ent->s.origin2 );

			if ( VectorCompare( &ent->s.origin, &ent->s.origin2 ) ) {
				ent->s.origin2.z += 2.0f; //whatever, at least it won't mess up.
			}
		}

		G_MissileImpact( ent, &tr );

		if ( tr.entityNum == ent->s.otherEntityNum ) {
			// if the impact event other and the trace ent match then it's ok to do the g2 mark
			ent->s.trickedEntIndex[0] = 1;
		}

		if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART ) {
			return;		// exploded
		}
	}

passthrough:
	if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags & EF_MISSILE_STICK) ) {
		// stuck missiles should check some special stuff
		G_RunStuckMissile( ent );
		return;
	}

	if ( ent->s.weapon == G2_MODEL_PART ) {
		if ( ent->s.groundEntityNum == ENTITYNUM_WORLD ) {
			ent->s.pos.trType = TR_LINEAR;
			VectorClear( &ent->s.pos.trDelta );
			ent->s.pos.trTime = level.time;

			VectorCopy( &groundSpot, &ent->s.pos.trBase );
			VectorCopy( &groundSpot, &ent->r.currentOrigin );

			if ( ent->s.apos.trType != TR_STATIONARY ) {
				ent->s.apos.trType = TR_STATIONARY;
				ent->s.apos.trTime = level.time;

				ent->s.apos.trBase.roll = 0;
				ent->s.apos.trBase.pitch = 0;
			}
		}
	}

	// check think function after bouncing
	G_RunThink( ent );
}
Exemple #2
0
/*
================
G_RunMissile
================
*/
void G_RunMissile( gentity_t *ent ) {
    vec3_t		origin, groundSpot;
    trace_t		tr;
    int			passent;
    qboolean	isKnockedSaber = qfalse;

    if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
    {
        isKnockedSaber = qtrue;
        ent->s.pos.trType = TR_GRAVITY;
    }

    // get current position
    BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

    // if this missile bounced off an invulnerability sphere
    if ( ent->target_ent ) {
        passent = ent->target_ent->s.number;
    }
    else {
        // ignore interactions with the missile owner
        if ( (ent->r.svFlags&SVF_OWNERNOTSHARED)
                && (ent->s.eFlags&EF_JETPACK_ACTIVE) )
        {   //A vehicle missile that should be solid to its owner
            //I don't care about hitting my owner
            passent = ent->s.number;
        }
        else
        {
            passent = ent->r.ownerNum;
        }
    }
    // trace a line from the previous position to the current position
    if (d_projectileGhoul2Collision.integer)
    {
        trap->Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );

        if (tr.fraction != 1.0 && tr.entityNum < ENTITYNUM_WORLD)
        {
            gentity_t *g2Hit = &g_entities[tr.entityNum];

            if (g2Hit->inuse && g2Hit->client && g2Hit->ghoul2)
            {   //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
                g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags;
                g2Hit->client->g2LastSurfaceTime = level.time;
            }

            if (g2Hit->ghoul2)
            {
                tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
            }
        }
    }
    else
    {
        trap->Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, 0, 0 );
    }

    if ( tr.startsolid || tr.allsolid ) {
        // make sure the tr.entityNum is set to the entity we're stuck in
        trap->Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask, qfalse, 0, 0 );
        tr.fraction = 0;
    }
    else {
        VectorCopy( tr.endpos, ent->r.currentOrigin );
    }

    if (ent->passThroughNum && tr.entityNum == (ent->passThroughNum-1))
    {
        VectorCopy( origin, ent->r.currentOrigin );
        trap->LinkEntity( (sharedEntity_t *)ent );
        goto passthrough;
    }

    trap->LinkEntity( (sharedEntity_t *)ent );

    if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount)
    {
        vec3_t lowerOrg;
        trace_t trG;

        VectorCopy(ent->r.currentOrigin, lowerOrg);
        lowerOrg[2] -= 1;
        trap->Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask, qfalse, 0, 0 );

        VectorCopy(trG.endpos, groundSpot);

        if (!trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD)
        {
            ent->s.groundEntityNum = trG.entityNum;
        }
        else
        {
            ent->s.groundEntityNum = ENTITYNUM_NONE;
        }
    }

    if ( tr.fraction != 1) {
        // never explode or bounce on sky
        if ( tr.surfaceFlags & SURF_NOIMPACT ) {
            // If grapple, reset owner
            if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
                ent->parent->client->hook = NULL;
            }

            if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber)
            {
                G_RunThink( ent );
                return;
            }
            else if (ent->s.weapon != G2_MODEL_PART)
            {
                G_FreeEntity( ent );
                return;
            }
        }

#if 0 //will get stomped with missile impact event...
        if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
                (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
        {   //player or NPC, try making a mark on him
            /*
            gentity_t *evEnt = G_TempEntity(ent->r.currentOrigin, EV_GHOUL2_MARK);

            evEnt->s.owner = tr.entityNum; //the entity the mark should be placed on
            evEnt->s.weapon = ent->s.weapon; //the weapon used (to determine mark type)
            VectorCopy(ent->r.currentOrigin, evEnt->s.origin); //the point of impact

            //origin2 gets the predicted trajectory-based position.
            BG_EvaluateTrajectory( &ent->s.pos, level.time, evEnt->s.origin2 );

            //If they are the same, there will be problems.
            if (VectorCompare(evEnt->s.origin, evEnt->s.origin2))
            {
            	evEnt->s.origin2[2] += 2; //whatever, at least it won't mess up.
            }
            */
            //ok, let's try adding it to the missile ent instead (tempents bad!)
            G_AddEvent(ent, EV_GHOUL2_MARK, 0);

            //copy current pos to s.origin, and current projected traj to origin2
            VectorCopy(ent->r.currentOrigin, ent->s.origin);
            BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

            //the index for whoever we are hitting
            ent->s.otherEntityNum = tr.entityNum;

            if (VectorCompare(ent->s.origin, ent->s.origin2))
            {
                ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
            }
        }
#else
        if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
                (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
        {   //player or NPC, try making a mark on him
            //copy current pos to s.origin, and current projected traj to origin2
            VectorCopy(ent->r.currentOrigin, ent->s.origin);
            BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

            if (VectorCompare(ent->s.origin, ent->s.origin2))
            {
                ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
            }
        }
#endif

        G_MissileImpact( ent, &tr );

        if (tr.entityNum == ent->s.otherEntityNum)
        {   //if the impact event other and the trace ent match then it's ok to do the g2 mark
            ent->s.trickedentindex = 1;
        }

        if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART )
        {
            return;		// exploded
        }
    }

passthrough:
    if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
    {   //stuck missiles should check some special stuff
        G_RunStuckMissile( ent );
        return;
    }

    if (ent->s.weapon == G2_MODEL_PART)
    {
        if (ent->s.groundEntityNum == ENTITYNUM_WORLD)
        {
            ent->s.pos.trType = TR_LINEAR;
            VectorClear(ent->s.pos.trDelta);
            ent->s.pos.trTime = level.time;

            VectorCopy(groundSpot, ent->s.pos.trBase);
            VectorCopy(groundSpot, ent->r.currentOrigin);

            if (ent->s.apos.trType != TR_STATIONARY)
            {
                ent->s.apos.trType = TR_STATIONARY;
                ent->s.apos.trTime = level.time;

                ent->s.apos.trBase[ROLL] = 0;
                ent->s.apos.trBase[PITCH] = 0;
            }
        }
    }

    // check think function after bouncing
    G_RunThink( ent );
}
Exemple #3
0
/*
================
G_RunMissile
================
*/
void G_RunMissile( gentity_t *ent ) {
    vec3_t		origin, groundSpot;
    trace_t		tr;
    int			passent;
    qboolean	isKnockedSaber = qfalse;

    if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
    {
        isKnockedSaber = qtrue;
        ent->s.pos.trType = TR_GRAVITY;
    }

    // get current position
    BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );


    //If its a rocket, and older than 500ms, make it solid to the shooter.
    if ((g_tweakWeapons.integer & WT_SOLID_ROCKET) && (ent->s.weapon == WP_ROCKET_LAUNCHER) && (!ent->raceModeShooter) && (ent->nextthink - level.time < 9500)) {
        ent->r.ownerNum = ENTITYNUM_WORLD;
    }

    // if this missile bounced off an invulnerability sphere
    if ( ent->target_ent ) {
        passent = ent->target_ent->s.number;
    }
    else {
        // ignore interactions with the missile owner
        if ( (ent->r.svFlags&SVF_OWNERNOTSHARED)
                && (ent->s.eFlags&EF_JETPACK_ACTIVE) )
        {   //A vehicle missile that should be solid to its owner
            //I don't care about hitting my owner
            passent = ent->s.number;
        }
        else
        {
            passent = ent->r.ownerNum;
        }
    }
    // trace a line from the previous position to the current position
    if (d_projectileGhoul2Collision.integer == 1) //JAPRO - Serverside - Weapons - New Hitbox Option
    {
        JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );

        if (tr.fraction != 1.0 && tr.entityNum < ENTITYNUM_WORLD)
        {
            gentity_t *g2Hit = &g_entities[tr.entityNum];

            if (g2Hit->inuse && g2Hit->client && g2Hit->ghoul2)
            {   //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
                g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags;
                g2Hit->client->g2LastSurfaceTime = level.time;
            }

            if (g2Hit->ghoul2)
            {
                tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
            }
        }
    }
    else
    {
        JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, 0, 0 );
    }

    if ( tr.startsolid || tr.allsolid ) {
        // make sure the tr.entityNum is set to the entity we're stuck in
        JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask, qfalse, 0, 0 );
        tr.fraction = 0;
    }
    else {
        VectorCopy( tr.endpos, ent->r.currentOrigin );
    }

    if (ent->passThroughNum && tr.entityNum == (ent->passThroughNum-1))
    {
        VectorCopy( origin, ent->r.currentOrigin );
        trap->LinkEntity( (sharedEntity_t *)ent );
        goto passthrough;
    }

    trap->LinkEntity( (sharedEntity_t *)ent );

    if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount)
    {
        vec3_t lowerOrg;
        trace_t trG;

        VectorCopy(ent->r.currentOrigin, lowerOrg);
        lowerOrg[2] -= 1;
        JP_Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask, qfalse, 0, 0 );

        VectorCopy(trG.endpos, groundSpot);

        if (!trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD)
        {
            ent->s.groundEntityNum = trG.entityNum;
        }
        else
        {
            ent->s.groundEntityNum = ENTITYNUM_NONE;
        }
    }

    if (tr.fraction != 1) { //Hit something maybe
        qboolean skip = qfalse;

        gentity_t *other = &g_entities[tr.entityNum]; //Check to see if we hit a lightsaber and they are in another dimension, if so dont do the hit code..
        if (other && other->r.contents & CONTENTS_LIGHTSABER)
        {
            gentity_t *otherOwner = &g_entities[other->r.ownerNum];
            gentity_t *owner = &g_entities[ent->r.ownerNum];
            /*
            if (owner->s.bolt1 && !otherOwner->s.bolt1)//We are dueling/racing and they are not
            	skip = qtrue;
            else if (!owner->s.bolt1 && otherOwner->s.bolt1)//They are dueling/racing and we are not
            	skip = qtrue;
            */
            if (owner->s.bolt1 != otherOwner->s.bolt1) //Dont impact if its from another dimension
                skip = qtrue;
        }

        if ( tr.fraction != 1 && !skip) {

            // never explode or bounce on sky
            if ( tr.surfaceFlags & SURF_NOIMPACT ) {
                // If grapple, reset owner
                if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
                    ent->parent->client->hook = NULL;
                }

                if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber)
                {
                    G_RunThink( ent );
                    return;
                }
                else if (ent->s.weapon != G2_MODEL_PART)
                {
                    G_FreeEntity( ent );
                    return;
                }
            }

            if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
                    (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
            {   //player or NPC, try making a mark on him
                //copy current pos to s.origin, and current projected traj to origin2
                VectorCopy(ent->r.currentOrigin, ent->s.origin);
                BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

                if (VectorCompare(ent->s.origin, ent->s.origin2))
                {
                    ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
                }
            }

            G_MissileImpact( ent, &tr );

            if (tr.entityNum == ent->s.otherEntityNum)
            {   //if the impact event other and the trace ent match then it's ok to do the g2 mark
                ent->s.trickedentindex = 1;
            }

            if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART )
            {
                return;		// exploded
            }
        }
    }

passthrough:
    if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
    {   //stuck missiles should check some special stuff
        G_RunStuckMissile( ent );
        return;
    }

    if (ent->s.weapon == G2_MODEL_PART)
    {
        if (ent->s.groundEntityNum == ENTITYNUM_WORLD)
        {
            ent->s.pos.trType = TR_LINEAR;
            VectorClear(ent->s.pos.trDelta);
            ent->s.pos.trTime = level.time;

            VectorCopy(groundSpot, ent->s.pos.trBase);
            VectorCopy(groundSpot, ent->r.currentOrigin);

            if (ent->s.apos.trType != TR_STATIONARY)
            {
                ent->s.apos.trType = TR_STATIONARY;
                ent->s.apos.trTime = level.time;

                ent->s.apos.trBase[ROLL] = 0;
                ent->s.apos.trBase[PITCH] = 0;
            }
        }
    }
    // check think function after bouncing
    G_RunThink( ent );
}
Exemple #4
0
void G_RunMissile( gentity_t *ent ) 
{
	vec3_t		oldOrg;
	trace_t		tr;
	int			trHitLoc=HL_NONE;

	if ( (ent->s.eFlags&EF_HELD_BY_SAND_CREATURE) )
	{//in a sand creature's mouth
		if ( ent->activator )
		{
			mdxaBone_t	boltMatrix;
			// Getting the bolt here
			//in hand
			vec3_t scAngles = {0};
			scAngles[YAW] = ent->activator->currentAngles[YAW];
			gi.G2API_GetBoltMatrix( ent->activator->ghoul2, ent->activator->playerModel, ent->activator->gutBolt, 
					&boltMatrix, scAngles, ent->activator->currentOrigin, (cg.time?cg.time:level.time),
					NULL, ent->activator->s.modelScale );
			// Storing ent position, bolt position, and bolt axis
			gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->currentOrigin );
			G_SetOrigin( ent, ent->currentOrigin );
		}
		// check think function
		G_RunThink( ent );
		return;
	}

	VectorCopy( ent->currentOrigin, oldOrg );

	// get current position
	if ( ent->s.pos.trType == TR_INTERPOLATE )
	{//rolling missile?
		//FIXME: WTF?!!  Sticks to stick missiles?
		//FIXME: they stick inside the player
		G_RollMissile( ent );
		if ( ent->s.eType != ET_GENERAL )
		{//didn't explode
			VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
			gi.trace( &tr, oldOrg, ent->mins, ent->maxs, ent->currentOrigin, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 );
			if ( VectorCompare( ent->s.pos.trDelta, vec3_origin ) )
			{
				//VectorCopy( ent->currentAngles, ent->s.apos.trBase );
				VectorClear( ent->s.apos.trDelta );
			}
			else
			{
				vec3_t	ang, fwdDir, rtDir;
				float	speed;
				
				ent->s.apos.trType = TR_INTERPOLATE;
				VectorSet( ang, 0, ent->s.apos.trBase[1], 0 );
				AngleVectors( ang, fwdDir, rtDir, NULL );
				speed = VectorLength( ent->s.pos.trDelta )*4;

				//HMM, this works along an axis-aligned dir, but not along diagonals
				//This is because when roll gets to 90, pitch becomes yaw, and vice-versa
				//Maybe need to just set the angles directly?
				ent->s.apos.trDelta[0] = DotProduct( fwdDir, ent->s.pos.trDelta );
				ent->s.apos.trDelta[1] = 0;//never spin!
				ent->s.apos.trDelta[2] = DotProduct( rtDir, ent->s.pos.trDelta );

				VectorNormalize( ent->s.apos.trDelta );
				VectorScale( ent->s.apos.trDelta, speed, ent->s.apos.trDelta );

				ent->s.apos.trTime = level.previousTime;
			}
		}
	}
	else
	{
		vec3_t		origin; 
		EvaluateTrajectory( &ent->s.pos, level.time, origin );
		// trace a line from the previous position to the current position,
		// ignoring interactions with the missile owner
		gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
			ent->owner ? ent->owner->s.number : ent->s.number, ent->clipmask, G2_COLLIDE, 10 );
		
		if ( tr.entityNum != ENTITYNUM_NONE )
		{
			gentity_t *other = &g_entities[tr.entityNum];
			// check for hitting a lightsaber
			if ( other->contents & CONTENTS_LIGHTSABER )
			{//hit a lightsaber bbox
				if ( other->owner 
					&& other->owner->client 
					&& !other->owner->client->ps.saberInFlight 
					&& ( Q_irand( 0, (other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]*other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) ) == 0 
						|| !InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) ) )//other->owner->s.number == 0 &&
				{//Jedi cannot block shots from behind!
					//re-trace from here, ignoring the lightsaber
					gi.trace( &tr, tr.endpos, ent->mins, ent->maxs, origin, tr.entityNum, ent->clipmask, G2_RETURNONHIT, 10 );
				}
			}
		}

		VectorCopy( tr.endpos, ent->currentOrigin );
	}

	// get current angles
	VectorMA( ent->s.apos.trBase, (level.time - ent->s.apos.trTime) * 0.001, ent->s.apos.trDelta, ent->s.apos.trBase );

	//FIXME: Rolling things hitting G2 polys is weird
	///////////////////////////////////////////////////////
//?	if ( tr.fraction != 1 ) 
	{
	// did we hit or go near a Ghoul2 model?
//		qboolean hitModel = qfalse;
		for (int i=0; i < MAX_G2_COLLISIONS; i++)
		{
			if (tr.G2CollisionMap[i].mEntityNum == -1)
			{
				break;
			}

			CCollisionRecord &coll = tr.G2CollisionMap[i];
			gentity_t	*hitEnt = &g_entities[coll.mEntityNum];

			// process collision records here...
			// make sure we only do this once, not for all the entrance wounds we might generate
			if ((coll.mFlags & G2_FRONTFACE)/* && !(hitModel)*/ && hitEnt->health)
			{
				if (trHitLoc==HL_NONE)
				{
					G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL, ent->methodOfDeath );
				}

				break; // NOTE: the way this whole section was working, it would only get inside of this IF once anyway, might as well break out now
			}
		}
	}
/////////////////////////////////////////////////////////

	if ( tr.startsolid ) 
	{
		tr.fraction = 0;
	}

	gi.linkentity( ent );

	if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
	{//stuck missiles should check some special stuff
		G_RunStuckMissile( ent );
		return;
	}

	// check think function
	G_RunThink( ent );

	if ( ent->s.eType != ET_MISSILE ) 
	{
		return;		// exploded
	}

	if ( ent->mass )
	{
		G_MoverTouchPushTriggers( ent, oldOrg );
	}
	/*
	if ( !(ent->s.eFlags & EF_TELEPORT_BIT) )
	{
		G_MoverTouchTeleportTriggers( ent, oldOrg );
		if ( ent->s.eFlags & EF_TELEPORT_BIT )
		{//was teleported
			return;
		}
	}
	else
	{
		ent->s.eFlags &= ~EF_TELEPORT_BIT;
	}
	*/

	AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );//wakes them up when see a shot passes in front of them
	if ( !Q_irand( 0, 10 ) )
	{//not so often...
		if ( ent->splashDamage && ent->splashRadius )
		{//I'm an exploder, let people around me know danger is coming
			if ( ent->s.weapon == WP_TRIP_MINE )
			{//???
			}
			else 
			{
				if ( ent->s.weapon == WP_ROCKET_LAUNCHER && ent->e_ThinkFunc == thinkF_rocketThink )
				{//homing rocket- run like hell!
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER_GREAT, 50 );
				}
				else
				{
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER, 50 );
				}
				AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER );
			}
		}
		else
		{//makes them run from near misses
			AddSightEvent( ent->owner, ent->currentOrigin, 48, AEL_DANGER, 50 );
		}
	}

	if ( tr.fraction == 1 ) 
	{
		if ( ent->s.weapon == WP_THERMAL && ent->s.pos.trType == TR_INTERPOLATE )
		{//a rolling thermal that didn't hit anything
			G_MissileAddAlerts( ent );
		}
		return;
	}

	// never explode or bounce on sky
	if ( tr.surfaceFlags & SURF_NOIMPACT ) 
	{
		G_FreeEntity( ent );
		return;
	}

	G_MissileImpact( ent, &tr, trHitLoc );
}
void G_RunMissile( gentity_t *ent ) 
{
	vec3_t		origin, oldOrg;
	trace_t		tr;
	int			trHitLoc=HL_NONE;

	VectorCopy( ent->currentOrigin, oldOrg );

	// get current position
	if ( ent->s.pos.trType == TR_INTERPOLATE )
	{//rolling missile?
		//FIXME: WTF?!!  Sticks to stick missiles?
		//FIXME: they stick inside the player
		G_RollMissile( ent );
		if ( ent->s.eType != ET_GENERAL )
		{//didn't explode
			VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
			gi.trace( &tr, oldOrg, ent->mins, ent->maxs, ent->currentOrigin, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 );
			if ( VectorCompare( ent->s.pos.trDelta, vec3_origin ) )
			{
				//VectorCopy( ent->currentAngles, ent->s.apos.trBase );
				VectorClear( ent->s.apos.trDelta );
			}
			else
			{
				vec3_t	ang, fwdDir, rtDir;
				float	speed;
				
				ent->s.apos.trType = TR_INTERPOLATE;
				VectorSet( ang, 0, ent->s.apos.trBase[1], 0 );
				AngleVectors( ang, fwdDir, rtDir, NULL );
				speed = VectorLength( ent->s.pos.trDelta )*4;

				//HMM, this works along an axis-aligned dir, but not along diagonals
				//This is because when roll gets to 90, pitch becomes yaw, and vice-versa
				//Maybe need to just set the angles directly?
				ent->s.apos.trDelta[0] = DotProduct( fwdDir, ent->s.pos.trDelta );
				ent->s.apos.trDelta[1] = 0;//never spin!
				ent->s.apos.trDelta[2] = DotProduct( rtDir, ent->s.pos.trDelta );

				VectorNormalize( ent->s.apos.trDelta );
				VectorScale( ent->s.apos.trDelta, speed, ent->s.apos.trDelta );

				ent->s.apos.trTime = level.previousTime;
			}
		}
	}
	else
	{
		EvaluateTrajectory( &ent->s.pos, level.time, origin );
		// trace a line from the previous position to the current position,
		// ignoring interactions with the missile owner
		/*
		gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
			ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_RETURNONHIT, 10 );
		*/
		gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
			ent->owner ? ent->owner->s.number : ent->s.number, ent->clipmask, G2_COLLIDE, 10 );
		/*
		if ( !VectorCompare( ent->mins, vec3_origin ) || !VectorCompare( ent->maxs, vec3_origin ) )
		{//don't do ghoul trace if ent has size because g2 just ignores that anyway
			gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
				ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_NOCOLLIDE, 10 );
		}
		else
		//Now we always do ghoul trace, regardless of bbox size of missile, this is presuming that non-point ghoul traces will be possible...?
		{
			gi.trace( &tr, ent->currentOrigin, vec3_origin, vec3_origin, origin, 
				ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_RETURNONHIT, 10 );
		}
		*/
		/*
		if ( tr.fraction == 0.0f && tr.plane.normal[2] == 1.0f && origin[2] < ent->currentOrigin[2] )
		{
			if ( ent->s.pos.trType == TR_GRAVITY && !(ent->s.eFlags&EF_BOUNCE) && !(ent->s.eFlags&EF_BOUNCE_HALF) && ent->s.weapon == WP_THERMAL )//FIXME: EF_ROLLING
			{
				//FIXME: Needs to stop sometime!
				ent->s.pos.trType = TR_LINEAR;
				ent->s.pos.trDelta[2] = 0;
				EvaluateTrajectory( &ent->s.pos, level.time, origin );
				// trace a line from the previous position to the current position,
				// ignoring interactions with the missile owner
				gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
					ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask | CONTENTS_GHOUL2 );
				if ( tr.fraction == 1.0f )
				{
					VectorCopy( tr.endpos, ent->s.pos.trBase );
					VectorScale( ent->s.pos.trDelta, 0.975f, ent->s.pos.trDelta );
					ent->s.pos.trTime = level.time;
				}
				ent->s.pos.trType = TR_GRAVITY;
			}
		}
		*/

		if ( tr.entityNum != ENTITYNUM_NONE && &g_entities[tr.entityNum] != NULL )
		{
			gentity_t *other = &g_entities[tr.entityNum];
			// check for hitting a lightsaber
			if ( other->contents & CONTENTS_LIGHTSABER )
			{//hit a lightsaber bbox
				if ( other->owner && other->owner->client && !other->owner->client->ps.saberInFlight && !InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) )//other->owner->s.number == 0 &&
				{//Jedi cannot block shots from behind!
					//re-trace from here, ignoring the lightsaber
					gi.trace( &tr, tr.endpos, ent->mins, ent->maxs, origin, tr.entityNum, ent->clipmask, G2_RETURNONHIT, 10 );
				}
			}
		}

		VectorCopy( tr.endpos, ent->currentOrigin );
	}

	// get current angles
	VectorMA( ent->s.apos.trBase, (level.time - ent->s.apos.trTime) * 0.001, ent->s.apos.trDelta, ent->s.apos.trBase );

	//FIXME: Rolling things hitting G2 polys is weird
	///////////////////////////////////////////////////////
//?	if ( tr.fraction != 1 ) 
	{
	// did we hit or go near a Ghoul2 model?
//		qboolean hitModel = qfalse;
		for (int i=0; i < MAX_G2_COLLISIONS; i++)
		{
			if (tr.G2CollisionMap[i].mEntityNum == -1)
			{
				break;
			}

			CCollisionRecord &coll = tr.G2CollisionMap[i];
			gentity_t	*hitEnt = &g_entities[coll.mEntityNum];

/*	Sorry...this was just getting in the way....
#if _DEBUG
			vec3_t delta;
			VectorSubtract(origin, coll.mCollisionPosition, delta);
			VectorNormalize(delta);
			VectorScale(delta, 30, delta);

			if (coll.mFlags & G2_BACKFACE)
			{
				VectorAdd(delta, coll.mCollisionPosition, delta);
				G_DebugLine(coll.mCollisionPosition, delta, 10000, 0x00ff0000, qtrue);
			}
			else
			{
				VectorSubtract(coll.mCollisionPosition, delta, delta);
				G_DebugLine(coll.mCollisionPosition, delta, 10000, 0x0000ff00, qtrue);
			}

//loadsavecrash
//			VectorCopy(hitEnt->mins, hitEnt->s.mins);
//			VectorCopy(hitEnt->maxs, hitEnt->s.maxs);
#endif
*/

			// process collision records here...
			// make sure we only do this once, not for all the entrance wounds we might generate
			if ((coll.mFlags & G2_FRONTFACE)/* && !(hitModel)*/ && hitEnt->health)
			{
				// create a new surface using the details of what poly/surface/model we hit
//				int newSurface = gi.G2API_AddSurface(&hitEnt->ghoul2[coll.mModelIndex], coll.mSurfaceIndex, coll.mPolyIndex, coll.mBarycentricI, coll.mBarycentricJ, 10);
//				surfaceInfo_t	*newSuf = &hitEnt->ghoul2[coll.mModelIndex].mSlist[newSurface];
				// attach a bolt to this surface
//				int newBolt = gi.G2API_AddBoltSurfNum(&hitEnt->ghoul2[coll.mModelIndex], newSurface);
				// now attach an effect to this new bolt

//	Bolting on this effect just looks dumb and adds lots of unnecessary effects to the scene
//				
//				G_PlayEffect( G_EffectIndex( "blaster/smoke_bolton") , coll.mModelIndex, newBolt, hitEnt->s.number);
//
//

//				G_SetBoltSurfaceRemoval(coll.mEntityNum, coll.mModelIndex, newBolt, newSurface, 10000);
//				hitModel = qtrue;

				if (trHitLoc==HL_NONE)
				{
					G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL, ent->methodOfDeath );
				}

				break; // NOTE: the way this whole section was working, it would only get inside of this IF once anyway, might as well break out now
			}
		}
	}
/////////////////////////////////////////////////////////

	if ( tr.startsolid ) 
	{
		tr.fraction = 0;
	}

	gi.linkentity( ent );

	if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
	{//stuck missiles should check some special stuff
		G_RunStuckMissile( ent );
		return;
	}

	// check think function
	G_RunThink( ent );

	if ( ent->s.eType != ET_MISSILE ) 
	{
		return;		// exploded
	}

	if ( ent->mass )
	{
		G_MoverTouchPushTriggers( ent, oldOrg );
	}
	/*
	if ( !(ent->s.eFlags & EF_TELEPORT_BIT) )
	{
		G_MoverTouchTeleportTriggers( ent, oldOrg );
		if ( ent->s.eFlags & EF_TELEPORT_BIT )
		{//was teleported
			return;
		}
	}
	else
	{
		ent->s.eFlags &= ~EF_TELEPORT_BIT;
	}
	*/

	AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );//wakes them up when see a shot passes in front of them
	if ( !Q_irand( 0, 10 ) )
	{//not so often...
		if ( ent->splashDamage && ent->splashRadius )
		{//I'm an exploder, let people around me know danger is coming
			if ( ent->s.weapon == WP_TRIP_MINE )
			{//???
			}
			else 
			{
				if ( ent->s.weapon == WP_ROCKET_LAUNCHER && ent->e_ThinkFunc == thinkF_rocketThink )
				{//homing rocket- run like hell!
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER_GREAT, 50 );
				}
				else
				{
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER, 50 );
				}
				AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER );
			}
		}
		else
		{//makes them run from near misses
			AddSightEvent( ent->owner, ent->currentOrigin, 48, AEL_DANGER, 50 );
		}
	}

	if ( tr.fraction == 1 ) 
	{
		return;
	}

	// never explode or bounce on sky
	if ( tr.surfaceFlags & SURF_NOIMPACT ) 
	{
		G_FreeEntity( ent );
		return;
	}

	G_MissileImpact( ent, &tr, trHitLoc );
}
Exemple #6
0
//[/RealTrace]
void G_RunMissile( gentity_t *ent ) {
    vec3_t		origin, groundSpot;
    trace_t		tr;
    int			passent;
    qboolean	isKnockedSaber = qfalse;

    if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
    {
        isKnockedSaber = qtrue;
        //[SaberThrowSys]
        if(!(ent->s.eFlags & EF_MISSILE_STICK) )
        {   //only go into gravity mode if we're not stuck to something
            ent->s.pos.trType = TR_GRAVITY;
        }
        //[/SaberThrowSys]
    }

    // get current position
    BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

    // if this missile bounced off an invulnerability sphere
    if ( ent->target_ent ) {
        passent = ent->target_ent->s.number;
    }
    else {
        // ignore interactions with the missile owner
        if ( (ent->r.svFlags&SVF_OWNERNOTSHARED)
                && (ent->s.eFlags&EF_JETPACK_ACTIVE) )
        {   //A vehicle missile that should be solid to its owner
            //I don't care about hitting my owner
            passent = ent->s.number;
        }
        else
        {
            passent = ent->r.ownerNum;
        }
    }
    // trace a line from the previous position to the current position
    //[RealTrace]
    G_RealTrace( ent, &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, -1, -1 );
    //[/RealTrace]

    if ( !tr.startsolid && !tr.allsolid )
        VectorCopy( tr.endpos, ent->r.currentOrigin );

    if (ent->passThroughNum && tr.entityNum == (ent->passThroughNum-1))
    {
        VectorCopy( origin, ent->r.currentOrigin );
        trap_LinkEntity( ent );
        goto passthrough;
    }

    trap_LinkEntity( ent );
    //racc - assign groundEntityNum for body parts.
    if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount)
    {
        vec3_t lowerOrg;
        trace_t trG;

        VectorCopy(ent->r.currentOrigin, lowerOrg);
        lowerOrg[2] -= 1;
        trap_Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask );

        VectorCopy(trG.endpos, groundSpot);

        if (!trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD)
        {
            ent->s.groundEntityNum = trG.entityNum;
        }
        else
        {
            ent->s.groundEntityNum = ENTITYNUM_NONE;
        }
    }

    if ( tr.fraction != 1) {
        // never explode or bounce on sky
        if ( tr.surfaceFlags & SURF_NOIMPACT ) {
            // If grapple, reset owner
            if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
                ent->parent->client->hook = NULL;
            }

            //racc - make dropped sabers think when they hit a non-impact surface.
            if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber)
            {
                G_RunThink( ent );
                return;
            }
            //just kill off other weapon shots when they hit a non-impact surface.
            else if (ent->s.weapon != G2_MODEL_PART)
            {
                G_FreeEntity( ent );
                return;
            }
        }
        if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
                (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
        {   //player or NPC, try making a mark on him
            //copy current pos to s.origin, and current projected traj to origin2
            VectorCopy(ent->r.currentOrigin, ent->s.origin);
            BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

            if (VectorCompare(ent->s.origin, ent->s.origin2))
            {   //racc - don't allow the current origin/predicted origin be the same.
                ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
            }
        }

        //[DodgeSys]
        //changed G_MissileImpact to qboolean so that dodges will cause passthru behavor.
        if(!G_MissileImpact( ent, &tr ))
        {   //target dodged the damage.
            VectorCopy( origin, ent->r.currentOrigin );
            trap_LinkEntity( ent );
            return;
        }
        //G_MissileImpact( ent, &tr );
        //[/DodgeSys]

        if (tr.entityNum == ent->s.otherEntityNum)
        {   //if the impact event other and the trace ent match then it's ok to do the g2 mark
            ent->s.trickedentindex = 1;
        }

        if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART )
        {
            return;		// exploded
        }
    }

passthrough:
    if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
    {   //stuck missiles should check some special stuff
        G_RunStuckMissile( ent );
        return;
    }

    if (ent->s.weapon == G2_MODEL_PART)
    {
        if (ent->s.groundEntityNum == ENTITYNUM_WORLD)
        {
            ent->s.pos.trType = TR_LINEAR;
            VectorClear(ent->s.pos.trDelta);
            ent->s.pos.trTime = level.time;

            VectorCopy(groundSpot, ent->s.pos.trBase);
            VectorCopy(groundSpot, ent->r.currentOrigin);

            if (ent->s.apos.trType != TR_STATIONARY)
            {
                ent->s.apos.trType = TR_STATIONARY;
                ent->s.apos.trTime = level.time;

                ent->s.apos.trBase[ROLL] = 0;
                ent->s.apos.trBase[PITCH] = 0;
            }
        }
    }

    if(ent->damageDecreaseTime && ent->damageDecreaseTime <= level.time)
    {
        ent->damage-=4;
        ent->damageDecreaseTime = level.time + 300;
    }

    // check think function after bouncing
    G_RunThink( ent );
}