Beispiel #1
0
/**
 * @brief Console function to push a dropdown window at a position. It work like UI_PushWindow but move the window at the right position
 * @sa UI_PushWindow
 * @note The usage is "ui_push_dropdown sourcenode pointposition destinationnode pointposition"
 * sourcenode must be a node into the window we want to push,
 * we will move the window to have sourcenode over destinationnode
 * pointposition select for each node a position (like a corner).
 */
static void UI_PushDropDownWindow_f (void)
{
	vec2_t source;
	vec2_t destination;
	uiNode_t *node;
	int direction;
	size_t writtenBytes;
	int result;

	if (Cmd_Argc() != 4 && Cmd_Argc() != 5) {
		Com_Printf("Usage: %s <source-anchor> <point-in-source-anchor> <dest-anchor> <point-in-dest-anchor>\n", Cmd_Argv(0));
		return;
	}

	/* get the source anchor */
	node = UI_GetNodeByPath(Cmd_Argv(1));
	if (node == NULL) {
		Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(1));
		return;
	}
	result = Com_ParseValue(&direction, Cmd_Argv(2), V_INT, 0, sizeof(direction), &writtenBytes);
	if (result != RESULT_OK) {
		Com_Printf("UI_PushDropDownWindow_f: '%s' in not a V_INT\n", Cmd_Argv(2));
		return;
	}
	UI_NodeGetPoint(node, source, direction);
	UI_NodeRelativeToAbsolutePoint(node, source);

	/* get the destination anchor */
	if (Q_streq(Cmd_Argv(4), "mouse")) {
		destination[0] = mousePosX;
		destination[1] = mousePosY;
	} else {
		/* get the source anchor */
		node = UI_GetNodeByPath(Cmd_Argv(3));
		if (node == NULL) {
			Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(3));
			return;
		}
		result = Com_ParseValue(&direction, Cmd_Argv(4), V_INT, 0, sizeof(direction), &writtenBytes);
		if (result != RESULT_OK) {
			Com_Printf("UI_PushDropDownWindow_f: '%s' in not a V_INT\n", Cmd_Argv(4));
			return;
		}
		UI_NodeGetPoint(node, destination, direction);
		UI_NodeRelativeToAbsolutePoint(node, destination);
	}

	/* update the window and push it */
	node = UI_GetNodeByPath(Cmd_Argv(1));
	if (node == NULL) {
		Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(1));
		return;
	}
	node = node->root;
	node->box.pos[0] += destination[0] - source[0];
	node->box.pos[1] += destination[1] - source[1];
	UI_PushWindow(node->name);
}
Beispiel #2
0
/**
 * @brief Parse a property value
 * @todo don't read the next token (need to change the script language)
 */
