void AlienBuildableComponent::HandleDie(gentity_t* killer, meansOfDeath_t meansOfDeath) {
	entity.oldEnt->powered = false;

	// Warn if in main base and there's an overmind.
	gentity_t *om;
	if ((om = G_ActiveOvermind()) && om != entity.oldEnt && level.time > om->warnTimer
			&& G_InsideBase(entity.oldEnt, true) && G_IsWarnableMOD(meansOfDeath)) {
		om->warnTimer = level.time + ATTACKWARN_NEARBY_PERIOD;
		G_BroadcastEvent(EV_WARN_ATTACK, 0, TEAM_ALIENS);
		Beacon::NewArea(BCT_DEFEND, entity.oldEnt->s.origin, entity.oldEnt->buildableTeam);
	}

	// Set blast timer.
	int blastDelay = 0;
	if (entity.oldEnt->spawned && GetBuildableComponent().GetHealthComponent().Health() /
			GetBuildableComponent().GetHealthComponent().MaxHealth() > -1.0f) {
		blastDelay += GetBlastDelay();
	}

	alienBuildableLogger.Debug("Alien buildable dies, will blast in %i ms.", blastDelay);

	GetBuildableComponent().SetState(BuildableComponent::PRE_BLAST);

	GetBuildableComponent().REGISTER_THINKER(Blast, ThinkingComponent::SCHEDULER_BEFORE, blastDelay);
}
void BuildableComponent::HandleDie(gentity_t* killer, meansOfDeath_t meansOfDeath) {
	// Note that this->state is adjusted in (Alien|Human)BuildableComponent::HandleDie so they have
	// access to its current value.

	TeamComponent::team_t team = GetTeamComponent().Team();

	// TODO: Move animation code to BuildableComponent.
	G_SetBuildableAnim(entity.oldEnt, Powered() ? BANIM_DESTROY : BANIM_DESTROY_UNPOWERED, true);
	G_SetIdleBuildableAnim(entity.oldEnt, BANIM_DESTROYED);

	entity.oldEnt->killedBy = killer->s.number;

	G_LogDestruction(entity.oldEnt, killer, meansOfDeath);

	// TODO: Handle in TaggableComponent.
	Beacon::DetachTags(entity.oldEnt);

	// Report an attack to the defending team if the buildable was powered and there is a main
	// buildable that can report it. Note that the main buildables itself issues its own warnings.
	if (Powered() && entity.Get<MainBuildableComponent>() == nullptr &&
	    G_IsWarnableMOD(meansOfDeath) && G_ActiveMainBuildable(team)) {
		// Get a nearby location entity.
		gentity_t *location = GetCloseLocationEntity(entity.oldEnt);

		// Fall back to fake location entity if necessary.
		if (!location) location = level.fakeLocation;

		// Warn if there was no warning for this location recently.
		if (level.time > location->warnTimer) {
			bool inBase = G_InsideBase(entity.oldEnt);

			G_BroadcastEvent(EV_WARN_ATTACK, inBase ? 0 : location->s.number, team);
			Beacon::NewArea(BCT_DEFEND, entity.oldEnt->s.origin, team);
			location->warnTimer = level.time + ATTACKWARN_NEARBY_PERIOD;
		}
	}

	// If not deconstructed, add all build points to queue.
	if (meansOfDeath != MOD_DECONSTRUCT && meansOfDeath != MOD_REPLACE) {
		G_FreeBudget(team, 0, BG_Buildable(entity.oldEnt->s.modelindex)->buildPoints);
	}
}
Esempio n. 3
0
/*
==================
G_RewardAttackers

Function to distribute rewards to entities that killed this one.
==================
*/
void G_RewardAttackers( gentity_t *self )
{
	float     value, reward;
	int       playerNum, enemyDamage, maxHealth, damageShare;
	gentity_t *player;
	team_t    ownTeam, playerTeam;
	confidence_reason_t    reason;
	confidence_qualifier_t qualifier;

	// Only reward killing players and buildables
	if ( self->client )
	{
		ownTeam = self->client->pers.teamSelection;
		maxHealth = self->client->ps.stats[ STAT_MAX_HEALTH ];
		value = ( float )BG_GetValueOfPlayer( &self->client->ps );
	}
	else if ( self->s.eType == ET_BUILDABLE )
	{
		ownTeam = self->buildableTeam;
		maxHealth = BG_Buildable( self->s.modelindex )->health;
		value = ( float )BG_Buildable( self->s.modelindex )->value;

		// Give partial credits for buildables in construction
		if ( !self->spawned )
		{
			value *= ( float )( level.time - self->creationTime ) / BG_Buildable( self->s.modelindex )->buildTime;
		}
	}
	else
	{
		return;
	}

	enemyDamage = 0;

	// Sum up damage dealt by enemies
	for ( playerNum = 0; playerNum < level.maxclients; playerNum++ )
	{
		player = &g_entities[ playerNum ];
		playerTeam = player->client->pers.teamSelection;

		// Player must be on the other team
		if ( playerTeam == ownTeam || playerTeam <= TEAM_NONE || playerTeam >= NUM_TEAMS )
		{
			continue;
		}

		enemyDamage += self->credits[ playerNum ];
	}

	if ( enemyDamage <= 0 )
	{
		return;
	}

	// Give individual rewards
	for ( playerNum = 0; playerNum < level.maxclients; playerNum++ )
	{
		player = &g_entities[ playerNum ];
		playerTeam = player->client->pers.teamSelection;
		damageShare = self->credits[ playerNum ];

		// Clear reward array
		self->credits[ playerNum ] = 0;

		// Player must be on the other team
		if ( playerTeam == ownTeam || playerTeam <= TEAM_NONE || playerTeam >= NUM_TEAMS )
		{
			continue;
		}

		// Player must have dealt damage
		if ( damageShare <= 0 )
		{
			continue;
		}

		reward = value * ( damageShare / ( float )maxHealth );

		if ( reward <= 0.0f )
		{
			continue;
		}

		if ( self->s.eType == ET_BUILDABLE )
		{
			G_AddConfidenceToScore( player, reward );

			switch ( self->s.modelindex )
			{
				case BA_A_OVERMIND:
				case BA_H_REACTOR:
					reason = CONF_REAS_DESTR_CRUCIAL;
					break;

				case BA_A_ACIDTUBE:
				case BA_A_TRAPPER:
				case BA_A_HIVE:
				case BA_H_MGTURRET:
				case BA_H_TESLAGEN:
					reason = CONF_REAS_DESTR_AGGRESSIVE;
					break;

				default:
					reason = CONF_REAS_DESTR_SUPPORT;
			}

			qualifier = CONF_QUAL_NONE;

			G_AddConfidence( playerTeam, CONFIDENCE_DESTRUCTION, reason, qualifier, reward, player );
		}
		else
		{
			G_AddCreditsToScore( player, ( int )reward );
			G_AddCreditToClient( player->client, ( short )reward, qtrue );

			// Give confidence for killing non-naked players outside the friendly base
			switch ( self->client->ps.stats[ STAT_CLASS ] )
			{
				case PCL_ALIEN_LEVEL0:
				case PCL_ALIEN_BUILDER0:
				case PCL_ALIEN_BUILDER0_UPG:
					break;

				case PCL_HUMAN:
					// Treat a human just wearing light armor as naked
					if ( ( int )value <= BG_Class( PCL_HUMAN )->value +
					                     ( BG_Upgrade( UP_LIGHTARMOUR )->price / 2 ) )
					{
						break;
					}

				default:
					if ( G_InsideBase( player, qtrue ) || G_InsideBase( self, qfalse ) )
					{
						break;
					}

					qualifier = CONF_QUAL_OUTSIDE_OWN_BASE;

					G_AddConfidence( playerTeam, CONFIDENCE_KILLING, CONF_REAS_KILLING,
					                 qualifier, reward * CONFIDENCE_PER_CREDIT, player );
			}
		}
	}
}