Beispiel #1
0
/**
 * @brief Prints some reaction fire data to the console
 * @param[in] target The target entity
 */
static void G_ReactionFirePrintSituation (Edict* target)
{
	if (!G_IsAlien(target))
		return;

	Com_Printf("Alien %i at %i/%i/%i TU:%i\n", target->number, target->pos[0], target->pos[1], target->pos[2], target->TU);

	Actor* shooter = nullptr;
	/* check all possible shooters */
	while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
		if (G_IsAlien(shooter) || G_IsCivilian(shooter))
			continue;
		char msgHdr[100];
		Com_sprintf(msgHdr, sizeof(msgHdr), "S%i: at %i/%i/%i RF: ", shooter->number, shooter->pos[0], shooter->pos[1], shooter->pos[2]);
		int ttus = rft.getTriggerTUs(shooter, target);
		if (ttus == -2)
			Com_Printf("%s not initialized\n", msgHdr);
		if (ttus == -1)
			Com_Printf("%s not aiming\n", msgHdr);
		else if (rft.hasExpired(shooter, target, 0))
			Com_Printf("expired\n", msgHdr);
		else
			Com_Printf("%s not yet: %i\n", msgHdr, ttus);
	}
}
Beispiel #2
0
/**
 * @brief Called when 'target' is about to shoot, this forces a 'draw' to decide who gets the first shot
 * @param[in] target The entity about to shoot
 * @param[in] fdTime The TU of the shot
 * @sa G_ClientShoot
 */
void G_ReactionFirePreShot (const Actor* target, const int fdTime)
{
	bool repeat = true;

	/* Check to see whether this triggers any reaction fire */
	G_ReactionFireNotifyClientStartShot(target);
	rf.updateAllTargets(target);
	rf.notifyClientOnShot(target, fdTime);

	/* if any reaction fire occurs, we have to loop through all entities again to allow
	 * multiple (fast) RF snap shots before a (slow) aimed shot from the target occurs. */
	while (repeat) {
		Actor* shooter = nullptr;
		repeat = false;
		/* check all ents to see who wins and who loses a draw */
		while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
			const int entTUs = G_ReactionFireGetTUsForItem(shooter, target);
			/* indicates an RF weapon is there */
			if (entTUs <= 1)
				continue;
			if (!rft.hasExpired(shooter, target, fdTime))
				continue;
			if (!rf.tryToShoot(shooter, target)) {
				G_ReactionFireNotifyClientRFAborted(shooter, target, MAX_ROUTE);
				continue;
			}
			repeat = true;
			rft.advance(shooter, fdTime);
		}
	}
}
Beispiel #3
0
/**
 * @brief Check whether 'target' has just triggered any new reaction fire
 * @param[in] target The entity triggering fire
 * @sa G_CanReactionFire
 * @sa G_GetFiringTUs
 */
static void G_ReactionFireSearchTarget (const edict_t *target)
{
	edict_t *ent = NULL;

	/* check all possible shooters */
	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		int tus;

		/* not if ent has reaction target already */
		if (ent->reactionTarget)
			continue;

		/* check whether reaction fire is possible */
		if (!G_ReactionFireIsPossible(ent, target))
			continue;

		/* see how quickly ent can fire (if it can fire at all) */
		tus = G_ReactionFireGetTUsForItem(ent, target, RIGHT(ent));
		if (tus < 0)
			continue;

		/* queue a reaction fire to take place */
		ent->reactionTarget = target;
		/* An enemy entering the line of fire of a soldier on reaction
		 * fire should have the opportunity to spend time equal to the
		 * sum of these values. */
		ent->reactionTUs = max(0, target->TU - (tus / 4.0));
		ent->reactionNoDraw = qfalse;
	}
}
Beispiel #4
0
static void G_TouchEdict_f (void)
{
    edict_t *e, *ent;
    int i;

    if (gi.Cmd_Argc() < 2) {
        gi.DPrintf("Usage: %s <entnum>\n", gi.Cmd_Argv(0));
        return;
    }

    i = atoi(gi.Cmd_Argv(1));
    if (!G_EdictsIsValidNum(i))
        return;

    e = G_EdictsGetByNum(i);
    if (!e->touch) {
        gi.DPrintf("No touch function for entity %s\n", e->classname);
        return;
    }

    ent = G_EdictsGetNextLivingActor(NULL);
    if (!ent)
        return;	/* didn't find any */

    gi.DPrintf("Call touch function for %s\n", e->classname);
    e->touch(e, ent);
}
Beispiel #5
0
/**
 * @sa G_ClientConnect
 */
