예제 #1
0
/**
 * @brief Touch trigger
 * @sa SP_trigger_touch
 */
static bool Touch_TouchTrigger (Edict* self, Edict* activator)
{
	/* these actors should really not be able to trigger this - they don't move anymore */
	assert(!G_IsDead(activator));

	self->_owner = G_EdictsFindTargetEntity(self->target);
	if (!self->owner()) {
		gi.DPrintf("Target '%s' wasn't found for %s\n", self->target, self->classname);
		G_FreeEdict(self);
		return false;
	}

	if (self->owner()->flags & FL_CLIENTACTION) {
		G_ActorSetClientAction(activator, self->owner());
	} else if (!(self->spawnflags & TRIGGER_TOUCH_ONCE) || self->touchedNext == nullptr) {
		if (!self->owner()->use) {
			gi.DPrintf("Owner of %s doesn't have a use function\n", self->classname);
			G_FreeEdict(self);
			return false;
		}
		G_UseEdict(self->owner(), activator);
	}

	return false;
}
예제 #2
0
/*
* G_ClientEndSnapFrame
* 
* Called for each player at the end of the server frame
* and right after spawning
*/
void G_ClientEndSnapFrame( edict_t *ent )
{
	gclient_t *client;
	int i;

	if( trap_GetClientState( PLAYERNUM( ent ) ) < CS_SPAWNED )
		return;

	client = ent->r.client;

	// set fov
	if( !client->ps.pmove.stats[PM_STAT_ZOOMTIME] )
		client->ps.fov = ent->r.client->fov;
	else
	{
		float frac = (float)client->ps.pmove.stats[PM_STAT_ZOOMTIME] / (float)ZOOMTIME;
		client->ps.fov = client->fov - ( (float)( client->fov - client->zoomfov ) * frac );
	}

	// If the end of unit layout is displayed, don't give
	// the player any normal movement attributes
	if( GS_MatchState() >= MATCH_STATE_POSTMATCH )
	{
		G_SetClientStats( ent );
	}
	else
	{
		if( G_IsDead( ent ) && !level.gametype.customDeadBodyCam )
		{
			G_Client_DeadView( ent );
		}

		G_PlayerWorldEffects( ent ); // burn from lava, etc
		G_ClientDamageFeedback( ent ); // show damage taken along the snap
		G_SetClientStats( ent );
		G_SetClientEffects( ent );
		G_SetClientSound( ent );
		G_SetClientFrame( ent );

		client->ps.plrkeys = client->resp.snap.plrkeys;
	}

	G_ReleaseClientPSEvent( client );

	// set the delta angle
	for( i = 0; i < 3; i++ )
		client->ps.pmove.delta_angles[i] = ANGLE2SHORT( client->ps.viewangles[i] ) - client->ucmd.angles[i];

	// this is pretty hackish. We exploit the fact that servers *do not* transmit
	// origin2/old_origin for ET_PLAYER/ET_CORPSE entities, and we use it for sending the player velocity
	if( !G_ISGHOSTING( ent ) )
	{
		ent->r.svflags |= SVF_TRANSMITORIGIN2;
		VectorCopy( ent->velocity, ent->s.origin2 );
	}
	else
		ent->r.svflags &= ~SVF_TRANSMITORIGIN2;
}
예제 #3
0
/**
 * @brief Check whether ent can reaction fire at target, i.e. that it can see it and neither is dead etc.
 * @param[in] ent The entity that might be firing
 * @param[in] target The entity that might be fired at
 * @return @c true if 'ent' can actually fire at 'target', @c false otherwise
 */
static bool G_ReactionFireIsPossible (const edict_t *ent, const edict_t *target)
{
	float actorVis;
	bool frustum;

	/* an entity can't reaction fire at itself */
	if (ent == target)
		return false;

	/* Don't react in your own turn */
	if (ent->team == level.activeTeam)
		return false;

	/* ent can't use RF if is in STATE_DAZED (flashbang impact) */
	if (G_IsDazed(ent))
		return false;

	if (G_IsDead(target))
		return false;

	/* check ent has reaction fire enabled */
	if (!G_IsShaken(ent) && !G_IsReaction(ent))
		return false;

	/* check ent has weapon in RF hand */
	/* @todo Should this situation even happen when G_IsReaction(ent) is true? */
	if (!ACTOR_GET_INV(ent, ent->chr.RFmode.hand)) {
		/* print character info if this happens, for now */
		gi.DPrintf("Reaction fire enabled but no weapon for hand (name=%s,hand=%i,fmIdx=%i)\n",
				ent->chr.name, ent->chr.RFmode.hand, ent->chr.RFmode.fmIdx);
		return false;
	}

	if (!G_IsVisibleForTeam(target, ent->team))
		return false;

	/* If reaction fire is triggered by a friendly unit
	 * and the shooter is still sane, don't shoot;
	 * well, if the shooter isn't sane anymore... */
	if (G_IsCivilian(target) || target->team == ent->team)
		if (!G_IsShaken(ent) || (float) ent->morale / mor_shaken->value > frand())
			return false;

	/* check in range and visible */
	if (VectorDistSqr(ent->origin, target->origin) > MAX_SPOT_DIST * MAX_SPOT_DIST)
		return false;

	frustum = G_FrustumVis(ent, target->origin);
	if (!frustum)
		return false;

	actorVis = G_ActorVis(ent->origin, ent, target, true);
	if (actorVis <= 0.2)
		return false;

	/* okay do it then */
	return true;
}
예제 #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();
		}
	}
}
예제 #5
0
/**
 * @brief Check whether ent can reaction fire at target, i.e. that it can see it and neither is dead etc.
 * @param[in] ent The entity that might be firing
 * @param[in] target The entity that might be fired at
 * @return @c true if 'ent' can actually fire at 'target', @c false otherwise
 */
