#include "b_local.h" #include "boltOns.h" //#include "b_public.h" //extern void G_ParseBoltOnList( boltOn_t *boltOn ); extern gentity_t *G_CreateObject ( gentity_t *owner, vec3_t origin, vec3_t angles, int modelIndex, int frame, trType_t trType ); extern qboolean G_ParseLiteral( char **data, const char *string ); extern qboolean G_ParseString( char **data, char **s ) ; extern qboolean G_ParseInt( char **data, int *i ); extern qboolean G_ParseFloat( char **data, float *f ); #define BOLTON_NONE MAX_BOLT_ONS boltOn_t knownBoltOns[MAX_GAME_BOLTONS]; int numBoltOns; char boltOnList[0x10000]; int G_GetBoltOnIndex( const char *boltOnName ) { for ( int i = 0; i < numBoltOns; i++ ) { if ( Q_stricmp( knownBoltOns[i].name, boltOnName ) == 0 ) {//found it! return i; } } G_Error( "ERROR: Unknown boltOn name: %s!\n", boltOnName ); return MAX_GAME_BOLTONS; } void G_RegisterBoltOns (void) { boltOn_t *boltOn = NULL; char *token = NULL; char *value; char *p; int n; float f; p = boltOnList; COM_BeginParseSession(); while(1) { if ( numBoltOns >= MAX_GAME_BOLTONS ) { G_Error( "ERROR: Too many boltOns (%d) in boltOn.cfg!\n", MAX_GAME_BOLTONS ); return; } boltOn = &knownBoltOns[numBoltOns]; while ( 1 ) { token = COM_ParseExt( &p, qtrue ); if ( token[0] == 0 ) { //reached EOF return; } else if ( token[0] == '{' ) { //WTF? Unnamed boltOn? continue; } else if ( !p ) { //??? return; } else { //found a boltOn name break; } } Q_strncpyz( (char *)&boltOn->name, token, sizeof(boltOn->name), qtrue ); if ( G_ParseLiteral( &p, "{" ) ) {//couldn't find an open brace "{"! return; } //Set default scale VectorSet(boltOn->model.scaleXYZ, 100, 100, 100); // parse the boltOn info block while ( 1 ) { token = COM_ParseExt( &p, qtrue ); if ( !token[0] ) { gi.Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", boltOn->name ); return; } if ( !Q_stricmp( token, "}" ) ) { //reached end of boltOn, on to next break; } // modelName if ( !Q_stricmp( token, "modelName" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } boltOn->model.modelIndex = G_ModelIndex( value ); continue; } // target model to attach to, head, torso, legs or weapon if ( !Q_stricmp( token, "targetModel" ) ) { if ( G_ParseInt( &p, &n ) ) { continue; } if ( n < 0 || n >= NUM_TARGET_MODELS ) { gi.Printf("WARNING boltOn %s has targetModel out of range (<0 or >= %d)\n", boltOn->name, NUM_TARGET_MODELS); return; } boltOn->targetModel = (targetModel_t)n; continue; } // target tag to attach to if ( !Q_stricmp( token, "targetTag" ) ) { if ( G_ParseString( &p, &value ) ) { continue; } //boltOn->targetTag = G_NewString(value); Q_strncpyz( boltOn->targetTag, value, sizeof(boltOn->targetTag), qtrue); continue; } // pitch offset if ( !Q_stricmp( token, "pitchOffset" ) ) { if ( G_ParseFloat( &p, &f ) ) { continue; } boltOn->angleOffsets[0] = f; continue; } // yaw offset if ( !Q_stricmp( token, "yawOffset" ) ) { if ( G_ParseFloat( &p, &f ) ) { continue; } boltOn->angleOffsets[1] = f; continue; } // roll offset if ( !Q_stricmp( token, "rollOffset" ) ) { if ( G_ParseFloat( &p, &f ) ) { continue; } boltOn->angleOffsets[2] = f; continue; } // x offset if ( !Q_stricmp( token, "xOffset" ) ) { if ( G_ParseFloat( &p, &f ) ) { continue; } boltOn->originOffsets[0] = f; continue; } // y offset if ( !Q_stricmp( token, "yOffset" ) ) { if ( G_ParseFloat( &p, &f ) ) { continue; } boltOn->originOffsets[1] = f; continue; } // z offset if ( !Q_stricmp( token, "zOffset" ) ) { if ( G_ParseFloat( &p, &f ) ) { continue; } boltOn->originOffsets[2] = f; continue; } // Uniform XYZ scale if ( !Q_stricmp( token, "scale" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.scaleXYZ[0] = boltOn->model.scaleXYZ[1] = boltOn->model.scaleXYZ[2] = n; continue; } //X scale if ( !Q_stricmp( token, "scaleX" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.scaleXYZ[0] = n; continue; } //Y scale if ( !Q_stricmp( token, "scaleY" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.scaleXYZ[1] = n; continue; } //Z scale if ( !Q_stricmp( token, "scaleZ" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.scaleXYZ[2] = n; continue; } // Uniform RGB tint if ( !Q_stricmp( token, "tint" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.customRGB[0] = boltOn->model.customRGB[1] = boltOn->model.customRGB[2] = n; continue; } //red tint if ( !Q_stricmp( token, "tintRed" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.customRGB[0] = n; continue; } //Green tint if ( !Q_stricmp( token, "tintGreen" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.customRGB[1] = n; continue; } //Blue tint if ( !Q_stricmp( token, "tintBlue" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.customRGB[2] = n; continue; } //alpha if ( !Q_stricmp( token, "alpha" ) ) { if ( G_ParseInt( &p, &n ) ) { SkipRestOfLine( &p ); continue; } if ( n < 0 ) { gi.Printf( "bad %s in boltOn '%s'\n", token, boltOn->name ); continue; } boltOn->model.customAlpha = n; continue; } } numBoltOns++; } } void G_ClearBoltOnInfo( boltOnInfo_t *bOInfo ) { bOInfo->index = MAX_GAME_BOLTONS; VectorClear( bOInfo->lastOrigin ); VectorClear( bOInfo->lastAngles ); bOInfo->frame = bOInfo->startFrame = bOInfo->endFrame = 0; bOInfo->loopAnim = qfalse; } void G_LoadBoltOns( void ) { int len; const char filename[] = "ext_data/boltOns.cfg"; char *buffer; gi.Printf( "Parsing %s\n", filename ); len = gi.FS_ReadFile( filename, (void **) &buffer ); if ( len == -1 ) { gi.Printf( "file not found\n" ); return; } if ( len >= sizeof( boltOnList ) ) { G_Error( "ext_data/boltOns.cfg is too large" ); } strncpy( boltOnList, buffer, sizeof( boltOnList ) - 1 ); gi.FS_FreeFile( buffer ); G_RegisterBoltOns(); } byte G_AddBoltOn( gentity_t *ent, const char *boltOnName ) { int freeSlot, newIndex; if ( !ent || !boltOnName || !boltOnName[0] ) { return BOLTON_NONE; } newIndex = G_GetBoltOnIndex( boltOnName ); if ( newIndex < 0 || newIndex >= numBoltOns ) { return BOLTON_NONE; } if ( !ent->client ) { freeSlot = 0; G_ClearBoltOnInfo( &ent->boltOn ); ent->boltOn.index = newIndex; } else { for ( freeSlot = 0; freeSlot < MAX_BOLT_ONS; freeSlot++ ) { if ( ent->client->renderInfo.boltOns[freeSlot].index == MAX_GAME_BOLTONS ) {//Found a free slot break; } else if ( ent->client->renderInfo.boltOns[freeSlot].index == newIndex ) { #ifndef FINAL_BUILD gi.Printf("WARNING: %s already has boltOn turned on!\n", ent->targetname, boltOnName ); #endif return BOLTON_NONE; } } if ( freeSlot >= MAX_BOLT_ONS ) { gi.Printf("WARNING: %s out of free boltOn slots! (MAX = %d)\n", ent->targetname, MAX_BOLT_ONS ); return BOLTON_NONE; } G_ClearBoltOnInfo( &ent->client->renderInfo.boltOns[freeSlot] ); ent->client->renderInfo.boltOns[freeSlot].index = newIndex; } return freeSlot; } void G_RemoveBoltOn( gentity_t *ent, const char *boltOnName ) { int namedIndex; if ( !ent || !boltOnName || !boltOnName[0] ) { return; } namedIndex = G_GetBoltOnIndex( boltOnName ); if ( namedIndex < 0 || namedIndex >= numBoltOns ) { return; } if ( !ent->client ) { if ( ent->boltOn.index == namedIndex ) { G_ClearBoltOnInfo( &ent->boltOn ); } } else { for ( int i = 0; i < MAX_BOLT_ONS; i++ ) { if ( ent->client->renderInfo.boltOns[i].index == namedIndex ) {//Found it, clear it G_ClearBoltOnInfo( &ent->client->renderInfo.boltOns[i] ); } } } } void G_DropBoltOn( gentity_t *ent, const char *boltOnName ) { boltOn_t *boltOn; int namedIndex; if ( !ent || !boltOnName || !boltOnName[0] ) { return; } namedIndex = G_GetBoltOnIndex( boltOnName ); if ( namedIndex < 0 || namedIndex >= numBoltOns ) { return; } if ( !ent->client ) { if ( ent->boltOn.index != namedIndex ) { //FIXME: error msg return; } if ( ent->boltOn.index < 0 || ent->boltOn.index >= numBoltOns ) { return; } boltOn = &knownBoltOns[ent->boltOn.index]; //FIXME: what about tint, alpha and scale? And animation? gentity_t *newObject = G_CreateObject( ent, ent->boltOn.lastOrigin, ent->boltOn.lastAngles, boltOn->model.modelIndex, ent->boltOn.frame, TR_GRAVITY ); if ( newObject ) { newObject->targetname = G_NewString( va( "%s_%s", ent->targetname, boltOnName ) ); } //Remove it G_RemoveBoltOn( ent, boltOnName ); } else { for ( int i = 0; i < MAX_BOLT_ONS; i++ ) { if ( ent->client->renderInfo.boltOns[i].index < 0 || ent->client->renderInfo.boltOns[i].index >= numBoltOns ) { continue; } if ( ent->client->renderInfo.boltOns[i].index == namedIndex ) {//Found it boltOn = &knownBoltOns[ent->client->renderInfo.boltOns[i].index]; //GUH!!! Move these onto ENT!!! gentity_t *newObject = G_CreateObject( ent, ent->client->renderInfo.boltOns[i].lastOrigin, ent->client->renderInfo.boltOns[i].lastAngles, boltOn->model.modelIndex, ent->client->renderInfo.boltOns[i].frame, TR_GRAVITY );//TR_STATIONARY );// if ( newObject ) { newObject->targetname = G_NewString( va( "%s_%s", ent->targetname, boltOnName ) ); } //FIXME: what about tint, alpha and scale? And animation? //Remove it G_RemoveBoltOn( ent, boltOnName ); //Done return; } } } } byte G_BoltOnNumberForName( gentity_t *ent, const char *boltOnName ) { if ( !ent || !boltOnName || !boltOnName[0] ) { return MAX_BOLT_ONS; } if ( !ent->client ) {//non-clients only have one return 0; } for ( int i = 0; i < MAX_BOLT_ONS; i++ ) { if ( !Q_stricmp( boltOnName, knownBoltOns[ent->client->renderInfo.boltOns[i].index].name ) ) {//Found it, return it return i; } } return MAX_BOLT_ONS; } void G_InitBoltOnData ( gentity_t *ent ) { //UG, crappy here, but need to initialize boltOn index to invalid number ent->activeBoltOn = MAX_BOLT_ONS; G_ClearBoltOnInfo( &ent->boltOn ); if ( ent->client ) { for ( int i = 0; i < MAX_BOLT_ONS; i++ ) { G_ClearBoltOnInfo( &ent->client->renderInfo.boltOns[i] ); } } }