void G_ClientDisconnect (player_t * player)
{
#if 0
	edict_t *ent = NULL;
#endif

	/* only if the player already sent his began */
	if (player->began) {
		level.numplayers--;
		gi.ConfigString(CS_PLAYERCOUNT, "%i", level.numplayers);

		if (level.activeTeam == player->pers.team)
			G_ClientEndRound(player);

		/* if no more players are connected - stop the server */
		G_MatchEndCheck();
	}

#if 0
	/* now let's remove all the edicts that belongs to this player */
	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		if (ent->pnum == player->num)
			G_ActorDie(ent, STATE_DEAD, NULL);
	}
	G_MatchEndCheck();
#endif

	player->began = false;
	player->roundDone = false;
	player->isReady = false;

	gi.BroadcastPrintf(PRINT_CONSOLE, "%s disconnected.\n", player->pers.netname);
}
Beispiel #6
0
/**
 * @brief Called when 'target' is about to shoot, this forces a 'draw' to decide who gets the first shot
 * @param[in] target The entity about to shoot
 * @param[in] fdTime The TU of the shot
 * @sa G_ClientShoot
 */
void G_ReactionFirePreShot (const edict_t *target, const int fdTime)
{
	edict_t *shooter = NULL;
	bool repeat = true;

	/* Check to see whether this triggers any reaction fire */
	G_ReactionFireTargetsUpdateAll(target);

	/* if any reaction fire occurs, we have to loop through all entities again to allow
	 * multiple (fast) RF snap shots before a (slow) aimed shot from the target occurs. */
	while (repeat) {
		repeat = false;
		/* check all ents to see who wins and who loses a draw */
		while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
			int entTUs = G_ReactionFireGetTUsForItem(shooter, target, RIGHT(shooter));
			if (entTUs > 1) {	/* indicates an RF weapon is there */
				if (G_ReactionFireTargetsExpired(shooter, target, fdTime)) {
					if (G_ReactionFireTryToShoot(shooter, target)) {
						repeat = true;
						G_ReactionFireTargetsAdvance(shooter, target, fdTime);
					}
				}
			}
		}
	}
}
Beispiel #7
0
/**
 * @brief Iterate through the living actor entities of the given team
 * @param lastEnt The entity found in the previous iteration; if nullptr, we start at the beginning
 * @param team The team we are looking for
 */
Edict* G_EdictsGetNextLivingActorOfTeam (Edict* lastEnt, const int team)
{
	Edict* ent = lastEnt;

	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		if (ent->team == team)
			break;
	}
	return ent;
}
Beispiel #8
0
/**
 * @brief Iterate through the living actor entities of the given team
 * @param lastEnt The entity found in the previous iteration; if nullptr, we start at the beginning
 * @param team The team we are looking for
 */
Actor* G_EdictsGetNextLivingActorOfTeam (Actor* lastEnt, const int team)
{
	Actor* actor = lastEnt;

	while ((actor = G_EdictsGetNextLivingActor(actor))) {
		if (actor->getTeam() == team)
			break;
	}
	return actor;
}
Beispiel #9
0
/**
 * @brief Counts the still living actors for a player
 */
static int G_PlayerSoldiersCount (const Player& player)
{
	int cnt = 0;
	Actor* actor = nullptr;

	while ((actor = G_EdictsGetNextLivingActor(actor))) {
		if (actor->getPlayerNum() == player.getNum())
			cnt++;
	}

	return cnt;
}
Beispiel #10
0
/**
 * @brief Counts the still living actors for a player
 */
