Beispiel #1
0
qbool SV_CheckBottom (edict_t *ent)
{
    vec3_t	mins, maxs, start, stop;
    trace_t	trace;
    int		x, y;
    float	mid, bottom;

    VectorAdd (ent->v.origin, ent->v.mins, mins);
    VectorAdd (ent->v.origin, ent->v.maxs, maxs);

// if all of the points under the corners are solid world, don't bother
// with the tougher checks
// the corners must be within 16 of the midpoint
    start[2] = mins[2] - 1;
    for	(x=0 ; x<=1 ; x++)
        for	(y=0 ; y<=1 ; y++)
        {
            start[0] = x ? maxs[0] : mins[0];
            start[1] = y ? maxs[1] : mins[1];
            if (SV_PointContents (start) != CONTENTS_SOLID)
                goto realcheck;
        }

    return true;		// we got out easy

realcheck:
//
// check it for real...
//
    start[2] = mins[2];

// the midpoint must be within 16 of the bottom
    start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
    start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
    stop[2] = start[2] - 2*STEPSIZE;
    trace = SV_Trace (start, vec3_origin, vec3_origin, stop, true, ent);

    if (trace.fraction == 1.0)
        return false;
    mid = bottom = trace.endpos[2];

// the corners must be within 16 of the midpoint
    for	(x=0 ; x<=1 ; x++)
        for	(y=0 ; y<=1 ; y++)
        {
            start[0] = stop[0] = x ? maxs[0] : mins[0];
            start[1] = stop[1] = y ? maxs[1] : mins[1];

            trace = SV_Trace (start, vec3_origin, vec3_origin, stop, true, ent);

            if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
                bottom = trace.endpos[2];
            if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
                return false;
        }

    return true;
}
Beispiel #2
0
static void predict_move(sharedEntity_t *ent, float frametime, trajectory_t *tr, vec3_t result)
{
	float   stepSize;
	vec3_t  start_o, start_v, down, up;
	trace_t trace;

	VectorCopy(tr->trBase, result); // assume the move fails

	if (zero_vector(tr->trDelta)) // not moving
	{
		return;
	}

	if (predict_slide_move(ent, frametime, tr, result)) // move completed
	{
		return;
	}

	VectorCopy(tr->trBase, start_o);
	VectorCopy(tr->trDelta, start_v);

	VectorCopy(start_o, up);
	up[2] += STEPSIZE;

	// test the player position if they were a stepheight higher
	SV_Trace(&trace, start_o, ent->r.mins, ent->r.maxs, up, ent->s.number,
	         CONTENTS_SOLID, qfalse);

	if (trace.allsolid)     // can't step up
	{
		return;
	}

	stepSize = trace.endpos[2] - start_o[2];

	// try slidemove from this position
	VectorCopy(trace.endpos, tr->trBase);
	VectorCopy(start_v, tr->trDelta);

	predict_slide_move(ent, frametime, tr, result);

	// push down the final amount
	VectorCopy(tr->trBase, down);
	down[2] -= stepSize;
	SV_Trace(&trace, tr->trBase, ent->r.mins, ent->r.maxs, down, ent->s.number,
	         CONTENTS_SOLID, qfalse);

	if (!trace.allsolid)
	{
		VectorCopy(trace.endpos, result);
	}
}
Beispiel #3
0
/*
============
SV_TestEntityPosition

A small wrapper around SV_BoxInSolidEntity that never clips against the
supplied entity.
============
*/
edict_t	*SV_TestEntityPosition (edict_t *ent)
{
	trace_t	trace;

	if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
		// only clip against bmodels
		trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NOMONSTERS, ent);
	else
		trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent);
	
	if (trace.startsolid)
		return sv.edicts;
		
	return NULL;
}
Beispiel #4
0
/*
 * Kills all entities that would touch the
 * proposed new positioning of ent. Ent s
 * hould be unlinked before calling this!
 */
qboolean KillBox(edict_t *ent)
{
  trace_t tr;

  if (!ent) {
    return false;
  }

  while (1) {
    tr = SV_Trace(ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);

    if (!tr.ent) {
      break;
    }

    /* nail it */
    T_Damage(tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);

    /* if we didn't kill it, fail */
    if (tr.ent->solid) {
      return false;
    }
  }

  return true; /* all clear */
}
Beispiel #5
0
int SV_OrgVisibleBox(vec3_t org1, vec3_t mins, vec3_t maxs, vec3_t org2, int ignore, int rmg)
{
	trace_t tr;

	if (rmg)
	{
		SV_Trace(&tr, org1, NULL, NULL, org2, ignore, MASK_SOLID, 0, 0, 10);
	}
	else
	{
		SV_Trace(&tr, org1, mins, maxs, org2, ignore, MASK_SOLID, 0, 0, 10);
	}

	if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
	{
		return 1;
	}

	return 0;
}
/*
================
FinishSpawningItem

Traces down to find where an item should rest, instead of letting them
free fall from their spawn points
================
*/
void GameItem::Think_FinishSpawningItem::execute() 
{
	trace_t		tr;
	vec3_t		dest;

	VectorSet( self_->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS );
	VectorSet( self_->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );

	self_->s.eType = ET_ITEM;
	self_->s.modelindex = self_->item_ - bg_itemlist;		// store item number in modelindex
	self_->s.modelindex2 = 0; // zero indicates this isn't a dropped item

	self_->r.contents = CONTENTS_TRIGGER;
	self_->setTouch(new Touch_ItemTouch);

	// useing an item causes it to respawn
	self_->setUse(new Use_ItemUse);

	if( self_->spawnflags_ & 1 ) 
	{
		// suspended
		G_SetOrigin( self_, self_->s.origin );
	} 
	else 
	{
		// drop to floor
		VectorSet( dest, self_->s.origin[0], self_->s.origin[1], self_->s.origin[2] - 4096 );
		SV_Trace( &tr, self_->s.origin, self_->r.mins, self_->r.maxs, dest, self_->s.number, MASK_SOLID, false );
		if( tr.startsolid ) 
		{
			Com_Printf ("FinishSpawningItem: %s startsolid at %s\n", self_->classname_, vtos(self_->s.origin));
			//theLevel.removeEntity(self_);
			self_->freeUp();
			return;
		}

		// allow to ride movers
		self_->s.groundEntityNum = tr.entityNum;

		G_SetOrigin( self_, tr.endpos );
	}

	// team slaves and targeted items aren't present at start
	if( ( self_->flags_ & FL_TEAMSLAVE ) || self_->targetname_ ) 
	{
		self_->s.eFlags |= EF_NODRAW;
		self_->r.contents = 0;
		return;
	}

	SV_LinkEntity( self_ );
}
Beispiel #7
0
/*
============
SV_PushEntity

Does not change the entities velocity at all
============
*/
trace_t SV_PushEntity (edict_t *ent, vec3_t push)
{
    trace_t	trace;
    vec3_t	end;

    VectorAdd (ent->v.origin, push, end);

    if (ent->v.movetype == MOVETYPE_FLYMISSILE)
        trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
    else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
        // only clip against bmodels
        trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
    else
        trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);

    VectorCopy (trace.endpos, ent->v.origin);
    SV_LinkEdict (ent, true);

    if (trace.e.ent)
        SV_Impact (ent, trace.e.ent);

    return trace;
}
Beispiel #8
0
/*
==================
BotImport_Trace
==================
*/
static void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {
	trace_t trace;

	SV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse);
	//copy the trace information
	bsptrace->allsolid = trace.allsolid;
	bsptrace->startsolid = trace.startsolid;
	bsptrace->fraction = trace.fraction;
	VectorCopy(trace.endpos, bsptrace->endpos);
	bsptrace->plane.dist = trace.plane.dist;
	VectorCopy(trace.plane.normal, bsptrace->plane.normal);
	bsptrace->plane.signbits = trace.plane.signbits;
	bsptrace->plane.type = trace.plane.type;
	bsptrace->surface.value = trace.surfaceFlags;
	bsptrace->ent = trace.entityNum;
	bsptrace->exp_dist = 0;
	bsptrace->sidenum = 0;
	bsptrace->contents = 0;
}
Beispiel #9
0
/*
 * BotImport_Trace
 */
static void
BotImport_Trace(bsp_Trace *bsptrace, Vec3 start, Vec3 mins, Vec3 maxs,
		Vec3 end, int passent,
		int contentmask)
{
	Trace trace;

	SV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse);
	/* copy the trace information */
	bsptrace->allsolid	= trace.allsolid;
	bsptrace->startsolid	= trace.startsolid;
	bsptrace->fraction	= trace.fraction;
	copyv3(trace.endpos, bsptrace->endpos);
	bsptrace->plane.dist = trace.plane.dist;
	copyv3(trace.plane.normal, bsptrace->plane.normal);
	bsptrace->plane.signbits = trace.plane.signbits;
	bsptrace->plane.type = trace.plane.type;
	bsptrace->surface.value = trace.surfaceFlags;
	bsptrace->ent = trace.entityNum;
	bsptrace->exp_dist	= 0;
	bsptrace->sidenum	= 0;
	bsptrace->contents	= 0;
}
Beispiel #10
0
/*
=============
SV_movestep

Called by monster program code.
The move will be adjusted for slopes and stairs, but if the move isn't
possible, no move is done, false is returned, and
pr_global_struct->trace_normal is set to the normal of the blocking wall
=============
*/
qbool SV_movestep (edict_t *ent, vec3_t move, qbool relink)
{
    float		dz;
    vec3_t		oldorg, neworg, end;
    trace_t		trace;
    int			i;
    edict_t		*enemy;

// try the move
    VectorCopy (ent->v.origin, oldorg);
    VectorAdd (ent->v.origin, move, neworg);

// flying monsters don't step up
    if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) )
    {
        // try one move with vertical motion, then one without
        for (i=0 ; i<2 ; i++)
        {
            VectorAdd (ent->v.origin, move, neworg);
            enemy = PROG_TO_EDICT(ent->v.enemy);
            if (i == 0 && enemy != sv.edicts)
            {
                dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];
                if (dz > 40)
                    neworg[2] -= 8;
                if (dz < 30)
                    neworg[2] += 8;
            }
            trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent);

            if (trace.fraction == 1)
            {
                if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )
                    return false;	// swim monster left water

                VectorCopy (trace.endpos, ent->v.origin);
                if (relink)
                    SV_LinkEdict (ent, true);
                return true;
            }

            if (enemy == sv.edicts)
                break;
        }

        return false;
    }

// push down from a step height above the wished position
    neworg[2] += STEPSIZE;
    VectorCopy (neworg, end);
    end[2] -= STEPSIZE*2;

    trace = SV_Trace (neworg, ent->v.mins, ent->v.maxs, end, false, ent);

    if (trace.allsolid)
        return false;

    if (trace.startsolid)
    {
        neworg[2] -= STEPSIZE;
        trace = SV_Trace (neworg, ent->v.mins, ent->v.maxs, end, false, ent);
        if (trace.allsolid || trace.startsolid)
            return false;
    }
    if (trace.fraction == 1)
    {
        // if monster had the ground pulled out, go ahead and fall
        if ( (int)ent->v.flags & FL_PARTIALGROUND )
        {
            VectorAdd (ent->v.origin, move, ent->v.origin);
            if (relink)
                SV_LinkEdict (ent, true);
            ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
//	Com_Printf ("fall down\n");
            return true;
        }

        return false;		// walked off an edge
    }

// check point traces down for dangling corners
    VectorCopy (trace.endpos, ent->v.origin);

    if (!SV_CheckBottom (ent))
    {
        if ( (int)ent->v.flags & FL_PARTIALGROUND )
        {   // entity had floor mostly pulled out from underneath it
            // and is trying to correct
            if (relink)
                SV_LinkEdict (ent, true);
            return true;
        }
        VectorCopy (oldorg, ent->v.origin);
        return false;
    }

    if ( (int)ent->v.flags & FL_PARTIALGROUND )
    {
//		Com_Printf ("back on ground\n");
        ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;
    }
    ent->v.groundentity = EDICT_TO_PROG(trace.e.ent);

