Ejemplo n.º 1
0
/**
 * @note This is only working for one z-level. But our models should be
 * split for each level anyway.
 * @param ent The edict to fill the forbidden list for
 */
static void G_BuildForbiddenListForEntity (edict_t *ent)
{
	pos3_t mins, maxs, origin;
	vec3_t center, shiftedMins, shiftedMaxs;
	int xDelta, yDelta, size, i, j;

	VectorAdd(ent->absmin, ent->origin, shiftedMins);
	VectorAdd(ent->absmax, ent->origin, shiftedMaxs);

	VectorCenterFromMinsMaxs(shiftedMins, shiftedMaxs, center);
	VecToPos(shiftedMins, mins);
	VecToPos(shiftedMaxs, maxs);
	VecToPos(center, origin);

	xDelta = std::max(1, maxs[0] - mins[0]);
	yDelta = std::max(1, maxs[1] - mins[1]);

	size = xDelta * yDelta;
	ent->forbiddenListPos = (pos3_t *)G_TagMalloc(size * sizeof(pos3_t), TAG_LEVEL);
	ent->forbiddenListSize = size;

	for (i = 0; i < xDelta; i++) {
		for (j = 0; j < yDelta; j++) {
			const pos_t x = mins[0] + i;
			const pos_t y = mins[1] + j;
			const pos_t z = origin[2];
			VectorSet(ent->forbiddenListPos[i], x, y, z);
		}
	}
}
Ejemplo n.º 2
0
/**
 * @brief Fills in s->stmins[] and s->stmaxs[]
 */
static void R_SetSurfaceExtents (mBspSurface_t *surf, const model_t* mod)
{
	vec3_t mins, maxs;
	vec2_t stmins, stmaxs;
	int i, j;
	const mBspTexInfo_t *tex;

	VectorSet(mins, 999999, 999999, 999999);
	VectorSet(maxs, -999999, -999999, -999999);

	Vector2Set(stmins, 999999, 999999);
	Vector2Set(stmaxs, -999999, -999999);

	tex = surf->texinfo;

	for (i = 0; i < surf->numedges; i++) {
		const int e = mod->bsp.surfedges[surf->firstedge + i];
		const mBspVertex_t *v;
		vec3_t position;
		if (e >= 0)
			v = &mod->bsp.vertexes[mod->bsp.edges[e].v[0]];
		else
			v = &mod->bsp.vertexes[mod->bsp.edges[-e].v[1]];

		VectorCopy(v->position, position);

		for (j = 0; j < 3; j++) {  /* calculate mins, maxs */
			position[j] += (float)shift[j];
			if (position[j] > maxs[j])
				maxs[j] = position[j];
			if (position[j] < mins[j])
				mins[j] = position[j];
		}

		{  /* calculate stmins, stmaxs */
			const float valS = DotProduct(v->position, tex->uv) + tex->u_offset;
			const float valT = DotProduct(v->position, tex->vv) + tex->v_offset;
			stmins[0] = min(valS, stmins[0]);
			stmaxs[0] = max(valS, stmaxs[0]);
			stmins[1] = min(valT, stmins[1]);
			stmaxs[1] = max(valT, stmaxs[1]);
		}
	}

	VectorCopy(mins, surf->mins);
	VectorCopy(maxs, surf->maxs);
	VectorCenterFromMinsMaxs(surf->mins, surf->maxs, surf->center);

	for (i = 0; i < 2; i++) {
		const int bmins = floor(stmins[i] / surf->lightmap_scale);
		const int bmaxs = ceil(stmaxs[i] / surf->lightmap_scale);

		surf->stmins[i] = bmins * surf->lightmap_scale;
		surf->stmaxs[i] = bmaxs * surf->lightmap_scale;

		surf->stcenter[i] = (surf->stmaxs[i] + surf->stmins[i]) / 2.0;
		surf->stextents[i] = (bmaxs - bmins) * surf->lightmap_scale;
	}
}
Ejemplo n.º 3
0
static bool Destroy_Breakable (edict_t *self)
{
	vec3_t origin;
	const char *model = self->model;

	VectorCenterFromMinsMaxs(self->absmin, self->absmax, origin);

	/* the HP value is used to decide whether this was a triggered call or a
	 * call during a fight - a triggered call will be handled differently in
	 * terms of timing and the related particle effects in the client code */
	if (self->HP == 0)
		G_EventModelExplodeTriggered(self);
	else
		G_EventModelExplode(self);

	if (self->particle)
		G_SpawnParticle(origin, self->spawnflags, self->particle);

	switch (self->material) {
	case MAT_GLASS:
		G_EventSpawnSound(PM_ALL, false, self, origin, "misc/breakglass+");
		break;
	case MAT_METAL:
		G_EventSpawnSound(PM_ALL, false, self, origin, "misc/breakmetal+");
		break;
	case MAT_ELECTRICAL:
		G_EventSpawnSound(PM_ALL, false, self, origin, "misc/breakelectric+");
		break;
	case MAT_WOOD:
		G_EventSpawnSound(PM_ALL, false, self, origin, "misc/breakwood+");
		break;
	case MAT_MAX:
		break;
	}

	G_TouchEdicts(self, 10.0f);

	/* destroy the door trigger */
	if (self->child)
		G_FreeEdict(self->child);

	/* now we can destroy the edict completely */
	G_FreeEdict(self);

	AABB oldAABB(vec3_origin, vec3_origin);
	gi.GetInlineModelAABB(model, oldAABB);
	GridBox rerouteOldBox(oldAABB);
	G_RecalcRouting(model, rerouteOldBox);

	return true;
}
Ejemplo n.º 4
0
/**
 * @brief Calculates the bounding box for the given bsp model
 * @param[in] model The model to calculate the bbox for
 * @param[out] mins The maxs of the bbox
 * @param[out] maxs The mins of the bbox
 */
