/* ==================== 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; }
/* ==================== 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. ==================== */ qboolean G_ParseSpawnVars( void ) { 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 qfalse; } if ( com_token[ 0 ] != '{' ) { G_Error( "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 ) ) ) { G_Error( "G_ParseSpawnVars: EOF without closing brace" ); } if ( keyname[ 0 ] == '}' ) { break; } // parse value if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) { G_Error( "G_ParseSpawnVars: EOF without closing brace" ); } if ( com_token[ 0 ] == '}' ) { G_Error( "G_ParseSpawnVars: closing brace without data" ); } if ( level.numSpawnVars == MAX_SPAWN_VARS ) { G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" ); } level.spawnVars[ level.numSpawnVars ][ 0 ] = G_AddSpawnVarToken( keyname ); level.spawnVars[ level.numSpawnVars ][ 1 ] = G_AddSpawnVarToken( com_token ); level.numSpawnVars++; } return qtrue; }
/* ============== CG_ParseEntitiesFromString Parses textual entity definitions out of an entstring ============== */ void CG_ParseEntitiesFromString( void ) { // make sure it is reset trap_GetEntityToken( NULL, -1 ); // allow calls to CG_Spawn*() cg.spawning = qtrue; cg.numSpawnVars = 0; // the worldspawn is not an actual entity, but it still // has a "spawn" function to perform any global setup // needed by a level (setting configstrings or cvars, etc) if( !CG_ParseSpawnVars() ) { CG_Error( "ParseEntities: no entities" ); } SP_worldspawn(); // parse ents while( CG_ParseSpawnVars() ) { CG_ParseEntityFromSpawnVars(); } cg.spawning = qfalse; // any future calls to CG_Spawn*() will be errors }
/* ==================== CG_ParseSpawnVars Parses a brace bounded set of key / value pairs out of the level's entity strings into cg.spawnVars[] This does not actually spawn an entity. ==================== */ qboolean CG_ParseSpawnVars( void ) { char keyname[MAX_TOKEN_CHARS]; char com_token[MAX_TOKEN_CHARS]; char token[MAX_TOKEN_CHARS]; //char buf[MAX_TOKEN_CHARS]; const char *line; qboolean newLine; vec3_t origin; int wait; titem_t ti; int val; int skipItem; int i; //char *gametypeName; //char *value; int angle; int spawnflags; qboolean spawnPoint; qboolean redSpawn; qboolean blueSpawn; qboolean initial; qboolean deathmatch; qboolean portal; qboolean portalHasTarget; qboolean startTimer; qboolean stopTimer; qboolean gotOrigin; int pointContents; static char *gametypeNames[] = { "ffa", "tournament", "single", "team", /*FIXME clanarena*/ "ca", "ctf", "oneflag", "obelisk", "harvester", "ft", "dom", "ad", "rr", "race" }; //Com_Printf("cgs.gametype : %d\n", cgs.gametype); cg.numSpawnVars = 0; cg.numSpawnVarChars = 0; // parse the opening brace if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) { // end of spawn string return qfalse; } if ( com_token[0] != '{' ) { CG_Error( "CG_ParseSpawnVars: found %s when expecting {",com_token ); } // go through all the key / value pairs while ( 1 ) { // parse key if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) { CG_Error( "CG_ParseSpawnVars: EOF without closing brace" ); } if ( keyname[0] == '}' ) { break; } // parse value if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) { CG_Error( "CG_ParseSpawnVars: EOF without closing brace" ); } if ( com_token[0] == '}' ) { CG_Error( "CG_ParseSpawnVars: closing brace without data" ); } if ( cg.numSpawnVars == MAX_SPAWN_VARS ) { CG_Error( "CG_ParseSpawnVars: MAX_SPAWN_VARS" ); } cg.spawnVars[ cg.numSpawnVars ][0] = CG_AddSpawnVarToken( keyname ); cg.spawnVars[ cg.numSpawnVars ][1] = CG_AddSpawnVarToken( com_token ); cg.numSpawnVars++; if (!Q_stricmp(keyname, "enableDust")) { cg.mapEnableDust = atoi(com_token); } else if (!Q_stricmp(keyname, "enableBreath")) { cg.mapEnableBreath = atoi(com_token); } //CG_Printf("spawnvars %s : %s\n", cg.spawnVars[ cg.numSpawnVars - 1 ][0], cg.spawnVars[ cg.numSpawnVars - 1 ][1]); } if (cgs.gametype == GT_CA) { //return qtrue; } ti = noitem; wait = 0; skipItem = 0; angle = 0; spawnflags = 0; spawnPoint = qfalse; redSpawn = qfalse; blueSpawn = qfalse; initial = qfalse; deathmatch = qfalse; portal = qfalse; portalHasTarget = qfalse; startTimer = qfalse; stopTimer = qfalse; gotOrigin = qfalse; // get the rest while (1) { // parse key if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) { //CG_Printf("all done parsing ents\n"); break; } //Com_Printf("'%s'\n", keyname); if (keyname[0] == '{') { //CG_Printf("{\n"); // clear values ti = noitem; wait = 0; skipItem = 0; angle = 0; spawnflags = 0; spawnPoint = qfalse; redSpawn = qfalse; blueSpawn = qfalse; initial = qfalse; deathmatch = qfalse; portal = qfalse; portalHasTarget = qfalse; startTimer = qfalse; stopTimer = qfalse; gotOrigin = qfalse; continue; } if ( keyname[0] == '}' ) { //CG_Printf("}\n"); if (spawnPoint) { //Com_Printf("spawn: %f %f %f angle:%d spawnflags:%d r:%d b:%d\n", origin[0], origin[1], origin[2], angle, spawnflags, redSpawn, blueSpawn); i = cg.numSpawnPoints; if (i >= MAX_SPAWN_POINTS) { continue; } VectorCopy(origin, cg.spawnPoints[i].origin); cg.spawnPoints[i].angle = angle; cg.spawnPoints[i].spawnflags = spawnflags; cg.spawnPoints[i].redSpawn = redSpawn; cg.spawnPoints[i].blueSpawn = blueSpawn; cg.spawnPoints[i].initial = initial; cg.spawnPoints[i].deathmatch = deathmatch; cg.numSpawnPoints++; continue; } if (portal) { if (!portalHasTarget) { if (cg.numMirrorSurfaces > MAX_MIRROR_SURFACES) { Com_Printf("^3max mirror surfaces (%d)\n", MAX_MIRROR_SURFACES); continue; } VectorCopy(origin, cg.mirrorSurfaces[cg.numMirrorSurfaces]); cg.numMirrorSurfaces++; //Com_Printf("origin: %f %f %f\n", origin[0], origin[1], origin[2]); } //Com_Printf("^1origin: %f %f %f (hasTarget %d)\n", origin[0], origin[1], origin[2], portalHasTarget); continue; } if (startTimer) { cg.hasStartTimer = qtrue; VectorCopy(origin, cg.startTimerOrigin); Com_Printf("^5start timer %f %f %f\n", origin[0], origin[1], origin[2]); continue; } if (stopTimer) { cg.hasStopTimer = qtrue; VectorCopy(origin, cg.stopTimerOrigin); Com_Printf("^5stop timer %f %f %f\n", origin[0], origin[1], origin[2]); continue; } if (gotOrigin) { pointContents = CG_PointContents(origin, 0); } else { pointContents = 0; } if (skipItem) { continue; } else if (pointContents & 0x1) { // it's in an invalid place, some maps have this qzdm20 has 2 megas continue; } else if (ti == redArmor) { if (!wait) wait = 25; AddTimedItem(&cg.numRedArmors, cg.redArmors, origin, wait); } else if (ti == yellowArmor) { if (!wait) wait = 25; AddTimedItem(&cg.numYellowArmors, cg.yellowArmors, origin, wait); } else if (ti == greenArmor) { if (!wait) wait = 25; AddTimedItem(&cg.numGreenArmors, cg.greenArmors, origin, wait); } else if (ti == megaHealth) { if (!wait) wait = 35; AddTimedItem(&cg.numMegaHealths, cg.megaHealths, origin, wait); } else if (ti == quad) { if (!wait) wait = 120; AddTimedItem(&cg.numQuads, cg.quads, origin, wait); } else if (ti == battleSuit) { if (!wait) wait = 120; AddTimedItem(&cg.numBattleSuits, cg.battleSuits, origin, wait); } continue; } // parse value if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) { CG_Error( "CG_ParseSpawnVars: EOF without closing brace" ); } if ( com_token[0] == '}' ) { CG_Error( "CG_ParseSpawnVars: closing brace without data" ); } //CG_Printf("^3ent %s : %s\n", keyname, com_token); if (!Q_stricmp(keyname, "classname")) { if (!Q_stricmp(com_token, "info_player_deathmatch") || !Q_stricmp(com_token, "info_player_start")) { //FIXME spawnflags 4 spawnPoint = qtrue; deathmatch = qtrue; blueSpawn = qtrue; redSpawn = qtrue; //Com_Printf("deathmatch spawn %d\n", cg.numSpawnPoints); } else if (!Q_stricmp(com_token, "team_CTF_redspawn")) { spawnPoint = qtrue; redSpawn = qtrue; } else if (!Q_stricmp(com_token, "team_CTF_bluespawn")) { spawnPoint = qtrue; blueSpawn = qtrue; } else if (!Q_stricmp(com_token, "team_CTF_redplayer")) { spawnPoint = qtrue; redSpawn = qtrue; initial = qtrue; } else if (!Q_stricmp(com_token, "team_CTF_blueplayer")) { spawnPoint = qtrue; blueSpawn = qtrue; initial = qtrue; } else if (!Q_stricmp(com_token, "item_armor_body")) { // red armor //Com_Printf("red armor\n"); ti = redArmor; } else if (!Q_stricmp(com_token, "item_armor_combat")) { // yellow armor //Com_Printf("yellow armor\n"); ti = yellowArmor; } else if (!Q_stricmp(com_token, "item_armor_jacket")) { ti = greenArmor; } else if (!Q_stricmp(com_token, "item_health_mega")) { //Com_Printf("mega health\n"); ti = megaHealth; } else if (!Q_stricmp(com_token, "item_quad")) { //Com_Printf("quad\n"); ti = quad; } else if (!Q_stricmp(com_token, "item_enviro")) { // battlesuit //Com_Printf("battlesuit?\n"); ti = battleSuit; // count ?? } else if (!Q_stricmp(com_token, "misc_portal_surface")) { //Com_Printf("^3portal surface\n"); portal = qtrue; } else if (!Q_stricmp(com_token, "target_starttimer")) { startTimer = qtrue; } else if (!Q_stricmp(com_token, "target_stoptimer")) { stopTimer = qtrue; } else { //FIXME other? regen? } } else if (!Q_stricmp(keyname, "origin")) { if (SC_ParseVec3FromStr(com_token, origin) == -1) { //Com_Printf("FIXME getting origin for entitytoken %s", com_token); origin[0] = 0.0; origin[1] = 0.0; origin[2] = 0.0; } gotOrigin = qtrue; //Com_Printf("*** origin: %f %f %f\n", origin[0], origin[1], origin[2]); } else if (!Q_stricmp(keyname, "target")) { portalHasTarget = qtrue; //Q_strncpyz(buf, com_token, sizeof(buf)); //Com_Printf("^5target == '%s'\n", buf); } else if (!Q_stricmp(keyname, "wait")) { wait = atoi(com_token); } else if (!Q_stricmp(keyname, "notteam")) { val = atoi(com_token); //if (val && cgs.gametype >= GT_TEAM) { if (val && CG_IsTeamGame(cgs.gametype)) { skipItem = 1; } } else if (!Q_stricmp(keyname, "not_gametype")) { const char *value = com_token; const char *gametypeName; const char *s; //FIXME could be more than one digit in the list ?? if (isdigit(com_token[0])) { val = atoi(com_token); if (cgs.protocol == PROTOCOL_QL) { if (cgs.gametype == GT_RACE) { if (val == 2) { skipItem = 1; } } else { if (cgs.gametype == val) { skipItem = 1; } } } else { if (cgs.gametype == val) { skipItem = 1; } } } else { // string value s = NULL; if (cgs.gametype < ARRAY_LEN(gametypeNames)) { gametypeName = gametypeNames[cgs.gametype]; s = strstr(value, gametypeName); } if (!s) { // try alternate quake live gametype names if (cgs.gametype == GT_TEAM) { s = strstr(value, "tdm"); } else if (cgs.gametype == GT_TOURNAMENT) { s = strstr(value, "duel"); } else if (cgs.gametype == GT_HARVESTER) { s = strstr(value, "har"); } else if (cgs.gametype == GT_1FCTF) { s = strstr(value, "1f"); } else if (cgs.gametype == GT_OBELISK) { s = strstr(value, "obj"); } } if (s) { skipItem = 1; } } } else if (!Q_stricmp(keyname, "gametype")) { //FIXME this is wrong, see g_spawn.c //val = atoi(com_token); //if (val != cgs.gametype) { // skipItem = 1; //} qboolean found = qfalse; skipItem = 1; line = com_token; newLine = qfalse; while (*line && newLine == qfalse) { int ln; //Com_Printf("line1: '%s'\n", line); //FIXME const line = (char *)CG_GetTokenGameType(line, token, qfalse, &newLine); //Com_Printf("newline: %d\n", newLine); //Com_Printf("line2: '%s'\n", line); //Com_Printf(" token: '%s'\n", token); ln = strlen(token); if (ln && *token) { if (token[ln - 1] == ',') { token[ln - 1] = '\0'; } } for (i = 0; i < (sizeof(gametypeNames) / sizeof(char *)); i++) { if (!Q_stricmp(token, gametypeNames[i])) { found = qtrue; break; } } if (!found) { // try alternate quakelive name for 'team' if (!Q_stricmp(token, "tdm")) { if (cgs.gametype == GT_TEAM) { skipItem = 0; } } else if (!Q_stricmp(token, "duel")) { if (cgs.gametype == GT_TOURNAMENT) { skipItem = 0; } } else if (!Q_stricmp(token, "har")) { if (cgs.gametype == GT_HARVESTER) { skipItem = 0; } } else if (!Q_stricmp(token, "1f")) { if (cgs.gametype == GT_1FCTF) { skipItem = 0; } } else if (!Q_stricmp(token, "ob")) { if (cgs.gametype == GT_OBELISK) { skipItem = 0; } } else { Com_Printf("FIXME gametype : '%s' '%s'\n", com_token, token); } } else if (cgs.gametype < ARRAY_LEN(gametypeNames) && !Q_stricmp(token, gametypeNames[cgs.gametype])) { skipItem = 0; } } #if 0 if (!found) { Com_Printf("FIXME gametype : %s\n", com_token); } if (cgs.gametype >= ARRAY_LEN(gametypeNames) || Q_stricmp(com_token, gametypeNames[cgs.gametype])) { skipItem = 1; } #endif } else if (!Q_stricmp(keyname, "notfree")) { val = atoi(com_token); if (val && (cgs.gametype == GT_FFA || cgs.gametype == GT_TOURNAMENT)) { skipItem = 1; } } else if (!Q_stricmp(keyname, "notsingle")) { val = atoi(com_token); if (val && cgs.gametype == GT_SINGLE_PLAYER) { skipItem = 1; } } else if (!Q_stricmp(keyname, "angle")) { angle = atoi(com_token); } else if (!Q_stricmp(keyname, "spawnflags")) { spawnflags = atoi(com_token); } // count } return qtrue; }