diff --git a/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h b/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h index 08e5508ad0c..ed4423f1648 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h @@ -192,6 +192,7 @@ enum KindOfType CPP_11(: Int) KINDOF_TELEPORTER, KINDOF_SHIPYARD, + KINDOF_NO_MOVE_EFFECTS_ON_WATER, KINDOF_EXTRA1, KINDOF_EXTRA2, diff --git a/GeneralsMD/Code/GameEngine/Include/Common/Thing.h b/GeneralsMD/Code/GameEngine/Include/Common/Thing.h index 982a401ae69..c180ccd0372 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/Thing.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/Thing.h @@ -128,6 +128,8 @@ class Thing : public MemoryPoolObject Real getHeightAboveTerrain() const; Real getHeightAboveTerrainOrWater() const; + Bool isOverWater() const; + Bool isAboveTerrain() const { return getHeightAboveTerrain() > 0.0f; } Bool isAboveTerrainOrWater() const { return getHeightAboveTerrainOrWater() > 0.0f; } @@ -135,6 +137,7 @@ class Thing : public MemoryPoolObject If we treat this as airborne, then they slide down slopes. This checks whether they are high enough that we should let them act like they're flying. jba. */ Bool isSignificantlyAboveTerrain() const ; + Bool isSignificantlyAboveTerrainOrWater() const ; void convertBonePosToWorldPos(const Coord3D* bonePos, const Matrix3D* boneTransform, Coord3D* worldPos, Matrix3D* worldTransform) const; @@ -186,6 +189,7 @@ class Thing : public MemoryPoolObject mutable Coord3D m_cachedDirVector; ///< unit direction vector mutable Real m_cachedAltitudeAboveTerrain; mutable Real m_cachedAltitudeAboveTerrainOrWater; + mutable Bool m_cachedIsOverWater; mutable Int m_cacheFlags; }; diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h index bfa1e506f26..4f62d38d0c4 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h @@ -155,6 +155,7 @@ class DrawableLocoInfo : public MemoryPoolObject TWheelInfo m_wheelInfo; ///< Wheel offset & angle info for a wheeled type locomotor. DrawableLocoInfo(); + void reset(); }; //----------------------------------------------------------------------------- @@ -605,6 +606,8 @@ class Drawable : public Thing, Real friend_getExplicitOpacity( void ) { return m_explicitOpacity; } Real friend_getEffectiveStealthOpacity( void ) { return m_effectiveStealthOpacity; } + void resetPhysicsXform(); + protected: // snapshot methods diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/TintStatus.h b/GeneralsMD/Code/GameEngine/Include/GameClient/TintStatus.h index 6ed01a55744..9303d736daa 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/TintStatus.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/TintStatus.h @@ -26,6 +26,8 @@ enum TintStatus CPP_11(: Int) TINT_STATUS_TELEPORT_RECOVER, ///< (Chrono Legionnaire -> recover from teleport) TINT_STATUS_DISABLED_CHRONO, ///< Unit disabled by chrono gun TINT_STATUS_GAINING_CHRONO_DAMAGE, ///< Unit getting damaged from chrono gun + TINT_STATUS_FORCE_FIELD, + TINT_STATUS_IRON_CURTAIN, TINT_STATUS_EXTRA1, TINT_STATUS_EXTRA2, TINT_STATUS_EXTRA3, @@ -34,6 +36,8 @@ enum TintStatus CPP_11(: Int) TINT_STATUS_EXTRA6, TINT_STATUS_EXTRA7, TINT_STATUS_EXTRA8, + TINT_STATUS_EXTRA9, + TINT_STATUS_EXTRA10, TINT_STATUS_COUNT // Keep this last }; @@ -50,4 +54,4 @@ struct DrawableColorTint typedef BitFlags TintStatusFlags; // -------- -#endif /* __TINTSTATUS_H__ */ \ No newline at end of file +#endif /* __TINTSTATUS_H__ */ diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BuffUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BuffUpdate.h index e5c2ebf2b48..97b8d5d7f01 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BuffUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BuffUpdate.h @@ -74,6 +74,7 @@ class BuffUpdateModuleData : public UpdateModuleData KindOfMaskType m_forbiddenAffectKindOf; ///< Must be clear on target Int m_targetsMask; ///< ALLIES, ENEMIES or NEUTRALS Bool m_isAffectAirborne; ///< Affect Airborne targets + Bool m_requiresAllKindOfs; ///< requires ALL requiredKindOfs or just one of them UnsignedInt m_buffDuration; ///< How long a hit lasts on target UnsignedInt m_buffDelay; ///< How often to pulse Real m_buffRange; ///< How far to affect diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp index 1573fcfc451..9aae4ed4dab 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp @@ -181,6 +181,7 @@ const char* const KindOfMaskType::s_bitNameList[] = "TELEPORTER", "SHIPYARD", + "NO_MOVE_EFFECTS_ON_WATER", "EXTRA1", "EXTRA2", diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Thing/Thing.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Thing/Thing.cpp index 6fc61f7be96..0490ae3fc1f 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/Thing/Thing.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/Thing/Thing.cpp @@ -321,16 +321,29 @@ Real Thing::getHeightAboveTerrainOrWater() const if (TheTerrainLogic->isUnderwater(pos->x, pos->y, &waterZ)) { m_cachedAltitudeAboveTerrainOrWater = pos->z - waterZ; + m_cachedIsOverWater = TRUE; } else { m_cachedAltitudeAboveTerrainOrWater = getHeightAboveTerrain(); + m_cachedIsOverWater = FALSE; } m_cacheFlags |= VALID_ALTITUDE_SEALEVEL; } return m_cachedAltitudeAboveTerrainOrWater; } +// ------------------------------------------------------------------------------ +Bool Thing::isOverWater() const +{ + if (!(m_cacheFlags & VALID_ALTITUDE_SEALEVEL)) + { + getHeightAboveTerrainOrWater(); + } + return m_cachedIsOverWater; +} + + //============================================================================= /** If we treat this as airborne, then they slide down slopes. This checks whether they are high enough that we should let them act like they're flying. jba. */ @@ -341,6 +354,13 @@ Bool Thing::isSignificantlyAboveTerrain() const // then it's significantly airborne. jba return (getHeightAboveTerrain() > -(3*3)*TheGlobalData->m_gravity); } +//------------------------------------------------------------------------------------------------- +Bool Thing::isSignificantlyAboveTerrainOrWater() const +{ + // If it's high enough that it will take more than 3 frames to return to the ground, + // then it's significantly airborne. jba + return (getHeightAboveTerrainOrWater() > -(3 * 3) * TheGlobalData->m_gravity); +} //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 8616791fae8..8c32f2ffbb6 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -117,6 +117,7 @@ static_assert(ARRAY_SIZE(TheDrawableIconNames) == MAX_ICONS + 1, "Incorrect arra // ----- +template<> const char* const TintStatusFlags::s_bitNameList[] = { "NONE", @@ -131,6 +132,8 @@ const char* const TintStatusFlags::s_bitNameList[] = "TELEPORT_RECOVER", "DISABLED_CHRONO", "GAINING_CHRONO_DAMAGE", + "FORCE_FIELD", + "IRON_CURTAIN", "EXTRA1", "EXTRA2", "EXTRA3", @@ -139,8 +142,12 @@ const char* const TintStatusFlags::s_bitNameList[] = "EXTRA6", "EXTRA7", "EXTRA8", + "EXTRA9", + "EXTRA10", NULL }; +static_assert(ARRAY_SIZE(TintStatusFlags::s_bitNameList) == TintStatusFlags::NumBits + 1, "Incorrect array size"); + /** * Returns a special DynamicAudioEventInfo which can be used to mark a sound as "no sound". @@ -239,6 +246,13 @@ DrawableLocoInfo::~DrawableLocoInfo() { } +// ------------------------------------------------------------------------------------------------ +void DrawableLocoInfo::reset() +{ + *this = DrawableLocoInfo(); +} + + // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ static const char *drawableIconIndexToName( DrawableIconType iconIndex ) @@ -1461,6 +1475,22 @@ void Drawable::applyPhysicsXform(Matrix3D* mtx) } } +//------------------------------------------------------------------------------------------------- +void Drawable::resetPhysicsXform() +{ + if (m_physicsXform != NULL) + { + m_physicsXform->m_totalPitch = 0.0; + m_physicsXform->m_totalRoll = 0.0; + m_physicsXform->m_totalYaw = 0.0; + m_physicsXform->m_totalZ = 0.0; + + if (m_locoInfo) { + m_locoInfo->reset(); + } + } +} + //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- Bool Drawable::calcPhysicsXform(PhysicsXformInfo& info) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Locomotor.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Locomotor.cpp index 34b22f012ca..e37b1aa5ad1 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Locomotor.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Locomotor.cpp @@ -1909,8 +1909,7 @@ void Locomotor::moveTowardsPositionHover(Object* obj, PhysicsBehavior *physics, moveTowardsPositionOther(obj, physics, goalPos, onPathDistToGoal, desiredSpeed); // Only hover locomotors care about their OverWater special effects. (OverWater also affects speed, so this is not a client thing) - Coord3D newPosition = *obj->getPosition(); - if( TheTerrainLogic->isUnderwater( newPosition.x, newPosition.y ) ) + if( obj->isOverWater() ) { if( ! getFlag( OVER_WATER ) ) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp index e10d5e84631..fafc9fc143a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate.cpp @@ -952,6 +952,14 @@ void AIUpdateInterface::chooseGoodLocomotorFromCurrentSet( void ) // Add speed multiplier to loco if (m_speedMultiplier != 1.0) m_curLocomotor->applySpeedMultiplier(m_speedMultiplier); + + // Reset drawable transforms + if (prevLoco != NULL && prevLoco->getAppearance() != m_curLocomotor->getAppearance()) { + Drawable* draw = getObject()->getDrawable(); + if (draw) { + draw->resetPhysicsXform(); + } + } } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BuffUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BuffUpdate.cpp index a9f2056ba53..08c5899d838 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BuffUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BuffUpdate.cpp @@ -79,6 +79,7 @@ void BuffUpdateModuleData::buildFieldParse(MultiIniFieldParse& p) static const FieldParse dataFieldParse[] = { { "RequiredAffectKindOf", KindOfMaskType::parseFromINI, NULL, offsetof( BuffUpdateModuleData, m_requiredAffectKindOf ) }, + { "RequiresAllKindOfs", INI::parseBool, NULL, offsetof(BuffUpdateModuleData, m_requiresAllKindOfs) }, { "ForbiddenAffectKindOf", KindOfMaskType::parseFromINI, NULL, offsetof( BuffUpdateModuleData, m_forbiddenAffectKindOf ) }, { "AffectsTargets", INI::parseBitString32, TheWeaponAffectsMaskNames, offsetof(BuffUpdateModuleData, m_targetsMask) }, { "AffectAirborne", INI::parseBool, NULL, offsetof(BuffUpdateModuleData, m_isAffectAirborne) }, @@ -115,14 +116,21 @@ struct tempBuffData // This is used for iterator to apply buff to contained obje KindOfMaskType m_requiredMask; KindOfMaskType m_forbiddenMask; Bool m_isAffectAirborne; + Bool m_requiresAllKindOfs; }; void containIteratingDoBuff( Object *passenger, void *voidData) { tempBuffData *data = (tempBuffData *)voidData; - if (passenger->isKindOfMulti(data->m_requiredMask, data->m_forbiddenMask)) { + bool match = FALSE; + if (!data->m_requiresAllKindOfs) + match = passenger->isAnyKindOf(data->m_requiredMask) && !passenger->isAnyKindOf(data->m_forbiddenMask); + else + match = passenger->isKindOfMulti(data->m_requiredMask, data->m_forbiddenMask); + + if (match) { if (data->m_isAffectAirborne || !passenger->isAirborneTarget()) { - passenger->applyBuff(data->m_template, data->m_duration, data->m_sourceObj); // TODO: create function in object + passenger->applyBuff(data->m_template, data->m_duration, data->m_sourceObj); } } } @@ -170,16 +178,23 @@ UpdateSleepTime BuffUpdate::update( void ) buffData.m_duration = data->m_buffDuration; buffData.m_requiredMask = data->m_requiredAffectKindOf; buffData.m_forbiddenMask = data->m_forbiddenAffectKindOf; + buffData.m_requiresAllKindOfs = data->m_requiresAllKindOfs; buffData.m_isAffectAirborne = data->m_isAffectAirborne; buffData.m_sourceObj = me; // TODO: Support for projectiles for( Object *currentObj = iter->first(); currentObj != NULL; currentObj = iter->next() ) { - if( currentObj->isKindOfMulti(data->m_requiredAffectKindOf, data->m_forbiddenAffectKindOf) ) + bool match = FALSE; + if (!data->m_requiresAllKindOfs) + match = currentObj->isAnyKindOf(data->m_requiredAffectKindOf) && !currentObj->isAnyKindOf(data->m_forbiddenAffectKindOf); + else + match = currentObj->isKindOfMulti(data->m_requiredAffectKindOf, data->m_forbiddenAffectKindOf); + + if (match) { if (data->m_isAffectAirborne || !currentObj->isAirborneTarget()) { - currentObj->applyBuff(buffTemp, data->m_buffDuration, me); // TODO + currentObj->applyBuff(buffTemp, data->m_buffDuration, me); } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp index 080d63f18a7..14c5f1e17c1 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp @@ -2890,7 +2890,7 @@ Bool Weapon::privateFireWeapon( WeaponBonus bonus; computeBonus(sourceObj, extraBonusFlags, bonus); - debug_printWeaponBonus(&bonus, m_template->getName()); + // debug_printWeaponBonus(&bonus, m_template->getName()); DEBUG_ASSERTCRASH(getStatus() != OUT_OF_AMMO, ("Hmm, firing weapon that is OUT_OF_AMMO")); DEBUG_ASSERTCRASH(getStatus() == READY_TO_FIRE, ("Hmm, Weapon is firing more often than should be possible")); diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h index c4e70ed1f5d..d593cb31dc0 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h @@ -316,7 +316,7 @@ class W3DModelDrawModuleData : public ModuleData Bool m_showForOwnerOnly; ///< show this model only to the owning player - Bool m_autoSelectObject; ///< show this model only to the owning player + // Bool m_disableMoveEffectsOverWater; ///< disable track marks and tread/wheel anims over water W3DModelDrawModuleData(); ~W3DModelDrawModuleData(); diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp index d063884e4d6..146affad57a 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp @@ -1227,6 +1227,7 @@ void W3DModelDrawModuleData::buildFieldParse(MultiIniFieldParse& p) { "IgnoreAnimationSpeedScaling", INI::parseBool, NULL, offsetof(W3DModelDrawModuleData, m_ignoreAnimScaling) }, { "IgnoreRotation", INI::parseBool, NULL, offsetof(W3DModelDrawModuleData, m_ignoreRotation) }, { "OnlyVisibleToOwningPlayer", INI::parseBool, NULL, offsetof(W3DModelDrawModuleData, m_showForOwnerOnly) }, + //{ "DisableMovementEffectsOverWater", INI::parseBool, NULL, offsetof(W3DModelDrawModuleData, m_disableMoveEffectsOverWater) }, { 0, 0, 0, 0 } }; p.add(dataFieldParse); @@ -3743,13 +3744,13 @@ void W3DModelDraw::reactToTransformChange( const Matrix3D* oldMtx, Object *obj = getDrawable()->getObject(); const Coord3D* pos = getDrawable()->getPosition(); - if ( m_fullyObscuredByShroud || obj->testStatus( OBJECT_STATUS_STEALTHED ) == TRUE ) + if ( m_fullyObscuredByShroud || obj->testStatus( OBJECT_STATUS_STEALTHED ) == TRUE || getDrawable()->isDrawableEffectivelyHidden() ) { m_trackRenderObject->addCapEdgeToTrack(pos->x, pos->y); } else { - if (obj && obj->isSignificantlyAboveTerrain()) + if (obj->isSignificantlyAboveTerrain() || (obj->isKindOf(KINDOF_NO_MOVE_EFFECTS_ON_WATER) && obj->isOverWater())) { m_trackRenderObject->setAirborne(); } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp index 56af0e77ca1..cadf714315a 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp @@ -365,7 +365,7 @@ void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) m_treadDebrisRight->setBurstCountMultiplier( velMult.z ); //Update movement of treads - if (m_treadCount) + if (m_treadCount && !(obj->isKindOf(KINDOF_NO_MOVE_EFFECTS_ON_WATER) && obj->isOverWater())) { PhysicsTurningType turn=physics->getTurning(); Real offset_u; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp index 83945bf5f38..d2eca14b9d9 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp @@ -537,19 +537,33 @@ void W3DTankTruckDraw::doDrawModule(const Matrix3D* transformMtx) if (physics == NULL) return; + // skip wheel animations - if over water + bool overWater = false; + if (obj->isKindOf(KINDOF_NO_MOVE_EFFECTS_ON_WATER) && obj->isOverWater() && !obj->isSignificantlyAboveTerrainOrWater()) { + overWater = true; + // we need to zero all wheel offsets + + } + const Coord3D *vel = physics->getVelocity(); Real speed = physics->getVelocityMagnitude(); const TWheelInfo *wheelInfo = getDrawable()->getWheelInfo(); // note, can return null! if (wheelInfo && (m_frontLeftTireBone || m_rearLeftTireBone)) { - const Real rotationFactor = getW3DTankTruckDrawModuleData()->m_rotationSpeedMultiplier; - const Real powerslideRotationAddition = getW3DTankTruckDrawModuleData()->m_powerslideRotationAddition * m_isPowersliding; + if (!overWater) { + const Real rotationFactor = getW3DTankTruckDrawModuleData()->m_rotationSpeedMultiplier; + const Real powerslideRotationAddition = getW3DTankTruckDrawModuleData()->m_powerslideRotationAddition * m_isPowersliding; + + m_frontWheelRotation += rotationFactor * speed; + m_rearWheelRotation += rotationFactor * (speed + powerslideRotationAddition); + m_frontWheelRotation = WWMath::Normalize_Angle(m_frontWheelRotation); + m_rearWheelRotation = WWMath::Normalize_Angle(m_rearWheelRotation); + } - m_frontWheelRotation += rotationFactor*speed; - m_rearWheelRotation += rotationFactor*(speed+powerslideRotationAddition); - m_frontWheelRotation = WWMath::Normalize_Angle(m_frontWheelRotation); - m_rearWheelRotation = WWMath::Normalize_Angle(m_rearWheelRotation); + // For now, just use the same values for mid wheels -- may want to do independent calcs later... + m_midFrontWheelRotation = m_frontWheelRotation; + m_midRearWheelRotation = m_rearWheelRotation; Matrix3D wheelXfrm(1); if (m_frontLeftTireBone) @@ -707,7 +721,7 @@ void W3DTankTruckDraw::doDrawModule(const Matrix3D* transformMtx) m_treadDebrisRight->setBurstCountMultiplier( velMult.z ); #endif //Update movement of treads - if (m_treadCount) + if (m_treadCount && !(obj->isKindOf(KINDOF_NO_MOVE_EFFECTS_ON_WATER) && obj->isOverWater())) { Real offset_u; Real treadScrollSpeed=getW3DTankTruckDrawModuleData()->m_treadAnimationRate; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp index 49625d66289..c7a4f583aa8 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp @@ -416,11 +416,20 @@ void W3DTruckDraw::doDrawModule(const Matrix3D* transformMtx) if (physics == NULL) return; + // skip wheel animations - if over water + bool overWater = false; + if (obj->isKindOf(KINDOF_NO_MOVE_EFFECTS_ON_WATER) && obj->isOverWater() && !obj->isSignificantlyAboveTerrainOrWater()) { + overWater = true; + // we need to zero all wheel offsets + + } + const Coord3D *vel = physics->getVelocity(); Real speed = physics->getVelocityMagnitude(); const TWheelInfo *wheelInfo = getDrawable()->getWheelInfo(); // note, can return null! AIUpdateInterface *ai = obj->getAI(); + if (m_cabBone && wheelInfo) { Matrix3D cabXfrm(1); cabXfrm.Make_Identity(); @@ -463,31 +472,34 @@ void W3DTruckDraw::doDrawModule(const Matrix3D* transformMtx) if (m_frontLeftTireBone || m_rearLeftTireBone) { - const Real rotationFactor = moduleData->m_rotationSpeedMultiplier; - Real powerslideRotationAddition = moduleData->m_powerslideRotationAddition * m_isPowersliding; - - if (ai) { - Locomotor *loco = ai->getCurLocomotor(); - if (loco) { - if (loco->isMovingBackwards()) { - speed = -speed; // rotate wheels backwards. jba. - powerslideRotationAddition = -powerslideRotationAddition; + + if (!overWater) { + + const Real rotationFactor = moduleData->m_rotationSpeedMultiplier; + Real powerslideRotationAddition = moduleData->m_powerslideRotationAddition * m_isPowersliding; + + if (ai) { + Locomotor* loco = ai->getCurLocomotor(); + if (loco) { + if (loco->isMovingBackwards()) { + speed = -speed; // rotate wheels backwards. jba. + powerslideRotationAddition = -powerslideRotationAddition; + } } } - } - m_frontWheelRotation += rotationFactor*speed; - m_rearWheelRotation += rotationFactor*(speed + powerslideRotationAddition); - m_frontWheelRotation = WWMath::Normalize_Angle(m_frontWheelRotation); - m_rearWheelRotation = WWMath::Normalize_Angle(m_rearWheelRotation); + m_frontWheelRotation += rotationFactor * speed; + m_rearWheelRotation += rotationFactor * (speed + powerslideRotationAddition); + m_frontWheelRotation = WWMath::Normalize_Angle(m_frontWheelRotation); + m_rearWheelRotation = WWMath::Normalize_Angle(m_rearWheelRotation); + } // For now, just use the same values for mid wheels -- may want to do independent calcs later... m_midFrontWheelRotation = m_frontWheelRotation; m_midRearWheelRotation = m_rearWheelRotation; - Matrix3D wheelXfrm(1); - + Matrix3D wheelXfrm(1); if (m_frontLeftTireBone && wheelInfo) {