diff --git a/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h b/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h index 9c472d5df65..ef816463902 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/KindOf.h @@ -172,6 +172,12 @@ enum KindOfType CPP_11(: Int) KINDOF_IGNORE_DOCKING_BONES, ///< Structure will not look up docking bones. Patch 1.03 hack. // NEW KINDOFs + KINDOF_CAN_RETALIATE, ///< Required for Drones to override hardcoded retaliate behavior + + KINDOF_NO_BATTLE_PLAN, ///< No implicit logic, but can be used for BattlePlan ValidKindof lists + + KINDOF_ENABLE_INFANTRY_LIGHTING, ///< Enable infantry-style ambient lighting for this object + KINDOF_DISABLE_INFANTRY_LIGHTING, ///< Use regular lighting on this infantry object KINDOF_VTOL, KINDOF_LARGE_AIRCRAFT, @@ -203,6 +209,8 @@ enum KindOfType CPP_11(: Int) KINDOF_EXTRA14, KINDOF_EXTRA15, KINDOF_EXTRA16, + KINDOF_EXTRA17, + KINDOF_EXTRA18, KINDOF_COUNT // total number of kindofs diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BattlePlanBonusBehavior.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BattlePlanBonusBehavior.h index 12cd2d0d45b..2d4e5f67f1d 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BattlePlanBonusBehavior.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BattlePlanBonusBehavior.h @@ -52,7 +52,7 @@ class BattlePlanBonusBehaviorModuleData : public BehaviorModuleData public: UpgradeMuxData m_upgradeMuxData; - Bool m_initiallyActive; // Apply upgrade immediately (Does this make sense?) + Bool m_initiallyActive; // Apply upgrade immediately Bool m_overrideGlobal; // Do not apply effects from global BattlePlan bonus Bool m_shouldParalyze; // Paralyze this unit when applying BattlePlans diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ExperienceScalarUpgrade.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ExperienceScalarUpgrade.h index 945677ef273..12148a6a779 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ExperienceScalarUpgrade.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ExperienceScalarUpgrade.h @@ -49,6 +49,7 @@ class ExperienceScalarUpgradeModuleData: public UpgradeModuleData static void buildFieldParse(MultiIniFieldParse& p); + Bool m_initiallyActive; // Apply upgrade immediately Real m_addXPScalar; ///< Additive bonus to scalar for XP this unit gains Real m_addXPValueScalar; ///< Additive bonus to scalar for XP this unit gives when killed diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h index ff6fad61079..d498742f854 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h @@ -459,6 +459,8 @@ class WeaponTemplate : public MemoryPoolObject inline const AudioEventRTS& getFireSound() const { return m_fireSound; } inline UnsignedInt getFireSoundLoopTime() const { return m_fireSoundLoopTime; } inline UnsignedInt getContinuousLaserLoopTime() const { return m_continuousLaserLoopTime; } + inline Real getLaserGroundUnitTargetHeight() const { return m_laserGroundUnitTargetHeight; } + inline Real getLaserGroundTargetHeight() const { return m_laserGroundTargetHeight; } inline UnsignedInt getScatterTargetResetTime() const { return m_scatterTargetResetTime; } inline const std::vector& getScatterTargetsVector() const { return m_scatterTargets; } inline const WeaponBonusSet* getExtraBonus() const { return m_extraBonus; } @@ -588,6 +590,9 @@ class WeaponTemplate : public MemoryPoolObject UnsignedInt m_continuousLaserLoopTime; ///< time between shots the continuos laser object is kept alive instead of creating a new one + Real m_laserGroundTargetHeight; ///< when targeting the ground with a laser weapon, aim this much above + Real m_laserGroundUnitTargetHeight; ///< when targeting ground units with a laser weapon, aim this much above + Bool m_scatterTargetAligned; ///< if the scatter target pattern is aligned to the shooter Bool m_scatterTargetRandom; ///< if the scatter target pattern is fired in a random order Bool m_scatterTargetRandomAngle; ///< if the scatter target pattern is randomly aligned diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp index c4758a31e8b..e48e5ce0952 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/KindOf.cpp @@ -158,6 +158,12 @@ const char* KindOfMaskType::s_bitNameList[] = "DEMOTRAP", "CONSERVATIVE_BUILDING", "IGNORE_DOCKING_BONES", + "CAN_RETALIATE", + + "NO_BATTLE_PLAN", + + "ENABLE_INFANTRY_LIGHTING", + "DISABLE_INFANTRY_LIGHTING", "VTOL", "LARGE_AIRCRAFT", @@ -189,6 +195,8 @@ const char* KindOfMaskType::s_bitNameList[] = "EXTRA14", "EXTRA15", "EXTRA16", + "EXTRA17", + "EXTRA18", NULL }; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Body/ActiveBody.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Body/ActiveBody.cpp index cb55e14007d..ec08e9d2f1c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Body/ActiveBody.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Body/ActiveBody.cpp @@ -810,8 +810,8 @@ Bool ActiveBody::shouldRetaliate(Object *obj) if (obj->isKindOf( KINDOF_IMMOBILE )) { return false; } - // Drones never retaliate. [8/25/2003] - if (obj->isKindOf(KINDOF_DRONE)) { + // Drones never retaliate [8/25/2003] except when they do [2025/09/07] + if (obj->isKindOf(KINDOF_DRONE) && !obj->isKindOf(KINDOF_CAN_RETALIATE)) { return false; } // Any unit that isn't idle won't retaliate. [8/25/2003] diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Upgrade/ExperienceScalarUpgrade.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Upgrade/ExperienceScalarUpgrade.cpp index 7368ae3672d..7820f2fbff2 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Upgrade/ExperienceScalarUpgrade.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Upgrade/ExperienceScalarUpgrade.cpp @@ -39,6 +39,7 @@ //------------------------------------------------------------------------------------------------- ExperienceScalarUpgradeModuleData::ExperienceScalarUpgradeModuleData( void ) { + m_initiallyActive = false; m_addXPScalar = 0.0f; m_addXPValueScalar = 0.0f; } @@ -52,6 +53,7 @@ void ExperienceScalarUpgradeModuleData::buildFieldParse(MultiIniFieldParse& p) static const FieldParse dataFieldParse[] = { + { "StartsActive", INI::parseBool, NULL, offsetof(ExperienceScalarUpgradeModuleData, m_initiallyActive) }, { "AddXPScalar", INI::parseReal, NULL, offsetof( ExperienceScalarUpgradeModuleData, m_addXPScalar ) }, { "AddXPValueScalar", INI::parseReal, NULL, offsetof( ExperienceScalarUpgradeModuleData, m_addXPValueScalar ) }, { 0, 0, 0, 0 } @@ -65,6 +67,10 @@ void ExperienceScalarUpgradeModuleData::buildFieldParse(MultiIniFieldParse& p) //------------------------------------------------------------------------------------------------- ExperienceScalarUpgrade::ExperienceScalarUpgrade( Thing *thing, const ModuleData* moduleData ) : UpgradeModule( thing, moduleData ) { + if (getExperienceScalarUpgradeModuleData()->m_initiallyActive) + { + giveSelfUpgrade(); + } } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp index 11c4175d2fa..0ab0faf5797 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp @@ -249,6 +249,8 @@ const FieldParse WeaponTemplate::TheWeaponTemplateFieldParseTable[] = { "VeterancyPreAttackFX", parsePerVetLevelFXList, NULL, offsetof(WeaponTemplate, m_preAttackFXs) }, { "PreAttackFXDelay", INI::parseDurationUnsignedInt, NULL, offsetof(WeaponTemplate, m_preAttackFXDelay) }, { "ContinuousLaserLoopTime", INI::parseDurationUnsignedInt, NULL, offsetof(WeaponTemplate, m_continuousLaserLoopTime) }, + { "LaserGroundTargetHeight", INI::parseReal, NULL, offsetof(WeaponTemplate, m_laserGroundTargetHeight) }, + { "LaserGroundUnitTargetHeight", INI::parseReal, NULL, offsetof(WeaponTemplate, m_laserGroundUnitTargetHeight) }, { NULL, NULL, NULL, 0 } // keep this last }; @@ -341,6 +343,7 @@ WeaponTemplate::WeaponTemplate() : m_nextTemplate(NULL) m_scatterTargetCenteredAtShooter = FALSE; m_scatterTargetResetTime = 0; m_preAttackFXDelay = 6; // Non-Zero default! 6 frames = 200ms. This should be a good base value to avoid spamming + m_laserGroundUnitTargetHeight = 10; // Default Height offset } //------------------------------------------------------------------------------------------------- @@ -1066,11 +1069,16 @@ UnsignedInt WeaponTemplate::fireWeaponTemplate // Handle Detonation OCL Coord3D targetPos; // We need a better position to match the visual laser; targetPos.set(&projectileDestination); - if (victimObj && !victimObj->isKindOf(KINDOF_PROJECTILE) && !victimObj->isAirborneTarget()) - { - //Targets are positioned on the ground, so raise the beam up so we're not shooting their feet. - //Projectiles are a different story, target their exact position. - targetPos.z += 10.0f; + + if (victimObj) { + if (!victimObj->isKindOf(KINDOF_PROJECTILE) && !victimObj->isAirborneTarget()) { + //Targets are positioned on the ground, so raise the beam up so we're not shooting their feet. + //Projectiles are a different story, target their exact position. + targetPos.z += m_laserGroundUnitTargetHeight; + } + } + else { // We target the ground + targetPos.z += m_laserGroundTargetHeight; } VeterancyLevel vet = sourceObj->getVeterancyLevel(); @@ -2592,11 +2600,15 @@ ObjectID Weapon::createLaser( const Object *sourceObj, const Object *victimObj, if( update ) { Coord3D pos = *victimPos; - if( victimObj && !victimObj->isKindOf( KINDOF_PROJECTILE ) && !victimObj->isAirborneTarget() ) - { - //Targets are positioned on the ground, so raise the beam up so we're not shooting their feet. - //Projectiles are a different story, target their exact position. - pos.z += 10.0f; + if( victimObj) { + if (!victimObj->isKindOf(KINDOF_PROJECTILE) && !victimObj->isAirborneTarget()) { + //Targets are positioned on the ground, so raise the beam up so we're not shooting their feet. + //Projectiles are a different story, target their exact position. + pos.z += getTemplate()->getLaserGroundUnitTargetHeight(); + } + } + else { // We target the ground + pos.z += getTemplate()->getLaserGroundTargetHeight(); } update->initLaser( sourceObj, victimObj, sourceObj->getPosition(), &pos, m_template->getLaserBoneName() ); } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp index 4d5249b4873..fa796ae2e2d 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp @@ -651,7 +651,8 @@ void RTS3DScene::renderOneObject(RenderInfoClass &rinfo, RenderObjClass *robj, I } } - if (draw->isKindOf(KINDOF_INFANTRY)) + if ((draw->isKindOf(KINDOF_INFANTRY) && !draw->isKindOf(KINDOF_DISABLE_INFANTRY_LIGHTING)) || + draw->isKindOf(KINDOF_ENABLE_INFANTRY_LIGHTING)) { //ambient = m_infantryAmbient; //has no effect - see comment on m_infantryAmbient sceneLights = m_infantryLight; }