static bool G_ReactionFireIsPossible (Edict *ent, const Edict *target)
{
	/* an entity can't reaction fire at itself */
	if (ent == target)
		return false;

	/* Don't react in your own turn */
	if (ent->team == level.activeTeam)
		return false;

	/* ent can't use RF if is in STATE_DAZED (flashbang impact) */
	if (G_IsDazed(ent))
		return false;

	if (G_IsDead(target))
		return false;

	/* check ent has reaction fire enabled */
	if (!G_IsReaction(ent))
		return false;

	/* check ent has weapon in RF hand */
	if (!ent->getHandItem(ent->chr.RFmode.getHand())) {
		/* print character info if this happens, for now */
		gi.DPrintf("Reaction fire enabled but no weapon for hand (name=%s,entnum=%i,hand=%i,fmIdx=%i)\n",
				ent->chr.name, ent->number, ent->chr.RFmode.getHand(), ent->chr.RFmode.getFmIdx());
		G_RemoveReaction(ent);
		return false;
	}

	if (!G_IsVisibleForTeam(target, ent->team))
		return false;

	/* If reaction fire is triggered by a friendly unit
	 * and the shooter is still sane, don't shoot;
	 * well, if the shooter isn't sane anymore... */
	if (G_IsCivilian(target) || target->team == ent->team)
		if (!G_IsShaken(ent) || (float) ent->morale / mor_shaken->value > frand())
			return false;

	/* check in range and visible */
	const int spotDist = G_VisCheckDist(ent);
	if (VectorDistSqr(ent->origin, target->origin) > spotDist * spotDist)
		return false;

	const bool frustum = G_FrustumVis(ent, target->origin);
	if (!frustum)
		return false;

	const float actorVis = G_ActorVis(ent->origin, ent, target, true);
	if (actorVis <= 0.2)
		return false;

	/* okay do it then */
	return true;
}
예제 #6
0
파일: g_vis.cpp 프로젝트: ArkyRomania/ufoai
/**
 * @brief test if check is visible by from
 * @param[in] team Living team members are always visible. If this is a negative
 * number we inverse the team rules (see comments included). In combination with VT_NOFRUSTUM
 * we can check whether there is any edict (that is no in our team) that can see @c check
 * @param[in] from is from team @c team and must be a living actor
 * @param[in] check The edict we want to get the visibility for
 * @param[in] flags @c VT_NOFRUSTUM, ...
 */
bool G_Vis (const int team, const Edict* from, const Edict* check, const vischeckflags_t flags)
{
	vec3_t eye;

	/* if any of them isn't in use, then they're not visible */
	if (!from->inuse || !check->inuse)
		return false;

	/* only actors and 2x2 units can see anything */
	if (!G_IsLivingActor(from) && !G_IsActiveCamera(from))
		return false;

	/* living team members are always visible */
	if (team >= 0 && check->getTeam() == team && !G_IsDead(check))
		return true;

	/* standard team rules */
	if (team >= 0 && from->getTeam() != team)
		return false;

	/* inverse team rules */
	if (team < 0 && check->getTeam() == -team)
		return false;

	/* check for same pos */
	if (VectorCompare(from->pos, check->pos))
		return true;

	if (!G_IsVisibleOnBattlefield(check))
		return false;

	/* view distance check */
	const int spotDist = G_VisCheckDist(from);
	if (VectorDistSqr(from->origin, check->origin) > spotDist * spotDist)
		return false;

	/* view frustum check */
	if (!(flags & VT_NOFRUSTUM) && !G_FrustumVis(from, check->origin))
		return false;

	/* get viewers eye height */
	G_ActorGetEyeVector(from, eye);

	/* line trace check */
	switch (check->type) {
	case ET_ACTOR:
	case ET_ACTOR2x2:
		return G_ActorVis(eye, from, check, false) > ACTOR_VIS_0;
	case ET_ITEM:
	case ET_CAMERA:
	case ET_PARTICLE:
		return !G_LineVis(eye, check->origin);
	default:
		return false;
	}
}
예제 #7
0
/**
 * @brief Rescue trigger
 * @sa SP_trigger_resuce
 */
static bool Touch_RescueTrigger (Edict* self, Edict* activator)
{
	/* these actors should really not be able to trigger this - they don't move anymore */
	assert(!G_IsDead(activator));

	if (self->team == activator->team)
		G_ActorSetInRescueZone(activator, true);

	return false;
}
예제 #8
0
파일: g_mission.cpp 프로젝트: chagara/ufoai
static bool G_MissionIsTouched (Edict* self) {
	linkedList_t* touched = self->touchedList;
	while (touched) {
		const Edict* const ent = static_cast<const Edict* const>(touched->data);
		if (self->isSameTeamAs(ent) && !G_IsDead(ent))
			return true;
		touched = touched->next;
	}
	return false;
}
예제 #9
0
파일: g_awards.c 프로젝트: j0ki/racesow
void G_AwardResetPlayerComboStats( edict_t *ent )
{
    int i;
    int resetvalue;

    // combo from LB can be cancelled only if player's dead, if he missed or if he hasnt shot with LB for too long
    resetvalue = ( G_IsDead( ent ) ? 0 : COMBO_FLAG( WEAP_LASERGUN ) );

    for( i = 0; i < gs.maxclients; i++ )
        game.clients[i].resp.awardInfo.combo[PLAYERNUM( ent )] &= resetvalue;
}
예제 #10
0
파일: p_hud.cpp 프로젝트: Picmip/qfusion
static unsigned int G_FindPointedPlayer( edict_t *self ) {
	trace_t trace;
	int i, j, bestNum = 0;
	vec3_t boxpoints[8];
	float value, dist, value_best = 0.90f;   // if nothing better is found, print nothing
	edict_t *other;
	vec3_t vieworg, dir, viewforward;

	if( G_IsDead( self ) ) {
		return 0;
	}

	// we can't handle the thirdperson modifications in server side :/
	VectorSet( vieworg, self->r.client->ps.pmove.origin[0], self->r.client->ps.pmove.origin[1], self->r.client->ps.pmove.origin[2] + self->r.client->ps.viewheight );
	AngleVectors( self->r.client->ps.viewangles, viewforward, NULL, NULL );

	for( i = 0; i < gs.maxclients; i++ ) {
		other = PLAYERENT( i );
		if( !other->r.inuse ) {
			continue;
		}
		if( !other->r.client ) {
			continue;
		}
		if( other == self ) {
			continue;
		}
		if( !other->r.solid || ( other->r.svflags & SVF_NOCLIENT ) ) {
			continue;
		}

		VectorSubtract( other->s.origin, self->s.origin, dir );
		dist = VectorNormalize2( dir, dir );
		if( dist > 1000 ) {
			continue;
		}

		value = DotProduct( dir, viewforward );

		if( value > value_best ) {
			BuildBoxPoints( boxpoints, other->s.origin, tv( 4, 4, 4 ), tv( 4, 4, 4 ) );
			for( j = 0; j < 8; j++ ) {
				G_Trace( &trace, vieworg, vec3_origin, vec3_origin, boxpoints[j], self, MASK_SHOT | MASK_OPAQUE );
				if( trace.ent && trace.ent == ENTNUM( other ) ) {
					value_best = value;
					bestNum = ENTNUM( other );
				}
			}
		}
	}

	return bestNum;
}
예제 #11
0
/**
 * @brief Sets correct bounding box for actor (state dependent).
 * @param[in] ent Pointer to entity for which bounding box is being set.
 * @note Also re-links the actor edict - because the server must know about the
 * changed bounding box for tracing to work.
 */