static bool UI_ParseProperty (void* object, const value_t* property, const char* objectName, const char** text, const char** token)
{
	const char* errhead = "UI_ParseProperty: unexpected end of file (object";
	static const char* notWellFormedValue = "UI_ParseProperty: \"%s\" is not a well formed node name (it must be quoted, uppercase const, a number, or prefixed with '*')\n";
	size_t bytes;
	int result;
	const int specialType = property->type & V_UI_MASK;

	if (property->type == V_NULL) {
		return false;
	}

	switch (specialType) {
	case V_NOT_UI:	/* common type */

		*token = Com_EParse(text, errhead, objectName);
		if (!*text)
			return false;
		if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
			Com_Printf(notWellFormedValue, *token);
			return false;
		}

		if (property->type == V_TRANSLATION_STRING) {
			/* selectbox values are static arrays */
			char* const target = Com_GetValue<char[]>(object, property);
			const char* translatableToken = *token;
			assert(property->size);
			if (translatableToken[0] == '_')
				translatableToken++;
			Q_strncpyz(target, translatableToken, property->size);
		} else {
			result = Com_ParseValue(object, *token, property->type, property->ofs, property->size, &bytes);
			if (result != RESULT_OK) {
				Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
				return false;
			}
		}
		break;

	case V_UI_REF:
		*token = Com_EParse(text, errhead, objectName);
		if (!*text)
			return false;
		if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
			Com_Printf(notWellFormedValue, *token);
			return false;
		}

		/* a reference to data is handled like this */
		ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK));
		Com_GetValue<byte*>(object, property) = ui_global.curadata;

		/** @todo check for the moment its not a cvar */
		assert((*token)[0] != '*');

		/* sanity check */
		if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) {
			Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
			return false;
		}

		result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size, &bytes);
		if (result != RESULT_OK) {
			Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
			return false;
		}
		ui_global.curadata += bytes;

		break;

	case V_UI_CVAR:	/* common type */
		*token = Com_EParse(text, errhead, objectName);
		if (!*text)
			return false;
		if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
			Com_Printf(notWellFormedValue, *token);
			return false;
		}

		/* references are parsed as string */
		if ((*token)[0] == '*') {
			/* a reference to data */
			ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, V_STRING);
			Com_GetValue<byte*>(object, property) = ui_global.curadata;

			/* sanity check */
			if (strlen(*token) > MAX_VAR - 1) {
				Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
				return false;
			}

			result = Com_ParseValue(ui_global.curadata, *token, V_STRING, 0, 0, &bytes);
			if (result != RESULT_OK) {
				Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
				return false;
			}
			ui_global.curadata += bytes;
		} else {
			/* a reference to data */
			ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t)(property->type & V_BASETYPEMASK));
			Com_GetValue<byte*>(object, property) = ui_global.curadata;

			/* sanity check */
			if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) {
				Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
				return false;
			}

			result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t)(property->type & V_BASETYPEMASK), 0, property->size, &bytes);
			if (result != RESULT_OK) {
				Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
				return false;
			}
			ui_global.curadata += bytes;
		}
		break;

	case V_UI:

		switch ((int)property->type) {
		case V_UI_ACTION:
			result = UI_ParseEventProperty(static_cast<uiNode_t*>(object), property, text, token, errhead);
			if (!result)
				return false;
			break;

		case V_UI_EXCLUDERECT:
			result = UI_ParseExcludeRect(static_cast<uiNode_t*>(object), text, token, errhead);
			if (!result)
				return false;
			break;

		case V_UI_SPRITEREF:
			{
				*token = Com_EParse(text, errhead, objectName);
				if (!*text)
					return false;

				uiSprite_t const*& sprite = Com_GetValue<uiSprite_t const*>(object, property);
				sprite = UI_GetSpriteByName(*token);
				if (!sprite) {
					Com_Printf("UI_ParseProperty: sprite '%s' not found (object %s)\n", *token, objectName);
				}
			}
			break;

		case V_UI_IF:
			{
				*token = Com_EParse(text, errhead, objectName);
				if (!*text)
					return false;

				uiAction_t*& expression = Com_GetValue<uiAction_t*>(object, property);
				expression = UI_AllocStaticStringCondition(*token);
				if (!expression)
					return false;
			}
			break;

		case V_UI_DATAID:
			{
				*token = Com_EParse(text, errhead, objectName);
				if (!*text)
					return false;

				int& dataId = Com_GetValue<int>(object, property);
				dataId = UI_GetDataIDByName(*token);
				if (dataId < 0) {
					Com_Printf("UI_ParseProperty: Could not find shared data ID '%s' (%s@%s)\n",
							*token, objectName, property->string);
					return false;
				}
			}
			break;

		default:
			Com_Printf("UI_ParseProperty: unknown property type '%d' (0x%X) (%s@%s)\n",
					property->type, property->type, objectName, property->string);
			return false;
		}
		break;

	default:
		Com_Printf("UI_ParseProperties: unknown property type '%d' (0x%X) (%s@%s)\n",
				property->type, property->type, objectName, property->string);
		return false;
	}

	return true;
}
static void UI_MaterialEditorChangeValue_f (void)
{
	image_t* image;
	int id, stageType;
	const char* var, *value;
	size_t bytes;

	if (Cmd_Argc() < 5) {
		Com_Printf("Usage: %s <image index> <stage index> <variable> <value>\n", Cmd_Argv(0));
		return;
	}

	id = atoi(Cmd_Argv(1));
	if (id < 0 || id >= r_numImages) {
		Com_Printf("Given image index (%i) is out of bounds\n", id);
		return;
	}

	var = Cmd_Argv(3);
	value = Cmd_Argv(4);

	image = R_GetImageAtIndex(id);

	stageType = UI_MaterialEditorNameToStage(var);
	if (stageType == -1) {
		const value_t* val = UI_FindPropertyByName(materialValues, var);
		if (!val) {
			Com_Printf("Could not find material variable for '%s'\n", var);
			return;
		}
		Com_ParseValue(&image->material, value, val->type, val->ofs, val->size, &bytes);
	} else {
		materialStage_t* stage;
		int stageID;
		const value_t* val = UI_FindPropertyByName(materialStageValues, var);

		if (!val) {
			Com_Printf("Could not find material stage variable for '%s'\n", var);
			return;
		}

		stageID = atoi(Cmd_Argv(2));
		if (stageID < 0 || stageID >= image->material.num_stages) {
			Com_Printf("Given stage index (%i) is out of bounds\n", stageID);
			return;
		}

		stage = UI_MaterialEditorGetStage(&image->material, stageID);
		assert(stage);

		stage->flags |= stageType;

		Com_ParseValue(stage, value, val->type, val->ofs, val->size, &bytes);

		/* a texture or envmap means render it */
		if (stage->flags & (STAGE_TEXTURE | STAGE_ENVMAP))
			stage->flags |= STAGE_RENDER;

		if (stage->flags & (STAGE_TAPE | STAGE_TERRAIN | STAGE_DIRTMAP))
			stage->flags |= STAGE_LIGHTING;
	}

	R_ModReloadSurfacesArrays();
}
Beispiel #4
0
/**
 * @brief unittest around common type
 */
