1165 lines
24 KiB
C
1165 lines
24 KiB
C
|
//bg_saberLoad.c
|
||
|
#include "q_shared.h"
|
||
|
#include "bg_public.h"
|
||
|
#include "bg_local.h"
|
||
|
#include "w_saber.h"
|
||
|
|
||
|
//Could use strap stuff but I don't particularly care at the moment anyway.
|
||
|
#include "../namespace_begin.h"
|
||
|
extern int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
|
||
|
extern void trap_FS_Read( void *buffer, int len, fileHandle_t f );
|
||
|
extern void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
|
||
|
extern void trap_FS_FCloseFile( fileHandle_t f );
|
||
|
extern int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
|
||
|
extern qhandle_t trap_R_RegisterSkin( const char *name );
|
||
|
#include "../namespace_end.h"
|
||
|
|
||
|
|
||
|
#ifdef QAGAME
|
||
|
extern int G_SoundIndex( const char *name );
|
||
|
#elif defined CGAME
|
||
|
#include "../namespace_begin.h"
|
||
|
sfxHandle_t trap_S_RegisterSound( const char *sample);
|
||
|
#include "../namespace_end.h"
|
||
|
#endif
|
||
|
|
||
|
#include "../namespace_begin.h"
|
||
|
|
||
|
int BG_SoundIndex(char *sound)
|
||
|
{
|
||
|
#ifdef QAGAME
|
||
|
return G_SoundIndex(sound);
|
||
|
#elif defined CGAME
|
||
|
return trap_S_RegisterSound(sound);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
extern stringID_table_t FPTable[];
|
||
|
|
||
|
#define MAX_SABER_DATA_SIZE 0x10000
|
||
|
static char SaberParms[MAX_SABER_DATA_SIZE];
|
||
|
|
||
|
stringID_table_t SaberTable[] =
|
||
|
{
|
||
|
ENUM2STRING(SABER_NONE),
|
||
|
ENUM2STRING(SABER_SINGLE),
|
||
|
ENUM2STRING(SABER_STAFF),
|
||
|
ENUM2STRING(SABER_BROAD),
|
||
|
ENUM2STRING(SABER_PRONG),
|
||
|
ENUM2STRING(SABER_DAGGER),
|
||
|
ENUM2STRING(SABER_ARC),
|
||
|
ENUM2STRING(SABER_SAI),
|
||
|
ENUM2STRING(SABER_CLAW),
|
||
|
ENUM2STRING(SABER_LANCE),
|
||
|
ENUM2STRING(SABER_STAR),
|
||
|
ENUM2STRING(SABER_TRIDENT),
|
||
|
"", -1
|
||
|
};
|
||
|
|
||
|
//Also used in npc code
|
||
|
qboolean BG_ParseLiteral( const char **data, const char *string )
|
||
|
{
|
||
|
const char *token;
|
||
|
|
||
|
token = COM_ParseExt( data, qtrue );
|
||
|
if ( token[0] == 0 )
|
||
|
{
|
||
|
Com_Printf( "unexpected EOF\n" );
|
||
|
return qtrue;
|
||
|
}
|
||
|
|
||
|
if ( Q_stricmp( token, string ) )
|
||
|
{
|
||
|
Com_Printf( "required string '%s' missing\n", string );
|
||
|
return qtrue;
|
||
|
}
|
||
|
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
saber_colors_t TranslateSaberColor( const char *name )
|
||
|
{
|
||
|
if ( !Q_stricmp( name, "red" ) )
|
||
|
{
|
||
|
return SABER_RED;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "orange" ) )
|
||
|
{
|
||
|
return SABER_ORANGE;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "yellow" ) )
|
||
|
{
|
||
|
return SABER_YELLOW;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "green" ) )
|
||
|
{
|
||
|
return SABER_GREEN;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "blue" ) )
|
||
|
{
|
||
|
return SABER_BLUE;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "purple" ) )
|
||
|
{
|
||
|
return SABER_PURPLE;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "random" ) )
|
||
|
{
|
||
|
return ((saber_colors_t)(Q_irand( SABER_ORANGE, SABER_PURPLE )));
|
||
|
}
|
||
|
return SABER_BLUE;
|
||
|
}
|
||
|
|
||
|
saber_styles_t TranslateSaberStyle( const char *name )
|
||
|
{
|
||
|
if ( !Q_stricmp( name, "fast" ) )
|
||
|
{
|
||
|
return SS_FAST;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "medium" ) )
|
||
|
{
|
||
|
return SS_MEDIUM;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "strong" ) )
|
||
|
{
|
||
|
return SS_STRONG;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "desann" ) )
|
||
|
{
|
||
|
return SS_DESANN;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "tavion" ) )
|
||
|
{
|
||
|
return SS_TAVION;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "dual" ) )
|
||
|
{
|
||
|
return SS_DUAL;
|
||
|
}
|
||
|
if ( !Q_stricmp( name, "staff" ) )
|
||
|
{
|
||
|
return SS_STAFF;
|
||
|
}
|
||
|
return SS_NONE;
|
||
|
}
|
||
|
|
||
|
void WP_SaberSetDefaults( saberInfo_t *saber )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
//Set defaults so that, if it fails, there's at least something there
|
||
|
for ( i = 0; i < MAX_BLADES; i++ )
|
||
|
{
|
||
|
saber->blade[i].color = SABER_RED;
|
||
|
saber->blade[i].radius = SABER_RADIUS_STANDARD;
|
||
|
saber->blade[i].lengthMax = 32;
|
||
|
}
|
||
|
|
||
|
strcpy(saber->name, "default");
|
||
|
strcpy(saber->fullName, "lightsaber");
|
||
|
strcpy(saber->model, "models/weapons2/saber_reborn/saber_w.glm");
|
||
|
saber->skin = 0;
|
||
|
saber->soundOn = BG_SoundIndex( "sound/weapons/saber/enemy_saber_on.wav" );
|
||
|
saber->soundLoop = BG_SoundIndex( "sound/weapons/saber/saberhum3.wav" );
|
||
|
saber->soundOff = BG_SoundIndex( "sound/weapons/saber/enemy_saber_off.wav" );
|
||
|
saber->numBlades = 1;
|
||
|
saber->type = SABER_SINGLE;
|
||
|
saber->style = SS_NONE;
|
||
|
saber->maxChain = 0;//0 = use default behavior
|
||
|
saber->lockable = qtrue;
|
||
|
saber->throwable = qtrue;
|
||
|
saber->disarmable = qtrue;
|
||
|
saber->activeBlocking = qtrue;
|
||
|
saber->twoHanded = qfalse;
|
||
|
saber->forceRestrictions = 0;
|
||
|
saber->lockBonus = 0;
|
||
|
saber->parryBonus = 0;
|
||
|
saber->breakParryBonus = 0;
|
||
|
saber->disarmBonus = 0;
|
||
|
saber->singleBladeStyle = SS_NONE;//makes it so that you use a different style if you only have the first blade active
|
||
|
saber->singleBladeThrowable = qfalse;//makes it so that you can throw this saber if only the first blade is on
|
||
|
// saber->brokenSaber1 = NULL;//if saber is actually hit by another saber, it can be cut in half/broken and will be replaced with this saber in your right hand
|
||
|
// saber->brokenSaber2 = NULL;//if saber is actually hit by another saber, it can be cut in half/broken and will be replaced with this saber in your left hand
|
||
|
saber->returnDamage = qfalse;//when returning from a saber throw, it keeps spinning and doing damage
|
||
|
}
|
||
|
|
||
|
#define DEFAULT_SABER "Kyle"
|
||
|
|
||
|
qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber )
|
||
|
{
|
||
|
const char *token;
|
||
|
const char *value;
|
||
|
const char *p;
|
||
|
char useSaber[1024];
|
||
|
float f;
|
||
|
int n;
|
||
|
qboolean triedDefault = qfalse;
|
||
|
|
||
|
if ( !saber )
|
||
|
{
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
//Set defaults so that, if it fails, there's at least something there
|
||
|
WP_SaberSetDefaults( saber );
|
||
|
|
||
|
if ( !SaberName || !SaberName[0] )
|
||
|
{
|
||
|
strcpy(useSaber, DEFAULT_SABER); //default
|
||
|
triedDefault = qtrue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strcpy(useSaber, SaberName);
|
||
|
}
|
||
|
|
||
|
//try to parse it out
|
||
|
p = SaberParms;
|
||
|
COM_BeginParseSession("saberinfo");
|
||
|
|
||
|
// look for the right saber
|
||
|
while ( p )
|
||
|
{
|
||
|
token = COM_ParseExt( &p, qtrue );
|
||
|
if ( token[0] == 0 )
|
||
|
{
|
||
|
if (!triedDefault)
|
||
|
{ //fall back to default and restart, should always be there
|
||
|
p = SaberParms;
|
||
|
COM_BeginParseSession("saberinfo");
|
||
|
strcpy(useSaber, DEFAULT_SABER);
|
||
|
triedDefault = qtrue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return qfalse;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !Q_stricmp( token, useSaber ) )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
SkipBracedSection( &p );
|
||
|
}
|
||
|
if ( !p )
|
||
|
{ //even the default saber isn't found?
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
//got the name we're using for sure
|
||
|
strcpy(saber->name, useSaber);
|
||
|
|
||
|
if ( BG_ParseLiteral( &p, "{" ) )
|
||
|
{
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
// parse the saber info block
|
||
|
while ( 1 )
|
||
|
{
|
||
|
token = COM_ParseExt( &p, qtrue );
|
||
|
if ( !token[0] )
|
||
|
{
|
||
|
Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", useSaber );
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
if ( !Q_stricmp( token, "}" ) )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//saber fullName
|
||
|
if ( !Q_stricmp( token, "name" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
strcpy(saber->fullName, value);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//saber type
|
||
|
if ( !Q_stricmp( token, "saberType" ) )
|
||
|
{
|
||
|
int saberType;
|
||
|
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
saberType = GetIDForString( SaberTable, value );
|
||
|
if ( saberType >= SABER_SINGLE && saberType <= NUM_SABERS )
|
||
|
{
|
||
|
saber->type = (saberType_t)saberType;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//saber hilt
|
||
|
if ( !Q_stricmp( token, "saberModel" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
strcpy(saber->model, value);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( !Q_stricmp( token, "customSkin" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
saber->skin = trap_R_RegisterSkin(value);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//on sound
|
||
|
if ( !Q_stricmp( token, "soundOn" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
saber->soundOn = BG_SoundIndex( (char *)value );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//loop sound
|
||
|
if ( !Q_stricmp( token, "soundLoop" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
saber->soundLoop = BG_SoundIndex( (char *)value );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//off sound
|
||
|
if ( !Q_stricmp( token, "soundOff" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
saber->soundOff = BG_SoundIndex( (char *)value );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( !Q_stricmp( token, "numBlades" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
if ( n < 1 || n >= MAX_BLADES )
|
||
|
{
|
||
|
Com_Error(ERR_DROP, "WP_SaberParseParms: saber %s has illegal number of blades (%d) max: %d", useSaber, n, MAX_BLADES );
|
||
|
continue;
|
||
|
}
|
||
|
saber->numBlades = n;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// saberColor
|
||
|
if ( !Q_stricmpn( token, "saberColor", 10 ) )
|
||
|
{
|
||
|
if (strlen(token)==10)
|
||
|
{
|
||
|
n = -1;
|
||
|
}
|
||
|
else if (strlen(token)==11)
|
||
|
{
|
||
|
n = atoi(&token[10])-1;
|
||
|
if (n > 7 || n < 1 )
|
||
|
{
|
||
|
Com_Printf( S_COLOR_YELLOW"WARNING: bad saberColor '%s' in %s\n", token, useSaber );
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Com_Printf( S_COLOR_YELLOW"WARNING: bad saberColor '%s' in %s\n", token, useSaber );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( COM_ParseString( &p, &value ) ) //read the color
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (n==-1)
|
||
|
{//NOTE: this fills in the rest of the blades with the same color by default
|
||
|
saber_colors_t color = TranslateSaberColor( value );
|
||
|
for ( n = 0; n < MAX_BLADES; n++ )
|
||
|
{
|
||
|
saber->blade[n].color = color;
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
saber->blade[n].color = TranslateSaberColor( value );
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//saber length
|
||
|
if ( !Q_stricmpn( token, "saberLength", 11 ) )
|
||
|
{
|
||
|
if (strlen(token)==11)
|
||
|
{
|
||
|
n = -1;
|
||
|
}
|
||
|
else if (strlen(token)==12)
|
||
|
{
|
||
|
n = atoi(&token[11])-1;
|
||
|
if (n > 7 || n < 1 )
|
||
|
{
|
||
|
Com_Printf( S_COLOR_YELLOW"WARNING: bad saberLength '%s' in %s\n", token, useSaber );
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Com_Printf( S_COLOR_YELLOW"WARNING: bad saberLength '%s' in %s\n", token, useSaber );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( COM_ParseFloat( &p, &f ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
//cap
|
||
|
if ( f < 4.0f )
|
||
|
{
|
||
|
f = 4.0f;
|
||
|
}
|
||
|
|
||
|
if (n==-1)
|
||
|
{//NOTE: this fills in the rest of the blades with the same length by default
|
||
|
for ( n = 0; n < MAX_BLADES; n++ )
|
||
|
{
|
||
|
saber->blade[n].lengthMax = f;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
saber->blade[n].lengthMax = f;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//blade radius
|
||
|
if ( !Q_stricmpn( token, "saberRadius", 11 ) )
|
||
|
{
|
||
|
if (strlen(token)==11)
|
||
|
{
|
||
|
n = -1;
|
||
|
}
|
||
|
else if (strlen(token)==12)
|
||
|
{
|
||
|
n = atoi(&token[11])-1;
|
||
|
if (n > 7 || n < 1 )
|
||
|
{
|
||
|
Com_Printf( S_COLOR_YELLOW"WARNING: bad saberRadius '%s' in %s\n", token, useSaber );
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Com_Printf( S_COLOR_YELLOW"WARNING: bad saberRadius '%s' in %s\n", token, useSaber );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( COM_ParseFloat( &p, &f ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
//cap
|
||
|
if ( f < 0.25f )
|
||
|
{
|
||
|
f = 0.25f;
|
||
|
}
|
||
|
if (n==-1)
|
||
|
{//NOTE: this fills in the rest of the blades with the same length by default
|
||
|
for ( n = 0; n < MAX_BLADES; n++ )
|
||
|
{
|
||
|
saber->blade[n].radius = f;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
saber->blade[n].radius = f;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//locked saber style
|
||
|
if ( !Q_stricmp( token, "saberStyle" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
saber->style = TranslateSaberStyle( value );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//maxChain
|
||
|
if ( !Q_stricmp( token, "maxChain" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->maxChain = n;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//lockable
|
||
|
if ( !Q_stricmp( token, "lockable" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->lockable = ((qboolean)(n!=0));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//throwable
|
||
|
if ( !Q_stricmp( token, "throwable" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->throwable = ((qboolean)(n!=0));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//disarmable
|
||
|
if ( !Q_stricmp( token, "disarmable" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->disarmable = ((qboolean)(n!=0));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//active blocking
|
||
|
if ( !Q_stricmp( token, "blocking" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->activeBlocking = ((qboolean)(n!=0));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//twoHanded
|
||
|
if ( !Q_stricmp( token, "twoHanded" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->twoHanded = ((qboolean)(n!=0));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//force power restrictions
|
||
|
if ( !Q_stricmp( token, "forceRestrict" ) )
|
||
|
{
|
||
|
int fp;
|
||
|
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
fp = GetIDForString( FPTable, value );
|
||
|
if ( fp >= FP_FIRST && fp < NUM_FORCE_POWERS )
|
||
|
{
|
||
|
saber->forceRestrictions |= (1<<fp);
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//lockBonus
|
||
|
if ( !Q_stricmp( token, "lockBonus" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->lockBonus = n;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//parryBonus
|
||
|
if ( !Q_stricmp( token, "parryBonus" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->parryBonus = n;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//breakParryBonus
|
||
|
if ( !Q_stricmp( token, "breakParryBonus" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->breakParryBonus = n;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//disarmBonus
|
||
|
if ( !Q_stricmp( token, "disarmBonus" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->disarmBonus = n;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//single blade saber style
|
||
|
if ( !Q_stricmp( token, "singleBladeStyle" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
saber->singleBladeStyle = TranslateSaberStyle( value );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//single blade throwable
|
||
|
if ( !Q_stricmp( token, "singleBladeThrowable" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->singleBladeThrowable = ((qboolean)(n!=0));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//broken replacement saber1 (right hand)
|
||
|
if ( !Q_stricmp( token, "brokenSaber1" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
//saber->brokenSaber1 = G_NewString( value );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//broken replacement saber2 (left hand)
|
||
|
if ( !Q_stricmp( token, "brokenSaber2" ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
//saber->brokenSaber2 = G_NewString( value );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//spins and does damage on return from saberthrow
|
||
|
if ( !Q_stricmp( token, "returnDamage" ) )
|
||
|
{
|
||
|
if ( COM_ParseInt( &p, &n ) )
|
||
|
{
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
saber->returnDamage = ((qboolean)(n!=0));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ( !Q_stricmp( token, "notInMP" ) )
|
||
|
{//ignore this
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
//FIXME: saber sounds (on, off, loop)
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
Com_Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, useSaber );
|
||
|
#endif
|
||
|
SkipRestOfLine( &p );
|
||
|
}
|
||
|
|
||
|
//FIXME: precache the saberModel(s)?
|
||
|
|
||
|
return qtrue;
|
||
|
}
|
||
|
|
||
|
qboolean WP_SaberParseParm( const char *saberName, const char *parmname, char *saberData )
|
||
|
{
|
||
|
const char *token;
|
||
|
const char *value;
|
||
|
const char *p;
|
||
|
|
||
|
if ( !saberName || !saberName[0] )
|
||
|
{
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
//try to parse it out
|
||
|
p = SaberParms;
|
||
|
COM_BeginParseSession("saberinfo");
|
||
|
|
||
|
// look for the right saber
|
||
|
while ( p )
|
||
|
{
|
||
|
token = COM_ParseExt( &p, qtrue );
|
||
|
if ( token[0] == 0 )
|
||
|
{
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
if ( !Q_stricmp( token, saberName ) )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
SkipBracedSection( &p );
|
||
|
}
|
||
|
if ( !p )
|
||
|
{
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
if ( BG_ParseLiteral( &p, "{" ) )
|
||
|
{
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
// parse the saber info block
|
||
|
while ( 1 )
|
||
|
{
|
||
|
token = COM_ParseExt( &p, qtrue );
|
||
|
if ( !token[0] )
|
||
|
{
|
||
|
Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", saberName );
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
if ( !Q_stricmp( token, "}" ) )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( !Q_stricmp( token, parmname ) )
|
||
|
{
|
||
|
if ( COM_ParseString( &p, &value ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
strcpy( saberData, value );
|
||
|
return qtrue;
|
||
|
}
|
||
|
|
||
|
SkipRestOfLine( &p );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
qboolean WP_SaberValidForPlayerInMP( const char *saberName )
|
||
|
{
|
||
|
char allowed [8]={0};
|
||
|
if ( !WP_SaberParseParm( saberName, "notInMP", allowed ) )
|
||
|
{//not defined, default is yes
|
||
|
return qtrue;
|
||
|
}
|
||
|
if ( !allowed[0] )
|
||
|
{//not defined, default is yes
|
||
|
return qtrue;
|
||
|
}
|
||
|
else
|
||
|
{//return value
|
||
|
return ((qboolean)(atoi(allowed)==0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WP_RemoveSaber( saberInfo_t *sabers, int saberNum )
|
||
|
{
|
||
|
if ( !sabers )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
//reset everything for this saber just in case
|
||
|
WP_SaberSetDefaults( &sabers[saberNum] );
|
||
|
|
||
|
strcpy(sabers[saberNum].name, "none");
|
||
|
sabers[saberNum].model[0] = 0;
|
||
|
|
||
|
//ent->client->ps.dualSabers = qfalse;
|
||
|
BG_SI_Deactivate(&sabers[saberNum]);
|
||
|
BG_SI_SetLength(&sabers[saberNum], 0.0f);
|
||
|
// if ( ent->weaponModel[saberNum] > 0 )
|
||
|
// {
|
||
|
// gi.G2API_RemoveGhoul2Model( ent->ghoul2, ent->weaponModel[saberNum] );
|
||
|
// ent->weaponModel[saberNum] = -1;
|
||
|
// }
|
||
|
// if ( saberNum == 1 )
|
||
|
// {
|
||
|
// ent->client->ps.dualSabers = qfalse;
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
void WP_SetSaber( int entNum, saberInfo_t *sabers, int saberNum, const char *saberName )
|
||
|
{
|
||
|
if ( !sabers )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
if ( Q_stricmp( "none", saberName ) == 0 || Q_stricmp( "remove", saberName ) == 0 )
|
||
|
{
|
||
|
if (saberNum != 0)
|
||
|
{ //can't remove saber 0 ever
|
||
|
WP_RemoveSaber( sabers, saberNum );
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( entNum < MAX_CLIENTS &&
|
||
|
!WP_SaberValidForPlayerInMP( saberName ) )
|
||
|
{
|
||
|
WP_SaberParseParms( "Kyle", &sabers[saberNum] );//get saber info
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WP_SaberParseParms( saberName, &sabers[saberNum] );//get saber info
|
||
|
}
|
||
|
if (sabers[1].twoHanded)
|
||
|
{//not allowed to use a 2-handed saber as second saber
|
||
|
WP_RemoveSaber( sabers, 1 );
|
||
|
return;
|
||
|
}
|
||
|
else if (sabers[0].twoHanded &&
|
||
|
sabers[1].model[0])
|
||
|
{ //you can't use a two-handed saber with a second saber, so remove saber 2
|
||
|
WP_RemoveSaber( sabers, 1 );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WP_SaberSetColor( saberInfo_t *sabers, int saberNum, int bladeNum, char *colorName )
|
||
|
{
|
||
|
if ( !sabers )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
sabers[saberNum].blade[bladeNum].color = TranslateSaberColor( colorName );
|
||
|
}
|
||
|
|
||
|
static char bgSaberParseTBuffer[MAX_SABER_DATA_SIZE];
|
||
|
|
||
|
void WP_SaberLoadParms( void )
|
||
|
{
|
||
|
int len, totallen, saberExtFNLen, mainBlockLen, fileCnt, i;
|
||
|
//const char *filename = "ext_data/sabers.cfg";
|
||
|
char *holdChar, *marker;
|
||
|
char saberExtensionListBuf[2048]; // The list of file names read in
|
||
|
fileHandle_t f;
|
||
|
|
||
|
len = 0;
|
||
|
|
||
|
//remember where to store the next one
|
||
|
totallen = mainBlockLen = len;
|
||
|
marker = SaberParms+totallen;
|
||
|
*marker = 0;
|
||
|
|
||
|
//now load in the extra .sab extensions
|
||
|
fileCnt = trap_FS_GetFileList("ext_data/sabers", ".sab", saberExtensionListBuf, sizeof(saberExtensionListBuf) );
|
||
|
|
||
|
holdChar = saberExtensionListBuf;
|
||
|
for ( i = 0; i < fileCnt; i++, holdChar += saberExtFNLen + 1 )
|
||
|
{
|
||
|
saberExtFNLen = strlen( holdChar );
|
||
|
|
||
|
len = trap_FS_FOpenFile(va( "ext_data/sabers/%s", holdChar), &f, FS_READ);
|
||
|
|
||
|
if ( len == -1 )
|
||
|
{
|
||
|
Com_Printf( "error reading file\n" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (totallen + len + 1/*for the endline*/) >= MAX_SABER_DATA_SIZE ) {
|
||
|
Com_Error(ERR_DROP, "Saber extensions (*.sab) are too large" );
|
||
|
}
|
||
|
|
||
|
trap_FS_Read(bgSaberParseTBuffer, len, f);
|
||
|
bgSaberParseTBuffer[len] = 0;
|
||
|
|
||
|
Q_strcat( marker, MAX_SABER_DATA_SIZE-totallen, bgSaberParseTBuffer );
|
||
|
trap_FS_FCloseFile(f);
|
||
|
|
||
|
//get around the stupid problem of not having an endline at the bottom
|
||
|
//of a sab file -rww
|
||
|
Q_strcat(marker, MAX_SABER_DATA_SIZE-totallen, "\n");
|
||
|
len++;
|
||
|
|
||
|
totallen += len;
|
||
|
marker = SaberParms+totallen;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
rww -
|
||
|
The following were struct functions in SP. Of course
|
||
|
we can't have that in this codebase so I'm having to
|
||
|
externalize them. Which is why this probably seems
|
||
|
structured a bit oddly. But it's to make porting stuff
|
||
|
easier on myself. SI indicates it was under saberinfo,
|
||
|
and BLADE indicates it was under bladeinfo.
|
||
|
*/
|
||
|
|
||
|
//---------------------------------------
|
||
|
void BG_BLADE_ActivateTrail ( bladeInfo_t *blade, float duration )
|
||
|
{
|
||
|
blade->trail.inAction = qtrue;
|
||
|
blade->trail.duration = duration;
|
||
|
}
|
||
|
|
||
|
void BG_BLADE_DeactivateTrail ( bladeInfo_t *blade, float duration )
|
||
|
{
|
||
|
blade->trail.inAction = qfalse;
|
||
|
blade->trail.duration = duration;
|
||
|
}
|
||
|
//---------------------------------------
|
||
|
void BG_SI_Activate( saberInfo_t *saber )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0; i < saber->numBlades; i++ )
|
||
|
{
|
||
|
saber->blade[i].active = qtrue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BG_SI_Deactivate( saberInfo_t *saber )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0; i < saber->numBlades; i++ )
|
||
|
{
|
||
|
saber->blade[i].active = qfalse;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Description: Activate a specific Blade of this Saber.
|
||
|
// Created: 10/03/02 by Aurelio Reis, Modified: 10/03/02 by Aurelio Reis.
|
||
|
// [in] int iBlade Which Blade to activate.
|
||
|
// [in] bool bActive Whether to activate it (default true), or deactivate it (false).
|
||
|
// [return] void
|
||
|
void BG_SI_BladeActivate( saberInfo_t *saber, int iBlade, qboolean bActive )
|
||
|
{
|
||
|
// Validate blade ID/Index.
|
||
|
if ( iBlade < 0 || iBlade >= saber->numBlades )
|
||
|
return;
|
||
|
|
||
|
saber->blade[iBlade].active = bActive;
|
||
|
}
|
||
|
|
||
|
qboolean BG_SI_Active(saberInfo_t *saber)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0; i < saber->numBlades; i++ )
|
||
|
{
|
||
|
if ( saber->blade[i].active )
|
||
|
{
|
||
|
return qtrue;
|
||
|
}
|
||
|
}
|
||
|
return qfalse;
|
||
|
}
|
||
|
|
||
|
void BG_SI_SetLength( saberInfo_t *saber, float length )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0; i < saber->numBlades; i++ )
|
||
|
{
|
||
|
saber->blade[i].length = length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//not in sp, added it for my own convenience
|
||
|
void BG_SI_SetDesiredLength(saberInfo_t *saber, float len, int bladeNum )
|
||
|
{
|
||
|
int i, startBlade = 0, maxBlades = saber->numBlades;
|
||
|
|
||
|
if ( bladeNum >= 0 && bladeNum < saber->numBlades)
|
||
|
{//doing this on a specific blade
|
||
|
startBlade = bladeNum;
|
||
|
maxBlades = bladeNum+1;
|
||
|
}
|
||
|
for (i = startBlade; i < maxBlades; i++)
|
||
|
{
|
||
|
saber->blade[i].desiredLength = len;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//also not in sp, added it for my own convenience
|
||
|
void BG_SI_SetLengthGradual(saberInfo_t *saber, int time)
|
||
|
{
|
||
|
int i;
|
||
|
float amt, dLen;
|
||
|
|
||
|
for (i = 0; i < saber->numBlades; i++)
|
||
|
{
|
||
|
dLen = saber->blade[i].desiredLength;
|
||
|
|
||
|
if (dLen == -1)
|
||
|
{ //assume we want max blade len
|
||
|
dLen = saber->blade[i].lengthMax;
|
||
|
}
|
||
|
|
||
|
if (saber->blade[i].length == dLen)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (saber->blade[i].length == saber->blade[i].lengthMax ||
|
||
|
saber->blade[i].length == 0)
|
||
|
{
|
||
|
saber->blade[i].extendDebounce = time;
|
||
|
if (saber->blade[i].length == 0)
|
||
|
{
|
||
|
saber->blade[i].length++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
saber->blade[i].length--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
amt = (time - saber->blade[i].extendDebounce)*0.01;
|
||
|
|
||
|
if (amt < 0.2f)
|
||
|
{
|
||
|
amt = 0.2f;
|
||
|
}
|
||
|
|
||
|
if (saber->blade[i].length < dLen)
|
||
|
{
|
||
|
saber->blade[i].length += amt;
|
||
|
|
||
|
if (saber->blade[i].length > dLen)
|
||
|
{
|
||
|
saber->blade[i].length = dLen;
|
||
|
}
|
||
|
if (saber->blade[i].length > saber->blade[i].lengthMax)
|
||
|
{
|
||
|
saber->blade[i].length = saber->blade[i].lengthMax;
|
||
|
}
|
||
|
}
|
||
|
else if (saber->blade[i].length > dLen)
|
||
|
{
|
||
|
saber->blade[i].length -= amt;
|
||
|
|
||
|
if (saber->blade[i].length < dLen)
|
||
|
{
|
||
|
saber->blade[i].length = dLen;
|
||
|
}
|
||
|
if (saber->blade[i].length < 0)
|
||
|
{
|
||
|
saber->blade[i].length = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float BG_SI_Length(saberInfo_t *saber)
|
||
|
{//return largest length
|
||
|
int len1 = 0;
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0; i < saber->numBlades; i++ )
|
||
|
{
|
||
|
if ( saber->blade[i].length > len1 )
|
||
|
{
|
||
|
len1 = saber->blade[i].length;
|
||
|
}
|
||
|
}
|
||
|
return len1;
|
||
|
}
|
||
|
|
||
|
float BG_SI_LengthMax(saberInfo_t *saber)
|
||
|
{
|
||
|
int len1 = 0;
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0; i < saber->numBlades; i++ )
|
||
|
{
|
||
|
if ( saber->blade[i].lengthMax > len1 )
|
||
|
{
|
||
|
len1 = saber->blade[i].lengthMax;
|
||
|
}
|
||
|
}
|
||
|
return len1;
|
||
|
}
|
||
|
|
||
|
void BG_SI_ActivateTrail ( saberInfo_t *saber, float duration )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0; i < saber->numBlades; i++ )
|
||
|
{
|
||
|
//saber->blade[i].ActivateTrail( duration );
|
||
|
BG_BLADE_ActivateTrail(&saber->blade[i], duration);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BG_SI_DeactivateTrail ( saberInfo_t *saber, float duration )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0; i < saber->numBlades; i++ )
|
||
|
{
|
||
|
//saber->blade[i].DeactivateTrail( duration );
|
||
|
BG_BLADE_DeactivateTrail(&saber->blade[i], duration);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#include "../namespace_end.h"
|