void G_ActorSetMaxs (Edict* ent)
{
	if (G_IsCrouched(ent))
		VectorSet(ent->entBox.maxs, PLAYER_WIDTH, PLAYER_WIDTH, PLAYER_CROUCH);
	else if (G_IsDead(ent) && !CHRSH_IsTeamDefRobot(ent->chr.teamDef))
		VectorSet(ent->entBox.maxs, PLAYER_WIDTH, PLAYER_WIDTH, PLAYER_DEAD);
	else
		VectorSet(ent->entBox.maxs, PLAYER_WIDTH, PLAYER_WIDTH, PLAYER_STAND);

	/* Link it. */
	gi.LinkEdict(ent);
}
예제 #12
0
/**
 * @brief Rescue trigger
 * @sa SP_trigger_resuce
 */
static bool Touch_RescueTrigger (Edict* self, Edict* activator)
{
	/* these actors should really not be able to trigger this - they don't move anymore */
	assert(!G_IsDead(activator));

	if (G_IsActor(activator)) {
		Actor* actor = makeActor(activator);
		if (self->isSameTeamAs(actor))
			actor->setInRescueZone(true);
	}

	return false;
}
예제 #13
0
파일: g_reaction.c 프로젝트: kevlund/ufoai
/**
 * @brief Check whether ent can reaction fire at target, i.e. that it can see it and neither is dead etc.
 * @param[in] ent The entity that might be firing
 * @param[in] target The entity that might be fired at
 * @return @c true if 'ent' can actually fire at 'target', @c false otherwise
 */
static qboolean G_ReactionFireIsPossible (const edict_t *ent, const edict_t *target)
{
	float actorVis;
	qboolean frustum;

	/* an entity can't reaction fire at itself */
	if (ent == target)
		return qfalse;

	/* Don't react in your own turn */
	if (ent->team == level.activeTeam)
		return qfalse;

	/* ent can't use RF if is in STATE_DAZED (flashbang impact) */
	if (G_IsDazed(ent))
		return qfalse;

	if (G_IsDead(target))
		return qfalse;

	/* check ent has reaction fire enabled */
	if (!G_IsShaken(ent) && !G_IsReaction(ent))
		return qfalse;

	if (!G_IsVisibleForTeam(target, ent->team))
		return qfalse;

	/* If reaction fire is triggered by a friendly unit
	 * and the shooter is still sane, don't shoot;
	 * well, if the shooter isn't sane anymore... */
	if (G_IsCivilian(target) || target->team == ent->team)
		if (!G_IsShaken(ent) || (float) ent->morale / mor_shaken->value > frand())
			return qfalse;

	/* check in range and visible */
	if (VectorDistSqr(ent->origin, target->origin) > MAX_SPOT_DIST * MAX_SPOT_DIST)
		return qfalse;

	frustum = G_FrustumVis(ent, target->origin);
	if (!frustum)
		return qfalse;

	actorVis = G_ActorVis(ent->origin, target, qtrue);
	if (actorVis <= 0.2)
		return qfalse;

	/* okay do it then */
	return qtrue;
}
예제 #14
0
static bool G_ActorStun (Edict* ent, const Edict* attacker)
{
	/* already dead or stunned? */
	if (G_IsDead(ent))
		return false;

	/* no other state should be set here */
	ent->state = STATE_STUN;
	G_ActorSetMaxs(ent);
	ent->link = attacker;

	G_ActorModifyCounters(attacker, ent, -1, 0, 1);

	return true;
}
예제 #15
0
/*
* G_SetClientEffects
*/
static void G_SetClientEffects( edict_t *ent )
{
	gclient_t *client = ent->r.client;

	if( G_IsDead( ent ) || GS_MatchState() >= MATCH_STATE_POSTMATCH )
		return;

	if( client->ps.inventory[POWERUP_QUAD] > 0 )
	{
		ent->s.effects |= EF_QUAD;
		if( client->ps.inventory[POWERUP_QUAD] < 6 )
			ent->s.effects |= EF_EXPIRING_QUAD;
	}

	if( client->ps.inventory[POWERUP_SHELL] > 0 )
	{
		ent->s.effects |= EF_SHELL;
		if( client->ps.inventory[POWERUP_SHELL] < 6 )
			ent->s.effects |= EF_EXPIRING_SHELL;			
	}

	if( client->ps.inventory[POWERUP_REGEN] > 0 )
	{
		ent->s.effects |= EF_REGEN;
		if( client->ps.inventory[POWERUP_REGEN] < 6 )
			ent->s.effects |= EF_EXPIRING_REGEN;			
	}

	if( ent->s.weapon )
	{
		firedef_t *firedef = GS_FiredefForPlayerState( &client->ps, ent->s.weapon );
		if( firedef && firedef->fire_mode == FIRE_MODE_STRONG )
			ent->s.effects |= EF_STRONG_WEAPON;
	}

	if( client->ps.pmove.stats[PM_STAT_STUN] )
		ent->s.effects |= EF_PLAYER_STUNNED;
	else
		ent->s.effects &= ~EF_PLAYER_STUNNED;

	// show cheaters!!!
	if( ent->flags & FL_GODMODE )
		ent->s.effects |= EF_GODMODE;

	// add chatting icon effect
	if( ent->r.client->resp.snap.buttons & BUTTON_BUSYICON )
		ent->s.effects |= EF_BUSYICON;
}
예제 #16
0
/**
 * @brief Update character stats for this mission after successful shoot.
 * @note Mind you that this code is always from the view of PHALANX soldiers right now, not anybody else!
 * @param[in,out] attacker Pointer to attacker.
 * @param[in] fd Pointer to fireDef_t used in shoot.
 * @param[in] target Pointer to target.
 * @sa G_UpdateCharacterSkills
 */
