Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

g_team.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 //
00023 
00024 #include "g_local.h"
00025 
00026 
00027 typedef struct teamgame_s {
00028     float           last_flag_capture;
00029     int             last_capture_team;
00030     flagStatus_t    redStatus;  // CTF
00031     flagStatus_t    blueStatus; // CTF
00032     flagStatus_t    flagStatus; // One Flag CTF
00033     int             redTakenTime;
00034     int             blueTakenTime;
00035     int             redObeliskAttackedTime;
00036     int             blueObeliskAttackedTime;
00037 } teamgame_t;
00038 
00039 teamgame_t teamgame;
00040 
00041 gentity_t   *neutralObelisk;
00042 
00043 void Team_SetFlagStatus( int team, flagStatus_t status );
00044 
00045 void Team_InitGame( void ) {
00046     memset(&teamgame, 0, sizeof teamgame);
00047 
00048     switch( g_gametype.integer ) {
00049     case GT_CTF:
00050         teamgame.redStatus = teamgame.blueStatus = -1; // Invalid to force update
00051         Team_SetFlagStatus( TEAM_RED, FLAG_ATBASE );
00052         Team_SetFlagStatus( TEAM_BLUE, FLAG_ATBASE );
00053         break;
00054 #ifdef MISSIONPACK
00055     case GT_1FCTF:
00056         teamgame.flagStatus = -1; // Invalid to force update
00057         Team_SetFlagStatus( TEAM_FREE, FLAG_ATBASE );
00058         break;
00059 #endif
00060     default:
00061         break;
00062     }
00063 }
00064 
00065 int OtherTeam(int team) {
00066     if (team==TEAM_RED)
00067         return TEAM_BLUE;
00068     else if (team==TEAM_BLUE)
00069         return TEAM_RED;
00070     return team;
00071 }
00072 
00073 const char *TeamName(int team)  {
00074     if (team==TEAM_RED)
00075         return "RED";
00076     else if (team==TEAM_BLUE)
00077         return "BLUE";
00078     else if (team==TEAM_SPECTATOR)
00079         return "SPECTATOR";
00080     return "FREE";
00081 }
00082 
00083 const char *OtherTeamName(int team) {
00084     if (team==TEAM_RED)
00085         return "BLUE";
00086     else if (team==TEAM_BLUE)
00087         return "RED";
00088     else if (team==TEAM_SPECTATOR)
00089         return "SPECTATOR";
00090     return "FREE";
00091 }
00092 
00093 const char *TeamColorString(int team) {
00094     if (team==TEAM_RED)
00095         return S_COLOR_RED;
00096     else if (team==TEAM_BLUE)
00097         return S_COLOR_BLUE;
00098     else if (team==TEAM_SPECTATOR)
00099         return S_COLOR_YELLOW;
00100     return S_COLOR_WHITE;
00101 }
00102 
00103 // NULL for everyone
00104 void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... ) {
00105     char        msg[1024];
00106     va_list     argptr;
00107     char        *p;
00108     
00109     va_start (argptr,fmt);
00110     if (vsprintf (msg, fmt, argptr) > sizeof(msg)) {
00111         G_Error ( "PrintMsg overrun" );
00112     }
00113     va_end (argptr);
00114 
00115     // double quotes are bad
00116     while ((p = strchr(msg, '"')) != NULL)
00117         *p = '\'';
00118 
00119     trap_SendServerCommand ( ( (ent == NULL) ? -1 : ent-g_entities ), va("print \"%s\"", msg ));
00120 }
00121 
00122 /*
00123 ==============
00124 AddTeamScore
00125 
00126  used for gametype > GT_TEAM
00127  for gametype GT_TEAM the level.teamScores is updated in AddScore in g_combat.c
00128 ==============
00129 */
00130 void AddTeamScore(vec3_t origin, int team, int score) {
00131     gentity_t   *te;
00132 
00133     te = G_TempEntity(origin, EV_GLOBAL_TEAM_SOUND );
00134     te->r.svFlags |= SVF_BROADCAST;
00135 
00136     if ( team == TEAM_RED ) {
00137         if ( level.teamScores[ TEAM_RED ] + score == level.teamScores[ TEAM_BLUE ] ) {
00138             //teams are tied sound
00139             te->s.eventParm = GTS_TEAMS_ARE_TIED;
00140         }
00141         else if ( level.teamScores[ TEAM_RED ] <= level.teamScores[ TEAM_BLUE ] &&
00142                     level.teamScores[ TEAM_RED ] + score > level.teamScores[ TEAM_BLUE ]) {
00143             // red took the lead sound
00144             te->s.eventParm = GTS_REDTEAM_TOOK_LEAD;
00145         }
00146         else {
00147             // red scored sound
00148             te->s.eventParm = GTS_REDTEAM_SCORED;
00149         }
00150     }
00151     else {
00152         if ( level.teamScores[ TEAM_BLUE ] + score == level.teamScores[ TEAM_RED ] ) {
00153             //teams are tied sound
00154             te->s.eventParm = GTS_TEAMS_ARE_TIED;
00155         }
00156         else if ( level.teamScores[ TEAM_BLUE ] <= level.teamScores[ TEAM_RED ] &&
00157                     level.teamScores[ TEAM_BLUE ] + score > level.teamScores[ TEAM_RED ]) {
00158             // blue took the lead sound
00159             te->s.eventParm = GTS_BLUETEAM_TOOK_LEAD;
00160         }
00161         else {
00162             // blue scored sound
00163             te->s.eventParm = GTS_BLUETEAM_SCORED;
00164         }
00165     }
00166     level.teamScores[ team ] += score;
00167 }
00168 
00169 /*
00170 ==============
00171 OnSameTeam
00172 ==============
00173 */
00174 qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) {
00175     if ( !ent1->client || !ent2->client ) {
00176         return qfalse;
00177     }
00178 
00179     if ( g_gametype.integer < GT_TEAM ) {
00180         return qfalse;
00181     }
00182 
00183     if ( ent1->client->sess.sessionTeam == ent2->client->sess.sessionTeam ) {
00184         return qtrue;
00185     }
00186 
00187     return qfalse;
00188 }
00189 
00190 
00191 static char ctfFlagStatusRemap[] = { '0', '1', '*', '*', '2' };
00192 static char oneFlagStatusRemap[] = { '0', '1', '2', '3', '4' };
00193 
00194 void Team_SetFlagStatus( int team, flagStatus_t status ) {
00195     qboolean modified = qfalse;
00196 
00197     switch( team ) {
00198     case TEAM_RED:  // CTF
00199         if( teamgame.redStatus != status ) {
00200             teamgame.redStatus = status;
00201             modified = qtrue;
00202         }
00203         break;
00204 
00205     case TEAM_BLUE: // CTF
00206         if( teamgame.blueStatus != status ) {
00207             teamgame.blueStatus = status;
00208             modified = qtrue;
00209         }
00210         break;
00211 
00212     case TEAM_FREE: // One Flag CTF
00213         if( teamgame.flagStatus != status ) {
00214             teamgame.flagStatus = status;
00215             modified = qtrue;
00216         }
00217         break;
00218     }
00219 
00220     if( modified ) {
00221         char st[4];
00222 
00223         if( g_gametype.integer == GT_CTF ) {
00224             st[0] = ctfFlagStatusRemap[teamgame.redStatus];
00225             st[1] = ctfFlagStatusRemap[teamgame.blueStatus];
00226             st[2] = 0;
00227         }
00228         else {      // GT_1FCTF
00229             st[0] = oneFlagStatusRemap[teamgame.flagStatus];
00230             st[1] = 0;
00231         }
00232 
00233         trap_SetConfigstring( CS_FLAGSTATUS, st );
00234     }
00235 }
00236 
00237 void Team_CheckDroppedItem( gentity_t *dropped ) {
00238     if( dropped->item->giTag == PW_REDFLAG ) {
00239         Team_SetFlagStatus( TEAM_RED, FLAG_DROPPED );
00240     }
00241     else if( dropped->item->giTag == PW_BLUEFLAG ) {
00242         Team_SetFlagStatus( TEAM_BLUE, FLAG_DROPPED );
00243     }
00244     else if( dropped->item->giTag == PW_NEUTRALFLAG ) {
00245         Team_SetFlagStatus( TEAM_FREE, FLAG_DROPPED );
00246     }
00247 }
00248 
00249 /*
00250 ================
00251 Team_ForceGesture
00252 ================
00253 */
00254 void Team_ForceGesture(int team) {
00255     int i;
00256     gentity_t *ent;
00257 
00258     for (i = 0; i < MAX_CLIENTS; i++) {
00259         ent = &g_entities[i];
00260         if (!ent->inuse)
00261             continue;
00262         if (!ent->client)
00263             continue;
00264         if (ent->client->sess.sessionTeam != team)
00265             continue;
00266         //
00267         ent->flags |= FL_FORCE_GESTURE;
00268     }
00269 }
00270 
00271 /*
00272 ================
00273 Team_FragBonuses
00274 
00275 Calculate the bonuses for flag defense, flag carrier defense, etc.
00276 Note that bonuses are not cumulative.  You get one, they are in importance
00277 order.
00278 ================
00279 */
00280 void Team_FragBonuses(gentity_t *targ, gentity_t *inflictor, gentity_t *attacker)
00281 {
00282     int i;
00283     gentity_t *ent;
00284     int flag_pw, enemy_flag_pw;
00285     int otherteam;
00286     int tokens;
00287     gentity_t *flag, *carrier = NULL;
00288     char *c;
00289     vec3_t v1, v2;
00290     int team;
00291 
00292     // no bonus for fragging yourself or team mates
00293     if (!targ->client || !attacker->client || targ == attacker || OnSameTeam(targ, attacker))
00294         return;
00295 
00296     team = targ->client->sess.sessionTeam;
00297     otherteam = OtherTeam(targ->client->sess.sessionTeam);
00298     if (otherteam < 0)
00299         return; // whoever died isn't on a team
00300 
00301     // same team, if the flag at base, check to he has the enemy flag
00302     if (team == TEAM_RED) {
00303         flag_pw = PW_REDFLAG;
00304         enemy_flag_pw = PW_BLUEFLAG;
00305     } else {
00306         flag_pw = PW_BLUEFLAG;
00307         enemy_flag_pw = PW_REDFLAG;
00308     }
00309 
00310     if (g_gametype.integer == GT_1FCTF) {
00311         enemy_flag_pw = PW_NEUTRALFLAG;
00312     } 
00313 
00314     // did the attacker frag the flag carrier?
00315     tokens = 0;
00316 #ifdef MISSIONPACK
00317     if( g_gametype.integer == GT_HARVESTER ) {
00318         tokens = targ->client->ps.generic1;
00319     }
00320 #endif
00321     if (targ->client->ps.powerups[enemy_flag_pw]) {
00322         attacker->client->pers.teamState.lastfraggedcarrier = level.time;
00323         AddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS);
00324         attacker->client->pers.teamState.fragcarrier++;
00325         PrintMsg(NULL, "%s" S_COLOR_WHITE " fragged %s's flag carrier!\n",
00326             attacker->client->pers.netname, TeamName(team));
00327 
00328         // the target had the flag, clear the hurt carrier
00329         // field on the other team
00330         for (i = 0; i < g_maxclients.integer; i++) {
00331             ent = g_entities + i;
00332             if (ent->inuse && ent->client->sess.sessionTeam == otherteam)
00333                 ent->client->pers.teamState.lasthurtcarrier = 0;
00334         }
00335         return;
00336     }
00337 
00338     // did the attacker frag a head carrier? other->client->ps.generic1
00339     if (tokens) {
00340         attacker->client->pers.teamState.lastfraggedcarrier = level.time;
00341         AddScore(attacker, targ->r.currentOrigin, CTF_FRAG_CARRIER_BONUS * tokens * tokens);
00342         attacker->client->pers.teamState.fragcarrier++;
00343         PrintMsg(NULL, "%s" S_COLOR_WHITE " fragged %s's skull carrier!\n",
00344             attacker->client->pers.netname, TeamName(team));
00345 
00346         // the target had the flag, clear the hurt carrier
00347         // field on the other team
00348         for (i = 0; i < g_maxclients.integer; i++) {
00349             ent = g_entities + i;
00350             if (ent->inuse && ent->client->sess.sessionTeam == otherteam)
00351                 ent->client->pers.teamState.lasthurtcarrier = 0;
00352         }
00353         return;
00354     }
00355 
00356     if (targ->client->pers.teamState.lasthurtcarrier &&
00357         level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT &&
00358         !attacker->client->ps.powerups[flag_pw]) {
00359         // attacker is on the same team as the flag carrier and
00360         // fragged a guy who hurt our flag carrier
00361         AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
00362 
00363         attacker->client->pers.teamState.carrierdefense++;
00364         targ->client->pers.teamState.lasthurtcarrier = 0;
00365 
00366         attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
00367         team = attacker->client->sess.sessionTeam;
00368         // add the sprite over the player's head
00369         attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00370         attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
00371         attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00372 
00373         return;
00374     }
00375 
00376     if (targ->client->pers.teamState.lasthurtcarrier &&
00377         level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT) {
00378         // attacker is on the same team as the skull carrier and
00379         AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
00380 
00381         attacker->client->pers.teamState.carrierdefense++;
00382         targ->client->pers.teamState.lasthurtcarrier = 0;
00383 
00384         attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
00385         team = attacker->client->sess.sessionTeam;
00386         // add the sprite over the player's head
00387         attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00388         attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
00389         attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00390 
00391         return;
00392     }
00393 
00394     // flag and flag carrier area defense bonuses
00395 
00396     // we have to find the flag and carrier entities
00397 
00398 #ifdef MISSIONPACK  
00399     if( g_gametype.integer == GT_OBELISK ) {
00400         // find the team obelisk
00401         switch (attacker->client->sess.sessionTeam) {
00402         case TEAM_RED:
00403             c = "team_redobelisk";
00404             break;
00405         case TEAM_BLUE:
00406             c = "team_blueobelisk";
00407             break;      
00408         default:
00409             return;
00410         }
00411         
00412     } else if (g_gametype.integer == GT_HARVESTER ) {
00413         // find the center obelisk
00414         c = "team_neutralobelisk";
00415     } else {
00416 #endif
00417     // find the flag
00418     switch (attacker->client->sess.sessionTeam) {
00419     case TEAM_RED:
00420         c = "team_CTF_redflag";
00421         break;
00422     case TEAM_BLUE:
00423         c = "team_CTF_blueflag";
00424         break;      
00425     default:
00426         return;
00427     }
00428     // find attacker's team's flag carrier
00429     for (i = 0; i < g_maxclients.integer; i++) {
00430         carrier = g_entities + i;
00431         if (carrier->inuse && carrier->client->ps.powerups[flag_pw])
00432             break;
00433         carrier = NULL;
00434     }
00435 #ifdef MISSIONPACK
00436     }
00437 #endif
00438     flag = NULL;
00439     while ((flag = G_Find (flag, FOFS(classname), c)) != NULL) {
00440         if (!(flag->flags & FL_DROPPED_ITEM))
00441             break;
00442     }
00443 
00444     if (!flag)
00445         return; // can't find attacker's flag
00446 
00447     // ok we have the attackers flag and a pointer to the carrier
00448 
00449     // check to see if we are defending the base's flag
00450     VectorSubtract(targ->r.currentOrigin, flag->r.currentOrigin, v1);
00451     VectorSubtract(attacker->r.currentOrigin, flag->r.currentOrigin, v2);
00452 
00453     if ( ( ( VectorLength(v1) < CTF_TARGET_PROTECT_RADIUS &&
00454         trap_InPVS(flag->r.currentOrigin, targ->r.currentOrigin ) ) ||
00455         ( VectorLength(v2) < CTF_TARGET_PROTECT_RADIUS &&
00456         trap_InPVS(flag->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
00457         attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
00458 
00459         // we defended the base flag
00460         AddScore(attacker, targ->r.currentOrigin, CTF_FLAG_DEFENSE_BONUS);
00461         attacker->client->pers.teamState.basedefense++;
00462 
00463         attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
00464         // add the sprite over the player's head
00465         attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00466         attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
00467         attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00468 
00469         return;
00470     }
00471 
00472     if (carrier && carrier != attacker) {
00473         VectorSubtract(targ->r.currentOrigin, carrier->r.currentOrigin, v1);
00474         VectorSubtract(attacker->r.currentOrigin, carrier->r.currentOrigin, v1);
00475 
00476         if ( ( ( VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS &&
00477             trap_InPVS(carrier->r.currentOrigin, targ->r.currentOrigin ) ) ||
00478             ( VectorLength(v2) < CTF_ATTACKER_PROTECT_RADIUS &&
00479                 trap_InPVS(carrier->r.currentOrigin, attacker->r.currentOrigin ) ) ) &&
00480             attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam) {
00481             AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_PROTECT_BONUS);
00482             attacker->client->pers.teamState.carrierdefense++;
00483 
00484             attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
00485             // add the sprite over the player's head
00486             attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00487             attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
00488             attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00489 
00490             return;
00491         }
00492     }
00493 }
00494 
00495 /*
00496 ================
00497 Team_CheckHurtCarrier
00498 
00499 Check to see if attacker hurt the flag carrier.  Needed when handing out bonuses for assistance to flag
00500 carrier defense.
00501 ================
00502 */
00503 void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker)
00504 {
00505     int flag_pw;
00506 
00507     if (!targ->client || !attacker->client)
00508         return;
00509 
00510     if (targ->client->sess.sessionTeam == TEAM_RED)
00511         flag_pw = PW_BLUEFLAG;
00512     else
00513         flag_pw = PW_REDFLAG;
00514 
00515     // flags
00516     if (targ->client->ps.powerups[flag_pw] &&
00517         targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
00518         attacker->client->pers.teamState.lasthurtcarrier = level.time;
00519 
00520     // skulls
00521     if (targ->client->ps.generic1 &&
00522         targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
00523         attacker->client->pers.teamState.lasthurtcarrier = level.time;
00524 }
00525 
00526 
00527 gentity_t *Team_ResetFlag( int team ) {
00528     char *c;
00529     gentity_t *ent, *rent = NULL;
00530 
00531     switch (team) {
00532     case TEAM_RED:
00533         c = "team_CTF_redflag";
00534         break;
00535     case TEAM_BLUE:
00536         c = "team_CTF_blueflag";
00537         break;
00538     case TEAM_FREE:
00539         c = "team_CTF_neutralflag";
00540         break;
00541     default:
00542         return NULL;
00543     }
00544 
00545     ent = NULL;
00546     while ((ent = G_Find (ent, FOFS(classname), c)) != NULL) {
00547         if (ent->flags & FL_DROPPED_ITEM)
00548             G_FreeEntity(ent);
00549         else {
00550             rent = ent;
00551             RespawnItem(ent);
00552         }
00553     }
00554 
00555     Team_SetFlagStatus( team, FLAG_ATBASE );
00556 
00557     return rent;
00558 }
00559 
00560 void Team_ResetFlags( void ) {
00561     if( g_gametype.integer == GT_CTF ) {
00562         Team_ResetFlag( TEAM_RED );
00563         Team_ResetFlag( TEAM_BLUE );
00564     }
00565 #ifdef MISSIONPACK
00566     else if( g_gametype.integer == GT_1FCTF ) {
00567         Team_ResetFlag( TEAM_FREE );
00568     }
00569 #endif
00570 }
00571 
00572 void Team_ReturnFlagSound( gentity_t *ent, int team ) {
00573     gentity_t   *te;
00574 
00575     if (ent == NULL) {
00576         G_Printf ("Warning:  NULL passed to Team_ReturnFlagSound\n");
00577         return;
00578     }
00579 
00580     te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
00581     if( team == TEAM_BLUE ) {
00582         te->s.eventParm = GTS_RED_RETURN;
00583     }
00584     else {
00585         te->s.eventParm = GTS_BLUE_RETURN;
00586     }
00587     te->r.svFlags |= SVF_BROADCAST;
00588 }
00589 
00590 void Team_TakeFlagSound( gentity_t *ent, int team ) {
00591     gentity_t   *te;
00592 
00593     if (ent == NULL) {
00594         G_Printf ("Warning:  NULL passed to Team_TakeFlagSound\n");
00595         return;
00596     }
00597 
00598     // only play sound when the flag was at the base
00599     // or not picked up the last 10 seconds
00600     switch(team) {
00601         case TEAM_RED:
00602             if( teamgame.blueStatus != FLAG_ATBASE ) {
00603                 if (teamgame.blueTakenTime > level.time - 10000)
00604                     return;
00605             }
00606             teamgame.blueTakenTime = level.time;
00607             break;
00608 
00609         case TEAM_BLUE: // CTF
00610             if( teamgame.redStatus != FLAG_ATBASE ) {
00611                 if (teamgame.redTakenTime > level.time - 10000)
00612                     return;
00613             }
00614             teamgame.redTakenTime = level.time;
00615             break;
00616     }
00617 
00618     te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
00619     if( team == TEAM_BLUE ) {
00620         te->s.eventParm = GTS_RED_TAKEN;
00621     }
00622     else {
00623         te->s.eventParm = GTS_BLUE_TAKEN;
00624     }
00625     te->r.svFlags |= SVF_BROADCAST;
00626 }
00627 
00628 void Team_CaptureFlagSound( gentity_t *ent, int team ) {
00629     gentity_t   *te;
00630 
00631     if (ent == NULL) {
00632         G_Printf ("Warning:  NULL passed to Team_CaptureFlagSound\n");
00633         return;
00634     }
00635 
00636     te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
00637     if( team == TEAM_BLUE ) {
00638         te->s.eventParm = GTS_BLUE_CAPTURE;
00639     }
00640     else {
00641         te->s.eventParm = GTS_RED_CAPTURE;
00642     }
00643     te->r.svFlags |= SVF_BROADCAST;
00644 }
00645 
00646 void Team_ReturnFlag( int team ) {
00647     Team_ReturnFlagSound(Team_ResetFlag(team), team);
00648     if( team == TEAM_FREE ) {
00649         PrintMsg(NULL, "The flag has returned!\n" );
00650     }
00651     else {
00652         PrintMsg(NULL, "The %s flag has returned!\n", TeamName(team));
00653     }
00654 }
00655 
00656 void Team_FreeEntity( gentity_t *ent ) {
00657     if( ent->item->giTag == PW_REDFLAG ) {
00658         Team_ReturnFlag( TEAM_RED );
00659     }
00660     else if( ent->item->giTag == PW_BLUEFLAG ) {
00661         Team_ReturnFlag( TEAM_BLUE );
00662     }
00663     else if( ent->item->giTag == PW_NEUTRALFLAG ) {
00664         Team_ReturnFlag( TEAM_FREE );
00665     }
00666 }
00667 
00668 /*
00669 ==============
00670 Team_DroppedFlagThink
00671 
00672 Automatically set in Launch_Item if the item is one of the flags
00673 
00674 Flags are unique in that if they are dropped, the base flag must be respawned when they time out
00675 ==============
00676 */
00677 void Team_DroppedFlagThink(gentity_t *ent) {
00678     int     team = TEAM_FREE;
00679 
00680     if( ent->item->giTag == PW_REDFLAG ) {
00681         team = TEAM_RED;
00682     }
00683     else if( ent->item->giTag == PW_BLUEFLAG ) {
00684         team = TEAM_BLUE;
00685     }
00686     else if( ent->item->giTag == PW_NEUTRALFLAG ) {
00687         team = TEAM_FREE;
00688     }
00689 
00690     Team_ReturnFlagSound( Team_ResetFlag( team ), team );
00691     // Reset Flag will delete this entity
00692 }
00693 
00694 
00695 /*
00696 ==============
00697 Team_DroppedFlagThink
00698 ==============
00699 */
00700 int Team_TouchOurFlag( gentity_t *ent, gentity_t *other, int team ) {
00701     int         i;
00702     gentity_t   *player;
00703     gclient_t   *cl = other->client;
00704     int         enemy_flag;
00705 
00706 #ifdef MISSIONPACK
00707     if( g_gametype.integer == GT_1FCTF ) {
00708         enemy_flag = PW_NEUTRALFLAG;
00709     }
00710     else {
00711 #endif
00712     if (cl->sess.sessionTeam == TEAM_RED) {
00713         enemy_flag = PW_BLUEFLAG;
00714     } else {
00715         enemy_flag = PW_REDFLAG;
00716     }
00717 
00718     if ( ent->flags & FL_DROPPED_ITEM ) {
00719         // hey, its not home.  return it by teleporting it back
00720         PrintMsg( NULL, "%s" S_COLOR_WHITE " returned the %s flag!\n", 
00721             cl->pers.netname, TeamName(team));
00722         AddScore(other, ent->r.currentOrigin, CTF_RECOVERY_BONUS);
00723         other->client->pers.teamState.flagrecovery++;
00724         other->client->pers.teamState.lastreturnedflag = level.time;
00725         //ResetFlag will remove this entity!  We must return zero
00726         Team_ReturnFlagSound(Team_ResetFlag(team), team);
00727         return 0;
00728     }
00729 #ifdef MISSIONPACK
00730     }
00731 #endif
00732 
00733     // the flag is at home base.  if the player has the enemy
00734     // flag, he's just won!
00735     if (!cl->ps.powerups[enemy_flag])
00736         return 0; // We don't have the flag
00737 #ifdef MISSIONPACK
00738     if( g_gametype.integer == GT_1FCTF ) {
00739         PrintMsg( NULL, "%s" S_COLOR_WHITE " captured the flag!\n", cl->pers.netname );
00740     }
00741     else {
00742 #endif
00743     PrintMsg( NULL, "%s" S_COLOR_WHITE " captured the %s flag!\n", cl->pers.netname, TeamName(OtherTeam(team)));
00744 #ifdef MISSIONPACK
00745     }
00746 #endif
00747 
00748     cl->ps.powerups[enemy_flag] = 0;
00749 
00750     teamgame.last_flag_capture = level.time;
00751     teamgame.last_capture_team = team;
00752 
00753     // Increase the team's score
00754     AddTeamScore(ent->s.pos.trBase, other->client->sess.sessionTeam, 1);
00755     Team_ForceGesture(other->client->sess.sessionTeam);
00756 
00757     other->client->pers.teamState.captures++;
00758     // add the sprite over the player's head
00759     other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00760     other->client->ps.eFlags |= EF_AWARD_CAP;
00761     other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00762     other->client->ps.persistant[PERS_CAPTURES]++;
00763 
00764     // other gets another 10 frag bonus
00765     AddScore(other, ent->r.currentOrigin, CTF_CAPTURE_BONUS);
00766 
00767     Team_CaptureFlagSound( ent, team );
00768 
00769     // Ok, let's do the player loop, hand out the bonuses
00770     for (i = 0; i < g_maxclients.integer; i++) {
00771         player = &g_entities[i];
00772         if (!player->inuse)
00773             continue;
00774 
00775         if (player->client->sess.sessionTeam !=
00776             cl->sess.sessionTeam) {
00777             player->client->pers.teamState.lasthurtcarrier = -5;
00778         } else if (player->client->sess.sessionTeam ==
00779             cl->sess.sessionTeam) {
00780             if (player != other)
00781                 AddScore(player, ent->r.currentOrigin, CTF_TEAM_BONUS);
00782             // award extra points for capture assists
00783             if (player->client->pers.teamState.lastreturnedflag + 
00784                 CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {
00785                 AddScore (player, ent->r.currentOrigin, CTF_RETURN_FLAG_ASSIST_BONUS);
00786                 other->client->pers.teamState.assists++;
00787 
00788                 player->client->ps.persistant[PERS_ASSIST_COUNT]++;
00789                 // add the sprite over the player's head
00790                 player->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00791                 player->client->ps.eFlags |= EF_AWARD_ASSIST;
00792                 player->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00793 
00794             } else if (player->client->pers.teamState.lastfraggedcarrier + 
00795                 CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {
00796                 AddScore(player, ent->r.currentOrigin, CTF_FRAG_CARRIER_ASSIST_BONUS);
00797                 other->client->pers.teamState.assists++;
00798                 player->client->ps.persistant[PERS_ASSIST_COUNT]++;
00799                 // add the sprite over the player's head
00800                 player->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
00801                 player->client->ps.eFlags |= EF_AWARD_ASSIST;
00802                 player->client->rewardTime = level.time + REWARD_SPRITE_TIME;
00803             }
00804         }
00805     }
00806     Team_ResetFlags();
00807 
00808     CalculateRanks();
00809 
00810     return 0; // Do not respawn this automatically
00811 }
00812 
00813 int Team_TouchEnemyFlag( gentity_t *ent, gentity_t *other, int team ) {
00814     gclient_t *cl = other->client;
00815 
00816 #ifdef MISSIONPACK
00817     if( g_gametype.integer == GT_1FCTF ) {
00818         PrintMsg (NULL, "%s" S_COLOR_WHITE " got the flag!\n", other->client->pers.netname );
00819 
00820         cl->ps.powerups[PW_NEUTRALFLAG] = INT_MAX; // flags never expire
00821 
00822         if( team == TEAM_RED ) {
00823             Team_SetFlagStatus( TEAM_FREE, FLAG_TAKEN_RED );
00824         }
00825         else {
00826             Team_SetFlagStatus( TEAM_FREE, FLAG_TAKEN_BLUE );
00827         }
00828     }
00829     else{
00830 #endif
00831         PrintMsg (NULL, "%s" S_COLOR_WHITE " got the %s flag!\n",
00832             other->client->pers.netname, TeamName(team));
00833 
00834         if (team == TEAM_RED)
00835             cl->ps.powerups[PW_REDFLAG] = INT_MAX; // flags never expire
00836         else
00837             cl->ps.powerups[PW_BLUEFLAG] = INT_MAX; // flags never expire
00838 
00839         Team_SetFlagStatus( team, FLAG_TAKEN );
00840 #ifdef MISSIONPACK
00841     }
00842 #endif
00843 
00844     AddScore(other, ent->r.currentOrigin, CTF_FLAG_BONUS);
00845     cl->pers.teamState.flagsince = level.time;
00846     Team_TakeFlagSound( ent, team );
00847 
00848     return -1; // Do not respawn this automatically, but do delete it if it was FL_DROPPED
00849 }
00850 
00851 int Pickup_Team( gentity_t *ent, gentity_t *other ) {
00852     int team;
00853     gclient_t *cl = other->client;
00854 
00855 #ifdef MISSIONPACK
00856     if( g_gametype.integer == GT_OBELISK ) {
00857         // there are no team items that can be picked up in obelisk
00858         G_FreeEntity( ent );
00859         return 0;
00860     }
00861 
00862     if( g_gametype.integer == GT_HARVESTER ) {
00863         // the only team items that can be picked up in harvester are the cubes
00864         if( ent->spawnflags != cl->sess.sessionTeam ) {
00865             cl->ps.generic1 += 1;
00866         }
00867         G_FreeEntity( ent );
00868         return 0;
00869     }
00870 #endif
00871     // figure out what team this flag is
00872     if( strcmp(ent->classname, "team_CTF_redflag") == 0 ) {
00873         team = TEAM_RED;
00874     }
00875     else if( strcmp(ent->classname, "team_CTF_blueflag") == 0 ) {
00876         team = TEAM_BLUE;
00877     }
00878 #ifdef MISSIONPACK
00879     else if( strcmp(ent->classname, "team_CTF_neutralflag") == 0  ) {
00880         team = TEAM_FREE;
00881     }
00882 #endif
00883     else {
00884         PrintMsg ( other, "Don't know what team the flag is on.\n");
00885         return 0;
00886     }
00887 #ifdef MISSIONPACK
00888     if( g_gametype.integer == GT_1FCTF ) {
00889         if( team == TEAM_FREE ) {
00890             return Team_TouchEnemyFlag( ent, other, cl->sess.sessionTeam );
00891         }
00892         if( team != cl->sess.sessionTeam) {
00893             return Team_TouchOurFlag( ent, other, cl->sess.sessionTeam );
00894         }
00895         return 0;
00896     }
00897 #endif
00898     // GT_CTF
00899     if( team == cl->sess.sessionTeam) {
00900         return Team_TouchOurFlag( ent, other, team );
00901     }
00902     return Team_TouchEnemyFlag( ent, other, team );
00903 }
00904 
00905 /*
00906 ===========
00907 Team_GetLocation
00908 
00909 Report a location for the player. Uses placed nearby target_location entities
00910 ============
00911 */
00912 gentity_t *Team_GetLocation(gentity_t *ent)
00913 {
00914     gentity_t       *eloc, *best;
00915     float           bestlen, len;
00916     vec3_t          origin;
00917 
00918     best = NULL;
00919     bestlen = 3*8192.0*8192.0;
00920 
00921     VectorCopy( ent->r.currentOrigin, origin );
00922 
00923     for (eloc = level.locationHead; eloc; eloc = eloc->nextTrain) {
00924         len = ( origin[0] - eloc->r.currentOrigin[0] ) * ( origin[0] - eloc->r.currentOrigin[0] )
00925             + ( origin[1] - eloc->r.currentOrigin[1] ) * ( origin[1] - eloc->r.currentOrigin[1] )
00926             + ( origin[2] - eloc->r.currentOrigin[2] ) * ( origin[2] - eloc->r.currentOrigin[2] );
00927 
00928         if ( len > bestlen ) {
00929             continue;
00930         }
00931 
00932         if ( !trap_InPVS( origin, eloc->r.currentOrigin ) ) {
00933             continue;
00934         }
00935 
00936         bestlen = len;
00937         best = eloc;
00938     }
00939 
00940     return best;
00941 }
00942 
00943 
00944 /*
00945 ===========
00946 Team_GetLocation
00947 
00948 Report a location for the player. Uses placed nearby target_location entities
00949 ============
00950 */
00951 qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen)
00952 {
00953     gentity_t *best;
00954 
00955     best = Team_GetLocation( ent );
00956     
00957     if (!best)
00958         return qfalse;
00959 
00960     if (best->count) {
00961         if (best->count < 0)
00962             best->count = 0;
00963         if (best->count > 7)
00964             best->count = 7;
00965         Com_sprintf(loc, loclen, "%c%c%s" S_COLOR_WHITE, Q_COLOR_ESCAPE, best->count + '0', best->message );
00966     } else
00967         Com_sprintf(loc, loclen, "%s", best->message);
00968 
00969     return qtrue;
00970 }
00971 
00972 
00973 /*---------------------------------------------------------------------------*/
00974 
00975 /*
00976 ================
00977 SelectRandomDeathmatchSpawnPoint
00978 
00979 go to a random point that doesn't telefrag
00980 ================
00981 */
00982 #define MAX_TEAM_SPAWN_POINTS   32
00983 gentity_t *SelectRandomTeamSpawnPoint( int teamstate, team_t team ) {
00984     gentity_t   *spot;
00985     int         count;
00986     int         selection;
00987     gentity_t   *spots[MAX_TEAM_SPAWN_POINTS];
00988     char        *classname;
00989 
00990     if (teamstate == TEAM_BEGIN) {
00991         if (team == TEAM_RED)
00992             classname = "team_CTF_redplayer";
00993         else if (team == TEAM_BLUE)
00994             classname = "team_CTF_blueplayer";
00995         else
00996             return NULL;
00997     } else {
00998         if (team == TEAM_RED)
00999             classname = "team_CTF_redspawn";
01000         else if (team == TEAM_BLUE)
01001             classname = "team_CTF_bluespawn";
01002         else
01003             return NULL;
01004     }
01005     count = 0;
01006 
01007     spot = NULL;
01008 
01009     while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
01010         if ( SpotWouldTelefrag( spot ) ) {
01011             continue;
01012         }
01013         spots[ count ] = spot;
01014         if (++count == MAX_TEAM_SPAWN_POINTS)
01015             break;
01016     }
01017 
01018     if ( !count ) { // no spots that won't telefrag
01019         return G_Find( NULL, FOFS(classname), classname);
01020     }
01021 
01022     selection = rand() % count;
01023     return spots[ selection ];
01024 }
01025 
01026 
01027 /*
01028 ===========
01029 SelectCTFSpawnPoint
01030 
01031 ============
01032 */
01033 gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles ) {
01034     gentity_t   *spot;
01035 
01036     spot = SelectRandomTeamSpawnPoint ( teamstate, team );
01037 
01038     if (!spot) {
01039         return SelectSpawnPoint( vec3_origin, origin, angles );
01040     }
01041 
01042     VectorCopy (spot->s.origin, origin);
01043     origin[2] += 9;
01044     VectorCopy (spot->s.angles, angles);
01045 
01046     return spot;
01047 }
01048 
01049 /*---------------------------------------------------------------------------*/
01050 
01051 static int QDECL SortClients( const void *a, const void *b ) {
01052     return *(int *)a - *(int *)b;
01053 }
01054 
01055 
01056 /*
01057 ==================
01058 TeamplayLocationsMessage
01059 
01060 Format:
01061     clientNum location health armor weapon powerups
01062 
01063 ==================
01064 */
01065 void TeamplayInfoMessage( gentity_t *ent ) {
01066     char        entry[1024];
01067     char        string[8192];
01068     int         stringlength;
01069     int         i, j;
01070     gentity_t   *player;
01071     int         cnt;
01072     int         h, a;
01073     int         clients[TEAM_MAXOVERLAY];
01074 
01075     if ( ! ent->client->pers.teamInfo )
01076         return;
01077 
01078     // figure out what client should be on the display
01079     // we are limited to 8, but we want to use the top eight players
01080     // but in client order (so they don't keep changing position on the overlay)
01081     for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
01082         player = g_entities + level.sortedClients[i];
01083         if (player->inuse && player->client->sess.sessionTeam == 
01084             ent->client->sess.sessionTeam ) {
01085             clients[cnt++] = level.sortedClients[i];
01086         }
01087     }
01088 
01089     // We have the top eight players, sort them by clientNum
01090     qsort( clients, cnt, sizeof( clients[0] ), SortClients );
01091 
01092     // send the latest information on all clients
01093     string[0] = 0;
01094     stringlength = 0;
01095 
01096     for (i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
01097         player = g_entities + i;
01098         if (player->inuse && player->client->sess.sessionTeam == 
01099             ent->client->sess.sessionTeam ) {
01100 
01101             h = player->client->ps.stats[STAT_HEALTH];
01102             a = player->client->ps.stats[STAT_ARMOR];
01103             if (h < 0) h = 0;
01104             if (a < 0) a = 0;
01105 
01106             Com_sprintf (entry, sizeof(entry),
01107                 " %i %i %i %i %i %i", 
01108 //              level.sortedClients[i], player->client->pers.teamState.location, h, a, 
01109                 i, player->client->pers.teamState.location, h, a, 
01110                 player->client->ps.weapon, player->s.powerups);
01111             j = strlen(entry);
01112             if (stringlength + j > sizeof(string))
01113                 break;
01114             strcpy (string + stringlength, entry);
01115             stringlength += j;
01116             cnt++;
01117         }
01118     }
01119 
01120     trap_SendServerCommand( ent-g_entities, va("tinfo %i %s", cnt, string) );
01121 }
01122 
01123 void CheckTeamStatus(void) {
01124     int i;
01125     gentity_t *loc, *ent;
01126 
01127     if (level.time - level.lastTeamLocationTime > TEAM_LOCATION_UPDATE_TIME) {
01128 
01129         level.lastTeamLocationTime = level.time;
01130 
01131         for (i = 0; i < g_maxclients.integer; i++) {
01132             ent = g_entities + i;
01133 
01134             if ( ent->client->pers.connected != CON_CONNECTED ) {
01135                 continue;
01136             }
01137 
01138             if (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
01139                 loc = Team_GetLocation( ent );
01140                 if (loc)
01141                     ent->client->pers.teamState.location = loc->health;
01142                 else
01143                     ent->client->pers.teamState.location = 0;
01144             }
01145         }
01146 
01147         for (i = 0; i < g_maxclients.integer; i++) {
01148             ent = g_entities + i;
01149 
01150             if ( ent->client->pers.connected != CON_CONNECTED ) {
01151                 continue;
01152             }
01153 
01154             if (ent->inuse && (ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
01155                 TeamplayInfoMessage( ent );
01156             }
01157         }
01158     }
01159 }
01160 
01161 /*-----------------------------------------------------------------*/
01162 
01163 /*QUAKED team_CTF_redplayer (1 0 0) (-16 -16 -16) (16 16 32)
01164 Only in CTF games.  Red players spawn here at game start.
01165 */
01166 void SP_team_CTF_redplayer( gentity_t *ent ) {
01167 }
01168 
01169 
01170 /*QUAKED team_CTF_blueplayer (0 0 1) (-16 -16 -16) (16 16 32)
01171 Only in CTF games.  Blue players spawn here at game start.
01172 */
01173 void SP_team_CTF_blueplayer( gentity_t *ent ) {
01174 }
01175 
01176 
01177 /*QUAKED team_CTF_redspawn (1 0 0) (-16 -16 -24) (16 16 32)
01178 potential spawning position for red team in CTF games.
01179 Targets will be fired when someone spawns in on them.
01180 */
01181 void SP_team_CTF_redspawn(gentity_t *ent) {
01182 }
01183 
01184 /*QUAKED team_CTF_bluespawn (0 0 1) (-16 -16 -24) (16 16 32)
01185 potential spawning position for blue team in CTF games.
01186 Targets will be fired when someone spawns in on them.
01187 */
01188 void SP_team_CTF_bluespawn(gentity_t *ent) {
01189 }
01190 
01191 
01192 #ifdef MISSIONPACK
01193 /*
01194 ================
01195 Obelisks
01196 ================
01197 */
01198 
01199 static void ObeliskRegen( gentity_t *self ) {
01200     self->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
01201     if( self->health >= g_obeliskHealth.integer ) {
01202         return;
01203     }
01204 
01205     G_AddEvent( self, EV_POWERUP_REGEN, 0 );
01206     self->health += g_obeliskRegenAmount.integer;
01207     if ( self->health > g_obeliskHealth.integer ) {
01208         self->health = g_obeliskHealth.integer;
01209     }
01210 
01211     self->activator->s.modelindex2 = self->health * 0xff / g_obeliskHealth.integer;
01212     self->activator->s.frame = 0;
01213 }
01214 
01215 
01216 static void ObeliskRespawn( gentity_t *self ) {
01217     self->takedamage = qtrue;
01218     self->health = g_obeliskHealth.integer;
01219 
01220     self->think = ObeliskRegen;
01221     self->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
01222 
01223     self->activator->s.frame = 0;
01224 }
01225 
01226 
01227 static void ObeliskDie( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
01228     int         otherTeam;
01229 
01230     otherTeam = OtherTeam( self->spawnflags );
01231     AddTeamScore(self->s.pos.trBase, otherTeam, 1);
01232     Team_ForceGesture(otherTeam);
01233 
01234     CalculateRanks();
01235 
01236     self->takedamage = qfalse;
01237     self->think = ObeliskRespawn;
01238     self->nextthink = level.time + g_obeliskRespawnDelay.integer * 1000;
01239 
01240     self->activator->s.modelindex2 = 0xff;
01241     self->activator->s.frame = 2;
01242 
01243     G_AddEvent( self->activator, EV_OBELISKEXPLODE, 0 );
01244 
01245     AddScore(attacker, self->r.currentOrigin, CTF_CAPTURE_BONUS);
01246 
01247     // add the sprite over the player's head
01248     attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
01249     attacker->client->ps.eFlags |= EF_AWARD_CAP;
01250     attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
01251     attacker->client->ps.persistant[PERS_CAPTURES]++;
01252 
01253     teamgame.redObeliskAttackedTime = 0;
01254     teamgame.blueObeliskAttackedTime = 0;
01255 }
01256 
01257 
01258 static void ObeliskTouch( gentity_t *self, gentity_t *other, trace_t *trace ) {
01259     int         tokens;
01260 
01261     if ( !other->client ) {
01262         return;
01263     }
01264 
01265     if ( OtherTeam(other->client->sess.sessionTeam) != self->spawnflags ) {
01266         return;
01267     }
01268 
01269     tokens = other->client->ps.generic1;
01270     if( tokens <= 0 ) {
01271         return;
01272     }
01273 
01274     PrintMsg(NULL, "%s" S_COLOR_WHITE " brought in %i skull%s.\n",
01275                     other->client->pers.netname, tokens, tokens ? "s" : "" );
01276 
01277     AddTeamScore(self->s.pos.trBase, other->client->sess.sessionTeam, tokens);
01278     Team_ForceGesture(other->client->sess.sessionTeam);
01279 
01280     AddScore(other, self->r.currentOrigin, CTF_CAPTURE_BONUS*tokens);
01281 
01282     // add the sprite over the player's head
01283     other->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
01284     other->client->ps.eFlags |= EF_AWARD_CAP;
01285     other->client->rewardTime = level.time + REWARD_SPRITE_TIME;
01286     other->client->ps.persistant[PERS_CAPTURES] += tokens;
01287     
01288     other->client->ps.generic1 = 0;
01289     CalculateRanks();
01290 
01291     Team_CaptureFlagSound( self, self->spawnflags );
01292 }
01293 
01294 static void ObeliskPain( gentity_t *self, gentity_t *attacker, int damage ) {
01295     int actualDamage = damage / 10;
01296     if (actualDamage <= 0) {
01297         actualDamage = 1;
01298     }
01299     self->activator->s.modelindex2 = self->health * 0xff / g_obeliskHealth.integer;
01300     if (!self->activator->s.frame) {
01301         G_AddEvent(self, EV_OBELISKPAIN, 0);
01302     }
01303     self->activator->s.frame = 1;
01304     AddScore(attacker, self->r.currentOrigin, actualDamage);
01305 }
01306 
01307 gentity_t *SpawnObelisk( vec3_t origin, int team, int spawnflags) {
01308     trace_t     tr;
01309     vec3_t      dest;
01310     gentity_t   *ent;
01311 
01312     ent = G_Spawn();
01313 
01314     VectorCopy( origin, ent->s.origin );
01315     VectorCopy( origin, ent->s.pos.trBase );
01316     VectorCopy( origin, ent->r.currentOrigin );
01317 
01318     VectorSet( ent->r.mins, -15, -15, 0 );
01319     VectorSet( ent->r.maxs, 15, 15, 87 );
01320 
01321     ent->s.eType = ET_GENERAL;
01322     ent->flags = FL_NO_KNOCKBACK;
01323 
01324     if( g_gametype.integer == GT_OBELISK ) {
01325         ent->r.contents = CONTENTS_SOLID;
01326         ent->takedamage = qtrue;
01327         ent->health = g_obeliskHealth.integer;
01328         ent->die = ObeliskDie;
01329         ent->pain = ObeliskPain;
01330         ent->think = ObeliskRegen;
01331         ent->nextthink = level.time + g_obeliskRegenPeriod.integer * 1000;
01332     }
01333     if( g_gametype.integer == GT_HARVESTER ) {
01334         ent->r.contents = CONTENTS_TRIGGER;
01335         ent->touch = ObeliskTouch;
01336     }
01337 
01338     if ( spawnflags & 1 ) {
01339         // suspended
01340         G_SetOrigin( ent, ent->s.origin );
01341     } else {
01342         // mappers like to put them exactly on the floor, but being coplanar
01343         // will sometimes show up as starting in solid, so lif it up one pixel
01344         ent->s.origin[2] += 1;
01345 
01346         // drop to floor
01347         VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
01348         trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
01349         if ( tr.startsolid ) {
01350             ent->s.origin[2] -= 1;
01351             G_Printf( "SpawnObelisk: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin) );
01352 
01353             ent->s.groundEntityNum = ENTITYNUM_NONE;
01354             G_SetOrigin( ent, ent->s.origin );
01355         }
01356         else {
01357             // allow to ride movers
01358             ent->s.groundEntityNum = tr.entityNum;
01359             G_SetOrigin( ent, tr.endpos );
01360         }
01361     }
01362 
01363     ent->spawnflags = team;
01364 
01365     trap_LinkEntity( ent );
01366 
01367     return ent;
01368 }
01369 
01370 /*QUAKED team_redobelisk (1 0 0) (-16 -16 0) (16 16 8)
01371 */
01372 void SP_team_redobelisk( gentity_t *ent ) {
01373     gentity_t *obelisk;
01374 
01375     if ( g_gametype.integer <= GT_TEAM ) {
01376         G_FreeEntity(ent);
01377         return;
01378     }
01379     ent->s.eType = ET_TEAM;
01380     if ( g_gametype.integer == GT_OBELISK ) {
01381         obelisk = SpawnObelisk( ent->s.origin, TEAM_RED, ent->spawnflags );
01382         obelisk->activator = ent;
01383         // initial obelisk health value
01384         ent->s.modelindex2 = 0xff;
01385         ent->s.frame = 0;
01386     }
01387     if ( g_gametype.integer == GT_HARVESTER ) {
01388         obelisk = SpawnObelisk( ent->s.origin, TEAM_RED, ent->spawnflags );
01389         obelisk->activator = ent;
01390     }
01391     ent->s.modelindex = TEAM_RED;
01392     trap_LinkEntity(ent);
01393 }
01394 
01395 /*QUAKED team_blueobelisk (0 0 1) (-16 -16 0) (16 16 88)
01396 */
01397 void SP_team_blueobelisk( gentity_t *ent ) {
01398     gentity_t *obelisk;
01399 
01400     if ( g_gametype.integer <= GT_TEAM ) {
01401         G_FreeEntity(ent);
01402         return;
01403     }
01404     ent->s.eType = ET_TEAM;
01405     if ( g_gametype.integer == GT_OBELISK ) {
01406         obelisk = SpawnObelisk( ent->s.origin, TEAM_BLUE, ent->spawnflags );
01407         obelisk->activator = ent;
01408         // initial obelisk health value
01409         ent->s.modelindex2 = 0xff;
01410         ent->s.frame = 0;
01411     }
01412     if ( g_gametype.integer == GT_HARVESTER ) {
01413         obelisk = SpawnObelisk( ent->s.origin, TEAM_BLUE, ent->spawnflags );
01414         obelisk->activator = ent;
01415     }
01416     ent->s.modelindex = TEAM_BLUE;
01417     trap_LinkEntity(ent);
01418 }
01419 
01420 /*QUAKED team_neutralobelisk (0 0 1) (-16 -16 0) (16 16 88)
01421 */
01422 void SP_team_neutralobelisk( gentity_t *ent ) {
01423     if ( g_gametype.integer != GT_1FCTF && g_gametype.integer != GT_HARVESTER ) {
01424         G_FreeEntity(ent);
01425         return;
01426     }
01427     ent->s.eType = ET_TEAM;
01428     if ( g_gametype.integer == GT_HARVESTER) {
01429         neutralObelisk = SpawnObelisk( ent->s.origin, TEAM_FREE, ent->spawnflags);
01430         neutralObelisk->spawnflags = TEAM_FREE;
01431     }
01432     ent->s.modelindex = TEAM_FREE;
01433     trap_LinkEntity(ent);
01434 }
01435 
01436 
01437 /*
01438 ================
01439 CheckObeliskAttack
01440 ================
01441 */
01442 qboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker ) {
01443     gentity_t   *te;
01444 
01445     // if this really is an obelisk
01446     if( obelisk->die != ObeliskDie ) {
01447         return qfalse;
01448     }
01449 
01450     // if the attacker is a client
01451     if( !attacker->client ) {
01452         return qfalse;
01453     }
01454 
01455     // if the obelisk is on the same team as the attacker then don't hurt it
01456     if( obelisk->spawnflags == attacker->client->sess.sessionTeam ) {
01457         return qtrue;
01458     }
01459 
01460     // obelisk may be hurt
01461 
01462     // if not played any sounds recently
01463     if ((obelisk->spawnflags == TEAM_RED &&
01464         teamgame.redObeliskAttackedTime < level.time - OVERLOAD_ATTACK_BASE_SOUND_TIME) ||
01465         (obelisk->spawnflags == TEAM_BLUE &&
01466         teamgame.blueObeliskAttackedTime < level.time - OVERLOAD_ATTACK_BASE_SOUND_TIME) ) {
01467 
01468         // tell which obelisk is under attack
01469         te = G_TempEntity( obelisk->s.pos.trBase, EV_GLOBAL_TEAM_SOUND );
01470         if( obelisk->spawnflags == TEAM_RED ) {
01471             te->s.eventParm = GTS_REDOBELISK_ATTACKED;
01472             teamgame.redObeliskAttackedTime = level.time;
01473         }
01474         else {
01475             te->s.eventParm = GTS_BLUEOBELISK_ATTACKED;
01476             teamgame.blueObeliskAttackedTime = level.time;
01477         }
01478         te->r.svFlags |= SVF_BROADCAST;
01479     }
01480 
01481     return qfalse;
01482 }
01483 #endif

Generated on Thu Aug 25 12:37:33 2005 for Quake III Arena by  doxygen 1.3.9.1