diff --git a/GameSettings.cpp b/GameSettings.cpp index 1eb2c9d4..db6992f4 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -1446,7 +1446,7 @@ void LoadGameExternalOptions() gGameExternalOptions.iQuickItem8 = iniReader.ReadInteger("Tactical Interface Settings", "QUICK_ITEM_8", 0, -100, MAXITEMS); gGameExternalOptions.iQuickItem9 = iniReader.ReadInteger("Tactical Interface Settings", "QUICK_ITEM_9", 0, -100, MAXITEMS); gGameExternalOptions.iQuickItem0 = iniReader.ReadInteger("Tactical Interface Settings", "QUICK_ITEM_0", 0, -100, MAXITEMS); - + // Alternative system for aiming - progressive method depending on marksmanship of Merc gGameExternalOptions.bAltAimEnabled = iniReader.ReadBoolean("Tactical Interface Settings","ALT_AIMING_ENABLED",FALSE); @@ -3300,6 +3300,7 @@ void LoadCTHConstants() gGameCTHConstants.LASER_PERFORMANCE_BONUS_IRON = iniReader.ReadFloat("General","LASER_PERFORMANCE_BONUS_IRON", 0.0f, 0.0f, 50.0f); gGameCTHConstants.LASER_PERFORMANCE_BONUS_SCOPE = iniReader.ReadFloat("General","LASER_PERFORMANCE_BONUS_SCOPE", 0.0f, 0.0f, 50.0f); gGameCTHConstants.DEGREES_MAXIMUM_APERTURE = iniReader.ReadFloat("General", "DEGREES_MAXIMUM_APERTURE", 15.0, 0.0, 22.5); + gGameCTHConstants.IRON_SIGHTS_MAX_APERTURE_USE_GRADIENT = iniReader.ReadBoolean("General", "IRON_SIGHTS_MAX_APERTURE_USE_GRADIENT", FALSE); gGameCTHConstants.RANGE_COEFFICIENT = iniReader.ReadFloat("General", "RANGE_COEFFICIENT", 2.0, 0.001f, 100.0); gGameCTHConstants.GRAVITY_COEFFICIENT = iniReader.ReadFloat("General", "GRAVITY_COEFFICIENT", 1.0, 0.001f, 100.0); gGameCTHConstants.VERTICAL_BIAS = iniReader.ReadFloat("General", "VERTICAL_BIAS", 1.0f, 0.01f, 2.0f); diff --git a/GameSettings.h b/GameSettings.h index 88662621..f2b2f523 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1934,6 +1934,7 @@ typedef struct FLOAT LASER_PERFORMANCE_BONUS_IRON; // percentage bonus to base aperture size for laser pointers when using iron sights FLOAT LASER_PERFORMANCE_BONUS_SCOPE; // percentage bonus to base aperture size for laser pointers when using scopes FLOAT DEGREES_MAXIMUM_APERTURE; // Maximum possible aperture for a 100% muzzle sway shot. Decrease to make all shots more accurate. + BOOLEAN IRON_SIGHTS_MAX_APERTURE_USE_GRADIENT; // Use new curve instead of linear function to get the max aperture at target range for iron sights. FLOAT RANGE_COEFFICIENT; // Determines maximum range which decides when gravity forces bullets to drop FLOAT GRAVITY_COEFFICIENT; // Changes the way gravity works in the game. Higher values mean bullets don't drop as quickly after reaching max range. FLOAT VERTICAL_BIAS; // This float can be used to reduce the chance of missing too far upwards or downwards (compared to left/right). diff --git a/MainMenuScreen.cpp b/MainMenuScreen.cpp index feb86c81..7b53bd35 100644 --- a/MainMenuScreen.cpp +++ b/MainMenuScreen.cpp @@ -517,7 +517,7 @@ void HandleMainMenuInput() case 'n': gbHandledMainMenu = NEW_GAME; gfMainMenuScreenExit = TRUE; - SetMainMenuExitScreen( INIT_SCREEN ); + SetMainMenuExitScreen( GAME_INIT_OPTIONS_SCREEN ); break; case 'm': diff --git a/Tactical/Interface.cpp b/Tactical/Interface.cpp index 7c3673fb..7ff2b8e7 100644 --- a/Tactical/Interface.cpp +++ b/Tactical/Interface.cpp @@ -2546,11 +2546,8 @@ BOOLEAN DrawCTHIndicator() /////////////////////////////////////////////////////////// // Now we calculate the Aperture size. This is done using the same method as the shooting formula uses. - // Calculate the maximum angle of any shot. - DOUBLE ddMaxAngleRadians = (gGameCTHConstants.DEGREES_MAXIMUM_APERTURE * 6.283) / 360; - // Calculate the size of a "normal" aperture. This is how wide a shot can go at 1x Normal Distance. - FLOAT iBasicAperture = (FLOAT)((sin(ddMaxAngleRadians) * gGameCTHConstants.NORMAL_SHOOTING_DISTANCE) * 2); // The *2 compensates for the difference between CellXY and ScreenXY + FLOAT iBasicAperture = CalcBasicAperture() * 2; // The *2 compensates for the difference between CellXY and ScreenXY // sevenfm: moved declarations out of codeblock, will use them later for laser dot plotting FLOAT fLaserBonus = 0; @@ -2560,6 +2557,14 @@ BOOLEAN DrawCTHIndicator() // when using the reworked NCTH code we do additional calculations for iron sights and lasers if (gGameExternalOptions.fUseNewCTHCalculation) { + // silversurfer: New functionality for iron sights - There have been many complaints that iron sights lose their usefulness + // very fast the farther the target is away. Setting IRON_SIGHT_PERFORMANCE_BONUS too high makes them overly powerful at + // close range. This experimental formula implements a curve that lowers iBasicAperture the farther the target is away. + // At 1 tile distance iBasicAperture will be the same as before. That's the common start. + if ( gGameCTHConstants.IRON_SIGHTS_MAX_APERTURE_USE_GRADIENT && gCTHDisplay.ScopeMagFactor <= 1.0 && !pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bAimTime, gCTHDisplay.iTargetGridNo ) ) + + iBasicAperture = iBasicAperture * ( 1 / sqrt( d2DDistance / FLOAT(CELL_X_SIZE) ) / 4.0 + 0.75 ); + // iron sights can get a percentage bonus to make them overall better but only when not shooting from hip if ( gCTHDisplay.ScopeMagFactor <= 1.0 && !pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bAimTime, gCTHDisplay.iTargetGridNo ) ) diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index f7833a5d..f13a8075 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -7772,6 +7772,14 @@ void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT // when using the reworked NCTH code we do additional calculations for iron sights and lasers if (gGameExternalOptions.fUseNewCTHCalculation) { + // silversurfer: New functionality for iron sights - There have been many complaints that iron sights lose their usefulness + // very fast the farther the target is away. Setting IRON_SIGHT_PERFORMANCE_BONUS too high makes them overly powerful at + // close range. This experimental formula implements a curve that lowers iBasicAperture the farther the target is away. + // At 1 tile distance iBasicAperture will be the same as before. That's the common start. + if ( gGameCTHConstants.IRON_SIGHTS_MAX_APERTURE_USE_GRADIENT && gCTHDisplay.ScopeMagFactor <= 1.0 && !pShooter->IsValidAlternativeFireMode( pShooter->aiData.bAimTime, gCTHDisplay.iTargetGridNo ) ) + + iBasicAperture = iBasicAperture * ( 1 / sqrt( d2DDistance / FLOAT(CELL_X_SIZE) ) / 4.0 + 0.75 ); + // iron sights can get a percentage bonus to make them overall better but only when not shooting from hip if ( gCTHDisplay.ScopeMagFactor <= 1.0 && !pShooter->IsValidAlternativeFireMode( pShooter->aiData.bAimTime, gCTHDisplay.iTargetGridNo ) ) @@ -8217,7 +8225,7 @@ FLOAT CalcEffectiveMagFactor( SOLDIERTYPE *pShooter, FLOAT fRealMagFactor ) FLOAT CalcBasicAperture() { FLOAT iBasicAperture = 0.0; - + // Maximum aperture is the radius of a shot performed with 100% muzzle sway (a completely unstabled gun). // It is the radius of a circle "drawn" at 1xNormal Shooting Distance, at the end of a cone starting at the // tip ofour muzzle. diff --git a/Tactical/Weapons.cpp b/Tactical/Weapons.cpp index db5a8cbc..f9eb92fd 100644 --- a/Tactical/Weapons.cpp +++ b/Tactical/Weapons.cpp @@ -50,6 +50,7 @@ #include "LOS.h" // HEADROCK HAM 4: Required for new shooting mechanism. Alternately, maybe move the functions to LOS.h. #include "Campaign Types.h" // added by Flugente #include "CampaignStats.h" // added by Flugente + #include "environment.h" // added by silversurfer #endif //forward declarations of common classes to eliminate includes @@ -9063,13 +9064,72 @@ UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTim // distance to target FLOAT d2DDistance = (FLOAT) PythSpacesAway( pSoldier->sGridNo, sGridNo ) * (FLOAT) CELL_X_SIZE; - // basic aperture that is equal for everyone - FLOAT dBasicAperture = CalcBasicAperture( ); - // aperture at target distance without magnification - FLOAT dAperture = dBasicAperture * (d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); // magnification (1.0 or higher if scope is used) FLOAT dMagFactor = CalcMagFactor( pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), d2DDistance, sGridNo, (UINT8)ubAimTime ); + + // basic aperture that is equal for everyone + FLOAT dBasicAperture = CalcBasicAperture( ); + + if (gGameExternalOptions.fUseNewCTHCalculation) + { + // silversurfer: New functionality for iron sights - There have been many complaints that iron sights lose their usefulness + // very fast the farther the target is away. Setting IRON_SIGHT_PERFORMANCE_BONUS too high makes them overly powerful at + // close range. This experimental formula implements a curve that lowers dBasicAperture the farther the target is away. + // At 1 tile distance iBasicAperture will be the same as before. That's the common start. + if ( gGameCTHConstants.IRON_SIGHTS_MAX_APERTURE_USE_GRADIENT && dMagFactor <= 1.0 && !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) + + dBasicAperture = dBasicAperture * ( 1 / sqrt( d2DDistance / FLOAT(CELL_X_SIZE) ) / 4.0 + 0.75 ); + + // iron sights can get a percentage bonus to make them overall better but only when not shooting from hip + if ( dMagFactor <= 1.0 && !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) + + dBasicAperture = dBasicAperture * (FLOAT)( (100 - gGameCTHConstants.IRON_SIGHT_PERFORMANCE_BONUS) / 100); + + // laser pointers can provide a percentage bonus to base aperture + INT32 iLaserRange = GetBestLaserRange( &(pSoldier->inv[pSoldier->ubAttackingHand]) ); + if ( iLaserRange > 0 + && ( gGameCTHConstants.LASER_PERFORMANCE_BONUS_HIP + gGameCTHConstants.LASER_PERFORMANCE_BONUS_IRON + gGameCTHConstants.LASER_PERFORMANCE_BONUS_SCOPE != 0) ) + { + INT8 bLightLevel = LightTrueLevel(sGridNo, gsInterfaceLevel ); + INT32 iMaxLaserRange = ( iLaserRange*( 2*bLightLevel + 3*NORMAL_LIGHTLEVEL_NIGHT - 5*NORMAL_LIGHTLEVEL_DAY ) ) / ( 2 * ( NORMAL_LIGHTLEVEL_NIGHT - NORMAL_LIGHTLEVEL_DAY ) ); + + // laser only has effect when in range + if ( iMaxLaserRange > d2DDistance ) + { + FLOAT fLaserBonus = 0; + // which bonus do we want to apply? + if ( pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) + // shooting from hip + fLaserBonus = gGameCTHConstants.LASER_PERFORMANCE_BONUS_HIP; + else if ( dMagFactor <= 1.0 ) + // using iron sights or other 1x sights + fLaserBonus = gGameCTHConstants.LASER_PERFORMANCE_BONUS_IRON; + else + // must be using a scope + fLaserBonus = gGameCTHConstants.LASER_PERFORMANCE_BONUS_SCOPE; + + // light level influences how easy it is to spot the laser dot on the target + FLOAT fBrightnessModifier = (FLOAT)(bLightLevel) / (FLOAT)(NORMAL_LIGHTLEVEL_NIGHT); + + // laser fully efficient + if ( iLaserRange > d2DDistance ) + // apply full bonus + dBasicAperture = dBasicAperture * (FLOAT)( (100 - (fLaserBonus * fBrightnessModifier)) / 100); + else + { + // beyond BestLaserRange laser bonus drops linearly to 0 + FLOAT fEffectiveLaserRatio = (FLOAT)(iMaxLaserRange - d2DDistance) / (FLOAT)(iMaxLaserRange - iLaserRange); + // apply partial bonus + dBasicAperture = dBasicAperture * (FLOAT)( (100 - (fLaserBonus * fBrightnessModifier * fEffectiveLaserRatio)) / 100); + } + } + } + } + + // aperture at target distance without magnification + FLOAT dAperture = dBasicAperture * (d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + // Get effective mag factor for this shooter. This represents his ability to use scopes. FLOAT fEffectiveMagFactor = CalcEffectiveMagFactor( pSoldier, dMagFactor ); // modify aperture with magnification