//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 int i; for ( 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<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<client ) { if ( ent->client->ps.saber[0].Active() && ent->client->ps.saber[0].stylesForbidden ) { if ( (ent->client->ps.saber[0].stylesForbidden&(1<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<client->ps.saber[0].Active() && (ent->client->ps.saber[0].stylesLearned&(1<client->ps.saber[1].stylesLearned&(1<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<stylesForbidden = 0; for ( styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ ) { if ( styleNum != style ) { saber->stylesForbidden |= (1<stylesLearned |= (1<stylesForbidden |= (1<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<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<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; } } }