static void G_UpdateCharacterBodycount (edict_t *attacker, const fireDef_t *fd, const edict_t *target)
{
	chrScoreMission_t *scoreMission;
	chrScoreGlobal_t *scoreGlobal;
	killtypes_t type;

	if (!attacker || !target)
		return;

	scoreGlobal = &attacker->chr.score;
	scoreMission = attacker->chr.scoreMission;
	/* only phalanx soldiers have this */
	if (!scoreMission)
		return;

	switch (target->team) {
	case TEAM_ALIEN:
		type = KILLED_ENEMIES;
		if (fd) {
			assert(fd->weaponSkill >= 0);
			assert(fd->weaponSkill < lengthof(scoreMission->skillKills));
			scoreMission->skillKills[fd->weaponSkill]++;
		}
		break;
	case TEAM_CIVILIAN:
		type = KILLED_CIVILIANS;
		break;
	case TEAM_PHALANX:
		type = KILLED_TEAM;
		break;
	default:
		return;
	}

	if (G_IsStunned(target)) {
		scoreMission->stuns[type]++;
		scoreGlobal->stuns[type]++;
	} else if (G_IsDead(target)) {
		scoreMission->kills[type]++;
		scoreGlobal->kills[type]++;
	}
}
예제 #17
0
static bool G_ActorDie (Edict* ent, const Edict* attacker)
{
	const bool stunned = G_IsStunned(ent);

	G_RemoveStunned(ent);

	if (G_IsDead(ent))
		return false;

	G_SetState(ent, 1 + rand() % MAX_DEATH);
	G_ActorSetMaxs(ent);

	if (stunned) {
		G_ActorModifyCounters(attacker, ent, 0, 1, 0);
		G_ActorModifyCounters(ent->link, ent, 0, 0, -1);
	} else {
		G_ActorModifyCounters(attacker, ent, -1, 1, 0);
	}

	return true;
}
예제 #18
0
/**
 * @brief Function to calculate possible damages for mock pseudoaction.
 * @param[in,out] mock Pseudo action - only for calculating mock values - NULL 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_t *shooter, const edict_t *struck, int damage)
{
	assert(struck->number != shooter->number || mock->allow_self);

	if (damage > 0) {
		if (!struck->inuse || G_IsDead(struck))
			return;
		else if (!G_IsVisibleForTeam(struck, shooter->team))
			return;
		else if (G_IsCivilian(struck))
			mock->civilian += 1;
		else if (struck->team == shooter->team)
			mock->friendCount += 1;
		else if (G_IsActor(struck))
			mock->enemyCount += 1;
		else
			return;

		mock->damage += damage;
	}
}
예제 #19
0
/*
* G_CheckClientRespawnClick
*/
void G_CheckClientRespawnClick( edict_t *ent )
{
	if( !ent->r.inuse || !ent->r.client || !G_IsDead( ent ) )
		return;

	if( GS_MatchState() >= MATCH_STATE_POSTMATCH )
		return;

	if( trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED )
	{
		// if the spawnsystem doesn't require to click
		if( G_SpawnQueue_GetSystem( ent->s.team ) != SPAWNSYSTEM_INSTANT )
		{
			int minDelay = g_respawn_delay_min->integer;

			// waves system must wait for at least 500 msecs (to see the death, but very short for selfkilling tactics).
			if( G_SpawnQueue_GetSystem( ent->s.team ) == SPAWNSYSTEM_WAVES )
				minDelay = ( g_respawn_delay_min->integer < 500 ) ? 500 : g_respawn_delay_min->integer;

			// hold system must wait for at least 1000 msecs (to see the death properly)
			if( G_SpawnQueue_GetSystem( ent->s.team ) == SPAWNSYSTEM_HOLD )
				minDelay = ( g_respawn_delay_min->integer < 1300 ) ? 1300 : g_respawn_delay_min->integer;
				
			if( level.time >= ent->deathTimeStamp + minDelay )
				G_SpawnQueue_AddClient( ent );
		}
		// clicked
		else if( ent->r.client->resp.snap.buttons & BUTTON_ATTACK )
		{
			if( level.time > ent->deathTimeStamp + g_respawn_delay_min->integer )
				G_SpawnQueue_AddClient( ent );
		}
		// didn't click, but too much time passed
		else if( g_respawn_delay_max->integer && ( level.time > ent->deathTimeStamp + g_respawn_delay_max->integer ) )
		{
			G_SpawnQueue_AddClient( ent );
		}
	}
}
예제 #20
0
/**
 * @brief Check whether we want to shoot at the target.
 * @param[in] shooter The entity that might be firing
 * @param[in] target The entity that might be fired at
 */
bool ReactionFire::isEnemy (const Actor* shooter, const Edict* target) const
{
	/* an entity can't reaction fire at itself */
	if (shooter == target)
		return false;

	/* Don't react in your own turn */
	if (shooter->getTeam() == level.activeTeam)
		return false;

	if (G_IsDead(target))
		return false;

	/* If reaction fire is triggered by a friendly unit
	 * and the shooter is still sane, don't shoot;
	 * well, if the shooter isn't sane anymore... */
	if (G_IsCivilian(target) || target->isSameTeamAs(shooter))
		if (!shooter->isShaken() || (float) shooter->morale / mor_shaken->value > frand())
			return false;

	return true;
}
예제 #21
0
/**
 * @brief Checks whether the requested action is possible
 * @param[in] player Which player (human player) is trying to do the action
 * @param[in] ent Which of his units is trying to do the action.
 */
static bool G_ActionCheck (const player_t *player, edict_t *ent)
{
	/* don't check for a player - but maybe a server action */
	if (!player)
		return true;

	if (!ent || !ent->inuse) {
		G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - object not present!"));
		return false;
	}

	if (ent->type != ET_ACTOR && ent->type != ET_ACTOR2x2) {
		G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - not an actor!"));
		return false;
	}

	if (G_IsStunned(ent)) {
		G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - actor is stunned!"));
		return false;
	}

	if (G_IsDead(ent)) {
		G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - actor is dead!"));
		return false;
	}

	if (ent->team != player->pers.team) {
		G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - not on same team!"));
		return false;
	}

	if (ent->pnum != player->num) {
		G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - no control over allied actors!"));
		return false;
	}

	/* could be possible */
	return true;
}
예제 #22
0
/**
 * @brief Hurt trigger
 * @sa SP_trigger_hurt
 */
