Files
source/Tactical/SkillCheck.cpp
T
Wanne cde4ce4229 4 new tags in Items.xml that modify skill checks. (by JMich)
- LockPickModifier modifies the lockpick chance by a specific number. If the number is positive, it is proportional to the locksmith kit's status, if the number is negative, it will always be the same. Tag is ignored if the item isn't a LocksmithKit. FindLocksmithKit should return the one that gives the biggest bonus, but it may have trouble with stacked lockpicks. Hovering over the "Locksmith Kit" icon in UDB should tell you how much of a bonus (or penalty) that item gives you.

- CrowbarModifier increases your chances to force open by using a crowbar by the number indicated. Default vanilla crowbar has a bonus of 20, so an item with a bonus of 10 will be worse than a crowbar (but possibly smaller). FindUsableCrowbar should return the item with the biggest bonus. Tag is ignored if the item isn't a Crowbar. Hovering over the "Crowbar" Icon in UDB should tell you by how much your chances are improved, though if the item is also a weapon, the icon isn't visible.

- RepairModifier modifies a toolkit's effectiveness by that percentage. If you try to repair with a shoddy toolkit that has a RepairModifier of -20, you'll be 80% as effective, while repairing with an excellent toolkit that has a RepairModifier of 20 means you are 120% as effective. When checking if you have a toolkit at hand, it should select the one with the biggest bonus. Tag is ignored if item isn't also a Toolkit. Hovering over the "Toolkit" icon in UDB should tell you how effective the repair kit is.

- DisarmModifier increases your chances to disarm a trap by the indicated amount, modified by the Diffusal Kit's status. The FindDisarmKit should return the item with the biggest bonus, though it uses the top item in a stack. Currently using the "Wirecutters" icon in UDB, hovering over it should tell you by how much your trap disarm chance is improved.


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5472 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2012-08-14 15:04:02 +00:00

