00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
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",
00317 "pos",
00318 "vector",
00319 "color",
00320 "rgba",
00321 "string",
00322 "translation_string",
00323 "longstring",
00324 "align",
00325 "blend",
00326 "style",
00327 "fade",
00328 "shapes",
00329 "shapeb",
00330 "dmgtype",
00331 "dmgweight",
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,
00367 sizeof(qboolean),
00368 sizeof(char),
00369 sizeof(int),
00370 2 * sizeof(int),
00371 sizeof(float),
00372 sizeof(vec2_t),
00373 sizeof(vec3_t),
00374 sizeof(vec4_t),
00375 sizeof(vec4_t),
00376 0,
00377 0,
00378 0,
00379 sizeof(align_t),
00380 sizeof(blend_t),
00381 sizeof(style_t),
00382 sizeof(fade_t),
00383 sizeof(int),
00384 0,
00385 sizeof(byte),
00386 sizeof(byte),
00387 0,
00388 sizeof(float),
00389 0,
00390 0,
00391 sizeof(int),
00392 sizeof(racetypes_t),
00393 sizeof(ufoType_t),
00394 sizeof(ufoType_t),
00395 sizeof(humanAircraftType_t)
00396 };
00397 CASSERT(lengthof(vt_sizes) == V_NUM_TYPES);
00398
00400 static const size_t vt_aligns[] = {
00401 0,
00402 sizeof(qboolean),
00403 sizeof(char),
00404 sizeof(int),
00405 sizeof(int),
00406 sizeof(float),
00407 sizeof(vec_t),
00408 sizeof(vec_t),
00409 sizeof(vec_t),
00410 sizeof(vec_t),
00411 sizeof(char),
00412 sizeof(char),
00413 sizeof(char),
00414 sizeof(align_t),
00415 sizeof(blend_t),
00416 sizeof(style_t),
00417 sizeof(fade_t),
00418 sizeof(int),
00419 sizeof(uint32_t),
00420 sizeof(byte),
00421 sizeof(byte),
00422 sizeof(date_t),
00423 sizeof(float),
00424 0,
00425 sizeof(char),
00426 sizeof(int),
00427 sizeof(racetypes_t),
00428 sizeof(ufoType_t),
00429 sizeof(ufoType_t),
00430 sizeof(humanAircraftType_t)
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
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
01355 if (*(const float *) b > 2.0)
01356 Com_sprintf(valuestr, sizeof(valuestr), "+%.2f", *(const float *) b);
01357
01358 else if (*(const float *) b < 2.0)
01359 Com_sprintf(valuestr, sizeof(valuestr), "-%.2f", *(const float *) b);
01360
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
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
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
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
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
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
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
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
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
01697 if (val->type != V_NULL) {
01698
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
01707 switch (i) {
01708 case OD_WEAPON:
01709
01710 token = Com_Parse(text);
01711 if (od->numWeapons < MAX_WEAPONS_PER_OBJDEF) {
01712
01713 LIST_AddPointer(&parseItemWeapons, od);
01714 LIST_Add(&parseItemWeapons, (byte *)&od->numWeapons, sizeof(int));
01715 LIST_AddString(&parseItemWeapons, token);
01716
01717
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
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
01740 Com_ParseFire(name, text, &od->fd[weapFdsIdx][fdIdx]);
01741
01742 od->fd[weapFdsIdx][fdIdx].fdIdx = fdIdx;
01743
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
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
01786 token = Com_EParse(text, errhead, name);
01787 if (!*text)
01788 return;
01789
01790
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
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
01821
01822
01823
01824 static const value_t idps[] = {
01825 {"shape", V_SHAPE_BIG, offsetof(invDef_t, shape), 0},
01826
01827 {"single", V_BOOL, offsetof(invDef_t, single), MEMBER_SIZEOF(invDef_t, single)},
01828
01829 {"scroll", V_BOOL, offsetof(invDef_t, scroll), MEMBER_SIZEOF(invDef_t, scroll)},
01830
01831 {"extension", V_BOOL, offsetof(invDef_t, extension), MEMBER_SIZEOF(invDef_t, extension)},
01832
01833 {"armour", V_BOOL, offsetof(invDef_t, armour), MEMBER_SIZEOF(invDef_t, armour)},
01834
01835 {"headgear", V_BOOL, offsetof(invDef_t, headgear), MEMBER_SIZEOF(invDef_t, headgear)},
01836
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
01840 {"in", V_INT, offsetof(invDef_t, in), MEMBER_SIZEOF(invDef_t, in)},
01841
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
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;
01868 }
01869
01870
01871 id = &csi.ids[csi.numIDs++];
01872 memset(id, 0, sizeof(*id));
01873
01874 Q_strncpyz(id->name, name, sizeof(id->name));
01875
01876
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
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
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
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
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
01997 ed = &csi.eds[csi.numEDs++];
01998 memset(ed, 0, sizeof(*ed));
01999
02000 Q_strncpyz(ed->name, name, sizeof(ed->name));
02001
02002
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
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
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
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
02107 list = td->names[gender];
02108 for (j = 0; j < name; j++) {
02109 assert(list);
02110 list = list->next;
02111 }
02112
02113
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
02129 const int num = (rand() % td->numModels[gender]) * MODEL_NUM_TYPES + type;
02130
02131
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
02138 list = td->models[gender];
02139 for (j = 0; j < num; j++) {
02140 assert(list);
02141 list = list->next;
02142 }
02143
02144
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
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
02224 while (retry--) {
02225 const char *str;
02226 const int gender = rand() % NAME_LAST;
02227
02228 chr->gender = gender;
02229
02230
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
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
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
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
02305 token = Com_EParse(text, errhead, name);
02306 if (!*text)
02307 break;
02308 if (*token == '}')
02309 break;
02310
02311
02312 if (*token == '_')
02313 token++;
02314 LIST_AddString(&td->names[i], token);
02315 td->numNames[i]++;
02316 } while (*text);
02317
02318
02319
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
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
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
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
02398 if (j == 0)
02399 break;
02400
02401
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
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
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
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;
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
02510 for (i = 0, td = csi.teamDef; i < csi.numTeamDefs; i++, td++)
02511 if (!strcmp(td->id, name))
02512 break;
02513
02514
02515 if (i == csi.numTeamDefs) {
02516 if (csi.numTeamDefs < MAX_TEAMDEFS) {
02517 memset(td, 0, sizeof(*td));
02518
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;
02533 td->onlyWeapon = NULL;
02534
02535
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
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
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
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
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
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
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
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
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
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
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
02821 if (Com_GetTerrainType(name) != NULL) {
02822 Com_Printf("Terrain definition with same name already parsed: '%s'\n", name);
02823 return;
02824 }
02825
02826
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
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
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
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
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
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
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 = >s[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
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
02947 cvarlist = >->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
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
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
02992 if (*token == '_') {
02993 token++;
02994 csi.dts[csi.numDTs].showInMenu = qtrue;
02995 }
02996
02997
02998 for (i = 0; i < csi.numDTs; i++)
02999 if (!strcmp(token, csi.dts[i].id))
03000 break;
03001
03002
03003 if (i == csi.numDTs) {
03004 Q_strncpyz(csi.dts[csi.numDTs].id, token, sizeof(csi.dts[csi.numDTs].id));
03005
03006
03007 if (csi.dts[csi.numDTs].showInMenu) {
03008 Com_DPrintf(DEBUG_CLIENT, "Com_ParseDamageTypes: dmgtype/dmgweight %s\n", token);
03009
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
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
03167 while (ll) {
03168
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
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
03189 for (k = 0; k < od->numFiredefs[weaponsIdx]; k++) {
03190 od->fd[weaponsIdx][k].obj = od;
03191 }
03192 }
03193
03194
03195 LIST_Delete(&parseItemWeapons);
03196
03197
03198 for (i = 0, od = csi.ods; i < csi.numODs; i++, od++) {
03199 od->numAmmos = 0;
03200 if (od->numWeapons == 0 && (od->weapon || od->craftitem.type <= AC_ITEM_WEAPON)) {
03201
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
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
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
03245 FS_NextScriptHeader(NULL, NULL, NULL);
03246 text = NULL;
03247
03248 while ((type = FS_NextScriptHeader("ufos/*.ufo", &name, &text)) != NULL) {
03249
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
03268 FS_NextScriptHeader(NULL, NULL, NULL);
03269 text = NULL;
03270
03271 while ((type = FS_NextScriptHeader("ufos/*.ufo", &name, &text)) != NULL) {
03272
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();
03280
03281
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 }