bool Touch_HurtTrigger (Edict* self, Edict* activator)
{
	const int damage = G_ApplyProtection(activator, self->dmgtype, self->dmg);
	const bool stunEl = (self->dmgtype == gi.csi->damStunElectro);
	const bool stunGas = (self->dmgtype == gi.csi->damStunGas);
	const bool shock = (self->dmgtype == gi.csi->damShock);
	const bool isRobot = activator->chr.teamDef->robot;

	/* these actors should really not be able to trigger this - they don't move anymore */
	if (G_IsDead(activator))
		return false;

	if (stunEl || (stunGas && !isRobot)) {
		activator->STUN += damage;
	} else if (shock) {
		/** @todo Handle dazed via trigger_hurt */
	} else {
		G_TakeDamage(activator, damage);
	}

	return true;
}
예제 #23
0
파일: g_mission.cpp 프로젝트: chagara/ufoai
void G_MissionReset (Edict* self, Edict* activator)
{
	/* Don't reset the mission timer for 'bring item' missions G_MissionThink will handle that */
	if (!self->time || self->item)
		return;
	linkedList_t* touched = self->touchedList;
	while (touched) {
		const Edict* const ent = static_cast<const Edict* const>(touched->data);
		if (self->isSameTeamAs(ent) && !(G_IsDead(ent) || ent == activator)) {
			return;
		}
		touched = touched->next;
	}
	if (activator->getTeam() == self->getTeam()) {
		const char* const actTeam = G_MissionGetTeamString(activator->getTeam());
		if (self->targetname)
			gi.BroadcastPrintf(PRINT_HUD, _("%s forces have left the %s!"), actTeam, self->targetname);
		else
			gi.BroadcastPrintf(PRINT_HUD, _("%s forces have left their target zone!"), actTeam);
	}
	/* All team actors are gone, reset counter */
	self->count = 0;
}
예제 #24
0
파일: g_clip.c 프로젝트: Kaperstone/warsow
/*
* GClip_TouchTriggers
*/
void GClip_TouchTriggers( edict_t *ent )
{
	int i, num;
	edict_t	*hit;
	int touch[MAX_EDICTS];
	vec3_t mins, maxs;

	// dead things don't activate triggers!
	if( ent->r.client && G_IsDead( ent ) )
		return;

	VectorAdd( ent->s.origin, ent->r.mins, mins );
	VectorAdd( ent->s.origin, ent->r.maxs, maxs );

	// FIXME: should be s.origin + mins and s.origin + maxs because of absmin and absmax padding?
	num = GClip_AreaEdicts( ent->r.absmin, ent->r.absmax, touch, MAX_EDICTS, AREA_TRIGGERS, 0 );

	// be careful, it is possible to have an entity in this
	// list removed before we get to it (killtriggered)
	for( i = 0; i < num; i++ )
	{
		if( !ent->r.inuse )
			break;

		hit = &game.edicts[touch[i]];
		if( !hit->r.inuse )
			continue;

		if( !hit->touch && !hit->asTouchFunc )
			continue;

		if( !hit->item && !GClip_EntityContact( mins, maxs, hit ) )
			continue;

		G_CallTouch( hit, ent, NULL, 0 );
	}
}
예제 #25
0
파일: g_combat.cpp 프로젝트: ufoai/ufoai
/**
 * @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;
}
예제 #26
0
파일: g_clip.c 프로젝트: Kaperstone/warsow
void G_PMoveTouchTriggers( pmove_t *pm )
{
	int i, num;
	edict_t	*hit;
	int touch[MAX_EDICTS];
	vec3_t mins, maxs;
	edict_t	*ent;

	if( pm->playerState->POVnum <= 0 || (int)pm->playerState->POVnum > gs.maxclients )
		return;

	ent = game.edicts + pm->playerState->POVnum;
	if( !ent->r.client || G_IsDead( ent ) )  // dead things don't activate triggers!
		return;

	// update the entity with the new position
	VectorCopy( pm->playerState->pmove.origin, ent->s.origin );
	VectorCopy( pm->playerState->pmove.velocity, ent->velocity );
	VectorCopy( pm->playerState->viewangles, ent->s.angles );
	ent->viewheight = pm->playerState->viewheight;
	VectorCopy( pm->mins, ent->r.mins );
	VectorCopy( pm->maxs, ent->r.maxs );

	ent->waterlevel = pm->waterlevel;
	ent->watertype = pm->watertype;
	if( pm->groundentity == -1 )
	{
		ent->groundentity = NULL;
	}
	else
	{
		ent->groundentity = &game.edicts[pm->groundentity];
		ent->groundentity_linkcount = ent->groundentity->r.linkcount;
	}

	GClip_LinkEntity( ent );

	VectorAdd( pm->playerState->pmove.origin, pm->mins, mins );
	VectorAdd( pm->playerState->pmove.origin, pm->maxs, maxs );

	num = GClip_AreaEdicts( mins, maxs, touch, MAX_EDICTS, AREA_TRIGGERS, 0 );

	// be careful, it is possible to have an entity in this
	// list removed before we get to it (killtriggered)
	for( i = 0; i < num; i++ )
	{
		if( !ent->r.inuse )
			break;

		hit = &game.edicts[touch[i]];
		if( !hit->r.inuse )
			continue;

		if( !hit->touch && !hit->asTouchFunc )
			continue;

		if( !hit->item && !GClip_EntityContact( mins, maxs, hit ) )
			continue;

		G_CallTouch( hit, ent, NULL, 0 );
	}
}
예제 #27
0
/**
 * @brief Generates the client events that are send over the netchannel to move an actor
 * @param[in] player Player who is moving an actor
 * @param[in] visTeam The team to check the visibility for - if this is 0 we build the forbidden list
 * above all edicts - for the human controlled actors this would mean that clicking to a grid
 * position that is not reachable because an invisible actor is standing there would not result in
 * a single step - as the movement is aborted before. For AI movement this is in general @c 0 - but
 * not if they e.g. hide.
 * @param[in] ent Edict to move
 * @param[in] to The grid position to walk to
 * @sa CL_ActorStartMove
 * @sa PA_MOVE
 */