static int G_PlayerSoldiersCount (const Player& player)
{
	int cnt = 0;
	Edict* ent = nullptr;

	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		if (ent->pnum == player.getNum())
			cnt++;
	}

	return cnt;
}
Beispiel #11
0
/**
 * @brief Called at the end of turn, all outstanding reaction fire is resolved
 * @sa G_ClientEndRound
 */
void G_ReactionFireEndTurn (void)
{
	edict_t *ent = NULL;

	/* resolve all outstanding reaction firing if possible */
	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		if (!ent->reactionTarget)
			continue;

		G_ReactionFireTryToShoot(ent);
	}
}
Beispiel #12
0
/**
 * @brief Searches an actor at the given grid location.
 * @param pos The grid location to look for an edict.
 * @return @c nullptr if nothing was found, otherwise the actor located at the given grid position.
 */
Actor* G_EdictsGetLivingActorFromPos (const pos3_t pos)
{
	Actor* actor = nullptr;

	while ((actor = G_EdictsGetNextLivingActor(actor))) {
		if (!VectorCompare(pos, actor->pos))
			continue;

		return actor;
	}
	/* nothing found at this pos */
	return nullptr;
}
Beispiel #13
0
/**
 * @brief Searches an actor at the given grid location.
 * @param pos The grid location to look for an edict.
 * @return @c nullptr if nothing was found, otherwise the actor located at the given grid position.
 */
Edict* G_EdictsGetLivingActorFromPos (const pos3_t pos)
{
	Edict* ent = nullptr;

	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		if (!VectorCompare(pos, ent->pos))
			continue;

		return ent;
	}
	/* nothing found at this pos */
	return nullptr;
}
Beispiel #14
0
/**
 * @brief Check whether 'target' has just triggered any new reaction fire
 * @param[in] target The entity triggering fire
 */
void ReactionFire::updateAllTargets (const Edict* target)
{
	Actor* shooter = nullptr;

	/* check all possible shooters */
	while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
		/* check whether reaction fire is possible (friend/foe, LoS) */
		if (isPossible(shooter, target)) {
			const int TUs = G_ReactionFireGetTUsForItem(shooter, target);
			if (TUs < 0)
				continue;	/* no suitable weapon */
			rft.add(shooter, target, TUs);
		} else {
			rft.remove(shooter, target);
		}
	}
}
Beispiel #15
0
/**
 * @brief Check whether 'target' has just triggered any new reaction fire
 * @param[in] target The entity triggering fire
 */
static void G_ReactionFireTargetsUpdateAll (const edict_t *target)
{
	edict_t *shooter = NULL;

	/* check all possible shooters */
	while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
		/* check whether reaction fire is possible (friend/foe, LoS */
		if (G_ReactionFireIsPossible(shooter, target)) {
			const int TUs = G_ReactionFireGetTUsForItem(shooter, target, RIGHT(shooter));
			if (TUs < 0)
				continue;	/* no suitable weapon */
			G_ReactionFireTargetsAdd(shooter, target, TUs);
		} else {
			G_ReactionFireTargetsRemove(shooter, target);
		}
	}
}
Beispiel #16
0
/**
 * @brief Check all entities to see whether target has caused reaction fire to resolve.
 * @param[in] target The entity that might be resolving reaction fire
 * @returns whether any entity fired (or would fire) upon target
 * @sa G_ReactionFireOnMovement
 * @sa G_ReactionFirePostShot
 */
static bool G_ReactionFireCheckExecution (const edict_t *target)
{
	edict_t *shooter = NULL;
	bool fired = false;

	/* check all possible shooters */
	while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
		const int tus = G_ReactionFireGetTUsForItem(shooter, target, RIGHT(shooter));
		if (tus > 1) {	/* indicates an RF weapon is there */
			if (G_ReactionFireTargetsExpired(shooter, target, 0)) {
				if (G_ReactionFireTryToShoot(shooter, target)) {
					G_ReactionFireTargetsAdvance(shooter, target, tus);
					fired |= true;
				}
			}
		}
	}
	return fired;
}
Beispiel #17
0
/**
 * @brief Applies morale changes to actors who find themselves in the general direction of a shot.
 * @param shooter The shooting actor.
 * @param fd The firedef used to shoot.
 * @param from The weapon's muzzle location.
 * @param weapon The weapon used to shoot.
 * @param impact The shoot's impact location.
 */
