Exemplo n.º 1
0
/**
 * @param ent The actor to set the reaction fire for
 * @return @c true if the needed settings could have been made or settings are
 * already valid, @c false otherwise.
 */
static bool G_ReactionFireSetDefault (edict_t *ent)
{
	const objDef_t *weapon;
	const invList_t *invList;
	actorHands_t hand = ACTOR_HAND_RIGHT;

	if (G_ActorHasWorkingFireModeSet(ent))
		return true;

	invList = ACTOR_GET_INV(ent, hand);
	if (!invList) {
		hand = ACTOR_HAND_LEFT;
		invList = ACTOR_GET_INV(ent, hand);
	}

	weapon = INVSH_HasReactionFireEnabledWeapon(invList);
	if (!weapon)
		return false;

	ent->chr.RFmode.fmIdx = 0;
	ent->chr.RFmode.hand = hand;
	ent->chr.RFmode.weapon = weapon;

	if (!G_IsAI(ent))
		G_EventReactionFireChange(ent);

	return true;
}
Exemplo n.º 2
0
/**
 * @param ent The actor to set the reaction fire for
 * @return @c true if the needed settings could have been made or settings are
 * already valid, @c false otherwise.
 */
static bool G_ReactionFireSetDefault (edict_t *ent)
{
	if (G_ActorHasWorkingFireModeSet(ent))
		return true;

	actorHands_t hand = ACTOR_HAND_RIGHT;
	const invList_t *invList = ACTOR_GET_INV(ent, hand);
	if (!invList) {
		hand = ACTOR_HAND_LEFT;
		invList = ACTOR_GET_INV(ent, hand);
	}

	const objDef_t *weapon = INVSH_HasReactionFireEnabledWeapon(invList);
	if (!weapon)
		return false;

	ent->chr.RFmode.set(hand, 0, weapon);	/* no special firemode */

	if (!G_ActorHasWorkingFireModeSet(ent))
		return false;

	if (!G_IsAI(ent))
		G_EventReactionFireChange(ent);

	return true;
}
Exemplo n.º 3
0
/**
 * @brief Build the forbidden list for the pathfinding (server side).
 * @param[in] team The team number if the list should be calculated from the eyes of that team. Use 0 to ignore team.
 * @param[in] movingActor The moving actor to build the forbidden list for. If this is an AI actor, everything other actor will be
 * included in the forbidden list - even the invisible ones. This is needed to ensure that they are not walking into each other
 * (civilians <=> aliens, aliens <=> civilians)
 * @sa G_MoveCalc
 * @sa Grid_CheckForbidden
 * @sa CL_BuildForbiddenList <- shares quite some code
 * @note This is used for pathfinding.
 * It is a list of where the selected unit can not move to because others are standing there already.
 */
static void G_BuildForbiddenList (int team, const edict_t *movingActor)
{
    edict_t *ent = NULL;
    int visMask;

    forbiddenListLength = 0;

    /* team visibility */
    if (team)
        visMask = G_TeamToVisMask(team);
    else
        visMask = TEAM_ALL;

    while ((ent = G_EdictsGetNextInUse(ent))) {
        /* Dead 2x2 unit will stop walking, too. */
        if (G_IsBlockingMovementActor(ent) && (G_IsAI(movingActor) || (ent->visflags & visMask))) {
            forbiddenList[forbiddenListLength++] = ent->pos;
            forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize;
        } else if (ent->type == ET_SOLID) {
            int j;
            for (j = 0; j < ent->forbiddenListSize; j++) {
                forbiddenList[forbiddenListLength++] = ent->forbiddenListPos[j];
                forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize;
            }
        }
    }

    if (forbiddenListLength > MAX_FORBIDDENLIST)
        gi.Error("G_BuildForbiddenList: list too long\n");
}
Exemplo n.º 4
0
/**
 * @param ent The actor to set the reaction fire for
 * @return @c true if the needed settings could have been made or settings are
 * already valid, @c false otherwise.
 */
