mirror of
https://github.com/1dot13/source.git
synced 2026-07-29 13:52:17 +02:00
- New Feature: enemy assassins disguise as militia and can ambush player mercs
- Fix: invalid GridNo for mounting weapons git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5753 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
+6
-1
@@ -1062,7 +1062,12 @@ void LoadGameExternalOptions()
|
||||
// Flugente: the assassins are disguised initially, so it is harder for the player to detect them
|
||||
gGameExternalOptions.fAssassinsAreDisguised = iniReader.ReadBoolean("Tactical Difficulty Settings", "ASSASSINS_DISGUISED", TRUE);
|
||||
|
||||
|
||||
// Flugente: does the queen send out assassins that mix among your militia?
|
||||
gGameExternalOptions.fEnemyAssassins = iniReader.ReadBoolean("Tactical Difficulty Settings", "ENEMY_ASSASSINS", TRUE);
|
||||
gGameExternalOptions.usAssassinMinimumProgress = iniReader.ReadInteger("Tactical Difficulty Settings", "ASSASSIN_MINIMUM_PROGRESS", 30, 0, 100);
|
||||
gGameExternalOptions.usAssassinMinimumMilitia = iniReader.ReadInteger("Tactical Difficulty Settings", "ASSASSIN_MINIMUM_MILITIA", 10, 0, 64);
|
||||
gGameExternalOptions.usAssassinPropabilityModifier = iniReader.ReadInteger("Tactical Difficulty Settings", "ASSASSIN_PROPABILITY_MODIFIER", 100, 0, 1000);
|
||||
|
||||
//################# Tactical Vision Settings #################
|
||||
|
||||
// Sight range
|
||||
|
||||
+11
-1
@@ -361,7 +361,15 @@ typedef struct
|
||||
BOOLEAN fEnableChanceOfEnemyAmbushes;
|
||||
INT8 bChanceModifierEnemyAmbushes;
|
||||
UINT8 usSpecialNPCStronger;
|
||||
BOOLEAN fAssassinsAreDisguised; // added by Flugente
|
||||
|
||||
// Flugente: should kingpin's hitmen be disguised? This will make them have random clothes among other stuff
|
||||
BOOLEAN fAssassinsAreDisguised;
|
||||
|
||||
// Flugente: does the queen send out assassins that mix among your militia?
|
||||
BOOLEAN fEnemyAssassins;
|
||||
UINT8 usAssassinMinimumProgress;
|
||||
UINT8 usAssassinMinimumMilitia;
|
||||
UINT32 usAssassinPropabilityModifier;
|
||||
///////////////////////////////////////
|
||||
|
||||
// System settings
|
||||
@@ -522,6 +530,8 @@ typedef struct
|
||||
UINT32 ubGameProgressMikeAvailable;
|
||||
UINT32 ubGameProgressIggyAvaliable;
|
||||
BOOLEAN ubSendTroopsToDrassen;
|
||||
|
||||
// Flugente: new counterattacks and other new AI tactics
|
||||
UINT8 ubAgressiveStrategicAI;
|
||||
UINT32 ubGameProgressOffensiveStage1;
|
||||
UINT32 ubGameProgressOffensiveStage2;
|
||||
|
||||
@@ -953,6 +953,23 @@ void StartCivQuote( SOLDIERTYPE *pCiv )
|
||||
|
||||
}
|
||||
|
||||
// Flugente: if we are an assassin, we speak like the militia we emulate
|
||||
if ( pCiv->bSoldierFlagMask & SOLDIER_ASSASSIN )
|
||||
{
|
||||
switch ( pCiv->GetUniformType() )
|
||||
{
|
||||
case UNIFORM_MILITIA_REGULAR:
|
||||
ubCivQuoteID = CIV_QUOTE_MEDIUM_MILITIA;
|
||||
break;
|
||||
case UNIFORM_MILITIA_ELITE:
|
||||
ubCivQuoteID = CIV_QUOTE_ELITE_MILITIA;
|
||||
break;
|
||||
default:
|
||||
ubCivQuoteID = CIV_QUOTE_GREEN_MILITIA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine location...
|
||||
// Get location of civ on screen.....
|
||||
GetSoldierScreenPos( pCiv, &sScreenX, &sScreenY );
|
||||
|
||||
@@ -2125,7 +2125,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum
|
||||
{
|
||||
//MakeCivHostile( pSoldier, 2 );
|
||||
}
|
||||
if (pSoldier->ubProfile != NO_PROFILE && pSoldier->stats.bLife >= OKLIFE)
|
||||
if ( ( pSoldier->ubProfile != NO_PROFILE || pSoldier->IsAssassin() ) && pSoldier->stats.bLife >= OKLIFE )
|
||||
{
|
||||
// trigger quote!
|
||||
//TriggerNPCWithIHateYouQuote( pSoldier->ubProfile );
|
||||
|
||||
@@ -358,7 +358,7 @@ enum
|
||||
UNNAMED_CIV_GROUP_17,
|
||||
UNNAMED_CIV_GROUP_18,
|
||||
UNNAMED_CIV_GROUP_19,
|
||||
UNNAMED_CIV_GROUP_20,
|
||||
ASSASSIN_CIV_GROUP, // Flugente: enemy assassins belong to this group
|
||||
UNNAMED_CIV_GROUP_21,
|
||||
UNNAMED_CIV_GROUP_22,
|
||||
UNNAMED_CIV_GROUP_23,
|
||||
|
||||
+12
-26
@@ -3066,35 +3066,21 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving )
|
||||
}
|
||||
|
||||
}
|
||||
else if ( pSoldier->bTeam == CIV_TEAM && pSoldier->ubProfile != NO_PROFILE && pSoldier->aiData.bNeutral )
|
||||
else if ( pSoldier->bTeam == CIV_TEAM && pSoldier->IsAssassin() && pSoldier->aiData.bNeutral )
|
||||
{
|
||||
switch( pSoldier->ubProfile )
|
||||
{
|
||||
case JIM:
|
||||
case JACK:
|
||||
case OLAF:
|
||||
case RAY:
|
||||
case OLGA:
|
||||
case TYRONE:
|
||||
{
|
||||
INT32 sDesiredMercDist;
|
||||
INT32 sDesiredMercDist;
|
||||
|
||||
if (!TileIsOutOfBounds(ClosestPC( pSoldier, &sDesiredMercDist )))
|
||||
{
|
||||
if ( sDesiredMercDist <= NPC_TALK_RADIUS * 2 )
|
||||
{
|
||||
// stop
|
||||
CancelAIAction( pSoldier, TRUE );
|
||||
// aaaaaaaaaaaaaaaaaaaaatttaaaack!!!!
|
||||
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
||||
//MakeCivHostile( pSoldier, 2 );
|
||||
//TriggerNPCWithIHateYouQuote( pSoldier->ubProfile );
|
||||
}
|
||||
}
|
||||
if (!TileIsOutOfBounds(ClosestPC( pSoldier, &sDesiredMercDist )))
|
||||
{
|
||||
if ( sDesiredMercDist <= NPC_TALK_RADIUS * 2 )
|
||||
{
|
||||
// stop
|
||||
CancelAIAction( pSoldier, TRUE );
|
||||
// aaaaaaaaaaaaaaaaaaaaatttaaaack!!!!
|
||||
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
||||
//MakeCivHostile( pSoldier, 2 );
|
||||
//TriggerNPCWithIHateYouQuote( pSoldier->ubProfile );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2048,7 +2048,7 @@ void TakeCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
else if ( pCorpse->def.ubBodyType == REGFEMALE || pCorpse->def.ubBodyType == MINICIV || pCorpse->def.ubBodyType == DRESSCIV )
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_F;
|
||||
|
||||
if ( pCorpse->def.usFlags & ROTTING_CORPSE_HEAD_TAKEN )
|
||||
if ( pCorpse->def.usFlags & ROTTING_CORPSE_HEAD_TAKEN || pCorpse->def.fHeadTaken )
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_NO_HEAD;
|
||||
|
||||
if ( pCorpse->def.usFlags & ROTTING_CORPSE_NO_VEST )
|
||||
|
||||
@@ -13828,6 +13828,10 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void )
|
||||
if ( this->pathing.bLevel == 1 )
|
||||
return( FALSE );
|
||||
|
||||
// this is odd - invalid GridNo... well, not mounted then
|
||||
if ( TileIsOutOfBounds(this->sGridNo) )
|
||||
return( FALSE );
|
||||
|
||||
// we determine the height of the next tile in our direction. Because of the way structures are handled, we sometimes have to take the very tile we're occupying right now
|
||||
INT32 nextGridNoinSight = this->sGridNo;
|
||||
if ( this->ubDirection == NORTH || this->ubDirection == SOUTHWEST || this->ubDirection == WEST || this->ubDirection == NORTHWEST )
|
||||
@@ -14718,17 +14722,23 @@ BOOLEAN SOLDIERTYPE::EquipmentTooGood( BOOLEAN fCloselook )
|
||||
INT8 uniformtype = GetUniformType();
|
||||
|
||||
// adjust max coolness depending on uniform
|
||||
// enemy spies get a small bonus here
|
||||
switch ( uniformtype )
|
||||
{
|
||||
case UNIFORM_ENEMY_ADMIN:
|
||||
maxcoolnessallowed += 1;
|
||||
break;
|
||||
case UNIFORM_ENEMY_TROOP:
|
||||
case UNIFORM_MILITIA_ROOKIE:
|
||||
maxcoolnessallowed += 2;
|
||||
break;
|
||||
case UNIFORM_ENEMY_ELITE:
|
||||
case UNIFORM_MILITIA_REGULAR:
|
||||
maxcoolnessallowed += 3;
|
||||
break;
|
||||
case UNIFORM_MILITIA_ELITE:
|
||||
maxcoolnessallowed += 4;
|
||||
break;
|
||||
default:
|
||||
// we do not wear a proper army uniform, uncover us. Note: This should never happen - if this message shows, somewhere, something is wrong
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_UNIFORM_NOORDER], this->name );
|
||||
@@ -15108,16 +15118,17 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
|
||||
// are we targeting a buddy of our observer?
|
||||
if ( this->ubTargetID && MercPtrs[this->ubTargetID] && MercPtrs[this->ubTargetID]->bTeam == pSoldier->bTeam )
|
||||
{
|
||||
// if we aiming at a soldier, others will notice our intent... not covert!
|
||||
// if we are aiming at a soldier, others will notice our intent... not covert!
|
||||
if ( WeaponReady(this) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_TARGETTING_SOLDIER], this->name );
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_TARGETTING_SOLDIER], this->name, MercPtrs[this->ubTargetID]->name );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// even as a soldier, we will be caught around fresh corpses
|
||||
if (distance < gSkillTraitValues.sCOCloseDetectionRangeSoldierCorpse)
|
||||
// assassins will not be uncovered around corpses, as the AI cannot willingly evade them... one could 'ward' against assassins by surrounding yourself with fresh corpses
|
||||
if (distance < gSkillTraitValues.sCOCloseDetectionRangeSoldierCorpse && !(this->bSoldierFlagMask & SOLDIER_ASSASSIN) )
|
||||
{
|
||||
// check wether we are around a fresh corpse - this will make us much more suspicious
|
||||
// I deem this necessary, to avoid cheap exploits by nefarious players :-)
|
||||
@@ -15208,6 +15219,11 @@ BOOLEAN SOLDIERTYPE::RecognizeAsCombatant(UINT8 ubTargetID)
|
||||
// we have uncovered a spy! Get alerted, if we aren't already
|
||||
if ( this->aiData.bAlertStatus < STATUS_BLACK )
|
||||
this->aiData.bAlertStatus = STATUS_BLACK;
|
||||
|
||||
// reset our sight of this guy
|
||||
this->aiData.bOppList[pSoldier->ubID] = NOT_HEARD_OR_SEEN;
|
||||
|
||||
ManSeesMan(this, pSoldier, pSoldier->sGridNo, pSoldier->pathing.bLevel, 0, 0);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -15216,11 +15232,22 @@ BOOLEAN SOLDIERTYPE::RecognizeAsCombatant(UINT8 ubTargetID)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// dress up in our natural state
|
||||
// loose covert property
|
||||
void SOLDIERTYPE::LooseDisguise( void )
|
||||
{
|
||||
// loose any covert flags
|
||||
this->bSoldierFlagMask &= ~(SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER);
|
||||
|
||||
// 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 )
|
||||
{
|
||||
if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 )
|
||||
{
|
||||
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// undisguise or take off any clothes item and switch back to original clothes
|
||||
@@ -15327,7 +15354,7 @@ BOOLEAN SOLDIERTYPE::CanProcessPrisoners()
|
||||
if ( !prisonhere )
|
||||
return FALSE;
|
||||
|
||||
// Are there any prisoners in this prison?
|
||||
// Are there any prisoners in this prison? note that there are no underground prisons
|
||||
if ( !this->bSectorZ )
|
||||
{
|
||||
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( this->sSectorX, this->sSectorY ) ] );
|
||||
@@ -15335,14 +15362,6 @@ BOOLEAN SOLDIERTYPE::CanProcessPrisoners()
|
||||
if ( pSectorInfo->uiNumberOfPrisonersOfWar > 0 )
|
||||
return TRUE;
|
||||
}
|
||||
// no underground prisons anyway
|
||||
/*else
|
||||
{
|
||||
UNDERGROUND_SECTORINFO *pSectorInfo = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
|
||||
|
||||
if ( pSectorInfo->uiNumberOfPrisonersOfWar > 0 )
|
||||
return TRUE;
|
||||
}*/
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -15383,6 +15402,20 @@ BOOLEAN SOLDIERTYPE::UsesScubaGear()
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Flugente: are we an assassin?
|
||||
BOOLEAN SOLDIERTYPE::IsAssassin()
|
||||
{
|
||||
// kingpin's hitmen are assassins
|
||||
if ( this->ubProfile >= JIM && this->ubProfile <= TYRONE )
|
||||
return TRUE;
|
||||
|
||||
// there can be non-NPC assassins too
|
||||
if ( this->bSoldierFlagMask & SOLDIER_ASSASSIN )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
INT8 bBandaged; //,savedOurTurn;
|
||||
@@ -16731,23 +16764,17 @@ BOOLEAN SOLDIERTYPE::PlayerSoldierStartTalking( UINT8 ubTargetID, BOOLEAN fValid
|
||||
}
|
||||
else if (pTSoldier->aiData.bNeutral)
|
||||
{
|
||||
switch( pTSoldier->ubProfile )
|
||||
if ( pTSoldier->IsAssassin() )
|
||||
{
|
||||
case JIM:
|
||||
case JACK:
|
||||
case OLAF:
|
||||
case RAY:
|
||||
case OLGA:
|
||||
case TYRONE:
|
||||
// Start combat etc
|
||||
DeleteTalkingMenu();
|
||||
CancelAIAction( pTSoldier, TRUE );
|
||||
AddToShouldBecomeHostileOrSayQuoteList( pTSoldier->ubID );
|
||||
break;
|
||||
default:
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start talking!
|
||||
return( InitiateConversation( pTSoldier, this, NPC_INITIAL_QUOTE, 0 ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -358,9 +358,9 @@ enum
|
||||
#define SOLDIER_DAMAGED_PANTS 0x00000100 //256 // Soldier's vest is damaged (and thus can't be taken off)
|
||||
#define SOLDIER_HEADSHOT 0x00000200 //512 // last hit received was a headshot (attack to the head, so knifes/punches also work)
|
||||
#define SOLDIER_POW 0x00000400 //1024 // we are a prisoner of war
|
||||
/*#define ENEMY_NET_4_LVL_3 0x00000800 //2048
|
||||
#define SOLDIER_ASSASSIN 0x00000800 //2048 // we are an enemy assassin, and thus we will behave very different from normal enemies
|
||||
|
||||
#define ENEMY_NET_1_LVL_4 0x00001000 //4096
|
||||
/*#define ENEMY_NET_1_LVL_4 0x00001000 //4096
|
||||
#define ENEMY_NET_2_LVL_4 0x00002000 //8192
|
||||
#define ENEMY_NET_3_LVL_4 0x00004000 //16384
|
||||
#define ENEMY_NET_4_LVL_4 0x00008000 //32768
|
||||
@@ -1494,7 +1494,7 @@ public:
|
||||
// do we recognize someone else as a combatant?
|
||||
BOOLEAN RecognizeAsCombatant(UINT8 ubTargetID);
|
||||
|
||||
// loose disguise, dress up in our natural state
|
||||
// loose covert property
|
||||
void LooseDisguise( void );
|
||||
|
||||
// lose disguise or take off any clothes item and switch back to original clothes
|
||||
@@ -1506,6 +1506,9 @@ public:
|
||||
|
||||
// Flugente: scuba gear
|
||||
BOOLEAN UsesScubaGear();
|
||||
|
||||
// Flugente: are we an assassin?
|
||||
BOOLEAN IsAssassin();
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}; // SOLDIERTYPE;
|
||||
|
||||
+124
-3
@@ -1249,8 +1249,8 @@ BOOLEAN TacticalCopySoldierFromProfile( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STR
|
||||
//}
|
||||
}
|
||||
|
||||
// Flugente: if playing with the covert trait, the assasins come covert, so they are tougher to find
|
||||
if ( gGameExternalOptions.fAssassinsAreDisguised && gGameOptions.fNewTraitSystem && pSoldier->ubProfile >= JIM && pSoldier->ubProfile <= TYRONE )
|
||||
// Flugente: if playing with the covert trait, the assassins come covert, so they are tougher to find
|
||||
if ( gGameExternalOptions.fAssassinsAreDisguised && gGameOptions.fNewTraitSystem && pSoldier->IsAssassin() )
|
||||
{
|
||||
pSoldier->bSoldierFlagMask |= (SOLDIER_COVERT_SOLDIER|SOLDIER_COVERT_NPC_SPECIAL|SOLDIER_NEW_VEST|SOLDIER_NEW_PANTS);
|
||||
|
||||
@@ -3015,6 +3015,127 @@ SOLDIERTYPE* TacticalCreateCreature( INT8 bCreatureBodyType )
|
||||
return TacticalCreateSoldier( &pp, &ubID );
|
||||
}
|
||||
|
||||
// Flugente: assassins are elite soldiers of the civ team that go hostile on a certain event, otherwsie they jsut blend in
|
||||
SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype)
|
||||
{
|
||||
BASIC_SOLDIERCREATE_STRUCT bp;
|
||||
SOLDIERCREATE_STRUCT pp;
|
||||
UINT8 ubID;
|
||||
SOLDIERTYPE * pSoldier;
|
||||
|
||||
// this needs the covert ops trait, and thus the new trait system
|
||||
if ( !gGameOptions.fNewTraitSystem )
|
||||
return NULL;
|
||||
|
||||
// not in autoresolve!
|
||||
if( guiCurrentScreen == AUTORESOLVE_SCREEN )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) );
|
||||
RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ELITE );
|
||||
RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ELITE );
|
||||
bp.bTeam = CIV_TEAM;
|
||||
bp.bOrders = SEEKENEMY;
|
||||
bp.bAttitude = (INT8) Random( MAXATTITUDES );
|
||||
bp.bBodyType = Random(4);
|
||||
bp.ubSoldierClass = SOLDIER_CLASS_ELITE;
|
||||
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
|
||||
|
||||
pSoldier = TacticalCreateSoldier( &pp, &ubID );
|
||||
|
||||
if ( pSoldier )
|
||||
{
|
||||
// set correct stats
|
||||
pSoldier->stats.bLife = pSoldier->stats.bLifeMax = (INT8)( 70 + Random( 26 ) );
|
||||
pSoldier->stats.bAgility = (INT8)( 70 + Random( 16 ) );
|
||||
|
||||
// add assassin flag
|
||||
pSoldier->bSoldierFlagMask |= (SOLDIER_COVERT_SOLDIER|SOLDIER_ASSASSIN);
|
||||
|
||||
// add spy trait lvl2
|
||||
pSoldier->stats.ubSkillTraits[0] = COVERT_NT;
|
||||
pSoldier->stats.ubSkillTraits[1] = COVERT_NT;
|
||||
|
||||
// set correct civ group
|
||||
pSoldier->ubCivilianGroup = ASSASSIN_CIV_GROUP;
|
||||
|
||||
// set militia name to further irritate the player
|
||||
swprintf( pSoldier->name, TacticalStr[ MILITIA_TEAM_MERC_NAME ] );
|
||||
|
||||
// wear a militia uniform
|
||||
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
|
||||
|
||||
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
|
||||
{
|
||||
switch( disguisetype )
|
||||
{
|
||||
case ELITE_MILITIA:
|
||||
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_MILITIA_ELITE ].vest );
|
||||
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_MILITIA_ELITE ].pants );
|
||||
break;
|
||||
case REGULAR_MILITIA:
|
||||
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_MILITIA_REGULAR ].vest );
|
||||
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_MILITIA_REGULAR ].pants );
|
||||
break;
|
||||
default:
|
||||
SET_PALETTEREP_ID( pSoldier->VestPal, gUniformColors[ UNIFORM_MILITIA_ROOKIE ].vest );
|
||||
SET_PALETTEREP_ID( pSoldier->PantsPal, gUniformColors[ UNIFORM_MILITIA_ROOKIE ].pants );
|
||||
break;
|
||||
}
|
||||
|
||||
// Use palette from HVOBJECT, then use substitution for pants, etc
|
||||
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[ usPaletteAnimSurface ].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
|
||||
|
||||
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
|
||||
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
|
||||
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
|
||||
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
|
||||
|
||||
pSoldier->CreateSoldierPalettes();
|
||||
}
|
||||
|
||||
// send soldier to centre of map, roughly
|
||||
pSoldier->aiData.sNoiseGridno = (CENTRAL_GRIDNO + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) * WORLD_COLS);
|
||||
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
|
||||
}
|
||||
|
||||
return( pSoldier );
|
||||
}
|
||||
|
||||
void CreateAssassin(UINT8 disguisetype)
|
||||
{
|
||||
SOLDIERTYPE* pSoldier = TacticalCreateEnemyAssassin( disguisetype );
|
||||
|
||||
if ( pSoldier )
|
||||
{
|
||||
// find a valid starting gridno
|
||||
if ( pSoldier->sInsertionGridNo <= 0 )
|
||||
{
|
||||
UINT8 tries = 0; // counter for gridno function... if we fail to get a valid starting gridno multiple times, do not place assassin
|
||||
INT32 sGridNo = NOWHERE;
|
||||
do
|
||||
{
|
||||
if ( ++tries > 20 )
|
||||
return;
|
||||
|
||||
sGridNo = RandomGridNo();
|
||||
}
|
||||
// a valid starting gridno must be valid, not in a structure, not in water, and not too near to our mercs
|
||||
while( TileIsOutOfBounds(sGridNo) || FindStructure( sGridNo, STRUCTURE_BLOCKSMOVES ) || TERRAIN_IS_WATER( gpWorldLevelData[ sGridNo ].ubTerrainID) || GridNoNearPlayerMercs(sGridNo, 12) );
|
||||
|
||||
pSoldier->sInsertionGridNo = sGridNo;
|
||||
}
|
||||
|
||||
AddSoldierToSector( pSoldier->ubID );
|
||||
|
||||
// So we can see them!
|
||||
AllTeamsLookForAll(NO_INTERRUPTS);
|
||||
|
||||
gTacticalStatus.fCivGroupHostile[ ASSASSIN_CIV_GROUP ] = CIV_GROUP_WILL_BECOME_HOSTILE;
|
||||
}
|
||||
}
|
||||
|
||||
void RandomizeRelativeLevel( INT8 *pbRelLevel, UINT8 ubSoldierClass )
|
||||
{
|
||||
@@ -4794,4 +4915,4 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
|
||||
return( TRUE );
|
||||
else
|
||||
return( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,6 +426,10 @@ SOLDIERTYPE* TacticalCreateArmyTroop();
|
||||
SOLDIERTYPE* TacticalCreateMilitia( UINT8 ubMilitiaClass );
|
||||
SOLDIERTYPE* TacticalCreateCreature( INT8 bCreatureBodyType );
|
||||
|
||||
// Flugente: assassins are elite soldiers of the civ team that go hostile on a certain event, otherwise they just blend in
|
||||
SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype);
|
||||
void CreateAssassin(UINT8 disguisetype);
|
||||
|
||||
// randomly generates a relative level rating (attributes or equipment)
|
||||
void RandomizeRelativeLevel( INT8 *pbRelLevel, UINT8 ubSoldierClass );
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@
|
||||
#include "Queen Command.h"
|
||||
|
||||
#include "Map Edgepoints.h"
|
||||
#include "Campaign.h" // added by Flugente for HighestPlayerProgressPercentage()
|
||||
|
||||
BOOLEAN gfOriginalList = TRUE;
|
||||
|
||||
SOLDIERINITNODE *gSoldierInitHead = NULL;
|
||||
@@ -911,7 +913,12 @@ UINT8 AddSoldierInitListTeamToWorld( INT8 bTeam, UINT8 ubMaxNum )
|
||||
//we now have the number, so compared it to the num we can add, and determine how we will
|
||||
//randomly determine which nodes to add.
|
||||
if( !ubSlotsAvailable )
|
||||
{ //There aren't any basic placements of desired team, so exit.
|
||||
{
|
||||
// Flugente: decide wether to spawn enemy assassins in this sector (not kingpin's hitmen, they are handled elsewhere)
|
||||
if ( bTeam == MILITIA_TEAM )
|
||||
SectorAddAssassins(gWorldSectorX, gWorldSectorY, gbWorldSectorZ);
|
||||
|
||||
//There aren't any basic placements of desired team, so exit.
|
||||
return ubNumAdded;
|
||||
}
|
||||
curr = mark;
|
||||
@@ -953,6 +960,11 @@ UINT8 AddSoldierInitListTeamToWorld( INT8 bTeam, UINT8 ubMaxNum )
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
// Flugente: decide wether to spawn enemy assassins in this sector (not kingpin's hitmen, they are handled elsewhere)
|
||||
if ( bTeam == MILITIA_TEAM )
|
||||
SectorAddAssassins(gWorldSectorX, gWorldSectorY, gbWorldSectorZ);
|
||||
|
||||
return ubNumAdded;
|
||||
}
|
||||
|
||||
@@ -2676,3 +2688,82 @@ void AddSoldierInitListMilitiaOnEdge( UINT8 ubStrategicInsertionCode, UINT8 ubNu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern UINT32 GetWorldTotalMin( );
|
||||
|
||||
// Flugente: decide wether to spawn enemy assassins in this sector (not kingpin's hitmen, they are handled elsewhere)
|
||||
void SectorAddAssassins( INT16 sMapX, INT16 sMapY, INT16 sMapZ )
|
||||
{
|
||||
// this needs to be turned on on, and new trait system needs to be active
|
||||
if ( !gGameExternalOptions.fEnemyAssassins || !gGameOptions.fNewTraitSystem )
|
||||
return;
|
||||
|
||||
// only possible if a certain progress has been reached - the queen only sends out assassins after a while
|
||||
if ( HighestPlayerProgressPercentage() < gGameExternalOptions.usAssassinMinimumProgress )
|
||||
return;
|
||||
|
||||
// not in underground sectors
|
||||
if ( sMapZ > 0 )
|
||||
return;
|
||||
|
||||
SECTORINFO *pSector = &SectorInfo[ SECTOR( sMapX, sMapY ) ];
|
||||
if ( !pSector )
|
||||
return;
|
||||
|
||||
// does not work atm, time gets reset too early
|
||||
// not if we have recently been in this sector
|
||||
//if ( pSector->uiTimeCurrentSectorWasLastLoaded + 10 > GetWorldTotalMin() )
|
||||
//return;
|
||||
|
||||
// do not spawn if militia size is very small (we will be spotted much easier by the player)
|
||||
UINT32 totalmilitia = pSector->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] + pSector->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] + pSector->ubNumberOfCivsAtLevel[ ELITE_MILITIA ];
|
||||
if ( totalmilitia < gGameExternalOptions.usAssassinMinimumMilitia )
|
||||
return;
|
||||
|
||||
// count current number of civilians
|
||||
UINT16 numberofcivs = 0;
|
||||
SOLDIERTYPE* pTeamSoldier = NULL;
|
||||
INT32 cnt = gTacticalStatus.Team[ CIV_TEAM ].bFirstID;
|
||||
INT32 lastid = gTacticalStatus.Team[ CIV_TEAM ].bLastID;
|
||||
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt < lastid; ++cnt, ++pTeamSoldier)
|
||||
{
|
||||
// check if teamsoldier exists in this sector
|
||||
if ( pTeamSoldier && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->sSectorX == sMapX && pTeamSoldier->sSectorY == sMapY && pTeamSoldier->bSectorZ == sMapZ )
|
||||
++numberofcivs;
|
||||
}
|
||||
|
||||
// we can't spawn if all civilian slots are already taken
|
||||
if ( numberofcivs >= gGameExternalOptions.ubGameMaximumNumberOfCivilians )
|
||||
return;
|
||||
|
||||
// now count militia, and which type (green, regular, elite) is most numerous - that will be the best type to blend in
|
||||
UINT8 militiacnt = pSector->ubNumberOfCivsAtLevel[ GREEN_MILITIA ];
|
||||
UINT8 militiadisguise = GREEN_MILITIA;
|
||||
if ( pSector->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] > militiacnt )
|
||||
{
|
||||
militiacnt = pSector->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ];
|
||||
militiadisguise = REGULAR_MILITIA;
|
||||
}
|
||||
if ( pSector->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] > militiacnt )
|
||||
{
|
||||
militiacnt = pSector->ubNumberOfCivsAtLevel[ ELITE_MILITIA ];
|
||||
militiadisguise = ELITE_MILITIA;
|
||||
}
|
||||
|
||||
// the bigger the militia, the more likely infiltration
|
||||
// if militia is at maximum, there is a 10% chance of infiltration
|
||||
UINT32 resultrange = gGameExternalOptions.ubGameMaximumNumberOfRebels * 10;
|
||||
UINT32 modifiedmilitianumber = totalmilitia * gGameExternalOptions.usAssassinPropabilityModifier / 100;
|
||||
if ( Random(resultrange) >= modifiedmilitianumber )
|
||||
return;
|
||||
|
||||
CreateAssassin( militiadisguise );
|
||||
++numberofcivs;
|
||||
|
||||
// if there is still room for a second assassin, and we are feeling very lucky again, add a second one
|
||||
if ( numberofcivs < gGameExternalOptions.ubGameMaximumNumberOfCivilians && Random(resultrange) < modifiedmilitianumber )
|
||||
{
|
||||
CreateAssassin( militiadisguise );
|
||||
++numberofcivs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,4 +59,7 @@ void RemoveDetailedPlacementInfo( UINT8 ubNodeID );
|
||||
void AddProfilesUsingProfileInsertionData();
|
||||
void AddProfilesNotUsingProfileInsertionData();
|
||||
|
||||
// Flugente: decide wether to spawn enemy assassins in this sector (not kingpin's hitmen, they are handled elsewhere)
|
||||
void SectorAddAssassins( INT16 sMapX, INT16 sMapY, INT16 sMapZ );
|
||||
|
||||
#endif
|
||||
+64
-3
@@ -770,6 +770,11 @@ void CheckHostileOrSayQuoteList( void )
|
||||
{
|
||||
gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] = CIV_GROUP_HOSTILE;
|
||||
}
|
||||
|
||||
// reevaluate sight - we might already see people that weren't enemies until now
|
||||
ManLooksForOtherTeams(pSoldier);
|
||||
|
||||
pSoldier->aiData.bAlertStatus = STATUS_RED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2370,6 +2375,42 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Flugente: for assassins without profiles
|
||||
else if ( pSoldier->IsAssassin() && pSoldier->bTeam == CIV_TEAM )
|
||||
{
|
||||
// if we are an assassin and still neutral and undercover, approach target and then become hostile
|
||||
if ( pSoldier->aiData.bNeutral && pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) )
|
||||
{
|
||||
// only if this guy isn't disguised himself!
|
||||
if ( (pOpponent->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) == 0)
|
||||
{
|
||||
if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] >= CIV_GROUP_WILL_BECOME_HOSTILE )
|
||||
{
|
||||
// measure distance to our opponent, only go hostile if he is close enough
|
||||
if ( PythSpacesAway( pSoldier->sGridNo, pOpponent->sGridNo ) <= NPC_TALK_RADIUS * 2 )
|
||||
{
|
||||
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
||||
fNotAddedToList = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( fNotAddedToList )
|
||||
{
|
||||
// change orders, reset action!
|
||||
if ( pSoldier->aiData.bOrders != SEEKENEMY )
|
||||
{
|
||||
pSoldier->aiData.bOrders = SEEKENEMY;
|
||||
if ( pSoldier->aiData.bOppCnt == 0 )
|
||||
{
|
||||
// didn't see anyone before!
|
||||
CancelAIAction( pSoldier, TRUE );
|
||||
SetNewSituation( pSoldier );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pSoldier->bTeam == CIV_TEAM )
|
||||
@@ -2515,9 +2556,29 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo,
|
||||
*/
|
||||
}
|
||||
|
||||
// if both of us are not neutral, AND
|
||||
// if this man is actually a true opponent (we're not on the same side)
|
||||
if (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
||||
// Flugente: reworked this to account for covert ops and assassin mechanisms
|
||||
// if we are not neutral against this guy, we are truly opponents (we're not on the same side) and recognize him as an opponent...
|
||||
BOOLEAN fAddAsOpponent = FALSE;
|
||||
if ( !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
||||
{
|
||||
// ... check wether he is not neutral against us (account for the fact that we might be covert!)
|
||||
// if we are an NPC assassin
|
||||
if ( pSoldier->bSoldierFlagMask & SOLDIER_ASSASSIN && pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) )
|
||||
{
|
||||
// check wether our opponent would see us as an opponent if we weren't covert
|
||||
if ( !( (pSoldier->aiData.bNeutral || pSoldier->bSoldierFlagMask & SOLDIER_POW) && ( pOpponent->bTeam != CREATURE_TEAM || pOpponent->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) )
|
||||
fAddAsOpponent = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// simply check wether this guy sees us as an opponent too
|
||||
if ( !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) )
|
||||
fAddAsOpponent = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( fAddAsOpponent )
|
||||
{
|
||||
AddOneOpponent(pSoldier);
|
||||
|
||||
|
||||
@@ -1459,6 +1459,59 @@ INT32 ClosestPC( SOLDIERTYPE *pSoldier, INT32 * psDistance )
|
||||
return( sGridNo );
|
||||
}
|
||||
|
||||
// Flugente: like ClosestPC(...), but does not account for covert or not visible mercs
|
||||
INT32 ClosestUnDisguisedPC( SOLDIERTYPE *pSoldier, INT32 * psDistance )
|
||||
{
|
||||
// used by NPCs... find the closest PC
|
||||
// NOTE: skips EPCs!
|
||||
|
||||
UINT8 ubLoop;
|
||||
SOLDIERTYPE *pTargetSoldier;
|
||||
INT32 sMinDist = WORLD_MAX;
|
||||
INT32 sDist;
|
||||
INT32 sGridNo = NOWHERE;
|
||||
|
||||
// Loop through all mercs on player team
|
||||
ubLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
|
||||
for ( ; ubLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ubLoop++)
|
||||
{
|
||||
pTargetSoldier = Menptr + ubLoop;
|
||||
|
||||
if (!pTargetSoldier->bActive || !pTargetSoldier->bInSector)
|
||||
continue;
|
||||
|
||||
// if not conscious, skip him
|
||||
if (pTargetSoldier->stats.bLife < OKLIFE)
|
||||
continue;
|
||||
|
||||
if ( AM_AN_EPC( pTargetSoldier ) )
|
||||
continue;
|
||||
|
||||
if ( pTargetSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) )
|
||||
continue;
|
||||
|
||||
sDist = PythSpacesAway(pSoldier->sGridNo,pTargetSoldier->sGridNo);
|
||||
|
||||
// if this PC is not visible to the soldier, then add a penalty to the distance
|
||||
// so that we weight in favour of visible mercs
|
||||
if ( pTargetSoldier->bTeam != pSoldier->bTeam && pSoldier->aiData.bOppList[ ubLoop ] != SEEN_CURRENTLY )
|
||||
continue;
|
||||
|
||||
if (sDist < sMinDist)
|
||||
{
|
||||
sMinDist = sDist;
|
||||
sGridNo = pTargetSoldier->sGridNo;
|
||||
}
|
||||
}
|
||||
|
||||
if ( psDistance )
|
||||
{
|
||||
*psDistance = sMinDist;
|
||||
}
|
||||
|
||||
return( sGridNo );
|
||||
}
|
||||
|
||||
INT32 FindClosestClimbPointAvailableToAI( SOLDIERTYPE * pSoldier, INT32 sStartGridNo, INT32 sDesiredGridNo, BOOLEAN fClimbUp )
|
||||
{
|
||||
INT32 sGridNo;
|
||||
|
||||
@@ -440,7 +440,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
|
||||
//NumMessage("SHOT AttackValue = ",iAttackValue / 1000);
|
||||
|
||||
// special stuff for assassins to ignore militia more
|
||||
if ( pSoldier->ubProfile >= JIM && pSoldier->ubProfile <= TYRONE && pOpponent->bTeam == MILITIA_TEAM )
|
||||
if ( pSoldier->IsAssassin() && pOpponent->bTeam == MILITIA_TEAM )
|
||||
{
|
||||
iAttackValue /= 2;
|
||||
}
|
||||
|
||||
+61
-19
@@ -662,14 +662,8 @@ INT8 DecideActionNamedNPC( SOLDIERTYPE * pSoldier )
|
||||
}
|
||||
}
|
||||
|
||||
switch( pSoldier->ubProfile )
|
||||
if ( pSoldier->IsAssassin() )
|
||||
{
|
||||
case JIM:
|
||||
case JACK:
|
||||
case OLAF:
|
||||
case RAY:
|
||||
case OLGA:
|
||||
case TYRONE:
|
||||
sDesiredMercLoc = ClosestPC( pSoldier, &sDesiredMercDist );
|
||||
|
||||
if (!TileIsOutOfBounds(sDesiredMercLoc))
|
||||
@@ -691,9 +685,6 @@ INT8 DecideActionNamedNPC( SOLDIERTYPE * pSoldier )
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return( AI_ACTION_NONE );
|
||||
@@ -838,9 +829,36 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
}
|
||||
|
||||
if (pSoldier->ubProfile != NO_PROFILE)
|
||||
if ( pSoldier->ubProfile != NO_PROFILE || pSoldier->IsAssassin() )
|
||||
{
|
||||
pSoldier->aiData.bAction = DecideActionNamedNPC( pSoldier );
|
||||
if ( pSoldier->ubProfile != NO_PROFILE )
|
||||
pSoldier->aiData.bAction = DecideActionNamedNPC( pSoldier );
|
||||
else
|
||||
{
|
||||
INT32 sDesiredMercDist;
|
||||
INT32 sDesiredMercLoc = ClosestUnDisguisedPC( pSoldier, &sDesiredMercDist );
|
||||
|
||||
if (!TileIsOutOfBounds(sDesiredMercLoc))
|
||||
{
|
||||
if ( sDesiredMercDist <= NPC_TALK_RADIUS * 2 )
|
||||
{
|
||||
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
||||
// now wait a bit!
|
||||
pSoldier->aiData.usActionData = 5000;
|
||||
pSoldier->aiData.bAction = AI_ACTION_WAIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSoldier->aiData.usActionData = GoAsFarAsPossibleTowards( pSoldier, sDesiredMercLoc, AI_ACTION_APPROACH_MERC );
|
||||
|
||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||
{
|
||||
pSoldier->aiData.bAction = AI_ACTION_APPROACH_MERC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( pSoldier->aiData.bAction != AI_ACTION_NONE )
|
||||
{
|
||||
return( pSoldier->aiData.bAction );
|
||||
@@ -852,9 +870,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
// turn off counter so we don't check it again
|
||||
pSoldier->uiTimeSinceLastSpoke = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if not in the way, do nothing most of the time
|
||||
@@ -1440,18 +1456,44 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
// ******************
|
||||
// REAL TIME NPC CODE
|
||||
// ******************
|
||||
if (pSoldier->ubProfile != NO_PROFILE)
|
||||
if (pSoldier->ubProfile != NO_PROFILE || pSoldier->IsAssassin() )
|
||||
{
|
||||
pSoldier->aiData.bAction = DecideActionNamedNPC( pSoldier );
|
||||
if ( pSoldier->ubProfile != NO_PROFILE )
|
||||
pSoldier->aiData.bAction = DecideActionNamedNPC( pSoldier );
|
||||
else
|
||||
{
|
||||
INT32 sDesiredMercDist;
|
||||
INT32 sDesiredMercLoc = ClosestUnDisguisedPC( pSoldier, &sDesiredMercDist );
|
||||
|
||||
// Flugente: if this guy is disguised, do not consider him
|
||||
|
||||
if (!TileIsOutOfBounds(sDesiredMercLoc))
|
||||
{
|
||||
if ( sDesiredMercDist <= NPC_TALK_RADIUS * 2 )
|
||||
{
|
||||
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
||||
// now wait a bit!
|
||||
pSoldier->aiData.usActionData = 5000;
|
||||
pSoldier->aiData.bAction = AI_ACTION_WAIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSoldier->aiData.usActionData = GoAsFarAsPossibleTowards( pSoldier, sDesiredMercLoc, AI_ACTION_APPROACH_MERC );
|
||||
|
||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||
{
|
||||
pSoldier->aiData.bAction = AI_ACTION_APPROACH_MERC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( pSoldier->aiData.bAction != AI_ACTION_NONE )
|
||||
{
|
||||
return( pSoldier->aiData.bAction );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// determine the most important noise heard, and its relative value
|
||||
|
||||
@@ -162,6 +162,7 @@ INT8 ClosestPanicTrigger( SOLDIERTYPE * pSoldier );
|
||||
|
||||
INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel);
|
||||
INT32 ClosestPC( SOLDIERTYPE *pSoldier, INT32 * psDistance );
|
||||
INT32 ClosestUnDisguisedPC( SOLDIERTYPE *pSoldier, INT32 * psDistance ); // Flugente: like ClosestPC(...), but does not account for covert or not visible mercs
|
||||
BOOLEAN CanAutoBandage( BOOLEAN fDoFullCheck );
|
||||
|
||||
void DebugAI( STR szOutput );
|
||||
|
||||
@@ -1422,3 +1422,21 @@ INT32 RandomGridNo()
|
||||
}while( !GridNoOnVisibleWorldTile( iMapIndex ) );
|
||||
return iMapIndex;
|
||||
}
|
||||
|
||||
// Flugente: is this gridno near a player merc?
|
||||
BOOLEAN GridNoNearPlayerMercs( INT32 sGridNo, INT16 sRadius )
|
||||
{
|
||||
SOLDIERTYPE* pTeamSoldier = NULL;
|
||||
INT32 cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID;
|
||||
INT32 lastid = gTacticalStatus.Team[ OUR_TEAM ].bLastID;
|
||||
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt < lastid; ++cnt, ++pTeamSoldier)
|
||||
{
|
||||
if ( pTeamSoldier && pTeamSoldier->bActive && pTeamSoldier->bInSector )
|
||||
{
|
||||
if ( PythSpacesAway(sGridNo, pTeamSoldier->sGridNo) < sRadius )
|
||||
return( TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
@@ -151,5 +151,7 @@ BOOLEAN FindWallJumpDirection( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStart
|
||||
BOOLEAN FindLowerLevelWall( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStartingDir, INT8 *pbDirection );
|
||||
BOOLEAN FindWindowJumpDirection( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStartingDir, INT8 *pbDirection );
|
||||
|
||||
// Flugente: is this gridno near a player merc?
|
||||
BOOLEAN GridNoNearPlayerMercs( INT32 sGridNo, INT16 sRadius );
|
||||
|
||||
#endif
|
||||
+23
-19
@@ -614,26 +614,30 @@ void RenderRadarScreen( )
|
||||
}
|
||||
else
|
||||
{
|
||||
// If on roof, make darker....
|
||||
if ( pSoldier->pathing.bLevel > 0 )
|
||||
{
|
||||
usLineColor = Get16BPPColor( FROMRGB( 150, 150, 0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
usLineColor = Get16BPPColor( gTacticalStatus.Team[ pSoldier->bTeam ].RadarColor );
|
||||
}
|
||||
// If on roof, make darker....
|
||||
if ( pSoldier->pathing.bLevel > 0 )
|
||||
{
|
||||
usLineColor = Get16BPPColor( FROMRGB( 150, 150, 0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
usLineColor = Get16BPPColor( gTacticalStatus.Team[ pSoldier->bTeam ].RadarColor );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
usLineColor = Get16BPPColor( gTacticalStatus.Team[ pSoldier->bTeam ].RadarColor );
|
||||
|
||||
// Override civ team with red if hostile...
|
||||
if ( pSoldier->bTeam == CIV_TEAM && !pSoldier->aiData.bNeutral && ( pSoldier->bSide != gbPlayerNum ) )
|
||||
{
|
||||
|
||||
// Override civ team with red if hostile...
|
||||
if ( pSoldier->bTeam == CIV_TEAM && !pSoldier->aiData.bNeutral && ( pSoldier->bSide != gbPlayerNum ) )
|
||||
{
|
||||
usLineColor = Get16BPPColor( FROMRGB( 255, 0, 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: if we are a (still covert) enemy assassin, colour us like militia, so that the player wont notice us
|
||||
if ( pSoldier->bSoldierFlagMask & SOLDIER_ASSASSIN && pSoldier->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
usLineColor = Get16BPPColor( gTacticalStatus.Team[ MILITIA_TEAM ].RadarColor );
|
||||
|
||||
// Render different color if an enemy and he's unconscious
|
||||
if ( pSoldier->bTeam != gbPlayerNum && pSoldier->stats.bLife < OKLIFE )
|
||||
@@ -641,11 +645,11 @@ void RenderRadarScreen( )
|
||||
usLineColor = Get16BPPColor( FROMRGB( 128, 128, 128 ) );
|
||||
}
|
||||
|
||||
// If on roof, make darker....
|
||||
if ( pSoldier->bTeam == gbPlayerNum && pSoldier->pathing.bLevel > 0 )
|
||||
{
|
||||
usLineColor = Get16BPPColor( FROMRGB( 150, 150, 0 ) );
|
||||
}
|
||||
// If on roof, make darker....
|
||||
if ( pSoldier->bTeam == gbPlayerNum && pSoldier->pathing.bLevel > 0 )
|
||||
{
|
||||
usLineColor = Get16BPPColor( FROMRGB( 150, 150, 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
RectangleDraw( TRUE, sXSoldRadar, sYSoldRadar, sXSoldRadar+1, sYSoldRadar+1, usLineColor, pDestBuf );
|
||||
|
||||
@@ -1425,16 +1425,22 @@ void RenderOverheadOverlays()
|
||||
{ //normal
|
||||
if(is_networked)
|
||||
{
|
||||
if(pSoldier->bTeam!=0)
|
||||
if(pSoldier->bTeam != OUR_TEAM)
|
||||
{
|
||||
if(pSoldier->bSide==1)
|
||||
{
|
||||
// Civ (white)
|
||||
if (pSoldier->bTeam == 4)
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, 4 );
|
||||
if (pSoldier->bTeam == CIV_TEAM)
|
||||
{
|
||||
// Flugente: if we are a (still covert) enemy assassin, colour us like militia, so that the player wont notice us
|
||||
if ( pSoldier->bSoldierFlagMask & SOLDIER_ASSASSIN && pSoldier->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, MILITIA_TEAM );
|
||||
else
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, CIV_TEAM );
|
||||
}
|
||||
// Enemy (red)
|
||||
else
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, 1 );
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, ENEMY_TEAM );
|
||||
}
|
||||
|
||||
// Other clients
|
||||
@@ -1449,8 +1455,15 @@ void RenderOverheadOverlays()
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, pSoldier->bTeam );
|
||||
}
|
||||
else
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, pSoldier->bTeam );
|
||||
RegisterBackgroundRect(BGND_FLAG_SINGLE, NULL, sX, sY, (INT16)(sX + 3), (INT16)(sY + 9));
|
||||
{
|
||||
// Flugente: if we are a (still covert) enemy assassin, colour us like militia, so that the player wont notice us
|
||||
if ( pSoldier->bSoldierFlagMask & SOLDIER_ASSASSIN && pSoldier->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, MILITIA_TEAM );
|
||||
else
|
||||
Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, pSoldier->bTeam );
|
||||
|
||||
RegisterBackgroundRect(BGND_FLAG_SINGLE, NULL, sX, sY, (INT16)(sX + 3), (INT16)(sY + 9));
|
||||
}
|
||||
}
|
||||
else if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
|
||||
{ //vehicle
|
||||
|
||||
@@ -7426,11 +7426,11 @@ STR16 szCovertTextStr[]=
|
||||
L"%s 有迷彩油的痕迹!", //L"%s has camo!",
|
||||
L"%s 有不合身份的背包!", //L"%s has a backpack!",
|
||||
L"%s 被发现携带尸体!", //L"%s is seen carrying a corpse!",
|
||||
L"%s's %s is suspicious!",
|
||||
L"%s's %s is considered military hardware!",
|
||||
L"%s's %s is suspicious!",// TODO.Translate
|
||||
L"%s's %s is considered military hardware!",// TODO.Translate
|
||||
L"%s 携带了太多的枪支!", //L"%s carries too many guns!",
|
||||
L"%s's %s is too advanced for an arulcan soldier!",
|
||||
L"%s's %s has too many attachments!",
|
||||
L"%s's %s is too advanced for an arulcan soldier!",// TODO.Translate
|
||||
L"%s's %s has too many attachments!",// TODO.Translate
|
||||
L"%s 被发现有可疑举动!", //L"%s was seen performing suspicious activities!",
|
||||
L"%s 被发现不像个平民!", //L"%s does not look like a civilian!",
|
||||
L"%s 被发现流血不止了!", //L"%s bleeding was discovered!",
|
||||
@@ -7439,7 +7439,7 @@ STR16 szCovertTextStr[]=
|
||||
L"%s 不应该出现在这里!", //L"%s isn't supposed to be here!",
|
||||
L"%s 不应该在这个时候出现在这里!", //L"%s isn't supposed to be here at this time!",
|
||||
L"%s 被发现在新鲜尸体旁边行踪诡秘!", //L"%s was seen near a fresh corpse!",
|
||||
L"%s 的装备让人惊疑!", //L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targetting %s!", // TODO.Translate
|
||||
L"%s 被发现瞄准了其他士兵!", //L"%s is seen targeting a soldier!",
|
||||
L"%s 被识破了 %s 伪装!", //L"%s has seen through %s disguise!",
|
||||
L"无法找到对应的衣服信息在 Items.xml 中!", //L"No clothes item found in Items.xml!",
|
||||
@@ -7450,7 +7450,7 @@ STR16 szCovertTextStr[]=
|
||||
L"未发现制服!", //L"No uniform found!",
|
||||
L"%s 已伪装成平民", //L"%s is now disguised as a civilian.",
|
||||
L"%s 已伪装成士兵", //L"%s is now disguised as a soldier.",
|
||||
L"%s wears a disorderly uniform!",
|
||||
L"%s wears a disorderly uniform!",// TODO.Translate
|
||||
};
|
||||
|
||||
STR16 szCorpseTextStr[]=
|
||||
|
||||
@@ -7431,14 +7431,14 @@ STR16 szCovertTextStr[]=
|
||||
L"%s was seen performing suspicious activities!",
|
||||
L"%s does not look like a civilian!",
|
||||
L"%s bleeding was discovered!",
|
||||
L"%s is drunk and doesn't look like a soldier!",
|
||||
L"%s is drunk and doesn't behave like a soldier!",
|
||||
L"On closer inspection, %s's disguise does not hold!",
|
||||
L"%s isn't supposed to be here!",
|
||||
L"%s isn't supposed to be here at this time!",
|
||||
L"%s was seen near a fresh corpse!",
|
||||
L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targeting a soldier!",
|
||||
L"%s has seen through %s disguise!",
|
||||
L"%s is seen targetting %s!",
|
||||
L"%s has seen through %s's disguise!",
|
||||
L"No clothes item found in Items.xml!",
|
||||
L"This does not work with the old trait system!",
|
||||
L"Not enough APs!",
|
||||
|
||||
@@ -7419,14 +7419,14 @@ STR16 szCovertTextStr[]=
|
||||
L"%s was seen performing suspicious activities!",
|
||||
L"%s does not look like a civilian!",
|
||||
L"%s bleeding was discovered!",
|
||||
L"%s is drunk and doesn't look like a soldier!",
|
||||
L"%s is drunk and doesn't behave like a soldier!",
|
||||
L"On closer inspection, %s's disguise does not hold!",
|
||||
L"%s isn't supposed to be here!",
|
||||
L"%s isn't supposed to be here at this time!",
|
||||
L"%s was seen near a fresh corpse!",
|
||||
L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targeting a soldier!",
|
||||
L"%s has seen through %s disguise!",
|
||||
L"%s is seen targetting %s!",
|
||||
L"%s has seen through %s's disguise!",
|
||||
L"No clothes item found in Items.xml!",
|
||||
L"This does not work with the old trait system!",
|
||||
L"Not enough APs!",
|
||||
|
||||
@@ -7405,14 +7405,14 @@ STR16 szCovertTextStr[]=
|
||||
L"%s was seen performing suspicious activities!",
|
||||
L"%s does not look like a civilian!",
|
||||
L"%s bleeding was discovered!",
|
||||
L"%s is drunk and doesn't look like a soldier!",
|
||||
L"%s is drunk and doesn't behave like a soldier!",
|
||||
L"On closer inspection, %s's disguise does not hold!",
|
||||
L"%s isn't supposed to be here!",
|
||||
L"%s isn't supposed to be here at this time!",
|
||||
L"%s was seen near a fresh corpse!",
|
||||
L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targeting a soldier!",
|
||||
L"%s has seen through %s disguise!",
|
||||
L"%s is seen targetting %s!",
|
||||
L"%s has seen through %s's disguise!",
|
||||
L"No clothes item found in Items.xml!",
|
||||
L"This does not work with the old trait system!",
|
||||
L"Not enough APs!",
|
||||
|
||||
@@ -7246,14 +7246,14 @@ STR16 szCovertTextStr[]=
|
||||
L"%s was seen performing suspicious activities!",
|
||||
L"%s does not look like a civilian!",
|
||||
L"%s bleeding was discovered!",
|
||||
L"%s is drunk and doesn't look like a soldier!",
|
||||
L"%s is drunk and doesn't behave like a soldier!",
|
||||
L"On closer inspection, %s's disguise does not hold!",
|
||||
L"%s isn't supposed to be here!",
|
||||
L"%s isn't supposed to be here at this time!",
|
||||
L"%s was seen near a fresh corpse!",
|
||||
L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targeting a soldier!",
|
||||
L"%s has seen through %s disguise!",
|
||||
L"%s is seen targetting %s!",
|
||||
L"%s has seen through %s's disguise!",
|
||||
L"No clothes item found in Items.xml!",
|
||||
L"This does not work with the old trait system!",
|
||||
L"Not enough APs!",
|
||||
|
||||
@@ -7418,14 +7418,14 @@ STR16 szCovertTextStr[]=
|
||||
L"%s was seen performing suspicious activities!",
|
||||
L"%s does not look like a civilian!",
|
||||
L"%s bleeding was discovered!",
|
||||
L"%s is drunk and doesn't look like a soldier!",
|
||||
L"%s is drunk and doesn't behave like a soldier!",
|
||||
L"On closer inspection, %s's disguise does not hold!",
|
||||
L"%s isn't supposed to be here!",
|
||||
L"%s isn't supposed to be here at this time!",
|
||||
L"%s was seen near a fresh corpse!",
|
||||
L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targeting a soldier!",
|
||||
L"%s has seen through %s disguise!",
|
||||
L"%s is seen targetting %s!",
|
||||
L"%s has seen through %s's disguise!",
|
||||
L"No clothes item found in Items.xml!",
|
||||
L"This does not work with the old trait system!",
|
||||
L"Not enough APs!",
|
||||
|
||||
@@ -7432,14 +7432,14 @@ STR16 szCovertTextStr[]=
|
||||
L"%s was seen performing suspicious activities!",
|
||||
L"%s does not look like a civilian!",
|
||||
L"%s bleeding was discovered!",
|
||||
L"%s is drunk and doesn't look like a soldier!",
|
||||
L"%s is drunk and doesn't behave like a soldier!",
|
||||
L"On closer inspection, %s's disguise does not hold!",
|
||||
L"%s isn't supposed to be here!",
|
||||
L"%s isn't supposed to be here at this time!",
|
||||
L"%s was seen near a fresh corpse!",
|
||||
L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targeting a soldier!",
|
||||
L"%s has seen through %s disguise!",
|
||||
L"%s is seen targetting %s!",
|
||||
L"%s has seen through %s's disguise!",
|
||||
L"No clothes item found in Items.xml!",
|
||||
L"This does not work with the old trait system!",
|
||||
L"Not enough APs!",
|
||||
|
||||
@@ -7384,14 +7384,14 @@ STR16 szCovertTextStr[]=
|
||||
L"%s was seen performing suspicious activities!",
|
||||
L"%s does not look like a civilian!",
|
||||
L"%s bleeding was discovered!",
|
||||
L"%s is drunk and doesn't look like a soldier!",
|
||||
L"%s is drunk and doesn't behave like a soldier!",
|
||||
L"On closer inspection, %s's disguise does not hold!",
|
||||
L"%s isn't supposed to be here!",
|
||||
L"%s isn't supposed to be here at this time!",
|
||||
L"%s was seen near a fresh corpse!",
|
||||
L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targeting a soldier!",
|
||||
L"%s has seen through %s disguise!",
|
||||
L"%s is seen targetting %s!",
|
||||
L"%s has seen through %s's disguise!",
|
||||
L"No clothes item found in Items.xml!",
|
||||
L"This does not work with the old trait system!",
|
||||
L"Not enough APs!",
|
||||
|
||||
@@ -7435,14 +7435,14 @@ STR16 szCovertTextStr[]=
|
||||
L"%s was seen performing suspicious activities!",
|
||||
L"%s does not look like a civilian!",
|
||||
L"%s bleeding was discovered!",
|
||||
L"%s is drunk and doesn't look like a soldier!",
|
||||
L"%s is drunk and doesn't behave like a soldier!",
|
||||
L"On closer inspection, %s's disguise does not hold!",
|
||||
L"%s isn't supposed to be here!",
|
||||
L"%s isn't supposed to be here at this time!",
|
||||
L"%s was seen near a fresh corpse!",
|
||||
L"%s equipment raises a few eyebrows!",
|
||||
L"%s is seen targeting a soldier!",
|
||||
L"%s has seen through %s disguise!",
|
||||
L"%s is seen targetting %s!",
|
||||
L"%s has seen through %s's disguise!",
|
||||
L"No clothes item found in Items.xml!",
|
||||
L"This does not work with the old trait system!",
|
||||
L"Not enough APs!",
|
||||
|
||||
Reference in New Issue
Block a user