Esempio n. 1
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");
	}
Esempio n. 2
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 - nullptr for real shots
 * @param[in] tr The trace where the grenade hits something (or not)
 */
static void G_SplashDamage (Actor* ent, const fireDef_t* fd, vec3_t impact, shot_mock_t* mock, const trace_t* tr)
{
	assert(fd->splrad > 0.0f);

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

	Edict* check = nullptr;
	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;

		const bool isActor = G_IsLivingActor(check);
		vec3_t center;
		if (G_IsBrushModel(check) && G_IsBreakable(check))
			check->absBox.getCenter(center);
		else if (isActor || G_IsBreakable(check))
			VectorCopy(check->origin, center);
		else
			continue;

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

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

		/* check for walls */
		if (isActor && G_TestLine(impact, check->origin))
			continue;

		/* do damage */
		const int damage = shock ? 0 : fd->spldmg[0] * (1.0f - dist / fd->splrad);

		if (mock)
			mock->allow_self = true;
		/* Send hurt sounds for actors, but only if they'll recieve damage from this attack */
		if (G_Damage(check, fd, damage, ent, mock, nullptr) && isActor
				&& (G_ApplyProtection(check, fd->dmgweight,  damage) > 0) && !shock) {
			const teamDef_t* teamDef = check->chr.teamDef;
			const int gender = check->chr.gender;
			const char* sound = teamDef->getActorSound(gender, SND_HURT);
			G_EventSpawnSound(G_VisToPM(check->visflags), *check, nullptr, sound);
		}
		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");
	}