Skip to content

Commit 83875fd

Browse files
committed
2 parents c52765d + 10b5539 commit 83875fd

File tree

3 files changed

+157
-30
lines changed

3 files changed

+157
-30
lines changed

GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,10 @@ class WeaponStore : public SubsystemInterface
14401440
std::vector<WeaponTemplate*> m_weaponTemplateVector;
14411441
WeaponTemplateMap m_weaponTemplateHashMap;
14421442
std::list<WeaponDelayedDamageInfo> m_weaponDDI;
1443+
#define DEBUG_PRINT_WEAPON_USAGE 0 ///< activate this to print unused weapons into the debug log
1444+
#if DEBUG_PRINT_WEAPON_USAGE
1445+
mutable std::unordered_map<NameKeyType, UnsignedInt> m_weaponUseCounter;
1446+
#endif
14431447
};
14441448

14451449
// EXTERNALS //////////////////////////////////////////////////////////////////////////////////////

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/MissileAIUpdate.cpp

Lines changed: 131 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,16 @@ void MissileAIUpdate::projectileLaunchAtObjectOrPosition(
270270

271271
#define APPROACH_HEIGHT 10.0f
272272

273+
static Real getTorpedoTargetHeight(const Coord3D & pos, Locomotor* loco) {
274+
Real waterZ{ 0 };
275+
Real ret = pos.z;
276+
bool underwater = TheTerrainLogic && TheTerrainLogic->isUnderwater(pos.x, pos.y, &waterZ);
277+
if (underwater && loco) {
278+
ret= waterZ + loco->getPreferredHeight();
279+
}
280+
return ret;
281+
}
282+
273283
//-------------------------------------------------------------------------------------------------
274284
// The actual firing of the missile once setup.
275285
//-------------------------------------------------------------------------------------------------
@@ -351,12 +361,23 @@ void MissileAIUpdate::projectileFireAtObjectOrPosition( const Object *victim, co
351361
// instead of Attacking the target.
352362
if (victim && d->m_tryToFollowTarget && (!TheGlobalData->m_dynamicTargeting || !victim->isKindOf(KINDOF_STRUCTURE)))
353363
{
354-
getStateMachine()->setGoalPosition(victim->getPosition());
364+
Coord3D targetPos = *victim->getPosition();
365+
if (d->m_isTorpedo) {
366+
Locomotor* loco = getCurLocomotor();
367+
if (loco) {
368+
targetPos.z = getTorpedoTargetHeight(targetPos, loco);
369+
}
370+
}
371+
getStateMachine()->setGoalPosition(&targetPos);
355372
// ick. const-cast is evil. fix. (srj)
356-
//aiMoveToObject(const_cast<Object*>(victim), CMD_FROM_AI );
357-
/// IamInnocent - Edited... I'm gonna get fired but I'm unemployed.
358-
aiMoveToObject(TheGameLogic->findObjectByID( victim->getID() ), CMD_FROM_AI );
359-
m_originalTargetPos = *victim->getPosition();
373+
if (!d->m_isTorpedo) {
374+
/// IamInnocent - Edited... I'm gonna get fired but I'm unemployed.
375+
aiMoveToObject(TheGameLogic->findObjectByID( victim->getID() ), CMD_FROM_AI );
376+
}
377+
else {
378+
aiMoveToPosition(&targetPos, CMD_FROM_AI);
379+
}
380+
m_originalTargetPos = targetPos;
360381
m_isTrackingTarget = TRUE;// Remember that I was originally shot at a moving object, so if the
361382
// target dies I can do something cool.
362383
m_victimID = victim->getID();
@@ -639,10 +660,24 @@ void MissileAIUpdate::doAttackState(Bool turnOK, Bool randomPath)
639660
{
640661
DEBUG_LOG((">>> MissileAI - EndRandomPath: victim is not null.\n"));
641662

642-
getStateMachine()->setGoalPosition(victim->getPosition());
663+
Coord3D targetPos = *victim->getPosition();
664+
if (d->m_isTorpedo) {
665+
Locomotor* curLoco = getCurLocomotor();
666+
if (curLoco)
667+
{
668+
targetPos.z = getTorpedoTargetHeight(targetPos, curLoco);
669+
}
670+
}
671+
672+
getStateMachine()->setGoalPosition(&targetPos);
643673
getStateMachine()->setGoalObject(victim);
644-
aiMoveToObject(victim, CMD_FROM_AI);
645-
m_originalTargetPos = *victim->getPosition();
674+
if (!d->m_isTorpedo) {
675+
aiMoveToObject(victim, CMD_FROM_AI);
676+
}
677+
else {
678+
aiMoveToPosition(&targetPos, CMD_FROM_AI);
679+
}
680+
m_originalTargetPos = targetPos;
646681
m_isTrackingTarget = TRUE;// Remember that I was originally shot at a moving object, so if the
647682
// target dies I can do something cool.
648683
m_victimID = victim->getID();
@@ -704,7 +739,7 @@ void MissileAIUpdate::doAttackState(Bool turnOK, Bool randomPath)
704739
}
705740
}
706741

707-
if(curLoco && (curLoco->getPreferredHeight() > 0 || curLoco->getPreferredHeight() < 0) )
742+
if(curLoco && (curLoco->getPreferredHeight() > 0)) // || curLoco->getPreferredHeight() < 0) )
708743
{
709744
// Am I close enough to the target to ignore my preferred height setting?
710745
Real distanceToTargetSquared = ThePartitionManager->getDistanceSquared( getObject(), getGoalPosition(), FROM_CENTER_2D );
@@ -766,10 +801,19 @@ void MissileAIUpdate::doAttackState(Bool turnOK, Bool randomPath)
766801

767802
targetPos.add(&offset);
768803

769-
// Make sure Z is above ground
770-
PathfindLayerEnum layer = TheTerrainLogic->getHighestLayerForDestination(&targetPos);
771-
Real minHeight = TheTerrainLogic->getLayerHeight(targetPos.x, targetPos.y, layer) + APPROACH_HEIGHT;
772-
targetPos.z = __max(targetPos.z, minHeight);
804+
if (!d->m_isTorpedo) {
805+
// Make sure Z is above ground
806+
PathfindLayerEnum layer = TheTerrainLogic->getHighestLayerForDestination(&targetPos);
807+
Real minHeight = TheTerrainLogic->getLayerHeight(targetPos.x, targetPos.y, layer) + APPROACH_HEIGHT;
808+
targetPos.z = __max(targetPos.z, minHeight);
809+
}
810+
else {
811+
Locomotor* curLoco = getCurLocomotor();
812+
if (curLoco)
813+
{
814+
targetPos.z = getTorpedoTargetHeight(targetPos, curLoco);
815+
}
816+
}
773817

774818
getStateMachine()->setGoalPosition(&targetPos);
775819
getStateMachine()->setGoalObject(NULL);
@@ -797,20 +841,24 @@ void MissileAIUpdate::doAttackState(Bool turnOK, Bool randomPath)
797841

798842
// If I was fired at a flyer and have lost target (most likely they died), then I need to do something better
799843
// than cloverleaf around their last spot.
800-
if( m_isTrackingTarget && (getGoalObject() == NULL) )
844+
if( m_isTrackingTarget && (getGoalObject() == NULL) && !d->m_isTorpedo)
845+
airborneTargetGone();
846+
847+
if (m_isTrackingTarget && (getGoalPosition() == NULL) && d->m_isTorpedo)
801848
airborneTargetGone();
802849
}
803850

804851
//-------------------------------------------------------------------------------------------------
805852
void MissileAIUpdate::doKillState(void)
806853
{
807-
if( m_fuelExpirationDate && getMissileAIUpdateModuleData()->m_fuelLifetime && m_fuelExpirationDate >= TheGameLogic->getFrame() && ( !m_nextWakeUpTime || m_nextWakeUpTime > m_fuelExpirationDate ))
854+
const MissileAIUpdateModuleData* d = getMissileAIUpdateModuleData();
855+
if( m_fuelExpirationDate && d->m_fuelLifetime && m_fuelExpirationDate >= TheGameLogic->getFrame() && ( !m_nextWakeUpTime || m_nextWakeUpTime > m_fuelExpirationDate ))
808856
{
809857
m_nextWakeUpTime = m_fuelExpirationDate;
810858
}
811859
if (TheGameLogic->getFrame() >= m_fuelExpirationDate)
812860
{
813-
if( getMissileAIUpdateModuleData()->m_detonateOnNoFuel )
861+
if( d->m_detonateOnNoFuel )
814862
{
815863
detonate();
816864
return;
@@ -840,29 +888,53 @@ void MissileAIUpdate::doKillState(void)
840888
}
841889
if (isIdle()) {
842890
// we finished the move
843-
if (getGoalObject()!=NULL) {
891+
if (getGoalObject() != NULL) {
844892
Locomotor* curLoco = getCurLocomotor();
845893
Real closeEnough = 1.0f;
846894
if (curLoco)
847895
{
848896
closeEnough = curLoco->getMaxSpeedForCondition(BODY_PRISTINE);
849897
}
850-
Real distanceToTargetSq = ThePartitionManager->getDistanceSquared( getObject(), getGoalObject(), FROM_BOUNDINGSPHERE_3D);
898+
Real distanceToTargetSq = ThePartitionManager->getDistanceSquared(getObject(), getGoalObject(), FROM_BOUNDINGSPHERE_3D);
851899
// DEBUG_LOG((">>> MissileAI KILL (Idle) - Distance to target %f, closeEnough %f\n", sqrt(distanceToTargetSq), closeEnough));
852-
if (distanceToTargetSq < closeEnough*closeEnough) {
900+
if (distanceToTargetSq < closeEnough * closeEnough) {
853901
Coord3D pos = *getGoalObject()->getPosition();
854902
getObject()->setPosition(&pos);
855903
detonate();
856-
} else{
857-
aiMoveToObject(getGoalObject(), CMD_FROM_AI );
858904
}
859-
} else {
905+
else {
906+
aiMoveToObject(getGoalObject(), CMD_FROM_AI);
907+
}
908+
}
909+
else if (d->m_isTorpedo && getGoalPosition() != nullptr)
910+
{
911+
Locomotor* curLoco = getCurLocomotor();
912+
Real closeEnough = 1.0f;
913+
if (curLoco)
914+
{
915+
closeEnough = curLoco->getMaxSpeedForCondition(BODY_PRISTINE);
916+
}
917+
Real distanceToTargetSq = ThePartitionManager->getDistanceSquared(getObject(), getGoalPosition(), FROM_BOUNDINGSPHERE_2D);
918+
if (distanceToTargetSq < closeEnough * closeEnough) {
919+
Coord3D pos = *getGoalPosition();
920+
pos.z = getTorpedoTargetHeight(pos, curLoco);
921+
getObject()->setPosition(&pos);
922+
detonate();
923+
}
924+
else {
925+
aiMoveToObject(getGoalObject(), CMD_FROM_AI);
926+
}
927+
}
928+
else {
860929
detonate();
861930
}
862931
}
863932
// If I was fired at a flyer and have lost target (most likely they died), then I need to do something better
864933
// than cloverleaf around their last spot.
865-
if( m_isTrackingTarget && (getGoalObject() == NULL) )
934+
if( m_isTrackingTarget && (getGoalObject() == NULL) && !d->m_isTorpedo)
935+
airborneTargetGone();
936+
937+
if (m_isTrackingTarget && (getGoalPosition() == nullptr) && d->m_isTorpedo)
866938
airborneTargetGone();
867939
}
868940

@@ -895,6 +967,8 @@ UpdateSleepTime MissileAIUpdate::update()
895967
m_nextWakeUpTime = 1;
896968
}
897969

970+
const MissileAIUpdateModuleData* d = getMissileAIUpdateModuleData();
971+
898972
//If this missile has been marked to divert to countermeasures, check when
899973
//that will occur, then do it when the timer expires.
900974
if( m_framesTillDecoyed && m_framesTillDecoyed <= TheGameLogic->getFrame() )
@@ -964,9 +1038,22 @@ UpdateSleepTime MissileAIUpdate::update()
9641038
if( targetID != INVALID_ID )
9651039
{
9661040
victim = TheGameLogic->findObjectByID( targetID );
967-
getStateMachine()->setGoalPosition(victim->getPosition());
968-
aiMoveToObject(victim, CMD_FROM_AI );
969-
m_originalTargetPos = *victim->getPosition();
1041+
Coord3D targetPos = *victim->getPosition();
1042+
if (d->m_isTorpedo) {
1043+
Locomotor* curLoco = getCurLocomotor();
1044+
if (curLoco)
1045+
{
1046+
targetPos.z = getTorpedoTargetHeight(targetPos, curLoco);
1047+
}
1048+
}
1049+
getStateMachine()->setGoalPosition(&targetPos);
1050+
if (!d->m_isTorpedo) {
1051+
aiMoveToObject(victim, CMD_FROM_AI );
1052+
}
1053+
else {
1054+
aiMoveToPosition(&targetPos, CMD_FROM_AI);
1055+
}
1056+
m_originalTargetPos = targetPos;
9701057
m_isTrackingTarget = TRUE;// Remember that I was originally shot at a moving object, so if the
9711058
// target dies I can do something cool.
9721059
m_victimID = victim->getID();
@@ -984,11 +1071,28 @@ UpdateSleepTime MissileAIUpdate::update()
9841071
}
9851072

9861073
// If treated as torpedo, explode when not over water
987-
const MissileAIUpdateModuleData* d = getMissileAIUpdateModuleData();
9881074
if (d->m_isTorpedo && !getObject()->isOverWater()) {
9891075
detonate();
9901076
}
9911077

1078+
// If torpedo, update target location
1079+
if (d->m_isTorpedo && m_isTrackingTarget) {
1080+
Object * targetUnit = TheGameLogic->findObjectByID(m_victimID);
1081+
if (targetUnit != nullptr && !targetUnit->isEffectivelyDead()) {
1082+
Coord3D targetPos = *targetUnit->getPosition();
1083+
Locomotor* curLoco = getCurLocomotor();
1084+
if (curLoco)
1085+
{
1086+
targetPos.z = getTorpedoTargetHeight(targetPos, curLoco);
1087+
}
1088+
getStateMachine()->setGoalPosition(&targetPos);
1089+
getStateMachine()->setGoalObject(targetUnit);
1090+
aiMoveToPosition(&targetPos, CMD_FROM_AI);
1091+
m_originalTargetPos = targetPos;
1092+
m_isTrackingTarget = true;
1093+
}
1094+
}
1095+
9921096
switch( m_state )
9931097
{
9941098
case PRELAUNCH:

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3210,6 +3210,9 @@ WeaponStore::~WeaponStore()
32103210
deleteInstance(wt);
32113211
}
32123212
m_weaponTemplateHashMap.clear();
3213+
#if DEBUG_PRINT_WEAPON_USAGE
3214+
m_weaponUseCounter.clear();
3215+
#endif
32133216
}
32143217

32153218
//-------------------------------------------------------------------------------------------------
@@ -3291,12 +3294,14 @@ const WeaponTemplate *WeaponStore::findWeaponTemplate( const char* name ) const
32913294
WeaponTemplate *WeaponStore::findWeaponTemplatePrivate( NameKeyType key ) const
32923295
{
32933296
// search weapon list for name
3294-
/*for (size_t i = 0; i < m_weaponTemplateVector.size(); i++)
3295-
if( m_weaponTemplateVector[ i ]->getNameKey() == key )
3296-
return m_weaponTemplateVector[i];*/
32973297
WeaponTemplateMap::const_iterator it = m_weaponTemplateHashMap.find(key);
32983298
if(it != m_weaponTemplateHashMap.end())
3299+
{
3300+
#if DEBUG_PRINT_WEAPON_USAGE
3301+
m_weaponUseCounter[key]++;
3302+
#endif
32993303
return it->second;
3304+
}
33003305

33013306
return NULL;
33023307

@@ -3368,6 +3373,9 @@ void WeaponStore::resetWeaponTemplates( void )
33683373
{
33693374
WeaponTemplate* wt = m_weaponTemplateVector[i];
33703375
wt->reset();
3376+
#if DEBUG_PRINT_WEAPON_USAGE
3377+
m_weaponUseCounter.clear();
3378+
#endif
33713379
}
33723380
for (WeaponTemplateMap::iterator it = m_weaponTemplateHashMap.begin(); it != m_weaponTemplateHashMap.end(); ++it)
33733381
{
@@ -3441,6 +3449,17 @@ void WeaponStore::postProcessLoad()
34413449
wt->postProcessLoad();
34423450
}
34433451

3452+
#if DEBUG_PRINT_WEAPON_USAGE
3453+
// look for unused weapons
3454+
for (size_t i = 0; i < m_weaponTemplateVector.size(); i++)
3455+
{
3456+
WeaponTemplate* wt = m_weaponTemplateVector[i];
3457+
if (m_weaponUseCounter[wt->getNameKey()] <= 0) {
3458+
DEBUG_LOG(("Unused WeaponTemplate: '%s'", wt->getName().str()));
3459+
}
3460+
}
3461+
#endif
3462+
34443463
}
34453464

34463465
//-------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)