00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "g_local.h"
00030 #include <time.h>
00031
00036 void G_FreeEdict (edict_t *ent)
00037 {
00038 G_EventDestroyEdict(ent);
00039
00040
00041 gi.UnlinkEdict(ent);
00042
00043 memset(ent, 0, sizeof(*ent));
00044 ent->classname = "freed";
00045 ent->inuse = qfalse;
00046 }
00047
00054 edict_t *G_GetEdictFromPos (const pos3_t pos, const entity_type_t type)
00055 {
00056 edict_t *floor = NULL;
00057
00058 while ((floor = G_EdictsGetNextInUse(floor))) {
00059 if (type > ET_NULL && floor->type != type)
00060 continue;
00061 if (!VectorCompare(pos, floor->pos))
00062 continue;
00063
00064 return floor;
00065 }
00066
00067 return NULL;
00068 }
00069
00077 qboolean G_UseEdict (edict_t *ent, edict_t* activator)
00078 {
00079 if (!ent)
00080 return qfalse;
00081
00082
00083 if (!ent->use)
00084 return qfalse;
00085
00086 if (!ent->use(ent, activator))
00087 return qfalse;
00088
00089
00090 if (!(ent->flags & FL_GROUPSLAVE)) {
00091 edict_t* chain = ent->groupChain;
00092 while (chain) {
00093 G_UseEdict(chain, activator);
00094 chain = chain->groupChain;
00095 }
00096 }
00097
00098 return qtrue;
00099 }
00100
00106 static const objDef_t* G_GetObjectForFiredef (const fireDef_t* fd)
00107 {
00108 int i, j, k;
00109
00110
00111 for (i = 0; i < gi.csi->numODs; i++) {
00112 const objDef_t *od = &gi.csi->ods[i];
00113
00114 for (j = 0; j < od->numWeapons; j++) {
00115
00116 for (k = 0; k < od->numFiredefs[j]; k++) {
00117 const fireDef_t *csiFD = &od->fd[j][k];
00118 if (csiFD == fd)
00119 return od;
00120 }
00121 }
00122 }
00123
00124 return NULL;
00125 }
00126
00133 const char* G_GetWeaponNameForFiredef (const fireDef_t *fd)
00134 {
00135 const objDef_t* obj = G_GetObjectForFiredef(fd);
00136 if (!obj)
00137 return "unknown";
00138 else
00139 return obj->id;
00140 }
00141
00147 player_t* G_GetPlayerForTeam (int team)
00148 {
00149 int i;
00150 player_t *p;
00151
00152
00153 for (i = 0, p = game.players; i < game.sv_maxplayersperteam * 2; i++, p++)
00154 if (p->inuse && p->pers.team == team)
00155
00156 return p;
00157
00158 return NULL;
00159 }
00160
00170 void G_TakeDamage (edict_t *ent, int damage)
00171 {
00172 if (G_IsBreakable(ent) || G_IsActor(ent))
00173 ent->HP = max(ent->HP - damage, 0);
00174 }
00175
00181 static void G_TraceDraw (const vec3_t start, const vec3_t end)
00182 {
00183 if (g_drawtraces->integer)
00184 G_EventParticleSpawn(PM_ALL, "fadeTracerDebug", TRACING_ALL_VISIBLE_LEVELS, start, end, vec3_origin);
00185 }
00186
00193 qboolean G_TestLineWithEnts (const vec3_t start, const vec3_t end)
00194 {
00195 const char *entList[MAX_EDICTS];
00196
00197 G_GenerateEntList(entList);
00198 G_TraceDraw(start, end);
00199
00200 return gi.TestLineWithEnt(start, end, TL_FLAG_NONE, entList);
00201 }
00202
00209 qboolean G_TestLine (const vec3_t start, const vec3_t end)
00210 {
00211 G_TraceDraw(start, end);
00212 return gi.TestLine(start, end, TL_FLAG_NONE);
00213 }
00214
00221 trace_t G_Trace (const vec3_t start, const vec3_t end, const edict_t * passent, int contentmask)
00222 {
00223 G_TraceDraw(start, end);
00224 return gi.Trace(start, NULL, NULL, end, passent, contentmask);
00225 }
00226
00230 const char* G_GetPlayerName (int pnum)
00231 {
00232 if (pnum >= game.sv_maxplayersperteam)
00233 return "";
00234 else
00235 return game.players[pnum].pers.netname;
00236 }
00237
00242 void G_PrintStats (const char *buffer)
00243 {
00244 gi.DPrintf("[STATS] %s\n", buffer);
00245 if (logstatsfile) {
00246 struct tm *t;
00247 char tbuf[32];
00248 time_t aclock;
00249
00250 time(&aclock);
00251 t = localtime(&aclock);
00252
00253 Com_sprintf(tbuf, sizeof(tbuf), "%4i/%02i/%02i %02i:%02i:%02i", t->tm_year + 1900,
00254 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
00255
00256 fprintf(logstatsfile, "[STATS] %s - %s\n", tbuf, buffer);
00257 }
00258 }
00259
00268 void G_PrintActorStats (const edict_t *victim, const edict_t *attacker, const fireDef_t *fd)
00269 {
00270 char buffer[512];
00271
00272 if (attacker != NULL) {
00273 if (victim->pnum != attacker->pnum) {
00274 const char *victimName = G_GetPlayerName(victim->pnum);
00275 const char *attackerName = G_GetPlayerName(attacker->pnum);
00276 if (victimName[0] == '\0') {
00277 switch (victim->team) {
00278 case TEAM_CIVILIAN:
00279 victimName = "civilian";
00280 break;
00281 case TEAM_ALIEN:
00282 victimName = "alien";
00283 break;
00284 default:
00285 victimName = "unknown";
00286 break;
00287 }
00288 }
00289 if (attackerName[0] == '\0') {
00290 switch (attacker->team) {
00291 case TEAM_CIVILIAN:
00292 attackerName = "civilian";
00293 break;
00294 case TEAM_ALIEN:
00295 attackerName = "alien";
00296 break;
00297 default:
00298 attackerName = "unknown";
00299 break;
00300 }
00301 }
00302 if (victim->team != attacker->team) {
00303 Com_sprintf(buffer, sizeof(buffer), "%s (%s) %s %s (%s) with %s of %s",
00304 attackerName, attacker->chr.name,
00305 (victim->HP == 0 ? "kills" : "stuns"),
00306 victimName, victim->chr.name, fd->name, G_GetWeaponNameForFiredef(fd));
00307 } else {
00308 Com_sprintf(buffer, sizeof(buffer), "%s (%s) %s %s (%s) (teamkill) with %s of %s",
00309 attackerName, attacker->chr.name,
00310 (victim->HP == 0 ? "kills" : "stuns"),
00311 victimName, victim->chr.name, fd->name, G_GetWeaponNameForFiredef(fd));
00312 }
00313 } else {
00314 const char *attackerName = G_GetPlayerName(attacker->pnum);
00315 Com_sprintf(buffer, sizeof(buffer), "%s %s %s (own team) with %s of %s",
00316 attackerName, (victim->HP == 0 ? "kills" : "stuns"),
00317 victim->chr.name, fd->name, G_GetWeaponNameForFiredef(fd));
00318 }
00319 } else {
00320 const char *victimName = G_GetPlayerName(victim->pnum);
00321 Com_sprintf(buffer, sizeof(buffer), "%s (%s) was %s",
00322 victimName, victim->chr.name, (victim->HP == 0 ? "killed" : "stunned"));
00323 }
00324 G_PrintStats(buffer);
00325 }
00326
00344 edict_t *G_Find (edict_t * from, int fieldofs, char *match)
00345 {
00346 edict_t *ent = from;
00347
00348 while ((ent = G_EdictsGetNextInUse(ent))) {
00349 const char *s = *(const char **) ((byte *) ent + fieldofs);
00350 if (!s)
00351 continue;
00352 if (!Q_strcasecmp(s, match))
00353 return ent;
00354 }
00355
00356 return NULL;
00357 }
00358
00365 edict_t *G_FindTargetEntity (const char *target)
00366 {
00367 edict_t *ent = NULL;
00368
00369 while ((ent = G_EdictsGetNext(ent))) {
00370 const char *n = ent->targetname;
00371 if (n && !strcmp(n, target))
00372 return ent;
00373 }
00374
00375 return NULL;
00376 }
00377
00391 edict_t *G_FindRadius (edict_t * from, const vec3_t org, float rad, entity_type_t type)
00392 {
00393 edict_t *ent = from;
00394
00395 while ((ent = G_EdictsGetNextInUse(ent))) {
00396 int j;
00397 vec3_t eorg;
00398 for (j = 0; j < 3; j++)
00399 eorg[j] = org[j] - (ent->origin[j] + (ent->mins[j] + ent->maxs[j]) * 0.5);
00400 if (VectorLength(eorg) > rad)
00401 continue;
00402 if (type != ET_NULL && ent->type != type)
00403 continue;
00404 return ent;
00405 }
00406
00407 return NULL;
00408 }
00409
00410 #define IS_BMODEL(ent) ((ent)->model && (ent)->model[0] == '*' && (ent)->solid == SOLID_BSP)
00411
00418 void G_GenerateEntList (const char *entList[MAX_EDICTS])
00419 {
00420 int i = 0;
00421 edict_t *ent = NULL;
00422
00423
00424 while ((ent = G_EdictsGetNextInUse(ent)))
00425 if (IS_BMODEL(ent))
00426 entList[i++] = ent->model;
00427 entList[i] = NULL;
00428 }
00429
00434 void G_RecalcRouting (const edict_t * ent)
00435 {
00436 const char *entList[MAX_EDICTS];
00437
00438 G_GenerateEntList(entList);
00439
00440 gi.GridRecalcRouting(gi.routingMap, ent->model, entList);
00441 }
00442
00446 void G_CompleteRecalcRouting (void)
00447 {
00448 edict_t *ent = NULL;
00449
00450 while ((ent = G_EdictsGetNextInUse(ent)))
00451 if (IS_BMODEL(ent))
00452 G_RecalcRouting(ent);
00453 }
00454
00461 static void G_ResetTriggers (edict_t *ent, edict_t **touched, int num)
00462 {
00463 edict_t *trigger = NULL;
00464 while ((trigger = G_EdictsGetNextInUse(trigger))) {
00465 if (trigger->solid == SOLID_TRIGGER) {
00466 if (trigger->reset != NULL) {
00467 int i;
00468 for (i = 0; i < num; i++) {
00469 if (touched[i] == ent)
00470 break;
00471 }
00472 if (i == num)
00473 trigger->reset(trigger, ent);
00474 }
00475 }
00476 }
00477 }
00478
00483 int G_TouchTriggers (edict_t *ent)
00484 {
00485 int i, num, usedNum = 0;
00486 edict_t *touch[MAX_EDICTS];
00487
00488 if (!G_IsLivingActor(ent))
00489 return 0;
00490
00491 num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS);
00492
00493 G_ResetTriggers(ent, touch, num);
00494
00495
00496
00497 for (i = 0; i < num; i++) {
00498 edict_t *hit = touch[i];
00499 if (hit->solid != SOLID_TRIGGER)
00500 continue;
00501 if (!hit->touch)
00502 continue;
00503 if (hit->touch(hit, ent))
00504 usedNum++;
00505 }
00506 return usedNum;
00507 }
00508
00513 void G_TouchSolids (edict_t *ent)
00514 {
00515 int i, num;
00516 edict_t *touch[MAX_EDICTS];
00517
00518 num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS);
00519
00520
00521
00522 for (i = 0; i < num; i++) {
00523 edict_t* hit = touch[i];
00524 if (!hit->inuse)
00525 continue;
00526 if (hit->solid == SOLID_TRIGGER)
00527 continue;
00528 if (ent->touch)
00529 ent->touch(ent, hit);
00530 if (!ent->inuse)
00531 break;
00532 }
00533 }
00534
00541 void G_TouchEdicts (edict_t *ent, float extend)
00542 {
00543 int i, num;
00544 edict_t *touch[MAX_EDICTS];
00545 vec3_t absmin, absmax;
00546 const char *entName = (ent->model) ? ent->model : ent->chr.name;
00547
00548 for (i = 0; i < 3; i++) {
00549 absmin[i] = ent->absmin[i] - extend;
00550 absmax[i] = ent->absmax[i] + extend;
00551 }
00552
00553 num = gi.TouchEdicts(absmin, absmax, touch, MAX_EDICTS, ent);
00554 Com_DPrintf(DEBUG_GAME, "G_TouchEdicts: Entities touching %s: %i (%f extent).\n", entName, num, extend);
00555
00556
00557
00558 for (i = 0; i < num; i++) {
00559 edict_t* hit = touch[i];
00560 if (!hit->inuse)
00561 continue;
00562 if (ent->touch)
00563 ent->touch(ent, hit);
00564 }
00565 }