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); } }
/* ================== 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 ); } } } }