static void CM_CalculateBoundingBox (const cBspModel_t* model, vec3_t mins, vec3_t maxs)
{
	/* Quickly calculate the bounds of this model to see if they can overlap. */
	VectorAdd(model->origin, model->mins, mins);
	VectorAdd(model->origin, model->maxs, maxs);
	if (VectorNotEmpty(model->angles)) {
		vec3_t acenter, aoffset;
		const float offset = std::max(std::max(fabs(mins[0] - maxs[0]), fabs(mins[1] - maxs[1])), fabs(mins[2] - maxs[2])) / 2.0;
		VectorCenterFromMinsMaxs(mins, maxs, acenter);
		VectorSet(aoffset, offset, offset, offset);
		VectorAdd(acenter, aoffset, maxs);
		VectorSubtract(acenter, aoffset, mins);
	}
}
Ejemplo n.º 5
0
/**
 * @brief Compute scale and center for a model info data structure
 * @param[in] boxSize The size the model should fit into
 * @param[in,out] mi The model info that contains the model that should be scaled
 * @param[out] scale The scale vector
 * @param[out] center The center of the model (center of the model's bounding box)
 * @note The scale and center vectors are parameters here because the @c modelInfo_t
 * struct only holds pointers to the vectors.
 * @todo Take the rotation info from @c modelInfo_t into account
 */
void R_ModelAutoScale (const vec2_t boxSize, modelInfo_t *mi, vec3_t scale, vec3_t center)
{
	const float width = mi->model->maxs[0] - mi->model->mins[0];
	const float height = mi->model->maxs[2] - mi->model->mins[2];
	const float factorX = boxSize[0] / width;
	const float factorY = boxSize[1] / height;
	const float size = std::min(factorX, factorY);

	/* get center */
	VectorCenterFromMinsMaxs(mi->model->mins, mi->model->maxs, center);
	VectorNegate(center, center);
	VectorSet(scale, size, size, size);

	mi->center = center;
	mi->scale = scale;
}
Ejemplo n.º 6
0
/**
 * @brief Spawns a sound (that will be spatialized on the client side)
 * @param ent The edict that is causing the sound
 * @param origin The origin of the sound
 * @param sound The sound file, path relative to sounds/. If there is a + at the end the client will
 * choose a random sound. See the event function for more information.
 * of the path, a random sound will be taken.
 */