// the move is ok
    if (relink)
        SV_LinkEdict (ent, true);
    return true;
}
void updateTargetTracking( GameEntity *ent )
{
	unsigned long	targetcat = 0;
	trace_t			tr;
	vec3_t			forward, endpos, dir;
	float			radarrange = 0;
	bool			buildings = false, groundinstallations = false;
	GameEntity		*test;
	float			cone = 0.0f;
	
//	Com_Printf( "updateTargetTracking for %s\n", ent->client->pers.netname );

	// what can we lock on ?
	if(	ent->client_->ps_.ONOFF & OO_RADAR_AIR )
	{
		targetcat = CAT_PLANE|CAT_HELO;
		radarrange = availableVehicles[ent->client_->vehicle_].radarRange;
		cone = availableVehicles[ent->client_->vehicle_].trackCone;
	} 
	else if( ent->client_->ps_.ONOFF & OO_RADAR_GROUND ) 
	{
		targetcat = CAT_GROUND|CAT_BOAT;
		buildings = true;
		groundinstallations = true;
		radarrange = availableVehicles[ent->client_->vehicle_].radarRange2;
		cone = availableVehicles[ent->client_->vehicle_].trackCone2;
	}
	
	if( !targetcat ) 
	{
		if( ent->client_->ps_.stats[STAT_LOCKINFO] ) 
			untrack(ent);
		return;
	}

	// weapon range and vehicle direction
	if( (availableVehicles[ent->client_->vehicle_].cat & CAT_GROUND) ||
		(availableVehicles[ent->client_->vehicle_].cat & CAT_BOAT)) 
	{
		vec3_t	right, up, temp;
		AngleVectors( ent->client_->ps_.vehicleAngles, forward, right, up );
		RotatePointAroundVector( temp, up, forward, ent->client_->ps_.turretAngle );
		CrossProduct( up, temp, right );
		RotatePointAroundVector( dir, right, temp, ent->client_->ps_.gunAngle );
		VectorCopy( dir, forward );
	} 
	else
	{
		VectorCopy( ent->s.angles, dir );
		AngleVectors( dir, forward, 0, 0 );
	}

	// no target yet
	if( !ent->tracktarget_ ) 
	{
		VectorMA( ent->r.currentOrigin, radarrange, forward, endpos );
		SV_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, endpos, ent->s.number, MASK_ALL, false );
		// nothing found
		if( tr.entityNum == ENTITYNUM_NONE ) 
			return;

		// found something
		test = theLevel.getEntity(tr.entityNum);// &g_entities[tr.entityNum];
		if( test->s.eType == ET_VEHICLE && test->client_ && 
			(availableVehicles[test->client_->vehicle_].cat & targetcat) ) 
		{
			track(ent, test);
		} 
		else if( test->s.eType == ET_MISC_VEHICLE )
		{
			if( (test->s.modelindex == 255 && groundinstallations) || // ground installations
			    (availableVehicles[test->s.modelindex].cat & targetcat) ) 
				track(ent, test);
		} 
		else
		{
			if( buildings ) 
			{
				if( test->s.eType == ET_EXPLOSIVE && test->takedamage_ ) 
					track(ent, test);
			}
			else 
			{
				return;
			}
		}
	} 
	else 
	{ 
		// update existing target
		vec3_t diff;
		float dot, dist;
		int actualcat = 0;

		if( ent->tracktarget_->s.eType == ET_EXPLOSIVE ) 
		{
			vec3_t	mid;
			actualcat = CAT_GROUND;
			VectorAdd( ent->tracktarget_->r.absmax, ent->tracktarget_->r.absmin, mid );
			VectorScale( mid, 0.5f, mid );
			VectorSubtract( mid, ent->r.currentOrigin, diff );
		} 
		else 
		{
			if( ent->tracktarget_->s.eType == ET_MISC_VEHICLE )
			{
				if( ent->tracktarget_->s.modelindex == 255 )// groundinstallation
				{
					actualcat = CAT_GROUND;
					groundinstallations = true;
				}
				else
					actualcat = availableVehicles[ent->tracktarget_->s.modelindex].cat;
			} 
			else if( ent->tracktarget_->s.eType == ET_VEHICLE && ent->tracktarget_->client_ ) 
			{
				actualcat =	availableVehicles[ent->tracktarget_->client_->vehicle_].cat;
			}
			VectorSubtract( ent->tracktarget_->r.currentOrigin, ent->r.currentOrigin, diff );
		}
		if( !actualcat ) 
		{
			untrack(ent);
			return;
		}
			
		// check within range
		dist = VectorNormalize( diff );
		if( dist > radarrange )
		{
			untrack(ent);
			return;
		}
		// check within cone
		dot = DotProduct( forward, diff );
		if( dot < cone ) 
		{
			untrack(ent);
			return;
		} 
		else if( dot < availableWeapons[ent->s.weaponIndex].lockcone ) 
		{
			if( ent->client_->ps_.stats[STAT_LOCKINFO] & LI_LOCKING )	
				unlock(ent);
			ent->locktime_ = theLevel.time_;
			return;
		}
			
		// check LOS
		VectorMA( ent->r.currentOrigin, dist, diff, endpos );
		SV_Trace( &tr, ent->r.currentOrigin, 0, 0, endpos, ent->s.number, MASK_PLAYERSOLID, false );
		if( tr.fraction < 1 && tr.entityNum != ent->s.tracktarget ) 
		{
			untrack(ent);
			return;
		}

		// only weapons that can lock on
		if( availableWeapons[ent->s.weaponIndex].type != WT_GUIDEDBOMB &&
			availableWeapons[ent->s.weaponIndex].type != WT_ANTIAIRMISSILE &&
			availableWeapons[ent->s.weaponIndex].type != WT_ANTIGROUNDMISSILE &&
			availableWeapons[ent->s.weaponIndex].type != WT_ANTIRADARMISSILE )
		{
			//untrack(ent);
			if( ent->client_->ps_.stats[STAT_LOCKINFO] & LI_LOCKING )
				unlock(ent);
			return;
		}

		// what can we lock on ?
		targetcat = 0;
		if(	availableWeapons[ent->s.weaponIndex].type == WT_ANTIAIRMISSILE &&
			(ent->client_->ps_.ONOFF & OO_RADAR_AIR) ) 
		{
			targetcat = CAT_PLANE|CAT_HELO;
		} 
		else if( availableWeapons[ent->s.weaponIndex].type != WT_ANTIAIRMISSILE &&
			(ent->client_->ps_.ONOFF & OO_RADAR_GROUND) )
		{
			targetcat = CAT_GROUND|CAT_BOAT;
			buildings = true;
		}
		if( !targetcat ) 
		{
			unlock(ent);
			//untrack(ent);
			return;
		} 
		else if( !(targetcat & actualcat) ) 
		{
			unlock(ent);
			return;			
		}
		// check time
		if( theLevel.time_ > ent->locktime_ + availableWeapons[ent->s.weaponIndex].lockdelay )
		{
			ent->client_->ps_.stats[STAT_LOCKINFO] |= LI_LOCKING;
		}
		// update target
		if( ent->tracktarget_->client_ && (ent->client_->ps_.stats[STAT_LOCKINFO] & LI_LOCKING) )
		{
			ent->tracktarget_->client_->ps_.stats[STAT_LOCKINFO] |= LI_BEING_LOCKED;
		}
	}
}
Beispiel #12
0
/**
 * @brief This test cycles through the list of map definitions found in the maps.ufo script
 * and tries to find surfaces to stand on with no sound assigned to them.
 *
 * This test takes too long to be run every time testall is run. So it's set up almost like a game:
 * After 5 maps (the first of them is fully checked) with missing sounds, the test stops.
 * If we manage to 'clean' one of those 5 maps, the next map will show up in the next run.
 */
TEST_F(FootStepTest, DISABLED_MapDefsFootSteps)
{
	const char* filterId = TEST_GetStringProperty("mapdef-id");
	const mapDef_t* md;
	int mapCount = 0;				// the number of maps read
	int badMapCount = 0;
	const int skipCount = 20;		// to skip the first n mapDefs
	const int badMapCountMax = 25;	// # of maps with missing sounds before this test stops
	const int mapCountMax = 150;	// should of cause be higher than skip + bad
	const int texCountMax = 30;
	char texNames[texCountMax][MAX_QPATH];
	bool done = false;

	OBJZERO(texNames);
	ASSERT_TRUE(csi.numMDs > 0);

	MapDef_Foreach(md) {
		if (md->mapTheme[0] == '.')
			continue;
		if (filterId && !Q_streq(filterId, md->id))
			continue;

		mapCount++;
		if (mapCount <= skipCount)
			continue;
		/* use a known seed to reproduce an error */
		unsigned int seed;
		if (TEST_ExistsProperty("mapdef-seed")) {
			seed = TEST_GetLongProperty("mapdef-seed");
		} else {
			seed = (unsigned int) time(nullptr);
		}
		srand(seed);

		int count = 0;
		Com_Printf("testMapDefsFootSteps: Mapdef %s (seed %u)\n", md->id, seed);

		const char* asmName = (const char*)LIST_GetByIdx(md->params, 0);
		SV_Map(true, md->mapTheme, asmName);

		/* now that we have loaded the map, check all cells for walkable places */
		GridBox mBox(sv->mapData.mapBox);	// test ALL the cells
#if !FOOTSTEPS_FULL
		if (mapCount >= skipCount + 4) {	// after the first 4 maps, reduce the testing area
			const pos3_t center = {148, 128, 0};
			mBox.set(center, center);		// the box on the map we're testing
			mBox.expandXY(10);				// just test a few cells around the center of the map
			mBox.maxs[2] = 2;				// and 3 levels high
		}
#endif
		mBox.clipToMaxBoundaries();

		for (int x = mBox.getMinX(); x <= mBox.getMaxX() && !done; x++) {
			for (int y = mBox.getMinY(); y <= mBox.getMaxY() && !done; y++) {
				for (int z = mBox.getMinZ(); z <= mBox.getMaxZ(); z++) {
					const int floor = sv->mapData.routing.getFloor(1, x, y, z);
					if (floor < 0)						// if we have a floor in that cell
						continue;
					const AABB noBox(vec3_origin, vec3_origin);	// we're doing a point-trace
					const pos3_t cellPos = {(pos_t)x, (pos_t)y, (pos_t)z};			// the cell in question
					vec3_t from, to;
					PosToVec(cellPos, from);			// the center of the cell
					VectorCopy(from, to);				// also base for the endpoint of the trace
					from[2] -= UNIT_HEIGHT / 2;			// bottom of the cell
					from[2] += (floor + 2) * QUANT;		// add the height of the floor plus 2 QUANTS
					to[2] -= 2 * UNIT_HEIGHT;			// we should really hit the ground with this
					const trace_t trace = SV_Trace(Line(from, to), noBox, nullptr, MASK_SOLID);
					if (!trace.surface)
						continue;

					const char* snd = SV_GetFootstepSound(trace.surface->name);
					if (snd)
						continue;

					for (int i = 0; i < texCountMax; ++i) {
						if (!texNames[i][0]) {	// found a free slot ?
							Q_strncpyz(texNames[i], trace.surface->name, sizeof(texNames[i]));
							count++;
							break;
						}
						if (Q_streq(trace.surface->name, texNames[i]))	// already there ?
							break;
					}
					if (count > texCountMax) {
						done = true;
						break;	// the z-loop
					}
				}
			}
		}
		if (!texNames[0][0]) {
			Com_Printf("In map %s, asm %s: Nothing detected\n", md->mapTheme, asmName);
		} else {
			++badMapCount;
			for (int i = 0; i < texCountMax; ++i) {
				if (texNames[i][0]) {
					Com_Printf("In map %s, asm %s: No sound for: %s\n", md->mapTheme, asmName, texNames[i]);
				}
			}
		}
		OBJZERO(texNames);
		SV_ShutdownGameProgs();

		if (done || mapCount >= mapCountMax || badMapCount >= badMapCountMax)
			break;
	}
}
Beispiel #13
0
int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace, int type)
{
    int			bumpcount, numbumps;
    vec3_t		dir;
    float		d;
    int			numplanes;
    vec3_t		planes[MAX_CLIP_PLANES];
    vec3_t		primal_velocity, original_velocity, new_velocity;
    int			i, j;
    trace_t		trace;
    vec3_t		end;
    float		time_left;
    int			blocked;

    numbumps = 4;

    blocked = 0;
    VectorCopy (ent->v.velocity, original_velocity);
    VectorCopy (ent->v.velocity, primal_velocity);
    numplanes = 0;

    time_left = time;

    for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
    {
        for (i=0 ; i<3 ; i++)
            end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];

        trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent);

        if (trace.allsolid)
        {   // entity is trapped in another solid
            VectorClear (ent->v.velocity);
            return 3;
        }

        if (trace.fraction > 0)
        {   // actually covered some distance
            VectorCopy (trace.endpos, ent->v.origin);
            VectorCopy (ent->v.velocity, original_velocity);
            numplanes = 0;
        }

        if (trace.fraction == 1)
            break;		// moved the entire distance

        if (!trace.e.ent)
            Host_Error ("SV_FlyMove: !trace.e.ent");

        if (trace.plane.normal[2] > 0.7)
        {
            blocked |= 1;		// floor
            if (trace.e.ent->v.solid == SOLID_BSP)
            {
                ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
                ent->v.groundentity = EDICT_TO_PROG(trace.e.ent);
            }
        }
        if (!trace.plane.normal[2])
        {
            blocked |= 2;		// step
            if (steptrace)
                *steptrace = trace;	// save for player extrafriction
        }

