diff --git a/Tactical/DisplayCover.cpp b/Tactical/DisplayCover.cpp index 2ac7ca37..c562eee9 100644 --- a/Tactical/DisplayCover.cpp +++ b/Tactical/DisplayCover.cpp @@ -88,18 +88,23 @@ void AddCoverObjectsToViewArea(); void RemoveCoverObjectsFromViewArea(); void CalculateCover(); +void CalculateCoverFromEnemies(); void CalculateMines(); void CalculateTraitRange(); void CalculateTrackerRange(); void CalculateFortify(); void CalculateWeapondata(); +void CalculateCoverFromEnemySoldier(SOLDIERTYPE* pFromSoldier, const INT32& sTargetGridNo, const BOOLEAN& fRoof, INT8& bOverlayType, SOLDIERTYPE* pToSoldier, const BOOLEAN& bFromSoldierCowering, const UINT8& tunnelVision, const INT8 ToSoldierStealth, const INT8 ToSoldierLBeSightAdjustment); + + void GetGridNoForViewPort( const INT32& ubX, const INT32& ubY, INT32& sGridNo ); BOOLEAN GridNoOnScreenAndAround( const INT32& sGridNo, const UINT8& ubRadius=2 ); BOOLEAN IsTheRoofVisible( const INT32& sGridNo ); -BOOLEAN HasAdjTile( const INT32& ubX, const INT32& ubY ); +BOOLEAN HasAdjTile(const INT32& ubX, const INT32& ubY, const INT32& ubZ); + TileDefines GetOverlayIndex( INT8 bOverlayType ) { @@ -491,10 +496,13 @@ void DisplayCover( BOOLEAN forceUpdate ) switch ( gubDrawMode ) { case COVER_DRAW_MERC_VIEW: - case COVER_DRAW_ENEMY_VIEW: CalculateCover(); break; + case COVER_DRAW_ENEMY_VIEW: + CalculateCoverFromEnemies(); + break; + case MINES_DRAW_DETECT_ENEMY: case MINES_DRAW_PLAYERTEAM_NETWORKS: case MINES_DRAW_NETWORKCOLOURING: @@ -526,99 +534,40 @@ void DisplayCover( BOOLEAN forceUpdate ) } } -void CalculateCover() + + +static void CalculateCoverFromEnemies() { - register INT32 ubX, ubY; - register INT8 ubZ; - SOLDIERTYPE* pSoldier; - - if( gusSelectedSoldier == NOBODY ) + if (gusSelectedSoldier == NOBODY) return; - - GetSoldier( &pSoldier, gusSelectedSoldier ); - - for ( ubX=gsMinCellX; ubX<=gsMaxCellX; ++ubX ) + + SOLDIERTYPE* pSoldier; + GetSoldier(&pSoldier, gusSelectedSoldier); + INT8 OurSoldierStealth = GetStealth(pSoldier); + INT8 OurSoldierLBESightAdjustment = GetSightAdjustmentBasedOnLBE(pSoldier); + + + // Loop through the grid and reset cover + for (INT32 ubX = gsMinCellX; ubX <= gsMaxCellX; ++ubX) { - for ( ubY=gsMinCellY; ubY<=gsMaxCellY; ++ubY ) + for (INT32 ubY = gsMinCellY; ubY <= gsMaxCellY; ++ubY) { - for ( ubZ=0; ubZbActive && pSoldier->bInSector ) - { - if ( pSoldier->flags.uiStatusFlags & SOLDIER_MULTI_SELECTED ) - { - CalculateCoverFromSoldier( pSoldier, sGridNo, ubZ, bOverlayType ); - - // if the tile is already NO_COVER, there's no need to continue - if ( NO_COVER == bOverlayType ) - break; - } - } - } - } - else // single view from your merc - CalculateCoverFromSoldier( pSoldier, sGridNo, ubZ, bOverlayType ); - - // we use different enums for our merc's sight to avoid confusing inverse sight - bOverlayType = MAX_SEE - bOverlayType; - } + bOverlayType = MAX_COVER; } } } - AddCoverObjectsToViewArea(); -} -void CalculateCoverForSoldier( SOLDIERTYPE* pSoldier, const INT32& sTargetGridNo, const BOOLEAN& fRoof, INT8& bOverlayType ) -{ - UINT32 uiLoop; - SOLDIERTYPE *pOpponent; - INT8 *pbPersOL; - INT8 *pbPublOL; - - //loop through all the enemies and determine the cover - for (uiLoop = 0; uiLoop pOpponents; + std::vector bCowering; + std::vector tunnelVision; + for (UINT32 i = 0; i < guiNumMercSlots; ++i) { - pOpponent = MercSlots[ uiLoop ]; + SOLDIERTYPE *pOpponent = MercSlots[i]; // if this merc is inactive, at base, on assignment, dead, unconscious if (!pOpponent || pOpponent->stats.bLife < OKLIFE) @@ -627,30 +576,166 @@ void CalculateCoverForSoldier( SOLDIERTYPE* pSoldier, const INT32& sTargetGridNo } // if this man is neutral / on the same side, he's not an opponent - if( CONSIDERED_NEUTRAL( pSoldier, pOpponent ) || (pSoldier->bSide == pOpponent->bSide)) + if (CONSIDERED_NEUTRAL(pSoldier, pOpponent) || (pSoldier->bSide == pOpponent->bSide)) { continue; // next merc } - pbPersOL = pSoldier->aiData.bOppList + pOpponent->ubID; - pbPublOL = gbPublicOpplist[ OUR_TEAM ] + pOpponent->ubID; + INT8 *pbPersOL = pSoldier->aiData.bOppList + pOpponent->ubID; + INT8 *pbPublOL = gbPublicOpplist[OUR_TEAM] + pOpponent->ubID; // if this opponent is unknown personally and publicly - if( *pbPersOL != SEEN_CURRENTLY && *pbPublOL != SEEN_CURRENTLY ) + if (*pbPersOL != SEEN_CURRENTLY && *pbPublOL != SEEN_CURRENTLY) { continue; // next merc } - CalculateCoverFromSoldier( pOpponent, sTargetGridNo, fRoof, bOverlayType, pSoldier ); + pOpponents.push_back(pOpponent); + bCowering.push_back(CoweringShockLevel(pOpponent)); + tunnelVision.push_back(GetPercentTunnelVision(pOpponent)); + } - // if we got no cover, just return, can't get any worse than that. Helldorados lets you count - if ( bOverlayType == NO_COVER ) + + // Calculate cover for the whole grid, one opponent at a time. + for (UINT32 i = 0; i < pOpponents.size(); ++i) + { + SOLDIERTYPE *pOpponent = pOpponents[i]; + BOOLEAN isCowering = bCowering[i]; + UINT8 tunnelVisionPercentage = tunnelVision[i]; + + + for (INT32 ubX = gsMinCellX; ubX <= gsMaxCellX; ++ubX) { - return; + for (INT32 ubY = gsMinCellY; ubY <= gsMaxCellY; ++ubY) + { + for (INT8 ubZ = 0; ubZ < COVER_Z_CELLS; ++ubZ) + { + INT32& sGridNo = gCoverViewArea[ubX][ubY][ubZ].sGridNo; + if (!GridNoOnScreenAndAround(sGridNo, 2)) + continue; + + + INT8& bOverlayType = gCoverViewArea[ubX][ubY][ubZ].bOverlayType; + + if (IsTheRoofVisible(sGridNo)) + { + // do not show stuff on ground if roof is shown + if (ubZ == I_GROUND_LEVEL) + { + bOverlayType = INVALID_COVER; + continue; + } + } + else + { + // do not show stuff on roofs if ground is shown + if (ubZ == I_ROOF_LEVEL) + { + bOverlayType = INVALID_COVER; + continue; + } + } + + + if (!NewOKDestination(pSoldier, sGridNo, false, ubZ)) + continue; + + + //Skip cover calculation if there already is no cover. + if (bOverlayType == NO_COVER) + { + continue; + } + else + { + CalculateCoverFromEnemySoldier(pOpponent, sGridNo, ubZ, bOverlayType, pSoldier, isCowering, tunnelVisionPercentage, OurSoldierStealth, OurSoldierLBESightAdjustment); + } + } + } } } + + + AddCoverObjectsToViewArea(); } + +void CalculateCover() +{ + register INT32 ubX, ubY; + register INT8 ubZ; + SOLDIERTYPE* pSoldier; + + if (gusSelectedSoldier == NOBODY) + return; + + GetSoldier(&pSoldier, gusSelectedSoldier); + + for (ubX = gsMinCellX; ubX <= gsMaxCellX; ++ubX) + { + for (ubY = gsMinCellY; ubY <= gsMaxCellY; ++ubY) + { + for (ubZ = 0; ubZ < COVER_Z_CELLS; ++ubZ) + { + INT32& sGridNo = gCoverViewArea[ubX][ubY][ubZ].sGridNo; + + if (!GridNoOnScreenAndAround(sGridNo, 2)) + continue; + + if (IsTheRoofVisible(sGridNo)) + { + // do not show stuff on ground if roof is shown + if (ubZ == I_GROUND_LEVEL) + continue; + } + else + { + // do not show stuff on roofs if ground is shown + if (ubZ == I_ROOF_LEVEL) + continue; + } + + if (!NewOKDestination(pSoldier, sGridNo, false, ubZ)) + continue; + + INT8& bOverlayType = gCoverViewArea[ubX][ubY][ubZ].bOverlayType; + + // reset cover value + bOverlayType = MAX_COVER; + if (gTacticalStatus.fAtLeastOneGuyOnMultiSelect) // view of selected mercs + { + // OK, loop through all guys who are 'multi-selected' and + INT32 cnt = gTacticalStatus.Team[gbPlayerNum].bFirstID; + for (pSoldier = MercPtrs[cnt]; cnt <= gTacticalStatus.Team[gbPlayerNum].bLastID; ++cnt, ++pSoldier) + { + if (pSoldier->bActive && pSoldier->bInSector) + { + if (pSoldier->flags.uiStatusFlags & SOLDIER_MULTI_SELECTED) + { + CalculateCoverFromSoldier(pSoldier, sGridNo, ubZ, bOverlayType); + + // if the tile is already NO_COVER, there's no need to continue + if (NO_COVER == bOverlayType) + break; + } + } + } + } + else // single view from your merc + { + CalculateCoverFromSoldier(pSoldier, sGridNo, ubZ, bOverlayType); + } + + // we use different enums for our merc's sight to avoid confusing inverse sight + bOverlayType = MAX_SEE - bOverlayType; + } + } + } + + AddCoverObjectsToViewArea(); +} + + void CalculateCoverFromSoldier( SOLDIERTYPE* pFromSoldier, const INT32& sTargetGridNo, const BOOLEAN& fRoof, INT8& bOverlayType, SOLDIERTYPE* pToSoldier ) { UINT16 usSightLimit = pFromSoldier->GetMaxDistanceVisible(sTargetGridNo, (INT8)fRoof, CALC_FROM_WANTED_DIR); @@ -664,7 +749,7 @@ void CalculateCoverFromSoldier( SOLDIERTYPE* pFromSoldier, const INT32& sTargetG if (pToSoldier == NULL) { usAdjustedSight = usSightLimit; } else { - usAdjustedSight = usSightLimit + usSightLimit * GetSightAdjustment( pToSoldier, sTargetGridNo, (INT8) fRoof, ubStance ) /100; + usAdjustedSight = usSightLimit + usSightLimit * GetSightAdjustment( pToSoldier, GetStealth(pToSoldier), GetSightAdjustmentBasedOnLBE(pToSoldier), sTargetGridNo, (INT8) fRoof, ubStance ) /100; } if ( SoldierToVirtualSoldierLineOfSightTest( pFromSoldier, sTargetGridNo, (INT8) fRoof, ubStance, FALSE, usAdjustedSight ) != 0 ) @@ -675,6 +760,32 @@ void CalculateCoverFromSoldier( SOLDIERTYPE* pFromSoldier, const INT32& sTargetG } } +static void CalculateCoverFromEnemySoldier(SOLDIERTYPE* pFromSoldier, const INT32& sTargetGridNo, const BOOLEAN& fRoof, INT8& bOverlayType, SOLDIERTYPE* pToSoldier, const BOOLEAN& bFromSoldierCowering, const UINT8& tunnelVision, const INT8 ToSoldierStealth, const INT8 ToSoldierLBeSightAdjustment) +{ + // Had to extract this from SOLDIERTYPE::GetMaxDistanceVisible() function due to performance improvement from minimizing recalculating CoweringShockLevel(pSoldier) & GetPercentTunnelVision(pSoldier) + UINT16 usSightLimit = DistanceVisible(pFromSoldier, (SoldierHasLimitedVision(pFromSoldier) ? pFromSoldier->pathing.bDesiredDirection : DIRECTION_IRRELEVANT), DIRECTION_IRRELEVANT, sTargetGridNo, (INT8)fRoof, bFromSoldierCowering, tunnelVision); + + for (int i = 0; i < sizeof(animArr); ++i) + { + const UINT8& ubStance = animArr[i]; + + INT32 usAdjustedSight; + + if (pToSoldier == nullptr) { + usAdjustedSight = usSightLimit; + } + else { + usAdjustedSight = usSightLimit + usSightLimit * GetSightAdjustment(pToSoldier, ToSoldierStealth, ToSoldierLBeSightAdjustment, sTargetGridNo, (INT8)fRoof, ubStance) / 100; + } + + if (SoldierToVirtualSoldierLineOfSightTest(pFromSoldier, sTargetGridNo, (INT8)fRoof, ubStance, FALSE, usAdjustedSight) != 0) + { + if (bOverlayType > i) bOverlayType = i; + break; // we go from prone to stand, if soldier can see someone crouching, he can also see someone standing + } + } +} + BOOLEAN CanSoldierSeeFloor( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT8 bLevel ) { if ( !pSoldier ) @@ -717,7 +828,7 @@ void DisplayRangeToTarget( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) ubTerrainType = GetTerrainTypeForGrid(sTargetGridNo, gsInterfaceLevel); } - INT8 ubCover = - GetSightAdjustment(pSoldier, sTargetGridNo, gsInterfaceLevel); + INT8 ubCover = - GetSightAdjustment(pSoldier, GetStealth(pSoldier), GetSightAdjustmentBasedOnLBE(pSoldier), sTargetGridNo, gsInterfaceLevel); //display a string with cover value of current selected merc and brightness //swprintf( zOutputString, gzDisplayCoverText[DC_MSG__COVER_INFORMATION], ubCover, GetTerrainName(ubTerrainType), ubBrightness ); diff --git a/Tactical/DisplayCover.h b/Tactical/DisplayCover.h index 76505552..026fec03 100644 --- a/Tactical/DisplayCover.h +++ b/Tactical/DisplayCover.h @@ -11,7 +11,6 @@ void SwitchViewOff(); void ToggleMercView(); void ToggleEnemyView(); -void CalculateCoverForSoldier( SOLDIERTYPE* pForSoldier, const INT32& sTargetGridNo, const BOOLEAN& fRoof, INT8& bCover ); void CalculateCoverFromSoldier( SOLDIERTYPE* pFromSoldier, const INT32& sTargetGridNo, const BOOLEAN& fRoof, INT8& bCover, SOLDIERTYPE* pToSoldier = NULL ); BOOLEAN CanSoldierSeeFloor( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT8 bLevel ); @@ -83,13 +82,6 @@ enum COVER_DRAW_MODE { DRAW_MODE_WEAPONDATA, }; -void ChangeSizeOfDisplayCover( INT32 iNewSize ); - -void ChangeSizeOfLOS( INT32 iNewSize ); -//ddd for optimize oppponent turn -INT8 CalcCoverForGridNoBasedOnTeamKnownEnemies( SOLDIERTYPE *pSoldier, INT16 sTargetGridNo, INT8 bStance ); -//ddd for optimize oppponent turn - // ----------------------------- Mines display after this ---------------------------------------- // added by Flugente: display of mine, bombs and tripwire diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index 2f751a8f..bd5ac78e 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -461,7 +461,7 @@ inline UINT8 GetBrightness(const UINT8& ubLightLevel) * Calculates the total stealth value of a player. * * @param pSoldier -* @return ANIM_STAND or ANIM_CROUCH or ANIM_PRONE +* @return stealth percentage, capped to 100. */ inline INT8 GetStealth( SOLDIERTYPE* pSoldier ) { @@ -700,26 +700,27 @@ INT8 GetDetailedSightAdjustmentCamouflageOnTerrain( SOLDIERTYPE* pSoldier, const * - this will be used to calculate the penalty (sight addition) which occurs on the soldier who is been spot-tested * - it also will be used to reduce the ability to find others if the spotter moves * -* @param pSoldier the target +* @param bTilesMoved amount of tiles the target has moved +* @param ubLightLevel true light level at target location, given back by LightTrueLevel function +* @param ibStealthInPercent the target's stealth value, given back by GetStealth function +* @param hasStealthyTrait boolean value saying if target has the stealthy trait, given back by HAS_SKILL_TRAIT function * @return a negative value will indicate a reduction of sight, a positive one an addition to sight */ -INT8 GetSightAdjustmentThroughMovement( SOLDIERTYPE* pSoldier, const INT8& bTilesMoved, const UINT8& ubLightLevel ) +INT8 GetSightAdjustmentThroughMovement(const INT8& bTilesMoved, const UINT8& ubLightLevel, const INT8& ibStealthInPercent, const BOOLEAN& hasStealthyTrait) { if (gGameExternalOptions.ubMovementEffectiveness == 0) { return 0; } - INT8 stealth = GetStealth(pSoldier); - - INT8 bMovementAdjustment = bTilesMoved * ( 100 - stealth ) / 100; + INT8 bMovementAdjustment = bTilesMoved * (100 - ibStealthInPercent) / 100; // SANDRO - added reduction of penalty for moving for Stealthy trait with new traits - if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT )) - bMovementAdjustment = max(0, (bMovementAdjustment * (100 - gSkillTraitValues.ubSTStealthPenaltyForMovingReduction) / 100) ); + if (gGameOptions.fNewTraitSystem && hasStealthyTrait) + bMovementAdjustment = max(0, (bMovementAdjustment * (100 - gSkillTraitValues.ubSTStealthPenaltyForMovingReduction) / 100)); - UINT8 ubBrightness = (100 - GetBrightness( ubLightLevel )); + UINT8 ubBrightness = (100 - GetBrightness(ubLightLevel)); - return MINMAX100N( bMovementAdjustment * ubBrightness / 100 * gGameExternalOptions.ubMovementEffectiveness / 100 ); + return MINMAX100N(bMovementAdjustment * ubBrightness / 100 * gGameExternalOptions.ubMovementEffectiveness / 100); } INT8 GetSightAdjustmentThroughStance( const UINT8& ubStance ) @@ -785,25 +786,23 @@ INT8 GetSightAdjustmentBasedOnLBE( SOLDIERTYPE* pSoldier ) * Calculates a percentage value to be added (or substracted) from sight. it's based on the stealth value and the brightness. * - usually it should return something smaller than 0 but we might give a bonus if the target uses a lamp for better viewing (LAM-Lamp) which the spotter can see * -* @param pSoldier the target * @param ubLightLevel light level given back by the LightTrueLevel function +* @param ibStealthInPercent the target's stealth value, given back by the GetStealth function * @return a negative value will indicate a reduction of sight, a positive one an addition to sight */ -INT8 GetSightAdjustmentStealthAtLightLevel( SOLDIERTYPE* pSoldier, const UINT8& ubLightLevel ) +INT8 GetSightAdjustmentStealthAtLightLevel(const UINT8& ubLightLevel, const INT8& ibStealthInPercent) { if (gGameExternalOptions.ubStealthEffectiveness == 0) { return 0; } // set scaler to scale with light level (dark = 100%) - UINT8 ubScaler = GetBrightness( ubLightLevel ); + UINT8 ubScaler = GetBrightness(ubLightLevel); // last term corresponds to the maximum of ubScaler before - ubScaler = (UINT8)( ubScaler * gGameExternalOptions.ubStealthEffectiveness / 100.0f ); + ubScaler = (UINT8)(ubScaler * gGameExternalOptions.ubStealthEffectiveness / 100.0f); - INT8 ibStealthInPercent = GetStealth( pSoldier ); - - return MINMAX100N( - ibStealthInPercent * ubScaler / 100); + return MINMAX100N(-ibStealthInPercent * ubScaler / 100); } /** @@ -855,8 +854,11 @@ INT8 GetSightAdjustmentBehindStructure( const INT16& iRange, STRUCTURE* pStructu /* * Easy way to get all sight adjustments into one that affect a soldier +* +* Used by CalculateCoverFromEnemySoldier in DisplayCover.cpp +* Hoisting out the GetStealth and GetSightAdjustmentBasedOnLBE out of the hot loop made considerable difference in performance. */ -INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT16 bLevel, INT8 bStance ) +INT16 GetSightAdjustment(SOLDIERTYPE* pSoldier, INT8 soldierStealth, INT8 soldierLBESightAdjustment, INT32 sGridNo, INT16 bLevel, INT8 bStance) { if (sGridNo == -1) { sGridNo = pSoldier->sGridNo; @@ -867,50 +869,50 @@ INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT16 bLevel, IN } if (bStance == -1) { - bStance = GetCurrentHeightOfSoldier( pSoldier ); + bStance = GetCurrentHeightOfSoldier(pSoldier); } UINT8 ubTerrainType = NO_TERRAIN; // anv: additional tile properties ADDITIONAL_TILE_PROPERTIES_VALUES zGivenTileProperties; - memset(&zGivenTileProperties,0,sizeof(zGivenTileProperties)); - if(gGameExternalOptions.fAdditionalTileProperties) + memset(&zGivenTileProperties, 0, sizeof(zGivenTileProperties)); + if (gGameExternalOptions.fAdditionalTileProperties) { zGivenTileProperties = GetAllAdditonalTilePropertiesForGrid(sGridNo, bLevel); } else { - ubTerrainType = GetTerrainTypeForGrid( sGridNo, bLevel ); + ubTerrainType = GetTerrainTypeForGrid(sGridNo, bLevel); } - UINT8 ubLightLevel = LightTrueLevel( sGridNo, bLevel ); INT16 iSightAdjustment = 0; // general stuff (independant of soldier) - iSightAdjustment += GetSightAdjustmentThroughStance( bStance ); + iSightAdjustment += GetSightAdjustmentThroughStance(bStance); // context sensitive (needs soldier) - iSightAdjustment += GetSightAdjustmentBasedOnLBE( pSoldier ); + iSightAdjustment += soldierLBESightAdjustment; // context sensitive stuff with 2nd parameter (needs soldier for attributes but can be given a second parameter) - iSightAdjustment += GetSightAdjustmentThroughMovement( pSoldier, pSoldier->bTilesMoved, ubLightLevel ); - iSightAdjustment += GetSightAdjustmentStealthAtLightLevel( pSoldier, ubLightLevel ); + UINT8 ubLightLevel = LightTrueLevel(sGridNo, bLevel); + iSightAdjustment += GetSightAdjustmentThroughMovement(pSoldier->bTilesMoved, ubLightLevel, soldierStealth, HAS_SKILL_TRAIT(pSoldier, STEALTHY_NT)); + iSightAdjustment += GetSightAdjustmentStealthAtLightLevel(ubLightLevel, soldierStealth); - if(gGameExternalOptions.fAdditionalTileProperties) + if (gGameExternalOptions.fAdditionalTileProperties) { - iSightAdjustment += GetDetailedSightAdjustmentCamouflageOnTerrain( pSoldier, bStance, zGivenTileProperties ); + iSightAdjustment += GetDetailedSightAdjustmentCamouflageOnTerrain(pSoldier, bStance, zGivenTileProperties); } else { - iSightAdjustment += GetSightAdjustmentCamouflageOnTerrain( pSoldier, bStance, ubTerrainType ); + iSightAdjustment += GetSightAdjustmentCamouflageOnTerrain(pSoldier, bStance, ubTerrainType); } // anv: some places in vehicle completely obscure passenger from outside - INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier ); - if( bSeatIndex != (-1) ) + INT8 bSeatIndex = GetSeatIndexFromSoldier(pSoldier); + if (bSeatIndex != (-1)) { - if( gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[ bSeatIndex ].fHidden ) + if (gNewVehicle[pVehicleList[pSoldier->iVehicleId].ubVehicleType].VehicleSeats[bSeatIndex].fHidden) { iSightAdjustment = (-100); } @@ -919,6 +921,7 @@ INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT16 bLevel, IN return MINMAX100N(iSightAdjustment); } + BOOLEAN ResolveHitOnWall( STRUCTURE * pStructure, INT32 iGridNo, INT8 bLOSIndexX, INT8 bLOSIndexY, DOUBLE ddHorizAngle ) { BOOLEAN fNorthSouth, fEastWest; @@ -2342,20 +2345,21 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE // needed for sight limit calculation if (iTileSightLimit == CALC_FROM_ALL_DIRS || iTileSightLimit == CALC_FROM_WANTED_DIR) { iTileSightLimit = pStartSoldier->GetMaxDistanceVisible( pEndSoldier->sGridNo, pEndSoldier->pathing.bLevel, iTileSightLimit ); - iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier) / 100; + iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier, GetStealth(pEndSoldier), GetSightAdjustmentBasedOnLBE(pEndSoldier)) / 100; + } // needed for gun hit calculation (can you even hit him) else if (iTileSightLimit == NO_DISTANCE_LIMIT) { iTileSightLimit = pStartSoldier->GetMaxDistanceVisible( pEndSoldier->sGridNo, pEndSoldier->pathing.bLevel, CALC_FROM_ALL_DIRS ); - iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier) / 100; + iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier, GetStealth(pEndSoldier), GetSightAdjustmentBasedOnLBE(pEndSoldier)) / 100; iTileSightLimit += 255; // this shifts the limit for something special (we don't know yet) } // we assume that if we are given a limit it doesn't include stealth or similar stuff // for other function we assume the opposite but not this one, as we here are given the needed target soldier information to calculate sight adjustment else { - iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier) / 100; + iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier, GetStealth(pEndSoldier), GetSightAdjustmentBasedOnLBE(pEndSoldier)) / 100; } // anv: special check for vehicles - since they're no longer transparent, we need to check for visibility diff --git a/Tactical/LOS.h b/Tactical/LOS.h index 3af5798e..c3edc4a7 100644 --- a/Tactical/LOS.h +++ b/Tactical/LOS.h @@ -199,7 +199,7 @@ ADDITIONAL_TILE_PROPERTIES_VALUES GetAllAdditonalTilePropertiesForGrid( const IN INT8 GetSightAdjustmentThroughStance( const UINT8& ubStance ); // quick way to get all. should be used for all sight line tests with target soldier known -INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo = -1, INT16 bLevel = -1, INT8 bStance = -1 ); +INT16 GetSightAdjustment(SOLDIERTYPE* pSoldier, INT8 soldierStealth, INT8 soldierLBESightAdjustment, INT32 sGridNo = -1, INT16 bLevel = -1, INT8 bStance = -1); //zilpin: pellet spread patterns externalized in XML #define SPREADPATTERN_NAME_SIZE 32 @@ -254,4 +254,8 @@ FLOAT CalcCounterForceChange( SOLDIERTYPE * pShooter, UINT32 uiCounterForceAccur // Flugente: riot shields void DamageRiotShield( SOLDIERTYPE* pSoldier, INT32& rsDamage, INT32& rsSecondaryDamage ); + +extern INT8 GetStealth(SOLDIERTYPE* pSoldier); +extern INT8 GetSightAdjustmentBasedOnLBE(SOLDIERTYPE* pSoldier); + #endif \ No newline at end of file diff --git a/Tactical/opplist.cpp b/Tactical/opplist.cpp index 659f1cb6..7fce28bf 100644 --- a/Tactical/opplist.cpp +++ b/Tactical/opplist.cpp @@ -1182,13 +1182,13 @@ INT16 SOLDIERTYPE::GetMaxDistanceVisible(INT32 sGridNo, INT8 bLevel, int calcAsT if (calcAsType == CALC_FROM_ALL_DIRS) { - return DistanceVisible( this, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel ); + return DistanceVisible( this, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel, CoweringShockLevel(this), GetPercentTunnelVision(this) ); } - return DistanceVisible( this, (SoldierHasLimitedVision(this) ? this->pathing.bDesiredDirection : DIRECTION_IRRELEVANT), DIRECTION_IRRELEVANT, sGridNo, bLevel ); + return DistanceVisible( this, (SoldierHasLimitedVision(this) ? this->pathing.bDesiredDirection : DIRECTION_IRRELEVANT), DIRECTION_IRRELEVANT, sGridNo, bLevel, CoweringShockLevel(this), GetPercentTunnelVision(this)); } -INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, INT32 sSubjectGridNo, INT8 bLevel ) +INT16 DistanceVisible(SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, INT32 sSubjectGridNo, INT8 bLevel, const BOOLEAN& isCowering, const UINT8& tunnelVision) { INT16 sDistVisible; INT8 bLightLevel; @@ -1284,7 +1284,7 @@ INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, if ( sDistVisible != STRAIGHT || ( fLimitedVision && (bFacingDir != bSubjectDir) ) ) { - tunnelVisionInPercent = GetPercentTunnelVision( pSoldier ); + tunnelVisionInPercent = tunnelVision; } sDistVisible *= 2; @@ -1355,7 +1355,7 @@ INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, gGameExternalOptions.ubMaxSuppressionShock > 0 && sDistVisible > 0 ) { // Make sure character is cowering. - if ( CoweringShockLevel(pSoldier) ) + if (isCowering) { sDistVisible = __max(1,(sDistVisible * (gGameExternalOptions.ubMaxSuppressionShock - pSoldier->aiData.bShock)) / gGameExternalOptions.ubMaxSuppressionShock); } @@ -2097,7 +2097,7 @@ INT16 ManLooksForMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, UINT8 ubCall // BIG NOTE: must use desdir instead of direction, since in a projected // situation, the direction may still be changing if it's one of the first // few animation steps when this guy's turn to do his stepped look comes up - sDistVisible = DistanceVisible(pSoldier,pSoldier->pathing.bDesiredDirection,bDir, pOpponent->sGridNo, pOpponent->pathing.bLevel ); + sDistVisible = DistanceVisible(pSoldier, pSoldier->pathing.bDesiredDirection, bDir, pOpponent->sGridNo, pOpponent->pathing.bLevel, CoweringShockLevel(pSoldier), GetPercentTunnelVision(pSoldier)); //if (pSoldier->ubID == 0) //sprintf(gDebugStr,"dist visible %d: my dir %d to him %d",sDistVisible,pSoldier->bDesiredDirection,bDir); } @@ -7464,7 +7464,7 @@ void CheckForAlertWhenEnemyDies( SOLDIERTYPE * pDyingSoldier ) // distance we "see" then depends on the direction he is located from us bDir = atan8(pSoldier->sX,pSoldier->sY,pDyingSoldier->sX,pDyingSoldier->sY); - sDistVisible = DistanceVisible( pSoldier, pSoldier->pathing.bDesiredDirection, bDir, pDyingSoldier->sGridNo, pDyingSoldier->pathing.bLevel ); + sDistVisible = DistanceVisible( pSoldier, pSoldier->pathing.bDesiredDirection, bDir, pDyingSoldier->sGridNo, pDyingSoldier->pathing.bLevel, CoweringShockLevel(pSoldier), GetPercentTunnelVision(pSoldier)); sDistAway = PythSpacesAway( pSoldier->sGridNo, pDyingSoldier->sGridNo ); // if we see close enough to see the soldier diff --git a/Tactical/opplist.h b/Tactical/opplist.h index ba9b079b..9330b7e6 100644 --- a/Tactical/opplist.h +++ b/Tactical/opplist.h @@ -119,7 +119,7 @@ void AddOneOpponent(SOLDIERTYPE *pSoldier); void RemoveOneOpponent(SOLDIERTYPE *pSoldier); void UpdatePersonal(SOLDIERTYPE *pSoldier, UINT8 ubID, INT8 bNewOpplist, INT32 sGridNo, INT8 bLevel); INT16 MaxNormalDistanceVisible( void ); -INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, INT32 sSubjectGridNo, INT8 bLevel ); +INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, INT32 sSubjectGridNo, INT8 bLevel, const BOOLEAN& isCowering, const UINT8& tunnelVision); void ResetLastKnownLocs(SOLDIERTYPE *ptr); void RecalculateOppCntsDueToNoLongerNeutral( SOLDIERTYPE * pSoldier ); void ReevaluateBestSightingPosition( SOLDIERTYPE * pSoldier, INT8 bInterruptDuelPts );