jediacademy/code/game/wp_saberLoad.cpp
2013-04-04 18:21:13 -05:00

2672 lines
69 KiB
C++

//wp_saberLoad.cpp
// leave this line at the top for all NPC_xxxx.cpp files...
#include "g_headers.h"
#include "q_shared.h"
#include "wp_saber.h"
extern qboolean G_ParseLiteral( const char **data, const char *string );
extern saber_colors_t TranslateSaberColor( const char *name );
extern qboolean PM_SaberInStart( int move );
extern qboolean PM_SaberInTransition( int move );
extern qboolean PM_SaberInAttack( int move );
extern stringID_table_t FPTable[];
#define MAX_SABER_DATA_SIZE 0x80000
char SaberParms[MAX_SABER_DATA_SIZE];
void Saber_SithSwordPrecache( void )
{//*SIGH* special sounds used by the sith sword
for ( int i = 1; i < 5; i++ )
{
G_SoundIndex( va( "sound/weapons/sword/stab%d.wav", i ) );
}
for ( i = 1; i < 5; i++ )
{
G_SoundIndex( va( "sound/weapons/sword/swing%d.wav", i ) );
}
for ( i = 1; i < 7; i++ )
{
G_SoundIndex( va( "sound/weapons/sword/fall%d.wav", i ) );
}
/*
for ( i = 1; i < 4; i++ )
{
G_SoundIndex( va( "sound/weapons/sword/spin%d.wav", i ) );
}
*/
}
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),
ENUM2STRING(SABER_SITH_SWORD),
"", -1
};
stringID_table_t SaberMoveTable[] =
{
ENUM2STRING(LS_NONE),
// Attacks
ENUM2STRING(LS_A_TL2BR),
ENUM2STRING(LS_A_L2R),
ENUM2STRING(LS_A_BL2TR),
ENUM2STRING(LS_A_BR2TL),
ENUM2STRING(LS_A_R2L),
ENUM2STRING(LS_A_TR2BL),
ENUM2STRING(LS_A_T2B),
ENUM2STRING(LS_A_BACKSTAB),
ENUM2STRING(LS_A_BACK),
ENUM2STRING(LS_A_BACK_CR),
ENUM2STRING(LS_ROLL_STAB),
ENUM2STRING(LS_A_LUNGE),
ENUM2STRING(LS_A_JUMP_T__B_),
ENUM2STRING(LS_A_FLIP_STAB),
ENUM2STRING(LS_A_FLIP_SLASH),
ENUM2STRING(LS_JUMPATTACK_DUAL),
ENUM2STRING(LS_JUMPATTACK_ARIAL_LEFT),
ENUM2STRING(LS_JUMPATTACK_ARIAL_RIGHT),
ENUM2STRING(LS_JUMPATTACK_CART_LEFT),
ENUM2STRING(LS_JUMPATTACK_CART_RIGHT),
ENUM2STRING(LS_JUMPATTACK_STAFF_LEFT),
ENUM2STRING(LS_JUMPATTACK_STAFF_RIGHT),
ENUM2STRING(LS_BUTTERFLY_LEFT),
ENUM2STRING(LS_BUTTERFLY_RIGHT),
ENUM2STRING(LS_A_BACKFLIP_ATK),
ENUM2STRING(LS_SPINATTACK_DUAL),
ENUM2STRING(LS_SPINATTACK),
ENUM2STRING(LS_LEAP_ATTACK),
ENUM2STRING(LS_SWOOP_ATTACK_RIGHT),
ENUM2STRING(LS_SWOOP_ATTACK_LEFT),
ENUM2STRING(LS_TAUNTAUN_ATTACK_RIGHT),
ENUM2STRING(LS_TAUNTAUN_ATTACK_LEFT),
ENUM2STRING(LS_KICK_F),
ENUM2STRING(LS_KICK_B),
ENUM2STRING(LS_KICK_R),
ENUM2STRING(LS_KICK_L),
ENUM2STRING(LS_KICK_S),
ENUM2STRING(LS_KICK_BF),
ENUM2STRING(LS_KICK_RL),
ENUM2STRING(LS_KICK_F_AIR),
ENUM2STRING(LS_KICK_B_AIR),
ENUM2STRING(LS_KICK_R_AIR),
ENUM2STRING(LS_KICK_L_AIR),
ENUM2STRING(LS_STABDOWN),
ENUM2STRING(LS_STABDOWN_STAFF),
ENUM2STRING(LS_STABDOWN_DUAL),
ENUM2STRING(LS_DUAL_SPIN_PROTECT),
ENUM2STRING(LS_STAFF_SOULCAL),
ENUM2STRING(LS_A1_SPECIAL),
ENUM2STRING(LS_A2_SPECIAL),
ENUM2STRING(LS_A3_SPECIAL),
ENUM2STRING(LS_UPSIDE_DOWN_ATTACK),
ENUM2STRING(LS_PULL_ATTACK_STAB),
ENUM2STRING(LS_PULL_ATTACK_SWING),
ENUM2STRING(LS_SPINATTACK_ALORA),
ENUM2STRING(LS_DUAL_FB),
ENUM2STRING(LS_DUAL_LR),
ENUM2STRING(LS_HILT_BASH),
"", -1
};
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_SaberFreeStrings( saberInfo_t &saber )
{
if (saber.name && gi.bIsFromZone(saber.name , TAG_G_ALLOC)) {
gi.Free (saber.name);
saber.name=0;
}
if (saber.fullName && gi.bIsFromZone(saber.fullName , TAG_G_ALLOC)) {
gi.Free (saber.fullName);
saber.fullName=0;
}
if (saber.model && gi.bIsFromZone(saber.model , TAG_G_ALLOC)) {
gi.Free (saber.model);
saber.model=0;
}
if (saber.skin && gi.bIsFromZone(saber.skin , TAG_G_ALLOC)) {
gi.Free (saber.skin);
saber.skin=0;
}
if (saber.brokenSaber1 && gi.bIsFromZone(saber.brokenSaber1 , TAG_G_ALLOC)) {
gi.Free (saber.brokenSaber1);
saber.brokenSaber1=0;
}
if (saber.brokenSaber2 && gi.bIsFromZone(saber.brokenSaber2 , TAG_G_ALLOC)) {
gi.Free (saber.brokenSaber2);
saber.brokenSaber2=0;
}
}
qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum )
{
if ( saber )
{
if ( saber->bladeStyle2Start > 0 )
{
if ( bladeNum >= saber->bladeStyle2Start )
{
return qtrue;
}
}
}
return qfalse;
}
qboolean WP_SaberBladeDoTransitionDamage( saberInfo_t *saber, int bladeNum )
{
if ( !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum )
&& (saber->saberFlags2&SFL2_TRANSITION_DAMAGE) )
{//use first blade style for this blade
return qtrue;
}
else if ( WP_SaberBladeUseSecondBladeStyle( saber, bladeNum )
&& (saber->saberFlags2&SFL2_TRANSITION_DAMAGE2) )
{//use second blade style for this blade
return qtrue;
}
return qfalse;
}
qboolean WP_UseFirstValidSaberStyle( gentity_t *ent, int *saberAnimLevel )
{
if ( ent && ent->client )
{
qboolean styleInvalid = qfalse;
int validStyles = 0, styleNum;
//initially, all styles are valid
for ( styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ )
{
validStyles |= (1<<styleNum);
}
if ( ent->client->ps.saber[0].Active()
&& ent->client->ps.saber[0].stylesForbidden )
{
if ( (ent->client->ps.saber[0].stylesForbidden&(1<<*saberAnimLevel)) )
{//not a valid style for first saber!
styleInvalid = qtrue;
validStyles &= ~ent->client->ps.saber[0].stylesForbidden;
}
}
if ( ent->client->ps.dualSabers )
{//check second saber, too
if ( ent->client->ps.saber[1].Active()
&& ent->client->ps.saber[1].stylesForbidden )
{
if ( (ent->client->ps.saber[1].stylesForbidden&(1<<*saberAnimLevel)) )
{//not a valid style for second saber!
styleInvalid = qtrue;
//only the ones both sabers allow is valid
validStyles &= ~ent->client->ps.saber[1].stylesForbidden;
}
}
else
{//can't use dual style if not using 2 sabers
validStyles &= ~(1<<SS_DUAL);
}
}
else
{//can't use dual style if not using 2 sabers
validStyles &= ~(1<<SS_DUAL);
}
if ( styleInvalid && validStyles )
{//using an invalid style and have at least one valid style to use, so switch to it
for ( styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ )
{
if ( (validStyles&(1<<styleNum)) )
{
*saberAnimLevel = styleNum;
return qtrue;
}
}
}
}
return qfalse;
}
qboolean WP_SaberStyleValidForSaber( gentity_t *ent, int saberAnimLevel )
{
if ( ent && ent->client )
{
if ( ent->client->ps.saber[0].Active()
&& ent->client->ps.saber[0].stylesForbidden )
{
if ( (ent->client->ps.saber[0].stylesForbidden&(1<<saberAnimLevel)) )
{//not a valid style for first saber!
return qfalse;
}
}
if ( ent->client->ps.dualSabers )
{//check second saber, too
if ( ent->client->ps.saber[1].Active() )
{
if ( ent->client->ps.saber[1].stylesForbidden )
{
if ( (ent->client->ps.saber[1].stylesForbidden&(1<<saberAnimLevel)) )
{//not a valid style for second saber!
return qfalse;
}
}
//now: if using dual sabers, only dual and tavion (if given with this saber) are allowed
if ( saberAnimLevel != SS_DUAL )
{//dual is okay
if ( saberAnimLevel != SS_TAVION )
{//tavion might be okay, all others are not
return qfalse;
}
else
{//see if "tavion" style is okay
if ( ent->client->ps.saber[0].Active()
&& (ent->client->ps.saber[0].stylesLearned&(1<<SS_TAVION)) )
{//okay to use tavion style, first saber gave it to us
}
else if ( (ent->client->ps.saber[1].stylesLearned&(1<<SS_TAVION)) )
{//okay to use tavion style, second saber gave it to us
}
else
{//tavion style is not allowed because neither of the sabers we're using gave it to us (I know, doesn't quite make sense, but...)
return qfalse;
}
}
}
}
else if ( saberAnimLevel == SS_DUAL )
{//can't use dual style if not using dualSabers
return qfalse;
}
}
else if ( saberAnimLevel == SS_DUAL )
{//can't use dual style if not using dualSabers
return qfalse;
}
}
return qtrue;
}
qboolean WP_SaberCanTurnOffSomeBlades( saberInfo_t *saber )
{
if ( saber->bladeStyle2Start > 0
&& saber->numBlades > saber->bladeStyle2Start )
{
if ( (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE)
&& (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE2) )
{//all blades are always on
return qfalse;
}
}
else
{
if ( (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) )
{//all blades are always on
return qfalse;
}
}
//you can turn some off
return qtrue;
}
void WP_SaberSetDefaults( saberInfo_t *saber, qboolean setColors = qtrue )
{
//Set defaults so that, if it fails, there's at least something there
saber->name = NULL;
saber->fullName = NULL;
for ( int i = 0; i < MAX_BLADES; i++ )
{
if ( setColors )
{
saber->blade[i].color = SABER_RED;
}
saber->blade[i].radius = SABER_RADIUS_STANDARD;
saber->blade[i].lengthMax = 32;
}
saber->model = "models/weapons2/saber_reborn/saber_w.glm";
saber->skin = NULL;
saber->soundOn = G_SoundIndex( "sound/weapons/saber/enemy_saber_on.wav" );
saber->soundLoop = G_SoundIndex( "sound/weapons/saber/saberhum3.wav" );
saber->soundOff = G_SoundIndex( "sound/weapons/saber/enemy_saber_off.wav" );
saber->numBlades = 1;
saber->type = SABER_SINGLE;
saber->stylesLearned = 0;
saber->stylesForbidden = 0;
saber->maxChain = 0;//0 = use default behavior
saber->forceRestrictions = 0;
saber->lockBonus = 0;
saber->parryBonus = 0;
saber->breakParryBonus = 0;
saber->breakParryBonus2 = 0;
saber->disarmBonus = 0;
saber->disarmBonus2 = 0;
saber->singleBladeStyle = SS_NONE;//makes it so that you use a different style if you only have the first blade active
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
//===NEW========================================================================================
//these values are global to the saber, like all of the ones above
saber->saberFlags = 0; //see all the SFL_ flags
saber->saberFlags2 = 0; //see all the SFL2_ flags
saber->spinSound = 0; //none - if set, plays this sound as it spins when thrown
saber->swingSound[0] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!!
saber->swingSound[1] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!!
saber->swingSound[2] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!!
saber->fallSound[0] = 0; //none - if set, plays one of these 3 sounds when weapon falls to the ground - NOTE: must provide all 3!!!
saber->fallSound[1] = 0; //none - if set, plays one of these 3 sounds when weapon falls to the ground - NOTE: must provide all 3!!!
saber->fallSound[2] = 0; //none - if set, plays one of these 3 sounds when weapon falls to the ground - NOTE: must provide all 3!!!
//done in game (server-side code)
saber->moveSpeedScale = 1.0f; //1.0 - you move faster/slower when using this saber
saber->animSpeedScale = 1.0f; //1.0 - plays normal attack animations faster/slower
saber->kataMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they press both attack buttons at the same time
saber->lungeAtkMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they crouch+fwd+attack
saber->jumpAtkUpMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+attack
saber->jumpAtkFwdMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+fwd+attack
saber->jumpAtkBackMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+back+attack
saber->jumpAtkRightMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+rightattack
saber->jumpAtkLeftMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+left+attack
saber->readyAnim = -1; //-1 - anim to use when standing idle
saber->drawAnim = -1; //-1 - anim to use when drawing weapon
saber->putawayAnim = -1; //-1 - anim to use when putting weapon away
saber->tauntAnim = -1; //-1 - anim to use when hit "taunt"
saber->bowAnim = -1; //-1 - anim to use when hit "bow"
saber->meditateAnim = -1; //-1 - anim to use when hit "meditate"
saber->flourishAnim = -1; //-1 - anim to use when hit "flourish"
saber->gloatAnim = -1; //-1 - anim to use when hit "gloat"
//***NOTE: you can only have a maximum of 2 "styles" of blades, so this next value, "bladeStyle2Start" is the number of the first blade to use these value on... all blades before this use the normal values above, all blades at and after this number use the secondary values below***
saber->bladeStyle2Start = 0; //0 - if set, blades from this number and higher use the following values (otherwise, they use the normal values already set)
//***The following can be different for the extra blades - not setting them individually defaults them to the value for the whole saber (and first blade)***
//===PRIMARY BLADES=====================
//done in cgame (client-side code)
saber->trailStyle = 0; //0 - default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods)
saber->g2MarksShader[0]=0; //none - if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark"
saber->g2WeaponMarkShader[0]=0; //none - if set, the game will ry to project this shader onto the weapon when it damages a person (good for a blood splatter on the weapon)
//saber->bladeShader = 0; //none - if set, overrides the shader used for the saber blade?
//saber->trailShader = 0; //none - if set, overrides the shader used for the saber trail?
saber->hitSound[0] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!!
saber->hitSound[1] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!!
saber->hitSound[2] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!!
saber->blockSound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!!
saber->blockSound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!!
saber->blockSound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!!
saber->bounceSound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!!
saber->bounceSound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!!
saber->bounceSound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!!
saber->blockEffect = 0; //none - if set, plays this effect when the saber/sword hits another saber/sword (instead of "saber/saber_block.efx")
saber->hitPersonEffect = 0; //none - if set, plays this effect when the saber/sword hits a person (instead of "saber/blood_sparks_mp.efx")
saber->hitOtherEffect = 0; //none - if set, plays this effect when the saber/sword hits something else damagable (instead of "saber/saber_cut.efx")
saber->bladeEffect = 0; //none - if set, plays this effect at the blade tag
//done in game (server-side code)
saber->knockbackScale = 0; //0 - if non-zero, uses damage done to calculate an appropriate amount of knockback
saber->damageScale = 1.0f; //1 - scale up or down the damage done by the saber
saber->splashRadius = 0.0f; //0 - radius of splashDamage
saber->splashDamage = 0; //0 - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius
saber->splashKnockback = 0.0f; //0 - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius
//===SECONDARY BLADES===================
//done in cgame (client-side code)
saber->trailStyle2 = 0; //0 - default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods)
saber->g2MarksShader2[0]=0; //none - if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark"
saber->g2WeaponMarkShader2[0]=0; //none - if set, the game will ry to project this shader onto the weapon when it damages a person (good for a blood splatter on the weapon)
//saber->bladeShader = 0; //none - if set, overrides the shader used for the saber blade?
//saber->trailShader = 0; //none - if set, overrides the shader used for the saber trail?
saber->hit2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!!
saber->hit2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!!
saber->hit2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!!
saber->block2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!!
saber->block2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!!
saber->block2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!!
saber->bounce2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!!
saber->bounce2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!!
saber->bounce2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!!
saber->blockEffect2 = 0; //none - if set, plays this effect when the saber/sword hits another saber/sword (instead of "saber/saber_block.efx")
saber->hitPersonEffect2 = 0; //none - if set, plays this effect when the saber/sword hits a person (instead of "saber/blood_sparks_mp.efx")
saber->hitOtherEffect2 = 0; //none - if set, plays this effect when the saber/sword hits something else damagable (instead of "saber/saber_cut.efx")
saber->bladeEffect2 = 0; //none - if set, plays this effect at the blade tag
//done in game (server-side code)
saber->knockbackScale2 = 0; //0 - if non-zero, uses damage done to calculate an appropriate amount of knockback
saber->damageScale2 = 1.0f; //1 - scale up or down the damage done by the saber
saber->splashRadius2 = 0.0f; //0 - radius of splashDamage
saber->splashDamage2 = 0; //0 - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius
saber->splashKnockback2 = 0.0f; //0 - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius
//=========================================================================================================================================
}
qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean setColors )
{
const char *token;
const char *value;
const char *p;
float f;
int n;
if ( !saber )
{
return qfalse;
}
//Set defaults so that, if it fails, there's at least something there
WP_SaberSetDefaults( saber, setColors );
if ( !SaberName || !SaberName[0] )
{
return qfalse;
}
saber->name = G_NewString( SaberName );
//try to parse it out
p = SaberParms;
COM_BeginParseSession();
// 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 ( G_ParseLiteral( &p, "{" ) )
{
return qfalse;
}
// parse the saber info block
while ( 1 )
{
token = COM_ParseExt( &p, qtrue );
if ( !token[0] )
{
gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", SaberName );
return qfalse;
}
if ( !Q_stricmp( token, "}" ) )
{
break;
}
//saber fullName
if ( !Q_stricmp( token, "name" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->fullName = G_NewString( value );
continue;
}
//saber type
if ( !Q_stricmp( token, "saberType" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int 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;
}
saber->model = G_NewString( value );
continue;
}
if ( !Q_stricmp( token, "customSkin" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->skin = G_NewString( value );
continue;
}
//on sound
if ( !Q_stricmp( token, "soundOn" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->soundOn = G_SoundIndex( G_NewString( value ) );
continue;
}
//loop sound
if ( !Q_stricmp( token, "soundLoop" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->soundLoop = G_SoundIndex( G_NewString( value ) );
continue;
}
//off sound
if ( !Q_stricmp( token, "soundOff" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->soundOff = G_SoundIndex( G_NewString( value ) );
continue;
}
if ( !Q_stricmp( token, "numBlades" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n < 1 || n > MAX_BLADES )
{
G_Error( "WP_SaberParseParms: saber %s has illegal number of blades (%d) max: %d", SaberName, n, MAX_BLADES );
continue;
}
saber->numBlades = n;
continue;
}
// saberColor
if ( !Q_stricmpn( token, "saberColor", 10 ) )
{
if ( !setColors )
{//don't actually want to set the colors
//read the color out anyway just to advance the *p pointer
COM_ParseString( &p, &value );
continue;
}
else
{
if (strlen(token)==10)
{
n = -1;
}
else if (strlen(token)==11)
{
n = atoi(&token[10])-1;
if (n > 7 || n < 1 )
{
gi.Printf( S_COLOR_YELLOW"WARNING: bad saberColor '%s' in %s\n", token, SaberName );
//read the color out anyway just to advance the *p pointer
COM_ParseString( &p, &value );
continue;
}
}
else
{
gi.Printf( S_COLOR_YELLOW"WARNING: bad saberColor '%s' in %s\n", token, SaberName );
//read the color out anyway just to advance the *p pointer
COM_ParseString( &p, &value );
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 )
{
gi.Printf( S_COLOR_YELLOW"WARNING: bad saberLength '%s' in %s\n", token, SaberName );
continue;
}
}
else
{
gi.Printf( S_COLOR_YELLOW"WARNING: bad saberLength '%s' in %s\n", token, SaberName );
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 )
{
gi.Printf( S_COLOR_YELLOW"WARNING: bad saberRadius '%s' in %s\n", token, SaberName );
continue;
}
}
else
{
gi.Printf( S_COLOR_YELLOW"WARNING: bad saberRadius '%s' in %s\n", token, SaberName );
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" ) )
{
int style, styleNum;
if ( COM_ParseString( &p, &value ) )
{
continue;
}
//OLD WAY: only allowed ONE style
style = TranslateSaberStyle( value );
//learn only this style
saber->stylesLearned = (1<<style);
//forbid all other styles
saber->stylesForbidden = 0;
for ( styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ )
{
if ( styleNum != style )
{
saber->stylesForbidden |= (1<<styleNum);
}
}
continue;
}
//learned saber style
if ( !Q_stricmp( token, "saberStyleLearned" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->stylesLearned |= (1<<TranslateSaberStyle( value ));
continue;
}
//forbidden saber style
if ( !Q_stricmp( token, "saberStyleForbidden" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->stylesForbidden |= (1<<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;
}
if ( n == 0 )
{
saber->saberFlags |= SFL_NOT_LOCKABLE;
}
continue;
}
//throwable
if ( !Q_stricmp( token, "throwable" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n == 0 )
{
saber->saberFlags |= SFL_NOT_THROWABLE;
}
continue;
}
//disarmable
if ( !Q_stricmp( token, "disarmable" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n == 0 )
{
saber->saberFlags |= SFL_NOT_DISARMABLE;
}
continue;
}
//active blocking
if ( !Q_stricmp( token, "blocking" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n == 0 )
{
saber->saberFlags |= SFL_NOT_ACTIVE_BLOCKING;
}
continue;
}
//twoHanded
if ( !Q_stricmp( token, "twoHanded" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_TWO_HANDED;
}
continue;
}
//force power restrictions
if ( !Q_stricmp( token, "forceRestrict" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int 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;
}
//breakParryBonus2
if ( !Q_stricmp( token, "breakParryBonus2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
saber->breakParryBonus2 = n;
continue;
}
//disarmBonus
if ( !Q_stricmp( token, "disarmBonus" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
saber->disarmBonus = n;
continue;
}
//disarmBonus2
if ( !Q_stricmp( token, "disarmBonus2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
saber->disarmBonus2 = 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;
}
if ( n )
{
saber->saberFlags |= SFL_SINGLE_BLADE_THROWABLE;
}
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;
}
if ( n )
{
saber->saberFlags |= SFL_RETURN_DAMAGE;
}
continue;
}
//spin sound (when thrown)
if ( !Q_stricmp( token, "spinSound" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->spinSound = G_SoundIndex( (char *)value );
continue;
}
//swing sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "swingSound1" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->swingSound[0] = G_SoundIndex( (char *)value );
continue;
}
//swing sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "swingSound2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->swingSound[1] = G_SoundIndex( (char *)value );
continue;
}
//swing sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "swingSound3" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->swingSound[2] = G_SoundIndex( (char *)value );
continue;
}
//fall sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "fallSound1" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->fallSound[0] = G_SoundIndex( (char *)value );
continue;
}
//fall sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "fallSound2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->fallSound[1] = G_SoundIndex( (char *)value );
continue;
}
//fall sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "fallSound3" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->fallSound[2] = G_SoundIndex( (char *)value );
continue;
}
//you move faster/slower when using this saber
if ( !Q_stricmp( token, "moveSpeedScale" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->moveSpeedScale = f;
continue;
}
//plays normal attack animations faster/slower
if ( !Q_stricmp( token, "animSpeedScale" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->animSpeedScale = f;
continue;
}
//if set, weapon stays active even in water
if ( !Q_stricmp( token, "onInWater" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_ON_IN_WATER;
}
continue;
}
//if non-zero, the saber will bounce back when it hits solid architecture (good for real-sword type mods)
if ( !Q_stricmp( token, "bounceOnWalls" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_BOUNCE_ON_WALLS;
}
continue;
}
//if set, saber model is bolted to wrist, not in hand... useful for things like claws & shields, etc.
if ( !Q_stricmp( token, "boltToWrist" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_BOLT_TO_WRIST;
}
continue;
}
//kata move
if ( !Q_stricmp( token, "kataMove" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int saberMove = GetIDForString( SaberMoveTable, value );
if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX )
{
saber->kataMove = saberMove; //LS_INVALID - if set, player will execute this move when they press both attack buttons at the same time
}
continue;
}
//lungeAtkMove move
if ( !Q_stricmp( token, "lungeAtkMove" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int saberMove = GetIDForString( SaberMoveTable, value );
if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX )
{
saber->lungeAtkMove = saberMove;
}
continue;
}
//jumpAtkUpMove move
if ( !Q_stricmp( token, "jumpAtkUpMove" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int saberMove = GetIDForString( SaberMoveTable, value );
if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX )
{
saber->jumpAtkUpMove = saberMove;
}
continue;
}
//jumpAtkFwdMove move
if ( !Q_stricmp( token, "jumpAtkFwdMove" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int saberMove = GetIDForString( SaberMoveTable, value );
if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX )
{
saber->jumpAtkFwdMove = saberMove;
}
continue;
}
//jumpAtkBackMove move
if ( !Q_stricmp( token, "jumpAtkBackMove" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int saberMove = GetIDForString( SaberMoveTable, value );
if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX )
{
saber->jumpAtkBackMove = saberMove;
}
continue;
}
//jumpAtkRightMove move
if ( !Q_stricmp( token, "jumpAtkRightMove" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int saberMove = GetIDForString( SaberMoveTable, value );
if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX )
{
saber->jumpAtkRightMove = saberMove;
}
continue;
}
//jumpAtkLeftMove move
if ( !Q_stricmp( token, "jumpAtkLeftMove" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int saberMove = GetIDForString( SaberMoveTable, value );
if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX )
{
saber->jumpAtkLeftMove = saberMove;
}
continue;
}
//readyAnim
if ( !Q_stricmp( token, "readyAnim" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int anim = GetIDForString( animTable, value );
if ( anim >= 0 && anim < MAX_ANIMATIONS )
{
saber->readyAnim = anim;
}
continue;
}
//drawAnim
if ( !Q_stricmp( token, "drawAnim" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int anim = GetIDForString( animTable, value );
if ( anim >= 0 && anim < MAX_ANIMATIONS )
{
saber->drawAnim = anim;
}
continue;
}
//putawayAnim
if ( !Q_stricmp( token, "putawayAnim" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int anim = GetIDForString( animTable, value );
if ( anim >= 0 && anim < MAX_ANIMATIONS )
{
saber->putawayAnim = anim;
}
continue;
}
//tauntAnim
if ( !Q_stricmp( token, "tauntAnim" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int anim = GetIDForString( animTable, value );
if ( anim >= 0 && anim < MAX_ANIMATIONS )
{
saber->tauntAnim = anim;
}
continue;
}
//bowAnim
if ( !Q_stricmp( token, "bowAnim" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int anim = GetIDForString( animTable, value );
if ( anim >= 0 && anim < MAX_ANIMATIONS )
{
saber->bowAnim = anim;
}
continue;
}
//meditateAnim
if ( !Q_stricmp( token, "meditateAnim" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int anim = GetIDForString( animTable, value );
if ( anim >= 0 && anim < MAX_ANIMATIONS )
{
saber->meditateAnim = anim;
}
continue;
}
//flourishAnim
if ( !Q_stricmp( token, "flourishAnim" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int anim = GetIDForString( animTable, value );
if ( anim >= 0 && anim < MAX_ANIMATIONS )
{
saber->flourishAnim = anim;
}
continue;
}
//gloatAnim
if ( !Q_stricmp( token, "gloatAnim" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
int anim = GetIDForString( animTable, value );
if ( anim >= 0 && anim < MAX_ANIMATIONS )
{
saber->gloatAnim = anim;
}
continue;
}
//if set, cannot do roll-stab move at end of roll
if ( !Q_stricmp( token, "noRollStab" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_ROLL_STAB;
}
continue;
}
//if set, cannot do pull+attack move (move not available in MP anyway)
if ( !Q_stricmp( token, "noPullAttack" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_PULL_ATTACK;
}
continue;
}
//if set, cannot do back-stab moves
if ( !Q_stricmp( token, "noBackAttack" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_BACK_ATTACK;
}
continue;
}
//if set, cannot do stabdown move (when enemy is on ground)
if ( !Q_stricmp( token, "noStabDown" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_STABDOWN;
}
continue;
}
//if set, cannot side-run or forward-run on walls
if ( !Q_stricmp( token, "noWallRuns" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_WALL_RUNS;
}
continue;
}
//if set, cannot do backflip off wall or side-flips off walls
if ( !Q_stricmp( token, "noWallFlips" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_WALL_FLIPS;
}
continue;
}
//if set, cannot grab wall & jump off
if ( !Q_stricmp( token, "noWallGrab" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_WALL_GRAB;
}
continue;
}
//if set, cannot roll
if ( !Q_stricmp( token, "noRolls" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_ROLLS;
}
continue;
}
//if set, cannot do flips
if ( !Q_stricmp( token, "noFlips" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_FLIPS;
}
continue;
}
//if set, cannot do cartwheels
if ( !Q_stricmp( token, "noCartwheels" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_CARTWHEELS;
}
continue;
}
//if set, cannot do kicks (can't do kicks anyway if using a throwable saber/sword)
if ( !Q_stricmp( token, "noKicks" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_KICKS;
}
continue;
}
//if set, cannot do the simultaneous attack left/right moves (only available in Dual Lightsaber Combat Style)
if ( !Q_stricmp( token, "noMirrorAttacks" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags |= SFL_NO_MIRROR_ATTACKS;
}
continue;
}
if ( !Q_stricmp( token, "notInMP" ) )
{//ignore this
SkipRestOfLine( &p );
continue;
}
//===ABOVE THIS, ALL VALUES ARE GLOBAL TO THE SABER========================================================
//bladeStyle2Start - where to start using the second set of blade data
if ( !Q_stricmp( token, "bladeStyle2Start" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
saber->bladeStyle2Start = n;
continue;
}
//===BLADE-SPECIFIC FIELDS=================================================================================
//===PRIMARY BLADE====================================
//stops the saber from drawing marks on the world (good for real-sword type mods)
if ( !Q_stricmp( token, "noWallMarks" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_WALL_MARKS;
}
continue;
}
//stops the saber from drawing a dynamic light (good for real-sword type mods)
if ( !Q_stricmp( token, "noDlight" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_DLIGHT;
}
continue;
}
//stops the saber from drawing a blade (good for real-sword type mods)
if ( !Q_stricmp( token, "noBlade" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_BLADE;
}
continue;
}
//default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods)
if ( !Q_stricmp( token, "trailStyle" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
saber->trailStyle = n;
continue;
}
//if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark"
if ( !Q_stricmp( token, "g2MarksShader" ) )
{
if ( COM_ParseString( &p, &value ) )
{
SkipRestOfLine( &p );
continue;
}
Q_strncpyz( saber->g2MarksShader, value, sizeof(saber->g2MarksShader), qtrue );
//NOTE: registers this on cgame side where it registers all client assets
continue;
}
//if set, the game will ry to project this shader onto the weapon when it damages a person (good for a blood splatter on the weapon)
if ( !Q_stricmp( token, "g2WeaponMarkShader" ) )
{
if ( COM_ParseString( &p, &value ) )
{
SkipRestOfLine( &p );
continue;
}
Q_strncpyz( saber->g2WeaponMarkShader, value, sizeof(saber->g2WeaponMarkShader), qtrue );
//NOTE: registers this on cgame side where it registers all client assets
continue;
}
//if non-zero, uses damage done to calculate an appropriate amount of knockback
if ( !Q_stricmp( token, "knockbackScale" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->knockbackScale = f;
continue;
}
//scale up or down the damage done by the saber
if ( !Q_stricmp( token, "damageScale" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->damageScale = f;
continue;
}
//if non-zero, the saber never does dismemberment (good for pointed/blunt melee weapons)
if ( !Q_stricmp( token, "noDismemberment" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_DISMEMBERMENT;
}
continue;
}
//if non-zero, the saber will not do damage or any effects when it is idle (not in an attack anim). (good for real-sword type mods)
if ( !Q_stricmp( token, "noIdleEffect" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_IDLE_EFFECT;
}
continue;
}
//if set, the blades will always be blocking (good for things like shields that should always block)
if ( !Q_stricmp( token, "alwaysBlock" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_ALWAYS_BLOCK;
}
continue;
}
//if set, the blades cannot manually be toggled on and off
if ( !Q_stricmp( token, "noManualDeactivate" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_MANUAL_DEACTIVATE;
}
continue;
}
//if set, the blade does damage in start, transition and return anims (like strong style does)
if ( !Q_stricmp( token, "transitionDamage" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_TRANSITION_DAMAGE;
}
continue;
}
//splashRadius - radius of splashDamage
if ( !Q_stricmp( token, "splashRadius" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->splashRadius = f;
continue;
}
//splashDamage - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius
if ( !Q_stricmp( token, "splashDamage" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
saber->splashDamage = n;
continue;
}
//splashKnockback - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius
if ( !Q_stricmp( token, "splashKnockback" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->splashKnockback = f;
continue;
}
//hit sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "hitSound1" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hitSound[0] = G_SoundIndex( (char *)value );
continue;
}
//hit sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "hitSound2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hitSound[1] = G_SoundIndex( (char *)value );
continue;
}
//hit sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "hitSound3" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hitSound[2] = G_SoundIndex( (char *)value );
continue;
}
//block sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "blockSound1" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->blockSound[0] = G_SoundIndex( (char *)value );
continue;
}
//block sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "blockSound2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->blockSound[1] = G_SoundIndex( (char *)value );
continue;
}
//block sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "blockSound3" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->blockSound[2] = G_SoundIndex( (char *)value );
continue;
}
//bounce sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "bounceSound1" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->bounceSound[0] = G_SoundIndex( (char *)value );
continue;
}
//bounce sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "bounceSound2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->bounceSound[1] = G_SoundIndex( (char *)value );
continue;
}
//bounce sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "bounceSound3" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->bounceSound[2] = G_SoundIndex( (char *)value );
continue;
}
//block effect - when saber/sword hits another saber/sword
if ( !Q_stricmp( token, "blockEffect" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->blockEffect = G_EffectIndex( (char *)value );
continue;
}
//hit person effect - when saber/sword hits a person
if ( !Q_stricmp( token, "hitPersonEffect" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hitPersonEffect = G_EffectIndex( (char *)value );
continue;
}
//hit other effect - when saber/sword hits sopmething else damagable
if ( !Q_stricmp( token, "hitOtherEffect" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hitOtherEffect = G_EffectIndex( (char *)value );
continue;
}
//blade effect
if ( !Q_stricmp( token, "bladeEffect" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->bladeEffect = G_EffectIndex( (char *)value );
continue;
}
//if non-zero, the saber will not do the big, white clash flare with other sabers
if ( !Q_stricmp( token, "noClashFlare" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_CLASH_FLARE;
}
continue;
}
//===SECONDARY BLADE====================================
//stops the saber from drawing marks on the world (good for real-sword type mods)
if ( !Q_stricmp( token, "noWallMarks2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_WALL_MARKS2;
}
continue;
}
//stops the saber from drawing a dynamic light (good for real-sword type mods)
if ( !Q_stricmp( token, "noDlight2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_DLIGHT2;
}
continue;
}
//stops the saber from drawing a blade (good for real-sword type mods)
if ( !Q_stricmp( token, "noBlade2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_BLADE2;
}
continue;
}
//default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods)
if ( !Q_stricmp( token, "trailStyle2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
saber->trailStyle2 = n;
continue;
}
//if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark"
if ( !Q_stricmp( token, "g2MarksShader2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
SkipRestOfLine( &p );
continue;
}
Q_strncpyz( saber->g2MarksShader2, value, sizeof(saber->g2MarksShader2), qtrue );
//NOTE: registers this on cgame side where it registers all client assets
continue;
}
//if set, the game will ry to project this shader onto the weapon when it damages a person (good for a blood splatter on the weapon)
if ( !Q_stricmp( token, "g2WeaponMarkShader2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
SkipRestOfLine( &p );
continue;
}
Q_strncpyz( saber->g2WeaponMarkShader2, value, sizeof(saber->g2WeaponMarkShader2), qtrue );
//NOTE: registers this on cgame side where it registers all client assets
continue;
}
//if non-zero, uses damage done to calculate an appropriate amount of knockback
if ( !Q_stricmp( token, "knockbackScale2" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->knockbackScale2 = f;
continue;
}
//scale up or down the damage done by the saber
if ( !Q_stricmp( token, "damageScale2" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->damageScale2 = f;
continue;
}
//if non-zero, the saber never does dismemberment (good for pointed/blunt melee weapons)
if ( !Q_stricmp( token, "noDismemberment2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_DISMEMBERMENT2;
}
continue;
}
//if non-zero, the saber will not do damage or any effects when it is idle (not in an attack anim). (good for real-sword type mods)
if ( !Q_stricmp( token, "noIdleEffect2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_IDLE_EFFECT2;
}
continue;
}
//if set, the blades will always be blocking (good for things like shields that should always block)
if ( !Q_stricmp( token, "alwaysBlock2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_ALWAYS_BLOCK2;
}
continue;
}
//if set, the blades cannot manually be toggled on and off
if ( !Q_stricmp( token, "noManualDeactivate2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_MANUAL_DEACTIVATE2;
}
continue;
}
//if set, the blade does damage in start, transition and return anims (like strong style does)
if ( !Q_stricmp( token, "transitionDamage2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_TRANSITION_DAMAGE2;
}
continue;
}
//splashRadius - radius of splashDamage
if ( !Q_stricmp( token, "splashRadius2" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->splashRadius2 = f;
continue;
}
//splashDamage - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius
if ( !Q_stricmp( token, "splashDamage2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
saber->splashDamage2 = n;
continue;
}
//splashKnockback - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius
if ( !Q_stricmp( token, "splashKnockback2" ) )
{
if ( COM_ParseFloat( &p, &f ) )
{
SkipRestOfLine( &p );
continue;
}
saber->splashKnockback2 = f;
continue;
}
//hit sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "hit2Sound1" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hit2Sound[0] = G_SoundIndex( (char *)value );
continue;
}
//hit sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "hit2Sound2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hit2Sound[1] = G_SoundIndex( (char *)value );
continue;
}
//hit sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "hit2Sound3" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hit2Sound[2] = G_SoundIndex( (char *)value );
continue;
}
//block sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "block2Sound1" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->block2Sound[0] = G_SoundIndex( (char *)value );
continue;
}
//block sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "block2Sound2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->block2Sound[1] = G_SoundIndex( (char *)value );
continue;
}
//block sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "block2Sound3" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->block2Sound[2] = G_SoundIndex( (char *)value );
continue;
}
//bounce sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "bounce2Sound1" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->bounce2Sound[0] = G_SoundIndex( (char *)value );
continue;
}
//bounce sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "bounce2Sound2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->bounce2Sound[1] = G_SoundIndex( (char *)value );
continue;
}
//bounce sound - NOTE: must provide all 3!!!
if ( !Q_stricmp( token, "bounce2Sound3" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->bounce2Sound[2] = G_SoundIndex( (char *)value );
continue;
}
//block effect - when saber/sword hits another saber/sword
if ( !Q_stricmp( token, "blockEffect2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->blockEffect2 = G_EffectIndex( (char *)value );
continue;
}
//hit person effect - when saber/sword hits a person
if ( !Q_stricmp( token, "hitPersonEffect2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hitPersonEffect2 = G_EffectIndex( (char *)value );
continue;
}
//hit other effect - when saber/sword hits sopmething else damagable
if ( !Q_stricmp( token, "hitOtherEffect2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->hitOtherEffect2 = G_EffectIndex( (char *)value );
continue;
}
//blade effect 2
if ( !Q_stricmp( token, "bladeEffect2" ) )
{
if ( COM_ParseString( &p, &value ) )
{
continue;
}
saber->bladeEffect = G_EffectIndex( (char *)value );
continue;
}
//if non-zero, the saber will not do the big, white clash flare with other sabers
if ( !Q_stricmp( token, "noClashFlare2" ) )
{
if ( COM_ParseInt( &p, &n ) )
{
SkipRestOfLine( &p );
continue;
}
if ( n )
{
saber->saberFlags2 |= SFL2_NO_CLASH_FLARE2;
}
continue;
}
//===END BLADE-SPECIFIC FIELDS=============================================================================
gi.Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, SaberName );
SkipRestOfLine( &p );
}
//FIXME: precache the saberModel(s)?
if ( saber->type == SABER_SITH_SWORD )
{//precache all the sith sword sounds
Saber_SithSwordPrecache();
}
return qtrue;
}
void WP_RemoveSaber( gentity_t *ent, int saberNum )
{
if ( !ent || !ent->client )
{
return;
}
//reset everything for this saber just in case
WP_SaberSetDefaults( &ent->client->ps.saber[saberNum] );
ent->client->ps.dualSabers = qfalse;
ent->client->ps.saber[saberNum].Deactivate();
ent->client->ps.saber[saberNum].SetLength( 0.0f );
if ( ent->weaponModel[saberNum] > 0 )
{
gi.G2API_SetSkin( &ent->ghoul2[ent->weaponModel[saberNum]], -1, 0 );
gi.G2API_RemoveGhoul2Model( ent->ghoul2, ent->weaponModel[saberNum] );
ent->weaponModel[saberNum] = -1;
}
if ( ent->client->ps.saberAnimLevel == SS_DUAL
|| ent->client->ps.saberAnimLevel == SS_STAFF )
{//change to the style to the default
for ( int i = SS_NONE+1; i < SS_NUM_SABER_STYLES; i++ )
{
if ( (ent->client->ps.saberStylesKnown&(1<<i)) )
{
ent->client->ps.saberAnimLevel = i;
if ( ent->s.number < MAX_CLIENTS )
{
cg.saberAnimLevelPending = ent->client->ps.saberAnimLevel;
}
break;
}
}
}
}
void WP_SetSaber( gentity_t *ent, int saberNum, char *saberName )
{
if ( !ent || !ent->client )
{
return;
}
if ( Q_stricmp( "none", saberName ) == 0 || Q_stricmp( "remove", saberName ) == 0 )
{
WP_RemoveSaber( ent, saberNum );
return;
}
if ( ent->weaponModel[saberNum] > 0 )
{
gi.G2API_RemoveGhoul2Model(ent->ghoul2, ent->weaponModel[saberNum]);
ent->weaponModel[saberNum] = -1;
}
WP_SaberParseParms( saberName, &ent->client->ps.saber[saberNum] );//get saber info
if ( ent->client->ps.saber[saberNum].stylesLearned )
{
ent->client->ps.saberStylesKnown |= ent->client->ps.saber[saberNum].stylesLearned;
}
if ( ent->client->ps.saber[saberNum].singleBladeStyle )
{
ent->client->ps.saberStylesKnown |= ent->client->ps.saber[saberNum].singleBladeStyle;
}
if ( saberNum == 1 && (ent->client->ps.saber[1].saberFlags&SFL_TWO_HANDED) )
{//not allowed to use a 2-handed saber as second saber
WP_RemoveSaber( ent, saberNum );
return;
}
G_ModelIndex( ent->client->ps.saber[saberNum].model );
WP_SaberInitBladeData( ent );
if ( saberNum == 1 )
{//now have 2 sabers
ent->client->ps.dualSabers = qtrue;
}
/*
else if ( saberNum == 0 )
{
if ( ent->weaponModel[1] == -1 )
{//don't have 2 sabers
ent->client->ps.dualSabers = qfalse;
}
}
*/
WP_SaberAddG2SaberModels( ent, saberNum );
ent->client->ps.saber[saberNum].SetLength( 0.0f );
ent->client->ps.saber[saberNum].Activate();
if ( ent->client->ps.saber[saberNum].stylesLearned )
{//change to the style we're supposed to be using
ent->client->ps.saberStylesKnown |= ent->client->ps.saber[saberNum].stylesLearned;
}
if ( ent->client->ps.saber[saberNum].singleBladeStyle )
{
ent->client->ps.saberStylesKnown |= ent->client->ps.saber[saberNum].singleBladeStyle;
}
WP_UseFirstValidSaberStyle( ent, &ent->client->ps.saberAnimLevel );
if ( ent->s.number < MAX_CLIENTS )
{
cg.saberAnimLevelPending = ent->client->ps.saberAnimLevel;
}
}
void WP_SaberSetColor( gentity_t *ent, int saberNum, int bladeNum, char *colorName )
{
if ( !ent || !ent->client )
{
return;
}
ent->client->ps.saber[saberNum].blade[bladeNum].color = TranslateSaberColor( colorName );
}
extern void WP_SetSaberEntModelSkin( gentity_t *ent, gentity_t *saberent );
qboolean WP_BreakSaber( gentity_t *ent, const char *surfName, saberType_t saberType )
{//Make sure there *is* one specified and not using dualSabers
if ( ent == NULL || ent->client == NULL )
{//invalid ent or client
return qfalse;
}
if ( ent->s.number < MAX_CLIENTS )
{//player
//if ( g_spskill->integer < 3 )
{//only on the hardest level?
//FIXME: add a cvar?
return qfalse;
}
}
if ( ent->health <= 0 )
{//not if they're dead
return qfalse;
}
if ( ent->client->ps.weapon != WP_SABER )
{//not holding saber
return qfalse;
}
if ( ent->client->ps.dualSabers )
{//FIXME: handle this?
return qfalse;
}
if ( !ent->client->ps.saber[0].brokenSaber1 )
{//not breakable into another type of saber
return qfalse;
}
if ( PM_SaberInStart( ent->client->ps.saberMove ) //in a start
|| PM_SaberInTransition( ent->client->ps.saberMove ) //in a transition
|| PM_SaberInAttack( ent->client->ps.saberMove ) )//in an attack
{//don't break when in the middle of an attack
return qfalse;
}
if ( Q_stricmpn( "w_", surfName, 2 )
&& Q_stricmpn( "saber", surfName, 5 ) //hack because using mod-community made saber
&& Q_stricmp( "cylinder01", surfName ) )//hack because using mod-community made saber
{//didn't hit my weapon
return qfalse;
}
//Sith Sword should ALWAYS do this
if ( saberType != SABER_SITH_SWORD && Q_irand( 0, 50 ) )//&& Q_irand( 0, 10 ) )
{//10% chance - FIXME: extern this, too?
return qfalse;
}
//break it
char *replacementSaber1 = G_NewString( ent->client->ps.saber[0].brokenSaber1 );
char *replacementSaber2 = G_NewString( ent->client->ps.saber[0].brokenSaber2 );
int i, originalNumBlades = ent->client->ps.saber[0].numBlades;
qboolean broken = qfalse;
saber_colors_t colors[MAX_BLADES];
//store the colors
for ( i = 0; i < MAX_BLADES; i++ )
{
colors[i] = ent->client->ps.saber[0].blade[i].color;
}
//FIXME: chance of dropping the right-hand one? Based on damage, or...?
//FIXME: sound & effect when this happens, and send them into a broken parry?
//remove saber[0], replace with replacementSaber1
if ( replacementSaber1 )
{
WP_RemoveSaber( ent, 0 );
WP_SetSaber( ent, 0, replacementSaber1 );
for ( i = 0; i < ent->client->ps.saber[0].numBlades; i++ )
{
ent->client->ps.saber[0].blade[i].color = colors[i];
}
broken = qtrue;
//change my saberent's model and skin to match my new right-hand saber
WP_SetSaberEntModelSkin( ent, &g_entities[ent->client->ps.saberEntityNum] );
}
if ( originalNumBlades <= 1 )
{//nothing to split off
//FIXME: handle this?
}
else
{
//remove saber[1], replace with replacementSaber2
if ( replacementSaber2 )
{//FIXME: 25% chance that it just breaks - just spawn the second saber piece and toss it away immediately, can't be picked up.
//shouldn't be one in this hand, but just in case, remove it
WP_RemoveSaber( ent, 1 );
WP_SetSaber( ent, 1, replacementSaber2 );
//put the remainder of the original saber's blade colors onto this saber's blade(s)
for ( i = ent->client->ps.saber[0].numBlades; i < MAX_BLADES; i++ )
{
ent->client->ps.saber[1].blade[i-ent->client->ps.saber[0].numBlades].color = colors[i];
}
broken = qtrue;
}
}
return broken;
}
void WP_SaberLoadParms( void )
{
int len, totallen, saberExtFNLen, fileCnt, i;
char *buffer, *holdChar, *marker;
char saberExtensionListBuf[2048]; // The list of file names read in
//gi.Printf( "Parsing *.sab saber definitions\n" );
//set where to store the first one
totallen = 0;
marker = SaberParms;
marker[0] = '\0';
//now load in the .sab definitions
fileCnt = gi.FS_GetFileList("ext_data/sabers", ".sab", saberExtensionListBuf, sizeof(saberExtensionListBuf) );
holdChar = saberExtensionListBuf;
for ( i = 0; i < fileCnt; i++, holdChar += saberExtFNLen + 1 )
{
saberExtFNLen = strlen( holdChar );
len = gi.FS_ReadFile( va( "ext_data/sabers/%s", holdChar), (void **) &buffer );
if ( len == -1 )
{
gi.Printf( "WP_SaberLoadParms: error reading %s\n", holdChar );
}
else
{
if ( totallen && *(marker-1) == '}' )
{//don't let it end on a } because that should be a stand-alone token
strcat( marker, " " );
totallen++;
marker++;
}
len = COM_Compress( buffer );
if ( totallen + len >= MAX_SABER_DATA_SIZE ) {
G_Error( "WP_SaberLoadParms: ran out of space before reading %s\n(you must make the .sab files smaller)", holdChar );
}
strcat( marker, buffer );
gi.FS_FreeFile( buffer );
totallen += len;
marker += len;
}
}
}