Example #1
1
bool loadPlayerScript(QString path, int player, int difficulty)
{
	ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "Player index %d out of bounds", player);
	QScriptEngine *engine = new QScriptEngine();
	UDWORD size;
	char *bytes = NULL;
	if (!loadFile(path.toAscii().constData(), &bytes, &size))
	{
		debug(LOG_ERROR, "Failed to read script file \"%s\"", path.toAscii().constData());
		return false;
	}
	QString source = QString::fromAscii(bytes, size);
	free(bytes);
	QScriptSyntaxCheckResult syntax = QScriptEngine::checkSyntax(source);
	ASSERT_OR_RETURN(false, syntax.state() == QScriptSyntaxCheckResult::Valid, "Syntax error in %s line %d: %s", 
	                 path.toAscii().constData(), syntax.errorLineNumber(), syntax.errorMessage().toAscii().constData());
	// Special functions
	engine->globalObject().setProperty("setTimer", engine->newFunction(js_setTimer));
	engine->globalObject().setProperty("queue", engine->newFunction(js_queue));
	engine->globalObject().setProperty("removeTimer", engine->newFunction(js_removeTimer));
	engine->globalObject().setProperty("include", engine->newFunction(js_include));
	engine->globalObject().setProperty("bind", engine->newFunction(js_bind));

	// Special global variables
	//== \item[version] Current version of the game, set in \emph{major.minor} format.
	engine->globalObject().setProperty("version", "3.2", QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[selectedPlayer] The player ontrolled by the client on which the script runs.
	engine->globalObject().setProperty("selectedPlayer", selectedPlayer, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[gameTime] The current game time. Updated before every invokation of a script.
	engine->globalObject().setProperty("gameTime", gameTime, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[difficulty] The currently set campaign difficulty, or the current AI's difficulty setting. It will be one of
	//== EASY, MEDIUM, HARD or INSANE.
	engine->globalObject().setProperty("difficulty", difficulty, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[mapName] The name of the current map.
	engine->globalObject().setProperty("mapName", game.map, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[baseType] The type of base that the game starts with. It will be one of CAMP_CLEAN, CAMP_BASE or CAMP_WALLS.
	engine->globalObject().setProperty("baseType", game.base, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[alliancesType] The type of alliances permitted in this game. It will be one of NO_ALLIANCES, ALLIANCES or ALLIANCES_TEAMS.
	engine->globalObject().setProperty("alliancesType", game.alliance, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[powerType] The power level set for this game.
	engine->globalObject().setProperty("powerType", game.power, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[maxPlayers] The number of active players in this game.
	engine->globalObject().setProperty("maxPlayers", game.maxPlayers, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[scavengers] Whether or not scavengers are activated in this game.
	engine->globalObject().setProperty("scavengers", game.scavengers, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[mapWidth] Width of map in tiles.
	engine->globalObject().setProperty("mapWidth", mapWidth, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[mapHeight] Height of map in tiles.
	engine->globalObject().setProperty("mapHeight", mapHeight, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	//== \item[scavengerPlayer] Index of scavenger player. (3.2+ only)
	engine->globalObject().setProperty("scavengerPlayer", scavengerPlayer(), QScriptValue::ReadOnly | QScriptValue::Undeletable);

	// Regular functions
	registerFunctions(engine);

	// Remember internal, reserved names
	QScriptValueIterator it(engine->globalObject());
	while (it.hasNext())
	{
		it.next();
		internalNamespace.insert(it.name(), 1);
	}
	// We need to always save the 'me' special variable.
	//== \item[me] The player the script is currently running as.
	engine->globalObject().setProperty("me", player, QScriptValue::ReadOnly | QScriptValue::Undeletable);
	QScriptValue result = engine->evaluate(source, path);
	ASSERT_OR_RETURN(false, !engine->hasUncaughtException(), "Uncaught exception at line %d, file %s: %s", 
	                 engine->uncaughtExceptionLineNumber(), path.toAscii().constData(), result.toString().toAscii().constData());

	// Register script
	scripts.push_back(engine);

	debug(LOG_SAVE, "Created script engine %d for player %d from %s", scripts.size() - 1, player, path.toUtf8().constData());
	return true;
}
Example #2
0
/* Create a feature on the map */
FEATURE * buildFeature(FEATURE_STATS *psStats, UDWORD x, UDWORD y,bool FromSave)
{
	//try and create the Feature
	FEATURE *psFeature = new FEATURE(generateSynchronisedObjectId(), psStats);

	if (psFeature == NULL)
	{
		debug(LOG_WARNING, "Feature couldn't be built.");
		return NULL;
	}
	// features are not in the cluster system
	// this will cause an assert when they still end up there
	psFeature->cluster = ~0;
	//add the feature to the list - this enables it to be drawn whilst being built
	addFeature(psFeature);

	// snap the coords to a tile
	if (!FromSave)
	{
		x = (x & ~TILE_MASK) + psStats->baseWidth  %2 * TILE_UNITS/2;
		y = (y & ~TILE_MASK) + psStats->baseBreadth%2 * TILE_UNITS/2;
	}
	else
	{
		if ((x & TILE_MASK) != psStats->baseWidth  %2 * TILE_UNITS/2 ||
		    (y & TILE_MASK) != psStats->baseBreadth%2 * TILE_UNITS/2)
		{
			debug(LOG_WARNING, "Feature not aligned. position (%d,%d), size (%d,%d)", x, y, psStats->baseWidth, psStats->baseBreadth);
		}
	}

	psFeature->pos.x = x;
	psFeature->pos.y = y;

	StructureBounds b = getStructureBounds(psFeature);

	// get the terrain average height
	int foundationMin = INT32_MAX;
	int foundationMax = INT32_MIN;
	for (int breadth = 0; breadth <= b.size.y; ++breadth)
	{
		for (int width = 0; width <= b.size.x; ++width)
		{
			int h = map_TileHeight(b.map.x + width, b.map.y + breadth);
			foundationMin = std::min(foundationMin, h);
			foundationMax = std::max(foundationMax, h);
		}
	}
	//return the average of max/min height
	int height = (foundationMin + foundationMax) / 2;

	if (psStats->subType == FEAT_TREE)
	{
		psFeature->rot.direction = gameRand(DEG_360);
	}
	else
	{
		psFeature->rot.direction = 0;
	}
	psFeature->body = psStats->body;
	psFeature->periodicalDamageStart = 0;
	psFeature->periodicalDamage = 0;

	// it has never been drawn
	psFeature->sDisplay.frameNumber = 0;

	memset(psFeature->seenThisTick, 0, sizeof(psFeature->seenThisTick));
	memset(psFeature->visible, 0, sizeof(psFeature->visible));

	// set up the imd for the feature
	psFeature->sDisplay.imd = psStats->psImd;

	ASSERT_OR_RETURN(NULL, psFeature->sDisplay.imd, "No IMD for feature");		// make sure we have an imd.

	for (int breadth = 0; breadth < b.size.y; ++breadth)
	{
		for (int width = 0; width < b.size.x; ++width)
		{
			MAPTILE *psTile = mapTile(b.map.x + width, b.map.y + breadth);

			//check not outside of map - for load save game
			ASSERT_OR_RETURN(NULL, b.map.x + width < mapWidth, "x coord bigger than map width - %s, id = %d", getName(psFeature->psStats), psFeature->id);
			ASSERT_OR_RETURN(NULL, b.map.y + breadth < mapHeight, "y coord bigger than map height - %s, id = %d", getName(psFeature->psStats), psFeature->id);

			if (width != psStats->baseWidth && breadth != psStats->baseBreadth)
			{
				if (TileHasFeature(psTile))
				{
					FEATURE *psBlock = (FEATURE *)psTile->psObject;

					debug(LOG_ERROR, "%s(%d) already placed at (%d+%d, %d+%d) when trying to place %s(%d) at (%d+%d, %d+%d) - removing it",
					      getName(psBlock->psStats), psBlock->id, map_coord(psBlock->pos.x), psBlock->psStats->baseWidth, map_coord(psBlock->pos.y),
					      psBlock->psStats->baseBreadth, getName(psFeature->psStats), psFeature->id, b.map.x, b.size.x, b.map.y, b.size.y);

					removeFeature(psBlock);
				}

				psTile->psObject = (BASE_OBJECT*)psFeature;

				// if it's a tall feature then flag it in the map.
				if (psFeature->sDisplay.imd->max.y > TALLOBJECT_YMAX)
				{
					auxSetBlocking(b.map.x + width, b.map.y + breadth, AIR_BLOCKED);
				}

				if (psStats->subType != FEAT_GEN_ARTE && psStats->subType != FEAT_OIL_DRUM)
				{
					auxSetBlocking(b.map.x + width, b.map.y + breadth, FEATURE_BLOCKED);
				}
			}

			if( (!psStats->tileDraw) && (FromSave == false) )
			{
				psTile->height = height;
			}
		}
	}
	psFeature->pos.z = map_TileHeight(b.map.x, b.map.y);//jps 18july97

	return psFeature;
}
Example #3
0
bool assertValidImage(IMAGEFILE *imageFile, unsigned id)
{
	ASSERT_OR_RETURN(false, id < imageFile->imageDefs.size(), "Out of range 1: %u/%d", id, (int)imageFile->imageDefs.size());
	ASSERT_OR_RETURN(false, imageFile->imageDefs[id].TPageID < imageFile->pages.size(), "Out of range 2: %u", imageFile->imageDefs[id].TPageID);
	return true;
}
Example #4
0
/* This returns true if the key is currently depressed */
bool keyDown(KEY_CODE code)
{
	ASSERT_OR_RETURN(false, code < KEY_MAXSCAN, "Invalid keycode of %d!", (int)code);
	return (aKeyState[code].state != KEY_UP);
}
Example #5
0
/*!
 * Load shape levels recursively
 * \param ppFileData Pointer to the data (usualy read from a file)
 * \param FileDataEnd ???
 * \param nlevels Number of levels to load
 * \return pointer to iFSDShape structure (or NULL on error)
 * \pre ppFileData loaded
 * \post s allocated
 */
static iIMDShape *_imd_load_level(const char **ppFileData, const char *FileDataEnd, int nlevels, int pieVersion)
{
	const char *pFileName = GetLastResourceFilename(); // Last loaded filename
	const char *pFileData = *ppFileData;
	char buffer[PATH_MAX] = {'\0'};
	int cnt = 0, n = 0, i;
	iIMDShape *s = NULL;
	float dummy;

	if (nlevels == 0)
	{
		return NULL;
	}

	i = sscanf(pFileData, "%255s %n", buffer, &cnt);
	ASSERT_OR_RETURN(NULL, i == 1, "Bad directive following LEVEL");

	s = new iIMDShape;

	// Optionally load and ignore deprecated MATERIALS directive
	if (strcmp(buffer, "MATERIALS") == 0)
	{
		i = sscanf(pFileData, "%255s %f %f %f %f %f %f %f %f %f %f%n", buffer, &dummy, &dummy, &dummy, &dummy,
		           &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &cnt);
		ASSERT_OR_RETURN(NULL, i == 11, "Bad MATERIALS directive");
		debug(LOG_WARNING, "MATERIALS directive no longer supported!");
		pFileData += cnt;
	}
	else if (strcmp(buffer, "SHADERS") == 0)
	{
		char vertex[PATH_MAX], fragment[PATH_MAX];

		if (sscanf(pFileData, "%255s %255s %255s%n", buffer, vertex, fragment, &cnt) != 3)
		{
			debug(LOG_ERROR, "%s shader corrupt: %s", pFileName, buffer);
			return NULL;
		}
		s->shaderProgram = pie_LoadShader(pFileName, vertex, fragment);
		pFileData += cnt;
	}

	if (sscanf(pFileData, "%255s %d%n", buffer, &s->npoints, &cnt) != 2)
	{
		debug(LOG_ERROR, "_imd_load_level(2): file corrupt");
		return NULL;
	}
	pFileData += cnt;

	// load points

	ASSERT_OR_RETURN(NULL, strcmp(buffer, "POINTS") == 0, "Expecting 'POINTS' directive, got: %s", buffer);

	_imd_load_points(&pFileData, s);

	if (sscanf(pFileData, "%255s %d%n", buffer, &s->npolys, &cnt) != 2)
	{
		debug(LOG_ERROR, "_imd_load_level(3): file corrupt");
		return NULL;
	}
	pFileData += cnt;

	ASSERT_OR_RETURN(NULL, strcmp(buffer, "POLYGONS") == 0, "Expecting 'POLYGONS' directive, got: %s", buffer);

	_imd_load_polys(&pFileData, s, pieVersion);

	// NOW load optional stuff
	while (!AtEndOfFile(pFileData, FileDataEnd)) // check for end of file (give or take white space)
	{
		// Scans in the line ... if we don't get 2 parameters then quit
		if (sscanf(pFileData, "%255s %d%n", buffer, &n, &cnt) != 2)
		{
			break;
		}
		pFileData += cnt;

		if (strcmp(buffer, "LEVEL") == 0)	// check for next level
		{
			debug(LOG_3D, "imd[_load_level] = npoints %d, npolys %d", s->npoints, s->npolys);
			s->next = _imd_load_level(&pFileData, FileDataEnd, nlevels - 1, pieVersion);
		}
		else if (strcmp(buffer, "CONNECTORS") == 0)
		{
			//load connector stuff
			s->nconnectors = n;
			_imd_load_connectors(&pFileData, s);
		}
		else
		{
			debug(LOG_ERROR, "(_load_level) unexpected directive %s %d", buffer, n);
			break;
		}
	}

	// FINALLY, massage the data into what can stream directly to OpenGL
	glGenBuffers(VBO_COUNT, s->buffers);
	vertexCount = 0;
	for (int k = 0; k < MAX(1, s->numFrames); k++)
	{
		// Go through all polygons for each frame
		for (int i = 0; i < s->npolys; i++)
		{
			const iIMDPoly *pPolys = &s->polys[i];

			// Do we already have the vertex data for this polygon?
			indices.append(addVertex(s, 0, pPolys, k));
			indices.append(addVertex(s, 1, pPolys, k));
			indices.append(addVertex(s, 2, pPolys, k));
		}
	}
	glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_VERTEX]);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.constData(), GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_NORMAL]);
	glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(GLfloat), normals.constData(), GL_STATIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->buffers[VBO_INDEX]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.constData(), GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_TEXCOORD]);
	glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(GLfloat), texcoords.constData(), GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind

	indices.resize(0);
	vertices.resize(0);
	texcoords.resize(0);
	normals.resize(0);

	*ppFileData = pFileData;

	return s;
}
Example #6
0
// Run from screen.c on init. Do not change the order of loading here! First ones are enumerated.
bool pie_LoadShaders()
{
	pie_internal::SHADER_PROGRAM program;
	int result;

	// Load some basic shaders
	memset(&program, 0, sizeof(program));
	pie_internal::shaderProgram.push_back(program);
	int shaderEnum = 0;

	// TCMask shader for map-placed models with advanced lighting
	debug(LOG_3D, "Loading shader: SHADER_COMPONENT");
	result = pie_LoadShader("Component program", "shaders/tcmask.vert", "shaders/tcmask.frag",
		{ "colour", "teamcolour", "stretch", "tcmask", "fogEnabled", "normalmap", "specularmap", "ecmEffect", "alphaTest", "graphicsCycle",
		"ModelViewMatrix", "ModelViewProjectionMatrix", "NormalMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular",
		"fogEnd", "fogStart", "fogColor" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_COMPONENT, "Failed to load component shader");

	// TCMask shader for buttons with flat lighting
	debug(LOG_3D, "Loading shader: SHADER_BUTTON");
	result = pie_LoadShader("Button program", "shaders/button.vert", "shaders/button.frag",
		{ "colour", "teamcolour", "stretch", "tcmask", "fogEnabled", "normalmap", "specularmap", "ecmEffect", "alphaTest", "graphicsCycle",
		"ModelViewMatrix", "ModelViewProjectionMatrix", "NormalMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular",
		"fogEnd", "fogStart", "fogColor" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_BUTTON, "Failed to load button shader");

	// Plain shader for no lighting
	debug(LOG_3D, "Loading shader: SHADER_NOLIGHT");
	result = pie_LoadShader("Plain program", "shaders/nolight.vert", "shaders/nolight.frag",
		{ "colour", "teamcolour", "stretch", "tcmask", "fogEnabled", "normalmap", "specularmap", "ecmEffect", "alphaTest", "graphicsCycle",
		"ModelViewMatrix", "ModelViewProjectionMatrix", "NormalMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular",
		"fogEnd", "fogStart", "fogColor" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_NOLIGHT, "Failed to load no-lighting shader");

	debug(LOG_3D, "Loading shader: SHADER_TERRAIN");
	result = pie_LoadShader("terrain program", "shaders/terrain_water.vert", "shaders/terrain.frag",
		{ "ModelViewProjectionMatrix", "paramx1", "paramy1", "paramx2", "paramy2", "tex", "lightmap_tex", "textureMatrix1", "textureMatrix2",
		"fogEnabled", "fogEnd", "fogStart", "fogColor" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_TERRAIN, "Failed to load terrain shader");

	debug(LOG_3D, "Loading shader: SHADER_TERRAIN_DEPTH");
	result = pie_LoadShader("terrain_depth program", "shaders/terrain_water.vert", "shaders/terraindepth.frag",
	{ "ModelViewProjectionMatrix", "paramx2", "paramy2", "lightmap_tex", "textureMatrix1", "textureMatrix2" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_TERRAIN_DEPTH, "Failed to load terrain_depth shader");

	debug(LOG_3D, "Loading shader: SHADER_DECALS");
	result = pie_LoadShader("decals program", "shaders/decals.vert", "shaders/decals.frag",
		{ "ModelViewProjectionMatrix", "paramxlight", "paramylight", "tex", "lightmap_tex", "lightTextureMatrix",
		"fogEnabled", "fogEnd", "fogStart", "fogColor" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_DECALS, "Failed to load decals shader");

	debug(LOG_3D, "Loading shader: SHADER_WATER");
	result = pie_LoadShader("water program", "shaders/terrain_water.vert", "shaders/water.frag",
		{ "ModelViewProjectionMatrix", "paramx1", "paramy1", "paramx2", "paramy2", "tex1", "tex2", "textureMatrix1", "textureMatrix2",
		"fogEnabled", "fogEnd", "fogStart" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_WATER, "Failed to load water shader");

	// Rectangular shader
	debug(LOG_3D, "Loading shader: SHADER_RECT");
	result = pie_LoadShader("Rect program", "shaders/rect.vert", "shaders/rect.frag",
		{ "transformationMatrix", "color" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_RECT, "Failed to load rect shader");

	// Textured rectangular shader
	debug(LOG_3D, "Loading shader: SHADER_TEXRECT");
	result = pie_LoadShader("Textured rect program", "shaders/rect.vert", "shaders/texturedrect.frag",
		{ "transformationMatrix", "tuv_offset", "tuv_scale", "color", "texture" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_TEXRECT, "Failed to load textured rect shader");

	debug(LOG_3D, "Loading shader: SHADER_GFX_COLOUR");
	result = pie_LoadShader("gfx_color program", "shaders/gfx.vert", "shaders/gfx.frag",
		{ "posMatrix" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_GFX_COLOUR, "Failed to load textured gfx shader");

	debug(LOG_3D, "Loading shader: SHADER_GFX_TEXT");
	result = pie_LoadShader("gfx_text program", "shaders/gfx.vert", "shaders/texturedrect.frag",
		{ "posMatrix", "color", "texture" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_GFX_TEXT, "Failed to load textured gfx shader");

	debug(LOG_3D, "Loading shader: SHADER_GENERIC_COLOR");
	result = pie_LoadShader("generic color program", "shaders/generic.vert", "shaders/rect.frag", { "ModelViewProjectionMatrix", "color" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_GENERIC_COLOR, "Failed to load generic color shader");

	debug(LOG_3D, "Loading shader: SHADER_LINE");
	result = pie_LoadShader("line program", "shaders/line.vert", "shaders/rect.frag", { "from", "to", "color", "ModelViewProjectionMatrix" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_LINE, "Failed to load line shader");

	// Text shader
	debug(LOG_3D, "Loading shader: SHADER_TEXT");
	result = pie_LoadShader("Text program", "shaders/rect.vert", "shaders/text.frag",
		{ "transformationMatrix", "tuv_offset", "tuv_scale", "color", "texture" });
	ASSERT_OR_RETURN(false, result && ++shaderEnum == SHADER_TEXT, "Failed to load text shader");

	pie_internal::currentShaderMode = SHADER_NONE;

	GLbyte rect[] {
		0, 1, 0, 1,
		0, 0, 0, 1,
		1, 1, 0, 1,
		1, 0, 0, 1
	};
	glGenBuffers(1, &pie_internal::rectBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, pie_internal::rectBuffer);
	glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(GLbyte), rect, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	return true;
}
Example #7
0
bool assertValidImage(IMAGEFILE *imageFile, unsigned id)
{
	ASSERT_OR_RETURN(false, id < (unsigned)imageFile->NumImages, "Out of range 1: %u/%d", id, imageFile->NumImages);
	ASSERT_OR_RETURN(false, imageFile->ImageDefs[id].TPageID < MAX_NUM_TPAGEIDS, "Out of range 2: %u", imageFile->ImageDefs[id].TPageID);
	return true;
}
Example #8
0
ASR_RETVAL fpathAStarRoute(MOVE_CONTROL *psMove, PATHJOB *psJob)
{
	ASR_RETVAL      retval = ASR_OK;

	bool            mustReverse = true;

	const PathCoord tileOrig(map_coord(psJob->origX), map_coord(psJob->origY));
	const PathCoord tileDest(map_coord(psJob->destX), map_coord(psJob->destY));

	PathCoord endCoord;  // Either nearest coord (mustReverse = true) or orig (mustReverse = false).

	std::list<PathfindContext>::iterator contextIterator = fpathContexts.begin();
	for (contextIterator = fpathContexts.begin(); contextIterator != fpathContexts.end(); ++contextIterator)
	{
		if (!contextIterator->matches(psJob->blockingMap, tileDest))
		{
			// This context is not for the same droid type and same destination.
			continue;
		}

		// We have tried going to tileDest before.

		if (contextIterator->map[tileOrig.x + tileOrig.y*mapWidth].iteration == contextIterator->iteration
		 && contextIterator->map[tileOrig.x + tileOrig.y*mapWidth].visited)
		{
			// Already know the path from orig to dest.
			endCoord = tileOrig;
		}
		else
		{
			// Need to find the path from orig to dest, continue previous exploration.
			fpathAStarReestimate(*contextIterator, tileOrig);
			endCoord = fpathAStarExplore(*contextIterator, tileOrig);
		}

		if (endCoord != tileOrig)
		{
			// orig turned out to be on a different island than what this context was used for, so can't use this context data after all.
			continue;
		}

		mustReverse = false;  // We have the path from the nearest reachable tile to dest, to orig.
		break;  // Found the path! Don't search more contexts.
	}

	if (contextIterator == fpathContexts.end())
	{
		// We did not find an appropriate context. Make one.

		if (fpathContexts.size() < 30)
		{
			fpathContexts.push_back(PathfindContext());
		}
		--contextIterator;

		// Init a new context, overwriting the oldest one if we are caching too many.
		// We will be searching from orig to dest, since we don't know where the nearest reachable tile to dest is.
		fpathInitContext(*contextIterator, psJob->blockingMap, tileOrig, tileOrig, tileDest);
		endCoord = fpathAStarExplore(*contextIterator, tileDest);
		contextIterator->nearestCoord = endCoord;
	}

	PathfindContext &context = *contextIterator;

	// return the nearest route if no actual route was found
	if (context.nearestCoord != tileDest)
	{
		retval = ASR_NEAREST;
	}

	// Get route, in reverse order.
	static std::vector<Vector2i> path;  // Declared static to save allocations.
	path.clear();

	PathCoord newP;
	for (PathCoord p = endCoord; p != context.tileS; p = newP)
	{
		ASSERT_OR_RETURN(ASR_FAILED, tileOnMap(p.x, p.y), "Assigned XY coordinates (%d, %d) not on map!", (int)p.x, (int)p.y);
		ASSERT_OR_RETURN(ASR_FAILED, path.size() < (unsigned)mapWidth*mapHeight, "Pathfinding got in a loop.");

		path.push_back(Vector2i(world_coord(p.x) + TILE_UNITS / 2, world_coord(p.y) + TILE_UNITS / 2));

		PathExploredTile &tile = context.map[p.x + p.y*mapWidth];
		newP = PathCoord(p.x - tile.dx, p.y - tile.dy);
		if (p == newP)
		{
			break;  // We stopped moving, because we reached the closest reachable tile to context.tileS. Give up now.
		}
	}
	if (path.empty())
	{
		// We are probably already in the destination tile. Go to the exact coordinates.
		path.push_back(Vector2i(psJob->destX, psJob->destY));
	}
	else if (retval == ASR_OK)
	{
		// Found exact path, so use exact coordinates for last point, no reason to lose precision
		Vector2i v(psJob->destX, psJob->destY);
		if (mustReverse)
		{
			path.front() = v;
		}
		else
		{
			path.back() = v;
		}
	}

	// TODO FIXME once we can change numPoints to something larger than uint16_t
	psMove->numPoints = std::min<int>(UINT16_MAX, path.size());

	// Allocate memory
	psMove->asPath = static_cast<Vector2i *>(malloc(sizeof(*psMove->asPath) * path.size()));
	ASSERT(psMove->asPath, "Out of memory");
	if (!psMove->asPath)
	{
		fpathHardTableReset();
		return ASR_FAILED;
	}

	// get the route in the correct order
	// If as I suspect this is to reverse the list, then it's my suspicion that
	// we could route from destination to source as opposed to source to
	// destination. We could then save the reversal. to risky to try now...Alex M
	//
	// The idea is impractical, because you can't guarentee that the target is
	// reachable. As I see it, this is the reason why psNearest got introduced.
	// -- Dennis L.
	//
	// If many droids are heading towards the same destination, then destination
	// to source would be faster if reusing the information in nodeArray. --Cyp
	if (mustReverse)
	{
		// Copy the list, in reverse.
		std::copy(path.rbegin(), path.rend(), psMove->asPath);

		if (!context.isBlocked(tileOrig.x, tileOrig.y))  // If blocked, searching from tileDest to tileOrig wouldn't find the tileOrig tile.
		{
			// Next time, search starting from nearest reachable tile to the destination.
			fpathInitContext(context, psJob->blockingMap, tileDest, context.nearestCoord, tileOrig);
		}
	}
	else
	{
		// Copy the list.
		std::copy(path.begin(), path.end(), psMove->asPath);
	}

	// Move context to beginning of last recently used list.
	if (contextIterator != fpathContexts.begin())  // Not sure whether or not the splice is a safe noop, if equal.
	{
		fpathContexts.splice(fpathContexts.begin(), fpathContexts, contextIterator);
	}

	psMove->destination = psMove->asPath[path.size() - 1];

	return retval;
}
Example #9
0
// not a direct script function but a helper for scrSkDefenseLocation and scrSkDefenseLocationB
static bool defenseLocation(bool variantB)
{
	SDWORD		*pX,*pY,statIndex,statIndex2;
	UDWORD		x,y,gX,gY,dist,player,nearestSoFar,count;
	GATEWAY		*psGate,*psChosenGate;
	DROID		*psDroid;
	UDWORD		x1,x2,x3,x4,y1,y2,y3,y4;
	bool		noWater;
	UDWORD      minCount;
	UDWORD      offset;

	if (!stackPopParams(6,
						VAL_REF|VAL_INT, &pX,
						VAL_REF|VAL_INT, &pY,
						ST_STRUCTURESTAT, &statIndex,
						ST_STRUCTURESTAT, &statIndex2,
						ST_DROID, &psDroid,
						VAL_INT, &player) )
	{
		debug(LOG_ERROR,"defenseLocation: failed to pop");
		return false;
	}

	if (player >= MAX_PLAYERS)
	{
		ASSERT( false, "defenseLocation:player number is too high" );
		return false;
	}

	ASSERT_OR_RETURN( false, statIndex < numStructureStats, "Invalid range referenced for numStructureStats, %d > %d", statIndex, numStructureStats);

	ASSERT_OR_RETURN( false, statIndex2 < numStructureStats, "Invalid range referenced for numStructureStats, %d > %d", statIndex2, numStructureStats);
	STRUCTURE_STATS *psWStats = (asStructureStats + statIndex2);

    // check for wacky coords.
	if(		*pX < 0
		||	*pX > world_coord(mapWidth)
		||	*pY < 0
		||	*pY > world_coord(mapHeight)
	  )
	{
		goto failed;
	}

	x = map_coord(*pX);					// change to tile coords.
	y = map_coord(*pY);

	// go down the gateways, find the nearest gateway with >1 empty tiles
	nearestSoFar = UDWORD_MAX;
	psChosenGate = NULL;
	for (psGate = gwGetGateways(); psGate; psGate = psGate->psNext)
	{
		if (auxTile(psGate->x1, psGate->y1, player) & AUXBITS_THREAT)
		{
			continue;	// enemy can shoot there, not safe to build
		}
		count = 0;
		noWater = true;
		// does it have >1 tile unoccupied.
		if(psGate->x1 == psGate->x2)
		{// vert
			//skip gates that are too short
			if(variantB && (psGate->y2 - psGate->y1) <= 2)
			{
				continue;
			}
			gX = psGate->x1;
			for(gY=psGate->y1;gY <= psGate->y2; gY++)
			{
				if(! TileIsOccupied(mapTile(gX,gY) ))
				{
					count++;
				}
				if (terrainType(mapTile(gX,gY)) == TER_WATER)
				{
					noWater = false;
				}
			}
		}
		else
		{// horiz
			//skip gates that are too short
			if(variantB && (psGate->x2 - psGate->x1) <= 2)
			{
				continue;
			}
			gY = psGate->y1;
			for(gX=psGate->x1;gX <= psGate->x2; gX++)
			{
				if(! TileIsOccupied(mapTile(gX,gY) ))
				{
					count++;
				}
				if (terrainType(mapTile(gX,gY)) == TER_WATER)
				{
					noWater = false;
				}
			}
		}
		if(variantB) {
		    minCount = 2;
		} else {
		    minCount = 1;
		}
		if(count > minCount && noWater)	//<NEW> min 2 tiles
		{
			// ok it's free. Is it the nearest one yet?
			/* Get gateway midpoint */
			gX = (psGate->x1 + psGate->x2)/2;
			gY = (psGate->y1 + psGate->y2)/2;
			/* Estimate the distance to it */
			dist = iHypot(x - gX, y - gY);
			/* Is it best we've found? */
			if(dist<nearestSoFar && dist<30)
			{
				/* Yes, then keep a record of it */
				nearestSoFar = dist;
				psChosenGate = psGate;
			}
		}
	}

	if(!psChosenGate)	// we have a gateway.
	{
		goto failed;
	}

	// find an unnocupied tile on that gateway.
	if(psChosenGate->x1 == psChosenGate->x2)
	{// vert
		gX = psChosenGate->x1;
		for(gY=psChosenGate->y1;gY <= psChosenGate->y2; gY++)
		{
			if(! TileIsOccupied(mapTile(gX,gY) ))
			{
				y = gY;
				x = gX;
				break;
			}
		}
	}
	else
	{// horiz
		gY = psChosenGate->y1;
		for(gX=psChosenGate->x1;gX <= psChosenGate->x2; gX++)
		{
			if(! TileIsOccupied(mapTile(gX,gY) ))
			{
				y = gY;
				x = gX;
				break;
			}
		}
	}

	// back to world coords and store result.
	*pX = world_coord(x) + (TILE_UNITS / 2);		// return centre of tile.
	*pY = world_coord(y) + (TILE_UNITS / 2);

	scrFunctionResult.v.bval = true;
	if (!stackPushResult(VAL_BOOL,&scrFunctionResult))		// success
	{
		return false;
	}


	// order the droid to build two walls, one either side of the gateway.
	// or one in the case of a 2 size gateway.

	//find center of the gateway
	x = (psChosenGate->x1 + psChosenGate->x2)/2;
	y = (psChosenGate->y1 + psChosenGate->y2)/2;

	//find start pos of the gateway
	x1 = world_coord(psChosenGate->x1) + (TILE_UNITS / 2);
	y1 = world_coord(psChosenGate->y1) + (TILE_UNITS / 2);

	if(variantB) {
	    offset = 2;
	} else {
	    offset = 1;
	}
	if(psChosenGate->x1 == psChosenGate->x2)	//vert
	{
		x2 = x1;	//vert: end x pos of the first section = start x pos
		y2 = world_coord(y - 1) + TILE_UNITS / 2;	//start y loc of the first sec
		x3 = x1;
		y3 = world_coord(y + offset) + TILE_UNITS / 2;
	}
	else		//hor
	{
		x2 = world_coord(x - 1) + TILE_UNITS / 2;
		y2 = y1;
		x3 = world_coord(x+offset) + TILE_UNITS / 2;
		y3 = y1;

	}
	//end coords of the second section
	x4 = world_coord(psChosenGate->x2) + TILE_UNITS / 2;
	y4 = world_coord(psChosenGate->y2) + TILE_UNITS / 2;

	// first section.
	if(x1 == x2 && y1 == y2)	//first sec is 1 tile only: ((2 tile gate) or (3 tile gate and first sec))
	{
		orderDroidStatsLocDir(psDroid, DORDER_BUILD, psWStats, x1, y1, 0, ModeQueue);
	}
	else
	{
		orderDroidStatsTwoLocDir(psDroid, DORDER_LINEBUILD, psWStats,  x1, y1, x2, y2, 0, ModeQueue);
	}

	// second section
	if(x3 == x4 && y3 == y4)
	{
		orderDroidStatsLocDirAdd(psDroid, DORDER_BUILD, psWStats, x3, y3, 0);
	}
	else
	{
		orderDroidStatsTwoLocDirAdd(psDroid, DORDER_LINEBUILD, psWStats,  x3, y3, x4, y4, 0);
	}

	return true;

failed:
	scrFunctionResult.v.bval = false;
	if (!stackPushResult(VAL_BOOL,&scrFunctionResult))		// failed!
	{
		return false;
	}
	return true;
}
Example #10
0
/* Find a widget in a screen from its ID number */
WIDGET *widgGetFromID(W_SCREEN *psScreen, UDWORD id)
{
	ASSERT_OR_RETURN(NULL, psScreen != NULL, "Invalid screen pointer");
	return widgFormGetFromID((W_FORM *)psScreen->psForm, id);
}
Example #11
0
// Find a route for an DROID to a location in world coordinates
FPATH_RETVAL fpathDroidRoute(DROID* psDroid, SDWORD tX, SDWORD tY, FPATH_MOVETYPE moveType)
{
	bool acceptNearest;
	PROPULSION_STATS *psPropStats = getPropulsionStats(psDroid);

	// override for AI to blast our way through stuff
	if (!isHumanPlayer(psDroid->player) && moveType == FMT_MOVE)
	{
		moveType = (psDroid->asWeaps[0].nStat == 0) ? FMT_MOVE : FMT_ATTACK;
	}

	ASSERT_OR_RETURN(FPR_FAILED, psPropStats != NULL, "invalid propulsion stats pointer");
	ASSERT_OR_RETURN(FPR_FAILED, psDroid->type == OBJ_DROID, "We got passed an object that isn't a DROID!");

	// check whether the end point of the route
	// is a blocking tile and find an alternative if it is
	if (psDroid->sMove.Status != MOVEWAITROUTE && fpathDroidBlockingTile(psDroid, map_coord(tX), map_coord(tY), moveType))
	{
		// find the nearest non blocking tile to the DROID
		int minDist = SDWORD_MAX;
		int nearestDir = NUM_DIR;
		int dir;

		objTrace(psDroid->id, "BLOCKED(%d,%d) - trying workaround", map_coord(tX), map_coord(tY));
		for (dir = 0; dir < NUM_DIR; dir++)
		{
			int x = map_coord(tX) + aDirOffset[dir].x;
			int y = map_coord(tY) + aDirOffset[dir].y;

			if (tileOnMap(x, y) && !fpathDroidBlockingTile(psDroid, x, y, moveType))
			{
				// pick the adjacent tile closest to our starting point
				int tileDist = fpathDistToTile(x, y, psDroid->pos.x, psDroid->pos.y);

				if (tileDist < minDist)
				{
					minDist = tileDist;
					nearestDir = dir;
				}
			}

			if (dir == NUM_BASIC - 1 && nearestDir != NUM_DIR)
			{
				break;	// found a solution without checking at greater distance
			}
		}

		if (nearestDir == NUM_DIR)
		{
			// surrounded by blocking tiles, give up
			objTrace(psDroid->id, "route to (%d, %d) failed - target blocked", map_coord(tX), map_coord(tY));
			return FPR_FAILED;
		}
		else
		{
			tX = world_coord(map_coord(tX) + aDirOffset[nearestDir].x) + TILE_UNITS / 2;
			tY = world_coord(map_coord(tY) + aDirOffset[nearestDir].y) + TILE_UNITS / 2;
			objTrace(psDroid->id, "Workaround found at (%d, %d)", map_coord(tX), map_coord(tY));
		}
	}
	switch (psDroid->order)
	{
	case DORDER_BUILD:
	case DORDER_HELPBUILD:                       // help to build a structure
	case DORDER_LINEBUILD:                       // 6 - build a number of structures in a row (walls + bridges)
	case DORDER_DEMOLISH:                        // demolish a structure
	case DORDER_REPAIR:
		acceptNearest = false;
		break;
	default:
		acceptNearest = true;
		break;
	}
	return fpathRoute(&psDroid->sMove, psDroid->id, psDroid->pos.x, psDroid->pos.y, tX, tY, psPropStats->propulsionType, 
	                  psDroid->droidType, moveType, psDroid->player, acceptNearest);
}
Example #12
0
// ////////////////////////////////////////////////////////////////////////////
static bool pushedKeyCombo(KEY_CODE subkey)
{
	KEY_CODE	metakey = KEY_IGNORE;
	KEY_MAPPING	*pExist;
	KEY_MAPPING	*psMapping;
	KEY_CODE	alt;

	// check for
	// alt
	alt = (KEY_CODE)0;
	if (keyDown(KEY_RALT) || keyDown(KEY_LALT))
	{
		metakey = KEY_LALT;
		alt = KEY_RALT;
	}
	// ctrl
	else if (keyDown(KEY_RCTRL) || keyDown(KEY_LCTRL))
	{
		metakey = KEY_LCTRL;
		alt = KEY_RCTRL;
	}
	// shift
	else if (keyDown(KEY_RSHIFT) || keyDown(KEY_LSHIFT))
	{
		metakey = KEY_LSHIFT;
		alt = KEY_RSHIFT;
	}
	// meta (cmd)
	else if (keyDown(KEY_RMETA) || keyDown(KEY_LMETA))
	{
		metakey = KEY_LMETA;
		alt = KEY_RMETA;
	}

	// check if bound to a fixed combo.
	pExist = keyFindMapping(metakey,  subkey);
	if (pExist && (pExist->status == KEYMAP_ALWAYS || pExist->status == KEYMAP_ALWAYS_PROCESS))
	{
		selectedKeyMap = NULL;	// unhighlght selected.
		return false;
	}

	/* Clear down mappings using these keys... But only if it isn't unassigned */
	keyReAssignMapping(metakey, subkey, KEY_IGNORE, (KEY_CODE)KEY_MAXSCAN);

	/* Try and see if its there already - damn well should be! */
	psMapping = keyGetMappingFromFunction((void *)selectedKeyMap->function);

	/* Cough if it's not there */
	ASSERT_OR_RETURN(false, psMapping != NULL, "Trying to patch a non-existant function mapping - whoop whoop!!!");

	/* Now alter it to the new values */
	psMapping->metaKeyCode = metakey;
	psMapping->subKeyCode = subkey;
	// was "=="
	psMapping->status = KEYMAP_ASSIGNABLE; //must be
	if (alt)
	{
		psMapping->altMetaKeyCode = alt;
	}
	selectedKeyMap = NULL;	// unhighlght selected .
	return true;
}
Example #13
0
// get the array data for an array operation
static bool interpGetArrayVarData(INTERP_VAL **pip, VAL_CHUNK *psGlobals, SCRIPT_CODE *psProg, INTERP_VAL **ppsVal)
{
	SDWORD		i, dimensions, vals[VAR_MAX_DIMENSIONS];
	UBYTE		*elements;
	SDWORD		size, val;
	INTERP_VAL	*InstrPointer = *pip;
	UDWORD		base, index;

	// get the base index of the array
	base = InstrPointer->v.ival & ARRAY_BASE_MASK;

	// get the number of dimensions
	dimensions = (InstrPointer->v.ival & ARRAY_DIMENSION_MASK) >> ARRAY_DIMENSION_SHIFT;

	ASSERT_OR_RETURN(false, base < psProg->numArrays, "Arrray base index out of range (%d should be less than %d)", base, psProg->numArrays);
	ASSERT_OR_RETURN(false, dimensions == psProg->psArrayInfo[base].dimensions, "Array dimensions do not match (%d vs %d)", dimensions, psProg->psArrayInfo[base].dimensions);

	// get the number of elements for each dimension
	elements = psProg->psArrayInfo[base].elements;

	// calculate the index of the array element
	size = 1;
	index = 0;
	for(i=dimensions-1; i>=0; i-=1)
	{
		if (!stackPopParams(1, VAL_INT, &val))
		{
			return false;
		}

		if ( (val < 0) || (val >= elements[i]) )
		{
			debug( LOG_ERROR, "interpGetArrayVarData: Array index for dimension %d out of range (passed index = %d, max index = %d)", i , val, elements[i]);
			return false;
		}

		index += val * size;
		size *= psProg->psArrayInfo[base].elements[i];
		vals[i] = val;
	}

	// print out the debug trace
	if (interpTrace)
	{
		debug( LOG_NEVER, "%d->", base );
		for(i=0; i<dimensions; i+= 1)
		{
			debug( LOG_NEVER, "[%d/%d]", vals[i], elements[i] );
		}
		debug( LOG_NEVER, "(%d) ", index );
	}

	// check the index is valid
	ASSERT_OR_RETURN(false, index <= psProg->arraySize, "Array indexes out of variable space (%d)", index);

	// get the variable data
	*ppsVal = interpGetVarData(psGlobals, psProg->psArrayInfo[base].base + index);

	// update the instruction pointer
	*pip += 1;

	return true;
}
Example #14
0
static Spacetime interpolateSpacetime(Spacetime st1, Spacetime st2, uint32_t t)
{
	// Cyp says this should never happen, #3037 and #3238 say it does though.
	ASSERT_OR_RETURN(st1, st1.time != st2.time, "Spacetime overlap!");
	return Spacetime(interpolatePos(st1.pos, st2.pos, st1.time, st2.time, t), interpolateRot(st1.rot, st2.rot, st1.time, st2.time, t), t);
}
Example #15
0
/* Remove a Feature and free it's memory */
bool destroyFeature(FEATURE *psDel, unsigned impactTime)
{
	UDWORD			widthScatter,breadthScatter,heightScatter, i;
	EFFECT_TYPE		explosionSize;
	Vector3i pos;

	ASSERT_OR_RETURN(false, psDel != NULL, "Invalid feature pointer");

 	/* Only add if visible and damageable*/
	if(psDel->visible[selectedPlayer] && psDel->psStats->damageable)
	{
		/* Set off a destruction effect */
		/* First Explosions */
		widthScatter = TILE_UNITS/2;
		breadthScatter = TILE_UNITS/2;
		heightScatter = TILE_UNITS/4;
		//set which explosion to use based on size of feature
		if (psDel->psStats->baseWidth < 2 && psDel->psStats->baseBreadth < 2)
		{
			explosionSize = EXPLOSION_TYPE_SMALL;
		}
		else if (psDel->psStats->baseWidth < 3 && psDel->psStats->baseBreadth < 3)
		{
			explosionSize = EXPLOSION_TYPE_MEDIUM;
		}
		else
		{
			explosionSize = EXPLOSION_TYPE_LARGE;
		}
		for(i=0; i<4; i++)
		{
			pos.x = psDel->pos.x + widthScatter - rand()%(2*widthScatter);
			pos.z = psDel->pos.y + breadthScatter - rand()%(2*breadthScatter);
			pos.y = psDel->pos.z + 32 + rand()%heightScatter;
			addEffect(&pos, EFFECT_EXPLOSION, explosionSize, false, NULL, 0, impactTime);
		}

		if(psDel->psStats->subType == FEAT_SKYSCRAPER)
		{
			pos.x = psDel->pos.x;
			pos.z = psDel->pos.y;
			pos.y = psDel->pos.z;
			addEffect(&pos, EFFECT_DESTRUCTION, DESTRUCTION_TYPE_SKYSCRAPER, true, psDel->sDisplay.imd, 0, impactTime);
			initPerimeterSmoke(psDel->sDisplay.imd, pos);

			shakeStart(250);	// small shake
		}

		/* Then a sequence of effects */
		pos.x = psDel->pos.x;
		pos.z = psDel->pos.y;
		pos.y = map_Height(pos.x,pos.z);
		addEffect(&pos, EFFECT_DESTRUCTION, DESTRUCTION_TYPE_FEATURE, false, NULL, 0, impactTime);

		//play sound
		// ffs gj
		if(psDel->psStats->subType == FEAT_SKYSCRAPER)
		{
			audio_PlayStaticTrack( psDel->pos.x, psDel->pos.y, ID_SOUND_BUILDING_FALL );
		}
		else
		{
			audio_PlayStaticTrack( psDel->pos.x, psDel->pos.y, ID_SOUND_EXPLOSION );
		}
	}

	if (psDel->psStats->subType == FEAT_SKYSCRAPER)
	{
		// ----- Flip all the tiles under the skyscraper to a rubble tile
		// smoke effect should disguise this happening
		StructureBounds b = getStructureBounds(psDel);
		for (int breadth = 0; breadth < b.size.y; ++breadth)
		{
			for (int width = 0; width < b.size.x; ++width)
			{
				MAPTILE *psTile = mapTile(b.map.x + width, b.map.y + breadth);
				// stops water texture changing for underwater features
				if (terrainType(psTile) != TER_WATER)
				{
					if (terrainType(psTile) != TER_CLIFFFACE)
					{
						/* Clear feature bits */
						psTile->texture = TileNumber_texture(psTile->texture) | RUBBLE_TILE;
						auxClearBlocking(b.map.x + width, b.map.y + breadth, AUXBITS_ALL);
					}
					else
					{
						/* This remains a blocking tile */
						psTile->psObject = NULL;
						auxClearBlocking(b.map.x + width, b.map.y + breadth, AIR_BLOCKED);  // Shouldn't remain blocking for air units, however.
						psTile->texture = TileNumber_texture(psTile->texture) | BLOCKING_RUBBLE_TILE;
					}
				}
			}
		}
	}

	removeFeature(psDel);
	psDel->died = impactTime;
	return true;
}
Example #16
0
// this is able to handle multiple weapon graphics now
// removed mountRotation,they get such stuff from psObj directly now
static bool displayCompObj(DROID *psDroid, bool bButton, const glm::mat4 &viewMatrix)
{
	iIMDShape *psMoveAnim, *psStillAnim;
	SDWORD				iConnector;
	PROPULSION_STATS	*psPropStats;
	SDWORD				pieFlag, iPieData;
	PIELIGHT			brightness;
	UDWORD				colour;
	UBYTE	i;
	bool				didDrawSomething = false;

	glm::mat4 modelMatrix(1.f);

	if (graphicsTime - psDroid->timeLastHit < GAME_TICKS_PER_SEC / 4 && psDroid->lastHitWeapon == WSC_ELECTRONIC && !gamePaused())
	{
		colour = getPlayerColour(rand() % MAX_PLAYERS);
	}
	else
	{
		colour = getPlayerColour(psDroid->player);
	}

	/* get propulsion stats */
	psPropStats = asPropulsionStats + psDroid->asBits[COMP_PROPULSION];
	ASSERT_OR_RETURN(didDrawSomething, psPropStats != nullptr, "invalid propulsion stats pointer");

	//set pieflag for button object or ingame object
	if (bButton)
	{
		pieFlag = pie_BUTTON;
		brightness = WZCOL_WHITE;
	}
	else
	{
		pieFlag = pie_SHADOW;
		brightness = pal_SetBrightness(psDroid->illumination);
		// NOTE: Beware of transporters that are offscreen, on a mission!  We should *not* be checking tiles at this point in time!
		if (!isTransporter(psDroid) && !missionIsOffworld())
		{
			MAPTILE *psTile = worldTile(psDroid->pos.x, psDroid->pos.y);
			if (psTile->jammerBits & alliancebits[psDroid->player])
			{
				pieFlag |= pie_ECM;
			}
		}
	}

	/* set default components transparent */
	if (psDroid->asBits[COMP_PROPULSION] == 0)
	{
		pieFlag  |= pie_TRANSLUCENT;
		iPieData  = DEFAULT_COMPONENT_TRANSLUCENCY;
	}
	else
	{
		iPieData = 0;
	}

	if (!bButton && psPropStats->propulsionType == PROPULSION_TYPE_PROPELLOR)
	{
		// FIXME: change when adding submarines to the game
		modelMatrix *= glm::translate(glm::vec3(0.f, -world_coord(1) / 2.3f, 0.f));
	}

	iIMDShape *psShapeProp = (leftFirst ? getLeftPropulsionIMD(psDroid) : getRightPropulsionIMD(psDroid));
	if (psShapeProp)
	{
		if (pie_Draw3DShape(psShapeProp, 0, colour, brightness, pieFlag, iPieData, viewMatrix * modelMatrix))
		{
			didDrawSomething = true;
		}
	}

	/* set default components transparent */
	if (psDroid->asBits[COMP_BODY] == 0)
	{
		pieFlag  |= pie_TRANSLUCENT;
		iPieData  = DEFAULT_COMPONENT_TRANSLUCENCY;
	}
	else
	{
		pieFlag  &= ~pie_TRANSLUCENT;
		iPieData = 0;
	}

	/* Get the body graphic now*/
	iIMDShape *psShapeBody = BODY_IMD(psDroid, psDroid->player);
	if (psShapeBody)
	{
		iIMDShape *strImd = psShapeBody;
		if (psDroid->droidType == DROID_PERSON)
		{
			modelMatrix *= glm::scale(glm::vec3(.75f)); // FIXME - hideous....!!!!
		}
		if (strImd->objanimpie[psDroid->animationEvent])
		{
			strImd = psShapeBody->objanimpie[psDroid->animationEvent];
		}
		glm::mat4 viewModelMatrix = viewMatrix * modelMatrix;
		while (strImd)
		{
			if (drawShape(psDroid, strImd, colour, brightness, pieFlag, iPieData, viewModelMatrix))
			{
				didDrawSomething = true;
			}
			strImd = strImd->next;
		}
	}

	/* Render animation effects based on movement or lack thereof, if any */
	psMoveAnim = asBodyStats[psDroid->asBits[COMP_BODY]].ppMoveIMDList[psDroid->asBits[COMP_PROPULSION]];
	psStillAnim = asBodyStats[psDroid->asBits[COMP_BODY]].ppStillIMDList[psDroid->asBits[COMP_PROPULSION]];
	glm::mat4 viewModelMatrix = viewMatrix * modelMatrix;
	if (!bButton && psMoveAnim && psDroid->sMove.Status != MOVEINACTIVE)
	{
		if (pie_Draw3DShape(psMoveAnim, getModularScaledGraphicsTime(psMoveAnim->animInterval, psMoveAnim->numFrames), colour, brightness, pie_ADDITIVE, 200, viewModelMatrix))
		{
			didDrawSomething = true;
		}
	}
	else if (!bButton && psStillAnim) // standing still
	{
		if (pie_Draw3DShape(psStillAnim, getModularScaledGraphicsTime(psStillAnim->animInterval, psStillAnim->numFrames), colour, brightness, 0, 0, viewModelMatrix))
		{
			didDrawSomething = true;
		}
	}

	//don't change the screen coords of an object if drawing it in a button
	if (!bButton)
	{
		/* set up all the screen coords stuff - need to REMOVE FROM THIS LOOP */
		calcScreenCoords(psDroid, viewModelMatrix);
	}

	/* set default components transparent */
	if (psDroid->asWeaps[0].nStat        == 0 &&
	    psDroid->asBits[COMP_SENSOR]     == 0 &&
	    psDroid->asBits[COMP_ECM]        == 0 &&
	    psDroid->asBits[COMP_BRAIN]      == 0 &&
	    psDroid->asBits[COMP_REPAIRUNIT] == 0 &&
	    psDroid->asBits[COMP_CONSTRUCT]  == 0)
	{
		pieFlag  |= pie_TRANSLUCENT;
		iPieData  = DEFAULT_COMPONENT_TRANSLUCENCY;
	}
	else
	{
		pieFlag  &= ~pie_TRANSLUCENT;
		iPieData = 0;
	}

	if (psShapeBody && psShapeBody->nconnectors)
	{
		/* vtol weapons attach to connector 2 (underneath);
		 * all others to connector 1 */
		/* VTOL's now skip the first 5 connectors(0 to 4),
		VTOL's use 5,6,7,8 etc now */
		if (psPropStats->propulsionType == PROPULSION_TYPE_LIFT && psDroid->droidType == DROID_WEAPON)
		{
			iConnector = VTOL_CONNECTOR_START;
		}
		else
		{
			iConnector = 0;
		}

		switch (psDroid->droidType)
		{
		case DROID_DEFAULT:
		case DROID_TRANSPORTER:
		case DROID_SUPERTRANSPORTER:
		case DROID_CYBORG:
		case DROID_CYBORG_SUPER:
		case DROID_WEAPON:
		case DROID_COMMAND:		// command droids have a weapon to store all the graphics
			/*	Get the mounting graphic - we've already moved to the right position
			Allegedly - all droids will have a mount graphic so this shouldn't
			fall on it's arse......*/
			/* Double check that the weapon droid actually has any */
			for (i = 0; i < psDroid->numWeaps; i++)
			{
				if ((psDroid->asWeaps[i].nStat > 0 || psDroid->droidType == DROID_DEFAULT)
				    && psShapeBody->connectors)
				{
					Rotation rot = getInterpolatedWeaponRotation(psDroid, i, graphicsTime);

					glm::mat4 localModelMatrix = modelMatrix;

					//to skip number of VTOL_CONNECTOR_START ground unit connectors
					if (iConnector < VTOL_CONNECTOR_START)
					{
						localModelMatrix *= glm::translate(glm::vec3(psShapeBody->connectors[i].xzy()));
					}
					else
					{
						localModelMatrix *= glm::translate(glm::vec3(psShapeBody->connectors[iConnector + i].xzy()));
					}
					localModelMatrix *= glm::rotate(UNDEG(-rot.direction), glm::vec3(0.f, 1.f, 0.f));

					/* vtol weapons inverted */
					if (iConnector >= VTOL_CONNECTOR_START)
					{
						//this might affect gun rotation
						localModelMatrix *= glm::rotate(UNDEG(65536 / 2), glm::vec3(0.f, 0.f, 1.f));
					}

					/* Get the mount graphic */
					iIMDShape *psShape = WEAPON_MOUNT_IMD(psDroid, i);

					int recoilValue = getRecoil(psDroid->asWeaps[i]);
					localModelMatrix *= glm::translate(glm::vec3(0.f, 0.f, recoilValue / 3.f));

					/* Draw it */
					if (psShape)
					{
						if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, viewMatrix * localModelMatrix))
						{
							didDrawSomething = true;
						}
					}
					localModelMatrix *= glm::translate(glm::vec3(0, 0, recoilValue));

					/* translate for weapon mount point */
					if (psShape && psShape->nconnectors)
					{
						localModelMatrix *= glm::translate(glm::vec3(psShape->connectors->xzy()));
					}

					/* vtol weapons inverted */
					if (iConnector >= VTOL_CONNECTOR_START)
					{
						//pitch the barrel down
						localModelMatrix *= glm::rotate(UNDEG(-rot.pitch), glm::vec3(1.f, 0.f, 0.f));
					}
					else
					{
						//pitch the barrel up
						localModelMatrix *= glm::rotate(UNDEG(rot.pitch), glm::vec3(1.f, 0.f, 0.f));
					}

					/* Get the weapon (gun?) graphic */
					psShape = WEAPON_IMD(psDroid, i);

					// We have a weapon so we draw it and a muzzle flash from weapon connector
					if (psShape)
					{
						glm::mat4 localViewModelMatrix = viewMatrix * localModelMatrix;
						if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, localViewModelMatrix))
						{
							didDrawSomething = true;
						}
						drawMuzzleFlash(psDroid->asWeaps[i], psShape, MUZZLE_FLASH_PIE(psDroid, i), brightness, pieFlag, iPieData, localViewModelMatrix);
					}
				}
			}
			break;

		case DROID_SENSOR:
		case DROID_CONSTRUCT:
		case DROID_CYBORG_CONSTRUCT:
		case DROID_ECM:
		case DROID_REPAIR:
		case DROID_CYBORG_REPAIR:
			{
				Rotation rot = getInterpolatedWeaponRotation(psDroid, 0, graphicsTime);
				iIMDShape *psShape = nullptr;
				iIMDShape *psMountShape = nullptr;

				switch (psDroid->droidType)
				{
				default:
					ASSERT(false, "Bad component type");
					break;
				case DROID_SENSOR:
					psMountShape = SENSOR_MOUNT_IMD(psDroid, psDroid->player);
					/* Get the sensor graphic, assuming it's there */
					psShape = SENSOR_IMD(psDroid, psDroid->player);
					break;
				case DROID_CONSTRUCT:
				case DROID_CYBORG_CONSTRUCT:
					psMountShape = CONSTRUCT_MOUNT_IMD(psDroid, psDroid->player);
					/* Get the construct graphic assuming it's there */
					psShape = CONSTRUCT_IMD(psDroid, psDroid->player);
					break;
				case DROID_ECM:
					psMountShape = ECM_MOUNT_IMD(psDroid, psDroid->player);
					/* Get the ECM graphic assuming it's there.... */
					psShape = ECM_IMD(psDroid, psDroid->player);
					break;
				case DROID_REPAIR:
				case DROID_CYBORG_REPAIR:
					psMountShape = REPAIR_MOUNT_IMD(psDroid, psDroid->player);
					/* Get the Repair graphic assuming it's there.... */
					psShape = REPAIR_IMD(psDroid, psDroid->player);
					break;
				}
				/*	Get the mounting graphic - we've already moved to the right position
				Allegedly - all droids will have a mount graphic so this shouldn't
				fall on it's arse......*/
				//sensor and cyborg and ecm uses connectors[0]

				glm::mat4 localModelMatrix = modelMatrix;
				/* vtol weapons inverted */
				if (iConnector >= VTOL_CONNECTOR_START)
				{
					//this might affect gun rotation
					localModelMatrix *= glm::rotate(UNDEG(65536 / 2), glm::vec3(0.f, 0.f, 1.f));
				}

				localModelMatrix *= glm::translate(glm::vec3(psShapeBody->connectors[0].xzy()));

				localModelMatrix *= glm::rotate(UNDEG(-rot.direction), glm::vec3(0.f, 1.f, 0.f));
				/* Draw it */
				if (psMountShape)
				{
					if (pie_Draw3DShape(psMountShape, 0, colour, brightness, pieFlag, iPieData, viewMatrix * localModelMatrix))
					{
						didDrawSomething = true;
					}
				}

				/* translate for construct mount point if cyborg */
				if (cyborgDroid(psDroid) && psMountShape && psMountShape->nconnectors)
				{
					localModelMatrix *= glm::translate(glm::vec3(psMountShape->connectors[0].xzy()));
				}

				/* Draw it */
				if (psShape)
				{
					if (pie_Draw3DShape(psShape, 0, colour, brightness, pieFlag, iPieData, viewMatrix * localModelMatrix))
					{
						didDrawSomething = true;
					}

					// In repair droid case only:
					if ((psDroid->droidType == DROID_REPAIR || psDroid->droidType == DROID_CYBORG_REPAIR) &&
					    psShape->nconnectors && psDroid->action == DACTION_DROIDREPAIR)
					{
						Spacetime st = interpolateObjectSpacetime(psDroid, graphicsTime);
						localModelMatrix *= glm::translate(glm::vec3(psShape->connectors[0].xzy()));
						localModelMatrix *= glm::translate(glm::vec3(0.f, -20.f, 0.f));

						psShape = getImdFromIndex(MI_FLAME);

						/* Rotate for droid */
						localModelMatrix *= glm::rotate(UNDEG(st.rot.direction), glm::vec3(0.f, 1.f, 0.f));
						localModelMatrix *= glm::rotate(UNDEG(-st.rot.pitch), glm::vec3(1.f, 0.f, 0.f));
						localModelMatrix *= glm::rotate(UNDEG(-st.rot.roll), glm::vec3(0.f, 0.f, 1.f));
						//rotate Y
						localModelMatrix *= glm::rotate(UNDEG(rot.direction), glm::vec3(0.f, 1.f, 0.f));

						localModelMatrix *= glm::rotate(UNDEG(-player.r.y), glm::vec3(0.f, 1.f, 0.f));
						localModelMatrix *= glm::rotate(UNDEG(-player.r.x), glm::vec3(1.f, 0.f, 0.f));

						if (pie_Draw3DShape(psShape, getModularScaledGraphicsTime(psShape->animInterval, psShape->numFrames), 0, brightness, pie_ADDITIVE, 140, viewMatrix * localModelMatrix))
						{
							didDrawSomething = true;
						}

//						localModelMatrix *= glm::rotate(UNDEG(player.r.x), glm::vec3(1.f, 0.f, 0.f)); // Not used?
//						localModelMatrix *= glm::rotate(UNDEG(player.r.y), glm::vec3(0.f, 1.f, 0.f)); // Not used?
					}
				}
				break;
			}
		case DROID_PERSON:
			// no extra mounts for people
			break;
		default:
			ASSERT(!"invalid droid type", "Whoa! Weirdy type of droid found in drawComponentObject!!!");
			break;
		}
	}

	/* set default components transparent */
	if (psDroid->asBits[COMP_PROPULSION] == 0)
	{
		pieFlag  |= pie_TRANSLUCENT;
		iPieData  = DEFAULT_COMPONENT_TRANSLUCENCY;
	}
	else
	{
		pieFlag  &= ~pie_TRANSLUCENT;
		iPieData = 0;
	}

	// now render the other propulsion side
	psShapeProp = (leftFirst ? getRightPropulsionIMD(psDroid) : getLeftPropulsionIMD(psDroid));
	if (psShapeProp)
	{
		if (pie_Draw3DShape(psShapeProp, 0, colour, brightness, pieFlag, iPieData, viewModelMatrix)) // Safe to use viewModelMatrix because modelView has not been changed since it was calculated
		{
			didDrawSomething = true;
		}
	}

	return didDrawSomething;
}
Example #17
0
// Colour Lookups
// use col = MAX_PLAYERS for anycolour (see multiint.c)
bool setPlayerColour(UDWORD player, UDWORD col)
{
	ASSERT_OR_RETURN(false, player < MAX_PLAYERS && col < MAX_PLAYERS, "Bad colour setting");
	NetPlay.players[player].colour = col;
	return true;
}
Example #18
0
// ////////////////////////////////////////////////////////////////////////////
// receive droid creation information from other players
bool recvDroid(NETQUEUE queue)
{
	DROID_TEMPLATE* pT;
	DROID* psDroid;
	uint8_t player;
	uint32_t id;
	Position pos;
	uint32_t templateID;
	bool haveInitialOrders;
	INITIAL_DROID_ORDERS initialOrders;

	NETbeginDecode(queue, GAME_DEBUG_ADD_DROID);
	{
		NETuint8_t(&player);
		NETuint32_t(&id);
		NETPosition(&pos);
		NETuint32_t(&templateID);
		NETbool(&haveInitialOrders);
		if (haveInitialOrders)
		{
			NETuint32_t(&initialOrders.secondaryOrder);
			NETint32_t(&initialOrders.moveToX);
			NETint32_t(&initialOrders.moveToY);
			NETuint32_t(&initialOrders.factoryId);  // For making scripts happy.
		}

		pT = IdToTemplate(templateID, player);
	}
	NETend();

	if (!getDebugMappingStatus())
	{
		debug(LOG_WARNING, "Failed to add droid for player %u.", NetPlay.players[queue.index].position);
		return false;
	}

	ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "invalid player %u", player);

	debug(LOG_LIFE, "<=== getting Droid from %u id of %u ",player,id);
	if ((pos.x == 0 && pos.y == 0) || pos.x > world_coord(mapWidth) || pos.y > world_coord(mapHeight))
	{
		debug(LOG_ERROR, "Received bad droid position (%d, %d) from %d about p%d (%s)", (int)pos.x, (int)pos.y,
				queue.index, player, isHumanPlayer(player) ? "Human" : "AI");
		return false;
	}

	// If we can not find the template ask for the entire droid instead
	if (!pT)
	{
		debug(LOG_ERROR, "Packet from %d refers to non-existent template %u, [%s : p%d]",
				queue.index, templateID, isHumanPlayer(player) ? "Human" : "AI", player);
		return false;
	}

	// Create that droid on this machine.
	psDroid = reallyBuildDroid(pT, pos, player, false);

	// If we were able to build the droid set it up
	if (psDroid)
	{
		psDroid->id = id;
		addDroid(psDroid, apsDroidLists);

		if (haveInitialOrders)
		{
			psDroid->secondaryOrder = initialOrders.secondaryOrder;
			psDroid->secondaryOrderPending = psDroid->secondaryOrder;
			orderDroidLoc(psDroid, DORDER_MOVE, initialOrders.moveToX, initialOrders.moveToY, ModeImmediate);
			cbNewDroid(IdToStruct(initialOrders.factoryId, ANYPLAYER), psDroid);
		}

		syncDebugDroid(psDroid, '+');
	}
	else
	{
		debug(LOG_ERROR, "Packet from %d cannot create droid for p%d (%s)!", queue.index,
			player, isHumanPlayer(player) ? "Human" : "AI");
#ifdef DEBUG
		CONPRINTF(ConsoleString, (ConsoleString, "MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync"));
#endif
		return false;
	}

	return true;
}
Example #19
0
/*!
 * Load shape levels recursively
 * \param ppFileData Pointer to the data (usualy read from a file)
 * \param FileDataEnd ???
 * \param nlevels Number of levels to load
 * \return pointer to iFSDShape structure (or NULL on error)
 * \pre ppFileData loaded
 * \post s allocated
 */
static iIMDShape *_imd_load_level(const char **ppFileData, const char *FileDataEnd, int nlevels, int pieVersion)
{
	const char *pTmp, *pFileData = *ppFileData;
	char buffer[PATH_MAX] = {'\0'};
	int cnt = 0, n = 0, i;
	iIMDShape *s = NULL;

	if (nlevels == 0)
	{
		return NULL;
	}

	// Load optional MATERIALS directive
	pTmp = pFileData;	// remember position
	i = sscanf(pFileData, "%255s %n", buffer, &cnt);
	ASSERT_OR_RETURN(NULL, i == 1, "Bad directive following LEVEL");

	s = new iIMDShape;

	if (strcmp(buffer, "MATERIALS") == 0)
	{
		i = sscanf(pFileData, "%255s %f %f %f %f %f %f %f %f %f %f%n", buffer,
		           &s->material[LIGHT_AMBIENT][0], &s->material[LIGHT_AMBIENT][1], &s->material[LIGHT_AMBIENT][2],
		           &s->material[LIGHT_DIFFUSE][0], &s->material[LIGHT_DIFFUSE][1], &s->material[LIGHT_DIFFUSE][2],
	                   &s->material[LIGHT_SPECULAR][0], &s->material[LIGHT_SPECULAR][1], &s->material[LIGHT_SPECULAR][2],
		           &s->shininess, &cnt);
		ASSERT_OR_RETURN(NULL, i == 11, "Bad MATERIALS directive");
		pFileData += cnt;
	}
	else // use defaults
	{
		pFileData = pTmp;
	}

	if (sscanf(pFileData, "%255s %d%n", buffer, &s->npoints, &cnt) != 2)
	{
		debug(LOG_ERROR, "_imd_load_level(2): file corrupt");
		return NULL;
	}
	pFileData += cnt;

	// load points

	ASSERT_OR_RETURN(NULL, strcmp(buffer, "POINTS") == 0, "Expecting 'POINTS' directive, got: %s", buffer);

	_imd_load_points( &pFileData, s );

	if (sscanf(pFileData, "%255s %d%n", buffer, &s->npolys, &cnt) != 2)
	{
		debug(LOG_ERROR, "_imd_load_level(3): file corrupt");
		return NULL;
	}
	pFileData += cnt;

	ASSERT_OR_RETURN(NULL, strcmp(buffer, "POLYGONS") == 0, "Expecting 'POLYGONS' directive, got: %s", buffer);

	_imd_load_polys( &pFileData, s, pieVersion);

	// NOW load optional stuff
	while (!AtEndOfFile(pFileData, FileDataEnd)) // check for end of file (give or take white space)
	{
		// Scans in the line ... if we don't get 2 parameters then quit
		if (sscanf(pFileData, "%255s %d%n", buffer, &n, &cnt) != 2)
		{
			break;
		}
		pFileData += cnt;

		// check for next level ... or might be a BSP - This should handle an imd if it has a BSP tree attached to it
		// might be "BSP" or "LEVEL"
		if (strcmp(buffer, "LEVEL") == 0)
		{
			debug(LOG_3D, "imd[_load_level] = npoints %d, npolys %d", s->npoints, s->npolys);
			s->next = _imd_load_level(&pFileData, FileDataEnd, nlevels - 1, pieVersion);
		}
		else if (strcmp(buffer, "CONNECTORS") == 0)
		{
			//load connector stuff
			s->nconnectors = n;
			_imd_load_connectors( &pFileData, s );
		}
		else
		{
			debug(LOG_ERROR, "(_load_level) unexpected directive %s %d", buffer, n);
			break;
		}
	}

	// FINALLY, massage the data into what can stream directly to OpenGL
	glGenBuffers(VBO_COUNT, s->buffers);
	vertexCount = 0;
	for (int k = 0; k < MAX(1, s->numFrames); k++)
	{
		// Go through all polygons for each frame
		for (int i = 0; i < s->npolys; i++)
		{
			const iIMDPoly *pPolys = &s->polys[i];

			// Do we already have the vertex data for this polygon?
			indices.append(addVertex(s, 0, pPolys, k));
			indices.append(addVertex(s, 1, pPolys, k));
			indices.append(addVertex(s, 2, pPolys, k));
		}
	}
	glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_VERTEX]);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.constData(), GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_NORMAL]);
	glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(GLfloat), normals.constData(), GL_STATIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->buffers[VBO_INDEX]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.constData(), GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_TEXCOORD]);
	glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(GLfloat), texcoords.constData(), GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind

	indices.resize(0);
	vertices.resize(0);
	texcoords.resize(0);
	normals.resize(0);

	*ppFileData = pFileData;

	return s;
}
Example #20
0
/** Search the global list of sensors for a possible target for psObj. */
static BASE_OBJECT *aiSearchSensorTargets(BASE_OBJECT *psObj, int weapon_slot, WEAPON_STATS *psWStats, UWORD *targetOrigin)
{
	int		longRange = proj_GetLongRange(psWStats);
	int		tarDist = longRange * longRange;
	BOOL		foundCB = false;
	int		minDist = psWStats->minRange * psWStats->minRange;
	BASE_OBJECT	*psSensor, *psTarget = NULL;

	if (targetOrigin)
	{
		*targetOrigin = ORIGIN_UNKNOWN;
	}

	for (psSensor = apsSensorList[0]; psSensor; psSensor = psSensor->psNextFunc)
	{
		BASE_OBJECT	*psTemp = NULL;
		bool		isCB = false;
		bool		isRD = false;

		if (!aiCheckAlliances(psSensor->player, psObj->player))
		{
			continue;
		}
		else if (psSensor->type == OBJ_DROID)
		{
			DROID		*psDroid = (DROID *)psSensor;

			ASSERT_OR_RETURN(false, psDroid->droidType == DROID_SENSOR, "A non-sensor droid in a sensor list is non-sense");
			psTemp = psDroid->psTarget;
			isCB = cbSensorDroid(psDroid);
			isRD = objRadarDetector((BASE_OBJECT *)psDroid);
		}
		else if (psSensor->type == OBJ_STRUCTURE)
		{
			STRUCTURE	*psCStruct = (STRUCTURE *)psSensor;

			// skip incomplete structures
			if (psCStruct->status != SS_BUILT)
			{
				continue;
			}
			psTemp = psCStruct->psTarget[0];
			isCB = structCBSensor(psCStruct);
			isRD = objRadarDetector((BASE_OBJECT *)psCStruct);
		}
		if (!psTemp || aiObjectIsProbablyDoomed(psTemp) || !validTarget(psObj, psTemp, 0) || aiCheckAlliances(psTemp->player, psObj->player))
		{
			continue;
		}
		if (aiObjHasRange(psObj, psTemp, weapon_slot) && visibleObject(psSensor, psTemp, false))
		{
			int distSq = objPosDiffSq(psTemp->pos, psObj->pos);

			// Need to be in range, prefer closer targets or CB targets
			if ((isCB > foundCB || (isCB == foundCB && distSq < tarDist)) && distSq > minDist)
			{
				tarDist = distSq;
				psTarget = psTemp;
				if (targetOrigin)
				{
					*targetOrigin = ORIGIN_SENSOR;
				}
				
				if (isCB)
				{
					if (targetOrigin)
					{
						*targetOrigin = ORIGIN_CB_SENSOR;
					}
					foundCB = true;  // got CB target, drop everything and shoot!
				}
				else if (isRD)
				{
					if (targetOrigin)
					{
						*targetOrigin = ORIGIN_RADAR_DETECTOR;
					}
				}
			}
		}
	}
	return psTarget;
}
Example #21
0
// Read/compile/link shaders
SHADER_MODE pie_LoadShader(const char *programName, const char *vertexPath, const char *fragmentPath,
	const std::vector<std::string> &uniformNames)
{
	pie_internal::SHADER_PROGRAM program;
	GLint status;
	bool success = true; // Assume overall success
	char *buffer[2];

	program.program = glCreateProgram();
	glBindAttribLocation(program.program, 0, "vertex");
	glBindAttribLocation(program.program, 1, "vertexTexCoord");
	glBindAttribLocation(program.program, 2, "vertexColor");
	ASSERT_OR_RETURN(SHADER_NONE, program.program, "Could not create shader program!");

	*buffer = (char *)"";

	if (vertexPath)
	{
		success = false; // Assume failure before reading shader file

		if ((*(buffer + 1) = readShaderBuf(vertexPath)))
		{
			GLuint shader = glCreateShader(GL_VERTEX_SHADER);

			glShaderSource(shader, 2, (const char **)buffer, nullptr);
			glCompileShader(shader);

			// Check for compilation errors
			glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
			if (!status)
			{
				debug(LOG_ERROR, "Vertex shader compilation has failed [%s]", vertexPath);
				printShaderInfoLog(LOG_ERROR, shader);
			}
			else
			{
				printShaderInfoLog(LOG_3D, shader);
				glAttachShader(program.program, shader);
				success = true;
			}
			if (GLEW_VERSION_4_3 || GLEW_KHR_debug)
			{
				glObjectLabel(GL_SHADER, shader, -1, vertexPath);
			}
			free(*(buffer + 1));
		}
	}

	if (success && fragmentPath)
	{
		success = false; // Assume failure before reading shader file

		if ((*(buffer + 1) = readShaderBuf(fragmentPath)))
		{
			GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);

			glShaderSource(shader, 2, (const char **)buffer, nullptr);
			glCompileShader(shader);

			// Check for compilation errors
			glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
			if (!status)
			{
				debug(LOG_ERROR, "Fragment shader compilation has failed [%s]", fragmentPath);
				printShaderInfoLog(LOG_ERROR, shader);
			}
			else
			{
				printShaderInfoLog(LOG_3D, shader);
				glAttachShader(program.program, shader);
				success = true;
			}
			if (GLEW_VERSION_4_3 || GLEW_KHR_debug)
			{
				glObjectLabel(GL_SHADER, shader, -1, fragmentPath);
			}
			free(*(buffer + 1));
		}
	}

	if (success)
	{
		glLinkProgram(program.program);

		// Check for linkage errors
		glGetProgramiv(program.program, GL_LINK_STATUS, &status);
		if (!status)
		{
			debug(LOG_ERROR, "Shader program linkage has failed [%s, %s]", vertexPath, fragmentPath);
			printProgramInfoLog(LOG_ERROR, program.program);
			success = false;
		}
		else
		{
			printProgramInfoLog(LOG_3D, program.program);
		}
		if (GLEW_VERSION_4_3 || GLEW_KHR_debug)
		{
			glObjectLabel(GL_PROGRAM, program.program, -1, programName);
		}
	}
	GLuint p = program.program;
	std::transform(uniformNames.begin(), uniformNames.end(),
		std::back_inserter(program.locations),
		[p](const std::string name) { return glGetUniformLocation(p, name.data()); });

	getLocs(&program);
	glUseProgram(0);

	pie_internal::shaderProgram.push_back(program);

	return SHADER_MODE(pie_internal::shaderProgram.size() - 1);
}
Example #22
0
bool iV_loadImage_PNG(const char *fileName, iV_Image *image)
{
	unsigned char PNGheader[PNG_BYTES_TO_CHECK];
	PHYSFS_sint64 readSize;

	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;

	// Open file
	PHYSFS_file* fileHandle = PHYSFS_openRead(fileName);
	if (fileHandle == NULL)
	{
		debug(LOG_ERROR, "pie_PNGLoadFile: PHYSFS_openRead(%s) failed with error: %s\n", fileName, PHYSFS_getLastError());
		PNGReadCleanup(&info_ptr, &png_ptr, fileHandle);
		return false;
	}

	// Read PNG header from file
	readSize = PHYSFS_read(fileHandle, PNGheader, 1, PNG_BYTES_TO_CHECK);
	if (readSize < PNG_BYTES_TO_CHECK)
	{
		debug(LOG_ERROR, "pie_PNGLoadFile: PHYSFS_read(%s) failed with error: %s\n", fileName, PHYSFS_getLastError());
		PNGReadCleanup(&info_ptr, &png_ptr, fileHandle);
		return false;
	}

	// Verify the PNG header to be correct
	if (png_sig_cmp(PNGheader, 0, PNG_BYTES_TO_CHECK))
	{
		debug(LOG_3D, "pie_PNGLoadMem: Did not recognize PNG header in %s", fileName);
		PNGReadCleanup(&info_ptr, &png_ptr, fileHandle);
		return false;
	}

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) {
		debug(LOG_3D, "pie_PNGLoadMem: Unable to create png struct");
		PNGReadCleanup(&info_ptr, &png_ptr, fileHandle);
		return false;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		debug(LOG_3D, "pie_PNGLoadMem: Unable to create png info struct");
		PNGReadCleanup(&info_ptr, &png_ptr, fileHandle);
		return false;
	}

	// Set libpng's failure jump position to the if branch,
	// setjmp evaluates to false so the else branch will be executed at first
	if (setjmp(png_jmpbuf(png_ptr))) {
		debug(LOG_3D, "pie_PNGLoadMem: Error decoding PNG data in %s", fileName);
		PNGReadCleanup(&info_ptr, &png_ptr, fileHandle);
		return false;
	}

	// Tell libpng how many byte we already read
	png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

	/* Set up the input control */
	png_set_read_fn(png_ptr, fileHandle, wzpng_read_data);

	// Most of the following transformations are seemingly not needed
	// Filler is, however, for an unknown reason required for tertilesc[23]

	/* tell libpng to strip 16 bit/color files down to 8 bits/color */
 	png_set_strip_16(png_ptr);

	/* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
	 * byte into separate bytes (useful for paletted and grayscale images).
	 */
// 	png_set_packing(png_ptr);

	/* More transformations to ensure we end up with 32bpp, 4 channel RGBA */
// 	png_set_gray_to_rgb(png_ptr);
 	png_set_palette_to_rgb(png_ptr);
 	png_set_tRNS_to_alpha(png_ptr);
	png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
// 	png_set_gray_1_2_4_to_8(png_ptr);

	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

	image->width = png_get_image_width(png_ptr, info_ptr);
	image->height = png_get_image_height(png_ptr, info_ptr);
	image->depth = png_get_channels(png_ptr, info_ptr);
	image->bmp = (unsigned char *)malloc(image->height * png_get_rowbytes(png_ptr, info_ptr));

	{
		unsigned int i = 0;
		png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
		for ( i = 0; i < png_get_image_height(png_ptr, info_ptr); i++ )
			memcpy( image->bmp + (png_get_rowbytes(png_ptr, info_ptr) * i), row_pointers[i], png_get_rowbytes(png_ptr, info_ptr) );
	}

	PNGReadCleanup(&info_ptr, &png_ptr, fileHandle);

	ASSERT_OR_RETURN(false, image->depth > 3, "Unsupported image depth (%d) found.  We only support 3 (RGB) or 4 (ARGB)", image->depth);

	return true;
}
Example #23
0
/*!
 * Load shape level polygons
 * \param ppFileData Pointer to the data (usualy read from a file)
 * \param s Pointer to shape level
 * \return false on error (memory allocation failure/bad file format), true otherwise
 * \pre ppFileData loaded
 * \pre s allocated
 * \pre s->npolys set
 * \post s->polys allocated (iFSDPoly * s->npolys)
 * \post s->pindex allocated for each poly
 */
static bool _imd_load_polys(const char **ppFileData, iIMDShape *s, int pieVersion)
{
	const char *pFileData = *ppFileData;
	unsigned int i, j;
	iIMDPoly *poly;

	s->numFrames = 0;
	s->animInterval = 0;

	s->polys = (iIMDPoly *)malloc(sizeof(iIMDPoly) * s->npolys);
	if (s->polys == NULL)
	{
		debug(LOG_ERROR, "(_load_polys) Out of memory (polys)");
		return false;
	}

	for (i = 0, poly = s->polys; i < s->npolys; i++, poly++)
	{
		unsigned int flags, npnts;
		int cnt;

		if (sscanf(pFileData, "%x %u%n", &flags, &npnts, &cnt) != 2)
		{
			debug(LOG_ERROR, "(_load_polys) [poly %u] error loading flags and npoints", i);
		}
		pFileData += cnt;

		poly->flags = flags;
		ASSERT_OR_RETURN(false, npnts == 3, "Invalid polygon size (%d)", npnts);
		if (sscanf(pFileData, "%d %d %d%n", &poly->pindex[0], &poly->pindex[1], &poly->pindex[2], &cnt) != 3)
		{
			debug(LOG_ERROR, "failed reading triangle, point %d", i);
			return false;
		}
		pFileData += cnt;

		// calc poly normal
		{
			Vector3f p0, p1, p2;

			//assumes points already set
			p0.x = s->points[poly->pindex[0]].x;
			p0.y = s->points[poly->pindex[0]].y;
			p0.z = s->points[poly->pindex[0]].z;

			p1.x = s->points[poly->pindex[1]].x;
			p1.y = s->points[poly->pindex[1]].y;
			p1.z = s->points[poly->pindex[1]].z;

			p2.x = s->points[poly->pindex[2]].x;
			p2.y = s->points[poly->pindex[2]].y;
			p2.z = s->points[poly->pindex[2]].z;

			poly->normal = pie_SurfaceNormal3fv(p0, p1, p2);
		}

		// texture coord routine
		if (poly->flags & iV_IMD_TEX)
		{
			int nFrames, framesPerLine, frame, pbRate;
			float tWidth, tHeight;

			if (poly->flags & iV_IMD_TEXANIM)
			{
				if (sscanf(pFileData, "%d %d %f %f%n", &nFrames, &pbRate, &tWidth, &tHeight, &cnt) != 4)
				{
					debug(LOG_ERROR, "(_load_polys) [poly %u] error reading texanim data", i);
					return false;
				}
				pFileData += cnt;

				ASSERT(tWidth > 0.0001f, "%s: texture width = %f", GetLastResourceFilename(), tWidth);
				ASSERT(tHeight > 0.f, "%s: texture height = %f (width=%f)", GetLastResourceFilename(), tHeight, tWidth);
				ASSERT(nFrames > 1, "%s: animation frames = %d", GetLastResourceFilename(), nFrames);
				ASSERT(pbRate > 0, "%s: animation interval = %d ms", GetLastResourceFilename(), pbRate);

				/* Must have same number of frames and same playback rate for all polygons */
				if (s->numFrames == 0)
				{
					s->numFrames = nFrames;
					s->animInterval = pbRate;
				}
				else
				{
					ASSERT(s->numFrames == nFrames,
					       "%s: varying number of frames within one PIE level: %d != %d",
					       GetLastResourceFilename(), nFrames, s->numFrames);
					ASSERT(s->animInterval == pbRate,
					       "%s: varying animation intervals within one PIE level: %d != %d",
					       GetLastResourceFilename(), pbRate, s->animInterval);
				}

				poly->texAnim.x = tWidth;
				poly->texAnim.y = tHeight;

				if (pieVersion != PIE_FLOAT_VER)
				{
					poly->texAnim.x /= OLD_TEXTURE_SIZE_FIX;
					poly->texAnim.y /= OLD_TEXTURE_SIZE_FIX;
				}
				framesPerLine = 1 / poly->texAnim.x;
			}
			else
			{
				nFrames = 1;
				framesPerLine = 1;
				pbRate = 1;
				tWidth = 0.f;
				tHeight = 0.f;
				poly->texAnim.x = 0;
				poly->texAnim.y = 0;
			}

			poly->texCoord = (Vector2f *)malloc(sizeof(*poly->texCoord) * nFrames * 3);
			ASSERT_OR_RETURN(false, poly->texCoord, "Out of memory allocating texture coordinates");
			for (j = 0; j < 3; j++)
			{
				float VertexU, VertexV;

				if (sscanf(pFileData, "%f %f%n", &VertexU, &VertexV, &cnt) != 2)
				{
					debug(LOG_ERROR, "(_load_polys) [poly %u] error reading tex outline", i);
					return false;
				}
				pFileData += cnt;

				if (pieVersion != PIE_FLOAT_VER)
				{
					VertexU /= OLD_TEXTURE_SIZE_FIX;
					VertexV /= OLD_TEXTURE_SIZE_FIX;
				}

				for (frame = 0; frame < nFrames; frame++)
				{
					const float uFrame = (frame % framesPerLine) * poly->texAnim.x;
					const float vFrame = (frame / framesPerLine) * poly->texAnim.y;
					Vector2f *c = &poly->texCoord[frame * 3 + j];

					c->x = VertexU + uFrame;
					c->y = VertexV + vFrame;
				}
			}
		}
		else
		{
			ASSERT_OR_RETURN(false, !(poly->flags & iV_IMD_TEXANIM), "Polygons with texture animation must have textures!");
			poly->texCoord = NULL;
		}
	}

	*ppFileData = pFileData;

	return true;
}
Example #24
0
bool setPlayerName(int player, const char *sName)
{
	ASSERT_OR_RETURN(false, player < MAX_PLAYERS && player >= 0, "Player index (%u) out of range", player);
	sstrcpy(playerName[player], sName);
	return true;
}
Example #25
0
// ppFileData is incremented to the end of the file on exit!
static iIMDShape *iV_ProcessIMD(const char **ppFileData, const char *FileDataEnd)
{
	const char *pFileName = GetLastResourceFilename(); // Last loaded filename
	const char *pFileData = *ppFileData;
	char buffer[PATH_MAX], texfile[PATH_MAX], normalfile[PATH_MAX], specfile[PATH_MAX];
	int cnt, nlevels;
	iIMDShape *shape;
	UDWORD level;
	int32_t imd_version;
	uint32_t imd_flags;
	bool bTextured = false;
	GLuint shader = 0;

	memset(normalfile, 0, sizeof(normalfile));
	memset(specfile, 0, sizeof(specfile));

	if (sscanf(pFileData, "%255s %d%n", buffer, &imd_version, &cnt) != 2)
	{
		debug(LOG_ERROR, "iV_ProcessIMD %s bad version: (%s)", pFileName, buffer);
		assert(false);
		return NULL;
	}
	pFileData += cnt;

	if (strcmp(PIE_NAME, buffer) != 0)
	{
		debug(LOG_ERROR, "iV_ProcessIMD %s not an IMD file (%s %d)", pFileName, buffer, imd_version);
		return NULL;
	}

	//Now supporting version PIE_VER and PIE_FLOAT_VER files
	if (imd_version != PIE_VER && imd_version != PIE_FLOAT_VER)
	{
		debug(LOG_ERROR, "iV_ProcessIMD %s version %d not supported", pFileName, imd_version);
		return NULL;
	}

	// Read flag
	if (sscanf(pFileData, "%255s %x%n", buffer, &imd_flags, &cnt) != 2)
	{
		debug(LOG_ERROR, "iV_ProcessIMD %s bad flags: %s", pFileName, buffer);
		return NULL;
	}
	pFileData += cnt;

	/* This can be either texture or levels */
	if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
	{
		debug(LOG_ERROR, "iV_ProcessIMD %s expecting TEXTURE or LEVELS: %s", pFileName, buffer);
		return NULL;
	}
	pFileData += cnt;

	// get texture page if specified
	if (strncmp(buffer, "TEXTURE", 7) == 0)
	{
		int i, pwidth, pheight;
		char ch, texType[PATH_MAX];

		/* the first parameter for textures is always ignored; which is why we ignore
		 * nlevels read in above */
		ch = *pFileData++;

		// Run up to the dot or till the buffer is filled. Leave room for the extension.
		for (i = 0; i < PATH_MAX - 5 && (ch = *pFileData++) != '\0' && ch != '.'; ++i)
		{
			texfile[i] = ch;
		}
		texfile[i] = '\0';

		if (sscanf(pFileData, "%255s%n", texType, &cnt) != 1)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s texture info corrupt: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;

		if (strcmp(texType, "png") != 0)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s: only png textures supported", pFileName);
			return NULL;
		}
		sstrcat(texfile, ".png");

		if (sscanf(pFileData, "%d %d%n", &pwidth, &pheight, &cnt) != 2)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s bad texture size: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;

		/* Now read in LEVELS directive */
		if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s bad levels info: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;

		bTextured = true;
	}

	if (strncmp(buffer, "NORMALMAP", 9) == 0)
	{
		char ch, texType[PATH_MAX];
		int i;

		/* the first parameter for textures is always ignored; which is why we ignore
		 * nlevels read in above */
		ch = *pFileData++;

		// Run up to the dot or till the buffer is filled. Leave room for the extension.
		for (i = 0; i < PATH_MAX - 5 && (ch = *pFileData++) != '\0' && ch != '.'; ++i)
		{
			normalfile[i] = ch;
		}
		normalfile[i] = '\0';

		if (sscanf(pFileData, "%255s%n", texType, &cnt) != 1)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s normal map info corrupt: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;

		if (strcmp(texType, "png") != 0)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s: only png normal maps supported", pFileName);
			return NULL;
		}
		sstrcat(normalfile, ".png");

		/* Now read in LEVELS directive */
		if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s bad levels info: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;
	}

	if (strncmp(buffer, "SPECULARMAP", 11) == 0)
	{
		char ch, texType[PATH_MAX];
		int i;

		/* the first parameter for textures is always ignored; which is why we ignore nlevels read in above */
		ch = *pFileData++;

		// Run up to the dot or till the buffer is filled. Leave room for the extension.
		for (i = 0; i < PATH_MAX - 5 && (ch = *pFileData++) != '\0' && ch != '.'; ++i)
		{
			specfile[i] = ch;
		}
		specfile[i] = '\0';

		if (sscanf(pFileData, "%255s%n", texType, &cnt) != 1)
		{
			debug(LOG_ERROR, "%s specular map info corrupt: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;

		if (strcmp(texType, "png") != 0)
		{
			debug(LOG_ERROR, "%s: only png specular maps supported", pFileName);
			return NULL;
		}
		sstrcat(specfile, ".png");

		/* Try -again- to read in LEVELS directive */
		if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s bad levels info: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;
	}

	// DEPRECATED SHADERS DIRECTIVE! Has been moved into levels block now. Remove me later.
	if (strncmp(buffer, "SHADERS", 7) == 0)
	{
		char vertex[PATH_MAX], fragment[PATH_MAX];

		/* the first parameter for "textures" is always ignored; which is why we ignore nlevels read in above */
		pFileData++;

		if (sscanf(pFileData, "%255s %255s%n", vertex, fragment, &cnt) != 2)
		{
			debug(LOG_ERROR, "%s shader corrupt: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;
		shader = pie_LoadShader(pFileName, vertex, fragment);

		/* Try -yet again- to read in LEVELS directive */
		if (sscanf(pFileData, "%255s %d%n", buffer, &nlevels, &cnt) != 2)
		{
			debug(LOG_ERROR, "iV_ProcessIMD %s bad levels info: %s", pFileName, buffer);
			return NULL;
		}
		pFileData += cnt;
	}

	if (strncmp(buffer, "LEVELS", 6) != 0)
	{
		debug(LOG_ERROR, "iV_ProcessIMD: expecting 'LEVELS' directive (%s)", buffer);
		return NULL;
	}

	/* Read first LEVEL directive */
	if (sscanf(pFileData, "%255s %d%n", buffer, &level, &cnt) != 2)
	{
		debug(LOG_ERROR, "(_load_level) file corrupt -J");
		return NULL;
	}
	pFileData += cnt;

	if (strncmp(buffer, "LEVEL", 5) != 0)
	{
		debug(LOG_ERROR, "iV_ProcessIMD(2): expecting 'LEVEL' directive (%s)", buffer);
		return NULL;
	}

	shape = _imd_load_level(&pFileData, FileDataEnd, nlevels, imd_version);
	if (shape == NULL)
	{
		debug(LOG_ERROR, "iV_ProcessIMD %s unsuccessful", pFileName);
		return NULL;
	}

	// assign shader to all levels, if old deprecated SHADERS directive used. FIXME remove this later.
	for (iIMDShape *psShape = shape; shader && psShape != NULL; psShape = psShape->next)
	{
		shape->shaderProgram = shader;
	}

	// load texture page if specified
	if (bTextured)
	{
		int texpage = iV_GetTexture(texfile);
		int normalpage = iV_TEX_INVALID;
		int specpage = iV_TEX_INVALID;

		ASSERT_OR_RETURN(NULL, texpage >= 0, "%s could not load tex page %s", pFileName, texfile);

		if (normalfile[0] != '\0')
		{
			debug(LOG_TEXTURE, "Loading normal map %s for %s", normalfile, pFileName);
			normalpage = iV_GetTexture(normalfile);
			ASSERT_OR_RETURN(NULL, normalpage >= 0, "%s could not load tex page %s", pFileName, normalfile);
		}

		if (specfile[0] != '\0')
		{
			debug(LOG_TEXTURE, "Loading specular map %s for %s", specfile, pFileName);
			specpage = iV_GetTexture(specfile);
			ASSERT_OR_RETURN(NULL, specpage >= 0, "%s could not load tex page %s", pFileName, specfile);
		}

		// assign tex pages and flags to all levels
		for (iIMDShape *psShape = shape; psShape != NULL; psShape = psShape->next)
		{
			psShape->texpage = texpage;
			psShape->normalpage = normalpage;
			psShape->specularpage = specpage;
			psShape->flags = imd_flags;
		}

		// check if model should use team colour mask
		if (imd_flags & iV_IMD_TCMASK)
		{
			int texpage_mask;

			pie_MakeTexPageTCMaskName(texfile);
			sstrcat(texfile, ".png");
			texpage_mask = iV_GetTexture(texfile);

			ASSERT_OR_RETURN(shape, texpage_mask >= 0, "%s could not load tcmask %s", pFileName, texfile);

			// Propagate settings through levels
			for (iIMDShape *psShape = shape; psShape != NULL; psShape = psShape->next)
			{
				psShape->tcmaskpage = texpage_mask;
			}
		}
	}

	*ppFileData = pFileData;
	return shape;
}
Example #26
0
// Get values from a base object
bool scrBaseObjGet(UDWORD index)
{
	INTERP_TYPE		type = VAL_VOID;
	BASE_OBJECT		*psObj;
	DROID			*psDroid;
	STRUCTURE		*psStruct;
	FEATURE			*psFeature;

	if (!stackPopParams(1, ST_BASEOBJECT, &psObj))
	{
		debug(LOG_ERROR, "scrBaseObjGet: stackPopParams failed");
		return false;
	}

	// Check this is a valid pointer
	ASSERT_OR_RETURN(false, psObj, "Passed a NULL pointer to a base object");
	ASSERT_OR_RETURN(false, psObj->type == OBJ_DROID || psObj->type == OBJ_STRUCTURE || psObj->type == OBJ_FEATURE,
	                 "Invalid object %p of type %d", psObj, psObj->type);

	// set the type and return value
	switch (index)
	{
	case OBJID_POSX:
		type = VAL_INT;
		scrFunctionResult.v.ival = (SDWORD)psObj->pos.x;
		break;
	case OBJID_POSY:
		type = VAL_INT;
		scrFunctionResult.v.ival = (SDWORD)psObj->pos.y;
		break;
	case OBJID_POSZ:
		type = VAL_INT;
		scrFunctionResult.v.ival = (SDWORD)psObj->pos.z;
		break;
	case OBJID_ID:
		type = VAL_INT;
		scrFunctionResult.v.ival = (SDWORD)psObj->id;
		break;
	case OBJID_PLAYER:
		type = VAL_INT;
		scrFunctionResult.v.ival = (SDWORD)psObj->player;
		break;
	case OBJID_TYPE:
		type = VAL_INT;
		scrFunctionResult.v.ival = (SDWORD)psObj->type;
		break;
	case OBJID_ORDER:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: order only valid for a droid");
			return false;
		}
		type = VAL_INT;
		scrFunctionResult.v.ival = ((DROID *)psObj)->order.type;
		if (scrFunctionResult.v.ival == DORDER_GUARD && ((DROID *)psObj)->order.psObj == NULL)
		{
			scrFunctionResult.v.ival = DORDER_NONE;
		}
		break;
	//new member variable
	case OBJID_ACTION:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: action only valid for a droid");
			return false;
		}
		type = VAL_INT;
		scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->action;
		break;
	//new member variable - if droid is selected (humans only)
	case OBJID_SELECTED:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: selected only valid for a droid");
			return false;
		}
		type = VAL_BOOL;
		scrFunctionResult.v.bval = (SDWORD)((DROID *)psObj)->selected;
		break;
	case OBJID_STRUCTSTATTYPE:
		if (psObj->type == OBJ_STRUCTURE)
		{
			type = VAL_INT;
			scrFunctionResult.v.ival = ((STRUCTURE *)psObj)->pStructureType->type;
		}
		else
		{
			debug(LOG_ERROR, ".stattype is only supported by Structures");
			return false;
		}
		break;
	case OBJID_ORDERX:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: order only valid for a droid");
			return false;
		}
		type = VAL_INT;
		scrFunctionResult.v.ival = ((DROID *)psObj)->order.pos.x;
		break;
	case OBJID_ORDERY:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: order only valid for a droid");
			return false;
		}
		type = VAL_INT;
		scrFunctionResult.v.ival = ((DROID *)psObj)->order.pos.y;
		break;
	case OBJID_DROIDTYPE:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: droidType only valid for a droid");
			return false;
		}
		type = VAL_INT;
		scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->droidType;
		break;
	case OBJID_CLUSTERID:
		if (psObj->type == OBJ_FEATURE)
		{
			debug(LOG_ERROR, "scrBaseObjGet: clusterID not valid for features");
			return false;
		}
		type = VAL_INT;
		scrFunctionResult.v.ival = clustGetClusterID(psObj);
		break;
	case OBJID_HEALTH:
		switch (psObj->type)
		{
		case OBJ_DROID:
			psDroid = (DROID *)psObj;
			type = VAL_INT;
			scrFunctionResult.v.ival = psDroid->body * 100 / psDroid->originalBody;
			break;
		case OBJ_FEATURE:
			psFeature = (FEATURE *)psObj;
			type = VAL_INT;
			if (psFeature->psStats->damageable)
			{
				scrFunctionResult.v.ival = psFeature->body * 100 / psFeature->psStats->body;
			}
			else
			{
				scrFunctionResult.v.ival = 100;
			}
			break;
		case OBJ_STRUCTURE:
			psStruct = (STRUCTURE *)psObj;
			type = VAL_INT;
			//val = psStruct->body * 100 / psStruct->baseBodyPoints;
			scrFunctionResult.v.ival = psStruct->body * 100 / structureBody(psStruct);
			break;
		default:
			break;
		}
		break;
	case OBJID_BODY:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: body only valid for a droid");
			return false;
		}
		type = (INTERP_TYPE)ST_BODY;
		scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->asBits[COMP_BODY].nStat;
		break;
	case OBJID_PROPULSION:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: propulsion only valid for a droid");
			return false;
		}
		type = (INTERP_TYPE)ST_PROPULSION;
		scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->asBits[COMP_PROPULSION].nStat;
		break;
	case OBJID_WEAPON:		//TODO: only returns first weapon now
		type = (INTERP_TYPE)ST_WEAPON;
		switch (psObj->type)
		{
		case OBJ_DROID:
			if (((DROID *)psObj)->asWeaps[0].nStat == 0)
			{
				scrFunctionResult.v.ival = 0;
			}else{
				scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->asWeaps[0].nStat;
			}
			break;
		case OBJ_STRUCTURE:
			if (((STRUCTURE *)psObj)->numWeaps == 0 || ((STRUCTURE *)psObj)->asWeaps[0].nStat == 0)
			{
				scrFunctionResult.v.ival = 0;
			}else{
				scrFunctionResult.v.ival = (SDWORD)((STRUCTURE *)psObj)->asWeaps[0].nStat;
			}
			break;
		default:		//only droids and structures can have a weapon
			debug(LOG_ERROR, "scrBaseObjGet: weapon only valid for droids and structures" );
			return false;
			break;
		}

		break;
	case OBJID_STRUCTSTAT:
		//droid.stat - now returns the type of structure a truck is building for droids
		if (psObj->type == OBJ_STRUCTURE)
		{
			type = (INTERP_TYPE)ST_STRUCTURESTAT;
			scrFunctionResult.v.ival = ((STRUCTURE *)psObj)->pStructureType - asStructureStats;
		}
		else if (psObj->type == OBJ_DROID)
		{
			type = (INTERP_TYPE)ST_STRUCTURESTAT;
			scrFunctionResult.v.ival = ((DROID *)psObj)->order.psStats - asStructureStats;
		}
		else		//Nothing else supported
		{
			debug(LOG_ERROR, "scrBaseObjGet(): .stat only valid for structures and droids");
			return false;
		}
		break;
	case OBJID_TARGET:
		//added object->psTarget
		if (psObj->type == OBJ_STRUCTURE)
		{
			type = (INTERP_TYPE)ST_BASEOBJECT;
			scrFunctionResult.v.oval = ((STRUCTURE *)psObj)->psTarget[0];
		}
		else if (psObj->type == OBJ_DROID)
		{
			type = (INTERP_TYPE)ST_BASEOBJECT;
			scrFunctionResult.v.oval = ((DROID *)psObj)->order.psObj;
		}
		else		//Nothing else supported
		{
			debug(LOG_ERROR, "scrBaseObjGet(): .target only valid for structures and droids");
			return false;
		}
		break;
	case OBJID_GROUP:
		if (psObj->type != OBJ_DROID)
		{
			debug(LOG_ERROR, "scrBaseObjGet: group only valid for a droid");
			return false;
		}
		type = (INTERP_TYPE)ST_GROUP;
		scrFunctionResult.v.oval = ((DROID *)psObj)->psGroup;
		break;
	case OBJID_HITPOINTS:
		type = VAL_INT;
		switch (psObj->type)
		{
		case OBJ_DROID:
			scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->body;
			break;

		case OBJ_STRUCTURE:
			scrFunctionResult.v.ival = (SDWORD)((STRUCTURE *)psObj)->body;
			break;

		case OBJ_FEATURE:
			scrFunctionResult.v.ival = (SDWORD)((FEATURE *)psObj)->body;
			break;

		default:
			debug(LOG_ERROR, "scrBaseObjGet: unknown object type");
			return false;
			break;
		}
		break;
	case OBJID_ORIG_HITPOINTS:
		type = VAL_INT;
		switch (psObj->type)
		{
		case OBJ_DROID:
			scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->originalBody;
			break;
		case OBJ_STRUCTURE:
			scrFunctionResult.v.ival = (SDWORD)structureBody((STRUCTURE *)psObj);
			break;
		case OBJ_FEATURE:
			scrFunctionResult.v.ival = ((FEATURE *)psObj)->psStats->body;
			break;
		default:
			debug(LOG_ERROR, "scrBaseObjGet: unknown object type");
			return false;
			break;
		}
		break;
	default:
		debug(LOG_ERROR, "scrBaseObjGet: unknown variable index");
		return false;
		break;
	}

	// Return the value
	if (!stackPushResult(type, &scrFunctionResult))
	{
		debug(LOG_ERROR, "scrBaseObjGet: stackPushResult() failed");
		return false;
	}

	return true;
}
Example #27
0
/* This returns true if the key went from being down to being up this frame */
bool keyReleased(KEY_CODE code)
{
	ASSERT_OR_RETURN(false, code < KEY_MAXSCAN, "Invalid keycode of %d!", (int)code);
	return ((aKeyState[code].state == KEY_RELEASED) || (aKeyState[code].state == KEY_PRESSRELEASE));
}
Example #28
0
/// default value load routine
bool scrValDefLoad(INTERP_VAL *psVal, WzConfig &ini)
{
	DROID			*psCDroid;
	SDWORD			index, members;
	UDWORD			id;
	LEVEL_DATASET	*psLevel;
	DROID_GROUP		*psGroup = NULL;

	switch ((unsigned)psVal->type)  // Unsigned cast to suppress compiler warnings due to enum abuse.
	{
	case ST_INTMESSAGE:
		if (ini.contains("data"))
		{
			psVal->v.oval = (void*)getViewData(ini.value("data").toString().toAscii().constData());
		}
		else
		{
			psVal->v.oval = NULL;
		}
		break;
	case ST_BASEOBJECT:
	case ST_DROID:
	case ST_STRUCTURE:
	case ST_FEATURE:
		if (ini.contains("data"))
		{
			psVal->v.oval = (void*)getBaseObjFromId(ini.value("data").toInt());
		}
		else
		{
			psVal->v.oval = NULL;
		}
		break;
	case ST_BASESTATS:
	case ST_COMPONENT:
		break;
	case ST_STRUCTURESTAT:
		index = 0;
		if (ini.contains("data"))
		{
			index = getStructStatFromName(ini.value("data").toString().toAscii().constData());
			if (index == -1)
			{
				debug( LOG_FATAL, "Could not find stat");
				index = 0;
			}
		}
		psVal->v.ival = index;
		break;
	case ST_FEATURESTAT:
		index = 0;
		if (ini.contains("data"))
		{
			index = getFeatureStatFromName(ini.value("data").toString().toAscii().constData());
			if (index == -1)
			{
				debug( LOG_FATAL, "Could not find stat");
				index = 0;
			}
		}
		psVal->v.ival = index;
		break;
	case ST_BODY:
		index = getCompFromResName(COMP_BODY, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find body component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_PROPULSION:
		index = getCompFromResName(COMP_PROPULSION, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find propulsion component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_ECM:
		index = getCompFromResName(COMP_ECM, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find ECM component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_SENSOR:
		index = getCompFromResName(COMP_SENSOR, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find sensor component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_CONSTRUCT:
		index = getCompFromResName(COMP_CONSTRUCT, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find constructor component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_WEAPON:
		index = getCompFromResName(COMP_WEAPON, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find weapon");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_REPAIR:
		index = getCompFromResName(COMP_REPAIRUNIT, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find repair component");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_BRAIN:
		index = getCompFromResName(COMP_BRAIN, ini.value("data").toString().toAscii().constData());
		if (index == -1)
		{
			debug(LOG_FATAL, "Could not find repair brain");
			index = 0;
		}
		psVal->v.ival = index;
		break;
	case ST_TEMPLATE:
		psVal->v.oval = NULL;
		if (ini.contains("data"))
		{
			// FIXME: Ugh. Find a better way to show full template info
			psVal->v.oval = (void*)IdToTemplate(ini.value("data").toInt(), ANYPLAYER);
			if ((DROID_TEMPLATE*)(psVal->v.oval) == NULL)
			{
				debug(LOG_FATAL, "Could not find template %d", ini.value("data").toInt());
			}
		}
		break;
	case ST_TEXTSTRING:
		psVal->v.sval = NULL;
		if (ini.contains("data"))
		{
			psVal->v.sval = strdup(ini.value("data").toString().toAscii().constData());
		}
		break;
	case ST_LEVEL:
		psVal->v.sval = NULL;
		if (ini.contains("data"))
		{
			psLevel = levFindDataSet(ini.value("data").toString().toAscii().constData());
			if (psLevel == NULL)
			{
				debug(LOG_FATAL, "Could not find level dataset");
			}
			psVal->v.sval = psLevel->pName;
		}
		break;
	case ST_RESEARCH:
		psVal->v.oval = NULL;
		if (ini.contains("data"))
		{
			QString research = ini.value("data").toString();
			if (!research.isEmpty())
			{
				psVal->v.oval = (void*)getResearch(research.toUtf8().constData());
				ASSERT_OR_RETURN(false, psVal->v.oval, "Could not find research %s", research.toUtf8().constData());
			}
		}
		break;
	case ST_GROUP:
		if (psVal->v.oval == NULL)
		{
			DROID_GROUP *tmp = grpCreate();
			tmp->add(NULL);
			psVal->v.oval = tmp;
		}
		psGroup = (DROID_GROUP *)(psVal->v.oval);
		members = ini.value("members", 0).toInt();
		if (psGroup && members > 0)
		{
			QStringList droids = ini.value("data").toStringList();

			// load the retreat data
			psGroup->sRunData.sPos = ini.vector2i("runpos");
			psGroup->sRunData.forceLevel = ini.value("forceLevel").toInt();
			psGroup->sRunData.leadership = ini.value("leadership").toInt();
			psGroup->sRunData.healthLevel = ini.value("healthLevel").toInt();

			// load the droids
			while (members > 0)
			{
				id = droids.takeLast().toInt();
				psCDroid = (DROID *)getBaseObjFromId(id);
				if (!psCDroid)
				{
					debug(LOG_ERROR, "Could not find object id %d", id);
				}
				else
				{
					((DROID_GROUP*)(psVal->v.oval))->add(psCDroid);
				}
				members--;
			}
		}
		break;
	case ST_SOUND:
		// find audio id

		// don't use sound if it's disabled
		if (audio_Disabled())
		{
			psVal->v.ival = NO_SOUND;
			break;
		}

		index = audio_GetTrackID(ini.value("data").toString().toAscii().constData());
		if (index == SAMPLE_NOT_FOUND)
		{
			// find empty id and set track vals
			QString soundname = ini.value("data").toString();
			index = audio_SetTrackVals(soundname.toAscii().constData(), false, 100, 1800);
			if (!index)			// this is a NON fatal error.
			{
				// We can't find filename of the sound for some reason.
				debug(LOG_ERROR, "Sound ID not available %s not found", soundname.toAscii().constData());
				break;
			}
		}
		psVal->v.ival = index;
		break;
	case ST_STRUCTUREID:
	case ST_DROIDID:
	default:
		// just set the contents directly
		psVal->v.ival = ini.value("data").toInt();
		break;
	}

	return true;
}
Example #29
0
/** Load the research stats */
bool loadResearch(WzConfig &ini)
{
	ASSERT(ini.isAtDocumentRoot(), "WzConfig instance is in the middle of traversal");
	std::vector<WzString> list = ini.childGroups();
	PLAYER_RESEARCH dummy;
	memset(&dummy, 0, sizeof(dummy));
	std::vector< std::vector<WzString> > preResearch;
	preResearch.resize(list.size());
	for (size_t inc = 0; inc < list.size(); ++inc)
	{
		// HACK FIXME: the code assumes we have empty PLAYER_RESEARCH entries to throw around
		for (auto &j : asPlayerResList)
		{
			j.push_back(dummy);
		}

		ini.beginGroup(list[inc]);
		RESEARCH research;
		research.index = inc;
		research.name = ini.string("name");
		research.id = list[inc];

		//check the name hasn't been used already
		ASSERT_OR_RETURN(false, checkResearchName(&research, inc), "Research name '%s' used already", getName(&research));

		research.ref = REF_RESEARCH_START + inc;

		research.results = ini.json("results", nlohmann::json::array());

		//set subGroup icon
		WzString subGroup = ini.value("subgroupIconID", "").toWzString();
		if (subGroup.compare("") != 0)
		{
			research.subGroup = setIconID(subGroup.toUtf8().c_str(), getName(&research));
		}
		else
		{
			research.subGroup = NO_RESEARCH_ICON;
		}

		//set key topic
		unsigned int keyTopic = ini.value("keyTopic", 0).toUInt();
		ASSERT(keyTopic <= 1, "Invalid keyTopic for research topic - '%s' ", getName(&research));
		if (keyTopic <= 1)
		{
			research.keyTopic = ini.value("keyTopic", 0).toUInt();
		}
		else
		{
			research.keyTopic = 0;
		}

		//set tech code
		UBYTE techCode = ini.value("techCode", 0).toUInt();
		ASSERT(techCode <= 1, "Invalid tech code for research topic - '%s' ", getName(&research));
		if (techCode == 0)
		{
			research.techCode = TC_MAJOR;
		}
		else
		{
			research.techCode = TC_MINOR;
		}

		//set the iconID
		WzString iconID = ini.value("iconID", "").toWzString();
		if (iconID.compare("") != 0)
		{
			research.iconID = setIconID(iconID.toUtf8().c_str(), getName(&research));
		}
		else
		{
			research.iconID = NO_RESEARCH_ICON;
		}

		//get the IMDs used in the interface
		WzString statID = ini.value("statID", "").toWzString();
		research.psStat = nullptr;
		if (statID.compare("") != 0)
		{
			//try find the structure stat with given name
			research.psStat = getCompStatsFromName(statID);
			ASSERT_OR_RETURN(false, research.psStat, "Could not find stats for %s research %s", statID.toUtf8().c_str(), getName(&research));
		}

		WzString imdName = ini.value("imdName", "").toWzString();
		if (imdName.compare("") != 0)
		{
			research.pIMD = modelGet(imdName);
			ASSERT(research.pIMD != nullptr, "Cannot find the research PIE '%s' for record '%s'", imdName.toUtf8().data(), getName(&research));
		}

		WzString imdName2 = ini.value("imdName2", "").toWzString();
		if (imdName2.compare("") != 0)
		{
			research.pIMD2 = modelGet(imdName2);
			ASSERT(research.pIMD2 != nullptr, "Cannot find the 2nd research '%s' PIE for record '%s'", imdName2.toUtf8().data(), getName(&research));
		}

		WzString msgName = ini.value("msgName", "").toWzString();
		if (msgName.compare("") != 0)
		{
			//check its a major tech code
			ASSERT(research.techCode == TC_MAJOR, "This research should not have a message associated with it, '%s' the message will be ignored!", getName(&research));
			if (research.techCode == TC_MAJOR)
			{
				research.pViewData = getViewData(msgName);
			}
		}

		//set the researchPoints
		unsigned int resPoints = ini.value("researchPoints", 0).toUInt();
		ASSERT_OR_RETURN(false, resPoints <= UWORD_MAX, "Research Points too high for research topic - '%s' ", getName(&research));
		research.researchPoints = resPoints;

		//set the research power
		unsigned int resPower = ini.value("researchPower", 0).toUInt();
		ASSERT_OR_RETURN(false, resPower <= UWORD_MAX, "Research Power too high for research topic - '%s' ", getName(&research));
		research.researchPower = resPower;

		//remember research pre-requisites for futher checking
		preResearch[inc] = ini.value("requiredResearch").toWzStringList();

		//set components results
		std::vector<WzString> compResults = ini.value("resultComponents").toWzStringList();
		for (size_t j = 0; j < compResults.size(); j++)
		{
			WzString compID = compResults[j].trimmed();
			COMPONENT_STATS *pComp = getCompStatsFromName(compID);
			if (pComp != nullptr)
			{
				research.componentResults.push_back(pComp);
			}
			else
			{
				ASSERT(false, "Invalid item '%s' in list of result components of research '%s' ", compID.toUtf8().c_str(), getName(&research));
			}
		}

		//set replaced components
		std::vector<WzString> replacedComp = ini.value("replacedComponents").toWzStringList();
		for (size_t j = 0; j < replacedComp.size(); j++)
		{
			//read pair of components oldComponent:newComponent
			std::vector<WzString> pair = replacedComp[j].split(":");
			ASSERT(pair.size() == 2, "Invalid item '%s' in list of replaced components of research '%s'. Required format: 'oldItem:newItem, item1:item2'", replacedComp[j].toUtf8().c_str(), getName(&research));
			if (pair.size() != 2)
			{
				continue; //skip invalid entries
			}
			WzString oldCompID = pair[0].trimmed();
			WzString newCompID = pair[1].trimmed();
			COMPONENT_STATS *oldComp = getCompStatsFromName(oldCompID);
			if (oldComp == nullptr)
			{
				ASSERT(false, "Invalid item '%s' in list of replaced components of research '%s'. Wrong component code.", oldCompID.toUtf8().c_str(), getName(&research));
				continue;
			}
			COMPONENT_STATS *newComp = getCompStatsFromName(newCompID);
			if (newComp == nullptr)
			{
				ASSERT(false, "Invalid item '%s' in list of replaced components of research '%s'. Wrong component code.", newCompID.toUtf8().c_str(), getName(&research));
				continue;
			}
			RES_COMP_REPLACEMENT replItem;
			replItem.pOldComponent = oldComp;
			replItem.pNewComponent = newComp;
			research.componentReplacement.push_back(replItem);
		}

		//set redundant components
		std::vector<WzString> redComp = ini.value("redComponents").toWzStringList();
		for (size_t j = 0; j < redComp.size(); j++)
		{
			WzString compID = redComp[j].trimmed();
			COMPONENT_STATS *pComp = getCompStatsFromName(compID);
			if (pComp == nullptr)
			{
				ASSERT(false, "Invalid item '%s' in list of redundant components of research '%s' ", compID.toUtf8().c_str(), getName(&research));
			}
			else
			{
				research.pRedArtefacts.push_back(pComp);
			}
		}

		//set result structures
		std::vector<WzString> resStruct = ini.value("resultStructures").toWzStringList();
		for (size_t j = 0; j < resStruct.size(); j++)
		{
			WzString strucID = resStruct[j].trimmed();
			int structIndex = getStructStatFromName(strucID);
			ASSERT(structIndex >= 0, "Invalid item '%s' in list of result structures of research '%s' ", strucID.toUtf8().c_str(), getName(&research));
			if (structIndex >= 0)
			{
				research.pStructureResults.push_back(structIndex);
			}
		}

		//set required structures
		std::vector<WzString> reqStruct = ini.value("requiredStructures").toWzStringList();
		for (size_t j = 0; j < reqStruct.size(); j++)
		{
			WzString strucID = reqStruct[j].trimmed();
			int structIndex = getStructStatFromName(strucID.toUtf8().c_str());
			ASSERT(structIndex >= 0, "Invalid item '%s' in list of required structures of research '%s' ", strucID.toUtf8().c_str(), getName(&research));
			if (structIndex >= 0)
			{
				research.pStructList.push_back(structIndex);
			}
		}

		//set redundant structures
		std::vector<WzString> redStruct = ini.value("redStructures").toWzStringList();
		for (size_t j = 0; j < redStruct.size(); j++)
		{
			WzString strucID = redStruct[j].trimmed();
			int structIndex = getStructStatFromName(strucID.toUtf8().c_str());
			ASSERT(structIndex >= 0, "Invalid item '%s' in list of redundant structures of research '%s' ", strucID.toUtf8().c_str(), getName(&research));
			if (structIndex >= 0)
			{
				research.pRedStructs.push_back(structIndex);
			}
		}

		asResearch.push_back(research);
		ini.endGroup();
	}

	//Load and check research pre-requisites (need do it AFTER loading research items)
	for (size_t inc = 0; inc < asResearch.size(); inc++)
	{
		std::vector<WzString> &preRes = preResearch[inc];
		for (size_t j = 0; j < preRes.size(); j++)
		{
			WzString resID = preRes[j].trimmed();
			RESEARCH *preResItem = getResearch(resID.toUtf8().c_str());
			ASSERT(preResItem != nullptr, "Invalid item '%s' in list of pre-requisites of research '%s' ", resID.toUtf8().c_str(), getName(&asResearch[inc]));
			if (preResItem != nullptr)
			{
				asResearch[inc].pPRList.push_back(preResItem->index);
			}
		}
	}

	return true;
}
Example #30
0
bool loadFunctionStats(const char *pFunctionData, UDWORD bufferSize)
{
	//array of functions pointers for each load function
	static const LoadFunction pLoadFunction[NUMFUNCTIONS] =
	{
		loadProduction,
		loadProductionUpgradeFunction,
		loadResearchFunction,
		loadResearchUpgradeFunction,
		loadPowerGenFunction,
		loadResourceFunction,
		loadRepairDroidFunction,
		loadWeaponUpgradeFunction,
		loadWallFunction,
		loadStructureUpgradeFunction,
		loadWallDefenceUpgradeFunction,
		loadPowerUpgradeFunction,
		loadRepairUpgradeFunction,
		loadDroidRepairUpgradeFunction,
		loadDroidECMUpgradeFunction,
		loadDroidBodyUpgradeFunction,
		loadDroidSensorUpgradeFunction,
		loadDroidConstUpgradeFunction,
		loadReArmFunction,
		loadReArmUpgradeFunction,
	};

	const unsigned int totalFunctions = numCR(pFunctionData, bufferSize);
	UDWORD		i;
	FUNCTION_TYPE type;
	char		FunctionType[MAX_STR_LENGTH];
	FUNCTION	**pStartList;

	//allocate storage for the Function pointer array
	asFunctions = (FUNCTION **) malloc(totalFunctions * sizeof(FUNCTION *));
	pStartList = asFunctions;
	//initialise the storage
	memset(asFunctions, 0, totalFunctions * sizeof(FUNCTION *));
	numFunctions = 0;

	for (i = 0; i < totalFunctions; i++)
	{
		//read the data into the storage - the data is delimeted using comma's
		FunctionType[0] = '\0';
		sscanf(pFunctionData, "%255[^,'\r\n]", FunctionType);
		type = functionType(FunctionType);
		ASSERT_OR_RETURN(false, type != NUMFUNCTIONS, "Function type not found");
		pFunctionData += (strlen(FunctionType) + 1);

		if (!(pLoadFunction[type](pFunctionData)))
		{
			return false;
		}
		//increment the pointer to the start of the next record
		pFunctionData = strchr(pFunctionData, '\n') + 1;
	}
	//set the function list pointer to the start
	asFunctions = pStartList;

	return true;
}