New feature: mercs with a gun-related trait (New trait system only) can use the 'Focus' skill via the skill menu ([$] in tactical). This skill grants an interrupt modifier bonus in the targeted area, but also a penalty outside of it.

For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=20659&goto=350400&#msg_350400

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8432 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2017-07-26 13:49:38 +00:00
parent 7b00af164b
commit 0992a423e7
27 changed files with 203 additions and 45 deletions
+7
View File
@@ -2254,6 +2254,13 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
}
}
// Flugente: focus trait
if ( MercPtrs[pFace->ubSoldierID]->usSoldierFlagMask2 & SOLDIER_TRAIT_FOCUS )
{
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 17 );
bNumRightIcons++;
}
// Flugente: disease
if ( MercPtrs[pFace->ubSoldierID]->HasDisease(TRUE, FALSE, TRUE) )
{
+3 -3
View File
@@ -230,7 +230,7 @@ SkillSelection::Setup( UINT32 aVal )
pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction<void,UINT32>( &Wrapper_Function_SkillSelection, uiCounter ) );
// if we cannot perform this skill, grey it out
if ( !(pSoldier->CanUseSkill(uiCounter, TRUE)) )
if ( !(pSoldier->CanUseSkill( uiCounter, TRUE, sTraitsMenuTargetGridNo )) )
{
// Set this option off.
pOption->setAvail(new popupCallbackFunction<bool,void*>( &Popup_OptionOff, NULL ));
@@ -262,7 +262,7 @@ SkillSelection::Setup( UINT32 aVal )
{
UINT8 cnt = 0;
switch ( aVal )
{
{
case RADIO_OPERATOR_NT:
{
for(UINT32 uiCounter = SKILLS_RADIO_FIRST; uiCounter <= SKILLS_RADIO_LAST; ++uiCounter)
@@ -739,4 +739,4 @@ void TraitsMenu( INT32 usMapPos )
sTraitsMenuTargetGridNo = usMapPos;
gTraitSelection.Setup(0);
}
}
+52 -18
View File
@@ -17276,7 +17276,7 @@ void SOLDIERTYPE::SoldierPropertyUpkeep( )
}
// check if Soldier can use the spell skillwise, with fAPCheck = TRUE also check current APs
BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck )
BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck, INT32 sGridNo )
{
if ( fAPCheck )
{
@@ -17287,8 +17287,8 @@ BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck )
BOOLEAN canuse = FALSE;
switch ( iSkill )
{
// radio operator
{
// radio operator
case SKILLS_RADIO_ARTILLERY:
if ( (!fAPCheck || EnoughPoints( this, APBPConstants[AP_RADIO], APBPConstants[BP_RADIO], FALSE )) && CanUseRadio( ) )
{
@@ -17317,6 +17317,16 @@ BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck )
canuse = TRUE;
break;
case SKILLS_FOCUS:
// requires sniper trait, an aimed gun and only works on gridnos in our direction
if ( gGameOptions.fNewTraitSystem &&
(HAS_SKILL_TRAIT( this, AUTO_WEAPONS_NT ) || HAS_SKILL_TRAIT( this, HEAVY_WEAPONS_NT ) || HAS_SKILL_TRAIT( this, SNIPER_NT ) ||
HAS_SKILL_TRAIT( this, RANGER_NT ) || HAS_SKILL_TRAIT( this, GUNSLINGER_NT ))
&& this->inv[HANDPOS].exists( ) && Item[this->inv[HANDPOS].usItem].usItemClass & (IC_GUN | IC_LAUNCHER) && WeaponReady( this )
&& sGridNo != NOWHERE && this->ubDirection == GetDirectionFromGridNo( sGridNo, this ) )
canuse = TRUE;
break;
default:
break;
}
@@ -17327,24 +17337,24 @@ BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck )
// use a skill. For safety reasons, this calls CanUseSkill again
BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT8 ID )
{
if ( !CanUseSkill( iSkill, TRUE ) )
if ( !CanUseSkill( iSkill, TRUE, usMapPos ) )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_CANNOT_USE_SKILL] );
return FALSE;
}
switch ( iSkill )
{
// radio operator
// the call for SKILLS_RADIO_ARTILLERY is only used by the AI
{
// radio operator
// the call for SKILLS_RADIO_ARTILLERY is only used by the AI
case SKILLS_RADIO_ARTILLERY:
{
UINT32 sector = 0;
if ( this->CanAnyArtilleryStrikeBeOrdered( &sector ) )
{
return OrderArtilleryStrike( sector, usMapPos, this->bTeam );
}
}
{
UINT32 sector = 0;
if ( this->CanAnyArtilleryStrikeBeOrdered( &sector ) )
{
return OrderArtilleryStrike( sector, usMapPos, this->bTeam );
}
}
break;
case SKILLS_RADIO_JAM:
@@ -17372,6 +17382,20 @@ BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT8 ID )
return BecomeSpotter( usMapPos );
break;
case SKILLS_FOCUS:
// activating skill on same gridno again deactivates it
if ((usSoldierFlagMask2 & SOLDIER_TRAIT_FOCUS) && sFocusGridNo == usMapPos)
{
usSoldierFlagMask2 &= ~SOLDIER_TRAIT_FOCUS;
sFocusGridNo = NOWHERE;
}
else
{
usSoldierFlagMask2 |= SOLDIER_TRAIT_FOCUS;
sFocusGridNo = usMapPos;
}
break;
default:
break;
}
@@ -17395,15 +17419,15 @@ static CHAR16 skilldescarray[500];
// print a small description of the skill if we can use it, or its requirements if we cannot
STR16 SOLDIERTYPE::PrintSkillDesc( INT8 iSkill )
{
CHAR16 atStr[200];
swprintf( skilldescarray, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_REQ] );
if ( CanUseSkill( iSkill, TRUE ) )
{
return pTraitSkillsMenuDescStrings[iSkill];
}
else
{
CHAR16 atStr[200];
swprintf( skilldescarray, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_REQ] );
if ( iSkill >= SKILLS_RADIO_FIRST && iSkill <= SKILLS_RADIO_LAST )
{
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_X_AP], APBPConstants[AP_RADIO] );
@@ -17412,7 +17436,7 @@ STR16 SOLDIERTYPE::PrintSkillDesc( INT8 iSkill )
switch ( iSkill )
{
// radio operator
// radio operator
case SKILLS_RADIO_ARTILLERY:
case SKILLS_RADIO_JAM:
case SKILLS_RADIO_SCAN_FOR_JAM:
@@ -17439,6 +17463,16 @@ STR16 SOLDIERTYPE::PrintSkillDesc( INT8 iSkill )
wcscat( skilldescarray, atStr );
break;
case SKILLS_FOCUS:
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_GUNTRAIT] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_AIMEDGUN] );
wcscat(skilldescarray, atStr);
break;
default:
break;
}
+10 -5
View File
@@ -415,6 +415,7 @@ enum
#define SOLDIER_TAKEN_LARGE_HIT 0x00000800 // we recently received a lot of damage in a single hit
#define SOLDIER_COVERT_NOREDISGUISE 0x00001000 // this soldier does not want to be redisguised
#define SOLDIER_TRAIT_FOCUS 0x00002000 // 'focus' skill is active
#define SOLDIER_INTERROGATE_ALL 0x000001F8 // all interrogation flags
// ----------------------------------------------------------------
@@ -574,7 +575,7 @@ enum
enum{
// first skill
SKILLS_FIRST = 0,
// radio operator
SKILLS_RADIO_FIRST = SKILLS_FIRST,
SKILLS_RADIO_ARTILLERY = SKILLS_RADIO_FIRST,
@@ -588,7 +589,8 @@ enum{
// various
SKILLS_VARIOUS_FIRST,
SKILLS_SPOTTER = SKILLS_VARIOUS_FIRST,
SKILLS_VARIOUS_LAST = SKILLS_SPOTTER,
SKILLS_FOCUS,
SKILLS_VARIOUS_LAST = SKILLS_FOCUS,
SKILLS_MAX,
};
@@ -1525,10 +1527,13 @@ public:
// Flugente: diseases
INT16 sDiseasePoints[NUM_DISEASES]; // we store the state of our diseases here
UINT8 sDiseaseFlag[NUM_DISEASES]; // we need to store some special flags for every disease
// Flugente: Decrease this filler by 1 for each new UINT8 / BOOLEAN variable, so we can maintain savegame compatibility!!
// Note that we also have to account for padding, so you might need to substract more than just the size of the new variables
UINT8 ubFiller[20];
UINT8 ubFiller[16];
// Flugente: focus skill gridno
INT32 sFocusGridNo;
UINT32 usSoldierFlagMask2; // anv: another usSoldierFlagMask
@@ -1858,7 +1863,7 @@ public:
// Flugente: functions for skill usage
// traits can allow use of certain skills
// check if Soldier can use the spell skillwise, with fAPCheck = TRUE also check current APs
BOOLEAN CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck = TRUE );
BOOLEAN CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck = TRUE, INT32 sGridNo = -1 );
// use a skill. For safety reasons, this calls CanUseSkill again (it is possible to switch the soldier while the menu is open)
BOOLEAN UseSkill( UINT8 iSkill, INT32 usMapPos, UINT8 ID );
+25 -1
View File
@@ -1936,6 +1936,30 @@ INT8 CalcInterruptDuelPts( SOLDIERTYPE * pSoldier, UINT8 ubOpponentID, BOOLEAN f
{
iPoints -= 1;
}
// Flugente: focus skill
if ( (pSoldier->usSoldierFlagMask2 & SOLDIER_TRAIT_FOCUS) )
{
if ( pSoldier->CanUseSkill( SKILLS_FOCUS, FALSE, pSoldier->sFocusGridNo ) )
{
// if target is in focus, increase interrupt chance, otherwise lower it
// radius depends on range
INT16 range = PythSpacesAway( pSoldier->sFocusGridNo, pSoldier->sGridNo );
INT16 radius = gSkillTraitValues.ubSNFocusRadius * range / 20;
INT16 range_opponent = PythSpacesAway( pSoldier->sFocusGridNo, MercPtrs[ubOpponentID]->sGridNo );
if ( range_opponent <= radius )
iPoints += gSkillTraitValues.sSNFocusInterruptBonus;
else
iPoints -= 2 * gSkillTraitValues.sSNFocusInterruptBonus;
}
else
{
pSoldier->usSoldierFlagMask2 &= ~SOLDIER_TRAIT_FOCUS;
pSoldier->sFocusGridNo = NOWHERE;
}
}
}
else
{
@@ -1949,7 +1973,7 @@ INT8 CalcInterruptDuelPts( SOLDIERTYPE * pSoldier, UINT8 ubOpponentID, BOOLEAN f
}
}
}
// Flugente: interrupt modifier from special stats
iPoints += pSoldier->GetInterruptModifier( ubDistance );