void G_EventSpawnSound (unsigned int playerMask, bool instant, const edict_t* ent, const vec3_t origin, const char *sound)
{
	G_EventAdd(playerMask, EV_SOUND | (instant ? EVENT_INSTANTLY : 0), ent->number);

	/* use the entity origin unless it is a bmodel or explicitly specified */
	if (!origin) {
		if (ent->solid == SOLID_BSP) {
			vec3_t origin_v;
			VectorCenterFromMinsMaxs(ent->mins, ent->maxs, origin_v);
			VectorAdd(ent->origin, origin_v, origin_v);
			gi.WritePos(origin);
		} else {
			gi.WritePos(vec3_origin);
		}
	} else {
		gi.WritePos(origin);
	}
	gi.WriteString(sound);
	G_EventEnd();
}
Ejemplo n.º 7
0
void CalculateMinsMaxs (const vec3_t angles, const vec3_t mins, const vec3_t maxs, const vec3_t origin, vec3_t absmin, vec3_t absmax)
{
	/* expand for rotation */
	if (VectorNotEmpty(angles)) {
		vec3_t minVec, maxVec, tmpMinVec, tmpMaxVec;
		vec3_t centerVec, halfVec, newCenterVec, newHalfVec;
		vec3_t m[3];

		/* Find the center of the extents. */
		VectorCenterFromMinsMaxs(mins, maxs, centerVec);

		/* Find the half height and half width of the extents. */
		VectorSubtract(maxs, centerVec, halfVec);

		/* Rotate the center about the origin. */
		VectorCreateRotationMatrix(angles, m);
		VectorRotate(m, centerVec, newCenterVec);
		VectorRotate(m, halfVec, newHalfVec);

		/* Set minVec and maxVec to bound around newCenterVec at halfVec size. */
		VectorSubtract(newCenterVec, newHalfVec, tmpMinVec);
		VectorAdd(newCenterVec, newHalfVec, tmpMaxVec);

		/* rotation may have changed min and max of the box, so adjust it */
		minVec[0] = min(tmpMinVec[0], tmpMaxVec[0]);
		minVec[1] = min(tmpMinVec[1], tmpMaxVec[1]);
		minVec[2] = min(tmpMinVec[2], tmpMaxVec[2]);
		maxVec[0] = max(tmpMinVec[0], tmpMaxVec[0]);
		maxVec[1] = max(tmpMinVec[1], tmpMaxVec[1]);
		maxVec[2] = max(tmpMinVec[2], tmpMaxVec[2]);

		/* Adjust the absolute mins/maxs */
		VectorAdd(origin, minVec, absmin);
		VectorAdd(origin, maxVec, absmax);
	} else {  /* normal */
		VectorAdd(origin, mins, absmin);
		VectorAdd(origin, maxs, absmax);
	}
}
Ejemplo n.º 8
0
/**
 * @brief If origin is NULL, the origin is determined from the entity origin or the midpoint of the entity box for bmodels.
 */
void SV_StartSound (int mask, const vec3_t origin, const edict_t *entity, const char *sound)
{
	vec3_t origin_v;
	struct dbuffer *msg;

	/* use the entity origin unless it is a bmodel or explicitly specified */
	if (!origin) {
		origin = origin_v;
		if (entity->solid == SOLID_BSP) {
			VectorCenterFromMinsMaxs(entity->mins, entity->maxs, origin_v);
			VectorAdd(entity->origin, origin_v, origin_v);
		} else {
			VectorCopy(entity->origin, origin_v);
		}
	}

	msg = new_dbuffer();

	NET_WriteByte(msg, svc_sound);
	NET_WriteString(msg, sound);
	NET_WritePos(msg, origin);

	SV_Multicast(mask, msg);
}
Ejemplo n.º 9
0
/**
 * @brief This function recalculates the routing surrounding the entity name.
 * @sa CM_InlineModel
 * @sa CM_CheckUnit
 * @sa CM_UpdateConnection
 * @sa CMod_LoadSubmodels
 * @sa Grid_RecalcBoxRouting
 * @param[in] mapTiles List of tiles the current (RMA-)map is composed of
 * @param[in] routing The routing map (either server or client map)
 * @param[in] name Name of the inline model to compute the mins/maxs for
 * @param[in] box The box around the inline model (alternative to name)
 * @param[in] list The local models list (a local model has a name starting with * followed by the model number)
 */
