00001
00002
00003
00004
00005 #include "g_local.h"
00006 #include "bg_saga.h"
00007 #include "q_shared.h"
00008
00009 typedef struct {
00010 char oldShader[MAX_QPATH];
00011 char newShader[MAX_QPATH];
00012 float timeOffset;
00013 } shaderRemap_t;
00014
00015 #define MAX_SHADER_REMAPS 128
00016
00017 int remapCount = 0;
00018 shaderRemap_t remappedShaders[MAX_SHADER_REMAPS];
00019
00020 void AddRemap(const char *oldShader, const char *newShader, float timeOffset) {
00021 int i;
00022
00023 for (i = 0; i < remapCount; i++) {
00024 if (Q_stricmp(oldShader, remappedShaders[i].oldShader) == 0) {
00025
00026 strcpy(remappedShaders[i].newShader,newShader);
00027 remappedShaders[i].timeOffset = timeOffset;
00028 return;
00029 }
00030 }
00031 if (remapCount < MAX_SHADER_REMAPS) {
00032 strcpy(remappedShaders[remapCount].newShader,newShader);
00033 strcpy(remappedShaders[remapCount].oldShader,oldShader);
00034 remappedShaders[remapCount].timeOffset = timeOffset;
00035 remapCount++;
00036 }
00037 }
00038
00039 const char *BuildShaderStateConfig(void) {
00040 static char buff[MAX_STRING_CHARS*4];
00041 char out[(MAX_QPATH * 2) + 5];
00042 int i;
00043
00044 memset(buff, 0, MAX_STRING_CHARS);
00045 for (i = 0; i < remapCount; i++) {
00046 Com_sprintf(out, (MAX_QPATH * 2) + 5, "%s=%s:%5.2f@", remappedShaders[i].oldShader, remappedShaders[i].newShader, remappedShaders[i].timeOffset);
00047 Q_strcat( buff, sizeof( buff ), out);
00048 }
00049 return buff;
00050 }
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 static int G_FindConfigstringIndex( const char *name, int start, int max, qboolean create ) {
00067 int i;
00068 char s[MAX_STRING_CHARS];
00069
00070 if ( !name || !name[0] ) {
00071 return 0;
00072 }
00073
00074 for ( i=1 ; i<max ; i++ ) {
00075 trap_GetConfigstring( start + i, s, sizeof( s ) );
00076 if ( !s[0] ) {
00077 break;
00078 }
00079 if ( !strcmp( s, name ) ) {
00080 return i;
00081 }
00082 }
00083
00084 if ( !create ) {
00085 return 0;
00086 }
00087
00088 if ( i == max ) {
00089 G_Error( "G_FindConfigstringIndex: overflow" );
00090 }
00091
00092 trap_SetConfigstring( start + i, name );
00093
00094 return i;
00095 }
00096
00097
00098
00099
00100
00101 int G_BoneIndex( const char *name ) {
00102 return G_FindConfigstringIndex (name, CS_G2BONES, MAX_G2BONES, qtrue);
00103 }
00104
00105
00106
00107
00108 int G_ModelIndex( const char *name ) {
00109 #ifdef _DEBUG_MODEL_PATH_ON_SERVER
00110
00111
00112 fileHandle_t fh;
00113
00114 trap_FS_FOpenFile(name, &fh, FS_READ);
00115 if (!fh)
00116 {
00117 trap_FS_FOpenFile(va("models/%s", name), &fh, FS_READ);
00118 if (!fh)
00119 {
00120 Com_Printf("ERROR: Server tried to modelindex %s but it doesn't exist.\n", name);
00121 }
00122 }
00123
00124 if (fh)
00125 {
00126 trap_FS_FCloseFile(fh);
00127 }
00128 #endif
00129 return G_FindConfigstringIndex (name, CS_MODELS, MAX_MODELS, qtrue);
00130 }
00131
00132 int G_IconIndex( const char* name )
00133 {
00134 assert(name && name[0]);
00135 return G_FindConfigstringIndex (name, CS_ICONS, MAX_ICONS, qtrue);
00136 }
00137
00138 int G_SoundIndex( const char *name ) {
00139 assert(name && name[0]);
00140 return G_FindConfigstringIndex (name, CS_SOUNDS, MAX_SOUNDS, qtrue);
00141 }
00142
00143 int G_SoundSetIndex(const char *name)
00144 {
00145 return G_FindConfigstringIndex (name, CS_AMBIENT_SET, MAX_AMBIENT_SETS, qtrue);
00146 }
00147
00148 int G_EffectIndex( const char *name )
00149 {
00150 return G_FindConfigstringIndex (name, CS_EFFECTS, MAX_FX, qtrue);
00151 }
00152
00153 int G_BSPIndex( const char *name )
00154 {
00155 return G_FindConfigstringIndex (name, CS_BSP_MODELS, MAX_SUB_BSP, qtrue);
00156 }
00157
00158
00159
00160
00161
00162 qboolean G_PlayerHasCustomSkeleton(gentity_t *ent)
00163 {
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 return qfalse;
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197 void G_TeamCommand( team_t team, char *cmd ) {
00198 int i;
00199
00200 for ( i = 0 ; i < level.maxclients ; i++ ) {
00201 if ( level.clients[i].pers.connected == CON_CONNECTED ) {
00202 if ( level.clients[i].sess.sessionTeam == team ) {
00203 trap_SendServerCommand( i, va("%s", cmd ));
00204 }
00205 }
00206 }
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match)
00223 {
00224 char *s;
00225
00226 if (!from)
00227 from = g_entities;
00228 else
00229 from++;
00230
00231 for ( ; from < &g_entities[level.num_entities] ; from++)
00232 {
00233 if (!from->inuse)
00234 continue;
00235 s = *(char **) ((byte *)from + fieldofs);
00236 if (!s)
00237 continue;
00238 if (!Q_stricmp (s, match))
00239 return from;
00240 }
00241
00242 return NULL;
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252 int G_RadiusList ( vec3_t origin, float radius, gentity_t *ignore, qboolean takeDamage, gentity_t *ent_list[MAX_GENTITIES])
00253 {
00254 float dist;
00255 gentity_t *ent;
00256 int entityList[MAX_GENTITIES];
00257 int numListedEntities;
00258 vec3_t mins, maxs;
00259 vec3_t v;
00260 int i, e;
00261 int ent_count = 0;
00262
00263 if ( radius < 1 )
00264 {
00265 radius = 1;
00266 }
00267
00268 for ( i = 0 ; i < 3 ; i++ )
00269 {
00270 mins[i] = origin[i] - radius;
00271 maxs[i] = origin[i] + radius;
00272 }
00273
00274 numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
00275
00276 for ( e = 0 ; e < numListedEntities ; e++ )
00277 {
00278 ent = &g_entities[entityList[ e ]];
00279
00280 if ((ent == ignore) || !(ent->inuse) || ent->takedamage != takeDamage)
00281 continue;
00282
00283
00284 for ( i = 0 ; i < 3 ; i++ )
00285 {
00286 if ( origin[i] < ent->r.absmin[i] )
00287 {
00288 v[i] = ent->r.absmin[i] - origin[i];
00289 } else if ( origin[i] > ent->r.absmax[i] )
00290 {
00291 v[i] = origin[i] - ent->r.absmax[i];
00292 } else
00293 {
00294 v[i] = 0;
00295 }
00296 }
00297
00298 dist = VectorLength( v );
00299 if ( dist >= radius )
00300 {
00301 continue;
00302 }
00303
00304
00305 ent_list[ent_count] = ent;
00306 ent_count++;
00307
00308 }
00309
00310 return(ent_count);
00311 }
00312
00313
00314
00315 void G_Throw( gentity_t *targ, vec3_t newDir, float push )
00316
00317 {
00318 vec3_t kvel;
00319 float mass;
00320
00321 if ( targ->physicsBounce > 0 )
00322 {
00323 mass = targ->physicsBounce;
00324 }
00325 else
00326 {
00327 mass = 200;
00328 }
00329
00330 if ( g_gravity.value > 0 )
00331 {
00332 VectorScale( newDir, g_knockback.value * (float)push / mass * 0.8, kvel );
00333 kvel[2] = newDir[2] * g_knockback.value * (float)push / mass * 1.5;
00334 }
00335 else
00336 {
00337 VectorScale( newDir, g_knockback.value * (float)push / mass, kvel );
00338 }
00339
00340 if ( targ->client )
00341 {
00342 VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );
00343 }
00344 else if ( targ->s.pos.trType != TR_STATIONARY && targ->s.pos.trType != TR_LINEAR_STOP && targ->s.pos.trType != TR_NONLINEAR_STOP )
00345 {
00346 VectorAdd( targ->s.pos.trDelta, kvel, targ->s.pos.trDelta );
00347 VectorCopy( targ->r.currentOrigin, targ->s.pos.trBase );
00348 targ->s.pos.trTime = level.time;
00349 }
00350
00351
00352
00353 if ( targ->client && !targ->client->ps.pm_time )
00354 {
00355 int t;
00356
00357 t = push * 2;
00358
00359 if ( t < 50 )
00360 {
00361 t = 50;
00362 }
00363 if ( t > 200 )
00364 {
00365 t = 200;
00366 }
00367 targ->client->ps.pm_time = t;
00368 targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
00369 }
00370 }
00371
00372
00373
00374
00375
00376 void G_FreeFakeClient(gclient_t **cl)
00377 {
00378
00379
00380
00381 }
00382
00383
00384 #define MAX_VEHICLES_AT_A_TIME 128
00385 static Vehicle_t g_vehiclePool[MAX_VEHICLES_AT_A_TIME];
00386 static qboolean g_vehiclePoolOccupied[MAX_VEHICLES_AT_A_TIME];
00387 static qboolean g_vehiclePoolInit = qfalse;
00388 void G_AllocateVehicleObject(Vehicle_t **pVeh)
00389 {
00390 int i = 0;
00391
00392 if (!g_vehiclePoolInit)
00393 {
00394 g_vehiclePoolInit = qtrue;
00395 memset(g_vehiclePoolOccupied, 0, sizeof(g_vehiclePoolOccupied));
00396 }
00397
00398 while (i < MAX_VEHICLES_AT_A_TIME)
00399 {
00400 if (!g_vehiclePoolOccupied[i])
00401 {
00402 g_vehiclePoolOccupied[i] = qtrue;
00403 memset(&g_vehiclePool[i], 0, sizeof(Vehicle_t));
00404 *pVeh = &g_vehiclePool[i];
00405 return;
00406 }
00407 i++;
00408 }
00409 Com_Error(ERR_DROP, "Ran out of vehicle pool slots.");
00410 }
00411
00412
00413 void G_FreeVehicleObject(Vehicle_t *pVeh)
00414 {
00415 int i = 0;
00416 while (i < MAX_VEHICLES_AT_A_TIME)
00417 {
00418 if (g_vehiclePoolOccupied[i] &&
00419 &g_vehiclePool[i] == pVeh)
00420 {
00421 g_vehiclePoolOccupied[i] = qfalse;
00422 break;
00423 }
00424 i++;
00425 }
00426 }
00427
00428 gclient_t *gClPtrs[MAX_GENTITIES];
00429
00430 void G_CreateFakeClient(int entNum, gclient_t **cl)
00431 {
00432
00433 if (!gClPtrs[entNum])
00434 {
00435 gClPtrs[entNum] = (gclient_t *) BG_Alloc(sizeof(gclient_t));
00436 }
00437 *cl = gClPtrs[entNum];
00438 }
00439
00440 #ifdef _XBOX
00441 void G_ClPtrClear(void)
00442 {
00443 for(int i=0; i<MAX_GENTITIES; i++) {
00444 gClPtrs[i] = NULL;
00445 }
00446 }
00447 #endif
00448
00449
00450 void G_CleanAllFakeClients(void)
00451 {
00452 int i = MAX_CLIENTS;
00453 gentity_t *ent;
00454
00455 while (i < MAX_GENTITIES)
00456 {
00457 ent = &g_entities[i];
00458
00459 if (ent->inuse && ent->s.eType == ET_NPC && ent->client)
00460 {
00461 G_FreeFakeClient(&ent->client);
00462 }
00463 i++;
00464 }
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 #include "../namespace_begin.h"
00476 void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags, int blendTime);
00477 #include "../namespace_end.h"
00478
00479 void G_SetAnim(gentity_t *ent, usercmd_t *ucmd, int setAnimParts, int anim, int setAnimFlags, int blendTime)
00480 {
00481 #if 0 //old hackish way
00482 pmove_t pmv;
00483
00484 assert(ent && ent->inuse && ent->client);
00485
00486 memset (&pmv, 0, sizeof(pmv));
00487 pmv.ps = &ent->client->ps;
00488 pmv.animations = bgAllAnims[ent->localAnimIndex].anims;
00489 if (!ucmd)
00490 {
00491 pmv.cmd = ent->client->pers.cmd;
00492 }
00493 else
00494 {
00495 pmv.cmd = *ucmd;
00496 }
00497 pmv.trace = trap_Trace;
00498 pmv.pointcontents = trap_PointContents;
00499 pmv.gametype = g_gametype.integer;
00500
00501
00502 pm = &pmv;
00503 PM_SetAnim(setAnimParts, anim, setAnimFlags, blendTime);
00504 #else //new clean and shining way!
00505 assert(ent->client);
00506 BG_SetAnim(&ent->client->ps, bgAllAnims[ent->localAnimIndex].anims, setAnimParts,
00507 anim, setAnimFlags, blendTime);
00508 #endif
00509 }
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 #define MAXCHOICES 32
00520
00521 gentity_t *G_PickTarget (char *targetname)
00522 {
00523 gentity_t *ent = NULL;
00524 int num_choices = 0;
00525 gentity_t *choice[MAXCHOICES];
00526
00527 if (!targetname)
00528 {
00529 G_Printf("G_PickTarget called with NULL targetname\n");
00530 return NULL;
00531 }
00532
00533 while(1)
00534 {
00535 ent = G_Find (ent, FOFS(targetname), targetname);
00536 if (!ent)
00537 break;
00538 choice[num_choices++] = ent;
00539 if (num_choices == MAXCHOICES)
00540 break;
00541 }
00542
00543 if (!num_choices)
00544 {
00545 G_Printf("G_PickTarget: target %s not found\n", targetname);
00546 return NULL;
00547 }
00548
00549 return choice[rand() % num_choices];
00550 }
00551
00552 void GlobalUse(gentity_t *self, gentity_t *other, gentity_t *activator)
00553 {
00554 if (!self || (self->flags & FL_INACTIVE))
00555 {
00556 return;
00557 }
00558
00559 if (!self->use)
00560 {
00561 return;
00562 }
00563 self->use(self, other, activator);
00564 }
00565
00566 void G_UseTargets2( gentity_t *ent, gentity_t *activator, const char *string ) {
00567 gentity_t *t;
00568
00569 if ( !ent ) {
00570 return;
00571 }
00572
00573 if (ent->targetShaderName && ent->targetShaderNewName) {
00574 float f = level.time * 0.001;
00575 AddRemap(ent->targetShaderName, ent->targetShaderNewName, f);
00576 trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());
00577 }
00578
00579 if ( !string || !string[0] ) {
00580 return;
00581 }
00582
00583 t = NULL;
00584 while ( (t = G_Find (t, FOFS(targetname), string)) != NULL ) {
00585 if ( t == ent ) {
00586 G_Printf ("WARNING: Entity used itself.\n");
00587 } else {
00588 if ( t->use ) {
00589 GlobalUse(t, ent, activator);
00590 }
00591 }
00592 if ( !ent->inuse ) {
00593 G_Printf("entity was removed while using targets\n");
00594 return;
00595 }
00596 }
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 void G_UseTargets( gentity_t *ent, gentity_t *activator )
00610 {
00611 if (!ent)
00612 {
00613 return;
00614 }
00615 G_UseTargets2(ent, activator, ent->target);
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627 float *tv( float x, float y, float z ) {
00628 static int index;
00629 static vec3_t vecs[8];
00630 float *v;
00631
00632
00633
00634 v = vecs[index];
00635 index = (index + 1)&7;
00636
00637 v[0] = x;
00638 v[1] = y;
00639 v[2] = z;
00640
00641 return v;
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653 char *vtos( const vec3_t v ) {
00654 static int index;
00655 static char str[8][32];
00656 char *s;
00657
00658
00659 s = str[index];
00660 index = (index + 1)&7;
00661
00662 Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
00663
00664 return s;
00665 }
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 void G_SetMovedir( vec3_t angles, vec3_t movedir ) {
00679 static vec3_t VEC_UP = {0, -1, 0};
00680 static vec3_t MOVEDIR_UP = {0, 0, 1};
00681 static vec3_t VEC_DOWN = {0, -2, 0};
00682 static vec3_t MOVEDIR_DOWN = {0, 0, -1};
00683
00684 if ( VectorCompare (angles, VEC_UP) ) {
00685 VectorCopy (MOVEDIR_UP, movedir);
00686 } else if ( VectorCompare (angles, VEC_DOWN) ) {
00687 VectorCopy (MOVEDIR_DOWN, movedir);
00688 } else {
00689 AngleVectors (angles, movedir, NULL, NULL);
00690 }
00691 VectorClear( angles );
00692 }
00693
00694 void G_InitGentity( gentity_t *e ) {
00695 e->inuse = qtrue;
00696 e->classname = "noclass";
00697 e->s.number = e - g_entities;
00698 e->r.ownerNum = ENTITYNUM_NONE;
00699 e->s.modelGhoul2 = 0;
00700
00701 trap_ICARUS_FreeEnt( e );
00702 }
00703
00704
00705 static void G_SpewEntList(void)
00706 {
00707 int i = 0;
00708 int numNPC = 0;
00709 int numProjectile = 0;
00710 int numTempEnt = 0;
00711 int numTempEntST = 0;
00712 char className[MAX_STRING_CHARS];
00713 gentity_t *ent;
00714 char *str;
00715 #ifdef FINAL_BUILD
00716 #define VM_OR_FINAL_BUILD
00717 #elif defined Q3_VM
00718 #define VM_OR_FINAL_BUILD
00719 #endif
00720
00721 #ifndef VM_OR_FINAL_BUILD
00722 fileHandle_t fh;
00723 trap_FS_FOpenFile("entspew.txt", &fh, FS_WRITE);
00724 #endif
00725
00726 while (i < ENTITYNUM_MAX_NORMAL)
00727 {
00728 ent = &g_entities[i];
00729 if (ent->inuse)
00730 {
00731 if (ent->s.eType == ET_NPC)
00732 {
00733 numNPC++;
00734 }
00735 else if (ent->s.eType == ET_MISSILE)
00736 {
00737 numProjectile++;
00738 }
00739 else if (ent->freeAfterEvent)
00740 {
00741 numTempEnt++;
00742 if (ent->s.eFlags & EF_SOUNDTRACKER)
00743 {
00744 numTempEntST++;
00745 }
00746
00747 str = va("TEMPENT %4i: EV %i\n", ent->s.number, ent->s.eType-ET_EVENTS);
00748 Com_Printf(str);
00749 #ifndef VM_OR_FINAL_BUILD
00750 if (fh)
00751 {
00752 trap_FS_Write(str, strlen(str), fh);
00753 }
00754 #endif
00755 }
00756
00757 if (ent->classname && ent->classname[0])
00758 {
00759 strcpy(className, ent->classname);
00760 }
00761 else
00762 {
00763 strcpy(className, "Unknown");
00764 }
00765 str = va("ENT %4i: Classname %s\n", ent->s.number, className);
00766 Com_Printf(str);
00767 #ifndef VM_OR_FINAL_BUILD
00768 if (fh)
00769 {
00770 trap_FS_Write(str, strlen(str), fh);
00771 }
00772 #endif
00773 }
00774
00775 i++;
00776 }
00777
00778 str = va("TempEnt count: %i\nTempEnt ST: %i\nNPC count: %i\nProjectile count: %i\n", numTempEnt, numTempEntST, numNPC, numProjectile);
00779 Com_Printf(str);
00780 #ifndef VM_OR_FINAL_BUILD
00781 if (fh)
00782 {
00783 trap_FS_Write(str, strlen(str), fh);
00784 trap_FS_FCloseFile(fh);
00785 }
00786 #endif
00787 }
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804 gentity_t *G_Spawn( void ) {
00805 int i, force;
00806 gentity_t *e;
00807
00808 e = NULL;
00809 i = 0;
00810 for ( force = 0 ; force < 2 ; force++ ) {
00811
00812
00813 e = &g_entities[MAX_CLIENTS];
00814 for ( i = MAX_CLIENTS ; i<level.num_entities ; i++, e++) {
00815 if ( e->inuse ) {
00816 continue;
00817 }
00818
00819
00820
00821 if ( !force && e->freetime > level.startTime + 2000 && level.time - e->freetime < 1000 )
00822 {
00823 continue;
00824 }
00825
00826
00827 G_InitGentity( e );
00828 return e;
00829 }
00830 if ( i != MAX_GENTITIES ) {
00831 break;
00832 }
00833 }
00834 if ( i == ENTITYNUM_MAX_NORMAL ) {
00835
00836
00837
00838
00839
00840 G_SpewEntList();
00841 G_Error( "G_Spawn: no free entities" );
00842 }
00843
00844
00845 level.num_entities++;
00846
00847
00848 trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
00849 &level.clients[0].ps, sizeof( level.clients[0] ) );
00850
00851 G_InitGentity( e );
00852 return e;
00853 }
00854
00855
00856
00857
00858
00859
00860 qboolean G_EntitiesFree( void ) {
00861 int i;
00862 gentity_t *e;
00863
00864 e = &g_entities[MAX_CLIENTS];
00865 for ( i = MAX_CLIENTS; i < level.num_entities; i++, e++) {
00866 if ( e->inuse ) {
00867 continue;
00868 }
00869
00870 return qtrue;
00871 }
00872 return qfalse;
00873 }
00874
00875 #define MAX_G2_KILL_QUEUE 256
00876
00877 int gG2KillIndex[MAX_G2_KILL_QUEUE];
00878 int gG2KillNum = 0;
00879
00880 void G_SendG2KillQueue(void)
00881 {
00882 char g2KillString[1024];
00883 int i = 0;
00884
00885 if (!gG2KillNum)
00886 {
00887 return;
00888 }
00889
00890 Com_sprintf(g2KillString, 1024, "kg2");
00891
00892 while (i < gG2KillNum && i < 64)
00893 {
00894 Q_strcat(g2KillString, 1024, va(" %i", gG2KillIndex[i]));
00895 i++;
00896 }
00897
00898 trap_SendServerCommand(-1, g2KillString);
00899
00900
00901 gG2KillNum -= i;
00902 if (gG2KillNum < 0)
00903 {
00904 assert(0);
00905 gG2KillNum = 0;
00906 }
00907 }
00908
00909 void G_KillG2Queue(int entNum)
00910 {
00911 if (gG2KillNum >= MAX_G2_KILL_QUEUE)
00912 {
00913 #ifdef _DEBUG
00914 Com_Printf("WARNING: Exceeded the MAX_G2_KILL_QUEUE count for this frame!\n");
00915 #endif
00916
00917 trap_SendServerCommand(-1, va("kg2 %i", entNum));
00918 return;
00919 }
00920
00921 gG2KillIndex[gG2KillNum] = entNum;
00922 gG2KillNum++;
00923 }
00924
00925
00926
00927
00928
00929
00930
00931
00932 void G_FreeEntity( gentity_t *ed ) {
00933
00934
00935 if (ed->isSaberEntity)
00936 {
00937 #ifdef _DEBUG
00938 Com_Printf("Tried to remove JM saber!\n");
00939 #endif
00940 return;
00941 }
00942
00943 trap_UnlinkEntity (ed);
00944
00945 trap_ICARUS_FreeEnt( ed );
00946
00947 if ( ed->neverFree ) {
00948 return;
00949 }
00950
00951
00952
00953
00954
00955 if (ed->s.modelGhoul2)
00956 {
00957
00958
00959
00960
00961
00962
00963 G_KillG2Queue(ed->s.number);
00964 }
00965
00966
00967 if (ed->ghoul2)
00968 {
00969 trap_G2API_CleanGhoul2Models(&(ed->ghoul2));
00970 }
00971
00972 if (ed->s.eType == ET_NPC && ed->m_pVehicle)
00973 {
00974 G_FreeVehicleObject(ed->m_pVehicle);
00975 }
00976
00977 if (ed->s.eType == ET_NPC && ed->client)
00978 {
00979 int saberEntNum = -1;
00980 int i = 0;
00981 if (ed->client->ps.saberEntityNum)
00982 {
00983 saberEntNum = ed->client->ps.saberEntityNum;
00984 }
00985 else if (ed->client->saberStoredIndex)
00986 {
00987 saberEntNum = ed->client->saberStoredIndex;
00988 }
00989
00990 if (saberEntNum > 0 && g_entities[saberEntNum].inuse)
00991 {
00992 g_entities[saberEntNum].neverFree = qfalse;
00993 G_FreeEntity(&g_entities[saberEntNum]);
00994 }
00995
00996 while (i < MAX_SABERS)
00997 {
00998 if (ed->client->weaponGhoul2[i] && trap_G2_HaveWeGhoul2Models(ed->client->weaponGhoul2[i]))
00999 {
01000 trap_G2API_CleanGhoul2Models(&ed->client->weaponGhoul2[i]);
01001 }
01002 i++;
01003 }
01004
01005 G_FreeFakeClient(&ed->client);
01006 }
01007
01008 if (ed->s.eFlags & EF_SOUNDTRACKER)
01009 {
01010 int i = 0;
01011 gentity_t *ent;
01012
01013 while (i < MAX_CLIENTS)
01014 {
01015 ent = &g_entities[i];
01016
01017 if (ent && ent->inuse && ent->client)
01018 {
01019 int ch = TRACK_CHANNEL_NONE-50;
01020
01021 while (ch < NUM_TRACK_CHANNELS-50)
01022 {
01023 if (ent->client->ps.fd.killSoundEntIndex[ch] == ed->s.number)
01024 {
01025 ent->client->ps.fd.killSoundEntIndex[ch] = 0;
01026 }
01027
01028 ch++;
01029 }
01030 }
01031
01032 i++;
01033 }
01034
01035
01036 trap_SendServerCommand(-1, va("kls %i %i", ed->s.trickedentindex, ed->s.number));
01037 }
01038
01039 memset (ed, 0, sizeof(*ed));
01040 ed->classname = "freed";
01041 ed->freetime = level.time;
01042 ed->inuse = qfalse;
01043 }
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054 gentity_t *G_TempEntity( vec3_t origin, int event ) {
01055 gentity_t *e;
01056 vec3_t snapped;
01057
01058 e = G_Spawn();
01059 e->s.eType = ET_EVENTS + event;
01060
01061 e->classname = "tempEntity";
01062 e->eventTime = level.time;
01063 e->freeAfterEvent = qtrue;
01064
01065 VectorCopy( origin, snapped );
01066 SnapVector( snapped );
01067 G_SetOrigin( e, snapped );
01068
01069
01070
01071
01072
01073
01074 trap_LinkEntity( e );
01075
01076 return e;
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087 gentity_t *G_SoundTempEntity( vec3_t origin, int event, int channel ) {
01088 gentity_t *e;
01089 vec3_t snapped;
01090
01091 e = G_Spawn();
01092
01093 e->s.eType = ET_EVENTS + event;
01094 e->inuse = qtrue;
01095
01096 e->classname = "tempEntity";
01097 e->eventTime = level.time;
01098 e->freeAfterEvent = qtrue;
01099
01100 VectorCopy( origin, snapped );
01101 SnapVector( snapped );
01102 G_SetOrigin( e, snapped );
01103
01104
01105 trap_LinkEntity( e );
01106
01107 return e;
01108 }
01109
01110
01111
01112 void G_ScaleNetHealth(gentity_t *self)
01113 {
01114 int maxHealth = self->maxHealth;
01115
01116 if (maxHealth < 1000)
01117 {
01118 self->s.maxhealth = maxHealth;
01119 self->s.health = self->health;
01120
01121 if (self->s.health < 0)
01122 {
01123 self->s.health = 0;
01124 }
01125 return;
01126 }
01127
01128
01129 self->s.maxhealth = (maxHealth/100);
01130 self->s.health = (self->health/100);
01131
01132 if (self->s.health < 0)
01133 {
01134 self->s.health = 0;
01135 }
01136
01137 if (self->health > 0 &&
01138 self->s.health <= 0)
01139 {
01140 self->s.health = 1;
01141 }
01142 }
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162 void G_KillBox (gentity_t *ent) {
01163 int i, num;
01164 int touch[MAX_GENTITIES];
01165 gentity_t *hit;
01166 vec3_t mins, maxs;
01167
01168 VectorAdd( ent->client->ps.origin, ent->r.mins, mins );
01169 VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );
01170 num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
01171
01172 for (i=0 ; i<num ; i++) {
01173 hit = &g_entities[touch[i]];
01174 if ( !hit->client ) {
01175 continue;
01176 }
01177
01178 if (hit->s.number == ent->s.number)
01179 {
01180 continue;
01181 }
01182
01183 if (ent->r.ownerNum == hit->s.number)
01184 {
01185 continue;
01186 }
01187
01188
01189 G_Damage ( hit, ent, ent, NULL, NULL,
01190 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
01191 }
01192
01193 }
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206 void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm ) {
01207 if ( !ent->client ) {
01208 return;
01209 }
01210 BG_AddPredictableEventToPlayerstate( event, eventParm, &ent->client->ps );
01211 }
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221 void G_AddEvent( gentity_t *ent, int event, int eventParm ) {
01222 int bits;
01223
01224 if ( !event ) {
01225 G_Printf( "G_AddEvent: zero event added for entity %i\n", ent->s.number );
01226 return;
01227 }
01228
01229
01230 if ( ent->client ) {
01231 bits = ent->client->ps.externalEvent & EV_EVENT_BITS;
01232 bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;
01233 ent->client->ps.externalEvent = event | bits;
01234 ent->client->ps.externalEventParm = eventParm;
01235 ent->client->ps.externalEventTime = level.time;
01236 } else {
01237 bits = ent->s.event & EV_EVENT_BITS;
01238 bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;
01239 ent->s.event = event | bits;
01240 ent->s.eventParm = eventParm;
01241 }
01242 ent->eventTime = level.time;
01243 }
01244
01245
01246
01247
01248
01249
01250 gentity_t *G_PlayEffect(int fxID, vec3_t org, vec3_t ang)
01251 {
01252 gentity_t *te;
01253
01254 te = G_TempEntity( org, EV_PLAY_EFFECT );
01255 VectorCopy(ang, te->s.angles);
01256 VectorCopy(org, te->s.origin);
01257 te->s.eventParm = fxID;
01258
01259 return te;
01260 }
01261
01262
01263
01264
01265
01266
01267 gentity_t *G_PlayEffectID(const int fxID, vec3_t org, vec3_t ang)
01268 {
01269 gentity_t *te;
01270
01271 te = G_TempEntity( org, EV_PLAY_EFFECT_ID );
01272 VectorCopy(ang, te->s.angles);
01273 VectorCopy(org, te->s.origin);
01274 te->s.eventParm = fxID;
01275
01276 if (!te->s.angles[0] &&
01277 !te->s.angles[1] &&
01278 !te->s.angles[2])
01279 {
01280 te->s.angles[1] = 1;
01281 }
01282
01283 return te;
01284 }
01285
01286
01287
01288
01289
01290
01291 gentity_t *G_ScreenShake(vec3_t org, gentity_t *target, float intensity, int duration, qboolean global)
01292 {
01293 gentity_t *te;
01294
01295 te = G_TempEntity( org, EV_SCREENSHAKE );
01296 VectorCopy(org, te->s.origin);
01297 te->s.angles[0] = intensity;
01298 te->s.time = duration;
01299
01300 if (target)
01301 {
01302 te->s.modelindex = target->s.number+1;
01303 }
01304 else
01305 {
01306 te->s.modelindex = 0;
01307 }
01308
01309 if (global)
01310 {
01311 te->r.svFlags |= SVF_BROADCAST;
01312 }
01313
01314 return te;
01315 }
01316
01317
01318
01319
01320
01321
01322 void G_MuteSound( int entnum, int channel )
01323 {
01324 gentity_t *te, *e;
01325
01326 te = G_TempEntity( vec3_origin, EV_MUTE_SOUND );
01327 te->r.svFlags = SVF_BROADCAST;
01328 te->s.trickedentindex2 = entnum;
01329 te->s.trickedentindex = channel;
01330
01331 e = &g_entities[entnum];
01332
01333 if (e && (e->s.eFlags & EF_SOUNDTRACKER))
01334 {
01335 G_FreeEntity(e);
01336 e->s.eFlags = 0;
01337 }
01338 }
01339
01340
01341
01342
01343
01344
01345 void G_Sound( gentity_t *ent, int channel, int soundIndex ) {
01346 gentity_t *te;
01347
01348 assert(soundIndex);
01349
01350 te = G_SoundTempEntity( ent->r.currentOrigin, EV_GENERAL_SOUND, channel );
01351 te->s.eventParm = soundIndex;
01352 te->s.saberEntityNum = channel;
01353
01354 if (ent && ent->client && channel > TRACK_CHANNEL_NONE)
01355 {
01356 if (g_entities[ent->client->ps.fd.killSoundEntIndex[channel-50]].inuse &&
01357 ent->client->ps.fd.killSoundEntIndex[channel-50] > MAX_CLIENTS)
01358 {
01359 G_MuteSound(ent->client->ps.fd.killSoundEntIndex[channel-50], CHAN_VOICE);
01360 if (ent->client->ps.fd.killSoundEntIndex[channel-50] > MAX_CLIENTS && g_entities[ent->client->ps.fd.killSoundEntIndex[channel-50]].inuse)
01361 {
01362 G_FreeEntity(&g_entities[ent->client->ps.fd.killSoundEntIndex[channel-50]]);
01363 }
01364 ent->client->ps.fd.killSoundEntIndex[channel-50] = 0;
01365 }
01366
01367 ent->client->ps.fd.killSoundEntIndex[channel-50] = te->s.number;
01368 te->s.trickedentindex = ent->s.number;
01369 te->s.eFlags = EF_SOUNDTRACKER;
01370
01371 }
01372 }
01373
01374
01375
01376
01377
01378
01379 void G_SoundAtLoc( vec3_t loc, int channel, int soundIndex ) {
01380 gentity_t *te;
01381
01382 te = G_TempEntity( loc, EV_GENERAL_SOUND );
01383 te->s.eventParm = soundIndex;
01384 te->s.saberEntityNum = channel;
01385 }
01386
01387
01388
01389
01390
01391
01392 void G_EntitySound( gentity_t *ent, int channel, int soundIndex ) {
01393 gentity_t *te;
01394
01395 te = G_TempEntity( ent->r.currentOrigin, EV_ENTITY_SOUND );
01396 te->s.eventParm = soundIndex;
01397 te->s.clientNum = ent->s.number;
01398 te->s.trickedentindex = channel;
01399 }
01400
01401
01402 void G_SoundOnEnt( gentity_t *ent, int channel, const char *soundPath )
01403 {
01404 gentity_t *te;
01405
01406 te = G_TempEntity( ent->r.currentOrigin, EV_ENTITY_SOUND );
01407 te->s.eventParm = G_SoundIndex((char *)soundPath);
01408 te->s.clientNum = ent->s.number;
01409 te->s.trickedentindex = channel;
01410
01411 }
01412
01413 #ifdef _XBOX
01414
01415 void G_EntityPosition( int i, vec3_t ret )
01416 {
01417 if ( i >= 0 && i < MAX_GENTITIES && g_entities[i].inuse)
01418 {
01419 #if 0 // VVFIXME - Do we really care about doing this? It's slow and unnecessary
01420 gentity_t *ent = g_entities + i;
01421
01422 if (ent->bmodel)
01423 {
01424 vec3_t mins, maxs;
01425 clipHandle_t h = CM_InlineModel( ent->s.modelindex );
01426 CM_ModelBounds( cmg, h, mins, maxs );
01427 ret[0] = (mins[0] + maxs[0]) / 2 + ent->currentOrigin[0];
01428 ret[1] = (mins[1] + maxs[1]) / 2 + ent->currentOrigin[1];
01429 ret[2] = (mins[2] + maxs[2]) / 2 + ent->currentOrigin[2];
01430 }
01431 else
01432 #endif
01433 {
01434 VectorCopy(g_entities[i].r.currentOrigin, ret);
01435 }
01436 }
01437 else
01438 {
01439 ret[0] = ret[1] = ret[2] = 0;
01440 }
01441 }
01442 #endif
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453 qboolean ValidUseTarget( gentity_t *ent )
01454 {
01455 if ( !ent->use )
01456 {
01457 return qfalse;
01458 }
01459
01460 if ( ent->flags & FL_INACTIVE )
01461 {
01462 return qfalse;
01463 }
01464
01465