static void G_ShotMorale (const Actor* shooter, const fireDef_t* fd, const vec3_t from, const Item* weapon, const vec3_t impact)
{
	/* Skip not detectable shoots */
	if (weapon->def()->dmgtype == gi.csi->damLaser || fd->irgoggles)
		return;

	Actor* check = nullptr;
	const float minDist = UNIT_SIZE * 1.5f;
	while ((check = G_EdictsGetNextLivingActor(check))) {
		/* Skip yourself */
		if (check == shooter)
			continue;
		pos3_t target;
		VecToPos(impact, target);
		/* Skip the hit actor -- morale was already handled */
		if (check->isSamePosAs(target))
			continue;
		vec3_t dir1, dir2;
		VectorSubtract(check->origin, from, dir1);
		VectorSubtract(impact, from, dir2);
		const float len1 = VectorLength(dir1);
		const float len2 = VectorLength(dir2);
		const float dot = DotProduct(dir1, dir2);
		if (dot / (len1 * len2) < 0.7f)
			continue;
		/* Skip if shooting next or over an ally */
		if (check->isSameTeamAs(shooter) && VectorDistSqr(check->origin, shooter->origin)
				<= minDist * minDist)
			continue;
		vec3_t vec1;
		if (len1 > len2) {
			VectorSubtract(dir2, dir1, vec1);
		} else {
			VectorScale(dir2, dot / (len2 * len2), vec1);
			VectorSubtract(dir1, vec1, vec1);
		}
		const float morDist = (check->isSamePosAs(target) ? UNIT_SIZE * 0.5f : minDist);
		if (VectorLengthSqr(vec1) <= morDist * morDist) {
			/* @todo Add a visibility check here? */
			G_Morale(ML_SHOOT, check, shooter, fd->damage[0]);
		}
	}
}
Beispiel #18
0
/**
 * @brief Check all entities to see whether target has caused reaction fire to resolve.
 * @param[in] target The entity that might be resolving reaction fire
 * @returns whether any entity fired (or would fire) upon target
 * @sa G_ReactionFireOnMovement
 * @sa G_ReactionFirePostShot
 */
static qboolean G_ReactionFireCheckExecution (const edict_t *target)
{
	edict_t *ent = NULL;
	qboolean fired = qfalse;

	/* check all possible shooters */
	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		if (ent->reactionTarget) {
			const int reactionTargetTU = ent->reactionTarget->TU;
			const int reactionTU = ent->reactionTUs;
			const qboolean timeout = g_reaction_fair->integer == 0 || reactionTargetTU < reactionTU;
			/* check whether target has changed (i.e. the player is making a move with a
			 * different entity) or whether target is out of time. */
			if (ent->reactionTarget != target || timeout)
				fired |= G_ReactionFireTryToShoot(ent);
		}
	}
	return fired;
}
Beispiel #19
0
/**
 * @brief Check all entities to see whether target has caused reaction fire to resolve.
 * @param[in] target The entity that might be resolving reaction fire
 * @param[in] step The number of the step in the move we are checking reactions for
 * @returns whether any entity fired (or would fire) upon target
 * @sa G_ReactionFireOnMovement
 * @sa G_ReactionFirePostShot
 */
bool ReactionFire::checkExecution (const Edict* target, int step)
{
	Actor* shooter = nullptr;
	bool fired = false;

	/* check all possible shooters */
	while ((shooter = G_EdictsGetNextLivingActor(shooter))) {
		const int tus = G_ReactionFireGetTUsForItem(shooter, target);
		/* indicates an RF weapon is there */
		if (tus <= 1)
			continue;
		if (!rft.hasExpired(shooter, target, 0))
			continue;
		if (!rf.tryToShoot(shooter, target)) {
			G_ReactionFireNotifyClientRFAborted(shooter, target, step);
			continue;
		}
		rft.advance(shooter, tus);
		fired |= true;
	}
	return fired;
}
Beispiel #20
0
/**
 * @brief Called when 'target' is about to shoot, this forces a 'draw' to decide who gets the first shot
 * @param[in] target The entity about to shoot
 * @param[in] fdTime The TU of the shoot
 * @sa G_ClientShoot
 */