void G_ClientMove (const player_t * player, int visTeam, edict_t* ent, const pos3_t to)
{
    int status, initTU;
    dvec_t dvtab[MAX_DVTAB];
    int dir;
    byte numdv, length;
    pos3_t pos;
    float div;
    int oldState;
    int oldHP;
    bool autoCrouchRequired = false;
    byte crouchingState;

    if (VectorCompare(ent->pos, to))
        return;

    /* check if action is possible */
    if (!G_ActionCheckForCurrentTeam(player, ent, TU_MOVE_STRAIGHT))
        return;

    crouchingState = G_IsCrouched(ent) ? 1 : 0;
    oldState = oldHP = 0;

    /* calculate move table */
    G_MoveCalc(visTeam, ent, ent->pos, crouchingState, ent->TU);
    length = gi.MoveLength(level.pathingMap, to, crouchingState, false);

    /* length of ROUTING_NOT_REACHABLE means not reachable */
    if (length && length >= ROUTING_NOT_REACHABLE)
        return;

    /* Autostand: check if the actor is crouched and player wants autostanding...*/
    if (crouchingState && player->autostand) {
        /* ...and if this is a long walk... */
        if (SHOULD_USE_AUTOSTAND(length)) {
            /* ...make them stand first. If the player really wants them to walk a long
             * way crouched, he can move the actor in several stages.
             * Uses the threshold at which standing, moving and crouching again takes
             * fewer TU than just crawling while crouched. */
            G_ClientStateChange(player, ent, STATE_CROUCHED, true); /* change to stand state */
            crouchingState = G_IsCrouched(ent) ? 1 : 0;
            if (!crouchingState) {
                G_MoveCalc(visTeam, ent, ent->pos, crouchingState, ent->TU);
                length = gi.MoveLength(level.pathingMap, to, crouchingState, false);
                autoCrouchRequired = true;
            }
        }
    }

    /* this let the footstep sounds play even over network */
    ent->think = G_PhysicsStep;
    ent->nextthink = level.time;

    /* assemble dvec-encoded move data */
    VectorCopy(to, pos);
    initTU = ent->TU;

    numdv = G_FillDirectionTable(dvtab, lengthof(dvtab), crouchingState, pos);

    /* make sure to end any other pending events - we rely on EV_ACTOR_MOVE not being active anymore */
    gi.EndEvents();

    /* everything ok, found valid route? */
    if (VectorCompare(pos, ent->pos)) {
        byte* stepAmount = NULL;
        int usedTUs = 0;
        /* no floor inventory at this point */
        FLOOR(ent) = NULL;

        while (numdv > 0) {
            /* A flag to see if we needed to change crouch state */
            int crouchFlag;
            const byte oldDir = ent->dir;
            int dvec;

            /* get next dvec */
            numdv--;
            dvec = dvtab[numdv];
            /* This is the direction to make the step into */
            dir = getDVdir(dvec);

            /* turn around first */
            status = G_ActorDoTurn(ent, dir);
            if (status & VIS_STOP) {
                autoCrouchRequired = false;
                if (ent->moveinfo.steps == 0)
                    usedTUs += TU_TURN;
                break;
            }

            if (G_ActorShouldStopInMidMove(ent, status, dvtab, numdv)) {
                /* don't autocrouch if new enemy becomes visible */
                autoCrouchRequired = false;
                /* if something appears on our route that didn't trigger a VIS_STOP, we have to
                 * send the turn event if this is our first step */
                if (oldDir != ent->dir && ent->moveinfo.steps == 0) {
                    G_EventActorTurn(ent);
                    usedTUs += TU_TURN;
                }
                break;
            }

            /* decrease TUs */
            div = gi.GetTUsForDirection(dir, G_IsCrouched(ent));
            if ((int) (usedTUs + div) > ent->TU)
                break;
            usedTUs += div;

            /* This is now a flag to indicate a change in crouching - we need this for
             * the stop in mid move call(s), because we need the updated entity position */
            crouchFlag = 0;
            /* Calculate the new position after the decrease in TUs, otherwise the game
             * remembers the false position if the time runs out */
            PosAddDV(ent->pos, crouchFlag, dvec);

            /* slower if crouched */
            if (G_IsCrouched(ent))
                ent->speed = ACTOR_SPEED_CROUCHED;
            else
                ent->speed = ACTOR_SPEED_NORMAL;
            ent->speed *= g_actorspeed->value;

            if (crouchFlag == 0) { /* No change in crouch */
                edict_t* clientAction;
                int contentFlags;
                vec3_t pointTrace;

                G_EdictCalcOrigin(ent);
                VectorCopy(ent->origin, pointTrace);
                pointTrace[2] += PLAYER_MIN;

                contentFlags = gi.PointContents(pointTrace);

                /* link it at new position - this must be done for every edict
                 * movement - to let the server know about it. */
                gi.LinkEdict(ent);

                /* Only the PHALANX team has these stats right now. */
                if (ent->chr.scoreMission) {
                    float truediv = gi.GetTUsForDirection(dir, 0);		/* regardless of crouching ! */
                    if (G_IsCrouched(ent))
                        ent->chr.scoreMission->movedCrouched += truediv;
                    else
                        ent->chr.scoreMission->movedNormal += truediv;
                }
                /* write the step to the net */
                G_WriteStep(ent, &stepAmount, dvec, contentFlags);

                /* check if player appears/perishes, seen from other teams */
                G_CheckVis(ent, true);

                /* check for anything appearing, seen by "the moving one" */
                status = G_CheckVisTeamAll(ent->team, false, ent);

                /* Set ent->TU because the reaction code relies on ent->TU being accurate. */
                G_ActorSetTU(ent, initTU - usedTUs);

                clientAction = ent->clientAction;
                oldState = ent->state;
                oldHP = ent->HP;
                /* check triggers at new position */
                if (G_TouchTriggers(ent)) {
                    if (!clientAction)
                        status |= VIS_STOP;
                }

                G_TouchSolids(ent, 10.0f);

                /* state has changed - maybe we walked on a trigger_hurt */
                if (oldState != ent->state)
                    status |= VIS_STOP;
                else if (oldHP != ent->HP)
                    status |= VIS_STOP;
            } else if (crouchFlag == 1) {
                /* Actor is standing */
                G_ClientStateChange(player, ent, STATE_CROUCHED, true);
            } else if (crouchFlag == -1) {
                /* Actor is crouching and should stand up */
                G_ClientStateChange(player, ent, STATE_CROUCHED, false);
            }

            /* check for reaction fire */
            if (G_ReactionFireOnMovement(ent)) {
                status |= VIS_STOP;

                autoCrouchRequired = false;
            }

            /* check for death */
            if (((oldHP != 0 && oldHP != ent->HP) || (oldState != ent->state)) && !G_IsDazed(ent)) {
                /** @todo Handle dazed via trigger_hurt */
                /* maybe this was due to rf - then the G_ActorDie was already called */
                if (!G_IsDead(ent)) {
                    G_CheckDeathOrKnockout(ent, NULL, NULL, oldHP - ent->HP);
                }
                return;
            }

            if (G_ActorShouldStopInMidMove(ent, status, dvtab, numdv - 1)) {
                /* don't autocrouch if new enemy becomes visible */
                autoCrouchRequired = false;
                break;
            }

            /* Restore ent->TU because the movement code relies on it not being modified! */
            G_ActorSetTU(ent, initTU);
        }

        /* submit the TUs / round down */
        if (g_notu != NULL && g_notu->integer)
            G_ActorSetTU(ent, initTU);
        else
            G_ActorSetTU(ent, initTU - usedTUs);

        G_SendStats(ent);

        /* end the move */
        G_GetFloorItems(ent);
        gi.EndEvents();
    }

    if (autoCrouchRequired) {
        /* toggle back to crouched state */
        G_ClientStateChange(player, ent, STATE_CROUCHED, true);
    }
}
예제 #28
0
파일: g_awards.c 프로젝트: j0ki/racesow
void G_AwardPlayerHit( edict_t *targ, edict_t *attacker, int mod )
{
    int flag = -1;

    if( attacker->s.team == targ->s.team && attacker->s.team > TEAM_PLAYERS )
        return;

    switch( mod )
    {
    case MOD_INSTAGUN_W:
    case MOD_INSTAGUN_S:
        attacker->r.client->resp.awardInfo.ebhit_count++;
        if( attacker->r.client->resp.awardInfo.ebhit_count == EBHIT_FOR_AWARD )
        {
            attacker->r.client->resp.awardInfo.ebhit_count = 0;
            attacker->r.client->resp.awardInfo.accuracy_award++;
            G_PlayerAward( attacker, S_COLOR_BLUE "Accuracy!" );
        }
        flag = COMBO_FLAG( WEAP_INSTAGUN );
        break;
    case MOD_ELECTROBOLT_W:
    case MOD_ELECTROBOLT_S:
        attacker->r.client->resp.awardInfo.ebhit_count++;
        if( attacker->r.client->resp.awardInfo.ebhit_count == EBHIT_FOR_AWARD )
        {
            attacker->r.client->resp.awardInfo.ebhit_count = 0;
            attacker->r.client->resp.awardInfo.accuracy_award++;
            G_PlayerAward( attacker, S_COLOR_BLUE "Accuracy!" );
        }
        flag = COMBO_FLAG( WEAP_ELECTROBOLT );
        break;
    case MOD_ROCKET_W:
    case MOD_ROCKET_S:
    case MOD_ROCKET_SPLASH_W:
    case MOD_ROCKET_SPLASH_S:
        flag = COMBO_FLAG( WEAP_ROCKETLAUNCHER );
        break;
    case MOD_GUNBLADE_W:
    case MOD_GUNBLADE_S:
        flag = COMBO_FLAG( WEAP_GUNBLADE );
        break;
    case MOD_MACHINEGUN_W:
    case MOD_MACHINEGUN_S:
        flag = COMBO_FLAG( WEAP_MACHINEGUN );
        break;
    case MOD_RIOTGUN_W:
    case MOD_RIOTGUN_S:
        flag = COMBO_FLAG( WEAP_RIOTGUN );
        break;
    case MOD_GRENADE_W:
    case MOD_GRENADE_S:
    case MOD_GRENADE_SPLASH_W:
    case MOD_GRENADE_SPLASH_S:
        flag = COMBO_FLAG( WEAP_GRENADELAUNCHER );
        break;
    case MOD_PLASMA_W:
    case MOD_PLASMA_S:
    case MOD_PLASMA_SPLASH_W:
    case MOD_PLASMA_SPLASH_S:
        flag = COMBO_FLAG( WEAP_PLASMAGUN );
        break;
    case MOD_LASERGUN_W:
    case MOD_LASERGUN_S:
        flag = COMBO_FLAG( WEAP_LASERGUN );
        break;
    default:
        break;
    }

    if( flag )
    {
        if( attacker->r.client->resp.awardInfo.combo[PLAYERNUM( targ )] == COMBO_FLAG( WEAP_ROCKETLAUNCHER ) && G_IsDead( targ ) ) // RL...
        {
            if( flag == COMBO_FLAG( WEAP_ELECTROBOLT ) )  // to EB
                G_PlayerAward( attacker, S_COLOR_BLUE "RL to EB!" );
            else if( flag == COMBO_FLAG( WEAP_LASERGUN ) )  // to LG
                G_PlayerAward( attacker, S_COLOR_BLUE "RL to LG!" );
            else if( flag == COMBO_FLAG( WEAP_RIOTGUN ) )  // to RG
                G_PlayerAward( attacker, S_COLOR_BLUE "RL to RG!" );
            else if( flag == COMBO_FLAG( WEAP_GRENADELAUNCHER ) )  // to GL
                G_PlayerAward( attacker, S_COLOR_BLUE "RL to GL!" );
            //else if( flag == COMBO_FLAG( WEAP_ROCKETLAUNCHER ) )  // to RL
            //	G_PlayerAward( attacker, S_COLOR_BLUE "RL to RL!" );
        }
        else if( attacker->r.client->resp.awardInfo.combo[PLAYERNUM( targ )] == COMBO_FLAG( WEAP_ROCKETLAUNCHER ) && G_IsDead( targ ) ) // GL...
        {
            if( flag == COMBO_FLAG( WEAP_ELECTROBOLT ) )  // to EB
                G_PlayerAward( attacker, S_COLOR_BLUE "GL to EB!" );
            else if( flag == COMBO_FLAG( WEAP_LASERGUN ) )  // to LG
                G_PlayerAward( attacker, S_COLOR_BLUE "GL to LG!" );
            else if( flag == COMBO_FLAG( WEAP_RIOTGUN ) )  // to RG
                G_PlayerAward( attacker, S_COLOR_BLUE "GL to RG!" );
            else if( flag == COMBO_FLAG( WEAP_ROCKETLAUNCHER ) )  // to RL
                G_PlayerAward( attacker, S_COLOR_BLUE "GL to RL!" );
            //else if( flag == COMBO_FLAG( WEAP_GRENADELAUNCHER ) )  // to GL
            //	G_PlayerAward( attacker, S_COLOR_BLUE "GL to GL!" );
        }
        else if( attacker->r.client->resp.awardInfo.combo[PLAYERNUM( targ )] == COMBO_FLAG( WEAP_LASERGUN ) && G_IsDead( targ ) ) // LG...
        {
            if( flag == COMBO_FLAG( WEAP_ELECTROBOLT ) )  // to EB
                if( attacker->r.client->resp.awardInfo.lasthit == targ && level.time < attacker->r.client->resp.awardInfo.lasthit_time + LB_TIMEOUT_FOR_COMBO )
                    G_PlayerAward( attacker, S_COLOR_BLUE "LG to EB!" );
        }
        else if( attacker->r.client->resp.awardInfo.combo[PLAYERNUM( targ )] == COMBO_FLAG( WEAP_GUNBLADE ) && G_IsDead( targ ) )
        {
            if( flag == COMBO_FLAG( WEAP_GUNBLADE ) )
                if( attacker->r.client->resp.awardInfo.lasthit == targ && level.time < attacker->r.client->resp.awardInfo.lasthit_time + GUNBLADE_TIMEOUT_FOR_COMBO )
                    G_PlayerAward( attacker, S_COLOR_BLUE "Gunblade Combo!" );
        }

        attacker->r.client->resp.awardInfo.combo[PLAYERNUM( targ )] = flag;
    }

    attacker->r.client->resp.awardInfo.lasthit = targ;
    attacker->r.client->resp.awardInfo.lasthit_time = level.time;
}
예제 #29
0
/*
* G_Teams_TDM_UpdateTeamInfoMessages
*/
void G_Teams_UpdateTeamInfoMessages( void )
{
	static int nexttime = 0;
	static char teammessage[MAX_STRING_CHARS];
	edict_t	*ent, *e;
	size_t len;
	int i, j, team;
	char entry[MAX_TOKEN_CHARS];
	int locationTag;

	nexttime -= game.snapFrameTime;
	if( nexttime > 0 )
		return;

	while( nexttime <= 0 )
		nexttime += 2000;

	// time for a new update

	for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
	{
		*teammessage = 0;
		Q_snprintfz( teammessage, sizeof( teammessage ), "ti \"" );
		len = strlen( teammessage );

		// add our team info to the string
		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			ent = game.edicts + teamlist[team].playerIndices[i];

			if( G_IsDead( ent ) )  // don't show dead players
				continue;

			if( ent->r.client->teamstate.is_coach )  // don't show coachs
				continue;

			// get location name
			locationTag = G_MapLocationTAGForOrigin( ent->s.origin );
			if( locationTag == -1 )
				continue;

			*entry = 0;

			Q_snprintfz( entry, sizeof( entry ), "%i %i %i %i ", PLAYERNUM( ent ), locationTag, HEALTH_TO_INT( ent->health ), ARMOR_TO_INT( ent->r.client->resp.armor ) );

			if( MAX_STRING_CHARS - len > strlen( entry ) )
			{
				Q_strncatz( teammessage, entry, sizeof( teammessage ) );
				len = strlen( teammessage );
			}
		}

		// add closing quote
		*entry = 0;
		Q_snprintfz( entry, sizeof( entry ), "\"" );
		if( MAX_STRING_CHARS - len > strlen( entry ) )
		{
			Q_strncatz( teammessage, entry, sizeof( teammessage ) );
			len = strlen( teammessage );
		}

		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			ent = game.edicts + teamlist[team].playerIndices[i];

			if( !ent->r.inuse || !ent->r.client )
				continue;

			trap_GameCmd( ent, teammessage );

			// see if there are spectators chasing this player and send them the layout too
			for( j = 0; j < teamlist[TEAM_SPECTATOR].numplayers; j++ )
			{
				e = game.edicts + teamlist[TEAM_SPECTATOR].playerIndices[j];

				if( !e->r.inuse || !e->r.client )
					continue;

				if( e->r.client->resp.chase.active && e->r.client->resp.chase.target == ENTNUM( ent ) )
					trap_GameCmd( e, teammessage );
			}
		}
	}
}
예제 #30
0
파일: g_mission.cpp 프로젝트: chagara/ufoai
/**
 * @brief Mission trigger
 * @todo use level.nextmap to spawn another map when every living actor has touched the mission trigger
 * @note Don't set a client action here - otherwise the movement event might
 * be corrupted
 */