void Grid_RecalcRouting (mapTiles_t *mapTiles, Routing &routing, const char *name, const GridBox &box, const char **list)
{
	if (box.isZero()) {
		pos3_t min, max;
		vec3_t absmin, absmax;
		const cBspModel_t *model;
		unsigned int i;
		/* get inline model, if it is one */
		if (*name != '*') {
			Com_Printf("Called Grid_RecalcRouting with no inline model\n");
			return;
		}
		model = CM_InlineModel(mapTiles, name);
		if (!model) {
			Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name);
			return;
		}

#if 1
		/* An attempt to fix the 'doors starting opened' bug (# 3456).
		 * The main difference is the (missing) rotation of the halfVec.
		 * The results are better, but do not fix the problem. */
		CalculateMinsMaxs(model->angles, model->mins, model->maxs, model->origin, absmin, absmax);
#else
		/* get the target model's dimensions */
		if (VectorNotEmpty(model->angles)) {
			vec3_t minVec, maxVec;
			vec3_t centerVec, halfVec, newCenterVec;
			vec3_t m[3];

			/* Find the center of the extents. */
			VectorCenterFromMinsMaxs(model->mins, model->maxs, centerVec);

			/* Find the half height and half width of the extents. */
			VectorSubtract(model->maxs, centerVec, halfVec);

			/* Rotate the center about the origin. */
			VectorCreateRotationMatrix(model->angles, m);
			VectorRotate(m, centerVec, newCenterVec);

			/* Set minVec and maxVec to bound around newCenterVec at halfVec size. */
			VectorSubtract(newCenterVec, halfVec, minVec);
			VectorAdd(newCenterVec, halfVec, maxVec);

			/* Now offset by origin then convert to position (Doors do not have 0 origins) */
			VectorAdd(minVec, model->origin, absmin);
			VectorAdd(maxVec, model->origin, absmax);
		} else {  /* normal */
			/* Now offset by origin then convert to position (Doors do not have 0 origins) */
			VectorAdd(model->mins, model->origin, absmin);
			VectorAdd(model->maxs, model->origin, absmax);
		}
#endif
		VecToPos(absmin, min);
		VecToPos(absmax, max);

		/* fit min/max into the world size */
		max[0] = std::min(max[0], (pos_t)(PATHFINDING_WIDTH - 1));
		max[1] = std::min(max[1], (pos_t)(PATHFINDING_WIDTH - 1));
		max[2] = std::min(max[2], (pos_t)(PATHFINDING_HEIGHT - 1));
		for (i = 0; i < 3; i++)
			min[i] = std::max(min[i], (pos_t)0);

		/* We now have the dimensions, call the generic rerouting function. */
		GridBox rerouteBox(min, max);
		Grid_RecalcBoxRouting(mapTiles, routing, rerouteBox, list);
	} else {
		/* use the passed box */
		Grid_RecalcBoxRouting(mapTiles, routing, box, list);
	}
}
Ejemplo n.º 10
0
/**
 * @brief Deals splash damage to a target and its surroundings.
 * @param[in] ent The shooting actor
 * @param[in] fd The fire definition that defines what type of damage is dealt and how big the splash radius is.
 * @param[in] impact The impact vector where the grenade is exploding
 * @param[in,out] mock pseudo shooting - only for calculating mock values - NULL for real shots
 * @param[in] tr The trace where the grenade hits something (or not)
 */