void G_ReactionFirePreShot (const edict_t *target, const int fdTime)
{
	edict_t *ent = NULL;

	/* Check to see whether this triggers any reaction fire */
	G_ReactionFireSearchTarget(target);

	/* check all ents to see who wins and who loses a draw */
	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		int entTUs;

		if (!ent->reactionTarget)
			continue;

		/* check this ent hasn't already lost the draw */
		if (ent->reactionNoDraw)
			continue;

		/* can't reaction fire if no TUs to fire */
		entTUs = G_ReactionFireGetTUsForItem(ent, target, RIGHT(ent));
		if (entTUs < 0) {
			ent->reactionTarget = NULL;
			continue;
		}

		/* see who won */
		if (entTUs >= fdTime) {
			/* target wins, so delay ent */
			/* ent can't lose the TU battle again */
			ent->reactionNoDraw = qtrue;
		} else {
			/* ent wins so take the shot */
			G_ReactionFireTryToShoot(ent);
		}
	}
}
Beispiel #21
0
/**
 * @brief Handles the end of a match
 * @param[in] team The winning team number
 * @param[in] nextmap Is there a follow-up map within the same match ?
 * @sa G_RunFrame
 * @sa CL_ParseResults
 */
static void G_MatchSendResults (int team, bool nextmap)
{
	Edict* attacker = nullptr;
	Actor* actor = nullptr;
	/* Calculate new scores/skills for the soldiers. */
	while ((actor = G_EdictsGetNextLivingActor(actor))) {
		if (!G_IsAI(actor))
			G_UpdateCharacterExperience(actor);
		else if (actor->getTeam() == team)
			attacker = actor;
	}

	/* if aliens won, make sure every soldier that is not in the rescue zone dies */
	if (team == TEAM_ALIEN) {
		actor = nullptr;
		while ((actor = G_EdictsGetNextLivingActor(actor)))
			if (actor->getTeam() != team && !actor->isInRescueZone()) {
				actor->HP = 0;
				G_ActorDieOrStun(actor, attacker);
			}
	}

	G_VisMakeEverythingVisible();

	/* send results */
	G_EventAdd(PM_ALL, EV_RESULTS, -1);
	gi.WriteByte(MAX_TEAMS);
	gi.WriteByte(team);
	gi.WriteByte(nextmap);

	for (int i = 0; i < MAX_TEAMS; i++) {
		gi.WriteByte(level.num_spawned[i]);
		gi.WriteByte(level.num_alive[i]);
	}

	for (int i = 0; i <= MAX_TEAMS; i++)
		for (int j = 0; j < MAX_TEAMS; j++)
			gi.WriteByte(level.num_kills[i][j]);

	for (int i = 0; i <= MAX_TEAMS; i++)
		for (int j = 0; j < MAX_TEAMS; j++)
			gi.WriteByte(level.num_stuns[i][j]);

	/* how many actors */
	int n  = 0;
	actor = nullptr;
	while ((actor = G_EdictsGetNextActor(actor)))
		if (!G_IsAI(actor))
			n++;

	/* number of soldiers */
	gi.WriteByte(n);

	if (n) {
		actor = nullptr;
		while ((actor = G_EdictsGetNextActor(actor))) {
			if (!G_IsAI(actor)) {
				G_SendCharacterData(actor);
			}
		}
	}

	G_EventEnd();
}
Beispiel #22
0
/**
 * @brief Applies morale changes to actors around a wounded or killed actor.
 * @note only called when mor_panic is not zero
 * @param[in] type Type of morale modifier (@sa morale_modifiers)
 * @param[in] victim An actor being a victim of the attack.
 * @param[in] attacker An actor being attacker in this attack.
 * @param[in] param Used to modify morale changes, for G_Damage() it is value of damage.
 * @sa G_Damage
 */