bool G_MissionTouch (Edict* self, Edict* activator)
{
	if (!G_IsLivingActor(activator))
		return false;

	Actor* actor = makeActor(activator);
	const char* const actorTeam = G_MissionGetTeamString(actor->getTeam());
	if (!G_IsCivilian(actor) && self->isOpponent(actor)) {
		if (!self->item && self->count) {
			if (self->targetname) {
				gi.BroadcastPrintf(PRINT_HUD, _("%s forces are attacking the %s!"), actorTeam, self->targetname);
			} else {
				const char* const teamName = G_MissionGetTeamString(self->getTeam());
				gi.BroadcastPrintf(PRINT_HUD, _("%s forces are attacking %s target zone!"),
						actorTeam, teamName);
			}

			/* reset king of the hill counter */
			self->count = 0;
		}
		return false;
	}
	if (self->count)
		return false;

	if (self->isSameTeamAs(actor)) {
		self->count = level.actualRound;
		if (!self->item) {
			linkedList_t* touched = self->touchedList;
			while (touched) {
				const Edict* const ent = static_cast<const Edict* const>(touched->data);
				if (!self->isSameTeamAs(ent) && !G_IsDead(ent)) {
					return true;
				}
				touched = touched->next;
			}
			if (self->targetname) {
				gi.BroadcastPrintf(PRINT_HUD, _("%s forces have occupied the %s!"), actorTeam, self->targetname);
			} else {
				gi.BroadcastPrintf(PRINT_HUD, _("%s forces have occupied their target zone!"), actorTeam);
			}
			return true;
		}
	}

	/* search the item in the activator's inventory */
	/* ignore items linked from any temp container the actor must have this in his hands */
	const Container* cont = nullptr;
	while ((cont = actor->chr.inv.getNextCont(cont))) {
		Item* item = nullptr;
		while ((item = cont->getNextItem(item))) {
			const objDef_t* od = item->def();
			/* check whether we found the searched item in the actor's inventory */
			if (!Q_streq(od->id, self->item))
				continue;

			/* drop the weapon - even if out of TUs */
			G_ActorInvMove(actor, cont->def(), item, INVDEF(CID_FLOOR), NONE, NONE, false);
			if (self->targetname) {
				gi.BroadcastPrintf(PRINT_HUD, _("The %s was placed at the %s."), item->def()->name, self->targetname);
			} else {
				gi.BroadcastPrintf(PRINT_HUD, _("The %s was placed."), item->def()->name);
			}
			self->count = level.actualRound;
			return true;
		}
	}

	return false;
}