static void G_SplashDamage (edict_t *ent, const fireDef_t *fd, vec3_t impact, shot_mock_t *mock, const trace_t* tr)
{
	edict_t *check = NULL;
	vec3_t center;
	float dist;
	int damage;

	const bool shock = (fd->obj->dmgtype == gi.csi->damShock);

	assert(fd->splrad > 0.0);

	while ((check = G_EdictsGetNextInUse(check))) {
		/* If we use a blinding weapon we skip the target if it's looking
		 * away from the impact location. */
		if (shock && !G_FrustumVis(check, impact))
			continue;

		if (G_IsBrushModel(check) && G_IsBreakable(check))
			VectorCenterFromMinsMaxs(check->absmin, check->absmax, center);
		else if (G_IsLivingActor(check) || G_IsBreakable(check))
			VectorCopy(check->origin, center);
		else
			continue;

		/* check for distance */
		dist = VectorDist(impact, center);
		dist = dist > UNIT_SIZE / 2 ? dist - UNIT_SIZE / 2 : 0;
		if (dist > fd->splrad)
			continue;

		if (fd->irgoggles) {
			if (G_IsActor(check)) {
				/* check whether this actor (check) is in the field of view of the 'shooter' (ent) */
				if (G_FrustumVis(ent, check->origin)) {
					if (!mock) {
						const unsigned int playerMask = G_TeamToPM(ent->team) ^ G_VisToPM(check->visflags);
						G_AppearPerishEvent(playerMask, true, check, ent);
						G_VisFlagsAdd(check, G_PMToVis(playerMask));
					}
				}
			}
			continue;
		}

		/* check for walls */
		if (G_IsLivingActor(check) && !G_ActorVis(impact, ent, check, false))
			continue;

		/* do damage */
		if (shock)
			damage = 0;
		else
			damage = fd->spldmg[0] * (1.0 - dist / fd->splrad);

		if (mock)
			mock->allow_self = true;
		G_Damage(check, fd, damage, ent, mock, NULL);
		if (mock)
			mock->allow_self = false;
	}

	/** @todo splash might also hit other surfaces and the trace doesn't handle that */
	if (tr && G_FireAffectedSurface(tr->surface, fd)) {
		/* move a little away from the impact vector */
		VectorMA(impact, 1, tr->plane.normal, impact);
		G_SpawnParticle(impact, tr->contentFlags >> 8, "burning");
	}
Ejemplo n.º 11
0
/**
 * @brief This function recalculates the routing surrounding the entity name.
 * @sa CM_InlineModel
 * @sa CM_CheckUnit
 * @sa CM_UpdateConnection
 * @sa CMod_LoadSubmodels
 * @sa Grid_RecalcBoxRouting
 * @param[in] mapTiles List of tiles the current (RMA-)map is composed of
 * @param[in] map The routing map (either server or client map)
 * @param[in] name Name of the inline model to compute the mins/maxs for
 * @param[in] list The local models list (a local model has a name starting with * followed by the model number)
 */
void Grid_RecalcRouting (mapTiles_t *mapTiles, routing_t *map, const char *name, const char **list)
{
	const cBspModel_t *model;
	pos3_t min, max;
	unsigned int i;
	double start, end;

	start = time(NULL);

	/* get inline model, if it is one */
	if (*name != '*') {
		Com_Printf("Called Grid_RecalcRouting with no inline model\n");
		return;
	}
	model = CM_InlineModel(mapTiles, name);
	if (!model) {
		Com_Printf("Called Grid_RecalcRouting with invalid inline model name '%s'\n", name);
		return;
	}

	Com_DPrintf(DEBUG_PATHING, "Model:%s origin(%f,%f,%f) angles(%f,%f,%f) mins(%f,%f,%f) maxs(%f,%f,%f)\n", name,
		model->origin[0], model->origin[1], model->origin[2],
		model->angles[0], model->angles[1], model->angles[2],
		model->mins[0], model->mins[1], model->mins[2],
		model->maxs[0], model->maxs[1], model->maxs[2]);

	/* get the target model's dimensions */
	if (VectorNotEmpty(model->angles)) {
		vec3_t minVec, maxVec;
		vec3_t centerVec, halfVec, newCenterVec;
		vec3_t m[3];

		/* Find the center of the extents. */
		VectorCenterFromMinsMaxs(model->mins, model->maxs, centerVec);

		/* Find the half height and half width of the extents. */
		VectorSubtract(model->maxs, centerVec, halfVec);

		/* Rotate the center about the origin. */
		VectorCreateRotationMatrix(model->angles, m);
		VectorRotate(m, centerVec, newCenterVec);

		/* Set minVec and maxVec to bound around newCenterVec at halfVec size. */
		VectorSubtract(newCenterVec, halfVec, minVec);
		VectorAdd(newCenterVec, halfVec, maxVec);

		/* Now offset by origin then convert to position (Doors do not have 0 origins) */
		VectorAdd(minVec, model->origin, minVec);
		VecToPos(minVec, min);
		VectorAdd(maxVec, model->origin, maxVec);
		VecToPos(maxVec, max);
	} else {  /* normal */
		vec3_t temp;
		/* Now offset by origin then convert to position (Doors do not have 0 origins) */
		VectorAdd(model->mins, model->origin, temp);
		VecToPos(temp, min);
		VectorAdd(model->maxs, model->origin, temp);
		VecToPos(temp, max);
	}

	/* fit min/max into the world size */
	max[0] = min(max[0] + 1, PATHFINDING_WIDTH - 1);
	max[1] = min(max[1] + 1, PATHFINDING_WIDTH - 1);
	max[2] = min(max[2] + 1, PATHFINDING_HEIGHT - 1);
	for (i = 0; i < 3; i++)
		min[i] = max(min[i] - 1, 0);

	/* We now have the dimensions, call the generic rerouting function. */
	Grid_RecalcBoxRouting(mapTiles, map, min, max, list);

	end = time(NULL);
	Com_DPrintf(DEBUG_ROUTING, "Retracing for model %s between (%i, %i, %i) and (%i, %i %i) in %5.1fs\n",
			name, min[0], min[1], min[2], max[0], max[1], max[2], end - start);
}
Ejemplo n.º 12
0
static void CL_CenterCameraIntoMap_f (void)
{
	VectorCenterFromMinsMaxs(cl.mapData->mapMin, cl.mapData->mapMax, cl.cam.origin);
}