static void G_Morale (morale_modifiers type, const Edict* victim, const Edict* attacker, int param)
{
	Actor* actor = nullptr;
	while ((actor = G_EdictsGetNextLivingActor(actor))) {
		/* this only applies to ET_ACTOR but not ET_ACTOR2x2 */
		if (actor->type != ET_ACTOR)
			continue;
		if (G_IsCivilian(actor))
			continue;

		/* morale damage depends on the damage */
		float mod = mob_wound->value * param;
		if (type == ML_SHOOT)
			mod *= mob_shoot->value;
		/* death hurts morale even more than just damage */
		if (type == ML_DEATH)
			mod += mob_death->value;
		/* seeing how someone gets shot increases the morale change */
		if (actor == victim || (G_FrustumVis(actor, victim->origin) && G_ActorVis(actor, victim, false)))
			mod *= mof_watching->value;
		if (attacker != nullptr && actor->isSameTeamAs(attacker)) {
			/* teamkills are considered to be bad form, but won't cause an increased morale boost for the enemy */
			/* morale boost isn't equal to morale loss (it's lower, but morale gets regenerated) */
			if (victim->isSameTeamAs(attacker))
				mod *= mof_teamkill->value;
			else
				mod *= mof_enemy->value;
		}
		/* seeing a civilian die is more "acceptable" */
		if (G_IsCivilian(victim))
			mod *= mof_civilian->value;
		/* if an ally (or in singleplayermode, as human, a civilian) got shot, lower the morale, don't heighten it. */
		if (victim->isSameTeamAs(actor) || (G_IsCivilian(victim) && !G_IsAlien(actor) && G_IsSinglePlayer()))
			mod *= -1;
		if (attacker != nullptr) {
			/* if you stand near to the attacker or the victim, the morale change is higher. */
			mod *= mor_default->value + pow(0.5f, VectorDist(actor->origin, victim->origin) / mor_distance->value)
				* mor_victim->value + pow(0.5f, VectorDist(actor->origin, attacker->origin) / mor_distance->value)
				* mor_attacker->value;
		} else {
			mod *= mor_default->value + pow(0.5f, VectorDist(actor->origin, victim->origin) / mor_distance->value)
				* mor_victim->value;
		}
		/* morale damage depends on the number of living allies */
		mod *= (1 - mon_teamfactor->value)
			+ mon_teamfactor->value * (level.num_spawned[victim->getTeam()] + 1)
			/ (level.num_alive[victim->getTeam()] + 1);
		/* being hit isn't fun */
		if (actor == victim)
			mod *= mor_pain->value;
		/* clamp new morale */
		/*+0.9 to allow weapons like flamethrowers to inflict panic (typecast rounding) */
		const int newMorale = actor->morale + (int) (MORALE_RANDOM(mod) + 0.9);
		if (newMorale > GET_MORALE(actor->chr.score.skills[ABILITY_MIND]))
			actor->setMorale(GET_MORALE(actor->chr.score.skills[ABILITY_MIND]));
		else if (newMorale < 0)
			actor->setMorale(0);
		else
			actor->setMorale(newMorale);

		/* send phys data */
		G_SendStats(*actor);
	}
}
Beispiel #23
0
/**
 * @brief Returns what the actor can see.
 */
