Exemple #1
0
// Calculate model radius from the min/max extents
void CAssParser::CalculateModelProperties(S3DModel* model, const LuaTable& modelTable)
{
	CalculateModelDimensions(model, model->rootPiece);

	model->mins = modelTable.GetFloat3("mins", model->mins);
	model->maxs = modelTable.GetFloat3("maxs", model->maxs);

	model->radius = modelTable.GetFloat("radius", (model->maxs   - model->mins  ).Length() * 0.5f);
	model->height = modelTable.GetFloat("height", (model->maxs.y - model->mins.y)                );

	model->relMidPos = modelTable.GetFloat3("midpos", (model->maxs + model->mins) * 0.5f);
}
void SolidObjectDef::ParseCollisionVolume(const LuaTable& table)
{
	collisionVolume = new CollisionVolume(
		table.GetString("collisionVolumeType", ""),
		table.GetFloat3("collisionVolumeScales", ZeroVector),
		table.GetFloat3("collisionVolumeOffsets", ZeroVector)
	);

	// if this unit wants per-piece volumes, make
	// its main collision volume deferent and let
	// it ignore hits
	collisionVolume->SetDefaultToPieceTree(table.GetBool("usePieceCollisionVolumes", false));
	collisionVolume->SetDefaultToFootPrint(table.GetBool("useFootPrintCollisionVolume", false));
	collisionVolume->SetIgnoreHits(collisionVolume->DefaultToPieceTree());
}
Exemple #3
0
// Calculate model radius from the min/max extents
void CAssParser::CalculateModelProperties(S3DModel* model, const LuaTable& modelTable)
{
	CalculateModelDimensions(model, model->rootPiece);

	// note: overrides default midpos of the SpringRadius piece
	model->relMidPos.y = (model->maxs.y + model->mins.y) * 0.5f;

	// Simplified dimensions used for rough calculations
	model->radius = modelTable.GetFloat("radius", float3::max(float3::fabs(model->maxs), float3::fabs(model->mins)).Length());
	model->height = modelTable.GetFloat("height", model->maxs.y);
	model->relMidPos = modelTable.GetFloat3("midpos", model->relMidPos);
	model->mins = modelTable.GetFloat3("mins", model->mins);
	model->maxs = modelTable.GetFloat3("maxs", model->maxs);

	model->drawRadius = model->radius;
}
Exemple #4
0
void CAssParser::LoadPieceTransformations(SAssPiece* piece, const LuaTable& pieceMetaTable)
{
	//! Process transforms
	float3 rotate, scale, offset;
	aiVector3D _scale, _offset;
	aiQuaternion _rotate;
	piece->node->mTransformation.Decompose(_scale,_rotate,_offset);

	LOG_S(LOG_SECTION_PIECE,
			"(%d:%s) Assimp offset (%f,%f,%f), rotate (%f,%f,%f), scale (%f,%f,%f)",
			piece->model->numPieces, piece->name.c_str(),
			_offset.x, _offset.y, _offset.z,
			_rotate.x, _rotate.y, _rotate.z,
			_scale.x, _scale.y, _scale.z
			);

	offset   = pieceMetaTable.GetFloat3("offset", float3(_offset.x, _offset.y, _offset.z));
	offset.x = pieceMetaTable.GetFloat("offsetx", offset.x);
	offset.y = pieceMetaTable.GetFloat("offsety", offset.y);
	offset.z = pieceMetaTable.GetFloat("offsetz", offset.z);

	rotate   = QuaternionToRadianAngles(_rotate);
	rotate   = float3(rotate.z, rotate.x, rotate.y); //! swizzle
	rotate   = pieceMetaTable.GetFloat3("rotate", rotate * RADTODEG);
	rotate.x = pieceMetaTable.GetFloat("rotatex", rotate.x);
	rotate.y = pieceMetaTable.GetFloat("rotatey", rotate.y);
	rotate.z = pieceMetaTable.GetFloat("rotatez", rotate.z);
	rotate  *= DEGTORAD;

	scale   = pieceMetaTable.GetFloat3("scale", float3(_scale.x, _scale.z, _scale.y));
	scale.x = pieceMetaTable.GetFloat("scalex", scale.x);
	scale.y = pieceMetaTable.GetFloat("scaley", scale.y);
	scale.z = pieceMetaTable.GetFloat("scalez", scale.z);

	LOG_S(LOG_SECTION_PIECE,
			"(%d:%s) Relative offset (%f,%f,%f), rotate (%f,%f,%f), scale (%f,%f,%f)",
			piece->model->numPieces, piece->name.c_str(),
			offset.x, offset.y, offset.z,
			rotate.x, rotate.y, rotate.z,
			scale.x, scale.y, scale.z
			);
	piece->offset = offset;
	piece->rot = rotate;
	piece->scale = scale;
}
void CMapInfo::ReadAtmosphere()
{
	// MAP\ATMOSPHERE
	const LuaTable atmoTable = mapRoot->SubTable("atmosphere");
	atmosphere_t& atmo = atmosphere;
	atmo.cloudDensity = atmoTable.GetFloat("cloudDensity", 0.5f);
	atmo.minWind      = atmoTable.GetFloat("minWind", 5.0f);
	atmo.maxWind      = atmoTable.GetFloat("maxWind", 25.0f);
	atmo.fogStart     = atmoTable.GetFloat("fogStart", 0.1f);
	atmo.fogColor   = atmoTable.GetFloat3("fogColor", float3(0.7f, 0.7f, 0.8f));
	atmo.skyColor   = atmoTable.GetFloat3("skyColor", float3(0.1f, 0.15f, 0.7f));
	atmo.sunColor   = atmoTable.GetFloat3("sunColor", float3(1.0f, 1.0f, 1.0f));
	atmo.cloudColor = atmoTable.GetFloat3("cloudColor", float3(1.0f, 1.0f, 1.0f));
	atmo.skyBox = atmoTable.GetString("skyBox", "");

	// clamps
	atmo.cloudDensity = max(0.0f, atmo.cloudDensity);
	atmo.maxWind      = max(0.0f, atmo.maxWind);
	atmo.minWind      = max(0.0f, atmo.minWind);
	atmo.minWind      = min(atmo.maxWind, atmo.minWind);
}
Exemple #6
0
void CMapInfo::ReadLight()
{
	const LuaTable lightTable = parser->GetRoot().SubTable("lighting");

	light.sunStartAngle = lightTable.GetFloat("sunStartAngle", 0.0f);
	light.sunOrbitTime = lightTable.GetFloat("sunOrbitTime", 1440.0f);
	light.sunDir = lightTable.GetFloat4("sunDir", float4(0.0f, 1.0f, 2.0f, FLT_MAX));
	if (light.sunDir.w == FLT_MAX) { // if four params are not specified for sundir, fallback to the old three param format
		light.sunDir = lightTable.GetFloat3("sunDir", float3(0.0f, 1.0f, 2.0f));
		light.sunDir.w = FLT_MAX;
	}
	light.sunDir.ANormalize();

	light.groundAmbientColor  = lightTable.GetFloat3("groundAmbientColor", float3(0.5f, 0.5f, 0.5f));
	light.groundSunColor      = lightTable.GetFloat3("groundDiffuseColor", float3(0.5f, 0.5f, 0.5f));
	light.groundSpecularColor = lightTable.GetFloat3("groundSpecularColor", float3(0.1f, 0.1f, 0.1f));
	light.groundShadowDensity = lightTable.GetFloat("groundShadowDensity", 0.8f);

	light.unitAmbientColor  = lightTable.GetFloat3("unitAmbientColor", float3(0.4f, 0.4f, 0.4f));
	light.unitSunColor      = lightTable.GetFloat3("unitDiffuseColor", float3(0.7f, 0.7f, 0.7f));
	light.unitSpecularColor  = lightTable.GetFloat3("unitSpecularColor", light.unitSunColor);
	light.unitShadowDensity = lightTable.GetFloat("unitShadowDensity", 0.8f);
}
void CMapInfo::ReadLight()
{
	const LuaTable lightTable = mapRoot->SubTable("lighting");

	light.sunDir = lightTable.GetFloat3("sunDir", float3(0.0f, 1.0f, 2.0f));
	light.sunDir.Normalize();

	light.groundAmbientColor  = lightTable.GetFloat3("groundAmbientColor",
	                                                float3(0.5f, 0.5f, 0.5f));
	light.groundSunColor      = lightTable.GetFloat3("groundDiffuseColor",
	                                                float3(0.5f, 0.5f, 0.5f));
	light.groundSpecularColor = lightTable.GetFloat3("groundSpecularColor",
	                                                float3(0.1f, 0.1f, 0.1f));
	light.groundShadowDensity = lightTable.GetFloat("groundShadowDensity", 0.8f);

	light.unitAmbientColor  = lightTable.GetFloat3("unitAmbientColor",
	                                                float3(0.4f, 0.4f, 0.4f));
	light.unitSunColor      = lightTable.GetFloat3("unitDiffuseColor",
	                                                float3(0.7f, 0.7f, 0.7f));
	light.specularSunColor = lightTable.GetFloat3("unitSpecularColor",
	                                               light.unitSunColor);
	light.unitShadowDensity = lightTable.GetFloat("unitShadowDensity", 0.8f);
}
Exemple #8
0
void CAssParser::LoadPieceTransformations(
	SAssPiece* piece,
	const S3DModel* model,
	const aiNode* pieceNode,
	const LuaTable& pieceTable
) {
	aiVector3D aiScaleVec, aiTransVec;
	aiQuaternion aiRotateQuat;

	// process transforms
	pieceNode->mTransformation.Decompose(aiScaleVec, aiRotateQuat, aiTransVec);

	// metadata-scaling
	piece->scales   = pieceTable.GetFloat3("scale", aiVectorToFloat3(aiScaleVec));
	piece->scales.x = pieceTable.GetFloat("scalex", piece->scales.x);
	piece->scales.y = pieceTable.GetFloat("scaley", piece->scales.y);
	piece->scales.z = pieceTable.GetFloat("scalez", piece->scales.z);

	if (piece->scales.x != piece->scales.y || piece->scales.y != piece->scales.z) {
		// LOG_SL(LOG_SECTION_MODEL, L_WARNING, "Spring doesn't support non-uniform scaling");
		piece->scales.y = piece->scales.x;
		piece->scales.z = piece->scales.x;
	}

	// metadata-translation
	piece->offset   = pieceTable.GetFloat3("offset", aiVectorToFloat3(aiTransVec));
	piece->offset.x = pieceTable.GetFloat("offsetx", piece->offset.x);
	piece->offset.y = pieceTable.GetFloat("offsety", piece->offset.y);
	piece->offset.z = pieceTable.GetFloat("offsetz", piece->offset.z);

	// metadata-rotation
	// NOTE:
	//   these rotations are "pre-scripting" but "post-modelling"
	//   together with the (baked) aiRotateQuad they determine the
	//   model's pose *before* any animations execute
	//
	// float3 rotAngles = pieceTable.GetFloat3("rotate", aiQuaternionToRadianAngles(aiRotateQuat) * RADTODEG);
	float3 pieceRotAngles = pieceTable.GetFloat3("rotate", ZeroVector);

	pieceRotAngles.x = pieceTable.GetFloat("rotatex", pieceRotAngles.x);
	pieceRotAngles.y = pieceTable.GetFloat("rotatey", pieceRotAngles.y);
	pieceRotAngles.z = pieceTable.GetFloat("rotatez", pieceRotAngles.z);
	pieceRotAngles  *= DEGTORAD;

	LOG_SL(LOG_SECTION_PIECE, L_INFO,
		"(%d:%s) Assimp offset (%f,%f,%f), rotate (%f,%f,%f,%f), scale (%f,%f,%f)",
		model->numPieces, piece->name.c_str(),
		aiTransVec.x, aiTransVec.y, aiTransVec.z,
		aiRotateQuat.w, aiRotateQuat.x, aiRotateQuat.y, aiRotateQuat.z,
		aiScaleVec.x, aiScaleVec.y, aiScaleVec.z
	);
	LOG_SL(LOG_SECTION_PIECE, L_INFO,
		"(%d:%s) Relative offset (%f,%f,%f), rotate (%f,%f,%f), scale (%f,%f,%f)",
		model->numPieces, piece->name.c_str(),
		piece->offset.x, piece->offset.y, piece->offset.z,
		pieceRotAngles.x, pieceRotAngles.y, pieceRotAngles.z,
		piece->scales.x, piece->scales.y, piece->scales.z
	);

	// NOTE:
	//   at least collada (.dae) files generated by Blender represent
	//   a coordinate-system that differs from the "standard" formats
	//   (3DO, S3O, ...) for which existing tools at least have prior
	//   knowledge of Spring's expectations --> let the user override
	//   the ROOT rotational transform and the rotation-axis mapping
	//   used by animation scripts (but re-modelling/re-exporting is
	//   always preferred!) even though AssImp should convert models
	//   to its own system which matches that of Spring
	//
	//   .dae  : x=Rgt, y=-Fwd, z= Up, as=(-1, -1, 1), am=AXIS_XZY (if Z_UP)
	//   .dae  : x=Rgt, y=-Fwd, z= Up, as=(-1, -1, 1), am=AXIS_XZY (if Y_UP) [!?]
	//   .blend: ????
	piece->bakedRotMatrix = aiMatrixToMatrix(aiMatrix4x4t<float>(aiRotateQuat.GetMatrix()));

	if (piece == model->GetRootPiece()) {
		const float3 xaxis = pieceTable.GetFloat3("xaxis", piece->bakedRotMatrix.GetX());
		const float3 yaxis = pieceTable.GetFloat3("yaxis", piece->bakedRotMatrix.GetY());
		const float3 zaxis = pieceTable.GetFloat3("zaxis", piece->bakedRotMatrix.GetZ());

		if (math::fabs(xaxis.SqLength() - yaxis.SqLength()) < 0.01f && math::fabs(yaxis.SqLength() - zaxis.SqLength()) < 0.01f) {
			piece->bakedRotMatrix = CMatrix44f(ZeroVector, xaxis, yaxis, zaxis);
		}
	}

	piece->rotAxisSigns = pieceTable.GetFloat3("rotAxisSigns", float3(-OnesVector));
	piece->axisMapType = AxisMappingType(pieceTable.GetInt("rotAxisMap", AXIS_MAPPING_XYZ));

	// construct 'baked' part of the piece-space matrix
	// AssImp order is translate * rotate * scale * v;
	// we leave the translation and scale parts out and
	// put those in <offset> and <scales> --> transform
	// is just R instead of T * R * S
	//
	// note: for all non-AssImp models this is identity!
	//
	piece->ComposeRotation(piece->bakedRotMatrix, pieceRotAngles);
	piece->SetHasIdentityRotation(piece->bakedRotMatrix.IsIdentity() == 0);

	assert(piece->bakedRotMatrix.IsOrthoNormal() == 0);
}
void CMapInfo::ReadWater()
{
	const LuaTable wt = mapRoot->SubTable("water");

	water.repeatX = wt.GetFloat("repeatX", 0.0f);
	water.repeatY = wt.GetFloat("repeatY", 0.0f);
	water.damage  = wt.GetFloat("damage",  0.0f) * (16.0f / 30.0f);

	water.absorb    = wt.GetFloat3("absorb",    float3(0.0f, 0.0f, 0.0f));
	water.baseColor = wt.GetFloat3("baseColor", float3(0.0f, 0.0f, 0.0f));
	water.minColor  = wt.GetFloat3("minColor",  float3(0.0f, 0.0f, 0.0f));

	water.surfaceColor = wt.GetFloat3("surfaceColor", float3(0.75f, 0.8f, 0.85f));
	water.surfaceAlpha = wt.GetFloat("surfaceAlpha",  0.55f);

	water.planeColor = wt.GetFloat3("planeColor", float3(0.0f, 0.4f, 0.0f));
	hasWaterPlane    = wt.KeyExists("planeColor");

	water.specularColor  = wt.GetFloat3("specularColor", light.groundSunColor);
	water.specularFactor = wt.GetFloat("specularFactor", 20.0f);

	water.fresnelMin   = wt.GetFloat("fresnelMin",   0.2f);
	water.fresnelMax   = wt.GetFloat("fresnelMax",   0.3f);
	water.fresnelPower = wt.GetFloat("fresnelPower", 4.0f);

	water.texture       = wt.GetString("texture",       "");
	water.foamTexture   = wt.GetString("foamTexture",   "");
	water.normalTexture = wt.GetString("normalTexture", "");

	// use 'resources.lua' for missing fields  (our the engine defaults)
	const LuaTable resGfxMaps = resRoot->SubTable("graphics").SubTable("maps");

	if (!water.texture.empty()) {
		water.texture = "maps/" + water.texture;
	} else {
		water.texture = "bitmaps/" + resGfxMaps.GetString("watertex", "ocean.jpg");
	}

	if (!water.foamTexture.empty()) {
		water.foamTexture = "maps/" + water.foamTexture;
	} else {
		water.foamTexture = "bitmaps/" + resGfxMaps.GetString("waterfoamtex", "foam.jpg");
	}

	if (!water.normalTexture.empty()) {
		water.normalTexture = "maps/" + water.normalTexture;
	} else {
		water.normalTexture = "bitmaps/" + resGfxMaps.GetString("waternormaltex", "waterbump.png");
	}

	// water caustic textures
	LuaTable caustics = wt.SubTable("caustics");
	string causticPrefix = "maps/";
	if (!caustics.IsValid()) {
		caustics = resRoot->SubTable("graphics").SubTable("caustics");
		causticPrefix = "bitmaps/";
	}
	if (caustics.IsValid()) {
		for (int i = 1; true; i++) {
			const string texName = caustics.GetString(i, "");
			if (texName.empty()) {
				break;
			}
			water.causticTextures.push_back(causticPrefix + texName);
		}
	} else {
		// load the default 32 textures
		for (int i = 0; i < 32; i++) {
			char defTex[256];
			sprintf(defTex, "bitmaps/caustics/caustic%02i.jpg", i);
			water.causticTextures.push_back(defTex);
		}
	}
}
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;
}
Exemple #11
0
UnitDef::UnitDef(const LuaTable& udTable, const std::string& unitName, int id)
: name(unitName)
, id(id)
, collisionVolume(NULL)
, decoyDef(NULL)
, techLevel(-1)
, buildPic(NULL)
, buildangle(0)
{
	humanName = udTable.GetString("name", "");
	if (humanName.empty()) {
		const string errmsg = "missing 'name' parameter for the " + unitName + " unitdef";
		throw content_error(errmsg);
	}
	filename  = udTable.GetString("filename", "");
	if (filename.empty()) {
		const string errmsg = "missing 'filename' parameter for the" + unitName + " unitdef";
		throw content_error(errmsg);
	}
	tooltip = udTable.GetString("description", name);
	buildPicName = udTable.GetString("buildPic", "");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	const string lname = StringToLower(name);

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

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

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

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

	shieldWeaponDef    = NULL;
	stockpileWeaponDef = NULL;

	maxWeaponRange = 0.0f;
	maxCoverage = 0.0f;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	needGeo = false;

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

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

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

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

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


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

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

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


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

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

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

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

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

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

	// custom parameters table
	udTable.SubTable("customParams").GetMap(customParams);
}
Exemple #12
0
void CAssParser::LoadPieceTransformations(const S3DModel* model, SAssPiece* piece, const LuaTable& pieceMetaTable)
{
	// Process transforms
	float3 rotate, offset;
	float3 scale(1.0,1.0,1.0);
	aiVector3D _scale, _offset;
	aiQuaternion _rotate;
	piece->node->mTransformation.Decompose(_scale,_rotate,_offset);
	const aiMatrix4x4t<float> aiRotMatrix = aiMatrix4x4t<float>(_rotate.GetMatrix());

	LOG_S(LOG_SECTION_PIECE,
		"(%d:%s) Assimp offset (%f,%f,%f), rotate (%f,%f,%f,%f), scale (%f,%f,%f)",
		model->numPieces, piece->name.c_str(),
		_offset.x, _offset.y, _offset.z,
		_rotate.w, _rotate.x, _rotate.y, _rotate.z,
		_scale.x, _scale.y, _scale.z
	);

	// Scale
	scale   = pieceMetaTable.GetFloat3("scale", float3(_scale.x, _scale.z, _scale.y));
	scale.x = pieceMetaTable.GetFloat("scalex", scale.x);
	scale.y = pieceMetaTable.GetFloat("scaley", scale.y);
	scale.z = pieceMetaTable.GetFloat("scalez", scale.z);

	if (scale.x != scale.y || scale.y != scale.z) {
		//LOG_SL(LOG_SECTION_MODEL, L_WARNING, "Spring doesn't support non-uniform scaling");
		scale.y = scale.x;
		scale.z = scale.x;
	}

	// Rotate
	// Note these rotations are put into the `Spring rotations` and are not baked into the Assimp matrix!
	rotate   = pieceMetaTable.GetFloat3("rotate", float3(0,0,0));
	rotate.x = pieceMetaTable.GetFloat("rotatex", rotate.x);
	rotate.y = pieceMetaTable.GetFloat("rotatey", rotate.y);
	rotate.z = pieceMetaTable.GetFloat("rotatez", rotate.z);
	rotate  *= DEGTORAD;

	// Translate
	offset   = pieceMetaTable.GetFloat3("offset", float3(_offset.x, _offset.y, _offset.z));
	offset.x = pieceMetaTable.GetFloat("offsetx", offset.x);
	offset.y = pieceMetaTable.GetFloat("offsety", offset.y);
	offset.z = pieceMetaTable.GetFloat("offsetz", offset.z);

	LOG_S(LOG_SECTION_PIECE,
		"(%d:%s) Relative offset (%f,%f,%f), rotate (%f,%f,%f), scale (%f,%f,%f)",
		model->numPieces, piece->name.c_str(),
		offset.x, offset.y, offset.z,
		rotate.x, rotate.y, rotate.z,
		scale.x, scale.y, scale.z
	);

	// construct 'baked' part of the modelpiece matrix
	// Assimp order is: translate * rotate * scale * v
	piece->scaleRotMatrix.LoadIdentity();
	piece->scaleRotMatrix.Scale(scale);
	piece->scaleRotMatrix *= aiMatrixToMatrix(aiRotMatrix);
	// piece->scaleRotMatrix.Translate(offset);

	piece->offset = offset;
	piece->rot = rotate;
	piece->mIsIdentity = (scale.x == 1.0f) && aiRotMatrix.IsIdentity();
}
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 #14
0
void CFeatureHandler::CreateFeatureDef(const LuaTable& fdTable, const string& mixedCase)
{
	const string name = StringToLower(mixedCase);
	if (featureDefs.find(name) != featureDefs.end()) {
		return;
	}

	FeatureDef* fd = new FeatureDef;

	fd->myName = name;

	fd->filename = fdTable.GetString("filename", "unknown");

	fd->description = fdTable.GetString("description", "");

	fd->blocking      =  fdTable.GetBool("blocking",       true);
	fd->burnable      =  fdTable.GetBool("flammable",      false);
	fd->destructable  = !fdTable.GetBool("indestructible", false);
	fd->reclaimable   =  fdTable.GetBool("reclaimable",    fd->destructable);
	fd->autoreclaim   =  fdTable.GetBool("autoreclaimable",    fd->autoreclaim);
	fd->resurrectable =  fdTable.GetInt("resurrectable",   -1);

	//this seem to be the closest thing to floating that ta wreckage contains
	fd->floating = fdTable.GetBool("nodrawundergray", false);
	if (fd->floating && !fd->blocking) {
		fd->floating = false;
	}

	fd->noSelect = fdTable.GetBool("noselect", false);

	fd->deathFeature = fdTable.GetString("featureDead", "");

	fd->metal       = fdTable.GetFloat("metal",  0.0f);
	fd->energy      = fdTable.GetFloat("energy", 0.0f);
	fd->maxHealth   = fdTable.GetFloat("damage", 0.0f);
	fd->reclaimTime = fdTable.GetFloat("reclaimTime", (fd->metal + fd->energy)*6.f);

	fd->smokeTime = fdTable.GetInt("smokeTime", (fd->blocking) ? 300 : 0);

	fd->drawType = fdTable.GetInt("drawType", DRAWTYPE_MODEL);
	fd->modelname = fdTable.GetString("object", "");
	if (!fd->modelname.empty()) {
		if (fd->modelname.find(".") == std::string::npos) {
			fd->modelname += ".3do";
		}
		fd->modelname = string("objects3d/") + fd->modelname;
	}


	// these take precedence over the old sphere tags as well as
	// feature->radius (for feature <--> projectile interactions)
	fd->collisionVolumeTypeStr = fdTable.GetString("collisionVolumeType", "");
	fd->collisionVolumeScales  = fdTable.GetFloat3("collisionVolumeScales", ZeroVector);
	fd->collisionVolumeOffsets = fdTable.GetFloat3("collisionVolumeOffsets", ZeroVector);
	fd->collisionVolumeTest    = fdTable.GetInt("collisionVolumeTest", COLVOL_TEST_CONT);

	// initialize the (per-featuredef) collision-volume,
	// all CFeature instances hold a copy of this object
	fd->collisionVolume = new CollisionVolume(
		fd->collisionVolumeTypeStr,
		fd->collisionVolumeScales,
		fd->collisionVolumeOffsets,
		fd->collisionVolumeTest
	);


	fd->upright = fdTable.GetBool("upright", false);

	// our resolution is double TA's
	fd->xsize = fdTable.GetInt("footprintX", 1) * 2;
	fd->zsize = fdTable.GetInt("footprintZ", 1) * 2;

	const float defMass = (fd->metal * 0.4f) + (fd->maxHealth * 0.1f);
	fd->mass = fdTable.GetFloat("mass", defMass);
	fd->mass = max(0.001f, fd->mass);

	// custom parameters table
	fdTable.SubTable("customParams").GetMap(fd->customParams);

	AddFeatureDef(name, fd);
}
Exemple #15
0
void CMapInfo::ReadWater()
{
	const LuaTable wt = mapRoot->SubTable("water");

	water.repeatX = wt.GetFloat("repeatX", 0.0f);
	water.repeatY = wt.GetFloat("repeatY", 0.0f);
	water.damage  = wt.GetFloat("damage",  0.0f) * (16.0f / 30.0f);

	water.absorb    = wt.GetFloat3("absorb",    float3(0.0f, 0.0f, 0.0f));
	water.baseColor = wt.GetFloat3("baseColor", float3(0.0f, 0.0f, 0.0f));
	water.minColor  = wt.GetFloat3("minColor",  float3(0.0f, 0.0f, 0.0f));

	water.ambientFactor = wt.GetFloat("ambientFactor", 1.0f);
	water.diffuseFactor = wt.GetFloat("diffuseFactor", 1.0f);
	water.specularFactor= wt.GetFloat("specularFactor",1.0f);
	water.specularPower = wt.GetFloat("specularPower", 20.0f);

	water.planeColor    = wt.GetFloat3("planeColor", float3(0.0f, 0.4f, 0.0f));
	water.hasWaterPlane = wt.KeyExists("planeColor");

	water.surfaceColor  = wt.GetFloat3("surfaceColor", float3(0.75f, 0.8f, 0.85f));
	water.surfaceAlpha  = wt.GetFloat("surfaceAlpha",  0.55f);
	water.diffuseColor  = wt.GetFloat3("diffuseColor",  float3(1.0f, 1.0f, 1.0f));
	water.specularColor = wt.GetFloat3("specularColor", light.groundSunColor);

	water.fresnelMin   = wt.GetFloat("fresnelMin",   0.2f);
	water.fresnelMax   = wt.GetFloat("fresnelMax",   0.8f);
	water.fresnelPower = wt.GetFloat("fresnelPower", 4.0f);

	water.reflDistortion = wt.GetFloat("reflectionDistortion", 1.0f);

	water.blurBase     = wt.GetFloat("blurBase", 2.0f);
	water.blurExponent = wt.GetFloat("blurExponent", 1.5f);

	water.perlinStartFreq  = wt.GetFloat("perlinStartFreq",  8.0f);
	water.perlinLacunarity = wt.GetFloat("perlinLacunarity", 3.0f);
	water.perlinAmplitude  = wt.GetFloat("perlinAmplitude",  0.9f);
	water.windSpeed        = wt.GetFloat("windSpeed", 1.0f);

	water.texture       = wt.GetString("texture",       "");
	water.foamTexture   = wt.GetString("foamTexture",   "");
	water.normalTexture = wt.GetString("normalTexture", "");

	water.shoreWaves = wt.GetBool("shoreWaves", true);

	water.forceRendering = wt.GetBool("forceRendering", false);

	// use 'resources.lua' for missing fields  (our the engine defaults)
	const LuaTable resGfxMaps = resRoot->SubTable("graphics").SubTable("maps");

	if (!water.texture.empty()) {
		water.texture = "maps/" + water.texture;
	} else {
		water.texture = "bitmaps/" + resGfxMaps.GetString("watertex", "ocean.jpg");
	}

	if (!water.foamTexture.empty()) {
		water.foamTexture = "maps/" + water.foamTexture;
	} else {
		water.foamTexture = "bitmaps/" + resGfxMaps.GetString("waterfoamtex", "foam.jpg");
	}

	if (!water.normalTexture.empty()) {
		water.normalTexture = "maps/" + water.normalTexture;
		water.numTiles    = std::min(16,std::max(1,wt.GetInt("numTiles",1)));
	} else {
		water.normalTexture = "bitmaps/" + resGfxMaps.GetString("waternormaltex", "waterbump.png");
		if (resGfxMaps.KeyExists("waternormaltex")) {
			water.numTiles = std::min(16,std::max(1,resGfxMaps.GetInt("numTiles",1)));
		}else{
			// default texture is a TileSet of 3x3
			// user-defined textures are expected to be 1x1 (no DynWaves possible)
			water.numTiles = 3;
		}
	}

	// water caustic textures
	LuaTable caustics = wt.SubTable("caustics");
	string causticPrefix = "maps/";
	if (!caustics.IsValid()) {
		caustics = resRoot->SubTable("graphics").SubTable("caustics");
		causticPrefix = "bitmaps/";
	}
	if (caustics.IsValid()) {
		for (int i = 1; true; i++) {
			const string texName = caustics.GetString(i, "");
			if (texName.empty()) {
				break;
			}
			water.causticTextures.push_back(causticPrefix + texName);
		}
	} else {
		// load the default 32 textures
		for (int i = 0; i < 32; i++) {
			char defTex[256];
			sprintf(defTex, "bitmaps/caustics/caustic%02i.jpg", i);
			water.causticTextures.push_back(defTex);
		}
	}
}
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);
			}
		}
	}
}
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 #18
0
void UnitDef::ParseWeaponsTable(const LuaTable& weaponsTable)
{
	const WeaponDef* noWeaponDef = weaponDefHandler->GetWeapon("NOWEAPON");

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

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

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

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

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

		float3 mainDir = wTable.GetFloat3("mainDir", float3(1.0f, 0.0f, 0.0f)).SafeNormalize();
		const float angleDif = cos(wTable.GetFloat("maxAngleDif", 360.0f) * (PI / 360.0f));

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

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

		maxWeaponRange = std::max(maxWeaponRange, wd->range);

		if (wd->interceptor && wd->coverageRange > maxCoverage)
			maxCoverage = wd->coverageRange;

		if (wd->isShield) {
			if (!shieldWeaponDef || // use the biggest shield
			    (shieldWeaponDef->shieldRadius < wd->shieldRadius)) {
				shieldWeaponDef = wd;
			}
		}

		if (wd->stockpile) {
			// interceptors have priority
			if (wd->interceptor        ||
			    !stockpileWeaponDef ||
			    !stockpileWeaponDef->interceptor) {
				stockpileWeaponDef = wd;
			}
		}
	}
}
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);
    }
}
Exemple #20
0
void CUnitDefHandler::ParseUnitDefTable(const LuaTable& udTable, const string& unitName, int id)
{
	UnitDef& ud = unitDefs[id];

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	string lname = StringToLower(ud.name);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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


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

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

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

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

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

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

	// custom parameters table
	udTable.SubTable("customParams").GetMap(ud.customParams);
}