Beispiel #1
0
/**
 * @sa G_MoraleStopPanic
 * @sa G_MoraleRage
 * @sa G_MoraleStopRage
 * @sa G_MoraleBehaviour
 */
static void G_MoralePanic (edict_t * ent, qboolean sanity)
{
	G_ClientPrintf(G_PLAYER_FROM_ENT(ent), PRINT_HUD, _("%s panics!\n"), ent->chr.name);

	/* drop items in hands */
	if (!sanity && ent->chr.teamDef->weapons) {
		if (RIGHT(ent))
			G_ActorInvMove(ent, INVDEF(gi.csi->idRight), RIGHT(ent),
					INVDEF(gi.csi->idFloor), NONE, NONE, qtrue);
		if (LEFT(ent))
			G_ActorInvMove(ent, INVDEF(gi.csi->idLeft), LEFT(ent),
					INVDEF(gi.csi->idFloor), NONE, NONE, qtrue);
	}

	/* get up */
	G_RemoveCrouched(ent);
	G_ActorSetMaxs(ent);

	/* send panic */
	G_SetPanic(ent);
	G_EventSendState(G_VisToPM(ent->visflags), ent);

	/* center view */
	G_EventCenterView(ent);

	/* move around a bit, try to avoid opponents */
	AI_ActorThink(G_PLAYER_FROM_ENT(ent), ent);

	/* kill TUs */
	G_ActorSetTU(ent, 0);
}
Beispiel #2
0
/**
 * @sa G_MoraleStopPanic
 * @sa G_MoraleRage
 * @sa G_MoraleStopRage
 * @sa G_MoraleBehaviour
 */
static void G_MoralePanic (Edict* ent)
{
	G_ClientPrintf(ent->getPlayer(), PRINT_HUD, _("%s panics!"), ent->chr.name);
	G_PrintStats("%s panics (entnum %i).", ent->chr.name, ent->getIdNum());
	/* drop items in hands */
	if (G_IsInsane(ent) && ent->chr.teamDef->weapons) {
		if (ent->getRightHandItem())
			G_ActorInvMove(ent, INVDEF(CID_RIGHT), ent->getRightHandItem(),
					INVDEF(CID_FLOOR), NONE, NONE, true);
		if (ent->getLeftHandItem())
			G_ActorInvMove(ent, INVDEF(CID_LEFT), ent->getLeftHandItem(),
					INVDEF(CID_FLOOR), NONE, NONE, true);
		G_ClientStateChange(ent->getPlayer(), ent, ~STATE_REACTION, false);
	}

	/* get up */
	G_RemoveCrouched(ent);
	G_ActorSetMaxs(ent);

	/* send panic */
	G_SetPanic(ent);
	G_EventSendState(G_VisToPM(ent->visflags), *ent);

	/* center view */
	G_EventCenterView(*ent);

	/* move around a bit, try to avoid opponents */
	AI_ActorThink(ent->getPlayer(), ent);

	/* kill TUs */
	G_ActorSetTU(ent, 0);
}
Beispiel #3
0
/**
 * @brief Stops the rage state of an actor
 * @note This is only called when cvar mor_panic is not zero
 * @sa G_MoralePanic
 * @sa G_MoraleRage
 * @sa G_MoraleStopPanic
 * @sa G_MoraleBehaviour
 */
static void G_MoraleStopRage (edict_t * ent)
{
	if (ent->morale / mor_panic->value > m_rage_stop->value * frand()) {
		G_RemoveInsane(ent);
		G_EventSendState(G_VisToPM(ent->visflags), ent);
	} else
		G_MoralePanic(ent, qtrue); /* regains sanity */
}
Beispiel #4
0
/**
 * @brief Applies morale behaviour on actors
 * @note only called when mor_panic is not zero
 * @sa G_MoralePanic
 * @sa G_MoraleRage
 * @sa G_MoraleStopRage
 * @sa G_MoraleStopPanic
 */
