MoveDef::MoveDef(const LuaTable& moveDefTable, int moveDefID) { *this = MoveDef(); name = StringToLower(moveDefTable.GetString("name", "")); pathType = moveDefID - 1; crushStrength = moveDefTable.GetFloat("crushStrength", 10.0f); const LuaTable& depthModTable = moveDefTable.SubTable("depthModParams"); const LuaTable& speedModMultsTable = moveDefTable.SubTable("speedModMults"); const float minWaterDepth = moveDefTable.GetFloat("minWaterDepth", GetDefaultMinWaterDepth()); const float maxWaterDepth = moveDefTable.GetFloat("maxWaterDepth", GetDefaultMaxWaterDepth()); switch ((speedModClass = ParseSpeedModClass(name, moveDefTable))) { case MoveDef::Tank: { // fall-through } case MoveDef::KBot: { depthModParams[DEPTHMOD_MIN_HEIGHT] = std::max(0.00f, depthModTable.GetFloat("minHeight", 0.0f )); depthModParams[DEPTHMOD_MAX_HEIGHT] = ( depthModTable.GetFloat("maxHeight", std::numeric_limits<float>::max() )); depthModParams[DEPTHMOD_MAX_SCALE ] = std::max(0.01f, depthModTable.GetFloat("maxScale", std::numeric_limits<float>::max() )); depthModParams[DEPTHMOD_QUA_COEFF ] = std::max(0.00f, depthModTable.GetFloat("quadraticCoeff", 0.0f )); depthModParams[DEPTHMOD_LIN_COEFF ] = std::max(0.00f, depthModTable.GetFloat("linearCoeff", moveDefTable.GetFloat("depthMod", 0.1f))); depthModParams[DEPTHMOD_CON_COEFF ] = std::max(0.00f, depthModTable.GetFloat("constantCoeff", 1.0f )); // ensure [depthModMinHeight, depthModMaxHeight] is a valid range depthModParams[DEPTHMOD_MAX_HEIGHT] = std::max(depthModParams[DEPTHMOD_MIN_HEIGHT], depthModParams[DEPTHMOD_MAX_HEIGHT]); depth = maxWaterDepth; maxSlope = DegreesToMaxSlope(moveDefTable.GetFloat("maxSlope", 60.0f)); } break; case MoveDef::Hover: { depth = maxWaterDepth; maxSlope = DegreesToMaxSlope(moveDefTable.GetFloat("maxSlope", 15.0f)); } break; case MoveDef::Ship: { depth = minWaterDepth; subMarine = moveDefTable.GetBool("subMarine", false); } break; } speedModMults[SPEEDMOD_MOBILE_BUSY_MULT] = std::max(0.01f, speedModMultsTable.GetFloat("mobileBusyMult", 1.0f /*0.10f*/)); speedModMults[SPEEDMOD_MOBILE_IDLE_MULT] = std::max(0.01f, speedModMultsTable.GetFloat("mobileIdleMult", 1.0f /*0.35f*/)); speedModMults[SPEEDMOD_MOBILE_MOVE_MULT] = std::max(0.01f, speedModMultsTable.GetFloat("mobileMoveMult", 1.0f /*0.65f*/)); avoidMobilesOnPath = moveDefTable.GetBool("avoidMobilesOnPath", true); allowTerrainCollisions = moveDefTable.GetBool("allowTerrainCollisions", true); heatMapping = moveDefTable.GetBool("heatMapping", false); flowMapping = moveDefTable.GetBool("flowMapping", true); heatMod = moveDefTable.GetFloat("heatMod", (1.0f / (GAME_SPEED * 2)) * 0.25f); flowMod = moveDefTable.GetFloat("flowMod", 1.0f); // by default heat decays to zero after N=2 seconds // // the cost contribution to a square from heat must // be on the same order as its normal movement cost // PER FRAME, i.e. such that heatMod * heatProduced // ~= O(1 / (GAME_SPEED * N)) because unit behavior // in groups quickly becomes FUBAR if heatMod >>> 1 // heatProduced = moveDefTable.GetInt("heatProduced", GAME_SPEED * 2); // <maxSlope> ranges from 0.0 to 60 * 1.5 degrees, ie. from 0.0 to // 0.5 * PI radians, ie. from 1.0 - cos(0.0) to 1.0 - cos(0.5 * PI) // = [0, 1] --> DEFAULT <slopeMod> values range from (4 / 0.001) to // (4 / 1.001) = [4000.0, 3.996] // // speedMod values for a terrain-square slope in [0, 1] are given by // (1.0 / (1.0 + slope * slopeMod)) and therefore have a MAXIMUM at // <slope=0, slopeMod=...> and a MINIMUM at <slope=1, slopeMod=4000> // (of 1.0 / (1.0 + 0.0 * ...) = 1.0 and 1.0 / (1.0 + 1.0 * 4000.0) // = 0.00025 respectively) // slopeMod = moveDefTable.GetFloat("slopeMod", 4.0f / (maxSlope + 0.001f)); // ground units hug the ocean floor when in water, // ships stay at a "fixed" level (their waterline) followGround = (speedModClass == MoveDef::Tank || speedModClass == MoveDef::KBot); // TODO: // remove terrainClass, not used anywhere // and only AI's MIGHT have benefit from it // // tank or bot that cannot get its threads / feet // wet, or hovercraft (which doesn't touch ground // or water) if ((followGround && maxWaterDepth <= 0.0f) || speedModClass == MoveDef::Hover) terrainClass = MoveDef::Land; // ship (or sub) that cannot crawl onto shore, OR tank // or bot restricted to snorkling (strange but possible) if ((speedModClass == MoveDef::Ship && minWaterDepth > 0.0f) || (followGround && minWaterDepth > 0.0f)) terrainClass = MoveDef::Water; // tank or kbot that CAN go skinny-dipping (amph.), // or ship that CAN sprout legs when at the beach if ((followGround && maxWaterDepth > 0.0f) || (speedModClass == MoveDef::Ship && minWaterDepth < 0.0f)) terrainClass = MoveDef::Mixed; const int xsizeDef = std::max(1, moveDefTable.GetInt("footprintX", 1)); const int zsizeDef = std::max(1, moveDefTable.GetInt("footprintZ", xsizeDef)); // make all mobile footprints point-symmetric in heightmap space // (meaning that only non-even dimensions are possible and each // footprint always has a unique center square) xsize = xsizeDef * SPRING_FOOTPRINT_SCALE; zsize = zsizeDef * SPRING_FOOTPRINT_SCALE; xsize -= ((xsize & 1)? 0: 1); zsize -= ((zsize & 1)? 0: 1); // precalculated data for MoveMath xsizeh = xsize >> 1; zsizeh = zsize >> 1; assert((xsize & 1) == 1); assert((zsize & 1) == 1); }
MoveDef::MoveDef(const LuaTable& moveTable, int moveDefID) { *this = MoveDef(); name = StringToLower(moveTable.GetString("name", "")); pathType = moveDefID - 1; crushStrength = moveTable.GetFloat("crushStrength", 10.0f); const LuaTable& depthModTable = moveTable.SubTable("depthModParams"); const LuaTable& speedModMultsTable = moveTable.SubTable("speedModMults"); const float minWaterDepth = moveTable.GetFloat("minWaterDepth", 10.0f); const float maxWaterDepth = moveTable.GetFloat("maxWaterDepth", 0.0f); if ((name.find("boat") != string::npos) || (name.find("ship") != string::npos)) { depth = minWaterDepth; moveFamily = MoveDef::Ship; subMarine = moveTable.GetBool("subMarine", false); } else if (name.find("hover") != string::npos) { maxSlope = DegreesToMaxSlope(moveTable.GetFloat("maxSlope", 15.0f)); moveFamily = MoveDef::Hover; } else { depthModParams[DEPTHMOD_MIN_HEIGHT] = std::max(0.00f, depthModTable.GetFloat("minHeight", 0.0f )); depthModParams[DEPTHMOD_MAX_HEIGHT] = ( depthModTable.GetFloat("maxHeight", std::numeric_limits<float>::max() )); depthModParams[DEPTHMOD_MAX_SCALE ] = std::max(0.01f, depthModTable.GetFloat("maxScale", std::numeric_limits<float>::max() )); depthModParams[DEPTHMOD_QUA_COEFF ] = std::max(0.00f, depthModTable.GetFloat("quadraticCoeff", 0.0f )); depthModParams[DEPTHMOD_LIN_COEFF ] = std::max(0.00f, depthModTable.GetFloat("linearCoeff", moveTable.GetFloat("depthMod", 0.1f))); depthModParams[DEPTHMOD_CON_COEFF ] = std::max(0.00f, depthModTable.GetFloat("constantCoeff", 1.0f )); // ensure [depthModMinHeight, depthModMaxHeight] is a valid range depthModParams[DEPTHMOD_MAX_HEIGHT] = std::max(depthModParams[DEPTHMOD_MIN_HEIGHT], depthModParams[DEPTHMOD_MAX_HEIGHT]); depth = maxWaterDepth; maxSlope = DegreesToMaxSlope(moveTable.GetFloat("maxSlope", 60.0f)); if (name.find("tank") != string::npos) { moveFamily = MoveDef::Tank; } else { moveFamily = MoveDef::KBot; } } speedModMults[SPEEDMOD_MOBILE_BUSY_MULT] = std::max(0.01f, speedModMultsTable.GetFloat("mobileBusyMult", 1.0f /*0.10f*/)); speedModMults[SPEEDMOD_MOBILE_IDLE_MULT] = std::max(0.01f, speedModMultsTable.GetFloat("mobileIdleMult", 1.0f /*0.35f*/)); speedModMults[SPEEDMOD_MOBILE_MOVE_MULT] = std::max(0.01f, speedModMultsTable.GetFloat("mobileMoveMult", 1.0f /*0.65f*/)); avoidMobilesOnPath = moveTable.GetBool("avoidMobilesOnPath", true); heatMapping = moveTable.GetBool("heatMapping", false); flowMapping = moveTable.GetBool("flowMapping", true); heatMod = moveTable.GetFloat("heatMod", 50.0f); flowMod = moveTable.GetFloat("flowMod", 1.0f); heatProduced = moveTable.GetInt("heatProduced", GAME_SPEED * 2); // <maxSlope> ranges from 0.0 to 60 * 1.5 degrees, ie. from 0.0 to // 0.5 * PI radians, ie. from 1.0 - cos(0.0) to 1.0 - cos(0.5 * PI) // = [0, 1] --> DEFAULT <slopeMod> values range from (4 / 0.001) to // (4 / 1.001) = [4000.0, 3.996] // // speedMod values for a terrain-square slope in [0, 1] are given by // (1.0 / (1.0 + slope * slopeMod)) and therefore have a MAXIMUM at // <slope=0, slopeMod=...> and a MINIMUM at <slope=1, slopeMod=4000> // (of 1.0 / (1.0 + 0.0 * ...) = 1.0 and 1.0 / (1.0 + 1.0 * 4000.0) // = 0.00025 respectively) // slopeMod = moveTable.GetFloat("slopeMod", 4.0f / (maxSlope + 0.001f)); // ground units hug the ocean floor when in water, // ships stay at a "fixed" level (their waterline) followGround = (moveFamily == MoveDef::Tank || moveFamily == MoveDef::KBot); // tank or bot that cannot get its threads / feet // wet, or hovercraft (which doesn't touch ground // or water) const bool b0 = ((followGround && maxWaterDepth <= 0.0) || moveFamily == MoveDef::Hover); // ship (or sub) that cannot crawl onto shore, OR tank or // kbot restricted to snorkling (strange but possible) const bool b1 = ((moveFamily == MoveDef::Ship && minWaterDepth > 0.0) || ((followGround) && minWaterDepth > 0.0)); // tank or kbot that CAN go skinny-dipping (amph.), // or ship that CAN sprout legs when at the beach const bool b2 = ((followGround) && maxWaterDepth > 0.0) || (moveFamily == MoveDef::Ship && minWaterDepth < 0.0); if (b0) { terrainClass = MoveDef::Land; } if (b1) { terrainClass = MoveDef::Water; } if (b2) { terrainClass = MoveDef::Mixed; } const int xsizeDef = std::max(1, moveTable.GetInt("footprintX", 1)); const int zsizeDef = std::max(1, moveTable.GetInt("footprintZ", xsizeDef)); // make all mobile footprints point-symmetric in heightmap space // (meaning that only non-even dimensions are possible and each // footprint always has a unique center square) xsize = xsizeDef * SPRING_FOOTPRINT_SCALE; zsize = zsizeDef * SPRING_FOOTPRINT_SCALE; xsize -= ((xsize & 1)? 0: 1); zsize -= ((zsize & 1)? 0: 1); // precalculated data for MoveMath xsizeh = xsize >> 1; zsizeh = zsize >> 1; assert((xsize & 1) == 1); assert((zsize & 1) == 1); }