void game_score_act( gentity_t *self, gentity_t*, gentity_t *activator ) { if ( !activator ) { return; } G_AddCreditsToScore( activator, self->config.amount ); }
/* ================== player_die ================== */ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int meansOfDeath ) { gentity_t *ent; int anim; int killer; int i; const char *killerName, *obit; if ( self->client->ps.pm_type == PM_DEAD ) { return; } if ( level.intermissiontime ) { return; } self->client->ps.pm_type = PM_DEAD; self->suicideTime = 0; if ( attacker ) { killer = attacker->s.number; if ( attacker->client ) { killerName = attacker->client->pers.netname; } else { killerName = "<world>"; } } else { killer = ENTITYNUM_WORLD; killerName = "<world>"; } if ( meansOfDeath < 0 || meansOfDeath >= ARRAY_LEN( modNames ) ) { // fall back on the number obit = va( "%d", meansOfDeath ); } else { obit = modNames[ meansOfDeath ]; } G_LogPrintf( "Die: %d %d %s: %s" S_COLOR_WHITE " killed %s\n", killer, ( int )( self - g_entities ), obit, killerName, self->client->pers.netname ); // deactivate all upgrades for ( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) { BG_DeactivateUpgrade( i, self->client->ps.stats ); } // broadcast the death event to everyone ent = G_NewTempEntity( self->r.currentOrigin, EV_OBITUARY ); ent->s.eventParm = meansOfDeath; ent->s.otherEntityNum = self->s.number; ent->s.otherEntityNum2 = killer; ent->r.svFlags = SVF_BROADCAST; // send to everyone if ( attacker && attacker->client ) { if ( ( attacker == self || OnSameTeam( self, attacker ) ) ) { //punish team kills and suicides if ( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) { G_AddCreditToClient( attacker->client, -ALIEN_TK_SUICIDE_PENALTY, qtrue ); G_AddCreditsToScore( attacker, -ALIEN_TK_SUICIDE_PENALTY ); } else if ( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) { G_AddCreditToClient( attacker->client, -HUMAN_TK_SUICIDE_PENALTY, qtrue ); G_AddCreditsToScore( attacker, -HUMAN_TK_SUICIDE_PENALTY ); } } else if ( g_showKillerHP.integer ) { trap_SendServerCommand( self - g_entities, va( "print_tr %s %s %3i", QQ( N_("Your killer, $1$^7, had $2$ HP.\n") ), Quote( killerName ), attacker->health ) ); } } else if ( attacker->s.eType != ET_BUILDABLE ) { if ( self->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) { G_AddCreditsToScore( self, -ALIEN_TK_SUICIDE_PENALTY ); } else if ( self->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) { G_AddCreditsToScore( self, -HUMAN_TK_SUICIDE_PENALTY ); } } // give credits for killing this player G_RewardAttackers( self ); ScoreboardMessage( self ); // show scores // send updated scores to any clients that are following this one, // or they would get stale scoreboards for ( i = 0; i < level.maxclients; i++ ) { gclient_t *client; client = &level.clients[ i ]; if ( client->pers.connected != CON_CONNECTED ) { continue; } if ( client->sess.spectatorState == SPECTATOR_NOT ) { continue; } if ( client->sess.spectatorClient == self->s.number ) { ScoreboardMessage( g_entities + i ); } } VectorCopy( self->s.origin, self->client->pers.lastDeathLocation ); self->takedamage = qfalse; // can still be gibbed self->s.weapon = WP_NONE; if ( self->client->noclip ) { self->client->cliprcontents = CONTENTS_CORPSE; } else { self->r.contents = CONTENTS_CORPSE; } self->s.angles[ PITCH ] = 0; self->s.angles[ ROLL ] = 0; self->s.angles[ YAW ] = self->s.apos.trBase[ YAW ]; LookAtKiller( self, inflictor, attacker ); VectorCopy( self->s.angles, self->client->ps.viewangles ); self->s.loopSound = 0; self->r.maxs[ 2 ] = -8; // don't allow respawn until the death anim is done // g_forcerespawn may force spawning at some later time self->client->respawnTime = level.time + 1700; // clear misc memset( self->client->ps.misc, 0, sizeof( self->client->ps.misc ) ); { static int i; if ( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) { switch ( i ) { case 0: anim = BOTH_DEATH1; break; case 1: anim = BOTH_DEATH2; break; case 2: default: anim = BOTH_DEATH3; break; } } else { switch ( i ) { case 0: anim = NSPA_DEATH1; break; case 1: anim = NSPA_DEATH2; break; case 2: default: anim = NSPA_DEATH3; break; } } self->client->ps.legsAnim = ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; if ( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) { self->client->ps.torsoAnim = ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; } // use own entityid if killed by non-client to prevent uint8_t overflow G_AddEvent( self, EV_DEATH1 + i, ( killer < MAX_CLIENTS ) ? killer : self - g_entities ); // globally cycle through the different death animations i = ( i + 1 ) % 3; } trap_LinkEntity( self ); self->client->pers.infoChangeTime = level.time; }
/* ================== 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 ); } } } }
/** * @brief Function to distribute rewards to entities that killed this one. * @param self */ void G_RewardAttackers( gentity_t *self ) { float value, share, reward, enemyDamage, damageShare; int playerNum, maxHealth; gentity_t *player; team_t ownTeam, playerTeam; // Only reward killing players and buildables if ( self->client ) { ownTeam = (team_t) self->client->pers.team; maxHealth = self->client->ps.stats[ STAT_MAX_HEALTH ]; value = BG_GetValueOfPlayer( &self->client->ps ); } else if ( self->s.eType == ET_BUILDABLE ) { ownTeam = (team_t) self->buildableTeam; maxHealth = BG_Buildable( self->s.modelindex )->health; value = BG_Buildable( self->s.modelindex )->value; // Give partial credits for buildables in construction if ( !self->spawned ) { value *= ( level.time - self->creationTime ) / ( float )BG_Buildable( self->s.modelindex )->buildTime; } } else { return; } // Sum up damage dealt by enemies enemyDamage = 0.0f; for ( playerNum = 0; playerNum < level.maxclients; playerNum++ ) { player = &g_entities[ playerNum ]; playerTeam = (team_t) player->client->pers.team; // 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 = (team_t) player->client->pers.team; damageShare = self->credits[ playerNum ]; // Clear reward array self->credits[ playerNum ] = 0.0f; // 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.0f ) { continue; } share = damageShare / ( float )maxHealth; reward = value * share; if ( self->s.eType == ET_BUILDABLE ) { // Add score G_AddMomentumToScore( player, reward ); // Add momentum G_AddMomentumForDestroyingStep( self, player, share ); } else { // Add score G_AddCreditsToScore( player, ( int )reward ); // Add credits G_AddCreditToClient( player->client, ( short )reward, qtrue ); // Add momentum G_AddMomentumForKillingStep( self, player, share ); } } // Complete momentum modification G_AddMomentumEnd(); }