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 #2
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 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();
		}
	}
}
void ClassAliasList::Load(const LuaTable& aliasTable)
{
    map<string, string> aliasList;
    aliasTable.GetMap(aliasList);
    aliases.insert(aliasList.begin(), aliasList.end());
}
Exemple #5
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;
}
void CWeaponDefHandler::ParseTAWeapon(const LuaTable& wdTable, WeaponDef& wd)
{
	bool lineofsight;
	bool ballistic;
	//bool twophase;
	bool beamweapon;
	bool manualBombSettings; //Allow the user to manually specify the burst and burstrate for his AircraftBomb
	//bool guided;
	//bool vlaunch;
	int rendertype;
	int color;
	int beamlaser;
	//bool tracking;
	//bool selfprop;
	//bool turret;
	//bool smokeTrail;
	//string modelName;

	wd.tdfId = wdTable.GetInt("id", 0);

	wd.filename = wdTable.GetString("filename", "unknown");
	wd.description = wdTable.GetString("name", "Weapon");
	wd.cegTag = wdTable.GetString("cegTag", "");

	wd.avoidFriendly = wdTable.GetBool("avoidFriendly", true);
	wd.avoidFeature  = wdTable.GetBool("avoidFeature",  true);

	wd.collisionFlags = 0;
	const bool collideFriendly = wdTable.GetBool("collideFriendly", true);
	const bool collideFeature  = wdTable.GetBool("collideFeature",  true);
	if (!collideFriendly) { wd.collisionFlags += COLLISION_NOFRIENDLY; }
	if (!collideFeature)  { wd.collisionFlags += COLLISION_NOFEATURE;  }

	wd.minIntensity = wdTable.GetFloat("minIntensity", 0.0f);

	wd.dropped  = wdTable.GetBool("dropped", false);
	manualBombSettings = wdTable.GetBool("manualBombSettings", false);
	lineofsight = wdTable.GetBool("lineOfSight", false);
	ballistic   = wdTable.GetBool("ballistic",  false);
	wd.twophase = wdTable.GetBool("twoPhase",   false);
	beamweapon  = wdTable.GetBool("beamWeapon", false);
	wd.guided   = wdTable.GetBool("guidance",   false);
	rendertype  = wdTable.GetInt("renderType",  0);
	color       = wdTable.GetInt("color",       0);
	beamlaser   = wdTable.GetInt("beamlaser",   0);
	wd.vlaunch  = wdTable.GetBool("vlaunch",    false);
	wd.selfprop = wdTable.GetBool("selfprop",   false);
	wd.turret   = wdTable.GetBool("turret",     false);
	wd.noSelfDamage = wdTable.GetBool("noSelfDamage", false);
	wd.visuals.modelName = wdTable.GetString("model", "");
	wd.visuals.smokeTrail = wdTable.GetBool("smokeTrail", false);
	wd.visuals.alwaysVisible = wdTable.GetBool("alwaysVisible", false);

	wd.waterweapon   = wdTable.GetBool("waterWeapon",     false);
	wd.fireSubmersed = wdTable.GetBool("fireSubmersed",   wd.waterweapon);
	wd.submissile    = wdTable.GetBool("submissile",      false);
	wd.tracks        = wdTable.GetBool("tracks",          false);
	wd.fixedLauncher = wdTable.GetBool("fixedLauncher",   false);
	wd.noExplode     = wdTable.GetBool("noExplode",       false);
	wd.isShield      = wdTable.GetBool("isShield",        false);
	wd.maxvelocity   = wdTable.GetFloat("weaponVelocity", 0.0f);
	wd.beamtime      = wdTable.GetFloat("beamTime",       1.0f);
	wd.beamburst     = wdTable.GetBool("beamburst",       false);
		
	wd.waterBounce = wdTable.GetBool("waterbounce", false);
	wd.groundBounce = wdTable.GetBool("groundbounce", false);
	wd.bounceSlip = wdTable.GetFloat("bounceslip", 1);
	wd.bounceRebound = wdTable.GetFloat("bouncerebound", 1);
	wd.numBounce = wdTable.GetInt("numbounce", -1);

	wd.thickness      = wdTable.GetFloat("thickness",       2.0f);
	wd.corethickness  = wdTable.GetFloat("coreThickness",   0.25f);
	wd.laserflaresize = wdTable.GetFloat("laserFlareSize", 15.0f);
	wd.intensity      = wdTable.GetFloat("intensity",       0.9f);
	wd.duration       = wdTable.GetFloat("duration",        0.05f);
	wd.falloffRate    = wdTable.GetFloat("fallOffRate",     0.5f);
	wd.lodDistance    = wdTable.GetInt("lodDistance", 1000);

	wd.visuals.sizeDecay  = wdTable.GetFloat("sizeDecay",  0.0f);
	wd.visuals.alphaDecay = wdTable.GetFloat("alphaDecay", 1.0f);
	wd.visuals.separation = wdTable.GetFloat("separation", 1.0f);
	wd.visuals.noGap  = wdTable.GetBool("noGap", true);
	wd.visuals.stages = wdTable.GetInt("stages", 5);

	if (wd.name.find("disintegrator") != string::npos) {	//fulhack
		wd.visuals.renderType = WEAPON_RENDERTYPE_FIREBALL;
	} else if (wd.visuals.modelName.compare("") != 0) {
		wd.visuals.renderType = WEAPON_RENDERTYPE_MODEL;
	} else if (beamweapon) {
		wd.visuals.renderType = WEAPON_RENDERTYPE_LASER;
	} else {
		wd.visuals.renderType = WEAPON_RENDERTYPE_PLASMA;
	}

	wd.gravityAffected = false;
	if (wd.dropped || ballistic) {
		wd.gravityAffected = true;
	}

	if (wd.dropped) {
		wd.type = "AircraftBomb";

	}	else if (wd.vlaunch) {
		wd.type = "StarburstLauncher";

	}	else if (beamlaser) {
		wd.type = "BeamLaser";

	}	else if (wd.isShield) {
		wd.type = "Shield";

	} else if (wd.waterweapon) {
		wd.type = "TorpedoLauncher";

	} else if (wd.name.find("disintegrator") != string::npos) {
		wd.type = "DGun";

	} else if (lineofsight) {
		if (rendertype==7) {
			wd.type = "LightingCannon";
		} else if (beamweapon) {
			wd.type = "LaserCannon";
		} else if (wd.visuals.modelName.find("laser") != string::npos) {
			wd.type = "LaserCannon";		//swta fix
		} else if (/*selfprop && */wd.visuals.smokeTrail) {
			wd.type = "MissileLauncher";
		} else if (rendertype == 4 && color == 2) {
			wd.type = "EmgCannon";
		} else if (rendertype == 5) {
			wd.type = "Flame";
		//	} else if(rendertype == 1) {
		//		wd.type = "MissileLauncher";
		} else {
			wd.type = "Cannon";
		}
	} else {
		wd.type = "Cannon";
	}

	string ttype = wdTable.GetString("weaponType", "");
	if (ttype != "") {
		wd.type = ttype;
	}

//	logOutput.Print("%s as %s",weaponname.c_str(),wd.type.c_str());

	const bool melee = (wd.type == "Melee");
	wd.targetBorder = wdTable.GetFloat("targetBorder", melee ? 1.0f : 0.0f);
	if (wd.targetBorder > 1.0f) {
		logOutput.Print("warning: targetBorder truncated to 1 (was %f)", wd.targetBorder);
		wd.targetBorder = 1.0f;
	} else if (wd.targetBorder < -1.0f) {
		logOutput.Print("warning: targetBorder truncated to -1 (was %f)", wd.targetBorder);
		wd.targetBorder = -1.0f;
	}
	wd.cylinderTargetting = wdTable.GetFloat("cylinderTargetting", melee ? 1.0f : 0.0f);

	wd.range = wdTable.GetFloat("range", 10.0f);
	const float accuracy       = wdTable.GetFloat("accuracy",   0.0f);
	const float sprayangle     = wdTable.GetFloat("sprayAngle", 0.0f);
	const float movingAccuracy = wdTable.GetFloat("movingAccuracy", accuracy);
	// should really be tan but TA seem to cap it somehow
	// should also be 7fff or ffff theoretically but neither seems good
	wd.accuracy       = sin((accuracy)       * PI / 0xafff);
	wd.sprayangle     = sin((sprayangle)     * PI / 0xafff);
	wd.movingAccuracy = sin((movingAccuracy) * PI / 0xafff);

	wd.targetMoveError = wdTable.GetFloat("targetMoveError", 0.0f);
	wd.leadLimit = wdTable.GetFloat("leadLimit", -1.0f);
	wd.leadBonus = wdTable.GetFloat("leadBonus", 0.0f);

	// setup the default damages
	const LuaTable dmgTable = wdTable.SubTable("damage");
	float defDamage = dmgTable.GetFloat("default", 0.0f);
	if (defDamage == 0.0f) {
		defDamage = 1.0f; //avoid division by zeroes
	}
	for (int a = 0; a < damageArrayHandler->GetNumTypes(); ++a) {
		wd.damages[a] = defDamage;
	}

	map<string, float> damages;
	dmgTable.GetMap(damages);
	
	map<string, float>::const_iterator di;
	for (di = damages.begin(); di != damages.end(); ++di) {
		const int type = damageArrayHandler->GetTypeFromName(di->first);
		if (type != 0) {
			float dmg = di->second;
			if (dmg != 0.0f) {
				wd.damages[type] = dmg;
			} else {
				wd.damages[type] = 1.0f;
			}
		}
	}
	
	wd.damages.impulseFactor = wdTable.GetFloat("impulseFactor", 1.0f);
	wd.damages.impulseBoost  = wdTable.GetFloat("impulseBoost",  0.0f);
	wd.damages.craterMult    = wdTable.GetFloat("craterMult",  wd.damages.impulseFactor);
	wd.damages.craterBoost   = wdTable.GetFloat("craterBoost", 0.0f);

	wd.areaOfEffect = wdTable.GetFloat("areaOfEffect", 8.0f) * 0.5f;
	wd.edgeEffectiveness = wdTable.GetFloat("edgeEffectiveness", 0.0f);
	// prevent 0/0 division in CGameHelper::Explosion
	if (wd.edgeEffectiveness > 0.999f) {
		wd.edgeEffectiveness = 0.999f;
	}

	wd.projectilespeed = wdTable.GetFloat("weaponVelocity", 0.0f) / GAME_SPEED;
	wd.startvelocity = max(0.01f, wdTable.GetFloat("startVelocity", 0.0f) / GAME_SPEED);
	wd.weaponacceleration = wdTable.GetFloat("weaponAcceleration", 0.0f) / GAME_SPEED / GAME_SPEED;
	wd.reload = wdTable.GetFloat("reloadtime", 1.0f);
	wd.salvodelay = wdTable.GetFloat("burstrate", 0.1f);
	wd.salvosize = wdTable.GetInt("burst", 1);
	wd.projectilespershot = wdTable.GetInt("projectiles", 1);
	wd.maxAngle = wdTable.GetFloat("tolerance", 3000.0f) * 180.0f / 0x7fff;
	wd.restTime = 0.0f;
	wd.metalcost = wdTable.GetFloat("metalpershot", 0.0f);
	wd.energycost = wdTable.GetFloat("energypershot", 0.0f);
	wd.selfExplode = wdTable.GetBool("burnblow", false);
	wd.predictBoost = wdTable.GetFloat("predictBoost", wd.selfExplode ? 0.5f : 0.0f);
	wd.sweepFire = wdTable.GetBool("sweepfire", false);
	wd.canAttackGround = wdTable.GetBool("canattackground", true);
	wd.myGravity = wdTable.GetFloat("myGravity", 0.0f);

	wd.fireStarter = wdTable.GetFloat("fireStarter", 0.0f) * 0.01f;
	wd.paralyzer = wdTable.GetBool("paralyzer", false);
	if (wd.paralyzer) {
		wd.damages.paralyzeDamageTime = max(0, wdTable.GetInt("paralyzeTime", 10));
	} else {
		wd.damages.paralyzeDamageTime = 0;
	}

	const float defShake = wd.paralyzer ? 0.0f : wd.damages.GetDefaultDamage();
	wd.cameraShake = wdTable.GetFloat("cameraShake", defShake);
	wd.cameraShake = max(0.0f, wd.cameraShake);

	wd.soundTrigger = wdTable.GetBool("soundTrigger", false);

	//sunparser->GetDef(wd.highTrajectory, "0", weaponname + "minbarrelangle");
	wd.stockpile     = wdTable.GetBool("stockpile", false);
	wd.interceptor   = wdTable.GetInt("interceptor", 0);
	wd.targetable    = wdTable.GetInt("targetable",  0);
	wd.manualfire    = wdTable.GetBool("commandfire", false);
	wd.coverageRange = wdTable.GetFloat("coverage", 0.0f);

	// FIXME -- remove the old style ?
	LuaTable shTable = wdTable.SubTable("shield");
	const float3 shieldBadColor (1.0f, 0.5f, 0.5f);
	const float3 shieldGoodColor(0.5f, 0.5f, 1.0f);
	if (shTable.IsValid()) {
		wd.shieldRepulser         = shTable.GetBool("repulser",       false);
		wd.smartShield            = shTable.GetBool("smart",          false);
		wd.exteriorShield         = shTable.GetBool("exterior",       false);
		wd.visibleShield          = shTable.GetBool("visible",        false);
		wd.visibleShieldRepulse   = shTable.GetBool("visibleRepulse", false);
		wd.visibleShieldHitFrames = shTable.GetInt("visibleHitFrames", 0);
		wd.shieldEnergyUse        = shTable.GetFloat("energyUse",        0.0f);
		wd.shieldForce            = shTable.GetFloat("force",            0.0f);
		wd.shieldRadius           = shTable.GetFloat("radius",           0.0f);
		wd.shieldMaxSpeed         = shTable.GetFloat("maxSpeed",         0.0f);
		wd.shieldPower            = shTable.GetFloat("power",            0.0f);
		wd.shieldPowerRegen       = shTable.GetFloat("powerRegen",       0.0f);
		wd.shieldPowerRegenEnergy = shTable.GetFloat("powerRegenEnergy", 0.0f);
		wd.shieldStartingPower    = shTable.GetFloat("startingPower",    0.0f);
		wd.shieldInterceptType    = shTable.GetInt("interceptType", 0);
		wd.shieldBadColor         = shTable.GetFloat3("badColor",  shieldBadColor);
		wd.shieldGoodColor        = shTable.GetFloat3("goodColor", shieldGoodColor);
		wd.shieldAlpha            = shTable.GetFloat("alpha", 0.2f);
	}
	else {
		wd.shieldRepulser         = wdTable.GetBool("shieldRepulser",       false);
		wd.smartShield            = wdTable.GetBool("smartShield",          false);
		wd.exteriorShield         = wdTable.GetBool("exteriorShield",       false);
		wd.visibleShield          = wdTable.GetBool("visibleShield",        false);
		wd.visibleShieldRepulse   = wdTable.GetBool("visibleShieldRepulse", false);
		wd.visibleShieldHitFrames = wdTable.GetInt("visibleShieldHitFrames", 0);
		wd.shieldEnergyUse        = wdTable.GetFloat("shieldEnergyUse",        0.0f);
		wd.shieldForce            = wdTable.GetFloat("shieldForce",            0.0f);
		wd.shieldRadius           = wdTable.GetFloat("shieldRadius",           0.0f);
		wd.shieldMaxSpeed         = wdTable.GetFloat("shieldMaxSpeed",         0.0f);
		wd.shieldPower            = wdTable.GetFloat("shieldPower",            0.0f);
		wd.shieldPowerRegen       = wdTable.GetFloat("shieldPowerRegen",       0.0f);
		wd.shieldPowerRegenEnergy = wdTable.GetFloat("shieldPowerRegenEnergy", 0.0f);
		wd.shieldStartingPower    = wdTable.GetFloat("shieldStartingPower",    0.0f);
		wd.shieldInterceptType    = wdTable.GetInt("shieldInterceptType", 0);
		wd.shieldBadColor  = wdTable.GetFloat3("shieldBadColor",  shieldBadColor);
		wd.shieldGoodColor = wdTable.GetFloat3("shieldGoodColor", shieldGoodColor);
		wd.shieldAlpha = wdTable.GetFloat("shieldAlpha", 0.2f);
	}


	int defInterceptType = 0;
	if (wd.type == "Cannon") {
		defInterceptType = 1;
	} else if ((wd.type == "LaserCannon") || (wd.type == "BeamLaser")) {
		defInterceptType = 2;
	} else if ((wd.type == "StarburstLauncher") || (wd.type == "MissileLauncher")) {
		defInterceptType = 4;
	}
	wd.interceptedByShieldType = wdTable.GetInt("interceptedByShieldType", defInterceptType);

	wd.wobble = wdTable.GetFloat("wobble", 0.0f) * PI / 0x7fff / 30.0f;
	wd.dance = wdTable.GetFloat("dance", 0.0f) / GAME_SPEED;
	wd.trajectoryHeight = wdTable.GetFloat("trajectoryHeight", 0.0f);

	wd.noAutoTarget = (wd.manualfire || wd.interceptor || wd.isShield);

	wd.onlyTargetCategory = 0xffffffff;
	if (wdTable.GetBool("toAirWeapon", false)) {
		// fix if we sometime call aircrafts otherwise
		wd.onlyTargetCategory = CCategoryHandler::Instance()->GetCategories("VTOL");
		//logOutput.Print("air only weapon %s %i",weaponname.c_str(),wd.onlyTargetCategory);
	}

	wd.largeBeamLaser = wdTable.GetBool("largeBeamLaser", false);
	wd.visuals.tilelength  = wdTable.GetFloat("tileLength", 200.0f);
	wd.visuals.scrollspeed = wdTable.GetFloat("scrollSpeed",  5.0f);
	wd.visuals.pulseSpeed  = wdTable.GetFloat("pulseSpeed",   1.0f);
	wd.visuals.beamdecay   = wdTable.GetFloat("beamDecay",    1.0f);
	wd.visuals.beamttl     = wdTable.GetInt("beamTTL", 0);

	if (wd.type == "Cannon") {
		wd.heightmod = wdTable.GetFloat("heightMod", 0.8f);
	} else if (wd.type == "BeamLaser") {
		wd.heightmod = wdTable.GetFloat("heightMod", 1.0f);
	} else {
		wd.heightmod = wdTable.GetFloat("heightMod", 0.2f);
	}

	wd.supplycost = 0.0f;

	wd.onlyForward = !wd.turret && (wd.type != "StarburstLauncher");

	const int color2 = wdTable.GetInt("color2", 0);

	const float3 rgbcol = hs2rgb(color / float(255), color2 / float(255));
	wd.visuals.color  = wdTable.GetFloat3("rgbColor",  rgbcol);
	wd.visuals.color2 = wdTable.GetFloat3("rgbColor2", float3(1.0f, 1.0f, 1.0f));

	wd.uptime = wdTable.GetFloat("weaponTimer", 0.0f);
	wd.flighttime = wdTable.GetInt("flightTime", 0) * 32;

	wd.turnrate = wdTable.GetFloat("turnRate", 0.0f) * PI / 0x7fff / 30.0f;

	if ((wd.type == "AircraftBomb") && !manualBombSettings) {
		if (wd.reload < 0.5f) {
			wd.salvodelay = min(0.2f, wd.reload);
			wd.salvosize = (int)(1 / wd.salvodelay) + 1;
			wd.reload = 5;
		} else {
			wd.salvodelay = min(0.4f, wd.reload);
			wd.salvosize = 2;
		}
	}
	//if(!wd.turret && (wd.type != "TorpedoLauncher")) {
	//	wd.maxAngle*=0.4f;
	//}

	//2+min(damages[0]*0.0025f,weaponDef->areaOfEffect*0.1f)
	const float tempsize = 2.0f + min(wd.damages[0] * 0.0025f, wd.areaOfEffect * 0.1f);
	wd.size = wdTable.GetFloat("size", tempsize);
	wd.sizeGrowth = wdTable.GetFloat("sizeGrowth", 0.2f);
	wd.collisionSize = wdTable.GetFloat("collisionSize", 0.05f);

	wd.visuals.colorMap = 0;
	const string colormap = wdTable.GetString("colormap", "");
	if (colormap != "") {
		wd.visuals.colorMap = CColorMap::LoadFromDefString(colormap);
	}

	wd.heightBoostFactor = wdTable.GetFloat("heightBoostFactor", -1.0f);
	wd.proximityPriority = wdTable.GetFloat("proximityPriority", 1.0f);

	// get some weapon specific defaults
	if (wd.type == "Cannon") {
		// CExplosiveProjectile
		wd.visuals.texture1 = &ph->plasmatex;
		wd.visuals.color = wdTable.GetFloat3("rgbColor", float3(1.0f,0.5f,0.0f));
		wd.intensity = wdTable.GetFloat("intensity", 0.2f);
	} else if (wd.type == "Rifle") {
		// ...
	} else if (wd.type == "Melee") {
		// ...
	} else if (wd.type == "AircraftBomb") {
		// CExplosiveProjectile or CTorpedoProjectile
		wd.visuals.texture1 = &ph->plasmatex;
	} else if (wd.type == "Shield") {
		wd.visuals.texture1 = &ph->perlintex;
	} else if (wd.type == "Flame") {
		// CFlameProjectile
		wd.visuals.texture1 = &ph->flametex;
		wd.size          = wdTable.GetFloat("size",      tempsize);
		wd.sizeGrowth    = wdTable.GetFloat("sizeGrowth",    0.5f);
		wd.collisionSize = wdTable.GetFloat("collisionSize", 0.5f);
		wd.duration      = wdTable.GetFloat("flameGfxTime",  1.2f);

		if (wd.visuals.colorMap == 0) {
			wd.visuals.colorMap = CColorMap::Load12f(1.000f, 1.000f, 1.000f, 0.100f,
			                                         0.025f, 0.025f, 0.025f, 0.100f,
			                                         0.000f, 0.000f, 0.000f, 0.000f);
		}

	} else if (wd.type == "MissileLauncher") {
		// CMissileProjectile
		wd.visuals.texture1 = &ph->missileflaretex;
		wd.visuals.texture2 = &ph->missiletrailtex;
	} else if (wd.type == "TorpedoLauncher") {
		// CExplosiveProjectile or CTorpedoProjectile
		wd.visuals.texture1 = &ph->plasmatex;
	} else if (wd.type == "LaserCannon") {
		// CLaserProjectile
		wd.visuals.texture1 = &ph->laserfallofftex;
		wd.visuals.texture2 = &ph->laserendtex;
		wd.visuals.hardStop = wdTable.GetBool("hardstop", false);
		wd.collisionSize = wdTable.GetFloat("collisionSize", 0.5f);
	} else if (wd.type == "BeamLaser") {
		if (wd.largeBeamLaser) {
			wd.visuals.texture1 = ph->textureAtlas->GetTexturePtr("largebeam");
			wd.visuals.texture2 = &ph->laserendtex;
			wd.visuals.texture3 = ph->textureAtlas->GetTexturePtr("muzzleside");
			wd.visuals.texture4 = &ph->beamlaserflaretex;
		} else {
			wd.visuals.texture1 = &ph->laserfallofftex;
			wd.visuals.texture2 = &ph->laserendtex;
			wd.visuals.texture3 = &ph->beamlaserflaretex;
		}
	} else if (wd.type == "LightingCannon") {
		wd.visuals.texture1 = &ph->laserfallofftex;
		wd.thickness = wdTable.GetFloat("thickness", 0.8f);
	} else if (wd.type == "EmgCannon") {
		// CEmgProjectile
		wd.visuals.texture1 = &ph->plasmatex;
		wd.visuals.color = wdTable.GetFloat3("rgbColor", float3(0.9f,0.9f,0.2f)); 
		wd.size = wdTable.GetFloat("size", 3.0f);
	} else if (wd.type == "DGun") {
		// CFireBallProjectile
		wd.collisionSize = wdTable.GetFloat("collisionSize", 10.0f);
	} else if (wd.type == "StarburstLauncher") {
		// CStarburstProjectile
		wd.visuals.texture1 = &ph->sbflaretex;
		wd.visuals.texture2 = &ph->sbtrailtex;
		wd.visuals.texture3 = &ph->explotex;
	} else {
		wd.visuals.texture1 = &ph->plasmatex;
		wd.visuals.texture2 = &ph->plasmatex;
	}

	// FIXME -- remove the 'textureN' format?
	LuaTable texTable = wdTable.SubTable("textures");
	string texName;
	texName = wdTable.GetString("texture1", "");
	texName = texTable.GetString(1, texName);
	if (texName != "") {
		wd.visuals.texture1 = ph->textureAtlas->GetTexturePtr(texName);
	}
	texName = wdTable.GetString("texture2", "");
	texName = texTable.GetString(2, texName);
	if (texName != "") {
		wd.visuals.texture2 = ph->textureAtlas->GetTexturePtr(texName);
	}
	texName = wdTable.GetString("texture3", "");
	texName = texTable.GetString(3, texName);
	if (texName != "") {
		wd.visuals.texture3 = ph->textureAtlas->GetTexturePtr(texName);
	}
	texName = wdTable.GetString("texture4", "");
	texName = texTable.GetString(4, texName);
	if (texName != "") {
		wd.visuals.texture4 = ph->textureAtlas->GetTexturePtr(texName);
	}

	const string expGenTag = wdTable.GetString("explosionGenerator", "");
	if (expGenTag.empty()) {
		wd.explosionGenerator = NULL;
	} else {
		wd.explosionGenerator = explGenHandler->LoadGenerator(expGenTag);
	}
	const string bounceExpGenTag = wdTable.GetString("bounceExplosionGenerator", "");
	if (bounceExpGenTag.empty()) {
		wd.bounceExplosionGenerator = NULL;
	} else {
		wd.bounceExplosionGenerator = explGenHandler->LoadGenerator(bounceExpGenTag);
	}

	const float gd = max(30.0f, wd.damages[0] / 20.0f);
	const float defExpSpeed = (8.0f + (gd * 2.5f)) / (9.0f + (sqrtf(gd) * 0.7f)) * 0.5f;
	wd.explosionSpeed = wdTable.GetFloat("explosionSpeed", defExpSpeed);

	// Dynamic Damage
	wd.dynDamageInverted = wdTable.GetBool("dynDamageInverted", false);
	wd.dynDamageExp      = wdTable.GetFloat("dynDamageExp",   0.0f);
	wd.dynDamageMin      = wdTable.GetFloat("dynDamageMin",   0.0f);
	wd.dynDamageRange    = wdTable.GetFloat("dynDamageRange", 0.0f);

	LoadSound(wdTable, wd.firesound, "firesound");
	LoadSound(wdTable, wd.soundhit,  "soundhit");

	if ((wd.firesound.getVolume(0) == -1.0f) ||
	    (wd.soundhit.getVolume(0)  == -1.0f)) {
		// no volume (-1.0f) read from weapon definition, set it dynamically here
		if (wd.damages[0] <= 50.0f) {
			wd.soundhit.setVolume(0, 5.0f);
			wd.firesound.setVolume(0, 5.0f);
		}
		else {
			float soundVolume = sqrt(wd.damages[0] * 0.5f);

			if (wd.type == "LaserCannon") {
				soundVolume *= 0.5f;
			}

			float hitSoundVolume = soundVolume;

			if ((soundVolume > 100.0f) &&
			    ((wd.type == "MissileLauncher") ||
			     (wd.type == "StarburstLauncher"))) {
				soundVolume = 10.0f * sqrt(soundVolume);
			}

			if (wd.firesound.getVolume(0) == -1.0f) {
				wd.firesound.setVolume(0, soundVolume);
			}

			soundVolume = hitSoundVolume;

			if (wd.areaOfEffect > 8.0f) {
				soundVolume *= 2.0f;
			}
			if (wd.type == "DGun") {
				soundVolume *= 0.15f;
			}
			if (wd.soundhit.getVolume(0) == -1.0f) {
				wd.soundhit.setVolume(0, soundVolume);
			}
		}
	}
}
Exemple #7
0
WeaponDef::WeaponDef(const LuaTable& wdTable, const std::string& name_, int id_)
	: name(name_)

	, ptrailExplosionGeneratorID(CExplosionGeneratorHandler::EXPGEN_ID_INVALID)
	, impactExplosionGeneratorID(CExplosionGeneratorHandler::EXPGEN_ID_STANDARD)
	, bounceExplosionGeneratorID(CExplosionGeneratorHandler::EXPGEN_ID_INVALID)

	, id(id_)
	, projectileType(WEAPON_BASE_PROJECTILE)
	, collisionFlags(0)
{
	WeaponDefs.Load(this, wdTable);

	if (wdTable.KeyExists("cylinderTargetting"))
		LOG_L(L_WARNING, "WeaponDef (%s) cylinderTargetting is deprecated and will be removed in the next release (use cylinderTargeting).", name.c_str());

	if (wdTable.KeyExists("color1") || wdTable.KeyExists("color2"))
		LOG_L(L_WARNING, "WeaponDef (%s) color1 & color2 (= hue & sat) are removed. Use rgbColor instead!", name.c_str());

	if (wdTable.KeyExists("isShield"))
		LOG_L(L_WARNING, "WeaponDef (%s) The \"isShield\" tag has been removed. Use the weaponType=\"Shield\" tag instead!", name.c_str());

	shieldRechargeDelay = int(wdTable.GetFloat("rechargeDelay", 0) * GAME_SPEED);
	shieldArmorType = damageArrayHandler->GetTypeFromName(shieldArmorTypeName);
	flighttime = int(wdTable.GetFloat("flighttime", 0.0f) * 32);
	maxFireAngle = math::cos(wdTable.GetFloat("firetolerance", 3640.0f) * TAANG2RAD);
	
	//FIXME may be smarter to merge the collideXYZ tags with avoidXYZ and removing the collisionFlags tag (and move the code into CWeapon)?
	collisionFlags = 0;
	if (!wdTable.GetBool("collideEnemy",    true)) { collisionFlags |= Collision::NOENEMIES;    }
	if (!wdTable.GetBool("collideFriendly", true)) { collisionFlags |= Collision::NOFRIENDLIES; }
	if (!wdTable.GetBool("collideFeature",  true)) { collisionFlags |= Collision::NOFEATURES;   }
	if (!wdTable.GetBool("collideNeutral",  true)) { collisionFlags |= Collision::NONEUTRALS;   }
	if (!wdTable.GetBool("collideGround",   true)) { collisionFlags |= Collision::NOGROUND;     }

	//FIXME defaults depend on other tags
	{
		if (paralyzer)
			cameraShake = wdTable.GetFloat("cameraShake", 0.0f);

		if (selfExplode)
			predictBoost = wdTable.GetFloat("predictBoost", 0.5f);

		if (type == "Melee") {
			targetBorder = Clamp(wdTable.GetFloat("targetBorder", 1.0f), -1.0f, 1.0f);
			cylinderTargeting = Clamp(wdTable.GetFloat("cylinderTargeting", wdTable.GetFloat("cylinderTargetting", 1.0f)), 0.0f, 128.0f);
		}

		if (type == "Flame") {
			//FIXME move to lua (for all other weapons this tag is named `duration` and has a different default)
			duration = wdTable.GetFloat("flameGfxTime", 1.2f);
		}

		if (type == "Cannon") {
			heightmod = wdTable.GetFloat("heightMod", 0.8f);
		} else if (type == "BeamLaser" || type == "LightningCannon") {
			heightmod = wdTable.GetFloat("heightMod", 1.0f);
		}

		if (type == "LaserCannon") {
			// for lasers we want this to be true by default: it sets
			// projectile ttl values to the minimum required to hit a
			// target which prevents them overshooting (lasers travel
			// many elmos per frame and ttl's are rounded) at maximum
			// range
			selfExplode = wdTable.GetBool("burnblow", true);
		}
	}

	// setup the default damages
	{
		const LuaTable dmgTable = wdTable.SubTable("damage");
		float defDamage = dmgTable.GetFloat("default", 1.0f);

		// avoid division by zeros
		if (defDamage == 0.0f)
			defDamage = 1.0f;

		damages.SetDefaultDamage(defDamage);

		if (!paralyzer)
			damages.paralyzeDamageTime = 0;

		std::map<string, float> dmgs;
		std::map<string, float>::const_iterator di;

		dmgTable.GetMap(dmgs);

		for (di = dmgs.begin(); di != dmgs.end(); ++di) {
			const int type = damageArrayHandler->GetTypeFromName(di->first);
			if (type != 0) {
				float dmg = di->second;
				if (dmg != 0.0f) {
					damages[type] = dmg;
				} else {
					damages[type] = 1.0f;
				}
			}
		}

		const float tempsize = 2.0f + std::min(defDamage * 0.0025f, damageAreaOfEffect * 0.1f);
		const float gd = std::max(30.0f, defDamage / 20.0f);
		const float defExpSpeed = (8.0f + (gd * 2.5f)) / (9.0f + (math::sqrt(gd) * 0.7f)) * 0.5f;

		size = wdTable.GetFloat("size", tempsize);
		explosionSpeed = wdTable.GetFloat("explosionSpeed", defExpSpeed);
	}

	{
		// 0.78.2.1 backwards compatibility: non-burst beamlasers play one
		// sample per shot, not for each individual beam making up the shot
		const bool singleSampleShot = (type == "BeamLaser" && !beamburst);
		const bool singleShotWeapon = (type == "Melee" || type == "Rifle");

		soundTrigger = wdTable.GetBool("soundTrigger", singleSampleShot || singleShotWeapon);
	}

	// get some weapon specific defaults
	int defInterceptType = 0;

	if (type == "Cannon") {
		// CExplosiveProjectile
		defInterceptType = 1;
		projectileType = WEAPON_EXPLOSIVE_PROJECTILE;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.9f);
		intensity = wdTable.GetFloat("intensity", 0.2f);
	} else if (type == "Rifle") {
		// no projectile or intercept type
		defInterceptType = 128;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.9f);
	} else if (type == "Melee") {
		// no projectile or intercept type
		defInterceptType = 256;
	} else if (type == "Flame") {
		// CFlameProjectile
		projectileType = WEAPON_FLAME_PROJECTILE;
		defInterceptType = 16;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.2f);
		collisionSize     = wdTable.GetFloat("collisionSize", 0.5f);
	} else if (type == "MissileLauncher") {
		// CMissileProjectile
		projectileType = WEAPON_MISSILE_PROJECTILE;
		defInterceptType = 4;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
	} else if (type == "LaserCannon") {
		// CLaserProjectile
		projectileType = WEAPON_LASER_PROJECTILE;
		defInterceptType = 2;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
		collisionSize = wdTable.GetFloat("collisionSize", 0.5f);
	} else if (type == "BeamLaser") {
		projectileType = largeBeamLaser? WEAPON_LARGEBEAMLASER_PROJECTILE: WEAPON_BEAMLASER_PROJECTILE;
		defInterceptType = 2;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
	} else if (type == "LightningCannon") {
		projectileType = WEAPON_LIGHTNING_PROJECTILE;
		defInterceptType = 64;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
	} else if (type == "EmgCannon") {
		// CEmgProjectile
		projectileType = WEAPON_EMG_PROJECTILE;
		defInterceptType = 1;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
		size = wdTable.GetFloat("size", 3.0f);
	} else if (type == "TorpedoLauncher") {
		// WeaponLoader will create either BombDropper with dropTorpedoes = true
		// (owner->unitDef->canfly && !weaponDef->submissile) or TorpedoLauncher
		// (both types of weapons will spawn TorpedoProjectile's)
		//
		projectileType = WEAPON_TORPEDO_PROJECTILE;
		defInterceptType = 32;

		waterweapon = true;
	} else if (type == "DGun") {
		// CFireBallProjectile
		projectileType = WEAPON_FIREBALL_PROJECTILE;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
		collisionSize = wdTable.GetFloat("collisionSize", 10.0f);
	} else if (type == "StarburstLauncher") {
		// CStarburstProjectile
		projectileType = WEAPON_STARBURST_PROJECTILE;
		defInterceptType = 4;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
	} else if (type == "AircraftBomb") {
		// WeaponLoader will create BombDropper with dropTorpedoes = false
		// BombDropper with dropTorpedoes=false spawns ExplosiveProjectile's
		//
		projectileType = WEAPON_EXPLOSIVE_PROJECTILE;
		defInterceptType = 8;

		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.9f);
	} else {
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.0f);
	}

	interceptedByShieldType = wdTable.GetInt("interceptedByShieldType", defInterceptType);

	const std::string& colormap = wdTable.GetString("colormap", "");

	if (!colormap.empty()) {
		visuals.colorMap = CColorMap::LoadFromDefString(colormap);
	} else {
		visuals.colorMap = NULL;
	}

	ParseWeaponSounds(wdTable);

	// custom parameters table
	wdTable.SubTable("customParams").GetMap(customParams);

	// internal only
	isShield = (type == "Shield");
	noAutoTarget = (manualfire || interceptor || isShield);
	onlyForward = !turret && (type != "StarburstLauncher");
}
CProjectileHandler::CProjectileHandler()
{
	PrintLoadMsg("Creating projectile texture");

	maxParticles     = configHandler->Get("MaxParticles",      4000);
	maxNanoParticles = configHandler->Get("MaxNanoParticles", 10000);

	currentParticles       = 0;
	currentNanoParticles   = 0;
	particleSaturation     = 0.0f;
	nanoParticleSaturation = 0.0f;
	numPerlinProjectiles   = 0;

	// preload some IDs
	// (note that 0 is reserved for unsynced projectiles)
	for (int i = 1; i <= 12345; i++) {
		freeIDs.push_back(i);
	}
	maxUsedID = freeIDs.size();

	textureAtlas = new CTextureAtlas(2048, 2048);

	// used to block resources_map.tdf from loading textures
	set<string> blockMapTexNames;

	LuaParser resourcesParser("gamedata/resources.lua",
	                          SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
	if (!resourcesParser.Execute()) {
		logOutput.Print(resourcesParser.GetErrorLog());
	}
	const LuaTable rootTable = resourcesParser.GetRoot();
	const LuaTable gfxTable = rootTable.SubTable("graphics");

	const LuaTable ptTable = gfxTable.SubTable("projectileTextures");
	// add all textures in projectiletextures section
	map<string, string> ptex;
	ptTable.GetMap(ptex);

	for (map<string, string>::iterator pi=ptex.begin(); pi!=ptex.end(); ++pi) {
		textureAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
		blockMapTexNames.insert(StringToLower(pi->first));
	}

	// add all texture from sections within projectiletextures section
	vector<string> seclist;
	ptTable.GetKeys(seclist);
	for (size_t i = 0; i < seclist.size(); i++) {
		const LuaTable ptSubTable = ptTable.SubTable(seclist[i]);
		if (ptSubTable.IsValid()) {
			map<string, string> ptex2;
			ptSubTable.GetMap(ptex2);
			for (map<string, string>::iterator pi = ptex2.begin(); pi != ptex2.end(); ++pi) {
				textureAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
				blockMapTexNames.insert(StringToLower(pi->first));
			}
		}
	}

	// get the smoke textures, hold the count in 'smokeCount'
	const LuaTable smokeTable = gfxTable.SubTable("smoke");
	int smokeCount;
	if (smokeTable.IsValid()) {
		for (smokeCount = 0; true; smokeCount++) {
			const string tex = smokeTable.GetString(smokeCount + 1, "");
			if (tex.empty()) {
				break;
			}
			const string texName = "bitmaps/" + tex;
			const string smokeName = "ismoke" + IntToString(smokeCount, "%02i");
			textureAtlas->AddTexFromFile(smokeName, texName);
			blockMapTexNames.insert(StringToLower(smokeName));
		}
	}
	else {
		// setup the defaults
		for (smokeCount = 0; smokeCount < 12; smokeCount++) {
			const string smokeNum = IntToString(smokeCount, "%02i");
			const string smokeName = "ismoke" + smokeNum;
			const string texName = "bitmaps/smoke/smoke" + smokeNum + ".tga";
			textureAtlas->AddTexFromFile(smokeName, texName);
			blockMapTexNames.insert(StringToLower(smokeName));
		}
	}
	if (smokeCount <= 0) {
		throw content_error("missing smoke textures");
	}

	char tex[128][128][4];
	for (int y = 0; y < 128; y++) { // shield
		for (int x = 0; x < 128; x++) {
			tex[y][x][0] = 70;
			tex[y][x][1] = 70;
			tex[y][x][2] = 70;
			tex[y][x][3] = 70;
		}
	}
	textureAtlas->AddTexFromMem("perlintex", 128, 128, CTextureAtlas::RGBA32, tex);
	blockMapTexNames.insert("perlintex");

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

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

	// allow map specified atlas textures for gaia unit projectiles
	LuaParser mapResParser("gamedata/resources_map.lua",
	                              SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
	if (mapResParser.IsValid()) {
		const LuaTable mapRoot = mapResParser.GetRoot();
		const LuaTable mapTable = mapRoot.SubTable("projectileTextures");
		//add all textures in projectiletextures section
		map<string, string> mptex;
		mapTable.GetMap(mptex);
		map<string, string>::iterator pi;
		for (pi = mptex.begin(); pi != mptex.end(); ++pi) {
			if (blockMapTexNames.find(StringToLower(pi->first)) == blockMapTexNames.end()) {
				textureAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
			}
		}
		//add all texture from sections within projectiletextures section
		mapTable.GetKeys(seclist);
		for (size_t i = 0; i < seclist.size(); i++) {
			const LuaTable mapSubTable = mapTable.SubTable(seclist[i]);
			if (mapSubTable.IsValid()) {
				map<string, string> ptex2;
				mapSubTable.GetMap(ptex2);
				for (map<string, string>::iterator pi = ptex2.begin(); pi != ptex2.end(); ++pi) {
					if (blockMapTexNames.find(StringToLower(pi->first)) == blockMapTexNames.end()) {
						textureAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
					}
				}
			}
		}
	}

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

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

	for (int i = 0; i < smokeCount; i++) {
		const string smokeName = "ismoke" + IntToString(i, "%02i");
		smoketex.push_back(textureAtlas->GetTexture(smokeName));
	}

#define GETTEX(t, b) textureAtlas->GetTextureWithBackup((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

	groundFXAtlas = new CTextureAtlas(2048, 2048);
	//add all textures in groundfx section
	const LuaTable groundfxTable = gfxTable.SubTable("groundfx");
	groundfxTable.GetMap(ptex);
	for (map<string, string>::iterator pi = ptex.begin(); pi != ptex.end(); ++pi) {
		groundFXAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
	}
	//add all texture from sections within groundfx section
	groundfxTable.GetKeys(seclist);
	for (size_t i = 0; i < seclist.size(); i++) {
		const LuaTable gfxSubTable = groundfxTable.SubTable(seclist[i]);
		if (gfxSubTable.IsValid()) {
			map<string, string> ptex2;
			gfxSubTable.GetMap(ptex2);
			for (map<string, string>::iterator pi = ptex2.begin(); pi != ptex2.end(); ++pi) {
				groundFXAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
			}
		}
	}

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

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

	if (shadowHandler->canUseShadows) {
		projectileShadowVP = LoadVertexProgram("projectileshadow.vp");
	}

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

	unsigned char tempmem[4*16*16];
	for (int a = 0; a < 4 * 16 * 16; ++a) {
		tempmem[a] = 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();
	}
}
void CWeaponDefHandler::ParseWeapon(const LuaTable& wdTable, WeaponDef& wd)
{
	bool manualBombSettings; //Allow the user to manually specify the burst and burstrate for his AircraftBomb
	int color;
	int color2;

	wd.tdfId = wdTable.GetInt("id", 0);

	wd.description = wdTable.GetString("name",     "Weapon");
	wd.cegTag      = wdTable.GetString("cegTag",   "");

	wd.avoidFriendly = wdTable.GetBool("avoidFriendly", true);
	wd.avoidFeature  = wdTable.GetBool("avoidFeature",  true);
	wd.avoidNeutral  = wdTable.GetBool("avoidNeutral",  false);

	//FIXME may be smarter to merge the collideXYZ tags with avoidXYZ and removing the collisionFlags tag (and move the code into CWeapon)?
	wd.collisionFlags = 0;

	if (!wdTable.GetBool("collideEnemy",    true)) { wd.collisionFlags |= Collision::NOENEMIES;    }
	if (!wdTable.GetBool("collideFriendly", true)) { wd.collisionFlags |= Collision::NOFRIENDLIES; }
	if (!wdTable.GetBool("collideFeature",  true)) { wd.collisionFlags |= Collision::NOFEATURES;   }
	if (!wdTable.GetBool("collideNeutral",  true)) { wd.collisionFlags |= Collision::NONEUTRALS;   }
	if (!wdTable.GetBool("collideGround",   true)) { wd.collisionFlags |= Collision::NOGROUND;     }

	wd.minIntensity = wdTable.GetFloat("minIntensity", 0.0f);

	manualBombSettings = wdTable.GetBool("manualBombSettings", false);
	wd.turret   = wdTable.GetBool("turret",      false);
	wd.highTrajectory = wdTable.GetInt("highTrajectory", 2);
	wd.noSelfDamage   = wdTable.GetBool("noSelfDamage", false);
	wd.impactOnly     = wdTable.GetBool("impactOnly",   false);

	wd.waterweapon   = wdTable.GetBool("waterWeapon",     false);
	wd.fireSubmersed = wdTable.GetBool("fireSubmersed",   wd.waterweapon);
	wd.submissile    = wdTable.GetBool("submissile",      false);
	wd.tracks        = wdTable.GetBool("tracks",          false);
	wd.fixedLauncher = wdTable.GetBool("fixedLauncher",   false);
	wd.noExplode     = wdTable.GetBool("noExplode",       false);
	wd.isShield      = wdTable.GetBool("isShield",        false);
	wd.beamtime      = wdTable.GetFloat("beamTime",       1.0f);
	wd.beamburst     = wdTable.GetBool("beamburst",       false);

	wd.waterBounce   = wdTable.GetBool("waterBounce",    false);
	wd.groundBounce  = wdTable.GetBool("groundBounce",   false);
	wd.bounceSlip    = wdTable.GetFloat("bounceSlip",    1.0f);
	wd.bounceRebound = wdTable.GetFloat("bounceRebound", 1.0f);
	wd.numBounce     = wdTable.GetInt("numBounce",       -1);

	wd.thickness      = wdTable.GetFloat("thickness",      2.0f);
	wd.corethickness  = wdTable.GetFloat("coreThickness",  0.25f);
	wd.laserflaresize = wdTable.GetFloat("laserFlareSize", 15.0f);
	wd.intensity      = wdTable.GetFloat("intensity",      0.9f);
	wd.duration       = wdTable.GetFloat("duration",       0.05f);
	wd.falloffRate    = wdTable.GetFloat("fallOffRate",    0.5f);
	wd.lodDistance    = wdTable.GetInt("lodDistance",      1000);

	wd.visuals.modelName     = wdTable.GetString("model",       "");
	wd.visuals.explosionScar = wdTable.GetBool("explosionScar", true);
	wd.visuals.smokeTrail    = wdTable.GetBool("smokeTrail",    false);
	wd.visuals.alwaysVisible = wdTable.GetBool("alwaysVisible", false);
	wd.visuals.sizeDecay     = wdTable.GetFloat("sizeDecay",    0.0f);
	wd.visuals.alphaDecay    = wdTable.GetFloat("alphaDecay",   1.0f);
	wd.visuals.separation    = wdTable.GetFloat("separation",   1.0f);
	wd.visuals.noGap         = wdTable.GetBool("noGap",         true);
	wd.visuals.stages        = wdTable.GetInt("stages",         5);

	wd.gravityAffected = wdTable.GetBool("gravityAffected", false);

	wd.type = wdTable.GetString("weaponType", "Cannon");

	wd.targetBorder = Clamp(wdTable.GetFloat("targetBorder", (wd.type == "Melee")? 1.0f : 0.0f), -1.0f, 1.0f);
	wd.cylinderTargetting = Clamp(wdTable.GetFloat("cylinderTargetting", (wd.type == "Melee")? 1.0f : 0.0f), 0.0f, 128.0f);

	wd.range = wdTable.GetFloat("range", 10.0f);
	const float accuracy       = wdTable.GetFloat("accuracy",   0.0f);
	const float sprayAngle     = wdTable.GetFloat("sprayAngle", 0.0f);
	const float movingAccuracy = wdTable.GetFloat("movingAccuracy", accuracy);
	// should really be tan but TA seem to cap it somehow
	// should also be 7fff or ffff theoretically but neither seems good
	wd.accuracy       = sin((accuracy)       * PI / 0xafff);
	wd.sprayAngle     = sin((sprayAngle)     * PI / 0xafff);
	wd.movingAccuracy = sin((movingAccuracy) * PI / 0xafff);

	wd.targetMoveError = wdTable.GetFloat("targetMoveError", 0.0f);
	wd.leadLimit = wdTable.GetFloat("leadLimit", -1.0f);
	wd.leadBonus = wdTable.GetFloat("leadBonus", 0.0f);

	// setup the default damages
	const LuaTable dmgTable = wdTable.SubTable("damage");
	float defDamage = dmgTable.GetFloat("default", 0.0f);
	if (defDamage == 0.0f) {
		defDamage = 1.0f; //avoid division by zeroes
	}
	for (int a = 0; a < damageArrayHandler->GetNumTypes(); ++a) {
		wd.damages[a] = defDamage;
	}

	map<string, float> damages;
	dmgTable.GetMap(damages);

	map<string, float>::const_iterator di;
	for (di = damages.begin(); di != damages.end(); ++di) {
		const int type = damageArrayHandler->GetTypeFromName(di->first);
		if (type != 0) {
			float dmg = di->second;
			if (dmg != 0.0f) {
				wd.damages[type] = dmg;
			} else {
				wd.damages[type] = 1.0f;
			}
		}
	}

	wd.damages.impulseFactor = wdTable.GetFloat("impulseFactor", 1.0f);
	wd.damages.impulseBoost  = wdTable.GetFloat("impulseBoost",  0.0f);
	wd.damages.craterMult    = wdTable.GetFloat("craterMult",    wd.damages.impulseFactor);
	wd.damages.craterBoost   = wdTable.GetFloat("craterBoost",   0.0f);

	wd.areaOfEffect = wdTable.GetFloat("areaOfEffect", 8.0f) * 0.5f;
	wd.edgeEffectiveness = wdTable.GetFloat("edgeEffectiveness", 0.0f);
	// prevent 0/0 division in CGameHelper::Explosion
	if (wd.edgeEffectiveness > 0.999f) {
		wd.edgeEffectiveness = 0.999f;
	}

	wd.projectilespeed = std::max(0.01f, wdTable.GetFloat("weaponVelocity", 0.0f) / GAME_SPEED);
	wd.startvelocity = max(0.01f, wdTable.GetFloat("startVelocity", 0.0f) / GAME_SPEED);
	wd.weaponacceleration = wdTable.GetFloat("weaponAcceleration", 0.0f) / GAME_SPEED / GAME_SPEED;
	wd.reload = wdTable.GetFloat("reloadTime", 1.0f);
	wd.salvodelay = wdTable.GetFloat("burstRate", 0.1f);
	wd.salvosize = wdTable.GetInt("burst", 1);
	wd.projectilespershot = wdTable.GetInt("projectiles", 1);
	wd.maxAngle = wdTable.GetFloat("tolerance", 3000.0f) * 180.0f / COBSCALEHALF;
	wd.restTime = 0.0f;
	wd.metalcost = wdTable.GetFloat("metalPerShot", 0.0f);
	wd.energycost = wdTable.GetFloat("energyPerShot", 0.0f);
	wd.selfExplode = wdTable.GetBool("burnblow", false);
	wd.predictBoost = wdTable.GetFloat("predictBoost", wd.selfExplode ? 0.5f : 0.0f);
	wd.sweepFire = wdTable.GetBool("sweepfire", false);
	wd.canAttackGround = wdTable.GetBool("canAttackGround", true);
	wd.myGravity = wdTable.GetFloat("myGravity", 0.0f);

	wd.fireStarter = wdTable.GetFloat("fireStarter", 0.0f) * 0.01f;
	wd.paralyzer = wdTable.GetBool("paralyzer", false);
	if (wd.paralyzer) {
		wd.damages.paralyzeDamageTime = max(0, wdTable.GetInt("paralyzeTime", 10));
	} else {
		wd.damages.paralyzeDamageTime = 0;
	}

	const float defShake = wd.paralyzer ? 0.0f : wd.damages.GetDefaultDamage();
	wd.cameraShake = wdTable.GetFloat("cameraShake", defShake);
	wd.cameraShake = max(0.0f, wd.cameraShake);

	// 0.78.2.1 backwards compatibility
	bool defaultSoundTrigger = (wd.type == "BeamLaser" && !wd.beamburst) || 
								wd.type == "Melee"  || wd.type == "Rifle";
	wd.soundTrigger = wdTable.GetBool("soundTrigger", defaultSoundTrigger);

	//sunparser->GetDef(wd.highTrajectory, "0", weaponname + "minbarrelangle");
	wd.stockpile     = wdTable.GetBool("stockpile", false);
	wd.stockpileTime = wdTable.GetFloat("stockpileTime", wd.reload);
	wd.interceptor   = wdTable.GetInt("interceptor", 0);
	wd.targetable    = wdTable.GetInt("targetable",  0);
	wd.manualfire    = wdTable.GetBool("commandfire", false);
	wd.coverageRange = wdTable.GetFloat("coverage", 0.0f);

	// FIXME -- remove the old style ?
	LuaTable shTable = wdTable.SubTable("shield");
	const float3 shieldBadColor (1.0f, 0.5f, 0.5f);
	const float3 shieldGoodColor(0.5f, 0.5f, 1.0f);
	if (shTable.IsValid()) {
		wd.shieldRepulser         = shTable.GetBool("repulser",       false);
		wd.smartShield            = shTable.GetBool("smart",          false);
		wd.exteriorShield         = shTable.GetBool("exterior",       false);
		wd.visibleShield          = shTable.GetBool("visible",        false);
		wd.visibleShieldRepulse   = shTable.GetBool("visibleRepulse", false);
		wd.visibleShieldHitFrames = shTable.GetInt("visibleHitFrames", 0);
		wd.shieldEnergyUse        = shTable.GetFloat("energyUse",        0.0f);
		wd.shieldForce            = shTable.GetFloat("force",            0.0f);
		wd.shieldRadius           = shTable.GetFloat("radius",           0.0f);
		wd.shieldMaxSpeed         = shTable.GetFloat("maxSpeed",         0.0f);
		wd.shieldPower            = shTable.GetFloat("power",            0.0f);
		wd.shieldPowerRegen       = shTable.GetFloat("powerRegen",       0.0f);
		wd.shieldPowerRegenEnergy = shTable.GetFloat("powerRegenEnergy", 0.0f);
		wd.shieldRechargeDelay    = (int)(shTable.GetFloat("rechargeDelay", 0) * GAME_SPEED);
		wd.shieldStartingPower    = shTable.GetFloat("startingPower",    0.0f);
		wd.shieldInterceptType    = shTable.GetInt("interceptType", 0);
		wd.shieldBadColor         = shTable.GetFloat3("badColor",  shieldBadColor);
		wd.shieldGoodColor        = shTable.GetFloat3("goodColor", shieldGoodColor);
		wd.shieldAlpha            = shTable.GetFloat("alpha", 0.2f);
	}
	else {
		wd.shieldRepulser         = wdTable.GetBool("shieldRepulser",       false);
		wd.smartShield            = wdTable.GetBool("smartShield",          false);
		wd.exteriorShield         = wdTable.GetBool("exteriorShield",       false);
		wd.visibleShield          = wdTable.GetBool("visibleShield",        false);
		wd.visibleShieldRepulse   = wdTable.GetBool("visibleShieldRepulse", false);
		wd.visibleShieldHitFrames = wdTable.GetInt("visibleShieldHitFrames", 0);
		wd.shieldEnergyUse        = wdTable.GetFloat("shieldEnergyUse",        0.0f);
		wd.shieldForce            = wdTable.GetFloat("shieldForce",            0.0f);
		wd.shieldRadius           = wdTable.GetFloat("shieldRadius",           0.0f);
		wd.shieldMaxSpeed         = wdTable.GetFloat("shieldMaxSpeed",         0.0f);
		wd.shieldPower            = wdTable.GetFloat("shieldPower",            0.0f);
		wd.shieldPowerRegen       = wdTable.GetFloat("shieldPowerRegen",       0.0f);
		wd.shieldPowerRegenEnergy = wdTable.GetFloat("shieldPowerRegenEnergy", 0.0f);
		wd.shieldRechargeDelay    = (int)(wdTable.GetFloat("shieldRechargeDelay", 0) * GAME_SPEED);
		wd.shieldStartingPower    = wdTable.GetFloat("shieldStartingPower",    0.0f);
		wd.shieldInterceptType    = wdTable.GetInt("shieldInterceptType", 0);
		wd.shieldBadColor         = wdTable.GetFloat3("shieldBadColor",  shieldBadColor);
		wd.shieldGoodColor        = wdTable.GetFloat3("shieldGoodColor", shieldGoodColor);
		wd.shieldAlpha            = wdTable.GetFloat("shieldAlpha", 0.2f);
	}


	int defInterceptType = 0;
	if ((wd.type == "Cannon") || (wd.type == "EmgCannon")) {
		defInterceptType = 1;
	} else if ((wd.type == "LaserCannon") || (wd.type == "BeamLaser")) {
		defInterceptType = 2;
	} else if ((wd.type == "StarburstLauncher") || (wd.type == "MissileLauncher")) {
		defInterceptType = 4;
	} else if (wd.type == "AircraftBomb") {
		defInterceptType = 8;
	} else if (wd.type == "Flame") {
		defInterceptType = 16;
	} else if (wd.type == "TorpedoLauncher") {
		defInterceptType = 32;
	} else if (wd.type == "LightningCannon") {
		defInterceptType = 64;
	} else if (wd.type == "Rifle") {
		defInterceptType = 128;
	} else if (wd.type == "Melee") {
		defInterceptType = 256;
	}
	wd.interceptedByShieldType = wdTable.GetInt("interceptedByShieldType", defInterceptType);

	wd.wobble = wdTable.GetFloat("wobble", 0.0f) * TAANG2RAD / 30.0f;
	wd.dance = wdTable.GetFloat("dance", 0.0f) / GAME_SPEED;
	wd.trajectoryHeight = wdTable.GetFloat("trajectoryHeight", 0.0f);

	wd.noAutoTarget = (wd.manualfire || wd.interceptor || wd.isShield);

	wd.onlyTargetCategory = 0xffffffff;
	if (wdTable.GetBool("toAirWeapon", false)) {
		// fix if we sometime call aircrafts otherwise
		wd.onlyTargetCategory = CCategoryHandler::Instance()->GetCategories("VTOL");
		//LOG("air only weapon %s %i", weaponname.c_str(), wd.onlyTargetCategory);
	}

	wd.largeBeamLaser = wdTable.GetBool("largeBeamLaser", false);
	wd.visuals.tilelength  = wdTable.GetFloat("tileLength", 200.0f);
	wd.visuals.scrollspeed = wdTable.GetFloat("scrollSpeed",  5.0f);
	wd.visuals.pulseSpeed  = wdTable.GetFloat("pulseSpeed",   1.0f);
	wd.visuals.beamdecay   = wdTable.GetFloat("beamDecay",    1.0f);
	wd.visuals.beamttl     = wdTable.GetInt("beamTTL", 0);

	if (wd.type == "Cannon") {
		wd.heightmod = wdTable.GetFloat("heightMod", 0.8f);
	} else if (wd.type == "BeamLaser" || wd.type == "LightningCannon") {
		wd.heightmod = wdTable.GetFloat("heightMod", 1.0f);
	} else {
		wd.heightmod = wdTable.GetFloat("heightMod", 0.2f);
	}

	wd.onlyForward = !wd.turret && (wd.type != "StarburstLauncher");

	color  = wdTable.GetInt("color",  0);
	color2 = wdTable.GetInt("color2", 0);

	const float3 rgbcol = hs2rgb(color / float(255), color2 / float(255));
	wd.visuals.color  = wdTable.GetFloat3("rgbColor",  rgbcol);
	wd.visuals.color2 = wdTable.GetFloat3("rgbColor2", float3(1.0f, 1.0f, 1.0f));

	wd.uptime = wdTable.GetFloat("weaponTimer", 0.0f);
	wd.flighttime = wdTable.GetFloat("flightTime", 0) * 32;

	wd.turnrate = wdTable.GetFloat("turnRate", 0.0f) * TAANG2RAD / 30.0f;

	if ((wd.type == "AircraftBomb") && !manualBombSettings) {
		if (wd.reload < 0.5f) {
			wd.salvodelay = min(0.2f, wd.reload);
			wd.salvosize = (int)(1 / wd.salvodelay) + 1;
			wd.reload = 5;
		} else {
			wd.salvodelay = min(0.4f, wd.reload);
			wd.salvosize = 2;
		}
	}
	//if(!wd.turret && (wd.type != "TorpedoLauncher")) {
	//	wd.maxAngle*=0.4f;
	//}

	//2+min(damages[0]*0.0025f,weaponDef->areaOfEffect*0.1f)
	const float tempsize = 2.0f + min(wd.damages[0] * 0.0025f, wd.areaOfEffect * 0.1f);
	wd.size = wdTable.GetFloat("size", tempsize);
	wd.sizeGrowth = wdTable.GetFloat("sizeGrowth", 0.2f);
	wd.collisionSize = wdTable.GetFloat("collisionSize", 0.05f);

	wd.visuals.colorMap = 0;
	const string colormap = wdTable.GetString("colormap", "");
	if (colormap != "") {
		wd.visuals.colorMap = CColorMap::LoadFromDefString(colormap);
	}

	wd.heightBoostFactor = wdTable.GetFloat("heightBoostFactor", -1.0f);
	wd.proximityPriority = wdTable.GetFloat("proximityPriority", 1.0f);

	// get some weapon specific defaults
	if (wd.type == "Cannon") {
		// CExplosiveProjectile
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.9f);

		wd.visuals.color = wdTable.GetFloat3("rgbColor", float3(1.0f, 0.5f, 0.0f));
		wd.intensity = wdTable.GetFloat("intensity", 0.2f);
	} else if (wd.type == "Rifle") {
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.9f);
	} else if (wd.type == "Melee") {
		// ...
	} else if (wd.type == "Flame") {
		// CFlameProjectile
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.2f);
		wd.size              = wdTable.GetFloat("size",      tempsize);
		wd.sizeGrowth        = wdTable.GetFloat("sizeGrowth",    0.5f);
		wd.collisionSize     = wdTable.GetFloat("collisionSize", 0.5f);
		wd.duration          = wdTable.GetFloat("flameGfxTime",  1.2f);
	} else if (wd.type == "MissileLauncher") {
		// CMissileProjectile
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
	} else if (wd.type == "LaserCannon") {
		// CLaserProjectile
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
		wd.collisionSize = wdTable.GetFloat("collisionSize", 0.5f);

		wd.visuals.hardStop = wdTable.GetBool("hardstop", false);
	} else if (wd.type == "BeamLaser") {
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
	} else if (wd.type == "LightningCannon") {
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);

		wd.thickness = wdTable.GetFloat("thickness", 0.8f);
	} else if (wd.type == "EmgCannon") {
		// CEmgProjectile
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);

		wd.size = wdTable.GetFloat("size", 3.0f);
		wd.visuals.color = wdTable.GetFloat3("rgbColor", float3(0.9f, 0.9f, 0.2f));
	} else if (wd.type == "DGun") {
		// CFireBallProjectile
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
		wd.collisionSize = wdTable.GetFloat("collisionSize", 10.0f);
	} else if (wd.type == "StarburstLauncher") {
		// CStarburstProjectile
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
	} else {
		wd.ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.0f);
	}


	const LuaTable texTable = wdTable.SubTable("textures");

	wd.visuals.texNames[0] = texTable.GetString(1, wdTable.GetString("texture1", ""));
	wd.visuals.texNames[1] = texTable.GetString(2, wdTable.GetString("texture2", ""));
	wd.visuals.texNames[2] = texTable.GetString(3, wdTable.GetString("texture3", ""));
	wd.visuals.texNames[3] = texTable.GetString(4, wdTable.GetString("texture4", ""));

	wd.visuals.expGenTag = wdTable.GetString("explosionGenerator", "");
	wd.visuals.bounceExpGenTag = wdTable.GetString("bounceExplosionGenerator", "");

	const float gd = max(30.0f, wd.damages[0] / 20.0f);
	const float defExpSpeed = (8.0f + (gd * 2.5f)) / (9.0f + (sqrt(gd) * 0.7f)) * 0.5f;
	wd.explosionSpeed = wdTable.GetFloat("explosionSpeed", defExpSpeed);

	// Dynamic Damage
	wd.dynDamageInverted = wdTable.GetBool("dynDamageInverted", false);
	wd.dynDamageExp      = wdTable.GetFloat("dynDamageExp",   0.0f);
	wd.dynDamageMin      = wdTable.GetFloat("dynDamageMin",   0.0f);
	wd.dynDamageRange    = wdTable.GetFloat("dynDamageRange", 0.0f);

	LoadSound(wdTable, wd.firesound, "start");
	LoadSound(wdTable, wd.soundhit,  "hit");

	if ((wd.firesound.getVolume(0) == -1.0f) ||
	    (wd.soundhit.getVolume(0)  == -1.0f)) {
		// no volume (-1.0f) read from weapon definition, set it dynamically here
		if (wd.damages[0] <= 50.0f) {
			wd.soundhit.setVolume(0, 5.0f);
			wd.firesound.setVolume(0, 5.0f);
		}
		else {
			float soundVolume = sqrt(wd.damages[0] * 0.5f);

			if (wd.type == "LaserCannon") {
				soundVolume *= 0.5f;
			}

			float hitSoundVolume = soundVolume;

			if ((soundVolume > 100.0f) &&
			    ((wd.type == "MissileLauncher") ||
			     (wd.type == "StarburstLauncher"))) {
				soundVolume = 10.0f * sqrt(soundVolume);
			}

			if (wd.firesound.getVolume(0) == -1.0f) {
				wd.firesound.setVolume(0, soundVolume);
			}

			soundVolume = hitSoundVolume;

			if (wd.areaOfEffect > 8.0f) {
				soundVolume *= 2.0f;
			}
			if (wd.type == "DGun") {
				soundVolume *= 0.15f;
			}
			if (wd.soundhit.getVolume(0) == -1.0f) {
				wd.soundhit.setVolume(0, soundVolume);
			}
		}
	}

	// custom parameters table
	wdTable.SubTable("customParams").GetMap(wd.customParams);
}
Exemple #10
0
CProjectileDrawer::CProjectileDrawer(): CEventClient("[CProjectileDrawer]", 123456, false) {
	eventHandler.AddClient(this);

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

	textureAtlas = new CTextureAtlas(2048, 2048);

	// used to block resources_map.tdf from loading textures
	std::set<std::string> blockMapTexNames;

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

	const LuaTable rootTable = resourcesParser.GetRoot();
	const LuaTable gfxTable = rootTable.SubTable("graphics");
	const LuaTable ptTable = gfxTable.SubTable("projectileTextures");

	// add all textures in projectiletextures section
	std::map<std::string, std::string> ptex;
	ptTable.GetMap(ptex);

	for (std::map<std::string, std::string>::iterator pi = ptex.begin(); pi != ptex.end(); ++pi) {
		textureAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
		blockMapTexNames.insert(StringToLower(pi->first));
	}
	ptex.clear();

	// add all texture from sections within projectiletextures section
	std::vector<std::string> seclist;
	ptTable.GetKeys(seclist);

	for (size_t i = 0; i < seclist.size(); i++) {
		const LuaTable ptSubTable = ptTable.SubTable(seclist[i]);

		if (ptSubTable.IsValid()) {
			ptSubTable.GetMap(ptex);

			for (std::map<std::string, std::string>::iterator pi = ptex.begin(); pi != ptex.end(); ++pi) {
				textureAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
				blockMapTexNames.insert(StringToLower(pi->first));
			}
			ptex.clear();
		}
	}

	// get the smoke textures, hold the count in 'smokeCount'
	const LuaTable smokeTable = gfxTable.SubTable("smoke");
	int smokeCount;

	if (smokeTable.IsValid()) {
		for (smokeCount = 0; true; smokeCount++) {
			const std::string tex = smokeTable.GetString(smokeCount + 1, "");
			if (tex.empty()) {
				break;
			}
			const std::string texName = "bitmaps/" + tex;
			const std::string smokeName = "ismoke" + IntToString(smokeCount, "%02i");

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

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

	if (smokeCount <= 0) {
		throw content_error("missing smoke textures");
	}

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

	textureAtlas->AddTexFromMem("perlintex", 128, 128, CTextureAtlas::RGBA32, tex);
	blockMapTexNames.insert("perlintex");

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

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


	// allow map specified atlas textures for gaia unit projectiles
	LuaParser mapResParser("gamedata/resources_map.lua", SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
	
	if (mapResParser.Execute()) {
		const LuaTable mapRoot = mapResParser.GetRoot();
		const LuaTable mapTable = mapRoot.SubTable("projectileTextures");

		// add all textures in projectiletextures section
		std::map<std::string, std::string>::iterator pi;

		mapTable.GetMap(ptex);

		for (pi = ptex.begin(); pi != ptex.end(); ++pi) {
			if (blockMapTexNames.find(StringToLower(pi->first)) == blockMapTexNames.end()) {
				textureAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
			}
		}
		ptex.clear();

		// add all texture from sections within projectiletextures section
		mapTable.GetKeys(seclist);
		for (size_t i = 0; i < seclist.size(); i++) {
			const LuaTable mapSubTable = mapTable.SubTable(seclist[i]);
			if (mapSubTable.IsValid()) {
				mapSubTable.GetMap(ptex);
				for (pi = ptex.begin(); pi != ptex.end(); ++pi) {
					if (blockMapTexNames.find(StringToLower(pi->first)) == blockMapTexNames.end()) {
						textureAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
					}
				}
				ptex.clear();
			}
		}
	}

	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 < smokeCount; i++) {
		const std::string smokeName = "ismoke" + IntToString(i, "%02i");
		smoketex.push_back(textureAtlas->GetTexturePtr(smokeName));
	}

#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


	groundFXAtlas = new CTextureAtlas(2048, 2048);
	// add all textures in groundfx section
	const LuaTable groundfxTable = gfxTable.SubTable("groundfx");
	groundfxTable.GetMap(ptex);

	for (std::map<std::string, std::string>::iterator pi = ptex.begin(); pi != ptex.end(); ++pi) {
		groundFXAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
	}
	ptex.clear();

	// add all textures from sections within groundfx section
	groundfxTable.GetKeys(seclist);

	for (size_t i = 0; i < seclist.size(); i++) {
		const LuaTable gfxSubTable = groundfxTable.SubTable(seclist[i]);

		if (gfxSubTable.IsValid()) {
			gfxSubTable.GetMap(ptex);

			for (std::map<std::string, std::string>::iterator pi = ptex.begin(); pi != ptex.end(); ++pi) {
				groundFXAtlas->AddTexFromFile(pi->first, "bitmaps/" + pi->second);
			}
			ptex.clear();
		}
	}

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

	unsigned char tempmem[4 * 16 * 16];
	for (int a = 0; a < 4 * 16 * 16; ++a) {
		tempmem[a] = 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 #11
0
WeaponDef::WeaponDef(const LuaTable& wdTable, const std::string& name_, int id_)
	: name(name_)
	, id(id_)
	, isShield(false)
	, collisionFlags(0)
	, explosionGenerator(NULL)
	, bounceExplosionGenerator(NULL)
{
	WeaponDefs.Load(this, wdTable);

	if (wdTable.KeyExists("cylinderTargetting"))
		LOG_L(L_WARNING, "WeaponDef (%s) cylinderTargetting is deprecated and will be removed in the next release (use cylinderTargeting).", name.c_str());

	if (wdTable.KeyExists("color1") || wdTable.KeyExists("color2"))
		LOG_L(L_WARNING, "WeaponDef (%s) color1 & color2 (= hue & sat) are removed. Use rgbColor instead!", name.c_str());

	if (wdTable.KeyExists("isShield"))
		LOG_L(L_WARNING, "WeaponDef (%s) isShield is removed. Use weaponType=\"Shield\" instead!", name.c_str());

	shieldRechargeDelay = int(wdTable.GetFloat("rechargeDelay", 0) * GAME_SPEED);
	flighttime = int(wdTable.GetFloat("flighttime", 0.0f) * 32);

	//FIXME may be smarter to merge the collideXYZ tags with avoidXYZ and removing the collisionFlags tag (and move the code into CWeapon)?
	collisionFlags = 0;
	if (!wdTable.GetBool("collideEnemy",    true)) { collisionFlags |= Collision::NOENEMIES;    }
	if (!wdTable.GetBool("collideFriendly", true)) { collisionFlags |= Collision::NOFRIENDLIES; }
	if (!wdTable.GetBool("collideFeature",  true)) { collisionFlags |= Collision::NOFEATURES;   }
	if (!wdTable.GetBool("collideNeutral",  true)) { collisionFlags |= Collision::NONEUTRALS;   }
	if (!wdTable.GetBool("collideGround",   true)) { collisionFlags |= Collision::NOGROUND;     }

	//FIXME defaults depend on other tags
	{
		if (paralyzer)
			cameraShake = wdTable.GetFloat("cameraShake", 0.0f);

		if (selfExplode)
			predictBoost = wdTable.GetFloat("predictBoost", 0.5f);

		if (type == "Melee") {
			targetBorder = Clamp(wdTable.GetFloat("targetBorder", 1.0f), -1.0f, 1.0f);
			cylinderTargeting = Clamp(wdTable.GetFloat("cylinderTargeting", wdTable.GetFloat("cylinderTargetting", 1.0f)), 0.0f, 128.0f);
		}

		if (type == "Flame") {
			//FIXME move to lua (for all other weapons this tag is named `duration` and has a different default)
			duration = wdTable.GetFloat("flameGfxTime", 1.2f);
		}

		if (type == "Cannon") {
			heightmod = wdTable.GetFloat("heightMod", 0.8f);
		} else if (type == "BeamLaser" || type == "LightningCannon") {
			heightmod = wdTable.GetFloat("heightMod", 1.0f);
		}
	}

	// setup the default damages
	{
		const LuaTable dmgTable = wdTable.SubTable("damage");
		float defDamage = dmgTable.GetFloat("default", 1.0f);
		if (defDamage == 0.0f) {
			defDamage = 1.0f; //avoid division by zeros
		}
		damages.SetDefaultDamage(defDamage);

		if (!paralyzer)
			damages.paralyzeDamageTime = 0;

		std::map<string, float> dmgs;
		dmgTable.GetMap(dmgs);

		std::map<string, float>::const_iterator di;
		for (di = dmgs.begin(); di != dmgs.end(); ++di) {
			const int type = damageArrayHandler->GetTypeFromName(di->first);
			if (type != 0) {
				float dmg = di->second;
				if (dmg != 0.0f) {
					damages[type] = dmg;
				} else {
					damages[type] = 1.0f;
				}
			}
		}

		const float tempsize = 2.0f + std::min(defDamage * 0.0025f, damageAreaOfEffect * 0.1f);
		size = wdTable.GetFloat("size", tempsize);

		const float gd = std::max(30.0f, defDamage / 20.0f);
		const float defExpSpeed = (8.0f + (gd * 2.5f)) / (9.0f + (math::sqrt(gd) * 0.7f)) * 0.5f;
		explosionSpeed = wdTable.GetFloat("explosionSpeed", defExpSpeed);
	}

	{
		// 0.78.2.1 backwards compatibility: non-burst beamlasers play one
		// sample per shot, not for each individual beam making up the shot
		const bool singleSampleShot = (type == "BeamLaser" && !beamburst);
		const bool singleShotWeapon = (type == "Melee" || type == "Rifle");

		soundTrigger = wdTable.GetBool("soundTrigger", singleSampleShot || singleShotWeapon);
	}

	// get some weapon specific defaults
	int defInterceptType = 0;
	if ((type == "Cannon") || (type == "EmgCannon")) {
		defInterceptType = 1;
	} else if ((type == "LaserCannon") || (type == "BeamLaser")) {
		defInterceptType = 2;
	} else if ((type == "StarburstLauncher") || (type == "MissileLauncher")) {
		defInterceptType = 4;
	} else if (type == "AircraftBomb") {
		defInterceptType = 8;
	} else if (type == "Flame") {
		defInterceptType = 16;
	} else if (type == "TorpedoLauncher") {
		defInterceptType = 32;
	} else if (type == "LightningCannon") {
		defInterceptType = 64;
	} else if (type == "Rifle") {
		defInterceptType = 128;
	} else if (type == "Melee") {
		defInterceptType = 256;
	}
	interceptedByShieldType = wdTable.GetInt("interceptedByShieldType", defInterceptType);

	if (type == "Cannon") {
		// CExplosiveProjectile
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.9f);
		intensity = wdTable.GetFloat("intensity", 0.2f);
	} else if (type == "Rifle") {
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.9f);
	} else if (type == "Melee") {
		// ...
	} else if (type == "Flame") {
		// CFlameProjectile
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.2f);
		collisionSize     = wdTable.GetFloat("collisionSize", 0.5f);
	} else if (type == "MissileLauncher") {
		// CMissileProjectile
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
	} else if (type == "LaserCannon") {
		// CLaserProjectile
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
		collisionSize = wdTable.GetFloat("collisionSize", 0.5f);
	} else if (type == "BeamLaser") {
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
	} else if (type == "LightningCannon") {
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
	} else if (type == "EmgCannon") {
		// CEmgProjectile
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
		size = wdTable.GetFloat("size", 3.0f);
	} else if (type == "TorpedoLauncher") {
		assert(waterweapon);
		waterweapon = true;
	} else if (type == "DGun") {
		// CFireBallProjectile
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.5f);
		collisionSize = wdTable.GetFloat("collisionSize", 10.0f);
	} else if (type == "StarburstLauncher") {
		// CStarburstProjectile
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.7f);
	} else {
		ownerExpAccWeight = wdTable.GetFloat("ownerExpAccWeight", 0.0f);
	}

	const std::string& colormap = wdTable.GetString("colormap", "");
	visuals.colorMap = NULL;
	if (!colormap.empty()) {
		visuals.colorMap = CColorMap::LoadFromDefString(colormap);
	}

	ParseWeaponSounds(wdTable);

	// custom parameters table
	wdTable.SubTable("customParams").GetMap(customParams);

	// internal only
	isShield = (type == "Shield");
	noAutoTarget = (manualfire || interceptor || isShield);
	onlyForward = !turret && (type != "StarburstLauncher");
}