static qboolean wopSP_calcWon(void) { int i; gentity_t *player; int playerClientNum; // find the real player player = NULL; for (i = 0; i < level.maxclients; i++ ) { player = &g_entities[i]; if ( !player->inuse ) { continue; } if ( !( player->r.svFlags & SVF_BOT ) ) { break; } } if ( !player || i == level.maxclients ) { return qfalse; } playerClientNum = i; if ( g_gametype.integer >= GT_TEAM ) { if((player->client->sess.sessionTeam == TEAM_RED && level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE]) || (player->client->sess.sessionTeam == TEAM_BLUE && level.teamScores[TEAM_RED] < level.teamScores[TEAM_BLUE])) return qtrue; else return qfalse; } else { CalculateRanks(); return (player->client->ps.persistant[PERS_RANK] == 0); } }
/* ======================================================================================================================================= ObeliskDie ======================================================================================================================================= */ static void ObeliskDie(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod) { int otherTeam; otherTeam = OtherTeam(self->spawnflags); self->takedamage = qfalse; self->think = ObeliskRespawn; self->nextthink = level.time + g_obeliskRespawnDelay.integer * 1000; self->activator->s.modelindex2 = 0xff; self->activator->s.frame = 2; G_AddEvent(self->activator, EV_OBELISKEXPLODE, 0); if (self->spawnflags == attacker->client->sess.sessionTeam) { AddScore(attacker, self->r.currentOrigin, -CTF_CAPTURE_BONUS); } else { AddScore(attacker, self->r.currentOrigin, CTF_CAPTURE_BONUS); attacker->client->rewardTime = level.time + REWARD_TIME; attacker->client->ps.persistant[PERS_CAPTURES]++; } AddTeamScore(self->s.pos.trBase, otherTeam, 1); CalculateRanks(); Team_CaptureFlagSound(self, self->spawnflags); Team_ForceGesture(otherTeam); teamgame.redObeliskAttackedTime = 0; teamgame.blueObeliskAttackedTime = 0; trap_SendServerCommand(-1, va("cp \"%s" S_COLOR_WHITE "\ndestroyed the %s obelisk!\n\"", attacker->client->pers.netname, TeamName(self->spawnflags))); }
static void ObeliskTouch( gentity_t *self, gentity_t *other, trace_t *trace ) { int tokens; if ( !other->client ) { return; } if ( OtherTeam(other->client->sess.sessionTeam) != self->spawnflags ) { return; } tokens = other->client->ps.generic1; if( tokens <= 0 ) { return; } PrintMsg(NULL, "%s" S_COLOR_WHITE " brought in %i skull%s.\n", other->client->pers.netname, tokens, tokens ? "s" : "" ); AddTeamScore(self->s.pos.trBase, other->client->sess.sessionTeam, tokens); Team_ForceGesture(other->client->sess.sessionTeam); AddScore(other, self->r.currentOrigin, CTF_CAPTURE_BONUS*tokens); // add the sprite over the player's head other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP ); other->client->ps.eFlags |= EF_AWARD_CAP; other->client->rewardTime = level.time + REWARD_SPRITE_TIME; other->client->ps.persistant[PERS_CAPTURES] += tokens; other->client->ps.generic1 = 0; CalculateRanks(); Team_CaptureFlagSound( self, self->spawnflags ); }
/* ============ AddScore Adds score to both the client and his team ============ */ void AddScore(gentity_t * ent, vec3_t origin, int score) { if(!ent->client) { return; } // no scoring during pre-match warmup if(level.warmupTime) { return; } // Tr3B: don't draw zero skills scores if(score == 0) { return; } // show score plum ScorePlum(ent, origin, score); // ent->client->ps.persistant[PERS_SCORE] += score; if(g_gametype.integer == GT_TEAM) level.teamScores[ent->client->ps.persistant[PERS_TEAM]] += score; CalculateRanks(); }
/* ======================================================================================================================================= ObeliskTouch ======================================================================================================================================= */ static void ObeliskTouch(gentity_t *self, gentity_t *other, trace_t *trace) { int tokens; team_t otherTeam; if (!other->client) { return; } otherTeam = OtherTeam(other->client->sess.sessionTeam); if (otherTeam != self->spawnflags) { return; } tokens = other->client->ps.tokens; if (tokens <= 0) { return; } trap_SendServerCommand(-1, va("cp \"%s" S_COLOR_WHITE "\nbrought in %i %s %s!\n\"", other->client->pers.netname, tokens, TeamName(otherTeam), (tokens == 1) ? "skull" : "skulls")); other->client->rewardTime = level.time + REWARD_TIME; other->client->ps.persistant[PERS_CAPTURES] += tokens; other->client->ps.tokens = 0; AddScore(other, self->r.currentOrigin, CTF_CAPTURE_BONUS * tokens); AddTeamScore(self->s.pos.trBase, other->client->sess.sessionTeam, tokens); CalculateRanks(); Team_CaptureFlagSound(self, self->spawnflags); Team_ForceGesture(other->client->sess.sessionTeam); }
static void ObeliskDie(Gentity *self, Gentity *inflictor, Gentity *attacker, int damage, int mod) { int otherTeam; otherTeam = OtherTeam(self->spawnflags); AddTeamScore(self->s.pos.base, otherTeam, 1); Team_ForceGesture(otherTeam); CalculateRanks(); self->takedamage = qfalse; self->think = ObeliskRespawn; self->nextthink = level.time + g_obeliskRespawnDelay.integer * 1000; self->activator->s.modelindex2 = 0xff; self->activator->s.frame = 2; G_AddEvent(self->activator, EV_OBELISKEXPLODE, 0); AddScore(attacker, self->r.currentOrigin, CTF_CAPTURE_BONUS); /* add the sprite over the player's head */ attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP); attacker->client->ps.eFlags |= EF_AWARD_CAP; attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME; attacker->client->ps.persistant[PERS_CAPTURES]++; teamgame.redObeliskAttackedTime = 0; teamgame.blueObeliskAttackedTime = 0; }
/* =========== ClientBegin called when a client has finished connecting, and is ready to be placed into the level. This will happen every level load, and on transition between teams, but doesn't happen on respawns ============ */ void ClientBegin( int clientNum ) { gentity_t *ent; gclient_t *client; int flags; ent = g_entities + clientNum; client = level.clients + clientNum; if( ent->r.linked ) trap_UnlinkEntity( ent ); G_InitGentity( ent ); ent->touch = 0; ent->pain = 0; ent->client = client; client->pers.connected = CON_CONNECTED; client->pers.enterTime = level.time; client->pers.teamState.state = TEAM_BEGIN; client->pers.classSelection = PCL_NONE; // save eflags around this, because changing teams will // cause this to happen with a valid entity, and we // want to make sure the teleport bit is set right // so the viewpoint doesn't interpolate through the // world to the new position flags = client->ps.eFlags; memset( &client->ps, 0, sizeof( client->ps ) ); memset( &client->pmext, 0, sizeof( client->pmext ) ); client->ps.eFlags = flags; // locate ent at a spawn point ClientSpawn( ent, NULL, NULL, NULL ); trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) ); // name can change between ClientConnect() and ClientBegin() G_admin_namelog_update( client, qfalse ); // request the clients PTR code trap_SendServerCommand( ent - g_entities, "ptrcrequest" ); G_LogPrintf( "ClientBegin: %i\n", clientNum ); if( g_clientUpgradeNotice.integer ) { if( !Q_stricmp( ent->client->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) ) { trap_SendServerCommand( client->ps.clientNum, va( "print \"^1Your client is out of date. Updating your client will allow you to " "become an admin on servers and download maps much more quickly. Please replace your client executable with the one " "at ^2http://trem.tjw.org/backport/^1 and reconnect. \n\"" ) ); } } // count current clients and rank for scoreboard CalculateRanks( ); }
/* =========== PlayerBegin called when a player has finished connecting, and is ready to be placed into the level. This will happen every level load, and on transition between teams, but doesn't happen on respawns ============ */ void PlayerBegin( int playerNum ) { gentity_t *ent; gplayer_t *player; int flags; int i; ent = g_entities + playerNum; player = level.players + playerNum; if ( ent->r.linked ) { trap_UnlinkEntity( ent ); } G_InitGentity( ent ); ent->touch = 0; ent->pain = 0; ent->player = player; player->pers.connected = CON_CONNECTED; player->pers.enterTime = level.time; player->pers.teamState.state = TEAM_BEGIN; // save eflags around this, because changing teams will // cause this to happen with a valid entity, and we // want to make sure the teleport bit is set right // so the viewpoint doesn't interpolate through the // world to the new position flags = player->ps.eFlags; memset( &player->ps, 0, sizeof( player->ps ) ); player->ps.eFlags = flags; // locate ent at a spawn point PlayerSpawn( ent ); if ( player->pers.initialSpawn && g_gametype.integer != GT_TOURNAMENT ) { // This is only sent to bots because for humans the "joining the battle" etc // make it clear that the player is now finished connecting. Bots on the other // hand have "entered the game" hard coded in botfiles/match.c so continue to // send it to them. for ( i = 0; i < level.maxplayers; i++ ) { if ( level.players[i].pers.connected == CON_DISCONNECTED ) { continue; } if ( !(g_entities[i].r.svFlags & SVF_BOT) ) { continue; } trap_SendServerCommand( i, va("print \"%s" S_COLOR_WHITE " entered the game\n\"", player->pers.netname) ); } if ( !g_singlePlayer.integer ) { BroadcastTeamChange( player, -1 ); } } player->pers.initialSpawn = qfalse; G_LogPrintf( "PlayerBegin: %i\n", playerNum ); // count current players and rank for scoreboard CalculateRanks(); }
/* ============ AddScore Adds score to both the client and his team ============ */ void AddScore( gentity_t *ent, int score ) { if( !ent->client ) return; ent->client->ps.persistant[ PERS_SCORE ] += score; CalculateRanks( ); }
/* =========== ClientDisconnect Called when a player drops from the server. Will not be called between levels. This should NOT be called directly by any game logic, call trap_DropClient(), which will call this and do server system housekeeping. ============ */ void ClientDisconnect( int clientNum ) { gentity_t *ent; gentity_t *tent; int i; // cleanup if we are kicking a bot that // hasn't spawned yet G_RemoveQueuedBotBegin( clientNum ); ent = g_entities + clientNum; if ( !ent->client ) { return; } // stop any following clients for ( i = 0 ; i < level.maxclients ; i++ ) { if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR && level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW && level.clients[i].sess.spectatorClient == clientNum ) { StopFollowing( &g_entities[i] ); } } // send effect if they were completely connected if ( ent->client->pers.connected == CON_CONNECTED && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { // They don't get to take powerups with them! // Especially important for stuff like CTF flags TossClientItems( ent ); #ifdef MISSIONPACK TossClientPersistantPowerups( ent ); if( g_gametype.integer == GT_HARVESTER ) { TossClientCubes( ent ); } #endif } G_LogPrintf( "ClientDisconnect: %i\n", clientNum ); trap_UnlinkEntity (ent); ent->s.modelindex = 0; ent->inuse = qfalse; ent->classname = "disconnected"; ent->client->pers.connected = CON_DISCONNECTED; ent->client->ps.stats[STAT_TEAM] = TEAM_FREE; ent->client->sess.sessionTeam = TEAM_FREE; trap_SetConfigstring( CS_PLAYERS + clientNum, ""); CalculateRanks(); if ( ent->r.svFlags & SVF_BOT ) { BotAIShutdownClient( clientNum, qfalse ); } }
/* ================== UpdateTournamentInfo ================== */ void UpdateTournamentInfo( void ) { int n, accuracy, perfect; char buf[32], msg[MAX_STRING_CHARS]; unsigned int playerClientNum, i, buflen, msglen; gentity_t *player; // find the real player player = NULL; for (i = 0; i < level.maxclients; i++ ) { player = &g_entities[i]; if ( !player->inuse ) continue; if ( !( player->r.svFlags & SVF_BOT ) ) break; } // this should never happen! if ( !player || i == level.maxclients ) return; playerClientNum = i; CalculateRanks(); if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR ) { Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum ); } else { if( player->client->accuracy_shots ) accuracy = player->client->accuracy_hits * 100 / player->client->accuracy_shots; else accuracy = 0; perfect = ( level.clients[playerClientNum].ps.persistant[PERS_RANK] == 0 && player->client->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0; Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy, player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT], player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE], perfect ); } msglen = strlen( msg ); for( i = 0; i < level.numNonSpectatorClients; i++ ) { n = level.sortedClients[i]; Com_sprintf( buf, sizeof(buf), " %i %i %i", n, level.clients[n].ps.persistant[PERS_RANK], level.clients[n].ps.persistant[PERS_SCORE] ); buflen = strlen( buf ); if( msglen + buflen + 1 >= sizeof(msg) ) { break; } strcat( msg, buf ); } Cbuf_ExecuteText(EXEC_APPEND, msg ); }
/* =========== ClientDisconnect Called when a player drops from the server. Will not be called between levels. This should NOT be called directly by any game logic, call trap_DropClient(), which will call this and do server system housekeeping. ============ */ void ClientDisconnect( int clientNum ) { gentity_t *ent; gentity_t *tent; int i; buildHistory_t *ptr; ent = g_entities + clientNum; if( !ent->client ) return; // look through the bhist and readjust it if the referenced ent has left for( ptr = level.buildHistory; ptr; ptr = ptr->next ) { if( ptr->ent == ent ) { ptr->ent = NULL; Q_strncpyz( ptr->name, ent->client->pers.netname, MAX_NETNAME ); } } G_admin_namelog_update( ent->client, qtrue ); G_LeaveTeam( ent ); // stop any following clients for( i = 0; i < level.maxclients; i++ ) { // remove any /ignore settings for this clientNum BG_ClientListRemove( &level.clients[ i ].sess.ignoreList, clientNum ); } // send effect if they were completely connected if( ent->client->pers.connected == CON_CONNECTED && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = ent->s.clientNum; } if( ent->client->pers.connection ) ent->client->pers.connection->clientNum = -1; G_LogPrintf( "ClientDisconnect: %i [%s] (%s) \"%s\"\n", clientNum, ent->client->pers.ip, ent->client->pers.guid, ent->client->pers.netname ); trap_UnlinkEntity( ent ); ent->s.modelindex = 0; ent->inuse = qfalse; ent->classname = "disconnected"; ent->client->pers.connected = CON_DISCONNECTED; ent->client->ps.persistant[ PERS_TEAM ] = TEAM_FREE; ent->client->sess.sessionTeam = TEAM_FREE; trap_SetConfigstring( CS_PLAYERS + clientNum, ""); CalculateRanks( ); }
/* =========== ClientBegin called when a client has finished connecting, and is ready to be placed into the level. This will happen every level load, and on transition between teams, but doesn't happen on respawns ============ */ void ClientBegin(int clientNum) { gentity_t *ent; gclient_t *client; gentity_t *tent; int flags; ent = g_entities + clientNum; client = level.clients + clientNum; if(ent->r.linked) { trap_UnlinkEntity(ent); } G_InitGentity(ent); ent->touch = 0; ent->pain = 0; ent->client = client; client->pers.connected = CON_CONNECTED; client->pers.enterTime = level.time; client->pers.teamState.state = TEAM_BEGIN; // save eflags around this, because changing teams will // cause this to happen with a valid entity, and we // want to make sure the teleport bit is set right // so the viewpoint doesn't interpolate through the // world to the new position flags = client->ps.eFlags; memset(&client->ps, 0, sizeof(client->ps)); client->ps.eFlags = flags; // locate ent at a spawn point ClientSpawn(ent); if(client->sess.sessionTeam != TEAM_SPECTATOR) { // send event tent = G_TempEntity(ent->client->ps.origin, EV_PLAYER_TELEPORT_IN); tent->s.clientNum = ent->s.clientNum; if(g_gametype.integer != GT_TOURNAMENT) { trap_SendServerCommand(-1, va("print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname)); } } G_LogPrintf("ClientBegin: %i\n", clientNum); // count current clients and rank for scoreboard CalculateRanks(); #ifdef G_LUA // Lua API callbacks G_LuaHook_ClientBegin(clientNum); #endif }
// TODO: Draw a ScorePlum() as well? Needs cgame fixes to draw plum regardless of "owner" void AddTeamScore( vec3_t origin, int team, int score, char *reason ) { gentity_t *te; te = G_TempEntity(origin, EV_GLOBAL_TEAM_SOUND ); te->r.svFlags |= SVF_BROADCAST; if ( team == TEAM_RED ) { if ( level.teamScores[ TEAM_RED ] + score == level.teamScores[ TEAM_BLUE ] ) { //teams are tied sound te->s.eventParm = GTS_TEAMS_ARE_TIED; } else if ( level.teamScores[ TEAM_RED ] <= level.teamScores[ TEAM_BLUE ] && level.teamScores[ TEAM_RED ] + score > level.teamScores[ TEAM_BLUE ]) { // red took the lead sound te->s.eventParm = GTS_REDTEAM_TOOK_LEAD; } else { // red scored sound te->s.eventParm = GTS_REDTEAM_SCORED; // Hackity! In BB teams score continously, which makes for annoying // sound spam. Thus disable sound. // Better solution would be to either only do this sound on captures/destroys // or continously at fixed time offsets. // Also note that there already is a "blue/red balloon" sound in cgame CG_UpdateBalloonStates if ( g_gametype.integer == GT_BALLOON ) { G_FreeEntity( te ); } } } else { if ( level.teamScores[ TEAM_BLUE ] + score == level.teamScores[ TEAM_RED ] ) { //teams are tied sound te->s.eventParm = GTS_TEAMS_ARE_TIED; } else if ( level.teamScores[ TEAM_BLUE ] <= level.teamScores[ TEAM_RED ] && level.teamScores[ TEAM_BLUE ] + score > level.teamScores[ TEAM_RED ]) { // blue took the lead sound te->s.eventParm = GTS_BLUETEAM_TOOK_LEAD; } else { // blue scored sound te->s.eventParm = GTS_BLUETEAM_SCORED; // See note above if ( g_gametype.integer == GT_BALLOON ) { G_FreeEntity( te ); } } } level.teamScores[ team ] += score; CalculateRanks(); G_LogPrintf( "AddTeamScore: %s %i %s\n", TeamName( team ), score, reason ); }
/* =========== ClientBegin called when a client has finished connecting, and is ready to be placed into the level. This will happen every level load, and on transition between teams, but doesn't happen on respawns ============ */ void ClientBegin( int clientNum ) { gentity_t *ent; gclient_t *client; int flags; ent = g_entities + clientNum; client = level.clients + clientNum; // ignore if client already entered the game if( client->pers.connected != CON_CONNECTING ) return; if( ent->r.linked ) trap_UnlinkEntity( ent ); G_InitGentity( ent ); ent->touch = 0; ent->pain = 0; ent->client = client; client->pers.connected = CON_CONNECTED; client->pers.enterTime = level.time; // save eflags around this, because changing teams will // cause this to happen with a valid entity, and we // want to make sure the teleport bit is set right // so the viewpoint doesn't interpolate through the // world to the new position flags = client->ps.eFlags; memset( &client->ps, 0, sizeof( client->ps ) ); memset( &client->pmext, 0, sizeof( client->pmext ) ); client->ps.eFlags = flags; // locate ent at a spawn point ClientSpawn( ent, NULL, NULL, NULL ); trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) ); G_namelog_restore( client ); G_LogPrintf( "ClientBegin: %i\n", clientNum ); // count current clients and rank for scoreboard CalculateRanks( ); // send the client a list of commands that can be used G_ListCommands( ent ); // reset cuboidSelection client->cuboidSelection[ 0 ] = client->cuboidSelection[ 1 ] = client->cuboidSelection[ 2 ] = 32; }
/* ============ AddScoreHelper Helper function for G_AddCreditsToScore and G_AddConfidenceToScore. ============ */ static void AddScoreHelper( gentity_t *self, float score ) { if ( !self->client || self->client->pers.connected != CON_CONNECTED ) { return; } self->client->ps.persistant[ PERS_SCORE ] += ( int )( score + 0.5f ); CalculateRanks(); }
/** * @brief G_AddKillSkillPointsForDestruction * @param[in] attacker * @param[in] mod * @param[in] constructibleStats */ void G_AddKillSkillPointsForDestruction(gentity_t *attacker, meansOfDeath_t mod, g_constructible_stats_t *constructibleStats) { if (GetMODTableData(mod)->skillType < SK_NUM_SKILLS) { G_AddSkillPoints(attacker, GetMODTableData(mod)->skillType, constructibleStats->destructxpbonus); G_DebugAddSkillPoints(attacker, GetMODTableData(mod)->skillType, constructibleStats->destructxpbonus, "destroying a constructible/explosive"); } // prepare scoreboard CalculateRanks(); }
/* =========== ClientDisconnect Called when a player drops from the server. Will not be called between levels. This should NOT be called directly by any game logic, call trap_DropClient(), which will call this and do server system housekeeping. ============ */ void ClientDisconnect( int clientNum ) { gclient_t *client; gentity_t *ent; gentity_t *tent; int i; ent = g_entities + clientNum; if( !ent->client || ent->client->pers.connected == CON_DISCONNECTED ) return; G_LeaveTeam( ent ); G_namelog_disconnect( ent->client ); G_Vote( ent, TEAM_NONE, qfalse ); // stop any following clients for( i = 0; i < level.maxclients; i++ ) { client = &level.clients[ i ]; // remove any /ignore settings for this clientNum Com_ClientListRemove( &client->sess.ignoreList, clientNum ); // clear impregnatedBy for everyone impregnated by this player if( client->isImpregnated && client->impregnatedBy == clientNum ) client->impregnatedBy = -2; } // send effect if they were completely connected if( ent->client->pers.connected == CON_CONNECTED && ent->client->sess.spectatorState == SPECTATOR_NOT ) { tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = ent->s.clientNum; } G_LogPrintf( "ClientDisconnect: %i [%s] (%s) \"%s^7\"\n", clientNum, ent->client->pers.ip.str, ent->client->pers.guid, ent->client->pers.netname ); trap_UnlinkEntity( ent ); ent->s.modelindex = 0; ent->inuse = qfalse; ent->classname = "disconnected"; ent->client->pers.connected = CON_DISCONNECTED; ent->client->sess.spectatorState = ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_NOT; trap_SetConfigstring( CS_PLAYERS + clientNum, ""); CalculateRanks( ); }
/** * @brief G_AddKillSkillPoints * @param[in] attacker * @param[in] mod * @param[in] hr * @param[in] splash */ void G_AddKillSkillPoints(gentity_t *attacker, meansOfDeath_t mod, hitRegion_t hr, qboolean splash) { float points; skillType_t skillType; const char *reason; if (!attacker->client) { return; } if (GetMODTableData(mod)->hasHitRegion) { points = GetMODTableData(mod)->hitRegionKillPoints[hr]; switch (hr) { case HR_HEAD: reason = va("%s headshot kill", GetMODTableData(mod)->debugReasonMsg); break; case HR_ARMS: reason = va("%s armshot kill", GetMODTableData(mod)->debugReasonMsg); break; case HR_BODY: reason = va("%s bodyshot kill", GetMODTableData(mod)->debugReasonMsg); break; case HR_LEGS: reason = va("%s legshot kill", GetMODTableData(mod)->debugReasonMsg); break; default: reason = va("%s kill", GetMODTableData(mod)->debugReasonMsg); break; // for weapons that don't have localized damage, should not happen } } else if (splash) { points = GetMODTableData(mod)->splashKillPoints; reason = va("%s splash damage kill", GetMODTableData(mod)->debugReasonMsg); } else { points = GetMODTableData(mod)->defaultKillPoints; if (GetMODTableData(mod)->isExplosive) { reason = va("%s direct damage kill", GetMODTableData(mod)->debugReasonMsg); } else { reason = va("%s kill", GetMODTableData(mod)->debugReasonMsg); } } skillType = GetMODTableData(mod)->skillType; G_AddSkillPoints(attacker, skillType, points); G_DebugAddSkillPoints(attacker, skillType, points, reason); // prepare scoreboard CalculateRanks(); }
/* ============ AddKillScore Adds score to both the client and his team, only used for playerkills, for lms ============ */ void AddKillScore( gentity_t *ent, int score ) { if ( !ent || !ent->client ) { return; } // someone already won if( level.lmsWinningTeam ) return; ent->client->sess.game_points += score; CalculateRanks(); }
/* =========== ClientDisconnect Called when a player drops from the server. Will not be called between levels. This should NOT be called directly by any game logic, call trap_DropClient(), which will call this and do server system housekeeping. ============ */ void ClientDisconnect( int clientNum ) { gentity_t *ent; gentity_t *tent; int i; ent = g_entities + clientNum; if ( !ent->client || ent->client->pers.connected == CON_DISCONNECTED ) { return; } G_LeaveTeam( ent ); G_namelog_disconnect( ent->client ); G_Vote( ent, TEAM_NONE, false ); // stop any following clients for ( i = 0; i < level.maxclients; i++ ) { // remove any /ignore settings for this clientNum Com_ClientListRemove( &level.clients[ i ].sess.ignoreList, clientNum ); } // send effect if they were completely connected if ( ent->client->pers.connected == CON_CONNECTED && ent->client->sess.spectatorState == SPECTATOR_NOT ) { tent = G_NewTempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = ent->s.clientNum; } G_LogPrintf( "ClientDisconnect: %i [%s] (%s) \"%s^7\"", clientNum, ent->client->pers.ip.str, ent->client->pers.guid, ent->client->pers.netname ); ent->client->pers.connected = CON_DISCONNECTED; ent->client->sess.spectatorState = SPECTATOR_NOT; ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_NOT; G_FreeEntity(ent); ent->classname = "disconnected"; ent->client = level.clients + clientNum; trap_SetConfigstring( CS_PLAYERS + clientNum, "" ); CalculateRanks(); Beacon::PropagateAll(); }
/** * @brief Loose skill for evil tkers :E * @param[in] tker * @param[in] mod * @param hr - unused * @param splash - unused */ void G_LoseKillSkillPoints(gentity_t *tker, meansOfDeath_t mod, hitRegion_t hr, qboolean splash) { if (!tker->client) { return; } if (GetMODTableData(mod)->skillType < SK_NUM_SKILLS) { G_LoseSkillPoints(tker, GetMODTableData(mod)->skillType, GetMODTableData(mod)->defaultKillPoints); } // prepare scoreboard CalculateRanks(); }
/* =========== ClientDisconnect Called when a player drops from the server. Will not be called between levels. This should NOT be called directly by any game logic, call trap_DropClient(), which will call this and do server system housekeeping. ============ */ void ClientDisconnect( int clientNum ) { gentity_t *ent; gentity_t *tent; int i; ent = g_entities + clientNum; if( !ent->client ) return; G_admin_namelog_update( ent->client, qtrue ); G_LeaveTeam( ent ); G_Vote( ent, qfalse ); // stop any following clients for( i = 0; i < level.maxclients; i++ ) { // remove any /ignore settings for this clientNum BG_ClientListRemove( &level.clients[ i ].sess.ignoreList, clientNum ); } // send effect if they were completely connected if( ent->client->pers.connected == CON_CONNECTED && ent->client->sess.spectatorState == SPECTATOR_NOT ) { tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = ent->s.clientNum; } if( ent->client->pers.connection ) ent->client->pers.connection->clientNum = -1; G_LogPrintf( "ClientDisconnect: %i [%s] (%s) \"%s\"\n", clientNum, ent->client->pers.ip, ent->client->pers.guid, ent->client->pers.netname ); trap_UnlinkEntity( ent ); ent->s.modelindex = 0; ent->inuse = qfalse; ent->classname = "disconnected"; ent->client->pers.connected = CON_DISCONNECTED; ent->client->sess.spectatorState = ent->client->ps.persistant[ PERS_SPECSTATE ] = SPECTATOR_NOT; trap_SetConfigstring( CS_PLAYERS + clientNum, ""); CalculateRanks( ); }
/* =========== ClientBegin called when a client has finished connecting, and is ready to be placed into the level. This will happen every level load, and on transition between teams, but doesn't happen on respawns ============ */ void ClientBegin( int clientNum ) { gentity_t *ent; gclient_t *client; int flags; ent = g_entities + clientNum; client = level.clients + clientNum; if( ent->r.linked ) trap_UnlinkEntity( ent ); G_InitGentity( ent ); ent->touch = 0; ent->pain = 0; ent->client = client; client->pers.connected = CON_CONNECTED; client->pers.enterTime = level.time; // save eflags around this, because changing teams will // cause this to happen with a valid entity, and we // want to make sure the teleport bit is set right // so the viewpoint doesn't interpolate through the // world to the new position flags = client->ps.eFlags; memset( &client->ps, 0, sizeof( client->ps ) ); memset( &client->pmext, 0, sizeof( client->pmext ) ); client->ps.eFlags = flags; // locate ent at a spawn point ClientSpawn( ent, NULL, NULL, NULL ); trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) ); // name can change between ClientConnect() and ClientBegin() G_admin_namelog_update( client, qfalse ); // request the clients PTR code trap_SendServerCommand( ent - g_entities, "ptrcrequest" ); G_LogPrintf( "ClientBegin: %i\n", clientNum ); // count current clients and rank for scoreboard CalculateRanks( ); }
/* ============ AddScore Adds score to the client ============ */ void AddScore( gentity_t *ent, int score ) { if( !ent->client ) return; // make alien and human scores equivalent if ( ent->client->pers.teamSelection == TEAM_ALIENS ) { score = rint( ((float)score) / 2.0f ); } // scale values down to fit the scoreboard better score = rint( ((float)score) / 50.0f ); ent->client->ps.persistant[ PERS_SCORE ] += score; CalculateRanks( ); }
/* ============ AddScore Adds score to both the player and his team ============ */ void AddScore( gentity_t *ent, vec3_t origin, int score ) { if ( !ent->player ) { return; } // no scoring during pre-match warmup if ( level.warmupTime ) { return; } // show score plum ScorePlum(ent, origin, score); // ent->player->ps.persistant[PERS_SCORE] += score; if ( g_gametype.integer == GT_TEAM ) { AddTeamScore( origin, ent->player->ps.persistant[PERS_TEAM], score ); } CalculateRanks(); }
/** * @brief G_LoseSkillPoints * @param[in,out] ent * @param[in] skill * @param[in] points */ void G_LoseSkillPoints(gentity_t *ent, skillType_t skill, float points) { int oldskill; float oldskillpoints; if (!ent->client) { return; } // no skill loss during warmup if (g_gamestate.integer != GS_PLAYING) { return; } if (ent->client->sess.sessionTeam != TEAM_AXIS && ent->client->sess.sessionTeam != TEAM_ALLIES) { return; } if (g_gametype.integer == GT_WOLF_LMS) { return; // no xp in LMS } oldskillpoints = ent->client->sess.skillpoints[skill]; ent->client->sess.skillpoints[skill] -= points; // see if player increased in skill oldskill = ent->client->sess.skill[skill]; G_SetPlayerSkill(ent->client, skill); if (oldskill != ent->client->sess.skill[skill]) { ent->client->sess.skill[skill] = oldskill; ent->client->sess.skillpoints[skill] = GetSkillTableData(skill)->skillLevels[oldskill]; } G_Printf("%s ^7just lost %.0f skill points for skill %s\n", ent->client->pers.netname, (double)(oldskillpoints - ent->client->sess.skillpoints[skill]), GetSkillTableData(skill)->skillNames); level.teamScores[ent->client->ps.persistant[PERS_TEAM]] -= oldskillpoints - ent->client->sess.skillpoints[skill]; level.teamXP[skill][ent->client->sess.sessionTeam - TEAM_AXIS] -= oldskillpoints - ent->client->sess.skillpoints[skill]; // prepare scoreboard CalculateRanks(); }
/* ============ AddScore Adds score to both the client and his team ============ */ void AddScore( gentity_t *ent, vec3_t origin, int score ) { int i; if ( !ent->client ) { return; } // no scoring during pre-match warmup if ( level.warmupTime ) { return; } //No scoring during intermission if ( level.intermissiontime ) { return; } // show score plum if( level.numNonSpectatorClients<3 && score < 0 && (g_gametype.integer<GT_TEAM || g_ffa_gt==1)) { for ( i = 0 ; i < level.maxclients ; i++ ) { if ( level.clients[ i ].pers.connected != CON_CONNECTED ) continue; //Client was not connected if (level.clients[i].sess.sessionTeam == TEAM_SPECTATOR) continue; //Don't give anything to spectators if (g_entities+i == ent) continue; //Don't award dead one level.clients[i].ps.persistant[PERS_SCORE] -= score; ScorePlum(ent, origin, -score); } } else { ScorePlum(ent, origin, score); // ent->client->ps.persistant[PERS_SCORE] += score; if ( g_gametype.integer == GT_TEAM ) { int team = ent->client->ps.persistant[PERS_TEAM]; level.teamScores[ team ] += score; G_LogPrintf("TeamScore: %i %i: Team %d now has %d points\n", team, level.teamScores[ team ], team, level.teamScores[ team ] ); } } G_LogPrintf("PlayerScore: %i %i: %s now has %d points\n", ent->s.number, ent->client->ps.persistant[PERS_SCORE], ent->client->pers.netname, ent->client->ps.persistant[PERS_SCORE] ); CalculateRanks(); }
/** * @brief G_AddSkillPoints * @param[in,out] ent * @param[in] skill * @param[in] points */ void G_AddSkillPoints(gentity_t *ent, skillType_t skill, float points) { int oldskill; if (!ent->client) { return; } // no skill gaining during warmup if (g_gamestate.integer != GS_PLAYING) { return; } if (ent->client->sess.sessionTeam != TEAM_AXIS && ent->client->sess.sessionTeam != TEAM_ALLIES) { return; } if (g_gametype.integer == GT_WOLF_LMS) { return; // no xp in LMS } level.teamXP[skill][ent->client->sess.sessionTeam - TEAM_AXIS] += points; ent->client->sess.skillpoints[skill] += points; level.teamScores[ent->client->ps.persistant[PERS_TEAM]] += points; //G_Printf( "%s just got %.0f skill points for skill %s\n", ent->client->pers.netname, points, skillNames[skill] ); // see if player increased in skill oldskill = ent->client->sess.skill[skill]; G_SetPlayerSkill(ent->client, skill); if (oldskill != ent->client->sess.skill[skill]) { // call the new func that encapsulates the skill giving behavior G_UpgradeSkill(ent, skill); } // prepare scoreboard CalculateRanks(); }
/* =========== PlayerBegin called when a player has finished connecting, and is ready to be placed into the level. This will happen every level load, and on transition between teams, but doesn't happen on respawns ============ */ void PlayerBegin( int playerNum ) { gentity_t *ent; gplayer_t *player; int flags; ent = g_entities + playerNum; player = level.players + playerNum; if ( ent->r.linked ) { trap_UnlinkEntity( ent ); } G_InitGentity( ent ); ent->touch = 0; ent->pain = 0; ent->player = player; player->pers.connected = CON_CONNECTED; player->pers.enterTime = level.time; player->pers.teamState.state = TEAM_BEGIN; // save eflags around this, because changing teams will // cause this to happen with a valid entity, and we // want to make sure the teleport bit is set right // so the viewpoint doesn't interpolate through the // world to the new position flags = player->ps.eFlags; memset( &player->ps, 0, sizeof( player->ps ) ); player->ps.eFlags = flags; // locate ent at a spawn point PlayerSpawn( ent ); if ( player->pers.initialSpawn && !g_singlePlayer.integer ) { if ( g_gametype.integer != GT_TOURNAMENT ) { BroadcastTeamChange( player, -1 ); } } player->pers.initialSpawn = qfalse; G_LogPrintf( "PlayerBegin: %i\n", playerNum ); // count current players and rank for scoreboard CalculateRanks(); }