void G_MoraleBehaviour (int team)
{
	edict_t *ent = NULL;
	int newMorale;

	while ((ent = G_EdictsGetNextInUse(ent))) {
		/* this only applies to ET_ACTOR but not to ET_ACTOR2x2 */
		if (ent->type == ET_ACTOR && ent->team == team && !G_IsDead(ent)) {
			/* civilians have a 1:1 chance to randomly run away in multiplayer */
			if (sv_maxclients->integer >= 2 && level.activeTeam == TEAM_CIVILIAN && 0.5 > frand())
				G_MoralePanic(ent, qfalse);
			/* multiplayer needs enabled sv_enablemorale */
			/* singleplayer has this in every case */
			if (G_IsMoraleEnabled()) {
				/* if panic, determine what kind of panic happens: */
				if (ent->morale <= mor_panic->value && !G_IsPaniced(ent) && !G_IsRaged(ent)) {
					qboolean sanity;
					if ((float) ent->morale / mor_panic->value > (m_sanity->value * frand()))
						sanity = qtrue;
					else
						sanity = qfalse;
					if ((float) ent->morale / mor_panic->value > (m_rage->value * frand()))
						G_MoralePanic(ent, sanity);
					else
						G_MoraleRage(ent, sanity);
					/* if shaken, well .. be shaken; */
				} else if (ent->morale <= mor_shaken->value && !G_IsPaniced(ent)
						&& !G_IsRaged(ent)) {
					/* shaken is later reset along with reaction fire */
					G_SetShaken(ent);
					G_SetState(ent, STATE_REACTION);
					G_EventSendState(G_VisToPM(ent->visflags), ent);
					G_ClientPrintf(G_PLAYER_FROM_ENT(ent), PRINT_HUD, _("%s is currently shaken.\n"),
							ent->chr.name);
				} else {
					if (G_IsPaniced(ent))
						G_MoraleStopPanic(ent);
					else if (G_IsRaged(ent))
						G_MoraleStopRage(ent);
				}
			}

			G_ActorSetMaxs(ent);

			/* morale-regeneration, capped at max: */
			newMorale = ent->morale + MORALE_RANDOM(mor_regeneration->value);
			if (newMorale > GET_MORALE(ent->chr.score.skills[ABILITY_MIND]))
				ent->morale = GET_MORALE(ent->chr.score.skills[ABILITY_MIND]);
			else
				ent->morale = newMorale;

			/* send phys data and state: */
			G_SendStats(ent);
			gi.EndEvents();
		}
	}
}
Beispiel #5
0
/**
 * @brief Stops the panic state of an actor
 * @note This is only called when cvar mor_panic is not zero
 * @sa G_MoralePanic
 * @sa G_MoraleRage
 * @sa G_MoraleStopRage
 * @sa G_MoraleBehaviour
 */
static void G_MoraleStopPanic (Edict *ent)
{
	if (ent->morale / mor_panic->value > m_panic_stop->value * frand()) {
		G_RemovePanic(ent);
		G_PrintStats("%s is no longer panicked (entnum %i).", ent->chr.name, ent->number);
		G_EventSendState(G_VisToPM(ent->visflags), *ent);
	} else {
		G_MoralePanic(ent, true);
	}
}
Beispiel #6
0
/**
 * @brief Stops the rage state of an actor
 * @note This is only called when cvar mor_panic is not zero
 * @sa G_MoralePanic
 * @sa G_MoraleRage
 * @sa G_MoraleStopPanic
 * @sa G_MoraleBehaviour
 */
static void G_MoraleStopRage (Edict *ent)
{
	if (ent->morale / mor_panic->value > m_rage_stop->value * frand()) {
		G_RemoveInsane(ent);
		G_EventSendState(G_VisToPM(ent->visflags), *ent);
		G_PrintStats("%s is no longer insane (entnum %i).", ent->chr.name, ent->number);
	} else {
		G_MoralePanic(ent, true); /* regains sanity */
	}
}
Beispiel #7
0
/**
 * @brief Applies morale behaviour on actors
 * @note only called when mor_panic is not zero
 * @sa G_MoralePanic
 * @sa G_MoraleRage
 * @sa G_MoraleStopRage
 * @sa G_MoraleStopPanic
 */
