PageRenderTime 7ms CodeModel.GetById 5ms app.highlight 105ms RepoModel.GetById 1ms app.codeStats 1ms

/game/bg_saga.c

https://bitbucket.org/bshaw/jk3game_sdk_mingw
C | 1508 lines | 1200 code | 212 blank | 96 comment | 374 complexity | 56210dbf902d5c4e8773fc4e538632bb MD5 | raw file
   1// Copyright (C) 2000-2002 Raven Software, Inc.
   2//
   3/*****************************************************************************
   4 * name:		bg_saga.c
   5 *
   6 * desc:		Siege module, shared for game, cgame, and ui.
   7 *
   8 * $Author: osman $ 
   9 * $Revision: 1.9 $
  10 *
  11 *****************************************************************************/
  12#include "q_shared.h"
  13#include "bg_saga.h"
  14#include "bg_weapons.h"
  15#include "bg_public.h"
  16
  17#define SIEGECHAR_TAB 9 //perhaps a bit hacky, but I don't think there's any define existing for "tab"
  18
  19//Could use strap stuff but I don't particularly care at the moment anyway.
  20#include "../namespace_begin.h"
  21
  22extern int	trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
  23extern void	trap_FS_Read( void *buffer, int len, fileHandle_t f );
  24extern void	trap_FS_Write( const void *buffer, int len, fileHandle_t f );
  25extern void	trap_FS_FCloseFile( fileHandle_t f );
  26extern int	trap_FS_GetFileList(  const char *path, const char *extension, char *listbuf, int bufsize );
  27
  28#ifndef QAGAME //cgame, ui
  29qhandle_t	trap_R_RegisterShaderNoMip( const char *name );
  30#endif
  31
  32char		siege_info[MAX_SIEGE_INFO_SIZE];
  33int			siege_valid = 0;
  34
  35siegeTeam_t *team1Theme = NULL;
  36siegeTeam_t *team2Theme = NULL;
  37
  38siegeClass_t bgSiegeClasses[MAX_SIEGE_CLASSES];
  39int bgNumSiegeClasses = 0;
  40
  41siegeTeam_t bgSiegeTeams[MAX_SIEGE_TEAMS];
  42int bgNumSiegeTeams = 0;
  43
  44//class flags
  45stringID_table_t bgSiegeClassFlagNames[] =
  46{
  47	ENUM2STRING(CFL_MORESABERDMG),
  48	ENUM2STRING(CFL_STRONGAGAINSTPHYSICAL),
  49	ENUM2STRING(CFL_FASTFORCEREGEN),
  50	ENUM2STRING(CFL_STATVIEWER),
  51	ENUM2STRING(CFL_HEAVYMELEE),
  52	ENUM2STRING(CFL_SINGLE_ROCKET),
  53	ENUM2STRING(CFL_CUSTOMSKEL),
  54	ENUM2STRING(CFL_EXTRA_AMMO),
  55	"", -1
  56};
  57
  58//saber stances
  59stringID_table_t StanceTable[] =
  60{
  61	ENUM2STRING(SS_NONE),
  62	ENUM2STRING(SS_FAST),
  63	ENUM2STRING(SS_MEDIUM),
  64	ENUM2STRING(SS_STRONG),
  65	ENUM2STRING(SS_DESANN),
  66	ENUM2STRING(SS_TAVION),
  67	ENUM2STRING(SS_DUAL),
  68	ENUM2STRING(SS_STAFF),
  69	"", 0
  70};
  71
  72//Weapon and force power tables are also used in NPC parsing code and some other places.
  73stringID_table_t WPTable[] =
  74{
  75	"NULL",WP_NONE,
  76	ENUM2STRING(WP_NONE),
  77	// Player weapons
  78	ENUM2STRING(WP_STUN_BATON),
  79	ENUM2STRING(WP_MELEE),
  80	ENUM2STRING(WP_SABER),
  81	ENUM2STRING(WP_BRYAR_PISTOL),
  82	"WP_BLASTER_PISTOL", WP_BRYAR_PISTOL,
  83	ENUM2STRING(WP_BLASTER),
  84	ENUM2STRING(WP_DISRUPTOR),
  85	ENUM2STRING(WP_BOWCASTER),
  86	ENUM2STRING(WP_REPEATER),
  87	ENUM2STRING(WP_DEMP2),
  88	ENUM2STRING(WP_FLECHETTE),
  89	ENUM2STRING(WP_ROCKET_LAUNCHER),
  90	ENUM2STRING(WP_THERMAL),
  91	ENUM2STRING(WP_TRIP_MINE),
  92	ENUM2STRING(WP_DET_PACK),
  93	ENUM2STRING(WP_CONCUSSION),
  94	ENUM2STRING(WP_BRYAR_OLD),
  95	ENUM2STRING(WP_EMPLACED_GUN),
  96	ENUM2STRING(WP_TURRET),
  97	"", 0
  98};
  99
 100stringID_table_t FPTable[] =
 101{
 102	ENUM2STRING(FP_HEAL),
 103	ENUM2STRING(FP_LEVITATION),
 104	ENUM2STRING(FP_SPEED),
 105	ENUM2STRING(FP_PUSH),
 106	ENUM2STRING(FP_PULL),
 107	ENUM2STRING(FP_TELEPATHY),
 108	ENUM2STRING(FP_GRIP),
 109	ENUM2STRING(FP_LIGHTNING),
 110	ENUM2STRING(FP_RAGE),
 111	ENUM2STRING(FP_PROTECT),
 112	ENUM2STRING(FP_ABSORB),
 113	ENUM2STRING(FP_TEAM_HEAL),
 114	ENUM2STRING(FP_TEAM_FORCE),
 115	ENUM2STRING(FP_DRAIN),
 116	ENUM2STRING(FP_SEE),
 117	ENUM2STRING(FP_SABER_OFFENSE),
 118	ENUM2STRING(FP_SABER_DEFENSE),
 119	ENUM2STRING(FP_SABERTHROW),
 120	"",	-1
 121};
 122
 123stringID_table_t HoldableTable[] =
 124{
 125	ENUM2STRING(HI_NONE),
 126
 127	ENUM2STRING(HI_SEEKER),
 128	ENUM2STRING(HI_SHIELD),
 129	ENUM2STRING(HI_MEDPAC),
 130	ENUM2STRING(HI_MEDPAC_BIG),
 131	ENUM2STRING(HI_BINOCULARS),
 132	ENUM2STRING(HI_SENTRY_GUN),
 133	ENUM2STRING(HI_JETPACK),
 134	ENUM2STRING(HI_HEALTHDISP),
 135	ENUM2STRING(HI_AMMODISP),
 136	ENUM2STRING(HI_EWEB),
 137	ENUM2STRING(HI_CLOAK),
 138
 139	"", -1
 140};
 141
 142stringID_table_t PowerupTable[] =
 143{
 144	ENUM2STRING(PW_NONE),
 145	ENUM2STRING(PW_QUAD),
 146	ENUM2STRING(PW_BATTLESUIT),
 147	ENUM2STRING(PW_PULL),
 148	ENUM2STRING(PW_REDFLAG),
 149	ENUM2STRING(PW_BLUEFLAG),
 150	ENUM2STRING(PW_NEUTRALFLAG),
 151	ENUM2STRING(PW_SHIELDHIT),
 152	ENUM2STRING(PW_SPEEDBURST),
 153	ENUM2STRING(PW_DISINT_4),
 154	ENUM2STRING(PW_SPEED),
 155	ENUM2STRING(PW_CLOAKED),
 156	ENUM2STRING(PW_FORCE_ENLIGHTENED_LIGHT),
 157	ENUM2STRING(PW_FORCE_ENLIGHTENED_DARK),
 158	ENUM2STRING(PW_FORCE_BOON),
 159	ENUM2STRING(PW_YSALAMIRI),
 160
 161	"", -1
 162};
 163
 164
 165//======================================
 166//Parsing functions
 167//======================================
 168void BG_SiegeStripTabs(char *buf)
 169{
 170	int i = 0;
 171	int i_r = 0;
 172
 173	while (buf[i])
 174	{
 175		if (buf[i] != SIEGECHAR_TAB)
 176		{ //not a tab, just stick it in
 177			buf[i_r] = buf[i];
 178		}
 179		else
 180		{ //If it's a tab, convert it to a space.
 181			buf[i_r] = ' ';
 182		}
 183
 184		i_r++;
 185		i++;
 186	}
 187
 188	buf[i_r] = '\0';
 189}
 190
 191int BG_SiegeGetValueGroup(char *buf, char *group, char *outbuf)
 192{
 193	int i = 0;
 194	int j;
 195	char checkGroup[4096];
 196	qboolean isGroup;
 197	int parseGroups = 0;
 198
 199	while (buf[i])
 200	{
 201		if (buf[i] != ' ' && buf[i] != '{' && buf[i] != '}' && buf[i] != '\n' && buf[i] != '\r' && buf[i] != SIEGECHAR_TAB)
 202		{ //we're on a valid character
 203			if (buf[i] == '/' &&
 204				buf[i+1] == '/')
 205			{ //this is a comment, so skip over it
 206				while (buf[i] && buf[i] != '\n' && buf[i] != '\r' && buf[i] != SIEGECHAR_TAB)
 207				{
 208					i++;
 209				}
 210			}
 211			else
 212			{ //parse to the next space/endline/eos and check this value against our group value.
 213				j = 0;
 214
 215				while (buf[i] != ' ' && buf[i] != '\n' && buf[i] != '\r' && buf[i] != SIEGECHAR_TAB && buf[i] != '{' && buf[i])
 216				{
 217					if (buf[i] == '/' && buf[i+1] == '/')
 218					{ //hit a comment, break out.
 219						break;
 220					}
 221
 222					checkGroup[j] = buf[i];
 223					j++;
 224					i++;
 225				}
 226				checkGroup[j] = 0;
 227
 228				//Make sure this is a group as opposed to a globally defined value.
 229				if (buf[i] == '/' && buf[i+1] == '/')
 230				{ //stopped on a comment, so first parse to the end of it.
 231                    while (buf[i] && buf[i] != '\n' && buf[i] != '\r')
 232					{
 233						i++;
 234					}
 235					while (buf[i] == '\n' || buf[i] == '\r')
 236					{
 237						i++;
 238					}
 239				}
 240
 241				if (!buf[i])
 242				{
 243					Com_Error(ERR_DROP, "Unexpected EOF while looking for group '%s'", group);
 244				}
 245
 246				isGroup = qfalse;
 247
 248				while (buf[i] && buf[i] == ' ' || buf[i] == SIEGECHAR_TAB || buf[i] == '\n' || buf[i] == '\r')
 249				{ //parse to the next valid character
 250					i++;
 251				}
 252
 253				if (buf[i] == '{')
 254				{ //if the next valid character is an opening bracket, then this is indeed a group
 255					isGroup = qtrue;
 256				}
 257
 258				//Is this the one we want?
 259				if (isGroup && !Q_stricmp(checkGroup, group))
 260				{ //guess so. Parse until we hit the { indicating the beginning of the group.
 261					while (buf[i] != '{' && buf[i])
 262					{
 263						i++;
 264					}
 265
 266					if (buf[i])
 267					{ //We're at the start of the group now, so parse to the closing bracket.
 268						j = 0;
 269
 270						parseGroups = 0;
 271
 272						while ((buf[i] != '}' || parseGroups) && buf[i])
 273						{
 274							if (buf[i] == '{')
 275							{ //increment for the opening bracket.
 276								parseGroups++;
 277							}
 278							else if (buf[i] == '}')
 279							{ //decrement for the closing bracket
 280								parseGroups--;
 281							}
 282
 283							if (parseGroups < 0)
 284							{ //Syntax error, I guess.
 285								Com_Error(ERR_DROP, "Found a closing bracket without an opening bracket while looking for group '%s'", group);
 286							}
 287
 288							if ((buf[i] != '{' || parseGroups > 1) &&
 289								(buf[i] != '}' || parseGroups > 0))
 290							{ //don't put the start and end brackets for this group into the output buffer
 291								outbuf[j] = buf[i];
 292								j++;
 293							}
 294
 295							if (buf[i] == '}' && !parseGroups)
 296							{ //Alright, we can break out now.
 297								break;
 298							}
 299
 300							i++;
 301						}
 302						outbuf[j] = 0;
 303
 304						//Verify that we ended up on the closing bracket.
 305						if (buf[i] != '}')
 306						{
 307							Com_Error(ERR_DROP, "Group '%s' is missing a closing bracket", group);
 308						}
 309
 310						//Strip the tabs so we're friendly for value parsing.
 311						BG_SiegeStripTabs(outbuf);
 312
 313						return 1; //we got it, so return 1.
 314					}
 315					else
 316					{
 317						Com_Error(ERR_DROP, "Error parsing group in file, unexpected EOF before opening bracket while looking for group '%s'", group);
 318					}
 319				}
 320				else if (!isGroup)
 321				{ //if it wasn't a group, parse to the end of the line
 322					while (buf[i] && buf[i] != '\n' && buf[i] != '\r')
 323					{
 324						i++;
 325					}
 326				}
 327				else
 328				{ //this was a group but we not the one we wanted to find, so parse by it.
 329					parseGroups = 0;
 330
 331					while (buf[i] && (buf[i] != '}' || parseGroups))
 332					{
 333						if (buf[i] == '{')
 334						{
 335							parseGroups++;
 336						}
 337						else if (buf[i] == '}')
 338						{
 339							parseGroups--;
 340						}
 341
 342						if (parseGroups < 0)
 343						{ //Syntax error, I guess.
 344							Com_Error(ERR_DROP, "Found a closing bracket without an opening bracket while looking for group '%s'", group);
 345						}
 346
 347						if (buf[i] == '}' && !parseGroups)
 348						{ //Alright, we can break out now.
 349							break;
 350						}
 351
 352						i++;
 353					}
 354
 355					if (buf[i] != '}')
 356					{
 357						Com_Error(ERR_DROP, "Found an opening bracket without a matching closing bracket while looking for group '%s'", group);
 358					}
 359
 360					i++;
 361				}
 362			}
 363		}
 364		else if (buf[i] == '{')
 365		{ //we're in a group that isn't the one we want, so parse to the end.
 366			parseGroups = 0;
 367
 368			while (buf[i] && (buf[i] != '}' || parseGroups))
 369			{
 370				if (buf[i] == '{')
 371				{
 372					parseGroups++;
 373				}
 374				else if (buf[i] == '}')
 375				{
 376					parseGroups--;
 377				}
 378
 379				if (parseGroups < 0)
 380				{ //Syntax error, I guess.
 381					Com_Error(ERR_DROP, "Found a closing bracket without an opening bracket while looking for group '%s'", group);
 382				}
 383
 384				if (buf[i] == '}' && !parseGroups)
 385				{ //Alright, we can break out now.
 386					break;
 387				}
 388
 389				i++;
 390			}
 391
 392			if (buf[i] != '}')
 393			{
 394				Com_Error(ERR_DROP, "Found an opening bracket without a matching closing bracket while looking for group '%s'", group);
 395			}
 396		}
 397
 398		if (!buf[i])
 399		{
 400			break;
 401		}
 402		i++;
 403	}
 404
 405	return 0; //guess we never found it.
 406}
 407
 408int BG_SiegeGetPairedValue(char *buf, char *key, char *outbuf)
 409{
 410	int i = 0;
 411	int j;
 412	int k;
 413	char checkKey[4096];
 414
 415	while (buf[i])
 416	{
 417		if (buf[i] != ' ' && buf[i] != '{' && buf[i] != '}' && buf[i] != '\n' && buf[i] != '\r')
 418		{ //we're on a valid character
 419			if (buf[i] == '/' &&
 420				buf[i+1] == '/')
 421			{ //this is a comment, so skip over it
 422				while (buf[i] && buf[i] != '\n' && buf[i] != '\r')
 423				{
 424					i++;
 425				}
 426			}
 427			else
 428			{ //parse to the next space/endline/eos and check this value against our key value.
 429				j = 0;
 430
 431				while (buf[i] != ' ' && buf[i] != '\n' && buf[i] != '\r' && buf[i] != SIEGECHAR_TAB && buf[i])
 432				{
 433					if (buf[i] == '/' && buf[i+1] == '/')
 434					{ //hit a comment, break out.
 435						break;
 436					}
 437
 438					checkKey[j] = buf[i];
 439					j++;
 440					i++;
 441				}
 442				checkKey[j] = 0;
 443
 444				k = i;
 445
 446				while (buf[k] && (buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\r'))
 447				{
 448					k++;
 449				}
 450
 451				if (buf[k] == '{')
 452				{ //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.
 453					int openB = 0;
 454
 455					while (buf[i] && (buf[i] != '}' || openB))
 456					{
 457						if (buf[i] == '{')
 458						{
 459							openB++;
 460						}
 461						else if (buf[i] == '}')
 462						{
 463							openB--;
 464						}
 465
 466						if (openB < 0)
 467						{
 468							Com_Error(ERR_DROP, "Unexpected closing bracket (too many) while parsing to end of group '%s'", checkKey);
 469						}
 470
 471						if (buf[i] == '}' && !openB)
 472						{ //this is the end of the group
 473							break;
 474						}
 475						i++;
 476					}
 477
 478					if (buf[i] == '}')
 479					{
 480						i++;
 481					}
 482				}
 483				else
 484				{
 485					//Is this the one we want?
 486					if (buf[i] != '/' || buf[i+1] != '/')
 487					{ //make sure we didn't stop on a comment, if we did then this is considered an error in the file.
 488						if (!Q_stricmp(checkKey, key))
 489						{ //guess so. Parse along to the next valid character, then put that into the output buffer and return 1.
 490							while ((buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\r' || buf[i] == SIEGECHAR_TAB) && buf[i])
 491							{
 492								i++;
 493							}
 494
 495							if (buf[i])
 496							{ //We're at the start of the value now.
 497								qboolean parseToQuote = qfalse;
 498
 499								if (buf[i] == '\"')
 500								{ //if the value is in quotes, then stop at the next quote instead of ' '
 501									i++;
 502									parseToQuote = qtrue;
 503								}
 504
 505								j = 0;
 506								while ( ((!parseToQuote && buf[i] != ' ' && buf[i] != '\n' && buf[i] != '\r') || (parseToQuote && buf[i] != '\"')) )
 507								{
 508									if (buf[i] == '/' &&
 509										buf[i+1] == '/')
 510									{ //hit a comment after the value? This isn't an ideal way to be writing things, but we'll support it anyway.
 511										break;
 512									}
 513									outbuf[j] = buf[i];
 514									j++;
 515									i++;
 516
 517									if (!buf[i])
 518									{
 519										if (parseToQuote)
 520										{
 521											Com_Error(ERR_DROP, "Unexpected EOF while looking for endquote, error finding paired value for '%s'", key);
 522										}
 523										else
 524										{
 525											Com_Error(ERR_DROP, "Unexpected EOF while looking for space or endline, error finding paired value for '%s'", key);
 526										}
 527									}
 528								}
 529								outbuf[j] = 0;
 530
 531								return 1; //we got it, so return 1.
 532							}
 533							else
 534							{
 535								Com_Error(ERR_DROP, "Error parsing file, unexpected EOF while looking for valud '%s'", key);
 536							}
 537						}
 538						else
 539						{ //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
 540							while (buf[i] && buf[i] != '\n')
 541							{
 542								i++;
 543							}
 544						}
 545					}
 546					else
 547					{
 548						Com_Error(ERR_DROP, "Error parsing file, found comment, expected value for '%s'", key);
 549					}
 550				}
 551			}
 552		}
 553
 554		if (!buf[i])
 555		{
 556			break;
 557		}
 558		i++;
 559	}
 560
 561	return 0; //guess we never found it.
 562}
 563//======================================
 564//End parsing functions
 565//======================================
 566
 567
 568//======================================
 569//Class loading functions
 570//======================================
 571void BG_SiegeTranslateForcePowers(char *buf, siegeClass_t *siegeClass)
 572{
 573	char checkPower[1024];
 574	char checkLevel[256];
 575	int l = 0;
 576	int k = 0;
 577	int j = 0;
 578	int i = 0;
 579	int parsedLevel = 0;
 580	qboolean allPowers = qfalse;
 581	qboolean noPowers = qfalse;
 582
 583	if (!Q_stricmp(buf, "FP_ALL"))
 584	{ //this is a special case, just give us all the powers on level 3
 585		allPowers = qtrue;
 586	}
 587
 588	if (buf[0] == '0' && !buf[1])
 589	{ //no powers then
 590		noPowers = qtrue;
 591	}
 592
 593	//First clear out the powers, or in the allPowers case, give us all level 3.
 594	while (i < NUM_FORCE_POWERS)
 595	{
 596		if (allPowers)
 597		{
 598			siegeClass->forcePowerLevels[i] = FORCE_LEVEL_3;
 599		}
 600		else
 601		{
 602			siegeClass->forcePowerLevels[i] = 0;
 603		}
 604		i++;
 605	}
 606
 607	if (allPowers || noPowers)
 608	{ //we're done now then.
 609		return;
 610	}
 611
 612	i = 0;
 613	while (buf[i])
 614	{ //parse through the list which is seperated by |, and add all the weapons into a bitflag
 615		if (buf[i] != ' ' && buf[i] != '|')
 616		{
 617			j = 0;
 618
 619			while (buf[i] && buf[i] != ' ' && buf[i] != '|' && buf[i] != ',')
 620			{
 621				checkPower[j] = buf[i];
 622				j++;
 623				i++;
 624			}
 625			checkPower[j] = 0;
 626
 627			if (buf[i] == ',')
 628			{ //parse the power level
 629				i++;
 630				l = 0;
 631				while (buf[i] && buf[i] != ' ' && buf[i] != '|')
 632				{
 633					checkLevel[l] = buf[i];
 634					l++;
 635					i++;
 636				}
 637				checkLevel[l] = 0;
 638				parsedLevel = atoi(checkLevel);
 639
 640				//keep sane limits on the powers
 641				if (parsedLevel < 0)
 642				{
 643					parsedLevel = 0;
 644				}
 645				if (parsedLevel > FORCE_LEVEL_5)
 646				{
 647					parsedLevel = FORCE_LEVEL_5;
 648				}
 649			}
 650			else
 651			{ //if it's not there, assume level 3 I guess.
 652				parsedLevel = 3;
 653			}
 654
 655			if (checkPower[0])
 656			{ //Got the name, compare it against the weapon table strings.
 657				k = 0;
 658
 659				if (!Q_stricmp(checkPower, "FP_JUMP"))
 660				{ //haqery
 661                    strcpy(checkPower, "FP_LEVITATION");
 662				}
 663
 664				while (FPTable[k].id != -1 && FPTable[k].name[0])
 665				{
 666					if (!Q_stricmp(checkPower, FPTable[k].name))
 667					{ //found it, add the weapon into the weapons value
 668						siegeClass->forcePowerLevels[k] = parsedLevel;
 669						break;
 670					}
 671					k++;
 672				}
 673			}
 674		}
 675
 676		if (!buf[i])
 677		{
 678			break;
 679		}
 680		i++;
 681	}
 682}
 683
 684//Used for the majority of generic val parsing stuff. buf should be the value string,
 685//table should be the appropriate string/id table. If bitflag is qtrue then the
 686//values are accumulated into a bitflag. If bitflag is qfalse then the first value
 687//is returned as a directly corresponding id and no further parsing is done.
 688int BG_SiegeTranslateGenericTable(char *buf, stringID_table_t *table, qboolean bitflag)
 689{
 690	int items = 0;
 691	char checkItem[1024];
 692	int i = 0;
 693	int j = 0;
 694	int k = 0;
 695
 696	if (buf[0] == '0' && !buf[1])
 697	{ //special case, no items.
 698		return 0;
 699	}
 700
 701	while (buf[i])
 702	{ //Using basically the same parsing method as we do for weapons and forcepowers.
 703		if (buf[i] != ' ' && buf[i] != '|')
 704		{
 705			j = 0;
 706
 707			while (buf[i] && buf[i] != ' ' && buf[i] != '|')
 708			{
 709				checkItem[j] = buf[i];
 710				j++;
 711				i++;
 712			}
 713			checkItem[j] = 0;
 714
 715			if (checkItem[0])
 716			{
 717				k = 0;
 718
 719                while (table[k].name && table[k].name[0])
 720				{ //go through the list and check the parsed flag name against the hardcoded names
 721					if (!Q_stricmp(checkItem, table[k].name))
 722					{ //Got it, so add the value into our items value.
 723						if (bitflag)
 724						{
 725							items |= (1 << table[k].id);
 726						}
 727						else
 728						{ //return the value directly then.
 729							return table[k].id;
 730						}
 731						break;
 732					}
 733					k++;
 734				}
 735			}
 736		}
 737
 738		if (!buf[i])
 739		{
 740			break;
 741		}
 742
 743		i++;
 744	}
 745	return items;
 746}
 747
 748char *classTitles[SPC_MAX] =
 749{
 750"infantry",			// SPC_INFANTRY
 751"vanguard",			// SPC_VANGUARD
 752"support",			// SPC_SUPPORT
 753"jedi_general",		// SPC_JEDI
 754"demolitionist",	// SPC_DEMOLITIONIST
 755"heavy_weapons",	// SPC_HEAVY_WEAPONS
 756};
 757
 758
 759void BG_SiegeParseClassFile(const char *filename, siegeClassDesc_t *descBuffer)
 760{
 761	fileHandle_t f;
 762	int len;
 763	int i;
 764	char classInfo[4096];
 765	char parseBuf[4096];
 766
 767	len = trap_FS_FOpenFile(filename, &f, FS_READ);
 768
 769	if (!f || len >= 4096)
 770	{
 771		return;
 772	}
 773
 774	trap_FS_Read(classInfo, len, f);
 775
 776	trap_FS_FCloseFile(f);
 777
 778	classInfo[len] = 0;
 779
 780	//first get the description if we have a buffer for it
 781	if (descBuffer)
 782	{
 783		if (!BG_SiegeGetPairedValue(classInfo, "description", descBuffer->desc))
 784		{
 785			strcpy(descBuffer->desc, "DESCRIPTION UNAVAILABLE");
 786		}
 787
 788		//Hit this assert?  Memory has already been trashed.  Increase
 789		//SIEGE_CLASS_DESC_LEN.
 790		assert(strlen(descBuffer->desc) < SIEGE_CLASS_DESC_LEN);
 791	}
 792
 793	BG_SiegeGetValueGroup(classInfo, "ClassInfo", classInfo);
 794
 795	//Parse name
 796	if (BG_SiegeGetPairedValue(classInfo, "name", parseBuf))
 797	{
 798		strcpy(bgSiegeClasses[bgNumSiegeClasses].name, parseBuf);
 799	}
 800	else
 801	{
 802		Com_Error(ERR_DROP, "Siege class without name entry");
 803	}
 804
 805	//Parse forced model
 806	if (BG_SiegeGetPairedValue(classInfo, "model", parseBuf))
 807	{
 808		strcpy(bgSiegeClasses[bgNumSiegeClasses].forcedModel, parseBuf);
 809	}
 810	else
 811	{ //It's ok if there isn't one, it's optional.
 812		bgSiegeClasses[bgNumSiegeClasses].forcedModel[0] = 0;
 813	}
 814
 815	//Parse forced skin
 816	if (BG_SiegeGetPairedValue(classInfo, "skin", parseBuf))
 817	{
 818		strcpy(bgSiegeClasses[bgNumSiegeClasses].forcedSkin, parseBuf);
 819	}
 820	else
 821	{ //It's ok if there isn't one, it's optional.
 822		bgSiegeClasses[bgNumSiegeClasses].forcedSkin[0] = 0;
 823	}
 824
 825	//Parse first saber
 826	if (BG_SiegeGetPairedValue(classInfo, "saber1", parseBuf))
 827	{
 828		strcpy(bgSiegeClasses[bgNumSiegeClasses].saber1, parseBuf);
 829	}
 830	else
 831	{ //It's ok if there isn't one, it's optional.
 832		bgSiegeClasses[bgNumSiegeClasses].saber1[0] = 0;
 833	}
 834
 835	//Parse second saber
 836	if (BG_SiegeGetPairedValue(classInfo, "saber2", parseBuf))
 837	{
 838		strcpy(bgSiegeClasses[bgNumSiegeClasses].saber2, parseBuf);
 839	}
 840	else
 841	{ //It's ok if there isn't one, it's optional.
 842		bgSiegeClasses[bgNumSiegeClasses].saber2[0] = 0;
 843	}
 844
 845	//Parse forced saber stance
 846	if (BG_SiegeGetPairedValue(classInfo, "saberstyle", parseBuf))
 847	{
 848		bgSiegeClasses[bgNumSiegeClasses].saberStance = BG_SiegeTranslateGenericTable(parseBuf, StanceTable, qtrue);
 849	}
 850	else
 851	{ //It's ok if there isn't one, it's optional.
 852		bgSiegeClasses[bgNumSiegeClasses].saberStance = 0;
 853	}
 854
 855	//Parse forced saber color
 856	if (BG_SiegeGetPairedValue(classInfo, "sabercolor", parseBuf))
 857	{
 858		bgSiegeClasses[bgNumSiegeClasses].forcedSaberColor = atoi(parseBuf);
 859		bgSiegeClasses[bgNumSiegeClasses].hasForcedSaberColor = qtrue;
 860	}
 861	else
 862	{ //It's ok if there isn't one, it's optional.
 863		bgSiegeClasses[bgNumSiegeClasses].hasForcedSaberColor = qfalse;
 864	}
 865
 866	//Parse forced saber2 color
 867	if (BG_SiegeGetPairedValue(classInfo, "saber2color", parseBuf))
 868	{
 869		bgSiegeClasses[bgNumSiegeClasses].forcedSaber2Color = atoi(parseBuf);
 870		bgSiegeClasses[bgNumSiegeClasses].hasForcedSaber2Color = qtrue;
 871	}
 872	else
 873	{ //It's ok if there isn't one, it's optional.
 874		bgSiegeClasses[bgNumSiegeClasses].hasForcedSaber2Color = qfalse;
 875	}
 876
 877	//Parse weapons
 878	if (BG_SiegeGetPairedValue(classInfo, "weapons", parseBuf))
 879	{
 880		bgSiegeClasses[bgNumSiegeClasses].weapons = BG_SiegeTranslateGenericTable(parseBuf, WPTable, qtrue);
 881	}
 882	else
 883	{
 884		Com_Error(ERR_DROP, "Siege class without weapons entry");
 885	}
 886
 887	if (!(bgSiegeClasses[bgNumSiegeClasses].weapons & (1 << WP_SABER)))
 888	{ //make sure it has melee if there's no saber
 889		bgSiegeClasses[bgNumSiegeClasses].weapons |= (1 << WP_MELEE);
 890
 891		//always give them this too if they are not a saber user
 892		//bgSiegeClasses[bgNumSiegeClasses].weapons |= (1 << WP_BRYAR_PISTOL);
 893	}
 894
 895	//Parse forcepowers
 896	if (BG_SiegeGetPairedValue(classInfo, "forcepowers", parseBuf))
 897	{
 898		BG_SiegeTranslateForcePowers(parseBuf, &bgSiegeClasses[bgNumSiegeClasses]);
 899	}
 900	else
 901	{ //fine, clear out the powers.
 902		i = 0;
 903		while (i < NUM_FORCE_POWERS)
 904		{
 905			bgSiegeClasses[bgNumSiegeClasses].forcePowerLevels[i] = 0;
 906			i++;
 907		}
 908	}
 909
 910	//Parse classflags
 911	if (BG_SiegeGetPairedValue(classInfo, "classflags", parseBuf))
 912	{
 913		bgSiegeClasses[bgNumSiegeClasses].classflags = BG_SiegeTranslateGenericTable(parseBuf, bgSiegeClassFlagNames, qtrue);
 914	}
 915	else
 916	{ //fine, we'll 0 it.
 917		bgSiegeClasses[bgNumSiegeClasses].classflags = 0;
 918	}
 919
 920	//Parse maxhealth
 921	if (BG_SiegeGetPairedValue(classInfo, "maxhealth", parseBuf))
 922	{
 923		bgSiegeClasses[bgNumSiegeClasses].maxhealth = atoi(parseBuf);
 924	}
 925	else
 926	{ //It's alright, just default to 100 then.
 927		bgSiegeClasses[bgNumSiegeClasses].maxhealth = 100;
 928	}
 929
 930	//Parse starthealth
 931	if (BG_SiegeGetPairedValue(classInfo, "starthealth", parseBuf))
 932	{
 933		bgSiegeClasses[bgNumSiegeClasses].starthealth = atoi(parseBuf);
 934	}
 935	else
 936	{ //It's alright, just default to 100 then.
 937		bgSiegeClasses[bgNumSiegeClasses].starthealth = bgSiegeClasses[bgNumSiegeClasses].maxhealth;
 938	}
 939
 940
 941	//Parse startarmor
 942	if (BG_SiegeGetPairedValue(classInfo, "maxarmor", parseBuf))
 943	{
 944		bgSiegeClasses[bgNumSiegeClasses].maxarmor = atoi(parseBuf);
 945	}
 946	else
 947	{ //It's alright, just default to 0 then.
 948		bgSiegeClasses[bgNumSiegeClasses].maxarmor = 0;
 949	}
 950
 951	//Parse startarmor
 952	if (BG_SiegeGetPairedValue(classInfo, "startarmor", parseBuf))
 953	{
 954		bgSiegeClasses[bgNumSiegeClasses].startarmor = atoi(parseBuf);
 955		if (!bgSiegeClasses[bgNumSiegeClasses].maxarmor)
 956		{ //if they didn't specify a damn max armor then use this.
 957			bgSiegeClasses[bgNumSiegeClasses].maxarmor = bgSiegeClasses[bgNumSiegeClasses].startarmor;
 958		}
 959	}
 960	else
 961	{ //default to maxarmor.
 962		bgSiegeClasses[bgNumSiegeClasses].startarmor = bgSiegeClasses[bgNumSiegeClasses].maxarmor;
 963	}
 964
 965	//Parse speed (this is a multiplier value)
 966	if (BG_SiegeGetPairedValue(classInfo, "speed", parseBuf))
 967	{
 968		bgSiegeClasses[bgNumSiegeClasses].speed = atof(parseBuf);
 969	}
 970	else
 971	{ //It's alright, just default to 1 then.
 972		bgSiegeClasses[bgNumSiegeClasses].speed = 1.0f;
 973	}
 974
 975	//Parse shader for ui to use
 976	if (BG_SiegeGetPairedValue(classInfo, "uishader", parseBuf))
 977	{
 978#ifdef QAGAME
 979		bgSiegeClasses[bgNumSiegeClasses].uiPortraitShader = 0;
 980		memset(bgSiegeClasses[bgNumSiegeClasses].uiPortrait,0,sizeof(bgSiegeClasses[bgNumSiegeClasses].uiPortrait));
 981#elif defined CGAME
 982		bgSiegeClasses[bgNumSiegeClasses].uiPortraitShader = 0;
 983		memset(bgSiegeClasses[bgNumSiegeClasses].uiPortrait,0,sizeof(bgSiegeClasses[bgNumSiegeClasses].uiPortrait));
 984#else //ui
 985		bgSiegeClasses[bgNumSiegeClasses].uiPortraitShader = trap_R_RegisterShaderNoMip(parseBuf);
 986		memcpy(bgSiegeClasses[bgNumSiegeClasses].uiPortrait,parseBuf,sizeof(bgSiegeClasses[bgNumSiegeClasses].uiPortrait));
 987#endif
 988	}
 989	else
 990	{ //I guess this is an essential.. we don't want to render bad shaders or anything.
 991		Com_Error(ERR_DROP, "Siege class without uishader entry");
 992	}
 993
 994	//Parse shader for ui to use
 995	if (BG_SiegeGetPairedValue(classInfo, "class_shader", parseBuf))
 996	{
 997#ifdef QAGAME
 998		bgSiegeClasses[bgNumSiegeClasses].classShader = 0;
 999#else //cgame, ui
1000		bgSiegeClasses[bgNumSiegeClasses].classShader = trap_R_RegisterShaderNoMip(parseBuf);
1001		assert( bgSiegeClasses[bgNumSiegeClasses].classShader );
1002		if ( !bgSiegeClasses[bgNumSiegeClasses].classShader )
1003		{
1004			//Com_Error( ERR_DROP, "ERROR: could not find class_shader %s for class %s\n", parseBuf, bgSiegeClasses[bgNumSiegeClasses].name );
1005			Com_Printf( "ERROR: could not find class_shader %s for class %s\n", parseBuf, bgSiegeClasses[bgNumSiegeClasses].name );
1006		}
1007		// A very hacky way to determine class . . . 
1008		else
1009#endif
1010		{
1011			// Find the base player class based on the icon name - very bad, I know.
1012			int titleLength,i,arrayTitleLength;
1013			char *holdBuf;
1014
1015			titleLength = strlen(parseBuf);
1016			for (i=0;i<SPC_MAX;i++)
1017			{
1018				// Back up 
1019				arrayTitleLength = strlen(classTitles[i]);
1020				if (arrayTitleLength>titleLength)	// Too long
1021				{
1022					break;
1023				}
1024
1025				holdBuf = parseBuf + ( titleLength - arrayTitleLength);
1026				if (!strcmp(holdBuf,classTitles[i]))
1027				{
1028					bgSiegeClasses[bgNumSiegeClasses].playerClass = i;
1029					break;
1030				}
1031			}
1032
1033			// In case the icon name doesn't match up
1034			if (i>=SPC_MAX)
1035			{
1036				bgSiegeClasses[bgNumSiegeClasses].playerClass = SPC_INFANTRY;
1037			}
1038		}
1039	}
1040	else
1041	{ //No entry!  Bad bad bad
1042		//Com_Error( ERR_DROP, "ERROR: no class_shader defined for class %s\n", bgSiegeClasses[bgNumSiegeClasses].name );
1043		Com_Printf( "ERROR: no class_shader defined for class %s\n", bgSiegeClasses[bgNumSiegeClasses].name );
1044	}
1045
1046	//Parse holdable items to use
1047	if (BG_SiegeGetPairedValue(classInfo, "holdables", parseBuf))
1048	{
1049		bgSiegeClasses[bgNumSiegeClasses].invenItems = BG_SiegeTranslateGenericTable(parseBuf, HoldableTable, qtrue);
1050	}
1051	else
1052	{ //Just don't start out with any then.
1053		bgSiegeClasses[bgNumSiegeClasses].invenItems = 0;
1054	}
1055
1056	//Parse powerups to use
1057	if (BG_SiegeGetPairedValue(classInfo, "powerups", parseBuf))
1058	{
1059		bgSiegeClasses[bgNumSiegeClasses].powerups = BG_SiegeTranslateGenericTable(parseBuf, PowerupTable, qtrue);
1060	}
1061	else
1062	{ //Just don't start out with any then.
1063		bgSiegeClasses[bgNumSiegeClasses].powerups = 0;
1064	}
1065
1066	//A successful read.
1067	bgNumSiegeClasses++;
1068}
1069
1070// Count the number of like base classes
1071int BG_SiegeCountBaseClass(const int team, const short classIndex)
1072{
1073	int count = 0,i;
1074	siegeTeam_t *stm;
1075
1076	stm = BG_SiegeFindThemeForTeam(team);
1077	if (!stm)
1078	{
1079		return(0);
1080
1081	}
1082
1083	for (i=0;i<stm->numClasses;i++)
1084	{
1085
1086		if (stm->classes[i]->playerClass == classIndex)
1087		{
1088			count++;
1089		}
1090	}
1091	return(count);
1092}
1093
1094char *BG_GetUIPortraitFile(const int team, const short classIndex, const short cntIndex)
1095{
1096	int count = 0,i;
1097	siegeTeam_t *stm;
1098
1099	stm = BG_SiegeFindThemeForTeam(team);
1100	if (!stm)
1101	{
1102		return(0);
1103
1104	}
1105
1106	// Loop through all the classes for this team
1107	for (i=0;i<stm->numClasses;i++)
1108	{
1109		// does it match the base class?
1110		if (stm->classes[i]->playerClass == classIndex)
1111		{
1112			if (count==cntIndex)
1113			{
1114				return(stm->classes[i]->uiPortrait);
1115			}
1116			++count;
1117		}
1118	}
1119
1120	return(0);
1121}
1122
1123int BG_GetUIPortrait(const int team, const short classIndex, const short cntIndex)
1124{
1125	int count = 0,i;
1126	siegeTeam_t *stm;
1127
1128	stm = BG_SiegeFindThemeForTeam(team);
1129	if (!stm)
1130	{
1131		return(0);
1132
1133	}
1134
1135	// Loop through all the classes for this team
1136	for (i=0;i<stm->numClasses;i++)
1137	{
1138		// does it match the base class?
1139		if (stm->classes[i]->playerClass == classIndex)
1140		{
1141			if (count==cntIndex)
1142			{
1143				return(stm->classes[i]->uiPortraitShader);
1144			}
1145			++count;
1146		}
1147	}
1148
1149	return(0);
1150}
1151
1152// This is really getting ugly - looking to get the base class (within a class) based on the index passed in
1153siegeClass_t *BG_GetClassOnBaseClass(const int team, const short classIndex, const short cntIndex)
1154{
1155	int count = 0,i;
1156	siegeTeam_t *stm;
1157
1158	stm = BG_SiegeFindThemeForTeam(team);
1159	if (!stm)
1160	{
1161		return(0);
1162	}
1163
1164	// Loop through all the classes for this team
1165	for (i=0;i<stm->numClasses;i++)
1166	{
1167		// does it match the base class?
1168		if (stm->classes[i]->playerClass == classIndex)
1169		{
1170			if (count==cntIndex)
1171			{
1172				return(stm->classes[i]);
1173			}
1174			++count;
1175		}
1176	}
1177
1178	return(0);
1179}
1180
1181void BG_SiegeLoadClasses(siegeClassDesc_t *descBuffer)
1182{
1183	int numFiles;
1184	int filelen;
1185	char filelist[4096];
1186	char filename[MAX_QPATH];
1187	char* fileptr;
1188	int i;
1189
1190	bgNumSiegeClasses = 0;
1191
1192	numFiles = trap_FS_GetFileList("ext_data/Siege/Classes", ".scl", filelist, 4096 );
1193	fileptr = filelist;
1194
1195	for (i = 0; i < numFiles; i++, fileptr += filelen+1)
1196	{
1197		filelen = strlen(fileptr);
1198		strcpy(filename, "ext_data/Siege/Classes/");
1199		strcat(filename, fileptr);
1200
1201		if (descBuffer)
1202		{
1203			BG_SiegeParseClassFile(filename, &descBuffer[i]);
1204		}
1205		else
1206		{
1207			BG_SiegeParseClassFile(filename, NULL);
1208		}
1209	}
1210}
1211//======================================
1212//End class loading functions
1213//======================================
1214
1215
1216//======================================
1217//Team loading functions
1218//======================================
1219siegeClass_t *BG_SiegeFindClassByName(const char *classname)
1220{
1221	int i = 0;
1222
1223	while (i < bgNumSiegeClasses)
1224	{
1225		if (!Q_stricmp(bgSiegeClasses[i].name, classname))
1226		{ //found it
1227			return &bgSiegeClasses[i];
1228		}
1229		i++;
1230	}
1231
1232	return NULL;
1233}
1234
1235void BG_SiegeParseTeamFile(const char *filename)
1236{
1237	fileHandle_t f;
1238	int len;
1239	char teamInfo[2048];
1240	char parseBuf[1024];
1241	char lookString[256];
1242	int i = 1;
1243	qboolean success = qtrue;
1244
1245	len = trap_FS_FOpenFile(filename, &f, FS_READ);
1246
1247	if (!f || len >= 2048)
1248	{
1249		return;
1250	}
1251
1252	trap_FS_Read(teamInfo, len, f);
1253
1254	trap_FS_FCloseFile(f);
1255
1256	teamInfo[len] = 0;
1257
1258	if (BG_SiegeGetPairedValue(teamInfo, "name", parseBuf))
1259	{
1260		strcpy(bgSiegeTeams[bgNumSiegeTeams].name, parseBuf);
1261	}
1262	else
1263	{
1264		Com_Error(ERR_DROP, "Siege team with no name definition");
1265	}
1266
1267//I don't entirely like doing things this way but it's the easiest way.
1268#ifdef CGAME
1269	if (BG_SiegeGetPairedValue(teamInfo, "FriendlyShader", parseBuf))
1270	{
1271		bgSiegeTeams[bgNumSiegeTeams].friendlyShader = trap_R_RegisterShaderNoMip(parseBuf);
1272	}
1273#else
1274	bgSiegeTeams[bgNumSiegeTeams].friendlyShader = 0;
1275#endif
1276
1277	bgSiegeTeams[bgNumSiegeTeams].numClasses = 0;
1278
1279	if (BG_SiegeGetValueGroup(teamInfo, "Classes", teamInfo))
1280	{
1281		while (success && i < MAX_SIEGE_CLASSES)
1282		{ //keep checking for group values named class# up to MAX_SIEGE_CLASSES until we can't find one.
1283			strcpy(lookString, va("class%i", i));
1284
1285			success = BG_SiegeGetPairedValue(teamInfo, lookString, parseBuf);
1286
1287			if (!success)
1288			{
1289				break;
1290			}
1291
1292			bgSiegeTeams[bgNumSiegeTeams].classes[bgSiegeTeams[bgNumSiegeTeams].numClasses] = BG_SiegeFindClassByName(parseBuf);
1293
1294			if (!bgSiegeTeams[bgNumSiegeTeams].classes[bgSiegeTeams[bgNumSiegeTeams].numClasses])
1295			{
1296				Com_Error(ERR_DROP, "Invalid class specified: '%s'", parseBuf);
1297			}
1298
1299			bgSiegeTeams[bgNumSiegeTeams].numClasses++;
1300
1301			i++;
1302		}
1303	}
1304
1305	if (!bgSiegeTeams[bgNumSiegeTeams].numClasses)
1306	{
1307		Com_Error(ERR_DROP, "Team defined with no allowable classes\n");
1308	}
1309
1310	//If we get here then it was a success, so increment the team number
1311	bgNumSiegeTeams++;
1312}
1313
1314void BG_SiegeLoadTeams(void)
1315{
1316	int numFiles;
1317	int filelen;
1318	char filelist[4096];
1319	char filename[MAX_QPATH];
1320	char* fileptr;
1321	int i;
1322
1323	bgNumSiegeTeams = 0;
1324
1325	numFiles = trap_FS_GetFileList("ext_data/Siege/Teams", ".team", filelist, 4096 );
1326	fileptr = filelist;
1327
1328	for (i = 0; i < numFiles; i++, fileptr += filelen+1)
1329	{
1330		filelen = strlen(fileptr);
1331		strcpy(filename, "ext_data/Siege/Teams/");
1332		strcat(filename, fileptr);
1333		BG_SiegeParseTeamFile(filename);
1334	}
1335}
1336//======================================
1337//End team loading functions
1338//======================================
1339
1340
1341//======================================
1342//Misc/utility functions
1343//======================================
1344siegeTeam_t *BG_SiegeFindThemeForTeam(int team)
1345{
1346	if (team == SIEGETEAM_TEAM1)
1347	{
1348		return team1Theme;
1349	}
1350	else if (team == SIEGETEAM_TEAM2)
1351	{
1352		return team2Theme;
1353	}
1354
1355    return NULL;
1356}
1357
1358#ifndef UI_EXPORTS //only for game/cgame
1359//precache all the sabers for the active classes for the team
1360extern qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ); //bg_saberLoad.cpp
1361extern int BG_ModelCache(const char *modelName, const char *skinName); //bg_misc.c
1362
1363void BG_PrecacheSabersForSiegeTeam(int team)
1364{
1365	siegeTeam_t *t;
1366	saberInfo_t saber;
1367	char *saberName;
1368	int sNum;
1369
1370	t = BG_SiegeFindThemeForTeam(team);
1371
1372	if (t)
1373	{
1374		int i = 0;
1375
1376		while (i < t->numClasses)
1377		{
1378			sNum = 0;
1379
1380			while (sNum < MAX_SABERS)
1381			{
1382				switch (sNum)
1383				{
1384				case 0:
1385					saberName = &t->classes[i]->saber1[0];
1386					break;
1387				case 1:
1388					saberName = &t->classes[i]->saber2[0];
1389					break;
1390				default:
1391					saberName = NULL;
1392					break;
1393				}
1394
1395				if (saberName && saberName[0])
1396				{
1397					WP_SaberParseParms(saberName, &saber);
1398					if (!Q_stricmp(saberName, saber.name))
1399					{ //found the matching saber
1400						if (saber.model[0])
1401						{
1402							BG_ModelCache(saber.model, NULL);
1403						}
1404					}
1405				}
1406
1407				sNum++;
1408			}
1409
1410			i++;
1411		}
1412	}
1413}
1414#endif
1415
1416qboolean BG_SiegeCheckClassLegality(int team, char *classname)
1417{
1418	siegeTeam_t **teamPtr = NULL;
1419	int i = 0;
1420
1421	if (team == SIEGETEAM_TEAM1)
1422	{
1423		teamPtr = &team1Theme;
1424	}
1425	else if (team == SIEGETEAM_TEAM2)
1426	{
1427		teamPtr = &team2Theme;
1428	}
1429	else
1430	{ //spectator? Whatever, you're legal then.
1431		return qtrue;
1432	}
1433
1434	if (!teamPtr || !(*teamPtr))
1435	{ //Well, guess the class is ok, seeing as there is no team theme to begin with.
1436		return qtrue;
1437	}
1438
1439	//See if the class is listed on the team
1440	while (i < (*teamPtr)->numClasses)
1441	{
1442		if (!Q_stricmp(classname, (*teamPtr)->classes[i]->name))
1443		{ //found it, so it's alright
1444			return qtrue;
1445		}
1446		i++;
1447	}
1448
1449	//Didn't find it, so copy the name of the first valid class over it.
1450	strcpy(classname, (*teamPtr)->classes[0]->name);
1451
1452	return qfalse;
1453}
1454
1455siegeTeam_t *BG_SiegeFindTeamForTheme(char *themeName)
1456{
1457	int i = 0;
1458
1459	while (i < bgNumSiegeTeams)
1460	{
1461		if (bgSiegeTeams[i].name &&
1462			!Q_stricmp(bgSiegeTeams[i].name, themeName))
1463		{ //this is what we're looking for
1464			return &bgSiegeTeams[i];
1465		}
1466
1467		i++;
1468	}
1469
1470	return NULL;
1471}
1472
1473void BG_SiegeSetTeamTheme(int team, char *themeName)
1474{
1475	siegeTeam_t **teamPtr = NULL;
1476
1477	if (team == SIEGETEAM_TEAM1)
1478	{
1479		teamPtr = &team1Theme;
1480	}
1481	else
1482	{
1483		teamPtr = &team2Theme;
1484	}
1485
1486	(*teamPtr) = BG_SiegeFindTeamForTheme(themeName);
1487}
1488
1489int BG_SiegeFindClassIndexByName(const char *classname)
1490{
1491	int i = 0;
1492
1493	while (i < bgNumSiegeClasses)
1494	{
1495		if (!Q_stricmp(bgSiegeClasses[i].name, classname))
1496		{ //found it
1497			return i;
1498		}
1499		i++;
1500	}
1501
1502	return -1;
1503}
1504//======================================
1505//End misc/utility functions
1506//======================================
1507
1508#include "../namespace_end.h"