Exemple #1
0
int main(int argc, char* argv[])
{
	Threading::SetMainThread();
	try {
		spring_clock::PushTickRate();
		// initialize start time (can safely be done before SDL_Init
		// since we are not using SDL_GetTicks as our clock anymore)
		spring_time::setstarttime(spring_time::gettime(true));

		CLogOutput::LogSystemInfo();

		std::string scriptName;
		std::string scriptText;
		std::string binaryName = argv[0];

		gflags::SetUsageMessage("Usage: " + binaryName + " [options] path_to_script.txt");
		gflags::SetVersionString(SpringVersion::GetFull());
		gflags::ParseCommandLineFlags(&argc, &argv, true);
		ParseCmdLine(argc, argv, scriptName);

		GlobalConfig::Instantiate();
		FileSystemInitializer::InitializeLogOutput();
		FileSystemInitializer::Initialize();

		// Initialize crash reporting
		CrashHandler::Install();

		LOG("report any errors to Mantis or the forums.");
		LOG("loading script from file: %s", scriptName.c_str());

		// server will take ownership of these
		std::shared_ptr<ClientSetup> dsClientSetup(new ClientSetup());
		std::shared_ptr<GameData> dsGameData(new GameData());
		std::shared_ptr<CGameSetup> dsGameSetup(new CGameSetup());

		CFileHandler fh(scriptName);

		if (!fh.FileExists())
			throw content_error("script does not exist in given location: " + scriptName);

		if (!fh.LoadStringData(scriptText))
			throw content_error("script cannot be read: " + scriptName);

		dsClientSetup->LoadFromStartScript(scriptText);

		if (!dsGameSetup->Init(scriptText)) {
			// read the script provided by cmdline
			LOG_L(L_ERROR, "failed to load script %s", scriptName.c_str());
			return 1;
		}

		// Create the server, it will run in a separate thread
		CGlobalUnsyncedRNG rng;

		const unsigned sleepTime = FLAGS_sleeptime;
		const unsigned randSeed = time(nullptr) % ((spring_gettime().toNanoSecsi() + 1) * 9007);

		rng.Seed(randSeed);
		dsGameData->SetRandomSeed(rng.NextInt());

		//  Use script provided hashes if they exist
		if (dsGameSetup->mapHash != 0) {
			dsGameData->SetMapChecksum(dsGameSetup->mapHash);
			dsGameSetup->LoadStartPositions(false); // reduced mode
		} else {
			dsGameData->SetMapChecksum(archiveScanner->GetArchiveCompleteChecksum(dsGameSetup->mapName));

			CFileHandler f("maps/" + dsGameSetup->mapName);
			if (!f.FileExists())
				vfsHandler->AddArchiveWithDeps(dsGameSetup->mapName, false);

			dsGameSetup->LoadStartPositions(); // full mode
		}

		if (dsGameSetup->modHash != 0) {
			dsGameData->SetModChecksum(dsGameSetup->modHash);
		} else {
			const std::string& modArchive = archiveScanner->ArchiveFromName(dsGameSetup->modName);
			const unsigned int modCheckSum = archiveScanner->GetArchiveCompleteChecksum(modArchive);
			dsGameData->SetModChecksum(modCheckSum);
		}

		LOG("starting server...");

		{
			dsGameData->SetSetupText(dsGameSetup->setupText);
			CGameServer server(dsClientSetup, dsGameData, dsGameSetup);

			while (!server.HasGameID()) {
				// wait until gameID has been generated or
				// a timeout occurs (if no clients connect)
				if (server.HasFinished())
					break;

				spring_sleep(spring_secs(sleepTime));
			}

			while (!server.HasFinished()) {
				static bool printData = (server.GetDemoRecorder() != nullptr);

				if (printData) {
					printData = false;

					const std::unique_ptr<CDemoRecorder>& demoRec = server.GetDemoRecorder();
					const std::uint8_t* gameID = (demoRec->GetFileHeader()).gameID;

					LOG("recording demo: %s", (demoRec->GetName()).c_str());
					LOG("using mod: %s", (dsGameSetup->modName).c_str());
					LOG("using map: %s", (dsGameSetup->mapName).c_str());
					LOG("GameID: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", gameID[0], gameID[1], gameID[2], gameID[3], gameID[4], gameID[5], gameID[6], gameID[7], gameID[8], gameID[9], gameID[10], gameID[11], gameID[12], gameID[13], gameID[14], gameID[15]);
				}

				spring_secs(sleepTime).sleep(true);
			}
		}

		LOG("exiting");
		FileSystemInitializer::Cleanup();
		GlobalConfig::Deallocate();
		DataDirLocater::FreeInstance();

		spring_clock::PopTickRate();
		LOG("exited");
	}
	CATCH_SPRING_ERRORS

	return 0;
}
Exemple #2
0
void DataDirLocater::LocateDataDirs()
{
	// Prepare the data-dirs defined in different places

	// environment variable
	std::string dd_env = "";
	{
		char* env = getenv("SPRING_DATADIR");
		if (env && *env) {
			dd_env = SubstEnvVars(env);
		}
	}

	// If this is true, ie the var is present in env, we will only add the dir
	// where both binary and unitysnc lib reside in Portable mode,
	// or the parent dir, if it is a versioned data-dir.
	const bool isolationMode = (getenv("SPRING_ISOLATED") != NULL);

#if       defined(UNITSYNC)
	const std::string dd_curWorkDir = Platform::GetModulePath();
#else  // defined(UNITSYNC)
	const std::string dd_curWorkDir = Platform::GetProcessExecutablePath();
#endif // defined(UNITSYNC)

#if    defined(WIN32)
	// fetch my documents path
	TCHAR pathMyDocs[MAX_PATH];
	SHGetFolderPath( NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, pathMyDocs);

	// fetch app-data path
	TCHAR pathAppData[MAX_PATH];
	SHGetFolderPath( NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, pathAppData);

	std::string dd_myDocs = pathMyDocs;
	// e.g. F:\Dokumente und Einstellungen\Karl-Robert\Eigene Dateien\Spring
	dd_myDocs += "\\Spring";

	std::string dd_myDocsMyGames = pathMyDocs;
	// My Documents\My Games seems to be the MS standard even if no official guidelines exist
	// most if not all new Games For Windows(TM) games use this dir
	dd_myDocsMyGames += "\\My Games\\Spring";

	std::string dd_appData = pathAppData;
	// e.g. F:\Dokumente und Einstellungen\All Users\Anwendungsdaten\Spring
	dd_appData += "\\Spring";
#else // *nix (-OSX)
	// settings in /etc
	std::string dd_etc = "";
	{
		FILE* fileH = ::fopen("/etc/spring/datadir", "r");
		if (fileH) {
			const char whiteSpaces[3] = {'\t', ' ', '\0'};
			char lineBuf[1024];
			while (fgets(lineBuf, sizeof(lineBuf), fileH)) {
				char* newLineCharPos = strchr(lineBuf, '\n');
				if (newLineCharPos) {
					// remove the new line char
					*newLineCharPos = '\0';
				}
				// ignore lines consisting of only whitespaces
				if ((strlen(lineBuf) > 0) && strspn(lineBuf, whiteSpaces) != strlen(lineBuf)) {
					// append, separated by sPD (depending on OS): ';' or ':'
					dd_etc = dd_etc + (dd_etc.empty() ? "" : sPD) + SubstEnvVars(lineBuf);
				}
			}
			fclose(fileH);
		}
	}
#endif // defined(WIN32), defined(MACOSX_BUNDLE), else

	// Construct the list of dataDirs from various sources.
	dataDirs.clear();
	// The first dir added will be the writeable data dir.

	if (isolationMode) {
		AddCwdOrParentDir(dd_curWorkDir, true); // "./" or "../"
	} else {
		// same on all platforms
		AddDirs(dd_env);    // ENV{SPRING_DATADIR}
		// user defined in spring config handler
		// (Linux: ~/.springrc, Windows: .\springsettings.cfg)
		AddDirs(SubstEnvVars(configHandler->GetString("SpringData")));

#ifdef WIN32
		// All MS Windows variants

		AddCwdOrParentDir(dd_curWorkDir); // "./" or "../"
		AddDirs(dd_myDocsMyGames);  // "C:/.../My Documents/My Games/Spring/"
		AddDirs(dd_myDocs);         // "C:/.../My Documents/Spring/"
		AddDirs(dd_appData);        // "C:/.../All Users/Applications/Spring/"

#elif defined(MACOSX_BUNDLE)
		// Mac OS X Application Bundle (*.app) - single file install

		// directory structure (Apple standard):
		// Spring.app/Contents/MacOS/springlobby
		// Spring.app/Contents/Resources/bin/spring
		// Spring.app/Contents/Resources/lib/unitsync.dylib
		// Spring.app/Contents/Resources/share/games/spring/base/

		// This corresponds to Spring.app/Contents/Resources/
		const std::string bundleResourceDir = FileSystem::GetParent(dd_curWorkDir);

		// This has to correspond with the value in the build-script
		const std::string dd_curWorkDirData = bundleResourceDir + "/share/games/spring";

		// we need this as default writeable dir, because the Bundle.pp dir
		// might not be writeable by the user starting the game
		AddDirs(SubstEnvVars("$HOME/.spring")); // "~/.spring/"
		AddDirs(dd_curWorkDirData);             // "Spring.app/Contents/Resources/share/games/spring"
		AddDirs(dd_etc);                        // from /etc/spring/datadir

#else
		// Linux, FreeBSD, Solaris, Apple non-bundle

		AddCwdOrParentDir(dd_curWorkDir); // "./" or "../"
		AddDirs(SubstEnvVars("$HOME/.spring")); // "~/.spring/"
		AddDirs(dd_etc);            // from /etc/spring/datadir
#endif

#ifdef SPRING_DATADIR
		AddDirs(SubstEnvVars(SPRING_DATADIR)); // from -DSPRING_DATADIR
#endif
	}

	// Figure out permissions of all dataDirs
	DeterminePermissions();

	if (!writeDir) {
		// bail out
		const std::string errstr = "Not a single writable data directory found!\n\n"
				"Configure a writable data directory using either:\n"
				"- the SPRING_DATADIR environment variable,\n"
#ifdef WIN32
				"- a SpringData=C:/path/to/data declaration in spring's config file ./springsettings.cfg\n"
				"- by giving you write access to the installation directory";
#else
				"- a SpringData=/path/to/data declaration in ~/.springrc or\n"
				"- the configuration file /etc/spring/datadir";
#endif
		throw content_error(errstr);
	}

	// for now, chdir to the data directory as a safety measure:
	// Not only safety anymore, it's just easier if other code can safely assume that
	// writeDir == current working directory
	FileSystem::ChDir(GetWriteDir()->path.c_str());

	// Initialize the log. Only after this moment log will be written to file.
	logOutput.Initialize();
	// Logging MAY NOT start before the chdir, otherwise the logfile ends up
	// in the wrong directory.
	// Update: now it actually may start before, log has preInitLog.
	for (std::vector<DataDir>::const_iterator d = dataDirs.begin(); d != dataDirs.end(); ++d) {
		if (d->writable) {
			LOG("Using read-write data directory: %s", d->path.c_str());

			// tag the cache dir
			const std::string cacheDir = d->path + "cache";
			if (FileSystem::CreateDirectory(cacheDir)) {
				CacheDir::SetCacheDir(cacheDir, true);
			}
		} else {
			LOG("Using read-only data directory: %s",  d->path.c_str());
		}
	}
}
Exemple #3
0
static void option_parseOption(const LuaTable& root, int index, Option& opt,
		std::set<string>& optionsSet) {

	const LuaTable& optTbl = root.SubTable(index);
	if (!optTbl.IsValid()) {
		throw content_error("parseOption: subtable " + IntToString(index) + " is invalid");
	}

	// common options properties
	opt.key = optTbl.GetString("key", "");
	if (opt.key.empty()
			|| (opt.key.find_first_of(Option_badKeyChars) != string::npos)) {
		throw content_error("parseOption: (key=\"" + opt.key + "\") empty key or key contains bad characters (\"" + Option_badKeyChars + "\")");
	}
	opt.key = StringToLower(opt.key);

	opt.scope = optTbl.GetString("scope", "scope");
	if (opt.scope.find_first_of(Option_badKeyChars) != string::npos) {
		throw content_error("parseOption: (key=" + opt.key + ") scope contains bad characters (\"" + Option_badKeyChars + "\"): \"" + opt.scope + "\"");
	}
	opt.scope = StringToLower(opt.scope);

	if (optionsSet.find(opt.key) != optionsSet.end()) {
		throw content_error("parseOption: key \"" + opt.key + "\" exists already");
	}
	opt.name = optTbl.GetString("name", opt.key);
	if (opt.name.empty()) {
		throw content_error("parseOption: (key=" + opt.key + ") empty name");
	}
	opt.desc = optTbl.GetString("desc", opt.name);

	opt.section = optTbl.GetString("section", "");
	opt.style = optTbl.GetString("style", "");

	opt.type = optTbl.GetString("type", "");
	opt.type = StringToLower(opt.type);

	// option type specific properties
	if (opt.type == "bool") {
		opt.typeCode = opt_bool;
		opt.boolDef = optTbl.GetBool("def", false);
	}
	else if (opt.type == "number") {
		opt.typeCode = opt_number;
		opt.numberDef  = optTbl.GetFloat("def",  0.0f);
		opt.numberMin  = optTbl.GetFloat("min",  -1.0e30f);
		opt.numberMax  = optTbl.GetFloat("max",  +1.0e30f);
		opt.numberStep = optTbl.GetFloat("step", 0.0f);
	}
	else if (opt.type == "string") {
		opt.typeCode = opt_string;
		opt.stringDef    = optTbl.GetString("def", "");
		opt.stringMaxLen = optTbl.GetInt("maxlen", 0);
	}
	else if (opt.type == "list") {
		opt.typeCode = opt_list;

		const LuaTable& listTbl = optTbl.SubTable("items");
		if (!listTbl.IsValid()) {
			throw content_error("parseOption: (key=" + opt.key + ") subtables: items invalid");
		}

		for (int i = 1; listTbl.KeyExists(i); i++) {
			OptionListItem item;

			// string format
			item.key = listTbl.GetString(i, "");
			if (!item.key.empty() &&
			    (item.key.find_first_of(Option_badKeyChars) == string::npos)) {
				item.name = item.key;
				item.desc = item.name;
				opt.list.push_back(item);
				continue;
			}

			// table format  (name & desc)
			const LuaTable& itemTbl = listTbl.SubTable(i);
			if (!itemTbl.IsValid()) {
				throw content_error("parseOption: (key=" + opt.key + ") subtables: subtable " + IntToString(i) + " contains invalid items");
			}
			item.key = itemTbl.GetString("key", "");
			if (item.key.empty() || (item.key.find_first_of(Option_badKeyChars) != string::npos)) {
				throw content_error("parseOption: (key=" + opt.key + ") subtables: (key=\"" + item.key + "\") empty key or key contains bad characters (\"" + Option_badKeyChars + "\")");
			}
			item.key = StringToLower(item.key);
			item.name = itemTbl.GetString("name", item.key);
			if (item.name.empty()) {
				throw content_error("parseOption: (key=" + opt.key + ") subtables: (key=" + item.key + ") empty name");
			}
			item.desc = itemTbl.GetString("desc", item.name);
			opt.list.push_back(item);
		}

		if (opt.list.size() <= 0) {
			throw content_error("parseOption: (key=" + opt.key + ") subtables: empty list");
		}

		opt.listDef = optTbl.GetString("def", opt.list[0].name);
	}
	else if (opt.type == "section") {
		opt.typeCode = opt_section;
	}
	else {
		throw content_error("parseOption: (key=" + opt.key + ") unknown type \"" + opt.type + "\"");
	}

	optionsSet.insert(opt.key);
}
Exemple #4
0
CAdvWater::CAdvWater(bool loadShader)
{
	if (!FBO::IsSupported()) {
		throw content_error("Water Error: missing FBO support");
	}

	glGenTextures(1, &reflectTexture);
	unsigned char* scrap = new unsigned char[512 * 512 * 4];

	glBindTexture(GL_TEXTURE_2D, reflectTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     GL_CLAMP_TO_EDGE);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, scrap);

	glGenTextures(1, &bumpTexture);
	glBindTexture(GL_TEXTURE_2D, bumpTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, scrap);

	glGenTextures(4, rawBumpTexture);

	for (int y = 0; y < 64; ++y) {
		for (int x = 0; x < 64; ++x) {
			scrap[(y*64 + x)*4 + 0] = 128;
			scrap[(y*64 + x)*4 + 1] = (unsigned char)(sin(y*PI*2.0f/64.0f)*128 + 128);
			scrap[(y*64 + x)*4 + 2] = 0;
			scrap[(y*64 + x)*4 + 3] = 255;
		}
	}
	glBindTexture(GL_TEXTURE_2D, rawBumpTexture[0]);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, scrap);

	for (int y = 0; y < 64; ++y) {
		for (int x = 0; x < 64; ++x) {
			const float ang = 26.5f*PI/180.0f;
			const float pos = y*2+x;
			scrap[(y*64 + x)*4 + 0] = (unsigned char)((sin(pos*PI*2.0f/64.0f))*128*sin(ang)) + 128;
			scrap[(y*64 + x)*4 + 1] = (unsigned char)((sin(pos*PI*2.0f/64.0f))*128*cos(ang)) + 128;
		}
	}
	glBindTexture(GL_TEXTURE_2D, rawBumpTexture[1]);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, scrap);

	for (int y = 0; y < 64; ++y) {
		for (int x = 0; x < 64; ++x) {
			const float ang = -19*PI/180.0f;
			const float pos = 3*y - x;
			scrap[(y*64 + x)*4 + 0] = (unsigned char)((sin(pos*PI*2.0f/64.0f))*128*sin(ang)) + 128;
			scrap[(y*64 + x)*4 + 1] = (unsigned char)((sin(pos*PI*2.0f/64.0f))*128*cos(ang)) + 128;
		}
	}
	glBindTexture(GL_TEXTURE_2D, rawBumpTexture[2]);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, scrap);

	delete[] scrap;

	if (loadShader) {
		waterFP = LoadFragmentProgram("ARB/water.fp");
	}

	waterSurfaceColor = mapInfo->water.surfaceColor;

	reflectFBO.Bind();
	reflectFBO.AttachTexture(reflectTexture, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT);
	reflectFBO.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT32, 512, 512);
	bumpFBO.Bind();
	bumpFBO.AttachTexture(bumpTexture, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT);
	FBO::Unbind();

	if (!bumpFBO.IsValid()) {
		throw content_error("Water Error: Invalid FBO");
	}
}
void CCustomExplosionGenerator::ParseExplosionCode(
	CCustomExplosionGenerator::ProjectileSpawnInfo* psi,
	int offset, boost::shared_ptr<creg::IType> type, const string& script, string& code)
{

	string::size_type end = script.find(';', 0);
	string vastr = script.substr(0, end);


	if (vastr == "dir") { // first see if we can match any keywords
		// if the user uses a keyword assume he knows that it is put on the right datatype for now
		code += OP_DIR;
		boost::uint16_t ofs = offset;
		code.append((char*) &ofs, (char*) &ofs + 2);
	}
	else if (dynamic_cast<creg::BasicType*>(type.get())) {
		creg::BasicType *bt = (creg::BasicType*)type.get();

		if (bt->id != creg::crInt && bt->id != creg::crFloat && bt->id != creg::crUChar && bt->id != creg::crBool) {
			throw content_error("Projectile properties other than int, float and uchar, are not supported (" + script + ")");
			return;
		}

		int p = 0;
		while (p < script.length()) {
			char opcode;
			char c;
			do { c = script[p++]; } while (c == ' ');

			bool useInt = false;

			if (c == 'i')      opcode = OP_INDEX;
			else if (c == 'r') opcode = OP_RAND;
			else if (c == 'd') opcode = OP_DAMAGE;
			else if (c == 'm') opcode = OP_SAWTOOTH;
			else if (c == 'k') opcode = OP_DISCRETE;
			else if (c == 's') opcode = OP_SINE;
			else if (c == 'y') {opcode = OP_YANK; useInt = true;}
			else if (c == 'x') {opcode = OP_MULTIPLY; useInt = true;}
			else if (c == 'a') {opcode = OP_ADDBUFF; useInt = true;}
			else if (c == 'p') opcode = OP_POW;
			else if (c == 'q') {opcode = OP_POWBUFF; useInt = true;}
			else if (isdigit(c) || c == '.' || c == '-') { opcode = OP_ADD; p--; }
			else {
				logOutput.Print("[CCEG::ParseExplosionCode] WARNING: unknown op-code \"" + string(1, c) + "\" in \"" + script + "\"");
				continue;
			}

			char* endp;
			if (!useInt) {
				const float v = (float)strtod(&script[p], &endp);

				p += endp - &script[p];
				code += opcode;
				code.append((char*) &v, ((char*) &v) + 4);
			} else {
				const int v = std::max(0, std::min(16, (int)strtol(&script[p], &endp, 10)));

				p += endp - &script[p];
				code += opcode;
				code.append((char*) &v, ((char*) &v) + 4);
			}
		}

		switch (bt->id) {
			case creg::crInt: code.push_back(OP_STOREI); break;
			case creg::crBool: code.push_back(OP_STOREI); break;
			case creg::crFloat: code.push_back(OP_STOREF); break;
			case creg::crUChar: code.push_back(OP_STOREC); break;
			default:
				throw content_error("Explosion script variable is of unsupported type. "
					"Contact the Spring team to fix this.");
					break;
		}
		boost::uint16_t ofs = offset;
		code.append((char*)&ofs, (char*)&ofs + 2);
	}
	else if (dynamic_cast<creg::ObjectInstanceType*>(type.get())) {
		creg::ObjectInstanceType *oit = (creg::ObjectInstanceType *)type.get();

		string::size_type start = 0;
		for (creg::Class* c = oit->objectClass; c; c=c->base) {
			for (int a = 0; a < c->members.size(); a++) {
				string::size_type end = script.find(',', start+1);
				ParseExplosionCode(psi, offset + c->members [a]->offset, c->members[a]->type, script.substr(start,end-start), code);
				start = end+1;
				if (start >= script.length()) { break; }
			}
			if (start >= script.length()) { break; }
		}
	}
	else if (dynamic_cast<creg::StaticArrayBaseType*>(type.get())) {
		creg::StaticArrayBaseType *sat = (creg::StaticArrayBaseType*)type.get();

		string::size_type start = 0;
		for (unsigned int i=0; i < sat->size; i++) {
			string::size_type end = script.find(',', start+1);
			ParseExplosionCode(psi, offset + sat->elemSize * i, sat->elemType, script.substr(start, end-start), code);
			start = end+1;
			if (start >= script.length()) { break; }
		}
	}
	else {
		if (type->GetName() == "AtlasedTexture*") {
			string::size_type end = script.find(';', 0);
			string texname = script.substr(0, end);
			void* tex = projectileDrawer->textureAtlas->GetTexturePtr(texname);
			code += OP_LOADP;
			code.append((char*)(&tex), ((char*)(&tex)) + sizeof(void*));
			code += OP_STOREP;
			boost::uint16_t ofs = offset;
			code.append((char*)&ofs, (char*)&ofs + 2);
		} else if (type->GetName() == "GroundFXTexture*") {
			string::size_type end = script.find(';', 0);
			string texname = script.substr(0, end);
			void* tex = projectileDrawer->groundFXAtlas->GetTexturePtr(texname);
			code += OP_LOADP;
			code.append((char*)(&tex), ((char*)(&tex)) + sizeof(void*));
			code += OP_STOREP;
			boost::uint16_t ofs = offset;
			code.append((char*)&ofs, (char*)&ofs + 2);
		} else if (type->GetName() == "CColorMap*") {
			string::size_type end = script.find(';', 0);
			string colorstring = script.substr(0, end);
			void* colormap = CColorMap::LoadFromDefString(colorstring);
			code += OP_LOADP;
			code.append((char*)(&colormap), ((char*)(&colormap)) + sizeof(void*));
			code += OP_STOREP;
			boost::uint16_t ofs = offset;
			code.append((char*)&ofs, (char*)&ofs + 2);
		} else if (type->GetName() == "IExplosionGenerator*") {
			string::size_type end = script.find(';', 0);
			string name = script.substr(0, end);
			void* explgen = explGenHandler->LoadGenerator(name);
			code += OP_LOADP;
			code.append((char*)(&explgen), ((char*)(&explgen)) + sizeof(void*));
			code += OP_STOREP;
			boost::uint16_t ofs = offset;
			code.append((char*)&ofs, (char*)&ofs + 2);
		}
	}
}
void CCustomExplosionGenerator::ParseExplosionCode(
	CCustomExplosionGenerator::ProjectileSpawnInfo* psi,
	const int offset,
	const boost::shared_ptr<creg::IType> type,
	const string& script,
	string& code)
{
	// strtod&co expect C-style strings with NULLs,
	// c_str() is guaranteed to be NULL-terminated
	// (whether .data() == .c_str() depends on the
	// implementation of std::string)
	const char* scriptStr = script.c_str();

	string::size_type end = script.find(';', 0);
	string vastr = script.substr(0, end);

	if (vastr == "dir") { // first see if we can match any keywords
		// if the user uses a keyword assume he knows that it is put on the right datatype for now
		code += OP_DIR;
		boost::uint16_t ofs = offset;
		code.append((char*) &ofs, (char*) &ofs + 2);
	}
	else if (dynamic_cast<creg::BasicType*>(type.get())) {
		const creg::BasicType* basicType = (creg::BasicType*) type.get();
		const bool legalType =
			(basicType->id == creg::crInt  ) ||
			(basicType->id == creg::crFloat) ||
			(basicType->id == creg::crUChar) ||
			(basicType->id == creg::crBool );

		if (!legalType) {
			throw content_error("[CCEG::ParseExplosionCode] projectile type-properties other than int, float, uchar, or bool are not supported (" + script + ")");
			return;
		}

		int p = 0;

		while (p < script.length()) {
			char opcode = OP_END;
			char c = script[p++];

			// consume whitespace
			if (c == ' ')
				continue;

			bool useInt = false;

			     if (c == 'i')   opcode = OP_INDEX;
			else if (c == 'r')   opcode = OP_RAND;
			else if (c == 'd')   opcode = OP_DAMAGE;
			else if (c == 'm')   opcode = OP_SAWTOOTH;
			else if (c == 'k')   opcode = OP_DISCRETE;
			else if (c == 's')   opcode = OP_SINE;
			else if (c == 'p')   opcode = OP_POW;
			else if (c == 'y') { opcode = OP_YANK;     useInt = true; }
			else if (c == 'x') { opcode = OP_MULTIPLY; useInt = true; }
			else if (c == 'a') { opcode = OP_ADDBUFF;  useInt = true; }
			else if (c == 'q') { opcode = OP_POWBUFF;  useInt = true; }
			else if (isdigit(c) || c == '.' || c == '-') { opcode = OP_ADD; p--; }
			else {
				const char* fmt = "[CCEG::ParseExplosionCode] unknown op-code \"%c\" in \"%s\" at index %d";
				LOG_L(L_WARNING, fmt, c, scriptStr, p);
				continue;
			}

			// be sure to exit cleanly if there are no more operators or operands
			if (p >= script.size())
				continue;

			char* endp = NULL;

			if (!useInt) {
				const float v = (float)strtod(&scriptStr[p], &endp);

				p += (endp - &scriptStr[p]);
				code += opcode;
				code.append((char*) &v, ((char*) &v) + 4);
			} else {
				const int v = std::max(0, std::min(16, (int)strtol(&scriptStr[p], &endp, 10)));

				p += (endp - &scriptStr[p]);
				code += opcode;
				code.append((char*) &v, ((char*) &v) + 4);
			}
		}

		switch (basicType->id) {
			case creg::crInt:   code.push_back(OP_STOREI); break;
			case creg::crBool:  code.push_back(OP_STOREI); break;
			case creg::crFloat: code.push_back(OP_STOREF); break;
			case creg::crUChar: code.push_back(OP_STOREC); break;
			default: break;
		}

		boost::uint16_t ofs = offset;
		code.append((char*)&ofs, (char*)&ofs + 2);
	}
	else if (dynamic_cast<creg::ObjectInstanceType*>(type.get())) {
		creg::ObjectInstanceType *oit = (creg::ObjectInstanceType *)type.get();

		string::size_type start = 0;
		for (creg::Class* c = oit->objectClass; c; c=c->base) {
			for (int a = 0; a < c->members.size(); a++) {
				string::size_type end = script.find(',', start+1);
				ParseExplosionCode(psi, offset + c->members [a]->offset, c->members[a]->type, script.substr(start,end-start), code);
				start = end+1;
				if (start >= script.length()) { break; }
			}
			if (start >= script.length()) { break; }
		}
	}
	else if (dynamic_cast<creg::StaticArrayBaseType*>(type.get())) {
		creg::StaticArrayBaseType *sat = (creg::StaticArrayBaseType*)type.get();

		string::size_type start = 0;
		for (unsigned int i=0; i < sat->size; i++) {
			string::size_type end = script.find(',', start+1);
			ParseExplosionCode(psi, offset + sat->elemSize * i, sat->elemType, script.substr(start, end-start), code);
			start = end+1;
			if (start >= script.length()) { break; }
		}
	}
	else {
		if (type->GetName() == "AtlasedTexture*") {
			string::size_type end = script.find(';', 0);
			string texname = script.substr(0, end);
			// this memory is managed by textureAtlas (CTextureAtlas)
			void* tex = projectileDrawer->textureAtlas->GetTexturePtr(texname);
			code += OP_LOADP;
			code.append((char*)(&tex), ((char*)(&tex)) + sizeof(void*));
			code += OP_STOREP;
			boost::uint16_t ofs = offset;
			code.append((char*)&ofs, (char*)&ofs + 2);
		} else if (type->GetName() == "GroundFXTexture*") {
			string::size_type end = script.find(';', 0);
			string texname = script.substr(0, end);
			// this memory is managed by groundFXAtlas (CTextureAtlas)
			void* tex = projectileDrawer->groundFXAtlas->GetTexturePtr(texname);
			code += OP_LOADP;
			code.append((char*)(&tex), ((char*)(&tex)) + sizeof(void*));
			code += OP_STOREP;
			boost::uint16_t ofs = offset;
			code.append((char*)&ofs, (char*)&ofs + 2);
		} else if (type->GetName() == "CColorMap*") {
			string::size_type end = script.find(';', 0);
			string colorstring = script.substr(0, end);
			// gets stored and deleted at game end from inside CColorMap
			void* colormap = CColorMap::LoadFromDefString(colorstring);
			code += OP_LOADP;
			code.append((char*)(&colormap), ((char*)(&colormap)) + sizeof(void*));
			code += OP_STOREP;
			boost::uint16_t ofs = offset;
			code.append((char*)&ofs, (char*)&ofs + 2);
		} else if (type->GetName() == "IExplosionGenerator*") {
			string::size_type end = script.find(';', 0);
			string name = script.substr(0, end);

			IExplosionGenerator* explGen = explGenHandler->LoadGenerator(name);
			spawnExplGens.push_back(explGen); // these will be unloaded in ~CCustomExplosionGenerator()

			void* explGenRaw = (void*) explGen;
			code += OP_LOADP;
			code.append((char*)(&explGenRaw), ((char*)(&explGenRaw)) + sizeof(void*));
			code += OP_STOREP;
			boost::uint16_t ofs = offset;
			code.append((char*)&ofs, (char*)&ofs + 2);
		}
	}
}
CProjectileDrawer::CProjectileDrawer(): CEventClient("[CProjectileDrawer]", 123456, false) {
	eventHandler.AddClient(this);

	loadscreen->SetLoadMessage("Creating Projectile Textures");

	textureAtlas = new CTextureAtlas(2048, 2048);
	groundFXAtlas = new CTextureAtlas(2048, 2048);

	LuaParser resourcesParser("gamedata/resources.lua", SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
	LuaParser mapResParser("gamedata/resources_map.lua", SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);

	resourcesParser.Execute();

	const LuaTable& resTable = resourcesParser.GetRoot();
	const LuaTable& resGraphicsTable = resTable.SubTable("graphics");
	const LuaTable& resProjTexturesTable = resGraphicsTable.SubTable("projectileTextures");
	const LuaTable& resSmokeTexturesTable = resGraphicsTable.SubTable("smoke");
	const LuaTable& resGroundFXTexturesTable = resGraphicsTable.SubTable("groundfx");

	// used to block resources_map.* from overriding any of
	// resources.lua:{projectile, smoke, groundfx}textures,
	// as well as various defaults (repulsegfxtexture, etc)
	std::set<std::string> blockedTexNames;

	ParseAtlasTextures(true, resProjTexturesTable, blockedTexNames, textureAtlas);
	ParseAtlasTextures(true, resGroundFXTexturesTable, blockedTexNames, groundFXAtlas);

	int smokeTexCount = -1;

	{
		// get the smoke textures, hold the count in 'smokeTexCount'
		if (resSmokeTexturesTable.IsValid()) {
			for (smokeTexCount = 0; true; smokeTexCount++) {
				const std::string& tex = resSmokeTexturesTable.GetString(smokeTexCount + 1, "");
				if (tex.empty()) {
					break;
				}
				const std::string texName = "bitmaps/" + tex;
				const std::string smokeName = "ismoke" + IntToString(smokeTexCount, "%02i");

				textureAtlas->AddTexFromFile(smokeName, texName);
				blockedTexNames.insert(StringToLower(smokeName));
			}
		} else {
			// setup the defaults
			for (smokeTexCount = 0; smokeTexCount < 12; smokeTexCount++) {
				const std::string smokeNum = IntToString(smokeTexCount, "%02i");
				const std::string smokeName = "ismoke" + smokeNum;
				const std::string texName = "bitmaps/smoke/smoke" + smokeNum + ".tga";

				textureAtlas->AddTexFromFile(smokeName, texName);
				blockedTexNames.insert(StringToLower(smokeName));
			}
		}

		if (smokeTexCount <= 0) {
			// this needs to be an exception, other code
			// assumes at least one smoke-texture exists
			throw content_error("missing smoke textures");
		}
	}

	{
		// shield-texture memory
		char perlinTexMem[128][128][4];
		for (int y = 0; y < 128; y++) {
			for (int x = 0; x < 128; x++) {
				perlinTexMem[y][x][0] = 70;
				perlinTexMem[y][x][1] = 70;
				perlinTexMem[y][x][2] = 70;
				perlinTexMem[y][x][3] = 70;
			}
		}

		textureAtlas->AddTexFromMem("perlintex", 128, 128, CTextureAtlas::RGBA32, perlinTexMem);
	}

	blockedTexNames.insert("perlintex");
	blockedTexNames.insert("flare");
	blockedTexNames.insert("explo");
	blockedTexNames.insert("explofade");
	blockedTexNames.insert("heatcloud");
	blockedTexNames.insert("laserend");
	blockedTexNames.insert("laserfalloff");
	blockedTexNames.insert("randdots");
	blockedTexNames.insert("smoketrail");
	blockedTexNames.insert("wake");
	blockedTexNames.insert("perlintex");
	blockedTexNames.insert("flame");

	blockedTexNames.insert("sbtrailtexture");
	blockedTexNames.insert("missiletrailtexture");
	blockedTexNames.insert("muzzleflametexture");
	blockedTexNames.insert("repulsetexture");
	blockedTexNames.insert("dguntexture");
	blockedTexNames.insert("flareprojectiletexture");
	blockedTexNames.insert("sbflaretexture");
	blockedTexNames.insert("missileflaretexture");
	blockedTexNames.insert("beamlaserflaretexture");
	blockedTexNames.insert("bubbletexture");
	blockedTexNames.insert("geosquaretexture");
	blockedTexNames.insert("gfxtexture");
	blockedTexNames.insert("projectiletexture");
	blockedTexNames.insert("repulsegfxtexture");
	blockedTexNames.insert("sphereparttexture");
	blockedTexNames.insert("torpedotexture");
	blockedTexNames.insert("wrecktexture");
	blockedTexNames.insert("plasmatexture");

	if (mapResParser.Execute()) {
		// allow map-specified atlas textures (for gaia-projectiles and ground-flashes)
		const LuaTable& mapResTable = mapResParser.GetRoot();
		const LuaTable& mapResGraphicsTable = mapResTable.SubTable("graphics");
		const LuaTable& mapResProjTexturesTable = mapResGraphicsTable.SubTable("projectileTextures");
		const LuaTable& mapResGroundFXTexturesTable = mapResGraphicsTable.SubTable("groundfx");

		ParseAtlasTextures(false, mapResProjTexturesTable, blockedTexNames, textureAtlas);
		ParseAtlasTextures(false, mapResGroundFXTexturesTable, blockedTexNames, groundFXAtlas);
	}

	if (!textureAtlas->Finalize()) {
		LOG_L(L_ERROR, "Could not finalize projectile-texture atlas. Use less/smaller textures.");
	}

	flaretex        = textureAtlas->GetTexturePtr("flare");
	explotex        = textureAtlas->GetTexturePtr("explo");
	explofadetex    = textureAtlas->GetTexturePtr("explofade");
	heatcloudtex    = textureAtlas->GetTexturePtr("heatcloud");
	laserendtex     = textureAtlas->GetTexturePtr("laserend");
	laserfallofftex = textureAtlas->GetTexturePtr("laserfalloff");
	randdotstex     = textureAtlas->GetTexturePtr("randdots");
	smoketrailtex   = textureAtlas->GetTexturePtr("smoketrail");
	waketex         = textureAtlas->GetTexturePtr("wake");
	perlintex       = textureAtlas->GetTexturePtr("perlintex");
	flametex        = textureAtlas->GetTexturePtr("flame");

	for (int i = 0; i < smokeTexCount; i++) {
		const std::string smokeName = "ismoke" + IntToString(i, "%02i");
		const AtlasedTexture* smokeTex = textureAtlas->GetTexturePtr(smokeName);
		smoketex.push_back(smokeTex);
	}

#define GETTEX(t, b) (textureAtlas->GetTexturePtrWithBackup((t), (b)))
	sbtrailtex         = GETTEX("sbtrailtexture",         "smoketrail"    );
	missiletrailtex    = GETTEX("missiletrailtexture",    "smoketrail"    );
	muzzleflametex     = GETTEX("muzzleflametexture",     "explo"         );
	repulsetex         = GETTEX("repulsetexture",         "explo"         );
	dguntex            = GETTEX("dguntexture",            "flare"         );
	flareprojectiletex = GETTEX("flareprojectiletexture", "flare"         );
	sbflaretex         = GETTEX("sbflaretexture",         "flare"         );
	missileflaretex    = GETTEX("missileflaretexture",    "flare"         );
	beamlaserflaretex  = GETTEX("beamlaserflaretexture",  "flare"         );
	bubbletex          = GETTEX("bubbletexture",          "circularthingy");
	geosquaretex       = GETTEX("geosquaretexture",       "circularthingy");
	gfxtex             = GETTEX("gfxtexture",             "circularthingy");
	projectiletex      = GETTEX("projectiletexture",      "circularthingy");
	repulsegfxtex      = GETTEX("repulsegfxtexture",      "circularthingy");
	sphereparttex      = GETTEX("sphereparttexture",      "circularthingy");
	torpedotex         = GETTEX("torpedotexture",         "circularthingy");
	wrecktex           = GETTEX("wrecktexture",           "circularthingy");
	plasmatex          = GETTEX("plasmatexture",          "circularthingy");
#undef GETTEX


	if (!groundFXAtlas->Finalize()) {
		LOG_L(L_ERROR, "Could not finalize groundFX texture atlas. Use less/smaller textures.");
	}

	groundflashtex = groundFXAtlas->GetTexturePtr("groundflash");
	groundringtex = groundFXAtlas->GetTexturePtr("groundring");
	seismictex = groundFXAtlas->GetTexturePtr("seismic");

	for (int a = 0; a < 4; ++a) {
		perlinBlend[a] = 0.0f;
	}

	{
		unsigned char tempmem[4 * 16 * 16] = {0};

		for (int a = 0; a < 8; ++a) {
			glGenTextures(1, &perlinTex[a]);
			glBindTexture(GL_TEXTURE_2D, perlinTex[a]);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 16,16, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempmem);
		}
	}

	drawPerlinTex = false;

	if (perlinFB.IsValid()) {
		// we never refresh the full texture (just the perlin part). So we need to reload it then.
		perlinFB.reloadOnAltTab = true;

		perlinFB.Bind();
		perlinFB.AttachTexture(textureAtlas->gltex);
		drawPerlinTex = perlinFB.CheckStatus("PERLIN");
		perlinFB.Unbind();
	}


	modelRenderers.resize(MODELTYPE_OTHER, NULL);

	for (int modelType = MODELTYPE_3DO; modelType < MODELTYPE_OTHER; modelType++) {
		modelRenderers[modelType] = IWorldObjectModelRenderer::GetInstance(modelType);
	}
}
Exemple #8
0
void CUnitDefHandler::ParseUnitDefTable(const LuaTable& udTable, const string& unitName, int id)
{
	UnitDef& ud = unitDefs[id];

	// allocate and fill ud->unitImage
	ud.buildPicName = udTable.GetString("buildPic", "");

	ud.humanName = udTable.GetString("name", "");

	if (ud.humanName.empty()) {
		const string errmsg = "missing 'name' parameter for the " + unitName + " unitdef";
		throw content_error(errmsg);
	}
	ud.filename  = udTable.GetString("filename", "");
	if (ud.filename.empty()) {
		const string errmsg = "missing 'filename' parameter for the" + unitName + " unitdef";
		throw content_error(errmsg);
	}
	ud.tooltip = udTable.GetString("description", ud.name);

	const string decoy = udTable.GetString("decoyFor", "");
	if (!decoy.empty()) {
		decoyNameMap[ud.name] = StringToLower(decoy);
	}

	ud.gaia = udTable.GetString("gaia", "");

	ud.isCommander = udTable.GetBool("commander", false);

	if (ud.isCommander && gameSetup) {
		ud.metalStorage  = udTable.GetFloat("metalStorage",  gameSetup->startMetal);
		ud.energyStorage = udTable.GetFloat("energyStorage", gameSetup->startEnergy);
	} else {
		ud.metalStorage  = udTable.GetFloat("metalStorage",  0.0f);
		ud.energyStorage = udTable.GetFloat("energyStorage", 0.0f);
	}

	ud.extractsMetal  = udTable.GetFloat("extractsMetal",  0.0f);
	ud.windGenerator  = udTable.GetFloat("windGenerator",  0.0f);
	ud.tidalGenerator = udTable.GetFloat("tidalGenerator", 0.0f);

	ud.metalUpkeep  = udTable.GetFloat("metalUse",   0.0f);
	ud.energyUpkeep = udTable.GetFloat("energyUse",  0.0f);
	ud.metalMake    = udTable.GetFloat("metalMake",  0.0f);
	ud.makesMetal   = udTable.GetFloat("makesMetal", 0.0f);
	ud.energyMake   = udTable.GetFloat("energyMake", 0.0f);

	ud.health       = udTable.GetFloat("maxDamage",  0.0f);
	ud.autoHeal     = udTable.GetFloat("autoHeal",      0.0f) * (16.0f / GAME_SPEED);
	ud.idleAutoHeal = udTable.GetFloat("idleAutoHeal", 10.0f) * (16.0f / GAME_SPEED);
	ud.idleTime     = udTable.GetInt("idleTime", 600);

	ud.buildangle = udTable.GetInt("buildAngle", 0);

	ud.isMetalMaker = (ud.makesMetal >= 1 && ud.energyUpkeep > ud.makesMetal * 40);

	ud.controlRadius = 32;
	ud.losHeight = 20;
	ud.metalCost = udTable.GetFloat("buildCostMetal", 0.0f);
	if (ud.metalCost < 1.0f) {
		ud.metalCost = 1.0f; //avoid some nasty divide by 0 etc
	}
	ud.mass = udTable.GetFloat("mass", 0.0f);
	if (ud.mass <= 0.0f) {
		ud.mass=ud.metalCost;
	}
	ud.energyCost = udTable.GetFloat("buildCostEnergy", 0.0f);
	ud.buildTime = udTable.GetFloat("buildTime", 0.0f);
	if (ud.buildTime < 1.0f) {
		ud.buildTime = 1.0f; //avoid some nasty divide by 0 etc
	}

	ud.aihint = id; // FIXME? (as noted in SelectedUnits.cpp, aihint is ignored)
	ud.cobID = udTable.GetInt("cobID", -1);

	ud.losRadius = udTable.GetFloat("sightDistance", 0.0f) * modInfo.losMul / (SQUARE_SIZE * (1 << modInfo.losMipLevel));
	ud.airLosRadius = udTable.GetFloat("airSightDistance", -1.0f);
	if (ud.airLosRadius == -1.0f) {
		ud.airLosRadius=udTable.GetFloat("sightDistance", 0.0f) * modInfo.airLosMul * 1.5f / (SQUARE_SIZE * (1 << modInfo.airMipLevel));
	} else {
		ud.airLosRadius = ud.airLosRadius * modInfo.airLosMul / (SQUARE_SIZE * (1 << modInfo.airMipLevel));
	}

	ud.canSubmerge = udTable.GetBool("canSubmerge", false);
	ud.canfly      = udTable.GetBool("canFly",      false);
	ud.canmove     = udTable.GetBool("canMove",     false);
	ud.reclaimable = udTable.GetBool("reclaimable", true);
	ud.capturable  = udTable.GetBool("capturable",  true);
	ud.repairable  = udTable.GetBool("repairable",  true);
	ud.canAttack   = udTable.GetBool("canAttack",   true);
	ud.canFight    = udTable.GetBool("canFight",    true);
	ud.canPatrol   = udTable.GetBool("canPatrol",   true);
	ud.canGuard    = udTable.GetBool("canGuard",    true);
	ud.canRepeat   = udTable.GetBool("canRepeat",   true);

	ud.builder = udTable.GetBool("builder", true);

	ud.canRestore = udTable.GetBool("canRestore", ud.builder);
	ud.canRepair  = udTable.GetBool("canRepair",  ud.builder);
	ud.canReclaim = udTable.GetBool("canReclaim", ud.builder);
	ud.canAssist  = udTable.GetBool("canAssist",  ud.builder);

	ud.canBeAssisted = udTable.GetBool("canBeAssisted", true);
	ud.canSelfRepair = udTable.GetBool("canSelfRepair", false);
	ud.fullHealthFactory = udTable.GetBool("fullHealthFactory", false);
	ud.factoryHeadingTakeoff = udTable.GetBool("factoryHeadingTakeoff", true);

	ud.upright = udTable.GetBool("upright", false);
	ud.collide = udTable.GetBool("collide", true);
	ud.onoffable = udTable.GetBool("onoffable", false);

	ud.maxSlope = udTable.GetFloat("maxSlope", 0.0f);
	ud.maxHeightDif = 40 * tan(ud.maxSlope * (PI / 180));
	ud.maxSlope = cos(ud.maxSlope * (PI / 180));
	ud.minWaterDepth = udTable.GetFloat("minWaterDepth", -10e6f);
	ud.maxWaterDepth = udTable.GetFloat("maxWaterDepth", +10e6f);
	ud.minCollisionSpeed = udTable.GetFloat("minCollisionSpeed", 1.0f);
	ud.slideTolerance = udTable.GetFloat("slideTolerance", 0.0f); // disabled
	ud.pushResistant = udTable.GetBool("pushResistant", false);

	ud.waterline = udTable.GetFloat("waterline", 0.0f);
	if ((ud.waterline >= 5.0f) && ud.canmove) {
		// make subs travel at somewhat larger depths
		// to reduce vulnerability to surface weapons
		ud.waterline += 10.0f;
	}

	ud.canSelfD = udTable.GetBool("canSelfDestruct", true);
	ud.selfDCountdown = udTable.GetInt("selfDestructCountdown", 5);

	ud.speed  = udTable.GetFloat("maxVelocity",  0.0f) * GAME_SPEED;
	ud.rSpeed = udTable.GetFloat("maxReverseVelocity", 0.0f) * GAME_SPEED;
	ud.speed  = fabs(ud.speed);
	ud.rSpeed = fabs(ud.rSpeed);

	ud.maxAcc = fabs(udTable.GetFloat("acceleration", 0.5f)); // no negative values
	ud.maxDec = fabs(udTable.GetFloat("brakeRate",    3.0f * ud.maxAcc)) * (ud.canfly? 0.1f: 1.0f); // no negative values

	ud.turnRate    = udTable.GetFloat("turnRate",     0.0f);
	ud.turnInPlace = udTable.GetBool( "turnInPlace",  true);
	ud.turnInPlaceDistance = udTable.GetFloat("turnInPlaceDistance", 350.f);
	ud.turnInPlaceSpeedLimit = udTable.GetFloat("turnInPlaceSpeedLimit", 15.f);

	const bool noAutoFire  = udTable.GetBool("noAutoFire",  false);
	ud.canFireControl = udTable.GetBool("canFireControl", !noAutoFire);
	ud.fireState = udTable.GetInt("fireState", ud.canFireControl ? -1 : 2);
	ud.fireState = std::min(ud.fireState,2);
	ud.moveState = udTable.GetInt("moveState", (ud.canmove && ud.speed>0.0f)  ? -1 : 1);
	ud.moveState = std::min(ud.moveState,2);

	ud.buildRange3D = udTable.GetBool("buildRange3D", false);
	ud.buildDistance = udTable.GetFloat("buildDistance", 128.0f);
	ud.buildDistance = std::max(128.0f, ud.buildDistance);
	ud.buildSpeed = udTable.GetFloat("workerTime", 0.0f);

	ud.repairSpeed    = udTable.GetFloat("repairSpeed",    ud.buildSpeed);
	ud.maxRepairSpeed = udTable.GetFloat("maxRepairSpeed", 1e20f);
	ud.reclaimSpeed   = udTable.GetFloat("reclaimSpeed",   ud.buildSpeed);
	ud.resurrectSpeed = udTable.GetFloat("resurrectSpeed", ud.buildSpeed);
	ud.captureSpeed   = udTable.GetFloat("captureSpeed",   ud.buildSpeed);
	ud.terraformSpeed = udTable.GetFloat("terraformSpeed", ud.buildSpeed);

	ud.flankingBonusMode = udTable.GetInt("flankingBonusMode", modInfo.flankingBonusModeDefault);
	ud.flankingBonusMax  = udTable.GetFloat("flankingBonusMax", 1.9f);
	ud.flankingBonusMin  = udTable.GetFloat("flankingBonusMin", 0.9);
	ud.flankingBonusDir  = udTable.GetFloat3("flankingBonusDir", float3(0.0f, 0.0f, 1.0f));
	ud.flankingBonusMobilityAdd = udTable.GetFloat("flankingBonusMobilityAdd", 0.01f);

	ud.armoredMultiple = udTable.GetFloat("damageModifier", 1.0f);
	ud.armorType = damageArrayHandler->GetTypeFromName(ud.name);

	ud.radarRadius    = udTable.GetInt("radarDistance",    0);
	ud.sonarRadius    = udTable.GetInt("sonarDistance",    0);
	ud.jammerRadius   = udTable.GetInt("radarDistanceJam", 0);
	ud.sonarJamRadius = udTable.GetInt("sonarDistanceJam", 0);

	ud.stealth        = udTable.GetBool("stealth",            false);
	ud.sonarStealth   = udTable.GetBool("sonarStealth",       false);
	ud.targfac        = udTable.GetBool("isTargetingUpgrade", false);
	ud.isFeature      = udTable.GetBool("isFeature",          false);
	ud.canResurrect   = udTable.GetBool("canResurrect",       false);
	ud.canCapture     = udTable.GetBool("canCapture",         false);
	ud.hideDamage     = udTable.GetBool("hideDamage",         false);
	ud.showPlayerName = udTable.GetBool("showPlayerName",     false);

	ud.cloakCost = udTable.GetFloat("cloakCost", -1.0f);
	ud.cloakCostMoving = udTable.GetFloat("cloakCostMoving", -1.0f);
	if (ud.cloakCostMoving < 0) {
		ud.cloakCostMoving = ud.cloakCost;
	}
	ud.canCloak = (ud.cloakCost >= 0);

	ud.startCloaked     = udTable.GetBool("initCloaked", false);
	ud.decloakDistance  = udTable.GetFloat("minCloakDistance", 0.0f);
	ud.decloakSpherical = udTable.GetBool("decloakSpherical", true);
	ud.decloakOnFire    = udTable.GetBool("decloakOnFire",    true);

	ud.highTrajectoryType = udTable.GetInt("highTrajectory", 0);

	ud.canKamikaze = udTable.GetBool("kamikaze", false);
	ud.kamikazeDist = udTable.GetFloat("kamikazeDistance", -25.0f) + 25.0f; //we count 3d distance while ta count 2d distance so increase slightly

	ud.showNanoFrame = udTable.GetBool("showNanoFrame", true);
	ud.showNanoSpray = udTable.GetBool("showNanoSpray", true);
	ud.nanoColor = udTable.GetFloat3("nanoColor", float3(0.2f,0.7f,0.2f));

	ud.canhover = udTable.GetBool("canHover", false);

	ud.floater = udTable.GetBool("floater", udTable.KeyExists("WaterLine"));

	ud.builder = udTable.GetBool("builder", false);
	if (ud.builder && !ud.buildSpeed) { // core anti is flagged as builder for some reason
		ud.builder = false;
	}

	ud.airStrafe     = udTable.GetBool("airStrafe", true);
	ud.hoverAttack   = udTable.GetBool("hoverAttack", false);
	ud.wantedHeight  = udTable.GetFloat("cruiseAlt", 0.0f);
	ud.dlHoverFactor = udTable.GetFloat("airHoverFactor", -1.0f);
	ud.bankingAllowed = udTable.GetBool("bankingAllowed", true);

	ud.transportSize     = udTable.GetInt("transportSize",      0);
	ud.minTransportSize  = udTable.GetInt("minTransportSize",   0);
	ud.transportCapacity = udTable.GetInt("transportCapacity",  0);
	ud.isFirePlatform    = udTable.GetBool("isFirePlatform",    false);
	ud.isAirBase         = udTable.GetBool("isAirBase",         false);
	ud.loadingRadius     = udTable.GetFloat("loadingRadius",    220.0f);
	ud.unloadSpread      = udTable.GetFloat("unloadSpread",     1.0f);
	ud.transportMass     = udTable.GetFloat("transportMass",    100000.0f);
	ud.minTransportMass  = udTable.GetFloat("minTransportMass", 0.0f);
	ud.holdSteady        = udTable.GetBool("holdSteady",        true);
	ud.releaseHeld       = udTable.GetBool("releaseHeld",       false);
	ud.cantBeTransported = udTable.GetBool("cantBeTransported", false);
	ud.transportByEnemy  = udTable.GetBool("transportByEnemy",  true);
	ud.fallSpeed         = udTable.GetFloat("fallSpeed",    0.2);
	ud.unitFallSpeed     = udTable.GetFloat("unitFallSpeed",  0);
	ud.transportUnloadMethod	= udTable.GetInt("transportUnloadMethod" , 0);

	// modrules transport settings
	if ((!modInfo.transportAir    && ud.canfly)   ||
	    (!modInfo.transportShip   && ud.floater)  ||
	    (!modInfo.transportHover  && ud.canhover) ||
	    (!modInfo.transportGround && !ud.canhover && !ud.floater && !ud.canfly)) {
 		ud.cantBeTransported = true;
	}

	ud.wingDrag     = udTable.GetFloat("wingDrag",     0.07f);  // drag caused by wings
	ud.wingDrag = std::min(1.0f, std::max(0.0f, ud.wingDrag));
	ud.wingAngle    = udTable.GetFloat("wingAngle",    0.08f);  // angle between front and the wing plane
	ud.frontToSpeed = udTable.GetFloat("frontToSpeed", 0.1f);   // fudge factor for lining up speed and front of plane
	ud.speedToFront = udTable.GetFloat("speedToFront", 0.07f);  // fudge factor for lining up speed and front of plane
	ud.myGravity    = udTable.GetFloat("myGravity",    0.4f);   // planes are slower than real airplanes so lower gravity to compensate
	ud.crashDrag    = udTable.GetFloat("crashDrag",0.005f);     // drag used when crashing
	ud.crashDrag = std::min(1.0f, std::max(0.0f, ud.crashDrag));

	ud.maxBank = udTable.GetFloat("maxBank", 0.8f);         // max roll
	ud.maxPitch = udTable.GetFloat("maxPitch", 0.45f);      // max pitch this plane tries to keep
	ud.turnRadius = udTable.GetFloat("turnRadius", 500.0f); // hint to the ai about how large turn radius this plane needs
	ud.verticalSpeed = udTable.GetFloat("verticalSpeed", 3.0f); // speed of takeoff and landing, at least for gunships

	ud.maxAileron  = udTable.GetFloat("maxAileron",  0.015f); // turn speed around roll axis
	ud.maxElevator = udTable.GetFloat("maxElevator", 0.01f);  // turn speed around pitch axis
	ud.maxRudder   = udTable.GetFloat("maxRudder",   0.004f); // turn speed around yaw axis

	ud.maxFuel = udTable.GetFloat("maxFuel", 0.0f); //max flight time in seconds before aircraft must return to base
	ud.refuelTime = udTable.GetFloat("refuelTime", 5.0f);
	ud.minAirBasePower = udTable.GetFloat("minAirBasePower", 0.0f);
	ud.maxThisUnit = udTable.GetInt("unitRestricted", MAX_UNITS);

	string lname = StringToLower(ud.name);

	if (gameSetup->restrictedUnits.find(lname) != gameSetup->restrictedUnits.end()) {
		ud.maxThisUnit = std::min(ud.maxThisUnit, gameSetup->restrictedUnits.find(lname)->second);
	}

	ud.categoryString = udTable.GetString("category", "");
	ud.category = CCategoryHandler::Instance()->GetCategories(udTable.GetString("category", ""));
	ud.noChaseCategory = CCategoryHandler::Instance()->GetCategories(udTable.GetString("noChaseCategory", ""));
//	logOutput.Print("Unit %s has cat %i",ud.humanName.c_str(),ud.category);

	const string iconName = udTable.GetString("iconType", "default");
	ud.iconType = iconHandler->GetIcon(iconName);

	ud.shieldWeaponDef    = NULL;
	ud.stockpileWeaponDef = NULL;

	ud.maxWeaponRange = 0.0f;
	ud.maxCoverage = 0.0f;

	const WeaponDef* noWeaponDef = weaponDefHandler->GetWeapon("NOWEAPON");

	LuaTable weaponsTable = udTable.SubTable("weapons");
	for (int w = 0; w < COB_MaxWeapons; w++) {
		LuaTable wTable;
		string name = weaponsTable.GetString(w + 1, "");
		if (name.empty()) {
			wTable = weaponsTable.SubTable(w + 1);
			name = wTable.GetString("name", "");
		}
		const WeaponDef* wd = NULL;
		if (!name.empty()) {
			wd = weaponDefHandler->GetWeapon(name);
		}
		if (wd == NULL) {
			if (w <= 3) {
				continue; // allow empty weapons among the first 3
			} else {
				break;
			}
		}

		while (ud.weapons.size() < w) {
			if (!noWeaponDef) {
				logOutput.Print("Error: Spring requires a NOWEAPON weapon type "
				                "to be present as a placeholder for missing weapons");
				break;
			} else {
				ud.weapons.push_back(UnitDef::UnitDefWeapon());
				ud.weapons.back().def = noWeaponDef;
			}
		}

		const string badTarget = wTable.GetString("badTargetCategory", "");
		unsigned int btc = CCategoryHandler::Instance()->GetCategories(badTarget);

		const string onlyTarget = wTable.GetString("onlyTargetCategory", "");
		unsigned int otc;
		if (onlyTarget.empty()) {
			otc = 0xffffffff;
		} else {
			otc = CCategoryHandler::Instance()->GetCategories(onlyTarget);
		}

		const unsigned int slaveTo = wTable.GetInt("slaveTo", 0);

		float3 mainDir = wTable.GetFloat3("mainDir", float3(1.0f, 0.0f, 0.0f));
		mainDir.SafeNormalize();

		const float angleDif = cos(wTable.GetFloat("maxAngleDif", 360.0f) * (PI / 360.0f));

		const float fuelUse = wTable.GetFloat("fuelUsage", 0.0f);

		ud.weapons.push_back(UnitDef::UnitDefWeapon(name, wd, slaveTo, mainDir,
		                                            angleDif, btc, otc, fuelUse));

		if (wd->range > ud.maxWeaponRange) {
			ud.maxWeaponRange = wd->range;
		}
		if (wd->interceptor && wd->coverageRange > ud.maxCoverage) {
			ud.maxCoverage = wd->coverageRange;
		}
		if (wd->isShield) {
			if (!ud.shieldWeaponDef || // use the biggest shield
			    (ud.shieldWeaponDef->shieldRadius < wd->shieldRadius)) {
				ud.shieldWeaponDef = wd;
			}
		}
		if (wd->stockpile) {
			// interceptors have priority
			if (wd->interceptor        ||
			    !ud.stockpileWeaponDef ||
			    !ud.stockpileWeaponDef->interceptor) {
				ud.stockpileWeaponDef = wd;
			}
		}
	}

	ud.canDGun = udTable.GetBool("canDGun", false);

	string TEDClass = udTable.GetString("TEDClass", "0");
	ud.TEDClassString = TEDClass;

	ud.extractRange = 0.0f;
	ud.extractSquare = udTable.GetBool("extractSquare", false);

	if (ud.extractsMetal) {
		ud.extractRange = mapInfo->map.extractorRadius;
		ud.type = "MetalExtractor";
	}
	else if (ud.transportCapacity) {
		ud.type = "Transport";
	}
	else if (ud.builder) {
		if (TEDClass != "PLANT") {
			ud.type = "Builder";
		} else {
			ud.type = "Factory";
		}
	}
	else if (ud.canfly && !ud.hoverAttack) {
		if (!ud.weapons.empty() && (ud.weapons[0].def != 0) &&
		   (ud.weapons[0].def->type=="AircraftBomb" || ud.weapons[0].def->type=="TorpedoLauncher")) {
			ud.type = "Bomber";
			if (ud.turnRadius == 500) { // only reset it if user hasnt set it explicitly
				ud.turnRadius = 1000;     // hint to the ai about how large turn radius this plane needs
			}
		} else {
			ud.type = "Fighter";
		}
		ud.maxAcc = udTable.GetFloat("maxAcc", 0.065f); // engine power
	}
	else if (ud.canmove) {
		ud.type = "GroundUnit";
	}
	else {
		ud.type = "Building";
	}

	ud.movedata = 0;
	if (ud.canmove && !ud.canfly && (ud.type != "Factory")) {
		string moveclass = StringToLower(udTable.GetString("movementClass", ""));
		ud.movedata = moveinfo->GetMoveDataFromName(moveclass);

		if (!ud.movedata) {
			const string errmsg = "WARNING: Couldn't find a MoveClass named " + moveclass + " (used in UnitDef: " + unitName + ")";
			logOutput.Print(errmsg);
			// remove the UnitDef
			throw content_error(errmsg);
		}

		if ((ud.movedata->moveType == MoveData::Hover_Move) ||
		    (ud.movedata->moveType == MoveData::Ship_Move)) {
			ud.upright = true;
		}
		if (ud.canhover) {
			if (ud.movedata->moveType != MoveData::Hover_Move) {
				logOutput.Print("Inconsistent movedata %i for %s (moveclass %s): canhover, but not a hovercraft movetype",
				     ud.movedata->pathType, ud.name.c_str(), moveclass.c_str());
			}
		} else if (ud.floater) {
			if (ud.movedata->moveType != MoveData::Ship_Move) {
				logOutput.Print("Inconsistent movedata %i for %s (moveclass %s): floater, but not a ship movetype",
				     ud.movedata->pathType, ud.name.c_str(), moveclass.c_str());
			}
		} else {
			if (ud.movedata->moveType != MoveData::Ground_Move) {
				logOutput.Print("Inconsistent movedata %i for %s (moveclass %s): neither canhover nor floater, but not a ground movetype",
				     ud.movedata->pathType, ud.name.c_str(), moveclass.c_str());
			}
		}
	}

	if ((ud.maxAcc != 0) && (ud.speed != 0)) {
		//meant to set the drag such that the maxspeed becomes what it should be
		ud.drag = 1.0f / (ud.speed/GAME_SPEED * 1.1f / ud.maxAcc)
		          - (ud.wingAngle * ud.wingAngle * ud.wingDrag);
		ud.drag = std::min(1.0f, std::max(0.0f, ud.drag));
	} else {
		//shouldn't be needed since drag is only used in CAirMoveType anyway,
		//and aircraft without acceleration or speed aren't common :)
		//initializing it anyway just for safety
		ud.drag = 0.005f;
	}

	std::string objectname = udTable.GetString("objectName", "");
	if (objectname.find(".") == std::string::npos) {
		objectname += ".3do";
	}
	ud.modelDef.modelpath = "objects3d/" + objectname;
	ud.modelDef.modelname = objectname;

	ud.scriptName = udTable.GetString("script", unitName + ".cob");
	ud.scriptPath = "scripts/" + ud.scriptName;

	ud.wreckName = udTable.GetString("corpse", "");
	ud.deathExplosion = udTable.GetString("explodeAs", "");
	ud.selfDExplosion = udTable.GetString("selfDestructAs", "");

	ud.power = udTable.GetFloat("power", (ud.metalCost + (ud.energyCost / 60.0f)));

	// Prevent a division by zero in experience calculations.
	if (ud.power < 1.0e-3f) {
		logOutput.Print("Unit %s is really cheap? %f", ud.humanName.c_str(), ud.power);
		logOutput.Print("This can cause a division by zero in experience calculations.");
		ud.power = 1.0e-3f;
	}

	ud.activateWhenBuilt = udTable.GetBool("activateWhenBuilt", false);

	// TA has only half our res so multiply size with 2
	ud.xsize = udTable.GetInt("footprintX", 1) * 2;
	ud.zsize = udTable.GetInt("footprintZ", 1) * 2;

	ud.needGeo = false;
	if ((ud.type == "Building") || (ud.type == "Factory")) {
		CreateYardMap(&ud, udTable.GetString("yardMap", "c"));
	} else {
		for (int u = 0; u < 4; u++) {
			ud.yardmaps[u] = 0;
		}
	}

	ud.leaveTracks   = udTable.GetBool("leaveTracks", false);
	ud.trackWidth    = udTable.GetFloat("trackWidth",   32.0f);
	ud.trackOffset   = udTable.GetFloat("trackOffset",   0.0f);
	ud.trackStrength = udTable.GetFloat("trackStrength", 0.0f);
	ud.trackStretch  = udTable.GetFloat("trackStretch",  1.0f);
	if (ud.leaveTracks && groundDecals) {
		ud.trackType = groundDecals->GetTrackType(udTable.GetString("trackType", "StdTank"));
	}

	ud.useBuildingGroundDecal = udTable.GetBool("useBuildingGroundDecal", false);
	ud.buildingDecalSizeX = udTable.GetInt("buildingGroundDecalSizeX", 4);
	ud.buildingDecalSizeY = udTable.GetInt("buildingGroundDecalSizeY", 4);
	ud.buildingDecalDecaySpeed = udTable.GetFloat("buildingGroundDecalDecaySpeed", 0.1f);
	if (ud.useBuildingGroundDecal && groundDecals) {
		ud.buildingDecalType = groundDecals->GetBuildingDecalType(udTable.GetString("buildingGroundDecalType", ""));
	}

	ud.canDropFlare    = udTable.GetBool("canDropFlare", false);
	ud.flareReloadTime = udTable.GetFloat("flareReload",     5.0f);
	ud.flareDelay      = udTable.GetFloat("flareDelay",      0.3f);
	ud.flareEfficiency = udTable.GetFloat("flareEfficiency", 0.5f);
	ud.flareDropVector = udTable.GetFloat3("flareDropVector", ZeroVector);
	ud.flareTime       = udTable.GetInt("flareTime", 3) * GAME_SPEED;
	ud.flareSalvoSize  = udTable.GetInt("flareSalvoSize",  4);
	ud.flareSalvoDelay = udTable.GetInt("flareSalvoDelay", 0) * GAME_SPEED;

	ud.smoothAnim = udTable.GetBool("smoothAnim", false);
	ud.canLoopbackAttack = udTable.GetBool("canLoopbackAttack", false);
	ud.canCrash = udTable.GetBool("canCrash", true);
	ud.levelGround = udTable.GetBool("levelGround", true);
	ud.strafeToAttack = udTable.GetBool("strafeToAttack", false);


	ud.modelCenterOffset = udTable.GetFloat3("modelCenterOffset", ZeroVector);

	ud.collisionVolumeTypeStr   = udTable.GetString("collisionVolumeType", "");
	ud.collisionVolumeScales    = udTable.GetFloat3("collisionVolumeScales", ZeroVector);
	ud.collisionVolumeOffsets   = udTable.GetFloat3("collisionVolumeOffsets", ZeroVector);
	ud.collisionVolumeTest      = udTable.GetInt("collisionVolumeTest", COLVOL_TEST_DISC);
	ud.usePieceCollisionVolumes = udTable.GetBool("usePieceCollisionVolumes", false);

	// initialize the (per-unitdef) collision-volume
	// all CUnit instances hold a copy of this object
	ud.collisionVolume = new CollisionVolume(
		ud.collisionVolumeTypeStr,
		ud.collisionVolumeScales,
		ud.collisionVolumeOffsets,
		ud.collisionVolumeTest
	);

	if (ud.usePieceCollisionVolumes) {
		ud.collisionVolume->Disable();
	}


	ud.seismicRadius    = udTable.GetInt("seismicDistance", 0);
	ud.seismicSignature = udTable.GetFloat("seismicSignature", -1.0f);
	if (ud.seismicSignature == -1.0f) {
		if (!ud.floater && !ud.canhover && !ud.canfly) {
			ud.seismicSignature = sqrt(ud.mass / 100.0f);
		} else {
			ud.seismicSignature = 0.0f;
		}
	}

	LuaTable buildsTable = udTable.SubTable("buildOptions");
	if (buildsTable.IsValid()) {
		for (int bo = 1; true; bo++) {
			const string order = buildsTable.GetString(bo, "");
			if (order.empty()) {
				break;
			}
			ud.buildOptions[bo] = order;
		}
	}

	LuaTable sfxTable = udTable.SubTable("SFXTypes");
	LuaTable expTable = sfxTable.SubTable("explosionGenerators");
	for (int expNum = 1; expNum <= 1024; expNum++) {
		string expsfx = expTable.GetString(expNum, "");
		if (expsfx == "") {
			break;
		} else {
			ud.sfxExplGens.push_back(explGenHandler->LoadGenerator(expsfx));
		}
	}

	// we use range in a modulo operation, so it needs to be >= 1
	ud.pieceTrailCEGTag = udTable.GetString("pieceTrailCEGTag", "");
	ud.pieceTrailCEGRange = udTable.GetInt("pieceTrailCEGRange", 1);
	ud.pieceTrailCEGRange = std::max(ud.pieceTrailCEGRange, 1);

	LuaTable soundsTable = udTable.SubTable("sounds");

	LoadSounds(soundsTable, ud.sounds.ok,          "ok");      // eg. "ok1", "ok2", ...
	LoadSounds(soundsTable, ud.sounds.select,      "select");  // eg. "select1", "select2", ...
	LoadSounds(soundsTable, ud.sounds.arrived,     "arrived"); // eg. "arrived1", "arrived2", ...
	LoadSounds(soundsTable, ud.sounds.build,       "build");
	LoadSounds(soundsTable, ud.sounds.activate,    "activate");
	LoadSounds(soundsTable, ud.sounds.deactivate,  "deactivate");
	LoadSounds(soundsTable, ud.sounds.cant,        "cant");
	LoadSounds(soundsTable, ud.sounds.underattack, "underattack");

	// custom parameters table
	udTable.SubTable("customParams").GetMap(ud.customParams);
}
Exemple #9
0
CUnitDefHandler::CUnitDefHandler(void) : noCost(false)
{
	weaponDefHandler = new CWeaponDefHandler();

	PrintLoadMsg("Loading unit definitions");

	const LuaTable rootTable = game->defsParser->GetRoot().SubTable("UnitDefs");
	if (!rootTable.IsValid()) {
		throw content_error("Error loading UnitDefs");
	}

	vector<string> unitDefNames;
	rootTable.GetKeys(unitDefNames);

	numUnitDefs = unitDefNames.size();

	/*
	// ?? "restricted" does not automatically mean "cannot be built
	// at all, so we don't need the unitdef for this unit" -- Kloot
	numUnitDefs -= gameSetup->restrictedUnits.size();
	*/

	// This could be wasteful if there is a lot of restricted units, but that is not that likely
	unitDefs = new UnitDef[numUnitDefs + 1];

	// start at unitdef id 1
	unsigned int id = 1;

	for (unsigned int a = 0; a < unitDefNames.size(); ++a) {
		const string unitName = unitDefNames[a];

		/*
		// Restrictions may tell us not to use this unit at all
		// FIXME: causes mod errors when a unit is restricted to
		// 0, since GetUnitByName() will return NULL if its UnitDef
		// has not been loaded -- Kloot
		const std::map<std::string, int>& resUnits = gameSetup->restrictedUnits;

		if ((resUnits.find(unitName) != resUnits.end()) &&
			(resUnits.find(unitName)->second == 0)) {
			continue;
		}
		*/

		// Seems ok, load it
		unitDefs[id].valid = false;
		unitDefs[id].name = unitName;
		unitDefs[id].id = id;
		unitDefs[id].buildangle = 0;
		unitDefs[id].buildPic   = NULL;
		unitDefs[id].decoyDef   = NULL;
		unitDefs[id].techLevel  = -1;
		unitDefs[id].collisionVolume = NULL;
		unitID[unitName] = id;
		for (int ym = 0; ym < 4; ym++) {
			unitDefs[id].yardmaps[ym] = 0;
		}

		// parse the unitdef data (but don't load buildpics, etc...)
		LuaTable udTable = rootTable.SubTable(unitName);
		ParseUnitDef(udTable, unitName, id);

		// Increase index for next unit
		id++;
	}

	// set the real number of unitdefs
	numUnitDefs = (id - 1);

	CleanBuildOptions();
	FindStartUnits();
	ProcessDecoys();
	AssignTechLevels();
}
Exemple #10
0
UnitDef::UnitDef(const LuaTable& udTable, const std::string& unitName, int id)
: name(unitName)
, id(id)
, collisionVolume(NULL)
, decoyDef(NULL)
, techLevel(-1)
, buildPic(NULL)
, buildangle(0)
{
	humanName = udTable.GetString("name", "");
	if (humanName.empty()) {
		const string errmsg = "missing 'name' parameter for the " + unitName + " unitdef";
		throw content_error(errmsg);
	}
	filename  = udTable.GetString("filename", "");
	if (filename.empty()) {
		const string errmsg = "missing 'filename' parameter for the" + unitName + " unitdef";
		throw content_error(errmsg);
	}
	tooltip = udTable.GetString("description", name);
	buildPicName = udTable.GetString("buildPic", "");

	decoyName = udTable.GetString("decoyFor", "");
	gaia = udTable.GetString("gaia", "");

	isCommander = udTable.GetBool("commander", false);

	metalStorage  = udTable.GetFloat("metalStorage",  0.0f);
	energyStorage = udTable.GetFloat("energyStorage", 0.0f);

	extractsMetal  = udTable.GetFloat("extractsMetal",  0.0f);
	windGenerator  = udTable.GetFloat("windGenerator",  0.0f);
	tidalGenerator = udTable.GetFloat("tidalGenerator", 0.0f);

	metalUpkeep  = udTable.GetFloat("metalUse",   0.0f);
	energyUpkeep = udTable.GetFloat("energyUse",  0.0f);
	metalMake    = udTable.GetFloat("metalMake",  0.0f);
	makesMetal   = udTable.GetFloat("makesMetal", 0.0f);
	energyMake   = udTable.GetFloat("energyMake", 0.0f);

	health       = udTable.GetFloat("maxDamage",  0.0f);
	autoHeal     = udTable.GetFloat("autoHeal",      0.0f) * (16.0f / GAME_SPEED);
	idleAutoHeal = udTable.GetFloat("idleAutoHeal", 10.0f) * (16.0f / GAME_SPEED);
	idleTime     = udTable.GetInt("idleTime", 600);

	buildangle = udTable.GetInt("buildAngle", 0);

	losHeight = 20;
	metalCost = udTable.GetFloat("buildCostMetal", 0.0f);
	if (metalCost < 1.0f) {
		metalCost = 1.0f; //avoid some nasty divide by 0 etc
	}
	mass = udTable.GetFloat("mass", 0.0f);
	if (mass <= 0.0f) {
		mass = metalCost;
	}
	energyCost = udTable.GetFloat("buildCostEnergy", 0.0f);
	buildTime = udTable.GetFloat("buildTime", 0.0f);
	if (buildTime < 1.0f) {
		buildTime = 1.0f; //avoid some nasty divide by 0 etc
	}

	aihint = id; // FIXME? (as noted in SelectedUnits.cpp, aihint is ignored)
	cobID = udTable.GetInt("cobID", -1);

	losRadius = udTable.GetFloat("sightDistance", 0.0f) * modInfo.losMul / (SQUARE_SIZE * (1 << modInfo.losMipLevel));
	airLosRadius = udTable.GetFloat("airSightDistance", -1.0f);
	if (airLosRadius == -1.0f) {
		airLosRadius = udTable.GetFloat("sightDistance", 0.0f) * modInfo.airLosMul * 1.5f / (SQUARE_SIZE * (1 << modInfo.airMipLevel));
	} else {
		airLosRadius = airLosRadius * modInfo.airLosMul / (SQUARE_SIZE * (1 << modInfo.airMipLevel));
	}

	canSubmerge = udTable.GetBool("canSubmerge", false);
	canfly      = udTable.GetBool("canFly",      false);
	canmove     = udTable.GetBool("canMove",     false);
	reclaimable = udTable.GetBool("reclaimable", true);
	capturable  = udTable.GetBool("capturable",  true);
	repairable  = udTable.GetBool("repairable",  true);
	canAttack   = udTable.GetBool("canAttack",   true);
	canFight    = udTable.GetBool("canFight",    true);
	canPatrol   = udTable.GetBool("canPatrol",   true);
	canGuard    = udTable.GetBool("canGuard",    true);
	canRepeat   = udTable.GetBool("canRepeat",   true);

	builder = udTable.GetBool("builder", false);

	canRestore = udTable.GetBool("canRestore", builder);
	canRepair  = udTable.GetBool("canRepair",  builder);
	canReclaim = udTable.GetBool("canReclaim", builder);
	canAssist  = udTable.GetBool("canAssist",  builder);

	canBeAssisted = udTable.GetBool("canBeAssisted", true);
	canSelfRepair = udTable.GetBool("canSelfRepair", false);
	fullHealthFactory = udTable.GetBool("fullHealthFactory", false);
	factoryHeadingTakeoff = udTable.GetBool("factoryHeadingTakeoff", true);

	upright = udTable.GetBool("upright", false);
	collide = udTable.GetBool("collide", true);
	onoffable = udTable.GetBool("onoffable", false);

	maxSlope = Clamp(udTable.GetFloat("maxSlope", 0.0f), 0.0f, 89.0f);
	maxHeightDif = 40 * tan(maxSlope * (PI / 180));
	maxSlope = cos(maxSlope * (PI / 180));
	minWaterDepth = udTable.GetFloat("minWaterDepth", -10e6f);
	maxWaterDepth = udTable.GetFloat("maxWaterDepth", +10e6f);
	minCollisionSpeed = udTable.GetFloat("minCollisionSpeed", 1.0f);
	slideTolerance = udTable.GetFloat("slideTolerance", 0.0f); // disabled
	pushResistant = udTable.GetBool("pushResistant", false);

	waterline = udTable.GetFloat("waterline", 0.0f);
	if ((waterline >= 5.0f) && canmove) {
		// make subs travel at somewhat larger depths
		// to reduce vulnerability to surface weapons
		waterline += 10.0f;
	}

	canSelfD = udTable.GetBool("canSelfDestruct", true);
	selfDCountdown = udTable.GetInt("selfDestructCountdown", 5);

	speed  = udTable.GetFloat("maxVelocity",  0.0f) * GAME_SPEED;
	rSpeed = udTable.GetFloat("maxReverseVelocity", 0.0f) * GAME_SPEED;
	speed  = fabs(speed);
	rSpeed = fabs(rSpeed);

	maxAcc = fabs(udTable.GetFloat("acceleration", 0.5f)); // no negative values
	maxDec = fabs(udTable.GetFloat("brakeRate",    3.0f * maxAcc)) * (canfly? 0.1f: 1.0f); // no negative values

	turnRate    = udTable.GetFloat("turnRate",     0.0f);
	turnInPlace = udTable.GetBool( "turnInPlace",  true);
	turnInPlaceDistance = udTable.GetFloat("turnInPlaceDistance", 350.f);
	turnInPlaceSpeedLimit = udTable.GetFloat("turnInPlaceSpeedLimit", (speed / GAME_SPEED) * 0.2f);

	const bool noAutoFire  = udTable.GetBool("noAutoFire",  false);
	canFireControl = udTable.GetBool("canFireControl", !noAutoFire);
	fireState = udTable.GetInt("fireState", canFireControl ? -1 : 2);
	fireState = std::min(fireState,2);
	moveState = udTable.GetInt("moveState", (canmove && speed>0.0f)  ? -1 : 1);
	moveState = std::min(moveState,2);

	buildRange3D = udTable.GetBool("buildRange3D", false);
	buildDistance = udTable.GetFloat("buildDistance", 128.0f);
	buildDistance = std::max(128.0f, buildDistance);
	buildSpeed = udTable.GetFloat("workerTime", 0.0f);

	repairSpeed    = udTable.GetFloat("repairSpeed",    buildSpeed);
	maxRepairSpeed = udTable.GetFloat("maxRepairSpeed", 1e20f);
	reclaimSpeed   = udTable.GetFloat("reclaimSpeed",   buildSpeed);
	resurrectSpeed = udTable.GetFloat("resurrectSpeed", buildSpeed);
	captureSpeed   = udTable.GetFloat("captureSpeed",   buildSpeed);
	terraformSpeed = udTable.GetFloat("terraformSpeed", buildSpeed);

	flankingBonusMode = udTable.GetInt("flankingBonusMode", modInfo.flankingBonusModeDefault);
	flankingBonusMax  = udTable.GetFloat("flankingBonusMax", 1.9f);
	flankingBonusMin  = udTable.GetFloat("flankingBonusMin", 0.9);
	flankingBonusDir  = udTable.GetFloat3("flankingBonusDir", float3(0.0f, 0.0f, 1.0f));
	flankingBonusMobilityAdd = udTable.GetFloat("flankingBonusMobilityAdd", 0.01f);

	armoredMultiple = udTable.GetFloat("damageModifier", 1.0f);
	armorType = damageArrayHandler->GetTypeFromName(name);

	radarRadius    = udTable.GetInt("radarDistance",    0);
	sonarRadius    = udTable.GetInt("sonarDistance",    0);
	jammerRadius   = udTable.GetInt("radarDistanceJam", 0);
	sonarJamRadius = udTable.GetInt("sonarDistanceJam", 0);

	stealth        = udTable.GetBool("stealth",            false);
	sonarStealth   = udTable.GetBool("sonarStealth",       false);
	targfac        = udTable.GetBool("isTargetingUpgrade", false);
	isFeature      = udTable.GetBool("isFeature",          false);
	canResurrect   = udTable.GetBool("canResurrect",       false);
	canCapture     = udTable.GetBool("canCapture",         false);
	hideDamage     = udTable.GetBool("hideDamage",         false);
	showPlayerName = udTable.GetBool("showPlayerName",     false);

	cloakCost = udTable.GetFloat("cloakCost", -1.0f);
	cloakCostMoving = udTable.GetFloat("cloakCostMoving", -1.0f);
	if (cloakCostMoving < 0) {
		cloakCostMoving = cloakCost;
	}
	canCloak = (cloakCost >= 0);

	startCloaked     = udTable.GetBool("initCloaked", false);
	decloakDistance  = udTable.GetFloat("minCloakDistance", 0.0f);
	decloakSpherical = udTable.GetBool("decloakSpherical", true);
	decloakOnFire    = udTable.GetBool("decloakOnFire",    true);
	cloakTimeout     = udTable.GetInt("cloakTimeout", 128);

	highTrajectoryType = udTable.GetInt("highTrajectory", 0);

	canKamikaze = udTable.GetBool("kamikaze", false);
	kamikazeDist = udTable.GetFloat("kamikazeDistance", -25.0f) + 25.0f; //we count 3d distance while ta count 2d distance so increase slightly
	kamikazeUseLOS = udTable.GetBool("kamikazeUseLOS", false);

	showNanoFrame = udTable.GetBool("showNanoFrame", true);
	showNanoSpray = udTable.GetBool("showNanoSpray", true);
	nanoColor = udTable.GetFloat3("nanoColor", float3(0.2f,0.7f,0.2f));

	canhover = udTable.GetBool("canHover", false);

	floater = udTable.GetBool("floater", udTable.KeyExists("WaterLine"));

	if (builder && !buildSpeed) { // core anti is flagged as builder for some reason
		builder = false;
	}

	airStrafe      = udTable.GetBool("airStrafe", true);
	hoverAttack    = udTable.GetBool("hoverAttack", false);
	wantedHeight   = udTable.GetFloat("cruiseAlt", 0.0f);
	dlHoverFactor  = udTable.GetFloat("airHoverFactor", -1.0f);
	bankingAllowed = udTable.GetBool("bankingAllowed", true);
	useSmoothMesh  = udTable.GetBool("useSmoothMesh", true);

	transportSize     = udTable.GetInt("transportSize",      0);
	minTransportSize  = udTable.GetInt("minTransportSize",   0);
	transportCapacity = udTable.GetInt("transportCapacity",  0);
	isFirePlatform    = udTable.GetBool("isFirePlatform",    false);
	isAirBase         = udTable.GetBool("isAirBase",         false);
	loadingRadius     = udTable.GetFloat("loadingRadius",    220.0f);
	unloadSpread      = udTable.GetFloat("unloadSpread",     1.0f);
	transportMass     = udTable.GetFloat("transportMass",    100000.0f);
	minTransportMass  = udTable.GetFloat("minTransportMass", 0.0f);
	holdSteady        = udTable.GetBool("holdSteady",        false);
	releaseHeld       = udTable.GetBool("releaseHeld",       false);
	cantBeTransported = udTable.GetBool("cantBeTransported", false);
	transportByEnemy  = udTable.GetBool("transportByEnemy",  true);
	fallSpeed         = udTable.GetFloat("fallSpeed",    0.2);
	unitFallSpeed     = udTable.GetFloat("unitFallSpeed",  0);
	transportUnloadMethod	= udTable.GetInt("transportUnloadMethod" , 0);

	// modrules transport settings
	if ((!modInfo.transportAir    && canfly)   ||
	    (!modInfo.transportShip   && floater)  ||
	    (!modInfo.transportHover  && canhover) ||
	    (!modInfo.transportGround && !canhover && !floater && !canfly)) {
 		cantBeTransported = true;
	}

	wingDrag     = udTable.GetFloat("wingDrag",     0.07f);  // drag caused by wings
	wingDrag     = Clamp(wingDrag, 0.0f, 1.0f);
	wingAngle    = udTable.GetFloat("wingAngle",    0.08f);  // angle between front and the wing plane
	frontToSpeed = udTable.GetFloat("frontToSpeed", 0.1f);   // fudge factor for lining up speed and front of plane
	speedToFront = udTable.GetFloat("speedToFront", 0.07f);  // fudge factor for lining up speed and front of plane
	myGravity    = udTable.GetFloat("myGravity",    0.4f);   // planes are slower than real airplanes so lower gravity to compensate
	crashDrag    = udTable.GetFloat("crashDrag",    0.005f); // drag used when crashing
	crashDrag    = Clamp(crashDrag, 0.0f, 1.0f);

	maxBank = udTable.GetFloat("maxBank", 0.8f);         // max roll
	maxPitch = udTable.GetFloat("maxPitch", 0.45f);      // max pitch this plane tries to keep
	turnRadius = udTable.GetFloat("turnRadius", 500.0f); // hint to the ai about how large turn radius this plane needs
	verticalSpeed = udTable.GetFloat("verticalSpeed", 3.0f); // speed of takeoff and landing, at least for gunships

	maxAileron  = udTable.GetFloat("maxAileron",  0.015f); // turn speed around roll axis
	maxElevator = udTable.GetFloat("maxElevator", 0.01f);  // turn speed around pitch axis
	maxRudder   = udTable.GetFloat("maxRudder",   0.004f); // turn speed around yaw axis

	maxFuel = udTable.GetFloat("maxFuel", 0.0f); //max flight time in seconds before aircraft must return to base
	refuelTime = udTable.GetFloat("refuelTime", 5.0f);
	minAirBasePower = udTable.GetFloat("minAirBasePower", 0.0f);
	maxThisUnit = udTable.GetInt("unitRestricted", MAX_UNITS);
	transportableBuilding = udTable.GetBool("transportableBuilding", false);

	const string lname = StringToLower(name);

	if (gameSetup->restrictedUnits.find(lname) != gameSetup->restrictedUnits.end()) {
		maxThisUnit = std::min(maxThisUnit, gameSetup->restrictedUnits.find(lname)->second);
	}

	categoryString = udTable.GetString("category", "");

	category = CCategoryHandler::Instance()->GetCategories(udTable.GetString("category", ""));
	noChaseCategory = CCategoryHandler::Instance()->GetCategories(udTable.GetString("noChaseCategory", ""));

	const string iconName = udTable.GetString("iconType", "default");
	iconType = iconHandler->GetIcon(iconName);

	shieldWeaponDef    = NULL;
	stockpileWeaponDef = NULL;

	maxWeaponRange = 0.0f;
	maxCoverage = 0.0f;

	LuaTable weaponsTable = udTable.SubTable("weapons");
	ParseWeaponsTable(weaponsTable);

	canDGun = udTable.GetBool("canDGun", false);

	extractRange = 0.0f;
	extractSquare = udTable.GetBool("extractSquare", false);

	if (extractsMetal) {
		extractRange = mapInfo->map.extractorRadius;
		type = "MetalExtractor";
	}
	else if (transportCapacity) {
		type = "Transport";
	}
	else if (builder) {
		if ((speed > 0.0f) || canfly || udTable.GetString("yardMap", "").empty()) {
			// hubs and nano-towers need to be builders (for now)
			type = "Builder";
		} else {
			type = "Factory";
		}
	}
	else if (canfly && !hoverAttack) {
		if (!weapons.empty() && (weapons[0].def != 0) &&
		   (weapons[0].def->type == "AircraftBomb" || weapons[0].def->type == "TorpedoLauncher")) {
			type = "Bomber";

			if (turnRadius == 500) { // only reset it if user hasnt set it explicitly
				turnRadius *= 2;   // hint to the ai about how large turn radius this plane needs
			}
		} else {
			type = "Fighter";
		}
		maxAcc = udTable.GetFloat("maxAcc", 0.065f); // engine power
	}
	else if (canmove) {
		type = "GroundUnit";
	}
	else {
		type = "Building";
	}

	movedata = NULL;
	if (canmove && !canfly && (type != "Factory")) {
		string moveclass = StringToLower(udTable.GetString("movementClass", ""));
		movedata = moveinfo->GetMoveDataFromName(moveclass);

		if (!movedata) {
			const string errmsg = "WARNING: Couldn't find a MoveClass named " + moveclass + " (used in UnitDef: " + unitName + ")";
			throw content_error(errmsg); //! invalidate unitDef (this gets catched in ParseUnitDef!)
		}

		if ((movedata->moveType == MoveData::Hover_Move) ||
		    (movedata->moveType == MoveData::Ship_Move)) {
			upright = true;
		}
		if (canhover) {
			if (movedata->moveType != MoveData::Hover_Move) {
				logOutput.Print("Inconsistent movedata %i for %s (moveclass %s): canhover, but not a hovercraft movetype",
				     movedata->pathType, name.c_str(), moveclass.c_str());
			}
		} else if (floater) {
			if (movedata->moveType != MoveData::Ship_Move) {
				logOutput.Print("Inconsistent movedata %i for %s (moveclass %s): floater, but not a ship movetype",
				     movedata->pathType, name.c_str(), moveclass.c_str());
			}
		} else {
			if (movedata->moveType != MoveData::Ground_Move) {
				logOutput.Print("Inconsistent movedata %i for %s (moveclass %s): neither canhover nor floater, but not a ground movetype",
				     movedata->pathType, name.c_str(), moveclass.c_str());
			}
		}
	}

	if ((maxAcc != 0) && (speed != 0)) {
		//meant to set the drag such that the maxspeed becomes what it should be
		drag = 1.0f / (speed/GAME_SPEED * 1.1f / maxAcc)
		          - (wingAngle * wingAngle * wingDrag);
		drag = Clamp(drag, 0.0f, 1.0f);
	} else {
		//shouldn't be needed since drag is only used in CAirMoveType anyway,
		//and aircraft without acceleration or speed aren't common :)
		//initializing it anyway just for safety
		drag = 0.005f;
	}

	objectName = udTable.GetString("objectName", "");
	if (objectName.find(".") == std::string::npos) {
		objectName += ".3do"; // NOTE: get rid of this?
	}
	modelDef.modelPath = "objects3d/" + objectName;
	modelDef.modelName = objectName;

	scriptName = udTable.GetString("script", unitName + ".cob");
	scriptPath = "scripts/" + scriptName;

	wreckName = udTable.GetString("corpse", "");
	deathExplosion = udTable.GetString("explodeAs", "");
	selfDExplosion = udTable.GetString("selfDestructAs", "");

	power = udTable.GetFloat("power", (metalCost + (energyCost / 60.0f)));

	// Prevent a division by zero in experience calculations.
	if (power < 1.0e-3f) {
		logOutput.Print("Unit %s is really cheap? %f", humanName.c_str(), power);
		logOutput.Print("This can cause a division by zero in experience calculations.");
		power = 1.0e-3f;
	}

	activateWhenBuilt = udTable.GetBool("activateWhenBuilt", false);

	// TA has only half our res so multiply size with 2
	xsize = udTable.GetInt("footprintX", 1) * 2;
	zsize = udTable.GetInt("footprintZ", 1) * 2;

	needGeo = false;

	if (speed <= 0.0f) {
		CreateYardMap(udTable.GetString("yardMap", ""));
	}

	leaveTracks   = udTable.GetBool("leaveTracks", false);
	trackTypeName = udTable.GetString("trackType", "StdTank");
	trackWidth    = udTable.GetFloat("trackWidth",   32.0f);
	trackOffset   = udTable.GetFloat("trackOffset",   0.0f);
	trackStrength = udTable.GetFloat("trackStrength", 0.0f);
	trackStretch  = udTable.GetFloat("trackStretch",  1.0f);

	useBuildingGroundDecal = udTable.GetBool("useBuildingGroundDecal", false);
	buildingDecalTypeName = udTable.GetString("buildingGroundDecalType", "");
	buildingDecalSizeX = udTable.GetInt("buildingGroundDecalSizeX", 4);
	buildingDecalSizeY = udTable.GetInt("buildingGroundDecalSizeY", 4);
	buildingDecalDecaySpeed = udTable.GetFloat("buildingGroundDecalDecaySpeed", 0.1f);

	canDropFlare    = udTable.GetBool("canDropFlare", false);
	flareReloadTime = udTable.GetFloat("flareReload",     5.0f);
	flareDelay      = udTable.GetFloat("flareDelay",      0.3f);
	flareEfficiency = udTable.GetFloat("flareEfficiency", 0.5f);
	flareDropVector = udTable.GetFloat3("flareDropVector", ZeroVector);
	flareTime       = udTable.GetInt("flareTime", 3) * GAME_SPEED;
	flareSalvoSize  = udTable.GetInt("flareSalvoSize",  4);
	flareSalvoDelay = udTable.GetInt("flareSalvoDelay", 0) * GAME_SPEED;

	smoothAnim = udTable.GetBool("smoothAnim", false);
	canLoopbackAttack = udTable.GetBool("canLoopbackAttack", false);
	canCrash = udTable.GetBool("canCrash", true);
	levelGround = udTable.GetBool("levelGround", true);
	strafeToAttack = udTable.GetBool("strafeToAttack", false);


	modelCenterOffset = udTable.GetFloat3("modelCenterOffset", ZeroVector);
	usePieceCollisionVolumes = udTable.GetBool("usePieceCollisionVolumes", false);

	// initialize the (per-unitdef) collision-volume
	// all CUnit instances hold a copy of this object
	collisionVolume = new CollisionVolume(
		udTable.GetString("collisionVolumeType", ""),
		udTable.GetFloat3("collisionVolumeScales", ZeroVector),
		udTable.GetFloat3("collisionVolumeOffsets", ZeroVector),
		udTable.GetInt("collisionVolumeTest", CollisionVolume::COLVOL_HITTEST_DISC)
	);

	if (usePieceCollisionVolumes) {
		collisionVolume->Disable();
	}


	seismicRadius    = udTable.GetInt("seismicDistance", 0);
	seismicSignature = udTable.GetFloat("seismicSignature", -1.0f);
	if (seismicSignature == -1.0f) {
		if (!floater && !canhover && !canfly) {
			seismicSignature = sqrt(mass / 100.0f);
		} else {
			seismicSignature = 0.0f;
		}
	}

	LuaTable buildsTable = udTable.SubTable("buildOptions");
	if (buildsTable.IsValid()) {
		for (int bo = 1; true; bo++) {
			const string order = buildsTable.GetString(bo, "");
			if (order.empty()) {
				break;
			}
			buildOptions[bo] = order;
		}
	}

	LuaTable sfxTable = udTable.SubTable("SFXTypes");
	LuaTable expTable = sfxTable.SubTable("explosionGenerators");

	for (int expNum = 1; expNum <= 1024; expNum++) {
		std::string expsfx = expTable.GetString(expNum, "");

		if (expsfx == "") {
			break;
		} else {
			sfxExplGenNames.push_back(expsfx);
		}
	}

	// we use range in a modulo operation, so it needs to be >= 1
	pieceTrailCEGTag = udTable.GetString("pieceTrailCEGTag", "");
	pieceTrailCEGRange = udTable.GetInt("pieceTrailCEGRange", 1);
	pieceTrailCEGRange = std::max(pieceTrailCEGRange, 1);

	// custom parameters table
	udTable.SubTable("customParams").GetMap(customParams);
}
Exemple #11
0
int main(int argc, char *argv[])
{
#ifdef _WIN32
	try {
#endif
	std::cout << "If you find any errors, report them to mantis or the forums." << std::endl << std::endl;
	ConfigHandler::Instantiate("");
	FileSystemHandler::Cleanup();
	FileSystemHandler::Initialize(false);
	CGameServer* server = 0;
	CGameSetup* gameSetup = 0;

	if (argc > 1)
	{
		const std::string script(argv[1]);
		std::cout << "Loading script from file: " << script << std::endl;

		ClientSetup settings;
		CFileHandler fh(argv[1]);
		if (!fh.FileExists())
			throw content_error("Setupscript doesn't exists in given location: "+script);

		std::string buf;
		if (!fh.LoadStringData(buf))
			throw content_error("Setupscript cannot be read: "+script);
		settings.Init(buf);

		gameSetup = new CGameSetup();	// to store the gamedata inside
		if (!gameSetup->Init(buf))	// read the script provided by cmdline
		{
			std::cout << "Failed to load script" << std::endl;
			return 1;
		}

		std::cout << "Starting server..." << std::endl;
		// Create the server, it will run in a separate thread
		GameData* data = new GameData();
		UnsyncedRNG rng;
		rng.Seed(gameSetup->gameSetupText.length());
		rng.Seed(script.length());
		data->SetRandomSeed(rng.RandInt());

		//  Use script provided hashes if they exist
		if (gameSetup->mapHash != 0)
		{
			data->SetMapChecksum(gameSetup->mapHash);
			gameSetup->LoadStartPositions(false); // reduced mode
		}
		else
		{
			data->SetMapChecksum(archiveScanner->GetMapChecksum(gameSetup->mapName));

			CFileHandler* f = new CFileHandler("maps/" + gameSetup->mapName);
			if (!f->FileExists()) {
				std::vector<std::string> ars = archiveScanner->GetArchivesForMap(gameSetup->mapName);
				if (ars.empty()) {
					throw content_error("Couldn't find any archives for map '" + gameSetup->mapName + "'.");
				}
				for (std::vector<std::string>::iterator i = ars.begin(); i != ars.end(); ++i) {
					if (!vfsHandler->AddArchive(*i, false)) {
						throw content_error("Couldn't load archive '" + *i + "' for map '" + gameSetup->mapName + "'.");
					}
				}
			}
			delete f;
			gameSetup->LoadStartPositions(); // full mode
		}

		if (gameSetup->modHash != 0) {
			data->SetModChecksum(gameSetup->modHash);
		} else {
			const std::string modArchive = archiveScanner->ModNameToModArchive(gameSetup->modName);
			data->SetModChecksum(archiveScanner->GetModChecksum(modArchive));
		}

		data->SetSetup(gameSetup->gameSetupText);
		server = new CGameServer(&settings, false, data, gameSetup);

		while (!server->HasFinished()) // check if still running
#ifdef _WIN32
			Sleep(1000);
#else
			sleep(1);	// if so, wait 1  second
#endif
		delete server;	// delete the server after usage
	}
	else
	{
		std::cout << "usage: spring-dedicated <full_path_to_script>" << std::endl;
	}

	FileSystemHandler::Cleanup();

#ifdef _WIN32
	}
	catch (const std::exception& err)
	{
		std::cout << "Exception raised: " << err.what() << std::endl;
		return 1;
	}
#endif
	return 0;
}
Exemple #12
0
C3DOTextureHandler::C3DOTextureHandler()
{
	CFileHandler teamTexFile("unittextures/tatex/teamtex.txt");
	CFileHandler paletteFile("unittextures/tatex/palette.pal");

	CSimpleParser parser(teamTexFile);

	std::set<std::string> teamTexes;
	while (!parser.Eof()) {
		teamTexes.insert(StringToLower(parser.GetCleanLine()));
	}

	TexFile* texfiles[10000];

	int numfiles = 0;
	int totalSize = 0;

	const std::vector<std::string>& filesBMP = CFileHandler::FindFiles("unittextures/tatex/", "*.bmp");
	std::vector<std::string> files    = CFileHandler::FindFiles("unittextures/tatex/", "*.tga");
	files.insert(files.end(), filesBMP.begin(), filesBMP.end());

	std::set<string> usedNames;
	for (std::vector<std::string>::iterator fi = files.begin(); fi != files.end(); ++fi) {
		const std::string& s = *fi;
		const std::string s2 = StringToLower(FileSystem::GetBasename(s));

		// avoid duplicate names and give tga images priority
		if (usedNames.find(s2) != usedNames.end()) {
			continue;
		}
		usedNames.insert(s2);

		if(teamTexes.find(s2) == teamTexes.end()){
			TexFile* tex = CreateTex(s, s2, false);
			texfiles[numfiles++] = tex;
			totalSize += tex->tex.xsize * tex->tex.ysize;
		} else {
			TexFile* tex = CreateTex(s, s2, true);
			texfiles[numfiles++] = tex;
			totalSize += tex->tex.xsize * tex->tex.ysize;
		}
	}

	if (paletteFile.FileExists()) {
		palette.Init(paletteFile);
	}

	for (unsigned a = 0; a < CTAPalette::NUM_PALETTE_ENTRIES; ++a) {
		const std::string name = "ta_color" + IntToString(a, "%i");

		TexFile* tex = new TexFile;
		tex->name = name;
		tex->tex.Alloc(1, 1);
		tex->tex.mem[0] = palette[a][0];
		tex->tex.mem[1] = palette[a][1];
		tex->tex.mem[2] = palette[a][2];
		tex->tex.mem[3] = 0; // teamcolor

		tex->tex2.Alloc(1, 1);
		tex->tex2.mem[0] = 0;  // self illum
		tex->tex2.mem[1] = 30; // reflectivity
		tex->tex2.mem[2] =  0;
		tex->tex2.mem[3] = 255;

		texfiles[numfiles++] = tex;
		totalSize += tex->tex.xsize * tex->tex.ysize;
	}

	// pessimistic guess about how much space will be wasted
	totalSize = (int)(totalSize * 1.2f);

	if (totalSize < 1024*1024) {
		bigTexX = 1024;
		bigTexY = 1024;
	} else if (totalSize < 1024*2048) {
		bigTexX = 1024;
		bigTexY = 2048;
	} else if (totalSize < 2048*2048) {
		bigTexX = 2048;
		bigTexY = 2048;
	} else {
		bigTexX = 2048;
		bigTexY = 2048;
		throw content_error("Too many/large texture in 3do texture-atlas to fit in 2048*2048");
	}

	qsort(texfiles,numfiles,sizeof(TexFile*), CompareTatex2);

	unsigned char* bigtex1 = new unsigned char[bigTexX * bigTexY * 4];
	unsigned char* bigtex2 = new unsigned char[bigTexX * bigTexY * 4];
	for (int a = 0; a < (bigTexX * bigTexY); ++a) {
		bigtex1[a*4 + 0] = 128;
		bigtex1[a*4 + 1] = 128;
		bigtex1[a*4 + 2] = 128;
		bigtex1[a*4 + 3] = 0;

		bigtex2[a*4 + 0] = 0;
		bigtex2[a*4 + 1] = 128;
		bigtex2[a*4 + 2] = 0;
		bigtex2[a*4 + 3] = 255;
	}

	int cury = 0;
	int maxy = 0;
	int foundx = 0;
	int foundy = 0;
	std::list<int2> nextSub;
	std::list<int2> thisSub;
	for (int a = 0; a < numfiles; ++a) {
		CBitmap* curtex1 = &texfiles[a]->tex;
		CBitmap* curtex2 = &texfiles[a]->tex2;

		bool done = false;
		while (!done) {
			// Find space for us
			if (thisSub.empty()) {
				if (nextSub.empty()) {
					cury = maxy;
					maxy += curtex1->ysize;
					if (maxy > bigTexY) {
						delete[] bigtex1;
						delete[] bigtex2;
						throw content_error("Too many/large texture in 3do texture-atlas to fit in 2048*2048");
					}
					thisSub.push_back(int2(0, cury));
				} else {
					thisSub = nextSub;
					nextSub.clear();
				}
			}
			if (thisSub.front().x + curtex1->xsize>bigTexX) {
				thisSub.clear();
				continue;
			}
			if(thisSub.front().y+curtex1->ysize>maxy){
				thisSub.pop_front();
				continue;
			}
			// ok found space for us
			foundx=thisSub.front().x;
			foundy=thisSub.front().y;
			done=true;

			if (thisSub.front().y + curtex1->ysize<maxy){
				nextSub.push_back(int2(thisSub.front().x, thisSub.front().y + curtex1->ysize));
			}

			thisSub.front().x += curtex1->xsize;
			while ((thisSub.size() > 1) && (thisSub.front().x >= (++thisSub.begin())->x)) {
				(++thisSub.begin())->x = thisSub.front().x;
				thisSub.erase(thisSub.begin());
			}

		}
		for (int y = 0; y < curtex1->ysize; ++y) {
			for (int x = 0; x < curtex1->xsize; ++x) {
				for (int col = 0; col < 4; ++col) {
					bigtex1[(((foundy + y) * bigTexX + (foundx + x)) * 4) + col] = curtex1->mem[(((y * curtex1->xsize) + x) * 4) + col];
					bigtex2[(((foundy + y) * bigTexX + (foundx + x)) * 4) + col] = curtex2->mem[(((y * curtex1->xsize) + x) * 4) + col];
				}
			}
		}

		UnitTexture* unittex = new UnitTexture;

		unittex->xstart = (foundx + 0.5f) / (float)bigTexX;
		unittex->ystart = (foundy + 0.5f) / (float)bigTexY;
		unittex->xend = (foundx + curtex1->xsize - 0.5f) / (float)bigTexX;
		unittex->yend = (foundy + curtex1->ysize - 0.5f) / (float)bigTexY;
		textures[texfiles[a]->name] = unittex;

		delete texfiles[a];
	}

	glGenTextures(1, &atlas3do1);
	glBindTexture(GL_TEXTURE_2D, atlas3do1);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*_MIPMAP_NEAREST*/);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8 ,bigTexX, bigTexY, 0, GL_RGBA, GL_UNSIGNED_BYTE, bigtex1);
	//glBuildMipmaps(GL_TEXTURE_2D,GL_RGBA8 ,bigTexX, bigTexY, GL_RGBA, GL_UNSIGNED_BYTE, bigtex1);

	glGenTextures(1, &atlas3do2);
	glBindTexture(GL_TEXTURE_2D, atlas3do2);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*_MIPMAP_NEAREST*/);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, bigTexX, bigTexY, 0, GL_RGBA, GL_UNSIGNED_BYTE, bigtex2);
	//glBuildMipmaps(GL_TEXTURE_2D,GL_RGBA8, bigTexX, bigTexY, GL_RGBA, GL_UNSIGNED_BYTE, bigtex2);