void G_MoraleBehaviour (int team)
{
	bool enabled = G_IsMoraleEnabled(team);
	if (!enabled)
		return;

	Edict* ent = nullptr;
	while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, team)) != nullptr) {
		/* this only applies to ET_ACTOR but not to ET_ACTOR2x2 */
		if (ent->type != ET_ACTOR || CHRSH_IsTeamDefRobot(ent->chr.teamDef))
			continue;

		/* if panic, determine what kind of panic happens: */
		if (!G_IsPanicked(ent) && !G_IsRaged(ent)) {
			if (ent->morale <= mor_panic->integer) {
				const float ratio = (float) ent->morale / mor_panic->value;
				const bool sanity = ratio > (m_sanity->value * frand());
				if (!sanity)
					G_SetInsane(ent);
				if (ratio > (m_rage->value * frand()))
					G_MoralePanic(ent);
				else
					G_MoraleRage(ent);
				/* if shaken, well .. be shaken; */
			} else if (ent->morale <= mor_shaken->integer) {
				/* shaken is later reset along with reaction fire */
				G_SetShaken(ent);
				G_ClientStateChange(ent->getPlayer(), ent, STATE_REACTION, false);
				G_EventSendState(G_VisToPM(ent->visflags), *ent);
				G_ClientPrintf(ent->getPlayer(), PRINT_HUD, _("%s is currently shaken."),
						ent->chr.name);
				G_PrintStats("%s is shaken (entnum %i).", ent->chr.name, ent->getIdNum());
			}
		} else {
			if (G_IsPanicked(ent))
				G_MoraleStopPanic(ent);
			else if (G_IsRaged(ent))
				G_MoraleStopRage(ent);
		}

		G_ActorSetMaxs(ent);

		/* morale-regeneration, capped at max: */
		int newMorale = ent->morale + MORALE_RANDOM(mor_regeneration->value);
		const int maxMorale = GET_MORALE(ent->chr.score.skills[ABILITY_MIND]);
		if (newMorale > maxMorale)
			ent->morale = maxMorale;
		else
			ent->morale = newMorale;

		/* send phys data and state: */
		G_SendStats(*ent);
	}
}
Beispiel #8
0
/**
 * @sa G_MoralePanic
 * @sa G_MoraleStopPanic
 * @sa G_MoraleStopRage
 * @sa G_MoraleBehaviour
 */
static void G_MoraleRage (edict_t * ent, qboolean sanity)
{
	if (sanity)
		G_SetRage(ent);
	else
		G_SetInsane(ent);
	G_EventSendState(G_VisToPM(ent->visflags), ent);

	if (sanity)
		gi.BroadcastPrintf(PRINT_HUD, _("%s is on a rampage.\n"), ent->chr.name);
	else
		gi.BroadcastPrintf(PRINT_HUD, _("%s is consumed by mad rage!\n"), ent->chr.name);
	AI_ActorThink(G_PLAYER_FROM_ENT(ent), ent);
}
Beispiel #9
0
/**
 * @sa G_MoralePanic
 * @sa G_MoraleStopPanic
 * @sa G_MoraleStopRage
 * @sa G_MoraleBehaviour
 */
static void G_MoraleRage (Edict* ent)
{
	G_SetRage(ent);
	if (!G_IsInsane(ent)) {
		gi.BroadcastPrintf(PRINT_HUD, _("%s is on a rampage!"), ent->chr.name);
		G_PrintStats("%s is on a rampage (entnum %i).", ent->chr.name, ent->getIdNum());
	} else {
		gi.BroadcastPrintf(PRINT_HUD, _("%s is consumed by mad rage!"), ent->chr.name);
		G_PrintStats("%s is consumed by mad rage (entnum %i).", ent->chr.name, ent->getIdNum());
	}
	G_EventSendState(G_VisToPM(ent->visflags), *ent);
	G_ClientStateChange(ent->getPlayer(), ent, ~STATE_REACTION, false);

	AI_ActorThink(ent->getPlayer(), ent);
}
Beispiel #10
0
/**
 * @sa G_MoralePanic
 * @sa G_MoraleStopPanic
 * @sa G_MoraleStopRage
 * @sa G_MoraleBehaviour
 */