877 lines
26 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "SkillCheck.h"
#include "Soldier Profile.h"
#include "Random.h"
#include "Items.h"
#include "Dialogue Control.h"
#include "Overhead.h"
#include "Soldier macros.h"
#include "Isometric Utils.h"
#include "Morale.h"
#include "drugs and alcohol.h"
#include "strategicmap.h"
// added by SANDRO
#include "GameSettings.h"
#include "Animation Data.h"
#include "Soldier Control.h"
#endif
extern void ReducePointsForHunger( SOLDIERTYPE *pSoldier, UINT32 *pusPoints );
INT16 EffectiveStrength( SOLDIERTYPE *pSoldier, BOOLEAN fTrainer )
{
INT8 bBandaged;
INT32 iEffStrength;
// Effective strength is:
// 1/2 full strength
// plus 1/2 strength scaled according to how hurt we are
bBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding;
if (pSoldier->stats.bStrength > 0)
{
if ( fTrainer )
{
iEffStrength = pSoldier->stats.bStrength / 2;
iEffStrength += ( pSoldier->stats.bStrength / 2) * (pSoldier->stats.bLife + bBandaged / 2) / (pSoldier->stats.bLifeMax);
}
else
{
iEffStrength = ( pSoldier->stats.bStrength + pSoldier->bExtraStrength )/ 2;
iEffStrength += ( (pSoldier->stats.bStrength + pSoldier->bExtraStrength) / 2) * (pSoldier->stats.bLife + bBandaged / 2) / (pSoldier->stats.bLifeMax);
}
}
else
{
iEffStrength = 0;
}
// ATE: Make sure at least 2...
iEffStrength = __max( iEffStrength, 2 );
return( (INT16) iEffStrength );
}
INT16 EffectiveWisdom( SOLDIERTYPE * pSoldier)
{
INT32 iEffWisdom;
iEffWisdom = pSoldier->stats.bWisdom;
iEffWisdom += pSoldier->bExtraWisdom;
iEffWisdom = EffectStatForBeingDrunk( pSoldier, iEffWisdom );
return( (INT16) iEffWisdom );
}
INT16 EffectiveAgility( SOLDIERTYPE * pSoldier, BOOLEAN fTrainer )
{
INT32 iEffAgility;
iEffAgility = pSoldier->stats.bAgility;
if ( !fTrainer )
iEffAgility += pSoldier->bExtraAgility;
iEffAgility = EffectStatForBeingDrunk( pSoldier, iEffAgility );
if ( pSoldier->sWeightCarriedAtTurnStart > 100 )
{
iEffAgility = (iEffAgility * 100) / pSoldier->sWeightCarriedAtTurnStart;
}
return( (INT16) iEffAgility );
}
INT8 EffectiveMechanical( SOLDIERTYPE * pSoldier )
{
INT32 iEffMechanical;
iEffMechanical = pSoldier->stats.bMechanical;
iEffMechanical = EffectStatForBeingDrunk( pSoldier, iEffMechanical );
return( (INT8) iEffMechanical );
}
INT8 EffectiveExplosive( SOLDIERTYPE * pSoldier )
{
INT32 iEffExplosive;
iEffExplosive = pSoldier->stats.bExplosive;
iEffExplosive = EffectStatForBeingDrunk( pSoldier, iEffExplosive );
return( (INT8) iEffExplosive );
}
INT8 EffectiveMedical( SOLDIERTYPE * pSoldier )
{
INT32 iEffMedical;
iEffMedical = pSoldier->stats.bMedical;
iEffMedical = EffectStatForBeingDrunk( pSoldier, iEffMedical );
return( (INT8) iEffMedical );
}
INT8 EffectiveLeadership( SOLDIERTYPE * pSoldier )
{
INT32 iEffLeadership;
INT8 bDrunkLevel;
iEffLeadership = pSoldier->stats.bLeadership;
// if we are drunk, effect leader ship in a +ve way...
bDrunkLevel = GetDrunkLevel( pSoldier );
if ( bDrunkLevel == FEELING_GOOD )
{
iEffLeadership = ( iEffLeadership * 120 / 100 );
}
return( (INT8) iEffLeadership );
}
INT8 EffectiveExpLevel( SOLDIERTYPE * pSoldier )
{
INT32 iEffExpLevel;
INT8 bDrunkLevel;
INT32 iExpModifier[] =
{ 0, // SOBER
0, // Feeling good
-1, // Borderline
-2, // Drunk
0, // Hung
};
iEffExpLevel = pSoldier->stats.bExpLevel;
// SANDRO - STOMP traits - Squadleader bonus to effective level
if ( gGameOptions.fNewTraitSystem && IS_MERC_BODY_TYPE( pSoldier ))
{
iEffExpLevel += (gSkillTraitValues.ubSLEffectiveLevelInRadius * GetSquadleadersCountInVicinity( pSoldier, TRUE, FALSE ));
}
bDrunkLevel = GetDrunkLevel( pSoldier );
iEffExpLevel = iEffExpLevel + iExpModifier[ bDrunkLevel ];
if (pSoldier->ubProfile != NO_PROFILE)
{
// Flugente: drugs can temporarily cause a merc to be claustrophobic
if ( ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == CLAUSTROPHOBIC) || MercUnderTheInfluence(pSoldier, DRUG_TYPE_CLAUSTROPHOBIC) ) && pSoldier->bActive && pSoldier->bInSector && gbWorldSectorZ > 0)
{
// claustrophobic!
iEffExpLevel -= 2;
}
else if ( ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == FEAR_OF_INSECTS) || MercUnderTheInfluence(pSoldier, DRUG_TYPE_FEAROFINSECTS) )&& MercIsInTropicalSector( pSoldier ) )
{
// SANDRO - fear of insects, and we are in tropical sector
iEffExpLevel -= 1;
}
}
iEffExpLevel += pSoldier->bExtraExpLevel;
if (iEffExpLevel > 10)
{
// can't go over 10 - SANDRO
return( 10 );
}
else if (iEffExpLevel < 1)
{
// can't go below 1
return( 1 );
}
else
{
return( (INT8) iEffExpLevel );
}
}
INT8 EffectiveMarksmanship( SOLDIERTYPE * pSoldier )
{
INT32 iEffMarksmanship;
iEffMarksmanship = pSoldier->stats.bMarksmanship;
iEffMarksmanship = EffectStatForBeingDrunk( pSoldier, iEffMarksmanship );
return( (INT8) iEffMarksmanship );
}
INT16 EffectiveDexterity( SOLDIERTYPE * pSoldier, BOOLEAN fTrainer )
{
INT32 iEffDexterity;
iEffDexterity = pSoldier->stats.bDexterity;
if ( !fTrainer )
iEffDexterity += pSoldier->bExtraDexterity;
iEffDexterity = EffectStatForBeingDrunk( pSoldier, iEffDexterity );
return( (INT16) iEffDexterity );
}
UINT8 GetPenaltyForFatigue( SOLDIERTYPE *pSoldier )
{
UINT8 ubPercentPenalty;
if ( pSoldier->bBreathMax >= 85 ) ubPercentPenalty = 0;
else if ( pSoldier->bBreathMax >= 70 ) ubPercentPenalty = 10;
else if ( pSoldier->bBreathMax >= 50 ) ubPercentPenalty = 25;
else if ( pSoldier->bBreathMax >= 30 ) ubPercentPenalty = 50;
else if ( pSoldier->bBreathMax >= 15 ) ubPercentPenalty = 75;
else if ( pSoldier->bBreathMax > 0 ) ubPercentPenalty = 90;
else ubPercentPenalty = 100;
return( ubPercentPenalty );
}
void ReducePointsForFatigue( SOLDIERTYPE *pSoldier, UINT32 *pusPoints )
{
*pusPoints -= (*pusPoints * GetPenaltyForFatigue( pSoldier )) / 100;
}
INT32 GetSkillCheckPenaltyForFatigue( SOLDIERTYPE *pSoldier, INT32 iSkill )
{
// use only half the full effect of fatigue for skill checks
return( ( (iSkill * GetPenaltyForFatigue( pSoldier ) ) / 100) / 2 );
}
INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod )
{
INT32 iSkill;
INT32 iChance, iReportChance;
INT32 iRoll, iMadeItBy;
INT32 iLoop;
SOLDIERTYPE * pTeamSoldier;
INT8 bBuddyIndex;
BOOLEAN fForceDamnSound = FALSE;
iReportChance = -1;
switch (bReason)
{
case LOCKPICKING_CHECK:
case ELECTRONIC_LOCKPICKING_CHECK:
INT8 bSlot;
fForceDamnSound = TRUE;
iSkill = EffectiveMechanical( pSoldier );
if (iSkill == 0)
{
break;
}
// adjust skill based on wisdom (knowledge)
iSkill = iSkill * (EffectiveWisdom( pSoldier ) + 100) / 200;
// and dexterity (clumsy?)
iSkill = iSkill * (EffectiveDexterity( pSoldier, FALSE ) + 100) / 200;
// factor in experience
iSkill = iSkill + EffectiveExpLevel( pSoldier ) * 3;
// SANDRO - STOMP traits - Technician trait lockpicking bonus
if ( gGameOptions.fNewTraitSystem )
{
iSkill += gSkillTraitValues.bCheckModifierLockpicking; // reduce skill value for untrained mercs
// Simply reduce the skill value for this as usual
if (bReason == ELECTRONIC_LOCKPICKING_CHECK)
{
iSkill /= 2;
}
// then add a flat bonus (undivided by the electronic lock penalty above)
if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ))
{
iSkill += gSkillTraitValues.usTELockpickingBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT );
}
}
else // original code
{
if (HAS_SKILL_TRAIT( pSoldier, LOCKPICKING_OT ) )
{
// if we specialize in picking locks...
iSkill += gbSkillTraitBonus[LOCKPICKING_OT] * NUM_SKILL_TRAITS( pSoldier, LOCKPICKING_OT );
}
if (bReason == ELECTRONIC_LOCKPICKING_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT)) )
{
// if we are unfamiliar with electronics...
iSkill /= 2;
}
}
// adjust chance based on status of kit
bSlot = FindLocksmithKit( pSoldier );
if (bSlot == NO_SLOT)
{
// this should never happen, but might as well check...
iSkill = 0;
}
else
{
//JMich_SkillsModifiers: Modifying the skill by the bonus from the lockpick, then reducing due to status
iSkill += Item[pSoldier->inv[bSlot].usItem].LockPickModifier;
}
//JMich_SkillsModifiers: If skill goes negative due to crappy lockpicks, the status of them doesn't matter.
if (iSkill > 0)
{
iSkill = (iSkill * pSoldier->inv[bSlot][0]->data.objectStatus) / 100;
}
break;
case ATTACHING_DETONATOR_CHECK:
case ATTACHING_REMOTE_DETONATOR_CHECK:
iSkill = EffectiveExplosive( pSoldier );
if (iSkill == 0)
{
break;
}
iSkill = (iSkill * 3 + EffectiveDexterity( pSoldier, FALSE ) ) / 4;
// SANDRO - STOMP traits - Demolitions trait detonator attaching bonus
if ( gGameOptions.fNewTraitSystem )
{
iSkill += gSkillTraitValues.bCheckModifierAttachDetonators; // reduce skill value for untrained mercs
if ( bReason == ATTACHING_REMOTE_DETONATOR_CHECK )
{
iSkill /= 2;
}
// add a flat bonus instead of eliminating the penalty above
if ( HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT ))
{
iSkill += gSkillTraitValues.ubDEAttachDetonatorCheckBonus;
}
}
else // original code
{
if ( bReason == ATTACHING_REMOTE_DETONATOR_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT )) )
{
iSkill /= 2;
}
}
break;
case PLANTING_BOMB_CHECK:
case PLANTING_REMOTE_BOMB_CHECK:
iSkill = EffectiveExplosive( pSoldier ) * 7;
iSkill += EffectiveWisdom( pSoldier ) * 2;
iSkill += EffectiveExpLevel( pSoldier ) * 10;
iSkill = iSkill / 10; // bring the value down to a percentage
// SANDRO - STOMP traits - Demolitions trait planting bombs bonus
if ( gGameOptions.fNewTraitSystem )
{
iSkill += gSkillTraitValues.bCheckModifierSetExplosives; // reduce skill for untrained mercs
if ( bReason == PLANTING_REMOTE_BOMB_CHECK )
{
iSkill = (iSkill * 3) / 4;
}
// add a flat bonus instead of eliminating the penalty above
if ( HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT ))
{
iSkill += gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus;
}
}
else // original code
{
if ( bReason == PLANTING_REMOTE_BOMB_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT)) )
{
// deduct only a bit...
iSkill = (iSkill * 3) / 4;
}
}
// Ok, this is really damn easy, so skew the values...
// e.g. if calculated skill is 84, skewed up to 96
// 51 to 84
// 22 stays as is
iSkill = (iSkill + 100 * (iSkill / 25) ) / (iSkill / 25 + 1);
break;
case DISARM_TRAP_CHECK:
fForceDamnSound = TRUE;
// SANDRO - normal(exploding) traps should be based at least a little on mechanical skill as well
if ( gGameOptions.fNewTraitSystem)
{
// It is impossible without both skills
if ( (EffectiveMechanical( pSoldier ) <= 0) || (EffectiveExplosive( pSoldier ) <= 0) )
{
iSkill = 0;
break;
}
else
{
iSkill = EffectiveExplosive( pSoldier ) * 5;
iSkill += EffectiveMechanical( pSoldier ) * 2;
}
}
else
{
iSkill = EffectiveExplosive( pSoldier ) * 7;
if ( iSkill == 0 )
{
break;
}
}
iSkill += EffectiveDexterity( pSoldier, FALSE ) * 2;
iSkill += EffectiveExpLevel( pSoldier ) * 10;
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;
}
// SANDRO - STOMP traits - Demolitions trait removing traps bonus
if ( gGameOptions.fNewTraitSystem )
{
iSkill += gSkillTraitValues.bCheckModifierDisarmExplosiveTraps; // -15% for untrained mercs
if (HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT ))
iSkill += gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus; // +50% bonus for Demolitions
}
// penalty based on poor wisdom
iSkill -= (100 - EffectiveWisdom( pSoldier ) ) / 5;
break;
case DISARM_ELECTRONIC_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) || (EffectiveExplosive( pSoldier ) <= 0) )
{
iSkill = 0;
break;
}
else
{
iSkill = EffectiveExplosive( pSoldier ) * 2;
iSkill += EffectiveMechanical( pSoldier ) * 5;
}
}
else
{
iSkill = __max( EffectiveMechanical( pSoldier ) , EffectiveExplosive( pSoldier ) ) * 7;
if ( iSkill == 0 )
{
break;
}
}
iSkill += EffectiveDexterity( pSoldier, FALSE ) * 2;
iSkill += EffectiveExpLevel( pSoldier ) * 10;
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;
}
// penalty based on poor wisdom
iSkill -= (100 - EffectiveWisdom( pSoldier ) ) / 5;
// SANDRO - STOMP traits - Technician trait removing traps bonus
if ( gGameOptions.fNewTraitSystem )
{
iSkill += gSkillTraitValues.bCheckModifierDisarmElectronicTraps; // penalty for untrained mercs
iSkill = (iSkill * 3) / 4; // original penalty
// add a flat bonus instead of eliminating the penalty above
if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ))
{
iSkill += gSkillTraitValues.usTEDisarmElTrapBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT );
}
}
else // original code
{
if ( !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT)) )
{
iSkill = (iSkill * 3) / 4;
}
}
break;
case OPEN_WITH_CROWBAR:
// Add for crowbar...
//JMich_SkillModifiers: Changing the +20 to the crowbar's bonus.
bSlot = FindUsableCrowbar( pSoldier );
if (bSlot != NO_SLOT)
{
iSkill = EffectiveStrength( pSoldier, FALSE ) + Item[pSoldier->inv[bSlot].usItem].CrowbarModifier;
}
else //how are we trying to force with a crowbar, without having one??
{
iSkill = 0;
}
fForceDamnSound = TRUE;
break;
case SMASH_DOOR_CHECK:
iSkill = EffectiveStrength( pSoldier, FALSE );
// SANDRO - STOMP traits - Martial Arts trait kick doors bonus
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ))
{
iSkill += gSkillTraitValues.ubMAChanceToCkickDoors * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT );
}
break;
case UNJAM_GUN_CHECK:
iSkill = 30 + EffectiveMechanical( pSoldier ) / 2;
// SANDRO - STOMP traits - Technician trait unjamming guns bonus
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ))
{
iSkill += gSkillTraitValues.ubTEUnjamGunBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT );
}
break;
case NOTICE_DART_CHECK:
// only a max of ~20% chance
iSkill = EffectiveWisdom( pSoldier ) / 10 + EffectiveExpLevel( pSoldier );
break;
case LIE_TO_QUEEN_CHECK:
// competitive check vs the queen's wisdom and leadership... poor guy!
iSkill = 50 * ( EffectiveWisdom( pSoldier ) + EffectiveLeadership( pSoldier ) ) / ( gMercProfiles[ QUEEN ].bWisdom + gMercProfiles[ QUEEN ].bLeadership );
// squadleader has bonus for this, muhehe - SANDRO
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SQUADLEADER_NT ))
{
iSkill += (20 * NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT ));
}
break;
case ATTACHING_SPECIAL_ITEM_CHECK:
case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK:
iSkill = EffectiveMechanical( pSoldier );
if (iSkill == 0)
{
break;
}
// adjust skill based on wisdom (knowledge)
iSkill = iSkill * (EffectiveWisdom( pSoldier ) + 100) / 200;
// and dexterity (clumsy?)
iSkill = iSkill * (EffectiveDexterity( pSoldier, FALSE ) + 100) / 200;
// factor in experience
iSkill = iSkill + EffectiveExpLevel( pSoldier ) * 3;
// SANDRO - STOMP traits - Technician trait attaching special items bonus
if ( gGameOptions.fNewTraitSystem )
{
iSkill += gSkillTraitValues.bCheckModifierAttachSpecialItems; // penalty for untrained mercs
if ( bReason == ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK )
{
iSkill /= 2;
}
// add a flat bonus instead of eliminating the penalty above
if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ))
{
iSkill += gSkillTraitValues.usTEAttachingItemsBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT );
}
}
else // original code
{
if (bReason == ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT)) )
{
// if we are unfamiliar with electronics...
iSkill /= 2;
}
}
break;
case ATTACH_POWER_PACK: // added by Flugente
// technicians can attach it, other people can'
if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ))
iSkill = 100;
else
iSkill = 0;
break;
default:
iSkill = 0;
break;
}
iSkill -= GetSkillCheckPenaltyForFatigue( pSoldier, iSkill );
iChance = iSkill + bChanceMod;
////////////////////////////////////////////////////////////////////////
// SANDRO - STOMP - character traits and disabilities modifiers
//added heat intolerant penalty
if ( MercIsHot( pSoldier ) )
{
iChance -= 15;
}
// also added a small penalty for fear of insects in tropical sectors
else if ( ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == FEAR_OF_INSECTS) || MercUnderTheInfluence(pSoldier, DRUG_TYPE_FEAROFINSECTS) ) && MercIsInTropicalSector( pSoldier ))
{
// fear of insects, and we are in tropical sector
iChance -= 5;
}
// character traits influence
// Sociable - better performance in groups
if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SOCIABLE )
{
INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SOCIABLE );
if ( bNumMercs > 2 )
iChance += 5;
else if ( bNumMercs > 0 )
iChance += 2;
}
// Loner - better performance when alone
else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_LONER )
{
INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_LONER );
if ( bNumMercs == 0 )
iChance += 5;
else if ( bNumMercs <= 1 )
iChance += 2;
}
// Aggressive - penalty for actions needing patience
else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE )
{
switch ( bReason )
{
case LOCKPICKING_CHECK:
case ELECTRONIC_LOCKPICKING_CHECK:
case PLANTING_BOMB_CHECK:
case PLANTING_REMOTE_BOMB_CHECK:
case DISARM_TRAP_CHECK:
case DISARM_ELECTRONIC_TRAP_CHECK:
case ATTACHING_SPECIAL_ITEM_CHECK:
case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK:
iChance -= 10;
break;
}
}
// Phlegmatic - bonus for actions needing patience
else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_PHLEGMATIC )
{
switch ( bReason )
{
case LOCKPICKING_CHECK:
case ELECTRONIC_LOCKPICKING_CHECK:
case PLANTING_BOMB_CHECK:
case PLANTING_REMOTE_BOMB_CHECK:
case DISARM_TRAP_CHECK:
case DISARM_ELECTRONIC_TRAP_CHECK:
case ATTACHING_SPECIAL_ITEM_CHECK:
case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK:
iChance += 5;
break;
}
}
// Show-off - better performance if some babes around to impress
else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF )
{
INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SHOWOFF );
if ( bNumMercs > 1 )
iChance += 5;
else if ( bNumMercs > 0 )
iChance += 2;
}
//////////////////////////////////////////////////////////////////////
// CHRISL: If lock is flagged OPENING_NOT_POSSIBLE, then reset iChance to 0 regardless of mercs skills. Also, moved this check to after personality and
// disability checks since an unopenable door isn't going to suddenly be openable just cause we have some other bonus.
if(bChanceMod == -100)
iChance = 0;
// silversurfer: moved this down here where it belongs
// if this wasn't the last check a merc with certain disability modifiers would never completely fail
// to do something and would never do his speech telling that he can't do this
switch (bReason)
{
case LOCKPICKING_CHECK:
case ELECTRONIC_LOCKPICKING_CHECK:
case DISARM_TRAP_CHECK:
case DISARM_ELECTRONIC_TRAP_CHECK:
case OPEN_WITH_CROWBAR:
case SMASH_DOOR_CHECK:
case ATTACHING_SPECIAL_ITEM_CHECK:
case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK:
// for lockpicking and smashing locks, if the chance isn't reasonable
// we set it to 0 so they can never get through the door if they aren't
// good enough
//CHRISL: with this set to 30, some "hard" to open doors become basically impossible. Case in point, Drassen "dentist office" which imposes a
// -75 penalty on lockpicking/forcing chances. You find this near the start of the game but would need an 80 STR + Crowbar to open. It's
// impossible to force with just strength or lockpicking skills, regardless of how skilled you are.
if (iChance < 15)
{
iChance = 0;
break;
}
// else fall through
default:
iChance += GetMoraleModifier( pSoldier );
break;
}
if (iChance > 99)
{
iChance = 99;
}
else if (iChance < 0)
{
iChance = 0;
}
iRoll = PreRandom( 100 );
iMadeItBy = iChance - iRoll;
if (iMadeItBy < 0)
{
if ( (pSoldier->bLastSkillCheck == bReason) && (pSoldier->sGridNo == pSoldier->sSkillCheckGridNo) )
{
pSoldier->ubSkillCheckAttempts++;
if (pSoldier->ubSkillCheckAttempts > 2)
{
if (iChance == 0)
{
if ( MercIsHot( pSoldier ) && pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__PLAYER_CHARACTER) // SANDRO - added this
{
TacticalCharacterDialogue( pSoldier, QUOTE_PERSONALITY_TRAIT );
}
// do we realize that we just can't do this?
if ( (100 - (pSoldier->ubSkillCheckAttempts - 2) * 20) < EffectiveWisdom( pSoldier ) )
{
// say "I can't do this" quote
TacticalCharacterDialogue( pSoldier, QUOTE_DEFINITE_CANT_DO );
return( iMadeItBy );
}
}
}
}
else
{
pSoldier->bLastSkillCheck = bReason;
pSoldier->ubSkillCheckAttempts = 1;
pSoldier->sSkillCheckGridNo = pSoldier->sGridNo;
}
if ( fForceDamnSound || Random( 100 ) < 40 )
{
switch( bReason )
{
case UNJAM_GUN_CHECK:
case NOTICE_DART_CHECK:
case LIE_TO_QUEEN_CHECK:
// silent check
break;
default:
pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
break;
}
}
}
else
{
// A buddy might make a positive comment based on our success;
// Increase the chance for people with higher skill and for more difficult tasks
iChance = 15 + iSkill / 20 + (-bChanceMod) / 20;
if (iRoll < iChance)
{
// If a buddy of this merc is standing around nearby, they'll make a positive comment.
iLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
for ( pTeamSoldier = MercPtrs[ iLoop ]; iLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; iLoop++,pTeamSoldier++ )
{
if ( OK_INSECTOR_MERC( pTeamSoldier ) )
{
bBuddyIndex = WhichBuddy( pTeamSoldier->ubProfile, pSoldier->ubProfile );
if (bBuddyIndex >= 0 && SpacesAway( pSoldier->sGridNo, pTeamSoldier->sGridNo ) < 15)
{
switch( bBuddyIndex )
{
case 0:
// buddy #1 did something good!
TacticalCharacterDialogue( pTeamSoldier, QUOTE_BUDDY_1_GOOD );
break;
case 1:
// buddy #2 did something good!
TacticalCharacterDialogue( pTeamSoldier, QUOTE_BUDDY_2_GOOD );
break;
case 2:
// learn to like buddy did something good!
TacticalCharacterDialogue( pTeamSoldier, QUOTE_LEARNED_TO_LIKE_WITNESSED );
break;
default:
break;
}
}
}
}
}
}
return( iMadeItBy );
}
INT16 CalcTrapDetectLevel( SOLDIERTYPE * pSoldier, BOOLEAN fExamining )
{
// return the level of trap which the guy is able to detect
INT16 bDetectLevel;
// formula: 1 pt for every exp_level
// plus 1 pt for every 40 explosives
// less 1 pt for every 20 wisdom MISSING
bDetectLevel = EffectiveExpLevel( pSoldier );
bDetectLevel += (EffectiveExplosive( pSoldier ) / 40);
bDetectLevel -= ((100 - EffectiveWisdom( pSoldier ) ) / 20);
// STOMP traits - Technician trait detecting traps bonus - SANDRO
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ))
{
bDetectLevel += (gSkillTraitValues.ubTEChanceToDetectTrapsBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT )); // +2 trap level per trait
}
// if the examining flag is true, this isn't just a casual glance
// and the merc should have a higher chance
if (fExamining)
{
bDetectLevel += (INT8) PreRandom(bDetectLevel / 3 + 2);
}
// SANDRO - optimists just don't even think about the traps, randomly ignoring this all
else if ( gGameOptions.fNewTraitSystem && gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_OPTIMIST )
{
if ( Chance(50) )
bDetectLevel = 1;
else
bDetectLevel -= 2;
}
// if substantially bleeding, or still in serious shock, randomly lower value
if ((pSoldier->bBleeding > 20) || (pSoldier->aiData.bShock > 1))
{
bDetectLevel -= (INT8) PreRandom(3);
}
if (bDetectLevel < 1)
{
bDetectLevel = 1;
}
return( bDetectLevel );
}