TEST_F(ParserTest, ParserCommonType)
{
	int ivalue;
	bool bvalue;
	float fvalue;
	align_t align;
	blend_t blend;
	style_t style;
	fade_t fade;
	size_t bytes;
	int result;

	/* boolean */

	bytes = 0;
	result = Com_ParseValue (&bvalue, "true", V_BOOL, 0, sizeof(bool), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(bvalue, 1);
	ASSERT_EQ(bytes, sizeof(bool));

	bytes = 0;
	result = Com_ParseValue (&bvalue, "false", V_BOOL, 0, sizeof(bool), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(bvalue, 0);
	ASSERT_EQ(bytes, sizeof(bool));

	bytes = 0;
	result = Com_ParseValue (&bvalue, "foo", V_BOOL, 0, sizeof(int), &bytes);
	ASSERT_EQ(result, RESULT_ERROR);
	ASSERT_EQ(bytes, 0);

	/* int */

	bytes = 0;
	result = Com_ParseValue (&ivalue, "10", V_INT, 0, sizeof(int), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(ivalue, 10);
	ASSERT_EQ(bytes, sizeof(int));

	bytes = 0;
	result = Com_ParseValue (&ivalue, "abc", V_INT, 0, sizeof(int), &bytes);
	ASSERT_EQ(result, RESULT_ERROR);
	ASSERT_EQ(bytes, 0);

	/* float */

	bytes = 0;
	result = Com_ParseValue (&fvalue, "1.1", V_FLOAT, 0, sizeof(float), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(fvalue, 1.1f);
	ASSERT_EQ(bytes, sizeof(float));

	bytes = 0;
	result = Com_ParseValue (&fvalue, "9.8", V_FLOAT, 0, sizeof(float), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(fvalue, 9.8f);
	ASSERT_EQ(bytes, sizeof(float));

	bytes = 0;
	result = Com_ParseValue (&fvalue, "abc", V_FLOAT, 0, sizeof(float), &bytes);
	ASSERT_EQ(result, RESULT_ERROR);
	ASSERT_EQ(bytes, 0);

	/** @todo V_POS */
	/** @todo V_VECTOR */
	/** @todo V_COLOR */
	/** @todo V_STRING */
	/** @todo V_TRANSLATION_STRING */
	/** @todo V_LONGSTRING */

	/* align */

	bytes = 0;
	result = Com_ParseValue (&align, "cc", V_ALIGN, 0, sizeof(align_t), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(align, ALIGN_CC);
	ASSERT_EQ(bytes, sizeof(align_t));

	bytes = 0;
	result = Com_ParseValue (&align, "abc", V_ALIGN, 0, sizeof(align_t), &bytes);
	ASSERT_EQ(result, RESULT_ERROR);
	ASSERT_EQ(bytes, 0);

	/* blend */

	bytes = 0;
	result = Com_ParseValue (&blend, "blend", V_BLEND, 0, sizeof(blend_t), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(blend, BLEND_BLEND);
	ASSERT_EQ(bytes, sizeof(blend_t));

	bytes = 0;
	result = Com_ParseValue (&blend, "abc", V_BLEND, 0, sizeof(blend_t), &bytes);
	ASSERT_EQ(result, RESULT_ERROR);
	ASSERT_EQ(bytes, 0);

	/* style */

	bytes = 0;
	result = Com_ParseValue (&style, "rotated", V_STYLE, 0, sizeof(style_t), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(style, STYLE_ROTATED);
	ASSERT_EQ(bytes, sizeof(style_t));

	bytes = 0;
	result = Com_ParseValue (&style, "abc", V_STYLE, 0, sizeof(style_t), &bytes);
	ASSERT_EQ(result, RESULT_ERROR);
	ASSERT_EQ(bytes, 0);

	/* fade */

	bytes = 0;
	result = Com_ParseValue (&fade, "sin", V_FADE, 0, sizeof(fade_t), &bytes);
	ASSERT_EQ(result, RESULT_OK);
	ASSERT_EQ(fade, FADE_SIN);
	ASSERT_EQ(bytes, sizeof(fade_t));

	bytes = 0;
	result = Com_ParseValue (&fade, "abc", V_FADE, 0, sizeof(fade_t), &bytes);
	ASSERT_EQ(result, RESULT_ERROR);
	ASSERT_EQ(bytes, 0);
}
Beispiel #5
0
/**
 * @brief Set node property
 */
bool UI_NodeSetProperty (uiNode_t* node, const value_t* property, const char* value)
{
	const int specialType = property->type & V_UI_MASK;
	int result;
	size_t bytes;

	switch (specialType) {
	case V_NOT_UI:	/* common type */
		result = Com_ParseValue(node, value, property->type, property->ofs, property->size, &bytes);
		if (result != RESULT_OK) {
			Com_Printf("UI_NodeSetProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
			return false;
		}
		UI_Node_PropertyChanged(node, property);
		return true;

	case V_UI_CVAR:	/* cvar */
		switch ((int)property->type) {
		case V_UI_CVAR:
			if (Q_strstart(value, "*cvar:")) {
				char*& b = Com_GetValue<char*>(node, property);
				UI_FreeStringProperty(b);
				b = Mem_PoolStrDup(value, ui_dynStringPool, 0);
				UI_Node_PropertyChanged(node, property);
				return true;
			}
			break;
		case V_CVAR_OR_FLOAT:
			{
				float f;

				if (Q_strstart(value, "*cvar:")) {
					char*& b = Com_GetValue<char*>(node, property);
					UI_FreeStringProperty(b);
					b = Mem_PoolStrDup(value, ui_dynStringPool, 0);
					UI_Node_PropertyChanged(node, property);
					return true;
				}

				result = Com_ParseValue(&f, value, V_FLOAT, 0, sizeof(f), &bytes);
				if (result != RESULT_OK) {
					Com_Printf("UI_NodeSetProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
					return false;
				}

				void* const b = Com_GetValue<void*>(node, property);
				if (char const* const cvar = Q_strstart((char const*)b, "*cvar:"))
					Cvar_SetValue(cvar, f);
				else
					*(float*) b = f;
				UI_Node_PropertyChanged(node, property);
				return true;
			}
		case V_CVAR_OR_LONGSTRING:
		case V_CVAR_OR_STRING:
			{
				char*& b = Com_GetValue<char*>(node, property);
				UI_FreeStringProperty(b);
				b = Mem_PoolStrDup(value, ui_dynStringPool, 0);
				UI_Node_PropertyChanged(node, property);
				return true;
			}
		}
		break;

	case V_UI:
		switch ((int)property->type) {
		case V_UI_SPRITEREF:
			{
				uiSprite_t* sprite = UI_GetSpriteByName(value);
				Com_GetValue<uiSprite_t const*>(node, property) = sprite;
				UI_Node_PropertyChanged(node, property);
				return true;
			}
		}
		break;
	}

	Com_Printf("UI_NodeSetProperty: Unimplemented type for property '%s@%s'\n", UI_GetPath(node), property->string);
	return false;
}
static void SCP_ParseMission (const char *name, const char **text)
{
	const char *errhead = "SCP_ParseMission: unexpected end of file (mission ";
	staticMission_t *ms;
	const value_t *vp;
	const char *token;
	int i;
	size_t writtenBytes;

	token = Com_Parse(text);
	if (token[0] == '\0' || text[0] == '\0') {
		Com_Printf("SCP_ParseMission: mission def \"%s\" without name ignored\n", name);
		return;
	}

	/* search for missions with same name */
	for (i = 0; i < scd->numMissions; i++)
		if (Q_streq(token, scd->missions[i].id))
			break;

	if (i < scd->numMissions) {
		Com_Printf("SCP_ParseMission: mission def \"%s\" with same name found, second ignored\n", token);
		return;
	}

	if (scd->numMissions >= MAX_STATIC_MISSIONS) {
		Com_Printf("SCP_ParseMission: Too many missions, ignore '%s'\n", token);
		return;
	}

	/* initialize the menu */
	ms = &scd->missions[scd->numMissions];
	OBJZERO(*ms);

	Q_strncpyz(ms->id, token, sizeof(ms->id));

	/* get it's body */
	token = Com_Parse(text);

	if (text[0] == '\0' || !Q_streq(token, "{")) {
		Com_Printf("SCP_ParseMission: mission def \"%s\" without body ignored\n", ms->id);
		return;
	}

	do {
		token = Com_EParse(text, errhead, ms->id);
		if (text[0] == '\0')
			break;
		if (token[0] == '}')
			break;

		for (vp = mission_vals; vp->string; vp++)
			if (Q_streq(token, vp->string)) {
				/* found a definition */
				token = Com_EParse(text, errhead, ms->id);
				if (text[0] == '\0')
					return;

				if (vp->ofs) {
					Com_ParseValue(ms, token, vp->type, vp->ofs, vp->size, &writtenBytes);
				} else {
					Com_Printf("SCP_ParseMission: unknown token '%s'\n", token);
				}
				break;
			}

		if (!vp->string) {
			if (Q_streq(token, "city")) {
				const city_t *city;
				token = Com_EParse(text, errhead, ms->id);
				if (text[0] == '\0')
					return;
				city = CP_GetCity(token);
				if (city == NULL)
					Com_Printf("SCP_ParseMission: unknown city \"%s\" ignored (mission %s)\n", token, ms->id);
				else
					Vector2Copy(city->pos, ms->pos);
			} else {
				Com_Printf("SCP_ParseMission: unknown token \"%s\" ignored (mission %s)\n", token, ms->id);
			}
		}

	} while (*text);

	mapDef_t *mapDef = cgi->Com_GetMapDefinitionByID(ms->id);
	if (mapDef == NULL) {
		Com_Printf("SCP_ParseMission: invalid mapdef for '%s'\n", ms->id);
		return;
	}

	if (Vector2Empty(ms->pos)) {
		if (!CP_GetRandomPosOnGeoscapeWithParameters(ms->pos, mapDef->terrains, mapDef->cultures, mapDef->populations, NULL)) {
			Com_Printf("SCP_ParseMission: could not find a valid position for '%s'\n", ms->id);
			return;
		}
	}

	scd->numMissions++;
}
static void SCP_ParseStageSet (const char *name, const char **text)
{
	const char *errhead = "SCP_ParseStageSet: unexpected end of file (stageset ";
	stageSet_t *sp;
	const value_t *vp;
	char missionstr[256];
	const char *token, *misp;
	int j;
	size_t writtenBytes;

	/* initialize the stage */
	sp = &scd->stageSets[scd->numStageSets++];
	OBJZERO(*sp);
	Q_strncpyz(sp->name, name, sizeof(sp->name));

	/* get it's body */
	token = Com_Parse(text);
	if (text[0] == '\0' || !Q_streq(token, "{")) {
		Com_Printf("SCP_ParseStageSet: stageset def \"%s\" without body ignored\n", sp->name);
		scd->numStageSets--;
		return;
	}

	do {
		token = Com_EParse(text, errhead, sp->name);
		if (!*text)
			break;
		if (token[0] == '}')
			break;

		/* check for some standard values */
		for (vp = stageset_vals; vp->string; vp++)
			if (Q_streq(token, vp->string)) {
				/* found a definition */
				token = Com_EParse(text, errhead, sp->name);
				if (!*text)
					return;

				Com_ParseValue(sp, token, vp->type, vp->ofs, vp->size, &writtenBytes);
				break;
			}
		if (vp->string)
			continue;

		/* get mission set */
		if (Q_streq(token, "missions")) {
			token = Com_EParse(text, errhead, sp->name);
			if (!*text)
				return;
			Q_strncpyz(missionstr, token, sizeof(missionstr));
			misp = missionstr;

			/* add mission options */
			sp->numMissions = 0;
			do {
				token = Com_Parse(&misp);
				if (!misp)
					break;

				for (j = 0; j < scd->numMissions; j++) {
					if (Q_streq(token, scd->missions[j].id)) {
						sp->missions[sp->numMissions++] = j;
						break;
					}
				}

				if (j == scd->numMissions) {
					const mapDef_t *mapDef = cgi->Com_GetMapDefinitionByID(token);
					if (mapDef != NULL) {
						if (j < MAX_STATIC_MISSIONS - 1) {
							/* we don't need and mission definition in the scripts if we just would like to link a mapdef */
							staticMission_t *mis = &scd->missions[j];
							OBJZERO(*mis);
							Q_strncpyz(mis->id, token, sizeof(mis->id));
							if (!CP_GetRandomPosOnGeoscapeWithParameters(mis->pos, mapDef->terrains, mapDef->cultures, mapDef->populations, NULL)) {
								Com_Printf("SCP_ParseMission: could not find a valid position for '%s'\n", mis->id);
								continue;
							}
							sp->missions[sp->numMissions++] = scd->numMissions++;
						}
					} else {
						Com_Printf("SCP_ParseStageSet: unknown mission \"%s\" ignored (stageset %s)\n", token, sp->name);
					}
				}
			} while (misp && sp->numMissions < MAX_SETMISSIONS);
			continue;
		}

		Com_Printf("SCP_ParseStageSet: unknown token \"%s\" ignored (stageset %s)\n", token, sp->name);
	} while (*text);
}