static bool G_ReactionFireSettingsSetDefault (Edict* ent)
{
	if (G_ActorHasWorkingFireModeSet(ent))
		return true;

	actorHands_t hand = ACTOR_HAND_RIGHT;
	const Item* item = ent->getHandItem(hand);
	if (!item) {
		hand = ACTOR_HAND_LEFT;
		item = ent->getHandItem(hand);
	}

	if (!item)
		return false;

	const objDef_t* weapon = item->getReactionFireWeaponType();
	if (!weapon)
		return false;

	ent->chr.RFmode.set(hand, 0, weapon);	/* no special firemode */

	if (!G_ActorHasWorkingFireModeSet(ent))
		return false;

	if (!G_IsAI(ent))
		G_EventReactionFireChange(*ent);

	return true;
}
Exemplo n.º 5
0
/**
 * @brief Trigger to open the door we are standing in front of it
 * @sa CL_DoorOpen
 * @sa LE_CloseOpen
 * @sa CL_ActorDoorAction
 * @sa AI_CheckUsingDoor
 */
static bool Touch_DoorTrigger (edict_t *self, edict_t *activator)
{
    if (self->owner && self->owner->inuse) {
        if (G_IsAI(activator)) {
            /* let the ai interact with the door */
            if (self->flags & FL_GROUPSLAVE)
                self = self->groupMaster;
            if (AI_CheckUsingDoor(activator, self->owner))
                G_ActorUseDoor(activator, self->owner);
            /* we don't want the client action stuff to be send for ai actors */
            return false;
        } else {
            /* prepare for client action */
            G_ActorSetClientAction(activator, self->owner);
            return true;
        }
    }
    return false;
}
Exemplo n.º 6
0
/**
 * @brief Make the actor use (as in open/close) a door edict
 * @note Will also check whether the door is still reachable (this might have
 * changed due to the rotation) after the usage
 * @param actor The actor that is using the door
 * @param door The door that should be opened/closed
 */
void G_ActorUseDoor (Edict* actor, Edict* door)
{
	/* check whether it's part of an edict group but not the master */
	if (door->flags & FL_GROUPSLAVE)
		door = door->groupMaster;

	if (!G_ClientUseEdict(actor->getPlayer(), actor, door))
		return;

	/* end this loop here, for the AI this is a) not interesting,
	 * and b) could result in endless loops */
	if (G_IsAI(actor))
		return;

	Edict* closeActor = nullptr;
	while ((closeActor = G_FindRadius(closeActor, door->origin, UNIT_SIZE * 3))) {
		/* check whether the door is still reachable (this might have
		 * changed due to the rotation) or whether an actor can reach it now */
		G_TouchTriggers(closeActor);
	}
}
Exemplo n.º 7
0
/**
 * @brief Function to calculate possible damages for mock pseudoaction.
 * @param[in,out] mock Pseudo action - only for calculating mock values - nullptr for real action.
 * @param[in] shooter Pointer to attacker for this mock pseudoaction.
 * @param[in] struck Pointer to victim of this mock pseudoaction.
 * @param[in] damage Updates mock value of damage.
 * @note Called only from G_Damage().
 * @sa G_Damage
 */
static void G_UpdateShotMock (shot_mock_t* mock, const Edict* shooter, const Edict* struck, int damage)
{
	assert(!struck->isSameAs(shooter) || mock->allow_self);

	if (damage <= 0)
		return;

	if (!struck->inuse || G_IsDead(struck))
		return;

	if (!G_IsAI(shooter) && !G_IsVisibleForTeam(struck, shooter->getTeam()))
		return;

	if (G_IsCivilian(struck))
		mock->civilian += 1;
	else if (struck->isSameTeamAs(shooter))
		mock->friendCount += 1;
	else if (G_IsActor(struck))
		mock->enemyCount += 1;
	else
		return;

	mock->damage += damage;
}
Exemplo n.º 8
0
/**
 * @sa G_PlayerSoldiersCount
 */
