Beispiel #1
0
static int G_DoTestVis (const int team, edict_t * check, bool perish, int playerMask, const edict_t *ent)
{
	int status = 0;
	const int visFlags = perish ? VT_PERISH : 0;
	const int vis = G_TestVis(team, check, visFlags);

	/* visibility has changed ... */
	if (vis & VIS_CHANGE) {
		/* swap the vis mask for the given team */
		const bool appear = (vis & VIS_YES) == VIS_YES;
		if (playerMask == 0) {
			G_VisFlagsSwap(check, G_TeamToVisMask(team));
		} else {
			G_AppearPerishEvent(playerMask, appear, check, ent);
		}

		/* ... to visible */
		if (vis & VIS_YES) {
			status |= VIS_APPEAR;
			if (G_VisShouldStop(check))
				status |= VIS_STOP;
		} else
			status |= VIS_PERISH;
	}
	return status;
}
Beispiel #2
0
/**
 * @param[in] team The team looking at the edict (or not)
 * @param[in] check The edict to check the visibility for
 * @param[in] visFlags The flags for the vis check
 * @param[in] playerMask The mask for the players to send the appear/perish events to. If this is @c 0 the events
 * are not sent - we only update the visflags of the edict
 * @param[in] ent The edict that was responsible for letting the check edict appear and is looking
 */
static int G_DoTestVis (const int team, Edict* check, const vischeckflags_t visFlags, playermask_t playerMask, const Edict* ent)
{
	int status = 0;
	const int vis = G_TestVis(team, check, visFlags);

	/* visibility has changed ... */
	if (vis & VS_CHANGE) {
		/* swap the vis mask for the given team */
		const bool appear = (vis & VS_YES) == VS_YES;
		if (playerMask == 0) {
			G_VisFlagsSwap(*check, G_TeamToVisMask(team));
		} else {
			G_AppearPerishEvent(playerMask, appear, *check, ent);
		}

		/* ... to visible */
		if (vis & VS_YES) {
			status |= VIS_APPEAR;
			if (G_VisShouldStop(check))
				status |= VIS_STOP;
		} else {
			status |= VIS_PERISH;
		}
	} else if (vis == 0 && (visFlags & VT_NEW)) {
		if (G_IsActor(check)) {
			G_EventActorAdd(playerMask, *check);
		}
	}
	return status;
}
Beispiel #3
0
/**
 * @brief Make everything visible to anyone who can't already see it
 */
void G_VisMakeEverythingVisible (void)
{
	edict_t *ent = NULL;
	while ((ent = G_EdictsGetNextInUse(ent))) {
		const int playerMask = G_VisToPM(ent->visflags);
		G_AppearPerishEvent(~playerMask, true, ent, NULL);
		if (G_IsActor(ent))
			G_SendInventory(~G_TeamToPM(ent->team), ent);
	}
}
Beispiel #4
0
/**
 * @brief Make everything visible to anyone who can't already see it
 */
void G_VisMakeEverythingVisible (void)
{
	Edict* ent = nullptr;
	while ((ent = G_EdictsGetNextInUse(ent))) {
		const int playerMask = G_VisToPM(ent->visflags);
		G_AppearPerishEvent(~playerMask, true, *ent, nullptr);
		if (G_IsActor(ent))
			G_SendInventory(~G_TeamToPM(ent->getTeam()), *ent);
	}
}
Beispiel #5
0
static void SVCmd_ShowAll_f (void)
{
	Edict* ent = nullptr;

	/* Make everything visible to anyone who can't already see it */
	while ((ent = G_EdictsGetNextInUse(ent))) {
		G_AppearPerishEvent(~G_VisToPM(ent->visflags), 1, *ent, nullptr);
		G_VisFlagsAdd(*ent, ~ent->visflags);
	}
	gi.DPrintf("All items and creatures revealed to all sides\n");
}
Beispiel #6
0
/**
 * @note Think functions are only executed when the match is running
 * or in other word, the game has started
 */