//
// run the impact function
//
        SV_Impact (ent, trace.e.ent);
        if (!ent->inuse)
            break;		// removed by the impact function


        time_left -= time_left * trace.fraction;

        // cliped to another plane
        if (numplanes >= MAX_CLIP_PLANES)
        {   // this shouldn't really happen
            VectorClear (ent->v.velocity);
            return 3;
        }

        VectorCopy (trace.plane.normal, planes[numplanes]);
        numplanes++;

//
// modify original_velocity so it parallels all of the clip planes
//
        for (i=0 ; i<numplanes ; i++)
        {
            ClipVelocity (original_velocity, planes[i], new_velocity, 1);
            for (j=0 ; j<numplanes ; j++)
                if (j != i)
                {
                    if (DotProduct (new_velocity, planes[j]) < 0)
                        break;	// not ok
                }
            if (j == numplanes)
                break;
        }

        if (i != numplanes)
        {   // go along this plane
            VectorCopy (new_velocity, ent->v.velocity);
        }
        else
        {   // go along the crease
            if (numplanes != 2)
            {
//				Com_Printf ("clip velocity, numplanes == %i\n",numplanes);
                VectorClear (ent->v.velocity);
                return 7;
            }
            CrossProduct (planes[0], planes[1], dir);
            d = DotProduct (dir, ent->v.velocity);
            VectorScale (dir, d, ent->v.velocity);
        }

//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
        if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
        {
            VectorClear (ent->v.velocity);
            return blocked;
        }
    }

    return blocked;
}
Beispiel #14
0
/*
 * Tests whether the player entity ent is visible from the point origin.
 */
