mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
- Some fixing and adding position in overhead map to be in center of big map. Details: - Calculate overhead map cords from your current position on big maps. - Fix incorrect placing room numbers in maps with cliffs. - Fix CTD during deletion of sector items using CTRL+D or CTRL+Del. - Remove light, door and item cursor and item tiles after coping building. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@6888 3b4a5df2-a311-0410-b5c6-a8a6f20db521
7718 lines
247 KiB
C++
7718 lines
247 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Tactical All.h"
|
|
#else
|
|
#include "sgp.h"
|
|
//#include "ai.h"
|
|
#include "Isometric Utils.h"
|
|
#include "overhead.h"
|
|
#include "math.h"
|
|
#include "Event Pump.h"
|
|
#include "random.h"
|
|
#include "Overhead Types.h"
|
|
#include "opplist.h"
|
|
#include "ai.h"
|
|
#include "font control.h"
|
|
#include "Animation COntrol.h"
|
|
#include "los.h"
|
|
#include "fov.h"
|
|
#include "dialogue control.h"
|
|
#include "lighting.h"
|
|
#include "environment.h"
|
|
#include "interface dialogue.h"
|
|
#include "message.h"
|
|
#include "soldier profile.h"
|
|
#include "TeamTurns.h"
|
|
#include "interactive tiles.h"
|
|
#include "render fun.h"
|
|
#include "Text.h"
|
|
#include "timer control.h"
|
|
#include "soldier macros.h"
|
|
#include "soldier functions.h"
|
|
#include "handle ui.h"
|
|
#include "Queen Command.h"
|
|
#include "keys.h"
|
|
#include "Campaign.h"
|
|
#include "Soldier Init List.h"
|
|
#include "music control.h"
|
|
#include "Soldier Profile.h"
|
|
#include "Strategicmap.h"
|
|
#include "Quests.h"
|
|
#include "meanwhile.h"
|
|
#include "WorldMan.h"
|
|
#include "SkillCheck.h"
|
|
#include "GameSettings.h"
|
|
#include "Smell.h"
|
|
#include "Game Clock.h"
|
|
#include "civ quotes.h"
|
|
#include "Sound Control.h"
|
|
#include "drugs and alcohol.h"
|
|
#include "Interface.h"
|
|
#include "Explosion Control.h"//dnl ch40 200909
|
|
#endif
|
|
|
|
#ifdef JA2UB
|
|
#include "Ja25_Tactical.h"
|
|
#endif
|
|
|
|
#include "Music Control.h"
|
|
|
|
#include "connect.h"
|
|
#include "../ModularizedTacticalAI/include/Plan.h"
|
|
#include "../ModularizedTacticalAI/include/PlanFactoryLibrary.h"
|
|
#include "../ModularizedTacticalAI/include/AbstractPlanFactory.h"
|
|
|
|
//rain
|
|
//#define VIS_DIST_DECREASE_PER_RAIN_INTENSITY 20
|
|
//end rain
|
|
|
|
#define WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
|
|
extern void SetSoldierAniSpeed( SOLDIERTYPE *pSoldier );
|
|
// HEADROCK HAM 3.6: Moved to header
|
|
//void MakeBloodcatsHostile( void );
|
|
|
|
void OurNoise( UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage );
|
|
void TheirNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage = NULL );
|
|
void ProcessNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubBaseVolume, UINT8 ubNoiseType, STR16 zNoiseMessage = NULL );
|
|
UINT8 CalcEffVolume(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT8 ubNoiseType, UINT8 ubBaseVolume, UINT8 bCheckTerrain, UINT8 ubTerrType1, UINT8 ubTerrType2);
|
|
void HearNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 *ubSeen);
|
|
void TellPlayerAboutNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 ubNoiseDir, STR16 zNoiseMessage = NULL );
|
|
void OurTeamSeesSomeone( SOLDIERTYPE * pSoldier, INT8 bNumReRevealed, INT8 bNumNewEnemies );
|
|
|
|
void IncrementWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel );
|
|
void SetWatchedLocAsUsed( UINT8 ubID, INT32 sGridNo, INT8 bLevel );
|
|
void DecayWatchedLocs( INT8 bTeam );
|
|
|
|
void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT8 * pPersOL, INT8 * pbPublOL );
|
|
|
|
// The_Bob - real time sneaking code 01/06/09
|
|
extern void CancelItemPointer(void);
|
|
extern BOOLEAN NobodyAlerted(void);
|
|
extern void ShowRadioLocator( UINT8 ubID, UINT8 ubLocatorSpeed );
|
|
//#define TESTOPPLIST
|
|
|
|
// for ManSeesMan()
|
|
#define MANLOOKSFORMAN 0
|
|
#define HEARNOISE 1
|
|
#define NOTICEUNSEENATTACKER 2
|
|
|
|
|
|
// for ManLooksForMan()
|
|
#define MANLOOKSFOROTHERTEAMS 0
|
|
#define OTHERTEAMSLOOKFORMAN 1
|
|
#define VERIFYANDDECAYOPPLIST 2
|
|
#define HANDLESTEPPEDLOOKAT 3
|
|
#define LOOKANDLISTEN 4
|
|
#define UPDATEPUBLIC 5
|
|
#define CALLER_UNKNOWN 6
|
|
|
|
// this variable is a flag used in HandleSight to determine whether (while in non-combat RT)
|
|
// someone has just been seen, EITHER THE MOVER OR SOMEONE THE MOVER SEES
|
|
BOOLEAN gfPlayerTeamSawCreatures = FALSE;
|
|
BOOLEAN gfPlayerTeamSawJoey = FALSE;
|
|
BOOLEAN gfMikeShouldSayHi = FALSE;
|
|
|
|
#ifdef JA2UB
|
|
//JA25 UB
|
|
BOOLEAN gfMorrisShouldSayHi = FALSE;
|
|
#endif
|
|
|
|
UINT8 gubBestToMakeSighting[BEST_SIGHTING_ARRAY_SIZE];
|
|
UINT8 gubBestToMakeSightingSize = 0;
|
|
//BOOLEAN gfHumanSawSomeoneInRealtime;
|
|
|
|
BOOLEAN gfDelayResolvingBestSightingDueToDoor = FALSE;
|
|
|
|
#define SHOULD_BECOME_HOSTILE_SIZE 32
|
|
|
|
UINT8 gubShouldBecomeHostileOrSayQuote[ SHOULD_BECOME_HOSTILE_SIZE ];
|
|
UINT8 gubNumShouldBecomeHostileOrSayQuote;
|
|
|
|
// NB this ID is set for someone opening a door
|
|
UINT8 gubInterruptProvoker = NOBODY;
|
|
|
|
INT8 gbPublicOpplist[MAXTEAMS][TOTAL_SOLDIERS];
|
|
INT8 gbSeenOpponents[TOTAL_SOLDIERS][TOTAL_SOLDIERS];
|
|
INT32 gsLastKnownOppLoc[TOTAL_SOLDIERS][TOTAL_SOLDIERS]; // merc vs. merc
|
|
INT8 gbLastKnownOppLevel[TOTAL_SOLDIERS][TOTAL_SOLDIERS];
|
|
INT32 gsPublicLastKnownOppLoc[MAXTEAMS][TOTAL_SOLDIERS]; // team vs. merc
|
|
INT8 gbPublicLastKnownOppLevel[MAXTEAMS][TOTAL_SOLDIERS];
|
|
UINT8 gubPublicNoiseVolume[MAXTEAMS];
|
|
INT32 gsPublicNoiseGridNo[MAXTEAMS];
|
|
INT8 gbPublicNoiseLevel[MAXTEAMS];
|
|
|
|
UINT8 gubKnowledgeValue[10][10] =
|
|
{
|
|
// P E R S O N A L O P P L I S T //
|
|
// -4 -3 -2 -1 0 1 2 3 4 5 //
|
|
{ 0, 1, 2, 3, 0, 5, 4, 3, 2, 1}, // -4
|
|
{ 0, 0, 1, 2, 0, 4, 3, 2, 1, 0}, // -3 O
|
|
{ 0, 0, 0, 1, 0, 3, 2, 1, 0, 0}, // -2 P P
|
|
{ 0, 0, 0, 0, 0, 2, 1, 0, 0, 0}, // -1 U P
|
|
{ 0, 1, 2, 3, 0, 5, 4, 3, 2, 1}, // 0 B L
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 1 L I
|
|
{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // 2 I S
|
|
{ 0, 0, 0, 1, 0, 2, 1, 0, 0, 0}, // 3 C T
|
|
{ 0, 0, 1, 2, 0, 3, 2, 1, 0, 0}, // 4
|
|
{ 0, 1, 2, 3, 0, 4, 3, 2, 1, 0} // 5
|
|
|
|
/*
|
|
// P E R S O N A L O P P L I S T //
|
|
// -3 -2 -1 0 1 2 3 4 //
|
|
{ 0, 1, 2, 0, 4, 3, 2, 1 }, // -3 O
|
|
{ 0, 0, 1, 0, 3, 2, 1, 0 }, // -2 P P
|
|
{ 0, 0, 0, 0, 2, 1, 0, 0 }, // -1 U P
|
|
{ 1, 2, 3, 0, 5, 4, 3, 2 }, // 0 B L
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // 1 L I
|
|
{ 0, 0, 0, 0, 1, 0, 0, 0 }, // 2 I S
|
|
{ 0, 0, 1, 0, 2, 1, 0, 0 }, // 3 C T
|
|
{ 0, 1, 2, 0, 3, 2, 1, 0 } // 4
|
|
*/
|
|
};
|
|
|
|
#define MAX_WATCHED_LOC_POINTS 4
|
|
#define WATCHED_LOC_RADIUS 1
|
|
|
|
INT32 gsWatchedLoc[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
|
|
INT8 gbWatchedLocLevel[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
|
|
UINT8 gubWatchedLocPoints[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
|
|
BOOLEAN gfWatchedLocReset[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
|
|
BOOLEAN gfWatchedLocHasBeenIncremented[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
|
|
|
|
INT8 gbLookDistance[8][8];
|
|
|
|
INT8 BEHIND;
|
|
INT8 SBEHIND;
|
|
INT8 SIDE;
|
|
INT8 ANGLE;
|
|
INT8 STRAIGHT;
|
|
|
|
void InitSightRange()
|
|
{
|
|
BEHIND = (INT8)( BEHIND_RATIO * gGameExternalOptions.ubStraightSightRange );
|
|
SBEHIND = (INT8)( SBEHIND_RATIO * gGameExternalOptions.ubStraightSightRange );
|
|
SIDE = (INT8)( SIDE_RATIO * gGameExternalOptions.ubStraightSightRange );
|
|
ANGLE = (INT8)( ANGLE_RATIO * gGameExternalOptions.ubStraightSightRange );
|
|
STRAIGHT = (INT8)( STRAIGHT_RATIO * gGameExternalOptions.ubStraightSightRange );
|
|
|
|
INT8 dummy[15][15];
|
|
|
|
|
|
{ //Pulmu: VC6 compatibility
|
|
for (int i=0; i<8; i++)
|
|
{
|
|
dummy[i][i]=STRAIGHT;
|
|
dummy[i][i+1]=ANGLE;
|
|
dummy[i+1][i]=ANGLE;
|
|
dummy[i][i+2]=SIDE;
|
|
dummy[i+2][i]=SIDE;
|
|
dummy[i][i+3]=SBEHIND;
|
|
dummy[i+3][i]=SBEHIND;
|
|
dummy[i][i+4]=BEHIND;
|
|
dummy[i+4][i]=BEHIND;
|
|
dummy[i][i+5]=SBEHIND;
|
|
dummy[i+5][i]=SBEHIND;
|
|
dummy[i][i+6]=SIDE;
|
|
dummy[i+6][i]=SIDE;
|
|
dummy[i][i+7]=ANGLE;
|
|
dummy[i+7][i]=ANGLE;
|
|
}
|
|
}
|
|
for (int i=0; i<8; i++)
|
|
{
|
|
for (int j=0; j<8; j++)
|
|
{
|
|
gbLookDistance[i][j] = dummy[i][j];
|
|
}
|
|
}
|
|
//gbLookDistance[8][8] =
|
|
//{
|
|
// // LOOKER DIR LOOKEE DIR
|
|
// // NORTH | NORTHEAST | EAST | SOUTHEAST | SOUTH | SOUTHWEST | WEST | NORTHWEST
|
|
// /* NORTH */ STRAIGHT, ANGLE, SIDE, SBEHIND, BEHIND, SBEHIND, SIDE, ANGLE,
|
|
// /* NORTHEAST */ ANGLE, STRAIGHT, ANGLE, SIDE, SBEHIND, BEHIND, SBEHIND, SIDE,
|
|
// /* EAST */ SIDE, ANGLE, STRAIGHT, ANGLE, SIDE, SBEHIND, BEHIND, SBEHIND,
|
|
// /* SOUTHEAST */ SBEHIND, SIDE, ANGLE, STRAIGHT, ANGLE, SIDE, SBEHIND, BEHIND,
|
|
// /* SOUTH */ BEHIND, SBEHIND, SIDE, ANGLE, STRAIGHT, ANGLE, SIDE, SBEHIND,
|
|
// /* SOUTHWEST */ SBEHIND, BEHIND, SBEHIND, SIDE, ANGLE, STRAIGHT, ANGLE, SIDE,
|
|
// /* WEST */ SIDE, SBEHIND, BEHIND, SBEHIND, SIDE, ANGLE, STRAIGHT, ANGLE,
|
|
// /* NORTHWEST */ ANGLE, SIDE, SBEHIND, BEHIND, SBEHIND, SIDE, ANGLE, STRAIGHT
|
|
// };
|
|
}
|
|
|
|
|
|
INT8 gbSmellStrength[3] =
|
|
{
|
|
NORMAL_HUMAN_SMELL_STRENGTH, // normal
|
|
NORMAL_HUMAN_SMELL_STRENGTH + 2, // slob
|
|
NORMAL_HUMAN_SMELL_STRENGTH - 1 // snob
|
|
};
|
|
|
|
|
|
UINT16 gsWhoThrewRock = NOBODY;
|
|
|
|
// % values of sighting distance at various light levels
|
|
//DBrot: use gGameExternalOptions.ubBrightnessVisionMod instead
|
|
/*
|
|
INT8 gbLightSighting[1][SHADE_MIN+1] =
|
|
{
|
|
{ // human
|
|
80, // brightest
|
|
86,
|
|
93,
|
|
100, // normal daylight, 3
|
|
94,
|
|
88,
|
|
82,
|
|
76,
|
|
70, // mid-dawn, 8
|
|
64,
|
|
58,
|
|
51,
|
|
43, // normal nighttime, 12 (11 tiles)
|
|
30,
|
|
17,
|
|
9
|
|
}
|
|
};*/
|
|
/*
|
|
{
|
|
{ // human
|
|
80, // brightest
|
|
86,
|
|
93,
|
|
100, // normal daylight, 3
|
|
93,
|
|
86,
|
|
79,
|
|
72,
|
|
65, // mid-dawn, 8
|
|
58,
|
|
53,
|
|
43, // normal nighttime, 11 (11 tiles)
|
|
35,
|
|
26,
|
|
17,
|
|
9
|
|
}
|
|
};
|
|
*/
|
|
|
|
UINT8 gubSightFlags = 0;
|
|
|
|
void DECAY_OPPLIST_VALUE( INT8& value )
|
|
{
|
|
if ( (value) >= SEEN_THIS_TURN)
|
|
{
|
|
(value)++;
|
|
if ( (value) > OLDEST_SEEN_VALUE )
|
|
{
|
|
(value) = NOT_HEARD_OR_SEEN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (value) <= HEARD_THIS_TURN)
|
|
{
|
|
(value)--;
|
|
if ( (value) < OLDEST_HEARD_VALUE)
|
|
{
|
|
(value) = NOT_HEARD_OR_SEEN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//rain
|
|
extern INT8 gbCurrentRainIntensity;
|
|
extern BOOLEAN gfLightningInProgress;
|
|
extern BOOLEAN gfHaveSeenSomeone;
|
|
extern UINT8 ubRealAmbientLightLevel;
|
|
//end rain
|
|
|
|
|
|
INT16 AdjustMaxSightRangeForEnvEffects( SOLDIERTYPE *pSoldier, INT8 bLightLevel, INT16 sDistVisible )
|
|
{
|
|
INT16 sNewDist = 0;
|
|
|
|
//sNewDist = sDistVisible * gbLightSighting[ 0 ][ bLightLevel ] / 100;
|
|
sNewDist = sDistVisible * gGameExternalOptions.ubBrightnessVisionMod[ bLightLevel ] / 100;
|
|
// Adjust it based on weather...
|
|
if ( guiEnvWeather & ( WEATHER_FORECAST_SHOWERS | WEATHER_FORECAST_THUNDERSHOWERS ) )
|
|
{
|
|
//sNewDist = sNewDist * 70 / 100;
|
|
//rain
|
|
//Added a feature reducing weather penalty for ranger trait - SANDRO
|
|
INT16 sWeatherPenalty = 0; // percent vision reduction 0-100%
|
|
sWeatherPenalty = min( (max( 0, (gGameExternalOptions.ubVisDistDecreasePerRainIntensity * gbCurrentRainIntensity))), 100) ;
|
|
if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) )
|
|
{
|
|
sWeatherPenalty = (sWeatherPenalty * ( 100 - (gSkillTraitValues.ubRAWeatherPenaltiesReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ) / 100;
|
|
sWeatherPenalty = min( (max( 0, sWeatherPenalty)), 100 ); // keep it in 0-100 range
|
|
}
|
|
|
|
sNewDist = (sNewDist * ( 100 - sWeatherPenalty )) / 100;
|
|
|
|
//end rain
|
|
}
|
|
|
|
//rain
|
|
if( gfLightningInProgress )
|
|
sNewDist += sNewDist * ( ubRealAmbientLightLevel ) / 10; // 10% per dark level
|
|
//end rain
|
|
|
|
return( sNewDist );
|
|
}
|
|
|
|
void SwapBestSightingPositions( INT8 bPos1, INT8 bPos2 )
|
|
{
|
|
UINT8 ubTemp;
|
|
|
|
ubTemp = gubBestToMakeSighting[ bPos1 ];
|
|
gubBestToMakeSighting[ bPos1 ] = gubBestToMakeSighting[ bPos2 ];
|
|
gubBestToMakeSighting[ bPos2 ] = ubTemp;
|
|
}
|
|
|
|
void ReevaluateBestSightingPosition( SOLDIERTYPE * pSoldier, INT8 bInterruptDuelPts )
|
|
{
|
|
UINT8 ubLoop, ubLoop2;
|
|
BOOLEAN fFound = FALSE;
|
|
BOOLEAN fPointsGotLower = FALSE;
|
|
|
|
if ( bInterruptDuelPts == NO_INTERRUPT )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER ) )
|
|
{
|
|
//gfHumanSawSomeoneInRealtime = TRUE;
|
|
}
|
|
|
|
if ( (pSoldier->aiData.bInterruptDuelPts != NO_INTERRUPT) && (bInterruptDuelPts < pSoldier->aiData.bInterruptDuelPts) )
|
|
{
|
|
fPointsGotLower = TRUE;
|
|
}
|
|
|
|
if ( fPointsGotLower )
|
|
{
|
|
// loop to end of array less 1 entry since we can't swap the last entry out of the array
|
|
for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize - 1; ubLoop++ )
|
|
{
|
|
if ( pSoldier->ubID == gubBestToMakeSighting[ ubLoop ] )
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// this guy has fewer interrupt pts vs another enemy! reduce position unless in last place
|
|
if (fFound)
|
|
{
|
|
// set new points
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: reducing points for %d to %d", pSoldier->ubID, bInterruptDuelPts ) );
|
|
pSoldier->aiData.bInterruptDuelPts = bInterruptDuelPts;
|
|
|
|
// must percolate him down
|
|
for ( ubLoop2 = ubLoop + 1; ubLoop2 < gubBestToMakeSightingSize; ubLoop2++ )
|
|
{
|
|
if ( gubBestToMakeSighting[ ubLoop2 ] != NOBODY && MercPtrs[ gubBestToMakeSighting[ ubLoop2 - 1 ] ]->aiData.bInterruptDuelPts < MercPtrs[ gubBestToMakeSighting[ ubLoop2 ] ]->aiData.bInterruptDuelPts )
|
|
{
|
|
SwapBestSightingPositions( (UINT8) (ubLoop2 - 1), ubLoop2 );
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if ( pSoldier->ubID == gubBestToMakeSighting[ gubBestToMakeSightingSize - 1] )
|
|
{
|
|
// in list but can't be bumped down... set his new points
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: reduced points for last individual %d to %d", pSoldier->ubID, bInterruptDuelPts ) );
|
|
pSoldier->aiData.bInterruptDuelPts = bInterruptDuelPts;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// loop through whole array
|
|
for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize; ubLoop++ )
|
|
{
|
|
if ( pSoldier->ubID == gubBestToMakeSighting[ ubLoop ] )
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fFound)
|
|
{
|
|
for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize; ubLoop++ )
|
|
{
|
|
if ( pSoldier->RecognizeAsCombatant(gubBestToMakeSighting[ ubLoop ]) && (gubBestToMakeSighting[ ubLoop ] == NOBODY) || (bInterruptDuelPts > MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->aiData.bInterruptDuelPts ) )
|
|
{
|
|
if ( gubBestToMakeSighting[ gubBestToMakeSightingSize - 1 ] != NOBODY )
|
|
{
|
|
MercPtrs[ gubBestToMakeSighting[ gubBestToMakeSightingSize - 1 ] ]->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: resetting points for %d to zilch", pSoldier->ubID ) );
|
|
}
|
|
|
|
// set new points
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: setting points for %d to %d", pSoldier->ubID, bInterruptDuelPts ) );
|
|
pSoldier->aiData.bInterruptDuelPts = bInterruptDuelPts;
|
|
|
|
// insert here!
|
|
for ( ubLoop2 = gubBestToMakeSightingSize - 1; ubLoop2 > ubLoop; ubLoop2-- )
|
|
{
|
|
gubBestToMakeSighting[ ubLoop2 ] = gubBestToMakeSighting[ ubLoop2 - 1 ];
|
|
}
|
|
gubBestToMakeSighting[ ubLoop ] = pSoldier->ubID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// else points didn't get lower, so do nothing (because we want to leave each merc with as low int points as possible)
|
|
}
|
|
|
|
for ( ubLoop = 0; ubLoop < BEST_SIGHTING_ARRAY_SIZE; ubLoop++ )
|
|
{
|
|
if ( (gubBestToMakeSighting[ ubLoop ] != NOBODY) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP entry %d: %d (%d pts)", ubLoop, gubBestToMakeSighting[ ubLoop ], MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->aiData.bInterruptDuelPts ) );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void HandleBestSightingPositionInRealtime( void )
|
|
{
|
|
// This function is called for handling interrupts when opening a door in non-combat or
|
|
// just sighting in non-combat, deciding who gets the first turn
|
|
|
|
UINT8 ubLoop;
|
|
|
|
if ( gfDelayResolvingBestSightingDueToDoor )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "HBSPIR: skipping due to door flag" );
|
|
return;
|
|
}
|
|
|
|
// Also delay until attack busy returns
|
|
// if (gTacticalStatus.ubAttackBusyCount > 0)
|
|
// {
|
|
// return;
|
|
// }
|
|
|
|
if (gubBestToMakeSighting[ 0 ] != NOBODY)
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "HBSPIR called and there is someone in the list" );
|
|
|
|
//if (gfHumanSawSomeoneInRealtime)
|
|
{
|
|
if (gubBestToMakeSighting[ 1 ] == NOBODY)
|
|
{ // The_Bob - real time sneaking code 01/06/09
|
|
// if real time sneaking conditions are met...
|
|
// this is now in the preferences window - SANDRO
|
|
if (gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] && MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == OUR_TEAM && NobodyAlerted() )
|
|
{
|
|
// get rid of the item under cursor (we gotta react FAST)
|
|
CancelItemPointer();
|
|
// select (and center screen on) the merc who saw the enemy
|
|
// HEADROCK HAM 3.6: A much-requested toggle.
|
|
if (gusSelectedSoldier != (UINT16)MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID &&
|
|
!gGameExternalOptions.fNoAutoFocusChangeInRealtimeSneak)
|
|
SelectSoldier (MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID, false, true);
|
|
// if not quiet, emit a message warning the player
|
|
if (!gGameExternalOptions.fQuietRealTimeSneak)
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_RTM_ENEMIES_SPOOTED]);
|
|
|
|
return; // and do nothing
|
|
}
|
|
else if ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam != OUR_TEAM && MercPtrs[gubBestToMakeSighting[ 0 ]]->aiData.bOppCnt > 0 )
|
|
{
|
|
// otherwise, simply award the turn to the team that saw the enemy first
|
|
EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
|
|
}
|
|
else
|
|
// otherwise, simply award the turn to the team that saw the enemy first
|
|
EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
// if 1st and 2nd on same team, or 1st and 3rd on same team, or there IS no 3rd, award turn to 1st
|
|
if ( /*MercPtrs[gubBestToMakeSighting[ 0 ]]->aiData.bOppCnt > 0 &&*/ ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == MercPtrs[gubBestToMakeSighting[ 1 ]]->bTeam ) ||
|
|
( (gubBestToMakeSighting[ 2 ] == NOBODY) || ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == MercPtrs[gubBestToMakeSighting[ 2 ]]->bTeam ) )
|
|
)
|
|
{
|
|
EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
|
|
}
|
|
else //if ( MercPtrs[gubBestToMakeSighting[ 1 ]]->aiData.bOppCnt > 0 ) // give turn to 2nd best but interrupt to 1st
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Entering combat mode: turn for 2nd best, int for best" );
|
|
|
|
EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 1 ]]->bTeam );
|
|
// 2nd guy loses control
|
|
AddToIntList( gubBestToMakeSighting[ 1 ], FALSE, TRUE);
|
|
// 1st guy gains control
|
|
AddToIntList( gubBestToMakeSighting[ 0 ], TRUE, TRUE);
|
|
// done
|
|
DoneAddingToIntList( MercPtrs[gubBestToMakeSighting[ 0 ]], TRUE, SIGHTINTERRUPT );
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( ubLoop = 0; ubLoop < BEST_SIGHTING_ARRAY_SIZE; ubLoop++ )
|
|
{
|
|
if ( gubBestToMakeSighting[ ubLoop ] != NOBODY )
|
|
{
|
|
MercPtrs[ gubBestToMakeSighting[ ubLoop ]]->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: done, resetting points for %d to zilch", MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->ubID ) );
|
|
}
|
|
}
|
|
|
|
for ( ubLoop = 0; ubLoop < guiNumMercSlots; ubLoop++ )
|
|
{
|
|
if ( MercSlots[ ubLoop ] )
|
|
{
|
|
AssertMsg( MercSlots[ ubLoop ]->aiData.bInterruptDuelPts == NO_INTERRUPT, String( "%S (%d) still has interrupt pts!", MercSlots[ ubLoop ]->name, MercSlots[ ubLoop ]->ubID ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void HandleBestSightingPositionInTurnbased( void )
|
|
{
|
|
// This function is called for handling interrupts when opening a door in turnbased
|
|
|
|
UINT8 ubLoop, ubLoop2;
|
|
BOOLEAN fOk = FALSE;
|
|
|
|
if ( gubBestToMakeSighting[ 0 ] != NOBODY )
|
|
{
|
|
if ( MercPtrs[ gubBestToMakeSighting[ 0 ] ]->bTeam != gTacticalStatus.ubCurrentTeam )
|
|
{
|
|
|
|
// interrupt!
|
|
for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize; ubLoop++ )
|
|
{
|
|
if ( gubBestToMakeSighting[ ubLoop ] == NOBODY )
|
|
{
|
|
if (gubInterruptProvoker == NOBODY)
|
|
{
|
|
// do nothing (for now) - abort!
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// use this guy as the "interrupted" fellow
|
|
gubBestToMakeSighting[ ubLoop ] = gubInterruptProvoker;
|
|
fOk = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if ( MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->bTeam == gTacticalStatus.ubCurrentTeam )
|
|
{
|
|
fOk = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( fOk )
|
|
{
|
|
// this is the guy who gets "interrupted"; all else before him interrupted him
|
|
AddToIntList( gubBestToMakeSighting[ ubLoop ], FALSE, TRUE);
|
|
for ( ubLoop2 = 0; ubLoop2 < ubLoop; ubLoop2++ )
|
|
{
|
|
AddToIntList( gubBestToMakeSighting[ ubLoop2 ], TRUE, TRUE);
|
|
}
|
|
// done
|
|
DoneAddingToIntList( MercPtrs[ gubBestToMakeSighting[ ubLoop ] ], TRUE, SIGHTINTERRUPT );
|
|
}
|
|
|
|
}
|
|
for ( ubLoop = 0; ubLoop < BEST_SIGHTING_ARRAY_SIZE; ubLoop++ )
|
|
{
|
|
if ( gubBestToMakeSighting[ ubLoop ] != NOBODY )
|
|
{
|
|
MercPtrs[ gubBestToMakeSighting[ ubLoop ]]->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP (TB): done, resetting points for %d to zilch", MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->ubID ) );
|
|
}
|
|
}
|
|
|
|
for ( ubLoop = 0; ubLoop < guiNumMercSlots; ubLoop++ )
|
|
{
|
|
if ( MercSlots[ ubLoop ] )
|
|
{
|
|
AssertMsg( MercSlots[ ubLoop ]->aiData.bInterruptDuelPts == NO_INTERRUPT, String( "%S (%d) still has interrupt pts!", MercSlots[ ubLoop ]->name, MercSlots[ ubLoop ]->ubID ) );
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void InitSightArrays( void )
|
|
{
|
|
UINT32 uiLoop;
|
|
|
|
for ( uiLoop = 0; uiLoop < BEST_SIGHTING_ARRAY_SIZE; uiLoop++ )
|
|
{
|
|
gubBestToMakeSighting[ uiLoop ] = NOBODY;
|
|
}
|
|
//gfHumanSawSomeoneInRealtime = FALSE;
|
|
|
|
// It is assumed that once the sight arrays are (re)initialized, the enemies should all have no
|
|
// interrupt points. At least a paranoia check in the HandleSightingInRealtime and HandleSightingInTurnBased
|
|
// both make sure no interrupt points remain after they drain the sighting list.
|
|
// I do not fully grok the interrupt system, but it IS possible for this function to be called when there are
|
|
// still soldiers on the sighting list, which gives them lingering interrupt points. So the best course of
|
|
// action is to reset their points. However, I think I'll just do a clean sweep here to make sure I get them all.
|
|
for ( uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++ )
|
|
{
|
|
if (MercSlots[ uiLoop ] )
|
|
{
|
|
MercSlots[ uiLoop ]->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AddToShouldBecomeHostileOrSayQuoteList( UINT8 ubID )
|
|
{
|
|
UINT8 ubLoop;
|
|
|
|
Assert( gubNumShouldBecomeHostileOrSayQuote < SHOULD_BECOME_HOSTILE_SIZE );
|
|
|
|
if ( MercPtrs[ ubID ]->stats.bLife < OKLIFE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// make sure not already in list
|
|
for ( ubLoop = 0; ubLoop < gubNumShouldBecomeHostileOrSayQuote; ubLoop++ )
|
|
{
|
|
if ( gubShouldBecomeHostileOrSayQuote[ ubLoop ] == ubID )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
gubShouldBecomeHostileOrSayQuote[ gubNumShouldBecomeHostileOrSayQuote ] = ubID;
|
|
gubNumShouldBecomeHostileOrSayQuote++;
|
|
}
|
|
|
|
UINT8 SelectSpeakerFromHostileOrSayQuoteList( void )
|
|
{
|
|
UINT8 ubProfileList[ SHOULD_BECOME_HOSTILE_SIZE ]; // NB list of merc IDs, not profiles!
|
|
UINT8 ubLoop, ubNumProfiles = 0;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
for ( ubLoop = 0; ubLoop < gubNumShouldBecomeHostileOrSayQuote; ubLoop++ )
|
|
{
|
|
pSoldier = MercPtrs[ gubShouldBecomeHostileOrSayQuote[ ubLoop ] ];
|
|
if ( pSoldier->ubProfile != NO_PROFILE )
|
|
{
|
|
|
|
// make sure person can say quote!!!!
|
|
gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_NEEDS_TO_SAY_HOSTILE_QUOTE;
|
|
|
|
if ( NPCHasUnusedHostileRecord( pSoldier->ubProfile, APPROACH_DECLARATION_OF_HOSTILITY ) )
|
|
{
|
|
ubProfileList[ ubNumProfiles ] = gubShouldBecomeHostileOrSayQuote[ ubLoop ];
|
|
ubNumProfiles++;
|
|
}
|
|
else
|
|
{
|
|
// turn flag off again
|
|
gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 &= ~PROFILE_MISC_FLAG2_NEEDS_TO_SAY_HOSTILE_QUOTE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if ( ubNumProfiles == 0 )
|
|
{
|
|
return( NOBODY );
|
|
}
|
|
else
|
|
{
|
|
return( ubProfileList[ Random( ubNumProfiles ) ] );
|
|
}
|
|
}
|
|
|
|
extern BOOLEAN gfWaitingForTriggerTimer;
|
|
|
|
void CheckHostileOrSayQuoteList( void )
|
|
{
|
|
if ( gubNumShouldBecomeHostileOrSayQuote == 0 || !DialogueQueueIsEmpty() || gfInTalkPanel || gfWaitingForTriggerTimer )
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
UINT8 ubSpeaker, ubLoop;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
ubSpeaker = SelectSpeakerFromHostileOrSayQuoteList();
|
|
if ( ubSpeaker == NOBODY )
|
|
{
|
|
// make sure everyone on this list is hostile
|
|
for ( ubLoop = 0; ubLoop < gubNumShouldBecomeHostileOrSayQuote; ubLoop++ )
|
|
{
|
|
pSoldier = MercPtrs[ gubShouldBecomeHostileOrSayQuote[ ubLoop ] ];
|
|
if ( pSoldier->aiData.bNeutral )
|
|
{
|
|
MakeCivHostile( pSoldier, 2 );
|
|
// make civ group, if any, hostile
|
|
if ( pSoldier->bTeam == CIV_TEAM && pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] == CIV_GROUP_WILL_BECOME_HOSTILE )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
// unpause all AI
|
|
UnPauseAI();
|
|
// reset the list
|
|
memset( &gubShouldBecomeHostileOrSayQuote, NOBODY, SHOULD_BECOME_HOSTILE_SIZE );
|
|
gubNumShouldBecomeHostileOrSayQuote = 0;
|
|
//and return/go into combat
|
|
if ( !(gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
EnterCombatMode( CIV_TEAM );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// pause all AI
|
|
PauseAIUntilManuallyUnpaused();
|
|
// stop everyone?
|
|
|
|
// We want to make this guy visible to the player.
|
|
if ( MercPtrs[ ubSpeaker ]->bVisible != TRUE )
|
|
{
|
|
gbPublicOpplist[ gbPlayerNum ][ ubSpeaker ] = HEARD_THIS_TURN;
|
|
HandleSight( MercPtrs[ ubSpeaker ], SIGHT_LOOK | SIGHT_RADIO );
|
|
}
|
|
// trigger hater
|
|
TriggerNPCWithIHateYouQuote( MercPtrs[ ubSpeaker ]->ubProfile );
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandleSight(SOLDIERTYPE *pSoldier, UINT8 ubSightFlags)
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE *pThem;
|
|
INT8 bTempNewSituation;
|
|
|
|
if (!pSoldier->bActive || !pSoldier->bInSector || pSoldier->flags.uiStatusFlags & SOLDIER_DEAD )
|
|
{
|
|
// I DON'T THINK SO!
|
|
return;
|
|
}
|
|
|
|
gubSightFlags = ubSightFlags;
|
|
|
|
if ( gubBestToMakeSightingSize != BEST_SIGHTING_ARRAY_SIZE_ALL_TEAMS_LOOK_FOR_ALL )
|
|
{
|
|
// if this is not being called as a result of all teams look for all, reset array size
|
|
if ( (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
// NB the incombat size is 0
|
|
gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_INCOMBAT;
|
|
}
|
|
else
|
|
{
|
|
gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_NONCOMBAT;
|
|
}
|
|
|
|
InitSightArrays();
|
|
}
|
|
|
|
for ( uiLoop = 0; uiLoop < NUM_WATCHED_LOCS; ++uiLoop )
|
|
{
|
|
gfWatchedLocHasBeenIncremented[ pSoldier->ubID ][ uiLoop ] = FALSE;
|
|
}
|
|
|
|
gfPlayerTeamSawCreatures = FALSE;
|
|
|
|
// store new situation value
|
|
bTempNewSituation = pSoldier->aiData.bNewSituation;
|
|
pSoldier->aiData.bNewSituation = FALSE;
|
|
|
|
// if we've been told to make this soldier look (& others look back at him)
|
|
if (ubSightFlags & SIGHT_LOOK)
|
|
{
|
|
// if this soldier's under our control and well enough to look
|
|
if (pSoldier->stats.bLife >= OKLIFE )
|
|
{
|
|
/*
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"ManLooksForOtherTeams (HandleSight/Look) for %d\n",pSoldier->guynum);
|
|
#endif
|
|
*/
|
|
// he looks for all other soldiers not on his own team
|
|
ManLooksForOtherTeams(pSoldier);
|
|
|
|
// if "Show only enemies seen" option is ON and it's this guy looking
|
|
//if (pSoldier->ubID == ShowOnlySeenPerson)
|
|
//NewShowOnlySeenPerson(pSoldier); // update the string
|
|
}
|
|
|
|
|
|
/*
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"OtherTeamsLookForMan (HandleSight/Look) for %d\n",ptr->guynum);
|
|
#endif
|
|
*/
|
|
|
|
// all soldiers under our control but not on ptr's team look for him
|
|
OtherTeamsLookForMan(pSoldier);
|
|
} // end of SIGHT_LOOK
|
|
|
|
// if we've been told that interrupts are possible as a result of sighting
|
|
if ((gTacticalStatus.uiFlags & TURNBASED) &&
|
|
(gTacticalStatus.uiFlags & INCOMBAT) &&
|
|
(ubSightFlags & SIGHT_INTERRUPT) &&
|
|
(!gGameOptions.fImprovedInterruptSystem || (gGameOptions.fImprovedInterruptSystem && gGameExternalOptions.fAllowInstantInterruptsOnSight) ) )
|
|
{
|
|
ResolveInterruptsVs( pSoldier, SIGHTINTERRUPT );
|
|
}
|
|
|
|
if ( gubBestToMakeSightingSize == BEST_SIGHTING_ARRAY_SIZE_NONCOMBAT )
|
|
{
|
|
HandleBestSightingPositionInRealtime();
|
|
}
|
|
|
|
if ( pSoldier->aiData.bNewSituation && !(pSoldier->flags.uiStatusFlags & SOLDIER_PC) )
|
|
{
|
|
pSoldier->HaultSoldierFromSighting( TRUE );
|
|
}
|
|
pSoldier->aiData.bNewSituation = __max( pSoldier->aiData.bNewSituation, bTempNewSituation );
|
|
|
|
// if we've been told to radio the results
|
|
if (ubSightFlags & SIGHT_RADIO)
|
|
{
|
|
if (pSoldier->flags.uiStatusFlags & SOLDIER_PC )
|
|
{
|
|
// update our team's public knowledge
|
|
RadioSightings(pSoldier,EVERYBODY, pSoldier->bTeam );
|
|
/* comm by ddd
|
|
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
RadioSightings(pSoldier,EVERYBODY, MILITIA_TEAM);
|
|
#endif*/
|
|
//ddd{
|
|
if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
|
|
RadioSightings(pSoldier,EVERYBODY, MILITIA_TEAM);
|
|
|
|
#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
|
|
//haydent
|
|
if(is_networked && pSoldier->bSide == 0 && pSoldier->bTeam != OUR_TEAM)
|
|
RadioSightings(pSoldier,EVERYBODY, OUR_TEAM);
|
|
#endif
|
|
|
|
//ddd}
|
|
// if it's our local player's merc
|
|
if (PTR_OURTEAM)
|
|
// revealing roofs and looking for items handled here, too
|
|
RevealRoofsAndItems(pSoldier,TRUE, TRUE, pSoldier->pathing.bLevel, FALSE );
|
|
}
|
|
// unless in easy mode allow alerted enemies to radio
|
|
else if ( gGameOptions.ubDifficultyLevel >= DIF_LEVEL_MEDIUM )
|
|
{
|
|
// don't allow admins to radio
|
|
//Madd: Huh? why not admins? removed.
|
|
if ( pSoldier->bTeam == ENEMY_TEAM && gTacticalStatus.Team[ ENEMY_TEAM ].bAwareOfOpposition ) //&& pSoldier->ubSoldierClass != SOLDIER_CLASS_ADMINISTRATOR )
|
|
{
|
|
RadioSightings(pSoldier,EVERYBODY, pSoldier->bTeam );
|
|
}
|
|
}
|
|
|
|
pSoldier->bNewOppCnt = 0;
|
|
pSoldier->pathing.bNeedToLook = FALSE;
|
|
|
|
// Temporary for opplist synching - disable random order radioing
|
|
#ifndef RECORDOPPLIST
|
|
// if this soldier's NOT on our team (MAY be under our control, though!)
|
|
if (!PTR_OURTEAM)
|
|
OurTeamRadiosRandomlyAbout(pSoldier->ubID); // radio about him only
|
|
#endif
|
|
|
|
// all non-humans under our control would now radio, if they were allowed
|
|
// to radio automatically (but they're not). So just nuke new opp cnt
|
|
// NEW: under LOCALOPPLIST, humans on other teams now also radio in here
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop)
|
|
{
|
|
pThem = MercSlots[ uiLoop ];
|
|
|
|
if (pThem != NULL && pThem->stats.bLife >= OKLIFE)
|
|
{
|
|
// if this merc is on the same team as the target soldier
|
|
if (pThem->bTeam == pSoldier->bTeam)
|
|
continue; // he doesn't look (he ALWAYS knows about him)
|
|
|
|
// other human team's merc report sightings to their teams now
|
|
if (pThem->flags.uiStatusFlags & SOLDIER_PC)
|
|
{
|
|
// Temporary for opplist synching - disable random order radioing
|
|
#ifdef RECORDOPPLIST
|
|
// do our own team, too, since we've bypassed random radioing
|
|
if (TRUE)
|
|
#else
|
|
// exclude our own team, we've already done them, randomly
|
|
if (pThem->bTeam != gbPlayerNum)
|
|
#endif
|
|
RadioSightings(pThem,pSoldier->ubID, pThem->bTeam);
|
|
}
|
|
// unless in easy mode allow alerted enemies to radio
|
|
else if ( gGameOptions.ubDifficultyLevel >= DIF_LEVEL_MEDIUM )
|
|
{
|
|
// don't allow admins to radio
|
|
if ( pThem->bTeam == ENEMY_TEAM && gTacticalStatus.Team[ ENEMY_TEAM ].bAwareOfOpposition && pThem->ubSoldierClass != SOLDIER_CLASS_ADMINISTRATOR )
|
|
{
|
|
RadioSightings(pThem,EVERYBODY, pThem->bTeam );
|
|
}
|
|
}
|
|
|
|
pThem->bNewOppCnt = 0;
|
|
pThem->pathing.bNeedToLook = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// CJC August 13 2002: at the end of handling sight, reset sight flags to allow interrupts in case an audio cue should
|
|
// cause someone to see an enemy
|
|
gubSightFlags |= SIGHT_INTERRUPT;
|
|
}
|
|
|
|
|
|
void OurTeamRadiosRandomlyAbout(UINT8 ubAbout)
|
|
{
|
|
INT32 iLoop;
|
|
// WDS - make number of mercenaries, etc. be configurable
|
|
INT8 radioCnt = 0,radioMan[CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS];
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
|
|
// Temporary for opplist synching - disable random order radioing
|
|
#ifdef RECORDOPPLIST
|
|
for (iLoop = Status.team[Net.pnum].guystart,ourPtr = MercPtrs[iLoop]; iLoop < Status.team[Net.pnum].guyend; iLoop++,ourPtr++)
|
|
{
|
|
// if this merc is active, in this sector, and well enough to look
|
|
if (pSoldier->active && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE))
|
|
{
|
|
RadioSightings(pSoldier,ubAbout,pSoldier->bTeam);
|
|
pSoldier->bNewOppCnt = 0;
|
|
}
|
|
}
|
|
|
|
return;
|
|
#endif
|
|
|
|
|
|
// All mercs on our local team check if they should radio about him
|
|
iLoop = gTacticalStatus.Team[gbPlayerNum].bFirstID;
|
|
|
|
// make a list of all of our team's mercs
|
|
for (pSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; iLoop++,pSoldier++)
|
|
{
|
|
// if this merc is active, in this sector, and well enough to look
|
|
if (pSoldier->bActive && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE))
|
|
// put him on our list, and increment the counter
|
|
radioMan[radioCnt++] = (INT8)iLoop;
|
|
}
|
|
|
|
|
|
// now RANDOMLY handle each of the mercs on our list, until none remain
|
|
// (this is all being done ONLY so that the mercs in the earliest merc
|
|
// slots do not arbitrarily get the bulk of the sighting speech quote
|
|
// action, while the later ones almost never pipe up, and is NOT
|
|
// strictly necessary, but a nice improvement over original JA)
|
|
while (radioCnt)
|
|
{
|
|
// pick a merc from one of the remaining slots at random
|
|
iLoop = Random(radioCnt);
|
|
|
|
// handle radioing for that merc
|
|
RadioSightings(MercPtrs[radioMan[iLoop]],ubAbout,MercPtrs[radioMan[iLoop]]->bTeam);
|
|
Menptr[radioMan[iLoop]].bNewOppCnt = 0;
|
|
|
|
// unless it WAS the last used slot that we happened to pick
|
|
if (iLoop != (radioCnt - 1))
|
|
// move the contents of the last slot into the one just handled
|
|
radioMan[iLoop] = radioMan[radioCnt - 1];
|
|
|
|
radioCnt--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INT16 TeamNoLongerSeesMan( UINT8 ubTeam, SOLDIERTYPE *pOpponent, UINT8 ubExcludeID, INT8 bIteration )
|
|
{
|
|
UINT16 bLoop;
|
|
SOLDIERTYPE *pMate;
|
|
|
|
|
|
bLoop = gTacticalStatus.Team[ubTeam].bFirstID;
|
|
|
|
// look for all mercs on the same team, check opplists for this soldier
|
|
for (pMate = MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[ubTeam].bLastID; ++bLoop,pMate++)
|
|
{
|
|
// if this "teammate" is me, myself, or I (whom we want to exclude)
|
|
if (bLoop == ubExcludeID)
|
|
continue; // skip to next teammate, I KNOW I don't see him...
|
|
|
|
// if this merc is not on the same team
|
|
if (pMate->bTeam != ubTeam)
|
|
continue; // skip him, he's no teammate at all!
|
|
|
|
// if this merc is not active, at base, on assignment, dead, unconscious
|
|
if (!pMate->bActive || !pMate->bInSector || (pMate->stats.bLife < OKLIFE))
|
|
continue; // next merc
|
|
|
|
// if this teammate currently sees this opponent
|
|
if (pMate->aiData.bOppList[pOpponent->ubID] == SEEN_CURRENTLY)
|
|
return(FALSE); // that's all I need to know, get out of here
|
|
}
|
|
|
|
/* comm by ddd
|
|
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
if ( bIteration == 0 )
|
|
{
|
|
if ( ubTeam == gbPlayerNum && gTacticalStatus.Team[ MILITIA_TEAM ].bTeamActive )
|
|
{
|
|
// check militia team as well
|
|
return( TeamNoLongerSeesMan( MILITIA_TEAM, pOpponent, ubExcludeID, 1 ) );
|
|
}
|
|
else if ( ubTeam == MILITIA_TEAM && gTacticalStatus.Team[ gbPlayerNum ].bTeamActive )
|
|
{
|
|
// check player team as well
|
|
return( TeamNoLongerSeesMan( gbPlayerNum, pOpponent, ubExcludeID, 1 ) );
|
|
}
|
|
}
|
|
#endif
|
|
*/
|
|
//ddd
|
|
if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
|
|
{
|
|
if ( bIteration == 0 )
|
|
{
|
|
if ( ubTeam == gbPlayerNum && gTacticalStatus.Team[ MILITIA_TEAM ].bTeamActive )
|
|
{
|
|
// check militia team as well
|
|
return( TeamNoLongerSeesMan( MILITIA_TEAM, pOpponent, ubExcludeID, 1 ) );
|
|
}
|
|
else if ( ubTeam == MILITIA_TEAM && gTacticalStatus.Team[ gbPlayerNum ].bTeamActive )
|
|
{
|
|
// check player team as well
|
|
return( TeamNoLongerSeesMan( gbPlayerNum, pOpponent, ubExcludeID, 1 ) );
|
|
}
|
|
}
|
|
|
|
}
|
|
//ddd
|
|
|
|
// none of my friends is currently seeing the guy, so return success
|
|
return(TRUE);
|
|
}
|
|
|
|
INT16 DistanceSmellable( SOLDIERTYPE *pSoldier, SOLDIERTYPE * pSubject )
|
|
{
|
|
INT16 sDistVisible = STRAIGHT; // as a base
|
|
|
|
//if (gTacticalStatus.uiFlags & TURNBASED)
|
|
//{
|
|
sDistVisible *= 2;
|
|
//}
|
|
//else
|
|
//{
|
|
|
|
// sDistVisible += 3;
|
|
//}
|
|
|
|
if (pSubject)
|
|
{
|
|
if (pSubject->flags.uiStatusFlags & SOLDIER_MONSTER)
|
|
{
|
|
// trying to smell a friend; change nothing
|
|
}
|
|
else
|
|
{
|
|
// smelling a human or animal; if they are coated with monster smell, distance shrinks
|
|
sDistVisible = sDistVisible * (pSubject->aiData.bNormalSmell - pSubject->aiData.bMonsterSmell) / NORMAL_HUMAN_SMELL_STRENGTH;
|
|
if (sDistVisible < 0)
|
|
{
|
|
sDistVisible = 0;
|
|
}
|
|
}
|
|
}
|
|
return( sDistVisible );
|
|
}
|
|
|
|
INT16 MaxNormalDistanceVisible( void )
|
|
{
|
|
return( STRAIGHT * 2 );
|
|
}
|
|
|
|
INT16 SOLDIERTYPE::GetMaxDistanceVisible(INT32 sGridNo, INT8 bLevel, int calcAsType)
|
|
{
|
|
if (sGridNo == NOWHERE)
|
|
{
|
|
return MaxNormalDistanceVisible();
|
|
}
|
|
|
|
if (bLevel == -1)
|
|
{
|
|
bLevel = this->pathing.bLevel;
|
|
}
|
|
|
|
if (calcAsType == CALC_FROM_ALL_DIRS)
|
|
{
|
|
return DistanceVisible( this, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel );
|
|
}
|
|
|
|
return DistanceVisible( this, (SoldierHasLimitedVision(this) ? this->pathing.bDesiredDirection : DIRECTION_IRRELEVANT), DIRECTION_IRRELEVANT, sGridNo, bLevel );
|
|
}
|
|
|
|
INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, INT32 sSubjectGridNo, INT8 bLevel )
|
|
{
|
|
INT16 sDistVisible;
|
|
INT8 bLightLevel;
|
|
BOOLEAN sideViewLimit = FALSE;
|
|
SOLDIERTYPE* pSubject = SimpleFindSoldier( sSubjectGridNo, bLevel );
|
|
|
|
if (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER)
|
|
{
|
|
if ( !pSubject )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( DistanceSmellable( pSoldier, pSubject ) );
|
|
}
|
|
|
|
if (pSoldier->bBlindedCounter > 0)
|
|
{
|
|
// we're bliiiiiiiiind!!!
|
|
return( 0 );
|
|
}
|
|
|
|
if ( bFacingDir == DIRECTION_IRRELEVANT && TANK( pSoldier ) )
|
|
{
|
|
// always calculate direction for tanks so we have something to work with
|
|
bFacingDir = pSoldier->pathing.bDesiredDirection;
|
|
bSubjectDir = (INT8) GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, sSubjectGridNo );
|
|
//bSubjectDir = atan8(pSoldier->sX,pSoldier->sY,pOpponent->sX,pOpponent->sY);
|
|
}
|
|
|
|
if ( !TANK( pSoldier ) && ( bFacingDir == DIRECTION_IRRELEVANT || (pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT) || (pSubject && pSubject->flags.fMuzzleFlash) ) )
|
|
{
|
|
sDistVisible = MaxNormalDistanceVisible();
|
|
}
|
|
else
|
|
{
|
|
if (pSoldier->sGridNo == sSubjectGridNo)
|
|
{
|
|
// looking up or down or two people accidentally in same tile... don't want it to be 0!
|
|
sDistVisible = MaxNormalDistanceVisible();
|
|
}
|
|
else
|
|
{
|
|
// Flugente: no need to calculate this multiple times
|
|
BOOLEAN fLimitedVision = SoldierHasLimitedVision(pSoldier);
|
|
|
|
// Lesh: added this
|
|
if( fLimitedVision )
|
|
{
|
|
bSubjectDir = (INT8) GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, sSubjectGridNo );
|
|
}
|
|
|
|
if (bFacingDir == DIRECTION_IRRELEVANT)
|
|
{
|
|
bFacingDir = pSoldier->ubDirection;
|
|
}
|
|
|
|
sDistVisible = gbLookDistance[bFacingDir][bSubjectDir];
|
|
|
|
// Lesh: and this
|
|
if ( (sDistVisible == 0) && fLimitedVision )
|
|
return(0);
|
|
|
|
if ( sDistVisible != STRAIGHT )
|
|
{
|
|
INT16 tunnelVisionInPercent = GetPercentTunnelVision(pSoldier);
|
|
|
|
if ( tunnelVisionInPercent > 0)
|
|
{
|
|
sideViewLimit = TRUE;
|
|
sDistVisible = sDistVisible * (100 - tunnelVisionInPercent ) / 100 ;
|
|
}
|
|
}
|
|
|
|
// ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"sDistVisible: %d", GetPercentTunnelVision(pSoldier) );
|
|
|
|
if ( sDistVisible == ANGLE && (pSoldier->bTeam == OUR_TEAM || pSoldier->aiData.bAlertStatus >= STATUS_RED ) )
|
|
{
|
|
sDistVisible = STRAIGHT;
|
|
}
|
|
|
|
sDistVisible *= 2;
|
|
|
|
if ( pSoldier->usAnimState == RUNNING )
|
|
{
|
|
if ( gbLookDistance[bFacingDir][bSubjectDir] != STRAIGHT )
|
|
{
|
|
// reduce sight when we're not looking in that direction...
|
|
sDistVisible = (INT16) (sDistVisible * ANGLE_RATIO);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pSoldier->pathing.bLevel != bLevel)
|
|
{
|
|
// add two tiles distance to visibility to/from roofs
|
|
// sDistVisible += (STRAIGHT_RATIO * 2); //2;
|
|
sDistVisible += ( sDistVisible / 6 ); //lal changed distance to 1/6 from visible range
|
|
}
|
|
|
|
// now reduce based on light level; SHADE_MIN is the define for the
|
|
// highest number the light can be
|
|
|
|
// If we're about to ask for a light level for a location outside of our
|
|
// valid map references then use the ambient light level instead.
|
|
if ( TileIsOutOfBounds( sSubjectGridNo ) )
|
|
{
|
|
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("113/UC Warning! Tried to detect the light level when character %ls[%d] looks at a location outside of the valid map (gridno %d). Assigning default %d",
|
|
pSoldier->name, pSoldier->ubID, pSoldier->sGridNo, ubAmbientLightLevel));
|
|
|
|
bLightLevel = ubAmbientLightLevel;
|
|
}
|
|
else
|
|
{
|
|
bLightLevel = LightTrueLevel(sSubjectGridNo, bLevel);
|
|
}
|
|
|
|
// Snap: I think this was intended to give maximum visibility to targets with muzzle flash...
|
|
// Corrected accordingly:
|
|
//if ( pSubject && !( pSubject->flags.fMuzzleFlash && (bLightLevel > NORMAL_LIGHTLEVEL_DAY) ) )
|
|
if ( !( pSubject && pSubject->flags.fMuzzleFlash && (bLightLevel > NORMAL_LIGHTLEVEL_DAY) ) )
|
|
{
|
|
// ATE: Made function to adjust light distance...
|
|
sDistVisible = AdjustMaxSightRangeForEnvEffects( pSoldier, bLightLevel, sDistVisible );
|
|
}
|
|
|
|
// Snap: this takes care of all equipment bonuses at all light levels
|
|
// The rest is special code for robots, bloodcats and NO specialists
|
|
// Lalien: change to % instead of tiles, add bonus only to front view when using scope
|
|
if (!sideViewLimit)
|
|
{
|
|
sDistVisible += sDistVisible * GetTotalVisionRangeBonus(pSoldier, bLightLevel) / 100;
|
|
|
|
// HEADROCK HAM 3.2: Further reduce sightrange for cowering characters.
|
|
// SANDRO - this calls many sub-functions over and over, we should at least skip this for civilians and such
|
|
// Flugente: we can check for more conditions before calculating suppression tolerance
|
|
if ( (gGameExternalOptions.ubCoweringReducesSightRange == 1 || gGameExternalOptions.ubCoweringReducesSightRange == 2) &&
|
|
IS_MERC_BODY_TYPE(pSoldier) && (pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM || pSoldier->bTeam == gbPlayerNum) &&
|
|
gGameExternalOptions.ubMaxSuppressionShock > 0 && sDistVisible > 0 )
|
|
{
|
|
INT8 bTolerance = CalcSuppressionTolerance( pSoldier );
|
|
|
|
// Make sure character is cowering.
|
|
if ( pSoldier->aiData.bShock >= bTolerance )
|
|
{
|
|
sDistVisible = __max(1,(sDistVisible * (gGameExternalOptions.ubMaxSuppressionShock - pSoldier->aiData.bShock)) / gGameExternalOptions.ubMaxSuppressionShock);
|
|
}
|
|
}
|
|
}
|
|
|
|
// give one step better vision for people with nightops
|
|
// old/new traits check - SANDRO
|
|
if (gGameOptions.fNewTraitSystem)
|
|
{
|
|
if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ))
|
|
sDistVisible += NightBonusScale( gSkillTraitValues.ubNOeSightRangeBonusInDark, bLightLevel);
|
|
}
|
|
else
|
|
{
|
|
if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT ))
|
|
sDistVisible += NightBonusScale( 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT ), bLightLevel);
|
|
}
|
|
// Bloodcat bonus only works above ground
|
|
if ( pSoldier->ubBodyType == BLOODCAT && gbWorldSectorZ == 0 )
|
|
{
|
|
sDistVisible += NightBonusScale( UVGOGGLES_BONUS, bLightLevel);
|
|
}
|
|
else if ( AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
sDistVisible += NightBonusScale( NIGHTSIGHTGOGGLES_BONUS, bLightLevel);
|
|
}
|
|
|
|
// let tanks see and be seen further (at night)
|
|
if ( (TANK( pSoldier ) && sDistVisible > 0) || (pSubject && TANK( pSubject ) ) )
|
|
{
|
|
#if 0
|
|
if ( TANK(pSoldier) && sDistVisible > 0 && pSubject)
|
|
{
|
|
sDistVisible = __max( sDistVisible + 5, pSubject->GetMaxDistanceVisible(pSoldier->sGridNo, pSoldier->pathing.bLevel) );
|
|
}
|
|
else
|
|
{
|
|
sDistVisible = __max( sDistVisible + 5, pSoldier->GetMaxDistanceVisible() );
|
|
}
|
|
#endif
|
|
// 0verhaul: This bit of code 1) seems to have no real reason to exist (MaxDistVisible just calls this function anyway),
|
|
// and 2) causes infinite recursion because MaxDistVisible just calls this function, which comes right back here. Just
|
|
// add 5 to sDistVisible and go on.
|
|
sDistVisible = sDistVisible + 5;
|
|
}
|
|
|
|
if ( gpWorldLevelData[ pSoldier->sGridNo ].ubExtFlags[ bLevel ] & (MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS) )
|
|
{
|
|
//dnl ch40 200909
|
|
INT8 bPosOfMask = FindGasMask(pSoldier);
|
|
if(bPosOfMask == HEAD1POS || bPosOfMask == HEAD2POS)
|
|
{
|
|
if(pSoldier->inv[bPosOfMask][0]->data.objectStatus < GASMASK_MIN_STATUS)
|
|
sDistVisible = __min(sDistVisible, 2+pSoldier->inv[bPosOfMask][0]->data.objectStatus/15);
|
|
}
|
|
else
|
|
sDistVisible = __min(sDistVisible, 2);
|
|
}
|
|
if ( gpWorldLevelData[ pSoldier->sGridNo ].ubExtFlags[ bLevel ] & MAPELEMENT_EXT_BURNABLEGAS )
|
|
{
|
|
{
|
|
// in FLAMETHERgas ; reduce max distance visible to 2 tiles at most
|
|
sDistVisible = __min( sDistVisible, 2 );
|
|
}
|
|
}
|
|
|
|
return(sDistVisible);
|
|
}
|
|
|
|
|
|
|
|
void EndMuzzleFlash( SOLDIERTYPE * pSoldier )
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE * pOtherSoldier;
|
|
|
|
pSoldier->flags.fMuzzleFlash = FALSE;
|
|
/*comm by ddd
|
|
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
if ( pSoldier->bTeam != gbPlayerNum && pSoldier->bTeam != MILITIA_TEAM )
|
|
#else
|
|
if ( pSoldier->bTeam != gbPlayerNum )
|
|
#endif
|
|
|
|
{
|
|
pSoldier->bVisible = 0; // indeterminate state
|
|
}
|
|
*/
|
|
|
|
|
|
#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
|
|
//haydent
|
|
if(is_networked && pSoldier->bSide == 0)
|
|
{
|
|
//stay visible
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
|
|
{ if ( pSoldier->bTeam != gbPlayerNum && pSoldier->bTeam != MILITIA_TEAM )
|
|
pSoldier->bVisible = 0; // indeterminate state
|
|
}
|
|
else
|
|
{
|
|
if ( pSoldier->bTeam != gbPlayerNum )
|
|
pSoldier->bVisible = 0; // indeterminate state
|
|
}
|
|
}//haydent
|
|
|
|
|
|
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pOtherSoldier = MercSlots[ uiLoop ];
|
|
|
|
if ( pOtherSoldier != NULL )
|
|
{
|
|
if ( pOtherSoldier->aiData.bOppList[ pSoldier->ubID ] == SEEN_CURRENTLY )
|
|
{
|
|
if (!TileIsOutOfBounds(pOtherSoldier->sGridNo))
|
|
{
|
|
if ( PythSpacesAway( pOtherSoldier->sGridNo, pSoldier->sGridNo ) > pOtherSoldier->GetMaxDistanceVisible(pSoldier->sGridNo, pSoldier->pathing.bLevel, CALC_FROM_WANTED_DIR ) )
|
|
{
|
|
// if this guy can no longer see us, change to seen this turn
|
|
HandleManNoLongerSeen( pOtherSoldier, pSoldier, &(pOtherSoldier->aiData.bOppList[ pSoldier->ubID ]), &(gbPublicOpplist[ pOtherSoldier->bTeam ][ pSoldier->ubID ] ) );
|
|
}
|
|
|
|
// else this person is still seen, if the looker is on our side or the militia the person should stay visible
|
|
/* comm by ddd
|
|
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
else if ( pOtherSoldier->bTeam == gbPlayerNum || pOtherSoldier->bTeam == MILITIA_TEAM )
|
|
#else
|
|
else if ( pOtherSoldier->bTeam == gbPlayerNum )
|
|
#endif
|
|
|
|
{
|
|
pSoldier->bVisible = TRUE; // yes, still seen
|
|
}
|
|
*/
|
|
//ddd{
|
|
else if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
|
|
{
|
|
if ( pOtherSoldier->bTeam == gbPlayerNum || pOtherSoldier->bTeam == MILITIA_TEAM )
|
|
{pSoldier->bVisible = TRUE;} // yes, still seen
|
|
}
|
|
else
|
|
{
|
|
if ( pOtherSoldier->bTeam == gbPlayerNum )
|
|
pSoldier->bVisible = TRUE; // yes, still seen
|
|
}
|
|
//ddd}
|
|
|
|
|
|
#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
|
|
//haydent
|
|
if(is_networked && pOtherSoldier->bSide == 0 && pOtherSoldier->bTeam != OUR_TEAM)
|
|
pSoldier->bVisible = TRUE; // yes, still seen
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DecideTrueVisibility( pSoldier, FALSE );
|
|
|
|
}
|
|
|
|
void TurnOffEveryonesMuzzleFlashes( void )
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
if ( pSoldier != NULL && pSoldier->flags.fMuzzleFlash )
|
|
{
|
|
EndMuzzleFlash( pSoldier );
|
|
}
|
|
}
|
|
}
|
|
|
|
void TurnOffTeamsMuzzleFlashes( UINT8 ubTeam )
|
|
{
|
|
UINT8 ubLoop;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
for (ubLoop = gTacticalStatus.Team[ ubTeam ].bFirstID; ubLoop <= gTacticalStatus.Team[ ubTeam ].bLastID; ubLoop++)
|
|
{
|
|
pSoldier = MercPtrs[ ubLoop ];
|
|
|
|
if ( pSoldier->flags.fMuzzleFlash )
|
|
{
|
|
EndMuzzleFlash( pSoldier );
|
|
}
|
|
}
|
|
}
|
|
|
|
INT8 DecideHearing( SOLDIERTYPE * pSoldier )
|
|
{
|
|
// calculate the hearing value for the merc...
|
|
INT8 bHearing;
|
|
|
|
if ( TANK( pSoldier ) )
|
|
{
|
|
return( -5 );
|
|
}
|
|
else if ( pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER )
|
|
{
|
|
return( -10 );
|
|
}
|
|
|
|
bHearing = 0;
|
|
|
|
if (EffectiveExpLevel( pSoldier ) > 3) // SANDRO - changed to calculate effective level
|
|
{
|
|
bHearing++;
|
|
}
|
|
|
|
// old/new traits check - SANDRO
|
|
if (gGameOptions.fNewTraitSystem)
|
|
{
|
|
if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ))
|
|
bHearing += gSkillTraitValues.ubNOHearingRangeBonus;
|
|
}
|
|
else
|
|
{
|
|
if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT ))
|
|
bHearing += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT );
|
|
}
|
|
|
|
bHearing += pSoldier->GetHearingBonus();
|
|
|
|
// adjust for dark conditions
|
|
switch ( ubAmbientLightLevel )
|
|
{
|
|
case 8:
|
|
case 9:
|
|
bHearing += 1;
|
|
break;
|
|
case 10:
|
|
bHearing += 2;
|
|
break;
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
bHearing += 3;
|
|
// yet another bonus for nighttime
|
|
// old/new traits check - SANDRO
|
|
if (gGameOptions.fNewTraitSystem)
|
|
{
|
|
if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ))
|
|
bHearing += gSkillTraitValues.ubNOHearingRangeBonusInDark;
|
|
}
|
|
else
|
|
{
|
|
if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT ))
|
|
bHearing += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return( bHearing );
|
|
}
|
|
|
|
void InitOpplistForDoorOpening( void )
|
|
{
|
|
// this is called before generating a noise for opening a door so that
|
|
// the results of hearing the noise are lumped in with the results from AllTeamsLookForAll
|
|
gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_ALL_TEAMS_LOOK_FOR_ALL;
|
|
gfDelayResolvingBestSightingDueToDoor = TRUE; // will be turned off in allteamslookforall
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "HBSPIR: setting door flag on" );
|
|
// must init sight arrays here
|
|
InitSightArrays();
|
|
}
|
|
|
|
|
|
void AllTeamsLookForAll(UINT8 ubAllowInterrupts)
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
if( ( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ubAllowInterrupts || !(gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_ALL_TEAMS_LOOK_FOR_ALL;
|
|
if ( gfDelayResolvingBestSightingDueToDoor )
|
|
{
|
|
// turn off flag now, and skip init of sight arrays
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "HBSPIR: turning door flag off" );
|
|
gfDelayResolvingBestSightingDueToDoor = FALSE;
|
|
}
|
|
else
|
|
{
|
|
InitSightArrays();
|
|
}
|
|
}
|
|
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
if ( pSoldier != NULL && pSoldier->stats.bLife >= OKLIFE )
|
|
{
|
|
HandleSight(pSoldier,SIGHT_LOOK); // no radio or interrupts yet
|
|
}
|
|
}
|
|
|
|
// the player team now radios about all sightings
|
|
for ( uiLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; uiLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; uiLoop++ )
|
|
{
|
|
HandleSight( MercPtrs[ uiLoop ], SIGHT_RADIO ); // looking was done above
|
|
}
|
|
|
|
if ( !(gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
// decide who should get first turn
|
|
HandleBestSightingPositionInRealtime();
|
|
// this could have made us switch to combat mode
|
|
if ( (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_INCOMBAT;
|
|
}
|
|
else
|
|
{
|
|
gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_NONCOMBAT;
|
|
}
|
|
}
|
|
else if ( ubAllowInterrupts )
|
|
{
|
|
HandleBestSightingPositionInTurnbased();
|
|
// reset sighting size to 0
|
|
gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_INCOMBAT;
|
|
}
|
|
|
|
/*
|
|
|
|
// do this here as well as in overhead so the looks/interrupts are combined!
|
|
|
|
// if a door was recently opened/closed (doesn't matter if we could see it)
|
|
// this is done here so we can first handle everyone looking through the
|
|
// door, and deal with the resulting opplist changes, interrupts, etc.
|
|
if ( !TileIsOutOfBounds(Status.doorCreakedGridno))
|
|
{
|
|
// opening/closing a door makes a bit of noise (constant volume)
|
|
MakeNoise(Status.doorCreakedGuynum,Status.doorCreakedGridno,TTypeList[Grid[Status.doorCreakedGridno].land],DOOR_NOISE_VOLUME,NOISE_CREAKING,EXPECTED_NOSEND);
|
|
|
|
Status.doorCreakedGridno = NOWHERE;
|
|
Status.doorCreakedGuynum = NOBODY;
|
|
}
|
|
|
|
|
|
// all soldiers now radio their findings (NO interrupts permitted this early!)
|
|
// NEW: our entire team must radio first, so that they radio about EVERYBODY
|
|
// rather radioing about individuals one a a time (repeats see 1 enemy quote)
|
|
for (cnt = Status.team[Net.pnum].guystart,ptr = MercPtrs[cnt]; cnt < Status.team[Net.pnum].guyend; cnt++,ptr++)
|
|
{
|
|
if (ptr->active && ptr->in_sector && (ptr->life >= OKLIFE))
|
|
HandleSight(ptr,SIGHT_RADIO); // looking was done above
|
|
}
|
|
|
|
for (cnt = 0,ptr = Menptr; cnt < MAXMERCS; cnt++,ptr++)
|
|
{
|
|
if (ptr->active && ptr->in_sector && (ptr->life >= OKLIFE) && !PTR_OURTEAM)
|
|
HandleSight(ptr,SIGHT_RADIO); // looking was done above
|
|
}
|
|
|
|
|
|
// if interrupts were allowed
|
|
if (allowInterrupts)
|
|
// resolve interrupts against the selected character (others disallowed)
|
|
HandleSight(MercPtrs[Status.allLookCharacter],SIGHT_INTERRUPT);
|
|
|
|
|
|
// revert to normal interrupt operation
|
|
InterruptOnlyGuynum = NOBODY;
|
|
InterruptsAllowed = TRUE;
|
|
*/
|
|
|
|
// reset interrupt only guynum which may have been used
|
|
gubInterruptProvoker = NOBODY;
|
|
}
|
|
|
|
|
|
|
|
|
|
void ManLooksForOtherTeams(SOLDIERTYPE *pSoldier)
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE *pOpponent;
|
|
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("MANLOOKSFOROTHERTEAMS ID %d(%S) team %d side %d",pSoldier->ubID,pSoldier->name,pSoldier->bTeam,pSoldier->bSide));
|
|
#endif
|
|
|
|
|
|
// one soldier (pSoldier) looks for every soldier on another team (pOpponent)
|
|
|
|
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pOpponent = MercSlots[ uiLoop ];
|
|
|
|
// if this soldier is around and alive
|
|
if (pOpponent && pOpponent->stats.bLife)
|
|
{
|
|
// and if he's on another team...
|
|
if (pSoldier->bTeam != pOpponent->bTeam)
|
|
{
|
|
|
|
// use both sides actual x,y co-ordinates (neither side's moving)
|
|
// if he sees this opponent...
|
|
ManLooksForMan(pSoldier,pOpponent,MANLOOKSFOROTHERTEAMS);
|
|
|
|
// OK, We now want to , if in non-combat, set visiblity to 0 if not visible still....
|
|
// This allows us to walk away from buddy and have them disappear instantly
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && !( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
if ( pOpponent->bVisible == 0)
|
|
{
|
|
pOpponent->bVisible = -1;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT8 * pPersOL, INT8 * pbPublOL )
|
|
{
|
|
// if neither side is neutral AND
|
|
// if this soldier is an opponent (fights for different side)
|
|
if (pSoldier->bActive && pOpponent->bActive && !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
|
{
|
|
RemoveOneOpponent(pSoldier);
|
|
}
|
|
|
|
// change personal opplist to indicate "seen this turn"
|
|
// don't use UpdatePersonal() here, because we're changing to a *lower*
|
|
// opplist value (which UpdatePersonal ignores) and we're not updating
|
|
// the lastKnown gridno at all, we're keeping it at its previous value
|
|
/*
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"ManLooksForMan: changing personalOpplist to %d for guynum %d, opp %d\n",SEEN_THIS_TURN,ptr->guynum,oppPtr->guynum);
|
|
#endif
|
|
*/
|
|
|
|
*pPersOL = SEEN_THIS_TURN;
|
|
|
|
if ( (pSoldier->ubCivilianGroup == KINGPIN_CIV_GROUP) && (pOpponent->bTeam == gbPlayerNum ) )
|
|
{
|
|
//DBrot: More Rooms
|
|
//UINT8 ubRoom;
|
|
UINT16 usRoom;
|
|
|
|
if ( InARoom( pOpponent->sGridNo, &usRoom ) && IN_BROTHEL( usRoom ) && ( IN_BROTHEL_GUARD_ROOM( usRoom ) ) )
|
|
{
|
|
// unauthorized!
|
|
// make guard run to block guard room
|
|
CancelAIAction( pSoldier, TRUE );
|
|
RESETTIMECOUNTER( pSoldier->timeCounters.AICounter, 0 );
|
|
pSoldier->aiData.bNextAction = AI_ACTION_RUN;
|
|
pSoldier->aiData.usNextActionData = 13250;
|
|
}
|
|
}
|
|
|
|
// if opponent was seen publicly last time
|
|
if (*pbPublOL == SEEN_CURRENTLY)
|
|
{
|
|
// check if I was the only one who was seeing this guy (exlude ourselves)
|
|
// THIS MUST HAPPEN EVEN FOR ENEMIES, TO MAKE THEIR PUBLIC opplist DECAY!
|
|
if (TeamNoLongerSeesMan(pSoldier->bTeam,pOpponent,pSoldier->ubID, 0 ))
|
|
{
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "TeamNoLongerSeesMan: ID %d(%S) to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
|
|
#endif
|
|
|
|
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"TeamNoLongerSeesMan returns TRUE for team %d, opp %d\n",ptr->team,oppPtr->guynum);
|
|
fprintf(OpplistFile,"ManLooksForMan: changing publicOpplist to %d for team %d, opp %d\n",SEEN_THIS_TURN,ptr->team,oppPtr->guynum);
|
|
#endif
|
|
|
|
// don't use UpdatePublic() here, because we're changing to a *lower*
|
|
// opplist value (which UpdatePublic ignores) and we're not updating
|
|
// the lastKnown gridno at all, we're keeping it at its previous value
|
|
*pbPublOL = SEEN_THIS_TURN;
|
|
|
|
// ATE: Set visiblity to 0
|
|
/*comm by ddd
|
|
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
if ( (pSoldier->bTeam == gbPlayerNum || pSoldier->bTeam == MILITIA_TEAM) && !(pOpponent->bTeam == gbPlayerNum || pOpponent->bTeam == MILITIA_TEAM ) )
|
|
#else
|
|
if ( pSoldier->bTeam == gbPlayerNum && pOpponent->bTeam != gbPlayerNum )
|
|
#endif
|
|
{
|
|
pOpponent->bVisible = 0;
|
|
}
|
|
*/
|
|
|
|
|
|
#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
|
|
//haydent
|
|
if(is_networked && pSoldier->bSide == 0)
|
|
{
|
|
//stay visible
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
|
|
{
|
|
if ( (pSoldier->bTeam == gbPlayerNum || pSoldier->bTeam == MILITIA_TEAM) && !(pOpponent->bTeam == gbPlayerNum || pOpponent->bTeam == MILITIA_TEAM ) )
|
|
pOpponent->bVisible = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( pSoldier->bTeam == gbPlayerNum && pOpponent->bTeam != gbPlayerNum )
|
|
pOpponent->bVisible = 0;
|
|
}
|
|
}//haydent
|
|
}
|
|
}
|
|
#ifdef TESTOPPLIST
|
|
else
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("ManLooksForMan: ID %d(%S) to ID %d Personally seen, public %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pbPublOL) );
|
|
#endif
|
|
|
|
// if we had only seen the guy for an instant and now lost sight of him
|
|
if (gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] == -1)
|
|
// we can't leave it -1, because InterruptDuel() uses the special -1
|
|
// value to know if we're only JUST seen the guy and screw up otherwise
|
|
// it's enough to know we have seen him before
|
|
gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] = TRUE;
|
|
|
|
}
|
|
|
|
|
|
INT16 ManLooksForMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, UINT8 ubCaller)
|
|
{
|
|
INT8 bDir,bAware = FALSE,bSuccess = FALSE;
|
|
INT16 sDistVisible,sDistAway;
|
|
INT8 *pPersOL,*pbPublOL;
|
|
|
|
|
|
/*
|
|
if (ptr->guynum >= TOTAL_SOLDIERS)
|
|
{
|
|
#ifdef BETAVERSION
|
|
NumMessage("ManLooksForMan: ERROR - ptr->guynum = ",ptr->guynum);
|
|
#endif
|
|
return(success);
|
|
}
|
|
|
|
if (oppPtr->guynum >= TOTAL_SOLDIERS)
|
|
{
|
|
#ifdef BETAVERSION
|
|
NumMessage("ManLooksForMan: ERROR - oppPtr->guynum = ",oppPtr->guynum);
|
|
#endif
|
|
return(success);
|
|
}
|
|
*/
|
|
|
|
// if we're somehow looking while inactive, at base, dead or dying
|
|
if (!pSoldier->bActive || !pSoldier->bInSector || (pSoldier->stats.bLife < OKLIFE))
|
|
{
|
|
/*
|
|
#ifdef BETAVERSION
|
|
sprintf(tempstr,"ManLooksForMan: ERROR - %s is looking while inactive/at base/dead/dying. Caller %s",
|
|
ExtMen[ptr->guynum].name,LastCaller2Text[caller]);
|
|
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\n\t%s\n\n",tempstr);
|
|
#endif
|
|
|
|
PopMessage(tempstr);
|
|
#endif
|
|
*/
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("ERROR: ManLooksForMan - WE are inactive/dead etc ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
|
|
#endif
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// if we're somehow looking for a guy who is inactive, at base, or already dead
|
|
if (!pOpponent->bActive || !pOpponent->bInSector || pOpponent->stats.bLife <= 0 || TileIsOutOfBounds(pOpponent->sGridNo))
|
|
{
|
|
/*
|
|
#ifdef BETAVERSION
|
|
sprintf(tempstr,"ManLooksForMan: ERROR - %s looks for %s, who is inactive/at base/dead. Caller %s",
|
|
ExtMen[ptr->guynum].name,ExtMen[oppPtr->guynum].name,LastCaller2Text[caller]);
|
|
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\n\t%s\n\n",tempstr);
|
|
#endif
|
|
|
|
PopMessage(tempstr);
|
|
#endif
|
|
*/
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("ERROR: ManLooksForMan - TARGET is inactive etc ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
|
|
#endif
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
// if he's looking for a guy who is on the same team
|
|
if (pSoldier->bTeam == pOpponent->bTeam)
|
|
{
|
|
/*
|
|
#ifdef BETAVERSION
|
|
sprintf(tempstr,"ManLooksFormMan: ERROR - on SAME TEAM. ptr->guynum = %d, oppPtr->guynum = %d",
|
|
ptr->guynum,oppPtr->guynum);
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\n\t%s\n\n",tempstr);
|
|
#endif
|
|
|
|
PopMessage(tempstr);
|
|
#endif
|
|
*/
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("ERROR: ManLooksForMan - SAME TEAM ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
|
|
#endif
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// Flugente: we already checked for OKLIFE above..
|
|
if ( pSoldier->flags.fMercAsleep )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// NEED TO CHANGE THIS
|
|
/*
|
|
// don't allow unconscious persons to look, but COLLAPSED, etc. is OK
|
|
if (ptr->anitype[ptr->anim] == UNCONSCIOUS)
|
|
return(success);
|
|
*/
|
|
|
|
if ( pSoldier->ubBodyType == LARVAE_MONSTER || (pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->bTeam == OUR_TEAM) )
|
|
{
|
|
// don't do sight for these
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
/*
|
|
if (ptrProjected)
|
|
{
|
|
// use looker's PROJECTED x,y co-ordinates (those of his next gridno)
|
|
fromX = ptr->destx;
|
|
fromY = ptr->desty;
|
|
fromGridno = ExtMen[ptr->guynum].nextGridno;
|
|
}
|
|
else
|
|
{
|
|
// use looker's ACTUAL x,y co-ordinates (those of gridno he's in now)
|
|
fromX = ptr->x;
|
|
fromY = ptr->y;
|
|
fromGridno = ptr->sGridNo;
|
|
}
|
|
|
|
|
|
if (oppPtrProjected)
|
|
{
|
|
// use target's PROJECTED x,y co-ordinates (those of his next gridno)
|
|
toX = oppPtr->destx;
|
|
toY = oppPtr->desty;
|
|
toGridno = ExtMen[oppPtr->guynum].nextGridno;
|
|
}
|
|
else
|
|
{
|
|
// use target's ACTUAL x,y co-ordinates (those of gridno he's in now)
|
|
toX = oppPtr->x;
|
|
toY = oppPtr->y;
|
|
toGridno = oppPtr->gridno;
|
|
}
|
|
*/
|
|
|
|
pPersOL = &(pSoldier->aiData.bOppList[pOpponent->ubID]);
|
|
pbPublOL = &(gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID]);
|
|
|
|
// if soldier is known about (SEEN or HEARD within last few turns)
|
|
if (*pPersOL || *pbPublOL)
|
|
{
|
|
bAware = TRUE;
|
|
|
|
// then we look for him full viewing distance in EVERY direction
|
|
|
|
//ADB the comment above says EVERY direction but the code used to be:
|
|
//sDistVisible = DistanceVisible(pSoldier, (SoldierHasLimitedVision(pSoldier) ? pSoldier->bDesiredDirection : DIRECTION_IRRELEVANT), 0, pOpponent->sGridNo, pOpponent->bLevel, pOpponent );
|
|
//if the code below says CALC_FROM_ALL_DIRS, then the opponent will NOT be greyed out if a merc sees him and a second merc turns away from him
|
|
//calcing from the wanted dir will make the opponent be greyed out, which I think is the intended effect
|
|
sDistVisible = pSoldier->GetMaxDistanceVisible( pOpponent->sGridNo, pOpponent->pathing.bLevel, CALC_FROM_WANTED_DIR );
|
|
//if (pSoldier->ubID == 0)
|
|
//sprintf(gDebugStr,"ALREADY KNOW: ME %d him %d val %d",pSoldier->ubID,pOpponent->ubID,pSoldier->bOppList[pOpponent->ubID]);
|
|
}
|
|
else // soldier is not currently known about
|
|
{
|
|
// distance we "see" then depends on the direction he is located from us
|
|
bDir = atan8(pSoldier->sX,pSoldier->sY,pOpponent->sX,pOpponent->sY);
|
|
// BIG NOTE: must use desdir instead of direction, since in a projected
|
|
// situation, the direction may still be changing if it's one of the first
|
|
// few animation steps when this guy's turn to do his stepped look comes up
|
|
sDistVisible = DistanceVisible(pSoldier,pSoldier->pathing.bDesiredDirection,bDir, pOpponent->sGridNo, pOpponent->pathing.bLevel );
|
|
//if (pSoldier->ubID == 0)
|
|
//sprintf(gDebugStr,"dist visible %d: my dir %d to him %d",sDistVisible,pSoldier->bDesiredDirection,bDir);
|
|
}
|
|
|
|
// calculate how many spaces away soldier is (using Pythagoras' theorem)
|
|
sDistAway = PythSpacesAway(pSoldier->sGridNo,pOpponent->sGridNo);
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "MANLOOKSFORMAN: ID %d(%S) to ID %d: sDistAway %d sDistVisible %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,sDistAway,sDistVisible) );
|
|
#endif
|
|
|
|
// if we see close enough to see the soldier
|
|
if (sDistAway <= sDistVisible)
|
|
{
|
|
// and we can trace a line of sight to his x,y coordinates
|
|
// must use the REAL opplist value here since we may or may not know of him
|
|
if (SoldierToSoldierLineOfSightTest(pSoldier,pOpponent,bAware,sDistVisible))
|
|
{
|
|
ManSeesMan(pSoldier,pOpponent,pOpponent->sGridNo,pOpponent->pathing.bLevel,MANLOOKSFORMAN,ubCaller);
|
|
bSuccess = TRUE;
|
|
}
|
|
#ifdef TESTOPPLIST
|
|
else
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("FAILED LINEOFSIGHT: ID %d (%S)to ID %d Personally %d, public %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL) );
|
|
#endif
|
|
|
|
/*
|
|
// if we're looking for a local merc, and changed doors were in the way
|
|
if (PTR_OURTEAM && (NextFreeDoorIndex > 0))
|
|
// make or fail, if we passed through any "changed" doors along the way,
|
|
// reveal their true status (change the structure to its real value)
|
|
// (do this even if we don't have LOS, to close doors that *BREAK* LOS)
|
|
RevealDoorsAlongLOS();
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"MLFM: %s by %2d(g%4d,x%3d,y%3d,%s) at %2d(g%4d,x%3d,y%3d,%s), aware %d, dA=%d,dV=%d, desDir=%d, %s\n",
|
|
(success) ? "SCS" : "FLR",
|
|
ptr->guynum,fromGridno,fromX,fromY,(ptrProjected)?"PROJ":"REG.",
|
|
oppPtr->guynum,toGridno,toX,toY,(oppPtrProjected)?"PROJ":"REG.",
|
|
aware,distAway,distVisible,ptr->desdir,
|
|
LastCaller2Text[caller]);
|
|
#endif
|
|
*/
|
|
|
|
// if soldier seen personally LAST time could not be seen THIS time
|
|
if (!bSuccess && (*pPersOL == SEEN_CURRENTLY))
|
|
{
|
|
HandleManNoLongerSeen( pSoldier, pOpponent, pPersOL, pbPublOL );
|
|
}
|
|
#ifdef TESTOPPLIST
|
|
else
|
|
{
|
|
if (!bSuccess)
|
|
{
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("NO LONGER VISIBLE ID %d (%S)to ID %d Personally %d, public %d success: %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL,bSuccess) );
|
|
|
|
// we didn't see the opponent, but since we didn't last time, we should be
|
|
//if (*pbPublOL)
|
|
//pOpponent->bVisible = TRUE;
|
|
}
|
|
else
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("COOL. STILL VISIBLE ID %d (%S)to ID %d Personally %d, public %d success: %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL,bSuccess) );
|
|
}
|
|
#endif
|
|
|
|
return(bSuccess);
|
|
}
|
|
|
|
|
|
|
|
|
|
void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, INT8 bOppLevel, UINT8 ubCaller, UINT8 ubCaller2)
|
|
{
|
|
INT8 bDoLocate = FALSE;
|
|
BOOLEAN fNewOpponent = FALSE;
|
|
BOOLEAN fNotAddedToList = TRUE;
|
|
INT8 bOldOppList = pSoldier->aiData.bOppList[pOpponent->ubID];
|
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"ManSeesMan");
|
|
|
|
if (pSoldier->ubID >= TOTAL_SOLDIERS)
|
|
return;
|
|
if (pOpponent->ubID >= TOTAL_SOLDIERS)
|
|
return;
|
|
// if we're somehow looking while inactive, at base, dying or already dead
|
|
if (!pSoldier->bActive || !pSoldier->bInSector || (pSoldier->stats.bLife < OKLIFE))
|
|
return;
|
|
// if we're somehow seeing a guy who is inactive, at base, or already dead
|
|
if (!pOpponent->bActive || !pOpponent->bInSector || pOpponent->stats.bLife <= 0)
|
|
return;
|
|
// if we're somehow seeing a guy who is on the same team
|
|
if (pSoldier->bTeam == pOpponent->bTeam)
|
|
return;
|
|
// Flugente: if the other guy is in med or deep water and wearing scua gear, then we cannot see him as he is submerged
|
|
if ( pOpponent->UsesScubaGear() )
|
|
return;
|
|
// Flugente: update our sight concerning this guy, otherwise we could get way with open attacks because this does not get updated
|
|
pSoldier->RecognizeAsCombatant(pOpponent->ubID);
|
|
|
|
// if we're seeing a guy we didn't see on our last chance to look for him
|
|
if (pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_CURRENTLY)
|
|
{
|
|
if ( pOpponent->bTeam == gbPlayerNum )
|
|
{
|
|
if ( pSoldier->ubProfile != NO_PROFILE )
|
|
{
|
|
if ( pSoldier->bTeam == CIV_TEAM )
|
|
{
|
|
// if this person doing the sighting is a member of a civ group that hates us but
|
|
// this fact hasn't been revealed, change the side of these people now. This will
|
|
// make them non-neutral so AddOneOpponent will be called, and the guy will say his
|
|
// "I hate you" quote
|
|
if ( pSoldier->aiData.bNeutral )
|
|
{
|
|
if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] >= CIV_GROUP_WILL_BECOME_HOSTILE )
|
|
{
|
|
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
|
fNotAddedToList = FALSE;
|
|
}
|
|
}
|
|
else if ( NPCHasUnusedRecordWithGivenApproach( pSoldier->ubProfile, APPROACH_DECLARATION_OF_HOSTILITY ) )
|
|
{
|
|
// only add if have something to say
|
|
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
|
fNotAddedToList = FALSE;
|
|
}
|
|
|
|
if ( fNotAddedToList )
|
|
{
|
|
switch( pSoldier->ubProfile )
|
|
{
|
|
case CARMEN:
|
|
#ifdef JA2UB
|
|
// no UB
|
|
#else
|
|
if (pOpponent->ubProfile == SLAY ) // 64
|
|
{
|
|
// Carmen goes to war (against Slay)
|
|
if ( pSoldier->aiData.bNeutral )
|
|
{
|
|
//SetSoldierNonNeutral( pSoldier );
|
|
pSoldier->aiData.bAttitude = ATTACKSLAYONLY;
|
|
TriggerNPCRecord( pSoldier->ubProfile, 28 );
|
|
}
|
|
/*
|
|
if ( ! gTacticalStatus.uiFlags & INCOMBAT )
|
|
{
|
|
EnterCombatMode( pSoldier->bTeam );
|
|
}
|
|
*/
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
break;
|
|
case ELDIN:
|
|
if ( pSoldier->aiData.bNeutral )
|
|
{
|
|
//DBrot: More Rooms
|
|
//UINT8 ubRoom = 0;
|
|
UINT16 usRoom = 0;
|
|
// if player is in behind the ropes of the museum display
|
|
// or if alarm has gone off (status red)
|
|
InARoom( pOpponent->sGridNo, &usRoom );
|
|
|
|
if ( ( CheckFact( FACT_MUSEUM_OPEN, 0 ) == FALSE && usRoom >= 22 && usRoom <= 41 ) || CheckFact( FACT_MUSEUM_ALARM_WENT_OFF, 0 ) || ( usRoom == 39 || usRoom == 40 ) || ( FindObj( pOpponent, CHALICE ) != NO_SLOT ) )
|
|
{
|
|
SetFactTrue( FACT_MUSEUM_ALARM_WENT_OFF );
|
|
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
|
}
|
|
}
|
|
break;
|
|
case JIM:
|
|
case JACK:
|
|
case OLAF:
|
|
case RAY:
|
|
case OLGA:
|
|
case TYRONE:
|
|
// 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 );
|
|
}
|
|
}
|
|
break;
|
|
case ANGEL:
|
|
if ( pOpponent->ubProfile == MARIA )
|
|
{
|
|
if ( CheckFact( FACT_MARIA_ESCORTED_AT_LEATHER_SHOP, MARIA ) == TRUE )
|
|
{
|
|
// she was rescued! yay!
|
|
TriggerNPCRecord( ANGEL, 12 );
|
|
}
|
|
}
|
|
else if ( ( CheckFact( FACT_ANGEL_LEFT_DEED, ANGEL ) == TRUE ) && ( CheckFact( FACT_ANGEL_MENTIONED_DEED, ANGEL ) == FALSE ) )
|
|
{
|
|
CancelAIAction( pSoldier, TRUE );
|
|
pSoldier->sAbsoluteFinalDestination = NOWHERE;
|
|
pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection );
|
|
TriggerNPCRecord( ANGEL, 20 );
|
|
// trigger Angel to walk off afterwards
|
|
//TriggerNPCRecord( ANGEL, 24 );
|
|
}
|
|
break;
|
|
//case QUEEN:
|
|
#ifdef JA2UB
|
|
//Ja25
|
|
//No Queen,Joe, or elliot
|
|
#else
|
|
case JOE:
|
|
case ELLIOT:
|
|
if ( ! ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) )
|
|
{
|
|
if ( !AreInMeanwhile() )
|
|
{
|
|
TriggerNPCRecord( pSoldier->ubProfile, 4 );
|
|
gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch( pSoldier->ubProfile )
|
|
{
|
|
case IGGY:
|
|
if ( ! ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) )
|
|
{
|
|
TriggerNPCRecord( pSoldier->ubProfile, 9 );
|
|
gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE;
|
|
gbPublicOpplist[ gbPlayerNum ][ pSoldier->ubID ] = HEARD_THIS_TURN;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// 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 )
|
|
{
|
|
if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] >= CIV_GROUP_WILL_BECOME_HOSTILE && pSoldier->aiData.bNeutral )
|
|
{
|
|
AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
|
|
}
|
|
else if ( pSoldier->ubCivilianGroup == KINGPIN_CIV_GROUP )
|
|
{
|
|
// generic kingpin goon...
|
|
|
|
// check to see if we are looking at Maria or unauthorized personnel in the brothel
|
|
if (pOpponent->ubProfile == MARIA)
|
|
{
|
|
MakeCivHostile( pSoldier, 2 );
|
|
if ( ! (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
EnterCombatMode( pSoldier->bTeam );
|
|
}
|
|
SetFactTrue( FACT_MARIA_ESCAPE_NOTICED );
|
|
}
|
|
else
|
|
{
|
|
//DBrot: More Rooms
|
|
//UINT8 ubRoom;
|
|
UINT16 usRoom;
|
|
|
|
// JA2 Gold: only go hostile if see player IN guard room
|
|
//if ( InARoom( pOpponent->sGridNo, &ubRoom ) && IN_BROTHEL( ubRoom ) && ( gMercProfiles[ MADAME ].bNPCData == 0 || IN_BROTHEL_GUARD_ROOM( ubRoom ) ) )
|
|
if ( InARoom( pOpponent->sGridNo, &usRoom ) && IN_BROTHEL_GUARD_ROOM( usRoom ) )
|
|
{
|
|
// unauthorized!
|
|
MakeCivHostile( pSoldier, 2 );
|
|
if ( ! (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
EnterCombatMode( pSoldier->bTeam );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( pSoldier->ubCivilianGroup == HICKS_CIV_GROUP && CheckFact( FACT_HICKS_MARRIED_PLAYER_MERC, 0 ) == FALSE )
|
|
{
|
|
UINT32 uiTime;
|
|
INT16 sX, sY;
|
|
|
|
// if before 6:05 or after 22:00, make hostile and enter combat
|
|
uiTime = GetWorldMinutesInDay();
|
|
if ( uiTime < 365 || uiTime > 1320 )
|
|
{
|
|
// get off our farm!
|
|
MakeCivHostile( pSoldier, 2 );
|
|
if ( ! (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
EnterCombatMode( pSoldier->bTeam );
|
|
|
|
LocateSoldier( pSoldier->ubID, TRUE );
|
|
GetSoldierScreenPos( pSoldier, &sX, &sY );
|
|
// begin quote
|
|
BeginCivQuote( pSoldier, CIV_QUOTE_HICKS_SEE_US_AT_NIGHT, 0, sX, sY );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( pSoldier->bTeam == gbPlayerNum )
|
|
{
|
|
#ifdef JA2UB
|
|
if( (pOpponent->ubProfile == MORRIS_UB ) &&
|
|
( GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( NULL, NULL ) != 0 ) &&
|
|
!( pSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_EXT_MORRIS ) &&
|
|
!( gMercProfiles[ MORRIS_UB ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) )
|
|
{
|
|
gfMorrisShouldSayHi = TRUE;
|
|
}
|
|
#else
|
|
if ( (pOpponent->ubProfile == MIKE) && ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC || pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__MERC ) && !(pSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_EXT_MIKE) )
|
|
{
|
|
if (gfMikeShouldSayHi == FALSE)
|
|
{
|
|
gfMikeShouldSayHi = TRUE;
|
|
}
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_AIM_SEEN_MIKE );
|
|
pSoldier->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_EXT_MIKE;
|
|
}
|
|
#endif
|
|
else if ( pOpponent->ubProfile == JOEY && gfPlayerTeamSawJoey == FALSE )
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_SPOTTED_JOEY );
|
|
gfPlayerTeamSawJoey = TRUE;
|
|
}
|
|
}
|
|
|
|
// as soon as a bloodcat sees someone, it becomes hostile
|
|
// this is safe to do here because we haven't made this new person someone we've seen yet
|
|
// (so we are assured we won't count 'em twice for oppcnt purposes)
|
|
if ( pSoldier->ubBodyType == BLOODCAT )
|
|
{
|
|
if ( pSoldier->aiData.bNeutral )
|
|
{
|
|
MakeBloodcatsHostile();
|
|
/*
|
|
SetSoldierNonNeutral( pSoldier );
|
|
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
|
|
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
CheckForPotentialAddToBattleIncrement( pSoldier );
|
|
}
|
|
*/
|
|
|
|
//PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
|
PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, MIDVOLUME +10, 1, MIDDLEPAN );
|
|
}
|
|
else
|
|
{
|
|
if ( pSoldier->aiData.bOppCnt == 0 )
|
|
{
|
|
if ( Random( 2 ) == 0 )
|
|
{
|
|
//PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
|
PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, MIDVOLUME + 10, 1, MIDDLEPAN );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( pOpponent->ubBodyType == BLOODCAT && pOpponent->aiData.bNeutral)
|
|
{
|
|
// HEADROCK HAM 3.6: If bloodcats are set as affiliated with civilians, do not trigger hostilities.
|
|
if ( gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ 0 ].PlacementType != BLOODCAT_PLACEMENT_STATIC ||
|
|
gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ gGameOptions.ubDifficultyLevel - 1 ].ubFactionAffiliation == NON_CIV_GROUP ||
|
|
gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ gGameOptions.ubDifficultyLevel - 1 ].ubFactionAffiliation == QUEENS_CIV_GROUP )
|
|
{
|
|
MakeBloodcatsHostile();
|
|
}
|
|
/*
|
|
SetSoldierNonNeutral( pOpponent );
|
|
RecalculateOppCntsDueToNoLongerNeutral( pOpponent );
|
|
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
CheckForPotentialAddToBattleIncrement( pOpponent );
|
|
}
|
|
*/
|
|
}
|
|
|
|
// 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);
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "ManSeesMan: ID %d(%S) to ID %d NEW TO ME",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
|
|
#endif
|
|
// SANDRO - if this is an enemy guy, who was unaware of us till now, and the combat didn't started yet, throw "taunt" and indicator we have been seen
|
|
if ( pSoldier->aiData.bOppList[pOpponent->ubID] <= NOT_HEARD_OR_SEEN && pSoldier->aiData.bAlertStatus != STATUS_RED && pSoldier->aiData.bAlertStatus != STATUS_BLACK )
|
|
{
|
|
PossiblyStartEnemyTaunt( pSoldier, TAUNT_NOTICED_UNSEEN, pOpponent );
|
|
}
|
|
// anv: we're already in fight, but we still can say hi to new enemy
|
|
else if ( pSoldier->aiData.bOppList[pOpponent->ubID] <= NOT_HEARD_OR_SEEN )
|
|
{
|
|
PossiblyStartEnemyTaunt( pSoldier, TAUNT_SAY_HI, pOpponent );
|
|
}
|
|
|
|
ShowRadioLocator( pSoldier->ubID, 1 );
|
|
|
|
|
|
// if we also haven't seen him earlier this turn
|
|
if (pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_THIS_TURN)
|
|
{
|
|
fNewOpponent = TRUE;
|
|
pSoldier->bNewOppCnt++; // increment looker's NEW opponent count
|
|
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Soldier %d sees soldier %d!", pSoldier->ubID, pOpponent->ubID );
|
|
|
|
//ExtMen[ptr->guynum].lastCaller = caller;
|
|
//ExtMen[ptr->guynum].lastCaller2 = caller2;
|
|
|
|
IncrementWatchedLoc( pSoldier->ubID, pOpponent->sGridNo, pOpponent->pathing.bLevel );
|
|
|
|
if ( pSoldier->bTeam == OUR_TEAM && pOpponent->bTeam == ENEMY_TEAM )
|
|
{
|
|
if ( CheckFact( FACT_FIRST_BATTLE_FOUGHT, 0 ) == FALSE )
|
|
{
|
|
SetFactTrue( FACT_FIRST_BATTLE_BEING_FOUGHT );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetWatchedLocAsUsed( pSoldier->ubID, pOpponent->sGridNo, pOpponent->pathing.bLevel );
|
|
}
|
|
|
|
// we already know the soldier isn't SEEN_CURRENTLY,
|
|
// now check if he is really "NEW" ie. not expected to be there
|
|
|
|
// if the looker hasn't seen this opponent at all earlier this turn, OR
|
|
// if the opponent is not where the looker last thought him to be
|
|
if ((pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_THIS_TURN) ||
|
|
(gsLastKnownOppLoc[pSoldier->ubID][pOpponent->ubID] != sOppGridNo))
|
|
{
|
|
SetNewSituation( pSoldier ); // force the looker to re-evaluate
|
|
// anv: simulate informing buddies about detected enemy's position
|
|
if(gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] != SEEN_CURRENTLY)
|
|
PossiblyStartEnemyTaunt( pSoldier, TAUNT_INFORM_ABOUT, pOpponent );
|
|
|
|
}
|
|
else
|
|
{
|
|
// if we in a non-combat movement decision, presumably this is not
|
|
// something we were quite expecting, so make a new decision. For
|
|
// other (combat) movement decisions, we took his position into account
|
|
// when we made it, so don't make us think again & slow things down.
|
|
switch (pSoldier->aiData.bAction)
|
|
{
|
|
case AI_ACTION_RANDOM_PATROL:
|
|
case AI_ACTION_SEEK_OPPONENT:
|
|
case AI_ACTION_SEEK_FRIEND:
|
|
case AI_ACTION_POINT_PATROL:
|
|
case AI_ACTION_LEAVE_WATER_GAS:
|
|
case AI_ACTION_SEEK_NOISE:
|
|
SetNewSituation( pSoldier ); // force the looker to re-evaluate
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
#ifdef TESTOPPLIST
|
|
else
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "ManSeesMan: ID %d(%S) to ID %d ALREADYSEENCURRENTLY",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
|
|
#endif
|
|
//bOldOppValue = pSoldier->aiData.bOppList[ pOpponent->ubID ];
|
|
// remember that the soldier is currently seen and his new location
|
|
UpdatePersonal(pSoldier,pOpponent->ubID,SEEN_CURRENTLY,sOppGridNo,bOppLevel);
|
|
|
|
if ( ubCaller2 == MANLOOKSFOROTHERTEAMS || ubCaller2 == OTHERTEAMSLOOKFORMAN || ubCaller2 == CALLER_UNKNOWN ) // unknown->hearing
|
|
{
|
|
|
|
if ( gubBestToMakeSightingSize != BEST_SIGHTING_ARRAY_SIZE_INCOMBAT && gTacticalStatus.bBoxingState == NOT_BOXING )
|
|
{
|
|
if ( fNewOpponent )
|
|
{
|
|
if ( gTacticalStatus.uiFlags & INCOMBAT )
|
|
{
|
|
// presumably a door opening... we do require standard interrupt conditions
|
|
if (StandardInterruptConditionsMet(pSoldier,pOpponent->ubID,bOldOppList))
|
|
{
|
|
ReevaluateBestSightingPosition( pSoldier, CalcInterruptDuelPts( pSoldier, pOpponent->ubID, TRUE ) );
|
|
}
|
|
}
|
|
// require the enemy not to be dying if we are the sighter; in other words,
|
|
// always add for AI guys, and always add for people with life >= OKLIFE
|
|
else if ( !(pSoldier->bTeam == gbPlayerNum && pOpponent->stats.bLife < OKLIFE ) )
|
|
{
|
|
ReevaluateBestSightingPosition( pSoldier, CalcInterruptDuelPts( pSoldier, pOpponent->ubID, TRUE ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if this man has never seen this opponent before in this sector
|
|
if (gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] == FALSE)
|
|
// remember that he is just seeing him now for the first time (-1)
|
|
gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] = -1;
|
|
else
|
|
// man is seeing an opponent AGAIN whom he has seen at least once before
|
|
gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] = TRUE;
|
|
|
|
//ddd{
|
|
BOOLEAN SEE_MENT = FALSE;
|
|
|
|
if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
|
|
{
|
|
if ( ( PTR_OURTEAM || (pSoldier->bTeam == MILITIA_TEAM) ) && (pOpponent->bVisible <= 0))
|
|
SEE_MENT = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (PTR_OURTEAM && (pOpponent->bVisible <= 0))
|
|
SEE_MENT = TRUE;
|
|
}
|
|
|
|
#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
|
|
//haydent
|
|
if((is_networked && pSoldier->bSide == 0 && pSoldier->bTeam != OUR_TEAM) && (pOpponent->bVisible <= 0))
|
|
SEE_MENT = TRUE;
|
|
#endif
|
|
|
|
//ddd}
|
|
|
|
/*comm by ddd
|
|
// if looker is on local team, and the enemy was invisible or "maybe"
|
|
// visible just prior to this
|
|
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
if ( ( PTR_OURTEAM || (pSoldier->bTeam == MILITIA_TEAM) ) && (pOpponent->bVisible <= 0))
|
|
#else
|
|
if (PTR_OURTEAM && (pOpponent->bVisible <= 0))
|
|
#endif
|
|
*/
|
|
if(SEE_MENT)
|
|
{
|
|
// if opponent was truly invisible, not just turned off temporarily (FALSE)
|
|
if (pOpponent->bVisible == -1)
|
|
{
|
|
// then locate to him and set his locator flag
|
|
bDoLocate = TRUE;
|
|
|
|
//rain
|
|
if( gfLightningInProgress ) gfHaveSeenSomeone = TRUE;
|
|
//end rain
|
|
}
|
|
|
|
// make opponent visible (to us)
|
|
// must do this BEFORE the locate since it checks for visibility
|
|
pOpponent->bVisible = TRUE;
|
|
|
|
//ATE: Cancel any fading going on!
|
|
// ATE: Added for fade in.....
|
|
if ( pOpponent->flags.fBeginFade == 1 || pOpponent->flags.fBeginFade == 2 )
|
|
{
|
|
pOpponent->flags.fBeginFade = FALSE;
|
|
|
|
if ( pOpponent->pathing.bLevel > 0 && gpWorldLevelData[ pOpponent->sGridNo ].pRoofHead != NULL )
|
|
{
|
|
pOpponent->ubFadeLevel = gpWorldLevelData[ pOpponent->sGridNo ].pRoofHead->ubShadeLevel;
|
|
}
|
|
else
|
|
{
|
|
pOpponent->ubFadeLevel = gpWorldLevelData[ pOpponent->sGridNo ].pLandHead->ubShadeLevel;
|
|
}
|
|
|
|
// Set levelnode shade level....
|
|
if ( pOpponent->pLevelNode )
|
|
{
|
|
pOpponent->pLevelNode->ubShadeLevel = pOpponent->ubFadeLevel;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("!!! ID %d (%S) MAKING %d VISIBLE",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
|
|
#endif
|
|
|
|
// update variable for STATUS screen
|
|
//pOpponent->bLastKnownLife = pOpponent->life;
|
|
|
|
if (bDoLocate)
|
|
{
|
|
|
|
// Change his anim speed!
|
|
SetSoldierAniSpeed( pOpponent );
|
|
|
|
// if show enemies is ON, then we must have already revealed these roofs
|
|
// and we're also following his movements, so don't bother sliding
|
|
if (!gbShowEnemies)
|
|
{
|
|
//DoSoldierRoofs(pOpponent);
|
|
|
|
// slide to the newly seen opponent, and if appropriate, start his locator
|
|
//SlideToMe = oppPtr->guynum;
|
|
}
|
|
|
|
//LastOpponentLocatedTo = oppPtr->guynum;
|
|
|
|
/*
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\tManSeesMan - LOCATE\n");
|
|
#endif
|
|
*/
|
|
|
|
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && ( ( gTacticalStatus.uiFlags & INCOMBAT ) | gTacticalStatus.fVirginSector ) )
|
|
{
|
|
if (!pOpponent->aiData.bNeutral && (pSoldier->bSide != pOpponent->bSide))
|
|
{
|
|
//SlideTo(0,pOpponent->ubID, pSoldier->ubID, SETLOCATOR);
|
|
//rain
|
|
SlideTo(0,pOpponent->ubID, pSoldier->ubID, SETLOCATORFAST);
|
|
//end rain
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
else if (!PTR_OURTEAM)
|
|
{
|
|
// ATE: Check stance, change to threatending
|
|
ReevaluateEnemyStance( pSoldier, pSoldier->usAnimState );
|
|
}
|
|
AI::tactical::AIInputData ai_input(AI::tactical::AIInputData::Visual(), pOpponent, sOppGridNo, bOppLevel, ubCaller, ubCaller2);
|
|
AI::tactical::PlanInputData plan_input((gTacticalStatus.uiFlags & TURNBASED)!=0, gTacticalStatus);
|
|
AI::tactical::PlanFactoryLibrary* plan_lib(AI::tactical::PlanFactoryLibrary::instance());
|
|
plan_lib->update_plan(pSoldier->bAIIndex, pSoldier, ai_input);
|
|
}
|
|
|
|
|
|
void DecideTrueVisibility(SOLDIERTYPE *pSoldier, UINT8 ubLocate)
|
|
{
|
|
// if his visibility is still in the special "limbo" state (FALSE)
|
|
if (pSoldier->bVisible == FALSE)
|
|
{
|
|
// then none of our team's merc turned him visible,
|
|
// therefore he now becomes truly invisible
|
|
pSoldier->bVisible = -1;
|
|
|
|
// Don;t adjust anim speed here, it's done once fade is over!
|
|
}
|
|
|
|
|
|
// If soldier is not visible, make sure his red "locator" is turned off
|
|
//if ((pSoldier->bVisible < 0) && !gbShowEnemies)
|
|
// pSoldier->bLocator = FALSE;
|
|
|
|
|
|
if (ubLocate)
|
|
{
|
|
// if he remains visible (or ShowEnemies ON)
|
|
if ((pSoldier->bVisible >= 0) || gbShowEnemies)
|
|
{
|
|
/*
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\tDecideTrueVisibility - LOCATE\n");
|
|
#endif
|
|
*/
|
|
|
|
if (PTR_OURTEAM)
|
|
{
|
|
//if (ConfigOptions[FOLLOWMODE] && Status.stopSlidingAt == NOBODY)
|
|
// LocateMember(ptr->guynum,DONTSETLOCATOR);
|
|
}
|
|
else // not our team - if we're NOT allied then locate...
|
|
//if (pSoldier->side != gTacticalStatus.Team[gbPlayerNum].side && ConfigOptions[FOLLOWMODE])
|
|
//if (Status.stopSlidingAt == NOBODY)
|
|
if (gTacticalStatus.uiFlags & TURNBASED && ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
//LocateSoldier(pSoldier->ubID,DONTSETLOCATOR);
|
|
SlideTo(0,pSoldier->ubID, NOBODY, DONTSETLOCATOR);
|
|
|
|
// follow his movement on our screen as he moves around...
|
|
//LocateMember(ptr->guynum,DONTSETLOCATOR);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OtherTeamsLookForMan(SOLDIERTYPE *pOpponent)
|
|
{
|
|
UINT32 uiLoop;
|
|
INT8 bOldOppList;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
|
|
//NumMessage("OtherTeamsLookForMan, guy#",oppPtr->guynum);
|
|
|
|
/* comm by ddd
|
|
// if the guy we're looking for is NOT on our team AND is currently visible
|
|
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
if ((pOpponent->bTeam != gbPlayerNum && pOpponent->bTeam != MILITIA_TEAM) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife)
|
|
#else
|
|
if ((pOpponent->bTeam != gbPlayerNum) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife)
|
|
#endif
|
|
{
|
|
// assume he's no longer visible, until one of our mercs sees him again
|
|
pOpponent->bVisible = 0;
|
|
}
|
|
*/
|
|
|
|
|
|
#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
|
|
//haydent
|
|
if(is_networked && pOpponent->bSide == 0)
|
|
{
|
|
//stay visible
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
|
|
if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
|
|
{
|
|
if ((pOpponent->bTeam != gbPlayerNum && pOpponent->bTeam != MILITIA_TEAM) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife)
|
|
pOpponent->bVisible = 0;
|
|
}
|
|
else
|
|
{
|
|
if ((pOpponent->bTeam != gbPlayerNum) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife)
|
|
pOpponent->bVisible = 0;
|
|
}
|
|
|
|
}//haydent
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("OTHERTEAMSLOOKFORMAN ID %d(%S) team %d side %d",pOpponent->ubID,pOpponent->name,pOpponent->bTeam,pOpponent->bSide ));
|
|
#endif
|
|
|
|
|
|
// all soldiers not on oppPtr's team now look for him
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
// if this merc is active, in this sector, and well enough to look
|
|
if (pSoldier != NULL && pSoldier->stats.bLife >= OKLIFE && (pSoldier->ubBodyType != LARVAE_MONSTER))
|
|
{
|
|
// if this merc is on the same team as the target soldier
|
|
if (pSoldier->bTeam == pOpponent->bTeam)
|
|
{
|
|
continue; // he doesn't look (he ALWAYS knows about him)
|
|
}
|
|
|
|
bOldOppList = pSoldier->aiData.bOppList[pOpponent->ubID];
|
|
|
|
// this merc looks for the soldier in question
|
|
// use both sides actual x,y co-ordinates (neither side's moving)
|
|
if (ManLooksForMan(pSoldier,pOpponent,OTHERTEAMSLOOKFORMAN))
|
|
{
|
|
// if a new opponent is seen (which must be oppPtr himself)
|
|
//if ((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && pSoldier->bNewOppCnt)
|
|
// Calc interrupt points in non-combat because we might get an interrupt or be interrupted
|
|
// on our first turn
|
|
|
|
// if doing regular in-combat sighting (not on opening doors!)
|
|
if ( gubBestToMakeSightingSize == BEST_SIGHTING_ARRAY_SIZE_INCOMBAT )
|
|
{
|
|
if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && pSoldier->bNewOppCnt )
|
|
{
|
|
// as long as viewer meets minimum interrupt conditions
|
|
if ( gubSightFlags & SIGHT_INTERRUPT && StandardInterruptConditionsMet(pSoldier,pOpponent->ubID,bOldOppList))
|
|
{
|
|
// calculate the interrupt duel points
|
|
pSoldier->aiData.bInterruptDuelPts = CalcInterruptDuelPts(pSoldier, pOpponent->ubID, TRUE);
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Calculating int duel pts in OtherTeamsLookForMan, %d has %d points", pSoldier->ubID, pSoldier->aiData.bInterruptDuelPts ) );
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if "Show only enemies seen" option is ON and it's this guy looking
|
|
//if (ptr->guynum == ShowOnlySeenPerson)
|
|
//NewShowOnlySeenPerson(ptr); // update the string
|
|
}
|
|
}
|
|
|
|
|
|
// if he's not on our team
|
|
if (pOpponent->bTeam != gbPlayerNum)
|
|
{
|
|
// don't do a locate here, it's already done by Man Sees Man for new opps.
|
|
DecideTrueVisibility(pOpponent,NOLOCATE);
|
|
}
|
|
}
|
|
|
|
void AddOneOpponent(SOLDIERTYPE *pSoldier)
|
|
{
|
|
INT8 bOldOppCnt = pSoldier->aiData.bOppCnt;
|
|
|
|
pSoldier->aiData.bOppCnt++;
|
|
|
|
if (!bOldOppCnt)
|
|
{
|
|
// if we hadn't known about opponents being here for sure prior to this
|
|
if (pSoldier->ubBodyType == LARVAE_MONSTER)
|
|
{
|
|
// never become aware of you!
|
|
return;
|
|
}
|
|
|
|
if (pSoldier->aiData.bAlertStatus < STATUS_RED)
|
|
{
|
|
CheckForChangingOrders(pSoldier);
|
|
}
|
|
|
|
pSoldier->aiData.bAlertStatus = STATUS_BLACK; // force black AI status right away
|
|
|
|
if (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER)
|
|
{
|
|
pSoldier->aiData.ubCaller = NOBODY;
|
|
pSoldier->aiData.bCallPriority = 0;
|
|
}
|
|
}
|
|
|
|
if (pSoldier->bTeam == gbPlayerNum)
|
|
{
|
|
// adding an opponent for player; reset # of turns that we haven't seen an enemy
|
|
gTacticalStatus.bConsNumTurnsNotSeen = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveOneOpponent(SOLDIERTYPE *pSoldier)
|
|
{
|
|
pSoldier->aiData.bOppCnt--;
|
|
|
|
if ( pSoldier->aiData.bOppCnt < 0 )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Oppcnt for %d (%s) tried to go below 0", pSoldier->ubID, pSoldier->name ) );
|
|
#ifdef JA2BETAVERSION
|
|
ScreenMsg( MSG_FONT_YELLOW, MSG_UI_FEEDBACK, L"Opponent counter dropped below 0 for person %d (%s). Please inform Sir-tech of this, and what has just been happening in the game.", pSoldier->ubID, pSoldier->name );
|
|
#endif
|
|
pSoldier->aiData.bOppCnt = 0;
|
|
}
|
|
|
|
// if no opponents remain in sight, drop status to RED (but NOT newSit.!)
|
|
if (!pSoldier->aiData.bOppCnt)
|
|
pSoldier->aiData.bAlertStatus = STATUS_RED;
|
|
}
|
|
|
|
|
|
|
|
|
|
void RemoveManAsTarget(SOLDIERTYPE *pSoldier)
|
|
{
|
|
|
|
SOLDIERTYPE *pOpponent;
|
|
UINT8 ubTarget,ubLoop;
|
|
|
|
|
|
ubTarget = pSoldier->ubID;
|
|
|
|
// clean up the public opponent lists and locations
|
|
for (ubLoop = 0; ubLoop < MAXTEAMS; ubLoop++)
|
|
// never causes any additional looks
|
|
UpdatePublic(ubLoop,ubTarget,NOT_HEARD_OR_SEEN,NOWHERE,0);
|
|
|
|
/*
|
|
|
|
|
|
IAN COMMENTED THIS OUT MAY 1997 - DO WE NEED THIS?
|
|
|
|
// make sure this guy is no longer a possible target for anyone
|
|
for (cnt = 0, pOpponent = Menptr; cnt < MAXMERCS; cnt++,pOpponent++)
|
|
{
|
|
if (pOpponent->bOppNum == ubTarget)
|
|
pOpponent->bOppNum = NOBODY;
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
// clean up all opponent's opplists
|
|
for (ubLoop = 0; ubLoop < guiNumMercSlots; ubLoop++)
|
|
{
|
|
pOpponent = MercSlots[ ubLoop ];
|
|
|
|
// if the target is active, a true opponent and currently seen by this merc
|
|
if (pOpponent)
|
|
{
|
|
// check to see if OPPONENT considers US neutral
|
|
if ( (pOpponent->aiData.bOppList[ubTarget] == SEEN_CURRENTLY) && !pOpponent->aiData.bNeutral && (pSoldier->bSide != pOpponent->bSide) )
|
|
{
|
|
// Flugente: we consider enemies to be neutral if they are prisoners of war (otherwise the AI would kill prisoners). Bu as we want to remove them, we have to account for that
|
|
// we also move RecognizeAsCombatant to be the last condition checked, because it is the most computationally expensive one
|
|
if ( ( !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) || pSoldier->bSoldierFlagMask & SOLDIER_POW ) && pOpponent->RecognizeAsCombatant(pSoldier->ubID) )
|
|
RemoveOneOpponent(pOpponent);
|
|
}
|
|
UpdatePersonal(pOpponent,ubTarget,NOT_HEARD_OR_SEEN,NOWHERE,0);
|
|
gbSeenOpponents[ubLoop][ubTarget] = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
for (ubLoop = 0,pOpponent = Menptr; ubLoop < MAXMERCS; ubLoop++,pOpponent++)
|
|
{
|
|
// if the target is a true opponent and currently seen by this merc
|
|
if (!pSoldier->aiData.bNeutral && !pSoldier->aiData.bNeutral &&
|
|
(pOpponent->aiData.bOppList[ubTarget] == SEEN_CURRENTLY)
|
|
|
|
)
|
|
///*** UNTIL ANDREW GETS THE SIDE PARAMETERS WORKING
|
|
// && (pSoldier->side != pOpponent->side))
|
|
{
|
|
RemoveOneOpponent(pOpponent);
|
|
}
|
|
|
|
UpdatePersonal(pOpponent,ubTarget,NOT_HEARD_OR_SEEN,NOWHERE,0);
|
|
|
|
gbSeenOpponents[ubLoop][ubTarget] = FALSE;
|
|
}
|
|
*/
|
|
|
|
ResetLastKnownLocs(pSoldier);
|
|
|
|
if (gTacticalStatus.Team[pSoldier->bTeam].ubLastMercToRadio == ubTarget)
|
|
gTacticalStatus.Team[pSoldier->bTeam].ubLastMercToRadio = NOBODY;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UpdatePublic(UINT8 ubTeam, UINT8 ubID, INT8 bNewOpplist, INT32 sGridNo, INT8 bLevel)
|
|
{
|
|
INT32 cnt;
|
|
INT8 *pbPublOL;
|
|
UINT8 ubTeamMustLookAgain = FALSE, ubMadeDifference = FALSE;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
|
|
pbPublOL = &(gbPublicOpplist[ubTeam][ubID]);
|
|
|
|
// if new opplist is more up-to-date, or we are just wiping it for some reason
|
|
if ((gubKnowledgeValue[*pbPublOL - OLDEST_HEARD_VALUE][bNewOpplist - OLDEST_HEARD_VALUE] > 0) ||
|
|
(bNewOpplist == NOT_HEARD_OR_SEEN))
|
|
{
|
|
// if this team is becoming aware of a soldier it wasn't previously aware of
|
|
if ((bNewOpplist != NOT_HEARD_OR_SEEN) && (*pbPublOL == NOT_HEARD_OR_SEEN))
|
|
ubTeamMustLookAgain = TRUE;
|
|
|
|
// change the public opplist *BEFORE* anyone looks again or we'll recurse!
|
|
*pbPublOL = bNewOpplist;
|
|
}
|
|
|
|
|
|
// always update the gridno, no matter what
|
|
gsPublicLastKnownOppLoc[ubTeam][ubID] = sGridNo;
|
|
gbPublicLastKnownOppLevel[ubTeam][ubID] = bLevel;
|
|
|
|
// if team has been told about a guy the team was completely unaware of
|
|
if (ubTeamMustLookAgain)
|
|
{
|
|
// then everyone on team who's not aware of guynum must look for him
|
|
cnt = gTacticalStatus.Team[ubTeam].bFirstID;
|
|
|
|
for (pSoldier = MercPtrs[cnt]; cnt <= gTacticalStatus.Team[ubTeam].bLastID; ++cnt, pSoldier++)
|
|
{
|
|
// if this soldier is active, in this sector, and well enough to look
|
|
if (pSoldier->bActive && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE) && !( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) )
|
|
{
|
|
// if soldier isn't aware of guynum, give him another chance to see
|
|
if (pSoldier->aiData.bOppList[ubID] == NOT_HEARD_OR_SEEN)
|
|
{
|
|
if (ManLooksForMan(pSoldier,MercPtrs[ubID],UPDATEPUBLIC))
|
|
// then he actually saw guynum because of our new public knowledge
|
|
ubMadeDifference = TRUE;
|
|
|
|
// whether successful or not, whack newOppCnt. Since this is a
|
|
// delayed reaction to a radio call, there's no chance of interrupt!
|
|
pSoldier->bNewOppCnt = 0;
|
|
|
|
// if "Show only enemies seen" option is ON and it's this guy looking
|
|
//if (pSoldier->ubID == ShowOnlySeenPerson)
|
|
// NewShowOnlySeenPerson(pSoldier); // update the string
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void UpdatePersonal(SOLDIERTYPE *pSoldier, UINT8 ubID, INT8 bNewOpplist, INT32 sGridNo, INT8 bLevel)
|
|
{
|
|
/*
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"UpdatePersonal - for %d about %d to %d (was %d) at g%d\n", ptr->guynum,guynum,newOpplist,ptr->opplist[guynum],gridno);
|
|
#endif
|
|
*/
|
|
|
|
// if new opplist is more up-to-date, or we are just wiping it for some reason
|
|
if ((gubKnowledgeValue[pSoldier->aiData.bOppList[ubID] - OLDEST_HEARD_VALUE][bNewOpplist - OLDEST_HEARD_VALUE] > 0) || (bNewOpplist == NOT_HEARD_OR_SEEN))
|
|
{
|
|
pSoldier->aiData.bOppList[ubID] = bNewOpplist;
|
|
}
|
|
|
|
// always update the gridno, no matter what
|
|
gsLastKnownOppLoc[pSoldier->ubID][ubID] = sGridNo;
|
|
gbLastKnownOppLevel[pSoldier->ubID][ubID] = bLevel;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
INT8 OurMaxPublicOpplist()
|
|
{
|
|
UINT32 uiLoop;
|
|
INT8 bHighestOpplist = 0;
|
|
UINT8 ubOppValue,ubHighestValue = 0;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
// if this merc is inactive, at base, on assignment, or dead
|
|
if (!pSoldier || !pSoldier->stats.bLife)
|
|
continue; // next merc
|
|
|
|
// if this man is NEUTRAL / on our side, he's not an opponent
|
|
if (pSoldier->aiData.bNeutral || (gTacticalStatus.Team[gbPlayerNum].bSide == Menptr[pSoldier->ubID].bSide))
|
|
continue; // next merc
|
|
|
|
// opponent, check our public opplist value for him
|
|
ubOppValue = gubKnowledgeValue[0 - OLDEST_HEARD_VALUE][gbPublicOpplist[gbPlayerNum][pSoldier->ubID] - OLDEST_HEARD_VALUE];
|
|
|
|
if (ubOppValue > ubHighestValue)
|
|
{
|
|
ubHighestValue = ubOppValue;
|
|
bHighestOpplist = gbPublicOpplist[gbPlayerNum][pSoldier->ubID];
|
|
}
|
|
}
|
|
|
|
return(bHighestOpplist);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
BOOLEAN VisibleAnywhere(SOLDIERTYPE *pSoldier)
|
|
{
|
|
INT8 team,cnt;
|
|
SOLDIERTYPE *pOpponent;
|
|
|
|
|
|
// this takes care of any mercs on our own team
|
|
if (pSoldier->bVisible >= 0)
|
|
return(TRUE);
|
|
|
|
// if playing alone, "anywhere" is just over here!
|
|
//if (!Net.multiType || Net.activePlayers < 2)
|
|
//return(FALSE);
|
|
|
|
|
|
for (bTeam = 0; bTeam < MAXTEAMS; bTeam++)
|
|
{
|
|
// skip our team (local visible flag will do for them)
|
|
if (bTeam == gbPlayerNum)
|
|
continue;
|
|
|
|
// skip any inactive teams
|
|
if (!gTacticalStatus.team[bTeam].teamActive)
|
|
continue;
|
|
|
|
// skip non-human teams (they don't communicate for their machines!)
|
|
if (!gTacticalStatus.Team[bTeam].human)
|
|
continue;
|
|
|
|
// so we're left with another human player's team of mercs...
|
|
|
|
// check if soldier is currently visible to any human mercs on other teams
|
|
for (cnt = Status.team[team].guystart,oppPtr = Menptr + cnt; cnt < Status.team[team].guyend; cnt++,oppPtr++)
|
|
{
|
|
// if this merc is inactive, or in no condition to care
|
|
if (!oppPtr->active || !oppPtr->in_sector || oppPtr->deadAndRemoved || (oppPtr->life < OKLIFE))
|
|
continue; // skip him!
|
|
|
|
if (oppPtr->opplist[ptr->guynum] == SEEN_CURRENTLY)
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
// nobody anywhere sees him
|
|
return(FALSE);
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
void ResetLastKnownLocs(SOLDIERTYPE *pSoldier)
|
|
{
|
|
UINT32 uiLoop;
|
|
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
if (MercSlots[uiLoop])
|
|
{
|
|
gsLastKnownOppLoc[pSoldier->ubID][MercSlots[uiLoop]->ubID] = NOWHERE;
|
|
|
|
// IAN added this June 14/97
|
|
gsPublicLastKnownOppLoc[pSoldier->bTeam][MercSlots[uiLoop]->ubID] = NOWHERE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
// INITIALIZATION STUFF
|
|
-------------------------
|
|
// Upon loading a scenario, call these:
|
|
InitOpponentKnowledgeSystem();
|
|
|
|
// loop through all soldiers and for each soldier call
|
|
InitSoldierOpplist(pSoldier);
|
|
|
|
// call this once
|
|
AllTeamsLookForAll(NO_INTERRUPTS); // no interrupts permitted this early
|
|
|
|
|
|
// for each additional soldier created, call
|
|
InitSoldierOpplist(pSoldier);
|
|
HandleSight(pSoldier,SIGHT_LOOK);
|
|
|
|
|
|
|
|
MOVEMENT STUFF
|
|
-----------------
|
|
// whenever new tile is reached, call
|
|
HandleSight(pSoldier,SIGHT_LOOK);
|
|
|
|
*/
|
|
|
|
void InitOpponentKnowledgeSystem(void)
|
|
{
|
|
INT32 iTeam, cnt, cnt2;
|
|
|
|
memset(gbSeenOpponents,0,sizeof(gbSeenOpponents));
|
|
memset(gbPublicOpplist,NOT_HEARD_OR_SEEN,sizeof(gbPublicOpplist));
|
|
|
|
for (iTeam=0; iTeam < MAXTEAMS; iTeam++)
|
|
{
|
|
gubPublicNoiseVolume[iTeam] = 0;
|
|
gsPublicNoiseGridNo[iTeam] = NOWHERE;
|
|
gbPublicNoiseLevel[iTeam] = 0;
|
|
for (cnt = 0; cnt < MAX_NUM_SOLDIERS; cnt++)
|
|
{
|
|
gsPublicLastKnownOppLoc[ iTeam ][ cnt ] = NOWHERE;
|
|
}
|
|
}
|
|
|
|
// initialize public last known locations for all teams
|
|
for (cnt = 0; cnt < MAX_NUM_SOLDIERS; cnt++)
|
|
{
|
|
for (cnt2 = 0; cnt2 < NUM_WATCHED_LOCS; cnt2++ )
|
|
{
|
|
gsWatchedLoc[ cnt ][ cnt2 ] = NOWHERE;
|
|
gubWatchedLocPoints[ cnt ][ cnt2 ] = 0;
|
|
gfWatchedLocReset[ cnt ][ cnt2 ] = FALSE;
|
|
}
|
|
}
|
|
|
|
for ( cnt = 0; cnt < SHOULD_BECOME_HOSTILE_SIZE; cnt++ )
|
|
{
|
|
gubShouldBecomeHostileOrSayQuote[ cnt ] = NOBODY;
|
|
}
|
|
|
|
gubNumShouldBecomeHostileOrSayQuote = 0;
|
|
}
|
|
|
|
|
|
|
|
void InitSoldierOppList(SOLDIERTYPE *pSoldier)
|
|
{
|
|
memset(pSoldier->aiData.bOppList,NOT_HEARD_OR_SEEN,sizeof(pSoldier->aiData.bOppList));
|
|
pSoldier->aiData.bOppCnt = 0;
|
|
ResetLastKnownLocs(pSoldier);
|
|
memset(gbSeenOpponents[pSoldier->ubID],0,MAXMERCS);
|
|
}
|
|
|
|
|
|
void BetweenTurnsVisibilityAdjustments(void)
|
|
{
|
|
INT32 cnt;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
|
|
// make all soldiers on other teams that are no longer seen not visible
|
|
for (cnt = 0, pSoldier = Menptr; cnt < MAXMERCS; cnt++,pSoldier++)
|
|
{
|
|
if (pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife)
|
|
{
|
|
BOOLEAN SEE_MENT = FALSE;
|
|
|
|
#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
|
|
if(is_networked && pSoldier->bSide == 0)//haydent
|
|
{
|
|
//stay visible
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
|
|
if (gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
|
|
{if (!PTR_OURTEAM && pSoldier->bTeam != MILITIA_TEAM)
|
|
SEE_MENT = TRUE;
|
|
}
|
|
else
|
|
{ if (!PTR_OURTEAM) SEE_MENT = TRUE;
|
|
}
|
|
|
|
}//haydent
|
|
|
|
/*comm by ddd
|
|
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
|
|
if (!PTR_OURTEAM && pSoldier->bTeam != MILITIA_TEAM)
|
|
#else
|
|
if (!PTR_OURTEAM)
|
|
#endif
|
|
*/
|
|
|
|
if(SEE_MENT)
|
|
{
|
|
// check if anyone on our team currently sees him (exclude NOBODY)
|
|
if (TeamNoLongerSeesMan(gbPlayerNum,pSoldier,NOBODY,0))
|
|
{
|
|
// then our team has lost sight of him
|
|
pSoldier->bVisible = -1; // make him fully invisible
|
|
|
|
// Allow fade to adjust anim speed
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SaySeenQuote( SOLDIERTYPE *pSoldier, BOOLEAN fSeenCreature, BOOLEAN fVirginSector, BOOLEAN fSeenJoey )
|
|
{
|
|
SOLDIERTYPE *pTeamSoldier;
|
|
UINT8 ubNumEnemies = 0;
|
|
UINT8 ubNumAllies = 0;
|
|
UINT32 cnt;
|
|
#ifdef JA2UB
|
|
//Ja25 No meanwhiles
|
|
#else
|
|
if ( AreInMeanwhile( ) )
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
// Check out for our under large fire quote
|
|
if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_IN_SHIT ) )
|
|
{
|
|
// Get total enemies.
|
|
// Loop through all mercs in sector and count # of enemies
|
|
for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
|
|
{
|
|
pTeamSoldier = MercSlots[ cnt ];
|
|
|
|
if ( pTeamSoldier != NULL )
|
|
{
|
|
if ( OK_ENEMY_MERC( pTeamSoldier ) )
|
|
{
|
|
ubNumEnemies++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OK, after this, check our guys
|
|
for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
|
|
{
|
|
pTeamSoldier = MercSlots[ cnt ];
|
|
|
|
if ( pTeamSoldier != NULL )
|
|
{
|
|
if ( !OK_ENEMY_MERC( pTeamSoldier ) )
|
|
{
|
|
if ( pTeamSoldier->aiData.bOppCnt >= ( ubNumEnemies / 2 ) )
|
|
{
|
|
ubNumAllies++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// now check!
|
|
if ( ( pSoldier->aiData.bOppCnt - ubNumAllies ) > 2 )
|
|
{
|
|
// Say quote!
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_IN_TROUBLE_SLASH_IN_BATTLE );
|
|
//pSoldier->ubLastEnemyAttackingProvokingQuote =
|
|
pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_IN_SHIT;
|
|
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ( fSeenCreature == 1 )
|
|
{
|
|
|
|
// Is this our first time seeing them?
|
|
if ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags & PROFILE_MISC_FLAG_HAVESEENCREATURE )
|
|
{
|
|
// Are there multiplaes and we have not said this quote during this battle?
|
|
if ( !( pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_MULTIPLE_CREATURES ) )
|
|
{
|
|
// Check for multiples!
|
|
ubNumEnemies = 0;
|
|
|
|
// Get total enemies.
|
|
// Loop through all mercs in sector and count # of enemies
|
|
for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
|
|
{
|
|
pTeamSoldier = MercSlots[ cnt ];
|
|
|
|
if ( pTeamSoldier != NULL )
|
|
{
|
|
if ( OK_ENEMY_MERC( pTeamSoldier ) )
|
|
{
|
|
if ( pTeamSoldier->flags.uiStatusFlags & SOLDIER_MONSTER && pSoldier->aiData.bOppList[ pTeamSoldier->ubID ] == SEEN_CURRENTLY )
|
|
{
|
|
ubNumEnemies++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ubNumEnemies > 2 )
|
|
{
|
|
// Yes, set flag
|
|
pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_MULTIPLE_CREATURES;
|
|
|
|
// Say quote
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_ATTACKED_BY_MULTIPLE_CREATURES );
|
|
}
|
|
else
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_CREATURE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_CREATURE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Yes, set flag
|
|
gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_HAVESEENCREATURE;
|
|
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_FIRSTTIME_GAME_SEE_CREATURE );
|
|
}
|
|
}
|
|
// 2 is for bloodcat...
|
|
else if ( fSeenCreature == 2 )
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_SPOTTED_BLOODCAT );
|
|
}
|
|
else
|
|
{
|
|
if ( fVirginSector )
|
|
{
|
|
// First time we've seen a guy this sector
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY_VARIATION );
|
|
}
|
|
else
|
|
{
|
|
// Flugente: no quotes on seeing enemy when covert
|
|
if ( (pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) ) == 0 )
|
|
{
|
|
#ifdef ENGLISH
|
|
if ( Random( 100 ) < 30 )
|
|
{
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_ENEMY );
|
|
}
|
|
else
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
|
//pSoldier->ubLastEnemyDetectedProvokingQuote = pSoldier->aiData.ubCaller;
|
|
}
|
|
#else
|
|
//ddd TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
|
if(Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) )
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void OurTeamSeesSomeone( SOLDIERTYPE * pSoldier, INT8 bNumReRevealed, INT8 bNumNewEnemies )
|
|
{
|
|
if ( gTacticalStatus.fVirginSector )
|
|
{
|
|
// If we are in NPC dialogue now... stop!
|
|
DeleteTalkingMenu( );
|
|
|
|
// Say quote!
|
|
SaySeenQuote( pSoldier, gfPlayerTeamSawCreatures, TRUE, gfPlayerTeamSawJoey );
|
|
|
|
pSoldier->HaultSoldierFromSighting( TRUE );
|
|
|
|
// Set virgin sector to false....
|
|
gTacticalStatus.fVirginSector = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// if this merc is selected and he's actually moving
|
|
//if ((pSoldier->ubID == gusSelectedSoldier) && !pSoldier->pathing.bLevel)
|
|
// ATE: Change this to if the guy is ours....
|
|
// How will this feel?
|
|
if ( pSoldier->bTeam == gbPlayerNum )
|
|
{
|
|
// Flugente: disguised mercs do not alert us if they see an enemy, as otherwise one has to continously give them new orders
|
|
if ( !(pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) )
|
|
{
|
|
// STOP IF WE WERE MOVING....
|
|
/// Speek up!
|
|
if ( bNumReRevealed > 0 && bNumNewEnemies == 0 )
|
|
{
|
|
pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
|
|
}
|
|
else
|
|
{
|
|
SaySeenQuote( pSoldier, gfPlayerTeamSawCreatures, FALSE, gfPlayerTeamSawJoey );
|
|
}
|
|
|
|
pSoldier->HaultSoldierFromSighting( TRUE );
|
|
|
|
if ( gTacticalStatus.fEnemySightingOnTheirTurn )
|
|
{
|
|
// Locate to our guy, then slide to enemy
|
|
LocateSoldier( pSoldier->ubID, SETLOCATOR );
|
|
|
|
// Now slide to other guy....
|
|
SlideTo( NOWHERE, gTacticalStatus.ubEnemySightingOnTheirTurnEnemyID, NOBODY ,SETLOCATOR);
|
|
|
|
}
|
|
|
|
// Unset User's turn UI
|
|
UnSetUIBusy( pSoldier->ubID );
|
|
}
|
|
}
|
|
}
|
|
|
|
// OK, check what music mode we are in, change to battle if we're in battle
|
|
// If we are in combat....
|
|
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
// If we are NOT in any music mode...
|
|
if ( GetMusicMode() == MUSIC_NONE )
|
|
{
|
|
#ifdef NEWMUSIC
|
|
GlobalSoundID = MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalBattle[gbWorldSectorZ];
|
|
if ( MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalBattle[gbWorldSectorZ] != -1 )
|
|
SetMusicModeID( MUSIC_TACTICAL_BATTLE, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalBattle[gbWorldSectorZ] );
|
|
else
|
|
#endif
|
|
SetMusicMode( MUSIC_TACTICAL_BATTLE );
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void RadioSightings(SOLDIERTYPE *pSoldier, UINT8 ubAbout, UINT8 ubTeamToRadioTo )
|
|
{
|
|
SOLDIERTYPE *pOpponent;
|
|
INT32 iLoop;
|
|
UINT8 start,end,revealedEnemies = 0,unknownEnemies = 0,stillUnseen=TRUE;
|
|
UINT8 scrollToGuynum = NOBODY,sightedHatedOpponent = FALSE;
|
|
//UINT8 oppIsCivilian;
|
|
INT8 *pPersOL,*pbPublOL; //,dayQuote;
|
|
BOOLEAN fContactSeen;
|
|
BOOLEAN fSawCreatureForFirstTime = FALSE;
|
|
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("RADIO SIGHTINGS: for %d about %d",pSoldier->ubID,ubAbout) );
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef RECORDNET
|
|
if (!ptr->human)
|
|
fprintf(NetDebugFile,"\tNPC %d(%s) radios his sightings to his team\n",ptr->guynum,ExtMen[ptr->guynum].name);
|
|
#endif
|
|
|
|
gTacticalStatus.Team[pSoldier->bTeam].ubLastMercToRadio = pSoldier->ubID;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// who are we radioing about?
|
|
if (ubAbout == EVERYBODY)
|
|
{
|
|
start = 0;
|
|
end = MAXMERCS;
|
|
}
|
|
else
|
|
{
|
|
start = ubAbout;
|
|
end = ubAbout + 1;
|
|
}
|
|
|
|
|
|
// hang a pointer to the start of our this guy's personal opplist
|
|
pPersOL = &(pSoldier->aiData.bOppList[start]);
|
|
|
|
// hang a pointer to the start of this guy's opponents in the public opplist
|
|
pbPublOL = &(gbPublicOpplist[ubTeamToRadioTo][start]);
|
|
|
|
pOpponent = MercPtrs[start];
|
|
|
|
// loop through every one of this guy's opponents
|
|
for (iLoop = start; iLoop < end; ++iLoop,pOpponent++,pPersOL++,pbPublOL++)
|
|
{
|
|
fContactSeen = FALSE;
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("RS: checking %d",pOpponent->ubID) );
|
|
#endif
|
|
|
|
|
|
// make sure this merc is active, here & still alive (unconscious OK)
|
|
if (!pOpponent->bActive || !pOpponent->bInSector || !pOpponent->stats.bLife)
|
|
{
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("RS: inactive/notInSector/life %d",pOpponent->ubID) );
|
|
#endif
|
|
|
|
|
|
continue; // skip to the next merc
|
|
}
|
|
|
|
// if these two mercs are on the same SIDE, then they're NOT opponents
|
|
// NEW: Apr. 21 '96: must allow ALL non-humans to get radioed about
|
|
if ((pSoldier->bSide == pOpponent->bSide) && (pOpponent->flags.uiStatusFlags & SOLDIER_PC))
|
|
{
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("RS: same side %d",pSoldier->bSide) );
|
|
#endif
|
|
|
|
continue; // skip to the next merc
|
|
}
|
|
|
|
// determine whether we think we're still unseen or if "our cover's blown"
|
|
// if we know about this opponent's location for any reason
|
|
if ((pOpponent->bVisible >= 0) || gbShowEnemies)
|
|
{
|
|
// and he can see us, then gotta figure we KNOW that he can see us
|
|
if (pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY)
|
|
stillUnseen = FALSE;
|
|
}
|
|
|
|
|
|
// if we personally don't know a thing about this opponent
|
|
if (*pPersOL == NOT_HEARD_OR_SEEN)
|
|
{
|
|
#ifdef RECORDOPPLIST
|
|
//fprintf(OpplistFile,"not heard or seen\n");
|
|
#endif
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("RS: not heard or seen") );
|
|
#endif
|
|
|
|
continue; // skip to the next opponent
|
|
}
|
|
|
|
// if personal knowledge is NOT more up to date and NOT the same as public
|
|
if ((!gubKnowledgeValue[*pbPublOL - OLDEST_HEARD_VALUE][*pPersOL - OLDEST_HEARD_VALUE]) &&
|
|
(*pbPublOL != *pPersOL))
|
|
{
|
|
#ifdef RECORDOPPLIST
|
|
//fprintf(OpplistFile,"no new knowledge (per %d, pub %d)\n",*pPersOL,*pbPublOL);
|
|
#endif
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("RS: no new knowledge per %d pub %d",*pPersOL,*pbPublOL) );
|
|
#endif
|
|
|
|
|
|
|
|
continue; // skip to the next opponent
|
|
}
|
|
|
|
#ifdef RECORDOPPLIST
|
|
//fprintf(OpplistFile,"made it!\n");
|
|
#endif
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("RS: made it!") );
|
|
#endif
|
|
|
|
|
|
|
|
// if it's our merc, and he currently sees this opponent
|
|
if (PTR_OURTEAM && (*pPersOL == SEEN_CURRENTLY) && !(( pOpponent->bSide == pSoldier->bSide) || pOpponent->aiData.bNeutral))
|
|
{
|
|
// used by QueueDayMessage() to scroll to one of the new enemies
|
|
// scroll to the last guy seen, unless we see a hated guy, then use him!
|
|
if (!sightedHatedOpponent)
|
|
scrollToGuynum = pOpponent->ubID;
|
|
|
|
// don't care whether and how many new enemies are seen if everyone visible
|
|
// and he's healthy enough to be a threat (so is worth talking about)
|
|
|
|
// do the following if we're radioing to our own team; if radioing to militia
|
|
// then alert them instead
|
|
if ( ubTeamToRadioTo != MILITIA_TEAM )
|
|
{
|
|
if (!gbShowEnemies && (pOpponent->stats.bLife >= OKLIFE))
|
|
{
|
|
// if this enemy has not been publicly seen or heard recently
|
|
if (*pbPublOL == NOT_HEARD_OR_SEEN)
|
|
{
|
|
// chalk up another "unknown" enemy
|
|
unknownEnemies++;
|
|
|
|
fContactSeen = TRUE;
|
|
// if this enemy is hated by the merc doing the sighting
|
|
//if (MercHated(Proptr[ptr->characternum].p_bias,oppPtr->characternum))
|
|
//sightedHatedOpponent = TRUE;
|
|
|
|
// now the important part: does this enemy see him/her back?
|
|
if (pOpponent->aiData.bOppList[pSoldier->ubID] != SEEN_CURRENTLY)
|
|
{
|
|
// EXPERIENCE GAIN (10): Discovered a new enemy without being seen
|
|
StatChange(pSoldier,EXPERAMT,10,FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// if he has publicly not been seen now, or anytime during this turn
|
|
if ((*pbPublOL != SEEN_CURRENTLY) && (*pbPublOL != SEEN_THIS_TURN))
|
|
{
|
|
// chalk up another "revealed" enemy
|
|
++revealedEnemies;
|
|
fContactSeen = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if ( MercPtrs[0]->stats.bLife < 10 )
|
|
{
|
|
//int breakpoint = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fContactSeen )
|
|
{
|
|
if ( pSoldier->bTeam == gbPlayerNum )
|
|
{
|
|
if ( gTacticalStatus.ubCurrentTeam != gbPlayerNum )
|
|
{
|
|
// Save some stuff!
|
|
if (gTacticalStatus.fEnemySightingOnTheirTurn)
|
|
{
|
|
// this has already come up so turn OFF the pause-all-anims flag for the previous
|
|
// person and set it for this next person
|
|
MercPtrs[gTacticalStatus.ubEnemySightingOnTheirTurnEnemyID]->flags.fPauseAllAnimation = FALSE;
|
|
}
|
|
else
|
|
{
|
|
gTacticalStatus.fEnemySightingOnTheirTurn = TRUE;
|
|
}
|
|
gTacticalStatus.ubEnemySightingOnTheirTurnEnemyID = pOpponent->ubID;
|
|
gTacticalStatus.ubEnemySightingOnTheirTurnPlayerID = pSoldier->ubID;
|
|
gTacticalStatus.uiTimeSinceDemoOn = GetJA2Clock( );
|
|
|
|
pOpponent->flags.fPauseAllAnimation = TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
if ( pOpponent->flags.uiStatusFlags & SOLDIER_MONSTER )
|
|
{
|
|
gfPlayerTeamSawCreatures = TRUE;
|
|
}
|
|
|
|
// ATE: Added for bloodcat...
|
|
if ( pOpponent->ubBodyType == BLOODCAT )
|
|
{
|
|
// 2 is for bloodcat
|
|
gfPlayerTeamSawCreatures = 2;
|
|
}
|
|
|
|
}
|
|
|
|
if ( pOpponent->flags.uiStatusFlags & SOLDIER_MONSTER )
|
|
{
|
|
if ( !(gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags & PROFILE_MISC_FLAG_HAVESEENCREATURE) )
|
|
{
|
|
fSawCreatureForFirstTime = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// radioing to militia that we saw someone! alert them!
|
|
if ( gTacticalStatus.Team[ MILITIA_TEAM ].bTeamActive && !gTacticalStatus.Team[ MILITIA_TEAM ].bAwareOfOpposition )
|
|
{
|
|
HandleInitialRedAlert( MILITIA_TEAM, FALSE );
|
|
}
|
|
}
|
|
} // end of our team's merc sees new opponent
|
|
|
|
// IF WE'RE HERE, OUR PERSONAL INFORMATION IS AT LEAST AS UP-TO-DATE
|
|
// AS THE PUBLIC KNOWLEDGE, SO WE WILL REPLACE THE PUBLIC KNOWLEDGE
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"UpdatePublic (RadioSightings) for team %d about %d\n",ptr->team,oppPtr->guynum);
|
|
#endif
|
|
|
|
|
|
#ifdef TESTOPPLIST
|
|
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
|
|
String("...............UPDATE PUBLIC: soldier %d SEEING soldier %d",pSoldier->ubID,pOpponent->ubID) );
|
|
#endif
|
|
|
|
|
|
|
|
UpdatePublic(ubTeamToRadioTo,pOpponent->ubID,*pPersOL,gsLastKnownOppLoc[pSoldier->ubID][pOpponent->ubID],gbLastKnownOppLevel[pSoldier->ubID][pOpponent->ubID]);
|
|
}
|
|
|
|
|
|
// if soldier heard a misc noise more important that his team's public one
|
|
if (pSoldier->aiData.ubNoiseVolume > gubPublicNoiseVolume[ubTeamToRadioTo])
|
|
{
|
|
// replace the soldier's team's public noise with his
|
|
gsPublicNoiseGridNo[ubTeamToRadioTo] = pSoldier->aiData.sNoiseGridno;
|
|
gbPublicNoiseLevel[ubTeamToRadioTo] = pSoldier->bNoiseLevel;
|
|
gubPublicNoiseVolume[ubTeamToRadioTo] = pSoldier->aiData.ubNoiseVolume;
|
|
}
|
|
|
|
|
|
// if this soldier is on the local team
|
|
if (PTR_OURTEAM)
|
|
{
|
|
// don't trigger sighting quotes or stop merc's movement if everyone visible
|
|
//if (!(gTacticalStatus.uiFlags & SHOW_ALL_MERCS))
|
|
{
|
|
// if we've revealed any enemies, or seen any previously unknown enemies
|
|
if (revealedEnemies || unknownEnemies)
|
|
{
|
|
// First check for a virgin map and set to false if we see our first guy....
|
|
// Only if this guy is an ememy!
|
|
|
|
OurTeamSeesSomeone( pSoldier, revealedEnemies, unknownEnemies );
|
|
}
|
|
else if (fSawCreatureForFirstTime)
|
|
{
|
|
gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_HAVESEENCREATURE;
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_FIRSTTIME_GAME_SEE_CREATURE );
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#define COLOR1 FONT_MCOLOR_BLACK<<8 | FONT_MCOLOR_LTGREEN
|
|
#define COLOR2 FONT_MCOLOR_BLACK<<8 | FONT_MCOLOR_LTGRAY2
|
|
|
|
#define LINE_HEIGHT 15
|
|
|
|
|
|
extern UINT32 guiNumBackSaves;
|
|
|
|
void DebugSoldierPage1( )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
UINT16 usSoldierIndex;
|
|
UINT32 uiMercFlags;
|
|
INT32 usMapPos;
|
|
UINT8 ubLine=0;
|
|
|
|
if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) )
|
|
{
|
|
// Get Soldier
|
|
GetSoldier( &pSoldier, usSoldierIndex );
|
|
|
|
SetFont( LARGEFONT1 );
|
|
gprintf( 0,0,L"DEBUG SOLDIER PAGE ONE, GRIDNO %d", pSoldier->sGridNo );
|
|
SetFont( LARGEFONT1 );
|
|
|
|
ubLine = 2;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"ID:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubID );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"TEAM:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bTeam );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SIDE:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bSide );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"STATUS FLAGS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%x", pSoldier->flags.uiStatusFlags );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"HUMAN:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gTacticalStatus.Team[pSoldier->bTeam].bHuman);
|
|
ubLine++;
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"APs:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bActionPoints );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Breath:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bBreath );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Life:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bLife );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"LifeMax:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bLifeMax );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Bleeding:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bBleeding );
|
|
|
|
ubLine = 2;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Agility:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bAgility, EffectiveAgility( pSoldier, FALSE ) );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Dexterity:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d( %d )", pSoldier->stats.bDexterity, EffectiveDexterity( pSoldier, FALSE ) );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Strength:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bStrength );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Wisdom:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bWisdom, EffectiveWisdom( pSoldier ) );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Exp Lvl:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bExpLevel, EffectiveExpLevel( pSoldier ) );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Mrksmnship:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bMarksmanship, EffectiveMarksmanship( pSoldier ) );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Mechanical:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bMechanical);
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Explosive:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bExplosive);
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Medical:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bMedical);
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Drug Effects:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->drugs.bDrugEffect[0] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Drug Side Effects:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->drugs.bDrugSideEffect[0] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Booze Effects:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->drugs.bDrugEffect[1] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"Hangover Side Effects:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->drugs.bDrugSideEffect[1] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"AI has Keys:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.bHasKeys );
|
|
ubLine++;
|
|
}
|
|
else if ( GetMouseMapPos( &usMapPos ) )
|
|
{
|
|
SetFont( LARGEFONT1 );
|
|
gprintf( 0,0,L"DEBUG LAND PAGE ONE" );
|
|
SetFont( LARGEFONT1 );
|
|
|
|
ubLine++;
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Num dirty rects:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 200, LINE_HEIGHT * ubLine, L"%d", guiNumBackSaves );
|
|
ubLine++;
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void DebugSoldierPage2( )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
UINT16 usSoldierIndex;
|
|
UINT32 uiMercFlags;
|
|
INT32 usMapPos;
|
|
TILE_ELEMENT TileElem;
|
|
LEVELNODE *pNode;
|
|
UINT8 ubLine;
|
|
|
|
if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) )
|
|
{
|
|
// Get Soldier
|
|
GetSoldier( &pSoldier, usSoldierIndex );
|
|
|
|
SetFont( LARGEFONT1 );
|
|
gprintf( 0,0,L"DEBUG SOLDIER PAGE TWO, GRIDNO %d", pSoldier->sGridNo );
|
|
SetFont( LARGEFONT1 );
|
|
|
|
ubLine = 2;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"ID:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubID );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Body Type:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubBodyType );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Opp Cnt:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->aiData.bOppCnt);
|
|
ubLine++;
|
|
|
|
if (pSoldier->bTeam == OUR_TEAM || pSoldier->bTeam == MILITIA_TEAM) // look at 8 to 15 opplist entries
|
|
{
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Opplist B:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d %d %d %d %d %d %d %d", pSoldier->aiData.bOppList[20],pSoldier->aiData.bOppList[21],pSoldier->aiData.bOppList[22],
|
|
pSoldier->aiData.bOppList[23],pSoldier->aiData.bOppList[24],pSoldier->aiData.bOppList[25],pSoldier->aiData.bOppList[26],pSoldier->aiData.bOppList[27]);
|
|
ubLine++;
|
|
}
|
|
else // team 1 - enemies so look at first 8 (0-7) opplist entries
|
|
{
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"OppList A:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d %d %d %d %d %d %d %d", pSoldier->aiData.bOppList[0],pSoldier->aiData.bOppList[1],pSoldier->aiData.bOppList[2],
|
|
pSoldier->aiData.bOppList[3],pSoldier->aiData.bOppList[4],pSoldier->aiData.bOppList[5],pSoldier->aiData.bOppList[6],
|
|
pSoldier->aiData.bOppList[7]);
|
|
ubLine++;
|
|
}
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Visible:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bVisible);
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Direction:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gzDirectionStr[ pSoldier->ubDirection] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"DesDirection:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gzDirectionStr[ pSoldier->pathing.bDesiredDirection] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"GridNo:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->sGridNo );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Dest:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->pathing.sFinalDestination );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Path Size:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->pathing.usPathDataSize);
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Path Index:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->pathing.usPathIndex );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"First 3 Steps:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d %d %d", pSoldier->pathing.usPathingData[0],
|
|
pSoldier->pathing.usPathingData[1],
|
|
pSoldier->pathing.usPathingData[2] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Next 3 Steps:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d %d %d", pSoldier->pathing.usPathingData[pSoldier->pathing.usPathIndex],
|
|
pSoldier->pathing.usPathingData[pSoldier->pathing.usPathIndex + 1],
|
|
pSoldier->pathing.usPathingData[pSoldier->pathing.usPathIndex + 2] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"FlashInd:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fFlashLocator );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"ShowInd:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fShowLocator );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Main hand:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HANDPOS].usItem] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Second hand:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SECONDHANDPOS].usItem] );
|
|
ubLine++;
|
|
|
|
if ( GetMouseMapPos( &usMapPos ) )
|
|
{
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"CurrGridNo:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", usMapPos );
|
|
ubLine++;
|
|
}
|
|
|
|
}
|
|
else if ( GetMouseMapPos( &usMapPos ) )
|
|
{
|
|
SetFont( LARGEFONT1 );
|
|
gprintf( 0,0,L"DEBUG LAND PAGE TWO" );
|
|
SetFont( LARGEFONT1 );
|
|
|
|
ubLine = 1;
|
|
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Land Raised:");
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"%d", gpWorldLevelData[ usMapPos ].sHeight );
|
|
ubLine++;
|
|
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Land Node:");
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"%x", gpWorldLevelData[ usMapPos ].pLandHead );
|
|
ubLine++;
|
|
|
|
if ( gpWorldLevelData[ usMapPos ].pLandHead != NULL )
|
|
{
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Land Node:");
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"%d", gpWorldLevelData[ usMapPos ].pLandHead->usIndex );
|
|
ubLine++;
|
|
|
|
TileElem = gTileDatabase[ gpWorldLevelData[ usMapPos ].pLandHead->usIndex ];
|
|
|
|
// Check for full tile
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Full Land:");
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"%d", TileElem.ubFullTile );
|
|
ubLine++;
|
|
}
|
|
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Land St Node:");
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"%x", gpWorldLevelData[ usMapPos ].pLandStart );
|
|
ubLine++;
|
|
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"GRIDNO:");
|
|
SetFontColors(COLOR2);
|
|
//dnl ch85 060214
|
|
INT16 sX, sY;
|
|
ConvertGridNoToXY(usMapPos, &sX, &sY);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"%d (%d,%d)", usMapPos, sX, sY );
|
|
ubLine++;
|
|
|
|
if ( gpWorldLevelData[ usMapPos ].uiFlags & MAPELEMENT_MOVEMENT_RESERVED )
|
|
{
|
|
SetFontColors(COLOR2);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Merc: %d", gpWorldLevelData[ usMapPos ].ubReservedSoldierID );
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"RESERVED MOVEMENT FLAG ON:" );
|
|
ubLine++;
|
|
}
|
|
|
|
|
|
pNode = GetCurInteractiveTile( );
|
|
|
|
if ( pNode != NULL )
|
|
{
|
|
SetFontColors(COLOR2);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Tile: %d", pNode->usIndex );
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"ON INT TILE" );
|
|
ubLine++;
|
|
}
|
|
|
|
|
|
if ( gpWorldLevelData[ usMapPos ].uiFlags & MAPELEMENT_REVEALED )
|
|
{
|
|
SetFontColors(COLOR2);
|
|
//mprintf( 0, LINE_HEIGHT * 9, L"Merc: %d", gpWorldLevelData[ sMapPos ].ubReservedSoldierID );
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"REVEALED" );
|
|
ubLine++;
|
|
}
|
|
|
|
if ( gpWorldLevelData[ usMapPos ].uiFlags & MAPELEMENT_RAISE_LAND_START )
|
|
{
|
|
SetFontColors(COLOR2);
|
|
//mprintf( 0, LINE_HEIGHT * 9, L"Merc: %d", gpWorldLevelData[ sMapPos ].ubReservedSoldierID );
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"Land Raise Start" );
|
|
ubLine++;
|
|
}
|
|
|
|
if ( gpWorldLevelData[ usMapPos ].uiFlags & MAPELEMENT_RAISE_LAND_END )
|
|
{
|
|
SetFontColors(COLOR2);
|
|
//mprintf( 0, LINE_HEIGHT * 9, L"Merc: %d", gpWorldLevelData[ usMapPos ].ubReservedSoldierID );
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"Raise Land End" );
|
|
ubLine++;
|
|
}
|
|
|
|
if (gusWorldRoomInfo[ usMapPos ] != NO_ROOM )
|
|
{
|
|
SetFontColors(COLOR2);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Room Number" );
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L"%d", gusWorldRoomInfo[ usMapPos ] );
|
|
ubLine++;
|
|
}
|
|
|
|
if ( gpWorldLevelData[ usMapPos ].ubExtFlags[0] & MAPELEMENT_EXT_NOBURN_STRUCT )
|
|
{
|
|
SetFontColors(COLOR2);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Don't Use Burn Through For Soldier" );
|
|
ubLine++;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void DebugSoldierPage3( )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
UINT16 usSoldierIndex;
|
|
UINT32 uiMercFlags;
|
|
INT32 usMapPos;
|
|
UINT8 ubLine;
|
|
|
|
if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) )
|
|
{
|
|
// Get Soldier
|
|
GetSoldier( &pSoldier, usSoldierIndex );
|
|
|
|
SetFont( LARGEFONT1 );
|
|
gprintf( 0,0,L"DEBUG SOLDIER PAGE THREE, GRIDNO %d", pSoldier->sGridNo );
|
|
SetFont( LARGEFONT1 );
|
|
|
|
ubLine = 2;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"ID:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubID );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Action:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gzActionStr[ pSoldier->aiData.bAction ] );
|
|
if (pSoldier->flags.uiStatusFlags & SOLDIER_ENEMY )
|
|
{
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"Alert %S", gzAlertStr[ pSoldier->aiData.bAlertStatus ] );
|
|
}
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Action Data:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->aiData.usActionData );
|
|
|
|
if (pSoldier->flags.uiStatusFlags & SOLDIER_ENEMY )
|
|
{
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"AIMorale %d", pSoldier->aiData.bAIMorale );
|
|
}
|
|
else
|
|
{
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"Morale %d", pSoldier->aiData.bMorale );
|
|
}
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Delayed Movement:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fDelayedMovement );
|
|
if ( gubWatchedLocPoints[ pSoldier->ubID ][ 0 ] > 0 )
|
|
{
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"Watch %d/%d for %d pts",
|
|
gsWatchedLoc[ pSoldier->ubID ][ 0 ],
|
|
gbWatchedLocLevel[ pSoldier->ubID ][ 0 ],
|
|
gubWatchedLocPoints[ pSoldier->ubID ][ 0 ]
|
|
);
|
|
}
|
|
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"ActionInProg:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->aiData.bActionInProgress);
|
|
ubLine++;
|
|
if ( gubWatchedLocPoints[ pSoldier->ubID ][ 1 ] > 0 )
|
|
{
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"Watch %d/%d for %d pts",
|
|
gsWatchedLoc[ pSoldier->ubID ][ 1 ],
|
|
gbWatchedLocLevel[ pSoldier->ubID ][ 1 ],
|
|
gubWatchedLocPoints[ pSoldier->ubID ][ 1 ]
|
|
);
|
|
}
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Last Action:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gzActionStr[ pSoldier->aiData.bLastAction ] );
|
|
ubLine++;
|
|
|
|
if ( gubWatchedLocPoints[ pSoldier->ubID ][ 2 ] > 0 )
|
|
{
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"Watch %d/%d for %d pts",
|
|
gsWatchedLoc[ pSoldier->ubID ][ 2 ],
|
|
gbWatchedLocLevel[ pSoldier->ubID ][ 2 ],
|
|
gubWatchedLocPoints[ pSoldier->ubID ][ 2 ]
|
|
);
|
|
}
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Animation:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gAnimControl[ pSoldier->usAnimState ].zAnimStr );
|
|
ubLine++;
|
|
|
|
/*
|
|
if ( gubWatchedLocPoints[ pSoldier->ubID ][ 3 ] > 0 )
|
|
{
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"Watch %d/%d for %d pts",
|
|
gsWatchedLoc[ pSoldier->ubID ][ 3 ],
|
|
gbWatchedLocLevel[ pSoldier->ubID ][ 3 ],
|
|
gubWatchedLocPoints[ pSoldier->ubID ][ 3 ]
|
|
);
|
|
}
|
|
*/
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Getting Hit:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fGettingHit );
|
|
|
|
if (pSoldier->ubCivilianGroup != 0)
|
|
{
|
|
gprintf( 350, LINE_HEIGHT * ubLine, L"Civ group %d", pSoldier->ubCivilianGroup );
|
|
}
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Suppress pts:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubSuppressionPoints );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Attacker ID:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubAttackerID );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"EndAINotCalled:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fTurnInProgress );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"PrevAnimation:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gAnimControl[ pSoldier->usOldAniState ].zAnimStr );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"PrevAniCode:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gusAnimInst[ pSoldier->usOldAniState ][ pSoldier->sOldAniCode ] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"GridNo:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->sGridNo);
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"AniCode:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gusAnimInst[ pSoldier->usAnimState ][ pSoldier->usAniCode ] );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"No APS To fin Move:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fNoAPToFinishMove );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Reload Delay:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->sReloadDelay );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Reloading:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fReloading );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Bullets out:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bBulletsLeft );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Anim non-int:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fInNonintAnim );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"RT Anim non-int:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fRTInNonintAnim );
|
|
ubLine++;
|
|
|
|
// OPIONION OF SELECTED MERC
|
|
//if ( gusSelectedSoldier != NOBODY && ( MercPtrs[ gusSelectedSoldier ]->ubProfile < FIRST_NPC ) && pSoldier->ubProfile != NO_PROFILE )
|
|
//new profiles by Jazz
|
|
if ( gusSelectedSoldier != NOBODY && ( gProfilesIMP[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesRPC[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesAIM[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesMERC[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile ) && pSoldier->ubProfile != NO_PROFILE )
|
|
{
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"NPC Opinion:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if (OKToCheckOpinion(MercPtrs[ gusSelectedSoldier ]->ubProfile))
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gMercProfiles[ pSoldier->ubProfile ].bMercOpinion[ MercPtrs[ gusSelectedSoldier ]->ubProfile ] );
|
|
ubLine++;
|
|
}
|
|
|
|
}
|
|
else if ( GetMouseMapPos( &usMapPos ) )
|
|
{
|
|
DOOR_STATUS *pDoorStatus;
|
|
STRUCTURE *pStructure;
|
|
|
|
SetFont( LARGEFONT1 );
|
|
gprintf( 0,0,L"DEBUG LAND PAGE THREE" );
|
|
SetFont( LARGEFONT1 );
|
|
|
|
// OK, display door information here.....
|
|
pDoorStatus = GetDoorStatus( usMapPos );
|
|
|
|
ubLine = 1;
|
|
|
|
if ( pDoorStatus == NULL )
|
|
{
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"No Door Status");
|
|
ubLine++;
|
|
ubLine++;
|
|
ubLine++;
|
|
}
|
|
else
|
|
{
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Door Status Found:");
|
|
SetFontColors(COLOR2);
|
|
mprintf( 150, LINE_HEIGHT * ubLine, L" %d", usMapPos );
|
|
ubLine++;
|
|
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Actual Status:");
|
|
SetFontColors(COLOR2);
|
|
|
|
if ( pDoorStatus->ubFlags & DOOR_OPEN )
|
|
{
|
|
mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" );
|
|
}
|
|
else
|
|
{
|
|
mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" );
|
|
}
|
|
ubLine++;
|
|
|
|
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"Perceived Status:");
|
|
SetFontColors(COLOR2);
|
|
|
|
if ( pDoorStatus->ubFlags & DOOR_PERCEIVED_NOTSET )
|
|
{
|
|
mprintf( 200, LINE_HEIGHT * ubLine, L"NOT SET" );
|
|
}
|
|
else
|
|
{
|
|
if ( pDoorStatus->ubFlags & DOOR_PERCEIVED_OPEN )
|
|
{
|
|
mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" );
|
|
}
|
|
else
|
|
{
|
|
mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" );
|
|
}
|
|
}
|
|
ubLine++;
|
|
}
|
|
|
|
//Find struct data and se what it says......
|
|
pStructure = FindStructure( usMapPos, STRUCTURE_ANYDOOR );
|
|
|
|
if ( pStructure == NULL )
|
|
{
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"No Door Struct Data");
|
|
ubLine++;
|
|
}
|
|
else
|
|
{
|
|
|
|
SetFontColors(COLOR1);
|
|
mprintf( 0, LINE_HEIGHT * ubLine, L"State:");
|
|
SetFontColors(COLOR2);
|
|
if ( !(pStructure->fFlags & STRUCTURE_OPEN) )
|
|
{
|
|
mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" );
|
|
}
|
|
else
|
|
{
|
|
mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" );
|
|
}
|
|
ubLine++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void AppendAttachmentCode( UINT16 usItem, STR16 str )
|
|
{
|
|
switch( usItem )
|
|
{
|
|
case SILENCER:
|
|
wcscat( str, L" Sil" );
|
|
break;
|
|
case SNIPERSCOPE:
|
|
wcscat( str, L" Scp" );
|
|
break;
|
|
case BIPOD:
|
|
wcscat( str, L" Bip" );
|
|
break;
|
|
case LASERSCOPE:
|
|
wcscat( str, L" Las" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void WriteQuantityAndAttachments( OBJECTTYPE *pObject, INT32 yp )
|
|
{
|
|
CHAR16 szAttach[30];
|
|
BOOLEAN fAttachments;
|
|
//100% Qty: 2 Attach:
|
|
//100% Qty: 2
|
|
//100% Attach:
|
|
//100%
|
|
if( pObject->exists() == false )
|
|
return;
|
|
//Build attachment string
|
|
fAttachments = FALSE;
|
|
if( (*pObject)[0]->AttachmentListSize() > 0 )
|
|
{
|
|
fAttachments = TRUE;
|
|
swprintf( szAttach, L"(" );
|
|
for (attachmentList::iterator iter = (*pObject)[0]->attachments.begin(); iter != (*pObject)[0]->attachments.end(); ++iter) {
|
|
if(iter->exists())
|
|
AppendAttachmentCode( iter->usItem, szAttach );
|
|
}
|
|
wcscat( szAttach, L" )" );
|
|
}
|
|
|
|
if( Item[pObject->usItem].usItemClass == IC_AMMO )
|
|
{ //ammo
|
|
if( pObject->ubNumberOfObjects > 1 )
|
|
{
|
|
CHAR16 str[100];
|
|
CHAR16 temp[10];
|
|
UINT8 i;
|
|
swprintf( str, L"Clips: %d (%d", pObject->ubNumberOfObjects, (*pObject)[0]->data.objectStatus );
|
|
for( i = 1; i < pObject->ubNumberOfObjects; i++ )
|
|
{
|
|
swprintf( temp, L", %d", (*pObject)[0]->data.objectStatus );
|
|
wcscat( str, temp );
|
|
}
|
|
wcscat( str, L")" );
|
|
gprintf( 320, yp, str );
|
|
}
|
|
else
|
|
gprintf( 320, yp, L"%d rounds", (*pObject)[0]->data.objectStatus );
|
|
return;
|
|
}
|
|
if( pObject->ubNumberOfObjects > 1 && fAttachments )
|
|
{ //everything
|
|
gprintf( 320, yp, L"%d%% Qty: %d %s",
|
|
(*pObject)[0]->data.objectStatus, pObject->ubNumberOfObjects, szAttach );
|
|
}
|
|
else if( pObject->ubNumberOfObjects > 1 )
|
|
{ //condition and quantity
|
|
gprintf( 320, yp, L"%d%% Qty: %d ",
|
|
(*pObject)[0]->data.objectStatus, pObject->ubNumberOfObjects );
|
|
}
|
|
else if( fAttachments )
|
|
{ //condition and attachments
|
|
gprintf( 320, yp, L"%d%% %s", (*pObject)[0]->data.objectStatus, szAttach );
|
|
}
|
|
else
|
|
{ //condition
|
|
gprintf( 320, yp, L"%d%%", (*pObject)[0]->data.objectStatus );
|
|
}
|
|
}
|
|
|
|
void DebugSoldierPage4( )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
UINT32 uiMercFlags;
|
|
CHAR16 szOrders[20];
|
|
CHAR16 szAttitude[20];
|
|
UINT16 usSoldierIndex;
|
|
UINT8 ubLine;
|
|
|
|
if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) )
|
|
{
|
|
// Get Soldier
|
|
GetSoldier( &pSoldier, usSoldierIndex );
|
|
|
|
SetFont( LARGEFONT1 );
|
|
gprintf( 0,0,L"DEBUG SOLDIER PAGE FOUR, GRIDNO %d", pSoldier->sGridNo );
|
|
SetFont( LARGEFONT1 );
|
|
ubLine = 2;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"Exp. Level:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bExpLevel, EffectiveExpLevel(pSoldier) ); // SANDRO - added effective level calc
|
|
switch( pSoldier->ubSoldierClass )
|
|
{
|
|
case SOLDIER_CLASS_ADMINISTRATOR: gprintf( 320, LINE_HEIGHT * ubLine, L"(Administrator)" ); break;
|
|
case SOLDIER_CLASS_ELITE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Elite)" ); break;
|
|
case SOLDIER_CLASS_ARMY: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Troop)" ); break;
|
|
case SOLDIER_CLASS_CREATURE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Creature)" ); break;
|
|
case SOLDIER_CLASS_GREEN_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Green Militia)" ); break;
|
|
case SOLDIER_CLASS_REG_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Reg Militia)" ); break;
|
|
case SOLDIER_CLASS_ELITE_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Elite Militia)" ); break;
|
|
case SOLDIER_CLASS_MINER: gprintf( 320, LINE_HEIGHT * ubLine, L"(Miner)" ); break;
|
|
|
|
#ifdef ENABLE_ZOMBIES
|
|
case SOLDIER_CLASS_ZOMBIE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" ); break;
|
|
#endif
|
|
|
|
default: break; //don't care (don't write anything)
|
|
}
|
|
ubLine++;
|
|
|
|
if( pSoldier->bTeam != OUR_TEAM )
|
|
{
|
|
SOLDIERINITNODE *pNode;
|
|
switch( pSoldier->aiData.bOrders )
|
|
{
|
|
case STATIONARY: swprintf( szOrders, L"STATIONARY" ); break;
|
|
case ONGUARD: swprintf( szOrders, L"ON GUARD" ); break;
|
|
case ONCALL: swprintf( szOrders, L"ON CALL" ); break;
|
|
case SEEKENEMY: swprintf( szOrders, L"SEEK ENEMY" ); break;
|
|
case CLOSEPATROL: swprintf( szOrders, L"CLOSE PATROL" ); break;
|
|
case FARPATROL: swprintf( szOrders, L"FAR PATROL" ); break;
|
|
case POINTPATROL: swprintf( szOrders, L"POINT PATROL" ); break;
|
|
case RNDPTPATROL: swprintf( szOrders, L"RND PT PATROL" ); break;
|
|
case SNIPER: swprintf( szOrders, L"SNIPER" ); break;
|
|
default: swprintf( szOrders, L"UNKNOWN" ); break;
|
|
}
|
|
switch( pSoldier->aiData.bAttitude )
|
|
{
|
|
case DEFENSIVE: swprintf( szAttitude, L"DEFENSIVE" ); break;
|
|
case BRAVESOLO: swprintf( szAttitude, L"BRAVE SOLO" ); break;
|
|
case BRAVEAID: swprintf( szAttitude, L"BRAVE AID" ); break;
|
|
case AGGRESSIVE: swprintf( szAttitude, L"AGGRESSIVE" ); break;
|
|
case CUNNINGSOLO: swprintf( szAttitude, L"CUNNING SOLO" ); break;
|
|
case CUNNINGAID: swprintf( szAttitude, L"CUNNING AID" ); break;
|
|
default: swprintf( szAttitude, L"UNKNOWN" ); break;
|
|
}
|
|
pNode = gSoldierInitHead;
|
|
while( pNode )
|
|
{
|
|
if( pNode->pSoldier == pSoldier )
|
|
break;
|
|
pNode = pNode->next;
|
|
}
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pNode )
|
|
{
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"%s, %s, REL EQUIP: %d, REL ATTR: %d",
|
|
szOrders, szAttitude, pNode->pBasicPlacement->bRelativeEquipmentLevel,
|
|
pNode->pBasicPlacement->bRelativeAttributeLevel );
|
|
}
|
|
else
|
|
{
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"%s, %s", szOrders, szAttitude );
|
|
}
|
|
ubLine++;
|
|
}
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"ID:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubID );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"HELMETPOS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[HELMETPOS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HELMETPOS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[HELMETPOS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"VESTPOS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[VESTPOS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[VESTPOS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[VESTPOS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"LEGPOS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[LEGPOS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[LEGPOS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[LEGPOS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"HEAD1POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[HEAD1POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HEAD1POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[HEAD1POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"HEAD2POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[HEAD2POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HEAD2POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[HEAD2POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"HANDPOS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[HANDPOS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HANDPOS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[HANDPOS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SECONDHANDPOS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SECONDHANDPOS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SECONDHANDPOS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SECONDHANDPOS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK1POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[BIGPOCK1POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK1POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK1POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK2POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[BIGPOCK2POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK2POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK2POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK3POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[BIGPOCK3POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK3POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK3POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK4POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[BIGPOCK4POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK4POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK4POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
// CHRISL: Added entries for all the new inventory pockets.
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK5POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[BIGPOCK5POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK5POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK5POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK6POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[BIGPOCK6POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK6POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK6POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK7POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[BIGPOCK7POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK7POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK7POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"MEDPOCK1POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[MEDPOCK1POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[MEDPOCK1POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[MEDPOCK1POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"MEDPOCK2POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[MEDPOCK2POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[MEDPOCK2POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[MEDPOCK2POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"MEDPOCK3POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[MEDPOCK3POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[MEDPOCK3POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[MEDPOCK3POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"MEDPOCK4POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[MEDPOCK4POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[MEDPOCK4POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[MEDPOCK4POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK1POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK1POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK1POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK1POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK2POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK2POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK2POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK2POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK3POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK3POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK3POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK3POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK4POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK4POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK4POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK4POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK5POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK5POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK5POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK5POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK6POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK6POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK6POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK6POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK7POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK7POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK7POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK7POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
// CHRISL: Added entries for all the new inventory pockets
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK8POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK8POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK8POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK8POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK9POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK9POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK9POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK9POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK10POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK10POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK10POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK10POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK11POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK11POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK11POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK11POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK12POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK12POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK12POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK12POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK13POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK13POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK13POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK13POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK14POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK14POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK14POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK14POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK15POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK15POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK15POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK15POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK16POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK16POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK16POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK16POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK17POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK17POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK17POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK17POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK18POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK18POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK18POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK18POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK19POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK19POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK19POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK19POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK20POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK20POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK20POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK20POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK21POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK21POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK21POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK21POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK22POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK22POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK22POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK22POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK23POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK23POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK23POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK23POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK24POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK24POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK24POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK24POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK25POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK25POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK25POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK25POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK26POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK26POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK26POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK26POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK27POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK27POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK27POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK27POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK28POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK28POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK28POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK28POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK29POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK29POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK29POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK29POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
|
|
gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK30POS:");
|
|
SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
|
|
if( pSoldier->inv[SMALLPOCK30POS].usItem )
|
|
gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK30POS].usItem] );
|
|
WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK30POS], LINE_HEIGHT*ubLine );
|
|
ubLine++;
|
|
}
|
|
else
|
|
{
|
|
SetFont( LARGEFONT1 );
|
|
gprintf( 0,0,L"DEBUG LAND PAGE FOUR" );
|
|
SetFont( LARGEFONT1 );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Noise stuff
|
|
//
|
|
|
|
#define MAX_MOVEMENT_NOISE 9
|
|
|
|
UINT8 MovementNoise( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT32 iStealthSkill, iRoll;
|
|
UINT8 ubMaxVolume, ubVolume, ubBandaged, ubEffLife;
|
|
INT8 bInWater = FALSE;
|
|
|
|
if ( pSoldier->bTeam == ENEMY_TEAM )
|
|
{
|
|
return( (UINT8) (MAX_MOVEMENT_NOISE - PreRandom( 2 )) );
|
|
}
|
|
|
|
// CHANGED BY SANDRO - LET'S MAKE THE STEALTH BASED ON AGILITY LIKE IT SHOULD BE
|
|
//iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveDexterity( pSoldier ) * 4) / 10); // 24-100
|
|
iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveAgility( pSoldier, FALSE ) * 4) / 10); // 24-100
|
|
|
|
// big bonus for those "extra stealthy" mercs
|
|
if ( pSoldier->ubBodyType == BLOODCAT )
|
|
{
|
|
iStealthSkill += 50;
|
|
}
|
|
// SANDRO - new/old traits
|
|
else if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT ))
|
|
{
|
|
iStealthSkill += gSkillTraitValues.ubSTBonusToMoveQuietly;
|
|
}
|
|
else if ( !gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_OT ))
|
|
{
|
|
iStealthSkill += 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY_OT );
|
|
}
|
|
|
|
INT16 wornstealth = GetWornStealth(pSoldier);
|
|
if ( wornstealth > 0 )
|
|
iStealthSkill += wornstealth / 2;
|
|
|
|
|
|
//NumMessage("Base Stealth = ",stealthSkill);
|
|
|
|
|
|
ubBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding;
|
|
ubEffLife = pSoldier->stats.bLife + (ubBandaged / 2);
|
|
|
|
// IF "SNEAKER'S" "EFFECTIVE LIFE" IS AT LESS THAN 50
|
|
if (ubEffLife < 50)
|
|
{
|
|
// reduce effective stealth skill by up to 50% for low life
|
|
iStealthSkill -= (iStealthSkill * (50 - ubEffLife)) / 100;
|
|
}
|
|
|
|
// if breath is below 50%
|
|
if (pSoldier->bBreath < 50)
|
|
{
|
|
// reduce effective stealth skill by up to 50%
|
|
iStealthSkill -= (iStealthSkill * (50 - pSoldier->bBreath)) / 100;
|
|
}
|
|
|
|
// if sneaker is moving through water
|
|
if (Water( pSoldier->sGridNo ) )
|
|
{
|
|
iStealthSkill -= 10; // 10% penalty
|
|
}
|
|
else if (DeepWater( pSoldier->sGridNo ) )
|
|
{
|
|
iStealthSkill -= 20; // 20% penalty
|
|
}
|
|
|
|
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ADRENALINE ] )
|
|
{
|
|
// minus 3 percent per bonus AP from adrenaline
|
|
iStealthSkill -= 3 * pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ADRENALINE ];
|
|
}
|
|
|
|
/*
|
|
// if sneaker is too eager and impatient to "do it right"
|
|
if ((pSoldier->bTrait == OVER_ENTHUS) || (pSoldier->aiData.bAttitude == AGGRESSIVE))
|
|
{
|
|
ubStealthSkill -= 10; // 10% penalty
|
|
}
|
|
*/
|
|
//NumMessage("Modified Stealth = ",stealthSkill);
|
|
|
|
iStealthSkill = __max( iStealthSkill, 0 );
|
|
|
|
if (!pSoldier->bStealthMode) // REGULAR movement
|
|
{
|
|
ubMaxVolume = MAX_MOVEMENT_NOISE - (iStealthSkill / 16); // 9 - (0 to 6) => 3 to 9
|
|
|
|
if (bInWater)
|
|
{
|
|
ubMaxVolume++; // in water, can be even louder
|
|
}
|
|
switch (pSoldier->usAnimState)
|
|
{
|
|
case CRAWLING:
|
|
ubMaxVolume -= 2;
|
|
break;
|
|
case SWATTING:
|
|
ubMaxVolume -= 1;
|
|
break;
|
|
case RUNNING:
|
|
ubMaxVolume += 3;
|
|
break;
|
|
}
|
|
|
|
if (ubMaxVolume < 2)
|
|
{
|
|
ubVolume = ubMaxVolume;
|
|
}
|
|
else
|
|
{
|
|
ubVolume = 1 + (UINT8) PreRandom(ubMaxVolume); // actual volume is 1 to max volume
|
|
}
|
|
}
|
|
else // in STEALTH mode
|
|
{
|
|
iRoll = (INT32) PreRandom(100); // roll them bones!
|
|
|
|
if (iRoll >= iStealthSkill) // v1.13 modification: give a second chance!
|
|
{
|
|
iRoll = (INT32) PreRandom(100);
|
|
}
|
|
|
|
if (iRoll < iStealthSkill)
|
|
{
|
|
ubVolume = 0; // made it, stayed quiet moving through this tile
|
|
}
|
|
else // OOPS!
|
|
{
|
|
ubVolume = 1 + ((iRoll - iStealthSkill + 1) / 16); // volume is 1 - 7 ...
|
|
switch (pSoldier->usAnimState)
|
|
{
|
|
case CRAWLING:
|
|
ubVolume -= 2;
|
|
break;
|
|
case SWATTING:
|
|
ubVolume -= 1;
|
|
break;
|
|
case RUNNING:
|
|
ubVolume += 3;
|
|
break;
|
|
}
|
|
if (ubVolume < 1)
|
|
{
|
|
ubVolume = 0;
|
|
}
|
|
|
|
// randomize at which movement step the sneaking failure will happen
|
|
// Status.stepsTilNoise = Random(MAXMOVESTEPS); // 0 - 6
|
|
}
|
|
}
|
|
|
|
//NumMessage("Volume = ",volume);
|
|
|
|
// save noise volume where stepped HandleSteppedLook can back get at it later
|
|
// Status.moveNoiseVolume = ubVolume;
|
|
return( ubVolume );
|
|
}
|
|
|
|
UINT8 DoorOpeningNoise( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT32 sGridNo;
|
|
DOOR_STATUS * pDoorStatus;
|
|
UINT8 ubDoorNoise;
|
|
|
|
// door being opened gridno is always the pending-action-data2 value
|
|
sGridNo = pSoldier->aiData.sPendingActionData2;
|
|
pDoorStatus = GetDoorStatus( sGridNo );
|
|
|
|
if ( pDoorStatus && pDoorStatus->ubFlags & DOOR_HAS_TIN_CAN )
|
|
{
|
|
// double noise possible!
|
|
ubDoorNoise = DOOR_NOISE_VOLUME * 3;
|
|
}
|
|
else
|
|
{
|
|
ubDoorNoise = DOOR_NOISE_VOLUME;
|
|
}
|
|
|
|
if ( MovementNoise( pSoldier ) )
|
|
{
|
|
// failed any stealth checks
|
|
return( ubDoorNoise );
|
|
}
|
|
|
|
// succeeded in being stealthy!
|
|
return( 0 );
|
|
}
|
|
|
|
void MakeNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage )
|
|
{
|
|
EV_S_NOISE SNoise;
|
|
|
|
SNoise.ubNoiseMaker = ubNoiseMaker;
|
|
SNoise.sGridNo = sGridNo;
|
|
SNoise.bLevel = bLevel;
|
|
SNoise.ubTerrType = ubTerrType;
|
|
SNoise.ubVolume = ubVolume;
|
|
SNoise.ubNoiseType = ubNoiseType;
|
|
swprintf( SNoise.zNoiseMessage, L"%s", zNoiseMessage );
|
|
//SNoise.zNoiseMessage = zNoiseMessage;
|
|
|
|
if ( gTacticalStatus.ubAttackBusyCount )
|
|
{
|
|
// delay these events until the attack is over!
|
|
AddGameEvent( S_NOISE, DEMAND_EVENT_DELAY, &SNoise );
|
|
}
|
|
else
|
|
{
|
|
// AddGameEvent( S_NOISE, 0, &SNoise );
|
|
|
|
// now call directly
|
|
OurNoise( SNoise.ubNoiseMaker, SNoise.sGridNo, SNoise.bLevel, SNoise.ubTerrType, SNoise.ubVolume, SNoise.ubNoiseType, SNoise.zNoiseMessage );
|
|
}
|
|
|
|
/*
|
|
INT8 bWeControlNoise = FALSE;
|
|
|
|
if (ubNoiseMode == UNEXPECTED)
|
|
{
|
|
bWeControlNoise = TRUE;
|
|
}
|
|
else // EXPECTED noise
|
|
{
|
|
if (ubNoiseMaker < TOTAL_SOLDIERS)
|
|
{
|
|
if (Menptr[ubNoiseMaker].controller == Net.pnum)
|
|
{
|
|
bWeControlNoise = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// expected noise by NOBODY is sent by LEADER, received by others
|
|
if (Net.pnum == LEADER)
|
|
{
|
|
bWeControlNoise = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bWeControlNoise)
|
|
{
|
|
OurNoise(ubNoiseMaker,sGridNo,ubTerrType,ubVolume,ubNoiseType,ubNoiseMode);
|
|
}
|
|
else
|
|
{
|
|
// can't be UNEXPECTED, check if it's a SEND or NO_SEND
|
|
if (ubNoiseMode == EXPECTED_NOSEND)
|
|
{
|
|
// no NET_NOISE message is required, trigger TheirNoise() right here
|
|
TheirNoise(ubNoiseMaker,sGridNo,ubTerrType,ubVolume,ubNoiseType,ubNoiseMode);
|
|
}
|
|
else
|
|
{
|
|
|
|
// EXPECTED_SEND, TheirNoise() will be triggered by the arrival of the
|
|
// NET_NOISE message, not by us. Wait here until that's all done...
|
|
|
|
// wait for the NET_NOISE to arrive (it will set noiseReceived flag)
|
|
//stopAction = TRUE; // prevent real-time events from passing us by
|
|
MarkTime(&LoopTime);
|
|
while (Status.noiseReceived != ubNoiseType)
|
|
{
|
|
LoopTimePast = Elapsed(&LoopTime);
|
|
if (LoopTimePast > 50 && LoopTimePast < 2000)
|
|
{
|
|
KeepInterfaceGoing(19); // xxx yyy zzz experimental Aug 16/96 9:15 pm
|
|
}
|
|
else
|
|
{
|
|
KeyHitReport("MakeNoise: Waiting for NET_NOISE, need ubNoiseType ",ubNoiseType);
|
|
}
|
|
CheckForNetIncoming();
|
|
};
|
|
//stopAction = FALSE; // re-enable real-time events
|
|
|
|
// turn off the oppChk flag again
|
|
Status.noiseReceived = -1;
|
|
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
void OurNoise( UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage )
|
|
{
|
|
#ifdef BYPASSNOISE
|
|
return;
|
|
#endif
|
|
|
|
#ifdef BETAVERSION
|
|
tempstr = String("OurNoise: ubNoiseType = %s, ubNoiseMaker = %d, ubNoiseMode = %d, sGridNo = %d, ubVolume = %d",
|
|
NoiseTypeStr[ubNoiseType],ubNoiseMaker,ubNoiseMode,sGridNo,ubVolume);
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\t%s\n",tempstr);
|
|
#endif
|
|
#ifdef TESTNOISE
|
|
PopMessage(tempstr);
|
|
#endif
|
|
#endif
|
|
|
|
// see if anyone actually hears this noise, sees ubNoiseMaker, etc.
|
|
ProcessNoise(ubNoiseMaker, sGridNo, bLevel, ubTerrType, ubVolume, ubNoiseType, zNoiseMessage );
|
|
|
|
if ((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && (ubNoiseMaker < TOTAL_SOLDIERS) && !gfDelayResolvingBestSightingDueToDoor )
|
|
{
|
|
// interrupts are possible, resolve them now (we're in control here)
|
|
// (you can't interrupt NOBODY, even if you hear the noise)
|
|
|
|
ResolveInterruptsVs(MercPtrs[ubNoiseMaker],NOISEINTERRUPT);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void TheirNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume,
|
|
UINT8 ubNoiseType, STR16 zNoiseMessage )
|
|
{
|
|
// SOLDIERTYPE *pSoldier;
|
|
|
|
|
|
#ifdef BYPASSNOISE
|
|
return;
|
|
#endif
|
|
|
|
|
|
#ifdef BETAVERSION
|
|
tempstr = String("TheirNoise: ubNoiseType = %s, ubNoiseMaker = %d, ubNoiseMode = %d, sGridNo = %d, ubVolume = %d",
|
|
NoiseTypeStr[ubNoiseType],ubNoiseMaker,ubNoiseMode,sGridNo,ubVolume);
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\t%s\n",tempstr);
|
|
#endif
|
|
|
|
#ifdef TESTNOISE
|
|
PopMessage(tempstr);
|
|
#endif
|
|
#endif
|
|
|
|
// see if anyone actually hears this noise, sees noiseMaker, etc.
|
|
ProcessNoise(ubNoiseMaker,sGridNo,bLevel,ubTerrType,ubVolume,ubNoiseType,zNoiseMessage);
|
|
|
|
// if noiseMaker is SOMEBODY
|
|
if (ubNoiseMaker < TOTAL_SOLDIERS)
|
|
{
|
|
/*
|
|
pSoldier = MercPtrs[ubNoiseMaker];
|
|
|
|
//stopAction = TRUE; // prevent real-time events from passing us by
|
|
MarkTime(&LoopTime);
|
|
do
|
|
{
|
|
LoopTimePast = Elapsed(&LoopTime);
|
|
if (LoopTimePast > 50 && LoopTimePast < 2000)
|
|
{
|
|
KeepInterfaceGoing(20); // xxx yyy zzz experimental Aug 16/96 9:15 pm
|
|
}
|
|
else
|
|
{
|
|
// the gridno is added to end of the string by KeyHitReport itself...
|
|
tempstr = String("TheirNoise: Waiting for NOISE_INT_DONE for guynum %d, ubNoiseType %d(%s), sGridNo ",
|
|
pSoldier->guynum,ubNoiseType,NoiseTypeStr[ubNoiseType]);
|
|
KeyHitReport(tempstr,sGridNo);
|
|
}
|
|
|
|
CheckForNetIncoming();
|
|
} while ((ExtMen[pSoldier->guynum].noiseRcvdGridno[ubNoiseType] != sGridNo) && pSoldier->in_sector);
|
|
//stopAction = FALSE; // re-enable real-time events
|
|
|
|
// reset the gridno flag for next time
|
|
ExtMen[pSoldier->guynum].noiseRcvdGridno[ubNoiseType] = NOWHERE;
|
|
*/
|
|
}
|
|
// else if noiseMaker's NOBODY, no opplist changes or interrupts are possible
|
|
}
|
|
|
|
|
|
|
|
void ProcessNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubBaseVolume, UINT8 ubNoiseType, STR16 zNoiseMessage )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
UINT8 bLoop, bTeam;
|
|
UINT8 ubLoudestEffVolume, ubEffVolume;
|
|
// UINT8 ubPlayVolume;
|
|
INT8 bCheckTerrain = FALSE;
|
|
UINT8 ubSourceTerrType, ubSource;
|
|
INT8 bTellPlayer = FALSE, bHeard, bSeen;
|
|
UINT8 ubHeardLoudestBy = NOBODY, ubNoiseDir = 0xff, ubLoudestNoiseDir = 0xff;
|
|
|
|
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"PN: nType=%s, nMaker=%d, g=%d, tType=%d, bVol=%d\n",
|
|
NoiseTypeStr[noiseType],ubNoiseMaker,sGridNo,ubTerrType,baseVolume);
|
|
#endif
|
|
|
|
// if the base volume itself was negligible
|
|
if (!ubBaseVolume)
|
|
return;
|
|
|
|
|
|
// EXPLOSIONs are special, because they COULD be caused by a merc who is
|
|
// no longer alive (but he placed the bomb or flaky grenade in the past).
|
|
// Later noiseMaker gets whacked to NOBODY anyway, so that's OK. So a
|
|
// dead noiseMaker is only used here to decide WHICH soldiers HearNoise().
|
|
|
|
// if noise is made by a person, AND it's not noise from an explosion
|
|
if ((ubNoiseMaker < TOTAL_SOLDIERS) && (ubNoiseType != NOISE_EXPLOSION))
|
|
{
|
|
// inactive/not in sector/dead soldiers, shouldn't be making noise!
|
|
if (!Menptr[ubNoiseMaker].bActive || !Menptr[ubNoiseMaker].bInSector ||
|
|
Menptr[ubNoiseMaker].flags.uiStatusFlags & SOLDIER_DEAD)
|
|
{
|
|
#ifdef BETAVERSION
|
|
NumMessage("ProcessNoise: ERROR - Noisemaker is inactive/not in sector/dead, Guy #",ubNoiseMaker);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// if he's out of life, and this isn't just his "dying scream" which is OK
|
|
if (!Menptr[ubNoiseMaker].stats.bLife && (ubNoiseType != NOISE_SCREAM))
|
|
{
|
|
#ifdef BETAVERSION
|
|
NumMessage("ProcessNoise: ERROR - Noisemaker is lifeless, Guy #",ubNoiseMaker);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// DETERMINE THE TERRAIN TYPE OF THE GRIDNO WHERE NOISE IS COMING FROM
|
|
|
|
ubSourceTerrType = gpWorldLevelData[sGridNo].ubTerrainID;
|
|
/*
|
|
// start with the terrain type passed in to us
|
|
ubSourceTerrType = ubTerrType;
|
|
|
|
// if this isn't enough to get a valid terrain type
|
|
if ((ubSourceTerrType < GROUNDTYPE) || (ubSourceTerrType > OCEANTYPE))
|
|
{
|
|
// use the source gridno of the noise itself
|
|
ubSourceTerrType = TTypeList[Terrain(sGridNo)];
|
|
}
|
|
*/
|
|
|
|
// if we have now somehow obtained a valid terrain type
|
|
if ((ubSourceTerrType >= FLAT_GROUND) || (ubSourceTerrType <= DEEP_WATER))
|
|
{
|
|
//NumMessage("Source Terrain Type = ",ubSourceTerrType);
|
|
bCheckTerrain = TRUE;
|
|
}
|
|
// else give up trying to get terrain type, just assume sound isn't muffled
|
|
|
|
|
|
// DETERMINE THE *PERCEIVED* SOURCE OF THE NOISE
|
|
switch (ubNoiseType)
|
|
{
|
|
// for noise generated by an OBJECT shot/thrown/dropped by the noiseMaker
|
|
case NOISE_ROCK_IMPACT:
|
|
gsWhoThrewRock = ubNoiseMaker;
|
|
//fall through here!!!
|
|
case NOISE_BULLET_IMPACT:
|
|
case NOISE_GRENADE_IMPACT:
|
|
case NOISE_EXPLOSION:
|
|
// the source of the noise is not at all obvious, so hide it from
|
|
// the listener and maintain noiseMaker's cover by making source NOBODY
|
|
ubSource = NOBODY;
|
|
break;
|
|
|
|
default:
|
|
// normal situation: the noiseMaker is obviously the source of the noise
|
|
ubSource = ubNoiseMaker;
|
|
break;
|
|
}
|
|
|
|
// LOOP THROUGH EACH TEAM
|
|
for (bTeam = 0; bTeam < MAXTEAMS; bTeam++)
|
|
{
|
|
// skip any inactive teams
|
|
if (!gTacticalStatus.Team[bTeam].bTeamActive)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// if a the noise maker is a person, not just NOBODY
|
|
if (ubNoiseMaker < TOTAL_SOLDIERS)
|
|
{
|
|
// if this team is the same TEAM as the noise maker's
|
|
// (for now, assume we will report noises by unknown source on same SIDE)
|
|
// OR, if the noise maker is currently in sight to this HUMAN team
|
|
|
|
// CJC: changed to if the side is the same side as the noise maker's!
|
|
// CJC: changed back!
|
|
|
|
if (bTeam == Menptr[ubNoiseMaker].bTeam)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (gTacticalStatus.Team[bTeam].bHuman)
|
|
{
|
|
if (gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_CURRENTLY && ubNoiseType != NOISE_VOICE)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef REPORTTHEIRNOISE
|
|
// if this is any team
|
|
if (TRUE)
|
|
#else
|
|
// if this is our team
|
|
if (TRUE)
|
|
//if (bTeam == Net.pnum)
|
|
#endif
|
|
{
|
|
// tell player about noise if enemies are present
|
|
bTellPlayer = gTacticalStatus.fEnemyInSector && ( !(gTacticalStatus.uiFlags & INCOMBAT) || (gTacticalStatus.ubCurrentTeam) );
|
|
|
|
#ifndef TESTNOISE
|
|
switch (ubNoiseType)
|
|
{
|
|
case NOISE_GUNFIRE:
|
|
case NOISE_BULLET_IMPACT:
|
|
case NOISE_ROCK_IMPACT:
|
|
case NOISE_GRENADE_IMPACT:
|
|
// It's noise caused by a projectile. If the projectile was seen by
|
|
// the local player while in flight (PublicBullet), then don't bother
|
|
// giving him a message about the noise it made, he's obviously aware.
|
|
if (1 /*PublicBullet*/)
|
|
{
|
|
bTellPlayer = FALSE;
|
|
}
|
|
|
|
break;
|
|
|
|
case NOISE_EXPLOSION:
|
|
// if center of explosion is in visual range of team, don't report
|
|
// noise, because the player is already watching the thing go BOOM!
|
|
if (TeamMemberNear(bTeam,sGridNo,STRAIGHT))
|
|
{
|
|
bTellPlayer = FALSE;
|
|
}
|
|
break;
|
|
|
|
case NOISE_SILENT_ALARM:
|
|
bTellPlayer = FALSE;
|
|
break;
|
|
}
|
|
|
|
// if noise was made by a person
|
|
if (ubNoiseMaker < TOTAL_SOLDIERS)
|
|
{
|
|
// if noisemaker has been *PUBLICLY* SEEN OR HEARD during THIS TURN
|
|
if ((gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_CURRENTLY) || // seen now
|
|
(gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_THIS_TURN) || // seen this turn
|
|
(gbPublicOpplist[bTeam][ubNoiseMaker] == HEARD_THIS_TURN)) // heard this turn
|
|
{
|
|
// then don't bother reporting any noise made by him to the player
|
|
bTellPlayer = FALSE;
|
|
}
|
|
/*
|
|
else if ( (Menptr[ubNoiseMaker].bVisible == TRUE) && (bTeam == gbPlayerNum) )
|
|
{
|
|
ScreenMsg( MSG_FONT_YELLOW, MSG_TESTVERSION, L"Handling noise from person not currently seen in player's public opplist" );
|
|
}
|
|
*/
|
|
|
|
// anv: special exception: we want to report enemy taunt, because of text content
|
|
if ( ubNoiseType == NOISE_VOICE )
|
|
{
|
|
bTellPlayer = TRUE;
|
|
}
|
|
|
|
if ( MercPtrs[ ubNoiseMaker ]->stats.bLife == 0 )
|
|
{
|
|
// this guy is dead (just dying) so don't report to player
|
|
bTellPlayer = FALSE;
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// refresh flags for this new team
|
|
bHeard = FALSE;
|
|
bSeen = FALSE;
|
|
ubLoudestEffVolume = 0;
|
|
ubHeardLoudestBy = NOBODY;
|
|
|
|
// All mercs on this team check if they are eligible to hear this noise
|
|
for (bLoop = gTacticalStatus.Team[bTeam].bFirstID,pSoldier = Menptr + bLoop; bLoop <= gTacticalStatus.Team[bTeam].bLastID; bLoop++,pSoldier++)
|
|
{
|
|
// if this "listener" is inactive, or in no condition to care
|
|
if (!pSoldier->bActive || !pSoldier->bInSector || pSoldier->flags.uiStatusFlags & SOLDIER_DEAD || (pSoldier->stats.bLife < OKLIFE) || pSoldier->ubBodyType == LARVAE_MONSTER)
|
|
{
|
|
continue; // skip him!
|
|
}
|
|
|
|
if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->bTeam == OUR_TEAM )
|
|
{
|
|
continue; // skip
|
|
}
|
|
|
|
if ( bTeam == gbPlayerNum && pSoldier->bAssignment == ASSIGNMENT_POW )
|
|
{
|
|
// POWs should not be processed for noise
|
|
continue;
|
|
}
|
|
|
|
// if a the noise maker is a person, not just NOBODY
|
|
if (ubNoiseMaker < TOTAL_SOLDIERS)
|
|
{
|
|
// if this listener can see this noise maker
|
|
if (pSoldier->aiData.bOppList[ubNoiseMaker] == SEEN_CURRENTLY)
|
|
{
|
|
// civilians care about gunshots even if they come from someone they can see
|
|
// ChrisL: Crows will fly away if they hear any noise
|
|
if ( !( pSoldier->aiData.bNeutral && ubNoiseType == NOISE_GUNFIRE ) && pSoldier->ubBodyType != CROW )
|
|
{
|
|
// anv: we want to report taunt even if we see noisemaker
|
|
if(ubNoiseType != NOISE_VOICE)
|
|
{
|
|
continue; // then who cares whether he can also hear the guy?
|
|
}
|
|
}
|
|
}
|
|
|
|
// screen out allied militia from hearing us
|
|
switch( MercPtrs[ ubNoiseMaker ]->bTeam )
|
|
{
|
|
case OUR_TEAM:
|
|
// if the listener is militia and still on our side, ignore noise from us
|
|
if ( pSoldier->bTeam == MILITIA_TEAM && pSoldier->bSide == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
case ENEMY_TEAM:
|
|
switch( pSoldier->ubProfile )
|
|
{
|
|
case WARDEN:
|
|
case GENERAL:
|
|
case SERGEANT:
|
|
case CONRAD:
|
|
// WANNE: This fixes the bug, that Conrad, when he is in OUR team, cannot interrupt enemies!!!
|
|
if (pSoldier->bTeam == OUR_TEAM)
|
|
{
|
|
// WANNE: Allow interrupt, if one of those guys is in OUR team!
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// No interrupt for those 4 guys
|
|
continue;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case MILITIA_TEAM:
|
|
// if the noisemaker is militia and still on our side, ignore noise if we're listening
|
|
if ( pSoldier->bTeam == OUR_TEAM && MercPtrs[ ubNoiseMaker ]->bSide == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// HEADROCK HAM 3.6: Bloodcat "static" sectors have been externalized, and there can be more than one.
|
|
// Also, there's a toggle that determines whether or not bloodcats can sense enemies in this sector.
|
|
UINT8 ubSectorID = SECTOR(gWorldSectorX, gWorldSectorY);
|
|
UINT8 PlacementType = gBloodcatPlacements[ ubSectorID ][0].PlacementType;
|
|
|
|
if (PlacementType == BLOODCAT_PLACEMENT_STATIC)
|
|
{
|
|
if (gBloodcatPlacements[ ubSectorID ][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation == QUEENS_CIV_GROUP)
|
|
{
|
|
// skip noises between army & bloodcats
|
|
if ( pSoldier->bTeam == ENEMY_TEAM && MercPtrs[ ubNoiseMaker ]->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == CREATURE_TEAM )
|
|
{
|
|
continue;
|
|
}
|
|
if ( pSoldier->bTeam == CREATURE_TEAM && pSoldier->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == ENEMY_TEAM )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (gBloodcatPlacements[ ubSectorID ][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation > NON_CIV_GROUP)
|
|
{
|
|
if ( MercPtrs[ ubNoiseMaker ]->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == CREATURE_TEAM && pSoldier->bSide != gbPlayerNum)
|
|
{
|
|
// Target is a bloodcat. He can't be heard by civilians no matter what.
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if ( pSoldier->bTeam == CREATURE_TEAM && pSoldier->ubBodyType == BLOODCAT )
|
|
{
|
|
// Source is a bloodcat. He can only hear player-side soldiers, and only if hostile.
|
|
if ( MercPtrs[ ubNoiseMaker ]->bSide != gbPlayerNum || pSoldier->aiData.bNeutral )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// screen out allied militia from hearing us
|
|
if ( (ubNoiseMaker == NOBODY) && pSoldier->bTeam == MILITIA_TEAM && pSoldier->bSide == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( (pSoldier->bTeam == CIV_TEAM) && (ubNoiseType == NOISE_GUNFIRE || ubNoiseType == NOISE_EXPLOSION) )
|
|
{
|
|
pSoldier->ubMiscSoldierFlags |= SOLDIER_MISC_HEARD_GUNSHOT;
|
|
}
|
|
|
|
// Can the listener hear noise of that volume given his circumstances?
|
|
ubEffVolume = CalcEffVolume(pSoldier,sGridNo,bLevel,ubNoiseType,ubBaseVolume,bCheckTerrain,pSoldier->bOverTerrainType,ubSourceTerrType);
|
|
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"PN: guy %d - effVol=%d,chkTer=%d,pSoldier->tType=%d,srcTType=%d\n",
|
|
bLoop,effVolume,bCheckTerrain,pSoldier->terrtype,ubSourceTerrType);
|
|
#endif
|
|
|
|
|
|
if (ubEffVolume > 0)
|
|
{
|
|
// ALL RIGHT! Passed all the tests, this listener hears this noise!!!
|
|
HearNoise(pSoldier,ubSource,sGridNo,bLevel,ubEffVolume,ubNoiseType, (UINT8 *)&bSeen);
|
|
|
|
bHeard = TRUE;
|
|
|
|
ubNoiseDir = atan8(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(sGridNo),CenterY(sGridNo));
|
|
|
|
// check the 'noise heard & reported' bit for that soldier & direction
|
|
if ( ubNoiseType != NOISE_MOVEMENT || bTeam != OUR_TEAM || (pSoldier->aiData.bInterruptDuelPts != NO_INTERRUPT) || !(pSoldier->ubMovementNoiseHeard & (1 << ubNoiseDir) ) )
|
|
{
|
|
if (ubEffVolume > ubLoudestEffVolume)
|
|
{
|
|
ubLoudestEffVolume = ubEffVolume;
|
|
ubHeardLoudestBy = pSoldier->ubID;
|
|
ubLoudestNoiseDir = ubNoiseDir;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//NameMessage(pSoldier," can't hear this noise",2500);
|
|
ubEffVolume = 0;
|
|
}
|
|
}
|
|
|
|
|
|
// if the noise was heard at all
|
|
if (bHeard)
|
|
{
|
|
// and we're doing our team
|
|
if (bTeam == OUR_TEAM)
|
|
/*
|
|
if (team == Net.pnum)
|
|
*/
|
|
{
|
|
// if we are to tell the player about this type of noise
|
|
if (bTellPlayer && ubHeardLoudestBy != NOBODY )
|
|
{
|
|
// the merc that heard it the LOUDEST is the one to comment
|
|
// should add level to this function call
|
|
TellPlayerAboutNoise(MercPtrs[ubHeardLoudestBy],ubNoiseMaker,sGridNo,bLevel,ubLoudestEffVolume,ubNoiseType, ubLoudestNoiseDir, zNoiseMessage);
|
|
|
|
if ( ubNoiseType == NOISE_MOVEMENT)
|
|
{
|
|
MercPtrs[ ubHeardLoudestBy ]->ubMovementNoiseHeard |= (1 << ubNoiseDir);
|
|
}
|
|
|
|
}
|
|
//if ( !(pSoldier->ubMovementNoiseHeard & (1 << ubNoiseDir) ) )
|
|
}
|
|
#ifdef REPORTTHEIRNOISE
|
|
else // debugging: report noise heard by other team's soldiers
|
|
{
|
|
if (bTellPlayer)
|
|
{
|
|
TellPlayerAboutNoise(MercPtrs[ubHeardLoudestBy],ubNoiseMaker,sGridNo,bLevel,ubLoudestEffVolume,ubNoiseType, ubLoudestNoiseDir);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// if the listening team is human-controlled AND
|
|
// the noise's source is another soldier
|
|
// (computer-controlled teams don't radio or automatically report NOISE)
|
|
if (gTacticalStatus.Team[bTeam].bHuman && (ubSource < TOTAL_SOLDIERS))
|
|
{
|
|
// if ubNoiseMaker was seen by at least one member of this team
|
|
if (bSeen)
|
|
{
|
|
// Temporary for opplist synching - disable random order radioing
|
|
#ifdef RECORDOPPLIST
|
|
// insure all machines radio in synch to keep logs the same
|
|
for (bLoop = Status.team[team].guystart,pSoldier = Menptr + bLoop; bLoop < Status.team[team].guyend; bLoop++,pSoldier++)
|
|
{
|
|
// if this merc is active, in this sector, and well enough to look
|
|
if (pSoldier->active && pSoldier->in_sector && (pSoldier->life >= OKLIFE))
|
|
{
|
|
RadioSightings(pSoldier,ubSource);
|
|
pSoldier->newOppCnt = 0;
|
|
}
|
|
}
|
|
#else
|
|
// if this human team is OURS
|
|
if (1 /* bTeam == Net.pnum */)
|
|
{
|
|
// this team is now allowed to report sightings and set Public flags
|
|
OurTeamRadiosRandomlyAbout(ubSource);
|
|
}
|
|
else // noise was heard by another human-controlled team (not ours)
|
|
{
|
|
// mark noise maker as being seen currently
|
|
//UpdatePublic(bTeam,ubSource,SEEN_CURRENTLY,sGridNo,NOUPDATE,ACTUAL);
|
|
UpdatePublic(bTeam,ubSource,SEEN_CURRENTLY,sGridNo,bLevel);
|
|
}
|
|
#endif
|
|
}
|
|
else // not seen
|
|
{
|
|
if (bHeard)
|
|
{
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"UpdatePublic (ProcessNoise/heard) for team %d about %d\n",team,ubSource);
|
|
#endif
|
|
|
|
// mark noise maker as having been PUBLICLY heard THIS TURN
|
|
//UpdatePublic(team,ubSource,HEARD_THIS_TURN,sGridNo,NOUPDATE,ACTUAL);
|
|
UpdatePublic(bTeam,ubSource,HEARD_THIS_TURN,sGridNo,bLevel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gsWhoThrewRock = NOBODY;
|
|
}
|
|
|
|
|
|
|
|
UINT8 CalcEffVolume(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT8 ubNoiseType, UINT8 ubBaseVolume,
|
|
UINT8 bCheckTerrain, UINT8 ubTerrType1, UINT8 ubTerrType2)
|
|
{
|
|
INT32 iEffVolume, iDistance;
|
|
|
|
// Lesh: deafness
|
|
if ( pSoldier->bDeafenedCounter > 0 )
|
|
{
|
|
return( 0 );
|
|
}
|
|
|
|
if ( FindWalkman(pSoldier) != ITEM_NOT_FOUND )
|
|
{
|
|
return( 0 );
|
|
}
|
|
|
|
if ( gTacticalStatus.uiFlags & INCOMBAT )
|
|
{
|
|
// ATE: Funny things happen to ABC stuff if bNewSituation set....
|
|
// anv: added exception to NOISE_VOICE
|
|
if ( gTacticalStatus.ubCurrentTeam == pSoldier->bTeam && ubNoiseType != NOISE_VOICE )
|
|
{
|
|
return( 0 );
|
|
}
|
|
}
|
|
|
|
//sprintf(tempstr,"CalcEffVolume BY %s for gridno %d, baseVolume = %d",pSoldier->name,gridno,baseVolume);
|
|
//PopMessage(tempstr);
|
|
|
|
// adjust default noise volume by listener's hearing capability
|
|
iEffVolume = (INT32) ubBaseVolume + (INT32) DecideHearing( pSoldier );
|
|
|
|
|
|
// effective volume reduced by listener's number of opponents in sight
|
|
iEffVolume -= pSoldier->aiData.bOppCnt;
|
|
|
|
|
|
// calculate the distance (in adjusted pixels) between the source of the
|
|
// noise (gridno) and the location of the would-be listener (pSoldier->gridno)
|
|
iDistance = (INT32) PythSpacesAway( pSoldier->sGridNo, sGridNo );
|
|
/*
|
|
distance = AdjPixelsAway(pSoldier->x,pSoldier->y,CenterX(sGridNo),CenterY(sGridNo));
|
|
|
|
distance /= 15; // divide by 15 to convert from adj. pixels to tiles
|
|
*/
|
|
//NumMessage("Distance = ",distance);
|
|
|
|
// effective volume fades over distance beyond 1 tile away
|
|
iEffVolume -= (iDistance - 1);
|
|
|
|
//ddd{ ������ ����� ������ ;)
|
|
if(gGameExternalOptions.bLazyCivilians)
|
|
if (pSoldier->bTeam == CIV_TEAM && pSoldier->ubBodyType != CROW )
|
|
if (pSoldier->ubCivilianGroup == 0 && pSoldier->ubProfile == NO_PROFILE)
|
|
iEffVolume =-100;
|
|
//ddd}
|
|
|
|
/*
|
|
if (pSoldier->bTeam == CIV_TEAM && pSoldier->ubBodyType != CROW )
|
|
{
|
|
if (pSoldier->ubCivilianGroup == 0 && pSoldier->ubProfile == NO_PROFILE)
|
|
{
|
|
// nameless civs reduce effective volume by 2 for gunshots etc
|
|
// (double the reduction due to distance)
|
|
// so that they don't cower from attacks that are really far away
|
|
switch (ubNoiseType)
|
|
{
|
|
case NOISE_GUNFIRE:
|
|
case NOISE_BULLET_IMPACT:
|
|
case NOISE_GRENADE_IMPACT:
|
|
case NOISE_EXPLOSION:
|
|
iEffVolume -= iDistance;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if (pSoldier->aiData.bNeutral)
|
|
{
|
|
// NPCs and people in groups ignore attack noises unless they are no longer neutral
|
|
switch (ubNoiseType)
|
|
{
|
|
case NOISE_GUNFIRE:
|
|
case NOISE_BULLET_IMPACT:
|
|
case NOISE_GRENADE_IMPACT:
|
|
case NOISE_EXPLOSION:
|
|
iEffVolume = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
if (pSoldier->usAnimState == RUNNING)
|
|
{
|
|
iEffVolume -= 5;
|
|
}
|
|
|
|
if (pSoldier->bAssignment == SLEEPING )
|
|
{
|
|
// decrease effective volume since we're asleep!
|
|
iEffVolume -= 5;
|
|
}
|
|
|
|
// check for floor/roof difference
|
|
if (bLevel > pSoldier->pathing.bLevel)
|
|
{
|
|
// sound is amplified by roof
|
|
iEffVolume += 5;
|
|
}
|
|
else if (bLevel < pSoldier->pathing.bLevel)
|
|
{
|
|
// sound is muffled
|
|
iEffVolume -= 5;
|
|
}
|
|
|
|
// if we still have a chance of hearing this, and the terrain types are known
|
|
if (iEffVolume > 0)
|
|
{
|
|
if (bCheckTerrain)
|
|
{
|
|
// if, between noise and listener, one is outside and one is inside
|
|
|
|
// NOTE: This is a pretty dumb way of doing things, since it won't detect
|
|
// the presence of walls between 2 spots both inside or both outside, but
|
|
// given our current system it's the best that we can do
|
|
|
|
if (((ubTerrType1 == FLAT_FLOOR) && (ubTerrType2 != FLAT_FLOOR)) ||
|
|
((ubTerrType1 != FLAT_FLOOR) && (ubTerrType2 == FLAT_FLOOR)))
|
|
{
|
|
//PopMessage("Sound is muffled by wall(s)");
|
|
|
|
// sound is muffled, reduce the effective volume of the noise
|
|
iEffVolume -= 5;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//NumMessage("effVolume = ",ubEffVolume);
|
|
if (iEffVolume > 0)
|
|
{
|
|
return( (UINT8) iEffVolume );
|
|
}
|
|
else
|
|
{
|
|
return( 0 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void HearNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume,
|
|
UINT8 ubNoiseType, UINT8 *ubSeen)
|
|
{
|
|
INT16 sNoiseX, sNoiseY;
|
|
INT8 bHadToTurn = FALSE, bSourceSeen = FALSE;
|
|
INT8 bOldOpplist;
|
|
INT8 bDirection;
|
|
BOOLEAN fMuzzleFlash = FALSE;
|
|
|
|
if ( pSoldier->ubBodyType == CROW )
|
|
{
|
|
CrowsFlyAway( pSoldier->bTeam );
|
|
return;
|
|
}
|
|
// DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "%d hears noise from %d (%d/%d) volume %d", pSoldier->ubID, ubNoiseMaker, sGridNo, bLevel, ubVolume ) );
|
|
|
|
// "Turn head" towards the source of the noise and try to see what's there
|
|
|
|
// don't use DistanceVisible here, but use maximum visibility distance
|
|
// in as straight line instead. Represents guy "turning just his head"
|
|
|
|
// CJC 97/10: CHANGE! Since STRAIGHT can not reliably be used as a
|
|
// max sighting distance (varies based on realtime/turnbased), call
|
|
// the function with the new DIRECTION_IRRELEVANT define
|
|
|
|
// is he close enough to see that gridno if he turns his head?
|
|
|
|
// ignore muzzle flashes when turning head to see noise
|
|
if ( ubNoiseType == NOISE_GUNFIRE && ubNoiseMaker != NOBODY && MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash )
|
|
{
|
|
sNoiseX = CenterX(sGridNo);
|
|
sNoiseY = CenterY(sGridNo);
|
|
bDirection = atan8(pSoldier->sX,pSoldier->sY,sNoiseX,sNoiseY);
|
|
if ( pSoldier->ubDirection != bDirection && pSoldier->ubDirection != gOneCDirection[ bDirection ] && pSoldier->ubDirection != gOneCCDirection[ bDirection ] )
|
|
{
|
|
// temporarily turn off muzzle flash so DistanceVisible can be calculated without it
|
|
MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash = FALSE;
|
|
fMuzzleFlash = TRUE;
|
|
}
|
|
}
|
|
|
|
int sDistVisible = pSoldier->GetMaxDistanceVisible(sGridNo, bLevel, CALC_FROM_WANTED_DIR );
|
|
|
|
if ( fMuzzleFlash )
|
|
{
|
|
// turn flash on again
|
|
MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash = TRUE;
|
|
}
|
|
|
|
if (PythSpacesAway(pSoldier->sGridNo,sGridNo) <= sDistVisible )
|
|
{
|
|
// just use the XXadjustedXX center of the gridno
|
|
sNoiseX = CenterX(sGridNo);
|
|
sNoiseY = CenterY(sGridNo);
|
|
|
|
if (pSoldier->ubDirection != atan8(pSoldier->sX,pSoldier->sY,sNoiseX,sNoiseY))
|
|
{
|
|
bHadToTurn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bHadToTurn = FALSE;
|
|
}
|
|
|
|
// and we can trace a line of sight to his x,y coordinates?
|
|
// (taking into account we are definitely aware of this guy now)
|
|
|
|
// skip LOS check if we had to turn and we're a tank. sorry Mr Tank, no looking out of the sides for you!
|
|
if ( !( bHadToTurn && TANK( pSoldier ) ) )
|
|
{
|
|
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, bLevel, 0, TRUE, sDistVisible ) )
|
|
{
|
|
// he can actually see the spot where the noise came from!
|
|
bSourceSeen = TRUE;
|
|
|
|
// if this sounds like a door opening/closing (could also be a crate)
|
|
// Flugente: unused check
|
|
/*if (ubNoiseType == NOISE_CREAKING)
|
|
{
|
|
// then look around and update ALL doors that have secretly changed
|
|
//LookForDoors(pSoldier,AWARE);
|
|
}*/
|
|
}
|
|
}
|
|
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"HN: %s by %2d(g%4d,x%3d,y%3d) at %2d(g%4d,x%3d,y%3d), hTT=%d\n",
|
|
(bSourceSeen) ? "SCS" : "FLR",
|
|
pSoldier->guynum,pSoldier->sGridNo,pSoldier->sX,pSoldier->sY,
|
|
ubNoiseMaker,sGridNo,sNoiseX,sNoiseY,
|
|
bHadToTurn);
|
|
#endif
|
|
}
|
|
|
|
// if noise is made by a person
|
|
if (ubNoiseMaker < TOTAL_SOLDIERS)
|
|
{
|
|
bOldOpplist = pSoldier->aiData.bOppList[ubNoiseMaker];
|
|
|
|
// WE ALREADY KNOW THAT HE'S ON ANOTHER TEAM, AND HE'S NOT BEING SEEN
|
|
// ProcessNoise() ALREADY DID THAT WORK FOR US
|
|
|
|
if (bSourceSeen)
|
|
{
|
|
ManSeesMan(pSoldier,MercPtrs[ubNoiseMaker],Menptr[ubNoiseMaker].sGridNo,Menptr[ubNoiseMaker].pathing.bLevel,HEARNOISE,CALLER_UNKNOWN);
|
|
|
|
// if it's an AI soldier, he is not allowed to automatically radio any
|
|
// noise heard, but manSeesMan has set his newOppCnt, so clear it here
|
|
if (!(pSoldier->flags.uiStatusFlags & SOLDIER_PC))
|
|
{
|
|
pSoldier->bNewOppCnt = 0;
|
|
}
|
|
|
|
*ubSeen = TRUE;
|
|
// RadioSightings() must only be called later on by ProcessNoise() itself
|
|
// because we want the soldier who heard noise the LOUDEST to report it
|
|
|
|
if ( pSoldier->aiData.bNeutral )
|
|
{
|
|
// could be a civilian watching us shoot at an enemy
|
|
if (((ubNoiseType == NOISE_GUNFIRE) || (ubNoiseType == NOISE_BULLET_IMPACT)) && (ubVolume >= 3))
|
|
{
|
|
// if status is only GREEN or YELLOW
|
|
if (pSoldier->aiData.bAlertStatus < STATUS_RED)
|
|
{
|
|
// then this soldier goes to status RED, has proof of enemy presence
|
|
pSoldier->aiData.bAlertStatus = STATUS_RED;
|
|
CheckForChangingOrders(pSoldier);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else // noise maker still can't be seen
|
|
{
|
|
SetNewSituation( pSoldier ); // re-evaluate situation
|
|
|
|
// if noise type was unmistakably that of gunfire
|
|
if (((ubNoiseType == NOISE_GUNFIRE) || (ubNoiseType == NOISE_BULLET_IMPACT)) && (ubVolume >= 3))
|
|
{
|
|
// if status is only GREEN or YELLOW
|
|
if (pSoldier->aiData.bAlertStatus < STATUS_RED)
|
|
{
|
|
// then this soldier goes to status RED, has proof of enemy presence
|
|
pSoldier->aiData.bAlertStatus = STATUS_RED;
|
|
CheckForChangingOrders(pSoldier);
|
|
}
|
|
}
|
|
|
|
// remember that the soldier has been heard and his new location
|
|
UpdatePersonal(pSoldier,ubNoiseMaker,HEARD_THIS_TURN,sGridNo, bLevel);
|
|
|
|
// Public info is not set unless EVERYONE on the team fails to see the
|
|
// ubnoisemaker, leaving the 'seen' flag FALSE. See ProcessNoise().
|
|
|
|
// CJC: set the noise gridno for the soldier, if appropriate - this is what is looked at by the AI!
|
|
if (ubVolume >= pSoldier->aiData.ubNoiseVolume)
|
|
{
|
|
// yes it is, so remember this noise INSTEAD (old noise is forgotten)
|
|
pSoldier->aiData.sNoiseGridno = sGridNo;
|
|
pSoldier->bNoiseLevel = bLevel;
|
|
|
|
// no matter how loud noise was, don't remember it for than 12 turns!
|
|
if (ubVolume < MAX_MISC_NOISE_DURATION)
|
|
{
|
|
pSoldier->aiData.ubNoiseVolume = ubVolume;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
|
|
}
|
|
|
|
SetNewSituation( pSoldier ); // force a fresh AI decision to be made
|
|
}
|
|
|
|
}
|
|
|
|
if ( pSoldier->aiData.fAIFlags & AI_ASLEEP )
|
|
{
|
|
switch( ubNoiseType )
|
|
{
|
|
case NOISE_BULLET_IMPACT:
|
|
case NOISE_GUNFIRE:
|
|
case NOISE_EXPLOSION:
|
|
case NOISE_SCREAM:
|
|
case NOISE_WINDOW_SMASHING:
|
|
case NOISE_DOOR_SMASHING:
|
|
// WAKE UP!
|
|
pSoldier->aiData.fAIFlags &= (~AI_ASLEEP);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// FIRST REQUIRE MUTUAL HOSTILES!
|
|
if (!CONSIDERED_NEUTRAL( MercPtrs[ ubNoiseMaker ], pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, MercPtrs[ ubNoiseMaker ] ) && (pSoldier->bSide != MercPtrs[ ubNoiseMaker ]->bSide))
|
|
{
|
|
// regardless of whether the noisemaker (who's not NOBODY) was seen or not,
|
|
// as long as listener meets minimum interrupt conditions
|
|
if ( gfDelayResolvingBestSightingDueToDoor)
|
|
{
|
|
if ( bSourceSeen && (!( (gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) ) || (gubSightFlags & SIGHTINTERRUPT && StandardInterruptConditionsMet(pSoldier,ubNoiseMaker,bOldOpplist)) ) )
|
|
{
|
|
// we should be adding this to the array for the AllTeamLookForAll to handle
|
|
// since this is a door opening noise, add a bonus equal to half the door volume
|
|
UINT8 ubPoints;
|
|
|
|
ubPoints = CalcInterruptDuelPts( pSoldier, ubNoiseMaker, TRUE );
|
|
if ( ubPoints != NO_INTERRUPT )
|
|
{
|
|
// require the enemy not to be dying if we are the sighter; in other words,
|
|
// always add for AI guys, and always add for people with life >= OKLIFE
|
|
if ( pSoldier->bTeam != gbPlayerNum || MercPtrs[ ubNoiseMaker ]->stats.bLife >= OKLIFE )
|
|
{
|
|
ReevaluateBestSightingPosition( pSoldier, (UINT8) (ubPoints + (ubVolume / 2)) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
if (StandardInterruptConditionsMet(pSoldier,ubNoiseMaker,bOldOpplist))
|
|
{
|
|
// he gets a chance to interrupt the noisemaker
|
|
pSoldier->aiData.bInterruptDuelPts = CalcInterruptDuelPts(pSoldier,ubNoiseMaker, TRUE );
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Calculating int duel pts in noise code, %d has %d points", pSoldier->ubID, pSoldier->aiData.bInterruptDuelPts ) );
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
}
|
|
}
|
|
else if ( bSourceSeen )
|
|
{
|
|
// seen source, in realtime, so check for sighting stuff
|
|
HandleBestSightingPositionInRealtime();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
else // noise made by NOBODY
|
|
{
|
|
// if noise type was unmistakably that of an explosion (seen or not) or alarm
|
|
if (!(pSoldier->flags.uiStatusFlags & SOLDIER_PC))
|
|
{
|
|
if ( ( ubNoiseType == NOISE_EXPLOSION || ubNoiseType == NOISE_SILENT_ALARM ) && (ubVolume >= 3) )
|
|
{
|
|
if ( ubNoiseType == NOISE_SILENT_ALARM )
|
|
{
|
|
WearGasMaskIfAvailable( pSoldier );
|
|
}
|
|
// if status is only GREEN or YELLOW
|
|
if (pSoldier->aiData.bAlertStatus < STATUS_RED)
|
|
{
|
|
// then this soldier goes to status RED, has proof of enemy presence
|
|
pSoldier->aiData.bAlertStatus = STATUS_RED;
|
|
CheckForChangingOrders(pSoldier);
|
|
}
|
|
}
|
|
}
|
|
// if the source of the noise can't be seen,
|
|
// OR if it's a rock and the listener had to turn so that by the time he
|
|
// looked all his saw was a bunch of rocks lying still
|
|
if (!bSourceSeen || ((ubNoiseType == NOISE_ROCK_IMPACT) && (bHadToTurn) ) || ubNoiseType == NOISE_SILENT_ALARM )
|
|
{
|
|
// check if the effective volume of this new noise is greater than or at
|
|
// least equal to the volume of the currently noticed noise stored
|
|
if (ubVolume >= pSoldier->aiData.ubNoiseVolume)
|
|
{
|
|
// yes it is, so remember this noise INSTEAD (old noise is forgotten)
|
|
pSoldier->aiData.sNoiseGridno = sGridNo;
|
|
pSoldier->bNoiseLevel = bLevel;
|
|
|
|
// no matter how loud noise was, don't remember it for than 12 turns!
|
|
if (ubVolume < MAX_MISC_NOISE_DURATION)
|
|
{
|
|
pSoldier->aiData.ubNoiseVolume = ubVolume;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
|
|
}
|
|
|
|
SetNewSituation( pSoldier ); // force a fresh AI decision to be made
|
|
}
|
|
}
|
|
else
|
|
// if listener sees the source of the noise, AND it's either a grenade,
|
|
// or it's a rock that he watched land (didn't need to turn)
|
|
{
|
|
SetNewSituation( pSoldier ); // re-evaluate situation
|
|
|
|
// if status is only GREEN or YELLOW
|
|
if (pSoldier->aiData.bAlertStatus < STATUS_RED)
|
|
{
|
|
// then this soldier goes to status RED, has proof of enemy presence
|
|
pSoldier->aiData.bAlertStatus = STATUS_RED;
|
|
CheckForChangingOrders(pSoldier);
|
|
}
|
|
}
|
|
|
|
if ( gubBestToMakeSightingSize == BEST_SIGHTING_ARRAY_SIZE_INCOMBAT )
|
|
{
|
|
// if the noise heard was the fall of a rock
|
|
if ((gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) && ubNoiseType == NOISE_ROCK_IMPACT )
|
|
{
|
|
// give every ELIGIBLE listener an automatic interrupt, since it's
|
|
// reasonable to assume the guy throwing wants to wait for their reaction!
|
|
if (StandardInterruptConditionsMet(pSoldier,NOBODY,FALSE))
|
|
{
|
|
pSoldier->aiData.bInterruptDuelPts = AUTOMATIC_INTERRUPT; // force automatic interrupt
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Calculating int duel pts in noise code, %d has %d points", pSoldier->ubID, pSoldier->aiData.bInterruptDuelPts ) );
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
AI::tactical::AIInputData ai_input(AI::tactical::AIInputData::Auditive(), ubNoiseMaker, sGridNo, bLevel, ubVolume, ubNoiseType);
|
|
AI::tactical::PlanInputData plan_input((gTacticalStatus.uiFlags & TURNBASED)!=0, gTacticalStatus);
|
|
AI::tactical::PlanFactoryLibrary* plan_lib(AI::tactical::PlanFactoryLibrary::instance());
|
|
plan_lib->update_plan(pSoldier->bAIIndex, pSoldier, ai_input);
|
|
}
|
|
|
|
void TellPlayerAboutNoise( SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 ubNoiseDir, STR16 zNoiseMessage )
|
|
{
|
|
UINT8 ubVolumeIndex;
|
|
|
|
// CJC: tweaked the noise categories upwards a bit because our movement noises can be louder now.
|
|
if (ubVolume < 4)
|
|
{
|
|
ubVolumeIndex = 0; // 1-3: faint noise
|
|
}
|
|
else if (ubVolume < 8) // 4-7: definite noise
|
|
{
|
|
ubVolumeIndex = 1;
|
|
}
|
|
else if (ubVolume < 12) // 8-11: loud noise
|
|
{
|
|
ubVolumeIndex = 2;
|
|
}
|
|
else // 12+: very loud noise
|
|
{
|
|
ubVolumeIndex = 3;
|
|
}
|
|
|
|
// display a message about a noise...
|
|
// e.g. Sidney hears a loud splash from/to? the north.
|
|
|
|
if ( ubNoiseMaker != NOBODY && pSoldier->bTeam == gbPlayerNum && pSoldier->bTeam == Menptr[ubNoiseMaker].bTeam )
|
|
{
|
|
#ifdef JA2BETAVERSION
|
|
ScreenMsg( MSG_FONT_RED, MSG_ERROR, L"ERROR! TAKE SCREEN CAPTURE AND TELL CAMFIELD NOW!" );
|
|
ScreenMsg( MSG_FONT_RED, MSG_ERROR, L"%s (%d) heard noise from %s (%d), noise at %dL%d, type %d", pSoldier->name, pSoldier->ubID, Menptr[ubNoiseMaker].name, ubNoiseMaker, sGridNo, bLevel, ubNoiseType );
|
|
#endif
|
|
}
|
|
|
|
// anv: special treatment of NOISE_VOICE - also display taunt message
|
|
if( ubNoiseType == NOISE_VOICE )
|
|
{
|
|
// information about direction etc. only displayed if we don't see noise maker
|
|
if( gbPublicOpplist[gbPlayerNum][ubNoiseMaker] != SEEN_CURRENTLY && pSoldier->aiData.bOppList[ubNoiseMaker] != SEEN_CURRENTLY )
|
|
{
|
|
if( bLevel == pSoldier->pathing.bLevel && ubNoiseType == NOISE_VOICE )
|
|
{
|
|
ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], pDirectionStr[ubNoiseDir] );
|
|
}
|
|
else if ( bLevel > pSoldier->pathing.bLevel )
|
|
{
|
|
// from above!
|
|
ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[6] );
|
|
}
|
|
else
|
|
{
|
|
// from below!
|
|
ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[7] );
|
|
}
|
|
}
|
|
if( ubVolumeIndex > 0 ) // definite noise - we're able to recognize words
|
|
{
|
|
// do we know who said that?
|
|
if( gbPublicOpplist[gbPlayerNum][ubNoiseMaker] == SEEN_CURRENTLY || pSoldier->aiData.bOppList[ubNoiseMaker] == SEEN_CURRENTLY )
|
|
{
|
|
if( gTauntsSettings.fTauntShowPopupBox == TRUE )
|
|
ShowTauntPopupBox( MercPtrs[ubNoiseMaker], zNoiseMessage );
|
|
if( gTauntsSettings.fTauntShowInLog == TRUE )
|
|
ScreenMsg( FONT_GRAY2, MSG_INTERFACE, L"%s: %s", MercPtrs[ubNoiseMaker]->GetName(), zNoiseMessage );
|
|
}
|
|
else
|
|
{
|
|
if( gTauntsSettings.fTauntShowPopupBox == TRUE && gTauntsSettings.fTauntShowPopupBoxIfHeard == TRUE )
|
|
ShowTauntPopupBox( MercPtrs[ubNoiseMaker], zNoiseMessage );
|
|
if( gTauntsSettings.fTauntShowInLog == TRUE && gTauntsSettings.fTauntShowInLogIfHeard == TRUE )
|
|
ScreenMsg( FONT_GRAY2, MSG_INTERFACE, L"%s: %s", pTauntUnknownVoice[0], zNoiseMessage );
|
|
}
|
|
}
|
|
}
|
|
else if ( bLevel == pSoldier->pathing.bLevel || ubNoiseType == NOISE_EXPLOSION || ubNoiseType == NOISE_SCREAM || ubNoiseType == NOISE_ROCK_IMPACT || ubNoiseType == NOISE_GRENADE_IMPACT )
|
|
{
|
|
ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], pDirectionStr[ubNoiseDir] );
|
|
}
|
|
else if ( bLevel > pSoldier->pathing.bLevel )
|
|
{
|
|
// from above!
|
|
ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[6] );
|
|
}
|
|
else
|
|
{
|
|
// from below!
|
|
ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[7] );
|
|
}
|
|
|
|
// if the quote was faint, say something
|
|
if (ubVolumeIndex == 0)
|
|
{
|
|
#ifdef JA2UB
|
|
//Ja25 No meanwhiles
|
|
#else
|
|
if ( !AreInMeanwhile( ) && !( gTacticalStatus.uiFlags & ENGAGED_IN_CONV) && pSoldier->ubTurnsUntilCanSayHeardNoise == 0)
|
|
#endif
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_HEARD_SOMETHING );
|
|
if ( gTacticalStatus.uiFlags & INCOMBAT )
|
|
{
|
|
pSoldier->ubTurnsUntilCanSayHeardNoise = 2;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->ubTurnsUntilCanSayHeardNoise = 5;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//DIGICRAB: Loud Sound Locator
|
|
//show a locator for very loud noises if we are in PLATINUM mode and have an extended ear
|
|
//Madd: if(gGameOptions.ubGameStyle == STYLE_PLATINUM && ubVolumeIndex >= 2)
|
|
if(ubVolumeIndex >= 2)
|
|
{
|
|
// INT8 bSlot;
|
|
|
|
//bSlot = FindObj( pSoldier, EXTENDEDEAR );
|
|
//if ( bSlot == HEAD1POS || bSlot == HEAD2POS)
|
|
if ( FindHearingAid(pSoldier) )
|
|
BeginMultiPurposeLocator(sGridNo, bLevel, (INT8)((gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT )));
|
|
}
|
|
|
|
// flag soldier as having reported noise in a particular direction
|
|
|
|
}
|
|
|
|
void VerifyAndDecayOpplist(SOLDIERTYPE *pSoldier)
|
|
{
|
|
UINT32 uiLoop;
|
|
INT8 *pPersOL; // pointer into soldier's opponent list
|
|
SOLDIERTYPE *pOpponent;
|
|
|
|
// reduce all seen/known opponent's turn counters by 1 (towards 0)
|
|
// 1) verify accuracy of the opplist by testing sight vs known opponents
|
|
// 2) increment opplist value if opponent is known but not currenly seen
|
|
// 3) forget about known opponents who haven't been noticed in some time
|
|
|
|
// if soldier is unconscious, make sure his opplist is wiped out & bail out
|
|
if (pSoldier->stats.bLife < OKLIFE)
|
|
{
|
|
memset(pSoldier->aiData.bOppList,NOT_HEARD_OR_SEEN,sizeof(pSoldier->aiData.bOppList));
|
|
pSoldier->aiData.bOppCnt = 0;
|
|
return;
|
|
}
|
|
|
|
// if any new opponents were seen earlier and not yet radioed
|
|
if (pSoldier->bNewOppCnt)
|
|
{
|
|
#ifdef BETAVERSION
|
|
tempstr = String("VerifyAndDecayOpplist: WARNING - %d(%s) still has %d NEW OPPONENTS - lastCaller %s/%s",
|
|
pSoldier->guynum,ExtMen[pSoldier->guynum].name,pSoldier->newOppCnt,
|
|
LastCallerText[ExtMen[pSoldier->guynum].lastCaller],
|
|
LastCaller2Text[ExtMen[pSoldier->guynum].lastCaller2]);
|
|
|
|
#ifdef TESTVERSION // make this ERROR/BETA again when it's fixed!
|
|
PopMessage(tempstr);
|
|
#endif
|
|
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\n\t%s\n\n",tempstr);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
if (pSoldier->flags.uiStatusFlags & SOLDIER_PC)
|
|
{
|
|
RadioSightings(pSoldier,EVERYBODY,pSoldier->bTeam);
|
|
}
|
|
|
|
pSoldier->bNewOppCnt = 0;
|
|
}
|
|
|
|
// man looks for each of his opponents WHO ARE ALREADY KNOWN TO HIM
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pOpponent = MercSlots[ uiLoop ];
|
|
|
|
// if this merc is active, here, and alive
|
|
if (pOpponent != NULL && pOpponent->stats.bLife)
|
|
{
|
|
// if this merc is on the same team, he's no opponent, so skip him
|
|
if (pSoldier->bTeam == pOpponent->bTeam)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID;
|
|
|
|
// if this opponent is "known" in any way (seen or heard recently)
|
|
if (*pPersOL != NOT_HEARD_OR_SEEN)
|
|
{
|
|
// use both sides actual x,y co-ordinates (neither side's moving)
|
|
ManLooksForMan(pSoldier,pOpponent,VERIFYANDDECAYOPPLIST);
|
|
|
|
// decay opplist value if necessary
|
|
DECAY_OPPLIST_VALUE( *pPersOL );
|
|
/*
|
|
// if opponent was SEEN recently but is NOT visible right now
|
|
if (*pPersOL >= SEEN_THIS_TURN)
|
|
{
|
|
(*pPersOL)++; // increment #turns it's been since last seen
|
|
|
|
// if it's now been longer than the maximum we care to remember
|
|
if (*pPersOL > SEEN_2_TURNS_AGO)
|
|
*pPersOL = 0; // forget that we knew this guy
|
|
}
|
|
else
|
|
{
|
|
// if opponent was merely HEARD recently, not actually seen
|
|
if (*pPersOL <= HEARD_THIS_TURN)
|
|
{
|
|
(*pPersOL)--; // increment #turns it's been since last heard
|
|
|
|
// if it's now been longer than the maximum we care to remember
|
|
if (*pPersOL < HEARD_2_TURNS_AGO)
|
|
*pPersOL = 0; // forget that we knew this guy
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// if any new opponents were seen
|
|
if (pSoldier->bNewOppCnt)
|
|
{
|
|
// turns out this is NOT an error! If this guy was gassed last time he
|
|
// looked, his sight limit was 2 tiles, and now he may no longer be gassed
|
|
// and thus he sees opponents much further away for the first time!
|
|
// - Always happens if you STUNGRENADE an opponent by surprise...
|
|
#ifdef RECORDNET
|
|
fprintf(NetDebugFile,"\tVerifyAndDecayOpplist: d(%s) saw %d new opponents\n",
|
|
pSoldier->guynum,ExtMen[pSoldier->guynum].name,pSoldier->newOppCnt);
|
|
#endif
|
|
|
|
if (pSoldier->flags.uiStatusFlags & SOLDIER_PC)
|
|
RadioSightings(pSoldier,EVERYBODY,pSoldier->bTeam);
|
|
|
|
pSoldier->bNewOppCnt = 0;
|
|
}
|
|
}
|
|
|
|
void DecayIndividualOpplist(SOLDIERTYPE *pSoldier)
|
|
{
|
|
UINT32 uiLoop;
|
|
INT8 *pPersOL; // pointer into soldier's opponent list
|
|
SOLDIERTYPE *pOpponent;
|
|
|
|
// reduce all currently seen opponent's turn counters by 1 (towards 0)
|
|
|
|
// if soldier is unconscious, make sure his opplist is wiped out & bail out
|
|
if (pSoldier->stats.bLife < OKLIFE)
|
|
{
|
|
// must make sure that public opplist is kept to match...
|
|
for ( uiLoop = 0; uiLoop < TOTAL_SOLDIERS; ++uiLoop )
|
|
{
|
|
if ( pSoldier->aiData.bOppList[ uiLoop ] == SEEN_CURRENTLY )
|
|
{
|
|
HandleManNoLongerSeen( pSoldier, MercPtrs[ uiLoop ], &(pSoldier->aiData.bOppList[ uiLoop ]), &(gbPublicOpplist[ pSoldier->bTeam ][ uiLoop ]) );
|
|
}
|
|
}
|
|
//void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT8 * pPersOL, INT8 * pbPublOL )
|
|
|
|
memset(pSoldier->aiData.bOppList,NOT_HEARD_OR_SEEN,sizeof(pSoldier->aiData.bOppList));
|
|
pSoldier->aiData.bOppCnt = 0;
|
|
return;
|
|
}
|
|
|
|
// man looks for each of his opponents WHO IS CURRENTLY SEEN
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop)
|
|
{
|
|
pOpponent = MercSlots[ uiLoop ];
|
|
|
|
// if this merc is active, here, and alive
|
|
if (pOpponent != NULL && pOpponent->stats.bLife)
|
|
{
|
|
// if this merc is on the same team, he's no opponent, so skip him
|
|
if (pSoldier->bTeam == pOpponent->bTeam)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID;
|
|
|
|
// if this opponent is seen currently
|
|
if (*pPersOL == SEEN_CURRENTLY)
|
|
{
|
|
// they are NOT visible now!
|
|
(*pPersOL)++;
|
|
if (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
|
{
|
|
RemoveOneOpponent(pSoldier);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void VerifyPublicOpplistDueToDeath(SOLDIERTYPE *pSoldier)
|
|
{
|
|
UINT32 uiLoop,uiTeamMateLoop;
|
|
INT8 *pPersOL,*pMatePersOL; // pointers into soldier's opponent list
|
|
SOLDIERTYPE *pOpponent,*pTeamMate;
|
|
BOOLEAN bOpponentStillSeen;
|
|
|
|
|
|
// OK, someone died. Anyone that the deceased ALONE saw has to decay
|
|
// immediately in the Public Opplist.
|
|
|
|
|
|
// If deceased didn't see ANYONE, don't bother
|
|
if (pSoldier->aiData.bOppCnt == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
// Deceased looks for each of his opponents who is "seen currently"
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
// first, initialize flag since this will be a "new" opponent
|
|
bOpponentStillSeen = FALSE;
|
|
|
|
// grab a pointer to the "opponent"
|
|
pOpponent = MercSlots[ uiLoop ];
|
|
|
|
// if this opponent is active, here, and alive
|
|
if (pOpponent != NULL && pOpponent->stats.bLife)
|
|
{
|
|
// if this opponent is on the same team, he's no opponent, so skip him
|
|
if (pSoldier->bTeam == pOpponent->bTeam)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// point to what the deceased's personal opplist value is
|
|
pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID;
|
|
|
|
// if this opponent was CURRENTLY SEEN by the deceased (before his
|
|
// untimely demise)
|
|
if (*pPersOL == SEEN_CURRENTLY)
|
|
{
|
|
// then we need to know if any teammates ALSO see this opponent, so loop through
|
|
// trying to find ONE witness to the death...
|
|
for (uiTeamMateLoop = 0; uiTeamMateLoop < guiNumMercSlots; uiTeamMateLoop++)
|
|
{
|
|
// grab a pointer to the potential teammate
|
|
pTeamMate = MercSlots[ uiTeamMateLoop ];
|
|
|
|
// if this teammate is active, here, and alive
|
|
if (pTeamMate != NULL && pTeamMate->stats.bLife)
|
|
{
|
|
// if this opponent is NOT on the same team, then skip him
|
|
if (pTeamMate->bTeam != pSoldier->bTeam)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// point to what the teammate's personal opplist value is
|
|
pMatePersOL = pTeamMate->aiData.bOppList + pOpponent->ubID;
|
|
|
|
// test to see if this value is "seen currently"
|
|
if (*pMatePersOL == SEEN_CURRENTLY)
|
|
{
|
|
// this opponent HAS been verified!
|
|
bOpponentStillSeen = TRUE;
|
|
|
|
// we can stop looking for other witnesses now
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if no witnesses for this opponent, then decay the Public Opplist
|
|
if ( !bOpponentStillSeen )
|
|
{
|
|
DECAY_OPPLIST_VALUE( gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void DecayPublicOpplist(INT8 bTeam)
|
|
{
|
|
UINT32 uiLoop;
|
|
INT8 bNoPubliclyKnownOpponents = TRUE;
|
|
SOLDIERTYPE *pSoldier;
|
|
INT8 *pbPublOL;
|
|
|
|
|
|
//NumMessage("Decay for team #",team);
|
|
|
|
// decay the team's public noise volume, forget public noise gridno if <= 0
|
|
// used to be -1 per turn but that's not fast enough!
|
|
if (gubPublicNoiseVolume[bTeam] > 0)
|
|
{
|
|
if ( gTacticalStatus.uiFlags & INCOMBAT )
|
|
{
|
|
gubPublicNoiseVolume[bTeam] = (UINT8) ( (UINT32) (gubPublicNoiseVolume[bTeam] * 7) / 10 );
|
|
}
|
|
else
|
|
{
|
|
gubPublicNoiseVolume[bTeam] = gubPublicNoiseVolume[bTeam] / 2;
|
|
}
|
|
|
|
if (gubPublicNoiseVolume[bTeam] <= 0)
|
|
{
|
|
gsPublicNoiseGridNo[bTeam] = NOWHERE;
|
|
}
|
|
}
|
|
|
|
// decay the team's Public Opplist
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[uiLoop];
|
|
|
|
// for every active, living soldier on ANOTHER team
|
|
if (pSoldier && pSoldier->stats.bLife && (pSoldier->bTeam != bTeam))
|
|
{
|
|
// hang a pointer to the byte holding team's public opplist for this merc
|
|
pbPublOL = &gbPublicOpplist[bTeam][pSoldier->ubID];
|
|
|
|
if (*pbPublOL == NOT_HEARD_OR_SEEN)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// well, that make this a "publicly known opponent", so nuke that flag
|
|
bNoPubliclyKnownOpponents = FALSE;
|
|
|
|
// if this person has been SEEN recently, but is not currently visible
|
|
if (*pbPublOL >= SEEN_THIS_TURN)
|
|
{
|
|
(*pbPublOL)++; // increment how long it's been
|
|
}
|
|
else
|
|
{
|
|
// if this person has been only HEARD recently
|
|
if (*pbPublOL <= HEARD_THIS_TURN)
|
|
{
|
|
(*pbPublOL)--; // increment how long it's been
|
|
}
|
|
}
|
|
|
|
// if it's been longer than the maximum we care to remember
|
|
if ((*pbPublOL > OLDEST_SEEN_VALUE) || (*pbPublOL < OLDEST_HEARD_VALUE))
|
|
{
|
|
#ifdef RECORDOPPLIST
|
|
fprintf(OpplistFile,"UpdatePublic (DecayPublicOpplist) for team %d about %d\n",team,pSoldier->guynum);
|
|
#endif
|
|
|
|
// forget about him,
|
|
// and also forget where he was last seen (it's been too long)
|
|
// this is mainly so POINT_PATROL guys don't SEEK_OPPONENTs forever
|
|
UpdatePublic(bTeam,pSoldier->ubID,NOT_HEARD_OR_SEEN,NOWHERE,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if all opponents are publicly unknown (NOT_HEARD_OR_SEEN)
|
|
if (bNoPubliclyKnownOpponents)
|
|
{
|
|
// forget about the last radio alert (ie. throw away who made the call)
|
|
// this is mainly so POINT_PATROL guys don't SEEK_FRIEND forever after
|
|
gTacticalStatus.Team[bTeam].ubLastMercToRadio = NOBODY;
|
|
}
|
|
|
|
// decay watched locs as well
|
|
DecayWatchedLocs( bTeam );
|
|
}
|
|
|
|
// bit of a misnomer; this is now decay all opplists
|
|
void NonCombatDecayPublicOpplist( UINT32 uiTime )
|
|
{
|
|
UINT32 cnt;
|
|
|
|
if ( uiTime - gTacticalStatus.uiTimeSinceLastOpplistDecay >= TIME_BETWEEN_RT_OPPLIST_DECAYS)
|
|
{
|
|
// decay!
|
|
for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
|
|
{
|
|
if ( MercSlots[ cnt ] )
|
|
{
|
|
VerifyAndDecayOpplist( MercSlots[ cnt ] );
|
|
}
|
|
}
|
|
|
|
|
|
for( cnt = 0; cnt < MAXTEAMS; cnt++ )
|
|
{
|
|
if ( gTacticalStatus.Team[ cnt ].bMenInSector > 0 )
|
|
{
|
|
// decay team's public opplist
|
|
DecayPublicOpplist( (INT8)cnt );
|
|
}
|
|
}
|
|
// update time
|
|
gTacticalStatus.uiTimeSinceLastOpplistDecay = uiTime;
|
|
}
|
|
}
|
|
|
|
void RecalculateOppCntsDueToNoLongerNeutral( SOLDIERTYPE * pSoldier )
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE * pOpponent;
|
|
|
|
pSoldier->aiData.bOppCnt = 0;
|
|
|
|
if (!pSoldier->aiData.bNeutral)
|
|
{
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pOpponent = MercSlots[uiLoop];
|
|
|
|
// for every active, living soldier on ANOTHER team
|
|
if (pOpponent && pOpponent->stats.bLife && !pOpponent->aiData.bNeutral && (pOpponent->bTeam != pSoldier->bTeam) && (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide)) )
|
|
{
|
|
if ( pSoldier->aiData.bOppList[pOpponent->ubID] == SEEN_CURRENTLY )
|
|
{
|
|
AddOneOpponent( pSoldier );
|
|
}
|
|
if ( pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY )
|
|
{
|
|
// WANNE: Chris, I reverted BUGZILLA #338 fix, because this leads to big problems on opponent count with enemies!
|
|
// have to add to opponent's oppcount as well since we just became non-neutral
|
|
//CHRISL: If we do this, Bloodcats get counted at opponents multiple times and never get removed from the OppCnt variable.
|
|
AddOneOpponent( pOpponent );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RecalculateOppCntsDueToBecomingNeutral( SOLDIERTYPE * pSoldier )
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE * pOpponent;
|
|
|
|
if (pSoldier->aiData.bNeutral)
|
|
{
|
|
pSoldier->aiData.bOppCnt = 0;
|
|
|
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pOpponent = MercSlots[uiLoop];
|
|
|
|
// for every active, living soldier on ANOTHER team
|
|
if (pOpponent && pOpponent->stats.bLife && !pOpponent->aiData.bNeutral && (pOpponent->bTeam != pSoldier->bTeam) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
|
{
|
|
if ( pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY )
|
|
{
|
|
// have to rem from opponent's oppcount as well since we just became neutral
|
|
RemoveOneOpponent( pOpponent );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NoticeUnseenAttacker( SOLDIERTYPE * pAttacker, SOLDIERTYPE * pDefender, INT8 bReason )
|
|
{
|
|
INT8 bOldOppList;
|
|
BOOLEAN fSeesAttacker = FALSE;
|
|
INT8 bDirection;
|
|
BOOLEAN fMuzzleFlash = FALSE;
|
|
|
|
if ( !(gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( pAttacker->usAttackingWeapon == DART_GUN )
|
|
{
|
|
// rarely noticed
|
|
if ( SkillCheck( pDefender, NOTICE_DART_CHECK, 0 ) < 0)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// do we need to do checks for life/breath here?
|
|
|
|
if ( pDefender->ubBodyType == LARVAE_MONSTER || (pDefender->flags.uiStatusFlags & SOLDIER_VEHICLE && pDefender->bTeam == OUR_TEAM) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
bOldOppList = pDefender->aiData.bOppList[ pAttacker->ubID ];
|
|
// check LOS, considering we are now aware of the attacker
|
|
// ignore muzzle flashes when must turning head
|
|
if ( pAttacker->flags.fMuzzleFlash )
|
|
{
|
|
bDirection = atan8( pDefender->sX,pDefender->sY, pAttacker->sX, pAttacker->sY );
|
|
if ( pDefender->ubDirection != bDirection && pDefender->ubDirection != gOneCDirection[ bDirection ] && pDefender->ubDirection != gOneCCDirection[ bDirection ] )
|
|
{
|
|
// temporarily turn off muzzle flash so DistanceVisible can be calculated without it
|
|
pAttacker->flags.fMuzzleFlash = FALSE;
|
|
fMuzzleFlash = TRUE;
|
|
}
|
|
}
|
|
|
|
if (SoldierToSoldierLineOfSightTest( pDefender, pAttacker, TRUE, CALC_FROM_WANTED_DIR ) != 0)
|
|
{
|
|
fSeesAttacker = TRUE;
|
|
}
|
|
if ( fMuzzleFlash )
|
|
{
|
|
pAttacker->flags.fMuzzleFlash = TRUE;
|
|
}
|
|
|
|
if (fSeesAttacker)
|
|
{
|
|
ManSeesMan( pDefender, pAttacker, pAttacker->sGridNo, pAttacker->pathing.bLevel, NOTICEUNSEENATTACKER, CALLER_UNKNOWN );
|
|
|
|
// newOppCnt not needed here (no radioing), must get reset right away
|
|
// CJC: Huh? well, leave it in for now
|
|
pDefender->bNewOppCnt = 0;
|
|
|
|
|
|
if (pDefender->bTeam == gbPlayerNum)
|
|
{
|
|
// EXPERIENCE GAIN (5): Victim notices/sees a previously UNSEEN attacker
|
|
StatChange( pDefender, EXPERAMT, 5, FALSE );
|
|
|
|
// mark attacker as being SEEN right now
|
|
RadioSightings( pDefender, pAttacker->ubID, pDefender->bTeam );
|
|
|
|
}
|
|
// NOTE: ENEMIES DON'T REPORT A SIGHTING PUBLICLY UNTIL THEY RADIO IT IN!
|
|
else
|
|
{
|
|
// go to threatening stance
|
|
ReevaluateEnemyStance( pDefender, pDefender->usAnimState );
|
|
}
|
|
}
|
|
else // victim NOTICED the attack, but CAN'T SEE the actual attacker
|
|
{
|
|
SetNewSituation( pDefender ); // re-evaluate situation
|
|
|
|
// if victim's alert status is only GREEN or YELLOW
|
|
if (pDefender->aiData.bAlertStatus < STATUS_RED)
|
|
{
|
|
// then this soldier goes to status RED, has proof of enemy presence
|
|
pDefender->aiData.bAlertStatus = STATUS_RED;
|
|
CheckForChangingOrders( pDefender );
|
|
}
|
|
|
|
UpdatePersonal( pDefender, pAttacker->ubID, HEARD_THIS_TURN, pAttacker->sGridNo, pAttacker->pathing.bLevel );
|
|
|
|
// if the victim is a human-controlled soldier, instantly report publicly
|
|
if (pDefender->flags.uiStatusFlags & SOLDIER_PC)
|
|
{
|
|
// mark attacker as having been PUBLICLY heard THIS TURN & remember where
|
|
UpdatePublic( pDefender->bTeam, pAttacker->ubID, HEARD_THIS_TURN, pAttacker->sGridNo, pAttacker->pathing.bLevel );
|
|
}
|
|
}
|
|
|
|
if ( !gGameOptions.fImprovedInterruptSystem || (gGameOptions.fImprovedInterruptSystem && gGameExternalOptions.fAllowInstantInterruptsOnSight) )
|
|
{
|
|
if ( StandardInterruptConditionsMet( pDefender, pAttacker->ubID, bOldOppList ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, standard conditions are met; defender %d, attacker %d", pDefender->ubID, pAttacker->ubID ) );
|
|
|
|
// calculate the interrupt duel points
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for defender in NUA" );
|
|
pDefender->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pDefender, pAttacker->ubID, FALSE);
|
|
}
|
|
else
|
|
{
|
|
pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
}
|
|
|
|
// say quote
|
|
|
|
if (pDefender->aiData.bInterruptDuelPts != NO_INTERRUPT)
|
|
{
|
|
// check for possible interrupt and handle control change if it happens
|
|
// this code is basically ResolveInterruptsVs for 1 man only...
|
|
|
|
// calculate active soldier's dueling pts for the upcoming interrupt duel
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for attacker in NUA" );
|
|
pAttacker->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pAttacker, pDefender->ubID, FALSE );
|
|
if ( InterruptDuel( pDefender, pAttacker ) )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, defender pts %d, attacker pts %d, defender gets interrupt", pDefender->aiData.bInterruptDuelPts, pAttacker->aiData.bInterruptDuelPts ) );
|
|
AddToIntList( pAttacker->ubID, FALSE, TRUE);
|
|
AddToIntList( pDefender->ubID, TRUE, TRUE);
|
|
DoneAddingToIntList( pDefender, TRUE, SIGHTINTERRUPT );
|
|
}
|
|
// either way, clear out both sides' duelPts fields to prepare next duel
|
|
pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
#ifdef DEBUG_INTERRUPTS
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pDefender->ubID ) );
|
|
#endif
|
|
pAttacker->aiData.bInterruptDuelPts = NO_INTERRUPT;
|
|
#ifdef DEBUG_INTERRUPTS
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pAttacker->ubID ) );
|
|
#endif
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void CheckForAlertWhenEnemyDies( SOLDIERTYPE * pDyingSoldier )
|
|
{
|
|
UINT8 ubID;
|
|
SOLDIERTYPE * pSoldier;
|
|
INT8 bDir;
|
|
INT16 sDistAway, sDistVisible;
|
|
|
|
for ( ubID = gTacticalStatus.Team[ pDyingSoldier->bTeam ].bFirstID; ubID <= gTacticalStatus.Team[ pDyingSoldier->bTeam ].bLastID; ubID++ )
|
|
{
|
|
|
|
pSoldier = MercPtrs[ ubID ];
|
|
|
|
if ( pSoldier->bActive && pSoldier->bInSector && (pSoldier != pDyingSoldier) && (pSoldier->stats.bLife >= OKLIFE) && (pSoldier->aiData.bAlertStatus < STATUS_RED ) )
|
|
{
|
|
// this guy might have seen the man die
|
|
|
|
// distance we "see" then depends on the direction he is located from us
|
|
bDir = atan8(pSoldier->sX,pSoldier->sY,pDyingSoldier->sX,pDyingSoldier->sY);
|
|
sDistVisible = DistanceVisible( pSoldier, pSoldier->pathing.bDesiredDirection, bDir, pDyingSoldier->sGridNo, pDyingSoldier->pathing.bLevel );
|
|
sDistAway = PythSpacesAway( pSoldier->sGridNo, pDyingSoldier->sGridNo );
|
|
|
|
// if we see close enough to see the soldier
|
|
if (sDistAway <= sDistVisible)
|
|
{
|
|
// and we can trace a line of sight to his x,y coordinates
|
|
// assume enemies are always aware of their buddies...
|
|
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pDyingSoldier->sGridNo, pDyingSoldier->pathing.bLevel, 0, TRUE, sDistVisible ) )
|
|
{
|
|
pSoldier->aiData.bAlertStatus = STATUS_RED;
|
|
CheckForChangingOrders( pSoldier );
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOLEAN ArmyKnowsOfPlayersPresence( void )
|
|
{
|
|
UINT8 ubID;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
// if anyone is still left...
|
|
if (gTacticalStatus.Team[ ENEMY_TEAM ].bTeamActive && gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector > 0 )
|
|
{
|
|
for ( ubID = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; ubID <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; ubID++ )
|
|
{
|
|
pSoldier = MercPtrs[ ubID ];
|
|
|
|
if ( pSoldier->bActive && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE) && (pSoldier->aiData.bAlertStatus >= STATUS_RED ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN MercSeesCreature( SOLDIERTYPE * pSoldier )
|
|
{
|
|
UINT8 ubID;
|
|
|
|
if (pSoldier->aiData.bOppCnt > 0)
|
|
{
|
|
for ( ubID = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; ubID <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; ubID++ )
|
|
{
|
|
if ( (pSoldier->aiData.bOppList[ ubID ] == SEEN_CURRENTLY) && (MercPtrs[ ubID ]->flags.uiStatusFlags & SOLDIER_MONSTER) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
INT8 FindUnusedWatchedLoc( UINT8 ubID )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
|
|
{
|
|
// WANNE: I think this was a bug, should be != NOWHERE!
|
|
//if ( gsWatchedLoc[ ubID ][ bLoop ] == NOWHERE )
|
|
|
|
if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]))
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( -1 );
|
|
}
|
|
|
|
INT8 FindWatchedLocWithLessThanXPointsLeft( UINT8 ubID, UINT8 ubPointLimit )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
|
|
{
|
|
if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]) && gubWatchedLocPoints[ ubID ][ bLoop ] <= ubPointLimit )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
return( -1 );
|
|
}
|
|
|
|
INT8 FindWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel )
|
|
{
|
|
INT8 bLoop;
|
|
|
|
for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
|
|
{
|
|
if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]) && gbWatchedLocLevel[ ubID ][ bLoop ] == bLevel )
|
|
{
|
|
if ( SpacesAway( gsWatchedLoc[ ubID ][ bLoop ], sGridNo ) <= WATCHED_LOC_RADIUS )
|
|
{
|
|
return( bLoop );
|
|
}
|
|
}
|
|
}
|
|
return( -1 );
|
|
}
|
|
|
|
INT8 GetWatchedLocPoints( UINT8 ubID, INT32 sGridNo, INT8 bLevel )
|
|
{
|
|
INT8 bLoc;
|
|
|
|
bLoc = FindWatchedLoc( ubID, sGridNo, bLevel );
|
|
if (bLoc != -1)
|
|
{
|
|
#ifdef JA2BETAVERSION
|
|
/*
|
|
if (gubWatchedLocPoints[ ubID ][ bLoc ] > 1)
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Soldier %d getting %d points for interrupt in watched location", ubID, gubWatchedLocPoints[ ubID ][ bLoc ] - 1 );
|
|
}
|
|
*/
|
|
#endif
|
|
// one loc point is worth nothing, so return number minus 1
|
|
|
|
// experiment with 1 loc point being worth 1 point
|
|
return( gubWatchedLocPoints[ ubID ][ bLoc ] );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
|
|
INT8 GetHighestVisibleWatchedLoc( UINT8 ubID )
|
|
{
|
|
INT8 bLoop;
|
|
INT8 bHighestLoc = -1;
|
|
INT8 bHighestPoints = 0;
|
|
|
|
for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
|
|
{
|
|
if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]) && gubWatchedLocPoints[ ubID ][ bLoop ] > bHighestPoints )
|
|
{
|
|
// look at standing height
|
|
if ( SoldierTo3DLocationLineOfSightTest( MercPtrs[ ubID ], gsWatchedLoc[ ubID ][ bLoop ], gbWatchedLocLevel[ ubID ][ bLoop ], 3, TRUE, CALC_FROM_WANTED_DIR ) )
|
|
{
|
|
bHighestLoc = bLoop;
|
|
bHighestPoints = gubWatchedLocPoints[ ubID ][ bLoop ];
|
|
}
|
|
}
|
|
}
|
|
return( bHighestLoc );
|
|
}
|
|
|
|
INT8 GetHighestWatchedLocPoints( UINT8 ubID )
|
|
{
|
|
INT8 bLoop;
|
|
INT8 bHighestPoints = 0;
|
|
|
|
for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
|
|
{
|
|
if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]) && gubWatchedLocPoints[ ubID ][ bLoop ] > bHighestPoints )
|
|
{
|
|
bHighestPoints = gubWatchedLocPoints[ ubID ][ bLoop ];
|
|
}
|
|
}
|
|
return( bHighestPoints );
|
|
}
|
|
|
|
|
|
void CommunicateWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel, UINT8 ubPoints )
|
|
{
|
|
UINT8 ubLoop;
|
|
INT8 bTeam, bLoopPoint, bPoint;
|
|
|
|
bTeam = MercPtrs[ ubID ]->bTeam;
|
|
|
|
for ( ubLoop = gTacticalStatus.Team[ bTeam ].bFirstID; ubLoop < gTacticalStatus.Team[ bTeam ].bLastID; ubLoop++ )
|
|
{
|
|
if ( ubLoop == ubID || MercPtrs[ ubLoop ]->bActive == FALSE || MercPtrs[ ubLoop ]->bInSector == FALSE || MercPtrs[ ubLoop ]->stats.bLife < OKLIFE )
|
|
{
|
|
continue;
|
|
}
|
|
bLoopPoint = FindWatchedLoc( ubLoop, sGridNo, bLevel );
|
|
if ( bLoopPoint == -1 )
|
|
{
|
|
// add this as a watched point
|
|
bPoint = FindUnusedWatchedLoc( ubLoop );
|
|
if (bPoint == -1)
|
|
{
|
|
// if we have a point with only 1 point left, replace it
|
|
bPoint = FindWatchedLocWithLessThanXPointsLeft( ubLoop, ubPoints );
|
|
}
|
|
if (bPoint != -1)
|
|
{
|
|
gsWatchedLoc[ ubLoop ][ bPoint ] = sGridNo;
|
|
gbWatchedLocLevel[ ubLoop ][ bPoint ] = bLevel;
|
|
gubWatchedLocPoints[ ubLoop ][ bPoint ] = ubPoints;
|
|
gfWatchedLocReset[ ubLoop ][ bPoint ] = FALSE;
|
|
gfWatchedLocHasBeenIncremented[ ubLoop ][ bPoint ] = TRUE;
|
|
}
|
|
// else no points available!
|
|
}
|
|
else
|
|
{
|
|
// increment to max
|
|
gubWatchedLocPoints[ ubLoop ][ bLoopPoint ] = __max( gubWatchedLocPoints[ ubLoop ][ bLoopPoint ], ubPoints );
|
|
|
|
gfWatchedLocReset[ ubLoop ][ bLoopPoint ] = FALSE;
|
|
gfWatchedLocHasBeenIncremented[ ubLoop ][ bLoopPoint ] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void IncrementWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel )
|
|
{
|
|
INT8 bPoint;
|
|
|
|
bPoint = FindWatchedLoc( ubID, sGridNo, bLevel );
|
|
if (bPoint == -1)
|
|
{
|
|
// try adding point
|
|
bPoint = FindUnusedWatchedLoc( ubID );
|
|
if (bPoint == -1)
|
|
{
|
|
// if we have a point with only 1 point left, replace it
|
|
bPoint = FindWatchedLocWithLessThanXPointsLeft( ubID, 1 );
|
|
}
|
|
|
|
if (bPoint != -1)
|
|
{
|
|
gsWatchedLoc[ ubID ][ bPoint ] = sGridNo;
|
|
gbWatchedLocLevel[ ubID ][ bPoint ] = bLevel;
|
|
gubWatchedLocPoints[ ubID ][ bPoint ] = 1;
|
|
gfWatchedLocReset[ ubID ][ bPoint ] = FALSE;
|
|
gfWatchedLocHasBeenIncremented[ ubID ][ bPoint ] = TRUE;
|
|
|
|
CommunicateWatchedLoc( ubID, sGridNo, bLevel, 1 );
|
|
}
|
|
// otherwise abort; no points available
|
|
}
|
|
else
|
|
{
|
|
if ( !gfWatchedLocHasBeenIncremented[ ubID ][ bPoint ] && gubWatchedLocPoints[ ubID ][ bPoint ] < MAX_WATCHED_LOC_POINTS )
|
|
{
|
|
gubWatchedLocPoints[ ubID ][ bPoint ]++;
|
|
CommunicateWatchedLoc( ubID, sGridNo, bLevel, gubWatchedLocPoints[ ubID ][ bPoint ] );
|
|
}
|
|
gfWatchedLocReset[ ubID ][ bPoint ] = FALSE;
|
|
gfWatchedLocHasBeenIncremented[ ubID ][ bPoint ] = TRUE;
|
|
}
|
|
}
|
|
|
|
void SetWatchedLocAsUsed( UINT8 ubID, INT32 sGridNo, INT8 bLevel )
|
|
{
|
|
INT8 bPoint;
|
|
|
|
bPoint = FindWatchedLoc( ubID, sGridNo, bLevel );
|
|
if (bPoint != -1)
|
|
{
|
|
gfWatchedLocReset[ ubID ][ bPoint ] = FALSE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN WatchedLocLocationIsEmpty( INT32 sGridNo, INT8 bLevel, INT8 bTeam )
|
|
{
|
|
// look to see if there is anyone near the watched loc who is not on this team
|
|
UINT8 ubID;
|
|
INT32 sTempGridNo;
|
|
INT16 sX, sY;
|
|
|
|
for ( sY = -WATCHED_LOC_RADIUS; sY <= WATCHED_LOC_RADIUS; sY++ )
|
|
{
|
|
for ( sX = -WATCHED_LOC_RADIUS; sX <= WATCHED_LOC_RADIUS; sX++ )
|
|
{
|
|
sTempGridNo = sGridNo + sX + sY * WORLD_ROWS;
|
|
if ( sTempGridNo < 0 || sTempGridNo >= WORLD_MAX )
|
|
{
|
|
continue;
|
|
}
|
|
ubID = WhoIsThere2( sTempGridNo, bLevel );
|
|
if ( ubID != NOBODY && MercPtrs[ ubID ]->bTeam != bTeam )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
void DecayWatchedLocs( INT8 bTeam )
|
|
{
|
|
UINT8 cnt, cnt2;
|
|
|
|
// loop through all soldiers
|
|
for ( cnt = gTacticalStatus.Team[ bTeam ].bFirstID; cnt <= gTacticalStatus.Team[ bTeam ].bLastID; cnt++ )
|
|
{
|
|
// for each watched location
|
|
for ( cnt2 = 0; cnt2 < NUM_WATCHED_LOCS; cnt2++ )
|
|
{
|
|
if (!TileIsOutOfBounds(gsWatchedLoc[ cnt ][ cnt2 ]) && WatchedLocLocationIsEmpty( gsWatchedLoc[ cnt ][ cnt2 ], gbWatchedLocLevel[ cnt ][ cnt2 ], bTeam ) )
|
|
{
|
|
// if the reset flag is still set, then we should decay this point
|
|
if (gfWatchedLocReset[ cnt ][ cnt2 ])
|
|
{
|
|
// turn flag off again
|
|
gfWatchedLocReset[ cnt ][ cnt2 ] = FALSE;
|
|
|
|
// halve points
|
|
gubWatchedLocPoints[ cnt ][ cnt2 ] /= 2;
|
|
// if points have reached 0, then reset the location
|
|
if (gubWatchedLocPoints[ cnt ][ cnt2 ] == 0)
|
|
{
|
|
gsWatchedLoc[ cnt ][ cnt2 ] = NOWHERE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// flag was false so set to true (will be reset if new people seen there next turn)
|
|
gfWatchedLocReset[ cnt ][ cnt2 ] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MakeBloodcatsHostile( void )
|
|
{
|
|
INT32 iLoop;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
iLoop = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID;
|
|
|
|
for (pSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; iLoop++,pSoldier++ )
|
|
{
|
|
if ( pSoldier->ubBodyType == BLOODCAT && pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 )
|
|
{
|
|
SetSoldierNonNeutral( pSoldier );
|
|
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
|
|
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
CheckForPotentialAddToBattleIncrement( pSoldier );
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
BOOLEAN SoldierHasLimitedVision(SOLDIERTYPE * pSoldier)
|
|
{
|
|
if ( gGameExternalOptions.gfAllowLimitedVision || GetPercentTunnelVision(pSoldier) > 0 )
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef JA2UB
|
|
INT32 MaxDistanceVisible( void )
|
|
{
|
|
return( STRAIGHT * 2 );
|
|
}
|
|
#endif
|