/** * @brief Send the appear or perish event to the affected clients * @param[in] playerMask These are the affected players or clients * In case of e.g. teamplay there can be more than one client affected - thus * this is a player mask * @param[in] appear Is this event about an appearing actor (or a perishing one) * @param[in] check The edict we are talking about (that appears or perishes) * @param[in] ent The edict that was responsible for letting the check edict appear * or perish. Might be @c NULL. * @sa CL_ActorAppear */ void G_AppearPerishEvent (playermask_t playerMask, bool appear, edict_t *check, const edict_t *ent) { teammask_t teamMaskDiff; /* test for pointless player mask */ if (!playerMask) return; teamMaskDiff = G_PMToVis(playerMask); G_VisFlagsSwap(check, teamMaskDiff); if (appear) { /* appear */ switch (check->type) { case ET_ACTOR: case ET_ACTOR2x2: G_EventActorAppear(playerMask, check, ent); break; case ET_CAMERA: G_EventCameraAppear(playerMask, check); break; case ET_ITEM: G_EventEdictAppear(playerMask, check); G_SendInventory(playerMask, check); break; case ET_PARTICLE: G_EventEdictAppear(playerMask, check); G_EventSendParticle(playerMask, check); break; case ET_TRIGGER_RESCUE: G_EventAddBrushModel(playerMask, check); break; default: if (G_IsVisibleOnBattlefield(check)) gi.Error("Missing edict type %i in G_AppearPerishEvent", check->type); break; } } else if (G_IsVisibleOnBattlefield(check)) { G_EventEdictPerish(playerMask, check); } }
/** * @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"); }
/** * @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"); }