ui_saber.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. //
  2. /*
  3. =======================================================================
  4. USER INTERFACE SABER LOADING & DISPLAY CODE
  5. =======================================================================
  6. */
  7. // leave this at the top of all UI_xxxx files for PCH reasons...
  8. //
  9. #include "../server/exe_headers.h"
  10. #include "ui_local.h"
  11. #include "ui_shared.h"
  12. #include "../ghoul2/G2.h"
  13. #define MAX_SABER_DATA_SIZE 0x8000
  14. // On Xbox, static linking lets us steal the buffer from wp_saberLoad
  15. // Just make sure that the saber data size is the same
  16. #ifdef _XBOX
  17. extern char SaberParms[MAX_SABER_DATA_SIZE];
  18. #else
  19. char SaberParms[MAX_SABER_DATA_SIZE];
  20. #endif
  21. qboolean ui_saber_parms_parsed = qfalse;
  22. static qhandle_t redSaberGlowShader;
  23. static qhandle_t redSaberCoreShader;
  24. static qhandle_t orangeSaberGlowShader;
  25. static qhandle_t orangeSaberCoreShader;
  26. static qhandle_t yellowSaberGlowShader;
  27. static qhandle_t yellowSaberCoreShader;
  28. static qhandle_t greenSaberGlowShader;
  29. static qhandle_t greenSaberCoreShader;
  30. static qhandle_t blueSaberGlowShader;
  31. static qhandle_t blueSaberCoreShader;
  32. static qhandle_t purpleSaberGlowShader;
  33. static qhandle_t purpleSaberCoreShader;
  34. void UI_CacheSaberGlowGraphics( void )
  35. {//FIXME: these get fucked by vid_restarts
  36. redSaberGlowShader = re.RegisterShader( "gfx/effects/sabers/red_glow" );
  37. redSaberCoreShader = re.RegisterShader( "gfx/effects/sabers/red_line" );
  38. orangeSaberGlowShader = re.RegisterShader( "gfx/effects/sabers/orange_glow" );
  39. orangeSaberCoreShader = re.RegisterShader( "gfx/effects/sabers/orange_line" );
  40. yellowSaberGlowShader = re.RegisterShader( "gfx/effects/sabers/yellow_glow" );
  41. yellowSaberCoreShader = re.RegisterShader( "gfx/effects/sabers/yellow_line" );
  42. greenSaberGlowShader = re.RegisterShader( "gfx/effects/sabers/green_glow" );
  43. greenSaberCoreShader = re.RegisterShader( "gfx/effects/sabers/green_line" );
  44. blueSaberGlowShader = re.RegisterShader( "gfx/effects/sabers/blue_glow" );
  45. blueSaberCoreShader = re.RegisterShader( "gfx/effects/sabers/blue_line" );
  46. purpleSaberGlowShader = re.RegisterShader( "gfx/effects/sabers/purple_glow" );
  47. purpleSaberCoreShader = re.RegisterShader( "gfx/effects/sabers/purple_line" );
  48. }
  49. qboolean UI_ParseLiteral( const char **data, const char *string )
  50. {
  51. const char *token;
  52. token = COM_ParseExt( data, qtrue );
  53. if ( token[0] == 0 )
  54. {
  55. ui.Printf( "unexpected EOF\n" );
  56. return qtrue;
  57. }
  58. if ( Q_stricmp( token, string ) )
  59. {
  60. ui.Printf( "required string '%s' missing\n", string );
  61. return qtrue;
  62. }
  63. return qfalse;
  64. }
  65. qboolean UI_SaberParseParm( const char *saberName, const char *parmname, char *saberData )
  66. {
  67. const char *token;
  68. const char *value;
  69. const char *p;
  70. if ( !saberName || !saberName[0] )
  71. {
  72. return qfalse;
  73. }
  74. //try to parse it out
  75. p = SaberParms;
  76. COM_BeginParseSession();
  77. // look for the right saber
  78. while ( p )
  79. {
  80. token = COM_ParseExt( &p, qtrue );
  81. if ( token[0] == 0 )
  82. {
  83. return qfalse;
  84. }
  85. if ( !Q_stricmp( token, saberName ) )
  86. {
  87. break;
  88. }
  89. SkipBracedSection( &p );
  90. }
  91. if ( !p )
  92. {
  93. return qfalse;
  94. }
  95. if ( UI_ParseLiteral( &p, "{" ) )
  96. {
  97. return qfalse;
  98. }
  99. // parse the saber info block
  100. while ( 1 )
  101. {
  102. token = COM_ParseExt( &p, qtrue );
  103. if ( !token[0] )
  104. {
  105. ui.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", saberName );
  106. return qfalse;
  107. }
  108. if ( !Q_stricmp( token, "}" ) )
  109. {
  110. break;
  111. }
  112. if ( !Q_stricmp( token, parmname ) )
  113. {
  114. if ( COM_ParseString( &p, &value ) )
  115. {
  116. continue;
  117. }
  118. strcpy( saberData, value );
  119. return qtrue;
  120. }
  121. SkipRestOfLine( &p );
  122. continue;
  123. }
  124. return qfalse;
  125. }
  126. qboolean UI_SaberProperNameForSaber( const char *saberName, char *saberProperName )
  127. {
  128. return UI_SaberParseParm( saberName, "name", saberProperName );
  129. }
  130. qboolean UI_SaberModelForSaber( const char *saberName, char *saberModel )
  131. {
  132. return UI_SaberParseParm( saberName, "saberModel", saberModel );
  133. }
  134. qboolean UI_SaberSkinForSaber( const char *saberName, char *saberSkin )
  135. {
  136. return UI_SaberParseParm( saberName, "customSkin", saberSkin );
  137. }
  138. qboolean UI_SaberTypeForSaber( const char *saberName, char *saberType )
  139. {
  140. return UI_SaberParseParm( saberName, "saberType", saberType );
  141. }
  142. int UI_SaberNumBladesForSaber( const char *saberName )
  143. {
  144. char numBladesString[8]={0};
  145. UI_SaberParseParm( saberName, "numBlades", numBladesString );
  146. int numBlades = atoi( numBladesString );
  147. if ( numBlades < 1 )
  148. {
  149. numBlades = 1;
  150. }
  151. else if ( numBlades > 8 )
  152. {
  153. numBlades = 8;
  154. }
  155. return numBlades;
  156. }
  157. float UI_SaberBladeLengthForSaber( const char *saberName, int bladeNum )
  158. {
  159. char lengthString[8]={0};
  160. float length = 40.0f;
  161. UI_SaberParseParm( saberName, "saberLength", lengthString );
  162. if ( lengthString[0] )
  163. {
  164. length = atof( lengthString );
  165. if ( length < 0.0f )
  166. {
  167. length = 0.0f;
  168. }
  169. }
  170. UI_SaberParseParm( saberName, va("saberLength%d", bladeNum+1), lengthString );
  171. if ( lengthString[0] )
  172. {
  173. length = atof( lengthString );
  174. if ( length < 0.0f )
  175. {
  176. length = 0.0f;
  177. }
  178. }
  179. return length;
  180. }
  181. float UI_SaberBladeRadiusForSaber( const char *saberName, int bladeNum )
  182. {
  183. char radiusString[8]={0};
  184. float radius = 3.0f;
  185. UI_SaberParseParm( saberName, "saberRadius", radiusString );
  186. if ( radiusString[0] )
  187. {
  188. radius = atof( radiusString );
  189. if ( radius < 0.0f )
  190. {
  191. radius = 0.0f;
  192. }
  193. }
  194. UI_SaberParseParm( saberName, va("saberRadius%d", bladeNum+1), radiusString );
  195. if ( radiusString[0] )
  196. {
  197. radius = atof( radiusString );
  198. if ( radius < 0.0f )
  199. {
  200. radius = 0.0f;
  201. }
  202. }
  203. return radius;
  204. }
  205. void UI_SaberLoadParms( void )
  206. {
  207. int len, totallen, saberExtFNLen, fileCnt, i;
  208. char *buffer, *holdChar, *marker;
  209. char saberExtensionListBuf[2048]; // The list of file names read in
  210. //ui.Printf( "UI Parsing *.sab saber definitions\n" );
  211. ui_saber_parms_parsed = qtrue;
  212. UI_CacheSaberGlowGraphics();
  213. //set where to store the first one
  214. totallen = 0;
  215. marker = SaberParms;
  216. marker[0] = '\0';
  217. //now load in the sabers
  218. fileCnt = ui.FS_GetFileList("ext_data/sabers", ".sab", saberExtensionListBuf, sizeof(saberExtensionListBuf) );
  219. holdChar = saberExtensionListBuf;
  220. for ( i = 0; i < fileCnt; i++, holdChar += saberExtFNLen + 1 )
  221. {
  222. saberExtFNLen = strlen( holdChar );
  223. len = ui.FS_ReadFile( va( "ext_data/sabers/%s", holdChar), (void **) &buffer );
  224. if ( len == -1 )
  225. {
  226. ui.Printf( "UI_SaberLoadParms: error reading %s\n", holdChar );
  227. }
  228. else
  229. {
  230. if ( totallen && *(marker-1) == '}' )
  231. {//don't let it end on a } because that should be a stand-alone token
  232. strcat( marker, " " );
  233. totallen++;
  234. marker++;
  235. }
  236. len = COM_Compress( buffer );
  237. if ( totallen + len >= MAX_SABER_DATA_SIZE ) {
  238. Com_Error( ERR_FATAL, "UI_SaberLoadParms: ran out of space before reading %s\n(you must make the .npc files smaller)", holdChar );
  239. }
  240. strcat( marker, buffer );
  241. ui.FS_FreeFile( buffer );
  242. totallen += len;
  243. marker += len;
  244. }
  245. }
  246. }
  247. void UI_DoSaber( vec3_t origin, vec3_t dir, float length, float lengthMax, float radius, saber_colors_t color )
  248. {
  249. vec3_t mid, rgb={1,1,1};
  250. qhandle_t blade = 0, glow = 0;
  251. refEntity_t saber;
  252. float radiusmult;
  253. if ( length < 0.5f )
  254. {
  255. // if the thing is so short, just forget even adding me.
  256. return;
  257. }
  258. // Find the midpoint of the saber for lighting purposes
  259. VectorMA( origin, length * 0.5f, dir, mid );
  260. switch( color )
  261. {
  262. case SABER_RED:
  263. glow = redSaberGlowShader;
  264. blade = redSaberCoreShader;
  265. VectorSet( rgb, 1.0f, 0.2f, 0.2f );
  266. break;
  267. case SABER_ORANGE:
  268. glow = orangeSaberGlowShader;
  269. blade = orangeSaberCoreShader;
  270. VectorSet( rgb, 1.0f, 0.5f, 0.1f );
  271. break;
  272. case SABER_YELLOW:
  273. glow = yellowSaberGlowShader;
  274. blade = yellowSaberCoreShader;
  275. VectorSet( rgb, 1.0f, 1.0f, 0.2f );
  276. break;
  277. case SABER_GREEN:
  278. glow = greenSaberGlowShader;
  279. blade = greenSaberCoreShader;
  280. VectorSet( rgb, 0.2f, 1.0f, 0.2f );
  281. break;
  282. case SABER_BLUE:
  283. glow = blueSaberGlowShader;
  284. blade = blueSaberCoreShader;
  285. VectorSet( rgb, 0.2f, 0.4f, 1.0f );
  286. break;
  287. case SABER_PURPLE:
  288. glow = purpleSaberGlowShader;
  289. blade = purpleSaberCoreShader;
  290. VectorSet( rgb, 0.9f, 0.2f, 1.0f );
  291. break;
  292. }
  293. // always add a light because sabers cast a nice glow before they slice you in half!! or something...
  294. /*
  295. if ( doLight )
  296. {//FIXME: RGB combine all the colors of the sabers you're using into one averaged color!
  297. cgi_R_AddLightToScene( mid, (length*2.0f) + (random()*8.0f), rgb[0], rgb[1], rgb[2] );
  298. }
  299. */
  300. memset( &saber, 0, sizeof( refEntity_t ));
  301. // Saber glow is it's own ref type because it uses a ton of sprites, otherwise it would eat up too many
  302. // refEnts to do each glow blob individually
  303. saber.saberLength = length;
  304. // Jeff, I did this because I foolishly wished to have a bright halo as the saber is unleashed.
  305. // It's not quite what I'd hoped tho. If you have any ideas, go for it! --Pat
  306. if (length < lengthMax )
  307. {
  308. radiusmult = 1.0 + (2.0 / length); // Note this creates a curve, and length cannot be < 0.5.
  309. }
  310. else
  311. {
  312. radiusmult = 1.0;
  313. }
  314. float radiusRange = radius * 0.075f;
  315. float radiusStart = radius-radiusRange;
  316. saber.radius = (radiusStart + crandom() * radiusRange)*radiusmult;
  317. //saber.radius = (2.8f + crandom() * 0.2f)*radiusmult;
  318. VectorCopy( origin, saber.origin );
  319. VectorCopy( dir, saber.axis[0] );
  320. saber.reType = RT_SABER_GLOW;
  321. saber.customShader = glow;
  322. saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff;
  323. //saber.renderfx = rfx;
  324. DC->addRefEntityToScene( &saber );
  325. // Do the hot core
  326. VectorMA( origin, length, dir, saber.origin );
  327. VectorMA( origin, -1, dir, saber.oldorigin );
  328. saber.customShader = blade;
  329. saber.reType = RT_LINE;
  330. radiusStart = radius/3.0f;
  331. saber.radius = (radiusStart + crandom() * radiusRange)*radiusmult;
  332. // saber.radius = (1.0 + crandom() * 0.2f)*radiusmult;
  333. DC->addRefEntityToScene( &saber );
  334. }
  335. saber_colors_t TranslateSaberColor( const char *name )
  336. {
  337. if ( !Q_stricmp( name, "red" ) )
  338. {
  339. return SABER_RED;
  340. }
  341. if ( !Q_stricmp( name, "orange" ) )
  342. {
  343. return SABER_ORANGE;
  344. }
  345. if ( !Q_stricmp( name, "yellow" ) )
  346. {
  347. return SABER_YELLOW;
  348. }
  349. if ( !Q_stricmp( name, "green" ) )
  350. {
  351. return SABER_GREEN;
  352. }
  353. if ( !Q_stricmp( name, "blue" ) )
  354. {
  355. return SABER_BLUE;
  356. }
  357. if ( !Q_stricmp( name, "purple" ) )
  358. {
  359. return SABER_PURPLE;
  360. }
  361. if ( !Q_stricmp( name, "random" ) )
  362. {
  363. return ((saber_colors_t)(Q_irand( SABER_ORANGE, SABER_PURPLE )));
  364. }
  365. return SABER_BLUE;
  366. }
  367. saberType_t TranslateSaberType( const char *name )
  368. {
  369. if ( !Q_stricmp( name, "SABER_SINGLE" ) )
  370. {
  371. return SABER_SINGLE;
  372. }
  373. if ( !Q_stricmp( name, "SABER_STAFF" ) )
  374. {
  375. return SABER_STAFF;
  376. }
  377. if ( !Q_stricmp( name, "SABER_BROAD" ) )
  378. {
  379. return SABER_BROAD;
  380. }
  381. if ( !Q_stricmp( name, "SABER_PRONG" ) )
  382. {
  383. return SABER_PRONG;
  384. }
  385. if ( !Q_stricmp( name, "SABER_DAGGER" ) )
  386. {
  387. return SABER_DAGGER;
  388. }
  389. if ( !Q_stricmp( name, "SABER_ARC" ) )
  390. {
  391. return SABER_ARC;
  392. }
  393. if ( !Q_stricmp( name, "SABER_SAI" ) )
  394. {
  395. return SABER_SAI;
  396. }
  397. if ( !Q_stricmp( name, "SABER_CLAW" ) )
  398. {
  399. return SABER_CLAW;
  400. }
  401. if ( !Q_stricmp( name, "SABER_LANCE" ) )
  402. {
  403. return SABER_LANCE;
  404. }
  405. if ( !Q_stricmp( name, "SABER_STAR" ) )
  406. {
  407. return SABER_STAR;
  408. }
  409. if ( !Q_stricmp( name, "SABER_TRIDENT" ) )
  410. {
  411. return SABER_TRIDENT;
  412. }
  413. if ( !Q_stricmp( name, "SABER_SITH_SWORD" ) )
  414. {
  415. return SABER_SITH_SWORD;
  416. }
  417. return SABER_SINGLE;
  418. }
  419. void UI_SaberDrawBlade( itemDef_t *item, char *saberName, int saberModel, saberType_t saberType, vec3_t origin, float curYaw, int bladeNum )
  420. {
  421. char bladeColorString[MAX_QPATH];
  422. vec3_t angles={0};
  423. // if ( item->flags&(ITF_ISANYSABER) && item->flags&(ITF_ISCHARACTER) )
  424. { //it's bolted to a dude!
  425. angles[YAW] = curYaw;
  426. }
  427. // else
  428. // {
  429. // angles[PITCH] = curYaw;
  430. // angles[ROLL] = 90;
  431. // }
  432. if ( saberModel >= item->ghoul2.size() )
  433. {//uhh... invalid index!
  434. return;
  435. }
  436. if ( (item->flags&ITF_ISSABER) && saberModel < 2 )
  437. {
  438. DC->getCVarString( "ui_saber_color", bladeColorString, sizeof(bladeColorString) );
  439. }
  440. else//if ( item->flags&ITF_ISSABER2 ) - presumed
  441. {
  442. DC->getCVarString( "ui_saber2_color", bladeColorString, sizeof(bladeColorString) );
  443. }
  444. saber_colors_t bladeColor = TranslateSaberColor( bladeColorString );
  445. float bladeLength = UI_SaberBladeLengthForSaber( saberName, bladeNum );
  446. float bladeRadius = UI_SaberBladeRadiusForSaber( saberName, bladeNum );
  447. vec3_t bladeOrigin={0};
  448. vec3_t axis[3]={0};
  449. mdxaBone_t boltMatrix;
  450. qboolean tagHack = qfalse;
  451. char *tagName = va( "*blade%d", bladeNum+1 );
  452. int bolt = DC->g2_AddBolt( &item->ghoul2[saberModel], tagName );
  453. if ( bolt == -1 )
  454. {
  455. tagHack = qtrue;
  456. //hmm, just fall back to the most basic tag (this will also make it work with pre-JKA saber models
  457. bolt = DC->g2_AddBolt( &item->ghoul2[saberModel], "*flash" );
  458. if ( bolt == -1 )
  459. {//no tag_flash either?!!
  460. bolt = 0;
  461. }
  462. }
  463. DC->g2_GetBoltMatrix( item->ghoul2, saberModel, bolt, &boltMatrix, angles, origin, uiInfo.uiDC.realTime, NULL, vec3_origin );//NULL was cgs.model_draw
  464. // work the matrix axis stuff into the original axis and origins used.
  465. DC->g2_GiveMeVectorFromMatrix(boltMatrix, ORIGIN, bladeOrigin);
  466. DC->g2_GiveMeVectorFromMatrix(boltMatrix, NEGATIVE_X, axis[0]);//front (was NEGATIVE_Y, but the md3->glm exporter screws up this tag somethin' awful)
  467. DC->g2_GiveMeVectorFromMatrix(boltMatrix, NEGATIVE_Y, axis[1]);//right
  468. DC->g2_GiveMeVectorFromMatrix(boltMatrix, POSITIVE_Z, axis[2]);//up
  469. float scale = DC->xscale;
  470. if ( tagHack )
  471. {
  472. switch ( saberType )
  473. {
  474. case SABER_SINGLE:
  475. case SABER_DAGGER:
  476. case SABER_LANCE:
  477. break;
  478. case SABER_STAFF:
  479. if ( bladeNum == 1 )
  480. {
  481. VectorScale( axis[0], -1, axis[0] );
  482. VectorMA( bladeOrigin, 16*scale, axis[0], bladeOrigin );
  483. }
  484. break;
  485. case SABER_BROAD:
  486. if ( bladeNum == 0 )
  487. {
  488. VectorMA( bladeOrigin, -1*scale, axis[1], bladeOrigin );
  489. }
  490. else if ( bladeNum == 1 )
  491. {
  492. VectorMA( bladeOrigin, 1*scale, axis[1], bladeOrigin );
  493. }
  494. break;
  495. case SABER_PRONG:
  496. if ( bladeNum == 0 )
  497. {
  498. VectorMA( bladeOrigin, -3*scale, axis[1], bladeOrigin );
  499. }
  500. else if ( bladeNum == 1 )
  501. {
  502. VectorMA( bladeOrigin, 3*scale, axis[1], bladeOrigin );
  503. }
  504. break;
  505. case SABER_ARC:
  506. VectorSubtract( axis[1], axis[2], axis[1] );
  507. VectorNormalize( axis[1] );
  508. switch ( bladeNum )
  509. {
  510. case 0:
  511. VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
  512. VectorScale( axis[0], 0.75f, axis[0] );
  513. VectorScale( axis[1], 0.25f, axis[1] );
  514. VectorAdd( axis[0], axis[1], axis[0] );
  515. break;
  516. case 1:
  517. VectorScale( axis[0], 0.25f, axis[0] );
  518. VectorScale( axis[1], 0.75f, axis[1] );
  519. VectorAdd( axis[0], axis[1], axis[0] );
  520. break;
  521. case 2:
  522. VectorMA( bladeOrigin, -8*scale, axis[0], bladeOrigin );
  523. VectorScale( axis[0], -0.25f, axis[0] );
  524. VectorScale( axis[1], 0.75f, axis[1] );
  525. VectorAdd( axis[0], axis[1], axis[0] );
  526. break;
  527. case 3:
  528. VectorMA( bladeOrigin, -16*scale, axis[0], bladeOrigin );
  529. VectorScale( axis[0], -0.75f, axis[0] );
  530. VectorScale( axis[1], 0.25f, axis[1] );
  531. VectorAdd( axis[0], axis[1], axis[0] );
  532. break;
  533. }
  534. break;
  535. case SABER_SAI:
  536. if ( bladeNum == 1 )
  537. {
  538. VectorMA( bladeOrigin, -3*scale, axis[1], bladeOrigin );
  539. }
  540. else if ( bladeNum == 2 )
  541. {
  542. VectorMA( bladeOrigin, 3*scale, axis[1], bladeOrigin );
  543. }
  544. break;
  545. case SABER_CLAW:
  546. switch ( bladeNum )
  547. {
  548. case 0:
  549. VectorMA( bladeOrigin, 2*scale, axis[0], bladeOrigin );
  550. VectorMA( bladeOrigin, 2*scale, axis[2], bladeOrigin );
  551. break;
  552. case 1:
  553. VectorMA( bladeOrigin, 2*scale, axis[0], bladeOrigin );
  554. VectorMA( bladeOrigin, 2*scale, axis[2], bladeOrigin );
  555. VectorMA( bladeOrigin, 2*scale, axis[1], bladeOrigin );
  556. break;
  557. case 2:
  558. VectorMA( bladeOrigin, 2*scale, axis[0], bladeOrigin );
  559. VectorMA( bladeOrigin, 2*scale, axis[2], bladeOrigin );
  560. VectorMA( bladeOrigin, -2*scale, axis[1], bladeOrigin );
  561. break;
  562. }
  563. break;
  564. case SABER_STAR:
  565. switch ( bladeNum )
  566. {
  567. case 0:
  568. VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
  569. break;
  570. case 1:
  571. VectorScale( axis[0], 0.33f, axis[0] );
  572. VectorScale( axis[2], 0.67f, axis[2] );
  573. VectorAdd( axis[0], axis[2], axis[0] );
  574. VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
  575. break;
  576. case 2:
  577. VectorScale( axis[0], -0.33f, axis[0] );
  578. VectorScale( axis[2], 0.67f, axis[2] );
  579. VectorAdd( axis[0], axis[2], axis[0] );
  580. VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
  581. break;
  582. case 3:
  583. VectorScale( axis[0], -1, axis[0] );
  584. VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
  585. break;
  586. case 4:
  587. VectorScale( axis[0], -0.33f, axis[0] );
  588. VectorScale( axis[2], -0.67f, axis[2] );
  589. VectorAdd( axis[0], axis[2], axis[0] );
  590. VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
  591. break;
  592. case 5:
  593. VectorScale( axis[0], 0.33f, axis[0] );
  594. VectorScale( axis[2], -0.67f, axis[2] );
  595. VectorAdd( axis[0], axis[2], axis[0] );
  596. VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
  597. break;
  598. }
  599. break;
  600. case SABER_TRIDENT:
  601. switch ( bladeNum )
  602. {
  603. case 0:
  604. VectorMA( bladeOrigin, 24*scale, axis[0], bladeOrigin );
  605. break;
  606. case 1:
  607. VectorMA( bladeOrigin, -6*scale, axis[1], bladeOrigin );
  608. VectorMA( bladeOrigin, 24*scale, axis[0], bladeOrigin );
  609. break;
  610. case 2:
  611. VectorMA( bladeOrigin, 6*scale, axis[1], bladeOrigin );
  612. VectorMA( bladeOrigin, 24*scale, axis[0], bladeOrigin );
  613. break;
  614. case 3:
  615. VectorMA( bladeOrigin, -32*scale, axis[0], bladeOrigin );
  616. VectorScale( axis[0], -1, axis[0] );
  617. break;
  618. }
  619. break;
  620. case SABER_SITH_SWORD:
  621. //no blade
  622. break;
  623. }
  624. }
  625. if ( saberType == SABER_SITH_SWORD )
  626. {//draw no blade
  627. return;
  628. }
  629. UI_DoSaber( bladeOrigin, axis[0], bladeLength, bladeLength, bladeRadius, bladeColor );
  630. }
  631. extern qboolean ItemParse_asset_model_go( itemDef_t *item, const char *name );
  632. extern qboolean ItemParse_model_g2skin_go( itemDef_t *item, const char *skinName );
  633. void UI_GetSaberForMenu( char *saber, int saberNum )
  634. {
  635. char saberTypeString[MAX_QPATH]={0};
  636. saberType_t saberType = SABER_NONE;
  637. if ( saberNum == 0 )
  638. {
  639. DC->getCVarString( "g_saber", saber, MAX_QPATH );
  640. }
  641. else
  642. {
  643. DC->getCVarString( "g_saber2", saber, MAX_QPATH );
  644. }
  645. //read this from the sabers.cfg
  646. UI_SaberTypeForSaber( saber, saberTypeString );
  647. if ( saberTypeString[0] )
  648. {
  649. saberType = TranslateSaberType( saberTypeString );
  650. }
  651. switch ( uiInfo.movesTitleIndex )
  652. {
  653. case 0://MD_ACROBATICS:
  654. break;
  655. case 1://MD_SINGLE_FAST:
  656. case 2://MD_SINGLE_MEDIUM:
  657. case 3://MD_SINGLE_STRONG:
  658. if ( saberType != SABER_SINGLE )
  659. {
  660. Q_strncpyz(saber,"single_1",MAX_QPATH,qtrue);
  661. }
  662. break;
  663. case 4://MD_DUAL_SABERS:
  664. if ( saberType != SABER_SINGLE )
  665. {
  666. Q_strncpyz(saber,"single_1",MAX_QPATH,qtrue);
  667. }
  668. break;
  669. case 5://MD_SABER_STAFF:
  670. if ( saberType == SABER_SINGLE || saberType == SABER_NONE )
  671. {
  672. Q_strncpyz(saber,"dual_1",MAX_QPATH,qtrue);
  673. }
  674. break;
  675. }
  676. }
  677. void UI_SaberDrawBlades( itemDef_t *item, vec3_t origin, float curYaw )
  678. {
  679. //NOTE: only allows one saber type in view at a time
  680. char saber[MAX_QPATH];
  681. int saberNum = 0;
  682. int saberModel = 0;
  683. int numSabers = 1;
  684. if ( (item->flags&ITF_ISCHARACTER)//hacked sabermoves sabers in character's hand
  685. && uiInfo.movesTitleIndex == 4 /*MD_DUAL_SABERS*/ )
  686. {
  687. numSabers = 2;
  688. }
  689. for ( saberNum = 0; saberNum < numSabers; saberNum++ )
  690. {
  691. if ( (item->flags&ITF_ISCHARACTER) )//hacked sabermoves sabers in character's hand
  692. {
  693. UI_GetSaberForMenu( saber, saberNum );
  694. saberModel = saberNum + 1;
  695. }
  696. else if ( (item->flags&ITF_ISSABER) )
  697. {
  698. DC->getCVarString( "ui_saber", saber, sizeof(saber) );
  699. saberModel = 0;
  700. }
  701. else if ( (item->flags&ITF_ISSABER2) )
  702. {
  703. DC->getCVarString( "ui_saber2", saber, sizeof(saber) );
  704. saberModel = 0;
  705. }
  706. else
  707. {
  708. return;
  709. }
  710. if ( saber[0] )
  711. {
  712. int numBlades = UI_SaberNumBladesForSaber( saber );
  713. if ( numBlades )
  714. {//okay, here we go, time to draw each blade...
  715. char saberTypeString[MAX_QPATH]={0};
  716. UI_SaberTypeForSaber( saber, saberTypeString );
  717. saberType_t saberType = TranslateSaberType( saberTypeString );
  718. for ( int curBlade = 0; curBlade < numBlades; curBlade++ )
  719. {
  720. UI_SaberDrawBlade( item, saber, saberModel, saberType, origin, curYaw, curBlade );
  721. }
  722. }
  723. }
  724. }
  725. }
  726. void UI_SaberAttachToChar( itemDef_t *item )
  727. {
  728. int numSabers = 1;
  729. int saberNum = 0;
  730. if ( item->ghoul2.size() > 2 && item->ghoul2[2].mModelindex >=0 )
  731. {//remove any extra models
  732. DC->g2_RemoveGhoul2Model(item->ghoul2, 2);
  733. }
  734. if ( item->ghoul2.size() > 1 && item->ghoul2[1].mModelindex >=0)
  735. {//remove any extra models
  736. DC->g2_RemoveGhoul2Model(item->ghoul2, 1);
  737. }
  738. if ( uiInfo.movesTitleIndex == 4 /*MD_DUAL_SABERS*/ )
  739. {
  740. numSabers = 2;
  741. }
  742. if ( Cvar_Get("ui_move_title", "4", 0)->integer == 4)
  743. {
  744. numSabers = 2;
  745. }
  746. for ( saberNum = 0; saberNum < numSabers; saberNum++ )
  747. {
  748. //bolt sabers
  749. char modelPath[MAX_QPATH];
  750. char skinPath[MAX_QPATH];
  751. char saber[MAX_QPATH];
  752. UI_GetSaberForMenu( saber, saberNum );
  753. if ( UI_SaberModelForSaber( saber, modelPath ) )
  754. {//successfully found a model
  755. int g2Saber = DC->g2_InitGhoul2Model(item->ghoul2, modelPath, 0, 0, 0, 0, 0); //add the model
  756. if (g2Saber)
  757. {
  758. //get the customSkin, if any
  759. if ( UI_SaberSkinForSaber( saber, skinPath ) )
  760. {
  761. int g2skin = DC->registerSkin(skinPath);
  762. DC->g2_SetSkin( &item->ghoul2[g2Saber], 0, g2skin );//this is going to set the surfs on/off matching the skin file
  763. }
  764. else
  765. {
  766. DC->g2_SetSkin( &item->ghoul2[g2Saber], -1, 0 );//turn off custom skin
  767. }
  768. int boltNum;
  769. if ( saberNum == 0 )
  770. {
  771. boltNum = G2API_AddBolt(&item->ghoul2[0], "*r_hand");
  772. }
  773. else
  774. {
  775. boltNum = G2API_AddBolt(&item->ghoul2[0], "*l_hand");
  776. }
  777. G2API_AttachG2Model(&item->ghoul2[g2Saber], &item->ghoul2[0], boltNum, 0);
  778. }
  779. }
  780. }
  781. }