diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h index 585d4849ed..12aa3827d2 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h @@ -588,6 +588,7 @@ class GlobalData : public SubsystemInterface DeathTypeFlags m_defaultExcludedDeathTypes; Bool m_heightAboveTerrainIncludesWater; + Bool m_hideScorchmarksAboveGround; // the trailing '\' is included! const AsciiString &getPath_UserData() const { return m_userDataDir; } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp index c38ed69fd7..c026ed8f7d 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp @@ -574,6 +574,7 @@ GlobalData* GlobalData::m_theOriginal = NULL; {"DefaultExcludedDeathTypes", INI::parseDeathTypeFlagsList, NULL, offsetof(GlobalData, m_defaultExcludedDeathTypes) }, {"HeightAboveTerrainIncludesWater", INI::parseBool, NULL, offsetof(GlobalData, m_heightAboveTerrainIncludesWater) }, + {"HideScorchmarksAboveGround", INI::parseBool, NULL, offsetof(GlobalData, m_hideScorchmarksAboveGround) }, { NULL, NULL, NULL, 0 } // keep this last }; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp index 1f3982336c..3e9a541084 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp @@ -489,6 +489,31 @@ class TerrainScorchFXNugget : public FXNugget { if (primary) { + // If scormarks are high above the ground + if (TheGlobalData->m_hideScorchmarksAboveGround && TheTerrainLogic) { + /*PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(primary); + Real groundHeight = 0; + if (layer != LAYER_GROUND) { + TheTerrainLogic->getLayerHeight(primary->x, primary->y, layer); + } + else { + Real waterZ; + Real terrainZ; + if (TheTerrainLogic->isUnderwater(primary->x, primary->y, &waterZ, &terrainZ)) + groundHeight = waterZ; + else + groundHeight = terrainZ; + }*/ + + PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(primary); + if (layer != LAYER_GROUND) + return; + + Real groundHeight = TheTerrainLogic->getLayerHeight(primary->x, primary->y, layer); + if (primary->z - groundHeight > m_radius) + return; + } + Int scorch = m_scorch; if (scorch < 0) { @@ -541,6 +566,21 @@ class TerrainScorchFXNugget : public FXNugget }; EMPTY_DTOR(TerrainScorchFXNugget) +//------------------------------------------------------------------------------------------------- +static const char* const AllowedSurfaceNames[] = +{ + "ALL", + "LAND", + "WATER", + NULL +}; + +enum AllowedSurfaceType CPP_11(: Int) { + SURFACE_ALL = 0, + SURFACE_LAND, + SURFACE_WATER +}; + //------------------------------------------------------------------------------------------------- class ParticleSystemFXNugget : public FXNugget { @@ -561,6 +601,11 @@ class ParticleSystemFXNugget : public FXNugget m_createAtGroundHeight = FALSE; m_useCallersRadius = FALSE; m_rotateX = m_rotateY = m_rotateZ = 0; + + m_maxAllowedHeight = INFINITY; + m_minAllowedHeight = -INFINITY; + // m_createAtWaterHeight = FALSE; + m_allowedSurfaceType = SURFACE_ALL; } virtual void doFXPos(const Coord3D *primary, const Matrix3D* primaryMtx, const Real /*primarySpeed*/, const Coord3D * /*secondary*/, const Real overrideRadius ) const @@ -623,6 +668,11 @@ class ParticleSystemFXNugget : public FXNugget { "AttachToObject", INI::parseBool, NULL, offsetof( ParticleSystemFXNugget, m_attachToObject ) }, { "CreateAtGroundHeight", INI::parseBool, NULL, offsetof( ParticleSystemFXNugget, m_createAtGroundHeight ) }, { "UseCallersRadius", INI::parseBool, NULL, offsetof( ParticleSystemFXNugget, m_useCallersRadius ) }, + // New height controls + // { "CreateAtWaterHeight", INI::parseBool, NULL, offsetof(ParticleSystemFXNugget, m_createAtWaterHeight) }, + { "MinAllowedHeight", INI::parseReal, NULL, offsetof(ParticleSystemFXNugget, m_minAllowedHeight) }, + { "MaxAllowedHeight", INI::parseReal, NULL, offsetof(ParticleSystemFXNugget, m_maxAllowedHeight) }, + { "AllowedSurface", INI::parseIndexList, AllowedSurfaceNames, offsetof(ParticleSystemFXNugget, m_allowedSurfaceType) }, { 0, 0, 0, 0 } }; @@ -650,6 +700,38 @@ class ParticleSystemFXNugget : public FXNugget DEBUG_ASSERTCRASH(tmp, ("ParticleSystem %s not found",m_name.str())); if (tmp) { + Real groundHeight = 0; // we might need it later + + // Evaluate Height and allowed surfaces first. + if ((TheTerrainLogic != NULL) && (m_minAllowedHeight > -INFINITY || m_maxAllowedHeight < INFINITY || m_allowedSurfaceType != SURFACE_ALL || m_createAtGroundHeight)) { + PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(primary); + + if (layer != LAYER_GROUND) { // Bridge + if (m_allowedSurfaceType == SURFACE_WATER) return; // No water effects over bridges. + groundHeight = TheTerrainLogic->getLayerHeight(primary->x, primary->y, layer); + } + else { // Ground (Water or Land) + Real waterZ = 0; + Real terrainZ = 0; + if (m_allowedSurfaceType != SURFACE_ALL || TheGlobalData->m_heightAboveTerrainIncludesWater) { // Do water check + Bool isWater = TheTerrainLogic->isUnderwater(primary->x, primary->y, &waterZ, &terrainZ); + + if (isWater) { + if (m_allowedSurfaceType == SURFACE_LAND) return; + groundHeight = waterZ; + } + else { + if (m_allowedSurfaceType == SURFACE_WATER) return; + groundHeight = terrainZ; + } + } + } + + Real zOffset = primary->z - groundHeight; + if (zOffset < m_minAllowedHeight || zOffset > m_maxAllowedHeight) return; + } + + for (Int i = 0; i < m_count; i++ ) { ParticleSystem *sys = TheParticleSystemManager->createParticleSystem(tmp); @@ -661,25 +743,35 @@ class ParticleSystemFXNugget : public FXNugget newPos.x = primary->x + offset.x + radius * cos(angle); newPos.y = primary->y + offset.y + radius * sin(angle); - if( m_createAtGroundHeight && TheTerrainLogic ) - { - //old way: - //newPos.z = TheTerrainLogic->getGrsoundHeight( newPos.x, newPos.y ) + 1;// The plus one prevents scissoring with terrain - //new way: now we allow bridges in the GroundHeight. - //newer way: include water - - PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(&newPos); - - if (Real waterZ = 0; TheGlobalData->m_heightAboveTerrainIncludesWater && layer == LAYER_GROUND && - TheTerrainLogic->isUnderwater(newPos.x, newPos.y, &waterZ)) { - newPos.z = waterZ; - } - else { - newPos.z = TheTerrainLogic->getLayerHeight(newPos.x, newPos.y, layer); - } + + + if (m_createAtGroundHeight) { + newPos.z = groundHeight + offset.z + m_height.getValue(); } - else + else { newPos.z = primary->z + offset.z + m_height.getValue(); + } + + //if( m_createAtGroundHeight && TheTerrainLogic ) + //{ + // //old way: + // //newPos.z = TheTerrainLogic->getGrsoundHeight( newPos.x, newPos.y ) + 1;// The plus one prevents scissoring with terrain + // //new way: now we allow bridges in the GroundHeight. + // //newer way: include water + // //newest way: include height limits and surface check + + // PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(&newPos); + // + // if (Real waterZ = 0; TheGlobalData->m_heightAboveTerrainIncludesWater && layer == LAYER_GROUND && + // TheTerrainLogic->isUnderwater(newPos.x, newPos.y, &waterZ)) { + // newPos.z = waterZ + offset.z + m_height.getValue(); + // } + // else { + // newPos.z = TheTerrainLogic->getLayerHeight(newPos.x, newPos.y, layer) + offset.z + m_height.getValue(); + // } + //} + //else + // newPos.z = primary->z + offset.z + m_height.getValue(); if (m_orientToObject && mtx) @@ -738,6 +830,11 @@ class ParticleSystemFXNugget : public FXNugget Bool m_createAtGroundHeight; Bool m_useCallersRadius; Bool m_ricochet; + + Real m_maxAllowedHeight; + Real m_minAllowedHeight; + //Bool m_createAtWaterHeight; + AllowedSurfaceType m_allowedSurfaceType; }; EMPTY_DTOR(ParticleSystemFXNugget)