PageRenderTime 114ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

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