00001
00002
00003 #include "g_local.h"
00004 #include "../ghoul2/G2.h"
00005 #include "bg_saga.h"
00006
00007
00008
00009 static vec3_t playerMins = {-15, -15, DEFAULT_MINS_2};
00010 static vec3_t playerMaxs = {15, 15, DEFAULT_MAXS_2};
00011
00012 extern int g_siegeRespawnCheck;
00013
00014 void WP_SaberAddG2Model( gentity_t *saberent, const char *saberModel, qhandle_t saberSkin );
00015 void WP_SaberRemoveG2Model( gentity_t *saberent );
00016 extern qboolean WP_SaberStyleValidForSaber( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int saberAnimLevel );
00017 extern qboolean WP_UseFirstValidSaberStyle( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int *saberAnimLevel );
00018
00019 forcedata_t Client_Force[MAX_CLIENTS];
00020
00021
00022
00023
00024
00025
00026
00027 void SP_info_player_duel( gentity_t *ent )
00028 {
00029 int i;
00030
00031 G_SpawnInt( "nobots", "0", &i);
00032 if ( i ) {
00033 ent->flags |= FL_NO_BOTS;
00034 }
00035 G_SpawnInt( "nohumans", "0", &i );
00036 if ( i ) {
00037 ent->flags |= FL_NO_HUMANS;
00038 }
00039 }
00040
00041
00042
00043
00044
00045
00046
00047 void SP_info_player_duel1( gentity_t *ent )
00048 {
00049 int i;
00050
00051 G_SpawnInt( "nobots", "0", &i);
00052 if ( i ) {
00053 ent->flags |= FL_NO_BOTS;
00054 }
00055 G_SpawnInt( "nohumans", "0", &i );
00056 if ( i ) {
00057 ent->flags |= FL_NO_HUMANS;
00058 }
00059 }
00060
00061
00062
00063
00064
00065
00066
00067 void SP_info_player_duel2( gentity_t *ent )
00068 {
00069 int i;
00070
00071 G_SpawnInt( "nobots", "0", &i);
00072 if ( i ) {
00073 ent->flags |= FL_NO_BOTS;
00074 }
00075 G_SpawnInt( "nohumans", "0", &i );
00076 if ( i ) {
00077 ent->flags |= FL_NO_HUMANS;
00078 }
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088 void SP_info_player_deathmatch( gentity_t *ent ) {
00089 int i;
00090
00091 G_SpawnInt( "nobots", "0", &i);
00092 if ( i ) {
00093 ent->flags |= FL_NO_BOTS;
00094 }
00095 G_SpawnInt( "nohumans", "0", &i );
00096 if ( i ) {
00097 ent->flags |= FL_NO_HUMANS;
00098 }
00099 }
00100
00101
00102
00103
00104
00105 void SP_info_player_start(gentity_t *ent) {
00106 ent->classname = "info_player_deathmatch";
00107 SP_info_player_deathmatch( ent );
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 void SP_info_player_start_red(gentity_t *ent) {
00122 SP_info_player_deathmatch( ent );
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 void SP_info_player_start_blue(gentity_t *ent) {
00137 SP_info_player_deathmatch( ent );
00138 }
00139
00140 void SiegePointUse( gentity_t *self, gentity_t *other, gentity_t *activator )
00141 {
00142
00143 if (self->genericValue1)
00144 {
00145 self->genericValue1 = 0;
00146 }
00147 else
00148 {
00149 self->genericValue1 = 1;
00150 }
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 void SP_info_player_siegeteam1(gentity_t *ent) {
00165 int soff = 0;
00166
00167 if (g_gametype.integer != GT_SIEGE)
00168 {
00169 ent->classname = "info_player_deathmatch";
00170 SP_info_player_deathmatch( ent );
00171
00172 return;
00173 }
00174
00175 G_SpawnInt("startoff", "0", &soff);
00176
00177 if (soff)
00178 {
00179 ent->genericValue1 = 0;
00180 }
00181 else
00182 {
00183 ent->genericValue1 = 1;
00184 }
00185
00186 ent->use = SiegePointUse;
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 void SP_info_player_siegeteam2(gentity_t *ent) {
00201 int soff = 0;
00202
00203 if (g_gametype.integer != GT_SIEGE)
00204 {
00205 ent->classname = "info_player_deathmatch";
00206 SP_info_player_deathmatch( ent );
00207
00208 return;
00209 }
00210
00211 G_SpawnInt("startoff", "0", &soff);
00212
00213 if (soff)
00214 {
00215 ent->genericValue1 = 0;
00216 }
00217 else
00218 {
00219 ent->genericValue1 = 1;
00220 }
00221
00222 ent->use = SiegePointUse;
00223 }
00224
00225
00226
00227
00228
00229
00230 void SP_info_player_intermission( gentity_t *ent ) {
00231
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241 void SP_info_player_intermission_red( gentity_t *ent ) {
00242
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252 void SP_info_player_intermission_blue( gentity_t *ent ) {
00253
00254 }
00255
00256 #define JMSABER_RESPAWN_TIME 20000 //in case it gets stuck somewhere no one can reach
00257
00258 void ThrowSaberToAttacker(gentity_t *self, gentity_t *attacker)
00259 {
00260 gentity_t *ent = &g_entities[self->client->ps.saberIndex];
00261 vec3_t a;
00262 int altVelocity = 0;
00263
00264 if (!ent || ent->enemy != self)
00265 {
00266
00267 #ifdef _DEBUG
00268 Com_Printf("Lost the saber! Attempting to use global pointer..\n");
00269 #endif
00270 ent = gJMSaberEnt;
00271
00272 if (!ent)
00273 {
00274 #ifdef _DEBUG
00275 Com_Printf("The global pointer was NULL. This is a bad thing.\n");
00276 #endif
00277 return;
00278 }
00279
00280 #ifdef _DEBUG
00281 Com_Printf("Got it (%i). Setting enemy to client %i.\n", ent->s.number, self->s.number);
00282 #endif
00283
00284 ent->enemy = self;
00285 self->client->ps.saberIndex = ent->s.number;
00286 }
00287
00288 trap_SetConfigstring ( CS_CLIENT_JEDIMASTER, "-1" );
00289
00290 if (attacker && attacker->client && self->client->ps.saberInFlight)
00291 {
00292
00293
00294 gentity_t *flyingsaber = &g_entities[self->client->ps.saberEntityNum];
00295
00296 if (flyingsaber && flyingsaber->inuse)
00297 {
00298 VectorCopy(flyingsaber->s.pos.trBase, ent->s.pos.trBase);
00299 VectorCopy(flyingsaber->s.pos.trDelta, ent->s.pos.trDelta);
00300 VectorCopy(flyingsaber->s.apos.trBase, ent->s.apos.trBase);
00301 VectorCopy(flyingsaber->s.apos.trDelta, ent->s.apos.trDelta);
00302
00303 VectorCopy(flyingsaber->r.currentOrigin, ent->r.currentOrigin);
00304 VectorCopy(flyingsaber->r.currentAngles, ent->r.currentAngles);
00305 altVelocity = 1;
00306 }
00307 }
00308
00309 self->client->ps.saberInFlight = qtrue;
00310
00311 WP_SaberAddG2Model( ent, self->client->saber[0].model, self->client->saber[0].skin );
00312
00313 ent->s.eFlags &= ~(EF_NODRAW);
00314 ent->s.modelGhoul2 = 1;
00315 ent->s.eType = ET_MISSILE;
00316 ent->enemy = NULL;
00317
00318 if (!attacker || !attacker->client)
00319 {
00320 VectorCopy(ent->s.origin2, ent->s.pos.trBase);
00321 VectorCopy(ent->s.origin2, ent->s.origin);
00322 VectorCopy(ent->s.origin2, ent->r.currentOrigin);
00323 ent->pos2[0] = 0;
00324 trap_LinkEntity(ent);
00325 return;
00326 }
00327
00328 if (!altVelocity)
00329 {
00330 VectorCopy(self->s.pos.trBase, ent->s.pos.trBase);
00331 VectorCopy(self->s.pos.trBase, ent->s.origin);
00332 VectorCopy(self->s.pos.trBase, ent->r.currentOrigin);
00333
00334 VectorSubtract(attacker->client->ps.origin, ent->s.pos.trBase, a);
00335
00336 VectorNormalize(a);
00337
00338 ent->s.pos.trDelta[0] = a[0]*256;
00339 ent->s.pos.trDelta[1] = a[1]*256;
00340 ent->s.pos.trDelta[2] = 256;
00341 }
00342
00343 trap_LinkEntity(ent);
00344 }
00345
00346 void JMSaberThink(gentity_t *ent)
00347 {
00348 gJMSaberEnt = ent;
00349
00350 if (ent->enemy)
00351 {
00352 if (!ent->enemy->client || !ent->enemy->inuse)
00353 {
00354 VectorCopy(ent->enemy->s.pos.trBase, ent->s.pos.trBase);
00355 VectorCopy(ent->enemy->s.pos.trBase, ent->s.origin);
00356 VectorCopy(ent->enemy->s.pos.trBase, ent->r.currentOrigin);
00357 ent->s.modelindex = G_ModelIndex("models/weapons2/saber/saber_w.glm");
00358 ent->s.eFlags &= ~(EF_NODRAW);
00359 ent->s.modelGhoul2 = 1;
00360 ent->s.eType = ET_MISSILE;
00361 ent->enemy = NULL;
00362
00363 ent->pos2[0] = 1;
00364 ent->pos2[1] = 0;
00365 trap_LinkEntity(ent);
00366 }
00367 else
00368 {
00369 ent->pos2[1] = level.time + JMSABER_RESPAWN_TIME;
00370 }
00371 }
00372 else if (ent->pos2[0] && ent->pos2[1] < level.time)
00373 {
00374 VectorCopy(ent->s.origin2, ent->s.pos.trBase);
00375 VectorCopy(ent->s.origin2, ent->s.origin);
00376 VectorCopy(ent->s.origin2, ent->r.currentOrigin);
00377 ent->pos2[0] = 0;
00378 trap_LinkEntity(ent);
00379 }
00380
00381 ent->nextthink = level.time + 50;
00382 G_RunObject(ent);
00383 }
00384
00385 void JMSaberTouch(gentity_t *self, gentity_t *other, trace_t *trace)
00386 {
00387 int i = 0;
00388
00389
00390 if (!other || !other->client || other->health < 1)
00391 {
00392 return;
00393 }
00394
00395 if (self->enemy)
00396 {
00397 return;
00398 }
00399
00400 if (!self->s.modelindex)
00401 {
00402 return;
00403 }
00404
00405 if (other->client->ps.stats[STAT_WEAPONS] & (1 << WP_SABER))
00406 {
00407 return;
00408 }
00409
00410 if (other->client->ps.isJediMaster)
00411 {
00412 return;
00413 }
00414
00415 self->enemy = other;
00416 other->client->ps.stats[STAT_WEAPONS] = (1 << WP_SABER);
00417 other->client->ps.weapon = WP_SABER;
00418 other->s.weapon = WP_SABER;
00419 G_AddEvent(other, EV_BECOME_JEDIMASTER, 0);
00420
00421
00422 trap_SetConfigstring ( CS_CLIENT_JEDIMASTER, va("%i", other->s.number ) );
00423
00424 if (g_spawnInvulnerability.integer)
00425 {
00426 other->client->ps.eFlags |= EF_INVULNERABLE;
00427 other->client->invulnerableTimer = level.time + g_spawnInvulnerability.integer;
00428 }
00429
00430 trap_SendServerCommand( -1, va("cp \"%s %s\n\"", other->client->pers.netname, G_GetStringEdString("MP_SVGAME", "BECOMEJM")) );
00431
00432 other->client->ps.isJediMaster = qtrue;
00433 other->client->ps.saberIndex = self->s.number;
00434
00435 if (other->health < 200 && other->health > 0)
00436 {
00437 other->client->ps.stats[STAT_HEALTH] = other->health = 200;
00438 }
00439
00440 if (other->client->ps.fd.forcePower < 100)
00441 {
00442 other->client->ps.fd.forcePower = 100;
00443 }
00444
00445 while (i < NUM_FORCE_POWERS)
00446 {
00447 other->client->ps.fd.forcePowersKnown |= (1 << i);
00448 other->client->ps.fd.forcePowerLevel[i] = FORCE_LEVEL_3;
00449
00450 i++;
00451 }
00452
00453 self->pos2[0] = 1;
00454 self->pos2[1] = level.time + JMSABER_RESPAWN_TIME;
00455
00456 self->s.modelindex = 0;
00457 self->s.eFlags |= EF_NODRAW;
00458 self->s.modelGhoul2 = 0;
00459 self->s.eType = ET_GENERAL;
00460
00461
00462
00463
00464
00465
00466 G_KillG2Queue(self->s.number);
00467
00468 return;
00469 }
00470
00471 gentity_t *gJMSaberEnt = NULL;
00472
00473
00474
00475
00476 void SP_info_jedimaster_start(gentity_t *ent)
00477 {
00478 if (g_gametype.integer != GT_JEDIMASTER)
00479 {
00480 gJMSaberEnt = NULL;
00481 G_FreeEntity(ent);
00482 return;
00483 }
00484
00485 ent->enemy = NULL;
00486
00487 ent->flags = FL_BOUNCE_HALF;
00488
00489 ent->s.modelindex = G_ModelIndex("models/weapons2/saber/saber_w.glm");
00490 ent->s.modelGhoul2 = 1;
00491 ent->s.g2radius = 20;
00492
00493 ent->s.eType = ET_MISSILE;
00494 ent->s.weapon = WP_SABER;
00495 ent->s.pos.trType = TR_GRAVITY;
00496 ent->s.pos.trTime = level.time;
00497 VectorSet( ent->r.maxs, 3, 3, 3 );
00498 VectorSet( ent->r.mins, -3, -3, -3 );
00499 ent->r.contents = CONTENTS_TRIGGER;
00500 ent->clipmask = MASK_SOLID;
00501
00502 ent->isSaberEntity = qtrue;
00503
00504 ent->bounceCount = -5;
00505
00506 ent->physicsObject = qtrue;
00507
00508 VectorCopy(ent->s.pos.trBase, ent->s.origin2);
00509
00510 ent->touch = JMSaberTouch;
00511
00512 trap_LinkEntity(ent);
00513
00514 ent->think = JMSaberThink;
00515 ent->nextthink = level.time + 50;
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532 qboolean SpotWouldTelefrag( gentity_t *spot ) {
00533 int i, num;
00534 int touch[MAX_GENTITIES];
00535 gentity_t *hit;
00536 vec3_t mins, maxs;
00537
00538 VectorAdd( spot->s.origin, playerMins, mins );
00539 VectorAdd( spot->s.origin, playerMaxs, maxs );
00540 num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
00541
00542 for (i=0 ; i<num ; i++) {
00543 hit = &g_entities[touch[i]];
00544
00545 if ( hit->client) {
00546 return qtrue;
00547 }
00548
00549 }
00550
00551 return qfalse;
00552 }
00553
00554 qboolean SpotWouldTelefrag2( gentity_t *mover, vec3_t dest )
00555 {
00556 int i, num;
00557 int touch[MAX_GENTITIES];
00558 gentity_t *hit;
00559 vec3_t mins, maxs;
00560
00561 VectorAdd( dest, mover->r.mins, mins );
00562 VectorAdd( dest, mover->r.maxs, maxs );
00563 num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
00564
00565 for (i=0 ; i<num ; i++)
00566 {
00567 hit = &g_entities[touch[i]];
00568 if ( hit == mover )
00569 {
00570 continue;
00571 }
00572
00573 if ( hit->r.contents & mover->r.contents )
00574 {
00575 return qtrue;
00576 }
00577 }
00578
00579 return qfalse;
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589 #define MAX_SPAWN_POINTS 128
00590 gentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) {
00591 gentity_t *spot;
00592 vec3_t delta;
00593 float dist, nearestDist;
00594 gentity_t *nearestSpot;
00595
00596 nearestDist = 999999;
00597 nearestSpot = NULL;
00598 spot = NULL;
00599
00600 while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
00601
00602 VectorSubtract( spot->s.origin, from, delta );
00603 dist = VectorLength( delta );
00604 if ( dist < nearestDist ) {
00605 nearestDist = dist;
00606 nearestSpot = spot;
00607 }
00608 }
00609
00610 return nearestSpot;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621 #define MAX_SPAWN_POINTS 128
00622 gentity_t *SelectRandomDeathmatchSpawnPoint( void ) {
00623 gentity_t *spot;
00624 int count;
00625 int selection;
00626 gentity_t *spots[MAX_SPAWN_POINTS];
00627
00628 count = 0;
00629 spot = NULL;
00630
00631 while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
00632 if ( SpotWouldTelefrag( spot ) ) {
00633 continue;
00634 }
00635 spots[ count ] = spot;
00636 count++;
00637 }
00638
00639 if ( !count ) {
00640 return G_Find( NULL, FOFS(classname), "info_player_deathmatch");
00641 }
00642
00643 selection = rand() % count;
00644 return spots[ selection ];
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654 gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, team_t team ) {
00655 gentity_t *spot;
00656 vec3_t delta;
00657 float dist;
00658 float list_dist[64];
00659 gentity_t *list_spot[64];
00660 int numSpots, rnd, i, j;
00661
00662 numSpots = 0;
00663 spot = NULL;
00664
00665
00666 if ( g_gametype.integer == GT_TEAM
00667 && team != TEAM_FREE
00668 && team != TEAM_SPECTATOR )
00669 {
00670 char *classname = NULL;
00671 if ( team == TEAM_RED )
00672 {
00673 classname = "info_player_start_red";
00674 }
00675 else
00676 {
00677 classname = "info_player_start_blue";
00678 }
00679 while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
00680 if ( SpotWouldTelefrag( spot ) ) {
00681 continue;
00682 }
00683 VectorSubtract( spot->s.origin, avoidPoint, delta );
00684 dist = VectorLength( delta );
00685 for (i = 0; i < numSpots; i++) {
00686 if ( dist > list_dist[i] ) {
00687 if ( numSpots >= 64 )
00688 numSpots = 64-1;
00689 for (j = numSpots; j > i; j--) {
00690 list_dist[j] = list_dist[j-1];
00691 list_spot[j] = list_spot[j-1];
00692 }
00693 list_dist[i] = dist;
00694 list_spot[i] = spot;
00695 numSpots++;
00696 if (numSpots > 64)
00697 numSpots = 64;
00698 break;
00699 }
00700 }
00701 if (i >= numSpots && numSpots < 64) {
00702 list_dist[numSpots] = dist;
00703 list_spot[numSpots] = spot;
00704 numSpots++;
00705 }
00706 }
00707 }
00708
00709 if ( !numSpots )
00710 {
00711 while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
00712 if ( SpotWouldTelefrag( spot ) ) {
00713 continue;
00714 }
00715 VectorSubtract( spot->s.origin, avoidPoint, delta );
00716 dist = VectorLength( delta );
00717 for (i = 0; i < numSpots; i++) {
00718 if ( dist > list_dist[i] ) {
00719 if ( numSpots >= 64 )
00720 numSpots = 64-1;
00721 for (j = numSpots; j > i; j--) {
00722 list_dist[j] = list_dist[j-1];
00723 list_spot[j] = list_spot[j-1];
00724 }
00725 list_dist[i] = dist;
00726 list_spot[i] = spot;
00727 numSpots++;
00728 if (numSpots > 64)
00729 numSpots = 64;
00730 break;
00731 }
00732 }
00733 if (i >= numSpots && numSpots < 64) {
00734 list_dist[numSpots] = dist;
00735 list_spot[numSpots] = spot;
00736 numSpots++;
00737 }
00738 }
00739 if (!numSpots) {
00740 spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch");
00741 if (!spot)
00742 G_Error( "Couldn't find a spawn point" );
00743 VectorCopy (spot->s.origin, origin);
00744 origin[2] += 9;
00745 VectorCopy (spot->s.angles, angles);
00746 return spot;
00747 }
00748 }
00749
00750
00751 rnd = random() * (numSpots / 2);
00752
00753 VectorCopy (list_spot[rnd]->s.origin, origin);
00754 origin[2] += 9;
00755 VectorCopy (list_spot[rnd]->s.angles, angles);
00756
00757 return list_spot[rnd];
00758 }
00759
00760 gentity_t *SelectDuelSpawnPoint( int team, vec3_t avoidPoint, vec3_t origin, vec3_t angles )
00761 {
00762 gentity_t *spot;
00763 vec3_t delta;
00764 float dist;
00765 float list_dist[64];
00766 gentity_t *list_spot[64];
00767 int numSpots, rnd, i, j;
00768 char *spotName;
00769
00770 if (team == DUELTEAM_LONE)
00771 {
00772 spotName = "info_player_duel1";
00773 }
00774 else if (team == DUELTEAM_DOUBLE)
00775 {
00776 spotName = "info_player_duel2";
00777 }
00778 else if (team == DUELTEAM_SINGLE)
00779 {
00780 spotName = "info_player_duel";
00781 }
00782 else
00783 {
00784 spotName = "info_player_deathmatch";
00785 }
00786 tryAgain:
00787
00788 numSpots = 0;
00789 spot = NULL;
00790
00791 while ((spot = G_Find (spot, FOFS(classname), spotName)) != NULL) {
00792 if ( SpotWouldTelefrag( spot ) ) {
00793 continue;
00794 }
00795 VectorSubtract( spot->s.origin, avoidPoint, delta );
00796 dist = VectorLength( delta );
00797 for (i = 0; i < numSpots; i++) {
00798 if ( dist > list_dist[i] ) {
00799 if ( numSpots >= 64 )
00800 numSpots = 64-1;
00801 for (j = numSpots; j > i; j--) {
00802 list_dist[j] = list_dist[j-1];
00803 list_spot[j] = list_spot[j-1];
00804 }
00805 list_dist[i] = dist;
00806 list_spot[i] = spot;
00807 numSpots++;
00808 if (numSpots > 64)
00809 numSpots = 64;
00810 break;
00811 }
00812 }
00813 if (i >= numSpots && numSpots < 64) {
00814 list_dist[numSpots] = dist;
00815 list_spot[numSpots] = spot;
00816 numSpots++;
00817 }
00818 }
00819 if (!numSpots)
00820 {
00821 if (Q_stricmp(spotName, "info_player_deathmatch"))
00822 {
00823 spotName = "info_player_deathmatch";
00824 goto tryAgain;
00825 }
00826
00827
00828 spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch");
00829 if (!spot)
00830 G_Error( "Couldn't find a spawn point" );
00831 VectorCopy (spot->s.origin, origin);
00832 origin[2] += 9;
00833 VectorCopy (spot->s.angles, angles);
00834 return spot;
00835 }
00836
00837
00838 rnd = random() * (numSpots / 2);
00839
00840 VectorCopy (list_spot[rnd]->s.origin, origin);
00841 origin[2] += 9;
00842 VectorCopy (list_spot[rnd]->s.angles, angles);
00843
00844 return list_spot[rnd];
00845 }
00846
00847
00848
00849
00850
00851
00852
00853
00854 gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, team_t team ) {
00855 return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles, team );
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884 }
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894 gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles, team_t team ) {
00895 gentity_t *spot;
00896
00897 spot = NULL;
00898 while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
00899 if ( spot->spawnflags & 1 ) {
00900 break;
00901 }
00902 }
00903
00904 if ( !spot || SpotWouldTelefrag( spot ) ) {
00905 return SelectSpawnPoint( vec3_origin, origin, angles, team );
00906 }
00907
00908 VectorCopy (spot->s.origin, origin);
00909 origin[2] += 9;
00910 VectorCopy (spot->s.angles, angles);
00911
00912 return spot;
00913 }
00914
00915
00916
00917
00918
00919
00920
00921 gentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) {
00922 FindIntermissionPoint();
00923
00924 VectorCopy( level.intermission_origin, origin );
00925 VectorCopy( level.intermission_angle, angles );
00926
00927 return NULL;
00928 }
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946 #define BODY_SINK_TIME 30000//45000
00947
00948
00949
00950
00951
00952
00953 void InitBodyQue (void) {
00954 int i;
00955 gentity_t *ent;
00956
00957 level.bodyQueIndex = 0;
00958 for (i=0; i<BODY_QUEUE_SIZE ; i++) {
00959 ent = G_Spawn();
00960 ent->classname = "bodyque";
00961 ent->neverFree = qtrue;
00962 level.bodyQue[i] = ent;
00963 }
00964 }
00965
00966
00967
00968
00969
00970
00971
00972
00973 void BodySink( gentity_t *ent ) {
00974 if ( level.time - ent->timestamp > BODY_SINK_TIME + 2500 ) {
00975
00976 trap_UnlinkEntity( ent );
00977 ent->physicsObject = qfalse;
00978 return;
00979 }
00980
00981
00982
00983 G_AddEvent(ent, EV_BODYFADE, 0);
00984 ent->nextthink = level.time + 18000;
00985 ent->takedamage = qfalse;
00986 }
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996 static qboolean CopyToBodyQue( gentity_t *ent ) {
00997 gentity_t *body;
00998 int contents;
00999 int islight = 0;
01000
01001 if (level.intermissiontime)
01002 {
01003 return qfalse;
01004 }
01005
01006 trap_UnlinkEntity (ent);
01007
01008
01009 contents = trap_PointContents( ent->s.origin, -1 );
01010 if ( contents & CONTENTS_NODROP ) {
01011 return qfalse;
01012 }
01013
01014 if (ent->client && (ent->client->ps.eFlags & EF_DISINTEGRATION))
01015 {
01016 return qfalse;
01017 }
01018
01019
01020 body = level.bodyQue[ level.bodyQueIndex ];
01021 level.bodyQueIndex = (level.bodyQueIndex + 1) % BODY_QUEUE_SIZE;
01022
01023 trap_UnlinkEntity (body);
01024 body->s = ent->s;
01025
01026
01027 body->s.angles[PITCH] = body->s.angles[ROLL] = body->s.apos.trBase[PITCH] = body->s.apos.trBase[ROLL] = 0;
01028
01029 body->s.g2radius = 100;
01030
01031 body->s.eType = ET_BODY;
01032 body->s.eFlags = EF_DEAD;
01033
01034 if (ent->client && (ent->client->ps.eFlags & EF_DISINTEGRATION))
01035 {
01036 body->s.eFlags |= EF_DISINTEGRATION;
01037 }
01038
01039 VectorCopy(ent->client->ps.lastHitLoc, body->s.origin2);
01040
01041 body->s.powerups = 0;
01042 body->s.loopSound = 0;
01043 body->s.loopIsSoundset = qfalse;
01044 body->s.number = body - g_entities;
01045 body->timestamp = level.time;
01046 body->physicsObject = qtrue;
01047 body->physicsBounce = 0;
01048 if ( body->s.groundEntityNum == ENTITYNUM_NONE ) {
01049 body->s.pos.trType = TR_GRAVITY;
01050 body->s.pos.trTime = level.time;
01051 VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta );
01052 } else {
01053 body->s.pos.trType = TR_STATIONARY;
01054 }
01055 body->s.event = 0;
01056
01057 body->s.weapon = ent->s.bolt2;
01058
01059 if (body->s.weapon == WP_SABER && ent->client->ps.saberInFlight)
01060 {
01061 body->s.weapon = WP_BLASTER;
01062 }
01063
01064
01065
01066 if (ent->client && ent->client->ps.fd.forceSide == FORCE_LIGHTSIDE)
01067 {
01068 islight = 1;
01069 }
01070 trap_SendServerCommand(-1, va("ircg %i %i %i %i", ent->s.number, body->s.number, body->s.weapon, islight));
01071
01072 body->r.svFlags = ent->r.svFlags | SVF_BROADCAST;
01073 VectorCopy (ent->r.mins, body->r.mins);
01074 VectorCopy (ent->r.maxs, body->r.maxs);
01075 VectorCopy (ent->r.absmin, body->r.absmin);
01076 VectorCopy (ent->r.absmax, body->r.absmax);
01077
01078 body->s.torsoAnim = body->s.legsAnim = ent->client->ps.legsAnim;
01079
01080 body->s.customRGBA[0] = ent->client->ps.customRGBA[0];
01081 body->s.customRGBA[1] = ent->client->ps.customRGBA[1];
01082 body->s.customRGBA[2] = ent->client->ps.customRGBA[2];
01083 body->s.customRGBA[3] = ent->client->ps.customRGBA[3];
01084
01085 body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
01086 body->r.contents = CONTENTS_CORPSE;
01087 body->r.ownerNum = ent->s.number;
01088
01089 body->nextthink = level.time + BODY_SINK_TIME;
01090 body->think = BodySink;
01091
01092 body->die = body_die;
01093
01094
01095 if ( ent->health <= GIB_HEALTH ) {
01096 body->takedamage = qfalse;
01097 } else {
01098 body->takedamage = qtrue;
01099 }
01100
01101 VectorCopy ( body->s.pos.trBase, body->r.currentOrigin );
01102 trap_LinkEntity (body);
01103
01104 return qtrue;
01105 }
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116 void SetClientViewAngle( gentity_t *ent, vec3_t angle ) {
01117 int i;
01118
01119
01120 for (i=0 ; i<3 ; i++) {
01121 int cmdAngle;
01122
01123 cmdAngle = ANGLE2SHORT(angle[i]);
01124 ent->client->ps.delta_angles[i] = cmdAngle - ent->client->pers.cmd.angles[i];
01125 }
01126 VectorCopy( angle, ent->s.angles );
01127 VectorCopy (ent->s.angles, ent->client->ps.viewangles);
01128 }
01129
01130 void MaintainBodyQueue(gentity_t *ent)
01131 {
01132 qboolean doRCG = qfalse;
01133
01134 assert(ent && ent->client);
01135 if (ent->client->tempSpectate > level.time ||
01136 (ent->client->ps.eFlags2 & EF2_SHIP_DEATH))
01137 {
01138 ent->client->noCorpse = qtrue;
01139 }
01140
01141 if (!ent->client->noCorpse && !ent->client->ps.fallingToDeath)
01142 {
01143 if (!CopyToBodyQue (ent))
01144 {
01145 doRCG = qtrue;
01146 }
01147 }
01148 else
01149 {
01150 ent->client->noCorpse = qfalse;
01151 ent->client->ps.fallingToDeath = qfalse;
01152 doRCG = qtrue;
01153 }
01154
01155 if (doRCG)
01156 {
01157 trap_SendServerCommand(-1, va("rcg %i", ent->s.clientNum));
01158 }
01159 }
01160
01161
01162
01163
01164
01165
01166 void SiegeRespawn(gentity_t *ent);
01167 void respawn( gentity_t *ent ) {
01168 MaintainBodyQueue(ent);
01169
01170 if (gEscaping || g_gametype.integer == GT_POWERDUEL)
01171 {
01172 ent->client->sess.sessionTeam = TEAM_SPECTATOR;
01173 ent->client->sess.spectatorState = SPECTATOR_FREE;
01174 ent->client->sess.spectatorClient = 0;
01175
01176 ent->client->pers.teamState.state = TEAM_BEGIN;
01177 ent->client->sess.spectatorTime = level.time;
01178 ClientSpawn(ent);
01179 ent->client->iAmALoser = qtrue;
01180 return;
01181 }
01182
01183 trap_UnlinkEntity (ent);
01184
01185 if (g_gametype.integer == GT_SIEGE)
01186 {
01187 if (g_siegeRespawn.integer)
01188 {
01189 if (ent->client->tempSpectate <= level.time)
01190 {
01191 int minDel = g_siegeRespawn.integer* 2000;
01192 if (minDel < 20000)
01193 {
01194 minDel = 20000;
01195 }
01196 ent->client->tempSpectate = level.time + minDel;
01197 ent->health = ent->client->ps.stats[STAT_HEALTH] = 1;
01198 ent->client->ps.weapon = WP_NONE;
01199 ent->client->ps.stats[STAT_WEAPONS] = 0;
01200 ent->client->ps.stats[STAT_HOLDABLE_ITEMS] = 0;
01201 ent->client->ps.stats[STAT_HOLDABLE_ITEM] = 0;
01202 ent->takedamage = qfalse;
01203 trap_LinkEntity(ent);
01204
01205
01206 if ( ent->s.number < MAX_CLIENTS )
01207 {
01208 gentity_t *te = G_TempEntity( ent->client->ps.origin, EV_SIEGESPEC );
01209 te->s.time = g_siegeRespawnCheck;
01210 te->s.owner = ent->s.number;
01211 }
01212
01213 return;
01214 }
01215 }
01216 SiegeRespawn(ent);
01217 }
01218 else
01219 {
01220 gentity_t *tent;
01221
01222 ClientSpawn(ent);
01223
01224
01225 tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
01226 tent->s.clientNum = ent->s.clientNum;
01227 }
01228 }
01229
01230
01231
01232
01233
01234
01235
01236
01237 team_t TeamCount( int ignoreClientNum, int team ) {
01238 int i;
01239 int count = 0;
01240
01241 for ( i = 0 ; i < level.maxclients ; i++ ) {
01242 if ( i == ignoreClientNum ) {
01243 continue;
01244 }
01245 if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
01246 continue;
01247 }
01248 if ( level.clients[i].sess.sessionTeam == team ) {
01249 count++;
01250 }
01251 else if (g_gametype.integer == GT_SIEGE &&
01252 level.clients[i].sess.siegeDesiredTeam == team)
01253 {
01254 count++;
01255 }
01256 }
01257
01258 return count;
01259 }
01260
01261
01262
01263
01264
01265
01266
01267
01268 int TeamLeader( int team ) {
01269 int i;
01270
01271 for ( i = 0 ; i < level.maxclients ; i++ ) {
01272 if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
01273 continue;
01274 }
01275 if ( level.clients[i].sess.sessionTeam == team ) {
01276 if ( level.clients[i].sess.teamLeader )
01277 return i;
01278 }
01279 }
01280
01281 return -1;
01282 }
01283
01284
01285
01286
01287
01288
01289
01290
01291 team_t PickTeam( int ignoreClientNum ) {
01292 int counts[TEAM_NUM_TEAMS];
01293
01294 counts[TEAM_BLUE] = TeamCount( ignoreClientNum, TEAM_BLUE );
01295 counts[TEAM_RED] = TeamCount( ignoreClientNum, TEAM_RED );
01296
01297 if ( counts[TEAM_BLUE] > counts[TEAM_RED] ) {
01298