mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
- 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
877 lines
26 KiB
C++
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 );
|
|
}
|