static int AIL_see (lua_State *L)
{
	int vision, team;
	int i, j, k, n, cur;
	edict_t *check = NULL;
	aiActor_t target;
	edict_t *sorted[MAX_EDICTS], *unsorted[MAX_EDICTS];
	float distLookup[MAX_EDICTS];

	/* Defaults. */
	team = TEAM_ALL;
	vision = 0;

	/* Handle parameters. */
	if ((lua_gettop(L) > 0)) {
		/* Get what to "see" with. */
		if (lua_isstring(L, 1)) {
			const char *s = lua_tostring(L, 1);
			/** @todo Properly implement at edict level, get rid of magic numbers.
			 * These are only "placeholders". */
			if (Q_streq(s, "all"))
				vision = 0;
			else if (Q_streq(s, "sight"))
				vision = 1;
			else if (Q_streq(s, "psionic"))
				vision = 2;
			else if (Q_streq(s, "infrared"))
				vision = 3;
			else
				AIL_invalidparameter(1);
		} else
			AIL_invalidparameter(1);

		/* We now check for different teams. */
		if ((lua_gettop(L) > 1)) {
			if (lua_isstring(L, 2)) {
				const char *s = lua_tostring(L, 2);
				team = AIL_toTeamInt(s);
			} else
				AIL_invalidparameter(2);
		}
	}

	n = 0;
	/* Get visible things. */
	while ((check = G_EdictsGetNextLivingActor(check))) {
		if (AIL_ent == check)
			continue;
		if (vision == 0 && (team == TEAM_ALL || check->team == team) /* Check for team match if needed. */
		 && G_Vis(AIL_ent->team, AIL_ent, check, VT_NOFRUSTUM)) {
			distLookup[n] = VectorDistSqr(AIL_ent->pos, check->pos);
			unsorted[n++] = check;
		}
	}

	/* Sort by distance - nearest first. */
	for (i = 0; i < n; i++) { /* Until we fill sorted */
		cur = -1;
		for (j = 0; j < n; j++) { /* Check for closest */
			/* Is shorter then current minimum? */
			if (cur < 0 || distLookup[j] < distLookup[cur]) {
				/* Check if not already in sorted. */
				for (k = 0; k < i; k++)
					if (sorted[k] == unsorted[j])
						break;

				/* Not already sorted and is new minimum. */
				if (k == i)
					cur = j;
			}
		}

		sorted[i] = unsorted[cur];
	}

	/* Now save it in a Lua table. */
	lua_newtable(L);
	for (i = 0; i < n; i++) {
		lua_pushnumber(L, i + 1); /* index, starts with 1 */
		target.ent = sorted[i];
		lua_pushactor(L, &target); /* value */
		lua_rawset(L, -3); /* store the value in the table */
	}
	return 1; /* Returns the table of actors. */
}
Beispiel #24
0
/**
 * @brief Handles the end of a match
 * @param[in] team The winning team number
 * @param[in] nextmap Is there a follow-up map within the same match ?
 * @sa G_RunFrame
 * @sa CL_ParseResults
 */
static void G_MatchSendResults (int team, bool nextmap)
{
	edict_t *ent, *attacker;
	int i, j = 0;

	attacker = NULL;
	ent = NULL;
	/* Calculate new scores/skills for the soldiers. */
	while ((ent = G_EdictsGetNextLivingActor(ent))) {
		if (!G_IsAI(ent))
			G_UpdateCharacterExperience(ent);
		else if (ent->team == team)
			attacker = ent;
	}

	/* if aliens won, make sure every soldier that is not in the rescue zone dies */
	if (team == TEAM_ALIEN) {
		ent = NULL;
		while ((ent = G_EdictsGetNextLivingActor(ent)))
			if (ent->team != team && !G_ActorIsInRescueZone(ent)) {
				ent->HP = 0;
				G_ActorDieOrStun(ent, attacker);
			}
	}

	G_VisMakeEverythingVisible();

	/* send results */
	G_EventAdd(PM_ALL, EV_RESULTS, -1);
	gi.WriteByte(MAX_TEAMS);
	gi.WriteByte(team);
	gi.WriteByte(nextmap);

	for (i = 0; i < MAX_TEAMS; i++) {
		gi.WriteByte(level.num_spawned[i]);
		gi.WriteByte(level.num_alive[i]);
	}

	for (i = 0; i <= MAX_TEAMS; i++)
		for (j = 0; j < MAX_TEAMS; j++)
			gi.WriteByte(level.num_kills[i][j]);

	for (i = 0; i <= MAX_TEAMS; i++)
		for (j = 0; j < MAX_TEAMS; j++)
			gi.WriteByte(level.num_stuns[i][j]);

	/* how many actors */
	j = 0;
	ent = NULL;
	while ((ent = G_EdictsGetNextActor(ent)))
		if (!G_IsAI(ent))
			j++;

	/* number of soldiers */
	gi.WriteByte(j);

	if (j) {
		ent = NULL;
		while ((ent = G_EdictsGetNextActor(ent))) {
			if (!G_IsAI(ent)) {
				G_SendCharacterData(ent);
			}
		}
	}

	G_EventEnd();
}
Beispiel #25
0
/**
 * @brief Prints all mission-score entries of all team members.
 * @note Console command: debug_listscore
 */
