Ejemplo n.º 1
0
void SV_LinkEdict(edict_t *ent)
{
	guard(SV_LinkEdict);

	int		i, j, k;

	//!! HOOK - move outside ?
	if (bspfile.type != map_q2)
	{
		if (ent->s.modelindex >= 0 && ent->s.modelindex < MAX_MODELS)
		{
			// link model hook
			const char *modelName = sv.configstrings[CS_MODELS + ent->s.modelindex];
			if (!strcmp(modelName, "models/objects/dmspot/tris.md2"))
			{
				// teleporter (source+target) was found
//				appPrintf(S_CYAN"teleport: %g %g %g\n", VECTOR_ARG(ent->s.origin));
				return;			// simply do not link model; trigger entity will be added anyway
			}
		}
	}

	if (ent->area.prev)
		SV_UnlinkEdict(ent);	// unlink from old position (i.e. relink edict)

	if (ent == ge->edicts)
		return;					// don't add the world

	if (!ent->inuse)
		return;

	entityHull_t &ex = ents[NUM_FOR_EDICT(ent)];
	memset(&ex, 0, sizeof(entityHull_t));
	ex.owner = ent;
	ex.axis.FromEuler(ent->s.angles);

	// set the size
	VectorSubtract(ent->bounds.maxs, ent->bounds.mins, ent->size);

	// encode the size into the entity_state for client prediction
	if (ent->solid == SOLID_BBOX)
	{
		// assume that x/y are equal and symetric
		i = appRound(ent->bounds.maxs[0] / 8);
		// z is not symetric
		j = appRound(-ent->bounds.mins[2] / 8);
		// and z maxs can be negative...
		k = appRound((ent->bounds.maxs[2] + 32) / 8);
		// original Q2 have bounded i/j/k/ with lower margin==1 (for client prediction only); this will
		// produce incorrect collision test when bbox mins/maxs is (0,0,0)
		i = bound(i, 0, 31);		// mins/maxs[0,1] range is -248..0/0..248
		j = bound(j, 0, 31);		// mins[2] range is [-248..0]
		k = bound(k, 0, 63);		// maxs[2] range is [-32..472]

		// if SVF_DEADMONSTER, s.solid should be 0
		ent->s.solid = (ent->svflags & SVF_DEADMONSTER) ? 0 : (k<<10) | (j<<5) | i;

		i *= 8;
		j *= 8;
		k *= 8;
		ex.bounds.mins.Set(-i, -i, -j);
		ex.bounds.maxs.Set(i, i, k - 32);
		ex.bounds.GetCenter(ex.center);
		ex.center.Add(ent->s.origin);
		ex.model  = NULL;
		ex.radius = VectorDistance(ex.bounds.maxs, ex.bounds.mins) / 2;
	}
	else if (ent->solid == SOLID_BSP)
	{
		ex.model = sv.models[ent->s.modelindex];
		if (!ex.model) Com_DropError("MOVETYPE_PUSH with a non bsp model");
		CVec3	v;
		ex.model->bounds.GetCenter(v);
		UnTransformPoint(ent->s.origin, ex.axis, v, ex.center);
		ex.radius = ex.model->radius;

		ent->s.solid = 31;		// a SOLID_BBOX will never create this value (mins=(-248,-248,0) maxs=(248,248,-32))
	}
	else if (ent->solid == SOLID_TRIGGER)
	{
		ent->s.solid = 0;
		// check for model link
		ex.model = sv.models[ent->s.modelindex];
		if (!ex.model)
		{
			// model not attached by game, check entstring
			//?? can optimize: add 'bool spawningEnts', set to 'true' before SpawnEntities()
			//?? and 'false' after; skip code below when 'false'
			for (triggerModelLink_t *link = bspfile.modelLinks; link; link = link->next)
#define CMP(n)	(fabs(ent->s.origin[n] - link->origin[n]) < 0.5f)
				if (CMP(0) && CMP(1) && CMP(2))
				{
					CBspModel *model = CM_InlineModel(link->modelIdx);
					VectorSubtract(model->bounds.maxs, ent->s.origin, ent->bounds.maxs);
					VectorSubtract(model->bounds.mins, ent->s.origin, ent->bounds.mins);
					break;
				}
#undef CMP
		}
	}
	else
		ent->s.solid = 0;

	// set the abs box
	if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]))
	{
		// expand for rotation
		for (i = 0; i < 3 ; i++)
		{
			ent->absBounds.mins[i] = ex.center[i] - ex.radius;
			ent->absBounds.maxs[i] = ex.center[i] + ex.radius;
		}
	}
	else
	{	// normal
		VectorAdd(ent->s.origin, ent->bounds.mins, ent->absBounds.mins);
		VectorAdd(ent->s.origin, ent->bounds.maxs, ent->absBounds.maxs);
	}

	// because movement is clipped an epsilon away from an actual edge,
	// we must fully check even when bounding boxes don't quite touch
	for (i = 0; i < 3; i++)
	{
		ent->absBounds.mins[i] -= 1;
		ent->absBounds.maxs[i] += 1;
	}

	// link to PVS leafs
	ent->num_clusters = 0;
	ent->zonenum      = 0;
	ent->zonenum2     = 0;

	// get all leafs, including solids
	CBspLeaf *leafs[MAX_TOTAL_ENT_LEAFS];
	int topnode;
	int num_leafs = CM_BoxLeafs(ent->absBounds, ARRAY_ARG(leafs), &topnode);

	// set zones
	int clusters[MAX_TOTAL_ENT_LEAFS];
	for (i = 0; i < num_leafs; i++)
	{
		clusters[i] = leafs[i]->cluster;
		int zone = leafs[i]->zone;
		if (zone)
		{	// doors may legally straggle two zones,
			// but nothing should evern need more than that
			if (ent->zonenum && ent->zonenum != zone)
			{
				if (ent->zonenum2 && ent->zonenum2 != zone && sv.state == ss_loading)
					Com_DPrintf("Object touching 3 zones at %g %g %g\n", VECTOR_ARG(ent->absBounds.mins));
				ent->zonenum2 = zone;
			}
			else
				ent->zonenum = zone;
		}
	}

	if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
	{	// assume we missed some leafs, and mark by headnode
		ent->num_clusters = -1;
		ent->headnode     = topnode;
	}
	else
	{
		ent->num_clusters = 0;
		for (i = 0; i < num_leafs; i++)
		{
			if (clusters[i] == -1)
				continue;		// not a visible leaf
			for (j = 0; j < i; j++)
				if (clusters[j] == clusters[i])
					break;
			if (j == i)
			{
				if (ent->num_clusters == MAX_ENT_CLUSTERS)
				{	// assume we missed some leafs, and mark by headnode
					ent->num_clusters = -1;
					ent->headnode     = topnode;
					break;
				}

				ent->clusternums[ent->num_clusters++] = clusters[i];
			}
		}
	}

	// if first time, make sure old_origin is valid
	if (!ent->linkcount)
		ent->s.old_origin = ent->s.origin;
	ent->linkcount++;

	if (ent->solid == SOLID_NOT)
		return;

	// find the first node that the ent's box crosses
	areanode_t *node = areaNodes;
	while (node->axis != -1)
	{
		if (ent->absBounds.mins[node->axis] > node->dist)
			node = node->children[0];
		else if (ent->absBounds.maxs[node->axis] < node->dist)
			node = node->children[1];
		else
			break;		// crosses the node
	}

	// link it in
	areanode_t *node2 = node;
	if (ent->solid == SOLID_TRIGGER)
	{
		InsertLinkBefore(ent->area, node->trigEdicts);
		for ( ; node2; node2 = node2->parent)
			node2->numTrigEdicts++;
	}
	else
	{
		InsertLinkBefore(ent->area, node->solidEdicts);
		for ( ; node2; node2 = node2->parent)
			node2->numSolidEdicts++;
	}
	ex.area = node;

	unguard;
}
Ejemplo n.º 2
0
/*
===============
SV_LinkEdict

General purpose routine shared between game DLL and MVD code.
Links entity to PVS leafs.
===============
*/
void SV_LinkEdict(cm_t *cm, edict_t *ent)
{
    mleaf_t     *leafs[MAX_TOTAL_ENT_LEAFS];
    int         clusters[MAX_TOTAL_ENT_LEAFS];
    int         num_leafs;
    int         i, j;
    int         area;
    mnode_t     *topnode;

    // set the size
    VectorSubtract(ent->maxs, ent->mins, ent->size);

    // set the abs box
    if (ent->solid == SOLID_BSP &&
        (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2])) {
        // expand for rotation
        float   max, v;
        int     i;

        max = 0;
        for (i = 0; i < 3; i++) {
            v = Q_fabs(ent->mins[i]);
            if (v > max)
                max = v;
            v = Q_fabs(ent->maxs[i]);
            if (v > max)
                max = v;
        }
        for (i = 0; i < 3; i++) {
            ent->absmin[i] = ent->s.origin[i] - max;
            ent->absmax[i] = ent->s.origin[i] + max;
        }
    } else {
        // normal
        VectorAdd(ent->s.origin, ent->mins, ent->absmin);
        VectorAdd(ent->s.origin, ent->maxs, ent->absmax);
    }

    // because movement is clipped an epsilon away from an actual edge,
    // we must fully check even when bounding boxes don't quite touch
    ent->absmin[0] -= 1;
    ent->absmin[1] -= 1;
    ent->absmin[2] -= 1;
    ent->absmax[0] += 1;
    ent->absmax[1] += 1;
    ent->absmax[2] += 1;