static void G_MoraleRage (edict_t *ent, bool sanity)
{
	if (sanity) {
		G_SetRage(ent);
		gi.BroadcastPrintf(PRINT_HUD, _("%s is on a rampage!"), ent->chr.name);
		G_PrintStats("%s is on a rampage (entnum %i).", ent->chr.name, ent->number);
	} else {
		G_SetInsane(ent);
		gi.BroadcastPrintf(PRINT_HUD, _("%s is consumed by mad rage!"), ent->chr.name);
		G_PrintStats("%s is consumed by mad rage (entnum %i).", ent->chr.name, ent->number);
	}
	G_EventSendState(G_VisToPM(ent->visflags), ent);

	AI_ActorThink(G_PLAYER_FROM_ENT(ent), ent);
}
Beispiel #11
0
/**
 * @brief After an actor changed his state, he might get visible for other
 * players. Check the vis here and send the state change to the clients that
 * are seeing him already.
 * @param ent The actor edict
 */
static void G_ClientStateChangeUpdate (edict_t *ent)
{
	/* Send the state change. */
	G_EventSendState(G_VisToPM(ent->visflags), ent);

	/* Check if the player appears/perishes, seen from other teams. */
	G_CheckVis(ent);

	/* Calc new vis for this player. */
	G_CheckVisTeamAll(ent->team, 0, ent);

	/* Send the new TUs. */
	G_SendStats(ent);

	/* End the event. */
	G_EventEnd();
}
Beispiel #12
0
/**
 * @brief Updates the reaction fire settings in case something was moved into a hand or from a hand
 * that would make the current settings invalid
 * @param[in,out] actor The actor edict to check the settings for
 * @param[in] fmIdx The fire mode index that should be used for reaction fire
 * @param[in] hand The hand that should be used for reaction fire
 * @param[in] od The object/weapon for the reaction fire
 */
void G_ReactionFireSettingsUpdate (Actor* actor, fireDefIndex_t fmIdx, actorHands_t hand, const objDef_t* od)
{
	actor->chr.RFmode.set(hand, fmIdx, od);	/* FiremodeSettings */

	if (!G_ActorHasWorkingFireModeSet(actor)) {
		/* Disable reaction fire if no valid firemode was found. */
		G_ClientStateChange(actor->getPlayer(), actor, ~STATE_REACTION, false);
		G_EventReactionFireChange(*actor);
		G_EventSendState(G_VisToPM(actor->visflags), *actor);
		return;
	}

	G_EventReactionFireChange(*actor);

	/* If reaction fire is active, update the reserved TUs */
	if (actor->isReaction()) {
		G_ReactionFireSettingsReserveTUs(actor);
	}
}
Beispiel #13
0
/**
 * @brief Deals damage of a give type and amount to a target.
 * @param[in,out] target What we want to damage.
 * @param[in] fd The fire definition that defines what type of damage is dealt.
 * @param[in] damage The value of the damage.
 * @param[in] attacker The attacker.
 * @param[in] mock pseudo shooting - only for calculating mock values - nullptr for real shots
 * @param[in] impact impact location - @c nullptr for splash damage
 * @return @c true if damage could be dealt (even if it was 0) @c false otherwise
 * @sa G_SplashDamage
 * @sa G_TakeDamage
 * @sa G_PrintActorStats
 */
