New feature: turncoats can be created from enemies and ordered to switch sides

Requires GameDir >= r2535

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

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8811 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2020-05-30 00:13:42 +00:00
parent 0f13599775
commit c5022fa1e5
44 changed files with 1587 additions and 140 deletions
+4
View File
@@ -2577,6 +2577,10 @@ void LoadSkillTraitsExternalSettings()
// Flugente: as the 'redisguise after x turns' part is missing the x turns part, this is now permanently set to TRUE until that changes
gSkillTraitValues.fCOStripIfUncovered = TRUE;// iniReader.ReadBoolean( "Covert Ops", "COVERT_STRIPIFUNCOVERED", FALSE );
gSkillTraitValues.fCOTurncoats = iniReader.ReadBoolean( "Covert Ops", "COVERT_TURNCOATS", TRUE );
gSkillTraitValues.fCOTurncoats_SectorActivationRequiresRadioOperator = iniReader.ReadBoolean( "Covert Ops", "COVERT_TURNCOATS_SECTOR_ACTIVATION_REQUIRES_RADIOOPERATOR", FALSE );
gSkillTraitValues.sCOTurncoats_PlayerConvinctionBonus = iniReader.ReadInteger( "Covert Ops", "COVERT_TURNCOATS_PLAYER_CONVINCTION_BONUS", 0, -100, 100 );
// Flugente: RADIO OPERATOR
gSkillTraitValues.fROAllowArtillery = iniReader.ReadBoolean("Radio Operator","RADIO_OPERATOR_ARTILLERY", TRUE);
+3
View File
@@ -1927,6 +1927,9 @@ typedef struct
UINT16 usCOEliteUncoverRadius;
BOOLEAN fCODetectIfBleeding; // will we be discovered if we are bleeding?
BOOLEAN fCOStripIfUncovered;
BOOLEAN fCOTurncoats; // can we create enemy turncoats that can be ordered to betray their comrades?
BOOLEAN fCOTurncoats_SectorActivationRequiresRadioOperator; // activating turncoats sector-wide requires a radio operator
INT32 sCOTurncoats_PlayerConvinctionBonus;
// RADIO OPERATOR
BOOLEAN fROAllowArtillery; // artillery can be forbidden for all teams with this setting
+2 -2
View File
@@ -55,8 +55,8 @@
#endif
CHAR8 czVersionNumber[16] = { "Build 20.05.17" }; //YY.MM.DD
CHAR8 czVersionNumber[16] = { "Build 20.05.30" }; //YY.MM.DD
CHAR16 zTrackingNumber[16] = { L"Z" };
CHAR16 zRevisionNumber[16] = { L"Revision 8804" };
CHAR16 zRevisionNumber[16] = { L"Revision 8811" };
// SAVE_GAME_VERSION is defined in header, change it there
+4 -2
View File
@@ -516,11 +516,13 @@ STR16 OperationText( UINT32 aNum )
STR16 operationame = GetIncidentName( battlereport.id );
if ( battlereport.flagmask & MILITIA_BATTLEREPORT_FLAG_RECRUITED )
if ( battlereport.flagmask & (MILITIA_BATTLEREPORT_FLAG_RECRUITED| MILITIA_BATTLEREPORT_FLAG_RECRUITED_TURNCOAT) )
{
STR16 originsectorstr = militia.GetOriginSector( );
if ( militia.origin == MO_PMC )
if ( battlereport.flagmask & MILITIA_BATTLEREPORT_FLAG_RECRUITED_TURNCOAT )
swprintf( gMilitiaOperationText, szIndividualMilitiaBattleReportText[11], day, hours, minutes, originsectorstr );
else if ( militia.origin == MO_PMC )
swprintf( gMilitiaOperationText, szIndividualMilitiaBattleReportText[8], day, hours, minutes, originsectorstr );
else if ( militia.origin == MO_DEFECTOR )
swprintf( gMilitiaOperationText, szIndividualMilitiaBattleReportText[9], day, hours, minutes, originsectorstr );
+7
View File
@@ -8223,6 +8223,13 @@ void AssignPersonnelSkillTraitHelpText( UINT8 ubTraitNumber, BOOLEAN fExpertLeve
INT16 apreduction = ( gSkillTraitValues.sCODisguiseAPReduction * (fExpertLevel ? 2 : 1));
swprintf( atStr, gzIMPMajorTraitsHelpTextsCovertOps[6], apreduction, sSpecialCharacters[0]);
wcscat( apStr, atStr );
if ( gSkillTraitValues.fCOTurncoats )
{
swprintf( atStr, gzIMPMajorTraitsHelpTextsCovertOps[7] );
wcscat( apStr, atStr );
}
break;
}
+7 -5
View File
@@ -6671,13 +6671,13 @@ void HandleSpyAssignments()
if ( Chance( uncoverrisk ) )
{
// if we are already in hiding, we will be uncovered
if ( pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] )
if ( pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] > 10 )
vector_uncoveredmercs.push_back( uiCnt );
// we get a penalty, and a chance to be uncovered
pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] += 2 + Random( 3 );
pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] += 20 + Random( 30 );
ScreenMsg( FONT_MCOLOR_RED, MSG_INTERFACE, szIntelText[1], pSoldier->GetName(), (pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] - 1) );
ScreenMsg( FONT_MCOLOR_RED, MSG_INTERFACE, szIntelText[1], pSoldier->GetName(), (pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] - 10) / 10 );
continue;
}
@@ -6688,8 +6688,10 @@ void HandleSpyAssignments()
}
// penalty runs out for every soldier, regardless of whether they are on an intel assignment
if ( pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] )
pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY]--;
if ( pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] > 10)
pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] -= 10;
else
pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] = 0;
}
}
+7 -1
View File
@@ -570,7 +570,13 @@ typedef struct SECTORINFO
// Flugente: burial assignment
FLOAT dBurial_UnappliedProgress; // progress done via assignment work. This way no work gets lost
INT8 bPadding[ 12 ];
// Flugente: number of turncoats
UINT8 ubNumAdmins_Turncoat;
UINT8 ubNumTroops_Turncoat;
UINT8 ubNumElites_Turncoat;
UINT8 bPadding_1;
INT8 bPadding[ 8 ];
}SECTORINFO;
+30
View File
@@ -6636,6 +6636,15 @@ UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
fCount = TRUE;
}
}
// Flugente: turncoats allow vision as well
if ( gSkillTraitValues.fCOTurncoats
&& TurncoatsInSector( sSectorX, sSectorY ) )
{
fDetection = TRUE;
fCount = TRUE;
fDirection = TRUE;
}
// Flugente: we can buy info on enemy groups with intel
GetInfoFromGroupsInSector( sSectorX, sSectorY, ENEMY_TEAM, fDetection, fCount, fDirection );
@@ -8466,6 +8475,27 @@ void DetermineMapIntelData( INT32 asSectorZ )
}
}
}
// Flugente: turncoats
if ( gSkillTraitValues.fCOTurncoats )
{
for ( UINT16 sector = 0; sector < 256; ++sector )
{
CorrectTurncoatCount( SECTORX( sector ), SECTORY( sector ) );
UINT16 numturncoats = NumTurncoatsOfClassInSector( SECTORX( sector ), SECTORY( sector ), SOLDIER_CLASS_ADMINISTRATOR )
+ NumTurncoatsOfClassInSector( SECTORX( sector ), SECTORY( sector ), SOLDIER_CLASS_ARMY )
+ NumTurncoatsOfClassInSector( SECTORX( sector ), SECTORY( sector ), SOLDIER_CLASS_ELITE );
if ( numturncoats )
{
CHAR16 str[128];
swprintf( str, szTurncoatText[9], numturncoats );
AddIntelAndQuestMapDataForSector( SECTORX( sector ), SECTORY( sector ), -1, 23, str, L"" );
}
}
}
}
// add lua data
+97
View File
@@ -580,6 +580,103 @@ UINT32 CreateNewIndividualMilitia( UINT8 aMilitiaRank, UINT8 aOrigin, UINT8 aSec
return newmilitia.id;
}
UINT32 CreateNewIndividualMilitiaFromSoldier( SOLDIERTYPE* pSoldier, UINT8 aOrigin )
{
if ( !gGameExternalOptions.fIndividualMilitia || !pSoldier )
return 0;
MILITIA newmilitia;
newmilitia.id = GetFreeIndividualMilitiaId();
switch ( pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_BANDIT:
newmilitia.militiarank = GREEN_MILITIA;
break;
case SOLDIER_CLASS_ELITE:
case SOLDIER_CLASS_ELITE_MILITIA:
newmilitia.militiarank = ELITE_MILITIA;
break;
case SOLDIER_CLASS_ARMY:
case SOLDIER_CLASS_REG_MILITIA:
newmilitia.militiarank = REGULAR_MILITIA;
break;
default:
return 0;
break;
}
// according to origin, we choose bodytype, skin, hair, fore- and surname
newmilitia.origin = aOrigin;
newmilitia.originsector = SECTOR( pSoldier->sSectorX, pSoldier->sSectorY );
newmilitia.sector = newmilitia.originsector;
newmilitia.bodytype = pSoldier->ubBodyType;
if ( COMPARE_PALETTEREP_ID( pSoldier->SkinPal, "PINKSKIN" ) ) newmilitia.skin = PINKSKIN;
else if ( COMPARE_PALETTEREP_ID( pSoldier->SkinPal, "TANSKIN" ) ) newmilitia.skin = TANSKIN;
else if ( COMPARE_PALETTEREP_ID( pSoldier->SkinPal, "DARKSKIN" ) ) newmilitia.skin = DARKSKIN;
else if ( COMPARE_PALETTEREP_ID( pSoldier->SkinPal, "BLACKSKIN" ) ) newmilitia.skin = BLACKSKIN;
if ( COMPARE_PALETTEREP_ID( pSoldier->HeadPal, "BROWNHEAD" ) ) newmilitia.hair = BROWNHEAD;
if ( COMPARE_PALETTEREP_ID( pSoldier->HeadPal, "BLACKHEAD" ) ) newmilitia.hair = BLACKHEAD;
if ( COMPARE_PALETTEREP_ID( pSoldier->HeadPal, "WHITEHEAD" ) ) newmilitia.hair = WHITEHEAD;
if ( COMPARE_PALETTEREP_ID( pSoldier->HeadPal, "BLONDHEAD" ) ) newmilitia.hair = BLONDEHEAD;
if ( COMPARE_PALETTEREP_ID( pSoldier->HeadPal, "REDHEAD" ) ) newmilitia.hair = REDHEAD;
// age is random
newmilitia.age = 16 + Random( 2 ) * ( 1 + Random( 8 ) )
+ Random( 2 ) * ( 1 + Random( 8 ) )
+ Random( 2 ) * ( 1 + Random( 8 ) )
+ Random( 2 ) * ( 1 + Random( 8 ) )
+ Random( 2 ) * ( 1 + Random( 8 ) )
+ Random( 2 ) * ( 1 + Random( 8 ) );
if ( newmilitia.hair == WHITEHEAD )
newmilitia.age = max( newmilitia.age, 38 + Random( 2 ) * ( 1 + Random( 8 ) ) );
// we have to choose a new name, as we cannot take the soldiers name, as those are set in separate arrays
if ( newmilitia.bodytype == REGFEMALE )
{
newmilitia.forename = Random( gMilitiaOriginData[newmilitia.origin].szFemale_Forename.size() );
newmilitia.surname = Random( gMilitiaOriginData[newmilitia.origin].szFemale_Surname.size() );
}
else
{
newmilitia.forename = Random( gMilitiaOriginData[newmilitia.origin].szMale_Forename.size() );
newmilitia.surname = Random( gMilitiaOriginData[newmilitia.origin].szMale_Surname.size() );
}
newmilitia.flagmask = 0;
newmilitia.healthratio = 100.0f * pSoldier->stats.bLife / pSoldier->stats.bLifeMax;
newmilitia.kills = 0;
newmilitia.assists = 0;
newmilitia.promotionpoints = 0.0f;
// promotion points are based on kills and assists. For proper accounting, award points for current rank
newmilitia.AddKills( 0, 0 );
// make up some history
MILITIA_BATTLEREPORT report;
report.flagmask |= MILITIA_BATTLEREPORT_FLAG_RECRUITED_TURNCOAT;
report.id = GetWorldTotalMin();
newmilitia.history.push_back( report );
gIndividualMilitiaVector.push_back( newmilitia );
return newmilitia.id;
}
// search for a individual militia that is alive and not currently in use in this sector, and return its id
// if none is found, create new and return that one
UINT32 GetIdOfUnusedIndividualMilitia( UINT8 aSoldierClass, UINT8 aSector )
+4
View File
@@ -38,6 +38,8 @@ NUM_TOTAL_STATS
#define MILITIA_BATTLEREPORT_FLAG_KILLEDENEMY 0x00000040 // killed an enemy
#define MILITIA_BATTLEREPORT_FLAG_FIRED 0x00000080 // militia was fired
#define MILITIA_BATTLEREPORT_FLAG_RECRUITED_TURNCOAT 0x00000100 // defected to our side
struct MILITIA_BATTLEREPORT
{
MILITIA_BATTLEREPORT( ) : id( 0 ), flagmask( 0 ) {}
@@ -166,6 +168,8 @@ UINT32 CreateRandomIndividualMilitia( UINT8 aMilitiaRank, UINT8 aOrigin, UINT8 a
UINT32 CreateNewIndividualMilitia( UINT8 aMilitiaRank, UINT8 aOrigin, UINT8 aSector );
UINT32 CreateNewIndividualMilitiaFromSoldier( SOLDIERTYPE* pSoldier, UINT8 aOrigin );
UINT32 GetIdOfUnusedIndividualMilitia( UINT8 aSoldierClass, UINT8 aSector );
BOOLEAN GetIdOfIndividualMilitiaWithClassSector( UINT8 aSoldierClass, UINT8 aSector, UINT32& arId );
+405
View File
@@ -3039,3 +3039,408 @@ void HandleBloodCatDeaths( SECTORINFO *pSector )
}
}
#endif
UINT16 NumTurncoatsOfClassInSector( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass )
{
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE )
{
return ( 0 );
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];
UINT16 num = 0;
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR: num += pSector->ubNumAdmins_Turncoat; break;
case SOLDIER_CLASS_ARMY: num += pSector->ubNumTroops_Turncoat; break;
case SOLDIER_CLASS_ELITE: num += pSector->ubNumElites_Turncoat; break;
default: break;
}
GROUP* pGroup = gpGroupList;
while ( pGroup )
{
if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR: num += pGroup->pEnemyGroup->ubNumAdmins_Turncoat; break;
case SOLDIER_CLASS_ARMY: num += pGroup->pEnemyGroup->ubNumTroops_Turncoat; break;
case SOLDIER_CLASS_ELITE: num += pGroup->pEnemyGroup->ubNumElites_Turncoat; break;
default: break;
}
}
pGroup = pGroup->next;
}
return num;
}
BOOLEAN TurncoatsInSector( INT16 sSectorX, INT16 sSectorY )
{
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE )
{
return ( 0 );
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];
if ( pSector->ubNumAdmins_Turncoat
|| pSector->ubNumTroops_Turncoat
|| pSector->ubNumElites_Turncoat )
return TRUE;
GROUP* pGroup = gpGroupList;
while ( pGroup )
{
if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat
|| pGroup->pEnemyGroup->ubNumTroops_Turncoat
|| pGroup->pEnemyGroup->ubNumElites_Turncoat )
return TRUE;
}
pGroup = pGroup->next;
}
return FALSE;
}
bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass )
{
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE )
{
return false;
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];
// count how many turncoats we have
UINT16 num_static = 0;
UINT16 num_groups = 0;
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
num_static = pSector->ubNumAdmins_Turncoat;
break;
case SOLDIER_CLASS_ARMY:
num_static = pSector->ubNumTroops_Turncoat;
break;
case SOLDIER_CLASS_ELITE:
num_static = pSector->ubNumElites_Turncoat;
break;
default:
break;
}
GROUP* pGroup = gpGroupList;
while ( pGroup )
{
if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
num_groups += pGroup->pEnemyGroup->ubNumAdmins_Turncoat;
break;
case SOLDIER_CLASS_ARMY:
num_groups += pGroup->pEnemyGroup->ubNumTroops_Turncoat;
break;
case SOLDIER_CLASS_ELITE:
num_groups += pGroup->pEnemyGroup->ubNumElites_Turncoat;
break;
default:
break;
}
}
pGroup = pGroup->next;
}
if ( num_static + num_groups )
{
if ( Chance( 100 * num_static / ( num_static + num_groups ) ) )
{
// add to garrison
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
pSector->ubNumAdmins_Turncoat--;
return true;
break;
case SOLDIER_CLASS_ARMY:
pSector->ubNumTroops_Turncoat--;
return true;
break;
case SOLDIER_CLASS_ELITE:
pSector->ubNumElites_Turncoat--;
return true;
break;
default:
break;
}
}
else
{
GROUP* pGroup = gpGroupList;
while ( pGroup )
{
if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat )
{
pGroup->pEnemyGroup->ubNumAdmins_Turncoat--;
return true;
}
break;
case SOLDIER_CLASS_ARMY:
if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat )
{
pGroup->pEnemyGroup->ubNumTroops_Turncoat--;
return true;
}
break;
case SOLDIER_CLASS_ELITE:
if ( pGroup->pEnemyGroup->ubNumElites_Turncoat )
{
pGroup->pEnemyGroup->ubNumElites_Turncoat--;
return true;
}
break;
default:
break;
}
}
pGroup = pGroup->next;
}
}
}
return false;
}
bool AddOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass )
{
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE )
{
return false;
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];
// count how many 'slots' we have for more turncoats, then add one at a random position
UINT16 freeslots_static = 0;
UINT16 freeslots_groups = 0;
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
if ( pSector->ubNumAdmins_Turncoat < pSector->ubNumAdmins )
freeslots_static = pSector->ubNumAdmins - pSector->ubNumAdmins_Turncoat;
break;
case SOLDIER_CLASS_ARMY:
if ( pSector->ubNumTroops_Turncoat < pSector->ubNumTroops )
freeslots_static = pSector->ubNumTroops - pSector->ubNumTroops_Turncoat;
break;
case SOLDIER_CLASS_ELITE:
if ( pSector->ubNumElites_Turncoat < pSector->ubNumElites )
freeslots_static = pSector->ubNumElites - pSector->ubNumElites_Turncoat;
break;
default:
break;
}
GROUP* pGroup = gpGroupList;
while ( pGroup )
{
if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat < pGroup->pEnemyGroup->ubNumAdmins )
freeslots_groups += pGroup->pEnemyGroup->ubNumAdmins - pGroup->pEnemyGroup->ubNumAdmins_Turncoat;
break;
case SOLDIER_CLASS_ARMY:
if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat < pGroup->pEnemyGroup->ubNumTroops )
freeslots_groups += pGroup->pEnemyGroup->ubNumTroops - pGroup->pEnemyGroup->ubNumTroops_Turncoat;
break;
case SOLDIER_CLASS_ELITE:
if ( pGroup->pEnemyGroup->ubNumElites_Turncoat < pGroup->pEnemyGroup->ubNumElites )
freeslots_groups += pGroup->pEnemyGroup->ubNumElites - pGroup->pEnemyGroup->ubNumElites_Turncoat;
break;
default:
break;
}
}
pGroup = pGroup->next;
}
if ( freeslots_static + freeslots_groups )
{
if ( Chance( 100 * freeslots_static / ( freeslots_static + freeslots_groups ) ) )
{
// add to garrison
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
pSector->ubNumAdmins_Turncoat++;
return true;
break;
case SOLDIER_CLASS_ARMY:
pSector->ubNumTroops_Turncoat++;
return true;
break;
case SOLDIER_CLASS_ELITE:
pSector->ubNumElites_Turncoat++;
return true;
break;
default:
break;
}
}
else
{
GROUP* pGroup = gpGroupList;
while ( pGroup )
{
if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
switch ( aSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat < pGroup->pEnemyGroup->ubNumAdmins )
{
pGroup->pEnemyGroup->ubNumAdmins_Turncoat++;
return true;
}
break;
case SOLDIER_CLASS_ARMY:
if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat < pGroup->pEnemyGroup->ubNumTroops )
{
pGroup->pEnemyGroup->ubNumTroops_Turncoat++;
return true;
}
break;
case SOLDIER_CLASS_ELITE:
if ( pGroup->pEnemyGroup->ubNumElites_Turncoat < pGroup->pEnemyGroup->ubNumElites )
{
pGroup->pEnemyGroup->ubNumElites_Turncoat++;
return true;
}
break;
default:
break;
}
}
pGroup = pGroup->next;
}
}
}
return false;
}
void CorrectTurncoatCount( INT16 sSectorX, INT16 sSectorY )
{
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE )
{
return;
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
SECTORINFO* pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];
if ( pSector->ubNumAdmins_Turncoat > pSector->ubNumAdmins )
{
pSector->ubNumTroops_Turncoat += pSector->ubNumAdmins_Turncoat - pSector->ubNumAdmins;
pSector->ubNumAdmins_Turncoat = pSector->ubNumAdmins;
}
if ( pSector->ubNumTroops_Turncoat > pSector->ubNumTroops )
{
pSector->ubNumElites_Turncoat += pSector->ubNumTroops_Turncoat - pSector->ubNumTroops;
pSector->ubNumTroops_Turncoat = pSector->ubNumTroops;
}
if ( pSector->ubNumElites_Turncoat > pSector->ubNumElites )
{
pSector->ubNumElites_Turncoat = pSector->ubNumElites;
}
GROUP* pGroup = gpGroupList;
while ( pGroup )
{
if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat > pGroup->pEnemyGroup->ubNumAdmins )
{
pGroup->pEnemyGroup->ubNumTroops_Turncoat += pGroup->pEnemyGroup->ubNumAdmins_Turncoat - pGroup->pEnemyGroup->ubNumAdmins;
pGroup->pEnemyGroup->ubNumAdmins_Turncoat = pGroup->pEnemyGroup->ubNumAdmins;
}
if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat > pGroup->pEnemyGroup->ubNumTroops )
{
pGroup->pEnemyGroup->ubNumElites_Turncoat += pGroup->pEnemyGroup->ubNumTroops_Turncoat - pGroup->pEnemyGroup->ubNumTroops;
pGroup->pEnemyGroup->ubNumTroops_Turncoat = pGroup->pEnemyGroup->ubNumTroops;
}
if ( pGroup->pEnemyGroup->ubNumElites_Turncoat > pGroup->pEnemyGroup->ubNumElites )
{
pGroup->pEnemyGroup->ubNumElites_Turncoat = pGroup->pEnemyGroup->ubNumElites;
}
}
pGroup = pGroup->next;
}
}
+7
View File
@@ -73,6 +73,13 @@ extern INT32 gsGridNoForMapEdgePointInfo;
// This currently does not exist for MILITIA_TEAM, making such a check relatively useless
BOOLEAN CheckPendingNonPlayerTeam(UINT8 usTeam);
// Flugente: turncoats
UINT16 NumTurncoatsOfClassInSector( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass );
BOOLEAN TurncoatsInSector( INT16 sSectorX, INT16 sSectorY );
bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass );
bool AddOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass );
void CorrectTurncoatCount( INT16 sSectorX, INT16 sSectorY );
extern UINT32 guiTurnCnt, guiReinforceTurn, guiMilitiaReinforceTurn;//dnl ch68 080913
#endif
+35
View File
@@ -5815,6 +5815,13 @@ void InvestigateSector( UINT8 ubSectorID )
ubNumToSend--;
ubAdmins[i]++;
ubTotal++;
// Flugente: turncoats might move as well
if ( pSector->ubNumAdmins_Turncoat > pSector->ubNumAdmins )
{
SectorInfo[ubSectorID].ubNumAdmins_Turncoat += pSector->ubNumAdmins_Turncoat - pSector->ubNumAdmins;
pSector->ubNumAdmins_Turncoat = pSector->ubNumAdmins;
}
}
else if( pSector->ubNumTroops )
{
@@ -5822,6 +5829,13 @@ void InvestigateSector( UINT8 ubSectorID )
ubNumToSend--;
ubTroops[i]++;
ubTotal++;
// Flugente: turncoats might move as well
if ( pSector->ubNumTroops_Turncoat > pSector->ubNumTroops )
{
SectorInfo[ubSectorID].ubNumTroops_Turncoat += pSector->ubNumTroops_Turncoat - pSector->ubNumTroops;
pSector->ubNumTroops_Turncoat = pSector->ubNumTroops;
}
}
else if( pSector->ubNumElites )
{
@@ -5829,6 +5843,13 @@ void InvestigateSector( UINT8 ubSectorID )
ubNumToSend--;
ubElites[i]++;
ubTotal++;
// Flugente: turncoats might move as well
if ( pSector->ubNumElites_Turncoat > pSector->ubNumElites )
{
SectorInfo[ubSectorID].ubNumElites_Turncoat += pSector->ubNumElites_Turncoat - pSector->ubNumElites;
pSector->ubNumElites_Turncoat = pSector->ubNumElites;
}
}
else
{
@@ -6571,6 +6592,13 @@ void UpgradeAdminsToTroops()
--ubAdminsToCheck;
}
// Flugente: make sure turncoat numbers are plausible
if ( pSector->ubNumAdmins_Turncoat > pSector->ubNumAdmins )
{
pSector->ubNumTroops_Turncoat += pSector->ubNumAdmins_Turncoat - pSector->ubNumAdmins;
pSector->ubNumAdmins_Turncoat = pSector->ubNumAdmins;
}
}
}
}
@@ -6628,6 +6656,13 @@ void UpgradeAdminsToTroops()
ubAdminsToCheck--;
}
// Flugente: make sure turncoat numbers are plausible
if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat > pGroup->pEnemyGroup->ubNumAdmins )
{
pGroup->pEnemyGroup->ubNumTroops_Turncoat += pGroup->pEnemyGroup->ubNumAdmins_Turncoat - pGroup->pEnemyGroup->ubNumAdmins;
pGroup->pEnemyGroup->ubNumAdmins_Turncoat = pGroup->pEnemyGroup->ubNumAdmins;
}
}
}
}
+8 -1
View File
@@ -75,7 +75,14 @@ typedef struct ENEMYGROUP
UINT8 ubTanksInBattle;
UINT8 ubNumJeeps;
UINT8 ubJeepsInBattle;
INT8 bPadding[16];
// Flugente: number of turncoats
UINT8 ubNumAdmins_Turncoat;
UINT8 ubNumTroops_Turncoat;
UINT8 ubNumElites_Turncoat;
UINT8 bPadding_1;
INT8 bPadding[12];
}ENEMYGROUP;
//NOTE: ALL FLAGS ARE CLEARED WHENEVER A GROUP ARRIVES IN A SECTOR, OR ITS WAYPOINTS ARE
+3
View File
@@ -431,12 +431,15 @@ INT8 SoldierClassToMilitiaRank(UINT8 ubSoldierClass)
switch( ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA:
bRank = GREEN_MILITIA;
break;
case SOLDIER_CLASS_ARMY:
case SOLDIER_CLASS_REG_MILITIA:
bRank = REGULAR_MILITIA;
break;
case SOLDIER_CLASS_ELITE:
case SOLDIER_CLASS_ELITE_MILITIA:
bRank = ELITE_MILITIA;
break;
+2 -2
View File
@@ -2395,9 +2395,9 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
fDoIcon_Assignment = TRUE;
fShowCustomText = TRUE;
if (pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY])
if (pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] > 10)
{
swprintf(sString, L"Hide %dh", pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY]);
swprintf(sString, L"Hide %dh", pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] / 10);
}
else
{
+124 -108
View File
@@ -6283,10 +6283,7 @@ BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier)
// this only works on enemy soldiers
if ( pSoldier->bTeam != ENEMY_TEAM && pSoldier->bTeam != CIV_TEAM )
return false;
if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] < gGameExternalOptions.usTurnsToUncover )
return false;
INT16 sXPos = 0;
INT16 sYPos = 0;
INT32 iBack = 0;
@@ -6297,113 +6294,29 @@ BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier)
sXPos += 50;
sYPos += 25;
// are we a VIP? show that only when the player knows a VIP is in this sector. otherwise, don't even show our officer property
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP && !pSoldier->bSectorZ )
if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] >= gGameExternalOptions.usTurnsToUncover )
{
if ( PlayerKnowsAboutVIP( pSoldier->sSectorX, pSoldier->sSectorY ) )
// are we a VIP? show that only when the player knows a VIP is in this sector. otherwise, don't even show our officer property
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP && !pSoldier->bSectorZ )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20), (INT16)(sYPos + 20) );
if ( iBack != -1 )
if ( PlayerKnowsAboutVIP( pSoldier->sSectorX, pSoldier->sSectorY ) )
{
SetBackgroundRectFilled( iBack );
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)( sXPos + 20 ), (INT16)( sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 6, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 6, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
}
// is this guy an officer?
if ( pSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
// if we look at this guy long enough, we might even learn that he is an advanced officer
if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] > 1.5 * gGameExternalOptions.usTurnsToUncover && NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT ) > 1 )
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 5, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
else
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 0, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// is this guy radio operator with a radio?
if ( pSoldier->CanUseRadio(false) )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 3, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// is this guy a doctor? we do not check for medical gear, as we would not have that information from a glance
if ( HAS_SKILL_TRAIT( pSoldier, DOCTOR_NT) )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 1, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// is this guy a sniper? Just check for the gun, trait is not necessary
if ( pSoldier->HasSniper() )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 2, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// is this guy a mortar guy? Just check for the gun, trait is not necessary
if ( pSoldier->HasMortar() )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 4, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// do we carry a key?
for ( int ubLoop = 0; ubLoop < NUM_KEYS; ++ubLoop )
{
if ( SoldierHasKey( pSoldier, ubLoop ) )
// is this guy an officer?
if ( pSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)( sXPos + 20 ), (INT16)( sYPos + 20 ) );
@@ -6413,12 +6326,115 @@ BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier)
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 11, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
// if we look at this guy long enough, we might even learn that he is an advanced officer
if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] > 1.5 * gGameExternalOptions.usTurnsToUncover && NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT ) > 1 )
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 5, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
else
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 0, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
break;
}
// is this guy radio operator with a radio?
if ( pSoldier->CanUseRadio( false ) )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)( sXPos + 20 ), (INT16)( sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 3, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// is this guy a doctor? we do not check for medical gear, as we would not have that information from a glance
if ( HAS_SKILL_TRAIT( pSoldier, DOCTOR_NT ) )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)( sXPos + 20 ), (INT16)( sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 1, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// is this guy a sniper? Just check for the gun, trait is not necessary
if ( pSoldier->HasSniper() )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)( sXPos + 20 ), (INT16)( sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 2, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// is this guy a mortar guy? Just check for the gun, trait is not necessary
if ( pSoldier->HasMortar() )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)( sXPos + 20 ), (INT16)( sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 4, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
// do we carry a key?
for ( int ubLoop = 0; ubLoop < NUM_KEYS; ++ubLoop )
{
if ( SoldierHasKey( pSoldier, ubLoop ) )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)( sXPos + 20 ), (INT16)( sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 11, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
break;
}
}
}
// turncoats are instantly visible
if ( gSkillTraitValues.fCOTurncoats && pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT )
{
// Add bars
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)( sXPos + 20 ), (INT16)( sYPos + 20 ) );
if ( iBack != -1 )
{
SetBackgroundRectFilled( iBack );
}
BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 12, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL );
sYPos += 20;
}
return true;
+246 -7
View File
@@ -114,6 +114,8 @@
#include "DynamicDialogue.h" // added by Flugente for HandleDynamicOpinions()
#include "DropDown.h" // added by Flugente
#include "Creature Spreading.h" // added by Flugente forResetCreatureAttackVariables()
#include "finances.h" // added by Flugente
#include "MilitiaIndividual.h" // added by Flugente
#endif
#include "connect.h"
@@ -153,6 +155,10 @@ class OBJECTTYPE;
class SOLDIERTYPE;
extern void HandleBestSightingPositionInRealtime();
extern INT32 GetCurrentBalance( void );
extern CHAR16 gzUserDefinedButton1[128];
extern CHAR16 gzUserDefinedButton2[128];
void UpdateFastForwardMode(SOLDIERTYPE* pSoldier, INT8 bAction); // sevenfm: to call in HandleAtNewGridNo
@@ -4214,15 +4220,13 @@ void SetSoldierNeutral( SOLDIERTYPE * pSoldier )
}
void MakeCivHostile(SOLDIERTYPE *pSoldier)
{
INT8 bNewSide;
if ( pSoldier->ubBodyType == COW )
{
return;
}
// default is hostile to player, allied to army
bNewSide = 1;
INT8 bNewSide = 1;
switch( pSoldier->ubProfile )
{
@@ -4267,6 +4271,11 @@ void MakeCivHostile(SOLDIERTYPE *pSoldier)
{
bNewSide = zCivGroupName[pSoldier->ubCivilianGroup].bSide;
}
// Flugente: enemies are already hostile, let's assume we want to make them friendly instead
else if ( pSoldier->bTeam == ENEMY_TEAM )
{
bNewSide = 0;
}
if ( !pSoldier->aiData.bNeutral && bNewSide == pSoldier->bSide )
{
@@ -4302,6 +4311,63 @@ void MakeCivHostile(SOLDIERTYPE *pSoldier)
pSoldier->aiData.bOrders = FARPATROL;
}
// Flugente: turncoats
if ( pSoldier->bTeam == ENEMY_TEAM )
{
// change to enemy team
SetSoldierNonNeutral( pSoldier );
pSoldier->bSide = bNewSide;
// remember old class and switch to its equivalent
UINT8 oldclass = pSoldier->ubSoldierClass;
UINT16 sector = SECTOR( pSoldier->sSectorX, pSoldier->sSectorY );
// extract militia profile from pSoldier, so that a fitting profile is ready to be taken during creation
CreateNewIndividualMilitiaFromSoldier( pSoldier, MO_DEFECTOR );
pSoldier = ChangeSoldierTeam( pSoldier, MILITIA_TEAM );
// it doesn't make sense to force a militia reset when all changes are in the sector, so set this back to original value afterwards
//BOOLEAN tmp = gfStrategicMilitiaChangesMade;
//gfStrategicMilitiaChangesMade = tmp;
if ( oldclass == SOLDIER_CLASS_ARMY )
{
pSoldier->ubSoldierClass = SOLDIER_CLASS_REG_MILITIA;
SectorInfo[sector].ubNumTroops = max( 0, SectorInfo[sector].ubNumTroops - 1 );
SectorInfo[sector].ubTroopsInBattle = max( 0, SectorInfo[sector].ubTroopsInBattle - 1 );
}
else if ( oldclass == SOLDIER_CLASS_ELITE )
{
pSoldier->ubSoldierClass = SOLDIER_CLASS_ELITE_MILITIA;
SectorInfo[sector].ubNumElites = max( 0, SectorInfo[sector].ubNumElites - 1 );
SectorInfo[sector].ubElitesInBattle = max( 0, SectorInfo[sector].ubElitesInBattle - 1 );
}
else
{
pSoldier->ubSoldierClass = SOLDIER_CLASS_GREEN_MILITIA;
SectorInfo[sector].ubNumAdmins = max( 0, SectorInfo[sector].ubNumAdmins - 1 );
SectorInfo[sector].ubAdminsInBattle = max( 0, SectorInfo[sector].ubAdminsInBattle - 1 );
}
StrategicAddMilitiaToSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass - 4, 1 );
// rehandle sight for everybody
SOLDIERTYPE* pTeamSoldier;
UINT16 iLoop = gTacticalStatus.Team[OUR_TEAM].bFirstID;
for ( pTeamSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[CIV_TEAM].bLastID; ++iLoop, ++pTeamSoldier )
{
if ( pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->stats.bLife > 0 )
{
RecalculateOppCntsDueToNoLongerNeutral( pTeamSoldier );
}
}
}
pSoldier->bSide = bNewSide;
if ( pSoldier->aiData.bNeutral )
@@ -6903,6 +6969,10 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
if ( pTeamSoldier->usSoldierFlagMask & SOLDIER_VIP )
DeleteVIP( pTeamSoldier->sSectorX, pTeamSoldier->sSectorY );
// Flugente: turncoats
if ( pTeamSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT )
RemoveOneTurncoat( sMapX, sMapY, pTeamSoldier->ubSoldierClass );
// Flugente: campaign stats
gCurrentIncident.AddStat( pTeamSoldier, CAMPAIGNHISTORY_TYPE_PRISONER );
@@ -10520,7 +10590,138 @@ void HandleDisplayingOfPlayerLostDialogue( )
}
#endif
static UINT8 prisonerdialoguetargetID = 0;
static UINT8 prisonerdialoguetargetID = NOBODY;
void TurnCoatAttemptMessageBoxCallBack( UINT8 ubExitValue )
{
// check ubExitValue to see whether we actually want to go through (2)
if ( ubExitValue != 2
|| prisonerdialoguetargetID == NOBODY
|| gusSelectedSoldier == NOBODY )
return;
SOLDIERTYPE* pSoldier = MercPtrs[prisonerdialoguetargetID];
if ( !pSoldier )
return;
INT16 approachselected = DropDownTemplate<DROPDOWNNR_MSGBOX_1>::getInstance().GetSelectedEntryKey();
UINT8 approachchance = MercPtrs[gusSelectedSoldier]->GetTurncoatConvinctionChance( prisonerdialoguetargetID, approachselected );
// you can never turn a VIP (though we don't tell the player if someone is a VIP, lest they have an exploit to find out)
if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP )
approachchance = 0;
// as using random numbers to pass the check would result in players savescumming, use a number based on the soldier's stats
UINT32 soldierconsistentnumber = ( 23 * EffectiveAgility( pSoldier, FALSE ) + 83 * EffectiveExplosive( pSoldier ) + 19 * EffectiveMarksmanship( pSoldier ) + 92 * pSoldier->stats.bLifeMax ) % 100;
if ( soldierconsistentnumber < approachchance )
{
pSoldier->usSoldierFlagMask2 |= SOLDIER_TURNCOAT;
AddOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass );
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szTurncoatText[0], pSoldier->GetName() );
// increase intel penalty. We can only try to convert enemies if the penalty is low, and having a high penalty means we can't mine intel for a few hours but have to hide
MercPtrs[gusSelectedSoldier]->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] += 1;
StatChange( MercPtrs[gusSelectedSoldier], EXPERAMT, 2, FROM_SUCCESS );
StatChange( MercPtrs[gusSelectedSoldier], LDRAMT, 4, FROM_SUCCESS );
}
else
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szTurncoatText[1], pSoldier->GetName() );
// increase intel penalty. We can only try to convert enemies if the penalty is low, and having a high penalty means we can't mine intel for a few hours but have to hide
MercPtrs[gusSelectedSoldier]->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] += 4;
StatChange( MercPtrs[gusSelectedSoldier], EXPERAMT, 1, FROM_FAILURE );
StatChange( MercPtrs[gusSelectedSoldier], LDRAMT, 1, FROM_FAILURE );
}
// explain that suspicion is so high that we have to stop
if ( MercPtrs[gusSelectedSoldier]->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] >= 20 )
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szTurncoatText[2] );
// use up resources spent, regardless of whether or not we were successful
if ( approachselected == 3 )
{
INT32 bribeamount = 10 * min( 10, CurrentPlayerProgressPercentage() );
// substract money spent
AddTransactionToPlayersBook ( TRANSFER_FUNDS_TO_MERC, MercPtrs[gusSelectedSoldier]->ubProfile, GetWorldTotalMin(), -bribeamount );
}
else if ( approachselected == 4 )
{
int intelbribeneeded = max( 2, ( CurrentPlayerProgressPercentage() + 5 ) / 10 );
AddIntel( -intelbribeneeded, TRUE );
}
//ReduceAttackBusyCount();
}
CHAR16 gTurncoatDropdownText[4][256];
void HandleTurncoatAttempt( SOLDIERTYPE* pSoldier )
{
// abort if bad pointer, or not an enemy and not a capturable civilian
if ( pSoldier
&& pSoldier->bTeam == ENEMY_TEAM
&& pSoldier->ubProfile == NO_PROFILE
&& !( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT )
&& !gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition
&& !pSoldier->RecognizeAsCombatant( gusSelectedSoldier ) )
{
// remember the target's ID
prisonerdialoguetargetID = pSoldier->ubID;
CHAR16 buf[256];
UINT8 ubCurrentProgress = CurrentPlayerProgressPercentage();
std::vector<std::pair<INT16, STR16> > dropdownvector_1;
int cnt = 1;
UINT8 chance = MercPtrs[gusSelectedSoldier]->GetTurncoatConvinctionChance( prisonerdialoguetargetID, cnt );
swprintf( gTurncoatDropdownText[cnt-1], szTurncoatText[3], chance );
dropdownvector_1.push_back( std::make_pair( cnt, gTurncoatDropdownText[cnt - 1] ) );
++cnt;
chance = MercPtrs[gusSelectedSoldier]->GetTurncoatConvinctionChance( prisonerdialoguetargetID, cnt );
swprintf( gTurncoatDropdownText[cnt - 1], szTurncoatText[4], chance );
dropdownvector_1.push_back( std::make_pair( cnt, gTurncoatDropdownText[cnt - 1] ) );
++cnt;
INT32 balance = GetCurrentBalance();
INT32 bribeamount = 10 * min( 10, ubCurrentProgress );
if ( bribeamount <= balance )
{
chance = MercPtrs[gusSelectedSoldier]->GetTurncoatConvinctionChance( prisonerdialoguetargetID, cnt );
swprintf( gTurncoatDropdownText[cnt - 1], szTurncoatText[5], bribeamount, chance );
dropdownvector_1.push_back( std::make_pair( cnt, gTurncoatDropdownText[cnt - 1] ) );
}
++cnt;
FLOAT intelreserve = GetIntel();
int intelbribeneeded = max( 2, ( ubCurrentProgress + 5 ) / 10 );
if ( intelbribeneeded <= intelreserve )
{
chance = MercPtrs[gusSelectedSoldier]->GetTurncoatConvinctionChance( prisonerdialoguetargetID, cnt );
swprintf( gTurncoatDropdownText[cnt - 1], szTurncoatText[6], intelbribeneeded, chance );
dropdownvector_1.push_back( std::make_pair( cnt, gTurncoatDropdownText[cnt - 1] ) );
}
DropDownTemplate<DROPDOWNNR_MSGBOX_1>::getInstance().SetEntries( dropdownvector_1 );
wcscpy( gzUserDefinedButton1, szTurncoatText[8] );
wcscpy( gzUserDefinedButton2, pEpcMenuStrings[4] );
DoMessageBox( MSG_BOX_BASIC_STYLE, szTurncoatText[7], guiCurrentScreen, ( MSG_BOX_FLAG_GENERIC_TWO_BUTTONS | MSG_BOX_FLAG_DROPDOWN_1 ),
TurnCoatAttemptMessageBoxCallBack, NULL );
}
}
void PrisonerSurrenderMessageBoxCallBack( UINT8 ubExitValue )
{
@@ -10679,11 +10880,11 @@ void PrisonerSurrenderMessageBoxCallBack( UINT8 ubExitValue )
}
}
}
// we offered to surrender OURSELVES TO the enemy
// we offered to surrender OURSELVES TO the enemy, or are attempting to turn a soldier into a turncoat
else if ( ubExitValue == 2 )
{
// we cannot surrender to bandits, talk instead
if ( MercPtrs[prisonerdialoguetargetID]->bTeam != CREATURE_TEAM )
if ( MercPtrs[prisonerdialoguetargetID]->bTeam == CREATURE_TEAM )
{
// normal dialog
StartCivQuote( MercPtrs[prisonerdialoguetargetID] );
@@ -10740,7 +10941,7 @@ void PrisonerSurrenderMessageBoxCallBack( UINT8 ubExitValue )
else if ( ubExitValue == 3 )
{
// Flugente: if we are disguised and talk to a non-profile NPC, we will continue to 'chat' with the enemy as long as we aren't ordered to do something else.
// This way we can easily order our spies to 'distract 'enemies'
// This way we can easily order our spies to 'distract' enemies
if ( GetSoldier( &pSoldier, gusSelectedSoldier ) &&
pSoldier->bTeam == gbPlayerNum &&
MercPtrs[prisonerdialoguetargetID] &&
@@ -11128,6 +11329,27 @@ UINT16 NumSoldiersWithFlagInSector( UINT8 aTeam, UINT32 aFlag )
return num;
}
UINT16 NumSoldiersofClassWithFlag2InSector( UINT8 aTeam, UINT8 aSoldierClass, UINT32 aFlag )
{
SOLDIERTYPE* pSoldier;
INT32 cnt = 0;
UINT16 num = 0;
for ( cnt = gTacticalStatus.Team[aTeam].bFirstID, pSoldier = MercPtrs[cnt]; cnt <= gTacticalStatus.Team[aTeam].bLastID; pSoldier++, ++cnt )
{
if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 )
{
if ( (pSoldier->usSoldierFlagMask2 & aFlag)
&& pSoldier->ubSoldierClass == aSoldierClass )
{
++num;
}
}
}
return num;
}
INT32 GetClosestSoldierWithFlag( UINT8 aTeam, UINT32 aFlag )
{
INT32 sBestGridNo = NOWHERE;
@@ -11414,3 +11636,20 @@ BOOLEAN IsCivFactionMemberAliveInSector( UINT8 usCivilianGroup )
return FALSE;
}
BOOLEAN IsFreeSlotAvailable( int aTeam )
{
SOLDIERTYPE *pSoldier;
INT32 cnt = gTacticalStatus.Team[aTeam].bFirstID;
// run through list
for ( pSoldier = MercPtrs[cnt]; cnt <= gTacticalStatus.Team[aTeam].bLastID; ++cnt, ++pSoldier )
{
if ( !pSoldier->bActive )
{
return TRUE;
}
}
return FALSE;
}
+6
View File
@@ -357,6 +357,9 @@ extern UINT8 NumZombiesInSector();
// Flugente: offer the enemy the chance to surrender
void HandleSurrenderOffer( SOLDIERTYPE* pSoldier );
// Flugente: attempt to convince a soldier to become a turncoat
void HandleTurncoatAttempt( SOLDIERTYPE* pSoldier );
// Flugente: disguised mercs can distract enemies by talking to them. In order to display that, we sometimes display excerpts of their 'chats'
void CheckChatPartners();
@@ -401,6 +404,7 @@ UINT8 HighestEnemyOfficersInSector(UINT8& aType);
// count all soldiers in the current sector that have a specific flag set
UINT16 NumSoldiersWithFlagInSector(UINT8 aTeam, UINT32 aFlag);
UINT16 NumSoldiersofClassWithFlag2InSector( UINT8 aTeam, UINT8 aSoldierClass, UINT32 aFlag );
INT32 GetClosestSoldierWithFlag( UINT8 aTeam, UINT32 aFlag );
// Flugente: VIP targets
@@ -426,5 +430,7 @@ void VIPFleesToMeduna();
// Flugente: is any member of a specific civilian faction still alive in the current sector?
BOOLEAN IsCivFactionMemberAliveInSector( UINT8 usCivilianGroup );
BOOLEAN IsFreeSlotAvailable( int aTeam );
#endif
+5
View File
@@ -300,6 +300,11 @@ void ReducePointsForFatigue( SOLDIERTYPE *pSoldier, UINT32 *pusPoints )
*pusPoints -= (*pusPoints * GetPenaltyForFatigue( pSoldier )) / 100;
}
void ReducePointsForFatigue( SOLDIERTYPE *pSoldier, INT32 *psPoints )
{
*psPoints -= ( *psPoints * GetPenaltyForFatigue( pSoldier ) ) / 100;
}
INT32 GetSkillCheckPenaltyForFatigue( SOLDIERTYPE *pSoldier, INT32 iSkill )
{
// use only half the full effect of fatigue for skill checks
+1
View File
@@ -5,6 +5,7 @@
#include "Soldier Control.h"
void ReducePointsForFatigue( SOLDIERTYPE *pSoldier, UINT32 *pusPoints );
void ReducePointsForFatigue( SOLDIERTYPE *pSoldier, INT32 *psPoints );
INT32 GetSkillCheckPenaltyForFatigue( SOLDIERTYPE *pSoldier, INT32 iSkill );
INT32 SkillCheck( SOLDIERTYPE *pSoldier, INT8 bReason, INT8 bDifficulty );
INT16 CalcTrapDetectLevel( SOLDIERTYPE *pSoldier, BOOLEAN fExamining );
+4 -4
View File
@@ -249,7 +249,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 ) );
@@ -309,7 +309,7 @@ SkillSelection::Setup( UINT32 aVal )
{
for(UINT32 uiCounter = SKILLS_RADIO_FIRST; uiCounter <= SKILLS_RADIO_LAST; ++uiCounter)
{
SetRegionFastHelpText( &(GetPopup()->MenuRegion[cnt++]), pSoldier->PrintSkillDesc(uiCounter) );
SetRegionFastHelpText( &(GetPopup()->MenuRegion[cnt++]), pSoldier->PrintSkillDesc( uiCounter, sTraitsMenuTargetGridNo ) );
}
}
break;
@@ -318,7 +318,7 @@ SkillSelection::Setup( UINT32 aVal )
{
for ( UINT32 uiCounter = SKILLS_INTEL_FIRST; uiCounter <= SKILLS_INTEL_LAST; ++uiCounter )
{
SetRegionFastHelpText( &( GetPopup()->MenuRegion[cnt++] ), pSoldier->PrintSkillDesc( uiCounter ) );
SetRegionFastHelpText( &( GetPopup()->MenuRegion[cnt++] ), pSoldier->PrintSkillDesc( uiCounter, sTraitsMenuTargetGridNo ) );
}
}
break;
@@ -327,7 +327,7 @@ SkillSelection::Setup( UINT32 aVal )
{
for(UINT32 uiCounter = SKILLS_VARIOUS_FIRST; uiCounter <= SKILLS_VARIOUS_LAST; ++uiCounter)
{
SetRegionFastHelpText( &(GetPopup()->MenuRegion[cnt++]), pSoldier->PrintSkillDesc(uiCounter) );
SetRegionFastHelpText( &(GetPopup()->MenuRegion[cnt++]), pSoldier->PrintSkillDesc(uiCounter, sTraitsMenuTargetGridNo ) );
}
}
break;
+6
View File
@@ -114,6 +114,8 @@ extern UINT8 gubInterruptProvoker;
extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance );
extern bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass );
// Animation code explanations!
//
// 0-399: Actual animation frame indices
@@ -4131,6 +4133,10 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
{
DeleteVIP( pSoldier->sSectorX, pSoldier->sSectorY );
}
// Flugente: turncoats
if ( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT )
RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass );
// Flugente: additional dialogue
if ( pSoldier->ubProfile != NO_PROFILE )
+389 -5
View File
@@ -10168,6 +10168,14 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
if ( this->ubBodyType != CROW && this->ubBodyType != COW )
HandleDynamicOpinionChange( MercPtrs[ubAttacker], OPINIONEVENT_CIV_ATTACKER, TRUE, TRUE );
}
// if we are a turncoat, lose the flag if we were attacked by player forces
if ( (this->usSoldierFlagMask2 & SOLDIER_TURNCOAT) && MercPtrs[ubAttacker]->bSide == 0 )
{
this->usSoldierFlagMask2 &= ~SOLDIER_TURNCOAT;
RemoveOneTurncoat( this->sSectorX, this->sSectorY, this->ubSoldierClass );
}
}
// CJC Jan 21 99: add check to see if we are hurting an enemy in an enemy-controlled
@@ -16200,7 +16208,7 @@ void SOLDIERTYPE::LooseDisguise( void )
// rehandle sight for everybody
SOLDIERTYPE* pSoldier;
UINT8 iLoop = gTacticalStatus.Team[OUR_TEAM].bFirstID;
for ( pSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[LAST_TEAM].bLastID; ++iLoop, ++pSoldier )
for ( pSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[CIV_TEAM].bLastID; ++iLoop, ++pSoldier )
{
if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 )
{
@@ -17794,6 +17802,16 @@ BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck, INT32 sGridNo )
canuse = TRUE;
break;
case SKILLS_RADIO_ACTIVATE_TURNCOATS_ALL:
if ( ( !fAPCheck || EnoughPoints( this, APBPConstants[AP_RADIO], APBPConstants[BP_RADIO], FALSE ) )
&& CanUseRadio()
&& gSkillTraitValues.fCOTurncoats
&& !gbWorldSectorZ
&& gTacticalStatus.ubInterruptPending == DISABLED_INTERRUPT
&& IsFreeSlotAvailable( MILITIA_TEAM ) )
canuse = TRUE;
break;
case SKILLS_INTEL_CONCEAL:
case SKILLS_INTEL_GATHERINTEL:
// in order to conceal, we need:
@@ -17855,6 +17873,52 @@ BOOLEAN SOLDIERTYPE::CanUseSkill( INT8 iSkill, BOOLEAN fAPCheck, INT32 sGridNo )
}
break;
case SKILLS_CREATE_TURNCOAT:
// in order to try to create a turncoat, we need:
// - a non-profile, not-already-turncoat enemy soldier
// - enemy team not aware of us
// - valid disguise
{
SOLDIERTYPE* pSoldier = SimpleFindSoldier( sGridNo, gsInterfaceLevel );
if ( pSoldier
&& InPositionForTurncoatAttempt( pSoldier->ubID ) )
{
canuse = TRUE;
}
}
break;
case SKILLS_ACTIVATE_TURNCOATS:
// not during an interrupt
if ( gSkillTraitValues.fCOTurncoats
&& !gbWorldSectorZ
&& gTacticalStatus.ubInterruptPending == DISABLED_INTERRUPT
&& IsFreeSlotAvailable( MILITIA_TEAM ) )
{
SOLDIERTYPE* pSoldier = SimpleFindSoldier( sGridNo, gsInterfaceLevel );
if ( pSoldier
&& pSoldier->bTeam == ENEMY_TEAM
&& pSoldier->ubProfile == NO_PROFILE
&& ( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT )
&& SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) )
{
canuse = TRUE;
}
}
break;
case SKILLS_ACTIVATE_TURNCOATS_ALL:
// not during an interrupt
if ( gSkillTraitValues.fCOTurncoats
&& !gbWorldSectorZ
&& gTacticalStatus.ubInterruptPending == DISABLED_INTERRUPT
&& !gSkillTraitValues.fCOTurncoats_SectorActivationRequiresRadioOperator
&& IsFreeSlotAvailable( MILITIA_TEAM ) )
{
canuse = TRUE;
}
break;
case SKILLS_SPOTTER:
if ( (!fAPCheck || EnoughPoints( this, APBPConstants[AP_SPOTTER], 0, FALSE )) && CanSpot( ) )
canuse = TRUE;
@@ -17928,6 +17992,10 @@ BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT32 ID )
return SwitchOffRadio( );
break;
case SKILLS_RADIO_ACTIVATE_TURNCOATS_ALL:
return RadioOrderAllTurnCoatToSwitchSides();
break;
case SKILLS_INTEL_CONCEAL:
case SKILLS_INTEL_GATHERINTEL:
{
@@ -17955,6 +18023,18 @@ BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT32 ID )
}
break;
case SKILLS_CREATE_TURNCOAT:
AttemptToCreateTurncoat ( ID );
break;
case SKILLS_ACTIVATE_TURNCOATS:
OrderTurnCoatToSwitchSides( ID );
break;
case SKILLS_ACTIVATE_TURNCOATS_ALL:
OrderAllTurnCoatToSwitchSides();
break;
case SKILLS_SPOTTER:
return BecomeSpotter( usMapPos );
break;
@@ -18001,9 +18081,9 @@ BOOLEAN SOLDIERTYPE::IsAIAllowedtoUseSkill( INT8 iSkill )
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 )
STR16 SOLDIERTYPE::PrintSkillDesc( INT8 iSkill, INT32 sGridNo )
{
if ( CanUseSkill( iSkill, TRUE ) )
if ( CanUseSkill( iSkill, TRUE, sGridNo ) )
{
return pTraitSkillsMenuDescStrings[iSkill];
}
@@ -18036,6 +18116,25 @@ STR16 SOLDIERTYPE::PrintSkillDesc( INT8 iSkill )
break;
case SKILLS_RADIO_ACTIVATE_TURNCOATS_ALL:
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_X_TXT], gzMercSkillTextNew[RADIO_OPERATOR_NT] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_X_TXT], New113Message[MSG113_WORKING_RADIO_SET] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_NOT_DURING_INTERRUPT] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_TURNED_ENEMY] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_SURFACELEVEL] );
wcscat( skilldescarray, atStr );
break;
case SKILLS_INTEL_CONCEAL:
case SKILLS_INTEL_GATHERINTEL:
@@ -18056,6 +18155,39 @@ STR16 SOLDIERTYPE::PrintSkillDesc( INT8 iSkill )
break;
case SKILLS_CREATE_TURNCOAT:
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_ENEMY] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_NOALARM] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_DISGUISE_CIV_OR_MIL] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_SURFACELEVEL] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_STRATEGIC_SUSPICION] );
wcscat( skilldescarray, atStr );
break;
case SKILLS_ACTIVATE_TURNCOATS:
case SKILLS_ACTIVATE_TURNCOATS_ALL:
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_NOT_DURING_INTERRUPT] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_TURNED_ENEMY] );
wcscat( skilldescarray, atStr );
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_SURFACELEVEL] );
wcscat( skilldescarray, atStr );
break;
case SKILLS_SPOTTER:
swprintf( atStr, pTraitSkillsDenialStrings[TEXT_SKILL_DENIAL_X_AP], APBPConstants[AP_SPOTTER] );
wcscat( skilldescarray, atStr );
@@ -18836,6 +18968,21 @@ BOOLEAN SOLDIERTYPE::SwitchOffRadio( )
return TRUE;
}
BOOLEAN SOLDIERTYPE::RadioOrderAllTurnCoatToSwitchSides()
{
// not possible if already scanning
if ( !gSkillTraitValues.fCOTurncoats )
return FALSE;
// use the radio, this handles animation, batteries etc.
if ( !UseRadio() )
return FALSE;
OrderAllTurnCoatToSwitchSides();
return TRUE;
}
// display and error sound used either when the radio set fails or the sector is jammed - the player knows of the error, but cannot be sure of the cause
void
SOLDIERTYPE::RadioFail( )
@@ -20233,7 +20380,7 @@ UINT8 SOLDIERTYPE::GetUncoverRisk()
// if we do this disguised as a soldier, risk will be much higer, as we are under much more scrutiny. This makes up for the increased gain in soldier disguise
// less risk if we are asleep, just hiding or forced to hide
UINT8 typemultiplier = ( this->usSoldierFlagMask & SOLDIER_COVERT_SOLDIER ) ? 5 : 2;
if ( ( this->bAssignment == CONCEALED ) || this->flags.fMercAsleep || this->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] )
if ( ( this->bAssignment == CONCEALED ) || this->flags.fMercAsleep || this->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] > 10 )
typemultiplier = 1;
// we now take the sector coolness as a measurement of how important the sector is, and thus how intel we gain
@@ -20259,7 +20406,7 @@ FLOAT SOLDIERTYPE::GetIntelGain()
return 0.0f;
// if we're asleep, or on a penalty, we accomplish nothing
if ( this->flags.fMercAsleep || this->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] )
if ( this->flags.fMercAsleep || this->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] > 10 )
return 0.0f;
// the covert trait isn't that important in determining the intel gain. It is much more important in mitigating the risk of exposure, however
@@ -20624,6 +20771,243 @@ UINT8 SOLDIERTYPE::GetThiefEvadeDetectionChance()
return totalvalue;
}
BOOLEAN SOLDIERTYPE::InPositionForTurncoatAttempt( UINT16 usID )
{
if ( !gSkillTraitValues.fCOTurncoats
|| gbWorldSectorZ
|| gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition )
return FALSE;
if ( this->stats.bLife < OKLIFE
|| this->flags.fMercAsleep
|| this->bCollapsed
|| ( this->usSoldierFlagMask & SOLDIER_POW )
|| this->usSkillCooldown[SOLDIER_COOLDOWN_INTEL_PENALTY] > 20
|| usID == NOBODY )
return FALSE;
SOLDIERTYPE* pSoldier = MercPtrs[usID];
if ( !pSoldier
|| pSoldier->bTeam != ENEMY_TEAM
|| pSoldier->ubProfile != NO_PROFILE
|| pSoldier->stats.bLife != pSoldier->stats.bLifeMax
|| pSoldier->bCollapsed
|| ( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT )
|| !SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass )
|| !SeemsLegit( pSoldier->ubID ) )
return FALSE;
// additional checks if we want to know wether we can target a specific location
if ( PythSpacesAway( this->sGridNo, pSoldier->sGridNo ) < 10 )
{
INT32 val = SoldierToVirtualSoldierLineOfSightTest( this, pSoldier->sGridNo, this->pathing.bLevel, gAnimControl[this->usAnimState].ubEndHeight, FALSE, 10 );
// error if we cannot see the target
if ( !val )
return FALSE;
else
return TRUE;
}
return FALSE;
}
UINT8 SOLDIERTYPE::GetTurncoatConvinctionChance( UINT16 usID, UINT8 usApproach )
{
if ( usID >= NOBODY )
return 0;
SOLDIERTYPE* pSoldier = MercPtrs[usID];
if ( !pSoldier
|| pSoldier->bTeam != ENEMY_TEAM )
return 0;
if ( this->stats.bLife < OKLIFE )
return 0;
// determine effectiveness of merc
// nominally in [0; 1000]
INT32 basestatrating = 6 * EffectiveLeadership( this ) + 40 * EffectiveExpLevel( this, FALSE );
FLOAT recruitmodifier = ( 100 + this->GetBackgroundValue( BG_PERC_APPROACH_RECRUIT ) ) / 100.0f;
// personality/disability modifiers
FLOAT persmodifier = 1.0f;
if ( DoesMercHaveDisability( this, NERVOUS ) ) persmodifier -= 0.10f;
if ( gGameOptions.fNewTraitSystem )
{
if ( DoesMercHavePersonality( this, CHAR_TRAIT_SOCIABLE ) ) persmodifier += 0.08f;
if ( DoesMercHavePersonality( this, CHAR_TRAIT_LONER ) ) persmodifier -= 0.04f;
if ( DoesMercHavePersonality( this, CHAR_TRAIT_ASSERTIVE ) ) persmodifier += 0.05f;
if ( DoesMercHavePersonality( this, CHAR_TRAIT_AGGRESSIVE ) ) persmodifier -= 0.05f;
if ( DoesMercHavePersonality( this, CHAR_TRAIT_PHLEGMATIC ) ) persmodifier -= 0.02f;
if ( DoesMercHavePersonality( this, CHAR_TRAIT_DAUNTLESS ) ) persmodifier += 0.03f;
if ( DoesMercHavePersonality( this, CHAR_TRAIT_SHOWOFF ) ) persmodifier += 0.04f;
if ( DoesMercHavePersonality( this, CHAR_TRAIT_COWARD ) ) persmodifier -= 0.07f;
}
// nominally in [0; 100]
INT32 recruitrating = basestatrating * recruitmodifier * persmodifier * gMercProfiles[this->ubProfile].usApproachFactor[3] / 1000;
// optional ini bonus
recruitrating += gSkillTraitValues.sCOTurncoats_PlayerConvinctionBonus;
ReducePointsForFatigue( this, &recruitrating );
// determine resistance of soldier to our subversion
INT32 ubLocationModifier = 2 * max( 1, min( 20, gCoolnessBySector[SECTOR( this->sSectorX, this->sSectorY )] ) );
// enemy resistance is dependent on their level, class and the sector rating
INT32 enemyresistancerating = ubLocationModifier + 8 * EffectiveExpLevel( pSoldier, FALSE );
switch ( pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR: enemyresistancerating -= 30; break;
case SOLDIER_CLASS_ELITE: enemyresistancerating += 30; break;
default: break;
}
if ( pSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER )
enemyresistancerating += 30;
ReducePointsForFatigue( pSoldier, &enemyresistancerating );
switch ( usApproach )
{
// base approach
case 1:
break;
// we use our looks for seduction
// thus looking attractive lowers enemy resistance, while being ugly can increase it
// however this fails if the soldier is not attracted to us
case 2:
{
// determine whether the soldier is attracted to us in the first place (don't display this, otherwise people will want to set sexual orientation and whatnot)
INT32 stat_dependant_roll = ( 37 * EffectiveStrength( pSoldier, FALSE ) + 92 * EffectiveMedical( pSoldier ) + 51 * EffectiveDexterity( pSoldier, FALSE ) + 61 * pSoldier->stats.bLife ) % 100;
bool samesexattraction = ( stat_dependant_roll < 8 );
bool female_player = ( this->ubBodyType == REGFEMALE );
bool female_soldier = ( pSoldier->ubBodyType == REGFEMALE );
bool fittingattraction = false;
if ( female_player != female_soldier && !samesexattraction )
fittingattraction = true;
else if ( female_player == female_soldier && samesexattraction )
fittingattraction = true;
if ( gMercProfiles[this->ubProfile].bAppearance == APPEARANCE_UGLY ) enemyresistancerating += 50 - ( fittingattraction ? 5 : 0 );
else if ( gMercProfiles[this->ubProfile].bAppearance == APPEARANCE_HOMELY ) enemyresistancerating += 40 - ( fittingattraction ? 15 : 0 );
else if ( gMercProfiles[this->ubProfile].bAppearance == APPEARANCE_AVERAGE ) enemyresistancerating += 30 - ( fittingattraction ? 30 : 0 );
else if ( gMercProfiles[this->ubProfile].bAppearance == APPEARANCE_ATTRACTIVE ) enemyresistancerating += 20 - ( fittingattraction ? 45 : 0 );
else if ( gMercProfiles[this->ubProfile].bAppearance == APPEARANCE_BABE ) enemyresistancerating += 10 - ( fittingattraction ? 60 : 0 );
// seduction works better in civilian clothing
if ( this->usSoldierFlagMask & SOLDIER_COVERT_CIV )
enemyresistancerating -= 5;
}
break;
// we try to bribe the soldier with money
case 3:
{
// the amount of money depends on progress and unimportant in this case
// the worse the location, the poorer the soldier, thus the more effective money is
enemyresistancerating -= 30 + (40 - ubLocationModifier);
}
break;
// we try to bribe the soldier with intel
case 4:
{
// the amount of intel depends on progress and unimportant in this case
enemyresistancerating -= 80;
}
break;
default:
break;
}
if ( enemyresistancerating > recruitrating )
return 0;
return max( 0, min( 100, recruitrating - enemyresistancerating ) );
}
void SOLDIERTYPE::AttemptToCreateTurncoat( UINT16 usID )
{
if ( usID >= NOBODY )
return;
SOLDIERTYPE* pSoldier = MercPtrs[usID];
if ( !pSoldier
|| pSoldier->bTeam != ENEMY_TEAM
|| ( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT ) )
return;
HandleTurncoatAttempt( pSoldier );
}
BOOLEAN SOLDIERTYPE::OrderTurnCoatToSwitchSides( UINT16 usID )
{
if ( usID >= NOBODY )
return FALSE;
SOLDIERTYPE* pSoldier = MercPtrs[usID];
if (!pSoldier
|| pSoldier->bTeam != ENEMY_TEAM
|| !( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT ) )
return FALSE;
if ( IsFreeSlotAvailable( MILITIA_TEAM ) )
{
// remove turncoat property
pSoldier->usSoldierFlagMask2 &= ~SOLDIER_TURNCOAT;
RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass );
MakeCivHostile( pSoldier );
return TRUE;
}
return FALSE;
}
void SOLDIERTYPE::OrderAllTurnCoatToSwitchSides()
{
SOLDIERTYPE *pSoldier;
INT32 cnt = gTacticalStatus.Team[ENEMY_TEAM].bFirstID;
// run through list
for ( pSoldier = MercPtrs[cnt]; cnt <= gTacticalStatus.Team[ENEMY_TEAM].bLastID; ++cnt, ++pSoldier )
{
if ( pSoldier->bActive && pSoldier->bInSector )
{
if ( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT )
{
if ( IsFreeSlotAvailable( MILITIA_TEAM ) )
{
// remove turncoat property
pSoldier->usSoldierFlagMask2 &= ~SOLDIER_TURNCOAT;
RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass );
MakeCivHostile( pSoldier );
}
else
{
return;
}
}
}
}
}
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
{
INT8 bBandaged; //,savedOurTurn;
+16 -3
View File
@@ -426,6 +426,7 @@ enum
#define SOLDIER_DRAG_SOUND 0x00080000 // played sound when started dragging
#define SOLDIER_SPENT_AP 0x00100000 // soldier has spent some AP this turn (including realtime)
#define SOLDIER_TURNCOAT 0x00200000 // this enemy soldier will switch to the militia team if ordered to
#define SOLDIER_INTERROGATE_ALL 0x000001F8 // all interrogation flags
// ----------------------------------------------------------------
@@ -597,13 +598,17 @@ enum{
SKILLS_RADIO_LISTEN,
SKILLS_RADIO_CALLREINFORCEMENTS,
SKILLS_RADIO_TURNOFF,
SKILLS_RADIO_LAST = SKILLS_RADIO_TURNOFF,
SKILLS_RADIO_ACTIVATE_TURNCOATS_ALL, // order all enemy turncoats to turn into militia right now (in case this requires a radio)
SKILLS_RADIO_LAST = SKILLS_RADIO_ACTIVATE_TURNCOATS_ALL,
// spy
SKILLS_INTEL_FIRST,
SKILLS_INTEL_CONCEAL = SKILLS_INTEL_FIRST, // assignment: spy hides among the population
SKILLS_INTEL_GATHERINTEL, // assignment: spy gathers information while disguised
SKILLS_INTEL_LAST = SKILLS_INTEL_GATHERINTEL,
SKILLS_CREATE_TURNCOAT,
SKILLS_ACTIVATE_TURNCOATS, // order enemy turncoat to turn into militia right now
SKILLS_ACTIVATE_TURNCOATS_ALL, // order all enemy turncoats to turn into militia right now
SKILLS_INTEL_LAST = SKILLS_ACTIVATE_TURNCOATS_ALL,
// various
SKILLS_VARIOUS_FIRST,
@@ -1915,7 +1920,7 @@ public:
BOOLEAN IsAIAllowedtoUseSkill( INT8 iSkill );
// print a small description of the skill if we can use it, or its requirements if we cannot
STR16 PrintSkillDesc( INT8 iSkill);
STR16 PrintSkillDesc( INT8 iSkill, INT32 sGridNo = -1 );
// Flugente: functions for the radio operator trait
BOOLEAN CanUseRadio(BOOLEAN fCheckForAP = TRUE); // can we use radio, if we even have one?
@@ -1932,6 +1937,7 @@ public:
BOOLEAN RadioListen();
BOOLEAN RadioCallReinforcements( UINT32 usSector, UINT16 sNumber );
BOOLEAN SwitchOffRadio();
BOOLEAN RadioOrderAllTurnCoatToSwitchSides();
void RadioFail(); // display and error sound used either when the radio set fails or the sector is jammed - the player knows of the error, but cannot be sure of the cause
// Flugente: spotter
@@ -2025,6 +2031,13 @@ public:
// Flugente: those with the <scrounging> background occasionally steal money from the locals
UINT8 GetThiefStealMoneyChance();
UINT8 GetThiefEvadeDetectionChance();
// Flugente: turncoats
BOOLEAN InPositionForTurncoatAttempt( UINT16 usID );
UINT8 GetTurncoatConvinctionChance( UINT16 usID, UINT8 usApproach );
void AttemptToCreateTurncoat( UINT16 usID );
BOOLEAN OrderTurnCoatToSwitchSides( UINT16 usID );
void OrderAllTurnCoatToSwitchSides();
//////////////////////////////////////////////////////////////////////////////
}; // SOLDIERTYPE;
+9
View File
@@ -1864,6 +1864,15 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
}
}
}
// Flugente: turncoats
if ( gSkillTraitValues.fCOTurncoats && pCreateStruct->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) )
{
if ( NumSoldiersofClassWithFlag2InSector( pCreateStruct->bTeam, pSoldier->ubSoldierClass, SOLDIER_TURNCOAT ) < NumTurncoatsOfClassInSector( gWorldSectorX, gWorldSectorY, pSoldier->ubSoldierClass ) )
{
pSoldier->usSoldierFlagMask2 |= SOLDIER_TURNCOAT;
}
}
// SANDRO - If neither of these two options are activated, use the original code
// however, "no traits" means no traits at all, so commented out
+5
View File
@@ -1587,6 +1587,11 @@ SOLDIERTYPE *ChangeSoldierTeam( SOLDIERTYPE *pSoldier, UINT8 ubTeam )
MercCreateStruct.fPlayerMerc = TRUE;
}
if ( ubTeam == MILITIA_TEAM )
{
MercCreateStruct.ubSoldierClass = pSoldier->ubSoldierClass;
}
if ( TacticalCreateSoldier( &MercCreateStruct, &ubID ) )
{
pNewSoldier = MercPtrs[ ubID ];
+8
View File
@@ -1147,6 +1147,7 @@ enum
IMPROVEGEARPICKUPMAG_STR,
DISTRACT_STOP_STR,
DISTRACT_TRY_TO_TURNCOAT,
TEXT_NUM_TACTICAL_STR
};
@@ -2673,6 +2674,11 @@ enum
TEXT_SKILL_DENIAL_SINGLEMERC,
TEXT_SKILL_DENIAL_NOALARM,
TEXT_SKILL_DENIAL_DISGUISE_CIV_OR_MIL,
TEXT_SKILL_DENIAL_NOT_DURING_INTERRUPT,
TEXT_SKILL_DENIAL_TURNED_ENEMY,
TEXT_SKILL_DENIAL_ENEMY,
TEXT_SKILL_DENIAL_SURFACELEVEL,
TEXT_SKILL_DENIAL_STRATEGIC_SUSPICION,
TEXT_SKILL_DENIAL_MAX,
};
@@ -3093,6 +3099,8 @@ extern STR16 szMilitiaText[];
extern STR16 szFactoryText[];
extern STR16 szTurncoatText[];
#define TACTICAL_INVENTORY_DIALOG_NUM 16
#define TACTICAL_COVER_DIALOG_NUM 16
+15
View File
@@ -11597,6 +11597,21 @@ STR16 szFactoryText[] = // TODO.Translate
L"h/item",
};
STR16 szTurncoatText[] =
{
L"%s now secretly works for us!",
L"%s is not swayed by our offer. Suspicion against us rises...",
L"Suspicion against us is high. We should stop trying to turn more soldiers to our side and lay low for a while.",
L"Recruit approach (%d)",
L"Use seduction (%d)",
L"Bribe ($%d) (%d)", // 5
L"Offer %d intel (%d)",
L"How to convince the soldier to join your forces?",
L"Do it",
L"%d turncoats present",
};
// WANNE: Some Chinese specific strings that needs to be in unicode!
STR16 ChineseSpecString1 = L"%"; //defined in _ChineseText.cpp as this file is already unicode
STR16 ChineseSpecString2 = L"*%3d%%%"; //defined in _ChineseText.cpp as this file is already unicode
+15
View File
@@ -11613,4 +11613,19 @@ STR16 szFactoryText[] = // TODO.Translate
L"h/item",
};
STR16 szTurncoatText[] =
{
L"%s now secretly works for us!",
L"%s is not swayed by our offer. Suspicion against us rises...",
L"Suspicion against us is high. We should stop trying to turn more soldiers to our side and lay low for a while.",
L"Recruit approach (%d)",
L"Use seduction (%d)",
L"Bribe ($%d) (%d)", // 5
L"Offer %d intel (%d)",
L"How to convince the soldier to join your forces?",
L"Do it",
L"%d turncoats present",
};
#endif //DUTCH
+30
View File
@@ -2814,10 +2814,14 @@ STR16 pTraitSkillsMenuStrings[] =
L"Eavesdrop",
L"Call reinforcements",
L"Switch off radio set",
L"Radio: Activate all turncoats",
// spy
L"Hide assignment",
L"Get Intel assignment",
L"Recruit turncoat",
L"Activate turncoat",
L"Activate all turncoats",
// various
L"Spotter",
@@ -2835,10 +2839,14 @@ STR16 pTraitSkillsMenuDescStrings[] =
L"Use your radio equipment to continously listen for enemy movement.",
L"Call in reinforcements from neighbouring sectors.",
L"Turn off radio set.",
L"Order all previously turned soldiers in the sector to betray their comrades and join you.",
// spy
L"Assignment: hide among the population.",
L"Assignment: hide among the population and gather intel.",
L"Try to turn an enemy into a turncoat.",
L"Order previously turned soldier to betray their comrades and join you.",
L"Order all previously turned soldiers in the sector to betray their comrades and join you.",
// various
L"Observe an area, granting allied snipers a bonus to cth on anything you see.",
@@ -2867,6 +2875,11 @@ STR16 pTraitSkillsDenialStrings[] =
L" - single merc\n",
L" - no alarm raised\n",
L" - civilian or soldier disguise\n",
L" - being our turn\n",
L" - turned enemy soldier\n",
L" - enemy soldier\n",
L" - surface sector\n",
L" - not being under suspicion\n",
};
STR16 pSkillMenuStrings[] =
@@ -4075,6 +4088,7 @@ CHAR16 TacticalStr[][ MED_STRING_LENGTH ] =
L"%s picked up %s",
L"%s has stopped chatting with %s",
L"Attempt to turn",
};
//Varying helptext explains (for the "Go to Sector/Map" checkbox) what will happen given different circumstances in the "exiting sector" interface.
@@ -11260,6 +11274,7 @@ STR16 szIndividualMilitiaBattleReportText[] =
L"Hired from Kerberus on Day %d, %d:%02d in %s",
L"Defected to us on Day %d, %d:%02d in %s",
L"Contract terminated on Day %d, %d:%02d",
L"Defected to us on Day %d, %d:%02d in %s",
};
STR16 szIndividualMilitiaTraitRequirements[] =
@@ -11597,4 +11612,19 @@ STR16 szFactoryText[] =
L"h/item",
};
STR16 szTurncoatText[] =
{
L"%s now secretly works for us!",
L"%s is not swayed by our offer. Suspicion against us rises...",
L"Suspicion against us is high. We should stop trying to turn more soldiers to our side and lay low for a while.",
L"Recruit approach (%d)",
L"Use seduction (%d)",
L"Bribe ($%d) (%d)", // 5
L"Offer %d intel (%d)",
L"How to convince the soldier to join your forces?",
L"Do it",
L"%d turncoats present",
};
#endif //ENGLISH
+15
View File
@@ -11595,4 +11595,19 @@ STR16 szFactoryText[] = // TODO.Translate
L"h/item",
};
STR16 szTurncoatText[] =
{
L"%s now secretly works for us!",
L"%s is not swayed by our offer. Suspicion against us rises...",
L"Suspicion against us is high. We should stop trying to turn more soldiers to our side and lay low for a while.",
L"Recruit approach (%d)",
L"Use seduction (%d)",
L"Bribe ($%d) (%d)", // 5
L"Offer %d intel (%d)",
L"How to convince the soldier to join your forces?",
L"Do it",
L"%d turncoats present",
};
#endif //FRENCH
+15
View File
@@ -11425,4 +11425,19 @@ STR16 szFactoryText[] = // TODO.Translate
L"h/item",
};
STR16 szTurncoatText[] =
{
L"%s now secretly works for us!",
L"%s is not swayed by our offer. Suspicion against us rises...",
L"Suspicion against us is high. We should stop trying to turn more soldiers to our side and lay low for a while.",
L"Recruit approach (%d)",
L"Use seduction (%d)",
L"Bribe ($%d) (%d)", // 5
L"Offer %d intel (%d)",
L"How to convince the soldier to join your forces?",
L"Do it",
L"%d turncoats present",
};
#endif //GERMAN
+15
View File
@@ -11604,4 +11604,19 @@ STR16 szFactoryText[] = // TODO.Translate
L"h/item",
};
STR16 szTurncoatText[] =
{
L"%s now secretly works for us!",
L"%s is not swayed by our offer. Suspicion against us rises...",
L"Suspicion against us is high. We should stop trying to turn more soldiers to our side and lay low for a while.",
L"Recruit approach (%d)",
L"Use seduction (%d)",
L"Bribe ($%d) (%d)", // 5
L"Offer %d intel (%d)",
L"How to convince the soldier to join your forces?",
L"Do it",
L"%d turncoats present",
};
#endif //ITALIAN
+1
View File
@@ -259,6 +259,7 @@ STR16 gzIMPMajorTraitsHelpTextsCovertOps[]=
L"伪装状态下使用近战武器攻击时,命中率增加 +%d%s \n",//L"+%d%s CTH with covert melee weapons\n",
L"伪装状态下使用近战武器攻击时,秒杀几率增加 +%d%s \n",//L"+%d%s chance of instakill with covert melee weapons\n",
L"伪装动作消耗的行动点 -%d%s \n",//L"Disguise AP cost lowered by %d%s.\n",
L"Can convince enemy soldiers to secretly change sides.\n", // TODO.Translate
};
STR16 gzIMPMajorTraitsHelpTextsRadioOperator[]=
+1
View File
@@ -259,6 +259,7 @@ STR16 gzIMPMajorTraitsHelpTextsCovertOps[]=
L"+%d%s CtH with covert melee weapons\n",
L"+%d%s chance of instakill with covert melee weapons\n",
L"Disguise AP cost lowered by %d%s.\n",
L"Can convince enemy soldiers to secretly change sides.\n", // TODO.Translate
};
STR16 gzIMPMajorTraitsHelpTextsRadioOperator[]= // TODO.Translate
+1
View File
@@ -259,6 +259,7 @@ STR16 gzIMPMajorTraitsHelpTextsCovertOps[]=
L"+%d%s CtH with covert melee weapons\n",
L"+%d%s chance of instakill with covert melee weapons\n",
L"Disguise AP cost lowered by %d%s.\n",
L"Can convince enemy soldiers to secretly change sides.\n",
};
STR16 gzIMPMajorTraitsHelpTextsRadioOperator[]=
+1
View File
@@ -259,6 +259,7 @@ STR16 gzIMPMajorTraitsHelpTextsCovertOps[]=
L"+%d%s de chance de toucher avec une arme d'espion\n",
L"+%d%s de chance de tuer un ennemi instantanément avec une arme d'espion\n",
L"Le nombre de PA pour se déguiser, est réduit de %d%s\n",
L"Can convince enemy soldiers to secretly change sides.\n", // TODO.Translate
};
STR16 gzIMPMajorTraitsHelpTextsRadioOperator[]=
+1
View File
@@ -259,6 +259,7 @@ STR16 gzIMPMajorTraitsHelpTextsCovertOps[]=
L"+%d%s Trefferwahrscheinlichkeit mit verdeckten Nahkampfwaffen (z.B. Garotte)\n",
L"+%d%s Wahrscheinlichkeit für einen tödlichen Angriff mit verdeckten Nahkampfwaffen (z.B. Garotte)\n",
L"Um %d%s verringerte AP-Kosten zum Verkleiden\n",
L"Kann feindliche Soldaten zum Überlaufen überreden.\n",
};
STR16 gzIMPMajorTraitsHelpTextsRadioOperator[]=
+1
View File
@@ -257,6 +257,7 @@ STR16 gzIMPMajorTraitsHelpTextsCovertOps[]=
L"+%d%s CtH with covert melee weapons\n",
L"+%d%s chance of instakill with covert melee weapons\n",
L"Disguise AP cost lowered by %d%s.\n",
L"Can convince enemy soldiers to secretly change sides.\n", // TODO.Translate
};
STR16 gzIMPMajorTraitsHelpTextsRadioOperator[]= // TODO.Translate
+1
View File
@@ -259,6 +259,7 @@ STR16 gzIMPMajorTraitsHelpTextsCovertOps[]=
L"+%d%s CtH with covert melee weapons\n",
L"+%d%s chance of instakill with covert melee weapons\n",
L"Disguise AP cost lowered by %d%s.\n",
L"Can convince enemy soldiers to secretly change sides.\n", // TODO.Translate
};
STR16 gzIMPMajorTraitsHelpTextsRadioOperator[]= // TODO.Translate
+1
View File
@@ -259,6 +259,7 @@ STR16 gzIMPMajorTraitsHelpTextsCovertOps[]=
L"+%d%s к шансу попадания скрытным оружием ближнего боя.\n",
L"+%d%s к шансу на смертельный удар скрытным оружием ближнего боя.\n",
L"ОД на переодевание снижены на %d%s.\n",
L"Can convince enemy soldiers to secretly change sides.\n", // TODO.Translate
};
STR16 gzIMPMajorTraitsHelpTextsRadioOperator[]=
+15
View File
@@ -11617,4 +11617,19 @@ STR16 szFactoryText[] = // TODO.Translate
L"h/item",
};
STR16 szTurncoatText[] =
{
L"%s now secretly works for us!",
L"%s is not swayed by our offer. Suspicion against us rises...",
L"Suspicion against us is high. We should stop trying to turn more soldiers to our side and lay low for a while.",
L"Recruit approach (%d)",
L"Use seduction (%d)",
L"Bribe ($%d) (%d)", // 5
L"Offer %d intel (%d)",
L"How to convince the soldier to join your forces?",
L"Do it",
L"%d turncoats present",
};
#endif //POLISH
+15
View File
@@ -11597,4 +11597,19 @@ STR16 szFactoryText[] = // TODO.Translate
L"h/item",
};
STR16 szTurncoatText[] =
{
L"%s now secretly works for us!",
L"%s is not swayed by our offer. Suspicion against us rises...",
L"Suspicion against us is high. We should stop trying to turn more soldiers to our side and lay low for a while.",
L"Recruit approach (%d)",
L"Use seduction (%d)",
L"Bribe ($%d) (%d)", // 5
L"Offer %d intel (%d)",
L"How to convince the soldier to join your forces?",
L"Do it",
L"%d turncoats present",
};
#endif //RUSSIAN