codemp/ui/ui_saber.c

Go to the documentation of this file.
00001 //
00002 /*
00003 =======================================================================
00004 
00005 USER INTERFACE SABER LOADING & DISPLAY CODE
00006 
00007 =======================================================================
00008 */
00009 
00010 // leave this at the top of all UI_xxxx files for PCH reasons...
00011 //
00012 //#include "../server/exe_headers.h"
00013 #include "ui_local.h"
00014 #include "ui_shared.h"
00015 
00016 //#define MAX_SABER_DATA_SIZE 0x8000
00017 #define MAX_SABER_DATA_SIZE 0x80000
00018 
00019 // On Xbox, static linking lets us steal the buffer from wp_saberLoad
00020 // Just make sure that the saber data size is the same
00021 // Damn. OK. Gotta fix this again. Later.
00022 static char     SaberParms[MAX_SABER_DATA_SIZE];
00023 qboolean        ui_saber_parms_parsed = qfalse;
00024 
00025 static qhandle_t redSaberGlowShader;
00026 static qhandle_t redSaberCoreShader;
00027 static qhandle_t orangeSaberGlowShader;
00028 static qhandle_t orangeSaberCoreShader;
00029 static qhandle_t yellowSaberGlowShader;
00030 static qhandle_t yellowSaberCoreShader;
00031 static qhandle_t greenSaberGlowShader;
00032 static qhandle_t greenSaberCoreShader;
00033 static qhandle_t blueSaberGlowShader;
00034 static qhandle_t blueSaberCoreShader;
00035 static qhandle_t purpleSaberGlowShader;
00036 static qhandle_t purpleSaberCoreShader;
00037 
00038 void UI_CacheSaberGlowGraphics( void )
00039 {//FIXME: these get fucked by vid_restarts
00040         redSaberGlowShader                      = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/red_glow" );
00041         redSaberCoreShader                      = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/red_line" );
00042         orangeSaberGlowShader           = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/orange_glow" );
00043         orangeSaberCoreShader           = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/orange_line" );
00044         yellowSaberGlowShader           = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/yellow_glow" );
00045         yellowSaberCoreShader           = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/yellow_line" );
00046         greenSaberGlowShader            = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/green_glow" );
00047         greenSaberCoreShader            = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/green_line" );
00048         blueSaberGlowShader                     = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/blue_glow" );
00049         blueSaberCoreShader                     = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/blue_line" );
00050         purpleSaberGlowShader           = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/purple_glow" );
00051         purpleSaberCoreShader           = trap_R_RegisterShaderNoMip( "gfx/effects/sabers/purple_line" );
00052 }
00053 
00054 qboolean UI_ParseLiteral( const char **data, const char *string ) 
00055 {
00056         const char      *token;
00057 
00058         token = COM_ParseExt( data, qtrue );
00059         if ( token[0] == 0 ) 
00060         {
00061                 Com_Printf( "unexpected EOF\n" );
00062                 return qtrue;
00063         }
00064 
00065         if ( Q_stricmp( token, string ) ) 
00066         {
00067                 Com_Printf( "required string '%s' missing\n", string );
00068                 return qtrue;
00069         }
00070 
00071         return qfalse;
00072 }
00073 
00074 qboolean UI_ParseLiteralSilent( const char **data, const char *string ) 
00075 {
00076         const char      *token;
00077 
00078         token = COM_ParseExt( data, qtrue );
00079         if ( token[0] == 0 ) 
00080         {
00081                 return qtrue;
00082         }
00083 
00084         if ( Q_stricmp( token, string ) ) 
00085         {
00086                 return qtrue;
00087         }
00088 
00089         return qfalse;
00090 }
00091 
00092 qboolean UI_SaberParseParm( const char *saberName, const char *parmname, char *saberData ) 
00093 {
00094         const char      *token;
00095         const char      *value;
00096         const char      *p;
00097 
00098         if ( !saberName || !saberName[0] ) 
00099         {
00100                 return qfalse;
00101         }
00102 
00103         //try to parse it out
00104         p = SaberParms;
00105         // A bogus name is passed in
00106         COM_BeginParseSession("saberinfo");
00107 
00108         // look for the right saber
00109         while ( p )
00110         {
00111                 token = COM_ParseExt( &p, qtrue );
00112                 if ( token[0] == 0 )
00113                 {
00114                         return qfalse;
00115                 }
00116 
00117                 if ( !Q_stricmp( token, saberName ) ) 
00118                 {
00119                         break;
00120                 }
00121 
00122                 SkipBracedSection( &p );
00123         }
00124         if ( !p ) 
00125         {
00126                 return qfalse;
00127         }
00128 
00129         if ( UI_ParseLiteral( &p, "{" ) ) 
00130         {
00131                 return qfalse;
00132         }
00133                 
00134         // parse the saber info block
00135         while ( 1 ) 
00136         {
00137                 token = COM_ParseExt( &p, qtrue );
00138                 if ( !token[0] ) 
00139                 {
00140                         Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", saberName );
00141                         return qfalse;
00142                 }
00143 
00144                 if ( !Q_stricmp( token, "}" ) ) 
00145                 {
00146                         break;
00147                 }
00148 
00149                 if ( !Q_stricmp( token, parmname ) ) 
00150                 {
00151                         if ( COM_ParseString( &p, &value ) ) 
00152                         {
00153                                 continue;
00154                         }
00155                         strcpy( saberData, value );
00156                         return qtrue;
00157                 }
00158 
00159                 SkipRestOfLine( &p );
00160                 continue;
00161         }
00162 
00163         return qfalse;
00164 }
00165 
00166 
00167 qboolean UI_SaberModelForSaber( const char *saberName, char *saberModel )
00168 {
00169         return UI_SaberParseParm( saberName, "saberModel", saberModel );
00170 }
00171 
00172 qboolean UI_SaberSkinForSaber( const char *saberName, char *saberSkin )
00173 {
00174         return UI_SaberParseParm( saberName, "customSkin", saberSkin );
00175 }
00176 
00177 qboolean UI_SaberTypeForSaber( const char *saberName, char *saberType )
00178 {
00179         return UI_SaberParseParm( saberName, "saberType", saberType );
00180 }
00181 
00182 int UI_SaberNumBladesForSaber( const char *saberName )
00183 {
00184         int numBlades;
00185         char    numBladesString[8]={0};
00186         UI_SaberParseParm( saberName, "numBlades", numBladesString );
00187         numBlades = atoi( numBladesString );
00188         if ( numBlades < 1 )
00189         {
00190                 numBlades = 1;
00191         }
00192         else if ( numBlades > 8 )
00193         {
00194                 numBlades = 8;
00195         }
00196         return numBlades;
00197 }
00198 
00199 qboolean UI_SaberShouldDrawBlade( const char *saberName, int bladeNum )
00200 {
00201         int bladeStyle2Start = 0, noBlade = 0;
00202         char    bladeStyle2StartString[8]={0};
00203         char    noBladeString[8]={0};
00204         UI_SaberParseParm( saberName, "bladeStyle2Start", bladeStyle2StartString );
00205         if ( bladeStyle2StartString
00206                 && bladeStyle2StartString[0] )
00207         {
00208                 bladeStyle2Start = atoi( bladeStyle2StartString );
00209         }
00210         if ( bladeStyle2Start
00211                 && bladeNum >= bladeStyle2Start )
00212         {//use second blade style
00213                 UI_SaberParseParm( saberName, "noBlade2", noBladeString );
00214                 if ( noBladeString
00215                         && noBladeString[0] )
00216                 {
00217                         noBlade = atoi( noBladeString );
00218                 }
00219         }
00220         else
00221         {//use first blade style
00222                 UI_SaberParseParm( saberName, "noBlade", noBladeString );
00223                 if ( noBladeString
00224                         && noBladeString[0] )
00225                 {
00226                         noBlade = atoi( noBladeString );
00227                 }
00228         }
00229         return ((qboolean)(noBlade==0));
00230 }
00231 
00232 
00233 qboolean UI_IsSaberTwoHanded( const char *saberName )
00234 {
00235         int twoHanded;
00236         char    twoHandedString[8]={0};
00237         UI_SaberParseParm( saberName, "twoHanded", twoHandedString );
00238         if ( !twoHandedString[0] )
00239         {//not defined defaults to "no"
00240                 return qfalse;
00241         }
00242         twoHanded = atoi( twoHandedString );
00243         return ((qboolean)(twoHanded!=0));
00244 }
00245 
00246 float UI_SaberBladeLengthForSaber( const char *saberName, int bladeNum )
00247 {
00248         char    lengthString[8]={0};
00249         float   length = 40.0f;
00250         UI_SaberParseParm( saberName, "saberLength", lengthString );
00251         if ( lengthString[0] )
00252         {
00253                 length = atof( lengthString );
00254                 if ( length < 0.0f )
00255                 {
00256                         length = 0.0f;
00257                 }
00258         }
00259 
00260         UI_SaberParseParm( saberName, va("saberLength%d", bladeNum+1), lengthString );
00261         if ( lengthString[0] )
00262         {
00263                 length = atof( lengthString );
00264                 if ( length < 0.0f )
00265                 {
00266                         length = 0.0f;
00267                 }
00268         }
00269 
00270         return length;
00271 }
00272 
00273 float UI_SaberBladeRadiusForSaber( const char *saberName, int bladeNum )
00274 {
00275         char    radiusString[8]={0};
00276         float   radius = 3.0f;
00277         UI_SaberParseParm( saberName, "saberRadius", radiusString );
00278         if ( radiusString[0] )
00279         {
00280                 radius = atof( radiusString );
00281                 if ( radius < 0.0f )
00282                 {
00283                         radius = 0.0f;
00284                 }
00285         }
00286 
00287         UI_SaberParseParm( saberName, va("saberRadius%d", bladeNum+1), radiusString );
00288         if ( radiusString[0] )
00289         {
00290                 radius = atof( radiusString );
00291                 if ( radius < 0.0f )
00292                 {
00293                         radius = 0.0f;
00294                 }
00295         }
00296 
00297         return radius;
00298 }
00299 
00300 qboolean UI_SaberProperNameForSaber( const char *saberName, char *saberProperName )
00301 {
00302         char    stringedSaberName[1024];
00303         qboolean ret = UI_SaberParseParm( saberName, "name", stringedSaberName );
00304         // if it's a stringed reference translate it
00305         if( ret && stringedSaberName && stringedSaberName[0] == '@')
00306         {
00307                 trap_SP_GetStringTextString(&stringedSaberName[1], saberProperName, 1024);
00308         }
00309         else
00310         {
00311                 // no stringed so just use it as it
00312                 strcpy( saberProperName, stringedSaberName );
00313         }
00314 
00315         return ret;
00316         
00317 }
00318 
00319 qboolean UI_SaberValidForPlayerInMP( const char *saberName )
00320 {
00321         char allowed [8]={0};
00322         if ( !UI_SaberParseParm( saberName, "notInMP", allowed ) )
00323         {//not defined, default is yes
00324                 return qtrue;
00325         }
00326         if ( !allowed[0] )
00327         {//not defined, default is yes
00328                 return qtrue;
00329         }
00330         else
00331         {//return value
00332                 return ((qboolean)(atoi(allowed)==0));
00333         }
00334 }
00335 
00336 void UI_SaberLoadParms( void ) 
00337 {
00338         int                     len, totallen, saberExtFNLen, fileCnt, i;
00339         char            *holdChar, *marker;
00340         char            saberExtensionListBuf[2048];                    //      The list of file names read in
00341         fileHandle_t f;
00342         char buffer[MAX_MENUFILE];
00343 
00344         //ui.Printf( "UI Parsing *.sab saber definitions\n" );
00345         
00346         ui_saber_parms_parsed = qtrue;
00347         UI_CacheSaberGlowGraphics();
00348 
00349         //set where to store the first one
00350         totallen = 0;
00351         marker = SaberParms;
00352         marker[0] = '\0';
00353 
00354         //now load in the extra .npc extensions
00355         fileCnt = trap_FS_GetFileList("ext_data/sabers", ".sab", saberExtensionListBuf, sizeof(saberExtensionListBuf) );
00356 
00357         holdChar = saberExtensionListBuf;
00358         for ( i = 0; i < fileCnt; i++, holdChar += saberExtFNLen + 1 ) 
00359         {
00360                 saberExtFNLen = strlen( holdChar );
00361 
00362                 len = trap_FS_FOpenFile( va( "ext_data/sabers/%s", holdChar), &f, FS_READ );
00363 
00364                 if (!f)
00365                 {
00366                         continue;
00367                 }
00368 
00369                 if ( len == -1 ) 
00370                 {
00371                         Com_Printf( "UI_SaberLoadParms: error reading %s\n", holdChar );
00372                 }
00373                 else
00374                 {
00375                         if (len > sizeof(buffer) )
00376                         {
00377                                 Com_Error( ERR_FATAL, "UI_SaberLoadParms: file %s too large to read (max=%d)", holdChar, sizeof(buffer) );
00378                         }
00379                         trap_FS_Read( buffer, len, f );
00380                         trap_FS_FCloseFile( f );
00381                         buffer[len] = 0;
00382 
00383                         if ( totallen && *(marker-1) == '}' )
00384                         {//don't let it end on a } because that should be a stand-alone token
00385                                 strcat( marker, " " );
00386                                 totallen++;
00387                                 marker++; 
00388                         }
00389                         len = COM_Compress( buffer );
00390 
00391                         if ( totallen + len >= MAX_SABER_DATA_SIZE ) {
00392                                 Com_Error( ERR_FATAL, "UI_SaberLoadParms: ran out of space before reading %s\n(you must make the .sab files smaller)", holdChar );
00393                         }
00394                         strcat( marker, buffer );
00395 
00396                         totallen += len;
00397                         marker += len;
00398                 }
00399         }
00400 }
00401 
00402 void UI_DoSaber( vec3_t origin, vec3_t dir, float length, float lengthMax, float radius, saber_colors_t color )
00403 {
00404         vec3_t          mid, rgb={1,1,1};
00405         qhandle_t       blade = 0, glow = 0;
00406         refEntity_t saber;
00407         float radiusmult;
00408         float radiusRange;
00409         float radiusStart;
00410 
00411         if ( length < 0.5f )
00412         {
00413                 // if the thing is so short, just forget even adding me.
00414                 return;
00415         }
00416 
00417         // Find the midpoint of the saber for lighting purposes
00418         VectorMA( origin, length * 0.5f, dir, mid );
00419 
00420         switch( color )
00421         {
00422                 case SABER_RED:
00423                         glow = redSaberGlowShader;
00424                         blade = redSaberCoreShader;
00425                         VectorSet( rgb, 1.0f, 0.2f, 0.2f );
00426                         break;
00427                 case SABER_ORANGE:
00428                         glow = orangeSaberGlowShader;
00429                         blade = orangeSaberCoreShader;
00430                         VectorSet( rgb, 1.0f, 0.5f, 0.1f );
00431                         break;
00432                 case SABER_YELLOW:
00433                         glow = yellowSaberGlowShader;
00434                         blade = yellowSaberCoreShader;
00435                         VectorSet( rgb, 1.0f, 1.0f, 0.2f );
00436                         break;
00437                 case SABER_GREEN:
00438                         glow = greenSaberGlowShader;
00439                         blade = greenSaberCoreShader;
00440                         VectorSet( rgb, 0.2f, 1.0f, 0.2f );
00441                         break;
00442                 case SABER_BLUE:
00443                         glow = blueSaberGlowShader;
00444                         blade = blueSaberCoreShader;
00445                         VectorSet( rgb, 0.2f, 0.4f, 1.0f );
00446                         break;
00447                 case SABER_PURPLE:
00448                         glow = purpleSaberGlowShader;
00449                         blade = purpleSaberCoreShader;
00450                         VectorSet( rgb, 0.9f, 0.2f, 1.0f );
00451                         break;
00452         }
00453 
00454         // always add a light because sabers cast a nice glow before they slice you in half!!  or something...
00455         /*
00456         if ( doLight )
00457         {//FIXME: RGB combine all the colors of the sabers you're using into one averaged color!
00458                 cgi_R_AddLightToScene( mid, (length*2.0f) + (random()*8.0f), rgb[0], rgb[1], rgb[2] );
00459         }
00460         */
00461 
00462         memset( &saber, 0, sizeof( refEntity_t ));
00463 
00464         // Saber glow is it's own ref type because it uses a ton of sprites, otherwise it would eat up too many
00465         //      refEnts to do each glow blob individually
00466         saber.saberLength = length;
00467 
00468         // Jeff, I did this because I foolishly wished to have a bright halo as the saber is unleashed.  
00469         // It's not quite what I'd hoped tho.  If you have any ideas, go for it!  --Pat
00470         if (length < lengthMax )
00471         {
00472                 radiusmult = 1.0 + (2.0 / length);              // Note this creates a curve, and length cannot be < 0.5.
00473         }
00474         else
00475         {
00476                 radiusmult = 1.0;
00477         }
00478 
00479         radiusRange = radius * 0.075f;
00480         radiusStart = radius-radiusRange;
00481 
00482         saber.radius = (radiusStart + crandom() * radiusRange)*radiusmult;
00483         //saber.radius = (2.8f + crandom() * 0.2f)*radiusmult;
00484 
00485 
00486         VectorCopy( origin, saber.origin );
00487         VectorCopy( dir, saber.axis[0] );
00488         saber.reType = RT_SABER_GLOW;
00489         saber.customShader = glow;
00490         saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff;
00491         //saber.renderfx = rfx;
00492 
00493         trap_R_AddRefEntityToScene( &saber );
00494 
00495         // Do the hot core
00496         VectorMA( origin, length, dir, saber.origin );
00497         VectorMA( origin, -1, dir, saber.oldorigin );
00498         saber.customShader = blade;
00499         saber.reType = RT_LINE;
00500         radiusStart = radius/3.0f;
00501         saber.radius = (radiusStart + crandom() * radiusRange)*radiusmult;
00502 //      saber.radius = (1.0 + crandom() * 0.2f)*radiusmult;
00503 
00504         trap_R_AddRefEntityToScene( &saber );
00505 }
00506 
00507 char * SaberColorToString(saber_colors_t color)
00508 {
00509         if ( color == SABER_RED)
00510                 return "red";
00511         
00512         if ( color == SABER_ORANGE)
00513                 return "orange";
00514 
00515         if ( color == SABER_YELLOW)
00516                 return "yellow";
00517 
00518         if ( color == SABER_GREEN)
00519                 return "green";
00520 
00521         if (color == SABER_BLUE)
00522                 return "blue";
00523 
00524         if ( color == SABER_PURPLE)
00525                 return "purple";
00526         return NULL;
00527 }
00528 saber_colors_t TranslateSaberColor( const char *name ) 
00529 {
00530         if ( !Q_stricmp( name, "red" ) ) 
00531         {
00532                 return SABER_RED;
00533         }
00534         if ( !Q_stricmp( name, "orange" ) ) 
00535         {
00536                 return SABER_ORANGE;
00537         }
00538         if ( !Q_stricmp( name, "yellow" ) ) 
00539         {
00540                 return SABER_YELLOW;
00541         }
00542         if ( !Q_stricmp( name, "green" ) ) 
00543         {
00544                 return SABER_GREEN;
00545         }
00546         if ( !Q_stricmp( name, "blue" ) ) 
00547         {
00548                 return SABER_BLUE;
00549         }
00550         if ( !Q_stricmp( name, "purple" ) ) 
00551         {
00552                 return SABER_PURPLE;
00553         }
00554         if ( !Q_stricmp( name, "random" ) ) 
00555         {
00556                 return ((saber_colors_t)(Q_irand( SABER_ORANGE, SABER_PURPLE )));
00557         }
00558         return SABER_BLUE;
00559 }
00560 
00561 saberType_t TranslateSaberType( const char *name ) 
00562 {
00563         if ( !Q_stricmp( name, "SABER_SINGLE" ) ) 
00564         {
00565                 return SABER_SINGLE;
00566         }
00567         if ( !Q_stricmp( name, "SABER_STAFF" ) ) 
00568         {
00569                 return SABER_STAFF;
00570         }
00571         if ( !Q_stricmp( name, "SABER_BROAD" ) ) 
00572         {
00573                 return SABER_BROAD;
00574         }
00575         if ( !Q_stricmp( name, "SABER_PRONG" ) ) 
00576         {
00577                 return SABER_PRONG;
00578         }
00579         if ( !Q_stricmp( name, "SABER_DAGGER" ) ) 
00580         {
00581                 return SABER_DAGGER;
00582         }
00583         if ( !Q_stricmp( name, "SABER_ARC" ) ) 
00584         {
00585                 return SABER_ARC;
00586         }
00587         if ( !Q_stricmp( name, "SABER_SAI" ) ) 
00588         {
00589                 return SABER_SAI;
00590         }
00591         if ( !Q_stricmp( name, "SABER_CLAW" ) ) 
00592         {
00593                 return SABER_CLAW;
00594         }
00595         if ( !Q_stricmp( name, "SABER_LANCE" ) ) 
00596         {
00597                 return SABER_LANCE;
00598         }
00599         if ( !Q_stricmp( name, "SABER_STAR" ) ) 
00600         {
00601                 return SABER_STAR;
00602         }
00603         if ( !Q_stricmp( name, "SABER_TRIDENT" ) ) 
00604         {
00605                 return SABER_TRIDENT;
00606         }
00607         if ( !Q_stricmp( name, "SABER_SITH_SWORD" ) ) 
00608         {
00609                 return SABER_SITH_SWORD;
00610         }
00611         return SABER_SINGLE;
00612 }
00613 
00614 void UI_SaberDrawBlade( itemDef_t *item, char *saberName, int saberModel, saberType_t saberType, vec3_t origin, vec3_t angles, int bladeNum )
00615 {
00616 
00617         char bladeColorString[MAX_QPATH];
00618         saber_colors_t bladeColor;
00619         float bladeLength,bladeRadius;
00620         vec3_t  bladeOrigin={0};
00621         vec3_t  axis[3]={0};
00622 //      vec3_t  angles={0};
00623         mdxaBone_t      boltMatrix;
00624         qboolean tagHack = qfalse;
00625         char *tagName;
00626         int bolt;
00627         float scale;
00628 
00629         if ( (item->flags&ITF_ISSABER) && saberModel < 2 )
00630         {
00631                 trap_Cvar_VariableStringBuffer("ui_saber_color", bladeColorString, sizeof(bladeColorString) );
00632         }
00633         else//if ( item->flags&ITF_ISSABER2 ) - presumed
00634         {
00635                 trap_Cvar_VariableStringBuffer("ui_saber2_color", bladeColorString, sizeof(bladeColorString) );
00636         }
00637 
00638         if ( !trap_G2API_HasGhoul2ModelOnIndex(&(item->ghoul2),saberModel) )
00639         {//invalid index!
00640                 return;
00641         }
00642 
00643         bladeColor = TranslateSaberColor( bladeColorString );
00644 
00645         bladeLength = UI_SaberBladeLengthForSaber( saberName, bladeNum );
00646         bladeRadius = UI_SaberBladeRadiusForSaber( saberName, bladeNum );
00647 
00648         tagName = va( "*blade%d", bladeNum+1 );
00649         bolt = trap_G2API_AddBolt( item->ghoul2,saberModel, tagName );
00650         
00651         if ( bolt == -1 )
00652         {
00653                 tagHack = qtrue;
00654                 //hmm, just fall back to the most basic tag (this will also make it work with pre-JKA saber models
00655                 bolt = trap_G2API_AddBolt( item->ghoul2,saberModel, "*flash" );
00656                 if ( bolt == -1 )
00657                 {//no tag_flash either?!!
00658                         bolt = 0;
00659                 }
00660         }
00661         
00662 //      angles[PITCH] = curYaw;
00663 //      angles[ROLL] = 0;
00664 
00665         trap_G2API_GetBoltMatrix( item->ghoul2, saberModel, bolt, &boltMatrix, angles, origin, uiInfo.uiDC.realTime, NULL, vec3_origin );//NULL was cgs.model_draw
00666 
00667         // work the matrix axis stuff into the original axis and origins used.
00668         BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, bladeOrigin);
00669         BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, axis[0]);//front (was NEGATIVE_Y, but the md3->glm exporter screws up this tag somethin' awful)
00670                                                                                                                                 //              ...changed this back to NEGATIVE_Y              
00671         BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_X, axis[1]);//right ... and changed this to NEGATIVE_X
00672         BG_GiveMeVectorFromMatrix(&boltMatrix, POSITIVE_Z, axis[2]);//up
00673 
00674         // Where do I get scale from?
00675 //      scale = DC->xscale;
00676         scale = 1.0f;
00677 
00678         if ( tagHack )
00679         {
00680                 switch ( saberType )
00681                 {
00682                 case SABER_SINGLE:
00683                                 VectorMA( bladeOrigin, scale, axis[0], bladeOrigin );
00684                         break;
00685                 case SABER_DAGGER:
00686                 case SABER_LANCE:
00687                         break;
00688                 case SABER_STAFF:
00689                         if ( bladeNum == 0 )
00690                         {
00691                                 VectorMA( bladeOrigin, 12*scale, axis[0], bladeOrigin );
00692                         }
00693                         if ( bladeNum == 1 )
00694                         {
00695                                 VectorScale( axis[0], -1, axis[0] );
00696                                 VectorMA( bladeOrigin, 12*scale, axis[0], bladeOrigin );
00697                         }
00698                         break;
00699                 case SABER_BROAD:
00700                         if ( bladeNum == 0 )
00701                         {
00702                                 VectorMA( bladeOrigin, -1*scale, axis[1], bladeOrigin );
00703                         }
00704                         else if ( bladeNum == 1 )
00705                         {
00706                                 VectorMA( bladeOrigin, 1*scale, axis[1], bladeOrigin );
00707                         }
00708                         break;
00709                 case SABER_PRONG:
00710                         if ( bladeNum == 0 )
00711                         {
00712                                 VectorMA( bladeOrigin, -3*scale, axis[1], bladeOrigin );
00713                         }
00714                         else if ( bladeNum == 1 )
00715                         {
00716                                 VectorMA( bladeOrigin, 3*scale, axis[1], bladeOrigin );
00717                         }
00718                         break;
00719                 case SABER_ARC:
00720                         VectorSubtract( axis[1], axis[2], axis[1] );
00721                         VectorNormalize( axis[1] );
00722                         switch ( bladeNum )
00723                         {
00724                         case 0:
00725                                 VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
00726                                 VectorScale( axis[0], 0.75f, axis[0] );
00727                                 VectorScale( axis[1], 0.25f, axis[1] );
00728                                 VectorAdd( axis[0], axis[1], axis[0] );
00729                                 break;
00730                         case 1:
00731                                 VectorScale( axis[0], 0.25f, axis[0] );
00732                                 VectorScale( axis[1], 0.75f, axis[1] );
00733                                 VectorAdd( axis[0], axis[1], axis[0] );
00734                                 break;
00735                         case 2:
00736                                 VectorMA( bladeOrigin, -8*scale, axis[0], bladeOrigin );
00737                                 VectorScale( axis[0], -0.25f, axis[0] );
00738                                 VectorScale( axis[1], 0.75f, axis[1] );
00739                                 VectorAdd( axis[0], axis[1], axis[0] );
00740                                 break;
00741                         case 3:
00742                                 VectorMA( bladeOrigin, -16*scale, axis[0], bladeOrigin );
00743                                 VectorScale( axis[0], -0.75f, axis[0] );
00744                                 VectorScale( axis[1], 0.25f, axis[1] );
00745                                 VectorAdd( axis[0], axis[1], axis[0] );
00746                                 break;
00747                         }
00748                         break;
00749                 case SABER_SAI:
00750                         if ( bladeNum == 1 )
00751                         {
00752                                 VectorMA( bladeOrigin, -3*scale, axis[1], bladeOrigin );
00753                         }
00754                         else if ( bladeNum == 2 )
00755                         {
00756                                 VectorMA( bladeOrigin, 3*scale, axis[1], bladeOrigin );
00757                         }
00758                         break;
00759                 case SABER_CLAW:
00760                         switch ( bladeNum )
00761                         {
00762                         case 0:
00763                                 VectorMA( bladeOrigin, 2*scale, axis[0], bladeOrigin );
00764                                 VectorMA( bladeOrigin, 2*scale, axis[2], bladeOrigin );
00765                                 break;
00766                         case 1:
00767                                 VectorMA( bladeOrigin, 2*scale, axis[0], bladeOrigin );
00768                                 VectorMA( bladeOrigin, 2*scale, axis[2], bladeOrigin );
00769                                 VectorMA( bladeOrigin, 2*scale, axis[1], bladeOrigin );
00770                                 break;
00771                         case 2:
00772                                 VectorMA( bladeOrigin, 2*scale, axis[0], bladeOrigin );
00773                                 VectorMA( bladeOrigin, 2*scale, axis[2], bladeOrigin );
00774                                 VectorMA( bladeOrigin, -2*scale, axis[1], bladeOrigin );
00775                                 break;
00776                         }
00777                         break;
00778                 case SABER_STAR:
00779                         switch ( bladeNum )
00780                         {
00781                         case 0:
00782                                 VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
00783                                 break;
00784                         case 1:
00785                                 VectorScale( axis[0], 0.33f, axis[0] );
00786                                 VectorScale( axis[2], 0.67f, axis[2] );
00787                                 VectorAdd( axis[0], axis[2], axis[0] );
00788                                 VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
00789                                 break;
00790                         case 2:
00791                                 VectorScale( axis[0], -0.33f, axis[0] );
00792                                 VectorScale( axis[2], 0.67f, axis[2] );
00793                                 VectorAdd( axis[0], axis[2], axis[0] );
00794                                 VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
00795                                 break;
00796                         case 3:
00797                                 VectorScale( axis[0], -1, axis[0] );
00798                                 VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
00799                                 break;
00800                         case 4:
00801                                 VectorScale( axis[0], -0.33f, axis[0] );
00802                                 VectorScale( axis[2], -0.67f, axis[2] );
00803                                 VectorAdd( axis[0], axis[2], axis[0] );
00804                                 VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
00805                                 break;
00806                         case 5:
00807                                 VectorScale( axis[0], 0.33f, axis[0] );
00808                                 VectorScale( axis[2], -0.67f, axis[2] );
00809                                 VectorAdd( axis[0], axis[2], axis[0] );
00810                                 VectorMA( bladeOrigin, 8*scale, axis[0], bladeOrigin );
00811                                 break;
00812                         }
00813                         break;
00814                 case SABER_TRIDENT:
00815                         switch ( bladeNum )
00816                         {
00817                         case 0:
00818                                 VectorMA( bladeOrigin, 24*scale, axis[0], bladeOrigin );
00819                                 break;
00820                         case 1:
00821                                 VectorMA( bladeOrigin, -6*scale, axis[1], bladeOrigin );
00822                                 VectorMA( bladeOrigin, 24*scale, axis[0], bladeOrigin );
00823                                 break;
00824                         case 2:
00825                                 VectorMA( bladeOrigin, 6*scale, axis[1], bladeOrigin );
00826                                 VectorMA( bladeOrigin, 24*scale, axis[0], bladeOrigin );
00827                                 break;
00828                         case 3:
00829                                 VectorMA( bladeOrigin, -32*scale, axis[0], bladeOrigin );
00830                                 VectorScale( axis[0], -1, axis[0] );
00831                                 break;
00832                         }
00833                         break;
00834                 case SABER_SITH_SWORD:
00835                         //no blade
00836                         break;
00837                 }
00838         }
00839         if ( saberType == SABER_SITH_SWORD )
00840         {//draw no blade
00841                 return;
00842         }
00843 
00844         UI_DoSaber( bladeOrigin, axis[0], bladeLength, bladeLength, bladeRadius, bladeColor );
00845 
00846 }
00847 
00848 /*
00849 void UI_SaberDrawBlades( itemDef_t *item, vec3_t origin, vec3_t angles )
00850 {
00851         //NOTE: only allows one saber type in view at a time
00852         char saber[MAX_QPATH];
00853         if ( item->flags&ITF_ISSABER )
00854         {
00855                 trap_Cvar_VariableStringBuffer("ui_saber", saber, sizeof(saber) );
00856                 if ( !UI_SaberValidForPlayerInMP( saber ) )
00857                 {
00858                         trap_Cvar_Set( "ui_saber", "kyle" );
00859                         trap_Cvar_VariableStringBuffer("ui_saber", saber, sizeof(saber) );
00860                 }
00861         }
00862         else if ( item->flags&ITF_ISSABER2 )
00863         {
00864                 trap_Cvar_VariableStringBuffer("ui_saber2", saber, sizeof(saber) );
00865                 if ( !UI_SaberValidForPlayerInMP( saber ) )
00866                 {
00867                         trap_Cvar_Set( "ui_saber2", "kyle" );
00868                         trap_Cvar_VariableStringBuffer("ui_saber2", saber, sizeof(saber) );
00869                 }
00870         }
00871         else
00872         {
00873                 return;
00874         }
00875         if ( saber[0] )
00876         {
00877                 saberType_t saberType;
00878                 int curBlade;
00879                 int numBlades = UI_SaberNumBladesForSaber( saber );
00880                 if ( numBlades )
00881                 {//okay, here we go, time to draw each blade...
00882                         char    saberTypeString[MAX_QPATH]={0};
00883                         UI_SaberTypeForSaber( saber, saberTypeString );
00884                         saberType = TranslateSaberType( saberTypeString );
00885                         for ( curBlade = 0; curBlade < numBlades; curBlade++ )
00886                         {
00887                                 UI_SaberDrawBlade( item, saber, saberType, origin, angles, curBlade );
00888                         }
00889                 }
00890         }
00891 }
00892 */
00893 
00894 void UI_GetSaberForMenu( char *saber, int saberNum )
00895 {
00896         char saberTypeString[MAX_QPATH]={0};
00897         saberType_t saberType = SABER_NONE;
00898 
00899         if ( saberNum == 0 )
00900         {
00901                 trap_Cvar_VariableStringBuffer("ui_saber", saber, MAX_QPATH );
00902                 if ( !UI_SaberValidForPlayerInMP( saber ) )
00903                 {
00904                         trap_Cvar_Set( "ui_saber", "kyle" );
00905                         trap_Cvar_VariableStringBuffer("ui_saber", saber, MAX_QPATH );
00906                 }
00907         }
00908         else
00909         {
00910                 trap_Cvar_VariableStringBuffer("ui_saber2", saber, MAX_QPATH );
00911                 if ( !UI_SaberValidForPlayerInMP( saber ) )
00912                 {
00913                         trap_Cvar_Set( "ui_saber2", "kyle" );
00914                         trap_Cvar_VariableStringBuffer("ui_saber2", saber, MAX_QPATH );
00915                 }
00916         }
00917         //read this from the sabers.cfg
00918         UI_SaberTypeForSaber( saber, saberTypeString );
00919         if ( saberTypeString[0] )
00920         {
00921                 saberType = TranslateSaberType( saberTypeString );
00922         }
00923 
00924         switch ( uiInfo.movesTitleIndex )
00925         {
00926         case 0://MD_ACROBATICS:
00927                 break;
00928         case 1://MD_SINGLE_FAST:
00929         case 2://MD_SINGLE_MEDIUM:
00930         case 3://MD_SINGLE_STRONG:
00931                 if ( saberType != SABER_SINGLE )
00932                 {
00933                         Q_strncpyz(saber,"single_1",MAX_QPATH);
00934                 }
00935                 break;
00936         case 4://MD_DUAL_SABERS:
00937                 if ( saberType != SABER_SINGLE )
00938                 {
00939                         Q_strncpyz(saber,"single_1",MAX_QPATH);
00940                 }
00941                 break;
00942         case 5://MD_SABER_STAFF:
00943                 if ( saberType == SABER_SINGLE || saberType == SABER_NONE )
00944                 {
00945                         Q_strncpyz(saber,"dual_1",MAX_QPATH);
00946                 }
00947                 break;
00948         }
00949 
00950 }
00951 
00952 void UI_SaberDrawBlades( itemDef_t *item, vec3_t origin, vec3_t angles )
00953 {
00954         //NOTE: only allows one saber type in view at a time
00955         char saber[MAX_QPATH];
00956         int saberNum = 0;
00957         int saberModel = 0;
00958         int     numSabers = 1;
00959 
00960         if ( (item->flags&ITF_ISCHARACTER)//hacked sabermoves sabers in character's hand
00961                 && uiInfo.movesTitleIndex == 4 /*MD_DUAL_SABERS*/ )
00962         {
00963                 numSabers = 2;
00964         }
00965 
00966         for ( saberNum = 0; saberNum < numSabers; saberNum++ )
00967         {
00968                 if ( (item->flags&ITF_ISCHARACTER) )//hacked sabermoves sabers in character's hand
00969                 {
00970                         UI_GetSaberForMenu( saber, saberNum );
00971                         saberModel = saberNum + 1;
00972                 }
00973                 else if ( (item->flags&ITF_ISSABER) )
00974                 {
00975                         trap_Cvar_VariableStringBuffer("ui_saber", saber, sizeof(saber) );
00976                         if ( !UI_SaberValidForPlayerInMP( saber ) )
00977                         {
00978                                 trap_Cvar_Set( "ui_saber", "kyle" );
00979                                 trap_Cvar_VariableStringBuffer("ui_saber", saber, sizeof(saber) );
00980                         }
00981                         saberModel = 0;
00982                 }
00983                 else if ( (item->flags&ITF_ISSABER2) )
00984                 {
00985                         trap_Cvar_VariableStringBuffer("ui_saber2", saber, sizeof(saber) );
00986                         if ( !UI_SaberValidForPlayerInMP( saber ) )
00987                         {
00988                                 trap_Cvar_Set( "ui_saber2", "kyle" );
00989                                 trap_Cvar_VariableStringBuffer("ui_saber2", saber, sizeof(saber) );
00990                         }
00991                         saberModel = 0;
00992                 }
00993                 else
00994                 {
00995                         return;
00996                 }
00997                 if ( saber[0] )
00998                 {
00999                         saberType_t saberType;
01000                         int curBlade = 0;
01001                         int numBlades = UI_SaberNumBladesForSaber( saber );
01002                         if ( numBlades )
01003                         {//okay, here we go, time to draw each blade...
01004                                 char    saberTypeString[MAX_QPATH]={0};
01005                                 UI_SaberTypeForSaber( saber, saberTypeString );
01006                                 saberType = TranslateSaberType( saberTypeString );
01007                                 for ( curBlade = 0; curBlade < numBlades; curBlade++ )
01008                                 {
01009                                         if ( UI_SaberShouldDrawBlade( saber, curBlade ) )
01010                                         {
01011                                                 UI_SaberDrawBlade( item, saber, saberModel, saberType, origin, angles, curBlade );
01012                                         }
01013                                 }
01014                         }
01015                 }
01016         }
01017 }
01018 
01019 void UI_SaberAttachToChar( itemDef_t *item )
01020 {
01021         int     numSabers = 1;
01022         int     saberNum = 0;
01023 
01024         if ( trap_G2API_HasGhoul2ModelOnIndex(&(item->ghoul2),2) )
01025         {//remove any extra models
01026                 trap_G2API_RemoveGhoul2Model(&(item->ghoul2), 2);
01027         }
01028         if ( trap_G2API_HasGhoul2ModelOnIndex(&(item->ghoul2),1) )
01029         {//remove any extra models
01030                 trap_G2API_RemoveGhoul2Model(&(item->ghoul2), 1);
01031         }
01032 
01033         if ( uiInfo.movesTitleIndex == 4 /*MD_DUAL_SABERS*/ )
01034         {
01035                 numSabers = 2;
01036         }
01037 
01038         for ( saberNum = 0; saberNum < numSabers; saberNum++ )
01039         {
01040                 //bolt sabers
01041                 char modelPath[MAX_QPATH];
01042                 char skinPath[MAX_QPATH];
01043                 char saber[MAX_QPATH]; 
01044 
01045                 UI_GetSaberForMenu( saber, saberNum );
01046 
01047                 if ( UI_SaberModelForSaber( saber, modelPath ) )
01048                 {//successfully found a model
01049                         int g2Saber = trap_G2API_InitGhoul2Model( &(item->ghoul2), modelPath, 0, 0, 0, 0, 0 ); //add the model
01050                         if ( g2Saber )
01051                         {
01052                                 int boltNum;
01053                                 //get the customSkin, if any
01054                                 if ( UI_SaberSkinForSaber( saber, skinPath ) )
01055                                 {
01056                                         int g2skin = trap_R_RegisterSkin(skinPath);
01057                                         trap_G2API_SetSkin( item->ghoul2, g2Saber, 0, g2skin );//this is going to set the surfs on/off matching the skin file
01058                                 }
01059                                 else
01060                                 {
01061                                         trap_G2API_SetSkin( item->ghoul2, g2Saber, 0, 0 );//turn off custom skin
01062                                 }
01063                                 if ( saberNum == 0 )
01064                                 {
01065                                         boltNum = trap_G2API_AddBolt( item->ghoul2, 0, "*r_hand");
01066                                 }
01067                                 else
01068                                 {
01069                                         boltNum = trap_G2API_AddBolt( item->ghoul2, 0, "*l_hand");
01070                                 }
01071                                 trap_G2API_AttachG2Model( item->ghoul2, g2Saber, item->ghoul2, boltNum, 0);
01072                         }
01073                 }
01074         }
01075 }
01076 
01077 #define MAX_SABER_HILTS 64
01078 
01079 // Fill in with saber hilts
01080 void UI_SaberGetHiltInfo( const char *singleHilts[MAX_SABER_HILTS], const char *staffHilts[MAX_SABER_HILTS] )
01081 {
01082         int     numSingleHilts = 0, numStaffHilts = 0;
01083         const char      *saberName;
01084         const char      *token;
01085         const char      *p;
01086 
01087         //go through all the loaded sabers and put the valid ones in the proper list
01088         p = SaberParms;
01089         COM_BeginParseSession("saberlist");
01090 
01091         // look for a saber
01092         while ( p )
01093         {
01094                 token = COM_ParseExt( &p, qtrue );
01095                 if ( token[0] == 0 )
01096                 {//invalid name
01097                         continue;
01098                 }
01099                 saberName = String_Alloc( token );
01100                 //see if there's a "{" on the next line
01101                 SkipRestOfLine( &p );
01102 
01103                 if ( UI_ParseLiteralSilent( &p, "{" ) ) 
01104                 {//nope, not a name, keep looking
01105                         continue;
01106                 }
01107 
01108                 //this is a saber name
01109                 if ( !UI_SaberValidForPlayerInMP( saberName ) )
01110                 {
01111                         SkipBracedSection( &p );
01112                         continue;
01113                 }
01114 
01115                 if ( UI_IsSaberTwoHanded( saberName ) )
01116                 {
01117                         if ( numStaffHilts < MAX_SABER_HILTS-1 )//-1 because we have to NULL terminate the list
01118                         {
01119                                 staffHilts[numStaffHilts++] = saberName;
01120                         }
01121                         else
01122                         {
01123                                 Com_Printf( "WARNING: too many two-handed sabers, ignoring saber '%s'\n", saberName );
01124                         }
01125                 }
01126                 else
01127                 {
01128                         if ( numSingleHilts < MAX_SABER_HILTS-1 )//-1 because we have to NULL terminate the list
01129                         {
01130                                 singleHilts[numSingleHilts++] = saberName;
01131                         }
01132                         else
01133                         {
01134                                 Com_Printf( "WARNING: too many one-handed sabers, ignoring saber '%s'\n", saberName );
01135                         }
01136                 }
01137                 //skip the whole braced section and move on to the next entry
01138                 SkipBracedSection( &p );
01139         }
01140         //null terminate the list so the UI code knows where to stop listing them
01141         singleHilts[numSingleHilts] = NULL;
01142         staffHilts[numStaffHilts] = NULL;
01143 }