static bool G_Damage (Edict* target, const fireDef_t* fd, int damage, Actor* attacker, shot_mock_t* mock, const vec3_t impact)
{
	assert(target);

	const bool stunEl = (fd->obj->dmgtype == gi.csi->damStunElectro);
	const bool stunGas = (fd->obj->dmgtype == gi.csi->damStunGas);
	const bool shock = (fd->obj->dmgtype == gi.csi->damShock);
	const bool smoke = (fd->obj->dmgtype == gi.csi->damSmoke);

	/* Breakables */
	if (G_IsBrushModel(target) && G_IsBreakable(target)) {
		/* Breakables are immune to stun & shock damage. */
		if (stunEl || stunGas || shock || mock || smoke)
			return false;

		if (damage >= target->HP) {
			/* don't reset the HP value here, this value is used to distinguish
			 * between triggered destroy and a shoot */
			assert(target->destroy);
			target->destroy(target);

			/* maybe the attacker is seeing something new? */
			G_CheckVisTeamAll(attacker->getTeam(), 0, attacker);

			/* check if attacker appears/perishes for any other team */
			G_CheckVis(attacker);
		} else {
			G_TakeDamage(target, damage);
		}
		return true;
	}

	/* Actors don't die again. */
	if (!G_IsLivingActor(target))
		return false;
	/* Now we know that the target is an actor */
	Actor* victim = makeActor(target);

	/* only actors after this point - and they must have a teamdef */
	assert(victim->chr.teamDef);
	const bool isRobot = CHRSH_IsTeamDefRobot(victim->chr.teamDef);

	/* Apply armour effects. */
	if (damage > 0) {
		damage = G_ApplyProtection(victim, fd->dmgweight, damage);
	} else if (damage < 0) {
		/* Robots can't be healed. */
		if (isRobot)
			return false;
	}
	Com_DPrintf(DEBUG_GAME, " Total damage: %d\n", damage);

	/* Apply difficulty settings. */
	if (G_IsSinglePlayer()) {
		if (G_IsAlien(attacker) && !G_IsAlien(victim))
			damage *= pow(1.18f, g_difficulty->value);
		else if (!G_IsAlien(attacker) && G_IsAlien(victim))
			damage *= pow(1.18f, -g_difficulty->value);
	}

	assert(attacker->getTeam() >= 0 && attacker->getTeam() < MAX_TEAMS);
	assert(victim->getTeam() >= 0 && victim->getTeam() < MAX_TEAMS);

	if ((g_nodamage != nullptr && !g_nodamage->integer) || mock) {
		/* hit */
		if (mock) {
			G_UpdateShotMock(mock, attacker, victim, damage);
		} else if (stunEl) {
			victim->addStun(damage);
		} else if (stunGas) {
			if (!isRobot) /* Can't stun robots with gas */
				victim->addStun(damage);
		} else if (shock) {
			/* Only do this if it's not one from our own team ... they should have known that there was a flashbang coming. */
			if (!isRobot && !victim->isSameTeamAs(attacker)) {
				/** @todo there should be a possible protection, too */
				/* dazed entity wont reaction fire */
				victim->removeReaction();
				G_ActorReserveTUs(victim, 0, victim->chr.reservedTus.shot, victim->chr.reservedTus.crouch);
				/* flashbangs kill TUs */
				G_ActorSetTU(victim, 0);
				G_SendStats(*victim);
				/* entity is dazed */
				victim->setDazed();
				G_EventSendState(G_VisToPM(victim->visflags), *victim);
				return !mock;
			} else {
				return false;
			}
		} else {
			if (damage < 0) {
				/* The 'attacker' is healing the victim. */
				G_TreatActor(victim, fd, damage, attacker->getTeam());
			} else {
				/* Real damage was dealt. */
				G_DamageActor(victim, damage, impact);
				/* Update overall splash damage for stats/score. */
				if (!mock && damage > 0 && fd->splrad) /**< Check for >0 and splrad to not count this as direct hit. */
					G_UpdateHitScore(attacker, victim, fd, damage);
			}
		}
	}

	if (mock)
		return false;

	G_CheckDeathOrKnockout(victim, attacker, fd, damage);
	return true;
}