void CMapInfo::ReadTerrainTypes()
{
	const LuaTable terrTypeTable =
		mapRoot->SubTable("terrainTypes");

	for (int tt = 0; tt < 256; tt++) {
		TerrainType& terrType = terrainTypes[tt];
		const LuaTable terrain = terrTypeTable.SubTable(tt);
		terrType.name          = terrain.GetString("name", "Default");
		terrType.hardness      = terrain.GetFloat("hardness",   1.0f);
		terrType.receiveTracks = terrain.GetBool("receiveTracks", true);
		const LuaTable moveTable = terrain.SubTable("moveSpeeds");
		terrType.tankSpeed  = moveTable.GetFloat("tank",  1.0f);
		terrType.kbotSpeed  = moveTable.GetFloat("kbot",  1.0f);
		terrType.hoverSpeed = moveTable.GetFloat("hover", 1.0f);
		terrType.shipSpeed  = moveTable.GetFloat("ship",  1.0f);

		// clamps
		terrType.hardness   = max(0.0f, terrType.hardness);
		terrType.tankSpeed  = max(0.0f, terrType.tankSpeed);
		terrType.kbotSpeed  = max(0.0f, terrType.kbotSpeed);
		terrType.hoverSpeed = max(0.0f, terrType.hoverSpeed);
		terrType.shipSpeed  = max(0.0f, terrType.shipSpeed);
	}
}
void CArchiveScanner::ReadCacheData(const std::string& filename)
{
	if (!FileSystem::FileExists(filename)) {
		LOG_L(L_INFO, "Archive cache doesn't exist: %s", filename.c_str());
		return;
	}

	LuaParser p(filename, SPRING_VFS_RAW, SPRING_VFS_BASE);
	if (!p.Execute()) {
		LOG_L(L_ERROR, "Failed to parse archive cache: %s", p.GetErrorLog().c_str());
		return;
	}
	const LuaTable archiveCache = p.GetRoot();

	// Do not load old version caches
	const int ver = archiveCache.GetInt("internalVer", (INTERNAL_VER + 1));
	if (ver != INTERNAL_VER) {
		return;
	}

	const LuaTable archives = archiveCache.SubTable("archives");
	for (int i = 1; archives.KeyExists(i); ++i) {
		const LuaTable curArchive = archives.SubTable(i);
		const LuaTable archived = curArchive.SubTable("archivedata");
		std::string name = curArchive.GetString("name", "");

		ArchiveInfo& ai = archiveInfos[StringToLower(name)];
		ai.origName = name;
		ai.path     = curArchive.GetString("path", "");

		// do not use LuaTable.GetInt() for 32-bit integers, the Spring lua
		// library uses 32-bit floats to represent numbers, which can only
		// represent 2^24 consecutive integers
		ai.modified = strtoul(curArchive.GetString("modified", "0").c_str(), 0, 10);
		ai.checksum = strtoul(curArchive.GetString("checksum", "0").c_str(), 0, 10);
		ai.updated = false;

		ai.archiveData = CArchiveScanner::ArchiveData(archived, true);
		if (ai.archiveData.GetModType() == modtype::map) {
			AddDependency(ai.archiveData.GetDependencies(), "Map Helper v1");
		} else if (ai.archiveData.GetModType() == modtype::primary) {
			AddDependency(ai.archiveData.GetDependencies(), "Spring content v1");
		}
	}

	const LuaTable brokenArchives = archiveCache.SubTable("brokenArchives");
	for (int i = 1; brokenArchives.KeyExists(i); ++i) {
		const LuaTable curArchive = brokenArchives.SubTable(i);
		std::string name = curArchive.GetString("name", "");
		StringToLowerInPlace(name);

		BrokenArchive& ba = this->brokenArchives[name];
		ba.path = curArchive.GetString("path", "");
		ba.modified = strtoul(curArchive.GetString("modified", "0").c_str(), 0, 10);
		ba.updated = false;
		ba.problem = curArchive.GetString("problem", "unknown");
	}

	isDirty = false;
}
void CUnitDefHandler::LoadSounds(const LuaTable& soundsTable, GuiSoundSet& gsound, const string& soundName)
{
	string fileName = soundsTable.GetString(soundName, "");
	if (!fileName.empty()) {
		LoadSound(gsound, fileName, 1.0f);
		return;
	}

	LuaTable sndTable = soundsTable.SubTable(soundName);
	for (int i = 1; true; i++) {
		LuaTable sndFileTable = sndTable.SubTable(i);
		if (sndFileTable.IsValid()) {
			fileName = sndFileTable.GetString("file", "");
			if (!fileName.empty()) {
				const float volume = sndFileTable.GetFloat("volume", 1.0f);
				if (volume > 0.0f) {
					LoadSound(gsound, fileName, volume);
				}
			}
		} else {
			fileName = sndTable.GetString(i, "");
			if (fileName.empty()) {
				break;
			}
			LoadSound(gsound, fileName, 1.0f);
		}
	}
}
bool CSound::LoadSoundDefs(const std::string& filename)
{
	//! can be called from LuaUnsyncedCtrl too
	boost::mutex::scoped_lock lck(soundMutex);

	LuaParser parser(filename, SPRING_VFS_MOD, SPRING_VFS_ZIP);
	parser.SetLowerKeys(false);
	parser.SetLowerCppKeys(false);
	parser.Execute();
	if (!parser.IsValid())
	{
		LogObject(LOG_SOUND) << "Could not load " << filename << ": " << parser.GetErrorLog();
		return false;
	}
	else
	{
		const LuaTable soundRoot = parser.GetRoot();
		const LuaTable soundItemTable = soundRoot.SubTable("SoundItems");
		if (!soundItemTable.IsValid())
		{
			LogObject(LOG_SOUND) << "CSound(): could not parse SoundItems table in " << filename;
			return false;
		}
		else
		{
			std::vector<std::string> keys;
			soundItemTable.GetKeys(keys);
			for (std::vector<std::string>::const_iterator it = keys.begin(); it != keys.end(); ++it)
			{
				const std::string name(*it);
				soundItemDef bufmap;
				const LuaTable buf(soundItemTable.SubTable(*it));
				buf.GetMap(bufmap);
				bufmap["name"] = name;
				soundItemDefMap::const_iterator sit = soundItemDefs.find(name);
				if (sit != soundItemDefs.end())
					LogObject(LOG_SOUND) << "CSound(): two SoundItems have the same name: " << name;

				soundItemDef::const_iterator inspec = bufmap.find("file");
				if (inspec == bufmap.end())	// no file, drop
					LogObject(LOG_SOUND) << "CSound(): SoundItem has no file tag: " << name;
				else
					soundItemDefs[name] = bufmap;

				if (buf.KeyExists("preload"))
				{
					LogObject(LOG_SOUND) << "CSound(): preloading " << name;
					const size_t newid = sounds.size();
					sounds.push_back(new SoundItem(GetWaveBuffer(bufmap["file"], true), bufmap));
					soundMap[name] = newid;
				}
			}
			LogObject(LOG_SOUND) << "CSound(): Sucessfully parsed " << keys.size() << " SoundItems from " << filename;
		}
	}
	return true;
}
Exemple #5
0
bool CSound::LoadSoundDefs(const std::string& fileName)
{
	//! can be called from LuaUnsyncedCtrl too
	boost::recursive_mutex::scoped_lock lck(soundMutex);

	LuaParser parser(fileName, SPRING_VFS_MOD, SPRING_VFS_ZIP);
	parser.SetLowerKeys(false);
	parser.SetLowerCppKeys(false);
	parser.Execute();
	if (!parser.IsValid())
	{
		LOG_L(L_WARNING, "Could not load %s: %s",
				fileName.c_str(), parser.GetErrorLog().c_str());
		return false;
	}
	else
	{
		const LuaTable soundRoot = parser.GetRoot();
		const LuaTable soundItemTable = soundRoot.SubTable("SoundItems");
		if (!soundItemTable.IsValid())
		{
			LOG_L(L_WARNING, "CSound(): could not parse SoundItems table in %s", fileName.c_str());
			return false;
		}
		else
		{
			std::vector<std::string> keys;
			soundItemTable.GetKeys(keys);
			for (std::vector<std::string>::const_iterator it = keys.begin(); it != keys.end(); ++it)
			{
				const std::string name(*it);
				soundItemDef bufmap;
				const LuaTable buf(soundItemTable.SubTable(*it));
				buf.GetMap(bufmap);
				bufmap["name"] = name;
				soundItemDefMap::const_iterator sit = soundItemDefs.find(name);
				if (sit != soundItemDefs.end())
					LOG_L(L_WARNING, "Sound %s gets overwritten by %s", name.c_str(), fileName.c_str());

				soundItemDef::const_iterator inspec = bufmap.find("file");
				if (inspec == bufmap.end()) {	// no file, drop
					LOG_L(L_WARNING, "Sound %s is missing file tag (ignoring)", name.c_str());
				} else {
					soundItemDefs[name] = bufmap;
				}

				if (buf.KeyExists("preload")) {
					MakeItemFromDef(bufmap);
				}
			}
			LOG(" parsed %i sounds from %s", (int)keys.size(), fileName.c_str());
		}
	}
	return true;
}
void CMapInfo::ReadStartPos()
{
	const float defX = 1000.0f;
	const float defZ = 1000.0f;
	const float defXStep = 100.0f;
	const float defZStep = 100.0f;

	const LuaTable teamsTable = mapRoot->SubTable("teams");

	for (int t = 0; t < MAX_TEAMS; ++t) {
		float3 pos;
		pos.x = defX + (defXStep * t);
		pos.z = defZ + (defZStep * t);
		pos.y = 0.0f;
		const LuaTable posTable = teamsTable.SubTable(t).SubTable("startPos");
		if (posTable.KeyExists("x") &&
		    posTable.KeyExists("z")) {
			pos.x = posTable.GetFloat("x", pos.x);
			pos.z = posTable.GetFloat("z", pos.z);
			havePos.push_back(true);
		} else {
			havePos.push_back(false);
		}
		startPos.push_back(pos);		
	}
}
Exemple #7
0
CDamageArrayHandler::CDamageArrayHandler(LuaParser* defsParser)
{
	#define DEFAULT_ARMORDEF_NAME "default"

	try {
		const LuaTable rootTable = defsParser->GetRoot().SubTable("ArmorDefs");

		if (!rootTable.IsValid())
			throw content_error("Error loading ArmorDefs");

		// GetKeys() sorts the keys, so can not simply push_back before call
		rootTable.GetKeys(armorDefKeys);
		armorDefKeys.insert(armorDefKeys.begin(), DEFAULT_ARMORDEF_NAME);

		armorDefNameIdxMap[DEFAULT_ARMORDEF_NAME] = 0;

		LOG("[%s] number of ArmorDefs: " _STPF_, __FUNCTION__, armorDefKeys.size());

		// expects the following structure, subtables must be in array-format:
		//
		// {"tanks" = {[1] = "supertank", [2] = "megatank"}, "infantry" = {[1] = "dude"}, ...}
		//
		// the old (pre-95.0) <key, value> subtable definitions are no longer supported!
		//
		for (unsigned int armorDefIdx = 1; armorDefIdx < armorDefKeys.size(); armorDefIdx++) {
			const std::string armorDefName = StringToLower(armorDefKeys[armorDefIdx]);

			if (armorDefName == DEFAULT_ARMORDEF_NAME) {
				// ignore, no need to clear entire table
				LOG_L(L_WARNING, "[%s] ArmorDefs: tried to define the \"%s\" armor type!", __FUNCTION__, DEFAULT_ARMORDEF_NAME);
				continue;
			}

			armorDefNameIdxMap[armorDefName] = armorDefIdx;

			const LuaTable armorDefTable = rootTable.SubTable(armorDefKeys[armorDefIdx]);
			const unsigned int numArmorDefEntries = armorDefTable.GetLength();

			for (unsigned int armorDefEntryIdx = 0; armorDefEntryIdx < numArmorDefEntries; armorDefEntryIdx++) {
				const std::string& unitDefName = StringToLower(armorDefTable.GetString(armorDefEntryIdx + 1, ""));
				const auto armorDefTableIt = armorDefNameIdxMap.find(unitDefName);

				if (armorDefTableIt == armorDefNameIdxMap.end()) {
					armorDefNameIdxMap[unitDefName] = armorDefIdx;
					continue;
				}

				LOG_L(L_WARNING,
					"[%s] UnitDef \"%s\" in ArmorDef \"%s\" already belongs to ArmorDef category %d!",
					__FUNCTION__, unitDefName.c_str(), armorDefName.c_str(), armorDefTableIt->second);
			}
		}
	} catch (const content_error&) {
		armorDefNameIdxMap.clear();
		armorDefNameIdxMap[DEFAULT_ARMORDEF_NAME] = 0;

		armorDefKeys.clear();
		armorDefKeys.push_back(DEFAULT_ARMORDEF_NAME);
	}
}
Exemple #8
0
CFeatureHandler::CFeatureHandler() : nextFreeID(0)
{
	PrintLoadMsg("Loading feature definitions");

	drawQuadsX = gs->mapx/DRAW_QUAD_SIZE;
	drawQuadsY = gs->mapy/DRAW_QUAD_SIZE;
	drawQuads.resize(drawQuadsX * drawQuadsY);

	treeDrawer = CBaseTreeDrawer::GetTreeDrawer();

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

	//! featureDefIDs start with 1
	featureDefsVector.push_back(NULL);

	//! get most of the feature defs (missing trees and geovent from the map)
	vector<string> keys;
	rootTable.GetKeys(keys);
	for (int i = 0; i < (int)keys.size(); i++) {
		const string& name = keys[i];
		const LuaTable fdTable = rootTable.SubTable(name);
		CreateFeatureDef(fdTable, name);
	}
}
CWeaponDefHandler::CWeaponDefHandler()
{
	PrintLoadMsg("Loading weapon definitions");

	const LuaTable rootTable = game->defsParser->GetRoot().SubTable("WeaponDefs");
	if (!rootTable.IsValid()) {
		throw content_error("Error loading WeaponDefs");
	}
	
	vector<string> weaponNames;
	rootTable.GetKeys(weaponNames);

	numWeaponDefs = weaponNames.size(); // FIXME: starting at 0, don't need the +1 ?
	weaponDefs = SAFE_NEW WeaponDef[numWeaponDefs + 1];

	for (int wid = 0; wid < (int)weaponNames.size(); wid++) {
		WeaponDef& wd = weaponDefs[wid];
		wd.id = wid;
		wd.name = weaponNames[wid];
		weaponID[wd.name] = wid;

		const LuaTable wdTable = rootTable.SubTable(wd.name);
		ParseTAWeapon(wdTable, wd);
	}
}
CWeaponDefHandler::CWeaponDefHandler()
{
	PrintLoadMsg("Loading weapon definitions");

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

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

	numWeaponDefs = weaponNames.size();
	weaponDefs = new WeaponDef[numWeaponDefs];

	for (int wid = 0; wid < numWeaponDefs; wid++) {
		WeaponDef& wd = weaponDefs[wid];
		wd.id = wid;
		wd.name = weaponNames[wid];
		weaponID[wd.name] = wid;

		const LuaTable wdTable = rootTable.SubTable(wd.name);
		ParseWeapon(wdTable, wd);
	}
}
Exemple #11
0
CUnitDefHandler::CUnitDefHandler(void) : noCost(false)
{
	const LuaTable rootTable = game->defsParser->GetRoot().SubTable("UnitDefs");
	if (!rootTable.IsValid()) {
		throw content_error("Error loading UnitDefs");
	}

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

	unitDefs.reserve(unitDefNames.size() + 1);
	UnitDef* nullDef = new UnitDef();
	unitDefs.push_back(nullDef);

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

		// parse the unitdef data (but don't load buildpics, etc...)
		PushNewUnitDef(unitName, udTable);
	}

	CleanBuildOptions();
	FindStartUnits();
	ProcessDecoys();
	AssignTechLevels();
}
Exemple #12
0
void CArchiveScanner::ReadCacheData(const string& filename)
{
    LuaParser p(filename, SPRING_VFS_RAW, SPRING_VFS_BASE);

    if (!p.Execute()) {
        logOutput.Print("ERROR in " + filename + ": " + p.GetErrorLog());
    }
    const LuaTable archiveCache = p.GetRoot();
    const LuaTable archives = archiveCache.SubTable("archives");

    // Do not load old version caches
    const int ver = archiveCache.GetInt("internalVer", (INTERNAL_VER + 1));
    if (ver != INTERNAL_VER) {
        return;
    }

    for (int i = 1; archives.KeyExists(i); ++i) {
        const LuaTable curArchive = archives.SubTable(i);
        const LuaTable archived = curArchive.SubTable("archivedata");
        ArchiveInfo ai;

        ai.origName = curArchive.GetString("name", "");
        ai.path     = curArchive.GetString("path", "");

        // do not use LuaTable.GetInt() for 32-bit integers, the Spring lua
        // library uses 32-bit floats to represent numbers, which can only
        // represent 2^24 consecutive integers
        ai.modified = strtoul(curArchive.GetString("modified", "0").c_str(), 0, 10);
        ai.checksum = strtoul(curArchive.GetString("checksum", "0").c_str(), 0, 10);
        ai.updated = false;

        ai.archiveData = GetArchiveData(archived);
        if (ai.archiveData.modType == modtype::map)
            AddDependency(ai.archiveData.dependencies, "maphelper.sdz");
        else if (ai.archiveData.modType == modtype::primary)
            AddDependency(ai.archiveData.dependencies, "Spring content v1");

        string lcname = StringToLower(ai.origName);

        archiveInfo[lcname] = ai;
    }

    isDirty = false;
}
Exemple #13
0
CArchiveScanner::ArchiveData CArchiveScanner::GetArchiveData(const LuaTable& archiveTable)
{
	ArchiveData md;
	if (!archiveTable.IsValid()) {
		return md;
	}

	md.name        = archiveTable.GetString("name",        "");
	md.shortName   = archiveTable.GetString("shortName",   "");
	md.version     = archiveTable.GetString("version",     "");
	md.mutator     = archiveTable.GetString("mutator",     "");
	md.game        = archiveTable.GetString("game",        "");
	md.shortGame   = archiveTable.GetString("shortGame",   "");
	md.description = archiveTable.GetString("description", "");
	md.modType     = archiveTable.GetInt("modType", 0);
	md.mapfile = archiveTable.GetString("mapfile", "");

	const LuaTable dependencies = archiveTable.SubTable("depend");
	for (int dep = 1; dependencies.KeyExists(dep); ++dep) {
		const std::string depend = dependencies.GetString(dep, "");
		md.dependencies.push_back(depend);
	}

	const LuaTable replaces = archiveTable.SubTable("replace");
	for (int rep = 1; replaces.KeyExists(rep); ++rep) {
		md.replaces.push_back(replaces.GetString(rep, ""));
	}

	// HACK needed until lobbies, lobbyserver and unitsync are sorted out
	// so they can uniquely identify different versions of the same mod.
	// (at time of this writing they use name only)

	// NOTE when changing this, this function is used both by the code that
	// reads ArchiveCache.lua and the code that reads modinfo.lua from the mod.
	// so make sure it doesn't keep adding stuff to the name everytime
	// Spring/unitsync is loaded.

	if (md.name.find(md.version) == std::string::npos && !md.version.empty()) {
		md.name += " " + md.version;
	}

	return md;
}
void CSyncer::LoadUnits(bool checksum)
{
	unitsLeft = 0;

	LuaParser luaParser("gamedata/defs.lua",
	                    SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
	if (!luaParser.Execute()) {
		logOutput.Print("luaParser.Execute() failed");
		return;
	}

	LuaTable rootTable = luaParser.GetRoot().SubTable("UnitDefs");
	if (!rootTable.IsValid()) {
		logOutput.Print("root unitdef table invalid");
		return;
	}

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

	const int count = (int)unitDefNames.size();

	for (int i = 0; i < count; ++i) {
		const string& udName =  unitDefNames[i];
		LuaTable udTable = rootTable.SubTable(udName);

		Unit u;

		u.fullName = udTable.GetString("name", udName);

		if (checksum) {
			const string fileName  = udTable.GetString("filename", "");
			const string deadName  = udTable.GetString("corpse", udName + "_dead");
			const string modelName = udTable.GetString("objectname", udName);

			u.fbi    = CalculateCRC(fileName);
			u.cob    = CalculateCRC("scripts/" + udName + ".cob");
			u.model  = CalculateCRC("objects3d/" + modelName); // s3o ?
			u.model += CalculateCRC("objects3d/" + modelName + ".3do");
			u.model += CalculateCRC("objects3d/" +  deadName + ".3do");
		}

		units[udName] = u;
	}

	// map the unitIds
	map<string, Unit>::iterator mit;
	for (mit = units.begin(); mit != units.end(); ++mit) {
		unitIds.push_back(mit->first);
	}

	unitsLeft = count;

	return;
}
bool SideParser::Load()
{
	dataVec.clear();
	errorLog.clear();

	LuaParser parser("gamedata/sidedata.lua",
	                 SPRING_VFS_MOD_BASE, SPRING_VFS_MOD_BASE);
#if !defined UNITSYNC && !defined DEDICATED
	// this should not be included with unitsync:
	// 1. avoids linkage with LuaSyncedRead
	// 2. ModOptions are not valid during unitsync mod parsing
	parser.GetTable("Spring");
	parser.AddFunc("GetModOptions", LuaSyncedRead::GetModOptions);
	parser.EndTable();
#endif
	if (!parser.Execute()) {
		errorLog = parser.GetErrorLog();
		return false;
	}

	set<string> sideSet;

	const LuaTable root = parser.GetRoot();
	for (int i = 1; /* no-op */; i++) {
		const LuaTable sideTable = root.SubTable(i);
		if (!sideTable.IsValid()) {
			break;
		}

		Data data;
		data.caseName  = sideTable.GetString("name", "");
		data.sideName  = StringToLower(data.caseName);
		data.startUnit = sideTable.GetString("startUnit", "");
		data.startUnit = StringToLower(data.startUnit);

		if (data.sideName.empty()) {
			logOutput.Print("Missing side name: %i", i);
		}
		else if (data.startUnit.empty()) {
			logOutput.Print("Missing side start unit: " + data.sideName);
		}
		else {
			if (sideSet.find(data.sideName) != sideSet.end()) {
				logOutput.Print("Duplicate side name: " + data.sideName);
			}
			else {
				sideSet.insert(data.sideName);
				dataVec.push_back(data);
			}
		}
	}
	return true;
}
CExplosionGeneratorHandler::CExplosionGeneratorHandler()
    : luaParser("gamedata/explosions.lua",
                SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP)

{
    LuaParser aliasParser("gamedata/explosion_alias.lua",
                          SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
    if (!aliasParser.Execute()) {
        logOutput.Print(aliasParser.GetErrorLog());
    } else {
        const LuaTable root = aliasParser.GetRoot();
        projectileClasses.Load(root.SubTable("projectiles"));
        generatorClasses.Load(root.SubTable("generators"));
    }

    if (!luaParser.Execute()) {
        logOutput.Print(luaParser.GetErrorLog());
    } else {
        luaTable = luaParser.GetRoot();
    }
}
Exemple #17
0
void CUnitDefHandler::UnitDefLoadSounds(UnitDef* ud, const LuaTable& udTable)
{
	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");
}
void CProjectileDrawer::ParseAtlasTextures(
	const bool blockTextures,
	const LuaTable& textureTable,
	std::set<std::string>& blockedTextures,
	CTextureAtlas* textureAtlas)
{
	std::vector<std::string> subTables;
	std::map<std::string, std::string> texturesMap;
	std::map<std::string, std::string>::iterator texturesMapIt;

	textureTable.GetMap(texturesMap);
	textureTable.GetKeys(subTables);

	for (texturesMapIt = texturesMap.begin(); texturesMapIt != texturesMap.end(); ++texturesMapIt) {
		const std::string textureName = StringToLower(texturesMapIt->first);

		if (blockTextures) {
			// no textures added to this atlas are allowed
			// to be overwritten later by other textures of
			// the same name
			blockedTextures.insert(textureName);
		}
		if (blockTextures || (blockedTextures.find(textureName) == blockedTextures.end())) {
			textureAtlas->AddTexFromFile(texturesMapIt->first, "bitmaps/" + texturesMapIt->second);
		}
	}

	texturesMap.clear();

	for (size_t i = 0; i < subTables.size(); i++) {
		const LuaTable& textureSubTable = textureTable.SubTable(subTables[i]);

		if (textureSubTable.IsValid()) {
			textureSubTable.GetMap(texturesMap);

			for (texturesMapIt = texturesMap.begin(); texturesMapIt != texturesMap.end(); ++texturesMapIt) {
				const std::string textureName = StringToLower(texturesMapIt->first);

				if (blockTextures) {
					blockedTextures.insert(textureName);
				}
				if (blockTextures || (blockedTextures.find(textureName) == blockedTextures.end())) {
					textureAtlas->AddTexFromFile(texturesMapIt->first, "bitmaps/" + texturesMapIt->second);
				}
			}

			texturesMap.clear();
		}
	}
}
Exemple #19
0
bool MapParser::GetStartPos(int team, float3& pos) const
{
	if (!parser->IsValid()) {
		return false;
	}
	const LuaTable teamsTable = parser->GetRoot().SubTable("teams");
	const LuaTable posTable = teamsTable.SubTable(team).SubTable("startPos");
	if (!posTable.IsValid()) {
		return false;
	}

	pos.x = posTable.GetFloat("x", pos.x);
	pos.z = posTable.GetFloat("z", pos.z);

	return true;
}
void DefType::ReportUnknownTags(const std::string& instanceName, const LuaTable& luaTable, const std::string pre)
{
	std::vector<std::string> keys;
	luaTable.GetKeys(keys);
	for (const std::string& tag: keys) {
		const DefTagMetaData* meta = GetMetaDataByExternalKey(pre + tag);
		if (meta != nullptr)
			continue;

		if (luaTable.GetType(tag) == LuaTable::TABLE) {
			ReportUnknownTags(instanceName, luaTable.SubTable(tag), pre + tag + ".");
			continue;
		}

		LOG_L(L_WARNING, "%s: Unknown tag \"%s%s\" in \"%s\"", name.c_str(), pre.c_str(), tag.c_str(), instanceName.c_str());
	}
}
Exemple #21
0
bool MapParser::GetStartPos(int team, float3& pos) const
{
	errorLog.clear();

	if (!parser->IsValid()) {
		errorLog = "Map-Parser: Failed to get start position for team " + IntToString(team) + ", reason: " + parser->GetErrorLog();
		return false;
	}
	const LuaTable teamsTable = parser->GetRoot().SubTable("teams");
	const LuaTable posTable = teamsTable.SubTable(team).SubTable("startPos");
	if (!posTable.IsValid()) {
		errorLog = "Map-Parser: Failed to get start position for team " + IntToString(team) + ", reason: Not defined in the map's config!";
		return false;
	}

	pos.x = posTable.GetFloat("x", pos.x);
	pos.z = posTable.GetFloat("z", pos.z);

	return true;
}
Exemple #22
0
CFeatureHandler::CFeatureHandler()
{
	const LuaTable rootTable = game->defsParser->GetRoot().SubTable("FeatureDefs");
	if (!rootTable.IsValid()) {
		throw content_error("Error loading FeatureDefs");
	}

	// featureDefIDs start with 1
	featureDefsVector.push_back(NULL);

	// get most of the feature defs (missing trees and geovent from the map)
	vector<string> keys;
	rootTable.GetKeys(keys);
	for (int i = 0; i < (int)keys.size(); i++) {
		const string& nameMixedCase = keys[i];
		const string& nameLowerCase = StringToLower(nameMixedCase);
		const LuaTable& fdTable = rootTable.SubTable(nameMixedCase);

		AddFeatureDef(nameLowerCase, CreateFeatureDef(fdTable, nameLowerCase));
	}
}
Exemple #23
0
MoveDefHandler::MoveDefHandler(LuaParser* defsParser)
{
	const LuaTable rootTable = defsParser->GetRoot().SubTable("MoveDefs");

	if (!rootTable.IsValid())
		throw content_error("Error loading movement definitions");

	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;
	}

	moveDefs.reserve(rootTable.GetLength());
	for (size_t num = 1; /* no test */; num++) {
		const LuaTable moveDefTable = rootTable.SubTable(num);

		if (!moveDefTable.IsValid()) {
			break;
		}

		moveDefs.emplace_back(moveDefTable, num);
		const MoveDef& md = moveDefs.back();
		moveDefNames[md.name] = md.pathType;

		crc << md.GetCheckSum();
	}

	CMoveMath::noHoverWaterMove = (mapInfo->water.damage >= MAX_ALLOWED_WATER_DAMAGE_HMM);
	CMoveMath::waterDamageCost = (mapInfo->water.damage >= MAX_ALLOWED_WATER_DAMAGE_GMM)?
		0.0f: (1.0f / (1.0f + mapInfo->water.damage * 0.1f));

	crc << CMoveMath::waterDamageCost;
	crc << CMoveMath::noHoverWaterMove;

	checksum = crc.GetDigest();
}
Exemple #24
0
static bool info_parseInfoItem(const LuaTable& root, int index, InfoItem& inf,
		std::set<string>& infoSet)
{
	const LuaTable& infsTbl = root.SubTable(index);
	if (!infsTbl.IsValid()) {
		LOG_L(L_WARNING, "parseInfoItem: subtable %d invalid", index);
		return false;
	}

	// common info properties
	inf.key = infsTbl.GetString("key", "");
	if (inf.key.empty()
			|| (inf.key.find_first_of(InfoItem_badKeyChars) != string::npos)) {
		LOG_L(L_WARNING,
				"parseInfoItem: empty key or key contains bad characters");
		return false;
	}
	std::string lowerKey = StringToLower(inf.key);
	if (infoSet.find(inf.key) != infoSet.end()) {
		LOG_L(L_WARNING, "parseInfoItem: key toLowerCase(%s) exists already",
				inf.key.c_str());
		return false;
	}
	// TODO add support for info value types other then string
	inf.valueType = INFO_VALUE_TYPE_STRING;
	inf.valueTypeString = infsTbl.GetString("value", "");
	if (inf.valueTypeString.empty()) {
		LOG_L(L_WARNING, "parseInfoItem: %s: empty value", inf.key.c_str());
		return false;
	}
	inf.desc = infsTbl.GetString("desc", "");

	infoSet.insert(lowerKey);

	return true;
}
Exemple #25
0
/** Load the messages from gamedata/messages.lua into memory. */
void CMessages::Load()
{
    LuaParser luaParser("gamedata/messages.lua",
                        SPRING_VFS_MOD_BASE, SPRING_VFS_MOD_BASE);
    if (!luaParser.Execute()) {
        // Show parse errors in the infolog.
        logOutput.Print(string("ERROR: messages.lua: ") + luaParser.GetErrorLog());
        return;
    }

    const LuaTable root = luaParser.GetRoot();

    vector<string> labels;
    root.GetKeys(labels);

    for (size_t l = 0; l < labels.size(); l++) {
        const string label = StringToLower(labels[l]);
        const LuaTable msgTable = root.SubTable(label);
        if (!msgTable.IsValid()) {
            continue;
        }
        vector<string> msgs;
        for (int s = 1; true; s++) {
            const string msg = msgTable.GetString(s, "");
            if (msg.empty()) {
                break;
            }
            msgs.push_back(msg);
        }
        if (!msgs.empty()) {
            tr[label] = msgs;
        }
    }

    loaded = true;
}
Exemple #26
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);
}
void CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* h, const string& tag)
{
    static std::map<string, CEGData> cachedCEGs;
    std::map<string, CEGData>::iterator it = cachedCEGs.find(tag);

    if (it == cachedCEGs.end()) {
        CEGData cegData;

        const LuaTable& root = h->GetTable();
        const LuaTable expTable = root.SubTable(tag);
        if (!expTable.IsValid()) {
            throw content_error("Explosion info for " + tag + " not found.");
        }

        vector<string> spawns;
        expTable.GetKeys(spawns);

        for (vector<string>::iterator si = spawns.begin(); si != spawns.end(); ++si) {
            ProjectileSpawnInfo psi;

            const string& spawnName = *si;
            const LuaTable spawnTable = expTable.SubTable(spawnName);

            if (!spawnTable.IsValid() || spawnName == "groundflash") {
                continue;
            }

            const string className = spawnTable.GetString("class", spawnName);
            unsigned int flags = 0;

            if (spawnTable.GetBool("ground",     false)) {
                flags |= SPW_GROUND;
            }
            if (spawnTable.GetBool("water",      false)) {
                flags |= SPW_WATER;
            }
            if (spawnTable.GetBool("air",        false)) {
                flags |= SPW_AIR;
            }
            if (spawnTable.GetBool("underwater", false)) {
                flags |= SPW_UNDERWATER;
            }
            if (spawnTable.GetBool("unit",       false)) {
                flags |= SPW_UNIT;
            }
            if (spawnTable.GetBool("nounit",     false)) {
                flags |= SPW_NO_UNIT;
            }

            psi.projectileClass = h->projectileClasses.GetClass(className);
            psi.flags = flags;
            psi.count = spawnTable.GetInt("count", 1);

            string code;
            map<string, string> props;
            map<string, string>::const_iterator propIt;
            spawnTable.SubTable("properties").GetMap(props);

            for (propIt = props.begin(); propIt != props.end(); ++propIt) {
                creg::Class::Member* m = psi.projectileClass->FindMember(propIt->first.c_str());
                if (m && (m->flags & creg::CM_Config)) {
                    ParseExplosionCode(&psi, m->offset, m->type, propIt->second, code);
                }
            }

            code += (char)OP_END;
            psi.code.resize(code.size());
            copy(code.begin(), code.end(), psi.code.begin());

            cegData.projectileSpawn.push_back(psi);
        }

        const LuaTable gndTable = expTable.SubTable("groundflash");
        const int ttl = gndTable.GetInt("ttl", 0);
        if (ttl > 0) {
            cegData.groundFlash.circleAlpha  = gndTable.GetFloat("circleAlpha",  0.0f);
            cegData.groundFlash.flashSize    = gndTable.GetFloat("flashSize",    0.0f);
            cegData.groundFlash.flashAlpha   = gndTable.GetFloat("flashAlpha",   0.0f);
            cegData.groundFlash.circleGrowth = gndTable.GetFloat("circleGrowth", 0.0f);
            cegData.groundFlash.color        = gndTable.GetFloat3("color", float3(1.0f, 1.0f, 0.8f));

            unsigned int flags = SPW_GROUND;
            if (gndTable.GetBool("ground",     false)) {
                flags |= SPW_GROUND;
            }
            if (gndTable.GetBool("water",      false)) {
                flags |= SPW_WATER;
            }
            if (gndTable.GetBool("air",        false)) {
                flags |= SPW_AIR;
            }
            if (gndTable.GetBool("underwater", false)) {
                flags |= SPW_UNDERWATER;
            }
            if (gndTable.GetBool("unit",       false)) {
                flags |= SPW_UNIT;
            }
            if (gndTable.GetBool("nounit",     false)) {
                flags |= SPW_NO_UNIT;
            }

            cegData.groundFlash.flags = flags;
            cegData.groundFlash.ttl = ttl;
        }

        cegData.useDefaultExplosions = expTable.GetBool("useDefaultExplosions", false);

        cachedCEGs[tag] = cegData;
        currentCEG = &cachedCEGs[tag];
    } else {
        currentCEG = &(it->second);
    }
}
unsigned int CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* h, const string& tag)
{
	unsigned int explosionID = -1U;

	if (tag.empty()) {
		return explosionID;
	}

	const std::map<std::string, unsigned int>::const_iterator it = explosionIDs.find(tag);

	if (it == explosionIDs.end()) {
		CEGData cegData;

		const LuaTable* root = h->GetExplosionTableRoot();
		const LuaTable& expTable = (root != NULL)? root->SubTable(tag): LuaTable();

		if (!expTable.IsValid()) {
			// not a fatal error: any calls to ::Explosion will just return early
			logOutput.Print("[CCEG::Load] WARNING: table for CEG \"" + tag + "\" invalid (parse errors?)");
			return explosionID;
		}

		vector<string> spawns;
		expTable.GetKeys(spawns);

		for (vector<string>::iterator si = spawns.begin(); si != spawns.end(); ++si) {
			ProjectileSpawnInfo psi;

			const string& spawnName = *si;
			const LuaTable spawnTable = expTable.SubTable(spawnName);

			if (!spawnTable.IsValid() || spawnName == "groundflash") {
				continue;
			}

			const string className = spawnTable.GetString("class", spawnName);

			psi.projectileClass = h->projectileClasses.GetClass(className);
			psi.flags = GetFlagsFromTable(spawnTable);
			psi.count = spawnTable.GetInt("count", 1);

			if (psi.projectileClass->binder->flags & creg::CF_Synced) {
				psi.flags |= SPW_SYNCED;
			}

			string code;
			map<string, string> props;
			map<string, string>::const_iterator propIt;
			spawnTable.SubTable("properties").GetMap(props);

			for (propIt = props.begin(); propIt != props.end(); ++propIt) {
				creg::Class::Member* m = psi.projectileClass->FindMember(propIt->first.c_str());
				if (m && (m->flags & creg::CM_Config)) {
					ParseExplosionCode(&psi, m->offset, m->type, propIt->second, code);
				}
			}

			code += (char)OP_END;
			psi.code.resize(code.size());
			copy(code.begin(), code.end(), psi.code.begin());

			cegData.projectileSpawn.push_back(psi);
		}

		const LuaTable gndTable = expTable.SubTable("groundflash");
		const int ttl = gndTable.GetInt("ttl", 0);
		if (ttl > 0) {
			cegData.groundFlash.circleAlpha  = gndTable.GetFloat("circleAlpha",  0.0f);
			cegData.groundFlash.flashSize    = gndTable.GetFloat("flashSize",    0.0f);
			cegData.groundFlash.flashAlpha   = gndTable.GetFloat("flashAlpha",   0.0f);
			cegData.groundFlash.circleGrowth = gndTable.GetFloat("circleGrowth", 0.0f);
			cegData.groundFlash.color        = gndTable.GetFloat3("color", float3(1.0f, 1.0f, 0.8f));

			cegData.groundFlash.flags = SPW_GROUND | GetFlagsFromTable(gndTable);
			cegData.groundFlash.ttl = ttl;
		}

		cegData.useDefaultExplosions = expTable.GetBool("useDefaultExplosions", false);

		explosionID = explosionData.size();
		explosionData.push_back(cegData);
		explosionIDs[tag] = explosionID;
	} else {
		explosionID = it->second;
	}

	return explosionID;
}
void CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* h, const string& tag)
{
	typedef std::map<string, CEGData> CEGMap;
	typedef std::map<string, CEGData>::iterator CEGMapIt;

	CEGMapIt it = cachedCEGs.find(tag);

	if (it == cachedCEGs.end()) {
		CEGData cegData;

		const LuaTable& root = h->GetTable();
		const LuaTable expTable = root.SubTable(tag);
		if (!expTable.IsValid()) {
			throw content_error("Explosion info for " + tag + " not found.");
		}

		vector<string> spawns;
		expTable.GetKeys(spawns);

		for (vector<string>::iterator si = spawns.begin(); si != spawns.end(); ++si) {
			ProjectileSpawnInfo psi;

			const string& spawnName = *si;
			const LuaTable spawnTable = expTable.SubTable(spawnName);

			if (!spawnTable.IsValid() || spawnName == "groundflash") {
				continue;
			}

			const string className = spawnTable.GetString("class", spawnName);

			psi.projectileClass = h->projectileClasses.GetClass(className);
			psi.flags = GetFlagsFromTable(spawnTable);
			psi.count = spawnTable.GetInt("count", 1);

			if (psi.projectileClass->binder->flags & creg::CF_Synced) {
				psi.flags |= SPW_SYNCED;
			}

			string code;
			map<string, string> props;
			map<string, string>::const_iterator propIt;
			spawnTable.SubTable("properties").GetMap(props);

			for (propIt = props.begin(); propIt != props.end(); ++propIt) {
				creg::Class::Member* m = psi.projectileClass->FindMember(propIt->first.c_str());
				if (m && (m->flags & creg::CM_Config)) {
					ParseExplosionCode(&psi, m->offset, m->type, propIt->second, code);
				}
			}

			code += (char)OP_END;
			psi.code.resize(code.size());
			copy(code.begin(), code.end(), psi.code.begin());

			cegData.projectileSpawn.push_back(psi);
		}

		const LuaTable gndTable = expTable.SubTable("groundflash");
		const int ttl = gndTable.GetInt("ttl", 0);
		if (ttl > 0) {
			cegData.groundFlash.circleAlpha  = gndTable.GetFloat("circleAlpha",  0.0f);
			cegData.groundFlash.flashSize    = gndTable.GetFloat("flashSize",    0.0f);
			cegData.groundFlash.flashAlpha   = gndTable.GetFloat("flashAlpha",   0.0f);
			cegData.groundFlash.circleGrowth = gndTable.GetFloat("circleGrowth", 0.0f);
			cegData.groundFlash.color        = gndTable.GetFloat3("color", float3(1.0f, 1.0f, 0.8f));

			cegData.groundFlash.flags = SPW_GROUND | GetFlagsFromTable(gndTable);
			cegData.groundFlash.ttl = ttl;
		}

		cegData.useDefaultExplosions = expTable.GetBool("useDefaultExplosions", false);
		it = cachedCEGs.insert(std::make_pair(tag, cegData)).first;
	}

	currentCEG = it;
}
Exemple #30
0
bool CSound::LoadSoundDefsImpl(const std::string& fileName)
{
	//! can be called from LuaUnsyncedCtrl too
	boost::recursive_mutex::scoped_lock lck(soundMutex);

	LuaParser parser(fileName, SPRING_VFS_MOD, SPRING_VFS_ZIP);
	parser.Execute();
	if (!parser.IsValid())
	{
		LOG_L(L_WARNING, "Could not load %s: %s",
				fileName.c_str(), parser.GetErrorLog().c_str());
		return false;
	}
	else
	{
		const LuaTable soundRoot = parser.GetRoot();
		const LuaTable soundItemTable = soundRoot.SubTable("SoundItems");
		if (!soundItemTable.IsValid())
		{
			LOG_L(L_WARNING, "CSound(): could not parse SoundItems table in %s", fileName.c_str());
			return false;
		}
		else
		{
			std::vector<std::string> keys;
			soundItemTable.GetKeys(keys);
			for (std::vector<std::string>::const_iterator it = keys.begin(); it != keys.end(); ++it)
			{
				std::string name(*it);

				soundItemDef bufmap;
				const LuaTable buf(soundItemTable.SubTable(name));
				buf.GetMap(bufmap);
				bufmap["name"] = name;
				soundItemDefMap::const_iterator sit = soundItemDefs.find(name);

				if (name == "default") {
					defaultItem = bufmap;
					defaultItem.erase("name"); //must be empty for default item
					defaultItem.erase("file");
					continue;
				}

				if (sit != soundItemDefs.end())
					LOG_L(L_WARNING, "Sound %s gets overwritten by %s", name.c_str(), fileName.c_str());

				if (!buf.KeyExists("file")) {
					// no file, drop
					LOG_L(L_WARNING, "Sound %s is missing file tag (ignoring)", name.c_str());
					continue;
				} else {
					soundItemDefs[name] = bufmap;
				}

				if (buf.KeyExists("preload")) {
					MakeItemFromDef(bufmap);
				}
			}
			LOG(" parsed %i sounds from %s", (int)keys.size(), fileName.c_str());
		}
	}

	//FIXME why do sounds w/o an own soundItemDef create (!=pointer) a new one from the defaultItem?
	for (soundItemDefMap::iterator it = soundItemDefs.begin(); it != soundItemDefs.end(); ++it) {
		soundItemDef& snddef = it->second;
		if (snddef.find("name") == snddef.end()) {
			// uses defaultItem! update it!
			const std::string file = snddef["file"];
			snddef = defaultItem;
			snddef["file"] = file;
		}
	}

	return true;
}