Covert Ops trait improvements:

- performing suspicious activities renders a spy easily identifiable for a short time (realtime) or until he ha spend enough AP (turnbased). This should make exploiting disguises harder.
- if a spy is closer than COVERT_ELITES_UNCOVER_RADIUS to an elite or officer, they can uncover the spy, depending on uniform worn an experience levels.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7514 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2014-09-13 13:12:46 +00:00
parent 260f09356c
commit a642ab500d
16 changed files with 170 additions and 75 deletions
+1 -1
View File
@@ -2483,7 +2483,7 @@ void LoadSkillTraitsExternalSettings()
gSkillTraitValues.sCODisguiseAPReduction = iniReader.ReadInteger("Covert Ops","COVERT_DISGUISE_PERCENT_AP_REDUCTION", 20, 0, 50);
gSkillTraitValues.sCOCloseDetectionRange = iniReader.ReadInteger("Covert Ops","COVERT_CLOSE_DETECTION_RANGE", 10, 0, 100);
gSkillTraitValues.sCOCloseDetectionRangeSoldierCorpse = iniReader.ReadInteger("Covert Ops","COVERT_CLOSE_DETECTION_RANGE_SOLDIER_CORPSE", 5, 0, 100);
gSkillTraitValues.fCOElitesDetectNextTile = iniReader.ReadBoolean("Covert Ops","COVERT_ELITES_DETECT_NEXTTILE", TRUE);
gSkillTraitValues.usCOEliteUncoverRadius = iniReader.ReadInteger("Covert Ops","COVERT_ELITES_UNCOVER_RADIUS", 6 );
gSkillTraitValues.fCODetectIfBleeding = iniReader.ReadBoolean("Covert Ops","COVERT_DETECTEDIFBLEEDING", FALSE );
// Flugente: RADIO OPERATOR
+1 -1
View File
@@ -1888,7 +1888,7 @@ typedef struct
INT16 sCODisguiseAPReduction;
INT16 sCOCloseDetectionRange;
INT16 sCOCloseDetectionRangeSoldierCorpse;
BOOLEAN fCOElitesDetectNextTile;
UINT16 usCOEliteUncoverRadius;
BOOLEAN fCODetectIfBleeding; // will we be discovered if we are bleeding?
// RADIO OPERATOR
+9 -9
View File
@@ -15,9 +15,9 @@
#ifdef JA2EDITOR
#ifdef JA2UB
CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.7457 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.7514 (Development Build)" };
#else
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.7457 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.7514 (Development Build)" };
#endif
// ------------------------------
@@ -27,11 +27,11 @@
//DEBUG BUILD VERSION
#ifdef JA2UB
CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.7457 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.7514 (Development Build)" };
#elif defined (JA113DEMO)
CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.7457 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.7514 (Development Build)" };
#else
CHAR16 zVersionLabel[256] = { L"Debug: v1.13.7457 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Debug: v1.13.7514 (Development Build)" };
#endif
#elif defined CRIPPLED_VERSION
@@ -46,16 +46,16 @@
//RELEASE BUILD VERSION
#ifdef JA2UB
CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.7457 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.7514 (Development Build)" };
#elif defined (JA113DEMO)
CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.7457 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.7514 (Development Build)" };
#else
CHAR16 zVersionLabel[256] = { L"Release v1.13.7457 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Release v1.13.7514 (Development Build)" };
#endif
#endif
CHAR8 czVersionNumber[16] = { "Build 14.08.30" }; //YY.MM.DD
CHAR8 czVersionNumber[16] = { "Build 14.09.13" }; //YY.MM.DD
CHAR16 zTrackingNumber[16] = { L"Z" };
// SAVE_GAME_VERSION is defined in header, change it there
+18
View File
@@ -13612,6 +13612,24 @@ void TransformationMenuPopup_Arm( OBJECTTYPE* pObj )
gpItemDescSoldier->InventoryExplosion();
}
// Flugente: blowing up bombs in our inventory can be used to indirectly kill as a spy (via mustard gas), so make this a suspicious action
if ( gpItemDescSoldier->usSoldierFlagMask & (SOLDIER_COVERT_CIV | SOLDIER_COVERT_SOLDIER) )
{
// if e perform a suspicious action, we are easier to identify
UINT16 appenalty = 50;
if ( appenalty )
{
// mark us a easily identifiable
gpItemDescSoldier->usSoldierFlagMask |= SOLDIER_COVERT_TEMPORARY_OVERT;
// in realtime mode, remember the second when this event happened. Once suspicion is checked, we are either uncovered or, if enough time has passed, no longer suspicious
// in turnbase mode, remember our current APs. If a new turn has started or enough APs have been used, remove the flag
gpItemDescSoldier->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_SECONDS] = GetWorldTotalSeconds( ) + max( 1, appenalty / 25 );
gpItemDescSoldier->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] = appenalty;
}
}
DeleteObj( pObj );
return;
+9 -2
View File
@@ -873,10 +873,17 @@ void DeductPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost, UINT8 ub
INT16 sNewAP = 0;
INT8 bNewBreath;
// Flugente: if we spend AP, then spotter status ends
if ( sAPCost > 0)
// Flugente: if we spend AP...
if ( sAPCost > 0 )
{
// ... then spotter status ends
pSoldier->usSkillCounter[SOLDIER_COUNTER_SPOTTER] = 0;
// if we are temporarily overt
if ( pSoldier->usSoldierFlagMask & SOLDIER_COVERT_TEMPORARY_OVERT && pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] > 0 )
pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] = max( 0, (INT16)(pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] - sAPCost) );
}
// in real time, there IS no AP cost, (only breath cost)
if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) )
{
+107 -50
View File
@@ -4260,6 +4260,24 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart
}
}
// Flugente: if we are covert and perform a suspicious action, we will be easier to uncover for a short time
if ( this->usSoldierFlagMask & (SOLDIER_COVERT_CIV | SOLDIER_COVERT_SOLDIER) )
{
// if e perform a suspicious action, we are easier to identify
UINT16 appenalty = GetSuspiciousAnimationAPDuration( this->usAnimState );
if ( appenalty )
{
// mark us a easily identifiable
this->usSoldierFlagMask |= SOLDIER_COVERT_TEMPORARY_OVERT;
// in realtime mode, remember the second when this event happened. Once suspicion is checked, we are either uncovered or, if enough time has passed, no longer suspicious
// in turnbase mode, remember our current APs. If a new turn has started or enough APs have been used, remove the flag
this->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_SECONDS] = GetWorldTotalSeconds( ) + max( 1, appenalty / 25 );
this->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] = appenalty;
}
}
// If our own guy...
if ( this->bTeam == gbPlayerNum )
{
@@ -15584,52 +15602,21 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
if ( !(this->usSoldierFlagMask & (SOLDIER_COVERT_CIV | SOLDIER_COVERT_SOLDIER)) )
return FALSE;
// if we are in a suspicious activity: not covert
if ( this->usAnimState == NINJA_SPINKICK ||
this->usAnimState == NINJA_PUNCH ||
this->usAnimState == NINJA_LOWKICK ||
this->usAnimState == PUNCH_LOW ||
this->usAnimState == DECAPITATE ||
this->usAnimState == CROWBAR_ATTACK ||
this->usAnimState == THROW_GRENADE_STANCE ||
this->usAnimState == SHOOT_ROCKET_CROUCHED ||
this->usAnimState == LOB_GRENADE_STANCE ||
this->usAnimState == THROW_KNIFE ||
this->usAnimState == CUTTING_FENCE ||
this->usAnimState == HELIDROP ||
this->usAnimState == THROW_KNIFE_SP_BM ||
this->usAnimState == DODGE_ONE ||
this->usAnimState == SLICE ||
this->usAnimState == STAB ||
this->usAnimState == CROUCH_STAB ||
this->usAnimState == PUNCH ||
this->usAnimState == PUNCH_BREATH ||
this->usAnimState == KICK_DOOR ||
this->usAnimState == CUTTING_FENCE ||
this->usAnimState == PLANT_BOMB ||
this->usAnimState == USE_REMOTE ||
this->usAnimState == STEAL_ITEM ||
this->usAnimState == SHOOT_ROCKET ||
this->usAnimState == TAKE_BLOOD_FROM_CORPSE ||
this->usAnimState == PICK_LOCK ||
this->usAnimState == LOCKPICK_CROUCHED ||
this->usAnimState == STEAL_ITEM_CROUCHED ||
this->usAnimState == JUMPWINDOWS ||
this->usAnimState == FOCUSED_PUNCH ||
this->usAnimState == FOCUSED_STAB ||
this->usAnimState == HTH_KICK ||
this->usAnimState == FOCUSED_HTH_KICK ||
this->usAnimState == LONG_JUMP ||
this->usAnimState == THROW_GRENADE_STANCE ||
this->usAnimState == LOB_GRENADE_STANCE ||
this->usAnimState == THROW_ITEM ||
this->usAnimState == LOB_ITEM ||
this->usAnimState == THROW_ITEM_CROUCHED ||
this->usAnimState == SHOOT_ROCKET_CROUCHED
)
// if we perform suspicious actions, we are easier to uncover for a short time (but not by ourselves if we test the disguise)
if ( ubObserverID != this->ubID && this->usSoldierFlagMask & SOLDIER_COVERT_TEMPORARY_OVERT )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_ACTIVITIES], this->GetName( ) );
return FALSE;
// if enough time ha passed, or we have spend enough AP, lose the flag
if ( this->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] == 0 || GetWorldTotalSeconds( ) >= this->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_SECONDS] )
{
this->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_SECONDS] = 0;
this->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] = 0;
this->usSoldierFlagMask &= ~SOLDIER_COVERT_TEMPORARY_OVERT;
}
else
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_ACTIVITIES], this->GetName( ) );
return FALSE;
}
}
// if we are trying to dress like a civilian, but aren't sucessful: not covert
@@ -15652,7 +15639,7 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
// if we have the skill, our cover will blow if we dress up as a soldier, but not if we are dressed like a civilian
INT32 discoverrange = gSkillTraitValues.sCOCloseDetectionRange;
if ( distance < discoverrange )
if ( ubObserverID != this->ubID && distance < discoverrange )
{
switch ( covertlevel )
{
@@ -15704,10 +15691,18 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
break;
}
// if we are a soldier, elites can uncover us if we are VERY close, and more experienced
if ( this->usSoldierFlagMask & SOLDIER_COVERT_SOLDIER && gSkillTraitValues.fCOElitesDetectNextTile && distance < 2 && EffectiveExpLevel( pSoldier ) > EffectiveExpLevel( this ) + covertlevel )
// if we are disguised as a soldier, elites and officers can uncover us if they are close
if ( this->usSoldierFlagMask & SOLDIER_COVERT_SOLDIER && distance < gSkillTraitValues.usCOEliteUncoverRadius && EffectiveExpLevel( pSoldier ) >= EffectiveExpLevel( this ) + covertlevel )
{
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE )
// officers can uncover us even if we are disguised as an elite
if ( pSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_TOO_CLOSE_TO_OFFICER], this->GetName( ) );
return FALSE;
}
// elites uncover us if we a disguised as an admin or regular
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE && GetUniformType() < UNIFORM_ENEMY_ELITE )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_TOO_CLOSE_TO_ELITE], this->GetName( ) );
return FALSE;
@@ -16381,7 +16376,7 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction( )
this->ChangeSoldierState( CUTTING_FENCE, 0, 0 );
// as setting the new animation costs APBPConstants[AP_USEWIRECUTTERS] APs every time, account for that
this->bActionPoints += APBPConstants[AP_USEWIRECUTTERS];
bOverTurnAPS = max( 0, bOverTurnAPS - APBPConstants[AP_USEWIRECUTTERS] );
}
}
break;
@@ -22328,6 +22323,68 @@ UINT16 GridNoSpotterCTHBonus( SOLDIERTYPE* pSniper, INT32 sGridNo, UINT bTeam )
return bestvalue;
}
// get overt penalty duration in AP for using an animation
UINT16 GetSuspiciousAnimationAPDuration( UINT16 usAnimation )
{
switch ( usAnimation )
{
case NINJA_PUNCH:
case NINJA_LOWKICK:
case PUNCH_LOW:
case CROWBAR_ATTACK:
case DODGE_ONE:
case SLICE:
case STAB:
case CROUCH_STAB:
case PUNCH:
case PUNCH_BREATH:
case KICK_DOOR:
case FOCUSED_PUNCH:
case FOCUSED_STAB:
case HTH_KICK:
case FOCUSED_HTH_KICK:
return 60; break;
case THROW_GRENADE_STANCE:
case LOB_GRENADE_STANCE:
case THROW_KNIFE:
case THROW_KNIFE_SP_BM:
case THROW_ITEM:
case LOB_ITEM:
case THROW_ITEM_CROUCHED:
return 50; break;
case PICKUP_ITEM:
case DROP_ITEM:
return 30; break;
case DECAPITATE:
case TAKE_BLOOD_FROM_CORPSE:
return 50; break;
case PLANT_BOMB:
case USE_REMOTE:
case STEAL_ITEM:
case PICK_LOCK:
case LOCKPICK_CROUCHED:
case STEAL_ITEM_CROUCHED:
return 50; break;
case SHOOT_ROCKET_CROUCHED:
case SHOOT_ROCKET:
case HELIDROP:
case NINJA_SPINKICK:
return 100; break;
case CUTTING_FENCE:
case JUMPWINDOWS:
case LONG_JUMP:
return 60; break;
}
return 0;
}
void SetDamageDisplayCounter( SOLDIERTYPE* pSoldier )
{
INT16 sOffsetX, sOffsetY;
+8 -4
View File
@@ -391,9 +391,9 @@ enum
#define SOLDIER_ENEMY_OBSERVEDTHISTURN 0x08000000 //134217728 // enemy soldier was seen by the player this turn
#define SOLDIER_VIP 0x10000000 //268435456 // soldier is a VIP - the player will likely try to assassinate him
#define SOLDIER_BODYGUARD 0x20000000 //536870912 // soldier is a bodyguard for a VIP
/*#define WH40K_SOLDIER_ILLUSION 0x40000000 //1073741824 // Soldier is an Illusion
#define WH40K_SOLDIER_KILLTHISTURN 0x80000000 //2147483648 // Soldier is on a kill streak*/
#define SOLDIER_BODYGUARD 0x20000000 //536870912 // soldier is a bodyguard for a VIP/*
#define SOLDIER_COVERT_TEMPORARY_OVERT 0x40000000 //1073741824 // we are covert, but just performed a obviously suspicious task. For a short time, we can be uncovered more easily
//#define WH40K_SOLDIER_KILLTHISTURN 0x80000000 //2147483648 // Soldier is on a kill streak*/
// ----------------------------------------------------------------
// ------------------- more flags for soldiers --------------------
@@ -595,6 +595,9 @@ enum {
// Flugente: certain skills/traits/taints require a cooldown timer
enum {
SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_SECONDS = 0,
SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS,
SOLDIER_COOLDOWN_MAX = 20, // enough space for fillers
};
@@ -1746,7 +1749,7 @@ public:
// is our equipment too good for a soldier?
BOOLEAN EquipmentTooGood( BOOLEAN fCloselook );
// does soldier ubObserverID recognize us as his enemy?
BOOLEAN SeemsLegit( UINT8 ubObserverID );
@@ -2010,6 +2013,7 @@ BOOLEAN IsValidArtilleryOrderSector( INT16 sSectorX, INT16 sSectorY, INT8 bSecto
BOOLEAN SectorJammed();
BOOLEAN PlayerTeamIsScanning();
UINT16 GridNoSpotterCTHBonus( SOLDIERTYPE* pSniper, INT32 sGridNo, UINT bTeam); // bonus for snipers firing at this location (we get this if there are spotters)
UINT16 GetSuspiciousAnimationAPDuration( UINT16 usAnimation ); // get overt penalty duration in AP for using an animation
//typedef struct
class OLDSOLDIERTYPE_101
+1
View File
@@ -782,6 +782,7 @@ enum
STR_COVERT_STEAL_FAIL,
STR_COVERT_APPLYITEM_STEAL_FAIL,
STR_COVERT_TOO_CLOSE_TO_ELITE,
STR_COVERT_TOO_CLOSE_TO_OFFICER,
TEXT_NUM_COVERT_STR
};
+2 -1
View File
@@ -8084,7 +8084,8 @@ STR16 szCovertTextStr[]=
L"%s的伪装要被识破了。", // L"%s's disguise will not hold.",
L"%s在偷窃的时候被抓了!", // L"%s was caught stealing!",
L"%s在试图调整%s的物品栏。", // L"%s tried to manipulate %s's inventory."
L"%s太靠近精英士兵了。",
L"An elite soldier did not recognize %s!", // TODO.Translate
L"A officer knew %s was unfamiliar!",
};
STR16 szCorpseTextStr[]=
+2 -1
View File
@@ -8095,7 +8095,8 @@ STR16 szCovertTextStr[]=
L"%s's disguise will not hold.",
L"%s was caught stealing!",
L"%s tried to manipulate %s's inventory.",
L"%s is too close to an elite soldier!", // TODO.Translate
L"An elite soldier did not recognize %s!", // TODO.Translate
L"A officer knew %s was unfamiliar!",
};
STR16 szCorpseTextStr[]=
+2 -1
View File
@@ -8084,7 +8084,8 @@ STR16 szCovertTextStr[]=
L"%s's disguise will not hold.",
L"%s was caught stealing!",
L"%s tried to manipulate %s's inventory.",
L"%s is too close to an elite soldier!",
L"An elite soldier did not recognize %s!",
L"A officer knew %s was unfamiliar!",
};
STR16 szCorpseTextStr[]=
+2 -1
View File
@@ -8086,7 +8086,8 @@ STR16 szCovertTextStr[]=
L"Le déguisement de %s ne marchera pas...",
L"%s a été pris en train de voler !",
L"%s a essayé d'accéder à l'inventaire de %s.",
L"%s est trop près d'un soldat d'élite !",
L"An elite soldier did not recognize %s!", // TODO.Translate
L"A officer knew %s was unfamiliar!",
};
STR16 szCorpseTextStr[]=
+2 -1
View File
@@ -7913,7 +7913,8 @@ STR16 szCovertTextStr[]=
L"%s's Verkleidung wird auffliegen!",
L"%s wurde beim Stehlen erwischt!",
L"%s hat versucht, %s's Azsrüstung zu verändern.",
L"%s ist zu nah an einem Elitesoldat!",
L"Einem Elitesoldat schien %s verdächtig!",
L"Ein Offizier hat %s erkannt!",
};
STR16 szCorpseTextStr[]=
+2 -1
View File
@@ -8090,7 +8090,8 @@ STR16 szCovertTextStr[]=
L"%s's disguise will not hold.",
L"%s was caught stealing!",
L"%s tried to manipulate %s's inventory.",
L"%s is too close to an elite soldier!", // TODO.Translate
L"An elite soldier did not recognize %s!", // TODO.Translate
L"A officer knew %s was unfamiliar!",
};
STR16 szCorpseTextStr[]=
+2 -1
View File
@@ -8107,7 +8107,8 @@ STR16 szCovertTextStr[]=
L"%s's disguise will not hold.",
L"%s was caught stealing!",
L"%s tried to manipulate %s's inventory.",
L"%s is too close to an elite soldier!", // TODO.Translate
L"An elite soldier did not recognize %s!", // TODO.Translate
L"A officer knew %s was unfamiliar!",
};
STR16 szCorpseTextStr[]=
+2 -1
View File
@@ -8077,7 +8077,8 @@ STR16 szCovertTextStr[]=
L"%s: маскировка не выдержит проверки.",
L"%s был пойман на краже!",
L"%s пытался залезть в инвентарь %s.",
L"%s слишком близко к элитному солдату!",
L"An elite soldier did not recognize %s!", // TODO.Translate
L"A officer knew %s was unfamiliar!",
};
STR16 szCorpseTextStr[]=