// link to PVS leafs
    ent->num_clusters = 0;
    ent->areanum = 0;
    ent->areanum2 = 0;

    //get all leafs, including solids
    num_leafs = CM_BoxLeafs(cm, ent->absmin, ent->absmax,
                            leafs, MAX_TOTAL_ENT_LEAFS, &topnode);

    // set areas
    for (i = 0; i < num_leafs; i++) {
        clusters[i] = CM_LeafCluster(leafs[i]);
        area = CM_LeafArea(leafs[i]);
        if (area) {
            // doors may legally straggle two areas,
            // but nothing should evern need more than that
            if (ent->areanum && ent->areanum != area) {
                if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading) {
                    Com_DPrintf("Object touching 3 areas at %f %f %f\n",
                                ent->absmin[0], ent->absmin[1], ent->absmin[2]);
                }
                ent->areanum2 = area;
            } else
                ent->areanum = area;
        }
    }

    if (num_leafs >= MAX_TOTAL_ENT_LEAFS) {
        // assume we missed some leafs, and mark by headnode
        ent->num_clusters = -1;
        ent->headnode = CM_NumNode(cm, topnode);
    } else {
        ent->num_clusters = 0;
        for (i = 0; i < num_leafs; i++) {
            if (clusters[i] == -1)
                continue;        // not a visible leaf
            for (j = 0; j < i; j++)
                if (clusters[j] == clusters[i])
                    break;
            if (j == i) {
                if (ent->num_clusters == MAX_ENT_CLUSTERS) {
                    // assume we missed some leafs, and mark by headnode
                    ent->num_clusters = -1;
                    ent->headnode = CM_NumNode(cm, topnode);
                    break;
                }

                ent->clusternums[ent->num_clusters++] = clusters[i];
            }
        }
    }
}