g_utils.c

Go to the documentation of this file.
00001 
00006 /*
00007 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 Original file from Quake 2 v3.21: quake2-2.31/game/g_utils.c
00010 Copyright (C) 1997-2001 Id Software, Inc.
00011 
00012 This program is free software; you can redistribute it and/or
00013 modify it under the terms of the GNU General Public License
00014 as published by the Free Software Foundation; either version 2
00015 of the License, or (at your option) any later version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021 See the GNU General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; if not, write to the Free Software
00025 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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     /* unlink from world */
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     /* nothing found at this pos */
00067     return NULL;
00068 }
00069 
00077 qboolean G_UseEdict (edict_t *ent, edict_t* activator)
00078 {
00079     if (!ent)
00080         return qfalse;
00081 
00082     /* no use function assigned */
00083     if (!ent->use)
00084         return qfalse;
00085 
00086     if (!ent->use(ent, activator))
00087         return qfalse;
00088 
00089     /* only the master edict is calling the opening for the other group parts */
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     /* For each object ... */
00111     for (i = 0; i < gi.csi->numODs; i++) {
00112         const objDef_t *od = &gi.csi->ods[i];
00113         /* For each weapon-entry in the object ... */
00114         for (j = 0; j < od->numWeapons; j++) {
00115             /* For each fire-definition in the weapon entry  ... */
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     /* search corresponding player (even ai players) */
00153     for (i = 0, p = game.players; i < game.sv_maxplayersperteam * 2; i++, p++)
00154         if (p->inuse && p->pers.team == team)
00155             /* found player */
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     /* generate entity list */
00197     G_GenerateEntList(entList);
00198     G_TraceDraw(start, end);
00199     /* test for visibility */
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') { /* empty string */
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') { /* empty string */
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     /* generate entity list */
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     /* generate entity list */
00438     G_GenerateEntList(entList);
00439     /* recalculate routing */
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     /* be careful, it is possible to have an entity in this
00496      * list removed before we get to it (killtriggered) */
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     /* be careful, it is possible to have an entity in this
00521      * list removed before we get to it (killtriggered) */
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     /* be careful, it is possible to have an entity in this
00557      * list removed before we get to it (killtriggered) */
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 }

Generated by  doxygen 1.6.2