void G_MissionThink (Edict* self)
{
	if (!G_MatchIsRunning())
		return;

	/* when every player has joined the match - spawn the mission target
	 * particle (if given) to mark the trigger */
	if (self->particle) {
		self->link = G_SpawnParticle(self->origin, self->spawnflags, self->particle);

		/* This is automatically freed on map shutdown */
		self->particle = nullptr;
	}

	Edict* chain = self->groupMaster;
	if (!chain)
		chain = self;
	while (chain) {
		if (chain->type == ET_MISSION) {
			if (chain->item) {
				const Item* ic;
				G_GetFloorItems(chain);
				ic = chain->getFloor();
				if (!ic) {
					/* reset the counter if there is no item */
					chain->count = 0;
					return;
				}
				for (; ic; ic = ic->getNext()) {
					const objDef_t* od = ic->def();
					assert(od);
					/* not the item we are looking for */
					if (Q_streq(od->id, chain->item))
						break;
				}
				if (!ic) {
					/* reset the counter if it's not the searched item */
					chain->count = 0;
					return;
				}
			}
			if (chain->time) {
				/* Check that the target zone is still occupied (last defender might have died) */
				if (!chain->item && !G_MissionIsTouched(chain)) {
						chain->count = 0;
				}
				const int endTime = level.actualRound - chain->count;
				const int spawnIndex = (chain->getTeam() + level.teamOfs) % MAX_TEAMS;
				const int currentIndex = (level.activeTeam + level.teamOfs) % MAX_TEAMS;
				/* not every edict in the group chain has
				 * been occupied long enough */
				if (!chain->count || endTime < chain->time ||
						(endTime == chain->time && spawnIndex < currentIndex))
					return;
			}
			if (chain->target && !chain->time && !chain->item) {
				if (!G_MissionIsTouched(chain))
					return;
			}
		}
		chain = chain->groupChain;
	}

	const bool endMission = self->target == nullptr;

	/* store team before the edict is released */
	const int team = self->getTeam();
	chain = self->groupMaster;
	if (!chain)
		chain = self;
	while (chain) {
		if (chain->type == ET_MISSION) {
			G_UseEdict(chain, nullptr);
			if (chain->item != nullptr) {
				Edict* item = G_GetEdictFromPos(chain->pos, ET_ITEM);
				if (item != nullptr) {
					if (!G_InventoryRemoveItemByID(chain->item, item, CID_FLOOR)) {
						Com_Printf("Could not remove item '%s' from floor edict %i\n", chain->item, item->getIdNum());
					} else if (!item->getFloor()) {
						G_EventPerish(*item);
						G_FreeEdict(item);
					}
				}
			}
			if (chain->link != nullptr) {
				Edict* particle = G_GetEdictFromPos(chain->pos, ET_PARTICLE);
				if (particle != nullptr) {
					G_AppearPerishEvent(G_VisToPM(particle->visflags), false, *particle, nullptr);
					G_FreeEdict(particle);
				}
				chain->link = nullptr;
			}

			/* Display mission message */
			if (G_ValidMessage(chain)) {
				const char* msg = chain->message;
				if (msg[0] == '_')
					++msg;
				gi.BroadcastPrintf(PRINT_HUD, "%s", msg);
			}
		}

		Edict* ent = chain->groupChain;
		/* free the group chain */
		G_FreeEdict(chain);
		chain = ent;
	}

	if (endMission)
		G_MatchEndTrigger(team, level.activeTeam == TEAM_ALIEN ? 10 : 3);
}
Beispiel #7
0
/**
 * @note Think functions are only executed when the match is running
 * or in other word, the game has started
 */
void G_MissionThink (Edict* self)
{
	if (!G_MatchIsRunning())
		return;

	/* when every player has joined the match - spawn the mission target
	 * particle (if given) to mark the trigger */
	if (self->particle) {
		self->link = G_SpawnParticle(self->origin, self->spawnflags, self->particle);

		/* This is automatically freed on map shutdown */
		self->particle = nullptr;
	}

	Edict* chain = self->groupMaster;
	if (!chain)
		chain = self;
	while (chain) {
		if (chain->type == ET_MISSION) {
			if (chain->item) {
				const Item* ic;
				G_GetFloorItems(chain);
				ic = chain->getFloor();
				if (!ic) {
					/* reset the counter if there is no item */
					chain->count = 0;
					return;
				}
				for (; ic; ic = ic->getNext()) {
					const objDef_t* od = ic->def();
					assert(od);
					/* not the item we are looking for */
					if (Q_streq(od->id, chain->item))
						break;
				}
				if (!ic) {
					/* reset the counter if it's not the searched item */
					chain->count = 0;
					return;
				}
			}
			if (chain->time) {
				const int endTime = level.actualRound - chain->count;
				const int spawnIndex = (self->getTeam() + level.teamOfs) % MAX_TEAMS;
				const int currentIndex = (level.activeTeam + level.teamOfs) % MAX_TEAMS;
				/* not every edict in the group chain has
				 * been occupied long enough */
				if (!chain->count || endTime < chain->time ||
						(endTime == level.actualRound && spawnIndex <= currentIndex))
					return;
			}
			/* not destroyed yet */
			if ((chain->flags & FL_DESTROYABLE) && chain->HP)
				return;
		}
		chain = chain->groupChain;
	}

	if (self->use)
		self->use(self, nullptr);

	/* store team before the edict is released */
	const int team = self->getTeam();
	chain = self->groupMaster;
	if (!chain)
		chain = self;
	while (chain) {
		if (chain->item != nullptr) {
			Edict* item = G_GetEdictFromPos(chain->pos, ET_ITEM);
			if (item != nullptr) {
				if (!G_InventoryRemoveItemByID(chain->item, item, CID_FLOOR)) {
					Com_Printf("Could not remove item '%s' from floor edict %i\n", chain->item, item->getIdNum());
				} else if (!item->getFloor()) {
					G_EventPerish(*item);
					G_FreeEdict(item);
				}
			}
		}
		if (chain->link != nullptr) {
			Edict* particle = G_GetEdictFromPos(chain->pos, ET_PARTICLE);
			if (particle != nullptr) {
				G_AppearPerishEvent(PM_ALL, false, *particle, nullptr);
				G_FreeEdict(particle);
			}
			chain->link = nullptr;
		}

		Edict* ent = chain->groupChain;
		/* free the trigger */
		if (chain->child())
			G_FreeEdict(chain->child());
		/* free the group chain */
		G_FreeEdict(chain);
		chain = ent;
	}
	self = nullptr;

	/* still active mission edicts left */
	Edict* ent = nullptr;
	while ((ent = G_EdictsGetNextInUse(ent)))
		if (ent->type == ET_MISSION && ent->getTeam() == team)
			return;

	G_MatchEndTrigger(team, 10);
}
Beispiel #8
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");
	}
