scripts.c

Go to the documentation of this file.
00001 
00007 /*
00008 * This program is free software; you can redistribute it and/or modify
00009 * it under the terms of the GNU General Public License as published by
00010 * the Free Software Foundation; either version 2 of the License, or
00011 * (at your option) any later version.
00012 *
00013 * This program is distributed in the hope that it will be useful,
00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 * GNU General Public License for more details.
00017 *
00018 * You should have received a copy of the GNU General Public License
00019 * along with this program; if not, write to the Free Software
00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 
00024 #include "scripts.h"
00025 #include "../shared/parse.h"
00026 #include "../game/inventory.h"
00027 
00028 #define CONSTNAMEINT_HASH_SIZE  32
00029 
00030 #define MAX_CONSTNAMEINT_NAME   32
00031 
00035 typedef struct com_constNameInt_s {
00036     char name[MAX_CONSTNAMEINT_NAME];   
00037     char *fullname;         
00038     int value;              
00039     struct com_constNameInt_s *hash_next;   
00040     struct com_constNameInt_s *next;    
00041 } com_constNameInt_t;
00042 
00044 static com_constNameInt_t *com_constNameInt;
00046 static com_constNameInt_t *com_constNameInt_hash[CONSTNAMEINT_HASH_SIZE];
00047 
00053 static const char *Com_ConstIntGetVariable (const char *name)
00054 {
00055     const char *space = strstr(name, "::");
00056     if (space)
00057         return space + 2;
00058     return name;
00059 }
00060 
00070 qboolean Com_GetConstInt (const char *name, int *value)
00071 {
00072     com_constNameInt_t *a;
00073     unsigned int hash;
00074     const char *variable;
00075 
00076     variable = Com_ConstIntGetVariable(name);
00077 
00078     /* if the alias already exists */
00079     hash = Com_HashKey(variable, CONSTNAMEINT_HASH_SIZE);
00080     for (a = com_constNameInt_hash[hash]; a; a = a->hash_next) {
00081         if (!strcmp(variable, a->name)) {
00082             if (!a->fullname || variable == name || !strcmp(a->fullname, name)) {
00083                 *value = a->value;
00084                 return qtrue;
00085             }
00086         }
00087     }
00088 
00089     return qfalse;
00090 }
00091 
00103 qboolean Com_GetConstIntFromNamespace (const char *space, const char *variable, int *value)
00104 {
00105     if (!variable || variable[0] == '\0')
00106         return qfalse;
00107 
00108     if (!space || space[0] == '\0')
00109         return Com_GetConstInt(variable, value);
00110 
00111     return Com_GetConstInt(va("%s::%s", space, variable), value);
00112 }
00113 
00122 const char* Com_GetConstVariable (const char *space, int value)
00123 {
00124     com_constNameInt_t *a;
00125     const size_t namespaceLength = strlen(space);
00126 
00127     a = com_constNameInt;
00128     while (a) {
00129         if (a->value == value && a->fullname) {
00130             if (!strncmp(a->fullname, space, namespaceLength))
00131                 return a->name;
00132         }
00133         a = a->next;
00134     }
00135 
00136     return NULL;
00137 }
00138 
00148 qboolean Com_UnregisterConstVariable (const char *name)
00149 {
00150     com_constNameInt_t *a;
00151     com_constNameInt_t *prev = NULL;
00152 
00153     assert(strstr(name, "::") != NULL);
00154 
00155     a = com_constNameInt;
00156     while (a) {
00157         if (a->fullname) {
00158             if (!strcmp(a->fullname, name)) {
00159                 const char *variable = Com_ConstIntGetVariable(name);
00160                 const unsigned int hash = Com_HashKey(variable, CONSTNAMEINT_HASH_SIZE);
00161                 com_constNameInt_t *b;
00162 
00163                 if (prev)
00164                     prev->next = a->next;
00165                 else
00166                     com_constNameInt = a->next;
00167 
00168                 prev = NULL;
00169 
00170                 for (b = com_constNameInt_hash[hash]; b; prev = b, b = b->hash_next) {
00171                     if (b->fullname) {
00172                         if (!strcmp(name, b->fullname)) {
00173                             if (prev)
00174                                 prev->hash_next = b->hash_next;
00175                             else
00176                                 com_constNameInt_hash[hash] = com_constNameInt_hash[hash]->hash_next;
00177                             break;
00178                         }
00179                     }
00180                 }
00181                 if (a->fullname)
00182                     Mem_Free(a->fullname);
00183                 Mem_Free(a);
00184                 return qtrue;
00185             }
00186         }
00187         prev = a;
00188         a = a->next;
00189     }
00190     return qfalse;
00191 }
00192 
00204 void Com_RegisterConstInt (const char *name, int value)
00205 {
00206     com_constNameInt_t *a;
00207     unsigned int hash;
00208     const char *variable;
00209 
00210     variable = Com_ConstIntGetVariable(name);
00211 
00212     /* if the alias already exists, reuse it */
00213     hash = Com_HashKey(variable, CONSTNAMEINT_HASH_SIZE);
00214     for (a = com_constNameInt_hash[hash]; a; a = a->hash_next) {
00215         if (a->fullname) {
00216             if (!strcmp(a->fullname, name))
00217                 break;
00218         } else if (!strncmp(variable, a->name, sizeof(a->name))) {
00219             break;
00220         }
00221     }
00222 
00223     if (a) {
00224         Com_Printf("Com_RegisterConstInt: Const string already defined. '%s = %d' is not set.", name, value);
00225         return;
00226     }
00227 
00228     a = Mem_PoolAlloc(sizeof(*a), com_aliasSysPool, 0);
00229     Q_strncpyz(a->name, variable, sizeof(a->name));
00230     if (strcmp(variable, name))
00231         a->fullname = Mem_StrDup(name);
00232     a->next = com_constNameInt;
00233     /* com_constNameInt_hash should be null on the first run */
00234     a->hash_next = com_constNameInt_hash[hash];
00235     com_constNameInt_hash[hash] = a;
00236     com_constNameInt = a;
00237     a->value = value;
00238 }
00239 
00246 qboolean Com_UnregisterConstList (const constListEntry_t constList[])
00247 {
00248     int i;
00249     qboolean state = qtrue;
00250 
00251     for (i = 0; constList[i].name != NULL; i++)
00252         state &= Com_UnregisterConstVariable(constList[i].name);
00253 
00254     return state;
00255 }
00256 
00263 void Com_RegisterConstList (const constListEntry_t constList[])
00264 {
00265     int i;
00266 
00267     for (i = 0; constList[i].name != NULL; i++)
00268         Com_RegisterConstInt(constList[i].name, constList[i].value);
00269 }
00270 
00275 const char *Com_EParse (const char **text, const char *errhead, const char *errinfo)
00276 {
00277     const char *token;
00278 
00279     token = Com_Parse(text);
00280     if (!*text) {
00281         if (errinfo)
00282             Com_Printf("%s \"%s\")\n", errhead, errinfo);
00283         else
00284             Com_Printf("%s\n", errhead);
00285 
00286         return NULL;
00287     }
00288 
00289     return token;
00290 }
00291 
00292 static qboolean versionParsed;
00293 
00294 static void Com_ParseVersion (const char *version)
00295 {
00296     if (!versionParsed) {
00297         if (strcmp(version, UFO_VERSION))
00298             Sys_Error("You are mixing versions of the binary ("UFO_VERSION") and the script (%s) files.", version);
00299     } else {
00300         Sys_Error("More than one version string found in the script files.");
00301     }
00302 
00303     versionParsed = qtrue;
00304 }
00305 
00310 const char *const vt_names[] = {
00311     "",
00312     "bool",
00313     "char",
00314     "int",
00315     "int2",
00316     "float", /* 5 */
00317     "pos",
00318     "vector",
00319     "color",
00320     "rgba",
00321     "string", /* 10 */
00322     "translation_string",
00323     "longstring",
00324     "align",
00325     "blend",
00326     "style", /* 15 */
00327     "fade",
00328     "shapes",
00329     "shapeb",
00330     "dmgtype",
00331     "dmgweight", /* 20 */
00332     "date",
00333     "relabs",
00334     "client_hunk",
00335     "client_hunk_string",
00336     "team",
00337     "race",
00338     "ufo",
00339     "ufocrashed",
00340     "aircrafttype"
00341 };
00342 CASSERT(lengthof(vt_names) == V_NUM_TYPES);
00343 
00344 const char *const align_names[] = {
00345     "ul", "uc", "ur", "cl", "cc", "cr", "ll", "lc", "lr", "ul_rsl", "uc_rsl", "ur_rsl", "cl_rsl", "cc_rsl", "cr_rsl", "ll_rsl", "lc_rsl", "lr_rsl"
00346 };
00347 CASSERT(lengthof(align_names) == ALIGN_LAST);
00348 
00349 const char *const blend_names[] = {
00350     "replace", "one", "blend", "add", "filter", "invfilter"
00351 };
00352 CASSERT(lengthof(blend_names) == BLEND_LAST);
00353 
00354 const char *const style_names[] = {
00355     "facing", "rotated", "beam", "line", "axis", "circle"
00356 };
00357 CASSERT(lengthof(style_names) == STYLE_LAST);
00358 
00359 const char *const fade_names[] = {
00360     "none", "in", "out", "sin", "saw"
00361 };
00362 CASSERT(lengthof(fade_names) == FADE_LAST);
00363 
00365 static const size_t vt_sizes[] = {
00366     0,  /* V_NULL */
00367     sizeof(qboolean),   /* V_BOOL */
00368     sizeof(char),   /* V_CHAR */
00369     sizeof(int),    /* V_INT */
00370     2 * sizeof(int),    /* V_INT2 */
00371     sizeof(float),  /* V_FLOAT */
00372     sizeof(vec2_t), /* V_POS */
00373     sizeof(vec3_t), /* V_VECTOR */
00374     sizeof(vec4_t), /* V_COLOR */
00375     sizeof(vec4_t), /* V_RGBA */
00376     0,  /* V_STRING */
00377     0,  /* V_TRANSLATION_STRING */
00378     0,  /* V_LONGSTRING */
00379     sizeof(align_t),    /* V_ALIGN */
00380     sizeof(blend_t),    /* V_BLEND */
00381     sizeof(style_t),    /* V_STYLE */
00382     sizeof(fade_t), /* V_FADE */
00383     sizeof(int),    /* V_SHAPE_SMALL */
00384     0,  /* V_SHAPE_BIG */
00385     sizeof(byte),   /* V_DMGTYPE */
00386     sizeof(byte),   /* V_DMGWEIGHT */
00387     0,  /* V_DATE */
00388     sizeof(float),  /* V_RELABS */
00389     0,  /* V_CLIENT_HUNK */
00390     0,  /* V_CLIENT_HUNK_STRING */
00391     sizeof(int),        /* V_TEAM */
00392     sizeof(racetypes_t),        /* V_RACE */
00393     sizeof(ufoType_t),  /* V_UFO */
00394     sizeof(ufoType_t),  /* V_UFOCRASHED */
00395     sizeof(humanAircraftType_t)     /* V_AIRCRAFTTYPE */
00396 };
00397 CASSERT(lengthof(vt_sizes) == V_NUM_TYPES);
00398 
00400 static const size_t vt_aligns[] = {
00401     0,  /* V_NULL */
00402     sizeof(qboolean),   /* V_BOOL */
00403     sizeof(char),   /* V_CHAR */
00404     sizeof(int),    /* V_INT */
00405     sizeof(int),    /* V_INT2 */
00406     sizeof(float),  /* V_FLOAT */
00407     sizeof(vec_t),  /* V_POS */
00408     sizeof(vec_t),  /* V_VECTOR */
00409     sizeof(vec_t),  /* V_COLOR */
00410     sizeof(vec_t),  /* V_RGBA */
00411     sizeof(char),   /* V_STRING */
00412     sizeof(char),   /* V_TRANSLATION_STRING */
00413     sizeof(char),   /* V_LONGSTRING */
00414     sizeof(align_t),/* V_ALIGN */
00415     sizeof(blend_t),/* V_BLEND */
00416     sizeof(style_t),/* V_STYLE */
00417     sizeof(fade_t), /* V_FADE */
00418     sizeof(int),    /* V_SHAPE_SMALL */
00419     sizeof(uint32_t),   /* V_SHAPE_BIG */
00420     sizeof(byte),   /* V_DMGTYPE */
00421     sizeof(byte),   /* V_DMGWEIGHT */
00422     sizeof(date_t), /* V_DATE */
00423     sizeof(float),  /* V_RELABS */
00424     0,  /* V_CLIENT_HUNK */
00425     sizeof(char),   /* V_CLIENT_HUNK_STRING */
00426     sizeof(int),        /* V_TEAM */
00427     sizeof(racetypes_t),        /* V_RACE */
00428     sizeof(ufoType_t),  /* V_UFO */
00429     sizeof(ufoType_t),  /* V_UFOCRASHED */
00430     sizeof(humanAircraftType_t)     /* V_AIRCRAFTTYPE */
00431 };
00432 CASSERT(lengthof(vt_aligns) == V_NUM_TYPES);
00433 
00434 static char parseErrorMessage[256];
00435 
00440 const char* Com_GetLastParseError (void)
00441 {
00442     return parseErrorMessage;
00443 }
00444 
00449 void* Com_AlignPtr (void *memory, valueTypes_t type)
00450 {
00451     const size_t align = vt_aligns[type];
00452     assert(memory != NULL);
00453     if (align == V_NULL)
00454         Sys_Error("Com_AlignPtr: can't align V_NULL");
00455     if (type >= V_NUM_TYPES)
00456         Sys_Error("Com_AlignPtr: type hit V_NUM_TYPES");
00457     return ALIGN_PTR(memory, align);
00458 }
00459 
00472 int Com_ParseValue (void *base, const char *token, valueTypes_t type, int ofs, size_t size, size_t *writtenBytes)
00473 {
00474     byte *b;
00475     int x, y, w, h;
00476     byte num;
00477     resultStatus_t status = RESULT_OK;
00478     b = (byte *) base + ofs;
00479     *writtenBytes = 0;
00480 
00481     if (size) {
00482 #ifdef DEBUG
00483         if (size > vt_sizes[type]) {
00484             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Size mismatch: given size: "UFO_SIZE_T", should be: "UFO_SIZE_T" (type: %i). ", size, vt_sizes[type], type);
00485             status = RESULT_WARNING;
00486         }
00487 #endif
00488         if (size < vt_sizes[type]) {
00489             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Size mismatch: given size: "UFO_SIZE_T", should be: "UFO_SIZE_T". (type: %i)", size, vt_sizes[type], type);
00490             return RESULT_ERROR;
00491         }
00492     }
00493 
00494     switch (type) {
00495     case V_CLIENT_HUNK_STRING:
00496     case V_CLIENT_HUNK:
00497         snprintf(parseErrorMessage, sizeof(parseErrorMessage), "V_CLIENT_HUNK and V_CLIENT_HUNK_STRING are not parsed here");
00498         return RESULT_ERROR;
00499 
00500     case V_NULL:
00501         *writtenBytes = 0;
00502         break;
00503 
00504     case V_BOOL:
00505         if (!strcmp(token, "true") || *token == '1')
00506             *(qboolean *)b = qtrue;
00507         else if (!strcmp(token, "false") || *token == '0')
00508             *(qboolean *)b = qfalse;
00509         else {
00510             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal bool statement '%s'", token);
00511             return RESULT_ERROR;
00512         }
00513         *writtenBytes = sizeof(qboolean);
00514         break;
00515 
00516     case V_CHAR:
00517         if (token[0] == '\0') {
00518             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Char expected, but end of string found");
00519             return RESULT_ERROR;
00520         }
00521         if (token[1] != '\0') {
00522             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal end of string. '\\0' explected but 0x%x found", token[1]);
00523             return RESULT_ERROR;
00524         }
00525         *(char *) b = token[0];
00526         *writtenBytes = sizeof(char);
00527         break;
00528 
00529     case V_TEAM:
00530         if (!strcmp(token, "civilian"))
00531             *(int *) b = TEAM_CIVILIAN;
00532         else if (!strcmp(token, "phalanx"))
00533             *(int *) b = TEAM_PHALANX;
00534         else if (!strcmp(token, "alien"))
00535             *(int *) b = TEAM_ALIEN;
00536         else
00537             Sys_Error("Unknown team string: '%s' found in script files", token);
00538         *writtenBytes = sizeof(int);
00539         break;
00540 
00541     case V_RACE:
00542         if (!strcmp(token, "phalanx"))
00543             *(racetypes_t *) b = RACE_PHALANX_HUMAN;
00544         else if (!strcmp(token, "civilian"))
00545             *(racetypes_t *) b = RACE_CIVILIAN;
00546         else if (!strcmp(token, "robot"))
00547             *(racetypes_t *) b = RACE_ROBOT;
00548         else if (!strcmp(token, "taman"))
00549             *(racetypes_t *) b = RACE_TAMAN;
00550         else if (!strcmp(token, "ortnok"))
00551             *(racetypes_t *) b = RACE_ORTNOK;
00552         else if (!strcmp(token, "bloodspider"))
00553             *(racetypes_t *) b = RACE_BLOODSPIDER;
00554         else if (!strcmp(token, "shevaar"))
00555             *(racetypes_t *) b = RACE_SHEVAAR;
00556         else
00557             Sys_Error("Unknown race type: '%s'", token);
00558         *writtenBytes = sizeof(racetypes_t);
00559         break;
00560 
00561     case V_AIRCRAFTTYPE:
00562         if (!strcmp(token, "craft_drop_firebird"))
00563             *(humanAircraftType_t *) b = DROPSHIP_FIREBIRD;
00564         else if (!strcmp(token, "craft_drop_herakles"))
00565             *(humanAircraftType_t *) b = DROPSHIP_HERAKLES;
00566         else if (!strcmp(token, "craft_drop_raptor"))
00567             *(humanAircraftType_t *) b = DROPSHIP_RAPTOR;
00568         else if (!strcmp(token, "craft_inter_stiletto"))
00569             *(humanAircraftType_t *) b = INTERCEPTOR_STILETTO;
00570         else if (!strcmp(token, "craft_inter_saracen"))
00571             *(humanAircraftType_t *) b = INTERCEPTOR_SARACEN;
00572         else if (!strcmp(token, "craft_inter_dragon"))
00573             *(humanAircraftType_t *) b = INTERCEPTOR_DRAGON;
00574         else if (!strcmp(token, "craft_inter_starchaser"))
00575             *(humanAircraftType_t *) b = INTERCEPTOR_STARCHASER;
00576         else if (!strcmp(token, "craft_inter_stingray"))
00577             *(humanAircraftType_t *) b = INTERCEPTOR_STINGRAY;
00578         else
00579             Sys_Error("Unknown aircrafttype type: '%s'", token);
00580         *writtenBytes = sizeof(humanAircraftType_t);
00581         break;
00582 
00583     case V_UFO:
00584         if (!strcmp(token, "craft_ufo_bomber"))
00585             *(ufoType_t *) b = UFO_BOMBER;
00586         else if (!strcmp(token, "craft_ufo_carrier"))
00587             *(ufoType_t *) b = UFO_CARRIER;
00588         else if (!strcmp(token, "craft_ufo_corrupter"))
00589             *(ufoType_t *) b = UFO_CORRUPTER;
00590         else if (!strcmp(token, "craft_ufo_fighter"))
00591             *(ufoType_t *) b = UFO_FIGHTER;
00592         else if (!strcmp(token, "craft_ufo_harvester"))
00593             *(ufoType_t *) b = UFO_HARVESTER;
00594         else if (!strcmp(token, "craft_ufo_scout"))
00595             *(ufoType_t *) b = UFO_SCOUT;
00596         else if (!strcmp(token, "craft_ufo_supply"))
00597             *(ufoType_t *) b = UFO_SUPPLY;
00598         else if (!strcmp(token, "craft_ufo_gunboat"))
00599             *(ufoType_t *) b = UFO_GUNBOAT;
00600         else if (!strcmp(token, "craft_ufo_ripper"))
00601             *(ufoType_t *) b = UFO_RIPPER;
00602         else if (!strcmp(token, "craft_ufo_mothership"))
00603             *(ufoType_t *) b = UFO_MOTHERSHIP;
00604         else
00605             Sys_Error("Unknown ufo type: '%s'", token);
00606         *writtenBytes = sizeof(ufoType_t);
00607         break;
00608 
00609     case V_UFOCRASHED:
00610         if (!strcmp(token, "craft_crash_bomber"))
00611             *(ufoType_t *) b = UFO_BOMBER;
00612         else if (!strcmp(token, "craft_crash_carrier"))
00613             *(ufoType_t *) b = UFO_CARRIER;
00614         else if (!strcmp(token, "craft_crash_corrupter"))
00615             *(ufoType_t *) b = UFO_CORRUPTER;
00616         else if (!strcmp(token, "craft_crash_fighter"))
00617             *(ufoType_t *) b = UFO_FIGHTER;
00618         else if (!strcmp(token, "craft_crash_harvester"))
00619             *(ufoType_t *) b = UFO_HARVESTER;
00620         else if (!strcmp(token, "craft_crash_scout"))
00621             *(ufoType_t *) b = UFO_SCOUT;
00622         else if (!strcmp(token, "craft_crash_supply"))
00623             *(ufoType_t *) b = UFO_SUPPLY;
00624         else if (!strcmp(token, "craft_crash_gunboat"))
00625             *(ufoType_t *) b = UFO_GUNBOAT;
00626         else if (!strcmp(token, "craft_crash_ripper"))
00627             *(ufoType_t *) b = UFO_RIPPER;
00628         else if (!strcmp(token, "craft_crash_mothership"))
00629             *(ufoType_t *) b = UFO_MOTHERSHIP;
00630         else
00631             Sys_Error("Unknown ufo type: '%s'", token);
00632         *writtenBytes = sizeof(ufoType_t);
00633         break;
00634 
00635     case V_INT:
00636         if (sscanf(token, "%i", &((int *) b)[0]) != 1) {
00637             if (!Com_GetConstInt(token, &((int *) b)[0])) {
00638                 snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal int statement '%s'", token);
00639                 return RESULT_ERROR;
00640             }
00641         }
00642         *writtenBytes = sizeof(int);
00643         break;
00644 
00645     case V_INT2:
00646         if (sscanf(token, "%i %i", &((int *) b)[0], &((int *) b)[1]) != 2) {
00647             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal int2 statement '%s'", token);
00648             return RESULT_ERROR;
00649         }
00650         *writtenBytes = 2 * sizeof(int);
00651         break;
00652 
00653     case V_FLOAT:
00654         if (sscanf(token, "%f", &((float *) b)[0]) != 1) {
00655             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal float statement '%s'", token);
00656             return RESULT_ERROR;
00657         }
00658         *writtenBytes = sizeof(float);
00659         break;
00660 
00661     case V_POS:
00662         if (sscanf(token, "%f %f", &((float *) b)[0], &((float *) b)[1]) != 2) {
00663             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal pos statement '%s'", token);
00664             return RESULT_ERROR;
00665         }
00666         *writtenBytes = 2 * sizeof(float);
00667         break;
00668 
00669     case V_VECTOR:
00670         if (sscanf(token, "%f %f %f", &((float *) b)[0], &((float *) b)[1], &((float *) b)[2]) != 3) {
00671             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal vector statement '%s'", token);
00672             return RESULT_ERROR;
00673         }
00674         *writtenBytes = 3 * sizeof(float);
00675         break;
00676 
00677     case V_COLOR:
00678         {
00679             float* f = (float *) b;
00680             if (sscanf(token, "%f %f %f %f", &f[0], &f[1], &f[2], &f[3]) != 4) {
00681                 snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal color statement '%s'", token);
00682                 return RESULT_ERROR;
00683             }
00684             *writtenBytes = 4 * sizeof(float);
00685         }
00686         break;
00687 
00688     case V_RGBA:
00689         {
00690             int* i = (int *) b;
00691             if (sscanf(token, "%i %i %i %i", &i[0], &i[1], &i[2], &i[3]) != 4) {
00692                 snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal rgba statement '%s'", token);
00693                 return RESULT_ERROR;
00694             }
00695             *writtenBytes = 4 * sizeof(int);
00696         }
00697         break;
00698 
00699     case V_STRING:
00700         Q_strncpyz((char *) b, token, MAX_VAR);
00701         w = (int)strlen(token) + 1;
00702         *writtenBytes = w;
00703         break;
00704 
00705     /* just remove the _ but don't translate */
00706     case V_TRANSLATION_STRING:
00707         if (*token == '_')
00708             token++;
00709 
00710         Q_strncpyz((char *) b, token, MAX_VAR);
00711         w = (int)strlen((char *) b) + 1;
00712         *writtenBytes = w;
00713         break;
00714 
00715     case V_LONGSTRING:
00716         strcpy((char *) b, token);
00717         w = (int)strlen(token) + 1;
00718         *writtenBytes = w;
00719         break;
00720 
00721     case V_ALIGN:
00722         for (num = 0; num < ALIGN_LAST; num++)
00723             if (!strcmp(token, align_names[num]))
00724                 break;
00725         if (num == ALIGN_LAST)
00726             *(align_t *)b = 0;
00727         else
00728             *(align_t *)b = num;
00729         *writtenBytes = sizeof(align_t);
00730         break;
00731 
00732     case V_BLEND:
00733         for (num = 0; num < BLEND_LAST; num++)
00734             if (!strcmp(token, blend_names[num]))
00735                 break;
00736         if (num == BLEND_LAST)
00737             *(blend_t *)b = 0;
00738         else
00739             *(blend_t *)b = num;
00740         *writtenBytes = sizeof(blend_t);
00741         break;
00742 
00743     case V_STYLE:
00744         for (num = 0; num < STYLE_LAST; num++)
00745             if (!strcmp(token, style_names[num]))
00746                 break;
00747         if (num == STYLE_LAST)
00748             *(style_t *)b = 0;
00749         else
00750             *(style_t *)b = num;
00751         *writtenBytes = sizeof(style_t);
00752         break;
00753 
00754     case V_FADE:
00755         for (num = 0; num < FADE_LAST; num++)
00756             if (!strcmp(token, fade_names[num]))
00757                 break;
00758         if (num == FADE_LAST)
00759             *(fade_t *)b = 0;
00760         else
00761             *(fade_t *)b = num;
00762         *writtenBytes = sizeof(fade_t);
00763         break;
00764 
00765     case V_SHAPE_SMALL:
00766         if (sscanf(token, "%i %i %i %i", &x, &y, &w, &h) != 4) {
00767             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal shape small statement '%s'", token);
00768             return RESULT_ERROR;
00769         }
00770 
00771         if (y + h > SHAPE_SMALL_MAX_HEIGHT || y >= SHAPE_SMALL_MAX_HEIGHT || h > SHAPE_SMALL_MAX_HEIGHT) {
00772             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "illegal shape small statement - max h value is %i (y: %i, h: %i)", SHAPE_SMALL_MAX_HEIGHT, y, h);
00773             return RESULT_ERROR;
00774         }
00775         if (x + w > SHAPE_SMALL_MAX_WIDTH || x >= SHAPE_SMALL_MAX_WIDTH || w > SHAPE_SMALL_MAX_WIDTH) {
00776             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "illegal shape small statement - max x and w values are %i", SHAPE_SMALL_MAX_WIDTH);
00777             return RESULT_ERROR;
00778         }
00779         for (h += y; y < h; y++)
00780             *(uint32_t *) b |= ((1 << w) - 1) << x << (y * SHAPE_SMALL_MAX_WIDTH);
00781         *writtenBytes = SHAPE_SMALL_MAX_HEIGHT;
00782         break;
00783 
00784     case V_SHAPE_BIG:
00785         if (sscanf(token, "%i %i %i %i", &x, &y, &w, &h) != 4) {
00786             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal shape big statement '%s'", token);
00787             return RESULT_ERROR;
00788         }
00789         if (y + h > SHAPE_BIG_MAX_HEIGHT || y >= SHAPE_BIG_MAX_HEIGHT || h > SHAPE_BIG_MAX_HEIGHT) {
00790             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal shape big statement, max height is %i", SHAPE_BIG_MAX_HEIGHT);
00791             return RESULT_ERROR;
00792         }
00793         if (x + w > SHAPE_BIG_MAX_WIDTH || x >= SHAPE_BIG_MAX_WIDTH || w > SHAPE_BIG_MAX_WIDTH) {
00794             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "illegal shape big statement - max x and w values are %i ('%s')", SHAPE_BIG_MAX_WIDTH, token);
00795             return RESULT_ERROR;
00796         }
00797         w = ((1 << w) - 1) << x;
00798         for (h += y; y < h; y++)
00799             ((uint32_t *) b)[y] |= w;
00800         *writtenBytes = SHAPE_BIG_MAX_HEIGHT * SHAPE_SMALL_MAX_HEIGHT;
00801         break;
00802 
00803     case V_DMGWEIGHT:
00804     case V_DMGTYPE:
00805         for (num = 0; num < csi.numDTs; num++)
00806             if (!strcmp(token, csi.dts[num].id))
00807                 break;
00808         if (num == csi.numDTs)
00809             *b = 0;
00810         else
00811             *b = num;
00812         *writtenBytes = sizeof(byte);
00813         break;
00814 
00815     case V_DATE:
00816         if (sscanf(token, "%i %i %i", &x, &y, &w) != 3) {
00817             snprintf(parseErrorMessage, sizeof(parseErrorMessage), "Illegal if statement '%s'", token);
00818             return RESULT_ERROR;
00819         }
00820 
00821         ((date_t *) b)->day = DAYS_PER_YEAR * x + y;
00822         ((date_t *) b)->sec = SECONDS_PER_HOUR * w;
00823         *writtenBytes = sizeof(date_t);
00824         break;
00825 
00826     case V_RELABS:
00827         if (token[0] == '-' || token[0] == '+') {
00828             if (fabs(atof(token + 1)) <= 2.0f) {
00829                 snprintf(parseErrorMessage, sizeof(parseErrorMessage), "a V_RELABS (absolute) value should always be bigger than +/-2.0");
00830                 status = RESULT_WARNING;
00831             }
00832             if (token[0] == '-')
00833                 *(float *) b = atof(token + 1) * (-1);
00834             else
00835                 *(float *) b = atof(token + 1);
00836         } else {
00837             if (fabs(atof(token)) > 2.0f) {
00838                 snprintf(parseErrorMessage, sizeof(parseErrorMessage), "a V_RELABS (relative) value should only be between 0.00..1 and 2.0");
00839                 status = RESULT_WARNING;
00840             }
00841             *(float *) b = atof(token);
00842         }
00843         *writtenBytes = sizeof(float);
00844         break;
00845 
00846     default:
00847         snprintf(parseErrorMessage, sizeof(parseErrorMessage), "unknown value type '%s'", token);
00848         return RESULT_ERROR;
00849     }
00850     return status;
00851 }
00852 
00861 #ifdef DEBUG
00862 int Com_EParseValueDebug (void *base, const char *token, valueTypes_t type, int ofs, size_t size, const char *file, int line)
00863 #else
00864 int Com_EParseValue (void *base, const char *token, valueTypes_t type, int ofs, size_t size)
00865 #endif
00866 {
00867     size_t writtenBytes;
00868     const resultStatus_t result = Com_ParseValue(base, token, type, ofs, size, &writtenBytes);
00869     switch (result) {
00870     case RESULT_ERROR:
00871 #ifdef DEBUG
00872         Sys_Error("Com_EParseValue: %s (file: '%s', line: %i)\n", parseErrorMessage, file, line);
00873 #else
00874         Sys_Error("Com_EParseValue: %s\n", parseErrorMessage);
00875 #endif
00876         break;
00877     case RESULT_WARNING:
00878 #ifdef DEBUG
00879         Com_Printf("Com_EParseValue: %s (file: '%s', line: %i)\n", parseErrorMessage, file, line);
00880 #else
00881         Com_Printf("Com_EParseValue: %s\n", parseErrorMessage);
00882 #endif
00883         break;
00884     case RESULT_OK:
00885         break;
00886     }
00887     return writtenBytes;
00888 }
00889 
00895 qboolean Com_ParseBoolean (const char *token)
00896 {
00897     qboolean b;
00898     size_t writtenBytes;
00899     if (Com_ParseValue(&b, token, V_BOOL, 0, sizeof(b), &writtenBytes) != RESULT_ERROR) {
00900         assert(writtenBytes == sizeof(b));
00901         return b;
00902     }
00903     return qfalse;
00904 }
00905 
00915 #ifdef DEBUG
00916 int Com_SetValueDebug (void *base, const void *set, valueTypes_t type, int ofs, size_t size, const char *file, int line)
00917 #else
00918 int Com_SetValue (void *base, const void *set, valueTypes_t type, int ofs, size_t size)
00919 #endif
00920 {
00921     byte *b;
00922     int len;
00923 
00924     b = (byte *) base + ofs;
00925 
00926     if (size) {
00927 #ifdef DEBUG
00928         if (size > vt_sizes[type])
00929             Com_Printf("Warning: Size mismatch: given size: "UFO_SIZE_T", should be: "UFO_SIZE_T". File: '%s', line: %i (type: %i)\n", size, vt_sizes[type], file, line, type);
00930 
00931         if (size < vt_sizes[type])
00932             Sys_Error("Size mismatch: given size: "UFO_SIZE_T", should be: "UFO_SIZE_T". File: '%s', line: %i (type: %i)\n", size, vt_sizes[type], file, line, type);
00933 #else
00934         if (size < vt_sizes[type])
00935             Sys_Error("Size mismatch: given size: "UFO_SIZE_T", should be: "UFO_SIZE_T". (type: %i)\n", size, vt_sizes[type], type);
00936 #endif
00937     }
00938 
00939     switch (type) {
00940     case V_NULL:
00941         return 0;
00942 
00943     case V_BOOL:
00944         if (*(const qboolean *) set)
00945             *(qboolean *)b = qtrue;
00946         else
00947             *(qboolean *)b = qfalse;
00948         return sizeof(qboolean);
00949 
00950     case V_CHAR:
00951         *(char *) b = *(const char *) set;
00952         return sizeof(char);
00953 
00954     case V_TEAM:
00955         if (!strcmp((const char *)set, "civilian"))
00956             *(int *) b = TEAM_CIVILIAN;
00957         else if (!strcmp((const char *)set, "phalanx"))
00958             *(int *) b = TEAM_PHALANX;
00959         else if (!strcmp((const char *)set, "alien"))
00960             *(int *) b = TEAM_ALIEN;
00961         else
00962             Sys_Error("Unknown team given: '%s'", (const char *)set);
00963         return sizeof(int);
00964 
00965     case V_RACE:
00966         if (!strcmp((const char *)set, "phalanx"))
00967             *(racetypes_t *) b = RACE_PHALANX_HUMAN;
00968         else if (!strcmp((const char *)set, "civilian"))
00969             *(racetypes_t *) b = RACE_CIVILIAN;
00970         else if (!strcmp((const char *)set, "robot"))
00971             *(racetypes_t *) b = RACE_ROBOT;
00972         else if (!strcmp((const char *)set, "taman"))
00973             *(racetypes_t *) b = RACE_TAMAN;
00974         else if (!strcmp((const char *)set, "ortnok"))
00975             *(racetypes_t *) b = RACE_ORTNOK;
00976         else if (!strcmp((const char *)set, "bloodspider"))
00977             *(racetypes_t *) b = RACE_BLOODSPIDER;
00978         else if (!strcmp((const char *)set, "shevaar"))
00979             *(racetypes_t *) b = RACE_SHEVAAR;
00980         else
00981             Sys_Error("Unknown race type: '%s'", (const char *)set);
00982         return sizeof(racetypes_t);
00983 
00984     case V_AIRCRAFTTYPE:
00985         if (!strcmp((const char *)set, "craft_drop_firebird"))
00986             *(humanAircraftType_t *) b = DROPSHIP_FIREBIRD;
00987         else if (!strcmp((const char *)set, "craft_drop_herakles"))
00988             *(humanAircraftType_t *) b = DROPSHIP_HERAKLES;
00989         else if (!strcmp((const char *)set, "craft_drop_raptor"))
00990             *(humanAircraftType_t *) b = DROPSHIP_RAPTOR;
00991         else if (!strcmp((const char *)set, "craft_inter_stiletto"))
00992             *(humanAircraftType_t *) b = INTERCEPTOR_STILETTO;
00993         else if (!strcmp((const char *)set, "craft_inter_saracen"))
00994             *(humanAircraftType_t *) b = INTERCEPTOR_SARACEN;
00995         else if (!strcmp((const char *)set, "craft_inter_dragon"))
00996             *(humanAircraftType_t *) b = INTERCEPTOR_DRAGON;
00997         else if (!strcmp((const char *)set, "craft_inter_starchaser"))
00998             *(humanAircraftType_t *) b = INTERCEPTOR_STARCHASER;
00999         else if (!strcmp((const char *)set, "craft_inter_stingray"))
01000             *(humanAircraftType_t *) b = INTERCEPTOR_STINGRAY;
01001         else
01002             Sys_Error("Unknown aircrafttype type: '%s'", (const char *)set);
01003         return sizeof(humanAircraftType_t);
01004 
01005     case V_UFO:
01006         if (!strcmp((const char *)set, "craft_ufo_bomber"))
01007             *(ufoType_t *) b = UFO_BOMBER;
01008         else if (!strcmp((const char *)set, "craft_ufo_carrier"))
01009             *(ufoType_t *) b = UFO_CARRIER;
01010         else if (!strcmp((const char *)set, "craft_ufo_corrupter"))
01011             *(ufoType_t *) b = UFO_CORRUPTER;
01012         else if (!strcmp((const char *)set, "craft_ufo_fighter"))
01013             *(ufoType_t *) b = UFO_FIGHTER;
01014         else if (!strcmp((const char *)set, "craft_ufo_harvester"))
01015             *(ufoType_t *) b = UFO_HARVESTER;
01016         else if (!strcmp((const char *)set, "craft_ufo_scout"))
01017             *(ufoType_t *) b = UFO_SCOUT;
01018         else if (!strcmp((const char *)set, "craft_ufo_supply"))
01019             *(ufoType_t *) b = UFO_SUPPLY;
01020         else if (!strcmp((const char *)set, "craft_ufo_gunboat"))
01021             *(ufoType_t *) b = UFO_GUNBOAT;
01022         else if (!strcmp((const char *)set, "craft_ufo_ripper"))
01023             *(ufoType_t *) b = UFO_RIPPER;
01024         else if (!strcmp((const char *)set, "craft_ufo_mothership"))
01025             *(ufoType_t *) b = UFO_MOTHERSHIP;
01026         else
01027             Sys_Error("Unknown ufo type: '%s'", (const char *)set);
01028         return sizeof(ufoType_t);
01029 
01030     case V_UFOCRASHED:
01031         if (!strcmp((const char *)set, "craft_crash_bomber"))
01032             *(ufoType_t *) b = UFO_BOMBER;
01033         else if (!strcmp((const char *)set, "craft_crash_carrier"))
01034             *(ufoType_t *) b = UFO_CARRIER;
01035         else if (!strcmp((const char *)set, "craft_crash_corrupter"))
01036             *(ufoType_t *) b = UFO_CORRUPTER;
01037         else if (!strcmp((const char *)set, "craft_crash_fighter"))
01038             *(ufoType_t *) b = UFO_FIGHTER;
01039         else if (!strcmp((const char *)set, "craft_crash_harvester"))
01040             *(ufoType_t *) b = UFO_HARVESTER;
01041         else if (!strcmp((const char *)set, "craft_crash_scout"))
01042             *(ufoType_t *) b = UFO_SCOUT;
01043         else if (!strcmp((const char *)set, "craft_crash_supply"))
01044             *(ufoType_t *) b = UFO_SUPPLY;
01045         else if (!strcmp((const char *)set, "craft_crash_gunboat"))
01046             *(ufoType_t *) b = UFO_GUNBOAT;
01047         else if (!strcmp((const char *)set, "craft_crash_ripper"))
01048             *(ufoType_t *) b = UFO_RIPPER;
01049         else if (!strcmp((const char *)set, "craft_crash_mothership"))
01050             *(ufoType_t *) b = UFO_MOTHERSHIP;
01051         else
01052             Sys_Error("Unknown ufo type: '%s'", (const char *)set);
01053         return sizeof(ufoType_t);
01054 
01055     case V_INT:
01056         *(int *) b = *(const int *) set;
01057         return sizeof(int);
01058 
01059     case V_INT2:
01060         ((int *) b)[0] = ((const int *) set)[0];
01061         ((int *) b)[1] = ((const int *) set)[1];
01062         return 2 * sizeof(int);
01063 
01064     case V_FLOAT:
01065         *(float *) b = *(const float *) set;
01066         return sizeof(float);
01067 
01068     case V_POS:
01069         ((float *) b)[0] = ((const float *) set)[0];
01070         ((float *) b)[1] = ((const float *) set)[1];
01071         return 2 * sizeof(float);
01072 
01073     case V_VECTOR:
01074         ((float *) b)[0] = ((const float *) set)[0];
01075         ((float *) b)[1] = ((const float *) set)[1];
01076         ((float *) b)[2] = ((const float *) set)[2];
01077         return 3 * sizeof(float);
01078 
01079     case V_COLOR:
01080         ((float *) b)[0] = ((const float *) set)[0];
01081         ((float *) b)[1] = ((const float *) set)[1];
01082         ((float *) b)[2] = ((const float *) set)[2];
01083         ((float *) b)[3] = ((const float *) set)[3];
01084         return 4 * sizeof(float);
01085 
01086     case V_RGBA:
01087         ((int *) b)[0] = ((const int *) set)[0];
01088         ((int *) b)[1] = ((const int *) set)[1];
01089         ((int *) b)[2] = ((const int *) set)[2];
01090         ((int *) b)[3] = ((const int *) set)[3];
01091         return 4 * sizeof(int);
01092 
01093     case V_STRING:
01094         Q_strncpyz((char *) b, (const char *) set, MAX_VAR);
01095         len = (int)strlen((const char *) set) + 1;
01096         if (len > MAX_VAR)
01097             len = MAX_VAR;
01098         return len;
01099 
01100     case V_LONGSTRING:
01101         strcpy((char *) b, (const char *) set);
01102         len = (int)strlen((const char *) set) + 1;
01103         return len;
01104 
01105     case V_ALIGN:
01106         *(align_t *)b = *(const align_t *) set;
01107         return sizeof(align_t);
01108 
01109     case V_BLEND:
01110         *(blend_t *)b = *(const blend_t *) set;
01111         return sizeof(blend_t);
01112 
01113     case V_STYLE:
01114         *(style_t *)b = *(const style_t *) set;
01115         return sizeof(style_t);
01116 
01117     case V_FADE:
01118         *(fade_t *)b = *(const fade_t *) set;
01119         return sizeof(fade_t);
01120 
01121     case V_SHAPE_SMALL:
01122         *(int *) b = *(const int *) set;
01123         return SHAPE_SMALL_MAX_HEIGHT;
01124 
01125     case V_SHAPE_BIG:
01126         memcpy(b, set, 64);
01127         return SHAPE_BIG_MAX_HEIGHT * 4;
01128 
01129     case V_DMGWEIGHT:
01130     case V_DMGTYPE:
01131         *b = *(const byte *) set;
01132         return 1;
01133 
01134     case V_DATE:
01135         memcpy(b, set, sizeof(date_t));
01136         return sizeof(date_t);
01137 
01138     default:
01139         Sys_Error("Com_SetValue: unknown value type\n");
01140     }
01141 }
01142 
01150 const char *Com_ValueToStr (const void *base, const valueTypes_t type, const int ofs)
01151 {
01152     static char valuestr[MAX_VAR];
01153     const byte *b;
01154 
01155     b = (const byte *) base + ofs;
01156 
01157     switch (type) {
01158     case V_NULL:
01159         return 0;
01160 
01161     case V_CLIENT_HUNK:
01162     case V_CLIENT_HUNK_STRING:
01163         if (b == NULL)
01164             return "(null)";
01165         else
01166             return (const char*)b;
01167 
01168     case V_BOOL:
01169         if (*b)
01170             return "true";
01171         else
01172             return "false";
01173 
01174     case V_CHAR:
01175         return (const char *) b;
01176         break;
01177 
01178     case V_TEAM:
01179         switch (*(const int *) b) {
01180         case TEAM_CIVILIAN:
01181             return "civilian";
01182         case TEAM_PHALANX:
01183             return "phalanx";
01184         case TEAM_ALIEN:
01185             return "alien";
01186         default:
01187             Sys_Error("Unknown team id '%i'", *(const int *) b);
01188         }
01189 
01190     case V_RACE:
01191         switch (*(const racetypes_t *) b) {
01192         case RACE_PHALANX_HUMAN:
01193             return "phalanx";
01194         case RACE_CIVILIAN:
01195             return "civilian";
01196         case RACE_ROBOT:
01197             return "robot";
01198         case RACE_TAMAN:
01199             return "taman";
01200         case RACE_ORTNOK:
01201             return "ortnok";
01202         case RACE_BLOODSPIDER:
01203             return "bloodspider";
01204         case RACE_SHEVAAR:
01205             return "shevaar";
01206         default:
01207             Sys_Error("Unknown race type: '%i'", *(const racetypes_t *) b);
01208         }
01209 
01210     case V_AIRCRAFTTYPE:
01211         switch (*(const humanAircraftType_t *) b) {
01212         case DROPSHIP_FIREBIRD:
01213             return "craft_drop_firebird";
01214         case DROPSHIP_HERAKLES:
01215             return "craft_drop_herakles";
01216         case DROPSHIP_RAPTOR:
01217             return "craft_drop_raptor";
01218         case INTERCEPTOR_STILETTO:
01219             return "craft_inter_stiletto";
01220         case INTERCEPTOR_SARACEN:
01221             return "craft_inter_saracen";
01222         case INTERCEPTOR_DRAGON:
01223             return "craft_inter_dragon";
01224         case INTERCEPTOR_STARCHASER:
01225             return "craft_inter_starchaser";
01226         case INTERCEPTOR_STINGRAY:
01227             return "craft_inter_stingray";
01228         default:
01229             Sys_Error("Unknown aircrafttype type: '%i'", *(const humanAircraftType_t *) b);
01230         }
01231 
01232     case V_UFO:
01233         switch (*(const ufoType_t *) b) {
01234         case UFO_BOMBER:
01235             return "craft_ufo_bomber";
01236         case UFO_CARRIER:
01237             return "craft_ufo_carrier";
01238         case UFO_CORRUPTER:
01239             return "craft_ufo_corrupter";
01240         case UFO_FIGHTER:
01241             return "craft_ufo_fighter";
01242         case UFO_HARVESTER:
01243             return "craft_ufo_harvester";
01244         case UFO_SCOUT:
01245             return "craft_ufo_scout";
01246         case UFO_SUPPLY:
01247             return "craft_ufo_supply";
01248         case UFO_GUNBOAT:
01249             return "craft_ufo_gunboat";
01250         case UFO_RIPPER:
01251             return "craft_ufo_ripper";
01252         case UFO_MOTHERSHIP:
01253             return "craft_ufo_mothership";
01254         default:
01255             Sys_Error("Unknown ufo type: '%i'", *(const ufoType_t *) b);
01256         }
01257 
01258     case V_UFOCRASHED:
01259         switch (*(const ufoType_t *) b) {
01260         case UFO_BOMBER:
01261             return "craft_crash_bomber";
01262         case UFO_CARRIER:
01263             return "craft_crash_carrier";
01264         case UFO_CORRUPTER:
01265             return "craft_crash_corrupter";
01266         case UFO_FIGHTER:
01267             return "craft_crash_fighter";
01268         case UFO_HARVESTER:
01269             return "craft_crash_harvester";
01270         case UFO_SCOUT:
01271             return "craft_crash_scout";
01272         case UFO_SUPPLY:
01273             return "craft_crash_supply";
01274         case UFO_GUNBOAT:
01275             return "craft_crash_gunboat";
01276         case UFO_RIPPER:
01277             return "craft_crash_ripper";
01278         case UFO_MOTHERSHIP:
01279             return "craft_crash_mothership";
01280         default:
01281             Sys_Error("Unknown crashed ufo type: '%i'", *(const ufoType_t *) b);
01282         }
01283 
01284     case V_INT:
01285         Com_sprintf(valuestr, sizeof(valuestr), "%i", *(const int *) b);
01286         return valuestr;
01287 
01288     case V_INT2:
01289         Com_sprintf(valuestr, sizeof(valuestr), "%i %i", ((const int *) b)[0], ((const int *) b)[1]);
01290         return valuestr;
01291 
01292     case V_FLOAT:
01293         Com_sprintf(valuestr, sizeof(valuestr), "%.2f", *(const float *) b);
01294         return valuestr;
01295 
01296     case V_POS:
01297         Com_sprintf(valuestr, sizeof(valuestr), "%.2f %.2f", ((const float *) b)[0], ((const float *) b)[1]);
01298         return valuestr;
01299 
01300     case V_VECTOR:
01301         Com_sprintf(valuestr, sizeof(valuestr), "%.2f %.2f %.2f", ((const float *) b)[0], ((const float *) b)[1], ((const float *) b)[2]);
01302         return valuestr;
01303 
01304     case V_COLOR:
01305         Com_sprintf(valuestr, sizeof(valuestr), "%.2f %.2f %.2f %.2f", ((const float *) b)[0], ((const float *) b)[1], ((const float *) b)[2], ((const float *) b)[3]);
01306         return valuestr;
01307 
01308     case V_RGBA:
01309         Com_sprintf(valuestr, sizeof(valuestr), "%3i %3i %3i %3i", ((const int *) b)[0], ((const int *) b)[1], ((const int *) b)[2], ((const int *) b)[3]);
01310         return valuestr;
01311 
01312     case V_TRANSLATION_STRING:
01313     case V_STRING:
01314     case V_LONGSTRING:
01315         if (b == NULL)
01316             return "(null)";
01317         else
01318             return (const char *) b;
01319 
01320     case V_ALIGN:
01321         assert(*(const align_t *)b < ALIGN_LAST);
01322         Q_strncpyz(valuestr, align_names[*(const align_t *)b], sizeof(valuestr));
01323         return valuestr;
01324 
01325     case V_BLEND:
01326         assert(*(const blend_t *)b < BLEND_LAST);
01327         Q_strncpyz(valuestr, blend_names[*(const blend_t *)b], sizeof(valuestr));
01328         return valuestr;
01329 
01330     case V_STYLE:
01331         assert(*(const style_t *)b < STYLE_LAST);
01332         Q_strncpyz(valuestr, style_names[*(const style_t *)b], sizeof(valuestr));
01333         return valuestr;
01334 
01335     case V_FADE:
01336         assert(*(const fade_t *)b < FADE_LAST);
01337         Q_strncpyz(valuestr, fade_names[*(const fade_t *)b], sizeof(valuestr));
01338         return valuestr;
01339 
01340     case V_SHAPE_SMALL:
01341     case V_SHAPE_BIG:
01342         return "";
01343 
01344     case V_DMGWEIGHT:
01345     case V_DMGTYPE:
01346         assert(*(const byte *)b < MAX_DAMAGETYPES);
01347         return csi.dts[*(const byte *)b].id;
01348 
01349     case V_DATE:
01350         Com_sprintf(valuestr, sizeof(valuestr), "%i %i %i", ((const date_t *) b)->day / DAYS_PER_YEAR, ((const date_t *) b)->day % DAYS_PER_YEAR, ((const date_t *) b)->sec);
01351         return valuestr;
01352 
01353     case V_RELABS:
01354         /* absolute value */
01355         if (*(const float *) b > 2.0)
01356             Com_sprintf(valuestr, sizeof(valuestr), "+%.2f", *(const float *) b);
01357         /* absolute value */
01358         else if (*(const float *) b < 2.0)
01359             Com_sprintf(valuestr, sizeof(valuestr), "-%.2f", *(const float *) b);
01360         /* relative value */
01361         else
01362             Com_sprintf(valuestr, sizeof(valuestr), "%.2f", *(const float *) b);
01363         return valuestr;
01364 
01365     default:
01366         Sys_Error("Com_ValueToStr: unknown value type %i\n", type);
01367     }
01368 }
01369 
01370 
01371 /*
01372 ==============================================================================
01373 OBJECT DEFINITION INTERPRETER
01374 ==============================================================================
01375 */
01376 
01377 static const char *const skillNames[SKILL_NUM_TYPES + 1] = {
01378     "strength",
01379     "speed",
01380     "accuracy",
01381     "mind",
01382     "close",
01383     "heavy",
01384     "assault",
01385     "sniper",
01386     "explosive",
01387     "health"
01388 };
01389 
01391 enum {
01392     OD_WEAPON,          
01393     OD_PROTECTION,      
01394     OD_RATINGS          
01395 };
01396 
01401 static const value_t od_vals[] = {
01402     {"weapon_mod", V_NULL, 0, 0},
01403     {"protection", V_NULL, 0, 0},
01404     {"rating", V_NULL, 0, 0},
01405 
01406     {"name", V_TRANSLATION_STRING, offsetof(objDef_t, name), 0},
01407     {"armourpath", V_STRING, offsetof(objDef_t, armourPath), 0},
01408     {"model", V_STRING, offsetof(objDef_t, model), 0},
01409     {"image", V_STRING, offsetof(objDef_t, image), 0},
01410     {"type", V_STRING, offsetof(objDef_t, type), 0},
01411     {"animationindex", V_CHAR, offsetof(objDef_t, animationIndex), MEMBER_SIZEOF(objDef_t, animationIndex)},
01412     {"shape", V_SHAPE_SMALL, offsetof(objDef_t, shape), MEMBER_SIZEOF(objDef_t, shape)},
01413     {"scale", V_FLOAT, offsetof(objDef_t, scale), MEMBER_SIZEOF(objDef_t, scale)},
01414     {"center", V_VECTOR, offsetof(objDef_t, center), MEMBER_SIZEOF(objDef_t, center)},
01415     {"weapon", V_BOOL, offsetof(objDef_t, weapon), MEMBER_SIZEOF(objDef_t, weapon)},
01416     {"holdtwohanded", V_BOOL, offsetof(objDef_t, holdTwoHanded), MEMBER_SIZEOF(objDef_t, holdTwoHanded)},
01417     {"firetwohanded", V_BOOL, offsetof(objDef_t, fireTwoHanded), MEMBER_SIZEOF(objDef_t, fireTwoHanded)},
01418     {"extension", V_BOOL, offsetof(objDef_t, extension), MEMBER_SIZEOF(objDef_t, extension)},
01419     {"headgear", V_BOOL, offsetof(objDef_t, headgear), MEMBER_SIZEOF(objDef_t, headgear)},
01420     {"thrown", V_BOOL, offsetof(objDef_t, thrown), MEMBER_SIZEOF(objDef_t, thrown)},
01421     {"ammo", V_INT, offsetof(objDef_t, ammo), MEMBER_SIZEOF(objDef_t, ammo)},
01422     {"oneshot", V_BOOL, offsetof(objDef_t, oneshot), MEMBER_SIZEOF(objDef_t, oneshot)},
01423     {"deplete", V_BOOL, offsetof(objDef_t, deplete), MEMBER_SIZEOF(objDef_t, deplete)},
01424     {"reload", V_INT, offsetof(objDef_t, reload), MEMBER_SIZEOF(objDef_t, reload)},
01425     {"size", V_INT, offsetof(objDef_t, size), MEMBER_SIZEOF(objDef_t, size)},
01426     {"price", V_INT, offsetof(objDef_t, price), MEMBER_SIZEOF(objDef_t, price)},
01427     {"useable", V_TEAM, offsetof(objDef_t, useable), MEMBER_SIZEOF(objDef_t, useable)},
01428     {"notonmarket", V_BOOL, offsetof(objDef_t, notOnMarket), MEMBER_SIZEOF(objDef_t, notOnMarket)},
01429 
01430     {"installationTime", V_INT, offsetof(objDef_t, craftitem.installationTime), MEMBER_SIZEOF(objDef_t, craftitem.installationTime)},
01431     {"bullets", V_BOOL, offsetof(objDef_t, craftitem.bullets), MEMBER_SIZEOF(objDef_t, craftitem.bullets)},
01432     {"beam", V_BOOL, offsetof(objDef_t, craftitem.beam), MEMBER_SIZEOF(objDef_t, craftitem.beam)},
01433     {"beamcolor", V_COLOR, offsetof(objDef_t, craftitem.beamColor), MEMBER_SIZEOF(objDef_t, craftitem.beamColor)},
01434     {"wdamage", V_FLOAT, offsetof(objDef_t, craftitem.weaponDamage), MEMBER_SIZEOF(objDef_t, craftitem.weaponDamage)},
01435     {"wspeed", V_FLOAT, offsetof(objDef_t, craftitem.weaponSpeed), MEMBER_SIZEOF(objDef_t, craftitem.weaponSpeed)},
01436     {"delay", V_FLOAT, offsetof(objDef_t, craftitem.weaponDelay), MEMBER_SIZEOF(objDef_t, craftitem.weaponDelay)},
01437     {"shield", V_FLOAT, offsetof(objDef_t, craftitem.stats[AIR_STATS_SHIELD]), MEMBER_SIZEOF(objDef_t, craftitem.stats[AIR_STATS_SHIELD])},
01438     {"wrange", V_FLOAT, offsetof(objDef_t, craftitem.stats[AIR_STATS_WRANGE]), MEMBER_SIZEOF(objDef_t, craftitem.stats[AIR_STATS_WRANGE])},
01439     {"damage", V_RELABS, offsetof(objDef_t, craftitem.stats[AIR_STATS_DAMAGE]), MEMBER_SIZEOF(objDef_t, craftitem.stats[AIR_STATS_DAMAGE])},
01440     {"accuracy", V_RELABS, offsetof(objDef_t, craftitem.stats[AIR_STATS_ACCURACY]), MEMBER_SIZEOF(objDef_t, craftitem.stats[AIR_STATS_ACCURACY])},
01441     {"ecm", V_RELABS, offsetof(objDef_t, craftitem.stats[AIR_STATS_ECM]), MEMBER_SIZEOF(objDef_t, craftitem.stats[AIR_STATS_ECM])},
01442     {"speed", V_RELABS, offsetof(objDef_t, craftitem.stats[AIR_STATS_SPEED]), MEMBER_SIZEOF(objDef_t, craftitem.stats[AIR_STATS_SPEED])},
01443     {"maxspeed", V_RELABS, offsetof(objDef_t, craftitem.stats[AIR_STATS_MAXSPEED]), MEMBER_SIZEOF(objDef_t, craftitem.stats[AIR_STATS_SPEED])},
01444     {"fuelsize", V_RELABS, offsetof(objDef_t, craftitem.stats[AIR_STATS_FUELSIZE]), MEMBER_SIZEOF(objDef_t, craftitem.stats[AIR_STATS_FUELSIZE])},
01445     {"dmgtype", V_DMGTYPE, offsetof(objDef_t, dmgtype), MEMBER_SIZEOF(objDef_t, dmgtype)},
01446 
01447     {"is_primary", V_BOOL, offsetof(objDef_t, isPrimary), MEMBER_SIZEOF(objDef_t, isPrimary)},
01448     {"is_secondary", V_BOOL, offsetof(objDef_t, isSecondary), MEMBER_SIZEOF(objDef_t, isSecondary)},
01449     {"is_heavy", V_BOOL, offsetof(objDef_t, isHeavy), MEMBER_SIZEOF(objDef_t, isHeavy)},
01450     {"is_misc", V_BOOL, offsetof(objDef_t, isMisc), MEMBER_SIZEOF(objDef_t, isMisc)},
01451     {"is_ugvitem", V_BOOL, offsetof(objDef_t, isUGVitem), MEMBER_SIZEOF(objDef_t, isUGVitem)},
01452     {"is_dummy", V_BOOL, offsetof(objDef_t, isDummy), MEMBER_SIZEOF(objDef_t, isDummy)},
01453     {"virtual", V_BOOL, offsetof(objDef_t, isVirtual), MEMBER_SIZEOF(objDef_t, isVirtual)},
01454 
01455     {NULL, V_NULL, 0, 0}
01456 };
01457 
01458 /* =========================================================== */
01459 
01460 static const value_t fdps[] = {
01461     {"name", V_TRANSLATION_STRING, offsetof(fireDef_t, name), 0},
01462     {"shotorg", V_POS, offsetof(fireDef_t, shotOrg), MEMBER_SIZEOF(fireDef_t, shotOrg)},
01463     {"projtl", V_STRING, offsetof(fireDef_t, projectile), 0},
01464     {"impact", V_STRING, offsetof(fireDef_t, impact), 0},
01465     {"hitbody", V_STRING, offsetof(fireDef_t, hitBody), 0},
01466     {"firesnd", V_STRING, offsetof(fireDef_t, fireSound), 0},
01467     {"impsnd", V_STRING, offsetof(fireDef_t, impactSound), 0},
01468     {"bodysnd", V_STRING, offsetof(fireDef_t, hitBodySound), 0},
01469     {"bncsnd", V_STRING, offsetof(fireDef_t, bounceSound), 0},
01470     {"fireattenuation", V_FLOAT, offsetof(fireDef_t, fireAttenuation), MEMBER_SIZEOF(fireDef_t, fireAttenuation)},
01471     {"impactattenuation", V_FLOAT, offsetof(fireDef_t, impactAttenuation), MEMBER_SIZEOF(fireDef_t, impactAttenuation)},
01472     {"throughwall", V_INT, offsetof(fireDef_t, throughWall), MEMBER_SIZEOF(fireDef_t, throughWall)},
01473     {"sndonce", V_BOOL, offsetof(fireDef_t, soundOnce), MEMBER_SIZEOF(fireDef_t, soundOnce)},
01474     {"gravity", V_BOOL, offsetof(fireDef_t, gravity), MEMBER_SIZEOF(fireDef_t, gravity)},
01475     {"launched", V_BOOL, offsetof(fireDef_t, launched), MEMBER_SIZEOF(fireDef_t, launched)},
01476     {"rolled", V_BOOL, offsetof(fireDef_t, rolled), MEMBER_SIZEOF(fireDef_t, rolled)},
01477     {"reaction", V_BOOL, offsetof(fireDef_t, reaction), MEMBER_SIZEOF(fireDef_t, reaction)},
01478     {"delay", V_INT, offsetof(fireDef_t, delay), MEMBER_SIZEOF(fireDef_t, delay)},
01479     {"bounce", V_INT, offsetof(fireDef_t, bounce), MEMBER_SIZEOF(fireDef_t, bounce)},
01480     {"bncfac", V_FLOAT, offsetof(fireDef_t, bounceFac), MEMBER_SIZEOF(fireDef_t, bounceFac)},
01481     {"speed", V_FLOAT, offsetof(fireDef_t, speed), MEMBER_SIZEOF(fireDef_t, speed)},
01482     {"spread", V_POS, offsetof(fireDef_t, spread), MEMBER_SIZEOF(fireDef_t, spread)},
01483     {"crouch", V_FLOAT, offsetof(fireDef_t, crouch), MEMBER_SIZEOF(fireDef_t, crouch)},
01484     {"shots", V_INT, offsetof(fireDef_t, shots), MEMBER_SIZEOF(fireDef_t, shots)},
01485     {"ammo", V_INT, offsetof(fireDef_t, ammo), MEMBER_SIZEOF(fireDef_t, ammo)},
01486     {"delaybetweenshots", V_FLOAT, offsetof(fireDef_t, delayBetweenShots), MEMBER_SIZEOF(fireDef_t, delayBetweenShots)},
01487     {"time", V_INT, offsetof(fireDef_t, time), MEMBER_SIZEOF(fireDef_t, time)},
01488     {"damage", V_POS, offsetof(fireDef_t, damage), MEMBER_SIZEOF(fireDef_t, damage)},
01489     {"spldmg", V_POS, offsetof(fireDef_t, spldmg), MEMBER_SIZEOF(fireDef_t, spldmg)},
01490     {"dmgweight", V_DMGWEIGHT, offsetof(fireDef_t, dmgweight), MEMBER_SIZEOF(fireDef_t, dmgweight)},
01491     {"irgoggles", V_BOOL, offsetof(fireDef_t, irgoggles), MEMBER_SIZEOF(fireDef_t, irgoggles)},
01492     {NULL, 0, 0, 0}
01493 };
01494 
01495 
01496 static void Com_ParseFire (const char *name, const char **text, fireDef_t * fd)
01497 {
01498     const value_t *fdp;
01499     const char *errhead = "Com_ParseFire: unexpected end of file";
01500     const char *token;
01501 
01502     /* get its body */
01503     token = Com_Parse(text);
01504 
01505     if (!*text || *token != '{') {
01506         Com_Printf("Com_ParseFire: fire definition \"%s\" without body ignored\n", name);
01507         return;
01508     }
01509 
01510     do {
01511         token = Com_EParse(text, errhead, name);
01512         if (!*text)
01513             return;
01514         if (*token == '}')
01515             return;
01516 
01517         for (fdp = fdps; fdp->string; fdp++)
01518             if (!Q_strcasecmp(token, fdp->string)) {
01519                 /* found a definition */
01520                 token = Com_EParse(text, errhead, name);
01521                 if (!*text)
01522                     return;
01523 
01524                 Com_EParseValue(fd, token, fdp->type, fdp->ofs, fdp->size);
01525                 break;
01526             }
01527 
01528         if (!fdp->string) {
01529             if (!strncmp(token, "skill", 5)) {
01530                 int skill;
01531 
01532                 token = Com_EParse(text, errhead, name);
01533                 if (!*text)
01534                     return;
01535 
01536                 for (skill = ABILITY_NUM_TYPES; skill < SKILL_NUM_TYPES; skill++)
01537                     if (!strcmp(skillNames[skill], token)) {
01538                         fd->weaponSkill = skill;
01539                         break;
01540                     }
01541                 if (skill >= SKILL_NUM_TYPES)
01542                     Com_Printf("Com_ParseFire: unknown weapon skill \"%s\" ignored (weapon %s)\n", token, name);
01543             } else if (!strncmp(token, "range", 5)) {
01544                 token = Com_EParse(text, errhead, name);
01545                 if (!*text)
01546                     return;
01547                 fd->range = atof(token) * UNIT_SIZE;
01548             } else if (!strncmp(token, "splrad", 6)) {
01549                 token = Com_EParse(text, errhead, name);
01550                 if (!*text)
01551                     return;
01552                 fd->splrad = atof(token) * UNIT_SIZE;
01553             } else
01554                 Com_Printf("Com_ParseFire: unknown token \"%s\" ignored (weapon %s)\n", token, name);
01555         }
01556     } while (*text);
01557 
01558     if (fd->impactAttenuation < SOUND_ATTN_NONE || fd->impactAttenuation > SOUND_ATTN_MAX)
01559         Com_Printf("Com_ParseFire: firedef for weapon \"%s\" has an invalid impact sound attenuation value set\n", name);
01560 
01561     if (fd->fireAttenuation < SOUND_ATTN_NONE || fd->fireAttenuation > SOUND_ATTN_MAX)
01562         Com_Printf("Com_ParseFire: firedef for weapon \"%s\" has an invalid fire sound attenuation value set\n", name);
01563 
01564     if (fd->weaponSkill < ABILITY_NUM_TYPES)
01565         Com_Printf("Com_ParseFire: firedef for weapon \"%s\" doesn't have a skill set\n", name);
01566 }
01567 
01568 
01575 static void Com_ParseArmourOrResistance (const char *name, const char **text, short *ad, qboolean rating)
01576 {
01577     const char *errhead = "Com_ParseArmourOrResistance: unexpected end of file";
01578     const char *token;
01579     int i;
01580 
01581     /* get its body */
01582     token = Com_Parse(text);
01583 
01584     if (!*text || *token != '{') {
01585         Com_Printf("Com_ParseArmourOrResistance: armour definition \"%s\" without body ignored\n", name);
01586         return;
01587     }
01588 
01589     do {
01590         token = Com_EParse(text, errhead, name);
01591         if (!*text)
01592             return;
01593         if (*token == '}')
01594             return;
01595 
01596         for (i = 0; i < csi.numDTs; i++) {
01597             damageType_t *dt = &csi.dts[i];
01598             if (!strcmp(token, dt->id)) {
01599                 token = Com_EParse(text, errhead, name);
01600                 if (!*text)
01601                     return;
01602                 if (rating && !dt->showInMenu)
01603                     Sys_Error("Com_ParseArmourOrResistance: You try to set a rating value for a none menu displayed damage type '%s'",
01604                             dt->id);
01605                 /* protection or rating values */
01606                 ad[i] = atoi(token);
01607                 break;
01608             }
01609         }
01610 
01611         if (i >= csi.numDTs)
01612             Com_Printf("Com_ParseArmourOrResistance: unknown damage type \"%s\" ignored (in %s)\n", token, name);
01613     } while (*text);
01614 }
01615 
01616 
01621 const char *const air_slot_type_strings[] = {
01622     "base_missile",
01623     "base_laser",
01624     "weapon",
01625     "shield",
01626     "electronics",
01627     "pilot",
01628     "ammo",
01629     "base_ammo_missile",
01630     "base_ammo_laser"
01631 };
01632 CASSERT(lengthof(air_slot_type_strings) == MAX_ACITEMS);
01633 
01634 
01639 static linkedList_t *parseItemWeapons = NULL;
01640 
01645 static void Com_ParseItem (const char *name, const char **text)
01646 {
01647     const char *errhead = "Com_ParseItem: unexpected end of file (weapon ";
01648     const value_t *val;
01649     objDef_t *od;
01650     const char *token;
01651     int i;
01652     weaponFireDefIndex_t weapFdsIdx;
01653 
01654     /* search for items with same name */
01655     od = INVSH_GetItemByIDSilent(name);
01656     if (od != NULL) {
01657         Com_Printf("Com_ParseItem: weapon def \"%s\" with same name found, second ignored\n", name);
01658         return;
01659     }
01660 
01661     if (csi.numODs >= MAX_OBJDEFS)
01662         Sys_Error("Com_ParseItem: MAX_OBJDEFS exceeded\n");
01663 
01664     Com_DPrintf(DEBUG_SHARED, "...found item: '%s' (%i)\n", name, csi.numODs);
01665 
01666     /* initialize the object definition */
01667     od = &csi.ods[csi.numODs++];
01668     memset(od, 0, sizeof(*od));
01669 
01670     od->craftitem.type = MAX_ACITEMS; 
01672     Q_strncpyz(od->id, name, sizeof(od->id));
01673     if (od->id[0] == '\0')
01674         Sys_Error("Com_ParseItem: no id given\n");
01675 
01676     od->idx = csi.numODs - 1;
01677 
01678     /* get it's body */
01679     token = Com_Parse(text);
01680 
01681     if (!*text || *token != '{') {
01682         Com_Printf("Com_ParseItem: weapon def \"%s\" without body ignored\n", name);
01683         csi.numODs--;
01684         return;
01685     }
01686 
01687     do {
01688         token = Com_EParse(text, errhead, name);
01689         if (!*text)
01690             break;
01691         if (*token == '}')
01692             break;
01693 
01694         for (val = od_vals, i = 0; val->string; val++, i++) {
01695             if (!Q_strcasecmp(token, val->string)) {
01696                 /* found a definition */
01697                 if (val->type != V_NULL) {
01698                     /* parse a value */
01699                     token = Com_EParse(text, errhead, name);
01700                     if (!*text)
01701                         break;
01702 
01703                     if (Com_EParseValue(od, token, val->type, val->ofs, val->size) == -1)
01704                         Com_Printf("Com_ParseItem: Wrong size for value %s\n", val->string);
01705                 } else {
01706                     /* parse fire definitions */
01707                     switch (i) {
01708                     case OD_WEAPON:
01709                         /* Save the weapon id. */
01710                         token = Com_Parse(text);
01711                         if (od->numWeapons < MAX_WEAPONS_PER_OBJDEF) {
01712                             /* Store the current item-pointer and the weapon id for later linking of the "weapon" pointers */
01713                             LIST_AddPointer(&parseItemWeapons, od);
01714                             LIST_Add(&parseItemWeapons, (byte *)&od->numWeapons, sizeof(int));
01715                             LIST_AddString(&parseItemWeapons, token);
01716 
01717                             /* get it's body */
01718                             token = Com_Parse(text);
01719 
01720                             if (!*text || *token != '{') {
01721                                 Com_Printf("Com_ParseItem: weapon_mod \"%s\" without body ignored\n", name);
01722                                 break;
01723                             }
01724 
01725                             weapFdsIdx = od->numWeapons;
01726                             /* For parse each firedef entry for this weapon.  */
01727                             do {
01728                                 token = Com_EParse(text, errhead, name);
01729                                 if (!*text)
01730                                     return;
01731                                 if (*token == '}')
01732                                     break;
01733 
01734                                 if (!strcmp(token, "firedef")) {
01735                                     if (od->numFiredefs[weapFdsIdx] < MAX_FIREDEFS_PER_WEAPON) {
01736                                         const fireDefIndex_t fdIdx = od->numFiredefs[weapFdsIdx];
01737                                         od->fd[weapFdsIdx][fdIdx].fireAttenuation = SOUND_ATTN_NORM;
01738                                         od->fd[weapFdsIdx][fdIdx].impactAttenuation = SOUND_ATTN_NORM;
01739                                         /* Parse firemode into fd[IDXweapon][IDXfiremode] */
01740                                         Com_ParseFire(name, text, &od->fd[weapFdsIdx][fdIdx]);
01741                                         /* Self-link fd */
01742                                         od->fd[weapFdsIdx][fdIdx].fdIdx = fdIdx;
01743                                         /* Self-link weapon_mod */
01744                                         od->fd[weapFdsIdx][fdIdx].weapFdsIdx = weapFdsIdx;
01745                                         od->numFiredefs[od->numWeapons]++;
01746                                     } else {
01747                                         Com_Printf("Com_ParseItem: Too many firedefs at \"%s\". Max is %i\n", name, MAX_FIREDEFS_PER_WEAPON);
01748                                     }
01749                                 } else {
01750                                     Com_Printf("Unknown token '%s' - expected firedef\n", token);
01751                                 }
01752                             } while (*text);
01753                             od->numWeapons++;
01754                         } else {
01755                             Com_Printf("Com_ParseItem: Too many weapon_mod definitions at \"%s\". Max is %i\n", name, MAX_WEAPONS_PER_OBJDEF);
01756                         }
01757                         break;
01758                     case OD_PROTECTION:
01759                         Com_ParseArmourOrResistance(name, text, od->protection, qfalse);
01760                         break;
01761                     case OD_RATINGS:
01762                         Com_ParseArmourOrResistance(name, text, od->ratings, qtrue);
01763                         break;
01764                     default:
01765                         break;
01766                     }
01767                 }
01768                 break;
01769             }
01770         }
01771         if (!val->string) {
01772             if (!strcmp(token, "craftweapon")) {
01773                 /* parse a value */
01774                 token = Com_EParse(text, errhead, name);
01775                 if (od->numWeapons < MAX_WEAPONS_PER_OBJDEF) {
01777                     LIST_AddPointer(&parseItemWeapons, od);
01778                     LIST_Add(&parseItemWeapons, (byte *)&od->numWeapons, sizeof(int));
01779                     LIST_AddString(&parseItemWeapons, token);
01780                     od->numWeapons++;
01781                 } else {
01782                     Com_Printf("Com_ParseItem: Too many weapon_mod definitions at \"%s\". Max is %i\n", name, MAX_WEAPONS_PER_OBJDEF);
01783                 }
01784             } else if (!strcmp(token, "crafttype")) {
01785                 /* Craftitem type definition. */
01786                 token = Com_EParse(text, errhead, name);
01787                 if (!*text)
01788                     return;
01789 
01790                 /* Check which type it is and store the correct one.*/
01791                 for (i = 0; i < MAX_ACITEMS; i++) {
01792                     if (!strcmp(token, air_slot_type_strings[i])) {
01793                         od->craftitem.type = i;
01794                         break;
01795                     }
01796                 }
01797                 if (i == MAX_ACITEMS)
01798                     Com_Printf("AII_ParseAircraftItem: \"%s\" unknown craftitem type: \"%s\" - ignored.\n", name, token);
01799             } else
01800                 Com_Printf("Com_ParseItem: unknown token \"%s\" ignored (weapon %s)\n", token, name);
01801         }
01802 
01803     } while (*text);
01804 
01805     /* get size */
01806     for (i = SHAPE_SMALL_MAX_WIDTH - 1; i >= 0; i--)
01807         if (od->shape & (0x01010101 << i))
01808             break;
01809     od->sx = i + 1;
01810 
01811     for (i = SHAPE_SMALL_MAX_HEIGHT - 1; i >= 0; i--)
01812         if (od->shape & (0xFF << (i * SHAPE_SMALL_MAX_WIDTH)))
01813             break;
01814     od->sy = i + 1;
01815 }
01816 
01817 
01818 /*
01819 ==============================================================================
01820 INVENTORY DEFINITION INTERPRETER
01821 ==============================================================================
01822 */
01823 
01824 static const value_t idps[] = {
01825     {"shape", V_SHAPE_BIG, offsetof(invDef_t, shape), 0},
01826     /* only a single item */
01827     {"single", V_BOOL, offsetof(invDef_t, single), MEMBER_SIZEOF(invDef_t, single)},
01828     /* Scrollable container */
01829     {"scroll", V_BOOL, offsetof(invDef_t, scroll), MEMBER_SIZEOF(invDef_t, scroll)},
01830     /* only a single item as weapon extension - single should be set, too */
01831     {"extension", V_BOOL, offsetof(invDef_t, extension), MEMBER_SIZEOF(invDef_t, extension)},
01832     /* this is the armour container */
01833     {"armour", V_BOOL, offsetof(invDef_t, armour), MEMBER_SIZEOF(invDef_t, armour)},
01834     /* this is the headgear container */
01835     {"headgear", V_BOOL, offsetof(invDef_t, headgear), MEMBER_SIZEOF(invDef_t, headgear)},
01836     /* allow everything to be stored in this container (e.g armour and weapons) */
01837     {"all", V_BOOL, offsetof(invDef_t, all), MEMBER_SIZEOF(invDef_t, all)},
01838     {"temp", V_BOOL, offsetof(invDef_t, temp), MEMBER_SIZEOF(invDef_t, temp)},
01839     /* time units for moving something in */
01840     {"in", V_INT, offsetof(invDef_t, in), MEMBER_SIZEOF(invDef_t, in)},
01841     /* time units for moving something out */
01842     {"out", V_INT, offsetof(invDef_t, out), MEMBER_SIZEOF(invDef_t, out)},
01843 
01844     {NULL, 0, 0, 0}
01845 };
01846 
01847 static void Com_ParseInventory (const char *name, const char **text)
01848 {
01849     const char *errhead = "Com_ParseInventory: unexpected end of file (inventory ";
01850     invDef_t *id;
01851     const value_t *idp;
01852     const char *token;
01853     int i;
01854 
01855     /* search for containers with same name */
01856     for (i = 0; i < csi.numIDs; i++)
01857         if (!strncmp(name, csi.ids[i].name, sizeof(csi.ids[i].name)))
01858             break;
01859 
01860     if (i < csi.numIDs) {
01861         Com_Printf("Com_ParseInventory: inventory def \"%s\" with same name found, second ignored\n", name);
01862         return;
01863     }
01864 
01865     if (i >= MAX_INVDEFS) {
01866         Sys_Error("Too many inventory definitions - max allowed: %i\n", MAX_INVDEFS);
01867         return; /* never reached */
01868     }
01869 
01870     /* initialize the inventory definition */
01871     id = &csi.ids[csi.numIDs++];
01872     memset(id, 0, sizeof(*id));
01873 
01874     Q_strncpyz(id->name, name, sizeof(id->name));
01875 
01876     /* get it's body */
01877     token = Com_Parse(text);
01878 
01879     if (!*text || *token != '{') {
01880         Com_Printf("Com_ParseInventory: inventory def \"%s\" without body ignored\n", name);
01881         csi.numIDs--;
01882         return;
01883     }
01884 
01885     /* Special IDs for container. These are also used elsewhere, so be careful. */
01886     if (!strcmp(name, "right")) {
01887         csi.idRight = id - csi.ids;
01888         id->id = csi.idRight;
01889     } else if (!strcmp(name, "left")) {
01890         csi.idLeft = id - csi.ids;
01891         id->id = csi.idLeft;
01892     } else if (!strcmp(name, "extension")) {
01893         csi.idExtension = id - csi.ids;
01894         id->id = csi.idExtension;
01895     } else if (!strcmp(name, "belt")) {
01896         csi.idBelt = id - csi.ids;
01897         id->id = csi.idBelt;
01898     } else if (!strcmp(name, "holster")) {
01899         csi.idHolster = id - csi.ids;
01900         id->id = csi.idHolster;
01901     } else if (!strcmp(name, "backpack")) {
01902         csi.idBackpack = id - csi.ids;
01903         id->id = csi.idBackpack;
01904     } else if (!strcmp(name, "armour")) {
01905         csi.idArmour = id - csi.ids;
01906         id->id = csi.idArmour;
01907     } else if (!strcmp(name, "floor")) {
01908         csi.idFloor = id - csi.ids;
01909         id->id = csi.idFloor;
01910     } else if (!strcmp(name, "equip")) {
01911         csi.idEquip = id - csi.ids;
01912         id->id = csi.idEquip;
01913     } else if (!strcmp(name, "headgear")) {
01914         csi.idHeadgear = id - csi.ids;
01915         id->id = csi.idHeadgear;
01916     }
01917 
01918     do {
01919         token = Com_EParse(text, errhead, name);
01920         if (!*text)
01921             return;
01922         if (*token == '}')
01923             return;
01924 
01925         for (idp = idps; idp->string; idp++)
01926             if (!Q_strcasecmp(token, idp->string)) {
01927                 /* found a definition */
01928                 token = Com_EParse(text, errhead, name);
01929                 if (!*text)
01930                     return;
01931 
01932                 Com_EParseValue(id, token, idp->type, idp->ofs, idp->size);
01933                 break;
01934             }
01935 
01936         if (!idp->string)
01937             Com_Printf("Com_ParseInventory: unknown token \"%s\" ignored (inventory %s)\n", token, name);
01938 
01939     } while (*text);
01940 }
01941 
01942 
01943 /*
01944 ==============================================================================
01945 EQUIPMENT DEFINITION INTERPRETER
01946 ==============================================================================
01947 */
01948 
01949 typedef enum model_script_s {
01950     MODEL_PATH,
01951     MODEL_BODY,
01952     MODEL_HEAD,
01953     MODEL_SKIN,
01954 
01955     MODEL_NUM_TYPES
01956 } model_script_t;
01957 
01958 const char *const name_strings[NAME_NUM_TYPES] = {
01959     "neutral",
01960     "female",
01961     "male",
01962     "lastname",
01963     "female_lastname",
01964     "male_lastname"
01965 };
01966 
01968 static const value_t equipment_definition_vals[] = {
01969     {"mininterest", V_INT, offsetof(equipDef_t, minInterest), 0},
01970     {"maxinterest", V_INT, offsetof(equipDef_t, maxInterest), 0},
01971 
01972     {NULL, 0, 0, 0}
01973 };
01974 
01975 static void Com_ParseEquipment (const char *name, const char **text)
01976 {
01977     const char *errhead = "Com_ParseEquipment: unexpected end of file (equipment ";
01978     equipDef_t *ed;
01979     const char *token;
01980     const value_t *vp;
01981     int i, n;
01982 
01983     /* search for equipments with same name */
01984     for (i = 0; i < csi.numEDs; i++)
01985         if (!strcmp(name, csi.eds[i].name))
01986             break;
01987 
01988     if (i < csi.numEDs) {
01989         Com_Printf("Com_ParseEquipment: equipment def \"%s\" with same name found, second ignored\n", name);
01990         return;
01991     }
01992 
01993     if (i >= MAX_EQUIPDEFS)
01994         Sys_Error("Com_ParseEquipment: MAX_EQUIPDEFS exceeded\n");
01995 
01996     /* initialize the equipment definition */
01997     ed = &csi.eds[csi.numEDs++];
01998     memset(ed, 0, sizeof(*ed));
01999 
02000     Q_strncpyz(ed->name, name, sizeof(ed->name));
02001 
02002     /* get it's body */
02003     token = Com_Parse(text);
02004 
02005     if (!*text || *token != '{') {
02006         Com_Printf("Com_ParseEquipment: equipment def \"%s\" without body ignored\n", name);
02007         csi.numEDs--;
02008         return;
02009     }
02010 
02011     do {
02012         token = Com_EParse(text, errhead, name);
02013         if (!*text || *token == '}')
02014             return;
02015 
02016         for (vp = equipment_definition_vals; vp->string; vp++)
02017             if (!strcmp(token, vp->string)) {
02018                 /* found a definition */
02019                 token = Com_EParse(text, errhead, name);
02020                 if (!*text)
02021                     return;
02022                 Com_EParseValue(ed, token, vp->type, vp->ofs, vp->size);
02023                 break;
02024             }
02025 
02026         if (!vp->string) {
02027             if (!strcmp(token, "item")) {
02028                 objDef_t *od;
02029                 token = Com_EParse(text, errhead, name);
02030                 if (!*text || *token == '}')
02031                     Sys_Error("Invalid item token in equipment definition: %s", ed->name);
02032 
02033                 od = INVSH_GetItemByID(token);
02034                 if (od) {
02035                     token = Com_EParse(text, errhead, name);
02036                     if (!*text || *token == '}') {
02037                         Com_Printf("Com_ParseEquipment: unexpected end of equipment def \"%s\"\n", name);
02038                         return;
02039                     }
02040                     n = atoi(token);
02041                     if (ed->numItems[od->idx])
02042                         Com_Printf("Com_ParseEquipment: item '%s' is used several times in def '%s'. Only last entry will be taken into account.\n",
02043                             od->id, name);
02044                     if (n)
02045                         ed->numItems[od->idx] = n;
02046                 } else {
02047                     Com_Printf("Com_ParseEquipment: unknown token \"%s\" ignored (equipment %s)\n", token, name);
02048                 }
02049             } else if (!strcmp(token, "aircraft")) {
02050                 humanAircraftType_t type;
02051                 token = Com_EParse(text, errhead, name);
02052                 if (!*text || *token == '}')
02053                     Sys_Error("Invalid aircraft token in equipment definition: %s", ed->name);
02054 
02055                 type = Com_DropShipShortNameToID(token);
02056                 token = Com_EParse(text, errhead, name);
02057                 if (!*text || *token == '}') {
02058                     Com_Printf("Com_ParseEquipment: unexpected end of equipment def \"%s\"\n", name);
02059                     return;
02060                 }
02061                 n = atoi(token);
02062                 if (ed->numAircraft[type])
02063                     Com_Printf("Com_ParseEquipment: aircraft type '%i' is used several times in def '%s'. Only last entry will be taken into account.\n",
02064                         type, name);
02065                 if (n)
02066                     ed->numAircraft[type] = n;
02067             } else {
02068                 Sys_Error("unknown token in equipment in definition %s: '%s'", ed->name, token);
02069             }
02070         }
02071     } while (*text);
02072 }
02073 
02074 
02075 /*
02076 ==============================================================================
02077 NAME AND TEAM DEFINITION INTERPRETER
02078 ==============================================================================
02079 */
02080 
02086 static const char *Com_GiveName (int gender, const teamDef_t *td)
02087 {
02088     int j, name = 0;
02089     linkedList_t* list;
02090 
02091 #ifdef DEBUG
02092     for (j = 0; j < NAME_NUM_TYPES; j++)
02093         name += td->numNames[j];
02094     if (!name)
02095         Sys_Error("Could not find any valid name definitions for category '%s'\n", td->id);
02096 #endif
02097     /* found category */
02098     if (!td->numNames[gender]) {
02099 #ifdef DEBUG
02100         Com_DPrintf(DEBUG_ENGINE, "No valid name definitions for gender %i in category '%s'\n", gender, td->id);
02101 #endif
02102         return NULL;
02103     }
02104     name = rand() % td->numNames[gender];
02105 
02106     /* skip names */
02107     list = td->names[gender];
02108     for (j = 0; j < name; j++) {
02109         assert(list);
02110         list = list->next;
02111     }
02112 
02113     /* store the name */
02114     return (const char*)list->data;
02115 }
02116 
02123 static const char *Com_GiveModel (int type, int gender, const teamDef_t *td)
02124 {
02125     int j;
02126 
02127     const linkedList_t* list;
02128     /* search one of the model definitions and (the +) go to the type entry from team_*.ufo  */
02129     const int num = (rand() % td->numModels[gender]) * MODEL_NUM_TYPES + type;
02130 
02131     /* found category */
02132     if (!td->numModels[gender]) {
02133         Com_Printf("Com_GiveModel: no models defined for gender %i and category '%s'\n", gender, td->id);
02134         return NULL;
02135     }
02136 
02137     /* skip models and unwanted info */
02138     list = td->models[gender];
02139     for (j = 0; j < num; j++) {
02140         assert(list);
02141         list = list->next;
02142     }
02143 
02144     /* return the value */
02145     return (const char*)list->data;
02146 }
02147 
02154 const char* Com_GetActorSound (teamDef_t* td, int gender, actorSound_t soundType)
02155 {
02156     int random, j;
02157     linkedList_t* list;
02158 
02159     if (!td)
02160         return NULL;
02161 
02162     if (gender < 0 || gender >= NAME_LAST) {
02163         Com_DPrintf(DEBUG_SOUND|DEBUG_CLIENT, "Com_GetActorSound: invalid gender: %i\n", gender);
02164         return NULL;
02165     }
02166     if (td->numSounds[soundType][gender] <= 0) {
02167         Com_DPrintf(DEBUG_SOUND|DEBUG_CLIENT, "Com_GetActorSound: no sound defined for soundtype: %i, teamID: '%s', gender: %i\n", soundType, td->id, gender);
02168         return NULL;
02169     }
02170 
02171     random = rand() % td->numSounds[soundType][gender];
02172     list = td->sounds[soundType][gender];
02173     for (j = 0; j < random; j++) {
02174         assert(list);
02175         list = list->next;
02176     }
02177 
02178     assert(list);
02179     assert(list->data);
02180     return (const char*)list->data;
02181 }
02182 
02188 teamDef_t* Com_GetTeamDefinitionByID (const char *team)
02189 {
02190     int i;
02191 
02192     /* get team definition */
02193     for (i = 0; i < csi.numTeamDefs; i++)
02194         if (!strcmp(team, csi.teamDef[i].id))
02195             return &csi.teamDef[i];
02196 
02197     Com_Printf("Com_GetTeamDefinitionByID: could not find team definition for '%s' in team definitions\n", team);
02198     return NULL;
02199 }
02200 
02208 void Com_GetCharacterValues (const char *teamDefition, character_t * chr)
02209 {
02210     int retry = 1000;
02211 
02212     assert(chr);
02213 
02214     chr->teamDef = Com_GetTeamDefinitionByID(teamDefition);
02215     if (chr->teamDef == NULL)
02216         Com_Error(ERR_DROP, "Com_GetCharacterValues: could not find team '%s' in team definitions", teamDefition);
02217 
02218     if (chr->teamDef->size != ACTOR_SIZE_INVALID)
02219         chr->fieldSize = chr->teamDef->size;
02220     else
02221         chr->fieldSize = ACTOR_SIZE_NORMAL;
02222 
02223     /* get the models */
02224     while (retry--) {
02225         const char *str;
02226         const int gender = rand() % NAME_LAST;
02227 
02228         chr->gender = gender;
02229 
02230         /* get name */
02231         str = Com_GiveName(gender, chr->teamDef);
02232         if (!str)
02233             continue;
02234         Q_strncpyz(chr->name, str, sizeof(chr->name));
02235         Q_strcat(chr->name, " ", sizeof(chr->name));
02236         str = Com_GiveName(gender + NAME_LAST, chr->teamDef);
02237         if (!str)
02238             continue;
02239         Q_strcat(chr->name, str, sizeof(chr->name));
02240 
02241         /* get model */
02242         str = Com_GiveModel(MODEL_PATH, gender, chr->teamDef);
02243         if (!str)
02244             continue;
02245         Q_strncpyz(chr->path, str, sizeof(chr->path));
02246 
02247         str = Com_GiveModel(MODEL_BODY, gender, chr->teamDef);
02248         if (!str)
02249             continue;
02250         Q_strncpyz(chr->body, str, sizeof(chr->body));
02251 
02252         str = Com_GiveModel(MODEL_HEAD, gender, chr->teamDef);
02253         if (!str)
02254             continue;
02255         Q_strncpyz(chr->head, str, sizeof(chr->head));
02256 
02257         str = Com_GiveModel(MODEL_SKIN, gender, chr->teamDef);
02258         if (!str)
02259             continue;
02260         chr->skin = atoi(str);
02261         return;
02262     }
02263     Com_Error(ERR_DROP, "Could not set character values for team '%s'\n", teamDefition);
02264 }
02265 
02271 static void Com_ParseActorNames (const char *name, const char **text, teamDef_t* td)
02272 {
02273     const char *errhead = "Com_ParseNames: unexpected end of file (names ";
02274     const char *token;
02275     int i;
02276 
02277     /* get name list body body */
02278     token = Com_Parse(text);
02279 
02280     if (!*text || *token != '{') {
02281         Com_Printf("Com_ParseActorNames: names def \"%s\" without body ignored\n", name);
02282         return;
02283     }
02284 
02285     do {
02286         /* get the name type */
02287         token = Com_EParse(text, errhead, name);
02288         if (!*text)
02289             break;
02290         if (*token == '}')
02291             break;
02292 
02293         for (i = 0; i < NAME_NUM_TYPES; i++)
02294             if (!strcmp(token, name_strings[i])) {
02295                 td->numNames[i] = 0;
02296 
02297                 token = Com_EParse(text, errhead, name);
02298                 if (!*text)
02299                     break;
02300                 if (*token != '{')
02301                     break;
02302 
02303                 do {
02304                     /* get a name */
02305                     token = Com_EParse(text, errhead, name);
02306                     if (!*text)
02307                         break;
02308                     if (*token == '}')
02309                         break;
02310 
02311                     /* some names can be translatable */
02312                     if (*token == '_')
02313                         token++;
02314                     LIST_AddString(&td->names[i], token);
02315                     td->numNames[i]++;
02316                 } while (*text);
02317 
02318                 /* lastname is different */
02319                 /* fill female and male lastnames from neutral lastnames */
02320                 if (i == NAME_LAST)
02321                     for (i = NAME_NUM_TYPES - 1; i > NAME_LAST; i--) {
02322                         td->names[i] = td->names[NAME_LAST];
02323                         td->numNames[i] = td->numNames[NAME_LAST];
02324                     }
02325                 break;
02326             }
02327 
02328         if (i == NAME_NUM_TYPES)
02329             Com_Printf("Com_ParseNames: unknown token \"%s\" ignored (names %s)\n", token, name);
02330 
02331     } while (*text);
02332 
02333     if (td->numNames[NAME_FEMALE] && !td->numNames[NAME_FEMALE_LAST])
02334         Sys_Error("Com_ParseNames: '%s' has no female lastname category\n", td->id);
02335     if (td->numNames[NAME_MALE] && !td->numNames[NAME_MALE_LAST])
02336         Sys_Error("Com_ParseNames: '%s' has no male lastname category\n", td->id);
02337     if (td->numNames[NAME_NEUTRAL] && !td->numNames[NAME_LAST])
02338         Sys_Error("Com_ParseNames: '%s' has no neutral lastname category\n", td->id);
02339 }
02340 
02346 static void Com_ParseActorModels (const char *name, const char **text, teamDef_t* td)
02347 {
02348     const char *errhead = "Com_ParseActorModels: unexpected end of file (actors ";
02349     const char *token;
02350     int i, j;
02351 
02352     /* get name list body body */
02353     token = Com_Parse(text);
02354 
02355     if (!*text || *token != '{') {
02356         Com_Printf("Com_ParseActorModels: actor def \"%s\" without body ignored\n", td->id);
02357         return;
02358     }
02359 
02360     do {
02361         /* get the name type */
02362         token = Com_EParse(text, errhead, name);
02363         if (!*text)
02364             break;
02365         if (*token == '}')
02366             break;
02367 
02368         for (i = 0; i < NAME_NUM_TYPES; i++)
02369             if (!strcmp(token, name_strings[i])) {
02370                 if (td->numModels[i])
02371                     Sys_Error("Com_ParseActorModels: Already parsed models for actor definition '%s'\n", name);
02372                 td->numModels[i] = 0;
02373                 token = Com_EParse(text, errhead, name);
02374                 if (!*text)
02375                     break;
02376                 if (*token != '{') {
02377                     Com_Printf("Com_ParseActorModels: Empty model definition '%s' for gender '%s'\n", name, name_strings[i]);
02378                     break;
02379                 }
02380 
02381                 do {
02382                     /* get the path, body, head and skin */
02383                     for (j = 0; j < 4; j++) {
02384                         token = Com_EParse(text, errhead, name);
02385                         if (!*text) {
02386                             Com_Printf("Com_ParseActors: Premature end of script at j=%i\n", j);
02387                             break;
02388                         }
02389                         if (*token == '}')
02390                             break;
02391 
02392                         if (j == 3 && *token == '*')
02393                             LIST_AddString(&td->models[i], "");
02394                         else
02395                             LIST_AddString(&td->models[i], token);
02396                     }
02397                     /* first token was '}' */
02398                     if (j == 0)
02399                         break;
02400 
02401                     /* only add complete actor info */
02402                     if (j == 4)
02403                         td->numModels[i]++;
02404                     else {
02405                         Com_Printf("Com_ParseActors: Incomplete actor data: '%s' - j: %i\n", td->id, j);
02406                         break;
02407                     }
02408                 } while (*text);
02409                 if (!td->numModels[i])
02410                     Com_Printf("Com_ParseActors: actor definition '%s' with no models (gender: %s)\n", name, name_strings[i]);
02411                 break;
02412             }
02413 
02414         if (i == NAME_NUM_TYPES)
02415             Com_Printf("Com_ParseActors: unknown token \"%s\" ignored (actors %s)\n", token, name);
02416 
02417     } while (*text);
02418 }
02419 
02425 static void Com_ParseActorSounds (const char *name, const char **text, teamDef_t* td)
02426 {
02427     const char *const errhead = "Com_ParseActorSounds: unexpected end of file (actorsounds ";
02428     const char *token;
02429     int i;
02430 
02431     /* get name list body body */
02432     token = Com_Parse(text);
02433 
02434     if (!*text || *token != '{') {
02435         Com_Printf("Com_ParseActorSounds: actorsounds def \"%s\" without body ignored\n", name);
02436         return;
02437     }
02438 
02439     do {
02440         /* get the name type */
02441         token = Com_EParse(text, errhead, name);
02442         if (!*text)
02443             break;
02444         if (*token == '}')
02445             break;
02446 
02447         for (i = 0; i < NAME_LAST; i++)
02448             if (!strcmp(token, name_strings[i])) {
02449                 token = Com_EParse(text, errhead, name);
02450                 if (!*text)
02451                     break;
02452                 if (*token != '{')
02453                     break;
02454 
02455                 do {
02456                     /* get the sounds */
02457                     token = Com_EParse(text, errhead, name);
02458                     if (!*text)
02459                         break;
02460                     if (*token == '}')
02461                         break;
02462                     if (!strcmp(token, "hurtsound")) {
02463                         token = Com_EParse(text, errhead, name);
02464                         if (!*text)
02465                             break;
02466                         LIST_AddString(&td->sounds[SND_HURT][i], token);
02467                         td->numSounds[SND_HURT][i]++;
02468                     } else if (!strcmp(token, "deathsound")) {
02469                         token = Com_EParse(text, errhead, name);
02470                         if (!*text)
02471                             break;
02472                         LIST_AddString(&td->sounds[SND_DEATH][i], token);
02473                         td->numSounds[SND_DEATH][i]++;
02474                     } else {
02475                         Com_Printf("Com_ParseActorSounds: unknown token \"%s\" ignored (actorsounds %s)\n", token, name);
02476                     }
02477                 } while (*text);
02478                 break; /* next gender sound definition */
02479             }
02480 
02481         if (i == NAME_NUM_TYPES)
02482             Com_Printf("Com_ParseActorSounds: unknown token \"%s\" ignored (actorsounds %s)\n", token, name);
02483 
02484     } while (*text);
02485 }
02486 
02488 static const value_t teamDefValues[] = {
02489     {"tech", V_STRING, offsetof(teamDef_t, tech), 0}, 
02490     {"name", V_TRANSLATION_STRING, offsetof(teamDef_t, name), 0}, 
02491     {"armour", V_BOOL, offsetof(teamDef_t, armour), MEMBER_SIZEOF(teamDef_t, armour)}, 
02492     {"weapons", V_BOOL, offsetof(teamDef_t, weapons), MEMBER_SIZEOF(teamDef_t, weapons)}, 
02493     {"size", V_INT, offsetof(teamDef_t, size), MEMBER_SIZEOF(teamDef_t, size)}, 
02494     {"hit_particle", V_STRING, offsetof(teamDef_t, hitParticle), 0}, 
02495     {"death_texture", V_STRING, offsetof(teamDef_t, deathTextureName), 0},
02496     {"race", V_RACE, offsetof(teamDef_t, race), MEMBER_SIZEOF(teamDef_t, race)},
02497 
02498     {NULL, 0, 0, 0}
02499 };
02500 
02501 static void Com_ParseTeam (const char *name, const char **text)
02502 {
02503     teamDef_t *td;
02504     const char *errhead = "Com_ParseTeam: unexpected end of file (team ";
02505     const char *token;
02506     int i;
02507     const value_t *v;
02508 
02509     /* check for additions to existing name categories */
02510     for (i = 0, td = csi.teamDef; i < csi.numTeamDefs; i++, td++)
02511         if (!strcmp(td->id, name))
02512             break;
02513 
02514     /* reset new category */
02515     if (i == csi.numTeamDefs) {
02516         if (csi.numTeamDefs < MAX_TEAMDEFS) {
02517             memset(td, 0, sizeof(*td));
02518             /* index backlink */
02519             td->idx = csi.numTeamDefs;
02520             csi.numTeamDefs++;
02521         } else {
02522             Com_Printf("CL_ParseTeam: Too many team definitions, '%s' ignored.\n", name);
02523             return;
02524         }
02525     } else {
02526         Com_Printf("CL_ParseTeam: Team with same name found, second ignored '%s'\n", name);
02527         FS_SkipBlock(text);
02528         return;
02529     }
02530 
02531     Q_strncpyz(td->id, name, sizeof(td->id));
02532     td->armour = td->weapons = qtrue; /* default values */
02533     td->onlyWeapon = NULL;
02534 
02535     /* get name list body body */
02536     token = Com_Parse(text);
02537 
02538     if (!*text || *token != '{') {
02539         Com_Printf("Com_ParseTeam: team def \"%s\" without body ignored\n", name);
02540         if (csi.numTeamDefs - 1 == td - csi.teamDef)
02541             csi.numTeamDefs--;
02542         return;
02543     }
02544 
02545     do {
02546         /* get the name type */
02547         token = Com_EParse(text, errhead, name);
02548         if (!*text)
02549             break;
02550         if (*token == '}')
02551             break;
02552 
02553         for (v = teamDefValues; v->string; v++)
02554             if (!strncmp(token, v->string, strlen(token))) {
02555                 /* found a definition */
02556                 token = Com_EParse(text, errhead, name);
02557                 if (!*text)
02558                     return;
02559 
02560                 Com_EParseValue(td, token, v->type, v->ofs, v->size);
02561                 break;
02562             }
02563 
02564         if (!v->string) {
02565             if (!strcmp(token, "onlyWeapon")) {
02566                 objDef_t *od;
02567                 token = Com_EParse(text, errhead, name);
02568                 if (!*text)
02569                     return;
02570                 od = INVSH_GetItemByID(token);
02571 
02572                 if (od)
02573                     td->onlyWeapon = od;
02574                 else
02575                     Sys_Error("Com_ParseTeam: Could not get item definition for '%s'", token);
02576             } else if (!strcmp(token, "templates")) {
02577                 token = Com_EParse(text, errhead, name);
02578                 if (!*text || *token != '{')
02579                     Com_Printf("Com_ParseTeam: template list without body ignored in team def \"%s\" \n", name);
02580                 else {
02581                     do {
02582                         token = Com_EParse(text, errhead, name);
02583                         if (*token == '}')
02584                             break;
02585                         for (i = 0; i < td->numTemplates; i++) {
02586                             if (!strcmp(token, td->characterTemplates[i]->id)) {
02587                                 Com_Printf("Com_ParseTeam: template %s used more than once in team def %s second ignored", token, name);
02588                                 break;
02589                             }
02590                         }
02591                         if (i >= td->numTemplates) {
02592                             const chrTemplate_t *ct = Com_GetCharacterTemplateByID(token);
02593                             if (ct)
02594                                 td->characterTemplates[td->numTemplates++] = ct;
02595                             else
02596                                 Sys_Error("Com_ParseTeam: Could not get character template for '%s' in %s", token, name);
02597                         } else
02598                             break;
02599                     } while (*text);
02600                 }
02601             } else if (!strcmp(token, "models"))
02602                 Com_ParseActorModels(name, text, td);
02603             else if (!strcmp(token, "names"))
02604                 Com_ParseActorNames(name, text, td);
02605             else if (!strcmp(token, "actorsounds"))
02606                 Com_ParseActorSounds(name, text, td);
02607             else if (!strcmp(token, "resistance"))
02608                 Com_ParseArmourOrResistance(name, text, td->resistance, qfalse);
02609             else
02610                 Com_Printf("Com_ParseTeam: unknown token \"%s\" ignored (team %s)\n", token, name);
02611         }
02612     } while (*text);
02613 
02614     if (td->deathTextureName[0] == '\0') {
02615         const int i = rand() % MAX_DEATH;
02616         Q_strncpyz(td->deathTextureName, va("pics/sfx/blood_%i", i), sizeof(td->deathTextureName));
02617         Com_DPrintf(DEBUG_CLIENT, "Using random blood for teamdef: '%s' (%i)\n", td->id, i);
02618     }
02619 }
02620 
02626 const chrTemplate_t* Com_GetCharacterTemplateByID (const char *chrTemplate)
02627 {
02628     int i;
02629 
02630     /* get character template */
02631     for (i = 0; i < csi.numChrTemplates; i++)
02632         if (!strcmp(chrTemplate, csi.chrTemplates[i].id))
02633             return &csi.chrTemplates[i];
02634 
02635     Com_Printf("Com_GetCharacterTemplateByID: could not find character template: '%s'\n", chrTemplate);
02636     return NULL;
02637 }
02638 
02639 static const value_t ugvValues[] = {
02640     {"tu", V_INT, offsetof(ugv_t, tu), MEMBER_SIZEOF(ugv_t, tu)},
02641     {"weapon", V_STRING, offsetof(ugv_t, weapon), 0},
02642     {"armour", V_STRING, offsetof(ugv_t, armour), 0},
02643     {"actors", V_STRING, offsetof(ugv_t, actors), 0},
02644     {"price", V_INT, offsetof(ugv_t, price), 0},
02645 
02646     {NULL, 0, 0, 0}
02647 };
02648 
02653 static void Com_ParseUGVs (const char *name, const char **text)
02654 {
02655     const char *errhead = "Com_ParseUGVs: unexpected end of file (ugv ";
02656     const char *token;
02657     const value_t *v;
02658     ugv_t *ugv;
02659     int i;
02660 
02661     /* get name list body body */
02662     token = Com_Parse(text);
02663 
02664     if (!*text || *token != '{') {
02665         Com_Printf("Com_ParseUGVs: ugv \"%s\" without body ignored\n", name);
02666         return;
02667     }
02668 
02669     for (i = 0; i < csi.numUGV; i++) {
02670         if (!strcmp(name, csi.ugvs[i].id)) {
02671             Com_Printf("Com_ParseUGVs: ugv \"%s\" with same name already loaded\n", name);
02672             return;
02673         }
02674     }
02675 
02676     /* parse ugv */
02677     if (csi.numUGV >= MAX_UGV) {
02678         Com_Printf("Com_ParseUGVs: Too many UGV descriptions, '%s' ignored.\n", name);
02679         return;
02680     }
02681 
02682     ugv = &csi.ugvs[csi.numUGV];
02683     memset(ugv, 0, sizeof(*ugv));
02684     ugv->id = Mem_PoolStrDup(name, com_genericPool, 0);
02685     ugv->idx = csi.numUGV;
02686     csi.numUGV++;
02687 
02688     do {
02689         /* get the name type */
02690         token = Com_EParse(text, errhead, name);
02691         if (!*text)
02692             break;
02693         if (*token == '}')
02694             break;
02695         for (v = ugvValues; v->string; v++)
02696             if (!strncmp(token, v->string, sizeof(v->string))) {
02697                 /* found a definition */
02698                 token = Com_EParse(text, errhead, name);
02699                 if (!*text)
02700                     return;
02701                 Com_EParseValue(ugv, token, v->type, v->ofs, v->size);
02702                 break;
02703             }
02704             if (!v->string)
02705                 Com_Printf("Com_ParseUGVs: unknown token \"%s\" ignored (ugv %s)\n", token, name);
02706     } while (*text);
02707 }
02708 
02712 static void Com_ParseCharacterTemplate (const char *name, const char **text)
02713 {
02714     const char *errhead = "Com_ParseCharacterTemplate: unexpected end of file";
02715     const char *token;
02716     chrTemplate_t *ct;
02717     int i;
02718 
02719     for (i = 0; i < csi.numChrTemplates; i++)
02720         if (!strcmp(name, csi.chrTemplates[i].id)) {
02721             Com_Printf("Com_ParseCharacterTemplate: Template with same name found, second ignored '%s'\n", name);
02722             return;
02723         }
02724 
02725     if (i >= MAX_CHARACTER_TEMPLATES)
02726         Sys_Error("Com_ParseCharacterTemplate: too many character templates\n");
02727 
02728     /* initialize the character template */
02729     ct = &csi.chrTemplates[csi.numChrTemplates++];
02730     memset(ct, 0, sizeof(*ct));
02731 
02732     Q_strncpyz(ct->id, name, sizeof(ct->id));
02733 
02734     token = Com_Parse(text);
02735 
02736     if (!*text || *token != '{') {
02737         Com_Printf("Com_ParseCharacterTemplate: character template \"%s\" without body ignored\n", name);
02738         csi.numChrTemplates--;
02739         return;
02740     }
02741 
02742     do {
02743         token = Com_EParse(text, errhead, name);
02744         if (!*text || *token == '}')
02745             return;
02746 
02747         for (i = 0; i < SKILL_NUM_TYPES + 1; i++)
02748             if (!strcmp(token, skillNames[i])) {
02749                 /* found a definition */
02750                 token = Com_EParse(text, errhead, name);
02751                 if (!*text)
02752                     return;
02753 
02754                 Com_EParseValue(ct->skills[i], token, V_INT2, 0, sizeof(ct->skills[i]));
02755                 break;
02756             }
02757         if (i >= SKILL_NUM_TYPES + 1) {
02758             if (!strcmp(token, "rate")) {
02759                 token = Com_EParse(text, errhead, name);
02760                 if (!*text)
02761                     return;
02762                 ct->rate = atof(token);
02763             } else
02764                 Com_Printf("Com_ParseCharacterTemplate: unknown token \"%s\" ignored (template %s)\n", token, name);
02765         }
02766     } while (*text);
02767 }
02768 
02769 /*
02770 ==============================================================================
02771 TERRAIN PARSERS
02772 ==============================================================================
02773 */
02774 
02775 #define TERRAIN_HASH_SIZE 64
02776 static terrainType_t *terrainTypesHash[TERRAIN_HASH_SIZE];
02777 
02778 static const value_t terrainTypeValues[] = {
02779     {"footstepsound", V_STRING, offsetof(terrainType_t, footStepSound), 0},
02780     {"particle", V_STRING, offsetof(terrainType_t, particle), 0},
02781     {"footstepvolume", V_FLOAT, offsetof(terrainType_t, footStepVolume), 0},
02782     {"bouncefraction", V_FLOAT, offsetof(terrainType_t, bounceFraction), 0},
02783 
02784     {NULL, 0, 0, 0}
02785 };
02786 
02792 const terrainType_t* Com_GetTerrainType (const char *textureName)
02793 {
02794     unsigned hash;
02795     const terrainType_t *t;
02796 
02797     assert(textureName);
02798     hash = Com_HashKey(textureName, TERRAIN_HASH_SIZE);
02799     for (t = terrainTypesHash[hash]; t; t = t->hash_next) {
02800         if (!strcmp(textureName, t->texture))
02801             return t;
02802     }
02803 
02804     return NULL;
02805 }
02806 
02812 static void Com_ParseTerrain (const char *name, const char **text)
02813 {
02814     const char *errhead = "Com_ParseTerrain: unexpected end of file (terrain ";
02815     const char *token;
02816     terrainType_t *t;
02817     const value_t *v;
02818     unsigned hash;
02819 
02820     /* check for additions to existing name categories */
02821     if (Com_GetTerrainType(name) != NULL) {
02822         Com_Printf("Terrain definition with same name already parsed: '%s'\n", name);
02823         return;
02824     }
02825 
02826     /* get name list body body */
02827     token = Com_Parse(text);
02828     if (!*text || *token != '{') {
02829         Com_Printf("Com_ParseTerrain: terrain def \"%s\" without body ignored\n", name);
02830         return;
02831     }
02832 
02833     t = Mem_PoolAlloc(sizeof(*t), com_genericPool, 0);
02834     t->texture = Mem_PoolStrDup(name, com_genericPool, 0);
02835     hash = Com_HashKey(name, TERRAIN_HASH_SIZE);
02836     /* link in terrainTypesHash[hash] should be NULL on the first run */
02837     t->hash_next = terrainTypesHash[hash];
02838     terrainTypesHash[hash] = t;
02839     t->footStepVolume = SND_VOLUME_FOOTSTEPS;
02840     t->bounceFraction = 1.0f;
02841 
02842     do {
02843         /* get the name type */
02844         token = Com_EParse(text, errhead, name);
02845         if (!*text)
02846             break;
02847         if (*token == '}')
02848             break;
02849 
02850         for (v = terrainTypeValues; v->string; v++)
02851             if (!strncmp(token, v->string, sizeof(v->string))) {
02852                 /* found a definition */
02853                 token = Com_EParse(text, errhead, name);
02854                 if (!*text)
02855                     return;
02856                 switch (v->type) {
02857                 case V_STRING:
02858                     Mem_PoolStrDupTo(token, (char**) ((char*)t + (int)v->ofs), com_genericPool, 0);
02859                     break;
02860                 default:
02861                     Com_EParseValue(t, token, v->type, v->ofs, v->size);
02862                     break;
02863                 }
02864                 break;
02865             }
02866         if (!v->string)
02867             Com_Printf("Unknown token '%s' in terrain parsing\n", token);
02868     } while (*text);
02869 }
02870 
02871 /*
02872 ==============================================================================
02873 GAMETYPE INTERPRETER
02874 ==============================================================================
02875 */
02876 
02877 gametype_t gts[MAX_GAMETYPES];
02878 int numGTs = 0;
02879 
02881 static const value_t gameTypeValues[] = {
02882     {"name", V_TRANSLATION_STRING, offsetof(gametype_t, name), 0}, 
02883     {NULL, 0, 0, 0}
02884 };
02885 
02886 static void Com_ParseGameTypes (const char *name, const char **text)
02887 {
02888     const char *errhead = "Com_ParseGameTypes: unexpected end of file (gametype ";
02889     const char *token;
02890     int i;
02891     const value_t *v;
02892     gametype_t* gt;
02893     cvarlist_t* cvarlist;
02894 
02895     /* get it's body */
02896     token = Com_Parse(text);
02897     if (!*text || *token != '{') {
02898         Com_Printf("Com_ParseGameTypes: gametype \"%s\" without body ignored\n", name);
02899         return;
02900     }
02901 
02902     /* search for game types with same name */
02903     for (i = 0; i < numGTs; i++)
02904         if (!strncmp(token, gts[i].id, MAX_VAR))
02905             break;
02906 
02907     if (i == numGTs) {
02908         if (i >= MAX_GAMETYPES)
02909             Sys_Error("Com_ParseGameTypes: MAX_GAMETYPES exceeded\n");
02910         gt = &gts[numGTs++];
02911         memset(gt, 0, sizeof(*gt));
02912         Q_strncpyz(gt->id, name, sizeof(gt->id));
02913         if (numGTs >= MAX_GAMETYPES)
02914             Sys_Error("Com_ParseGameTypes: Too many gametypes.\n");
02915 
02916         do {
02917             token = Com_EParse(text, errhead, name);
02918             if (!*text)
02919                 break;
02920             if (*token == '}')
02921                 break;
02922 
02923             for (v = gameTypeValues; v->string; v++)
02924                 if (!strncmp(token, v->string, sizeof(v->string))) {
02925                     /* found a definition */
02926                     token = Com_EParse(text, errhead, name);
02927                     if (!*text)
02928                         return;
02929 
02930                     Com_EParseValue(gt, token, v->type, v->ofs, v->size);
02931                     break;
02932                 }
02933 
02934             if (!v->string) {
02935                 if (*token != '{')
02936                     Sys_Error("Com_ParseGameTypes: gametype \"%s\" without cvarlist\n", name);
02937 
02938                 do {
02939                     token = Com_EParse(text, errhead, name);
02940                     if (!*text || *token == '}') {
02941                         if (!gt->num_cvars)
02942                             Sys_Error("Com_ParseGameTypes: gametype \"%s\" with empty cvarlist\n", name);
02943                         else
02944                             break;
02945                     }
02946                     /* initial pointer */
02947                     cvarlist = &gt->cvars[gt->num_cvars++];
02948                     if (gt->num_cvars >= MAX_CVARLISTINGAMETYPE)
02949                         Sys_Error("Com_ParseGameTypes: gametype \"%s\" max cvarlist hit\n", name);
02950                     Q_strncpyz(cvarlist->name, token, sizeof(cvarlist->name));
02951                     token = Com_EParse(text, errhead, name);
02952                     if (!*text || *token == '}')
02953                         Sys_Error("Com_ParseGameTypes: gametype \"%s\" cvar \"%s\" with no value\n", name, cvarlist->name);
02954                     Q_strncpyz(cvarlist->value, token, sizeof(cvarlist->value));
02955                 } while (*text && *token != '}');
02956             }
02957         } while (*text);
02958     } else {
02959         Com_Printf("Com_ParseGameTypes: gametype \"%s\" with same already exists - ignore the second one\n", name);
02960         FS_SkipBlock(text);
02961     }
02962 }
02963 
02964 /*
02965 ==============================================================================
02966 DAMAGE TYPES INTERPRETER
02967 ==============================================================================
02968 */
02969 
02970 static void Com_ParseDamageTypes (const char *name, const char **text)
02971 {
02972     const char *errhead = "Com_ParseDamageTypes: unexpected end of file (damagetype ";
02973     const char *token;
02974     int i;
02975 
02976     /* get it's body */
02977     token = Com_Parse(text);
02978 
02979     if (!*text || *token != '{') {
02980         Com_Printf("Com_ParseDamageTypes: damage type list \"%s\" without body ignored\n", name);
02981         return;
02982     }
02983 
02984     do {
02985         token = Com_EParse(text, errhead, name);
02986         if (!*text)
02987             break;
02988         if (*token == '}')
02989             break;
02990 
02991         /* Gettext marker (also indicates that it is a dmgtype value - additional to being a dmgweight value) */
02992         if (*token == '_') {
02993             token++;
02994             csi.dts[csi.numDTs].showInMenu = qtrue;
02995         }
02996 
02997         /* search for damage types with same name */
02998         for (i = 0; i < csi.numDTs; i++)
02999             if (!strcmp(token, csi.dts[i].id))
03000                 break;
03001 
03002         /* Not found in the for loop. */
03003         if (i == csi.numDTs) {
03004             Q_strncpyz(csi.dts[csi.numDTs].id, token, sizeof(csi.dts[csi.numDTs].id));
03005 
03006             /* Check dmgtype IDs and store their IDs in csi. */
03007             if (csi.dts[csi.numDTs].showInMenu) {
03008                 Com_DPrintf(DEBUG_CLIENT, "Com_ParseDamageTypes: dmgtype/dmgweight %s\n", token);
03009                 /* Special IDs */
03010                 if (!strcmp(token, "normal"))
03011                     csi.damNormal = csi.numDTs;
03012                 else if (!strcmp(token, "blast"))
03013                     csi.damBlast = csi.numDTs;
03014                 else if (!strcmp(token, "fire"))
03015                     csi.damFire = csi.numDTs;
03016                 else if (!strcmp(token, "shock"))
03017                     csi.damShock = csi.numDTs;
03018                 else if (!strcmp(token, "laser"))
03019                     csi.damLaser = csi.numDTs;
03020                 else if (!strcmp(token, "plasma"))
03021                     csi.damPlasma = csi.numDTs;
03022                 else if (!strcmp(token, "particlebeam"))
03023                     csi.damParticle = csi.numDTs;
03024                 else if (!strcmp(token, "stun_electro"))
03025                     csi.damStunElectro = csi.numDTs;
03026                 else if (!strcmp(token, "stun_gas"))
03027                     csi.damStunGas = csi.numDTs;
03028                 else
03029                     Com_Printf("Unknown dmgtype: '%s'\n", token);
03030             } else {
03031                 Com_DPrintf(DEBUG_CLIENT, "Com_ParseDamageTypes: dmgweight %s\n", token);
03032             }
03033 
03034             csi.numDTs++;
03035             if (csi.numDTs >= MAX_DAMAGETYPES)
03036                 Sys_Error("Com_ParseDamageTypes: Too many damage types.\n");
03037         } else {
03038             Com_Printf("Com_ParseDamageTypes: damage type \"%s\" in list \"%s\" with same already exists - ignore the second one (#%i)\n", token, name, csi.numDTs);
03039         }
03040     } while (*text);
03041 }
03042 
03043 
03044 /*
03045 ==============================================================================
03046 MAIN SCRIPT PARSING FUNCTION
03047 ==============================================================================
03048 */
03049 
03058 const char *Com_GetRandomMapAssemblyNameForCraft (const char *craftID)
03059 {
03060     return va("+%s", craftID);
03061 }
03062 
03069 humanAircraftType_t Com_DropShipShortNameToID (const char *token)
03070 {
03071     humanAircraftType_t aircraftType;
03072     size_t dummy;
03073     Com_ParseValue(&aircraftType, token, V_AIRCRAFTTYPE, 0, sizeof(aircraftType), &dummy);
03074     return aircraftType;
03075 }
03076 
03081 const char* Com_DropShipTypeToShortName (humanAircraftType_t type)
03082 {
03083     return Com_ValueToStr(&type, V_AIRCRAFTTYPE, 0);
03084 }
03085 
03091 ufoType_t Com_UFOShortNameToID (const char *token)
03092 {
03093     ufoType_t ufoType;
03094     size_t dummy;
03095     Com_ParseValue(&ufoType, token, V_UFO, 0, sizeof(ufoType), &dummy);
03096     return ufoType;
03097 }
03098 
03104 const char* Com_UFOTypeToShortName (ufoType_t type)
03105 {
03106     return Com_ValueToStr(&type, V_UFO, 0);
03107 }
03108 
03113 const char* Com_UFOCrashedTypeToShortName (ufoType_t type)
03114 {
03115     return Com_ValueToStr(&type, V_UFOCRASHED, 0);
03116 }
03117 
03124 const ugv_t *Com_GetUGVByIDSilent (const char *ugvID)
03125 {
03126     int i;
03127 
03128     if (!ugvID)
03129         return NULL;
03130     for (i = 0; i < csi.numUGV; i++) {
03131         const ugv_t *ugv = &csi.ugvs[i];
03132         if (!strcmp(ugv->id, ugvID)) {
03133             return ugv;
03134         }
03135     }
03136     return NULL;
03137 }
03138 
03144 const ugv_t *Com_GetUGVByID (const char *ugvID)
03145 {
03146     const ugv_t *ugv = Com_GetUGVByIDSilent(ugvID);
03147 
03148     if (!ugvID)
03149         Com_Printf("Com_GetUGVByID Called with NULL ugvID!\n");
03150     else if (!ugv)
03151         Com_Printf("Com_GetUGVByID: No ugv_t entry found for id '%s' in %i entries.\n", ugvID, csi.numUGV);
03152     return ugv;
03153 }
03154 
03158 static void Com_AddObjectLinks (void)
03159 {
03160     linkedList_t* ll = parseItemWeapons;    
03161     objDef_t *od;
03162     int i, n, m;
03163     byte k, weaponsIdx;
03164     char *id;
03165 
03166     /* Add links to weapons. */
03167     while (ll) {
03168         /* Get the data stored in the linked list. */
03169         assert(ll);
03170         od = (objDef_t *) ll->data;
03171         ll = ll->next;
03172 
03173         assert(ll);
03174         weaponsIdx = *(int*)ll->data;
03175         ll = ll->next;
03176 
03177         assert(ll);
03178         id = (char*)ll->data;
03179         ll = ll->next;
03180 
03181         /* Link the weapon pointers for this item. */
03182         od->weapons[weaponsIdx] = INVSH_GetItemByID(id);
03183         if (!od->weapons[weaponsIdx]) {
03184             Sys_Error("Com_AddObjectLinks: Could not get item '%s' for linking into item '%s'\n",
03185                 id , od->id);
03186         }
03187 
03188         /* Back-link the obj-idx inside the fds */
03189         for (k = 0; k < od->numFiredefs[weaponsIdx]; k++) {
03190             od->fd[weaponsIdx][k].obj = od;
03191         }
03192     }
03193 
03194     /* Clear the temporary list. */
03195     LIST_Delete(&parseItemWeapons);
03196 
03197     /* Add links to ammos */
03198     for (i = 0, od = csi.ods; i < csi.numODs; i++, od++) {
03199         od->numAmmos = 0;   /* Default value */
03200         if (od->numWeapons == 0 && (od->weapon || od->craftitem.type <= AC_ITEM_WEAPON)) {
03201             /* this is a weapon, an aircraft weapon, or a base defence system */
03202             for (n = 0; n < csi.numODs; n++) {
03203                 objDef_t *weapon = INVSH_GetItemByIDX(n);
03204                 for (m = 0; m < weapon->numWeapons; m++) {
03205                     if (weapon->weapons[m] == od) {
03206                         assert(od->numAmmos <= MAX_AMMOS_PER_OBJDEF);
03207                         od->ammos[od->numAmmos++] = weapon;
03208                     }
03209                 }
03210             }
03211         }
03212     }
03213 }
03214 
03221 void Com_ParseScripts (qboolean onlyServer)
03222 {
03223     const char *type, *name, *text;
03224 
03225     Com_Printf("\n----------- parse scripts ----------\n");
03226 
03227     /* reset csi basic info */
03228     INVSH_InitCSI(&csi);
03229     csi.idRight = csi.idLeft = csi.idExtension = csi.idBackpack = csi.idBelt = csi.idHolster = csi.idArmour = csi.idFloor = csi.idEquip = csi.idHeadgear = NONE;
03230     csi.damNormal = csi.damBlast = csi.damFire = csi.damShock = csi.damLaser = csi.damPlasma = csi.damParticle = csi.damStunElectro = csi.damStunGas = NONE;
03231 
03232     /* pre-stage parsing */
03233     Com_Printf("%i script files\n", FS_BuildFileList("ufos/*.ufo"));
03234     text = NULL;
03235 
03236     while ((type = FS_NextScriptHeader("ufos/*.ufo", &name, &text)) != NULL)
03237         if (!strcmp(type, "damagetypes"))
03238             Com_ParseDamageTypes(name, &text);
03239         else if (!strcmp(type, "gametype"))
03240             Com_ParseGameTypes(name, &text);
03241         else if (!strcmp(type, "version"))
03242             Com_ParseVersion(name);
03243 
03244     /* stage one parsing */
03245     FS_NextScriptHeader(NULL, NULL, NULL);
03246     text = NULL;
03247 
03248     while ((type = FS_NextScriptHeader("ufos/*.ufo", &name, &text)) != NULL) {
03249         /* server/client scripts */
03250         if (!strcmp(type, "item") || !strcmp(type, "craftitem"))
03251             Com_ParseItem(name, &text);
03252         else if (!strcmp(type, "inventory"))
03253             Com_ParseInventory(name, &text);
03254         else if (!strcmp(type, "terrain"))
03255             Com_ParseTerrain(name, &text);
03256         else if (!strcmp(type, "ugv"))
03257             Com_ParseUGVs(name, &text);
03258         else if (!strcmp(type, "chrtemplate"))
03259             Com_ParseCharacterTemplate(name, &text);
03260         else if (!onlyServer)
03261             CL_ParseClientData(type, name, &text);
03262     }
03263 
03264     if (!versionParsed)
03265         Sys_Error("Could not find version string for script files");
03266 
03267     /* Stage two parsing (weapon/inventory dependant stuff). */
03268     FS_NextScriptHeader(NULL, NULL, NULL);
03269     text = NULL;
03270 
03271     while ((type = FS_NextScriptHeader("ufos/*.ufo", &name, &text)) != NULL) {
03272         /* server/client scripts */
03273         if (!strcmp(type, "equipment"))
03274             Com_ParseEquipment(name, &text);
03275         else if (!strcmp(type, "team"))
03276             Com_ParseTeam(name, &text);
03277     }
03278 
03279     Com_AddObjectLinks();   /* Add ammo<->weapon links to items.*/
03280 
03281     /* parse ui node script */
03282     if (!onlyServer) {
03283         Com_Printf("%i ui script files\n", FS_BuildFileList("ufos/ui/*.ufo"));
03284         FS_NextScriptHeader(NULL, NULL, NULL);
03285         text = NULL;
03286         while ((type = FS_NextScriptHeader("ufos/ui/*.ufo", &name, &text)) != NULL)
03287             CL_ParseClientData(type, name, &text);
03288     }
03289 
03290     Com_Printf("Shared Client/Server Info loaded\n");
03291     Com_Printf("...%3i items parsed\n", csi.numODs);
03292     Com_Printf("...%3i damage types parsed\n", csi.numDTs);
03293     Com_Printf("...%3i equipment definitions parsed\n", csi.numEDs);
03294     Com_Printf("...%3i inventory definitions parsed\n", csi.numIDs);
03295     Com_Printf("...%3i team definitions parsed\n", csi.numTeamDefs);
03296 }
03297 
03298 int Com_GetScriptChecksum (void)
03299 {
03300     int checksum = 0;
03301     const char *buf;
03302 
03303     while ((buf = FS_GetFileData("ufos/*.ufo")) != NULL)
03304         checksum += LittleLong(Com_BlockChecksum(buf, strlen(buf)));
03305     FS_GetFileData(NULL);
03306 
03307     return checksum;
03308 }

Generated by  doxygen 1.6.2