diff --git a/GameSettings.cpp b/GameSettings.cpp index 185cca9c..628e1df8 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -720,6 +720,9 @@ void LoadGameExternalOptions() // see Tactical\Weapons.cpp funtion CalcNewChanceToHitGun() gGameExternalOptions.fUseNewCTHCalculation = iniReader.ReadBoolean("System Limit Settings", "USE_NEW_CTH_CALCULATION", TRUE); + // Flugente: this change allows to target head/torso/legs of prone targets. This option will be removed once accepted + gGameExternalOptions.fAllowTargetHeadAndLegIfProne = iniReader.ReadBoolean( "System Limit Settings", "ALLOW_TARGET_HEADANDLEG_IFPRONE", TRUE ); + //################# Data File Settings ################# // WANNE: Always use prof.dat?? @@ -1682,9 +1685,7 @@ void LoadGameExternalOptions() gGameExternalOptions.dHearingReduction[WEATHER_FORECAST_THUNDERSHOWERS] = iniReader.ReadDouble( "Tactical Weather Settings", "HEARING_REDUCTION_THUNDERSTORM", 0.8f, 0.0f, 1.0f ); gGameExternalOptions.dHearingReduction[WEATHER_FORECAST_SANDSTORM] = iniReader.ReadDouble( "Tactical Weather Settings", "HEARING_REDUCTION_SANDSTORM", 0.6f, 0.0f, 1.0f ); gGameExternalOptions.dHearingReduction[WEATHER_FORECAST_SNOW] = iniReader.ReadDouble( "Tactical Weather Settings", "HEARING_REDUCTION_SNOW", 0.1f, 0.0f, 1.0f ); - - FLOAT dHearingReduction[WEATHER_FORECAST_MAX]; - + //################# Tactical Weapon Overheating Settings ################## // Flugente: These settings control the behavior of Weapon Overheating, its severity, and its display. gGameExternalOptions.fWeaponOverheating = iniReader.ReadBoolean("Tactical Weapon Overheating Settings","OVERHEATING",FALSE); diff --git a/GameSettings.h b/GameSettings.h index 09e28866..532b9731 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -542,6 +542,9 @@ typedef struct // see Tactical\Weapons.cpp funtion CalcNewChanceToHitGun() BOOLEAN fUseNewCTHCalculation; + // Flugente: this change allows to target head/torso/legs of prone targets. This option will be removed once accepted + BOOLEAN fAllowTargetHeadAndLegIfProne; + //Sight range UINT32 ubStraightSightRange; diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index df87589c..2969847e 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -2714,7 +2714,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend { // Flugente: kids are smaller. We have to keep hat in mind... otherwise we will never make a sucessful headshot BOOLEAN iskid = ( pTarget->ubBodyType == HATKIDCIV || pTarget->ubBodyType == KIDCIV ); - + switch (gAnimControl[ pTarget->usAnimState ].ubEndHeight) { case ANIM_STAND: @@ -2800,7 +2800,58 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend } break; case ANIM_PRONE: - ubHitLocation = AIM_SHOT_TORSO; + { + if ( gGameExternalOptions.fAllowTargetHeadAndLegIfProne ) + { + FLOAT x = (FLOAT)FIXEDPT_TO_INT32( pBullet->qCurrX + FloatToFixed( 0.5f ) ); // + 0.5); + FLOAT y = (FLOAT)FIXEDPT_TO_INT32( pBullet->qCurrY + FloatToFixed( 0.5f ) ); // (dCurrY + 0.5); + + // Flugente: we measure the distance of the bullet's location to the location of the soldier, and to the 2 gridnos his head and leg occupy + // From this we can decide what body part was hit + FLOAT bodycenterX = (FLOAT)CenterX( pTarget->sGridNo ); + FLOAT bodycenterY = (FLOAT)CenterY( pTarget->sGridNo ); + + FLOAT difftobodycenter = std::sqrt( (bodycenterX - x) * (bodycenterX - x) + (bodycenterY - y) * (bodycenterY - y) ); + + INT32 viewdirectiongridno = NewGridNo( pTarget->sGridNo, DirectionInc( pTarget->ubDirection ) ); + FLOAT nextgridnocenterX = (FLOAT)CenterX( viewdirectiongridno ); + FLOAT nextgridnocenterY = (FLOAT)CenterY( viewdirectiongridno ); + + FLOAT difftonextgridno = std::sqrt( (nextgridnocenterX - x) * (nextgridnocenterX - x) + (nextgridnocenterY - y) * (nextgridnocenterY - y) ); + + INT32 oppositeviewdirectiongridno = NewGridNo( pTarget->sGridNo, DirectionInc( gOppositeDirection[pTarget->ubDirection] ) ); + FLOAT oppositenextgridnocenterX = (FLOAT)CenterX( oppositeviewdirectiongridno ); + FLOAT oppositenextgridnocenterY = (FLOAT)CenterY( oppositeviewdirectiongridno ); + + FLOAT difftooppositenextgridno = std::sqrt( (oppositenextgridnocenterX - x) * (oppositenextgridnocenterX - x) + (oppositenextgridnocenterY - y) * (oppositenextgridnocenterY - y) ); + + if ( difftobodycenter < difftonextgridno ) + { + if ( difftobodycenter < difftooppositenextgridno ) + { + ubHitLocation = AIM_SHOT_TORSO; + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Torso hit" ); + } + else + { + ubHitLocation = AIM_SHOT_LEGS; + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Leg hit" ); + } + } + else + { + ubHitLocation = AIM_SHOT_HEAD; + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Headshot" ); + } + } + else + { + ubHitLocation = AIM_SHOT_TORSO; + } + } break; } @@ -3664,7 +3715,7 @@ UINT8 CalcChanceToGetThrough( BULLET * pBullet ) // in actually moving the bullet, we consider only count friends as targets if the bullet is unaimed // (buckshot), if they are the intended target, or beyond the range of automatic friendly fire hits // OR a 1 in 30 chance occurs - if (gAnimControl[ MercPtrs[pStructure->usStructureID]->usAnimState ].ubEndHeight == ANIM_STAND && + if ( (gGameExternalOptions.fAllowTargetHeadAndLegIfProne || gAnimControl[MercPtrs[pStructure->usStructureID]->usAnimState].ubEndHeight == ANIM_STAND) && ( (pBullet->fAimed && pBullet->iLoop > MIN_DIST_FOR_HIT_FRIENDS) || (!pBullet->fAimed && pBullet->iLoop > MIN_DIST_FOR_HIT_FRIENDS_UNAIMED) ) @@ -6495,7 +6546,7 @@ void MoveBullet( INT32 iBullet ) } } else if ( MercPtrs[ pStructure->usStructureID ]->bVisible == TRUE && - gAnimControl[ MercPtrs[pStructure->usStructureID]->usAnimState ].ubEndHeight == ANIM_STAND && + (gGameExternalOptions.fAllowTargetHeadAndLegIfProne || gAnimControl[ MercPtrs[pStructure->usStructureID]->usAnimState ].ubEndHeight == ANIM_STAND ) && ( (pBullet->fAimed && pBullet->iLoop > MIN_DIST_FOR_HIT_FRIENDS) || (!pBullet->fAimed && pBullet->iLoop > MIN_DIST_FOR_HIT_FRIENDS_UNAIMED) || PreRandom( 100 ) < MIN_CHANCE_TO_ACCIDENTALLY_HIT_SOMEONE @@ -6974,7 +7025,7 @@ void MoveBullet( INT32 iBullet ) } } - else if ( pBullet->iLoop > CLOSE_TO_FIRER || (pStructure->fFlags & ALWAYS_CONSIDER_HIT) || (pBullet->iLoop > CLOSE_TO_FIRER) || (fIntended) ) + else if ( pBullet->iLoop > CLOSE_TO_FIRER || (pStructure->fFlags & ALWAYS_CONSIDER_HIT) || fIntended ) { if (pStructure->fFlags & STRUCTURE_WALLSTUFF) { @@ -7123,7 +7174,8 @@ void MoveBullet( INT32 iBullet ) uiTileInc++; // HEADROCK HAM 5: Ignore if moving a fragment. - if(UsingNewCTHSystem() && pBullet->fFragment == false ){ + if(UsingNewCTHSystem() && pBullet->fFragment == false ) + { // HEADROCK HAM 4: This is kind of a hack. I'm measuring the distance the tile has moved in 2D space, // for purposes of determining whether gravity should take effect. FLOAT dDistanceMoved = PythSpacesAway( pBullet->pFirer->sGridNo, pBullet->sGridNo ) * 10.0f; @@ -7142,7 +7194,9 @@ void MoveBullet( INT32 iBullet ) //pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * (gGameCTHConstants.GRAVITY_COEFFICIENT / 2) ); } - } else { + } + else + { if ( (pBullet->iLoop > pBullet->iRange * 2) ) { // beyond max effective range, bullet starts to drop! diff --git a/Tactical/Soldier Find.cpp b/Tactical/Soldier Find.cpp index a1e1507f..f6471a0b 100644 --- a/Tactical/Soldier Find.cpp +++ b/Tactical/Soldier Find.cpp @@ -903,7 +903,6 @@ BOOLEAN FindRelativeSoldierPosition( SOLDIERTYPE *pSoldier, UINT16 *usFlags, INT INT16 sRelX, sRelY; FLOAT dRelPer; - // Get Rect contained in the soldier GetSoldierScreenRect( pSoldier, &aRect ); @@ -952,6 +951,56 @@ BOOLEAN FindRelativeSoldierPosition( SOLDIERTYPE *pSoldier, UINT16 *usFlags, INT } break; + case ANIM_PRONE: + { + // Flugente: if we are prone, determining what part of the body we are aiming for is trickier. + // Instead of focusing on relative height, we simply determine whether we are looking at the gridno the body itself is at, or an adjacent gridno. + // Then, depending on whether this is the gridno we are looking at, this will be head or legs + if ( gGameExternalOptions.fAllowTargetHeadAndLegIfProne ) + { + INT16 sWorldX, sWorldY; + GetMouseWorldCoords( &sWorldX, &sWorldY ); + + // Flugente: we measure the distance of the bullet's location to the location of the soldier, and to the 2 gridnos his head and leg occupy + // From this we can decide what body part was hit + FLOAT bodycenterX = (FLOAT)CenterX( pSoldier->sGridNo ); + FLOAT bodycenterY = (FLOAT)CenterY( pSoldier->sGridNo ); + + FLOAT difftobodycenter = std::sqrt( (bodycenterX - sWorldX) * (bodycenterX - sWorldX) + (bodycenterY - sWorldY) * (bodycenterY - sWorldY) ); + + INT32 viewdirectiongridno = NewGridNo( pSoldier->sGridNo, DirectionInc( pSoldier->ubDirection ) ); + FLOAT nextgridnocenterX = (FLOAT)CenterX( viewdirectiongridno ); + FLOAT nextgridnocenterY = (FLOAT)CenterY( viewdirectiongridno ); + + FLOAT difftonextgridno = std::sqrt( (nextgridnocenterX - sWorldX) * (nextgridnocenterX - sWorldX) + (nextgridnocenterY - sWorldY) * (nextgridnocenterY - sWorldY) ); + + INT32 oppositeviewdirectiongridno = NewGridNo( pSoldier->sGridNo, DirectionInc( gOppositeDirection[pSoldier->ubDirection] ) ); + FLOAT oppositenextgridnocenterX = (FLOAT)CenterX( oppositeviewdirectiongridno ); + FLOAT oppositenextgridnocenterY = (FLOAT)CenterY( oppositeviewdirectiongridno ); + + FLOAT difftooppositenextgridno = std::sqrt( (oppositenextgridnocenterX - sWorldX) * (oppositenextgridnocenterX - sWorldX) + (oppositenextgridnocenterY - sWorldY) * (oppositenextgridnocenterY - sWorldY) ); + + if ( difftobodycenter < difftonextgridno ) + { + if ( difftobodycenter < difftooppositenextgridno ) + { + (*usFlags) = TILE_FLAG_MID; + return(TRUE); + } + else + { + (*usFlags) = TILE_FLAG_FEET; + return(TRUE); + } + } + else + { + (*usFlags) = TILE_FLAG_HEAD; + return(TRUE); + } + } + } + break; } } diff --git a/Tactical/Weapons.cpp b/Tactical/Weapons.cpp index da376390..6c12fb59 100644 --- a/Tactical/Weapons.cpp +++ b/Tactical/Weapons.cpp @@ -1687,13 +1687,33 @@ void GetTargetWorldPositions( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, FLOAT switch( pSoldier->bAimShotLocation ) { case AIM_SHOT_HEAD: - CalculateSoldierZPos( pTargetSoldier, HEAD_TARGET_POS, &dTargetZ ); + { + CalculateSoldierZPos( pTargetSoldier, HEAD_TARGET_POS, &dTargetZ ); + + if ( gGameExternalOptions.fAllowTargetHeadAndLegIfProne && gAnimControl[pTargetSoldier->usAnimState].ubHeight == ANIM_PRONE ) + { + INT32 viewdirectiongridno = NewGridNo( pTargetSoldier->sGridNo, DirectionInc( pTargetSoldier->ubDirection ) ); + + dTargetX = (0.3f * dTargetX + 0.7f * (FLOAT)CenterX( viewdirectiongridno )) / 1.0f; + dTargetY = (0.3f * dTargetY + 0.7f * (FLOAT)CenterY( viewdirectiongridno )) / 1.0f; + } + } break; case AIM_SHOT_TORSO: CalculateSoldierZPos( pTargetSoldier, TORSO_TARGET_POS, &dTargetZ ); break; case AIM_SHOT_LEGS: - CalculateSoldierZPos( pTargetSoldier, LEGS_TARGET_POS, &dTargetZ ); + { + CalculateSoldierZPos( pTargetSoldier, LEGS_TARGET_POS, &dTargetZ ); + + if ( gGameExternalOptions.fAllowTargetHeadAndLegIfProne && gAnimControl[pTargetSoldier->usAnimState].ubHeight == ANIM_PRONE ) + { + INT32 viewdirectiongridno = NewGridNo( pTargetSoldier->sGridNo, DirectionInc( gOppositeDirection[pTargetSoldier->ubDirection] ) ); + + dTargetX = (0.3f * dTargetX + 0.7f * (FLOAT)CenterX( viewdirectiongridno )) / 1.0f; + dTargetY = (0.3f * dTargetY + 0.7f * (FLOAT)CenterY( viewdirectiongridno )) / 1.0f; + } + } break; default: // %)@#&(%? @@ -12565,10 +12585,6 @@ void GunIncreaseHeat( OBJECTTYPE *pObj, SOLDIERTYPE* pSoldier ) FLOAT newguntemperature = min(guntemperature + singleshottemperature, OVERHEATING_MAX_TEMPERATURE ); // ... calculate new temperature ... (*pObj)[0]->data.bTemperature = newguntemperature; // ... apply new temperature - -#ifdef JA2TESTVERSION - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Gun temperature increased from %4.2f to %4.2f", guntemperature, newguntemperature ); -#endif } }