Beispiel #9
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");
	}
Beispiel #10
0
/**
 * @note Think functions are only executed when the match is running
 * or in other word, the game has started
 */
void G_MissionThink (edict_t *self)
{
	edict_t *chain = self->groupMaster;
	edict_t *ent;
	int team;

	if (!G_MatchIsRunning())
		return;

	/* when every player has joined the match - spawn the mission target
	 * particle (if given) to mark the trigger */
	if (self->particle) {
		G_SpawnParticle(self->origin, self->spawnflags, self->particle);

		/* This is automatically freed on map shutdown */
		self->particle = NULL;
	}

	if (!chain)
		chain = self;
	while (chain) {
		if (chain->type == ET_MISSION) {
			if (chain->item) {
				const invList_t *ic;
				G_GetFloorItems(chain);
				ic = FLOOR(chain);
				if (!ic) {
					/* reset the counter if there is no item */
					chain->count = 0;
					return;
				}
				for (; ic; ic = ic->next) {
					const objDef_t *od = ic->item.t;
					assert(od);
					/* not the item we are looking for */
					if (Q_streq(od->id, chain->item))
						break;
				}
				if (!ic) {
					/* reset the counter if it's not the searched item */
					chain->count = 0;
					return;
				}
			}
			if (chain->time) {
				/* not every edict in the group chain has
				 * been occupied long enough */
				if (!chain->count || level.actualRound - chain->count < chain->time)
					return;
			}
			/* not destroyed yet */
			if ((chain->flags & FL_DESTROYABLE) && chain->HP)
				return;
		}
		chain = chain->groupChain;
	}

	if (self->use)
		self->use(self, NULL);

	/* store team before the edict is released */
	team = self->team;

	chain = self->groupMaster;
	if (!chain)
		chain = self;
	while (chain) {
		if (chain->item != NULL) {
			edict_t *item = G_GetEdictFromPos(chain->pos, ET_ITEM);
			if (item != NULL) {
				if (!G_InventoryRemoveItemByID(chain->item, item, gi.csi->idFloor)) {
					Com_Printf("Could not remove item '%s' from floor edict %i\n",
							chain->item, item->number);
				} else {
					G_AppearPerishEvent(G_VisToPM(item->visflags), false, item, NULL);
				}
			}
		}
		if (chain->particle != NULL) {
			/** @todo not yet working - particle stays active */
			edict_t *particle = G_GetEdictFromPos(chain->pos, ET_PARTICLE);
			if (particle != NULL) {
				G_AppearPerishEvent(PM_ALL, false, particle, NULL);
				G_FreeEdict(particle);
			}
		}

		ent = chain->groupChain;
		/* free the trigger */
		if (chain->child)
			G_FreeEdict(chain->child);
		/* free the group chain */
		G_FreeEdict(chain);
		chain = ent;
	}
	self = NULL;

	/* still active mission edicts left */
	ent = NULL;
	while ((ent = G_EdictsGetNextInUse(ent)))
		if (ent->type == ET_MISSION && ent->team == team)
			return;

	G_MatchEndTrigger(team, 10);
}