qboolean SV_IsPlayerVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, sharedEntity_t *ent, vec3_t diff) {
	int      i,contents_mask,goal_ent,viewer_clnum,ent_clnum,tries;
	trace_t   tr;
	vec3_t   start,end,dir,entangles,angles,temp,forward;
	sharedEntity_t *viewer_ent;
	client_t *viewer_cl;
//	client_t *ent_cl;
	playerState_t *viewer_ps, *ent_ps;
	float pitch;

	viewer_clnum = frame->ps.clientNum; // get the client number of the viewer
	ent_clnum = ent->s.clientNum; // get the client number of the other player

	if (viewer_clnum == ent_clnum) { // in case the viewer is the player entity
		return qtrue; // we don't need to hide us from ourselves
	}

	viewer_ps = &frame->ps;
	ent_ps = SV_GameClientNum(ent_clnum);

	if (viewer_ps->pm_type != PM_NORMAL) { // if the viewer is dead or spectating
		return qtrue; // let every entity be visible
	}

	if (ent_ps->pm_type != PM_NORMAL || (ent->s.weapon == WP_NONE)) { // if the player entity is dead or spectating
		return qtrue;
	}

	viewer_cl = svs.clients+viewer_clnum; // get the client of the viewer
//	ent_cl = svs.clients+ent_clnum; // get the client of the other player

//	if (viewer_clnum > ent_clnum) { // if viewer_clnum > ent_clnum, we have already tested whether ent_clnum is able to see viewer_clnum.
//		if (ent_cl->tracetimer[viewer_clnum] > sv.time) return qtrue; // and we could assume symmetry of SV_IsPlayerVisibleFromPoint
//	}

	if (viewer_cl->tracetimer[ent_clnum] > sv.time+MEMORY+10) { // if the sv.time has been reset
		viewer_cl->tracetimer[ent_clnum] = sv.time; // reset the tracetimer
	} else if (viewer_cl->tracetimer[ent_clnum] > (sv.time+MEMORY-10)) { // if we have recently seen this entity, we are lazy and assume it is still visible
		// Com_Printf(va("client: %i, seen: %i\n", ent_clnum, viewer_cl->tracetimer[ent_clnum]));
		return qtrue;
	}

	goal_ent = SV_NumForGentity(ent); // this might always be the same as ent_clnum
	viewer_ent = SV_GentityNum(viewer_clnum);
	contents_mask = CONTENTS_SOLID;// |CONTENTS_BODY will work for doors, but also for windows  |CONTENTS_PLAYERCLIP|CONTENTS_SOLID|CONTENTS_MOVER|CONTENTS_PLAYERCLIP

//	if (seen->v.movetype == MOVETYPE_PUSH ) { //don't cull doors and plats :(
//		return false;
//	}

//	if (sv_antiwallhack.value == 1)    //1 only check player models, 2 = check all ents
//	if (strcmp(pr_strings + seen->v.classname, "player"))
//	return qfalse;

	// get camera origin (according to \cg_drawdebug 1)
	start[0] = origin[0];
	start[1] = origin[1];
	start[2] = origin[2]+3.0f;
	VectorCopy(viewer_ps->viewangles, angles);
	AnglesNormalize180(angles);
	pitch = angles[PITCH];
	angles[PITCH] = 0;
	angles[ROLL] = 0;
	AngleVectors(angles, forward, NULL, NULL);
	VectorScale(forward, (pitch/3.5f), temp);
	VectorAdd( start, temp, start);

	// if there is sufficient distance between viewer and player entity, check if player entity is within viewer's field of vision
	VectorSubtract(ent->r.currentOrigin, start, dir);
//	VectorAdd(ent->r.currentOrigin,dir,diff);// fill diff
	VectorCopy(viewer_ent->s.pos.trBase,diff);// fill diff
	vectoangles(dir, entangles);
	dir[2]=0; // pretend, players are on the same level (the height should no be taken into account)
	if (VectorLength(dir) > 1024) {// if it is not within close range (x,y-wise, not z-wise)
		if (!InFieldOfVision(viewer_ps->viewangles, 60.f, entangles, ent_clnum)) {// If the player entity is not in the field of vision of the viewer
//			 Com_Printf( va("behind: %i  vorg: %f,%f,%f  vang: %f,%f,%f  eorg: %f,%f,%f  dir: %f,%f,%f  eang: %f,%f,%f  ent: %i\n", viewer_clnum,origin[0],origin[1],origin[2],viewer_ps->viewangles[0],viewer_ps->viewangles[1],viewer_ps->viewangles[2],ent->r.currentOrigin[0],ent->r.currentOrigin[1],ent->r.currentOrigin[2],dir[0],dir[1],dir[2],entangles[0],entangles[1],entangles[2],ent_clnum));
			return qtrue; // if the player entity is behind the viewer, abstain from any computations (and transmit the entity to hear sounds)
//		} else {
//			 Com_Printf( va("front: %i  vorg: %f,%f,%f  vang: %f,%f,%f  eorg: %f,%f,%f  dir: %f,%f,%f  eang: %f,%f,%f  ent: %i\n", viewer_clnum,origin[0],origin[1],origin[2],viewer_ps->viewangles[0],viewer_ps->viewangles[1],viewer_ps->viewangles[2],ent->r.currentOrigin[0],ent->r.currentOrigin[1],ent->r.currentOrigin[2],dir[0],dir[1],dir[2],entangles[0],entangles[1],entangles[2],ent_clnum));
		}
	}

	// aim straight at the head of the entity from our eyes
	end[0] = ent->r.currentOrigin[0];
	end[1] = ent->r.currentOrigin[1];
	end[2] = ent->r.currentOrigin[2]+ent->r.maxs[2];// "+3.0f" doesn't do it. "+ent->r.maxs[2]" is at the top of the BBox
	VectorCopy(ent_ps->viewangles, angles);
	AnglesNormalize180(angles);
	pitch = angles[PITCH];
	angles[PITCH] = 0;
	angles[ROLL] = 0;
	AngleVectors(angles, forward, NULL, NULL);
	VectorScale(forward, (pitch/3.5f), temp);
	VectorAdd( end, temp, end);



	memset (&tr, 0, sizeof(tr));
	tr.fraction = 1;

	// check the head
	SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse);
	// Com_Printf(va("client: %i, trace: %f\n", ent->s.clientNum, tr.fraction));
	if (tr.fraction == 1 || tr.entityNum==goal_ent) {// tr.fraction == 1 || if there is a line of sight to the entity
		viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units
		return qtrue;// and signal the entity is visible
	}
	// Com_Printf(va("origin(%f %f %f) min(%f %f %f) max(%f %f %f)\n", start[0], start[1], start[2], mins[0],mins[1],mins[2],maxs[0],maxs[1],maxs[2]));

	// check the last good offset
	VectorAdd(ent->r.currentOrigin,viewer_cl->lasttrace[ent_clnum],end);
	SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse);
	// Com_Printf(va("client: %i, trace: %f\n", ent->s.clientNum, tr.fraction));
	if (tr.fraction == 1 || tr.entityNum==goal_ent) {// tr.fraction == 1 || if there is a line of sight to the entity
		viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units
		return qtrue;// and signal the entity is visible
	}

	// random
	tries = (viewer_cl->tracetimer[ent_clnum]+(MEMORY*20) > sv.time)?8:2;// if we have seen an entity recently, we try hard to locate it again
	for (i=0; i<tries; i++) {// Even if the head is not visible, other body parts might be. Let's check a few randomly selected points
		end[0] = ent->r.currentOrigin[0] + offsetrandom(ent->r.mins[0], ent->r.maxs[0]);
		end[1] = ent->r.currentOrigin[1] + offsetrandom(ent->r.mins[1], ent->r.maxs[1]);
		end[2] = ent->r.currentOrigin[2] + offsetrandom(ent->r.mins[2], ent->r.maxs[2]+3.f);

		SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse);
		if (tr.fraction == 1 || tr.entityNum==goal_ent) {//  if there is a line of sight to the entity
			// Com_Printf(va("found ent in %i hits\n", i));
			viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units
			VectorSubtract(end, ent->r.currentOrigin, viewer_cl->lasttrace[ent_clnum]);// remember the offset
			return qtrue;// and signal the entity is visible
		}
	}

	viewer_cl->lasttrace[ent_clnum][0] = offsetrandom(ent->r.mins[0], ent->r.maxs[0]);
	viewer_cl->lasttrace[ent_clnum][1] = offsetrandom(ent->r.mins[1], ent->r.maxs[1]);
	viewer_cl->lasttrace[ent_clnum][2] = offsetrandom(ent->r.mins[2], ent->r.maxs[2]+3.f);

	return (viewer_cl->tracetimer[ent_clnum] > sv.time);// returns true if the entity was visible within the last 200 time units
}
Beispiel #15
0
/*
================
G_RunItem

================
*/
void G_RunItem( GameEntity *ent )
{
	vec3_t		origin;
	trace_t		tr;
	int			contents;
	int			mask;

	// if groundentity has been set to -1, it may have been pushed off an edge
	if ( ent->s.groundEntityNum == -1 ) 
	{
		if ( ent->s.pos.trType != TR_GRAVITY )
		{
			ent->s.pos.trType = TR_GRAVITY;
			ent->s.pos.trTime = theLevel.time_;
		}
	}

	if ( ent->s.pos.trType == TR_STATIONARY )
	{
		// check think function
		G_RunThink( ent );
		return;
	}

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

	// trace a line from the previous position to the current position
	if ( ent->clipmask_ ) 
		mask = ent->clipmask_;
	else 
		mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;

	SV_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, 
		ent->r.ownerNum, mask, false );

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

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

	SV_LinkEntity( ent );	// FIXME: avoid this for stationary?

	// check think function
	G_RunThink( ent );

	if ( tr.fraction == 1 ) 
		return;

	// if it is in a nodrop volume, remove it
	contents = SV_PointContents( ent->r.currentOrigin, -1 );
	if ( contents & CONTENTS_NODROP ) 
	{
		if (ent->item_ && ent->item_->giType == IT_TEAM) 
			Team_FreeEntity(ent);
		else 
			ent->freeUp();
		return;
	}

	G_BounceItem( ent, &tr );
}
Beispiel #16
0
/*
=======================================================================================================================================
BotImport_Trace
=======================================================================================================================================
*/
static void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {
	SV_Trace(bsptrace, start, mins, maxs, end, passent, contentmask, qfalse);
}
Beispiel #17
0
void SV_PostprocessFrame()
{
	edict_t *ent;
	int e, i;
	client_t *cl;

	guard(SV_PostprocessFrame);

	for (e = 0; e < ge->num_edicts; e++)
	{
		ent = EDICT_NUM(e);

		// ignore ents without visible models
		if (ent->svflags & SVF_NOCLIENT)
			continue;

		if (ent->s.event == EV_FOOTSTEP || ent->s.event == EV_FALLSHORT)
		{
			CVec3	point;
			point[0] = ent->s.origin[0];
			point[1] = ent->s.origin[1];
			point[2] = ent->s.origin[2] - 64;
			trace_t trace;
			SV_Trace(trace, ent->s.origin, point, ent->bounds, ent, MASK_PLAYERSOLID|MASK_MONSTERSOLID|MASK_WATER);
			if (trace.fraction < 1)
			{
				int footsteptype = trace.surface->material - 1;

				if (footsteptype < 0)//?? || footsteptype >= MATERIAL_COUNT)	// i.e. MATERIAL_SILENT (== 0) or incorrect
					ent->s.event = 0;	// EV_FOOTSTEP ?
/*				else if (footsteptype > MATERIAL_WATER)
				{	//!! DEBUG !! (and hack) - should not happen
					developer->integer = 2;
					Com_DPrintf(S_RED"Bad material sound: idx=%d", footsteptype);
					ent->s.event = 0;
				}
*/				else if (ent->s.event == EV_FOOTSTEP)
					ent->s.event = EV_FOOTSTEP0 + footsteptype;
				else
					ent->s.event = EV_FALLSHORT0 + footsteptype;
			}
		}
	}

	// work only in deathmatch game, not in single-player or coop game
	if (sv_deathmatch->integer) //!! should be another variable; campersounds - below!! && sv_campersounds->integer)
	{
		unsigned t = appMilliseconds();
		for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++)
		{
			if (cl->state != cs_spawned && cl->state != cs_connected)
			{
				cl->last_velocity2 = 0;
				continue;	// dead / not connected player
			}

			ent = cl->edict;
			pmove_state_t *pm = &ent->client->ps.pmove;

			int prev_vel = cl->last_velocity2;
			int curr_vel = pm->velocity[2];
			cl->last_velocity2 = curr_vel;

			if (cl->screaming && (curr_vel >= FALLING_SCREAM_VELOCITY1 || prev_vel >= FALLING_SCREAM_VELOCITY1
							 || pm->pm_type != PM_NORMAL))	// killed
			{	// stop scream
				SV_StartSoundNew(NULL, ent, CHAN_BODY, SV_SoundIndex("*falling1.wav"), 0.0f, ATTN_NORM, 0);	// volume=0
				cl->screaming = false;
			}

			if (ent->s.event) continue;		// have a sound event

/*			if (pm->pm_type == PM_SPECTATOR) //!! don't works - server doesn't send info about spectators (need another way)
			{
				sfxstate = 1;
				if (cl->sfxstate != sfxstate)
				{	// just changed to spectator
					cl->sfxstate = sfxstate;
					cl->nextsfxtime = t + 1000 + (rand()&0x7FF); // ~1-3 sec.
					continue;
				}
				if (cl->nextsfxtime > t) continue; // waiting for sfx time
				cl->nextsfxtime = t + 1000 + (rand()&0x7FF);
				ent->s.event = EV_SPECTATOR0 + (rand()&3);
				appPrintf("%i:SPECT-SFX\n",i);
			}
			else*/ if (pm->pm_type == PM_NORMAL)
			{
				CVec3	pm_origin;
				pm_origin[0] = pm->origin[0] / 8.0f;
				pm_origin[1] = pm->origin[1] / 8.0f;
				pm_origin[2] = pm->origin[2] / 8.0f;

				// check for falling sounds
				if (!cl->screaming)
				{
					if (curr_vel < FALLING_SCREAM_VELOCITY1 && prev_vel < FALLING_SCREAM_VELOCITY1)
					{
						CVec3 end = pm_origin;
						end[2] = pm_origin[2] - FALLING_SCREAM_HEIGHT_WATER;

						trace_t	trace;
						static const CBox bounds = {{-20, -20, -10}, {20, 20, 10}};
						SV_Trace(trace, pm_origin, end, bounds, NULL, CONTENTS_WATER);
						if (trace.fraction == 1.0 && !trace.startsolid)	// no water and start not in water
						{
							end[2] = pm_origin[2] - FALLING_SCREAM_HEIGHT_SOLID;
							SV_Trace(trace, pm_origin, end, bounds, NULL, CONTENTS_SOLID|CONTENTS_LAVA);
							if (trace.fraction == 1.0 || (!trace.ent && trace.plane.normal[2] < 0.5) ||
								trace.contents & CONTENTS_LAVA || trace.surface->flags & SURF_SKY)
								cl->screaming = true;
						}
					}
					if (cl->screaming)
					{
						SV_StartSoundNew(NULL, ent, CHAN_BODY, SV_SoundIndex("*falling1.wav"), 1, ATTN_NORM, 0);
						continue;
					}
				}
				else if (curr_vel >= FALLING_SCREAM_VELOCITY1 || prev_vel >= FALLING_SCREAM_VELOCITY1)
				{	// stop scream
					if (cl->screaming)
						SV_StartSoundNew(NULL, ent, CHAN_BODY, SV_SoundIndex("*falling1.wav"), 0.0, ATTN_NORM, 0);
					cl->screaming = false;
				}

				// check for idle (camper) sounds
				const CBspLeaf *leaf  = CM_FindLeaf(pm_origin);
				int clust = leaf->cluster;
				int sfxstate = 2;
				if (!clust)
					continue;	// possibly map without visinfo - no cluster partition (cannot detect campers with this way)

				if (clust != cl->lastcluster || cl->sfxstate != sfxstate || (leaf->contents & MASK_WATER))
				{	// changed cluster or state - not camping
					cl->sfxstate    = sfxstate;
					cl->lastcluster = clust;
					cl->nextsfxtime = t + CAMPER_TIMEOUT + rand()%CAMPER_TIMEOUT_DELTA;
					continue;
				}
				if (cl->nextsfxtime > t) continue; // waiting for sfx time
				cl->nextsfxtime = t + CAMPER_REPEAT + rand()%CAMPER_REPEAT_DELTA;
				int sfx0, sfxn;
				if (pm->pm_flags & PMF_DUCKED)
				{
					sfx0 = EV_CAMPER0;
					sfxn = 2;
				}
				else
				{
					sfx0 = EV_CAMPER0+2;
					sfxn = 7;
				}
				ent->s.event = sfx0 + rand() % sfxn;
			}
			else
			{
				cl->sfxstate = 0;
				continue;
			}
		}
	}

	unguard;
}
Beispiel #18
0
/*
====================
SV_GameSystemCalls

The module is making a system call
====================
*/
intptr_t SV_GameSystemCalls(intptr_t * args) {
	switch (args[0]) {
		case G_PRINT:
			Com_Printf("%s", (char *)VMA(1));
			return 0;
		case G_ERROR:
			Com_Error(ERR_DROP, "%s", (char *)VMA(1));
			return 0;
		case G_MILLISECONDS:
			return Sys_Milliseconds();
		case G_CVAR_REGISTER:
			Cvar_Register((vmCvar_t*)VMA(1), (char*)VMA(2), (char*)VMA(3), args[4]);
			return 0;
		case G_CVAR_UPDATE:
			Cvar_Update((vmCvar_t*)VMA(1));
			return 0;
		case G_CVAR_SET:
			Cvar_Set((const char *)VMA(1), (const char *)VMA(2));
			return 0;
		case G_CVAR_VARIABLE_INTEGER_VALUE:
			return Cvar_VariableIntegerValue((const char *)VMA(1));
		case G_CVAR_VARIABLE_STRING_BUFFER:
			Cvar_VariableStringBuffer((char *)VMA(1), (char*)VMA(2), args[3]);
			return 0;
		case G_CVAR_LATCHEDVARIABLESTRINGBUFFER:
			Cvar_LatchedVariableStringBuffer((char *)VMA(1), (char*)VMA(2), args[3]);
			return 0;
		case G_ARGC:
			return Cmd_Argc();
		case G_ARGV:
			Cmd_ArgvBuffer(args[1], (char*)VMA(2), args[3]);
			return 0;
		case G_SEND_CONSOLE_COMMAND:
			Cbuf_ExecuteText(args[1], (char *)VMA(2));
			return 0;
		case G_FS_FOPEN_FILE:
			return FS_FOpenFileByMode((char *)VMA(1), (fileHandle_t*)VMA(2), (fsMode_t)args[3]);
		case G_FS_READ:
			FS_Read2(VMA(1), args[2], args[3]);
			return 0;
		case G_FS_WRITE:
			return FS_Write(VMA(1), args[2], args[3]);
		case G_FS_RENAME:
			FS_Rename((char *)VMA(1), (char *)VMA(2));
			return 0;
		case G_FS_FCLOSE_FILE:
			FS_FCloseFile(args[1]);
			return 0;
		case G_FS_GETFILELIST:
			return FS_GetFileList((char *)VMA(1), (char *)VMA(2), (char*)VMA(3), args[4]);
		case G_LOCATE_GAME_DATA:
			SV_LocateGameData((sharedEntity_t*)VMA(1), args[2], args[3], (playerState_t*)VMA(4), args[5]);
			return 0;
		case G_DROP_CLIENT:
			SV_GameDropClient(args[1], (char*)VMA(2), args[3]);
			return 0;
		case G_SEND_SERVER_COMMAND:
			SV_GameSendServerCommand(args[1], (char*)VMA(2));
			return 0;
		case G_LINKENTITY:
			SV_LinkEntity((sharedEntity_t*)VMA(1));
			return 0;
		case G_UNLINKENTITY:
			SV_UnlinkEntity((sharedEntity_t*)VMA(1));
			return 0;
		case G_ENTITIES_IN_BOX:
			return SV_AreaEntities((float*)VMA(1), (float*)VMA(2), (int*)VMA(3), args[4]);
		case G_ENTITY_CONTACT:
			return SV_EntityContact((float*)VMA(1), (float*)VMA(2), (sharedEntity_t*)VMA(3), TT_AABB);
		case G_ENTITY_CONTACTCAPSULE:
			return SV_EntityContact((float*)VMA(1), (float*)VMA(2), (sharedEntity_t*)VMA(3), TT_CAPSULE);
		case G_TRACE:
			SV_Trace((trace_t*)VMA(1), (float*)VMA(2), (float*)VMA(3), (float*)VMA(4), (float*)VMA(5), args[6], args[7], TT_AABB);
			return 0;
		case G_TRACECAPSULE:
			SV_Trace((trace_t*)VMA(1), (float*)VMA(2), (float*)VMA(3), (float*)VMA(4), (float*)VMA(5), args[6], args[7], TT_CAPSULE);
			return 0;
		case G_POINT_CONTENTS:
			return SV_PointContents((float*)VMA(1), args[2]);
		case G_SET_BRUSH_MODEL:
			SV_SetBrushModel((sharedEntity_t*)VMA(1), (char*)VMA(2));
			return 0;
		case G_IN_PVS:
			return SV_inPVS((float*)VMA(1), (float*)VMA(2));
		case G_IN_PVS_IGNORE_PORTALS:
			return SV_inPVSIgnorePortals((float*)VMA(1), (float*)VMA(2));
		case G_SET_CONFIGSTRING:
			SV_SetConfigstring(args[1], (char*)VMA(2));
			return 0;
		case G_GET_CONFIGSTRING:
			SV_GetConfigstring(args[1], (char*)VMA(2), args[3]);
			return 0;
		case G_SET_CONFIGSTRING_RESTRICTIONS:
			SV_SetConfigstringRestrictions( args[1], (clientList_t*)VMA(2) );
			return 0;
		case G_SET_USERINFO:
			SV_SetUserinfo(args[1], (char*)VMA(2));
			return 0;
		case G_GET_USERINFO:
			SV_GetUserinfo(args[1], (char*)VMA(2), args[3]);
			return 0;
		case G_GET_SERVERINFO:
			SV_GetServerinfo((char*)VMA(1), args[2]);
			return 0;
		case G_ADJUST_AREA_PORTAL_STATE:
			SV_AdjustAreaPortalState((sharedEntity_t*)VMA(1),(bool)args[2]);
			return 0;
		case G_AREAS_CONNECTED:
			return CM_AreasConnected(args[1], args[2]);
		case G_UPDATE_SHARED_CONFIG:
			SV_UpdateSharedConfig( args[1], (char*)VMA(2) );
			return 0;
		case G_BOT_ALLOCATE_CLIENT:
			return SV_BotAllocateClient(args[1]);
		case G_BOT_FREE_CLIENT:
			SV_BotFreeClient(args[1]);
			return 0;
		case G_GET_USERCMD:
			SV_GetUsercmd(args[1], (usercmd_t*)VMA(2));
			return 0;
		case G_GET_ENTITY_TOKEN: {
			const char     *s;

			s = COM_Parse(&sv.entityParsePoint);
			Q_strncpyz((char*)VMA(1), s, args[2]);
			if(!sv.entityParsePoint && !s[0]) {
				return false;
			} else {
				return true;
			}
		}
		case G_DEBUG_POLYGON_CREATE:
			return BotImport_DebugPolygonCreate(args[1], args[2], (vec3_t*)VMA(3));
		case G_DEBUG_POLYGON_DELETE:
			BotImport_DebugPolygonDelete(args[1]);
			return 0;
		case G_REAL_TIME:
			return Com_RealTime((qtime_t*)VMA(1));
		case G_SNAPVECTOR:
			Q_SnapVector((float*)VMA(1));
			return 0;
		case G_SEND_GAMESTAT:
			SV_MasterGameStat( (char*)VMA(1) );
			return 0;
		case G_ADDCOMMAND:
			Cmd_AddCommand( (char*)VMA(1), NULL, (char*)VMA(3) );
			return 0;
		case G_REMOVECOMMAND:
			Cmd_RemoveCommand( (char*)VMA(1) );
			return 0;
		case G_GETTAG:
			return SV_GetTag(args[1], args[2], (char*)VMA(3), (orientation_t*)VMA(4));
		case G_REGISTERTAG:
			return SV_LoadTag((char*)VMA(1));
		case G_REGISTERSOUND:
			return S_RegisterSound((char*)VMA(1), (bool)args[2]);
		case G_GET_SOUND_LENGTH:
			return S_GetSoundLength(args[1]);
		case G_PARSE_ADD_GLOBAL_DEFINE:
			return Parse_AddGlobalDefine( (char*)VMA(1) );
		case G_PARSE_LOAD_SOURCE:
			return Parse_LoadSourceHandle( (char*)VMA(1) );
		case G_PARSE_FREE_SOURCE:
			return Parse_FreeSourceHandle( args[1] );
		case G_PARSE_READ_TOKEN:
			return Parse_ReadTokenHandle( args[1], (pc_token_t*)VMA(2) );
		case G_PARSE_SOURCE_FILE_AND_LINE:
			return Parse_SourceFileAndLine( args[1], (char*)VMA(2), (int*)VMA(3) );
		case BOTLIB_SETUP:
			return SV_BotLibSetup();
		case BOTLIB_SHUTDOWN:
			return SV_BotLibShutdown();
		case BOTLIB_LIBVAR_SET:
			return botlib_export->BotLibVarSet((char*)VMA(1), (char*)VMA(2));
		case BOTLIB_LIBVAR_GET:
			return botlib_export->BotLibVarGet((char*)VMA(1), (char*)VMA(2), args[3]);
		case BOTLIB_PC_ADD_GLOBAL_DEFINE:
			return Parse_AddGlobalDefine( (char*)VMA(1) );
		case BOTLIB_PC_LOAD_SOURCE:
			return Parse_LoadSourceHandle((char*)VMA(1));
		case BOTLIB_PC_FREE_SOURCE:
			return Parse_FreeSourceHandle(args[1]);
		case BOTLIB_PC_READ_TOKEN:
			return Parse_ReadTokenHandle(args[1], (pc_token_t*)VMA(2));
		case BOTLIB_PC_SOURCE_FILE_AND_LINE:
			return Parse_SourceFileAndLine(args[1], (char*)VMA(2), (int*)VMA(3));
		case BOTLIB_PC_UNREAD_TOKEN:
			Parse_UnreadLastTokenHandle(args[1]);
			return 0;
		case BOTLIB_START_FRAME:
			return botlib_export->BotLibStartFrame(VMF(1));
		case BOTLIB_LOAD_MAP:
			return botlib_export->BotLibLoadMap((char*)VMA(1));
		case BOTLIB_UPDATENTITY:
			return botlib_export->BotLibUpdateEntity(args[1], (bot_entitystate_t*)VMA(2));
		case BOTLIB_TEST:
			return botlib_export->Test( args[1], (char*)VMA(2), (float*)VMA(3), (float*)VMA(4) );
		case BOTLIB_GET_SNAPSHOT_ENTITY:
			return SV_BotGetSnapshotEntity(args[1], args[2]);
		case BOTLIB_GET_CONSOLE_MESSAGE:
			return SV_BotGetConsoleMessage(args[1], (char*)VMA(2), args[3]);
		case BOTLIB_USER_COMMAND:
			SV_ClientThink(&svs.clients[args[1]], (usercmd_t*)VMA(2));
			return 0;
		case BOTLIB_AAS_ENTITY_INFO:
			botlib_export->aas.AAS_EntityInfo(args[1], (aas_entityinfo_s*)VMA(2));
			return 0;
		case BOTLIB_AAS_INITIALIZED:
			return botlib_export->aas.AAS_Initialized();
		case BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX:
			botlib_export->aas.AAS_PresenceTypeBoundingBox( args[1], (float*)VMA(2), (float*)VMA(3) );
			return 0;
		case BOTLIB_AAS_TIME:
			return FloatAsInt(botlib_export->aas.AAS_Time());
		case BOTLIB_AAS_SETCURRENTWORLD:
			botlib_export->aas.AAS_SetCurrentWorld(args[1]);
			return 0;
		case BOTLIB_AAS_POINT_AREA_NUM:
			return botlib_export->aas.AAS_PointAreaNum( (float*)VMA(1) );
		case BOTLIB_AAS_TRACE_AREAS:
			return botlib_export->aas.AAS_TraceAreas( (float*)VMA(1), (float*)VMA(2), (int*)VMA(3), (vec3_t*)VMA(4), args[5] );
		case BOTLIB_AAS_BBOX_AREAS:
			return botlib_export->aas.AAS_BBoxAreas( (float*)VMA(1), (float*)VMA(2), (int*)VMA(3), args[4] );
		case BOTLIB_AAS_AREA_CENTER:
			botlib_export->aas.AAS_AreaCenter(args[1], (float*)VMA(2));
			return 0;
		case BOTLIB_AAS_AREA_WAYPOINT:
			return botlib_export->aas.AAS_AreaWaypoint(args[1], (float*)VMA(2));
		case BOTLIB_AAS_POINT_CONTENTS:
			return botlib_export->aas.AAS_PointContents((float*)VMA(1));
		case BOTLIB_AAS_NEXT_BSP_ENTITY:
			return botlib_export->aas.AAS_NextBSPEntity(args[1]);
		case BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY:
			return botlib_export->aas.AAS_ValueForBSPEpairKey(args[1], (char*)VMA(2), (char*)VMA(3), args[4]);
		case BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY:
			return botlib_export->aas.AAS_VectorForBSPEpairKey(args[1], (char*)VMA(2), (float*)VMA(3));
		case BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY:
			return botlib_export->aas.AAS_FloatForBSPEpairKey(args[1], (char*)VMA(2), (float*)VMA(3));
		case BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY:
			return botlib_export->aas.AAS_IntForBSPEpairKey(args[1], (char*)VMA(2), (int*)VMA(3));
		case BOTLIB_AAS_AREA_REACHABILITY:
			return botlib_export->aas.AAS_AreaReachability(args[1]);
		case BOTLIB_AAS_AREA_LADDER:
			return botlib_export->aas.AAS_AreaLadder(args[1]);
		case BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA:
			return botlib_export->aas.AAS_AreaTravelTimeToGoalArea(args[1], (float*)VMA(2), args[3], args[4]);
		case BOTLIB_AAS_SWIMMING:
			return botlib_export->aas.AAS_Swimming((float*)VMA(1));
		case BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT:
			return botlib_export->aas.AAS_PredictClientMovement((aas_clientmove_s*)VMA(1), args[2], (float*)VMA(3), args[4], args[5], (float*)VMA(6), (float*)VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13]);
		case BOTLIB_AAS_RT_SHOWROUTE:
			botlib_export->aas.AAS_RT_ShowRoute((float*)VMA(1), args[2], args[3]);
			return 0;
		case BOTLIB_AAS_NEARESTHIDEAREA:
			return botlib_export->aas.AAS_NearestHideArea(args[1], (float*)VMA(2), args[3], args[4], (float*)VMA(5), args[6], args[7], VMF(8), (float*)VMA(9));
		case BOTLIB_AAS_LISTAREASINRANGE:
			return botlib_export->aas.AAS_ListAreasInRange((float*)VMA(1), args[2], VMF(3), args[4], (vec3_t*)VMA(5), args[6]);
		case BOTLIB_AAS_AVOIDDANGERAREA:
			return botlib_export->aas.AAS_AvoidDangerArea((float*)VMA(1), args[2], (float*)VMA(3), args[4], VMF(5), args[6]);
		case BOTLIB_AAS_RETREAT:
			return botlib_export->aas.AAS_Retreat((int*)VMA(1), args[2], (float*)VMA(3), args[4], (float*)VMA(5), args[6], VMF(7), VMF(8), args[9]);
		case BOTLIB_AAS_ALTROUTEGOALS:
			return botlib_export->aas.AAS_AlternativeRouteGoals((float*)VMA(1), (float*)VMA(2), args[3], (aas_altroutegoal_t*)VMA(4), args[5], args[6]);
		case BOTLIB_AAS_SETAASBLOCKINGENTITY:
			botlib_export->aas.AAS_SetAASBlockingEntity((float*)VMA(1), (float*)VMA(2), args[3]);
			return 0;
		case BOTLIB_AAS_RECORDTEAMDEATHAREA:
			botlib_export->aas.AAS_RecordTeamDeathArea((float*)VMA(1), args[2], args[3], args[4], args[5]);
			return 0;
		case BOTLIB_EA_SAY:
			botlib_export->ea.EA_Say(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_EA_SAY_TEAM:
			botlib_export->ea.EA_SayTeam(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_EA_USE_ITEM:
			botlib_export->ea.EA_UseItem(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_EA_DROP_ITEM:
			botlib_export->ea.EA_DropItem(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_EA_USE_INV:
			botlib_export->ea.EA_UseInv(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_EA_DROP_INV:
			botlib_export->ea.EA_DropInv(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_EA_GESTURE:
			botlib_export->ea.EA_Gesture(args[1]);
			return 0;
		case BOTLIB_EA_COMMAND:
			botlib_export->ea.EA_Command(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_EA_SELECT_WEAPON:
			botlib_export->ea.EA_SelectWeapon(args[1], args[2]);
			return 0;
		case BOTLIB_EA_TALK:
			botlib_export->ea.EA_Talk(args[1]);
			return 0;
		case BOTLIB_EA_ATTACK:
			botlib_export->ea.EA_Attack(args[1]);
			return 0;
		case BOTLIB_EA_RELOAD:
			botlib_export->ea.EA_Reload(args[1]);
			return 0;
		case BOTLIB_EA_USE:
			botlib_export->ea.EA_Use(args[1]);
			return 0;
		case BOTLIB_EA_RESPAWN:
			botlib_export->ea.EA_Respawn(args[1]);
			return 0;
		case BOTLIB_EA_JUMP:
			botlib_export->ea.EA_Jump(args[1]);
			return 0;
		case BOTLIB_EA_DELAYED_JUMP:
			botlib_export->ea.EA_DelayedJump(args[1]);
			return 0;
		case BOTLIB_EA_CROUCH:
			botlib_export->ea.EA_Crouch(args[1]);
			return 0;
		case BOTLIB_EA_WALK:
			botlib_export->ea.EA_Walk(args[1]);
			return 0;
		case BOTLIB_EA_MOVE_UP:
			botlib_export->ea.EA_MoveUp(args[1]);
			return 0;
		case BOTLIB_EA_MOVE_DOWN:
			botlib_export->ea.EA_MoveDown(args[1]);
			return 0;
		case BOTLIB_EA_MOVE_FORWARD:
			botlib_export->ea.EA_MoveForward(args[1]);
			return 0;
		case BOTLIB_EA_MOVE_BACK:
			botlib_export->ea.EA_MoveBack(args[1]);
			return 0;
		case BOTLIB_EA_MOVE_LEFT:
			botlib_export->ea.EA_MoveLeft(args[1]);
			return 0;
		case BOTLIB_EA_MOVE_RIGHT:
			botlib_export->ea.EA_MoveRight(args[1]);
			return 0;
		case BOTLIB_EA_MOVE:
			botlib_export->ea.EA_Move(args[1], (float*)VMA(2), VMF(3));
			return 0;
		case BOTLIB_EA_VIEW:
			botlib_export->ea.EA_View(args[1], (float*)VMA(2));
			return 0;
		case BOTLIB_EA_PRONE:
			botlib_export->ea.EA_Prone(args[1]);
			return 0;
		case BOTLIB_EA_END_REGULAR:
			botlib_export->ea.EA_EndRegular(args[1], VMF(2));
			return 0;
		case BOTLIB_EA_GET_INPUT:
			botlib_export->ea.EA_GetInput(args[1], VMF(2), (bot_input_t*)VMA(3));
			return 0;
		case BOTLIB_EA_RESET_INPUT:
			botlib_export->ea.EA_ResetInput(args[1], (bot_input_t*)VMA(2));
			return 0;
		case BOTLIB_AI_LOAD_CHARACTER:
			return botlib_export->ai.BotLoadCharacter((char*)VMA(1), args[2]);
		case BOTLIB_AI_FREE_CHARACTER:
			botlib_export->ai.BotFreeCharacter(args[1]);
			return 0;
		case BOTLIB_AI_CHARACTERISTIC_FLOAT:
			return FloatAsInt(botlib_export->ai.Characteristic_Float(args[1], args[2]));
		case BOTLIB_AI_CHARACTERISTIC_BFLOAT:
			return FloatAsInt(botlib_export->ai.Characteristic_BFloat(args[1], args[2], VMF(3), VMF(4)));
		case BOTLIB_AI_CHARACTERISTIC_INTEGER:
			return botlib_export->ai.Characteristic_Integer(args[1], args[2]);
		case BOTLIB_AI_CHARACTERISTIC_BINTEGER:
			return botlib_export->ai.Characteristic_BInteger(args[1], args[2], args[3], args[4]);
		case BOTLIB_AI_CHARACTERISTIC_STRING:
			botlib_export->ai.Characteristic_String(args[1], args[2], (char*)VMA(3), args[4]);
			return 0;
		case BOTLIB_AI_ALLOC_CHAT_STATE:
			return botlib_export->ai.BotAllocChatState();
		case BOTLIB_AI_FREE_CHAT_STATE:
			botlib_export->ai.BotFreeChatState(args[1]);
			return 0;
		case BOTLIB_AI_QUEUE_CONSOLE_MESSAGE:
			botlib_export->ai.BotQueueConsoleMessage(args[1], args[2], (char*)VMA(3));
			return 0;
		case BOTLIB_AI_REMOVE_CONSOLE_MESSAGE:
			botlib_export->ai.BotRemoveConsoleMessage(args[1], args[2]);
			return 0;
		case BOTLIB_AI_NEXT_CONSOLE_MESSAGE:
			return botlib_export->ai.BotNextConsoleMessage(args[1], (bot_consolemessage_s*)VMA(2));
		case BOTLIB_AI_NUM_CONSOLE_MESSAGE:
			return botlib_export->ai.BotNumConsoleMessages(args[1]);
		case BOTLIB_AI_INITIAL_CHAT:
			botlib_export->ai.BotInitialChat(args[1], (char*)VMA(2), args[3], (char*)VMA(4), (char*)VMA(5), (char*)VMA(6), (char*)VMA(7), (char*)VMA(8), (char*)VMA(9), (char*)VMA(10), (char*)VMA(11));
			return 0;
		case BOTLIB_AI_NUM_INITIAL_CHATS:
			return botlib_export->ai.BotNumInitialChats(args[1], (char*)VMA(2));
		case BOTLIB_AI_REPLY_CHAT:
			return botlib_export->ai.BotReplyChat(args[1], (char*)VMA(2), args[3], args[4], (char*)VMA(5), (char*)VMA(6), (char*)VMA(7), (char*)VMA(8), (char*)VMA(9), (char*)VMA(10), (char*)VMA(11), (char*)VMA(12));
		case BOTLIB_AI_CHAT_LENGTH:
			return botlib_export->ai.BotChatLength(args[1]);
		case BOTLIB_AI_ENTER_CHAT:
			botlib_export->ai.BotEnterChat(args[1], args[2], args[3]);
			return 0;
		case BOTLIB_AI_GET_CHAT_MESSAGE:
			botlib_export->ai.BotGetChatMessage(args[1], (char*)VMA(2), args[3]);
			return 0;
		case BOTLIB_AI_STRING_CONTAINS:
			return botlib_export->ai.StringContains((char*)VMA(1), (char*)VMA(2), args[3]);
		case BOTLIB_AI_FIND_MATCH:
			return botlib_export->ai.BotFindMatch((char*)VMA(1), (bot_match_s*)VMA(2), args[3]);
		case BOTLIB_AI_MATCH_VARIABLE:
			botlib_export->ai.BotMatchVariable((bot_match_s*)VMA(1), args[2], (char*)VMA(3), args[4]);
			return 0;
		case BOTLIB_AI_UNIFY_WHITE_SPACES:
			botlib_export->ai.UnifyWhiteSpaces((char*)VMA(1));
			return 0;
		case BOTLIB_AI_REPLACE_SYNONYMS:
			botlib_export->ai.BotReplaceSynonyms((char*)VMA(1), args[2]);
			return 0;
		case BOTLIB_AI_LOAD_CHAT_FILE:
			return botlib_export->ai.BotLoadChatFile(args[1], (char*)VMA(2), (char*)VMA(3));
		case BOTLIB_AI_SET_CHAT_GENDER:
			botlib_export->ai.BotSetChatGender(args[1], args[2]);
			return 0;
		case BOTLIB_AI_SET_CHAT_NAME:
			botlib_export->ai.BotSetChatName(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_AI_RESET_GOAL_STATE:
			botlib_export->ai.BotResetGoalState(args[1]);
			return 0;
		case BOTLIB_AI_RESET_AVOID_GOALS:
			botlib_export->ai.BotResetAvoidGoals(args[1]);
			return 0;
		case BOTLIB_AI_REMOVE_FROM_AVOID_GOALS:
			botlib_export->ai.BotRemoveFromAvoidGoals(args[1], args[2]);
			return 0;
		case BOTLIB_AI_PUSH_GOAL:
			botlib_export->ai.BotPushGoal(args[1], (bot_goal_s*)VMA(2));
			return 0;
		case BOTLIB_AI_POP_GOAL:
			botlib_export->ai.BotPopGoal(args[1]);
			return 0;
		case BOTLIB_AI_EMPTY_GOAL_STACK:
			botlib_export->ai.BotEmptyGoalStack(args[1]);
			return 0;
		case BOTLIB_AI_DUMP_AVOID_GOALS:
			botlib_export->ai.BotDumpAvoidGoals(args[1]);
			return 0;
		case BOTLIB_AI_DUMP_GOAL_STACK:
			botlib_export->ai.BotDumpGoalStack(args[1]);
			return 0;
		case BOTLIB_AI_GOAL_NAME:
			botlib_export->ai.BotGoalName(args[1], (char*)VMA(2), args[3]);
			return 0;
		case BOTLIB_AI_GET_TOP_GOAL:
			return botlib_export->ai.BotGetTopGoal(args[1], (bot_goal_s*)VMA(2));
		case BOTLIB_AI_GET_SECOND_GOAL:
			return botlib_export->ai.BotGetSecondGoal(args[1], (bot_goal_s*)VMA(2));
		case BOTLIB_AI_CHOOSE_LTG_ITEM:
			return botlib_export->ai.BotChooseLTGItem(args[1], (float*)VMA(2), (int*)VMA(3), args[4]);
		case BOTLIB_AI_CHOOSE_NBG_ITEM:
			return botlib_export->ai.BotChooseNBGItem(args[1], (float*)VMA(2), (int*)VMA(3), args[4], (bot_goal_s*)VMA(5), VMF(6));
		case BOTLIB_AI_TOUCHING_GOAL:
			return botlib_export->ai.BotTouchingGoal((float*)VMA(1), (bot_goal_s*)VMA(2));
		case BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE:
			return botlib_export->ai.BotItemGoalInVisButNotVisible(args[1], (float*)VMA(2), (float*)VMA(3), (bot_goal_s*)VMA(4));
		case BOTLIB_AI_GET_LEVEL_ITEM_GOAL:
			return botlib_export->ai.BotGetLevelItemGoal(args[1], (char*)VMA(2), (bot_goal_s*)VMA(3));
		case BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL:
			return botlib_export->ai.BotGetNextCampSpotGoal(args[1], (bot_goal_s*)VMA(2));
		case BOTLIB_AI_GET_MAP_LOCATION_GOAL:
			return botlib_export->ai.BotGetMapLocationGoal((char*)VMA(1), (bot_goal_s*)VMA(2));
		case BOTLIB_AI_AVOID_GOAL_TIME:
			return FloatAsInt(botlib_export->ai.BotAvoidGoalTime(args[1], args[2]));
		case BOTLIB_AI_INIT_LEVEL_ITEMS:
			botlib_export->ai.BotInitLevelItems();
			return 0;
		case BOTLIB_AI_UPDATE_ENTITY_ITEMS:
			botlib_export->ai.BotUpdateEntityItems();
			return 0;
		case BOTLIB_AI_LOAD_ITEM_WEIGHTS:
			return botlib_export->ai.BotLoadItemWeights(args[1], (char*)VMA(2));
		case BOTLIB_AI_FREE_ITEM_WEIGHTS:
			botlib_export->ai.BotFreeItemWeights(args[1]);
			return 0;
		case BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC:
			botlib_export->ai.BotInterbreedGoalFuzzyLogic(args[1], args[2], args[3]);
			return 0;
		case BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC:
			botlib_export->ai.BotSaveGoalFuzzyLogic(args[1], (char*)VMA(2));
			return 0;
		case BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC:
			botlib_export->ai.BotMutateGoalFuzzyLogic(args[1], VMF(2));
			return 0;
		case BOTLIB_AI_ALLOC_GOAL_STATE:
			return botlib_export->ai.BotAllocGoalState(args[1]);
		case BOTLIB_AI_FREE_GOAL_STATE:
			botlib_export->ai.BotFreeGoalState(args[1]);
			return 0;
		case BOTLIB_AI_RESET_MOVE_STATE:
			botlib_export->ai.BotResetMoveState(args[1]);
			return 0;
		case BOTLIB_AI_MOVE_TO_GOAL:
			botlib_export->ai.BotMoveToGoal((bot_moveresult_s*)VMA(1), args[2], (bot_goal_s*)VMA(3), args[4]);
			return 0;
		case BOTLIB_AI_MOVE_IN_DIRECTION:
			return botlib_export->ai.BotMoveInDirection(args[1], (float*)VMA(2), VMF(3), args[4]);
		case BOTLIB_AI_RESET_AVOID_REACH:
			botlib_export->ai.BotResetAvoidReach(args[1]);
			return 0;
		case BOTLIB_AI_RESET_LAST_AVOID_REACH:
			botlib_export->ai.BotResetLastAvoidReach(args[1]);
			return 0;
		case BOTLIB_AI_REACHABILITY_AREA:
			return botlib_export->ai.BotReachabilityArea((float*)VMA(1), args[2]);
		case BOTLIB_AI_MOVEMENT_VIEW_TARGET:
			return botlib_export->ai.BotMovementViewTarget(args[1], (bot_goal_s*)VMA(2), args[3], VMF(4), (float*)VMA(5));
		case BOTLIB_AI_PREDICT_VISIBLE_POSITION:
			return botlib_export->ai.BotPredictVisiblePosition((float*)VMA(1), args[2], (bot_goal_s*)VMA(3), args[4], (vec_t*)VMA(5));
		case BOTLIB_AI_ALLOC_MOVE_STATE:
			return botlib_export->ai.BotAllocMoveState();
		case BOTLIB_AI_FREE_MOVE_STATE:
			botlib_export->ai.BotFreeMoveState(args[1]);
			return 0;
		case BOTLIB_AI_INIT_MOVE_STATE:
			botlib_export->ai.BotInitMoveState(args[1], (bot_initmove_s*)VMA(2));
			return 0;
		case BOTLIB_AI_INIT_AVOID_REACH:
			botlib_export->ai.BotInitAvoidReach(args[1]);
			return 0;
		case BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON:
			return botlib_export->ai.BotChooseBestFightWeapon(args[1], (int*)VMA(2));
		case BOTLIB_AI_GET_WEAPON_INFO:
			botlib_export->ai.BotGetWeaponInfo(args[1], args[2], (weaponinfo_s*)VMA(3));
			return 0;
		case BOTLIB_AI_LOAD_WEAPON_WEIGHTS:
			return botlib_export->ai.BotLoadWeaponWeights(args[1], (char*)VMA(2));
		case BOTLIB_AI_ALLOC_WEAPON_STATE:
			return botlib_export->ai.BotAllocWeaponState();
		case BOTLIB_AI_FREE_WEAPON_STATE:
			botlib_export->ai.BotFreeWeaponState(args[1]);
			return 0;
		case BOTLIB_AI_RESET_WEAPON_STATE:
			botlib_export->ai.BotResetWeaponState(args[1]);
			return 0;
		case BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION:
			return botlib_export->ai.GeneticParentsAndChildSelection(args[1], (float*)VMA(2), (int*)VMA(3), (int*)VMA(4), (int*)VMA(5));
		case G_ADD_PHYSICS_ENTITY:
#ifdef USE_PHYSICS
			CMod_PhysicsAddEntity((sharedEntity_t*)VMA(1));
#endif
			return 0;
		case G_ADD_PHYSICS_STATIC:
#ifdef USE_PHYSICS
			CMod_PhysicsAddStatic((sharedEntity_t*)VMA(1));
#endif
			return 0;
		case TRAP_MEMSET:
			memset(VMA(1), args[2], args[3]);
			return 0;
		case TRAP_MEMCPY:
			memcpy(VMA(1), VMA(2), args[3]);
			return 0;
		case TRAP_STRNCPY:
			return (intptr_t)strncpy( (char*)VMA( 1 ), (char*)VMA( 2 ), args[3] );
		case TRAP_SIN:
			return FloatAsInt(sin(VMF(1)));
		case TRAP_COS:
			return FloatAsInt(cos(VMF(1)));
		case TRAP_ATAN2:
			return FloatAsInt(atan2(VMF(1), VMF(2)));
		case TRAP_SQRT:
			return FloatAsInt(sqrt(VMF(1)));
		case TRAP_MATRIXMULTIPLY:
			AxisMultiply((vec3_t*)VMA(1), (vec3_t*)VMA(2), (vec3_t*)VMA(3));
			return 0;
		case TRAP_ANGLEVECTORS:
			AngleVectors((vec_t*)VMA(1), (vec_t*)VMA(2), (vec_t*)VMA(3), (vec_t*)VMA(4));
			return 0;
		case TRAP_PERPENDICULARVECTOR:
			PerpendicularVector((vec_t*)VMA(1), (vec_t*)VMA(2));
			return 0;
		case TRAP_FLOOR:
			return FloatAsInt(floor(VMF(1)));
		case TRAP_CEIL:
			return FloatAsInt(ceil(VMF(1)));
		case G_SENDMESSAGE:
			SV_SendBinaryMessage(args[1], (char*)VMA(2), args[3]);
			return 0;
		case G_MESSAGESTATUS:
			return SV_BinaryMessageStatus(args[1]);
#if defined(ET_MYSQL)
        case G_SQL_RUNQUERY:
                return OW_RunQuery( (char*)VMA(1) );
        case G_SQL_FINISHQUERY:
                OW_FinishQuery( args[1] );
                return 0;
        case G_SQL_NEXTROW:
                return OW_NextRow( args[1] );
        case G_SQL_ROWCOUNT:
                return OW_RowCount( args[1] );
        case G_SQL_GETFIELDBYID:
                OW_GetFieldByID( args[1], args[2], (char*)VMA(3), args[4]  );
                return 0;
        case G_SQL_GETFIELDBYNAME:
                OW_GetFieldByName( args[1], (char*)VMA(2), (char*)VMA(3), args[4] );
                return 0;
        case G_SQL_GETFIELDBYID_INT:
                return OW_GetFieldByID_int( args[1], args[2] );
        case G_SQL_GETFIELDBYNAME_INT:
                return OW_GetFieldByName_int( args[1], (char*)VMA(2) );
        case G_SQL_FIELDCOUNT:
                return OW_FieldCount( args[1] );
        case G_SQL_CLEANSTRING:
                OW_CleanString( (char*)VMA(1), (char*)VMA(2), args[3] );
                return 0;
#endif
		case G_RSA_GENMSG:
			return SV_RSAGenMsg( (char*)VMA(1), (char*)VMA(2), (char*)VMA(3) );
		default:
			Com_Error( ERR_DROP, "Bad game system trap: %ld", (long int) args[0] );
	}
	return -1;
}
Beispiel #19
0
static int predict_slide_move(sharedEntity_t *ent, float frametime, trajectory_t *tr, vec3_t result)
{
	int    count, numplanes = 0, i, j, k;
	float  d, time_left = frametime, into;
	vec3_t planes[MAX_CLIP_PLANES],
	       velocity, origin, clipVelocity, endVelocity, endClipVelocity, dir, end;
	trace_t trace;

	VectorCopy(tr->trBase, origin);
	origin[2] += Z_ADJUST;  // move it off the floor

	VectorCopy(tr->trDelta, velocity);
	VectorCopy(tr->trDelta, endVelocity);

	for (count = 0; count < NUMBUMPS; count++)
	{
		// calculate position we are trying to move to
		VectorMA(origin, time_left, velocity, end);

		// see if we can make it there
		SV_Trace(&trace, origin, ent->r.mins, ent->r.maxs, end, ent->s.number, CONTENTS_SOLID, qfalse);

		if (trace.allsolid)
		{
			// entity is completely trapped in another solid
			VectorCopy(origin, result);
			return 0;
		}

		if (trace.fraction > 0.99) // moved the entire distance
		{
			VectorCopy(trace.endpos, result);
			return 1;
		}

		if (trace.fraction > 0) // covered some distance
		{
			VectorCopy(trace.endpos, origin);
		}

		time_left -= time_left * trace.fraction;

		if (numplanes >= MAX_CLIP_PLANES)
		{
			// this shouldn't really happen
			VectorCopy(origin, result);
			return 0;
		}

		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		for (i = 0; i < numplanes; i++)
		{
			if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
			{
				VectorAdd(trace.plane.normal, velocity, velocity);
				break;
			}
		}

		if (i < numplanes)
		{
			continue;
		}

		VectorCopy(trace.plane.normal, planes[numplanes]);
		numplanes++;

		// modify velocity so it parallels all of the clip planes
		// find a plane that it enters
		for (i = 0; i < numplanes; i++)
		{
			into = DotProduct(velocity, planes[i]);
			if (into >= 0.1) // move doesn't interact with the plane
			{
				continue;
			}

			// slide along the plane
			predict_clip_velocity(velocity, planes[i], clipVelocity);

			// slide along the plane
			predict_clip_velocity(endVelocity, planes[i], endClipVelocity);

			// see if there is a second plane that the new move enters
			for (j = 0; j < numplanes; j++)
			{
				if (j == i)
				{
					continue;
				}

				if (DotProduct(clipVelocity, planes[j]) >= 0.1) // move doesn't interact with the plane
				{
					continue;
				}

				// try clipping the move to the plane
				predict_clip_velocity(clipVelocity, planes[j], clipVelocity);
				predict_clip_velocity(endClipVelocity, planes[j], endClipVelocity);

				// see if it goes back into the first clip plane
				if (DotProduct(clipVelocity, planes[i]) >= 0)
				{
					continue;
				}

				// slide the original velocity along the crease
				vec3_cross(planes[i], planes[j], dir);
				vec3_norm(dir);
				d = DotProduct(dir, velocity);
				VectorScale(dir, d, clipVelocity);

				vec3_cross(planes[i], planes[j], dir);
				vec3_norm(dir);
				d = DotProduct(dir, endVelocity);
				VectorScale(dir, d, endClipVelocity);

				// see if there is a third plane the new move enters
				for (k = 0; k < numplanes; k++)
				{
					if (k == i || k == j)
					{
						continue;
					}

					if (DotProduct(clipVelocity, planes[k]) >= 0.1) // move doesn't interact with the plane
					{
						continue;
					}

					// stop dead at a tripple plane interaction
					VectorCopy(origin, result);
					return 1;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy(clipVelocity, velocity);
			VectorCopy(endClipVelocity, endVelocity);
			break;
		}
	}

	VectorCopy(origin, result);

	if (count == 0)
	{
		return 1;
	}

	return 0;
}
/************************************************************************************************
 * CRMBSPInstance::Spawn
 *	spawns a bsp into the world using the previously aquired origin
 *
 * inputs:
 *  none
 *
 * return:
 *	none
 *
 ************************************************************************************************/
bool CRMBSPInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer)
{
#ifndef PRE_RELEASE_DEMO
//	TEntity*	ent;
	float		yaw;
	char		temp[10000];
	char		*savePtr;
	vec3_t		origin;
	vec3_t		notmirrored;
	float	water_level = terrain->GetLandScape()->GetWaterHeight();

	const vec3_t&	  terxelSize = terrain->GetLandScape()->GetTerxelSize ( );
	const vec3pair_t& bounds     = terrain->GetLandScape()->GetBounds();

	// If this entity somehow lost its collision flag then boot it
	if ( !GetArea().IsCollisionEnabled ( ) )
	{
		return false;
	}

	// copy out the unmirrored version
	VectorCopy(GetOrigin(), notmirrored);

	// we want to mirror it before determining the Z value just in case the landscape isn't perfectly mirrored
	if (mMirror)
	{
		GetOrigin()[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - GetOrigin()[0];
		GetOrigin()[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - GetOrigin()[1];
	}

	// Align the instance to the center of a terxel
	GetOrigin ( )[0] = bounds[0][0] + (int)((GetOrigin ( )[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0];
	GetOrigin ( )[1] = bounds[0][1] + (int)((GetOrigin ( )[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1];

	// Make sure the bsp is resting on the ground, not below or above it
	// NOTE: This check is basically saying "is this instance not a bridge", because when instances are created they are all
	// placed above the world's Z boundary, EXCEPT FOR BRIDGES. So this call to GetWorldHeight will move all other instances down to
	// ground level except bridges 
	if ( GetOrigin()[2] > terrain->GetBounds()[1][2] )
	{
		if( GetFlattenRadius() )
		{
			terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), false );
			GetOrigin()[2] += 5;
		}
		else if (IsServer)
		{	// if this instance does not flatten the ground around it, do a trace to more accurately determine its Z value
			trace_t		tr;
			vec3_t		end;
			vec3_t		start;

			VectorCopy(GetOrigin(), end);
			VectorCopy(GetOrigin(), start);
			// start the trace below the top height of the landscape
			start[2] = TheRandomMissionManager->GetLandScape()->GetBounds()[1][2] - 1;
			// end the trace at the bottom of the world
			end[2] = MIN_WORLD_COORD;
	
			memset ( &tr, 0, sizeof ( tr ) );
			SV_Trace( &tr, start, vec3_origin, vec3_origin, end, ENTITYNUM_NONE, CONTENTS_TERRAIN|CONTENTS_SOLID, G2_NOCOLLIDE, 0); //qfalse, 0, 10 );

			if( !(tr.contents & CONTENTS_TERRAIN) || (tr.fraction == 1.0) )
			{
				if ( 0 )
				assert(0); // this should never happen

				// restore the unmirrored origin
				VectorCopy( notmirrored, GetOrigin() );
				// don't spawn
				return false;
			}
			// assign the Z-value to wherever it hit the terrain	
			GetOrigin()[2] = tr.endpos[2];
			// lower it a little, otherwise the bottom of the instance might be exposed if on some weird sloped terrain
			GetOrigin()[2] -= 16; // FIXME: would it be better to use a number related to the instance itself like 1/5 it's height or something...
		}

	}
	else
	{
		terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), true );
	}
	
	// save away the origin
	VectorCopy(GetOrigin(), origin);
	// make sure not to spawn if in water
	if (!HasObjective() && GetOrigin()[2] < water_level)
		return false;
	// restore the origin
	VectorCopy(origin, GetOrigin());

	if (mMirror)
	{	// change blue things to red for symmetric maps
		if (strlen(mFilter) > 0)
		{
			char * blue = strstr(mFilter,"blue");
			if (blue)
			{
				blue[0] = (char) 0;
				strcat(mFilter, "red");
				SetSide(SIDE_RED);
			}
		}
		if (strlen(mTeamFilter) > 0)
		{
			char * blue = strstr(mTeamFilter,"blue");
			if (blue)
			{
				strcpy(mTeamFilter, "red");
				SetSide(SIDE_RED);
			}
		}
		yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle) + 180;
	}
	else
	{
		yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle);
	}

/*
	if( TheRandomMissionManager->GetMission()->GetSymmetric() )
	{
		vec3_t	diagonal;
		vec3_t	lineToPoint;
		vec3_t	mins;
		vec3_t	maxs;
		vec3_t	point;
		vec3_t	vProj;
		vec3_t	vec;
		float	distance;

		VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[1], maxs );
		VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[0], mins );
		VectorCopy( GetOrigin(), point );
		mins[2] = maxs[2] = point[2] = 0;
		VectorSubtract( point, mins, lineToPoint );
		VectorSubtract( maxs, mins, diagonal);


		VectorNormalize(diagonal);	
		VectorMA( mins, DotProduct(lineToPoint, diagonal), diagonal, vProj);
		VectorSubtract(point, vProj, vec );
		distance = VectorLength(vec);

		// if an instance is too close to the imaginary diagonal that cuts the world in half, don't spawn it
		// otherwise you can get overlapping instances
		if( distance < GetSpacingRadius() )
		{
#ifdef _DEBUG
			mAutomapSymbol = AUTOMAP_END;
#endif
			if( !HasObjective() )
			{
				return false;
			}
		}
	}
*/

	// Spawn in the bsp model
	sprintf(temp, 
		"{\n"
		"\"classname\"   \"misc_bsp\"\n"
		"\"bspmodel\"    \"%s\"\n"
		"\"origin\"      \"%f %f %f\"\n"
		"\"angles\"      \"0 %f 0\"\n"
		"\"filter\"      \"%s\"\n"
		"\"teamfilter\"  \"%s\"\n"
		"\"spacing\"	 \"%d\"\n"
		"\"flatten\"	 \"%d\"\n"
		"}\n",
		mBsp,
		GetOrigin()[0], GetOrigin()[1], GetOrigin()[2],
		AngleNormalize360(yaw),
		mFilter,
		mTeamFilter,
		(int)GetSpacingRadius(),
		(int)GetFlattenRadius()
		);

	if (IsServer)
	{	// only allow for true spawning on the server
		savePtr = sv.entityParsePoint;
		sv.entityParsePoint = temp;
//		VM_Call( cgvm, GAME_SPAWN_RMG_ENTITY );
	//	char *s;
		int bufferSize = 1024;
		char buffer[1024];

	//	s = COM_Parse( (const char **)&sv.entityParsePoint );
		Q_strncpyz( buffer, sv.entityParsePoint, bufferSize );
		if ( sv.entityParsePoint && sv.entityParsePoint[0] ) 
		{
			ge->GameSpawnRMGEntity(sv.entityParsePoint);
		}
		sv.entityParsePoint = savePtr;
	}

	
#ifndef DEDICATED
	DrawAutomapSymbol();
#endif
	Com_DPrintf( "RMG:  Building '%s' spawned at (%f %f %f)\n", mBsp, GetOrigin()[0], GetOrigin()[1], GetOrigin()[2] );
	// now restore the instances un-mirrored origin
	// NOTE: all this origin flipping, setting the side etc... should be done when mMirror is set
	// because right after this function is called, mMirror is set to 0 but all the instance data is STILL MIRRORED -- not good
	VectorCopy(notmirrored, GetOrigin());

#endif  // PRE_RELEASE_DEMO
	
	return true;
}
Beispiel #21
0
// hooked game trace function
void SV_TraceHook(trace0_t &trace, const CVec3 &start, const CVec3 *mins, const CVec3 *maxs, const CVec3 &end, edict_t *passedict, int contentmask)
{
	guard(SV_TraceHook);

	if (bspfile.suspendedItems && passedict)
	{
		// hack for game's droptofloor(): items, listed in bspfile.suspendedItems (for Q3A maps),
		// should 'fly' in the air; droptofloor always calls trace() with following params:
		//	trace(ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID)
		//	ent.solid == SOLID_TRIGGER (but: when item picked up, it still "thinking" with
		//	  droptofloor(), but with SOLID_NOT; see SetRespawn())
		//	dest = ent->s.origin + (0,0,-128)
		// Also, check for SV_PushEntity():
		//	trace(start, ent->mins, ent->maxs, end, ent, mask)
		//	start == ent->s.origin
		//	end   == start+delta
		//	mask  == ent->clipmask or MASK_SOLID (clipmask used for clients/monsters only?)
		// game source reference: g_phys.c
		if (start == passedict->s.origin		&&							// compare vectors, not pointers
			mins == &passedict->bounds.mins && maxs == &passedict->bounds.maxs &&
			contentmask == MASK_SOLID			&&
			(passedict->solid == SOLID_TRIGGER || passedict->solid == SOLID_NOT) &&	// trigger entity
			end[0] == start[0] && end[1] == start[1] && end[2] < start[2])	// falling down
		{
			// check list ...
			for (const originInfo_t *info = bspfile.suspendedItems; info; info = info->next)
#define CMP(n)	(fabs(start[n] - info->origin[n]) < 0.5f)
				if (CMP(0) && CMP(1) && CMP(2))
				{
					trace.startsolid = false;
					trace.endpos     = start;
					trace.fraction   = 1.0f;								// disable SV_Impact()
					return;
				}
#undef CMP
		}
	}

	trace_skipAlpha = true;		//!! hack for kingpin CONTENTS_ALPHA
	if (mins || maxs) trace_skipAlpha = false;

	CBox bounds = nullBox;
	if (mins) bounds.mins = *mins;		// required for game; may be NULL
	if (maxs) bounds.maxs = *maxs;

	// extended trace
	trace_t trace1;
	SV_Trace(trace1, start, end, bounds, passedict, contentmask);
	// copy base fields to trace0_t
	trace = trace1;
	trace_skipAlpha = false;	//!!
	if (!sv_extProtocol->integer) return;

	if (mins || maxs)
	{
	shot_skip:
		shotLevel = 0;
		return;
	}

	static edict_t *ent;		//??

	// for details, look game/g_weapon.c :: fire_lead()
	if (contentmask == MASK_SHOT && ((unsigned)passedict) + 4 == (unsigned)&start)
	{
		if (ent == passedict && end == shotStart)
			goto shot_skip;			// shotgun shot
		shotLevel = 1;
		shotStart = end;
		ent       = passedict;
	}
	else if (shotLevel == 1)
	{
		if (passedict != ent || start != shotStart ||
			(contentmask != (MASK_SHOT|MASK_WATER) && contentmask != MASK_SHOT))
			goto shot_skip;
		shotEnd = end;

		shotLevel = 2;
	}
	else if (shotLevel > 1)
	{
		if (passedict != ent) goto shot_skip;
	}

	unguard;
}