static void G_ListMissionScore_f (void)
{
    int team = -1;
    edict_t *ent = NULL;
    int i, j;

    /* With a parameter we will be able to get the info for a specific team */
    if (gi.Cmd_Argc() == 2) {
        team = atoi(gi.Cmd_Argv(1));
    } else {
        gi.DPrintf("Usage: %s <teamnumber>\n", gi.Cmd_Argv(0));
        return;
    }

    while ((ent = G_EdictsGetNextLivingActor(ent))) {
        if (team >= 0 && ent->team != team)
            continue;

        assert(ent->chr.scoreMission);

        gi.DPrintf("Soldier: %s\n", ent->chr.name);

        /* ===================== */
        gi.DPrintf("  Move: Normal=%i Crouched=%i\n", ent->chr.scoreMission->movedNormal, ent->chr.scoreMission->movedCrouched);

        gi.DPrintf("  Kills:");
        for (i = 0; i < KILLED_NUM_TYPES; i++) {
            gi.DPrintf(" %i", ent->chr.scoreMission->kills[i]);
        }
        gi.DPrintf("\n");

        gi.DPrintf("  Stuns:");
        for (i = 0; i < KILLED_NUM_TYPES; i++) {
            gi.DPrintf(" %i", ent->chr.scoreMission->stuns[i]);
        }
        gi.DPrintf("\n");

        /* ===================== */
        gi.DPrintf("  Fired:");
        for (i = 0; i < SKILL_NUM_TYPES; i++) {
            gi.DPrintf(" %i", ent->chr.scoreMission->fired[i]);
        }
        gi.DPrintf("\n");

        gi.DPrintf("  Hits:\n");
        for (i = 0; i < SKILL_NUM_TYPES; i++) {
            gi.DPrintf("    Skill%i: ",i);
            for (j = 0; j < KILLED_NUM_TYPES; j++) {
                gi.DPrintf(" %i", ent->chr.scoreMission->hits[i][j]);
            }
            gi.DPrintf("\n");
        }

        /* ===================== */
        gi.DPrintf("  Fired Splash:");
        for (i = 0; i < SKILL_NUM_TYPES; i++) {
            gi.DPrintf(" %i", ent->chr.scoreMission->firedSplash[i]);
        }
        gi.DPrintf("\n");

        gi.DPrintf("  Hits Splash:\n");
        for (i = 0; i < SKILL_NUM_TYPES; i++) {
            gi.DPrintf("    Skill%i: ",i);
            for (j = 0; j < KILLED_NUM_TYPES; j++) {
                gi.DPrintf(" %i", ent->chr.scoreMission->hitsSplash[i][j]);
            }
            gi.DPrintf("\n");
        }

        gi.DPrintf("  Splash Damage:\n");
        for (i = 0; i < SKILL_NUM_TYPES; i++) {
            gi.DPrintf("    Skill%i: ",i);
            for (j = 0; j < KILLED_NUM_TYPES; j++) {
                gi.DPrintf(" %i", ent->chr.scoreMission->hitsSplashDamage[i][j]);
            }
            gi.DPrintf("\n");
        }

        /* ===================== */
        gi.DPrintf("  Kills per skill:");
        for (i = 0; i < SKILL_NUM_TYPES; i++) {
            gi.DPrintf(" %i", ent->chr.scoreMission->skillKills[i]);
        }
        gi.DPrintf("\n");

        /* ===================== */
        gi.DPrintf("  Heal (received): %i\n", ent->chr.scoreMission->heal);
    }
}