checkentities.c

Go to the documentation of this file.
00001 
00005 /*
00006 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00007 
00008 Copyright (C) 1997-2001 Id Software, Inc.
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019 See the GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 
00025 */
00026 
00027 #include "../map.h"
00028 #include "checkentities.h"
00029 #include "../../../shared/mathlib.h"
00030 #include "../../../shared/entitiesdef.h"
00031 #include "../common/shared.h"
00032 #include "../bsp.h"
00033 #include "checklib.h"
00034 
00035 #define MIN_TILE_SIZE 256 
00037 static int numToMoveToWorldspawn = 0;
00038 
00039 static void Check_MapSize (vec3_t mapSize);
00040 mapbrush_t **Check_ExtraBrushesForWorldspawn (int *numBrushes);
00041 
00042 
00048 static qboolean Check_IsInfoStart(const char *classname)
00049 {
00050     return !strncmp(classname, "info_", 5) && strstr(classname, "_start");
00051 }
00052 
00059 static qboolean Check_InfoStartAligned (const entityDef_t *ed, const entity_t *e)
00060 {
00061     static int size[6];
00062     const entityKeyDef_t *sizeKd = ED_GetKeyDefEntity(ed, "size", 1); /* 1 means find abstract version of key */
00063     if (ED_GetIntVector(sizeKd, size, (int)(sizeof(size) / sizeof(int))) == ED_ERROR)
00064         Sys_Error("%s", ED_GetLastError());
00065 
00066     return (((int)e->origin[0] - size[0]) % UNIT_SIZE == 0)
00067         && (((int)e->origin[1] - size[1]) % UNIT_SIZE == 0);
00068 }
00069 
00074 static qboolean Check_TargetExists(const epair_t *kvp)
00075 {
00076     const char *thisKey = kvp->key;
00077     const char *value = kvp->value;
00078     const char *otherKey = !strcmp("target", thisKey) ? "targetname" : "target";
00079     int i;
00080 
00081     for (i = 0; i < num_entities; i++) {
00082         const entity_t *e = &entities[i];
00083         const char *searchVal = ValueForKey(e, otherKey);
00084 
00085         if (searchVal && !strcmp(searchVal, value))
00086             return qtrue;
00087     }
00088 
00089     return qfalse;
00090 }
00091 
00092 static void Check_EntityWithBrushes(entity_t *e, const char *classname, int entnum)
00093 {
00094     if (!e->numbrushes) {
00095         Check_Printf(VERB_CHECK, qtrue, entnum, -1, "%s with no brushes given - will be deleted\n", classname);
00096         e->skip = qtrue;
00097         return;
00098     }
00099 
00100     if (e->numbrushes > 1 && !strcmp(classname, "func_breakable")) {
00101         Check_Printf(VERB_CHECK, qfalse, entnum, -1, "func_breakable with more than one brush given (might break pathfinding)\n");
00102     }
00103 
00104     if (e->numbrushes == 1 && !strcmp(classname, "func_group")) {
00105         Check_Printf(VERB_CHECK, qtrue, entnum, -1, "%s with one brush only - will be moved to worldspawn\n", classname);
00106         numToMoveToWorldspawn++;
00107         e->skip = qtrue;
00108     }
00109 }
00110 
00114 void CheckEntities (void)
00115 {
00116     int i;
00117 
00118     Check_InitEntityDefs();
00119 
00120     for (i = 0; i < num_entities; i++) {
00121         entity_t *e = &entities[i];
00122         const char *name = ValueForKey(e, "classname");
00123         const entityDef_t *ed = ED_GetEntityDef(name);
00124         const epair_t *kvp;
00125         const entityKeyDef_t *kd;
00126 
00127         if (!ed) { /* check that a definition exists */
00128             Check_Printf(VERB_CHECK, qfalse, i, -1, "Not defined in entities.ufo: %s\n", name);
00129             continue;
00130         }
00131 
00132         /* check alignment of info_.+_start */
00133         if (Check_IsInfoStart(name) && !Check_InfoStartAligned(ed, e))
00134             Check_Printf(VERB_CHECK, qfalse, i, -1, "Misaligned %s\n", name);
00135 
00136         if (!strncmp("func_", name, 5)) /* func_* entities should have brushes */
00137             Check_EntityWithBrushes(e, name, i);
00138 
00139         /* check all keys in the entity - make sure they are OK */
00140         for (kvp = e->epairs; kvp; kvp = kvp->next) {
00141             kd = ED_GetKeyDefEntity(ed, kvp->key, 0); /* zero means ignore abstract (radiant only) keys */
00142 
00143             if (!kd) { /* make sure it has a definition */
00144                 Check_Printf(VERB_CHECK, qfalse, i, -1, "Not defined in entities.ufo: %s in %s\n", kvp->key,name);
00145                 continue;
00146             }
00147 
00148             if (ED_CheckKey(kd, kvp->value) == ED_ERROR) { /* check values against type and range definitions in entities.ufo */
00149                 Check_Printf(VERB_CHECK, qfalse, i, -1, "%s\n", ED_GetLastError());
00150                 continue;
00151             }
00152 
00153             if (!strcmp("target", kvp->key) || !strcmp("targetname", kvp->key)) {
00154                 if (!Check_TargetExists(kvp)) {
00155                     Check_Printf(VERB_CHECK, qfalse, i, -1,
00156                         "%s with %s of %s: no corresponding entity with %s with matching value\n",
00157                         ed->classname, kvp->key, kvp->value, !strcmp("target", kvp->key) ? "targetname" : "target");
00158                 }
00159             }
00160         }
00161 
00162         /* check keys in the entity definition - make sure mandatory ones are present */
00163         for (kd = ed->keyDefs; kd->name; kd++) {
00164             if (kd->flags & ED_MANDATORY) {
00165                 const char *keyNameInEnt = ValueForKey(e, kd->name);
00166                 if (keyNameInEnt[0] == '\0') {
00167                     const char *defaultVal = kd->defaultVal;
00168                     const qboolean hasDefault = defaultVal ? qtrue : qfalse;
00169                     Check_Printf(VERB_CHECK, hasDefault, i, -1, "Mandatory key missing from entity: %s in %s", kd->name, name);
00170                     if (defaultVal) {
00171                         Check_Printf(VERB_CHECK, hasDefault, i, -1, ", supplying default: %s", defaultVal);
00172                         SetKeyValue(e, kd->name, defaultVal);
00173                     }
00174                     Check_Printf(VERB_CHECK, hasDefault, i, -1, "\n");
00175                 }
00176             }
00177         }
00178     }
00179 }
00180 
00181 
00185 void Check_Stats(void) {
00186     vec3_t worldSize;
00187     int i, j;
00188     int *entNums;
00189 
00190     Check_InitEntityDefs();
00191 
00192     entNums = (int *)Mem_Alloc(numEntityDefs * sizeof(int));
00193 
00194     Check_MapSize(worldSize);
00195     Verb_Printf(VERB_NORMAL, "        Number of brushes: %i\n",nummapbrushes);
00196     Verb_Printf(VERB_NORMAL, "         Number of planes: %i\n",nummapplanes);
00197     Verb_Printf(VERB_NORMAL, "    Number of brush sides: %i\n",nummapbrushsides);
00198     Verb_Printf(VERB_NORMAL, "         Map size (units): %.0f %.0f %.0f\n", worldSize[0], worldSize[1], worldSize[2]);
00199     Verb_Printf(VERB_NORMAL, "        Map size (fields): %.0f %.0f %.0f\n", worldSize[0] / UNIT_SIZE, worldSize[1] / UNIT_SIZE, worldSize[2] / UNIT_HEIGHT);
00200     Verb_Printf(VERB_NORMAL, "         Map size (tiles): %.0f %.0f %.0f\n", worldSize[0] / (MIN_TILE_SIZE), worldSize[1] / (MIN_TILE_SIZE), worldSize[2] / UNIT_HEIGHT);
00201     Verb_Printf(VERB_NORMAL, "       Number of entities: %i\n", num_entities);
00202 
00203     /* count number of each type of entity */
00204     for (i = 0; i < num_entities; i++) {
00205         const char *name = ValueForKey(&entities[i], "classname");
00206 
00207         for (j = 0; j < numEntityDefs; j++)
00208             if (!strncmp(name, entityDefs[j].classname, strlen(entityDefs[j].classname))) {
00209                 entNums[j]++;
00210                 break;
00211             }
00212         if (j == numEntityDefs) {
00213             Com_Printf("Check_Stats: entity '%s' not recognised\n", name);
00214         }
00215 
00216     }
00217 
00218     /* print number of each type of entity */
00219     for (j = 0; j < numEntityDefs; j++)
00220         if (entNums[j])
00221             Com_Printf("%27s: %i\n", entityDefs[j].classname, entNums[j]);
00222 
00223     Mem_Free(entNums);
00224 }
00225 
00226 
00231 static void Check_MapSize (vec3_t mapSize)
00232 {
00233     int i, bi, vi;
00234     vec3_t mins, maxs;
00235 
00236     VectorSet(mins, 0, 0, 0);
00237     VectorSet(maxs, 0, 0, 0);
00238 
00239     for (i = 0; i < nummapbrushes; i++) {
00240         const mapbrush_t *brush = &mapbrushes[i];
00241 
00242         for (bi = 0; bi < brush->numsides; bi++) {
00243             const winding_t *winding = brush->original_sides[bi].winding;
00244 
00245             for (vi = 0; vi < winding->numpoints; vi++)
00246                 AddPointToBounds(winding->p[vi], mins, maxs);
00247         }
00248     }
00249 
00250     VectorSubtract(maxs, mins, mapSize);
00251 }
00252 
00259 mapbrush_t **Check_ExtraBrushesForWorldspawn (int *numBrushes)
00260 {
00261     int i, j;
00262     mapbrush_t **brushesToMove;
00263 
00264     *numBrushes = numToMoveToWorldspawn;
00265 
00266     if (!numToMoveToWorldspawn)
00267         return NULL;
00268 
00269     brushesToMove = (mapbrush_t **)Mem_Alloc(numToMoveToWorldspawn * sizeof(*brushesToMove));
00270     if (!brushesToMove)
00271         Sys_Error("Check_ExtraBrushesForWorldspawn: out of memory");
00272 
00273     /* 0 is the world - start at 1 */
00274     for (i = 1, j = 0; i < num_entities; i++) {
00275         const entity_t *e = &entities[i];
00276         const char *name = ValueForKey(e, "classname");
00277 
00278         if (e->numbrushes == 1 && !strcmp(name, "func_group")) {
00279             assert(j < numToMoveToWorldspawn);
00280             brushesToMove[j++] = &mapbrushes[e->firstbrush];
00281         }
00282     }
00283 
00284     return brushesToMove;
00285 }

Generated by  doxygen 1.6.2