/* ==================== G_ParseSpawnVars Parses a brace bounded set of key / value pairs out of the level's entity strings into level.spawnVars[] This does not actually spawn an entity. ==================== */ bool G_ParseSpawnVars( bool inSubBSP ) { char keyname[MAX_TOKEN_CHARS]; char com_token[MAX_TOKEN_CHARS]; level.numSpawnVars = 0; level.numSpawnVarChars = 0; // parse the opening brace if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) { // end of spawn string return false; } if ( com_token[0] != '{' ) { Com_Error( ERR_FATAL, "G_ParseSpawnVars: found %s when expecting {",com_token ); } // go through all the key / value pairs while ( 1 ) { // parse key if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) { Com_Error( ERR_FATAL, "G_ParseSpawnVars: EOF without closing brace" ); } if ( keyname[0] == '}' ) { break; } // parse value if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) { Com_Error( ERR_FATAL, "G_ParseSpawnVars: EOF without closing brace" ); } if ( com_token[0] == '}' ) { Com_Error( ERR_FATAL, "G_ParseSpawnVars: closing brace without data" ); } if ( level.numSpawnVars == MAX_SPAWN_VARS ) { Com_Error( ERR_FATAL, "G_ParseSpawnVars: MAX_SPAWN_VARS" ); } AddSpawnField(keyname, com_token); } if (inSubBSP) { HandleEntityAdjustment(); } return true; }
static void HandleEntityAdjustment( void ) { char *value; vector3 origin, newOrigin, angles; char temp[MAX_QPATH]; float rotation; G_SpawnString( "origin", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { sscanf( value, "%f %f %f", &origin.x, &origin.y, &origin.z ); } else { origin.x = origin.y = origin.z = 0.0f; } rotation = DEG2RAD( level.mRotationAdjust ); newOrigin.x = origin.x*cosf( rotation ) - origin.y*sinf( rotation ); newOrigin.y = origin.x*sinf( rotation ) + origin.y*cosf( rotation ); newOrigin.z = origin.z; VectorAdd( &newOrigin, &level.mOriginAdjust, &newOrigin ); // damn VMs don't handle outputing a float that is compatible with sscanf in all cases Com_sprintf( temp, MAX_QPATH, "%0.0f %0.0f %0.0f", newOrigin.x, newOrigin.y, newOrigin.z ); AddSpawnField( "origin", temp ); G_SpawnString( "angles", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { sscanf( value, "%f %f %f", &angles.x, &angles.y, &angles.z ); angles.yaw = fmod( angles.y + level.mRotationAdjust, 360.0f ); // damn VMs don't handle outputing a float that is compatible with sscanf in all cases Com_sprintf( temp, MAX_QPATH, "%0.0f %0.0f %0.0f", angles.x, angles.y, angles.z ); AddSpawnField( "angles", temp ); } else { G_SpawnString( "angle", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { sscanf( value, "%f", &angles.y ); } else { angles.y = 0.0f; } angles.y = fmod( angles.y + level.mRotationAdjust, 360.0f ); Com_sprintf( temp, MAX_QPATH, "%0.0f", angles.y ); AddSpawnField( "angle", temp ); } // RJR experimental code for handling "direction" field of breakable brushes // though direction is rarely ever used. G_SpawnString( "direction", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { sscanf( value, "%f %f %f", &angles.x, &angles.y, &angles.z ); } else { angles.x = angles.y = angles.z = 0.0f; } angles.y = fmod( angles.y + level.mRotationAdjust, 360.0f ); Com_sprintf( temp, MAX_QPATH, "%0.0f %0.0f %0.0f", angles.x, angles.y, angles.z ); AddSpawnField( "direction", temp ); AddSpawnField( "BSPInstanceID", level.mTargetAdjust ); G_SpawnString( "targetname", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { Com_sprintf( temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value ); AddSpawnField( "targetname", temp ); } G_SpawnString( "target", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { Com_sprintf( temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value ); AddSpawnField( "target", temp ); } G_SpawnString( "killtarget", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { Com_sprintf( temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value ); AddSpawnField( "killtarget", temp ); } G_SpawnString( "brushparent", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { Com_sprintf( temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value ); AddSpawnField( "brushparent", temp ); } G_SpawnString( "brushchild", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { Com_sprintf( temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value ); AddSpawnField( "brushchild", temp ); } G_SpawnString( "enemy", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { Com_sprintf( temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value ); AddSpawnField( "enemy", temp ); } G_SpawnString( "ICARUSname", NOVALUE, &value ); if ( Q_stricmp( value, NOVALUE ) != 0 ) { Com_sprintf( temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value ); AddSpawnField( "ICARUSname", temp ); } }
static void HandleEntityAdjustment(void) { char *value; vec3_t origin, newOrigin, angles; char temp[MAX_QPATH]; float rotation; G_SpawnString("origin", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sscanf( value, "%f %f %f", &origin[0], &origin[1], &origin[2] ); } else { origin[0] = origin[1] = origin[2] = 0.0; } rotation = DEG2RAD(level.mRotationAdjust); newOrigin[0] = origin[0]*cos(rotation) - origin[1]*sin(rotation); newOrigin[1] = origin[0]*sin(rotation) + origin[1]*cos(rotation); newOrigin[2] = origin[2]; VectorAdd(newOrigin, level.mOriginAdjust, newOrigin); // damn VMs don't handle outputing a float that is compatible with sscanf in all cases sprintf_s(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", newOrigin[0], newOrigin[1], newOrigin[2]); AddSpawnField("origin", temp); G_SpawnString("angles", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sscanf( value, "%f %f %f", &angles[0], &angles[1], &angles[2] ); angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0); // damn VMs don't handle outputing a float that is compatible with sscanf in all cases sprintf_s(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", angles[0], angles[1], angles[2]); AddSpawnField("angles", temp); } else { G_SpawnString("angle", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sscanf( value, "%f", &angles[1] ); } else { angles[1] = 0.0; } angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0); sprintf_s(temp, MAX_QPATH, "%0.0f", angles[1]); AddSpawnField("angle", temp); } // RJR experimental code for handling "direction" field of breakable brushes // though direction is rarely ever used. G_SpawnString("direction", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sscanf( value, "%f %f %f", &angles[0], &angles[1], &angles[2] ); } else { angles[0] = angles[1] = angles[2] = 0.0; } angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0); sprintf_s(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", angles[0], angles[1], angles[2]); AddSpawnField("direction", temp); AddSpawnField("BSPInstanceID", level.mTargetAdjust); G_SpawnString("targetname", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sprintf_s(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value); AddSpawnField("targetname", temp); } G_SpawnString("target", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sprintf_s(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value); AddSpawnField("target", temp); } G_SpawnString("killtarget", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sprintf_s(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value); AddSpawnField("killtarget", temp); } G_SpawnString("brushparent", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sprintf_s(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value); AddSpawnField("brushparent", temp); } G_SpawnString("brushchild", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sprintf_s(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value); AddSpawnField("brushchild", temp); } G_SpawnString("enemy", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sprintf_s(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value); AddSpawnField("enemy", temp); } G_SpawnString("ICARUSname", NOVALUE, &value); if (strcmp(value, NOVALUE) != 0) { sprintf_s(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value); AddSpawnField("ICARUSname", temp); } }
// For Maker Mod objects // combine the two sets of spawnVars. newVars overwrite spawnVars // we end up with level.spawnVars setup with our final values, the values applied to our ent, // and the appropriate spawn function executed. void G_ApplySpawnVars( gentity_t *ent, char *spawnVars, char *newVars ) { int i; char *token; //static char *gametypeNames[] = {"ffa", "holocron", "jedimaster", "duel", "powerduel", "single", "team", "siege", "ctf", "cty"}; char* p; char field[MAX_FIELDNAME_LENGTH + 1]; level.numSpawnVars = 0; level.numSpawnVarChars = 0; level.spawnVarChars[0] = '/0'; p = spawnVars; while ( p ) { token = ParseExt( &p, qfalse ); // TODO : make sure it's safe to use this function if ( token[0] == 0 ) break; strncpy( field, token, MAX_FIELDNAME_LENGTH ); token = ParseExt( &p, qfalse ); if ( token[0] == 0 ) break; AddSpawnField( field, token ); } p = newVars; while ( p ) { token = ParseExt( &p, qfalse ); // TODO : make sure it's safe to use this function if ( token[0] == 0 ) break; strncpy( field, token, MAX_FIELDNAME_LENGTH ); token = ParseExt( &p, qfalse ); if ( token[0] == 0 ) break; AddSpawnField( field, token ); } for ( i = 0 ; i < level.numSpawnVars ; i++ ) { BG_ParseField( fields, level.spawnVars[i][0], level.spawnVars[i][1], (byte *)ent ); } // move editor origin to pos VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); // if we didn't get a classname, don't bother spawning anything if ( !G_CallSpawn( ent ) ) { //G_FreeEntity( ent ); } //Tag on the ICARUS scripting information only to valid recipients if ( trap_ICARUS_ValidEnt( ent ) ) { trap_ICARUS_InitEnt( ent ); if ( ent->classname && ent->classname[0] ) { if ( Q_strncmp( "NPC_", ent->classname, 4 ) != 0 ) {//Not an NPC_spawner (rww - probably don't even care for MP, but whatever) G_ActivateBehavior( ent, BSET_SPAWN ); } } } }