PageRenderTime 175ms CodeModel.GetById 31ms app.highlight 116ms RepoModel.GetById 14ms app.codeStats 1ms

/codemp/game/bg_saga.c

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