//	CBitmap save(tex, bigTexX, bigTexY);
//	save.Save("unittex-1x.jpg");

	UnitTexture* t = new UnitTexture();
	t->xstart = 0.0f;
	t->ystart = 0.0f;
	t->xend = 1.0f;
	t->yend = 1.0f;
	textures["___dummy___"] = t;

	delete[] bigtex1;
	delete[] bigtex2;
}
Exemple #13
0
CMoveInfo::CMoveInfo()
{
	const LuaTable rootTable = game->defsParser->GetRoot().SubTable("MoveDefs");
	if (!rootTable.IsValid()) {
		throw content_error("Error loading movement definitions");
	}

	groundMoveMath = new CGroundMoveMath();
	hoverMoveMath = new CHoverMoveMath();
	seaMoveMath = new CShipMoveMath();

	CRC crc;

	for (int tt = 0; tt < CMapInfo::NUM_TERRAIN_TYPES; ++tt) {
		const CMapInfo::TerrainType& terrType = mapInfo->terrainTypes[tt];

		crc << terrType.tankSpeed << terrType.kbotSpeed;
		crc << terrType.hoverSpeed << terrType.shipSpeed;
	}

	for (size_t num = 1; /* no test */; num++) {
		const LuaTable moveTable = rootTable.SubTable(num);
		if (!moveTable.IsValid()) {
			break;
		}

		MoveData* md = new MoveData(NULL);

		md->name          = StringToLower(moveTable.GetString("name", ""));
		md->pathType      = (num - 1);
		md->crushStrength = moveTable.GetFloat("crushStrength", 10.0f);

		const float minWaterDepth = moveTable.GetFloat("minWaterDepth", 10.0f);
		const float maxWaterDepth = moveTable.GetFloat("maxWaterDepth", 0.0f);

		if ((md->name.find("boat") != string::npos) ||
		    (md->name.find("ship") != string::npos)) {
			md->moveType   = MoveData::Ship_Move;
			md->depth      = minWaterDepth;
			md->moveFamily = MoveData::Ship;
			md->moveMath   = seaMoveMath;
			md->subMarine  = moveTable.GetBool("subMarine", 0);
		} else if (md->name.find("hover") != string::npos) {
			md->moveType   = MoveData::Hover_Move;
			md->maxSlope   = DegreesToMaxSlope(moveTable.GetFloat("maxSlope", 15.0f));
			md->moveFamily = MoveData::Hover;
			md->moveMath   = hoverMoveMath;
		} else {
			md->moveType = MoveData::Ground_Move;
			md->depthMod = moveTable.GetFloat("depthMod", 0.1f);
			md->depth    = maxWaterDepth;
			md->maxSlope = DegreesToMaxSlope(moveTable.GetFloat("maxSlope", 60.0f));
			md->moveMath = groundMoveMath;

			if (md->name.find("tank") != string::npos) {
				md->moveFamily = MoveData::Tank;
			} else {
				md->moveFamily = MoveData::KBot;
			}
		}

		md->heatMapping = moveTable.GetBool("heatMapping", false);
		md->heatMod = moveTable.GetFloat("heatMod", 50.0f);
		md->heatProduced = moveTable.GetInt("heatProduced", 60);

		// ground units hug the ocean floor when in water,
		// ships stay at a "fixed" level (their waterline)
		md->followGround =
			(md->moveFamily == MoveData::Tank ||
			md->moveFamily == MoveData::KBot);

		// tank or bot that cannot get its threads / feet
		// wet, or hovercraft (which doesn't touch ground
		// or water)
		const bool b0 =
			((md->followGround && maxWaterDepth <= 0.0) ||
			md->moveFamily == MoveData::Hover);

		// ship (or sub) that cannot crawl onto shore, OR tank or
		// kbot restricted to snorkling (strange but possible)
		const bool b1 =
			((md->moveFamily == MoveData::Ship && minWaterDepth > 0.0) ||
			((md->followGround) && minWaterDepth > 0.0));

		// tank or kbot that CAN go skinny-dipping (amph.),
		// or ship that CAN sprout legs when at the beach
		const bool b2 =
			((md->followGround) && maxWaterDepth > 0.0) ||
			(md->moveFamily == MoveData::Ship && minWaterDepth < 0.0);

		if (b0) { md->terrainClass = MoveData::Land; }
		if (b1) { md->terrainClass = MoveData::Water; }
		if (b2) { md->terrainClass = MoveData::Mixed; }


		const int xsize = std::max(1, moveTable.GetInt("footprintX",     1));
		const int zsize = std::max(1, moveTable.GetInt("footprintZ", xsize));
		const int scale = 2;

		// make all mobile footprints point-symmetric in heightmap space
		// (meaning that only non-even dimensions are possible and each
		// footprint always has a unique center square)
		md->xsize = xsize * scale;
		md->zsize = zsize * scale;
		md->xsize -= ((md->xsize & 1)? 0: 1);
		md->zsize -= ((md->zsize & 1)? 0: 1);
		md->slopeMod = moveTable.GetFloat("slopeMod", 4.0f / (md->maxSlope + 0.001f));

		const unsigned int checksum =
			(md->xsize        << 16) +
			(md->zsize        <<  8) +
			(md->followGround <<  4) +
			(md->subMarine    <<  3) +
			(b2               <<  2) +
			(b1               <<  1) +
			(b0               <<  0);

		crc << checksum
			<< md->maxSlope << md->slopeMod
			<< md->depth << md->depthMod
			<< md->crushStrength;

		moveData.push_back(md);
		name2moveData[md->name] = md->pathType;
	}


	const float waterDamage = mapInfo->water.damage;
	if (waterDamage >= 1000.0f) {
		CGroundMoveMath::waterDamageCost = 0.0f; //! block water
	} else {
		CGroundMoveMath::waterDamageCost = 1.0f / (1.0f + waterDamage * 0.1f);
	}

	CHoverMoveMath::noWaterMove = (waterDamage >= 10000.0f);

	crc << CGroundMoveMath::waterDamageCost;
	crc << CHoverMoveMath::noWaterMove;

	moveInfoChecksum = crc.GetDigest();
}
CDxSound::CDxSound()
{
	maxSounds=ConfigHandler::GetInstance().GetInt("MaxSounds",16);
	if (maxSounds <= 0) {
		throw content_error("Internal error, (maxSounds <= 0) in CDxSound");
	}

	curThreshhold=0.1f;
	wantedSounds=maxSounds*0.75f;
	globalVolume=1.0f;

	m_pDS  = NULL;
	m_hWnd = NULL;

	HRESULT hr;

	LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;

	// Get window from SDL
	SDL_SysWMinfo wmInfo;
	SDL_VERSION(&wmInfo.version);
	if (SDL_GetWMInfo (&wmInfo) != 1) {
		throw "DxSound: Could not get window from SDL";
	}
	m_hWnd = wmInfo.window;
	
	// Initialize COM
	hr = CoInitialize( NULL );
	if( hr!=S_OK && hr!=S_FALSE){
		throw "DxSound: Could not initialize com";
	}
	
	// Create IDirectSound using the primary sound device
	if( FAILED( hr = DirectSoundCreate( NULL, &m_pDS, NULL ) ) ){
		throw "DxSound: Could not create direct sound object";
	}

    // Set coop level to DSSCL_PRIORITY
	if( FAILED( hr = m_pDS->SetCooperativeLevel( m_hWnd, DSSCL_PRIORITY ) ) ){
		throw "DxSound: Could not set cooperative level";
	}
	
	// Get the primary buffer 
	DSBUFFERDESC dsbd;
	ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
	dsbd.dwSize        = sizeof(DSBUFFERDESC);
	dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER;
	dsbd.dwBufferBytes = 0;
	dsbd.lpwfxFormat   = NULL;
	
	if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) ){
		throw "DxSound: Could not create primary sound buffer";
	}
	
	// Set primary buffer format to 22kHz and 16-bit output.
	WAVEFORMATEX wfx;
	ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); 
	wfx.wFormatTag      = WAVE_FORMAT_PCM; 
	wfx.nChannels       = 2; 
	wfx.nSamplesPerSec  = 22050; 
	wfx.wBitsPerSample  = 16; 
	wfx.nBlockAlign     = wfx.wBitsPerSample / 8 * wfx.nChannels;
	wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
	
	if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) ){
		throw "DxSound: Could not initialize primary sound format";
	}
	
	SAFE_RELEASE( pDSBPrimary );
	waveid[""]=0;
	SoundInfo* si=SAFE_NEW SoundInfo;
	loadedSounds.push_back(si);
}
Exemple #15
0
CBuilderCAI::CBuilderCAI(CUnit* owner):
	CMobileCAI(owner),
	building(false),
	cachedRadiusId(0),
	cachedRadius(0),
	buildRetries(0),
	lastPC1(-1),
	lastPC2(-1),
	lastPC3(-1),
	range3D(owner->unitDef->buildRange3D)
{
	CommandDescription c;
	if (owner->unitDef->canRepair) {
		c.id = CMD_REPAIR;
		c.action = "repair";
		c.type = CMDTYPE_ICON_UNIT_OR_AREA;
		c.name = "Repair";
		c.mouseicon = c.name;
		c.tooltip = "Repair: Repairs another unit";
		possibleCommands.push_back(c);
	}
	else if (owner->unitDef->canAssist) {
		c.id = CMD_REPAIR;
		c.action = "assist";
		c.type = CMDTYPE_ICON_UNIT_OR_AREA;
		c.name = "Assist";
		c.mouseicon = c.name;
		c.tooltip = "Assist: Help build something";
		possibleCommands.push_back(c);
	}

	if (owner->unitDef->canReclaim) {
		c.id = CMD_RECLAIM;
		c.action = "reclaim";
		c.type = CMDTYPE_ICON_UNIT_FEATURE_OR_AREA;
		c.name = "Reclaim";
		c.mouseicon = c.name;
		c.tooltip = "Reclaim: Sucks in the metal/energy content of a unit/feature and add it to your storage";
		possibleCommands.push_back(c);
	}

	if (owner->unitDef->canRestore && !mapDamage->disabled) {
		c.id = CMD_RESTORE;
		c.action = "restore";
		c.type = CMDTYPE_ICON_AREA;
		c.name = "Restore";
		c.mouseicon = c.name;
		c.tooltip = "Restore: Restores an area of the map to its original height";
		c.params.push_back("200");
		possibleCommands.push_back(c);
	}
	c.params.clear();

	if (owner->unitDef->canResurrect) {
		c.id = CMD_RESURRECT;
		c.action = "resurrect";
		c.type = CMDTYPE_ICON_UNIT_FEATURE_OR_AREA;
		c.name = "Resurrect";
		c.mouseicon = c.name;
		c.tooltip = "Resurrect: Resurrects a unit from a feature";
		possibleCommands.push_back(c);
	}
	if (owner->unitDef->canCapture) {
		c.id = CMD_CAPTURE;
		c.action = "capture";
		c.type = CMDTYPE_ICON_UNIT_OR_AREA;
		c.name = "Capture";
		c.mouseicon = c.name;
		c.tooltip = "Capture: Captures a unit from the enemy";
		possibleCommands.push_back(c);
	}

	CBuilder* builder = (CBuilder*) owner;

	map<int, string>::const_iterator bi;
	for (bi = builder->unitDef->buildOptions.begin(); bi != builder->unitDef->buildOptions.end(); ++bi) {
		const string name = bi->second;
		const UnitDef* ud = unitDefHandler->GetUnitDefByName(name);
		if (ud == NULL) {
		  string errmsg = "MOD ERROR: loading ";
		  errmsg += name.c_str();
		  errmsg += " for ";
		  errmsg += owner->unitDef->name;
			throw content_error(errmsg);
		}
		CommandDescription c;
		c.id = -ud->id; //build options are always negative
		c.action = "buildunit_" + StringToLower(ud->name);
		c.type = CMDTYPE_ICON_BUILDING;
		c.name = name;
		c.mouseicon = c.name;
		c.disabled = (ud->maxThisUnit <= 0);

		char tmp[1024];
		sprintf(tmp, "\nHealth %.0f\nMetal cost %.0f\nEnergy cost %.0f Build time %.0f",
		        ud->health, ud->metalCost, ud->energyCost, ud->buildTime);
		if (c.disabled) {
			c.tooltip = "\xff\xff\x22\x22" "DISABLED: " "\xff\xff\xff\xff";
		} else {
			c.tooltip = "Build: ";
		}
		c.tooltip += ud->humanName + " - " + ud->tooltip + tmp;

		possibleCommands.push_back(c);
		buildOptions[c.id] = name;
	}
	uh->AddBuilderCAI(this);
}
/**
 * @brief Adds the directories in the colon separated string to the datadir handler.
 */
