diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h index 7bae7326..e1aafee9 100644 --- a/Tactical/Item Types.h +++ b/Tactical/Item Types.h @@ -383,6 +383,7 @@ typedef struct INT16 percentburstfireapreduction; INT16 camobonus; + INT16 stealthbonus; UINT16 defaultattachment; } INVTYPE; diff --git a/Tactical/Items.cpp b/Tactical/Items.cpp index 7532dca3..0396dd4f 100644 --- a/Tactical/Items.cpp +++ b/Tactical/Items.cpp @@ -7177,4 +7177,34 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier) return aimLevels; } +//Madd: added +INT16 GetStealthBonus( OBJECTTYPE * pObj ) +{ + INT8 bLoop; + INT16 bns=0; + bns = (INT16) BonusReduce(Item[pObj->usItem].stealthbonus,pObj->bStatus[0]); + + for (bLoop = 0; bLoop < MAX_ATTACHMENTS; bLoop++) + { + bns += (INT16) BonusReduce(Item[pObj->usAttachItem[bLoop]].stealthbonus,pObj->bAttachStatus[bLoop]); + } + return( bns ); +} +INT16 GetWornStealth( SOLDIERTYPE * pSoldier ) +{ + //note: Stealth bonus is capped at 100 + //note: Stealth is not a perk! Stealth bonus only applies to equipment, and stacks with camouflage + //note: stealth bonus is not affected by terrain like the camo bonus, otherwise they're very similar + //note: stealth bonus also affects noise made by characters walking + INT8 bLoop; + INT16 ttl=0; + + for (bLoop = HELMETPOS; bLoop <= LEGPOS; bLoop++) + { + if ( pSoldier->inv[bLoop].usItem > NONE ) + ttl += GetStealthBonus(&pSoldier->inv[bLoop]); + } + + return __min( ttl, 100 ); +} diff --git a/Tactical/Items.h b/Tactical/Items.h index 2b4c184d..1979116b 100644 --- a/Tactical/Items.h +++ b/Tactical/Items.h @@ -277,6 +277,8 @@ INT8 FindTrigger( SOLDIERTYPE * pSoldier ); INT8 FindRemoteControl( SOLDIERTYPE * pSoldier ); INT16 GetWornCamo( SOLDIERTYPE * pSoldier ); INT16 GetCamoBonus( OBJECTTYPE * pObj ); +INT16 GetWornStealth( SOLDIERTYPE * pSoldier ); +INT16 GetStealthBonus( OBJECTTYPE * pObj ); void ApplyEquipmentBonuses(SOLDIERTYPE * pSoldier); diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index c735e637..582827fd 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -630,7 +630,7 @@ BOOLEAN ResolveHitOnWall( STRUCTURE * pStructure, INT32 iGridNo, INT8 bLOSIndexX * - stops at other obstacles * */ -INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT8 ubTileSightLimit, UINT8 ubTreeSightReduction, INT8 bAware, INT8 bCamouflage, BOOLEAN fSmell, INT16 * psWindowGridNo ) +INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT8 ubTileSightLimit, UINT8 ubTreeSightReduction, INT8 bAware, INT32 bCamouflage, BOOLEAN fSmell, INT16 * psWindowGridNo ) { // Parameters... // the X,Y,Z triplets should be obvious @@ -1548,8 +1548,10 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE FLOAT dStartZPos, dEndZPos; BOOLEAN fOk; BOOLEAN fSmell; - INT8 bEffectiveCamo; + INT16 bEffectiveCamo; + INT16 bEffectiveStealth; UINT8 ubTreeReduction; + INT32 iTemp; // TO ADD: if target is camouflaged and in cover, reduce sight distance by 30% // TO ADD: if in tear gas, reduce sight limit to 2 tiles @@ -1613,8 +1615,6 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE if ( ( pEndSoldier->bCamo + pEndSoldier->wornCamo ) > 0 && !bAware ) { - INT32 iTemp; - // reduce effects of camo of 5% per tile moved last turn if ( pEndSoldier->ubBodyType == BLOODCAT ) { @@ -1648,6 +1648,26 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE bEffectiveCamo = 0; } + //Madd: added - note stealth is capped at 100 just like camo + if ( ( GetWornStealth(pEndSoldier) ) > 0 && !bAware ) + { + + // reduce effects of stealth by 5% per tile moved last turn + bEffectiveStealth = max(0,min(100,(GetWornStealth(pEndSoldier)))) * (100 - pEndSoldier->bTilesMoved * 5) / 100; + + bEffectiveStealth = __max( bEffectiveStealth, 0 ); + + // reduce visibility by up to a third for Stealth! + // stance and terrain don't matter + iTemp = ubTileSightLimit; + iTemp -= iTemp * (bEffectiveStealth / 3) / 100; + ubTileSightLimit = (UINT8) iTemp; + } + else + { + bEffectiveStealth = 0; + } + if ( TANK( pEndSoldier ) ) { ubTreeReduction = 0; @@ -1657,7 +1677,7 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE ubTreeReduction = gubTreeSightReduction[ gAnimControl[pEndSoldier->usAnimState].ubEndHeight ]; } - return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) CenterX( pEndSoldier->sGridNo ), (FLOAT) CenterY( pEndSoldier->sGridNo ), dEndZPos, ubTileSightLimit, ubTreeReduction, bAware, bEffectiveCamo, fSmell, NULL ) ); + return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) CenterX( pEndSoldier->sGridNo ), (FLOAT) CenterY( pEndSoldier->sGridNo ), dEndZPos, ubTileSightLimit, ubTreeReduction, bAware, bEffectiveCamo + bEffectiveStealth, fSmell, NULL ) ); } INT16 SoldierToLocationWindowTest( SOLDIERTYPE * pStartSoldier, INT16 sEndGridNo ) diff --git a/Tactical/Weapons.cpp b/Tactical/Weapons.cpp index 1551372b..fddc4410 100644 --- a/Tactical/Weapons.cpp +++ b/Tactical/Weapons.cpp @@ -4144,6 +4144,17 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u iTotalProtection += ArmourProtection( pTarget, Item[pArmour->usItem].ubClassIndex, &(pArmour->bStatus[0]), iImpact, ubAmmoType ); if ( pArmour->bStatus[ 0 ] < USABLE ) { + //Madd: put any attachments that someone might have added to the armour in the merc's inventory + for (int bLoop = 0; bLoop < MAX_ATTACHMENTS; bLoop++) + { + OBJECTTYPE newObj; + CreateItem(pArmour->usAttachItem[bLoop], pArmour->bAttachStatus[bLoop], &newObj); + if ( !AutoPlaceObject( pTarget, &newObj, FALSE ) ) + { // put it on the ground + AddItemToPool( pTarget->sGridNo, &newObj, 1, pTarget->bLevel, 0 , -1 ); + } + } + DeleteObj( pArmour ); DirtyMercPanelInterface( pTarget, DIRTYLEVEL2 ); } diff --git a/Tactical/opplist.cpp b/Tactical/opplist.cpp index c63ece69..4f9b85d1 100644 --- a/Tactical/opplist.cpp +++ b/Tactical/opplist.cpp @@ -4671,6 +4671,9 @@ UINT8 MovementNoise( SOLDIERTYPE *pSoldier ) iStealthSkill += 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY ); } + if ( GetWornStealth(pSoldier) > 0 ) + iStealthSkill += GetWornStealth(pSoldier) / 2; + //NumMessage("Base Stealth = ",stealthSkill); diff --git a/Utils/XML_Items.cpp b/Utils/XML_Items.cpp index 7a17e001..d48736a5 100644 --- a/Utils/XML_Items.cpp +++ b/Utils/XML_Items.cpp @@ -197,6 +197,7 @@ itemStartElementHandle(void *userData, const char *name, const char **atts) strcmp(name, "PercentTunnelVision") == 0 || strcmp(name, "DefaultAttachment") == 0 || strcmp(name, "CamoBonus") == 0 || + strcmp(name, "StealthBonus") == 0 || strcmp(name, "fFlags") == 0 )) { @@ -514,6 +515,11 @@ itemEndElementHandle(void *userData, const char *name) pData->curElement = ELEMENT; pData->curItem.camobonus = (INT16) atol(pData->szCharData); } + else if(strcmp(name, "StealthBonus") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.stealthbonus = (INT16) atol(pData->szCharData); + } else if(strcmp(name, "PercentNoiseReduction") == 0) { pData->curElement = ELEMENT; @@ -1385,6 +1391,7 @@ BOOLEAN WriteItemStats() FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].rock ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].camobonus ); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].stealthbonus ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].flakjacket ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].leatherjacket );