diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp index f0cd9b97..f7780399 100644 --- a/Tactical/Handle Items.cpp +++ b/Tactical/Handle Items.cpp @@ -433,7 +433,7 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa { // first shot using "virgin" gun... set imprint ID pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.ubImprintID = pSoldier->ubProfile; - + // this could be an NPC (Krott) if (pSoldier->bTeam == gbPlayerNum) { @@ -1876,14 +1876,24 @@ void HandleSoldierDropBomb( SOLDIERTYPE *pSoldier, INT32 sGridNo ) // We have something... all we do is place... if ( ArmBomb( &(pSoldier->inv[ HANDPOS ]), 0 ) ) { - // Snap: Do a skill check here as well - INT32 iResult = SkillCheck( pSoldier, PLANTING_BOMB_CHECK, 0 ); + INT32 iResult = 0; + + if ( HasItemFlag( (pSoldier->inv[HANDPOS]).usItem, BEARTRAP ) ) + { + iResult = SkillCheck( pSoldier, PLANTING_MECHANICAL_BOMB_CHECK, 0 ); + } + else + { + iResult = SkillCheck( pSoldier, PLANTING_BOMB_CHECK, 0 ); + } if ( iResult >= 0 ) { // Less explosives gain for placing tripwire if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].tripwire ) StatChange( pSoldier, EXPLODEAMT, 1, FALSE ); + else if ( HasItemFlag( (pSoldier->inv[HANDPOS]).usItem, BEARTRAP ) ) + StatChange( pSoldier, MECHANAMT, 10, FALSE ); else // EXPLOSIVES GAIN (25): Place a bomb, or buried and armed a mine StatChange( pSoldier, EXPLODEAMT, 25, FALSE ); @@ -1935,6 +1945,10 @@ void HandleSoldierDropBomb( SOLDIERTYPE *pSoldier, INT32 sGridNo ) } else { + // beartraps don't explode... + if ( HasItemFlag( (pSoldier->inv[HANDPOS]).usItem, BEARTRAP ) ) + return; + // EXPLOSIVES GAIN (10): Failed to place a bomb, or bury and arm a mine StatChange( pSoldier, EXPLODEAMT, 10, FROM_FAILURE ); @@ -5357,6 +5371,10 @@ void BombMessageBoxCallBack( UINT8 ubExitValue ) { iResult = SkillCheck( gpTempSoldier, PLANTING_REMOTE_BOMB_CHECK, 0 ); } + else if ( HasItemFlag( (gpTempSoldier->inv[HANDPOS]).usItem, BEARTRAP ) ) + { + iResult = SkillCheck( gpTempSoldier, PLANTING_MECHANICAL_BOMB_CHECK, 0 ); + } else { iResult = SkillCheck( gpTempSoldier, PLANTING_BOMB_CHECK, 0 ); @@ -5367,12 +5385,18 @@ void BombMessageBoxCallBack( UINT8 ubExitValue ) // Less explosives gain for placing tripwire if ( Item[ gpTempSoldier->inv[ HANDPOS ].usItem ].tripwire == 1 ) StatChange( gpTempSoldier, EXPLODEAMT, 5, FALSE ); + else if ( HasItemFlag( (gpTempSoldier->inv[HANDPOS]).usItem, BEARTRAP ) ) + StatChange( gpTempSoldier, MECHANAMT, 10, FALSE ); else // EXPLOSIVES GAIN (25): Place a bomb, or buried and armed a mine StatChange( gpTempSoldier, EXPLODEAMT, 25, FALSE ); } else { + // beartraps don't explode... + if ( HasItemFlag( (gpTempSoldier->inv[HANDPOS]).usItem, BEARTRAP ) ) + return; + // EXPLOSIVES GAIN (10): Failed to place a bomb, or bury and arm a mine StatChange( gpTempSoldier, EXPLODEAMT, 10, FROM_FAILURE ); @@ -5809,7 +5833,6 @@ void BoobyTrapMessageBoxCallBack( UINT8 ubExitValue ) if ( CheckBombDisarmChance() >= 0) { - if ( gTempObject[0]->data.misc.ubBombOwner > 1 && ( (INT32)gTempObject[0]->data.misc.ubBombOwner - 2 >= gTacticalStatus.Team[ OUR_TEAM ].bFirstID && gTempObject[0]->data.misc.ubBombOwner - 2 <= gTacticalStatus.Team[ OUR_TEAM ].bLastID ) ) { if ( gTempObject[0]->data.misc.ubBombOwner - 2 == gpBoobyTrapSoldier->ubID ) @@ -5979,9 +6002,12 @@ void BoobyTrapMessageBoxCallBack( UINT8 ubExitValue ) else { // oops! trap goes off - StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (INT8) (3 * gbTrapDifficulty ), FROM_FAILURE ); + gpBoobyTrapSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + + if ( HasItemFlag( gTempObject.usItem, BEARTRAP ) ) + return; - gpBoobyTrapSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (INT8)(3 * gbTrapDifficulty), FROM_FAILURE ); if (gfDisarmingBuriedBomb) { @@ -6019,18 +6045,28 @@ void BoobyTrapInMapScreenMessageBoxCallBack( UINT8 ubExitValue ) if (ubExitValue == MSG_BOX_RETURN_YES) { INT32 iCheckResult; - iCheckResult = SkillCheck( gpBoobyTrapSoldier, DISARM_TRAP_CHECK, 0 ); + + if ( HasItemFlag( gpItemPointer->usItem, BEARTRAP ) ) + { + iCheckResult = SkillCheck( gpBoobyTrapSoldier, DISARM_MECHANICAL_TRAP_CHECK, 0 ); + } + else + { + iCheckResult = SkillCheck( gpBoobyTrapSoldier, DISARM_TRAP_CHECK, 0 ); + } if (iCheckResult >= 0) { // disarmed a boobytrap! - StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (UINT16) (6 * gbTrapDifficulty), FALSE ); + if ( HasItemFlag( gpItemPointer->usItem, BEARTRAP ) ) + StatChange( gpBoobyTrapSoldier, MECHANAMT, (3 * gbTrapDifficulty), FALSE ); + else + StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (UINT16) (6 * gbTrapDifficulty), FALSE ); // SANDRO - merc records - trap removal count if ( gpBoobyTrapSoldier->ubProfile != NO_PROFILE ) gMercProfiles[ gpBoobyTrapSoldier->ubProfile ].records.usTrapsRemoved++; - // have merc say this is good gpBoobyTrapSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 ); @@ -6074,10 +6110,14 @@ void BoobyTrapInMapScreenMessageBoxCallBack( UINT8 ubExitValue ) else { // oops! trap goes off - StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (INT8) (3 * gbTrapDifficulty ), FROM_FAILURE ); - gpBoobyTrapSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + // beartraps don't explode... + if ( HasItemFlag( gpItemPointer->usItem, BEARTRAP ) ) + return; + + StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (INT8) (3 * gbTrapDifficulty ), FROM_FAILURE ); + if (gfDisarmingBuriedBomb) { SetOffBombsInGridNo( gpBoobyTrapSoldier->ubID, gsBoobyTrapGridNo, TRUE, gbBoobyTrapLevel ); @@ -8646,24 +8686,27 @@ INT32 GetFirstObjectInSectorPosition( UINT16 ausItem ) INT32 CheckBombDisarmChance(void) { + INT8 diff = 0; + // NB owner grossness... bombs 'owned' by the enemy are stored with side value 1 in // the map. So if we want to detect a bomb placed by the player, owner is > 1, and // owner - 2 gives the ID of the character who planted it if ( gTempObject[0]->data.misc.ubBombOwner > 1 && ( (INT32)gTempObject[0]->data.misc.ubBombOwner - 2 >= gTacticalStatus.Team[ OUR_TEAM ].bFirstID && gTempObject[0]->data.misc.ubBombOwner - 2 <= gTacticalStatus.Team[ OUR_TEAM ].bLastID ) ) { + // my own boobytrap! if ( gTempObject[0]->data.misc.ubBombOwner - 2 == gpBoobyTrapSoldier->ubID ) - { - // my own boobytrap! - return SkillCheck( gpBoobyTrapSoldier, DISARM_TRAP_CHECK, 40 ); - } + diff = 40; + // our team's boobytrap! else - { - // our team's boobytrap! - return SkillCheck( gpBoobyTrapSoldier, DISARM_TRAP_CHECK, 20 ); - } + diff = 20; } - return SkillCheck( gpBoobyTrapSoldier, DISARM_TRAP_CHECK, 0 ); + if ( HasItemFlag( gTempObject.usItem, BEARTRAP ) ) + { + return SkillCheck( gpBoobyTrapSoldier, DISARM_MECHANICAL_TRAP_CHECK, diff ); + } + + return SkillCheck( gpBoobyTrapSoldier, DISARM_TRAP_CHECK, diff ); } void ExtendedDisarmMessageBox(void) diff --git a/Tactical/Interface Items.cpp b/Tactical/Interface Items.cpp index c8cdeda0..929a4fbe 100644 --- a/Tactical/Interface Items.cpp +++ b/Tactical/Interface Items.cpp @@ -13718,6 +13718,10 @@ void BombInventoryMessageBoxCallBack( UINT8 ubExitValue ) { iResult = SkillCheck( gpItemDescSoldier, PLANTING_REMOTE_BOMB_CHECK, 0 ); } + else if ( HasItemFlag( gpItemDescObject->usItem, BEARTRAP ) ) + { + iResult = SkillCheck( gpItemDescSoldier, PLANTING_MECHANICAL_BOMB_CHECK, 0 ); + } else { iResult = SkillCheck( gpItemDescSoldier, PLANTING_BOMB_CHECK, 0 ); @@ -13725,11 +13729,18 @@ void BombInventoryMessageBoxCallBack( UINT8 ubExitValue ) if ( iResult >= 0 ) { - // EXPLOSIVES GAIN (25): Place a bomb, or buried and armed a mine - StatChange( gpItemDescSoldier, EXPLODEAMT, 25, FALSE ); + if ( HasItemFlag( gpItemDescObject->usItem, BEARTRAP ) ) + StatChange( gpItemDescSoldier, MECHANAMT, 10, FALSE ); + else + // EXPLOSIVES GAIN (25): Place a bomb, or buried and armed a mine + StatChange( gpItemDescSoldier, EXPLODEAMT, 25, FALSE ); } else { + // beartraps don't explode... + if ( HasItemFlag( gpItemDescObject->usItem, BEARTRAP ) ) + return; + // EXPLOSIVES GAIN (10): Failed to place a bomb, or bury and arm a mine StatChange( gpItemDescSoldier, EXPLODEAMT, 10, FROM_FAILURE ); @@ -13834,54 +13845,57 @@ void BombInventoryDisArmMessageBoxCallBack( UINT8 ubExitValue ) return; } + INT8 diff = 0; + // NB owner grossness... bombs 'owned' by the enemy are stored with side value 1 in // the map. So if we want to detect a bomb placed by the player, owner is > 1, and // owner - 2 gives the ID of the character who planted it if ( (*gpItemDescObject)[0]->data.misc.ubBombOwner > 1 && ( (INT32)(*gpItemDescObject)[0]->data.misc.ubBombOwner - 2 >= gTacticalStatus.Team[ OUR_TEAM ].bFirstID && (*gpItemDescObject)[0]->data.misc.ubBombOwner - 2 <= gTacticalStatus.Team[ OUR_TEAM ].bLastID ) ) { // Flugente: get a tripwire-related bonus if we have a wire cutter in our hands - INT8 wirecutterbonus = 0; if ( ( (&gpItemDescSoldier->inv[HANDPOS])->exists() && Item[ gpItemDescSoldier->inv[HANDPOS].usItem ].wirecutters == 1 ) || ( (&gpItemDescSoldier->inv[SECONDHANDPOS])->exists() && Item[ gpItemDescSoldier->inv[SECONDHANDPOS].usItem ].wirecutters == 1 ) ) { // + 10 if item gets activated by tripwire if ( Item[gpItemDescObject->usItem].tripwireactivation == 1 ) - wirecutterbonus += 10; + diff += 10; // + 10 if item is tripwire if ( Item[gpItemDescObject->usItem].tripwire == 1 ) - wirecutterbonus += 10; + diff += 10; } + // my own boobytrap! if ( (*gpItemDescObject)[0]->data.misc.ubBombOwner - 2 == gpItemDescSoldier->ubID ) - { - // my own boobytrap! - iCheckResult = SkillCheck( gpItemDescSoldier, DISARM_TRAP_CHECK, 40 + wirecutterbonus ); - } + diff += 40; + // our team's boobytrap! else - { - // our team's boobytrap! - iCheckResult = SkillCheck( gpItemDescSoldier, DISARM_TRAP_CHECK, 20 + wirecutterbonus ); - } + diff += 20; + } + + if ( HasItemFlag( gpItemDescObject->usItem, BEARTRAP ) ) + { + iCheckResult = SkillCheck( gpItemDescSoldier, DISARM_MECHANICAL_TRAP_CHECK, diff ); } else { - iCheckResult = SkillCheck( gpItemDescSoldier, DISARM_TRAP_CHECK, 0 ); + iCheckResult = SkillCheck( gpItemDescSoldier, DISARM_TRAP_CHECK, diff ); } if (iCheckResult >= 0) { + UINT16 gain = 0; if ( (*gpItemDescObject)[0]->data.misc.ubBombOwner > 1 && ( (INT32)(*gpItemDescObject)[0]->data.misc.ubBombOwner - 2 >= gTacticalStatus.Team[ OUR_TEAM ].bFirstID && (*gpItemDescObject)[0]->data.misc.ubBombOwner - 2 <= gTacticalStatus.Team[ OUR_TEAM ].bLastID ) ) { + // disarmed our own boobytrap! if ( (*gpItemDescObject)[0]->data.misc.ubBombOwner - 2 == gpItemDescSoldier->ubID ) { - // disarmed my own boobytrap! - StatChange( gpItemDescSoldier, EXPLODEAMT, (UINT16) (2 * trapdifficulty), FALSE ); + gain = (UINT16)(2 * trapdifficulty); } else { // disarmed our team's boobytrap! - StatChange( gpItemDescSoldier, EXPLODEAMT, (UINT16) (4 * trapdifficulty), FALSE ); + gain = (UINT16)(4 * trapdifficulty); // SANDRO - merc records - trap removal count (don't count our own traps) gMercProfiles[ gpItemDescSoldier->ubProfile ].records.usTrapsRemoved++; @@ -13890,12 +13904,17 @@ void BombInventoryDisArmMessageBoxCallBack( UINT8 ubExitValue ) else { // disarmed a boobytrap! - StatChange( gpItemDescSoldier, EXPLODEAMT, (UINT16) (6 * trapdifficulty), FALSE ); + gain = (UINT16)(6 * trapdifficulty); // SANDRO - merc records - trap removal count gMercProfiles[ gpItemDescSoldier->ubProfile ].records.usTrapsRemoved++; } + if ( HasItemFlag( gpItemDescObject->usItem, BEARTRAP ) ) + StatChange( gpItemDescSoldier, MECHANAMT, gain / 2, FALSE ); + else + StatChange( gpItemDescSoldier, EXPLODEAMT, gain, FALSE ); + // have merc say this is good gpItemDescSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 ); @@ -13911,26 +13930,26 @@ void BombInventoryDisArmMessageBoxCallBack( UINT8 ubExitValue ) if ( (*gpItemDescObject).fFlags & OBJECT_ARMED_BOMB ) gpItemDescObject->fFlags &= ~( OBJECT_ARMED_BOMB ); - - /*if ( (*gpItemDescObject).fFlags & OBJECT_KNOWN_TO_BE_TRAPPED ) - gpItemDescObject->fFlags &= ~( OBJECT_KNOWN_TO_BE_TRAPPED );*/ } else { // oops! trap goes off - StatChange( gpItemDescSoldier, EXPLODEAMT, (INT8) (3 * trapdifficulty ), FROM_FAILURE ); - gpItemDescSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + // beartraps don't explode... + if ( HasItemFlag( gpItemDescObject->usItem, BEARTRAP ) ) + return; + + StatChange( gpItemDescSoldier, EXPLODEAMT, (INT8) (3 * trapdifficulty ), FROM_FAILURE ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Disarming of bomb failed. Resulting explosion damages %s's inventory and health", gpItemDescSoldier->name ); - INT8 screen = guiCurrentScreen; - if ( screen == GAME_SCREEN ) + if ( guiCurrentScreen == GAME_SCREEN ) { // ignite explosions manually - this item is not in the WorldBombs-structure, so we can't add it to the queue IgniteExplosion( (*gpItemDescObject)[0]->data.misc.ubBombOwner - 2, gpItemDescSoldier->sX, gpItemDescSoldier->sY, (INT16) (gpWorldLevelData[gpItemDescSoldier->sGridNo].sHeight), gpItemDescSoldier->sGridNo, gpItemDescObject->usItem, gpItemDescSoldier->pathing.bLevel, gpItemDescSoldier->ubDirection, gpItemDescObject ); } - else if ( (screen == MAP_SCREEN) || (screen == MSG_BOX_SCREEN) ) + else if ( guiCurrentScreen == MAP_SCREEN || guiCurrentScreen == MSG_BOX_SCREEN ) { // no explosions in map screen - instead we simply damage the inventory and harm our health gpItemDescSoldier->InventoryExplosion(); diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h index 1b1cf8cd..6695095c 100644 --- a/Tactical/Item Types.h +++ b/Tactical/Item Types.h @@ -733,7 +733,7 @@ extern OBJECTTYPE gTempObject; // note that these should not be used to determine what kind of an attachment an item is, that is determined by attachmentclass and the AC_xxx flags above //#define EMPTY_SANDBAG 0x00000001 //1 #define MANPAD 0x00000002 //2 // this item is a MAn-Portable Air-Defense System -//#define SHOVEL 0x00000004 //4 // a shovel is used for filling sandbags and other building-related tasks +#define BEARTRAP 0x00000004 //4 // a mechanical trap that does no explosion, but causes leg damage to whoever activates it //#define CONCERTINA 0x00000008 //8 #define WATER_DRUM 0x00000010 //16 // water drums allow to refill canteens in the sector they are in diff --git a/Tactical/SkillCheck.cpp b/Tactical/SkillCheck.cpp index ebd8d3bd..91195b8e 100644 --- a/Tactical/SkillCheck.cpp +++ b/Tactical/SkillCheck.cpp @@ -445,6 +445,14 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) iSkill = (iSkill + 100 * (iSkill / 25) ) / (iSkill / 25 + 1); break; + case PLANTING_MECHANICAL_BOMB_CHECK: + iSkill = EffectiveMechanical( pSoldier ) * 3; + iSkill += EffectiveStrength(pSoldier, FALSE) * 5; + iSkill += EffectiveDexterity( pSoldier, FALSE ) * 1.5f; + iSkill += EffectiveExpLevel( pSoldier ) * 5; + iSkill = iSkill / 10; // bring the value down to a percentage + break; + case DISARM_TRAP_CHECK: fForceDamnSound = TRUE; @@ -565,6 +573,44 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) } break; + case DISARM_MECHANICAL_TRAP_CHECK: + fForceDamnSound = TRUE; + + // SANDRO - electronic traps are based more on mechanical skill + if ( gGameOptions.fNewTraitSystem) + { + // It is impossible without both skills + if ( (EffectiveMechanical( pSoldier ) <= 0) || (EffectiveStrength( pSoldier, FALSE ) <= 0) ) + { + iSkill = 0; + break; + } + else + { + iSkill = EffectiveMechanical( pSoldier ) * 3; + iSkill += EffectiveStrength( pSoldier, FALSE ) * 5; + } + } + else + { + iSkill = __max( EffectiveMechanical( pSoldier ) , EffectiveStrength( pSoldier, FALSE ) ) * 7; + if ( iSkill == 0 ) + { + break; + } + } + iSkill += EffectiveDexterity( pSoldier, FALSE ) * 1.5f; + iSkill += EffectiveExpLevel( pSoldier ) * 5; + iSkill = iSkill / 10; // bring the value down to a percentage + + //JMich_SkillModifiers: Adding a Disarm Trap bonus + bSlot = FindDisarmKit( pSoldier); + if (bSlot != NO_SLOT) + { + iSkill += Item[pSoldier->inv[bSlot].usItem].DisarmModifier * pSoldier->inv[bSlot][0]->data.objectStatus / 100; + } + break; + case OPEN_WITH_CROWBAR: // Add for crowbar... //JMich_SkillModifiers: Changing the +20 to the crowbar's bonus. @@ -708,8 +754,10 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) case ELECTRONIC_LOCKPICKING_CHECK: case PLANTING_BOMB_CHECK: case PLANTING_REMOTE_BOMB_CHECK: + case PLANTING_MECHANICAL_BOMB_CHECK: case DISARM_TRAP_CHECK: case DISARM_ELECTRONIC_TRAP_CHECK: + case DISARM_MECHANICAL_TRAP_CHECK: case ATTACHING_SPECIAL_ITEM_CHECK: case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK: iChance -= 10; @@ -725,8 +773,10 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) case ELECTRONIC_LOCKPICKING_CHECK: case PLANTING_BOMB_CHECK: case PLANTING_REMOTE_BOMB_CHECK: + case PLANTING_MECHANICAL_BOMB_CHECK: case DISARM_TRAP_CHECK: case DISARM_ELECTRONIC_TRAP_CHECK: + case DISARM_MECHANICAL_TRAP_CHECK: case ATTACHING_SPECIAL_ITEM_CHECK: case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK: iChance += 5; @@ -758,6 +808,7 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) case ELECTRONIC_LOCKPICKING_CHECK: case DISARM_TRAP_CHECK: case DISARM_ELECTRONIC_TRAP_CHECK: + case DISARM_MECHANICAL_TRAP_CHECK: case OPEN_WITH_CROWBAR: case SMASH_DOOR_CHECK: case ATTACHING_SPECIAL_ITEM_CHECK: diff --git a/Tactical/SkillCheck.h b/Tactical/SkillCheck.h index 51e41ea3..96f6cd59 100644 --- a/Tactical/SkillCheck.h +++ b/Tactical/SkillCheck.h @@ -39,6 +39,8 @@ enum SkillChecks ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK, DISARM_ELECTRONIC_TRAP_CHECK, ATTACH_POWER_PACK, // Flugente: attach a power pack to power armor + PLANTING_MECHANICAL_BOMB_CHECK, + DISARM_MECHANICAL_TRAP_CHECK, } ; diff --git a/TileEngine/Explosion Control.cpp b/TileEngine/Explosion Control.cpp index 1598a68f..f1a20032 100644 --- a/TileEngine/Explosion Control.cpp +++ b/TileEngine/Explosion Control.cpp @@ -67,6 +67,7 @@ #include "Text.h" // added by SANDRO #include "campaign.h" // yet another one added #include "CampaignStats.h" // added by Flugente +#include "Points.h" // added by Flugente #endif #include "Soldier Macros.h" @@ -3956,6 +3957,95 @@ void HandleExplosionQueue( void ) RemoveItemFromPool( sGridNo, gWorldBombs[ uiWorldBombIndex ].iItemIndex, ubLevel ); } + // beartraps don't cause explosions, but cause special leg damage + else if ( HasItemFlag( pObj->usItem, BEARTRAP ) ) + { + // play sound + UINT16 ubTypeID = Explosive[Item[pObj->usItem].ubClassIndex].ubAnimationID; + + INT32 sSoundID = gExpAniData[ubTypeID].sExplosionSoundID; + + // Randomize + if ( gExpAniData[ubTypeID].sAltExplosionSoundID > NO_ALT_SOUND && sSoundID < 0 ) + sSoundID = gExpAniData[ubTypeID].sAltExplosionSoundID; + + if ( sSoundID > NO_ALT_SOUND ) + PlayJA2Sample( sSoundID, RATE_11025, SoundVolume( HIGHVOLUME, sGridNo ), 1, SoundDir( sGridNo ) ); + + UINT8 ubID = WhoIsThere2( sGridNo, ubLevel ); + + if ( ubID != NOBODY ) + { + SOLDIERTYPE* pSoldier = MercPtrs[ubID]; + + INT16 damage = Explosive[Item[pObj->usItem].ubClassIndex].ubDamage * 0.67f + Random( Explosive[Item[pObj->usItem].ubClassIndex].ubDamage * 0.67f ); + INT16 breathdamage = Explosive[Item[pObj->usItem].ubClassIndex].ubStunDamage * 0.67f + Random( Explosive[Item[pObj->usItem].ubClassIndex].ubStunDamage * 0.67f ); + + pSoldier->SoldierTakeDamage( 0, damage, breathdamage, TAKE_DAMAGE_EXPLOSION, NOBODY, sGridNo, 0, TRUE ); + + // play additional 'hit' sound + PlayJA2SampleFromFile( "Sounds\\beartrap_fleshhit.wav", RATE_11025, SoundVolume( HIGHVOLUME, sGridNo ), 1, SoundDir( sGridNo ) ); + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s activated %s!", pSoldier->GetName( ), Item[pObj->usItem].szItemName ); + + DeductPoints( pSoldier, 200, 0 ); + + SoldierCollapse( pSoldier ); + + // Flugente: disease + HandlePossibleInfection( pSoldier, NULL, INFECTION_TYPE_WOUND_AGI, 1.5f ); + HandlePossibleInfection( pSoldier, NULL, INFECTION_TYPE_WOUND_AGI, 1.5f ); + + INT8 bStatLoss = min( 3 + Random( 5 ) + Random( 8 ), pSoldier->stats.bAgility - 1 ); + + if ( bStatLoss > 0 ) + { + pSoldier->stats.bAgility -= bStatLoss; + + // SANDRO - added this for healing lost stats feature + pSoldier->ubCriticalStatDamage[DAMAGED_STAT_AGILITY] += bStatLoss; + + if ( pSoldier->ubProfile != NO_PROFILE ) + { + gMercProfiles[pSoldier->ubProfile].bAgility = pSoldier->stats.bAgility; + } + + if ( pSoldier->name[0] && pSoldier->bVisible == TRUE ) + { + // make stat RED for a while... + pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock( ); + pSoldier->usValueGoneUp &= ~(AGIL_INCREASE); + + if ( bStatLoss == 1 ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_AGIL], pSoldier->GetName( ) ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_AGIL], pSoldier->GetName( ), bStatLoss ); + } + } + } + } + + // object can be used again + { + OBJECTTYPE newObject; + CreateItem( (*pObj)[0]->data.misc.usBombItem, (*pObj)[0]->data.objectStatus, &newObject ); + + // this is important: delete the tripwire, otherwise we get into an infinite loop if there are two piecs of tripwire.... + RemoveItemFromPool( sGridNo, gWorldBombs[uiWorldBombIndex].iItemIndex, ubLevel ); + + // if no other bomb exists here + CheckForBuriedBombsAndRemoveFlags( sGridNo, ubLevel ); + + // delete the flag, otherwise wire will only work once + (newObject)[0]->data.sObjectFlag &= ~TRIPWIRE_ACTIVATED; + + // now add a tripwire item to the floor, simulating that activating tripwire deactivates it + AddItemToPool( sGridNo, &newObject, 1, ubLevel, 0, -1 ); + } + } // Flugente: handle tripwire gun traps here... // tripwire gets called and activated in ActivateSurroundingTripwire else if ( Item[pObj->usItem].tripwire == 1 )