/codemp/game/bg_saga.c
C | 1508 lines | 1200 code | 212 blank | 96 comment | 374 complexity | 17411c8e9aa1eb7c74a55dbbc80cdc6c MD5 | raw file
Possible License(s): GPL-2.0
- // Copyright (C) 2000-2002 Raven Software, Inc.
- //
- /*****************************************************************************
- * name: bg_saga.c
- *
- * desc: Siege module, shared for game, cgame, and ui.
- *
- * $Author: osman $
- * $Revision: 1.9 $
- *
- *****************************************************************************/
- #include "qcommon/q_shared.h"
- #include "bg_saga.h"
- #include "bg_weapons.h"
- #include "bg_public.h"
- #define SIEGECHAR_TAB 9 //perhaps a bit hacky, but I don't think there's any define existing for "tab"
- //Could use strap stuff but I don't particularly care at the moment anyway.
- extern int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
- extern void trap_FS_Read( void *buffer, int len, fileHandle_t f );
- extern void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
- extern void trap_FS_FCloseFile( fileHandle_t f );
- extern int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
- #ifndef QAGAME //cgame, ui
- qhandle_t trap_R_RegisterShaderNoMip( const char *name );
- #endif
- char siege_info[MAX_SIEGE_INFO_SIZE];
- int siege_valid = 0;
- siegeTeam_t *team1Theme = NULL;
- siegeTeam_t *team2Theme = NULL;
- siegeClass_t bgSiegeClasses[MAX_SIEGE_CLASSES];
- int bgNumSiegeClasses = 0;
- siegeTeam_t bgSiegeTeams[MAX_SIEGE_TEAMS];
- int bgNumSiegeTeams = 0;
- //class flags
- stringID_table_t bgSiegeClassFlagNames[] =
- {
- ENUM2STRING(CFL_MORESABERDMG),
- ENUM2STRING(CFL_STRONGAGAINSTPHYSICAL),
- ENUM2STRING(CFL_FASTFORCEREGEN),
- ENUM2STRING(CFL_STATVIEWER),
- ENUM2STRING(CFL_HEAVYMELEE),
- ENUM2STRING(CFL_SINGLE_ROCKET),
- ENUM2STRING(CFL_CUSTOMSKEL),
- ENUM2STRING(CFL_EXTRA_AMMO),
- {"", -1}
- };
- //saber stances
- stringID_table_t StanceTable[] =
- {
- ENUM2STRING(SS_NONE),
- ENUM2STRING(SS_FAST),
- ENUM2STRING(SS_MEDIUM),
- ENUM2STRING(SS_STRONG),
- ENUM2STRING(SS_DESANN),
- ENUM2STRING(SS_TAVION),
- ENUM2STRING(SS_DUAL),
- ENUM2STRING(SS_STAFF),
- {"", 0}
- };
- //Weapon and force power tables are also used in NPC parsing code and some other places.
- stringID_table_t WPTable[] =
- {
- {"NULL",WP_NONE},
- ENUM2STRING(WP_NONE),
- // Player weapons
- ENUM2STRING(WP_STUN_BATON),
- ENUM2STRING(WP_MELEE),
- ENUM2STRING(WP_SABER),
- ENUM2STRING(WP_BRYAR_PISTOL),
- {"WP_BLASTER_PISTOL", WP_BRYAR_PISTOL},
- ENUM2STRING(WP_BLASTER),
- ENUM2STRING(WP_DISRUPTOR),
- ENUM2STRING(WP_BOWCASTER),
- ENUM2STRING(WP_REPEATER),
- ENUM2STRING(WP_DEMP2),
- ENUM2STRING(WP_FLECHETTE),
- ENUM2STRING(WP_ROCKET_LAUNCHER),
- ENUM2STRING(WP_THERMAL),
- ENUM2STRING(WP_TRIP_MINE),
- ENUM2STRING(WP_DET_PACK),
- ENUM2STRING(WP_CONCUSSION),
- ENUM2STRING(WP_BRYAR_OLD),
- ENUM2STRING(WP_EMPLACED_GUN),
- ENUM2STRING(WP_TURRET),
- {"", 0}
- };
- stringID_table_t FPTable[] =
- {
- ENUM2STRING(FP_HEAL),
- ENUM2STRING(FP_LEVITATION),
- ENUM2STRING(FP_SPEED),
- ENUM2STRING(FP_PUSH),
- ENUM2STRING(FP_PULL),
- ENUM2STRING(FP_TELEPATHY),
- ENUM2STRING(FP_GRIP),
- ENUM2STRING(FP_LIGHTNING),
- ENUM2STRING(FP_RAGE),
- ENUM2STRING(FP_PROTECT),
- ENUM2STRING(FP_ABSORB),
- ENUM2STRING(FP_TEAM_HEAL),
- ENUM2STRING(FP_TEAM_FORCE),
- ENUM2STRING(FP_DRAIN),
- ENUM2STRING(FP_SEE),
- ENUM2STRING(FP_SABER_OFFENSE),
- ENUM2STRING(FP_SABER_DEFENSE),
- ENUM2STRING(FP_SABERTHROW),
- {"", -1}
- };
- stringID_table_t HoldableTable[] =
- {
- ENUM2STRING(HI_NONE),
- ENUM2STRING(HI_SEEKER),
- ENUM2STRING(HI_SHIELD),
- ENUM2STRING(HI_MEDPAC),
- ENUM2STRING(HI_MEDPAC_BIG),
- ENUM2STRING(HI_BINOCULARS),
- ENUM2STRING(HI_SENTRY_GUN),
- ENUM2STRING(HI_JETPACK),
- ENUM2STRING(HI_HEALTHDISP),
- ENUM2STRING(HI_AMMODISP),
- ENUM2STRING(HI_EWEB),
- ENUM2STRING(HI_CLOAK),
- {"", -1}
- };
- stringID_table_t PowerupTable[] =
- {
- ENUM2STRING(PW_NONE),
- #ifdef BASE_COMPAT
- ENUM2STRING(PW_QUAD),
- ENUM2STRING(PW_BATTLESUIT),
- #endif // BASE_COMPAT
- ENUM2STRING(PW_PULL),
- ENUM2STRING(PW_REDFLAG),
- ENUM2STRING(PW_BLUEFLAG),
- ENUM2STRING(PW_NEUTRALFLAG),
- ENUM2STRING(PW_SHIELDHIT),
- ENUM2STRING(PW_SPEEDBURST),
- ENUM2STRING(PW_DISINT_4),
- ENUM2STRING(PW_SPEED),
- ENUM2STRING(PW_CLOAKED),
- ENUM2STRING(PW_FORCE_ENLIGHTENED_LIGHT),
- ENUM2STRING(PW_FORCE_ENLIGHTENED_DARK),
- ENUM2STRING(PW_FORCE_BOON),
- ENUM2STRING(PW_YSALAMIRI),
- {"", -1}
- };
- //======================================
- //Parsing functions
- //======================================
- void BG_SiegeStripTabs(char *buf)
- {
- int i = 0;
- int i_r = 0;
- while (buf[i])
- {
- if (buf[i] != SIEGECHAR_TAB)
- { //not a tab, just stick it in
- buf[i_r] = buf[i];
- }
- else
- { //If it's a tab, convert it to a space.
- buf[i_r] = ' ';
- }
- i_r++;
- i++;
- }
- buf[i_r] = '\0';
- }
- int BG_SiegeGetValueGroup(char *buf, char *group, char *outbuf)
- {
- int i = 0;
- int j;
- char checkGroup[4096];
- qboolean isGroup;
- int parseGroups = 0;
- while (buf[i])
- {
- if (buf[i] != ' ' && buf[i] != '{' && buf[i] != '}' && buf[i] != '\n' && buf[i] != '\r' && buf[i] != SIEGECHAR_TAB)
- { //we're on a valid character
- if (buf[i] == '/' &&
- buf[i+1] == '/')
- { //this is a comment, so skip over it
- while (buf[i] && buf[i] != '\n' && buf[i] != '\r' && buf[i] != SIEGECHAR_TAB)
- {
- i++;
- }
- }
- else
- { //parse to the next space/endline/eos and check this value against our group value.
- j = 0;
- while (buf[i] != ' ' && buf[i] != '\n' && buf[i] != '\r' && buf[i] != SIEGECHAR_TAB && buf[i] != '{' && buf[i])
- {
- if (buf[i] == '/' && buf[i+1] == '/')
- { //hit a comment, break out.
- break;
- }
- checkGroup[j] = buf[i];
- j++;
- i++;
- }
- checkGroup[j] = 0;
- //Make sure this is a group as opposed to a globally defined value.
- if (buf[i] == '/' && buf[i+1] == '/')
- { //stopped on a comment, so first parse to the end of it.
- while (buf[i] && buf[i] != '\n' && buf[i] != '\r')
- {
- i++;
- }
- while (buf[i] == '\n' || buf[i] == '\r')
- {
- i++;
- }
- }
- if (!buf[i])
- {
- Com_Error(ERR_DROP, "Unexpected EOF while looking for group '%s'", group);
- }
- isGroup = qfalse;
- while ( buf[i] && (buf[i] == ' ' || buf[i] == SIEGECHAR_TAB || buf[i] == '\n' || buf[i] == '\r') )
- { //parse to the next valid character
- i++;
- }
- if (buf[i] == '{')
- { //if the next valid character is an opening bracket, then this is indeed a group
- isGroup = qtrue;
- }
- //Is this the one we want?
- if (isGroup && !Q_stricmp(checkGroup, group))
- { //guess so. Parse until we hit the { indicating the beginning of the group.
- while (buf[i] != '{' && buf[i])
- {
- i++;
- }
- if (buf[i])
- { //We're at the start of the group now, so parse to the closing bracket.
- j = 0;
- parseGroups = 0;
- while ((buf[i] != '}' || parseGroups) && buf[i])
- {
- if (buf[i] == '{')
- { //increment for the opening bracket.
- parseGroups++;
- }
- else if (buf[i] == '}')
- { //decrement for the closing bracket
- parseGroups--;
- }
- if (parseGroups < 0)
- { //Syntax error, I guess.
- Com_Error(ERR_DROP, "Found a closing bracket without an opening bracket while looking for group '%s'", group);
- }
- if ((buf[i] != '{' || parseGroups > 1) &&
- (buf[i] != '}' || parseGroups > 0))
- { //don't put the start and end brackets for this group into the output buffer
- outbuf[j] = buf[i];
- j++;
- }
- if (buf[i] == '}' && !parseGroups)
- { //Alright, we can break out now.
- break;
- }
- i++;
- }
- outbuf[j] = 0;
- //Verify that we ended up on the closing bracket.
- if (buf[i] != '}')
- {
- Com_Error(ERR_DROP, "Group '%s' is missing a closing bracket", group);
- }
- //Strip the tabs so we're friendly for value parsing.
- BG_SiegeStripTabs(outbuf);
- return 1; //we got it, so return 1.
- }
- else
- {
- Com_Error(ERR_DROP, "Error parsing group in file, unexpected EOF before opening bracket while looking for group '%s'", group);
- }
- }
- else if (!isGroup)
- { //if it wasn't a group, parse to the end of the line
- while (buf[i] && buf[i] != '\n' && buf[i] != '\r')
- {
- i++;
- }
- }
- else
- { //this was a group but we not the one we wanted to find, so parse by it.
- parseGroups = 0;
- while (buf[i] && (buf[i] != '}' || parseGroups))
- {
- if (buf[i] == '{')
- {
- parseGroups++;
- }
- else if (buf[i] == '}')
- {
- parseGroups--;
- }
- if (parseGroups < 0)
- { //Syntax error, I guess.
- Com_Error(ERR_DROP, "Found a closing bracket without an opening bracket while looking for group '%s'", group);
- }
- if (buf[i] == '}' && !parseGroups)
- { //Alright, we can break out now.
- break;
- }
- i++;
- }
- if (buf[i] != '}')
- {
- Com_Error(ERR_DROP, "Found an opening bracket without a matching closing bracket while looking for group '%s'", group);
- }
- i++;
- }
- }
- }
- else if (buf[i] == '{')
- { //we're in a group that isn't the one we want, so parse to the end.
- parseGroups = 0;
- while (buf[i] && (buf[i] != '}' || parseGroups))
- {
- if (buf[i] == '{')
- {
- parseGroups++;
- }
- else if (buf[i] == '}')
- {
- parseGroups--;
- }
- if (parseGroups < 0)
- { //Syntax error, I guess.
- Com_Error(ERR_DROP, "Found a closing bracket without an opening bracket while looking for group '%s'", group);
- }
- if (buf[i] == '}' && !parseGroups)
- { //Alright, we can break out now.
- break;
- }
- i++;
- }
- if (buf[i] != '}')
- {
- Com_Error(ERR_DROP, "Found an opening bracket without a matching closing bracket while looking for group '%s'", group);
- }
- }
- if (!buf[i])
- {
- break;
- }
- i++;
- }
- return 0; //guess we never found it.
- }
- int BG_SiegeGetPairedValue(char *buf, char *key, char *outbuf)
- {
- int i = 0;
- int j;
- int k;
- char checkKey[4096];
- while (buf[i])
- {
- if (buf[i] != ' ' && buf[i] != '{' && buf[i] != '}' && buf[i] != '\n' && buf[i] != '\r')
- { //we're on a valid character
- if (buf[i] == '/' &&
- buf[i+1] == '/')
- { //this is a comment, so skip over it
- while (buf[i] && buf[i] != '\n' && buf[i] != '\r')
- {
- i++;
- }
- }
- else
- { //parse to the next space/endline/eos and check this value against our key value.
- j = 0;
- while (buf[i] != ' ' && buf[i] != '\n' && buf[i] != '\r' && buf[i] != SIEGECHAR_TAB && buf[i])
- {
- if (buf[i] == '/' && buf[i+1] == '/')
- { //hit a comment, break out.
- break;
- }
- checkKey[j] = buf[i];
- j++;
- i++;
- }
- checkKey[j] = 0;
- k = i;
- while (buf[k] && (buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\r'))
- {
- k++;
- }
- if (buf[k] == '{')
- { //this is not the start of a value but rather of a group. We don't want to look in subgroups so skip over the whole thing.
- int openB = 0;
- while (buf[i] && (buf[i] != '}' || openB))
- {
- if (buf[i] == '{')
- {
- openB++;
- }
- else if (buf[i] == '}')
- {
- openB--;
- }
- if (openB < 0)
- {
- Com_Error(ERR_DROP, "Unexpected closing bracket (too many) while parsing to end of group '%s'", checkKey);
- }
- if (buf[i] == '}' && !openB)
- { //this is the end of the group
- break;
- }
- i++;
- }
- if (buf[i] == '}')
- {
- i++;
- }
- }
- else
- {
- //Is this the one we want?
- if (buf[i] != '/' || buf[i+1] != '/')
- { //make sure we didn't stop on a comment, if we did then this is considered an error in the file.
- if (!Q_stricmp(checkKey, key))
- { //guess so. Parse along to the next valid character, then put that into the output buffer and return 1.
- while ((buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\r' || buf[i] == SIEGECHAR_TAB) && buf[i])
- {
- i++;
- }
- if (buf[i])
- { //We're at the start of the value now.
- qboolean parseToQuote = qfalse;
- if (buf[i] == '\"')
- { //if the value is in quotes, then stop at the next quote instead of ' '
- i++;
- parseToQuote = qtrue;
- }
- j = 0;
- while ( ((!parseToQuote && buf[i] != ' ' && buf[i] != '\n' && buf[i] != '\r') || (parseToQuote && buf[i] != '\"')) )
- {
- if (buf[i] == '/' &&
- buf[i+1] == '/')
- { //hit a comment after the value? This isn't an ideal way to be writing things, but we'll support it anyway.
- break;
- }
- outbuf[j] = buf[i];
- j++;
- i++;
- if (!buf[i])
- {
- if (parseToQuote)
- {
- Com_Error(ERR_DROP, "Unexpected EOF while looking for endquote, error finding paired value for '%s'", key);
- }
- else
- {
- Com_Error(ERR_DROP, "Unexpected EOF while looking for space or endline, error finding paired value for '%s'", key);
- }
- }
- }
- outbuf[j] = 0;
- return 1; //we got it, so return 1.
- }
- else
- {
- Com_Error(ERR_DROP, "Error parsing file, unexpected EOF while looking for valud '%s'", key);
- }
- }
- else
- { //if that wasn't the desired key, then make sure we parse to the end of the line, so we don't mistake a value for a key
- while (buf[i] && buf[i] != '\n')
- {
- i++;
- }
- }
- }
- else
- {
- Com_Error(ERR_DROP, "Error parsing file, found comment, expected value for '%s'", key);
- }
- }
- }
- }
- if (!buf[i])
- {
- break;
- }
- i++;
- }
- return 0; //guess we never found it.
- }
- //======================================
- //End parsing functions
- //======================================
- //======================================
- //Class loading functions
- //======================================
- void BG_SiegeTranslateForcePowers(char *buf, siegeClass_t *siegeClass)
- {
- char checkPower[1024];
- char checkLevel[256];
- int l = 0;
- int k = 0;
- int j = 0;
- int i = 0;
- int parsedLevel = 0;
- qboolean allPowers = qfalse;
- qboolean noPowers = qfalse;
- if (!Q_stricmp(buf, "FP_ALL"))
- { //this is a special case, just give us all the powers on level 3
- allPowers = qtrue;
- }
- if (buf[0] == '0' && !buf[1])
- { //no powers then
- noPowers = qtrue;
- }
- //First clear out the powers, or in the allPowers case, give us all level 3.
- while (i < NUM_FORCE_POWERS)
- {
- if (allPowers)
- {
- siegeClass->forcePowerLevels[i] = FORCE_LEVEL_3;
- }
- else
- {
- siegeClass->forcePowerLevels[i] = 0;
- }
- i++;
- }
- if (allPowers || noPowers)
- { //we're done now then.
- return;
- }
- i = 0;
- while (buf[i])
- { //parse through the list which is seperated by |, and add all the weapons into a bitflag
- if (buf[i] != ' ' && buf[i] != '|')
- {
- j = 0;
- while (buf[i] && buf[i] != ' ' && buf[i] != '|' && buf[i] != ',')
- {
- checkPower[j] = buf[i];
- j++;
- i++;
- }
- checkPower[j] = 0;
- if (buf[i] == ',')
- { //parse the power level
- i++;
- l = 0;
- while (buf[i] && buf[i] != ' ' && buf[i] != '|')
- {
- checkLevel[l] = buf[i];
- l++;
- i++;
- }
- checkLevel[l] = 0;
- parsedLevel = atoi(checkLevel);
- //keep sane limits on the powers
- if (parsedLevel < 0)
- {
- parsedLevel = 0;
- }
- if (parsedLevel > FORCE_LEVEL_5)
- {
- parsedLevel = FORCE_LEVEL_5;
- }
- }
- else
- { //if it's not there, assume level 3 I guess.
- parsedLevel = 3;
- }
- if (checkPower[0])
- { //Got the name, compare it against the weapon table strings.
- k = 0;
- if (!Q_stricmp(checkPower, "FP_JUMP"))
- { //haqery
- strcpy(checkPower, "FP_LEVITATION");
- }
- while (FPTable[k].id != -1 && FPTable[k].name[0])
- {
- if (!Q_stricmp(checkPower, FPTable[k].name))
- { //found it, add the weapon into the weapons value
- siegeClass->forcePowerLevels[k] = parsedLevel;
- break;
- }
- k++;
- }
- }
- }
- if (!buf[i])
- {
- break;
- }
- i++;
- }
- }
- //Used for the majority of generic val parsing stuff. buf should be the value string,
- //table should be the appropriate string/id table. If bitflag is qtrue then the
- //values are accumulated into a bitflag. If bitflag is qfalse then the first value
- //is returned as a directly corresponding id and no further parsing is done.
- int BG_SiegeTranslateGenericTable(char *buf, stringID_table_t *table, qboolean bitflag)
- {
- int items = 0;
- char checkItem[1024];
- int i = 0;
- int j = 0;
- int k = 0;
- if (buf[0] == '0' && !buf[1])
- { //special case, no items.
- return 0;
- }
- while (buf[i])
- { //Using basically the same parsing method as we do for weapons and forcepowers.
- if (buf[i] != ' ' && buf[i] != '|')
- {
- j = 0;
- while (buf[i] && buf[i] != ' ' && buf[i] != '|')
- {
- checkItem[j] = buf[i];
- j++;
- i++;
- }
- checkItem[j] = 0;
- if (checkItem[0])
- {
- k = 0;
- while (table[k].name && table[k].name[0])
- { //go through the list and check the parsed flag name against the hardcoded names
- if (!Q_stricmp(checkItem, table[k].name))
- { //Got it, so add the value into our items value.
- if (bitflag)
- {
- items |= (1 << table[k].id);
- }
- else
- { //return the value directly then.
- return table[k].id;
- }
- break;
- }
- k++;
- }
- }
- }
- if (!buf[i])
- {
- break;
- }
- i++;
- }
- return items;
- }
- char *classTitles[SPC_MAX] =
- {
- "infantry", // SPC_INFANTRY
- "vanguard", // SPC_VANGUARD
- "support", // SPC_SUPPORT
- "jedi_general", // SPC_JEDI
- "demolitionist", // SPC_DEMOLITIONIST
- "heavy_weapons", // SPC_HEAVY_WEAPONS
- };
- void BG_SiegeParseClassFile(const char *filename, siegeClassDesc_t *descBuffer)
- {
- fileHandle_t f;
- int len;
- int i;
- char classInfo[4096];
- char parseBuf[4096];
- len = trap_FS_FOpenFile(filename, &f, FS_READ);
- if (!f || len >= 4096)
- {
- return;
- }
- trap_FS_Read(classInfo, len, f);
- trap_FS_FCloseFile(f);
- classInfo[len] = 0;
- //first get the description if we have a buffer for it
- if (descBuffer)
- {
- if (!BG_SiegeGetPairedValue(classInfo, "description", descBuffer->desc))
- {
- strcpy(descBuffer->desc, "DESCRIPTION UNAVAILABLE");
- }
- //Hit this assert? Memory has already been trashed. Increase
- //SIEGE_CLASS_DESC_LEN.
- assert(strlen(descBuffer->desc) < SIEGE_CLASS_DESC_LEN);
- }
- BG_SiegeGetValueGroup(classInfo, "ClassInfo", classInfo);
- //Parse name
- if (BG_SiegeGetPairedValue(classInfo, "name", parseBuf))
- {
- strcpy(bgSiegeClasses[bgNumSiegeClasses].name, parseBuf);
- }
- else
- {
- Com_Error(ERR_DROP, "Siege class without name entry");
- }
- //Parse forced model
- if (BG_SiegeGetPairedValue(classInfo, "model", parseBuf))
- {
- strcpy(bgSiegeClasses[bgNumSiegeClasses].forcedModel, parseBuf);
- }
- else
- { //It's ok if there isn't one, it's optional.
- bgSiegeClasses[bgNumSiegeClasses].forcedModel[0] = 0;
- }
- //Parse forced skin
- if (BG_SiegeGetPairedValue(classInfo, "skin", parseBuf))
- {
- strcpy(bgSiegeClasses[bgNumSiegeClasses].forcedSkin, parseBuf);
- }
- else
- { //It's ok if there isn't one, it's optional.
- bgSiegeClasses[bgNumSiegeClasses].forcedSkin[0] = 0;
- }
- //Parse first saber
- if (BG_SiegeGetPairedValue(classInfo, "saber1", parseBuf))
- {
- strcpy(bgSiegeClasses[bgNumSiegeClasses].saber1, parseBuf);
- }
- else
- { //It's ok if there isn't one, it's optional.
- bgSiegeClasses[bgNumSiegeClasses].saber1[0] = 0;
- }
- //Parse second saber
- if (BG_SiegeGetPairedValue(classInfo, "saber2", parseBuf))
- {
- strcpy(bgSiegeClasses[bgNumSiegeClasses].saber2, parseBuf);
- }
- else
- { //It's ok if there isn't one, it's optional.
- bgSiegeClasses[bgNumSiegeClasses].saber2[0] = 0;
- }
- //Parse forced saber stance
- if (BG_SiegeGetPairedValue(classInfo, "saberstyle", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].saberStance = BG_SiegeTranslateGenericTable(parseBuf, StanceTable, qtrue);
- }
- else
- { //It's ok if there isn't one, it's optional.
- bgSiegeClasses[bgNumSiegeClasses].saberStance = 0;
- }
- //Parse forced saber color
- if (BG_SiegeGetPairedValue(classInfo, "sabercolor", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].forcedSaberColor = atoi(parseBuf);
- bgSiegeClasses[bgNumSiegeClasses].hasForcedSaberColor = qtrue;
- }
- else
- { //It's ok if there isn't one, it's optional.
- bgSiegeClasses[bgNumSiegeClasses].hasForcedSaberColor = qfalse;
- }
- //Parse forced saber2 color
- if (BG_SiegeGetPairedValue(classInfo, "saber2color", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].forcedSaber2Color = atoi(parseBuf);
- bgSiegeClasses[bgNumSiegeClasses].hasForcedSaber2Color = qtrue;
- }
- else
- { //It's ok if there isn't one, it's optional.
- bgSiegeClasses[bgNumSiegeClasses].hasForcedSaber2Color = qfalse;
- }
- //Parse weapons
- if (BG_SiegeGetPairedValue(classInfo, "weapons", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].weapons = BG_SiegeTranslateGenericTable(parseBuf, WPTable, qtrue);
- }
- else
- {
- Com_Error(ERR_DROP, "Siege class without weapons entry");
- }
- if (!(bgSiegeClasses[bgNumSiegeClasses].weapons & (1 << WP_SABER)))
- { //make sure it has melee if there's no saber
- bgSiegeClasses[bgNumSiegeClasses].weapons |= (1 << WP_MELEE);
- //always give them this too if they are not a saber user
- //bgSiegeClasses[bgNumSiegeClasses].weapons |= (1 << WP_BRYAR_PISTOL);
- }
- //Parse forcepowers
- if (BG_SiegeGetPairedValue(classInfo, "forcepowers", parseBuf))
- {
- BG_SiegeTranslateForcePowers(parseBuf, &bgSiegeClasses[bgNumSiegeClasses]);
- }
- else
- { //fine, clear out the powers.
- i = 0;
- while (i < NUM_FORCE_POWERS)
- {
- bgSiegeClasses[bgNumSiegeClasses].forcePowerLevels[i] = 0;
- i++;
- }
- }
- //Parse classflags
- if (BG_SiegeGetPairedValue(classInfo, "classflags", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].classflags = BG_SiegeTranslateGenericTable(parseBuf, bgSiegeClassFlagNames, qtrue);
- }
- else
- { //fine, we'll 0 it.
- bgSiegeClasses[bgNumSiegeClasses].classflags = 0;
- }
- //Parse maxhealth
- if (BG_SiegeGetPairedValue(classInfo, "maxhealth", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].maxhealth = atoi(parseBuf);
- }
- else
- { //It's alright, just default to 100 then.
- bgSiegeClasses[bgNumSiegeClasses].maxhealth = 100;
- }
- //Parse starthealth
- if (BG_SiegeGetPairedValue(classInfo, "starthealth", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].starthealth = atoi(parseBuf);
- }
- else
- { //It's alright, just default to 100 then.
- bgSiegeClasses[bgNumSiegeClasses].starthealth = bgSiegeClasses[bgNumSiegeClasses].maxhealth;
- }
- //Parse startarmor
- if (BG_SiegeGetPairedValue(classInfo, "maxarmor", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].maxarmor = atoi(parseBuf);
- }
- else
- { //It's alright, just default to 0 then.
- bgSiegeClasses[bgNumSiegeClasses].maxarmor = 0;
- }
- //Parse startarmor
- if (BG_SiegeGetPairedValue(classInfo, "startarmor", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].startarmor = atoi(parseBuf);
- if (!bgSiegeClasses[bgNumSiegeClasses].maxarmor)
- { //if they didn't specify a damn max armor then use this.
- bgSiegeClasses[bgNumSiegeClasses].maxarmor = bgSiegeClasses[bgNumSiegeClasses].startarmor;
- }
- }
- else
- { //default to maxarmor.
- bgSiegeClasses[bgNumSiegeClasses].startarmor = bgSiegeClasses[bgNumSiegeClasses].maxarmor;
- }
- //Parse speed (this is a multiplier value)
- if (BG_SiegeGetPairedValue(classInfo, "speed", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].speed = atof(parseBuf);
- }
- else
- { //It's alright, just default to 1 then.
- bgSiegeClasses[bgNumSiegeClasses].speed = 1.0f;
- }
- //Parse shader for ui to use
- if (BG_SiegeGetPairedValue(classInfo, "uishader", parseBuf))
- {
- #ifdef QAGAME
- bgSiegeClasses[bgNumSiegeClasses].uiPortraitShader = 0;
- memset(bgSiegeClasses[bgNumSiegeClasses].uiPortrait,0,sizeof(bgSiegeClasses[bgNumSiegeClasses].uiPortrait));
- #elif defined CGAME
- bgSiegeClasses[bgNumSiegeClasses].uiPortraitShader = 0;
- memset(bgSiegeClasses[bgNumSiegeClasses].uiPortrait,0,sizeof(bgSiegeClasses[bgNumSiegeClasses].uiPortrait));
- #else //ui
- bgSiegeClasses[bgNumSiegeClasses].uiPortraitShader = trap_R_RegisterShaderNoMip(parseBuf);
- memcpy(bgSiegeClasses[bgNumSiegeClasses].uiPortrait,parseBuf,sizeof(bgSiegeClasses[bgNumSiegeClasses].uiPortrait));
- #endif
- }
- else
- { //I guess this is an essential.. we don't want to render bad shaders or anything.
- Com_Error(ERR_DROP, "Siege class without uishader entry");
- }
- //Parse shader for ui to use
- if (BG_SiegeGetPairedValue(classInfo, "class_shader", parseBuf))
- {
- #ifdef QAGAME
- bgSiegeClasses[bgNumSiegeClasses].classShader = 0;
- #else //cgame, ui
- bgSiegeClasses[bgNumSiegeClasses].classShader = trap_R_RegisterShaderNoMip(parseBuf);
- assert( bgSiegeClasses[bgNumSiegeClasses].classShader );
- if ( !bgSiegeClasses[bgNumSiegeClasses].classShader )
- {
- //Com_Error( ERR_DROP, "ERROR: could not find class_shader %s for class %s\n", parseBuf, bgSiegeClasses[bgNumSiegeClasses].name );
- Com_Printf( "ERROR: could not find class_shader %s for class %s\n", parseBuf, bgSiegeClasses[bgNumSiegeClasses].name );
- }
- // A very hacky way to determine class . . .
- else
- #endif
- {
- // Find the base player class based on the icon name - very bad, I know.
- int titleLength, arrayTitleLength;
- char *holdBuf;
- titleLength = strlen(parseBuf);
- for (i=0;i<SPC_MAX;i++)
- {
- // Back up
- arrayTitleLength = strlen(classTitles[i]);
- if (arrayTitleLength>titleLength) // Too long
- {
- break;
- }
- holdBuf = parseBuf + ( titleLength - arrayTitleLength);
- if (!strcmp(holdBuf,classTitles[i]))
- {
- bgSiegeClasses[bgNumSiegeClasses].playerClass = i;
- break;
- }
- }
- // In case the icon name doesn't match up
- if (i>=SPC_MAX)
- {
- bgSiegeClasses[bgNumSiegeClasses].playerClass = SPC_INFANTRY;
- }
- }
- }
- else
- { //No entry! Bad bad bad
- //Com_Error( ERR_DROP, "ERROR: no class_shader defined for class %s\n", bgSiegeClasses[bgNumSiegeClasses].name );
- Com_Printf( "ERROR: no class_shader defined for class %s\n", bgSiegeClasses[bgNumSiegeClasses].name );
- }
- //Parse holdable items to use
- if (BG_SiegeGetPairedValue(classInfo, "holdables", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].invenItems = BG_SiegeTranslateGenericTable(parseBuf, HoldableTable, qtrue);
- }
- else
- { //Just don't start out with any then.
- bgSiegeClasses[bgNumSiegeClasses].invenItems = 0;
- }
- //Parse powerups to use
- if (BG_SiegeGetPairedValue(classInfo, "powerups", parseBuf))
- {
- bgSiegeClasses[bgNumSiegeClasses].powerups = BG_SiegeTranslateGenericTable(parseBuf, PowerupTable, qtrue);
- }
- else
- { //Just don't start out with any then.
- bgSiegeClasses[bgNumSiegeClasses].powerups = 0;
- }
- //A successful read.
- bgNumSiegeClasses++;
- }
- // Count the number of like base classes
- int BG_SiegeCountBaseClass(const int team, const short classIndex)
- {
- int count = 0,i;
- siegeTeam_t *stm;
- stm = BG_SiegeFindThemeForTeam(team);
- if (!stm)
- {
- return(0);
- }
- for (i=0;i<stm->numClasses;i++)
- {
- if (stm->classes[i]->playerClass == classIndex)
- {
- count++;
- }
- }
- return(count);
- }
- char *BG_GetUIPortraitFile(const int team, const short classIndex, const short cntIndex)
- {
- int count = 0,i;
- siegeTeam_t *stm;
- stm = BG_SiegeFindThemeForTeam(team);
- if (!stm)
- {
- return(0);
- }
- // Loop through all the classes for this team
- for (i=0;i<stm->numClasses;i++)
- {
- // does it match the base class?
- if (stm->classes[i]->playerClass == classIndex)
- {
- if (count==cntIndex)
- {
- return(stm->classes[i]->uiPortrait);
- }
- ++count;
- }
- }
- return(0);
- }
- int BG_GetUIPortrait(const int team, const short classIndex, const short cntIndex)
- {
- int count = 0,i;
- siegeTeam_t *stm;
- stm = BG_SiegeFindThemeForTeam(team);
- if (!stm)
- {
- return(0);
- }
- // Loop through all the classes for this team
- for (i=0;i<stm->numClasses;i++)
- {
- // does it match the base class?
- if (stm->classes[i]->playerClass == classIndex)
- {
- if (count==cntIndex)
- {
- return(stm->classes[i]->uiPortraitShader);
- }
- ++count;
- }
- }
- return(0);
- }
- // This is really getting ugly - looking to get the base class (within a class) based on the index passed in
- siegeClass_t *BG_GetClassOnBaseClass(const int team, const short classIndex, const short cntIndex)
- {
- int count = 0,i;
- siegeTeam_t *stm;
- stm = BG_SiegeFindThemeForTeam(team);
- if (!stm)
- {
- return(0);
- }
- // Loop through all the classes for this team
- for (i=0;i<stm->numClasses;i++)
- {
- // does it match the base class?
- if (stm->classes[i]->playerClass == classIndex)
- {
- if (count==cntIndex)
- {
- return(stm->classes[i]);
- }
- ++count;
- }
- }
- return(0);
- }
- void BG_SiegeLoadClasses(siegeClassDesc_t *descBuffer)
- {
- int numFiles;
- int filelen;
- char filelist[4096];
- char filename[MAX_QPATH];
- char* fileptr;
- int i;
- bgNumSiegeClasses = 0;
- numFiles = trap_FS_GetFileList("ext_data/Siege/Classes", ".scl", filelist, 4096 );
- fileptr = filelist;
- for (i = 0; i < numFiles; i++, fileptr += filelen+1)
- {
- filelen = strlen(fileptr);
- strcpy(filename, "ext_data/Siege/Classes/");
- strcat(filename, fileptr);
- if (descBuffer)
- {
- BG_SiegeParseClassFile(filename, &descBuffer[i]);
- }
- else
- {
- BG_SiegeParseClassFile(filename, NULL);
- }
- }
- }
- //======================================
- //End class loading functions
- //======================================
- //======================================
- //Team loading functions
- //======================================
- siegeClass_t *BG_SiegeFindClassByName(const char *classname)
- {
- int i = 0;
- while (i < bgNumSiegeClasses)
- {
- if (!Q_stricmp(bgSiegeClasses[i].name, classname))
- { //found it
- return &bgSiegeClasses[i];
- }
- i++;
- }
- return NULL;
- }
- void BG_SiegeParseTeamFile(const char *filename)
- {
- fileHandle_t f;
- int len;
- char teamInfo[2048];
- char parseBuf[1024];
- char lookString[256];
- int i = 1;
- qboolean success = qtrue;
- len = trap_FS_FOpenFile(filename, &f, FS_READ);
- if (!f || len >= 2048)
- {
- return;
- }
- trap_FS_Read(teamInfo, len, f);
- trap_FS_FCloseFile(f);
- teamInfo[len] = 0;
- if (BG_SiegeGetPairedValue(teamInfo, "name", parseBuf))
- {
- strcpy(bgSiegeTeams[bgNumSiegeTeams].name, parseBuf);
- }
- else
- {
- Com_Error(ERR_DROP, "Siege team with no name definition");
- }
- //I don't entirely like doing things this way but it's the easiest way.
- #ifdef CGAME
- if (BG_SiegeGetPairedValue(teamInfo, "FriendlyShader", parseBuf))
- {
- bgSiegeTeams[bgNumSiegeTeams].friendlyShader = trap_R_RegisterShaderNoMip(parseBuf);
- }
- #else
- bgSiegeTeams[bgNumSiegeTeams].friendlyShader = 0;
- #endif
- bgSiegeTeams[bgNumSiegeTeams].numClasses = 0;
- if (BG_SiegeGetValueGroup(teamInfo, "Classes", teamInfo))
- {
- while (success && i < MAX_SIEGE_CLASSES)
- { //keep checking for group values named class# up to MAX_SIEGE_CLASSES until we can't find one.
- strcpy(lookString, va("class%i", i));
- success = BG_SiegeGetPairedValue(teamInfo, lookString, parseBuf);
- if (!success)
- {
- break;
- }
- bgSiegeTeams[bgNumSiegeTeams].classes[bgSiegeTeams[bgNumSiegeTeams].numClasses] = BG_SiegeFindClassByName(parseBuf);
- if (!bgSiegeTeams[bgNumSiegeTeams].classes[bgSiegeTeams[bgNumSiegeTeams].numClasses])
- {
- Com_Printf( "Invalid class specified: '%s'\n", parseBuf);
- }
- bgSiegeTeams[bgNumSiegeTeams].numClasses++;
- i++;
- }
- }
- if (!bgSiegeTeams[bgNumSiegeTeams].numClasses)
- {
- Com_Error(ERR_DROP, "Team defined with no allowable classes\n");
- }
- //If we get here then it was a success, so increment the team number
- bgNumSiegeTeams++;
- }
- void BG_SiegeLoadTeams(void)
- {
- int numFiles;
- int filelen;
- char filelist[4096];
- char filename[MAX_QPATH];
- char* fileptr;
- int i;
- bgNumSiegeTeams = 0;
- numFiles = trap_FS_GetFileList("ext_data/Siege/Teams", ".team", filelist, 4096 );
- fileptr = filelist;
- for (i = 0; i < numFiles; i++, fileptr += filelen+1)
- {
- filelen = strlen(fileptr);
- strcpy(filename, "ext_data/Siege/Teams/");
- strcat(filename, fileptr);
- BG_SiegeParseTeamFile(filename);
- }
- }
- //======================================
- //End team loading functions
- //======================================
- //======================================
- //Misc/utility functions
- //======================================
- siegeTeam_t *BG_SiegeFindThemeForTeam(int team)
- {
- if (team == SIEGETEAM_TEAM1)
- {
- return team1Theme;
- }
- else if (team == SIEGETEAM_TEAM2)
- {
- return team2Theme;
- }
- return NULL;
- }
- #ifndef UI_EXPORTS //only for game/cgame
- //precache all the sabers for the active classes for the team
- extern qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ); //bg_saberLoad.cpp
- extern int BG_ModelCache(const char *modelName, const char *skinName); //bg_misc.c
- void BG_PrecacheSabersForSiegeTeam(int team)
- {
- siegeTeam_t *t;
- saberInfo_t saber;
- char *saberName;
- int sNum;
- t = BG_SiegeFindThemeForTeam(team);
- if (t)
- {
- int i = 0;
- while (i < t->numClasses)
- {
- sNum = 0;
- while (sNum < MAX_SABERS)
- {
- switch (sNum)
- {
- case 0:
- saberName = &t->classes[i]->saber1[0];
- break;
- case 1:
- saberName = &t->classes[i]->saber2[0];
- break;
- default:
- saberName = NULL;
- break;
- }
- if (saberName && saberName[0])
- {
- WP_SaberParseParms(saberName, &saber);
- if (!Q_stricmp(saberName, saber.name))
- { //found the matching saber
- if (saber.model[0])
- {
- BG_ModelCache(saber.model, NULL);
- }
- }
- }
- sNum++;
- }
- i++;
- }
- }
- }
- #endif
- qboolean BG_SiegeCheckClassLegality(int team, char *classname)
- {
- siegeTeam_t **teamPtr = NULL;
- int i = 0;
- if (team == SIEGETEAM_TEAM1)
- {
- teamPtr = &team1Theme;
- }
- else if (team == SIEGETEAM_TEAM2)
- {
- teamPtr = &team2Theme;
- }
- else
- { //spectator? Whatever, you're legal then.
- return qtrue;
- }
- if (!teamPtr || !(*teamPtr))
- { //Well, guess the class is ok, seeing as there is no team theme to begin with.
- return qtrue;
- }
- //See if the class is listed on the team
- while (i < (*teamPtr)->numClasses)
- {
- if (!Q_stricmp(classname, (*teamPtr)->classes[i]->name))
- { //found it, so it's alright
- return qtrue;
- }
- i++;
- }
- //Didn't find it, so copy the name of the first valid class over it.
- strcpy(classname, (*teamPtr)->classes[0]->name);
- return qfalse;
- }
- siegeTeam_t *BG_SiegeFindTeamForTheme(char *themeName)
- {
- int i = 0;
- while (i < bgNumSiegeTeams)
- {
- if (bgSiegeTeams[i].name &&
- !Q_stricmp(bgSiegeTeams[i].name, themeName))
- { //this is what we're looking for
- return &bgSiegeTeams[i];
- }
- i++;
- }
- return NULL;
- }
- void BG_SiegeSetTeamTheme(int team, char *themeName)
- {
- siegeTeam_t **teamPtr = NULL;
- if (team == SIEGETEAM_TEAM1)
- {
- teamPtr = &team1Theme;
- }
- else
- {
- teamPtr = &team2Theme;
- }
- (*teamPtr) = BG_SiegeFindTeamForTheme(themeName);
- }
- int BG_SiegeFindClassIndexByName(const char *classname)
- {
- int i = 0;
- while (i < bgNumSiegeClasses)
- {
- if (!Q_stricmp(bgSiegeClasses[i].name, classname))
- { //found it
- return i;
- }
- i++;
- }
- return -1;
- }
- //======================================
- //End misc/utility functions
- //======================================