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 return TEAM_RED;
01299 }
01300 if ( counts[TEAM_RED] > counts[TEAM_BLUE] ) {
01301 return TEAM_BLUE;
01302 }
01303
01304 if ( level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED] ) {
01305 return TEAM_RED;
01306 }
01307 return TEAM_BLUE;
01308 }
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335 static void ClientCleanName( const char *in, char *out, int outSize ) {
01336 int len, colorlessLen;
01337 char ch;
01338 char *p;
01339 int spaces;
01340
01341
01342 outSize--;
01343
01344 len = 0;
01345 colorlessLen = 0;
01346 p = out;
01347 *p = 0;
01348 spaces = 0;
01349
01350 while( 1 ) {
01351 ch = *in++;
01352 if( !ch ) {
01353 break;
01354 }
01355
01356
01357 if( !*p && ch == ' ' ) {
01358 continue;
01359 }
01360
01361
01362 if( ch == Q_COLOR_ESCAPE ) {
01363
01364 if( !*in ) {
01365 break;
01366 }
01367
01368
01369 if( ColorIndex(*in) == 0 ) {
01370 in++;
01371 continue;
01372 }
01373
01374
01375 if( len > outSize - 2 ) {
01376 break;
01377 }
01378
01379 *out++ = ch;
01380 *out++ = *in++;
01381 len += 2;
01382 continue;
01383 }
01384
01385
01386 if( ch == ' ' ) {
01387 spaces++;
01388 if( spaces > 3 ) {
01389 continue;
01390 }
01391 }
01392 else {
01393 spaces = 0;
01394 }
01395
01396 if( len > outSize - 1 ) {
01397 break;
01398 }
01399
01400 *out++ = ch;
01401 colorlessLen++;
01402 len++;
01403 }
01404 *out = 0;
01405
01406
01407 if( *p == 0 || colorlessLen == 0 ) {
01408 Q_strncpyz( p, "Padawan", outSize );
01409 }
01410 }
01411
01412 #ifdef _DEBUG
01413 void G_DebugWrite(const char *path, const char *text)
01414 {
01415 fileHandle_t f;
01416
01417 trap_FS_FOpenFile( path, &f, FS_APPEND );
01418 trap_FS_Write(text, strlen(text), f);
01419 trap_FS_FCloseFile(f);
01420 }
01421 #endif
01422
01423 qboolean G_SaberModelSetup(gentity_t *ent)
01424 {
01425 int i = 0;
01426 qboolean fallbackForSaber = qtrue;
01427
01428 while (i < MAX_SABERS)
01429 {
01430 if (ent->client->saber[i].model[0])
01431 {
01432
01433 if (ent->client->weaponGhoul2[i])
01434 {
01435 trap_G2API_CleanGhoul2Models(&(ent->client->weaponGhoul2[i]));
01436 }
01437 trap_G2API_InitGhoul2Model(&ent->client->weaponGhoul2[i], ent->client->saber[i].model, 0, 0, -20, 0, 0);
01438
01439 if (ent->client->weaponGhoul2[i])
01440 {
01441 int j = 0;
01442 char *tagName;
01443 int tagBolt;
01444
01445 if (ent->client->saber[i].skin)
01446 {
01447 trap_G2API_SetSkin(ent->client->weaponGhoul2[i], 0, ent->client->saber[i].skin, ent->client->saber[i].skin);
01448 }
01449
01450 if (ent->client->saber[i].saberFlags & SFL_BOLT_TO_WRIST)
01451 {
01452 trap_G2API_SetBoltInfo(ent->client->weaponGhoul2[i], 0, 3+i);
01453 }
01454 else
01455 {
01456 trap_G2API_SetBoltInfo(ent->client->weaponGhoul2[i], 0, i);
01457 }
01458
01459
01460 while (j < ent->client->saber[i].numBlades)
01461 {
01462 tagName = va("*blade%i", j+1);
01463 tagBolt = trap_G2API_AddBolt(ent->client->weaponGhoul2[i], 0, tagName);
01464
01465 if (tagBolt == -1)
01466 {
01467 if (j == 0)
01468 {
01469 tagBolt = trap_G2API_AddBolt(ent->client->weaponGhoul2[i], 0, "*flash");
01470 fallbackForSaber = qfalse;
01471 break;
01472 }
01473
01474 if (tagBolt == -1)
01475 {
01476 assert(0);
01477 break;
01478
01479 }
01480 }
01481 j++;
01482
01483 fallbackForSaber = qfalse;
01484 }
01485
01486
01487 trap_G2API_CopySpecificGhoul2Model(ent->client->weaponGhoul2[i], 0, ent->ghoul2, i+1);
01488 }
01489 }
01490 else
01491 {
01492 break;
01493 }
01494
01495 i++;
01496 }
01497
01498 return fallbackForSaber;
01499 }
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511 void *g2SaberInstance = NULL;
01512
01513 #include "../namespace_begin.h"
01514 qboolean BG_IsValidCharacterModel(const char *modelName, const char *skinName);
01515 qboolean BG_ValidateSkinForTeam( const char *modelName, char *skinName, int team, float *colors );
01516 void BG_GetVehicleModelName(char *modelname);
01517 #include "../namespace_end.h"
01518
01519 void SetupGameGhoul2Model(gentity_t *ent, char *modelname, char *skinName)
01520 {
01521 int handle;
01522 char afilename[MAX_QPATH];
01523 #if 0
01524 char *slash;
01525 #endif
01526 char GLAName[MAX_QPATH];
01527 vec3_t tempVec = {0,0,0};
01528
01529
01530 if (ent->ghoul2 && trap_G2_HaveWeGhoul2Models(ent->ghoul2))
01531 {
01532 trap_G2API_CleanGhoul2Models(&(ent->ghoul2));
01533 }
01534
01535
01536 if (!precachedKyle)
01537 {
01538 int defSkin;
01539
01540 Com_sprintf( afilename, sizeof( afilename ), "models/players/kyle/model.glm" );
01541 handle = trap_G2API_InitGhoul2Model(&precachedKyle, afilename, 0, 0, -20, 0, 0);
01542
01543 if (handle<0)
01544 {
01545 return;
01546 }
01547
01548 defSkin = trap_R_RegisterSkin("models/players/kyle/model_default.skin");
01549 trap_G2API_SetSkin(precachedKyle, 0, defSkin, defSkin);
01550 }
01551
01552 if (precachedKyle && trap_G2_HaveWeGhoul2Models(precachedKyle))
01553 {
01554 if (d_perPlayerGhoul2.integer || ent->s.number >= MAX_CLIENTS ||
01555 G_PlayerHasCustomSkeleton(ent))
01556 {
01557 char modelFullPath[MAX_QPATH];
01558 char truncModelName[MAX_QPATH];
01559 char skin[MAX_QPATH];
01560 char vehicleName[MAX_QPATH];
01561 int skinHandle = 0;
01562 int i = 0;
01563 char *p;
01564
01565
01566 if ( ent->client->NPC_class == CLASS_VEHICLE )
01567 {
01568 strcpy(vehicleName, modelname);
01569 BG_GetVehicleModelName(modelname);
01570 strcpy(truncModelName, modelname);
01571 skin[0] = 0;
01572 if ( ent->m_pVehicle
01573 && ent->m_pVehicle->m_pVehicleInfo
01574 && ent->m_pVehicle->m_pVehicleInfo->skin
01575 && ent->m_pVehicle->m_pVehicleInfo->skin[0] )
01576 {
01577 skinHandle = trap_R_RegisterSkin(va("models/players/%s/model_%s.skin", modelname, ent->m_pVehicle->m_pVehicleInfo->skin));
01578 }
01579 else
01580 {
01581 skinHandle = trap_R_RegisterSkin(va("models/players/%s/model_default.skin", modelname));
01582 }
01583 }
01584 else
01585 {
01586 if (skinName && skinName[0])
01587 {
01588 strcpy(skin, skinName);
01589 strcpy(truncModelName, modelname);
01590 }
01591 else
01592 {
01593 strcpy(skin, "default");
01594
01595 strcpy(truncModelName, modelname);
01596 p = Q_strrchr(truncModelName, '/');
01597
01598 if (p)
01599 {
01600 *p = 0;
01601 p++;
01602
01603 while (p && *p)
01604 {
01605 skin[i] = *p;
01606 i++;
01607 p++;
01608 }
01609 skin[i] = 0;
01610 i = 0;
01611 }
01612
01613 if (!BG_IsValidCharacterModel(truncModelName, skin))
01614 {
01615 strcpy(truncModelName, "kyle");
01616 strcpy(skin, "default");
01617 }
01618
01619 if ( g_gametype.integer >= GT_TEAM && g_gametype.integer != GT_SIEGE && !g_trueJedi.integer )
01620 {
01621 BG_ValidateSkinForTeam( truncModelName, skin, ent->client->sess.sessionTeam, NULL );
01622 }
01623 else if (g_gametype.integer == GT_SIEGE)
01624 {
01625 if (ent->client->siegeClass != -1)
01626 {
01627 siegeClass_t *scl = &bgSiegeClasses[ent->client->siegeClass];
01628 if (scl->forcedSkin[0])
01629 {
01630 strcpy(skin, scl->forcedSkin);
01631 }
01632 }
01633 }
01634 }
01635 }
01636
01637 if (skin[0])
01638 {
01639 char *useSkinName;
01640
01641 if (strchr(skin, '|'))
01642 {
01643 useSkinName = va("models/players/%s/|%s", truncModelName, skin);
01644 }
01645 else
01646 {
01647 useSkinName = va("models/players/%s/model_%s.skin", truncModelName, skin);
01648 }
01649
01650 skinHandle = trap_R_RegisterSkin(useSkinName);
01651 }
01652
01653 strcpy(modelFullPath, va("models/players/%s/model.glm", truncModelName));
01654 handle = trap_G2API_InitGhoul2Model(&ent->ghoul2, modelFullPath, 0, skinHandle, -20, 0, 0);
01655
01656 if (handle<0)
01657 {
01658
01659 if (ent->ghoul2 && trap_G2_HaveWeGhoul2Models(ent->ghoul2))
01660 {
01661 trap_G2API_CleanGhoul2Models(&(ent->ghoul2));
01662 }
01663 ent->ghoul2 = NULL;
01664 trap_G2API_DuplicateGhoul2Instance(precachedKyle, &ent->ghoul2);
01665 }
01666 else
01667 {
01668 trap_G2API_SetSkin(ent->ghoul2, 0, skinHandle, skinHandle);
01669
01670 GLAName[0] = 0;
01671 trap_G2API_GetGLAName( ent->ghoul2, 0, GLAName);
01672
01673 if (!GLAName[0] || (!strstr(GLAName, "players/_humanoid/") && ent->s.number < MAX_CLIENTS && !G_PlayerHasCustomSkeleton(ent)))
01674 {
01675 trap_G2API_CleanGhoul2Models(&(ent->ghoul2));
01676 ent->ghoul2 = NULL;
01677 trap_G2API_DuplicateGhoul2Instance(precachedKyle, &ent->ghoul2);
01678 }
01679
01680 if (ent->s.number >= MAX_CLIENTS)
01681 {
01682 ent->s.modelGhoul2 = 1;
01683
01684 if (skin[0])
01685 {
01686 strcat( modelFullPath, va("*%s", skin) );
01687 }
01688
01689 if ( ent->client->NPC_class == CLASS_VEHICLE )
01690 {
01691 ent->s.modelindex = G_ModelIndex(vehicleName);
01692 }
01693 else
01694 {
01695 ent->s.modelindex = G_ModelIndex(modelFullPath);
01696 }
01697 }
01698 }
01699 }
01700 else
01701 {
01702 trap_G2API_DuplicateGhoul2Instance(precachedKyle, &ent->ghoul2);
01703 }
01704 }
01705 else
01706 {
01707 return;
01708 }
01709
01710
01711
01712 trap_G2API_AttachInstanceToEntNum(ent->ghoul2, ent->s.number, qtrue);
01713
01714
01715
01716 GLAName[0] = 0;
01717
01718 if (!BGPAFtextLoaded)
01719 {
01720 if (BG_ParseAnimationFile("models/players/_humanoid/animation.cfg", bgHumanoidAnimations, qtrue) == -1)
01721 {
01722 Com_Printf( "Failed to load humanoid animation file\n");
01723 return;
01724 }
01725 }
01726
01727 if (ent->s.number >= MAX_CLIENTS || G_PlayerHasCustomSkeleton(ent))
01728 {
01729 ent->localAnimIndex = -1;
01730
01731 GLAName[0] = 0;
01732 trap_G2API_GetGLAName(ent->ghoul2, 0, GLAName);
01733
01734 if (GLAName[0] &&
01735 !strstr(GLAName, "players/_humanoid/")
01736 )
01737 {
01738 char *slash = Q_strrchr( GLAName, '/' );
01739 if ( slash )
01740 {
01741 strcpy(slash, "/animation.cfg");
01742
01743 ent->localAnimIndex = BG_ParseAnimationFile(GLAName, NULL, qfalse);
01744 }
01745 }
01746 else
01747 {
01748 if (strstr(GLAName, "players/rockettrooper/"))
01749 {
01750 ent->localAnimIndex = 1;
01751 }
01752 else
01753 {
01754 ent->localAnimIndex = 0;
01755 }
01756 }
01757
01758 if (ent->localAnimIndex == -1)
01759 {
01760 Com_Error(ERR_DROP, "NPC had an invalid GLA\n");
01761 }
01762 }
01763 else
01764 {
01765 GLAName[0] = 0;
01766 trap_G2API_GetGLAName(ent->ghoul2, 0, GLAName);
01767
01768 if (strstr(GLAName, "players/rockettrooper/"))
01769 {
01770
01771 ent->localAnimIndex = 1;
01772 }
01773 else
01774 {
01775 ent->localAnimIndex = 0;
01776 }
01777 }
01778
01779 if (ent->s.NPC_class == CLASS_VEHICLE &&
01780 ent->m_pVehicle)
01781 {
01782 char strTemp[128];
01783 int i;
01784
01785
01786 i = trap_G2API_AddBolt( ent->ghoul2, 0, "model_root" );
01787
01788
01789 ent->m_pVehicle->m_iDroidUnitTag = trap_G2API_AddBolt( ent->ghoul2, 0, "*droidunit" );
01790
01791
01792 for ( i = 0; i < MAX_VEHICLE_EXHAUSTS; i++ )
01793 {
01794 Com_sprintf( strTemp, 128, "*exhaust%i", i + 1 );
01795 ent->m_pVehicle->m_iExhaustTag[i] = trap_G2API_AddBolt( ent->ghoul2, 0, strTemp );
01796 }
01797
01798
01799 for ( i = 0; i < MAX_VEHICLE_MUZZLES; i++ )
01800 {
01801 Com_sprintf( strTemp, 128, "*muzzle%i", i + 1 );
01802 ent->m_pVehicle->m_iMuzzleTag[i] = trap_G2API_AddBolt( ent->ghoul2, 0, strTemp );
01803 if ( ent->m_pVehicle->m_iMuzzleTag[i] == -1 )
01804 {
01805 Com_sprintf( strTemp, 128, "*flash%i", i + 1 );
01806 ent->m_pVehicle->m_iMuzzleTag[i] = trap_G2API_AddBolt( ent->ghoul2, 0, strTemp );
01807 }
01808 }
01809
01810
01811 for ( i = 0; i < MAX_VEHICLE_TURRET_MUZZLES; i++ )
01812 {
01813 if ( ent->m_pVehicle->m_pVehicleInfo->turret[i].gunnerViewTag )
01814 {
01815 ent->m_pVehicle->m_iGunnerViewTag[i] = trap_G2API_AddBolt( ent->ghoul2, 0, ent->m_pVehicle->m_pVehicleInfo->turret[i].gunnerViewTag );
01816 }
01817 else
01818 {
01819 ent->m_pVehicle->m_iGunnerViewTag[i] = -1;
01820 }
01821 }
01822 }
01823
01824 if (ent->client->ps.weapon == WP_SABER || ent->s.number < MAX_CLIENTS)
01825 {
01826 trap_G2API_AddBolt(ent->ghoul2, 0, "*r_hand");
01827 trap_G2API_AddBolt(ent->ghoul2, 0, "*l_hand");
01828
01829
01830
01831 trap_G2API_AddBolt(ent->ghoul2, 0, "*chestg");
01832
01833
01834 trap_G2API_AddBolt(ent->ghoul2, 0, "*r_hand_cap_r_arm");
01835 trap_G2API_AddBolt(ent->ghoul2, 0, "*l_hand_cap_l_arm");
01836
01837 trap_G2API_SetBoneAnim(ent->ghoul2, 0, "model_root", 0, 12, BONE_ANIM_OVERRIDE_LOOP, 1.0f, level.time, -1, -1);
01838 trap_G2API_SetBoneAngles(ent->ghoul2, 0, "upper_lumbar", tempVec, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time);
01839 trap_G2API_SetBoneAngles(ent->ghoul2, 0, "cranium", tempVec, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, NULL, 0, level.time);
01840
01841 if (!g2SaberInstance)
01842 {
01843 trap_G2API_InitGhoul2Model(&g2SaberInstance, "models/weapons2/saber/saber_w.glm", 0, 0, -20, 0, 0);
01844
01845 if (g2SaberInstance)
01846 {
01847
01848 trap_G2API_SetBoltInfo(g2SaberInstance, 0, 0);
01849
01850 trap_G2API_AddBolt(g2SaberInstance, 0, "*blade1");
01851 }
01852 }
01853
01854 if (G_SaberModelSetup(ent))
01855 {
01856 if (g2SaberInstance)
01857 {
01858 trap_G2API_CopySpecificGhoul2Model(g2SaberInstance, 0, ent->ghoul2, 1);
01859 }
01860 }
01861 }
01862
01863 if (ent->s.number >= MAX_CLIENTS)
01864 {
01865 if (trap_G2API_AddBolt(ent->ghoul2, 0, "lower_lumbar") == -1)
01866 {
01867 ent->noLumbar = qtrue;
01868 }
01869 }
01870 }
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886 qboolean G_SetSaber(gentity_t *ent, int saberNum, char *saberName, qboolean siegeOverride);
01887 void G_ValidateSiegeClassForTeam(gentity_t *ent, int team);
01888 void ClientUserinfoChanged( int clientNum ) {
01889 gentity_t *ent;
01890 int teamTask, teamLeader, team, health;
01891 char *s;
01892 char model[MAX_QPATH];
01893
01894 char forcePowers[MAX_QPATH];
01895 char oldname[MAX_STRING_CHARS];
01896 gclient_t *client;
01897 char c1[MAX_INFO_STRING];
01898 char c2[MAX_INFO_STRING];
01899
01900
01901 char userinfo[MAX_INFO_STRING];
01902 char className[MAX_QPATH];
01903 char saberName[MAX_QPATH];
01904 char saber2Name[MAX_QPATH];
01905 char *value;
01906 int maxHealth;
01907 qboolean modelChanged = qfalse;
01908
01909 ent = g_entities + clientNum;
01910 client = ent->client;
01911
01912 trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
01913
01914
01915 if ( !Info_Validate(userinfo) ) {
01916 strcpy (userinfo, "\\name\\badinfo");
01917 }
01918
01919
01920 s = Info_ValueForKey( userinfo, "ip" );
01921 if ( !strcmp( s, "localhost" ) ) {
01922 client->pers.localClient = qtrue;
01923 }
01924
01925
01926 s = Info_ValueForKey( userinfo, "cg_predictItems" );
01927 if ( !atoi( s ) ) {
01928 client->pers.predictItemPickup = qfalse;
01929 } else {
01930 client->pers.predictItemPickup = qtrue;
01931 }
01932
01933
01934 Q_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) );
01935 s = Info_ValueForKey (userinfo, "name");
01936 ClientCleanName( s, client->pers.netname, sizeof(client->pers.netname) );
01937
01938 if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
01939 if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
01940 Q_strncpyz( client->pers.netname, "scoreboard", sizeof(client->pers.netname) );
01941 }
01942 }
01943
01944 if ( client->pers.connected == CON_CONNECTED ) {
01945 if ( strcmp( oldname, client->pers.netname ) )
01946 {
01947 if ( client->pers.netnameTime > level.time )
01948 {
01949 trap_SendServerCommand( clientNum, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "NONAMECHANGE")) );
01950
01951 Info_SetValueForKey( userinfo, "name", oldname );
01952 trap_SetUserinfo( clientNum, userinfo );
01953 strcpy ( client->pers.netname, oldname );
01954 }
01955 else
01956 {
01957 trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " %s %s\n\"", oldname, G_GetStringEdString("MP_SVGAME", "PLRENAME"), client->pers.netname) );
01958 client->pers.netnameTime = level.time + 5000;
01959 }
01960 }
01961 }
01962
01963
01964 Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) );
01965
01966 if (d_perPlayerGhoul2.integer)
01967 {
01968 if (Q_stricmp(model, client->modelname))
01969 {
01970 strcpy(client->modelname, model);
01971 modelChanged = qtrue;
01972 }
01973 }
01974
01975
01976 value = Info_ValueForKey (userinfo, "char_color_red");
01977 if (value)
01978 {
01979 client->ps.customRGBA[0] = atoi(value);
01980 }
01981 else
01982 {
01983 client->ps.customRGBA[0] = 255;
01984 }
01985
01986 value = Info_ValueForKey (userinfo, "char_color_green");
01987 if (value)
01988 {
01989 client->ps.customRGBA[1] = atoi(value);
01990 }
01991 else
01992 {
01993 client->ps.customRGBA[1] = 255;
01994 }
01995
01996 value = Info_ValueForKey (userinfo, "char_color_blue");
01997 if (value)
01998 {
01999 client->ps.customRGBA[2] = atoi(value);
02000 }
02001 else
02002 {
02003 client->ps.customRGBA[2] = 255;
02004 }
02005
02006 if ((client->ps.customRGBA[0]+client->ps.customRGBA[1]+client->ps.customRGBA[2]) < 100)
02007 {
02008 client->ps.customRGBA[0] = client->ps.customRGBA[1] = client->ps.customRGBA[2] = 255;
02009 }
02010
02011 client->ps.customRGBA[3]=255;
02012
02013 Q_strncpyz( forcePowers, Info_ValueForKey (userinfo, "forcepowers"), sizeof( forcePowers ) );
02014
02015
02016 if (g_gametype.integer >= GT_TEAM && g_entities[clientNum].r.svFlags & SVF_BOT) {
02017 s = Info_ValueForKey( userinfo, "team" );
02018 if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) {
02019 team = TEAM_RED;
02020 } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) {
02021 team = TEAM_BLUE;
02022 } else {
02023
02024 team = PickTeam( clientNum );
02025 }
02026 }
02027 else {
02028 team = client->sess.sessionTeam;
02029 }
02030
02031
02032 if (g_gametype.integer == GT_SIEGE)
02033 {
02034 strcpy(className, client->sess.siegeClass);
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045 client->siegeClass = BG_SiegeFindClassIndexByName(className);
02046 if (client->siegeClass == -1)
02047 {
02048 BG_SiegeCheckClassLegality(team, className);
02049 strcpy(client->sess.siegeClass, className);
02050 client->siegeClass = BG_SiegeFindClassIndexByName(className);
02051 }
02052 else
02053 {
02054 G_ValidateSiegeClassForTeam(ent, team);
02055 strcpy(className, client->sess.siegeClass);
02056 }
02057
02058
02059 if (client->siegeClass != -1)
02060 {
02061 siegeClass_t *scl = &bgSiegeClasses[client->siegeClass];
02062
02063 if (scl->saber1[0])
02064 {
02065 G_SetSaber(ent, 0, scl->saber1, qtrue);
02066 }
02067 else
02068 {
02069 G_SetSaber(ent, 0, "Kyle", qtrue);
02070 }
02071 if (scl->saber2[0])
02072 {
02073 G_SetSaber(ent, 1, scl->saber2, qtrue);
02074 }
02075 else
02076 {
02077 G_SetSaber(ent, 1, "none", qtrue);
02078 }
02079
02080
02081 G_SaberModelSetup(ent);
02082
02083 if (scl->forcedModel[0])
02084 {
02085 strcpy(model, scl->forcedModel);
02086 if (d_perPlayerGhoul2.integer)
02087 {
02088 if (Q_stricmp(model, client->modelname))
02089 {
02090 strcpy(client->modelname, model);
02091 modelChanged = qtrue;
02092 }
02093 }
02094 }
02095
02096
02097 if (G_PlayerHasCustomSkeleton(ent))
02098 {
02099 if (Q_stricmp(model, client->modelname) || ent->localAnimIndex == 0)
02100 {
02101 strcpy(client->modelname, model);
02102 modelChanged = qtrue;
02103 }
02104 }
02105 }
02106 }
02107 else
02108 {
02109 strcpy(className, "none");
02110 }
02111
02112
02113 strcpy(saberName, client->sess.saberType);
02114 strcpy(saber2Name, client->sess.saber2Type);
02115
02116
02117 if (g_gametype.integer == GT_SIEGE && client->siegeClass != -1)
02118 {
02119 siegeClass_t *scl = &bgSiegeClasses[client->siegeClass];
02120 maxHealth = 100;
02121
02122 if (scl->maxhealth)
02123 {
02124 maxHealth = scl->maxhealth;
02125 }
02126
02127 health = maxHealth;
02128 }
02129 else
02130 {
02131 maxHealth = 100;
02132 health = 100;
02133 }
02134 client->pers.maxHealth = health;
02135 if ( client->pers.maxHealth < 1 || client->pers.maxHealth > maxHealth ) {
02136 client->pers.maxHealth = 100;
02137 }
02138 client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161 if (g_gametype.integer >= GT_TEAM) {
02162 client->pers.teamInfo = qtrue;
02163 } else {
02164 s = Info_ValueForKey( userinfo, "teamoverlay" );
02165 if ( ! *s || atoi( s ) != 0 ) {
02166 client->pers.teamInfo = qtrue;
02167 } else {
02168 client->pers.teamInfo = qfalse;
02169 }
02170 }
02171
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182 teamTask = atoi(Info_ValueForKey(userinfo, "teamtask"));
02183
02184 teamLeader = client->sess.teamLeader;
02185
02186
02187 strcpy(c1, Info_ValueForKey( userinfo, "color1" ));
02188 strcpy(c2, Info_ValueForKey( userinfo, "color2" ));
02189
02190
02191
02192
02193
02194
02195 if ( ent->r.svFlags & SVF_BOT ) {
02196 s = va("n\\%s\\t\\%i\\model\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d\\siegeclass\\%s\\st\\%s\\st2\\%s\\dt\\%i\\sdt\\%i",
02197 client->pers.netname, team, model, c1, c2,
02198 client->pers.maxHealth, client->sess.wins, client->sess.losses,
02199 Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader, className, saberName, saber2Name, client->sess.duelTeam, client->sess.siegeDesiredTeam );
02200 } else {
02201 if (g_gametype.integer == GT_SIEGE)
02202 {
02203 s = va("n\\%s\\t\\%i\\model\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d\\siegeclass\\%s\\st\\%s\\st2\\%s\\dt\\%i\\sdt\\%i",
02204 client->pers.netname, client->sess.sessionTeam, model, c1, c2,
02205 client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader, className, saberName, saber2Name, client->sess.duelTeam, client->sess.siegeDesiredTeam);
02206 }
02207 else
02208 {
02209 s = va("n\\%s\\t\\%i\\model\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d\\st\\%s\\st2\\%s\\dt\\%i",
02210 client->pers.netname, client->sess.sessionTeam, model, c1, c2,
02211 client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader, saberName, saber2Name, client->sess.duelTeam);
02212 }
02213 }
02214
02215 trap_SetConfigstring( CS_PLAYERS+clientNum, s );
02216
02217 if (modelChanged)
02218 {
02219 char *modelname = Info_ValueForKey (userinfo, "model");
02220 SetupGameGhoul2Model(ent, modelname, NULL);
02221
02222 if (ent->ghoul2 && ent->client)
02223 {
02224 ent->client->renderInfo.lastG2 = NULL;
02225 }
02226
02227 client->torsoAnimExecute = client->legsAnimExecute = -1;
02228 client->torsoLastFlip = client->legsLastFlip = qfalse;
02229 }
02230
02231 if (g_logClientInfo.integer)
02232 {
02233 G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s );
02234 }
02235 }
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258 char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) {
02259 char *value;
02260
02261 gclient_t *client;
02262 char userinfo[MAX_INFO_STRING];
02263 gentity_t *ent;
02264 gentity_t *te;
02265
02266 ent = &g_entities[ clientNum ];
02267
02268 trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );
02269
02270
02271 value = Info_ValueForKey (userinfo, "ip");
02272 if ( G_FilterPacket( value ) ) {
02273 return "Banned.";
02274 }
02275
02276 if ( !( ent->r.svFlags & SVF_BOT ) && !isBot && g_needpass.integer ) {
02277
02278 value = Info_ValueForKey (userinfo, "password");
02279 if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) &&
02280 strcmp( g_password.string, value) != 0) {
02281 static char sTemp[1024];
02282 Q_strncpyz(sTemp, G_GetStringEdString("MP_SVGAME","INVALID_ESCAPE_TO_MAIN"), sizeof (sTemp) );
02283 return sTemp;
02284 }
02285 }
02286
02287
02288 ent->client = level.clients + clientNum;
02289 client = ent->client;
02290
02291
02292 ent->playerState = &ent->client->ps;
02293
02294
02295
02296 memset( client, 0, sizeof(*client) );
02297
02298 client->pers.connected = CON_CONNECTING;
02299
02300
02301 if ( firstTime || level.newSession ) {
02302 G_InitSessionData( client, userinfo, isBot );
02303 }
02304 G_ReadSessionData( client );
02305
02306 if (g_gametype.integer == GT_SIEGE &&
02307 (firstTime || level.newSession))
02308 {
02309 client->sess.siegeDesiredTeam = 0;
02310
02311
02312
02313
02314 }
02315
02316
02317 if (g_gametype.integer == GT_SIEGE && client->sess.sessionTeam != TEAM_SPECTATOR)
02318 {
02319 if (firstTime || level.newSession)
02320 {
02321 client->sess.siegeDesiredTeam = client->sess.sessionTeam;
02322 client->sess.sessionTeam = TEAM_SPECTATOR;
02323 }
02324 }
02325 else if (g_gametype.integer == GT_POWERDUEL && client->sess.sessionTeam != TEAM_SPECTATOR)
02326 {
02327 client->sess.sessionTeam = TEAM_SPECTATOR;
02328 }
02329
02330 if( isBot ) {
02331 ent->r.svFlags |= SVF_BOT;
02332 ent->inuse = qtrue;
02333 if( !G_BotConnect( clientNum, !firstTime ) ) {
02334 return "BotConnectfailed";
02335 }
02336 }
02337
02338
02339 G_LogPrintf( "ClientConnect: %i\n", clientNum );
02340 ClientUserinfoChanged( clientNum );
02341
02342
02343 if ( firstTime ) {
02344 trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " %s\n\"", client->pers.netname, G_GetStringEdString("MP_SVGAME", "PLCONNECT")) );
02345 }
02346
02347 if ( g_gametype.integer >= GT_TEAM &&
02348 client->sess.sessionTeam != TEAM_SPECTATOR ) {
02349 BroadcastTeamChange( client, -1 );
02350 }
02351
02352
02353 CalculateRanks();
02354
02355 te = G_TempEntity( vec3_origin, EV_CLIENTJOIN );
02356 te->r.svFlags |= SVF_BROADCAST;
02357 te->s.eventParm = clientNum;
02358
02359
02360
02361
02362
02363
02364 return NULL;
02365 }
02366
02367 void G_WriteClientSessionData( gclient_t *client );
02368
02369 #include "../namespace_begin.h"
02370 void WP_SetSaber( int entNum, saberInfo_t *sabers, int saberNum, const char *saberName );
02371 #include "../namespace_end.h"
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382 extern qboolean gSiegeRoundBegun;
02383 extern qboolean gSiegeRoundEnded;
02384 void SetTeamQuick(gentity_t *ent, int team, qboolean doBegin);
02385 void ClientBegin( int clientNum, qboolean allowTeamReset ) {
02386 gentity_t *ent;
02387 gclient_t *client;
02388 gentity_t *tent;
02389 int flags, i;
02390 char userinfo[MAX_INFO_VALUE], *modelname;
02391
02392 ent = g_entities + clientNum;
02393
02394 if ((ent->r.svFlags & SVF_BOT) && g_gametype.integer >= GT_TEAM)
02395 {
02396 if (allowTeamReset)
02397 {
02398 const char *team = "Red";
02399 int preSess;
02400
02401
02402 ent->client->sess.sessionTeam = PickTeam(-1);
02403 trap_GetUserinfo(clientNum, userinfo, MAX_INFO_STRING);
02404
02405 if (ent->client->sess.sessionTeam == TEAM_SPECTATOR)
02406 {
02407 ent->client->sess.sessionTeam = TEAM_RED;
02408 }
02409
02410 if (ent->client->sess.sessionTeam == TEAM_RED)
02411 {
02412 team = "Red";
02413 }
02414 else
02415 {
02416 team = "Blue";
02417 }
02418
02419 Info_SetValueForKey( userinfo, "team", team );
02420
02421 trap_SetUserinfo( clientNum, userinfo );
02422
02423 ent->client->ps.persistant[ PERS_TEAM ] = ent->client->sess.sessionTeam;
02424
02425 preSess = ent->client->sess.sessionTeam;
02426 G_ReadSessionData( ent->client );
02427 ent->client->sess.sessionTeam = preSess;
02428 G_WriteClientSessionData(ent->client);
02429 ClientUserinfoChanged( clientNum );
02430 ClientBegin(clientNum, qfalse);
02431 return;
02432 }
02433 }
02434
02435 client = level.clients + clientNum;
02436
02437 if ( ent->r.linked ) {
02438 trap_UnlinkEntity( ent );
02439 }
02440 G_InitGentity( ent );
02441 ent->touch = 0;
02442 ent->pain = 0;
02443 ent->client = client;
02444
02445
02446 ent->playerState = &ent->client->ps;
02447
02448 client->pers.connected = CON_CONNECTED;
02449 client->pers.enterTime = level.time;
02450 client->pers.teamState.state = TEAM_BEGIN;
02451
02452
02453
02454
02455
02456
02457 flags = client->ps.eFlags;
02458
02459 i = 0;
02460
02461 while (i < NUM_FORCE_POWERS)
02462 {
02463 if (ent->client->ps.fd.forcePowersActive & (1 << i))
02464 {
02465 WP_ForcePowerStop(ent, i);
02466 }
02467 i++;
02468 }
02469
02470 i = TRACK_CHANNEL_1;
02471
02472 while (i < NUM_TRACK_CHANNELS)
02473 {
02474 if (ent->client->ps.fd.killSoundEntIndex[i-50] && ent->client->ps.fd.killSoundEntIndex[i-50] < MAX_GENTITIES && ent->client->ps.fd.killSoundEntIndex[i-50] > 0)
02475 {
02476 G_MuteSound(ent->client->ps.fd.killSoundEntIndex[i-50], CHAN_VOICE);
02477 }
02478 i++;
02479 }
02480 i = 0;
02481
02482 memset( &client->ps, 0, sizeof( client->ps ) );
02483 client->ps.eFlags = flags;
02484
02485 client->ps.hasDetPackPlanted = qfalse;
02486
02487
02488 WP_InitForcePowers( ent );
02489
02490
02491 WP_SaberInitBladeData( ent );
02492
02493
02494 trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );
02495 modelname = Info_ValueForKey (userinfo, "model");
02496 SetupGameGhoul2Model(ent, modelname, NULL);
02497
02498 if (ent->ghoul2 && ent->client)
02499 {
02500 ent->client->renderInfo.lastG2 = NULL;
02501 }
02502
02503 if (g_gametype.integer == GT_POWERDUEL && client->sess.sessionTeam != TEAM_SPECTATOR &&
02504 client->sess.duelTeam == DUELTEAM_FREE)
02505 {
02506 SetTeam(ent, "s");
02507 }
02508 else
02509 {
02510 if (g_gametype.integer == GT_SIEGE && (!gSiegeRoundBegun || gSiegeRoundEnded))
02511 {
02512 SetTeamQuick(ent, TEAM_SPECTATOR, qfalse);
02513 }
02514
02515 if ((ent->r.svFlags & SVF_BOT) &&
02516 g_gametype.integer != GT_SIEGE)
02517 {
02518 char *saberVal = Info_ValueForKey(userinfo, "saber1");
02519 char *saber2Val = Info_ValueForKey(userinfo, "saber2");
02520
02521 if (!saberVal || !saberVal[0])
02522 {
02523 int r = rand()%50;
02524 char sab1[1024];
02525 char sab2[1024];
02526
02527 if (r <= 17)
02528 {
02529 strcpy(sab1, "Katarn");
02530 strcpy(sab2, "none");
02531 }
02532 else if (r <= 34)
02533 {
02534 strcpy(sab1, "Katarn");
02535 strcpy(sab2, "Katarn");
02536 }
02537 else
02538 {
02539 strcpy(sab1, "dual_1");
02540 strcpy(sab2, "none");
02541 }
02542 G_SetSaber(ent, 0, sab1, qfalse);
02543 G_SetSaber(ent, 0, sab2, qfalse);
02544 Info_SetValueForKey( userinfo, "saber1", sab1 );
02545 Info_SetValueForKey( userinfo, "saber2", sab2 );
02546 trap_SetUserinfo( clientNum, userinfo );
02547 }
02548 else
02549 {
02550 G_SetSaber(ent, 0, saberVal, qfalse);
02551 }
02552
02553 if (saberVal && saberVal[0] &&
02554 (!saber2Val || !saber2Val[0]))
02555 {
02556 G_SetSaber(ent, 0, "none", qfalse);
02557 Info_SetValueForKey( userinfo, "saber2", "none" );
02558 trap_SetUserinfo( clientNum, userinfo );
02559 }
02560 else
02561 {
02562 G_SetSaber(ent, 0, saber2Val, qfalse);
02563 }
02564 }
02565
02566
02567 ClientSpawn( ent );
02568 }
02569
02570 if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
02571
02572 tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
02573 tent->s.clientNum = ent->s.clientNum;
02574
02575 if ( g_gametype.integer != GT_DUEL || g_gametype.integer == GT_POWERDUEL ) {
02576 trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " %s\n\"", client->pers.netname, G_GetStringEdString("MP_SVGAME", "PLENTER")) );
02577 }
02578 }
02579 G_LogPrintf( "ClientBegin: %i\n", clientNum );
02580
02581
02582 CalculateRanks();
02583
02584 G_ClearClientLog(clientNum);
02585 }
02586
02587 static qboolean AllForceDisabled(int force)
02588 {
02589 int i;
02590
02591 if (force)
02592 {
02593 for (i=0;i<NUM_FORCE_POWERS;i++)
02594 {
02595 if (!(force & (1<<i)))
02596 {
02597 return qfalse;
02598 }
02599 }
02600
02601 return qtrue;
02602 }
02603
02604 return qfalse;
02605 }
02606
02607
02608 void G_BreakArm(gentity_t *ent, int arm)
02609 {
02610 int anim = -1;
02611
02612 assert(ent && ent->client);
02613
02614 if (ent->s.NPC_class == CLASS_VEHICLE || ent->localAnimIndex > 1)
02615 {
02616 return;
02617 }
02618
02619 if (!arm)
02620 {
02621 ent->client->ps.brokenLimbs = 0;
02622 return;
02623 }
02624
02625 if (ent->client->ps.fd.saberAnimLevel == SS_STAFF)
02626 {
02627 return;
02628 }
02629
02630 if (arm == BROKENLIMB_LARM)
02631 {
02632 if (ent->client->saber[1].model[0] &&
02633 ent->client->ps.weapon == WP_SABER &&
02634 !ent->client->ps.saberHolstered &&
02635 ent->client->saber[1].soundOff)
02636 {
02637 G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOff);
02638 }
02639 }
02640
02641 ent->client->ps.brokenLimbs = 0;
02642 ent->client->ps.brokenLimbs |= (1 << arm);
02643
02644
02645 if (arm == BROKENLIMB_LARM)
02646 {
02647 anim = BOTH_PAIN2;
02648 }
02649 else if (arm == BROKENLIMB_RARM)
02650 {
02651 anim = BOTH_PAIN3;
02652 }
02653
02654 if (anim == -1)
02655 {
02656 return;
02657 }
02658
02659 G_SetAnim(ent, &ent->client->pers.cmd, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0);
02660
02661
02662
02663 G_EntitySound( ent, CHAN_VOICE, G_SoundIndex("*pain25.wav") );
02664
02665 G_Sound(ent, CHAN_AUTO, G_SoundIndex( va("sound/player/bodyfall_human%i.wav", Q_irand(1, 3)) ));
02666 }
02667
02668
02669 #include "../namespace_begin.h"
02670 qboolean BG_SaberStanceAnim( int anim );
02671 qboolean PM_RunningAnim( int anim );
02672 #include "../namespace_end.h"
02673 void G_UpdateClientAnims(gentity_t *self, float animSpeedScale)
02674 {
02675 static int f;
02676 static int torsoAnim;
02677 static int legsAnim;
02678 static int firstFrame, lastFrame;
02679 static int aFlags;
02680 static float animSpeed, lAnimSpeedScale;
02681 qboolean setTorso = qfalse;
02682
02683 torsoAnim = (self->client->ps.torsoAnim);
02684 legsAnim = (self->client->ps.legsAnim);
02685
02686 if (self->client->ps.saberLockFrame)
02687 {
02688 trap_G2API_SetBoneAnim(self->ghoul2, 0, "model_root", self->client->ps.saberLockFrame, self->client->ps.saberLockFrame+1, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150);
02689 trap_G2API_SetBoneAnim(self->ghoul2, 0, "lower_lumbar", self->client->ps.saberLockFrame, self->client->ps.saberLockFrame+1, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150);
02690 trap_G2API_SetBoneAnim(self->ghoul2, 0, "Motion", self->client->ps.saberLockFrame, self->client->ps.saberLockFrame+1, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150);
02691 return;
02692 }
02693
02694 if (self->localAnimIndex > 1 &&
02695 bgAllAnims[self->localAnimIndex].anims[legsAnim].firstFrame == 0 &&
02696 bgAllAnims[self->localAnimIndex].anims[legsAnim].numFrames == 0)
02697 {
02698 goto tryTorso;
02699 }
02700
02701 if (self->client->legsAnimExecute != legsAnim || self->client->legsLastFlip != self->client->ps.legsFlip)
02702 {
02703 animSpeed = 50.0f / bgAllAnims[self->localAnimIndex].anims[legsAnim].frameLerp;
02704 lAnimSpeedScale = (animSpeed *= animSpeedScale);
02705
02706 if (bgAllAnims[self->localAnimIndex].anims[legsAnim].loopFrames != -1)
02707 {
02708 aFlags = BONE_ANIM_OVERRIDE_LOOP;
02709 }
02710 else
02711 {
02712 aFlags = BONE_ANIM_OVERRIDE_FREEZE;
02713 }
02714
02715 if (animSpeed < 0)
02716 {
02717 lastFrame = bgAllAnims[self->localAnimIndex].anims[legsAnim].firstFrame;
02718 firstFrame = bgAllAnims[self->localAnimIndex].anims[legsAnim].firstFrame + bgAllAnims[self->localAnimIndex].anims[legsAnim].numFrames;
02719 }
02720 else
02721 {
02722 firstFrame = bgAllAnims[self->localAnimIndex].anims[legsAnim].firstFrame;
02723 lastFrame = bgAllAnims[self->localAnimIndex].anims[legsAnim].firstFrame + bgAllAnims[self->localAnimIndex].anims[legsAnim].numFrames;
02724 }
02725
02726 aFlags |= BONE_ANIM_BLEND;
02727
02728 trap_G2API_SetBoneAnim(self->ghoul2, 0, "model_root", firstFrame, lastFrame, aFlags, lAnimSpeedScale, level.time, -1, 150);
02729 self->client->legsAnimExecute = legsAnim;
02730 self->client->legsLastFlip = self->client->ps.legsFlip;
02731 }
02732
02733 tryTorso:
02734 if (self->localAnimIndex > 1 &&
02735 bgAllAnims[self->localAnimIndex].anims[torsoAnim].firstFrame == 0 &&
02736 bgAllAnims[self->localAnimIndex].anims[torsoAnim].numFrames == 0)
02737
02738 {
02739 return;
02740 }
02741 else if (self->s.number >= MAX_CLIENTS &&
02742 self->s.NPC_class == CLASS_VEHICLE)
02743 {
02744 return;
02745 }
02746
02747 if ((self->client->torsoAnimExecute != torsoAnim || self->client->torsoLastFlip != self->client->ps.torsoFlip) &&
02748 !self->noLumbar)
02749 {
02750 aFlags = 0;
02751 animSpeed = 0;
02752
02753 f = torsoAnim;
02754
02755 BG_SaberStartTransAnim(self->s.number, self->client->ps.fd.saberAnimLevel, self->client->ps.weapon, f, &animSpeedScale, self->client->ps.brokenLimbs);
02756
02757 animSpeed = 50.0f / bgAllAnims[self->localAnimIndex].anims[f].frameLerp;
02758 lAnimSpeedScale = (animSpeed *= animSpeedScale);
02759
02760 if (bgAllAnims[self->localAnimIndex].anims[f].loopFrames != -1)
02761 {
02762 aFlags = BONE_ANIM_OVERRIDE_LOOP;
02763 }
02764 else
02765 {
02766 aFlags = BONE_ANIM_OVERRIDE_FREEZE;
02767 }
02768
02769 aFlags |= BONE_ANIM_BLEND;
02770
02771 if (animSpeed < 0)
02772 {
02773 lastFrame = bgAllAnims[self->localAnimIndex].anims[f].firstFrame;
02774 firstFrame = bgAllAnims[self->localAnimIndex].anims[f].firstFrame + bgAllAnims[self->localAnimIndex].anims[f].numFrames;
02775 }
02776 else
02777 {
02778 firstFrame = bgAllAnims[self->localAnimIndex].anims[f].firstFrame;
02779 lastFrame = bgAllAnims[self->localAnimIndex].anims[f].firstFrame + bgAllAnims[self->localAnimIndex].anims[f].numFrames;
02780 }
02781
02782 trap_G2API_SetBoneAnim(self->ghoul2, 0, "lower_lumbar", firstFrame, lastFrame, aFlags, lAnimSpeedScale, level.time, -1, 150);
02783
02784 self->client->torsoAnimExecute = torsoAnim;
02785 self->client->torsoLastFlip = self->client->ps.torsoFlip;
02786
02787 setTorso = qtrue;
02788 }
02789
02790 if (setTorso &&
02791 self->localAnimIndex <= 1)
02792 {
02793 trap_G2API_SetBoneAnim(self->ghoul2, 0, "Motion", firstFrame, lastFrame, aFlags, lAnimSpeedScale, level.time, -1, 150);
02794 }
02795
02796 #if 0 //disabled for now
02797 if (self->client->ps.brokenLimbs != self->client->brokenLimbs ||
02798 setTorso)
02799 {
02800 if (self->localAnimIndex <= 1 && self->client->ps.brokenLimbs &&
02801 (self->client->ps.brokenLimbs & (1 << BROKENLIMB_LARM)))
02802 {
02803 char *brokenBone = "lhumerus";
02804 animation_t *armAnim;
02805 int armFirstFrame;
02806 int armLastFrame;
02807 int armFlags = 0;
02808 float armAnimSpeed;
02809
02810 armAnim = &bgAllAnims[self->localAnimIndex].anims[ BOTH_DEAD21 ];
02811 self->client->brokenLimbs = self->client->ps.brokenLimbs;
02812
02813 armFirstFrame = armAnim->firstFrame;
02814 armLastFrame = armAnim->firstFrame+armAnim->numFrames;
02815 armAnimSpeed = 50.0f / armAnim->frameLerp;
02816 armFlags = (BONE_ANIM_OVERRIDE_LOOP|BONE_ANIM_BLEND);
02817
02818 trap_G2API_SetBoneAnim(self->ghoul2, 0, brokenBone, armFirstFrame, armLastFrame, armFlags, armAnimSpeed, level.time, -1, 150);
02819 }
02820 else if (self->localAnimIndex <= 1 && self->client->ps.brokenLimbs &&
02821 (self->client->ps.brokenLimbs & (1 << BROKENLIMB_RARM)))
02822 {
02823 char *brokenBone = "rhumerus";
02824 char *supportBone = "lhumerus";
02825
02826 self->client->brokenLimbs = self->client->ps.brokenLimbs;
02827
02828
02829
02830 if ((
02831 self->client->ps.weapon != WP_SABER ||
02832 BG_SaberStanceAnim(self->client->ps.torsoAnim) ||
02833 PM_RunningAnim(self->client->ps.torsoAnim)) &&
02834 (!self->client->saber[1].model[0] || self->client->ps.weapon != WP_SABER))
02835 {
02836 int armFirstFrame;
02837 int armLastFrame;
02838 int armFlags = 0;
02839 float armAnimSpeed;
02840 animation_t *armAnim;
02841
02842 if (self->client->ps.weapon == WP_MELEE ||
02843 self->client->ps.weapon == WP_SABER ||
02844 self->client->ps.weapon == WP_BRYAR_PISTOL)
02845 {
02846 armAnim = &bgAllAnims[self->localAnimIndex].anims[ BOTH_ATTACK2 ];
02847
02848
02849 armFirstFrame = armAnim->firstFrame+armAnim->numFrames;
02850 armLastFrame = armAnim->firstFrame+armAnim->numFrames;
02851 armAnimSpeed = 50.0f / armAnim->frameLerp;
02852 armFlags = (BONE_ANIM_OVERRIDE_LOOP|BONE_ANIM_BLEND);
02853
02854 trap_G2API_SetBoneAnim(self->ghoul2, 0, brokenBone, armFirstFrame, armLastFrame, armFlags, armAnimSpeed, level.time, -1, 150);
02855 }
02856 else
02857 {
02858 trap_G2API_SetBoneAnim(self->ghoul2, 0, brokenBone, firstFrame, lastFrame, aFlags, lAnimSpeedScale, level.time, -1, 150);
02859 }
02860
02861 if (self->client->ps.torsoAnim != BOTH_MELEE1 &&
02862 self->client->ps.torsoAnim != BOTH_MELEE2 &&
02863 (self->client->ps.torsoAnim == TORSO_WEAPONREADY2 || self->client->ps.torsoAnim == BOTH_ATTACK2 || self->client->ps.weapon < WP_BRYAR_PISTOL))
02864 {
02865
02866 armAnim = &bgAllAnims[self->localAnimIndex].anims[ BOTH_STAND2 ];
02867 armFirstFrame = armAnim->firstFrame;
02868 armLastFrame = armAnim->firstFrame+armAnim->numFrames;
02869 armAnimSpeed = 50.0f / armAnim->frameLerp;
02870 armFlags = (BONE_ANIM_OVERRIDE_LOOP|BONE_ANIM_BLEND);
02871
02872 trap_G2API_SetBoneAnim(self->ghoul2, 0, supportBone, armFirstFrame, armLastFrame, armFlags, armAnimSpeed, level.time, -1, 150);
02873 }
02874 else
02875 {
02876 trap_G2API_SetBoneAnim(self->ghoul2, 0, supportBone, firstFrame, lastFrame, aFlags, lAnimSpeedScale, level.time, -1, 150);
02877 }
02878 }
02879 else
02880 {
02881 trap_G2API_SetBoneAnim(self->ghoul2, 0, brokenBone, firstFrame, lastFrame, aFlags, lAnimSpeedScale, level.time, -1, 150);
02882 trap_G2API_SetBoneAnim(self->ghoul2, 0, supportBone, firstFrame, lastFrame, aFlags, lAnimSpeedScale, level.time, -1, 150);
02883 }
02884 }
02885 else if (self->client->brokenLimbs)
02886 {
02887 char *brokenBone = NULL;
02888 int broken = 0;
02889
02890
02891
02892 if (self->client->brokenLimbs & (1<<BROKENLIMB_LARM))
02893 {
02894 brokenBone = "lhumerus";
02895 broken |= (1<<BROKENLIMB_LARM);
02896 }
02897 else if (self->client->brokenLimbs & (1<<BROKENLIMB_RARM))
02898 {
02899 brokenBone = "rhumerus";
02900 broken |= (1<<BROKENLIMB_RARM);
02901
02902
02903 trap_G2API_SetBoneAnim(self->ghoul2, 0, "lhumerus", 0, 1, 0, 0, level.time, -1, 0);
02904 trap_G2API_RemoveBone(self->ghoul2, "lhumerus", 0);
02905 }
02906
02907 assert(brokenBone);
02908
02909
02910 trap_G2API_SetBoneAnim(self->ghoul2, 0, brokenBone, 0, 1, 0, 0, level.time, -1, 0);
02911
02912
02913 trap_G2API_RemoveBone(self->ghoul2, brokenBone, 0);
02914 self->client->brokenLimbs &= ~broken;
02915 }
02916 }
02917 #endif
02918 }
02919
02920
02921
02922
02923
02924
02925
02926
02927
02928
02929 extern qboolean WP_HasForcePowers( const playerState_t *ps );
02930 void ClientSpawn(gentity_t *ent) {
02931 int index;
02932 vec3_t spawn_origin, spawn_angles;
02933 gclient_t *client;
02934 int i;
02935 clientPersistant_t saved;
02936 clientSession_t savedSess;
02937 int persistant[MAX_PERSISTANT];
02938 gentity_t *spawnPoint;
02939 int flags, gameFlags;
02940 int savedPing;
02941 int accuracy_hits, accuracy_shots;
02942 int eventSequence;
02943 char userinfo[MAX_INFO_STRING];
02944 forcedata_t savedForce;
02945 int saveSaberNum = ENTITYNUM_NONE;
02946 int wDisable = 0;
02947 int savedSiegeIndex = 0;
02948 int maxHealth;
02949 saberInfo_t saberSaved[MAX_SABERS];
02950 int l = 0;
02951 void *g2WeaponPtrs[MAX_SABERS];
02952 char *value;
02953 char *saber;
02954 qboolean changedSaber = qfalse;
02955 qboolean inSiegeWithClass = qfalse;
02956
02957 index = ent - g_entities;
02958 client = ent->client;
02959
02960
02961 trap_GetUserinfo( index, userinfo, sizeof(userinfo) );
02962 while (l < MAX_SABERS)
02963 {
02964 switch (l)
02965 {
02966 case 0:
02967 saber = &ent->client->sess.saberType[0];
02968 break;
02969 case 1:
02970 saber = &ent->client->sess.saber2Type[0];
02971 break;
02972 default:
02973 saber = NULL;
02974 break;
02975 }
02976
02977 value = Info_ValueForKey (userinfo, va("saber%i", l+1));
02978 if (saber &&
02979 value &&
02980 (Q_stricmp(value, saber) || !saber[0] || !ent->client->saber[0].model[0]))
02981 {
02982 if (G_SetSaber(ent, l, value, qfalse))
02983 {
02984 changedSaber = qtrue;
02985 }
02986 else if (!saber[0] || !ent->client->saber[0].model[0])
02987 {
02988 changedSaber = qtrue;
02989 }
02990 }
02991 l++;
02992 }
02993
02994 if (changedSaber)
02995 {
02996 ClientUserinfoChanged( ent->s.number );
02997
02998
02999 G_SaberModelSetup(ent);
03000
03001 l = 0;
03002 while (l < MAX_SABERS)
03003 {
03004 switch (l)
03005 {
03006 case 0:
03007 saber = &ent->client->sess.saberType[0];
03008 break;
03009 case 1:
03010 saber = &ent->client->sess.saber2Type[0];
03011 break;
03012 default:
03013 saber = NULL;
03014 break;
03015 }
03016
03017 value = Info_ValueForKey (userinfo, va("saber%i", l+1));
03018
03019 if (Q_stricmp(value, saber))
03020 {
03021 Info_SetValueForKey(userinfo, va("saber%i", l+1), saber);
03022 trap_SetUserinfo( ent->s.number, userinfo );
03023 }
03024 l++;
03025 }
03026
03027 if (ent->client->saber[0].model[0] &&
03028 ent->client->saber[1].model[0])
03029 {
03030 ent->client->ps.fd.saberAnimLevelBase = ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = SS_DUAL;
03031 }
03032 else if ((ent->client->saber[0].saberFlags&SFL_TWO_HANDED))
03033 {
03034 ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = SS_STAFF;
03035 }
03036 else
03037 {
03038 if (ent->client->sess.saberLevel < SS_FAST)
03039 {
03040 ent->client->sess.saberLevel = SS_FAST;
03041 }
03042 else if (ent->client->sess.saberLevel > SS_STRONG)
03043 {
03044 ent->client->sess.saberLevel = SS_STRONG;
03045 }
03046 ent->client->ps.fd.saberAnimLevelBase = ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = ent->client->sess.saberLevel;
03047
03048 if (g_gametype.integer != GT_SIEGE &&
03049 ent->client->ps.fd.saberAnimLevel > ent->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE])
03050 {
03051 ent->client->ps.fd.saberAnimLevelBase = ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = ent->client->sess.saberLevel = ent->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE];
03052 }
03053 }
03054 if ( g_gametype.integer != GT_SIEGE )
03055 {
03056
03057 if ( !WP_SaberStyleValidForSaber( &ent->client->saber[0], &ent->client->saber[1], ent->client->ps.saberHolstered, ent->client->ps.fd.saberAnimLevel ) )
03058 {
03059 WP_UseFirstValidSaberStyle( &ent->client->saber[0], &ent->client->saber[1], ent->client->ps.saberHolstered, &ent->client->ps.fd.saberAnimLevel );
03060 ent->client->ps.fd.saberAnimLevelBase = ent->client->saberCycleQueue = ent->client->ps.fd.saberAnimLevel;
03061 }
03062 }
03063 }
03064 l = 0;
03065
03066 if (client->ps.fd.forceDoInit)
03067 {
03068 WP_InitForcePowers( ent );
03069 client->ps.fd.forceDoInit = 0;
03070 }
03071
03072 if (ent->client->ps.fd.saberAnimLevel != SS_STAFF &&
03073 ent->client->ps.fd.saberAnimLevel != SS_DUAL &&
03074 ent->client->ps.fd.saberAnimLevel == ent->client->ps.fd.saberDrawAnimLevel &&
03075 ent->client->ps.fd.saberAnimLevel == ent->client->sess.saberLevel)
03076 {
03077 if (ent->client->sess.saberLevel < SS_FAST)
03078 {
03079 ent->client->sess.saberLevel = SS_FAST;
03080 }
03081 else if (ent->client->sess.saberLevel > SS_STRONG)
03082 {
03083 ent->client->sess.saberLevel = SS_STRONG;
03084 }
03085 ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = ent->client->sess.saberLevel;
03086
03087 if (g_gametype.integer != GT_SIEGE &&
03088 ent->client->ps.fd.saberAnimLevel > ent->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE])
03089 {
03090 ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = ent->client->sess.saberLevel = ent->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE];
03091 }
03092 }
03093
03094
03095
03096
03097 if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
03098 spawnPoint = SelectSpectatorSpawnPoint (
03099 spawn_origin, spawn_angles);
03100 } else if (g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY) {
03101
03102 spawnPoint = SelectCTFSpawnPoint (
03103 client->sess.sessionTeam,
03104 client->pers.teamState.state,
03105 spawn_origin, spawn_angles);
03106 }
03107 else if (g_gametype.integer == GT_SIEGE)
03108 {
03109 spawnPoint = SelectSiegeSpawnPoint (
03110 client->siegeClass,
03111 client->sess.sessionTeam,
03112 client->pers.teamState.state,
03113 spawn_origin, spawn_angles);
03114 }
03115 else {
03116 do {
03117 if (g_gametype.integer == GT_POWERDUEL)
03118 {
03119 spawnPoint = SelectDuelSpawnPoint(client->sess.duelTeam, client->ps.origin, spawn_origin, spawn_angles);
03120 }
03121 else if (g_gametype.integer == GT_DUEL)
03122 {
03123 spawnPoint = SelectDuelSpawnPoint(DUELTEAM_SINGLE, client->ps.origin, spawn_origin, spawn_angles);
03124 }
03125 else
03126 {
03127
03128 if ( !client->pers.initialSpawn && client->pers.localClient ) {
03129 client->pers.initialSpawn = qtrue;
03130 spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles, client->sess.sessionTeam );
03131 } else {
03132
03133 spawnPoint = SelectSpawnPoint (
03134 client->ps.origin,
03135 spawn_origin, spawn_angles, client->sess.sessionTeam );
03136 }
03137 }
03138
03139
03140
03141 if ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) {
03142 continue;
03143 }
03144
03145 if ( ( spawnPoint->flags & FL_NO_HUMANS ) && !( ent->r.svFlags & SVF_BOT ) ) {
03146 continue;
03147 }
03148
03149 break;
03150
03151 } while ( 1 );
03152 }
03153 client->pers.teamState.state = TEAM_ACTIVE;
03154
03155
03156
03157 flags = ent->client->ps.eFlags & (EF_TELEPORT_BIT );
03158 flags ^= EF_TELEPORT_BIT;
03159 gameFlags = ent->client->mGameFlags & ( PSG_VOTED | PSG_TEAMVOTED);
03160
03161
03162
03163 saved = client->pers;
03164 savedSess = client->sess;
03165 savedPing = client->ps.ping;
03166
03167 accuracy_hits = client->accuracy_hits;
03168 accuracy_shots = client->accuracy_shots;
03169 for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
03170 persistant[i] = client->ps.persistant[i];
03171 }
03172 eventSequence = client->ps.eventSequence;
03173
03174 savedForce = client->ps.fd;
03175
03176 saveSaberNum = client->ps.saberEntityNum;
03177
03178 savedSiegeIndex = client->siegeClass;
03179
03180 l = 0;
03181 while (l < MAX_SABERS)
03182 {
03183 saberSaved[l] = client->saber[l];
03184 g2WeaponPtrs[l] = client->weaponGhoul2[l];
03185 l++;
03186 }
03187
03188 i = 0;
03189 while (i < HL_MAX)
03190 {
03191 ent->locationDamage[i] = 0;
03192 i++;
03193 }
03194
03195 memset (client, 0, sizeof(*client));
03196 client->bodyGrabIndex = ENTITYNUM_NONE;
03197
03198
03199 value = Info_ValueForKey (userinfo, "char_color_red");
03200 if (value)
03201 {
03202 client->ps.customRGBA[0] = atoi(value);
03203 }
03204 else
03205 {
03206 client->ps.customRGBA[0] = 255;
03207 }
03208
03209 value = Info_ValueForKey (userinfo, "char_color_green");
03210 if (value)
03211 {
03212 client->ps.customRGBA[1] = atoi(value);
03213 }
03214 else
03215 {
03216 client->ps.customRGBA[1] = 255;
03217 }
03218
03219 value = Info_ValueForKey (userinfo, "char_color_blue");
03220 if (value)
03221 {
03222 client->ps.customRGBA[2] = atoi(value);
03223 }
03224 else
03225 {
03226 client->ps.customRGBA[2] = 255;
03227 }
03228
03229 if ((client->ps.customRGBA[0]+client->ps.customRGBA[1]+client->ps.customRGBA[2]) < 100)
03230 {
03231 client->ps.customRGBA[0] = client->ps.customRGBA[1] = client->ps.customRGBA[2] = 255;
03232 }
03233
03234 client->ps.customRGBA[3]=255;
03235
03236 client->siegeClass = savedSiegeIndex;
03237
03238 l = 0;
03239 while (l < MAX_SABERS)
03240 {
03241 client->saber[l] = saberSaved[l];
03242 client->weaponGhoul2[l] = g2WeaponPtrs[l];
03243 l++;
03244 }
03245
03246
03247 client->ps.saberEntityNum = saveSaberNum;
03248 client->saberStoredIndex = saveSaberNum;
03249
03250 client->ps.fd = savedForce;
03251
03252 client->ps.duelIndex = ENTITYNUM_NONE;
03253
03254
03255 client->ps.jetpackFuel = 100;
03256 client->ps.cloakFuel = 100;
03257
03258 client->pers = saved;
03259 client->sess = savedSess;
03260 client->ps.ping = savedPing;
03261
03262 client->accuracy_hits = accuracy_hits;
03263 client->accuracy_shots = accuracy_shots;
03264 client->lastkilled_client = -1;
03265
03266 for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
03267 client->ps.persistant[i] = persistant[i];
03268 }
03269 client->ps.eventSequence = eventSequence;
03270
03271 client->ps.persistant[PERS_SPAWN_COUNT]++;
03272 client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam;
03273
03274 client->airOutTime = level.time + 12000;
03275
03276
03277 if (g_gametype.integer == GT_SIEGE && client->siegeClass != -1)
03278 {
03279 siegeClass_t *scl = &bgSiegeClasses[client->siegeClass];
03280 maxHealth = 100;
03281
03282 if (scl->maxhealth)
03283 {
03284 maxHealth = scl->maxhealth;
03285 }
03286 }
03287 else
03288 {
03289 maxHealth = 100;
03290 }
03291 client->pers.maxHealth = maxHealth;
03292 if ( client->pers.maxHealth < 1 || client->pers.maxHealth > maxHealth ) {
03293 client->pers.maxHealth = 100;
03294 }
03295
03296 client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
03297 client->ps.eFlags = flags;
03298 client->mGameFlags = gameFlags;
03299
03300 ent->s.groundEntityNum = ENTITYNUM_NONE;
03301 ent->client = &level.clients[index];
03302 ent->playerState = &ent->client->ps;
03303 ent->takedamage = qtrue;
03304 ent->inuse = qtrue;
03305 ent->classname = "player";
03306 ent->r.contents = CONTENTS_BODY;
03307 ent->clipmask = MASK_PLAYERSOLID;
03308 ent->die = player_die;
03309 ent->waterlevel = 0;
03310 ent->watertype = 0;
03311 ent->flags = 0;
03312
03313 VectorCopy (playerMins, ent->r.mins);
03314 VectorCopy (playerMaxs, ent->r.maxs);
03315 client->ps.crouchheight = CROUCH_MAXS_2;
03316 client->ps.standheight = DEFAULT_MAXS_2;
03317
03318 client->ps.clientNum = index;
03319
03320 client->ps.stats[STAT_WEAPONS] = ( 1 << WP_NONE );
03321
03322 if (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL)
03323 {
03324 wDisable = g_duelWeaponDisable.integer;
03325 }
03326 else
03327 {
03328 wDisable = g_weaponDisable.integer;
03329 }
03330
03331
03332
03333 if ( g_gametype.integer != GT_HOLOCRON
03334 && g_gametype.integer != GT_JEDIMASTER
03335 && !HasSetSaberOnly()
03336 && !AllForceDisabled( g_forcePowerDisable.integer )
03337 && g_trueJedi.integer )
03338 {
03339 if ( g_gametype.integer >= GT_TEAM && (client->sess.sessionTeam == TEAM_BLUE || client->sess.sessionTeam == TEAM_RED) )
03340 {
03341 if ( level.numPlayingClients > 0 )
03342 {
03343 int i, forceTeam = TEAM_SPECTATOR;
03344 for ( i = 0 ; i < level.maxclients ; i++ )
03345 {
03346 if ( level.clients[i].pers.connected == CON_DISCONNECTED ) {
03347 continue;
03348 }
03349 if ( level.clients[i].sess.sessionTeam == TEAM_BLUE || level.clients[i].sess.sessionTeam == TEAM_RED )
03350 {
03351 if ( WP_HasForcePowers( &level.clients[i].ps ) )
03352 {
03353 forceTeam = level.clients[i].sess.sessionTeam;
03354 }
03355 else
03356 {
03357 if ( level.clients[i].sess.sessionTeam == TEAM_BLUE )
03358 {
03359 forceTeam = TEAM_RED;
03360 }
03361 else
03362 {
03363 forceTeam = TEAM_BLUE;
03364 }
03365 }
03366 break;
03367 }
03368 }
03369 if ( WP_HasForcePowers( &client->ps ) && client->sess.sessionTeam != forceTeam )
03370 {
03371 const char *teamName = TeamName( forceTeam );
03372
03373 SetTeam( ent, (char *)teamName );
03374 return;
03375 }
03376 }
03377 }
03378
03379 if ( WP_HasForcePowers( &client->ps ) )
03380 {
03381 client->ps.trueNonJedi = qfalse;
03382 client->ps.trueJedi = qtrue;
03383
03384 client->ps.weapon = WP_SABER;
03385 client->ps.stats[STAT_WEAPONS] = (1 << WP_SABER);
03386 }
03387 else
03388 {
03389 client->ps.trueNonJedi = qtrue;
03390 client->ps.trueJedi = qfalse;
03391 if (!wDisable || !(wDisable & (1 << WP_BRYAR_PISTOL)))
03392 {
03393 client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL );
03394 }
03395 if (!wDisable || !(wDisable & (1 << WP_BLASTER)))
03396 {
03397 client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BLASTER );
03398 }
03399 if (!wDisable || !(wDisable & (1 << WP_BOWCASTER)))
03400 {
03401 client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BOWCASTER );
03402 }
03403 client->ps.stats[STAT_WEAPONS] &= ~(1 << WP_SABER);
03404 client->ps.stats[STAT_WEAPONS] |= (1 << WP_MELEE);
03405 client->ps.ammo[AMMO_POWERCELL] = ammoData[AMMO_POWERCELL].max;
03406 client->ps.weapon = WP_BRYAR_PISTOL;
03407 }
03408 }
03409 else
03410 {
03411 trap_Cvar_Set( "g_jediVmerc", "0" );
03412 if (g_gametype.integer == GT_HOLOCRON)
03413 {
03414
03415 client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SABER );
03416 }
03417 else
03418 {
03419 if (client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE])
03420 {
03421 client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SABER );
03422 }
03423 else
03424 {
03425 client->ps.stats[STAT_WEAPONS] |= (1 << WP_MELEE);
03426 }
03427 }
03428
03429 if (g_gametype.integer != GT_SIEGE)
03430 {
03431 if (!wDisable || !(wDisable & (1 << WP_BRYAR_PISTOL)))
03432 {
03433 client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL );
03434 }
03435 else if (g_gametype.integer == GT_JEDIMASTER)
03436 {
03437 client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL );
03438 }
03439 }
03440
03441 if (g_gametype.integer == GT_JEDIMASTER)
03442 {
03443 client->ps.stats[STAT_WEAPONS] &= ~(1 << WP_SABER);
03444 client->ps.stats[STAT_WEAPONS] |= (1 << WP_MELEE);
03445 }
03446
03447 if (client->ps.stats[STAT_WEAPONS] & (1 << WP_SABER))
03448 {
03449 client->ps.weapon = WP_SABER;
03450 }
03451 else if (client->ps.stats[STAT_WEAPONS] & (1 << WP_BRYAR_PISTOL))
03452 {
03453 client->ps.weapon = WP_BRYAR_PISTOL;
03454 }
03455 else
03456 {
03457 client->ps.weapon = WP_MELEE;
03458 }
03459 }
03460
03461
03462
03463
03464
03465
03466 if (g_gametype.integer == GT_SIEGE && client->siegeClass != -1 &&
03467 client->sess.sessionTeam != TEAM_SPECTATOR)
03468 {
03469 int m = 0;
03470
03471 client->ps.stats[STAT_WEAPONS] = bgSiegeClasses[client->siegeClass].weapons;
03472
03473 if (client->ps.stats[STAT_WEAPONS] & (1 << WP_SABER))
03474 {
03475 client->ps.weapon = WP_SABER;
03476 }
03477 else if (client->ps.stats[STAT_WEAPONS] & (1 << WP_BRYAR_PISTOL))
03478 {
03479 client->ps.weapon = WP_BRYAR_PISTOL;
03480 }
03481 else
03482 {
03483 client->ps.weapon = WP_MELEE;
03484 }
03485 inSiegeWithClass = qtrue;
03486
03487 while (m < WP_NUM_WEAPONS)
03488 {
03489 if (client->ps.stats[STAT_WEAPONS] & (1 << m))
03490 {
03491 if (client->ps.weapon != WP_SABER)
03492 {
03493 if (m > client->ps.weapon)
03494 {
03495 client->ps.weapon = m;
03496 }
03497 }
03498
03499 if (m >= WP_BRYAR_PISTOL)
03500 {
03501 if ( g_gametype.integer == GT_SIEGE
03502 && m == WP_ROCKET_LAUNCHER )
03503 {
03504
03505 if ( client->siegeClass != -1 &&
03506 (bgSiegeClasses[client->siegeClass].classflags & (1<<CFL_SINGLE_ROCKET)) )
03507 {
03508 client->ps.ammo[weaponData[m].ammoIndex] = 1;
03509 }
03510 else
03511 {
03512 client->ps.ammo[weaponData[m].ammoIndex] = 10;
03513 }
03514 }
03515 else
03516 {
03517 if ( g_gametype.integer == GT_SIEGE
03518 && client->siegeClass != -1
03519 && (bgSiegeClasses[client->siegeClass].classflags & (1<<CFL_EXTRA_AMMO)) )
03520 {
03521 client->ps.ammo[weaponData[m].ammoIndex] = ammoData[weaponData[m].ammoIndex].max*2;
03522 client->ps.eFlags |= EF_DOUBLE_AMMO;
03523 }
03524 else
03525 {
03526 client->ps.ammo[weaponData[m].ammoIndex] = ammoData[weaponData[m].ammoIndex].max;
03527 }
03528 }
03529 }
03530 }
03531 m++;
03532 }
03533 }
03534
03535 if (g_gametype.integer == GT_SIEGE &&
03536 client->siegeClass != -1 &&
03537 client->sess.sessionTeam != TEAM_SPECTATOR)
03538 {
03539 client->ps.stats[STAT_HOLDABLE_ITEMS] = bgSiegeClasses[client->siegeClass].invenItems;
03540 client->ps.stats[STAT_HOLDABLE_ITEM] = 0;
03541 }
03542 else
03543 {
03544 client->ps.stats[STAT_HOLDABLE_ITEMS] = 0;
03545 client->ps.stats[STAT_HOLDABLE_ITEM] = 0;
03546 }
03547
03548 if (g_gametype.integer == GT_SIEGE &&
03549 client->siegeClass != -1 &&
03550 bgSiegeClasses[client->siegeClass].powerups &&
03551 client->sess.sessionTeam != TEAM_SPECTATOR)
03552 {
03553 i = 0;
03554 while (i < PW_NUM_POWERUPS)
03555 {
03556 if (bgSiegeClasses[client->siegeClass].powerups & (1 << i))
03557 {
03558 client->ps.powerups[i] = Q3_INFINITE;
03559 }
03560 i++;
03561 }
03562 }
03563
03564 if ( client->sess.sessionTeam == TEAM_SPECTATOR )
03565 {
03566 client->ps.stats[STAT_WEAPONS] = 0;
03567 client->ps.stats[STAT_HOLDABLE_ITEMS] = 0;
03568 client->ps.stats[STAT_HOLDABLE_ITEM] = 0;
03569 }
03570
03571
03572 if ( inSiegeWithClass == qfalse )
03573 {
03574 client->ps.ammo[AMMO_BLASTER] = 100;
03575 }
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588 client->ps.rocketLockIndex = ENTITYNUM_NONE;
03589 client->ps.rocketLockTime = 0;
03590
03591
03592
03593
03594
03595
03596
03597
03598
03599
03600 client->ps.genericEnemyIndex = -1;
03601
03602 client->ps.isJediMaster = qfalse;
03603
03604 if (client->ps.fallingToDeath)
03605 {
03606 client->ps.fallingToDeath = 0;
03607 client->noCorpse = qtrue;
03608 }
03609
03610
03611 WP_SpawnInitForcePowers( ent );
03612
03613
03614 if (g_gametype.integer == GT_SIEGE &&
03615 client->siegeClass != -1 &&
03616 bgSiegeClasses[client->siegeClass].starthealth)
03617 {
03618 ent->health = client->ps.stats[STAT_HEALTH] = bgSiegeClasses[client->siegeClass].starthealth;
03619 }
03620 else if ( g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL )
03621 {
03622 if ( g_gametype.integer == GT_POWERDUEL && client->sess.duelTeam == DUELTEAM_LONE )
03623 {
03624 if ( g_duel_fraglimit.integer )
03625 {
03626
03627 ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] =
03628 g_powerDuelStartHealth.integer - ((g_powerDuelStartHealth.integer - g_powerDuelEndHealth.integer) * (float)client->sess.wins / (float)g_duel_fraglimit.integer);
03629 }
03630 else
03631 {
03632 ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] = 150;
03633 }
03634 }
03635 else
03636 {
03637 ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] = 100;
03638 }
03639 }
03640 else if (client->ps.stats[STAT_MAX_HEALTH] <= 100)
03641 {
03642 ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] * 1.25;
03643 }
03644 else if (client->ps.stats[STAT_MAX_HEALTH] < 125)
03645 {
03646 ent->health = client->ps.stats[STAT_HEALTH] = 125;
03647 }
03648 else
03649 {
03650 ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH];
03651 }
03652
03653
03654 if (g_gametype.integer == GT_SIEGE &&
03655 client->siegeClass != -1
03656 )
03657 {
03658 client->ps.stats[STAT_ARMOR] = bgSiegeClasses[client->siegeClass].startarmor;
03659 }
03660 else if ( g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL )
03661 {
03662 client->ps.stats[STAT_ARMOR] = 0;
03663 }
03664 else
03665 {
03666 client->ps.stats[STAT_ARMOR] = client->ps.stats[STAT_MAX_HEALTH] * 0.25;
03667 }
03668
03669 G_SetOrigin( ent, spawn_origin );
03670 VectorCopy( spawn_origin, client->ps.origin );
03671
03672
03673 client->ps.pm_flags |= PMF_RESPAWNED;
03674
03675 trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
03676 SetClientViewAngle( ent, spawn_angles );
03677
03678 if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
03679
03680 } else {
03681 G_KillBox( ent );
03682 trap_LinkEntity (ent);
03683
03684
03685
03686
03687 if (client->ps.weapon <= WP_NONE)
03688 {
03689 client->ps.weapon = WP_BRYAR_PISTOL;
03690 }
03691
03692 client->ps.torsoTimer = client->ps.legsTimer = 0;
03693
03694 if (client->ps.weapon == WP_SABER)
03695 {
03696 G_SetAnim(ent, NULL, SETANIM_BOTH, BOTH_STAND1TO2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_HOLDLESS, 0);
03697 }
03698 else
03699 {
03700 G_SetAnim(ent, NULL, SETANIM_TORSO, TORSO_RAISEWEAP1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_HOLDLESS, 0);
03701 client->ps.legsAnim = WeaponReadyAnim[client->ps.weapon];
03702 }
03703 client->ps.weaponstate = WEAPON_RAISING;
03704 client->ps.weaponTime = client->ps.torsoTimer;
03705 }
03706
03707
03708 client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
03709 client->ps.pm_time = 100;
03710
03711 client->respawnTime = level.time;
03712 client->inactivityTime = level.time + g_inactivity.integer * 1000;
03713 client->latched_buttons = 0;
03714
03715 if ( level.intermissiontime ) {
03716 MoveClientToIntermission( ent );
03717 } else {
03718
03719 G_UseTargets( spawnPoint, ent );
03720
03721
03722
03723
03724
03725
03726
03727
03728
03729
03730
03731
03732 }
03733
03734
03735 if (g_gametype.integer == GT_SIEGE)
03736 {
03737 if (client->sess.sessionTeam == SIEGETEAM_TEAM1)
03738 {
03739 client->playerTeam = ent->s.teamowner = NPCTEAM_ENEMY;
03740 client->enemyTeam = NPCTEAM_PLAYER;
03741 }
03742 else
03743 {
03744 client->playerTeam = ent->s.teamowner = NPCTEAM_PLAYER;
03745 client->enemyTeam = NPCTEAM_ENEMY;
03746 }
03747 }
03748 else
03749 {
03750 client->playerTeam = ent->s.teamowner = NPCTEAM_PLAYER;
03751 client->enemyTeam = NPCTEAM_ENEMY;
03752 }
03753
03754
03755
03756
03757
03758
03759
03760
03761
03762
03763
03764
03765
03766
03767 client->ps.commandTime = level.time - 100;
03768 ent->client->pers.cmd.serverTime = level.time;
03769 ClientThink( ent-g_entities, NULL );
03770
03771
03772 if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
03773 BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
03774 VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
03775 trap_LinkEntity( ent );
03776 }
03777
03778 if (g_spawnInvulnerability.integer)
03779 {
03780 ent->client->ps.eFlags |= EF_INVULNERABLE;
03781 ent->client->invulnerableTimer = level.time + g_spawnInvulnerability.integer;
03782 }
03783
03784
03785 ClientEndFrame( ent );
03786
03787
03788 BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
03789
03790
03791 trap_ICARUS_FreeEnt( ent );
03792 trap_ICARUS_InitEnt( ent );
03793 }
03794
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807
03808 void ClientDisconnect( int clientNum ) {
03809 gentity_t *ent;
03810 gentity_t *tent;
03811 int i;
03812
03813
03814
03815 G_RemoveQueuedBotBegin( clientNum );
03816
03817 ent = g_entities + clientNum;
03818 if ( !ent->client ) {
03819 return;
03820 }
03821
03822 i = 0;
03823
03824 while (i < NUM_FORCE_POWERS)
03825 {
03826 if (ent->client->ps.fd.forcePowersActive & (1 << i))
03827 {
03828 WP_ForcePowerStop(ent, i);
03829 }
03830 i++;
03831 }
03832
03833 i = TRACK_CHANNEL_1;
03834
03835 while (i < NUM_TRACK_CHANNELS)
03836 {
03837 if (ent->client->ps.fd.killSoundEntIndex[i-50] && ent->client->ps.fd.killSoundEntIndex[i-50] < MAX_GENTITIES && ent->client->ps.fd.killSoundEntIndex[i-50] > 0)
03838 {
03839 G_MuteSound(ent->client->ps.fd.killSoundEntIndex[i-50], CHAN_VOICE);
03840 }
03841 i++;
03842 }
03843 i = 0;
03844
03845 if (ent->client->ps.m_iVehicleNum)
03846 {
03847 gentity_t *veh = &g_entities[ent->client->ps.m_iVehicleNum];
03848
03849 if (veh->inuse && veh->client && veh->m_pVehicle)
03850 {
03851 int pCon = ent->client->pers.connected;
03852
03853 ent->client->pers.connected = 0;
03854 veh->m_pVehicle->m_pVehicleInfo->Eject(veh->m_pVehicle, (bgEntity_t *)ent, qtrue);
03855 ent->client->pers.connected = pCon;
03856 }
03857 }
03858
03859
03860 for ( i = 0 ; i < level.maxclients ; i++ ) {
03861 if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR
03862 && level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW
03863 && level.clients[i].sess.spectatorClient == clientNum ) {
03864 StopFollowing( &g_entities[i] );
03865 }
03866 }
03867
03868
03869 if ( ent->client->pers.connected == CON_CONNECTED
03870 && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
03871 tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
03872 tent->s.clientNum = ent->s.clientNum;
03873
03874
03875
03876 TossClientItems( ent );
03877 }
03878
03879 G_LogPrintf( "ClientDisconnect: %i\n", clientNum );
03880
03881
03882 if ( (g_gametype.integer == GT_DUEL )
03883 && !level.intermissiontime
03884 && !level.warmupTime ) {
03885 if ( level.sortedClients[1] == clientNum ) {
03886 level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] = 0;
03887 level.clients[ level.sortedClients[0] ].sess.wins++;
03888 ClientUserinfoChanged( level.sortedClients[0] );
03889 }
03890 else if ( level.sortedClients[0] == clientNum ) {
03891 level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] = 0;
03892 level.clients[ level.sortedClients[1] ].sess.wins++;
03893 ClientUserinfoChanged( level.sortedClients[1] );
03894 }
03895 }
03896
03897 if (ent->ghoul2 && trap_G2_HaveWeGhoul2Models(ent->ghoul2))
03898 {
03899 trap_G2API_CleanGhoul2Models(&ent->ghoul2);
03900 }
03901 i = 0;
03902 while (i < MAX_SABERS)
03903 {
03904 if (ent->client->weaponGhoul2[i] && trap_G2_HaveWeGhoul2Models(ent->client->weaponGhoul2[i]))
03905 {
03906 trap_G2API_CleanGhoul2Models(&ent->client->weaponGhoul2[i]);
03907 }
03908 i++;
03909 }
03910
03911 trap_UnlinkEntity (ent);
03912 ent->s.modelindex = 0;
03913 ent->inuse = qfalse;
03914 ent->classname = "disconnected";
03915 ent->client->pers.connected = CON_DISCONNECTED;
03916 ent->client->ps.persistant[PERS_TEAM] = TEAM_FREE;
03917 ent->client->sess.sessionTeam = TEAM_FREE;
03918 ent->r.contents = 0;
03919
03920 trap_SetConfigstring( CS_PLAYERS + clientNum, "");
03921
03922 CalculateRanks();
03923
03924 if ( ent->r.svFlags & SVF_BOT ) {
03925 BotAIShutdownClient( clientNum, qfalse );
03926 }
03927
03928 G_ClearClientLog(clientNum);
03929 }
03930
03931