void G_ClientEndRound (Player& player)
{
	Player* p;

	const int lastTeamIndex = (G_GetActiveTeam() + level.teamOfs) % MAX_TEAMS;

	if (!G_IsAIPlayer(&player)) {
		/* inactive players can't end their inactive turn :) */
		if (level.activeTeam != player.getTeam())
			return;

		/* check for "team oszillation" */
		if (level.framenum < level.nextEndRound)
			return;

		level.nextEndRound = level.framenum + 20;
	}

	/* only use this for teamplay matches like coopX or fight2on2 and above
	 * also skip this for ai players, this is only called when all ai actors
	 * have finished their 'thinking' */
	if (!G_IsAIPlayer(&player) && sv_teamplay->integer) {
		/* check if all team members are ready */
		if (!player.roundDone) {
			player.roundDone = true;
			G_EventEndRoundAnnounce(player);
			G_EventEnd();
		}
		p = nullptr;
		while ((p = G_PlayerGetNextActiveHuman(p)))
			if (p->getTeam() == level.activeTeam && !p->roundDone && G_PlayerSoldiersCount(*p) > 0)
				return;
		p = nullptr;
		while ((p = G_PlayerGetNextActiveAI(p)))
			if (p->getTeam() == level.activeTeam && !p->roundDone && G_PlayerSoldiersCount(*p) > 0)
				return;
	} else {
		player.roundDone = true;
	}

	/* clear any remaining reaction fire */
	G_ReactionFireOnEndTurn();

	if (!G_IsAIPlayer(&player)) {
		if (g_lastseen->integer > 0) {
			Edict* ent = nullptr;
			while ((ent = G_EdictsGetNextActor(ent))) {
				if (G_IsAI(ent) && G_IsVisibleForTeam(ent, level.activeTeam)) {
					player.lastSeen = level.actualRound;
					break;
				}
			}
			if (level.actualRound - player.lastSeen > g_lastseen->integer) {
				Com_Printf("round end triggered by g_lastseen (player %i (team %i) last seen in round %i of %i rounds)\n",
						player.getNum(), level.activeTeam, player.lastSeen, level.actualRound);
				G_MatchEndTrigger(-1, 0);
			}
		}
	}

	/* let all the invisible players perish now */
	G_CheckVisTeamAll(level.activeTeam, VIS_APPEAR, nullptr);

	G_GetNextActiveTeam();

	AI_CheckRespawn(TEAM_ALIEN);

	/* no other team left? */
	if (!G_MatchIsRunning())
		return;

	if (lastTeamIndex > (level.activeTeam + level.teamOfs) % MAX_TEAMS)
		level.actualRound++;

	/* communicate next player in row to clients */
	G_EventEndRound();

	/* store the round start time to be able to abort the round after a give time */
	level.roundstartTime = level.time;

	/* Wounded team members bleed */
	G_BleedWounds(level.activeTeam);

	/* Update the state of stuned team-members. The actual statistics are sent below! */
	G_UpdateStunState(level.activeTeam);

	/* Give the actors of the now active team their TUs. */
	G_GiveTimeUnits(level.activeTeam);

	/* apply morale behaviour, reset reaction fire */
	G_ReactionFireReset(level.activeTeam);
	if (mor_panic->integer)
		G_MoraleBehaviour(level.activeTeam);

	G_UpdateCarriedWeight(level.activeTeam);

	/* start ai - there is only one player for ai teams, and the last pointer must only
	 * be updated for ai players */
	p = G_GetPlayerForTeam(level.activeTeam);
	if (p == nullptr)
		gi.Error("Could not find player for team %i", level.activeTeam);

	/* finish off events */
	G_EventEnd();

	/* reset ready flag for every player on the current team (even ai players) */
	p = nullptr;
	while ((p = G_PlayerGetNextActiveHuman(p))) {
		if (p->getTeam() == level.activeTeam) {
			p->roundDone = false;
		}
	}

	p = nullptr;
	while ((p = G_PlayerGetNextActiveAI(p))) {
		if (p->getTeam() == level.activeTeam) {
			p->roundDone = false;
		}
	}
}
Exemplo n.º 9
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();
}
Exemplo n.º 10
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();
}