void DataDirLocater::AddDirs(const std::string& in)
{
	size_t prev_colon = 0, colon;
#ifndef _WIN32
	while ((colon = in.find(':', prev_colon)) != std::string::npos) {
#else
	while ((colon = in.find(';', prev_colon)) != std::string::npos) {
#endif
		datadirs.push_back(in.substr(prev_colon, colon - prev_colon));
#ifdef DEBUG
		logOutput.Print("Adding %s to directories" , in.substr(prev_colon, colon - prev_colon).c_str());
#endif
		prev_colon = colon + 1;
	}
#ifdef DEBUG
	logOutput.Print("Adding %s to directories" , in.substr(prev_colon).c_str());
#endif
	datadirs.push_back(in.substr(prev_colon));
}

/**
 * @brief Figure out permissions we have for a single data directory d.
 * @returns whether we have permissions to read the data directory.
 */
bool DataDirLocater::DeterminePermissions(DataDir* d)
{
#ifndef _WIN32
	if (d->path.c_str()[0] != '/' || d->path.find("..") != std::string::npos)
#else
	if (d->path.find("..") != std::string::npos)
#endif
		throw content_error("specify data directories using absolute paths please");
	// Figure out whether we have read/write permissions
	// First check read access, if we got that check write access too
	// (no support for write-only directories)
	// Note: we check for executable bit otherwise we can't browse the directory
	// Note: we fail to test whether the path actually is a directory
	// Note: modifying permissions while or after this function runs has undefined behaviour
#ifndef _WIN32
	if (access(d->path.c_str(), R_OK | X_OK | F_OK) == 0) {
		// Note: disallow multiple write directories.
		// There isn't really a use for it as every thing is written to the first one anyway,
		// and it may give funny effects on errors, e.g. it probably only gives funny things
		// like network mounted datadir lost connection and suddenly files end up in some
		// other random writedir you didn't even remember you had added it.
		if (!writedir && access(d->path.c_str(), W_OK) == 0) {
#else
	if (_access(d->path.c_str(), 4) == 0) {
		if (!writedir && _access(d->path.c_str(), 2) == 0) {
#endif
			d->writable = true;
			writedir = &*d;
		}
		return true;
	} else {
		if (filesystem.CreateDirectory(d->path)) {
			// it didn't exist before, now it does and we just created it with rw access,
			// so we just assume we still have read-write acces...
			if (!writedir) {
				d->writable = true;
				writedir = d;
			}
			return true;
		}
	}
	return false;
}

/**
 * @brief Figure out permissions we have for the data directories.
 */
void DataDirLocater::DeterminePermissions()
{
	std::vector<DataDir> newDatadirs;
	std::string previous; // used to filter out consecutive duplicates
	// (I didn't bother filtering out non-consecutive duplicates because then
	//  there is the question which of the multiple instances to purge.)

	writedir = NULL;

	for (std::vector<DataDir>::iterator d = datadirs.begin(); d != datadirs.end(); ++d) {
		if (d->path != previous && DeterminePermissions(&*d)) {
			newDatadirs.push_back(*d);
			previous = d->path;
		}
	}

	datadirs = newDatadirs;
}

/**
 * @brief locate spring data directory
 *
 * On *nix platforms, attempts to locate
 * and change to the spring data directory
 *
 * In Unixes, the data directory to chdir to is determined by the following, in this
 * order (first items override lower items):
 *
 * - 'SPRING_DATADIR' environment variable. (colon separated list, like PATH)
 * - 'SpringData=/path/to/data' declaration in '~/.springrc'. (colon separated list)
 * - "$HOME/.spring"
 * - In the same order any line in '/etc/spring/datadir', if that file exists.
 * - 'datadir=/path/to/data' option passed to 'scons configure'.
 * - 'prefix=/install/path' option passed to scons configure. The datadir is
 *   assumed to be at '$prefix/games/spring' in this case.
 * - the default datadirs in the default prefix, ie. '/usr/local/games/spring'
 *   (This is set by the build system, ie. SPRING_DATADIR and SPRING_DATADIR_2
 *   preprocessor definitions.)
 *
 * In Windows, its:
 * - SPRING_DATADIR env-variable
 * - user configurable (SpringData in registry)
 * - location of the binary dir (like it has been until 0.76b1)
 * - the Users 'Documents'-directory (in subdirectory Spring), unless spring is configured to use another
 * - all users app-data (in subdirectory Spring)
 * - compiler flags SPRING_DATADIR and SPRING_DATADIR_2
 *
 * All of the above methods support environment variable substitution, eg.
 * '$HOME/myspringdatadir' will be converted by spring to something like
 * '/home/username/myspringdatadir'.
 *
 * If it fails to chdir to the above specified directory spring will asume the
 * current working directory is the data directory.
 */
void DataDirLocater::LocateDataDirs()
{
	// Construct the list of datadirs from various sources.
	datadirs.clear();

	// environment variable
	char* env = getenv("SPRING_DATADIR");
	if (env && *env)
		AddDirs(SubstEnvVars(env));

	// user defined (in spring config handler (Linux: ~/.spring, Windows: registry))
	std::string userDef = configHandler.GetString("SpringData", "");
	if (!userDef.empty())
	{
		AddDirs(SubstEnvVars(userDef));
	}

#ifdef WIN32
	TCHAR currentDir[MAX_PATH];
	::GetCurrentDirectory(sizeof(currentDir) - 1, currentDir);
	std::string curPath = currentDir;
	AddDirs(std::string(currentDir));
	
	// my documents
	TCHAR strPath[MAX_PATH];
	SHGetFolderPath( NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, strPath);
	std::string cfg = strPath;
	cfg += "\\Spring"; // e.g. F:\Dokumente und Einstellungen\Karl-Robert\Eigene Dateien\Spring
	AddDirs(cfg);
	cfg.clear();

	// appdata
	SHGetFolderPath( NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, strPath);
	cfg = strPath;
	cfg += "\\Spring"; // e.g. F:\Dokumente und Einstellungen\All Users\Anwendungsdaten\Spring
	AddDirs(cfg);
#else
	// home
	AddDirs(SubstEnvVars("$HOME/.spring"));

	// settings in /etc
	FILE* f = ::fopen("/etc/spring/datadir", "r");
	if (f) {
		char buf[1024];
		while (fgets(buf, sizeof(buf), f)) {
			char* newl = strchr(buf, '\n');
			if (newl)
				*newl = 0;
			char white[3] = {'\t', ' ', 0};
			if (strlen(buf) > 0 && strspn(buf, white) != strlen(buf)) // don't count lines of whitespaces / tabulators
				AddDirs(SubstEnvVars(buf));
		}
		fclose(f);
	}
#endif

	// compiler flags
#ifdef SPRING_DATADIR
	datadirs.push_back(SubstEnvVars(SPRING_DATADIR));
#endif
	// should not be needed because you can seperate directories with a ':' in SPRING_DATADIR(1)
#ifdef SPRING_DATADIR_2
	datadirs.push_back(SubstEnvVars(SPRING_DATADIR_2));
#endif

	// Figure out permissions of all datadirs
	DeterminePermissions();

	if (!writedir) {
		// bail out
		throw content_error("Not a single writable data directory found!\n\n"
				"Configure a writable data directory using either:\n"
				"- the SPRING_DATADIR environment variable,\n"
				"- a SpringData=/path/to/data declaration in ~/.springrc or\n"
				"- the configuration file /etc/spring/datadir");
	}

	// for now, chdir to the datadirectory as a safety measure:
	// all AIs still just assume it's ok to put their stuff in the current directory after all
	// Not only safety anymore, it's just easier if other code can safely assume that
	// writedir == current working directory
#ifndef _WIN32
	chdir(GetWriteDir()->path.c_str());
#else
	_chdir(GetWriteDir()->path.c_str());
#endif
	// Logging MAY NOT start before the chdir, otherwise the logfile ends up
	// in the wrong directory.
	for (std::vector<DataDir>::const_iterator d = datadirs.begin(); d != datadirs.end(); ++d) {
		if (d->writable)
			logOutput.Print("Using read-write data directory: %s", d->path.c_str());
		else
			logOutput.Print("Using read-only  data directory: %s", d->path.c_str());
	}
}
Exemple #17
0
void CModInfo::Init(const char* modname)
{
	filename = modname;

	humanName = archiveScanner->ModArchiveToModName(modname);

	const CArchiveScanner::ModData md = archiveScanner->ModArchiveToModData(modname);

	shortName   = md.shortName;
	version     = md.version;
	mutator     = md.mutator;
	description = md.description;

	// initialize the parser
	LuaParser parser("gamedata/modrules.lua",
	                 SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
	// customize the defs environment
	parser.GetTable("Spring");
	parser.AddFunc("GetModOptions", LuaSyncedRead::GetModOptions);
	parser.EndTable();
	parser.Execute();
	if (!parser.IsValid()) {
		logOutput.Print("Error loading modrules, using defaults");
		logOutput.Print(parser.GetErrorLog());
	}
	const LuaTable root = parser.GetRoot();

	// determine if bombers are allowed to leave map boundaries
	const LuaTable movementTbl = root.SubTable("movement");
	allowAirPlanesToLeaveMap = movementTbl.GetBool("allowAirPlanesToLeaveMap", true);

	// determine whether the modder allows the user to use team coloured nanospray
	const LuaTable nanosprayTbl = root.SubTable("nanospray");
	allowTeamColors = nanosprayTbl.GetBool("allow_team_colors", true);
	if (allowTeamColors) {
		// Load the users preference for team coloured nanospray
		gu->teamNanospray = !!configHandler->Get("TeamNanoSpray", 1);
	}

	// constructions
	const LuaTable constructionTbl = root.SubTable("construction");
	constructionDecay = constructionTbl.GetBool("constructionDecay", true);
	constructionDecayTime = (int)(constructionTbl.GetFloat("constructionDecayTime", 6.66) * 30);
	constructionDecaySpeed = constructionTbl.GetFloat("constructionDecaySpeed", 0.03);

	// reclaim
	const LuaTable reclaimTbl = root.SubTable("reclaim");
	multiReclaim  = reclaimTbl.GetInt("multiReclaim",  0);
	reclaimMethod = reclaimTbl.GetInt("reclaimMethod", 1);
	reclaimUnitMethod = reclaimTbl.GetInt("unitMethod", 1);
	reclaimUnitEnergyCostFactor = reclaimTbl.GetFloat("unitEnergyCostFactor", 0.0);
	reclaimUnitEfficiency = reclaimTbl.GetFloat("unitEfficiency", 1.0);
	reclaimFeatureEnergyCostFactor = reclaimTbl.GetFloat("featureEnergyCostFactor", 0.0);
	reclaimAllowEnemies = reclaimTbl.GetBool("allowEnemies", true);
	reclaimAllowAllies = reclaimTbl.GetBool("allowAllies", true);

	// repair
	const LuaTable repairTbl = root.SubTable("repair");
	repairEnergyCostFactor = repairTbl.GetFloat("energyCostFactor", 0.0);

	// resurrect
	const LuaTable resurrectTbl = root.SubTable("resurrect");
	resurrectEnergyCostFactor  = resurrectTbl.GetFloat("energyCostFactor",  0.5);

	// capture
	const LuaTable captureTbl = root.SubTable("capture");
	captureEnergyCostFactor = captureTbl.GetFloat("energyCostFactor", 0.0);

	// fire-at-dead-units
	const LuaTable fireAtDeadTbl = root.SubTable("fireAtDead");
	fireAtKilled   = fireAtDeadTbl.GetBool("fireAtKilled", false);
	fireAtCrashing = fireAtDeadTbl.GetBool("fireAtCrashing", false);

	// transportability
	const LuaTable transportTbl = root.SubTable("transportability");
	transportAir    = transportTbl.GetInt("transportAir",   false);
	transportShip   = transportTbl.GetInt("transportShip",  false);
	transportHover  = transportTbl.GetInt("transportHover", false);
	transportGround = transportTbl.GetInt("transportGround", true);

	// experience
	const LuaTable experienceTbl = root.SubTable("experience");
	CUnit::SetExpMultiplier (experienceTbl.GetFloat("experienceMult", 1.0f));
	CUnit::SetExpPowerScale (experienceTbl.GetFloat("powerScale",  1.0f));
	CUnit::SetExpHealthScale(experienceTbl.GetFloat("healthScale", 0.7f));
	CUnit::SetExpReloadScale(experienceTbl.GetFloat("reloadScale", 0.4f));

	// flanking bonus
	const LuaTable flankingBonusTbl = root.SubTable("flankingBonus");
	flankingBonusModeDefault = flankingBonusTbl.GetInt("defaultMode", 1);

	// feature visibility
	const LuaTable featureLOS = root.SubTable("featureLOS");
	featureVisibility = featureLOS.GetInt("featureVisibility", 3);
	if (featureVisibility < 0 || featureVisibility > 3)
		throw content_error("invalid modinfo: featureVisibility, valid range is 0..3");

	// sensors
	const LuaTable sensors = root.SubTable("sensors");
	requireSonarUnderWater = sensors.GetBool("requireSonarUnderWater", true);
	/// LoS
	const LuaTable los = sensors.SubTable("los");
	// losMipLevel is used as index to readmap->mipHeightmap,
	// so the max value is CReadMap::numHeightMipMaps - 1
	losMipLevel = los.GetInt("losMipLevel", 1);
	losMul = los.GetFloat("losMul", 1.0f);
	if ((losMipLevel < 0) || (losMipLevel > 6)) {
		throw content_error("Sensors\\Los\\LosMipLevel out of bounds. "
		                    "The minimum value is 0. The maximum value is 6.");
	}
	// airLosMipLevel doesn't have such restrictions, it's just used in various
	// bitshifts with signed integers
	airMipLevel = los.GetInt("airMipLevel", 2);
	if ((airMipLevel < 0) || (airMipLevel > 30)) {
		throw content_error("Sensors\\Los\\AirLosMipLevel out of bounds. "
		                    "The minimum value is 0. The maximum value is 30.");
	}
	airLosMul = los.GetFloat("airLosMul", 1.0f);
}
Exemple #18
0
CWeapon* CUnitLoader::LoadWeapon(const WeaponDef *weapondef, CUnit* owner, const UnitDef::UnitDefWeapon* udw)
{
	CWeapon* weapon;

	if (!weapondef) {
		logOutput.Print("Error: No weapon def?");
	}

	if (udw->name == "NOWEAPON") {
		weapon = new CNoWeapon(owner);
	} else if (weapondef->type == "Cannon") {
		weapon = new CCannon(owner);
		((CCannon*)weapon)->selfExplode = weapondef->selfExplode;
	} else if (weapondef->type == "Rifle") {
		weapon = new CRifle(owner);
	} else if (weapondef->type == "Melee") {
		weapon = new CMeleeWeapon(owner);
	} else if (weapondef->type == "AircraftBomb") {
		weapon = new CBombDropper(owner, false);
	} else if (weapondef->type == "Shield") {
		weapon = new CPlasmaRepulser(owner);
	} else if (weapondef->type == "Flame") {
		weapon = new CFlameThrower(owner);
	} else if (weapondef->type == "MissileLauncher") {
		weapon = new CMissileLauncher(owner);
	} else if (weapondef->type == "TorpedoLauncher") {
		if (owner->unitDef->canfly && !weapondef->submissile) {
			weapon = new CBombDropper(owner, true);
			if (weapondef->tracks)
				((CBombDropper*) weapon)->tracking = weapondef->turnrate;
			((CBombDropper*) weapon)->bombMoveRange = weapondef->range;
		} else {
			weapon = new CTorpedoLauncher(owner);
			if (weapondef->tracks)
				((CTorpedoLauncher*) weapon)->tracking = weapondef->turnrate;
		}
	} else if (weapondef->type == "LaserCannon") {
		weapon = new CLaserCannon(owner);
		((CLaserCannon*) weapon)->color = weapondef->visuals.color;
	} else if (weapondef->type == "BeamLaser") {
		weapon = new CBeamLaser(owner);
		((CBeamLaser*) weapon)->color = weapondef->visuals.color;
	} else if (weapondef->type == "LightningCannon") {
		weapon = new CLightningCannon(owner);
		((CLightningCannon*) weapon)->color = weapondef->visuals.color;
	} else if (weapondef->type == "EmgCannon") {
		weapon = new CEmgCannon(owner);
	} else if (weapondef->type == "DGun") {
		weapon = new CDGunWeapon(owner);
	} else if (weapondef->type == "StarburstLauncher"){
		weapon = new CStarburstLauncher(owner);
		if (weapondef->tracks)
			((CStarburstLauncher*) weapon)->tracking = weapondef->turnrate;
		else
			((CStarburstLauncher*) weapon)->tracking = 0;
		((CStarburstLauncher*) weapon)->uptime = weapondef->uptime * GAME_SPEED;
	} else {
		LogObject() << "Unknown weapon type " << weapondef->type.c_str() << "\n";
		return 0;
	}
	weapon->weaponDef = weapondef;

	weapon->reloadTime = (int) (weapondef->reload * GAME_SPEED);
	if (weapon->reloadTime == 0)
		weapon->reloadTime = 1;
	weapon->range = weapondef->range;
//	weapon->baseRange = weapondef->range;
	weapon->heightMod = weapondef->heightmod;
	weapon->projectileSpeed = weapondef->projectilespeed;
//	weapon->baseProjectileSpeed = weapondef->projectilespeed / GAME_SPEED;

	weapon->areaOfEffect = weapondef->areaOfEffect;
	weapon->accuracy = weapondef->accuracy;
	weapon->sprayAngle = weapondef->sprayAngle;

	weapon->stockpileTime = (int) (weapondef->stockpileTime * GAME_SPEED);

	weapon->salvoSize = weapondef->salvosize;
	weapon->salvoDelay = (int) (weapondef->salvodelay * GAME_SPEED);
	weapon->projectilesPerShot = weapondef->projectilespershot;

	weapon->metalFireCost = weapondef->metalcost;
	weapon->energyFireCost = weapondef->energycost;

	weapon->fireSoundId = weapondef->firesound.getID(0);
	weapon->fireSoundVolume = weapondef->firesound.getVolume(0);

	weapon->onlyForward = weapondef->onlyForward;
	if (owner->unitDef->type == "Fighter" && !owner->unitDef->hoverAttack) {
		// fighter aircraft have too big tolerance in TA
		weapon->maxAngleDif = cos(weapondef->maxAngle * 0.4f / 180 * PI);
	} else {
		weapon->maxAngleDif = cos(weapondef->maxAngle / 180 * PI);
	}

	weapon->SetWeaponNum(owner->weapons.size());

	weapon->badTargetCategory = udw->badTargetCat;
	weapon->onlyTargetCategory = weapondef->onlyTargetCategory & udw->onlyTargetCat;

	if (udw->slavedTo) {
		const int index = (udw->slavedTo - 1);
		if ((index < 0) || (static_cast<size_t>(index) >= owner->weapons.size())) {
			throw content_error("Bad weapon slave in " + owner->unitDef->name);
		}
		weapon->slavedTo = owner->weapons[index];
	}

	weapon->mainDir = udw->mainDir;
	weapon->maxMainDirAngleDif = udw->maxAngleDif;

	weapon->fuelUsage = udw->fuelUsage;
	weapon->avoidFriendly = weapondef->avoidFriendly;
	weapon->avoidFeature = weapondef->avoidFeature;
	weapon->avoidNeutral = weapondef->avoidNeutral;
	weapon->targetBorder = weapondef->targetBorder;
	weapon->cylinderTargetting = weapondef->cylinderTargetting;
	weapon->minIntensity = weapondef->minIntensity;
	weapon->heightBoostFactor = weapondef->heightBoostFactor;
	weapon->collisionFlags = weapondef->collisionFlags;
	weapon->Init();

	return weapon;
}
Exemple #19
0
S3DModel* CAssParser::Load(const std::string& modelFilePath)
{
	LOG_SL(LOG_SECTION_MODEL, L_INFO, "Loading model: %s", modelFilePath.c_str());

	const std::string& modelPath = FileSystem::GetDirectory(modelFilePath);
	const std::string& modelName = FileSystem::GetBasename(modelFilePath);

	// Load the lua metafile. This contains properties unique to Spring models and must return a table
	std::string metaFileName = modelFilePath + ".lua";

	if (!CFileHandler::FileExists(metaFileName, SPRING_VFS_ZIP)) {
		// Try again without the model file extension
		metaFileName = modelPath + '/' + modelName + ".lua";
	}
	if (!CFileHandler::FileExists(metaFileName, SPRING_VFS_ZIP)) {
		LOG_SL(LOG_SECTION_MODEL, L_INFO, "No meta-file '%s'. Using defaults.", metaFileName.c_str());
	}

	LuaParser metaFileParser(metaFileName, SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);

	if (!metaFileParser.Execute()) {
		LOG_SL(LOG_SECTION_MODEL, L_ERROR, "'%s': %s. Using defaults.", metaFileName.c_str(), metaFileParser.GetErrorLog().c_str());
	}

	// Get the (root-level) model table
	const LuaTable& modelTable = metaFileParser.GetRoot();

	if (!modelTable.IsValid()) {
		LOG_SL(LOG_SECTION_MODEL, L_INFO, "No valid model metadata in '%s' or no meta-file", metaFileName.c_str());
	}


	// Create a model importer instance
	Assimp::Importer importer;

	// Create a logger for debugging model loading issues
	Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
	Assimp::DefaultLogger::get()->attachStream(new AssLogStream(), ASS_LOGGING_OPTIONS);

	// Give the importer an IO class that handles Spring's VFS
	importer.SetIOHandler(new AssVFSSystem());
	// Speed-up processing by skipping things we don't need
	importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, ASS_IMPORTER_OPTIONS);

#ifndef BITMAP_NO_OPENGL
	{
		// Optimize VBO-Mesh sizes/ranges
		GLint maxIndices  = 1024;
		GLint maxVertices = 1024;
		// FIXME returns non-optimal data, at best compute it ourselves (pre-TL cache size!)
		glGetIntegerv(GL_MAX_ELEMENTS_INDICES,  &maxIndices);
		glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &maxVertices);
		importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,   maxVertices);
		importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, maxIndices / 3);
	}
#endif

	// Read the model file to build a scene object
	LOG_SL(LOG_SECTION_MODEL, L_INFO, "Importing model file: %s", modelFilePath.c_str());

	const aiScene* scene;
	{
		// ASSIMP spams many SIGFPEs atm in normal & tangent generation
		ScopedDisableFpuExceptions fe;
		scene = importer.ReadFile(modelFilePath, ASS_POSTPROCESS_OPTIONS);
	}

	if (scene != NULL) {
		LOG_SL(LOG_SECTION_MODEL, L_INFO,
			"Processing scene for model: %s (%d meshes / %d materials / %d textures)",
			modelFilePath.c_str(), scene->mNumMeshes, scene->mNumMaterials,
			scene->mNumTextures);
	} else {
		throw content_error("[AssimpParser] Model Import: " + std::string(importer.GetErrorString()));
	}

	S3DModel* model = new S3DModel();
	model->name = modelFilePath;
	model->type = MODELTYPE_ASS;

	// Load textures
	FindTextures(model, scene, modelTable, modelPath, modelName);
	LOG_SL(LOG_SECTION_MODEL, L_INFO, "Loading textures. Tex1: '%s' Tex2: '%s'", model->tex1.c_str(), model->tex2.c_str());
	texturehandlerS3O->LoadS3OTexture(model);

	// Load all pieces in the model
	LOG_SL(LOG_SECTION_MODEL, L_INFO, "Loading pieces from root node '%s'", scene->mRootNode->mName.data);
	LoadPiece(model, scene->mRootNode, scene, modelTable);

	// Update piece hierarchy based on metadata
	BuildPieceHierarchy(model);
	CalculateModelProperties(model, modelTable);

	// Verbose logging of model properties
	LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->name: %s", model->name.c_str());
	LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->numobjects: %d", model->numPieces);
	LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->radius: %f", model->radius);
	LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->height: %f", model->height);
	LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->drawRadius: %f", model->drawRadius);
	LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->mins: (%f,%f,%f)", model->mins[0], model->mins[1], model->mins[2]);
	LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->maxs: (%f,%f,%f)", model->maxs[0], model->maxs[1], model->maxs[2]);
	LOG_SL(LOG_SECTION_MODEL, L_INFO, "Model %s Imported.", model->name.c_str());
	return model;
}
Exemple #20
0
CUnit* CUnitLoader::LoadUnit(const UnitDef* ud, float3 pos, int team,
                             bool build, int facing, const CUnit* builder)
{
	GML_RECMUTEX_LOCK(sel); // LoadUnit - for anti deadlock purposes.
	GML_RECMUTEX_LOCK(quad); // LoadUnit - make sure other threads cannot access an incomplete unit

	SCOPED_TIMER("Unit loader");

	CUnit* unit;

	std::string type = ud->type;

	// clamp to map
	if (pos.x < 0)
		pos.x = 0;
	if (pos.x >= gs->mapx * SQUARE_SIZE)
		pos.x = gs->mapx-1;
	if (pos.z < 0)
		pos.z = 0;
	if (pos.z >= gs->mapy * SQUARE_SIZE)
		pos.z = gs->mapy-1;

	if (!build) {
		pos.y = ground->GetHeight2(pos.x, pos.z);
		if (ud->floater && pos.y < 0.0f) {
			// adjust to waterline iif we are submerged
 			pos.y = -ud->waterline;
		}
	}

	if (team < 0) {
		team = teamHandler->GaiaTeamID(); // FIXME use gs->gaiaTeamID ?  (once it is always enabled)
		if (team < 0)
			throw content_error("Invalid team and no gaia team to put unit in");
	}

	if (type == "GroundUnit") {
		unit = new CUnit;
	} else if (type == "Transport") {
		unit = new CTransportUnit;
	} else if (type == "Building") {
		unit = new CBuilding;
	} else if (type == "Factory") {
		unit = new CFactory;
	} else if (type == "Builder") {
		unit = new CBuilder;
	} else if (type == "Bomber" || type == "Fighter") {
		unit = new CUnit;
	} else if (type == "MetalExtractor") {
		unit = new CExtractorBuilding;
	} else {
		LogObject() << "Unknown unit type " << type.c_str() << "\n";
		return NULL;
	}

	unit->UnitInit(ud, team, pos);
	unit->beingBuilt = build;

	unit->buildFacing = abs(facing) % 4;
	unit->xsize = ((unit->buildFacing & 1) == 0) ? ud->xsize : ud->zsize;
	unit->zsize = ((unit->buildFacing & 1) == 1) ? ud->xsize : ud->zsize;

	unit->power = ud->power;
	unit->maxHealth = ud->health;
	unit->health = ud->health;
	//unit->metalUpkeep = ud->metalUpkeep*16.0f/GAME_SPEED;
	//unit->energyUpkeep = ud->energyUpkeep*16.0f/GAME_SPEED;
	unit->controlRadius = (int)(ud->controlRadius / SQUARE_SIZE);
	unit->losHeight = ud->losHeight;
	unit->metalCost = ud->metalCost;
	unit->energyCost = ud->energyCost;
	unit->buildTime = ud->buildTime;
	unit->aihint = ud->aihint;
	unit->tooltip = ud->humanName + " - " + ud->tooltip;
	unit->armoredMultiple = std::max(0.0001f, ud->armoredMultiple);		//armored multiple of 0 will crash spring
	unit->wreckName = ud->wreckName;

	unit->realLosRadius = (int) (ud->losRadius);
	unit->realAirLosRadius = (int) (ud->airLosRadius);
	unit->upright = ud->upright;
	unit->radarRadius      = ud->radarRadius    / (SQUARE_SIZE * 8);
	unit->sonarRadius      = ud->sonarRadius    / (SQUARE_SIZE * 8);
	unit->jammerRadius     = ud->jammerRadius   / (SQUARE_SIZE * 8);
	unit->sonarJamRadius   = ud->sonarJamRadius / (SQUARE_SIZE * 8);
	unit->seismicRadius    = ud->seismicRadius  / (SQUARE_SIZE * 8);
	unit->seismicSignature = ud->seismicSignature;
	unit->hasRadarCapacity = unit->radarRadius  || unit->sonarRadius    ||
	                         unit->jammerRadius || unit->sonarJamRadius ||
	                         unit->seismicRadius;
	unit->stealth = ud->stealth;
	unit->sonarStealth = ud->sonarStealth;
	unit->category = ud->category;
	unit->armorType = ud->armorType;
	unit->floatOnWater =
		ud->floater || (ud->movedata && ((ud->movedata->moveType == MoveData::Hover_Move) ||
		                                 (ud->movedata->moveType == MoveData::Ship_Move)));
	unit->maxSpeed = ud->speed / GAME_SPEED;
	unit->decloakDistance = ud->decloakDistance;

	unit->flankingBonusMode        = ud->flankingBonusMode;
	unit->flankingBonusDir         = ud->flankingBonusDir;
	unit->flankingBonusMobility    = ud->flankingBonusMobilityAdd * 1000;
	unit->flankingBonusMobilityAdd = ud->flankingBonusMobilityAdd;
	unit->flankingBonusAvgDamage = (ud->flankingBonusMax + ud->flankingBonusMin) * 0.5f;
	unit->flankingBonusDifDamage = (ud->flankingBonusMax - ud->flankingBonusMin) * 0.5f;


	if(ud->highTrajectoryType==1)
		unit->useHighTrajectory=true;

	if(ud->fireState >= 0)
		unit->fireState = ud->fireState;

	if(build){
		unit->ChangeLos(1,1);
		unit->health=0.1f;
	} else {
		unit->ChangeLos((int)(ud->losRadius),(int)(ud->airLosRadius));
	}

	if (type == "GroundUnit") {
		new CMobileCAI(unit);
	}
	else if (type == "Transport") {
		new CTransportCAI(unit);
	}
	else if (type == "Factory") {
		new CFactoryCAI(unit);
	}
	else if (type == "Builder") {
		new CBuilderCAI(unit);
	}
	else if (type == "Bomber") {
		if (ud->hoverAttack) {
			new CMobileCAI(unit);
		} else {
			new CAirCAI(unit);
		}
	}
	else if(type == "Fighter"){
		if (ud->hoverAttack) {
			new CMobileCAI(unit);
		} else {
			new CAirCAI(unit);
		}
	}
	else {
		new CCommandAI(unit);
	}

	if (ud->canmove && !ud->canfly && (type != "Factory")) {
		CGroundMoveType* mt = new CGroundMoveType(unit);
		mt->maxSpeed = ud->speed / GAME_SPEED;
		mt->maxWantedSpeed = ud->speed / GAME_SPEED;
		mt->turnRate = ud->turnRate;
		mt->baseTurnRate = ud->turnRate;

		if (mt->accRate <= 0.0f) {
			LogObject() << "acceleration of unit-type " << ud->name.c_str() << " is zero or negative!\n";
			mt->accRate = 0.01f;
		}

		mt->accRate = ud->maxAcc;
		mt->decRate = ud->maxDec;
		mt->floatOnWater = (ud->movedata->moveType == MoveData::Hover_Move ||
		                    ud->movedata->moveType == MoveData::Ship_Move);

		if (!unit->beingBuilt) {
			// otherwise set this when finished building instead
			unit->mass = ud->mass;
		}
		unit->moveType = mt;

		// Ground-mobility
		unit->mobility = new MoveData(ud->movedata);

	} else if (ud->canfly) {
		// Air-mobility
		unit->mobility = new MoveData(ud->movedata);

		if (!unit->beingBuilt) {
			// otherwise set this when finished building instead
			unit->mass = ud->mass;
		}

		if ((type == "Builder") || ud->hoverAttack || ud->transportCapacity) {
			CTAAirMoveType* mt = new CTAAirMoveType(unit);

			mt->turnRate = ud->turnRate;
			mt->maxSpeed = ud->speed / GAME_SPEED;
			mt->accRate = ud->maxAcc;
			mt->decRate = ud->maxDec;
			mt->wantedHeight = ud->wantedHeight + gs->randFloat() * 5;
			mt->orgWantedHeight = mt->wantedHeight;
			mt->dontLand = ud->DontLand();
			mt->collide = ud->collide;
			mt->altitudeRate = ud->verticalSpeed;
			mt->bankingAllowed = ud->bankingAllowed;

			unit->moveType = mt;
		}
		else {
			CAirMoveType *mt = new CAirMoveType(unit);

			if(type=="Fighter")
				mt->isFighter=true;

			mt->collide = ud->collide;

			mt->wingAngle = ud->wingAngle;
			mt->crashDrag = 1 - ud->crashDrag;
			mt->invDrag = 1 - ud->drag;
			mt->frontToSpeed = ud->frontToSpeed;
			mt->speedToFront = ud->speedToFront;
			mt->myGravity = ud->myGravity;

			mt->maxBank = ud->maxBank;
			mt->maxPitch = ud->maxPitch;
			mt->turnRadius = ud->turnRadius;
			mt->wantedHeight = (ud->wantedHeight * 1.5f) +
			                   ((gs->randFloat() - 0.3f) * 15 * (mt->isFighter ? 2 : 1));

			mt->maxAcc = ud->maxAcc;
			mt->maxAileron = ud->maxAileron;
			mt->maxElevator = ud->maxElevator;
			mt->maxRudder = ud->maxRudder;

			unit->moveType = mt;
		}
	} else {
		unit->moveType = new CMoveType(unit);
		unit->upright = true;
	}

	unit->energyTickMake = ud->energyMake;

	if (ud->tidalGenerator > 0)
		unit->energyTickMake += ud->tidalGenerator * mapInfo->map.tidalStrength;


	unit->model = ud->LoadModel();
	unit->SetRadius(unit->model->radius);

	modelParser->CreateLocalModel(unit);


	// copy the UnitDef volume instance
	//
	// aircraft still get half-size spheres for coldet purposes
	// iif no custom volume is defined (unit->model->radius and
	// unit->radius themselves are no longer altered)
	unit->collisionVolume = new CollisionVolume(ud->collisionVolume, unit->model->radius * ((ud->canfly)? 0.5f: 1.0f));

	if (unit->model->radius <= 60.0f) {
		// the interval-based method fails too easily for units
		// with small default volumes, force use of raytracing
		unit->collisionVolume->SetTestType(COLVOL_TEST_CONT);
	}


	if (ud->floater) {
		// restrict our depth to our waterline
		unit->pos.y = std::max(-ud->waterline, ground->GetHeight2(unit->pos.x, unit->pos.z));
	} else {
		unit->pos.y = ground->GetHeight2(unit->pos.x, unit->pos.z);
	}

	unit->script = CUnitScriptFactory::CreateScript(ud->scriptPath, unit);

	unit->weapons.reserve(ud->weapons.size());
	for (unsigned int i = 0; i < ud->weapons.size(); i++) {
		unit->weapons.push_back(LoadWeapon(ud->weapons[i].def, unit, &ud->weapons[i]));
	}

	// Call initializing script functions
	unit->script->Create();

	unit->heading = GetHeadingFromFacing(facing);
	unit->frontdir = GetVectorFromHeading(unit->heading);
	unit->updir = UpVector;
	unit->rightdir = unit->frontdir.cross(unit->updir);

	unit->yardMap = ud->yardmaps[facing];

	unit->Init(builder);

	if (!build) {
		unit->FinishedBuilding();
	}
	return unit;
}
void CPreGame::UpdateClientNet()
{
	int a;
	if((a=net->GetData(&inbuf[inbuflength],15000-inbuflength,0))==-1){
		globalQuit=true;
		return;
	}
	inbuflength+=a;

	while(inbufpos<inbuflength){
		switch (inbuf[inbufpos]){
		case NETMSG_HELLO:
			inbufpos += 1;
			break;

		case NETMSG_SCRIPT:
			CScriptHandler::SelectScript((char*)(&inbuf[inbufpos+2]));
			if (mapName.empty()) state = WAIT_ON_MAP;
			else if (modName.empty()) state = WAIT_ON_MOD;
			else state = ALL_READY;
			inbufpos += inbuf[inbufpos+1];
			break;

		case NETMSG_MAPNAME:
			SelectMap((char*)(&inbuf[inbufpos+6]));
			if (GetMapChecksum() != *(unsigned*)(&inbuf[inbufpos+2])) {
				char buf[256];
				sprintf(buf, "Local map archive(s) are not binary equal to host map archive(s).\n"
						"Make sure you installed all map dependencies & consider redownloading the map."
						"\n\nLocal checksum = %u\nRemote checksum = %u", GetMapChecksum(), *(unsigned*)(&inbuf[inbufpos+2]));
				throw content_error(buf);
			}
			if (!CScriptHandler::Instance().chosenScript) state = WAIT_ON_SCRIPT;
			else if (modName.empty()) state = WAIT_ON_MOD;
			else state = ALL_READY;
			inbufpos += inbuf[inbufpos+1];
			break;

		case NETMSG_MODNAME:
			SelectMod((char*)(&inbuf[inbufpos+6]));
			if (GetModChecksum() != *(unsigned*)(&inbuf[inbufpos+2])) {
				char buf[256];
				sprintf(buf, "Local mod archive(s) are not binary equal to host mod archive(s).\n"
						"Make sure you installed all mod dependencies & consider redownloading the mod."
						"\n\nLocal checksum = %u\nRemote checksum = %u", GetModChecksum(), *(unsigned*)(&inbuf[inbufpos+2]));
				throw content_error(buf);
			}
			if (!CScriptHandler::Instance().chosenScript) state = WAIT_ON_SCRIPT;
			else if (mapName.empty()) state = WAIT_ON_MAP;
			else state = ALL_READY;
			inbufpos += inbuf[inbufpos+1];

		case NETMSG_MAPDRAW:
			inbufpos += inbuf[inbufpos+1];	
			break;

		case NETMSG_SYSTEMMSG:
		case NETMSG_CHAT:{
			int player=inbuf[inbufpos+2];
			string s=(char*)(&inbuf[inbufpos+3]);
			logOutput.Print(s);
			inbufpos += inbuf[inbufpos+1];	
			break;}

		case NETMSG_STARTPOS:{
			inbufpos += 15;
			break;}

		case NETMSG_SETPLAYERNUM:
			gu->myPlayerNum=inbuf[inbufpos+1];
			logOutput.Print("Became player %i",gu->myPlayerNum);
			inbufpos += 2;
			break;

		case NETMSG_PLAYERNAME:
			gs->players[inbuf[inbufpos+2]]->playerName=(char*)(&inbuf[inbufpos+3]);
			gs->players[inbuf[inbufpos+2]]->readyToStart=true;
			gs->players[inbuf[inbufpos+2]]->active=true;
			inbufpos += inbuf[inbufpos+1];
			break;

		case NETMSG_QUIT:
			net->connected=false;
			globalQuit=true;
			return;

		case NETMSG_USER_SPEED:
		case NETMSG_INTERNAL_SPEED:
			inbufpos += 5;
			break;
		default:
			char txt[200];
			sprintf(txt,"Unknown net msg in client %d",(int)inbuf[inbufpos]);
			handleerror(0,txt,"Network error in CPreGame",0);
			inbufpos++;
			break;
		}
	}
}
S3DOModel* CS3OParser::LoadS3O(std::string name,float scale,int side)
{
	GML_STDMUTEX_LOCK(model); // LoadS3O

	if(name.find(".")==std::string::npos)
		name+=".s3o";

	StringToLowerInPlace(name);

	std::map<std::string,S3DOModel*>::iterator ui;
	if((ui=units.find(name))!=units.end()){
		return ui->second;
	}

	PUSH_CODE_MODE;
	ENTER_SYNCED;

	CFileHandler file(name);
	if(!file.FileExists()){
		POP_CODE_MODE;
		throw content_error("File not found: "+name);
	}
	unsigned char* fileBuf=SAFE_NEW unsigned char[file.FileSize()];
	file.Read(fileBuf, file.FileSize());
	S3OHeader header;
	memcpy(&header,fileBuf,sizeof(header));
	header.swap();

	S3DOModel *model = SAFE_NEW S3DOModel;
	model->numobjects=0;
	SS3O* object=LoadPiece(fileBuf,header.rootPiece,model);
	model->rootobjects3o=object;
	model->rootobject3do=0;
	object->isEmpty=true;
	model->name=name;
	model->tex1=(char*)&fileBuf[header.texture1];
	model->tex2=(char*)&fileBuf[header.texture2];
	texturehandler->LoadS3OTexture(model);

	FindMinMax(object);

	units[name]=model;

	CreateLists(object);

	// this is a hack to make aircrafts less likely to collide and get hit by nontracking weapons
	// note: does not apply anymore, unit <--> projectile coldet no longer depends on model->radius
	model->radius = header.radius * scale;
	model->height = header.height;
	model->relMidPos.x=header.midx;
	model->relMidPos.y=header.midy;
	model->relMidPos.z=header.midz;
	if(model->relMidPos.y<1)
		model->relMidPos.y=1;

//	logOutput.Print("%s has height %f",name,model->height);
	fartextureHandler->CreateFarTexture(model);

	model->maxx=model->rootobjects3o->maxx;
	model->maxy=model->rootobjects3o->maxy;
	model->maxz=model->rootobjects3o->maxz;

	model->minx=model->rootobjects3o->minx;
	model->miny=model->rootobjects3o->miny;
	model->minz=model->rootobjects3o->minz;

	delete[] fileBuf;
	POP_CODE_MODE;
	return model;
}
Exemple #23
0
void CMouseHandler::ReloadCursors()
{
	const CMouseCursor::HotSpot mCenter  = CMouseCursor::Center;
	const CMouseCursor::HotSpot mTopLeft = CMouseCursor::TopLeft;

	activeCursorIdx = -1;

	loadedCursors.clear();
	loadedCursors.reserve(32);
	// null-cursor; always lives at index 0
	loadedCursors.emplace_back();

	cursorCommandMap.clear();
	cursorCommandMap.reserve(32);
	cursorFileMap.clear();
	cursorFileMap.reserve(32);

	cursorCommandMap["none"] = loadedCursors.size() - 1;
	cursorFileMap["null"] = loadedCursors.size() - 1;

	AssignMouseCursor("",             "cursornormal",     mTopLeft, false);

	AssignMouseCursor("Area attack",  "cursorareaattack", mCenter,  false);
	AssignMouseCursor("Area attack",  "cursorattack",     mCenter,  false); // backup

	AssignMouseCursor("Attack",       "cursorattack",     mCenter,  false);
	AssignMouseCursor("AttackBad",    "cursorattackbad",  mCenter,  false);
	AssignMouseCursor("AttackBad",    "cursorattack",     mCenter,  false); // backup
	AssignMouseCursor("BuildBad",     "cursorbuildbad",   mCenter,  false);
	AssignMouseCursor("BuildGood",    "cursorbuildgood",  mCenter,  false);
	AssignMouseCursor("Capture",      "cursorcapture",    mCenter,  false);
	AssignMouseCursor("Centroid",     "cursorcentroid",   mCenter,  false);

	AssignMouseCursor("DeathWait",    "cursordwatch",     mCenter,  false);
	AssignMouseCursor("DeathWait",    "cursorwait",       mCenter,  false); // backup

	AssignMouseCursor("ManualFire",   "cursormanfire",    mCenter,  false);
	AssignMouseCursor("ManualFire",   "cursordgun",       mCenter,  false); // backup (backward compability)
	AssignMouseCursor("ManualFire",   "cursorattack",     mCenter,  false); // backup

	AssignMouseCursor("Fight",        "cursorfight",      mCenter,  false);
	AssignMouseCursor("Fight",        "cursorattack",     mCenter,  false); // backup

	AssignMouseCursor("GatherWait",   "cursorgather",     mCenter,  false);
	AssignMouseCursor("GatherWait",   "cursorwait",       mCenter,  false); // backup

	AssignMouseCursor("Guard",        "cursordefend",     mCenter,  false);
	AssignMouseCursor("Load units",   "cursorpickup",     mCenter,  false);
	AssignMouseCursor("Move",         "cursormove",       mCenter,  false);
	AssignMouseCursor("Patrol",       "cursorpatrol",     mCenter,  false);
	AssignMouseCursor("Reclaim",      "cursorreclamate",  mCenter,  false);
	AssignMouseCursor("Repair",       "cursorrepair",     mCenter,  false);

	AssignMouseCursor("Resurrect",    "cursorrevive",     mCenter,  false);
	AssignMouseCursor("Resurrect",    "cursorrepair",     mCenter,  false); // backup

	AssignMouseCursor("Restore",      "cursorrestore",    mCenter,  false);
	AssignMouseCursor("Restore",      "cursorrepair",     mCenter,  false); // backup

	AssignMouseCursor("SelfD",        "cursorselfd",      mCenter,  false);

	AssignMouseCursor("SquadWait",    "cursornumber",     mCenter,  false);
	AssignMouseCursor("SquadWait",    "cursorwait",       mCenter,  false); // backup

	AssignMouseCursor("TimeWait",     "cursortime",       mCenter,  false);
	AssignMouseCursor("TimeWait",     "cursorwait",       mCenter,  false); // backup

	AssignMouseCursor("Unload units", "cursorunload",     mCenter,  false);
	AssignMouseCursor("Wait",         "cursorwait",       mCenter,  false);

	// the default cursor must exist
	const auto defCursorIt = cursorCommandMap.find("");

	if (defCursorIt == cursorCommandMap.end()) {
		throw content_error(
			"Unable to load default cursor. Check that you have the required\n"
			"content packages installed in your Spring \"base/\" directory.\n");
	}

	activeCursorIdx = defCursorIt->second;
}
void CSpawnScript::Update()
{
	switch(gs->frameNum){
	case 0:
		LoadSpawns();

		const std::string startUnit0 = sideParser.GetStartUnit(0);

		if (startUnit0.length() == 0) {
			throw content_error ("Unable to load a startUnit for the first side");
		}

		MapParser mapParser(stupidGlobalMapname);
		if (!mapParser.IsValid()) {
			throw content_error("MapParser: " + mapParser.GetErrorLog());
		}
		float3 startPos0(1000.0f, 80.0f, 1000.0f);
		mapParser.GetStartPos(0, startPos0);

		// Set the TEAM0 startpos as spawnpos if we're supposed to be
		// autonomous, load the commander for the player if not.
		if (autonomous) {
			spawnPos.push_back(startPos0);
		} else {
			unitLoader.LoadUnit(startUnit0, startPos0, 0, false, 0, NULL);
		}

		// load the start positions for teams 1 - 3
		for (int teamID = 1; teamID <= 3; teamID++) {
			float3 sp(1000.0f, 80.0f, 1000.0f);
			mapParser.GetStartPos(teamID, sp);
			spawnPos.push_back(sp);
		}
	}

	if(!spawns.empty()){
		while(curSpawn->frame+frameOffset<gs->frameNum){
			int num = gs->randInt() % spawnPos.size();
			int team = autonomous ? (num & 1) : 1;
			float3 pos;
			float dist=200;
			CFeature* feature;
			do {
				pos=spawnPos[num]+gs->randVector()*dist;
				dist*=1.05f;
			} while (dist < 500 && uh->TestUnitBuildSquare(BuildInfo(curSpawn->name,pos,0),feature,team) != 2);

			// Ignore unit if it really doesn't fit.
			// (within 18 tries, 200*1.05f^18 < 500 < 200*1.05f^19)
			if (dist < 500) {
				CUnit* u = unitLoader.LoadUnit(curSpawn->name, pos, team, false, 0, NULL);

				Unit unit;
				unit.id=u->id;
				unit.target=-1;
				unit.team=team;
				myUnits.push_back(unit);
				if(myUnits.size()==1)
					curUnit=myUnits.begin();
			}

			++curSpawn;
			if(curSpawn==spawns.end()){
				curSpawn=spawns.begin();
				frameOffset+=spawns.back().frame;
			}
		}
	}

	if(!myUnits.empty() && !gs->Team(1 - curUnit->team)->units.empty()) {
		if(uh->units[curUnit->id]){
			if(curUnit->target<0 || uh->units[curUnit->target]==0){
				// We can't rely on the ordering of units in a std::set<CUnit*>,
				// because they're sorted on memory address. Hence we must first
				// build a set of IDs and then pick an unit from that.
				// This guarantees the script doesn't desync in multiplayer games.
				int num = gs->randInt() % gs->Team(1 - curUnit->team)->units.size();
				std::set<int> unitids;
				CUnitSet* tu = &gs->Team(1 - curUnit->team)->units;
				for (CUnitSet::iterator u = tu->begin(); u != tu->end(); ++u)
					unitids.insert((*u)->id);
				std::set<int>::iterator ui = unitids.begin();
				for(int a=0;a<num;++a)
					++ui;
				curUnit->target=(*ui);
				curUnit->lastTargetPos.x=-500;
			}
			float3 pos=uh->units[curUnit->target]->pos;
			if(pos.distance2D(curUnit->lastTargetPos)>100){
				curUnit->lastTargetPos=pos;
				Command c;
				c.id=CMD_PATROL;
				c.options=0;
				c.params.push_back(pos.x);
				c.params.push_back(pos.y);
				c.params.push_back(pos.z);
				uh->units[curUnit->id]->commandAI->GiveCommand(c);
			}
			curUnit++;
		} else {
			curUnit=myUnits.erase(curUnit);
		}
		if(curUnit==myUnits.end())
			curUnit=myUnits.begin();
	}
}
Exemple #25
0
int main(int argc, char *argv[])
{
#ifdef _WIN32
	try {
#endif
	SDL_Init(SDL_INIT_TIMER);
	std::cout << "If you find any errors, report them to mantis or the forums." << std::endl << std::endl;

	ConfigHandler::Instantiate(); // use the default config file
	FileSystemHandler::Initialize(false);

	CGameServer* server = 0;
	CGameSetup* gameSetup = 0;

	if (argc == 2) {
		const std::string script(argv[1]);
		std::string buf;

		std::cout << "Loading script from file: " << script << std::endl;

		ClientSetup settings;
		CFileHandler fh(argv[1]);

		if (!fh.FileExists())
			throw content_error("script does not exist in given location: " + script);

		if (!fh.LoadStringData(buf))
			throw content_error("script cannot be read: " + script);
		settings.Init(buf);

		gameSetup = new CGameSetup();	// to store the gamedata inside

		if (!gameSetup->Init(buf)) {
			// read the script provided by cmdline
			std::cout << "Failed to load script" << std::endl;
			return 1;
		}

		std::cout << "Starting server..." << std::endl;

		// Create the server, it will run in a separate thread
		GameData data;
		UnsyncedRNG rng;

		rng.Seed(gameSetup->gameSetupText.length());
		rng.Seed(script.length());
		data.SetRandomSeed(rng.RandInt());

		//  Use script provided hashes if they exist
		if (gameSetup->mapHash != 0) {
			data.SetMapChecksum(gameSetup->mapHash);
			gameSetup->LoadStartPositions(false); // reduced mode
		} else {
			data.SetMapChecksum(archiveScanner->GetArchiveCompleteChecksum(gameSetup->mapName));

			CFileHandler f("maps/" + gameSetup->mapName);
			if (!f.FileExists()) {
				vfsHandler->AddArchiveWithDeps(gameSetup->mapName, false);
			}
			gameSetup->LoadStartPositions(); // full mode
		}

		if (gameSetup->modHash != 0) {
			data.SetModChecksum(gameSetup->modHash);
		} else {
			const std::string& modArchive = archiveScanner->ArchiveFromName(gameSetup->modName);
			const unsigned int modCheckSum = archiveScanner->GetArchiveCompleteChecksum(modArchive);
			data.SetModChecksum(modCheckSum);
		}

		data.SetSetup(gameSetup->gameSetupText);
		server = new CGameServer(settings.hostIP, settings.hostPort, &data, gameSetup);

		while (!server->HasFinished()) // check if still running
#ifdef _WIN32
			Sleep(1000);
#else
			sleep(1);	// if so, wait 1  second
#endif
		delete server;	// delete the server after usage
	} else {
		std::cout << "usage: " << argv[0] << " <full_path_to_script>" << std::endl;
	}

	FileSystemHandler::Cleanup();
	ConfigHandler::Deallocate();

#ifdef _WIN32
	} catch (const std::exception& err) {
		std::cout << "Exception raised: " << err.what() << std::endl;
		return 1;
	}
#endif
	return 0;
}
Exemple #26
0
void CMapGenerator::GenerateSMT(CVirtualArchive* archive)
{
	CVirtualFile* fileSMT = archive->AddFile("maps/generated.smt");

	const int tileSize = 32;

	//--- Make TileFileHeader ---
	TileFileHeader smtHeader;
	strcpy(smtHeader.magic, "spring tilefile");
	smtHeader.version = 1;
	smtHeader.numTiles = 1; //32 * 32 * (generator->GetMapSize().x * 32) * (generator->GetMapSize().y * 32);
	smtHeader.tileSize = tileSize;
	smtHeader.compressionType = 1;

	const int bpp = 3;
	int tilePos = 0;
	unsigned char tileData[tileSize * tileSize * bpp];
	for(int x = 0; x < tileSize; x++)
	{
		for(int y = 0; y < tileSize; y++)
		{
			tileData[tilePos] = 0;
			tileData[tilePos + 1] = 0xFF;
			tileData[tilePos + 2] = 0;
			tilePos += bpp;
		}
	}
	glClearErrors();
	GLuint tileTex;
	glGenTextures(1, &tileTex);
	glBindTexture(GL_TEXTURE_2D, tileTex);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, tileSize, tileSize, 0, GL_RGB, GL_UNSIGNED_BYTE, tileData);
	glGenerateMipmapEXT(GL_TEXTURE_2D);
	char tileDataDXT[SMALL_TILE_SIZE];

	int dxtImageOffset = 0;
	int dxtImageSize = 512;
	for(int x = 0; x < 4; x++)
	{
		glGetCompressedTexImage(GL_TEXTURE_2D, x, tileDataDXT + dxtImageOffset);
		dxtImageOffset += dxtImageSize;
		dxtImageSize /= 4;
	}

	glDeleteTextures(1, &tileTex);

	GLenum errorcode = glGetError();
	if(errorcode != GL_NO_ERROR)
	{
		throw content_error("Error generating map - texture generation not supported");
	}

	size_t totalSize = sizeof(TileFileHeader);
	fileSMT->buffer.resize(totalSize);

	int writePosition = 0;
	memcpy(&(fileSMT->buffer[writePosition]), &smtHeader, sizeof(smtHeader));
	writePosition += sizeof(smtHeader);

	fileSMT->buffer.resize(fileSMT->buffer.size() + smtHeader.numTiles * SMALL_TILE_SIZE);
	for(int x = 0; x < smtHeader.numTiles; x++)
	{
		memcpy(&(fileSMT->buffer[writePosition]), tileDataDXT, SMALL_TILE_SIZE);
		writePosition += SMALL_TILE_SIZE;
	}
}
Exemple #27
0
void CMouseHandler::LoadCursors()
{
	const CMouseCursor::HotSpot mCenter  = CMouseCursor::Center;
	const CMouseCursor::HotSpot mTopLeft = CMouseCursor::TopLeft;

	CMouseCursor* nullCursor = CMouseCursor::GetNullCursor();
	cursorCommandMap["none"] = nullCursor;
	// Note: we intentionally don't add it there cause GetNullCursor() returns
	//  a pointer to a static var, so it gets automatically deleted
	//cursorFileMap["null"] = nullCursor;

	AssignMouseCursor("",             "cursornormal",     mTopLeft, false);

	AssignMouseCursor("Area attack",  "cursorareaattack", mCenter,  false);
	AssignMouseCursor("Area attack",  "cursorattack",     mCenter,  false); // backup

	AssignMouseCursor("Attack",       "cursorattack",     mCenter,  false);
	AssignMouseCursor("AttackBad",    "cursorattackbad",  mCenter,  false);
	AssignMouseCursor("AttackBad",    "cursorattack",     mCenter,  false); // backup
	AssignMouseCursor("BuildBad",     "cursorbuildbad",   mCenter,  false);
	AssignMouseCursor("BuildGood",    "cursorbuildgood",  mCenter,  false);
	AssignMouseCursor("Capture",      "cursorcapture",    mCenter,  false);
	AssignMouseCursor("Centroid",     "cursorcentroid",   mCenter,  false);

	AssignMouseCursor("DeathWait",    "cursordwatch",     mCenter,  false);
	AssignMouseCursor("DeathWait",    "cursorwait",       mCenter,  false); // backup

	AssignMouseCursor("ManualFire",   "cursormanfire",    mCenter,  false);
	AssignMouseCursor("ManualFire",   "cursordgun",       mCenter,  false); // backup (backward compability)
	AssignMouseCursor("ManualFire",   "cursorattack",     mCenter,  false); // backup

	AssignMouseCursor("Fight",        "cursorfight",      mCenter,  false);
	AssignMouseCursor("Fight",        "cursorattack",     mCenter,  false); // backup

	AssignMouseCursor("GatherWait",   "cursorgather",     mCenter,  false);
	AssignMouseCursor("GatherWait",   "cursorwait",       mCenter,  false); // backup

	AssignMouseCursor("Guard",        "cursordefend",     mCenter,  false);
	AssignMouseCursor("Load units",   "cursorpickup",     mCenter,  false);
	AssignMouseCursor("Move",         "cursormove",       mCenter,  false);
	AssignMouseCursor("Patrol",       "cursorpatrol",     mCenter,  false);
	AssignMouseCursor("Reclaim",      "cursorreclamate",  mCenter,  false);
	AssignMouseCursor("Repair",       "cursorrepair",     mCenter,  false);

	AssignMouseCursor("Resurrect",    "cursorrevive",     mCenter,  false);
	AssignMouseCursor("Resurrect",    "cursorrepair",     mCenter,  false); // backup

	AssignMouseCursor("Restore",      "cursorrestore",    mCenter,  false);
	AssignMouseCursor("Restore",      "cursorrepair",     mCenter,  false); // backup

	AssignMouseCursor("SelfD",        "cursorselfd",      mCenter,  false);

	AssignMouseCursor("SquadWait",    "cursornumber",     mCenter,  false);
	AssignMouseCursor("SquadWait",    "cursorwait",       mCenter,  false); // backup

	AssignMouseCursor("TimeWait",     "cursortime",       mCenter,  false);
	AssignMouseCursor("TimeWait",     "cursorwait",       mCenter,  false); // backup

	AssignMouseCursor("Unload units", "cursorunload",     mCenter,  false);
	AssignMouseCursor("Wait",         "cursorwait",       mCenter,  false);

	// the default cursor must exist
	if (cursorCommandMap.find("") == cursorCommandMap.end()) {
		throw content_error(
			"Unable to load default cursor. Check that you have the required\n"
			"content packages installed in your Spring \"base/\" directory.\n");
	}
}
Exemple #28
0
CUnit* CUnitLoader::LoadUnit(const UnitLoadParams& cparams)
{
    CUnit* unit = NULL;
    UnitLoadParams& params = const_cast<UnitLoadParams&>(cparams);

    {
        GML_RECMUTEX_LOCK(sel); // LoadUnit - for anti deadlock purposes.
        GML_RECMUTEX_LOCK(quad); // LoadUnit - make sure other threads cannot access an incomplete unit

        const UnitDef* ud = params.unitDef;

        if (ud == NULL)
            return unit;
        // need to check this BEFORE creating the instance
        if (!unitHandler->CanAddUnit(cparams.unitID))
            return unit;

        if (params.teamID < 0) {
            // FIXME use gs->gaiaTeamID ?  (once it is always enabled)
            if ((params.teamID = teamHandler->GaiaTeamID()) < 0)
                throw content_error("Invalid team and no gaia team to put unit in");
        }

        if (ud->IsTransportUnit()) {
            unit = new CTransportUnit();
        } else if (ud->IsFactoryUnit()) {
            // special static builder structures that can always be given
            // move orders (which are passed on to all mobile buildees)
            unit = new CFactory();
        } else if (ud->IsMobileBuilderUnit() || ud->IsStaticBuilderUnit()) {
            // all other types of non-structure "builders", including hubs and
            // nano-towers (the latter should not have any build-options at all,
            // whereas the former should be unable to build any mobile units)
            unit = new CBuilder();
        } else if (ud->IsBuildingUnit()) {
            // static non-builder structures
            if (ud->IsExtractorUnit()) {
                unit = new CExtractorBuilding();
            } else {
                unit = new CBuilding();
            }
        } else {
            // regular mobile unit
            unit = new CUnit();
        }

        unit->PreInit(params);

        if (ud->IsTransportUnit()) {
            new CTransportCAI(unit);
        } else if (ud->IsFactoryUnit()) {
            new CFactoryCAI(unit);
        } else if (ud->IsMobileBuilderUnit() || ud->IsStaticBuilderUnit()) {
            new CBuilderCAI(unit);
        } else if (ud->IsStrafingAirUnit()) {
            // non-hovering fighter or bomber aircraft; coupled to StrafeAirMoveType
            new CAirCAI(unit);
        } else if (ud->IsAirUnit()) {
            // all other aircraft; coupled to HoverAirMoveType
            new CMobileCAI(unit);
        } else if (ud->IsGroundUnit()) {
            new CMobileCAI(unit);
        } else {
            new CCommandAI(unit);
        }
    }

    unit->PostInit(params.builder);
    (eventBatchHandler->GetUnitCreatedDestroyedBatch()).enqueue(EventBatchHandler::UD(unit, unit->isCloaked));

    if (params.flattenGround) {
        FlattenGround(unit);
    }

    return unit;
}
CFactoryCAI::CFactoryCAI(CUnit* owner)
: CCommandAI(owner),
	building(false),
	lastRestrictedWarning(0)
{
	commandQue.SetQueueType(CCommandQueue::BuildQueueType);
	newUnitCommands.SetQueueType(CCommandQueue::NewUnitQueueType);

	CommandDescription c;

	// can't check for canmove here because it should be possible to assign rallypoint
	// with a non-moving factory.
	c.id=CMD_MOVE;
	c.action="move";
	c.type=CMDTYPE_ICON_MAP;
	c.name="Move";
	c.mouseicon=c.name;
	c.tooltip="Move: Order ready built units to move to a position";
	possibleCommands.push_back(c);

	if (owner->unitDef->canPatrol) {
		c.id=CMD_PATROL;
		c.action="patrol";
		c.type=CMDTYPE_ICON_MAP;
		c.name="Patrol";
		c.mouseicon=c.name;
		c.tooltip="Patrol: Order ready built units to patrol to one or more waypoints";
		possibleCommands.push_back(c);
	}

	if (owner->unitDef->canFight) {
		c.id = CMD_FIGHT;
		c.action="fight";
		c.type = CMDTYPE_ICON_MAP;
		c.name = "Fight";
		c.mouseicon=c.name;
		c.tooltip = "Fight: Order ready built units to take action while moving to a position";
		possibleCommands.push_back(c);
	}

	if (owner->unitDef->canGuard) {
		c.id=CMD_GUARD;
		c.action="guard";
		c.type=CMDTYPE_ICON_UNIT;
		c.name="Guard";
		c.mouseicon=c.name;
		c.tooltip="Guard: Order ready built units to guard another unit and attack units attacking it";
		possibleCommands.push_back(c);
	}

	CFactory* fac=(CFactory*)owner;

	map<int,string>::const_iterator bi;
	for (bi = fac->unitDef->buildOptions.begin(); bi != fac->unitDef->buildOptions.end(); ++bi) {
		const string name = bi->second;

		const UnitDef* ud = unitDefHandler->GetUnitByName(name);
		if (ud == NULL) {
		  string errmsg = "MOD ERROR: loading ";
		  errmsg += name.c_str();
		  errmsg += " for ";
		  errmsg += owner->unitDef->name;
			throw content_error(errmsg);
		}

		CommandDescription c;
		c.id = -ud->id; //build options are always negative
		c.action = "buildunit_" + StringToLower(ud->name);
		c.type = CMDTYPE_ICON;
		c.name = name;
		c.mouseicon = c.name;
		c.disabled = (ud->maxThisUnit <= 0);

		char tmp[1024];
		sprintf(tmp, "\nHealth %.0f\nMetal cost %.0f\nEnergy cost %.0f Build time %.0f",
		        ud->health, ud->metalCost, ud->energyCost, ud->buildTime);
		if (c.disabled) {
			c.tooltip = "\xff\xff\x22\x22" "DISABLED: " "\xff\xff\xff\xff";
		} else {
			c.tooltip = "Build: ";
		}
		c.tooltip += ud->humanName + " - " + ud->tooltip + tmp;

		possibleCommands.push_back(c);
		BuildOption bo;
		bo.name = name;
		bo.fullName = name;
		bo.numQued = 0;
		buildOptions[c.id] = bo;
	}
}
CUnit* CUnitLoader::LoadUnit(const string& name, float3 pos, int team,
                             bool build, int facing, const CUnit* builder)
{
//	GML_RECMUTEX_LOCK(unit); // LoadUnit. Unitinit puts unit in the quadfield and activeUnits -
	GML_RECMUTEX_LOCK(sel); // LoadUnit. For anti deadlock purposes.
	GML_RECMUTEX_LOCK(quad); // LoadUnit. - make sure other threads cannot access an incomplete unit

	CUnit* unit;

	SCOPED_TIMER("Unit loader");

	const UnitDef* ud = unitDefHandler->GetUnitByName(name);
	if (!ud) {
		throw content_error("Couldn't find unittype " +  name);
	}

	string type = ud->type;

	if (!build) {
		pos.y = ground->GetHeight2(pos.x, pos.z);
		if (ud->floater && pos.y < 0.0f) {
			// adjust to waterline iif we are submerged
 			pos.y = -ud->waterline;
		}
	}

	if (team < 0) {
		team = MAX_TEAMS - 1; // FIXME use gs->gaiaTeamID ?  (once it is always enabled)
	}

	if (type == "GroundUnit") {
		unit = SAFE_NEW CUnit;
	} else if (type == "Transport") {
		unit = SAFE_NEW CTransportUnit;
	} else if (type == "Building") {
		unit = SAFE_NEW CBuilding;
	} else if (type == "Factory") {
		unit = SAFE_NEW CFactory;
	} else if (type == "Builder") {
		unit = SAFE_NEW CBuilder;
	} else if (type == "Bomber" || type == "Fighter") {
		unit = SAFE_NEW CUnit;
	} else if (type == "MetalExtractor") {
		unit = SAFE_NEW CExtractorBuilding;
	} else {
		logOutput << "Unknown unit type " << type.c_str() << "\n";
		return NULL;
	}

	unit->UnitInit(ud, team, pos);

	unit->beingBuilt = build;

	unit->xsize = ((facing & 1) == 0) ? ud->xsize : ud->zsize;
	unit->zsize = ((facing & 1) == 1) ? ud->xsize : ud->zsize;
	unit->buildFacing = facing;
	unit->power = ud->power;
	unit->maxHealth = ud->health;
	unit->health = ud->health;
	//unit->metalUpkeep = ud->metalUpkeep*16.0f/GAME_SPEED;
	//unit->energyUpkeep = ud->energyUpkeep*16.0f/GAME_SPEED;
	unit->controlRadius = (int)(ud->controlRadius / SQUARE_SIZE);
	unit->losHeight = ud->losHeight;
	unit->metalCost = ud->metalCost;
	unit->energyCost = ud->energyCost;
	unit->buildTime = ud->buildTime;
	unit->aihint = ud->aihint;
	unit->tooltip = ud->humanName + " - " + ud->tooltip;
	unit->armoredMultiple = std::max(0.0001f, ud->armoredMultiple);		//armored multiple of 0 will crash spring
	unit->wreckName = ud->wreckName;

	unit->realLosRadius = (int) (ud->losRadius);
	unit->realAirLosRadius = (int) (ud->airLosRadius);
	unit->upright = ud->upright;
	unit->radarRadius      = ud->radarRadius    / (SQUARE_SIZE * 8);
	unit->sonarRadius      = ud->sonarRadius    / (SQUARE_SIZE * 8);
	unit->jammerRadius     = ud->jammerRadius   / (SQUARE_SIZE * 8);
	unit->sonarJamRadius   = ud->sonarJamRadius / (SQUARE_SIZE * 8);
	unit->seismicRadius    = ud->seismicRadius  / (SQUARE_SIZE * 8);
	unit->seismicSignature = ud->seismicSignature;
	unit->hasRadarCapacity = unit->radarRadius  || unit->sonarRadius    ||
	                         unit->jammerRadius || unit->sonarJamRadius ||
	                         unit->seismicRadius;
	unit->stealth = ud->stealth;
	unit->sonarStealth = ud->sonarStealth;
	unit->category = ud->category;
	unit->armorType = ud->armorType;
	unit->floatOnWater =
		ud->floater || (ud->movedata && ((ud->movedata->moveType == MoveData::Hover_Move) ||
		                                 (ud->movedata->moveType == MoveData::Ship_Move)));
	unit->maxSpeed = ud->speed / 30.0f;
	unit->decloakDistance = ud->decloakDistance;

	unit->flankingBonusMode        = ud->flankingBonusMode;
	unit->flankingBonusDir         = ud->flankingBonusDir;
	unit->flankingBonusMobility    = ud->flankingBonusMobilityAdd * 1000;
	unit->flankingBonusMobilityAdd = ud->flankingBonusMobilityAdd;
	unit->flankingBonusAvgDamage = (ud->flankingBonusMax + ud->flankingBonusMin) * 0.5f;
	unit->flankingBonusDifDamage = (ud->flankingBonusMax - ud->flankingBonusMin) * 0.5f;


	if(ud->highTrajectoryType==1)
		unit->useHighTrajectory=true;

	if(ud->fireState >= 0)
		unit->fireState = ud->fireState;

	if(build){
		unit->ChangeLos(1,1);
		unit->health=0.1f;
	} else {
		unit->ChangeLos((int)(ud->losRadius),(int)(ud->airLosRadius));
	}

	if (type == "GroundUnit") {
		SAFE_NEW CMobileCAI(unit);
	}
	else if (type == "Transport") {
		SAFE_NEW CTransportCAI(unit);
	}
	else if (type == "Factory") {
		SAFE_NEW CFactoryCAI(unit);
	}
	else if (type == "Builder") {
		SAFE_NEW CBuilderCAI(unit);
	}
	else if (type == "Bomber") {
		if (ud->hoverAttack) {
			SAFE_NEW CMobileCAI(unit);
		} else {
			SAFE_NEW CAirCAI(unit);
		}
	}
	else if(type == "Fighter"){
		if (ud->hoverAttack) {
			SAFE_NEW CMobileCAI(unit);
		} else {
			SAFE_NEW CAirCAI(unit);
		}
	}
	else {
		SAFE_NEW CCommandAI(unit);
	}

	if (ud->canmove && !ud->canfly && (type != "Factory")) {
		CGroundMoveType* mt = SAFE_NEW CGroundMoveType(unit);
		mt->maxSpeed = ud->speed / GAME_SPEED;
		mt->maxWantedSpeed = ud->speed / GAME_SPEED;
		mt->turnRate = ud->turnRate;
		mt->baseTurnRate = ud->turnRate;

		if (!mt->accRate) {
			logOutput << "acceleration of " << ud->name.c_str() << " is zero!!\n";
		}

		mt->moveType = ud->moveType;
		mt->accRate = ud->maxAcc;
		mt->decRate = ud->maxDec;
		mt->floatOnWater = (ud->movedata->moveType == MoveData::Hover_Move ||
		                    ud->movedata->moveType == MoveData::Ship_Move);

		if (!unit->beingBuilt) {
			// otherwise set this when finished building instead
			unit->mass = ud->mass;
		}
		unit->moveType = mt;

		// Ground-mobility
		unit->mobility = SAFE_NEW MoveData(ud->movedata, GAME_SPEED);

	} else if (ud->canfly) {
		// Air-mobility
		unit->mobility = SAFE_NEW MoveData(ud->movedata, GAME_SPEED);

		if (!unit->beingBuilt) {
			// otherwise set this when finished building instead
			unit->mass = ud->mass;
		}

		if ((type == "Builder") || ud->hoverAttack || ud->transportCapacity) {
			CTAAirMoveType* mt = SAFE_NEW CTAAirMoveType(unit);

			mt->turnRate = ud->turnRate;
			mt->maxSpeed = ud->speed / GAME_SPEED;
			mt->accRate = ud->maxAcc;
			mt->decRate = ud->maxDec;
			mt->wantedHeight = ud->wantedHeight + gs->randFloat() * 5;
			mt->orgWantedHeight = mt->wantedHeight;
			mt->dontLand = ud->DontLand();
			mt->collide = ud->collide;
			mt->altitudeRate = ud->verticalSpeed;
			mt->bankingAllowed = ud->bankingAllowed;

			unit->moveType = mt;
		}
		else {
			CAirMoveType *mt = SAFE_NEW CAirMoveType(unit);

			if(type=="Fighter")
				mt->isFighter=true;

			mt->collide = ud->collide;

			mt->wingAngle = ud->wingAngle;
			mt->crashDrag = 1 - ud->crashDrag;
			mt->invDrag = 1 - ud->drag;
			mt->frontToSpeed = ud->frontToSpeed;
			mt->speedToFront = ud->speedToFront;
			mt->myGravity = ud->myGravity;

			mt->maxBank = ud->maxBank;
			mt->maxPitch = ud->maxPitch;
			mt->turnRadius = ud->turnRadius;
			mt->wantedHeight = (ud->wantedHeight * 1.5f) +
			                   ((gs->randFloat() - 0.3f) * 15 * (mt->isFighter ? 2 : 1));

			mt->maxAcc = ud->maxAcc;
			mt->maxAileron = ud->maxAileron;
			mt->maxElevator = ud->maxElevator;
			mt->maxRudder = ud->maxRudder;

			unit->moveType = mt;
		}
	} else {
		unit->moveType = SAFE_NEW CMoveType(unit);
		unit->upright = true;
	}

	unit->energyTickMake = ud->energyMake;

	if (ud->tidalGenerator > 0)
		unit->energyTickMake += ud->tidalGenerator * mapInfo->map.tidalStrength;


	unit->model = LoadModel(ud);
	unit->SetRadius(unit->model->radius);

	// copy the UnitDef volume archetype data
	unit->collisionVolume = SAFE_NEW CollisionVolume(ud->collisionVolume);

	// if no "collisionVolumeScales" tag was defined in UnitDef,
	// the default scale for this volume will be a ZeroVector
	if (unit->collisionVolume->GetScale(COLVOL_AXIS_X) <= 1.0f &&
		unit->collisionVolume->GetScale(COLVOL_AXIS_Y) <= 1.0f &&
		unit->collisionVolume->GetScale(COLVOL_AXIS_Z) <= 1.0f) {
		// aircraft still get half-size spheres for coldet purposes
		// if no custom volume is defined (unit->model->radius and
		// unit->radius themselves are no longer altered)
		const float scaleFactor = (ud->canfly)? 0.5f: 1.0f;
		unit->collisionVolume->SetDefaultScale(unit->model->radius * scaleFactor);

		if (unit->collisionVolume->GetBoundingRadius() <= 30.0f) {
			// the interval-based method fails too easily for units
			// with small default volumes, force use of raytracing
			unit->collisionVolume->SetTestType(COLVOL_TEST_CONT);
		}
	}

	if (ud->floater) {
		// restrict our depth to our waterline
		unit->pos.y = std::max(-ud->waterline, ground->GetHeight2(unit->pos.x, unit->pos.z));
	} else {
		unit->pos.y = ground->GetHeight2(unit->pos.x, unit->pos.z);
	}

	modelParser->CreateLocalModel(unit);
	unit->cob = SAFE_NEW CCobInstance(GCobEngine.GetCobFile("scripts/" + ud->cobFilename), unit);

	unit->weapons.reserve(ud->weapons.size());
	for (unsigned int i = 0; i < ud->weapons.size(); i++) {
		unit->weapons.push_back(LoadWeapon(ud->weapons[i].def, unit, &ud->weapons[i]));
	}

	// Calculate the max() of the available weapon reloadtimes
	int relMax = 0;
	for (vector<CWeapon*>::iterator i = unit->weapons.begin(); i != unit->weapons.end(); ++i) {
		if ((*i)->reloadTime > relMax)
			relMax = (*i)->reloadTime;
		if (dynamic_cast<CBeamLaser*>(*i))
			relMax = 150;
	}

	// convert ticks to milliseconds
	relMax *= 30;

	// TA does some special handling depending on weapon count
	if (unit->weapons.size() > 1) {
		relMax = std::max(relMax, 3000);
	}

	// Call initializing script functions
	unit->cob->Call(COBFN_Create);
	unit->cob->Call("SetMaxReloadTime", relMax);

	unit->heading = GetHeadingFromFacing(facing);
	unit->frontdir = GetVectorFromHeading(unit->heading);
	unit->updir = UpVector;
	unit->rightdir = unit->frontdir.cross(unit->updir);

	unit->yardMap = ud->yardmaps[facing];

	unit->Init(builder);

	if (!build) {
		unit->FinishedBuilding();
	}
	return unit;
}