00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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);
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) {
00128 Check_Printf(VERB_CHECK, qfalse, i, -1, "Not defined in entities.ufo: %s\n", name);
00129 continue;
00130 }
00131
00132
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))
00137 Check_EntityWithBrushes(e, name, i);
00138
00139
00140 for (kvp = e->epairs; kvp; kvp = kvp->next) {
00141 kd = ED_GetKeyDefEntity(ed, kvp->key, 0);
00142
00143 if (!kd) {
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) {
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
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
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
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
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 }