Files
source/Tactical/opplist.cpp
T
Sevenfm 904fae7a96 CancelDrag, StartDrag: update interface panel to change drag icon status.
DrawTraitRadius uses usColour.
Allow to start dragging from any stance, soldier will crouch automatically.
Show draggable objects when drag skill menu is active.
Press [\] key to start dragging object/solder/corpse in front of merc.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@9369 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2022-04-24 18:21:44 +00:00

7890 lines
256 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
#include "Vehicles.h"
#endif
#ifdef JA2UB
#include "Ja25_Tactical.h"
#endif
#include "GameInitOptionsScreen.h"
#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 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 BOOLEAN gfLightningInProgress;
extern BOOLEAN gfHaveSeenSomeone;
extern UINT8 ubRealAmbientLightLevel;
//end rain
INT16 AdjustMaxSightRangeForEnvEffects( SOLDIERTYPE *pSoldier, INT8 bLightLevel, INT16 sDistVisible )
{
INT16 sNewDist = sDistVisible * gGameExternalOptions.ubBrightnessVisionMod[bLightLevel] / 100;
// Adjust it based on weather...
if ( !pSoldier->bSectorZ )
{
FLOAT weatherpenalty = gGameExternalOptions.dVisDistDecrease[SectorInfo[SECTOR( pSoldier->sSectorX, pSoldier->sSectorY )].usWeather];
FLOAT appliedpenalty = 1.0f;
if ( HAS_SKILL_TRAIT( pSoldier, SURVIVAL_NT ) && (gGameOptions.fNewTraitSystem) )
appliedpenalty = min( 1.0f, max( 0.0f, appliedpenalty - gSkillTraitValues.dSVWeatherPenaltiesReduction * NUM_SKILL_TRAITS( pSoldier, SURVIVAL_NT ) ) );
sNewDist -= (INT16)(sNewDist * weatherpenalty * appliedpenalty);
//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) || ( 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);
// 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) &&
(!UsingImprovedInterruptSystem() || 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 ( zDiffSetting[gGameOptions.ubDifficultyLevel].bRadioSightings )
{
// 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 ( zDiffSetting[gGameOptions.ubDifficultyLevel].bRadioSightings2 )
{
// don't allow admins to radio
// silversurfer: Why not? Removed just like above.
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, this->IsCowering(), GetPercentTunnelVision(this) );
}
return DistanceVisible( this, (SoldierHasLimitedVision(this) ? this->pathing.bDesiredDirection : DIRECTION_IRRELEVANT), DIRECTION_IRRELEVANT, sGridNo, bLevel, this->IsCowering(), GetPercentTunnelVision(this));
}
INT16 DistanceVisible(SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, INT32 sSubjectGridNo, INT8 bLevel, const BOOLEAN& isCowering, const UINT8& tunnelVision)
{
INT16 sDistVisible;
INT8 bLightLevel;
BOOLEAN sideViewLimit = FALSE;
SOLDIERTYPE* pSubject = SimpleFindSoldier( sSubjectGridNo, bLevel );
INT16 tunnelVisionInPercent = 0;
if (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER)
{
if ( !pSubject )
{
return( FALSE );
}
return( DistanceSmellable( pSoldier, pSubject ) );
}
if (pSoldier->bBlindedCounter > 0)
{
// we're bliiiiiiiiind!!!
return( 0 );
}
// sevenfm: if soldier is unconscious, he can't see anything
if ( pSoldier->bCollapsed && pSoldier->bBreath == 0 )
{
return( 0 );
}
// Bob: if gridNo isn't set, this would cause a access violation later on
if (pSoldier->sGridNo < 0) {
// ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"DistanceVisible(): Caught bad LOS distance check!");
return(0);
}
// anv: some places in vehicle don't give passenger any view outside
INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier );
if( bSeatIndex != (-1) )
{
SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier ->iVehicleId );
// need to check this even if bSubjectDir is DIRECTION_IRRELEVANT
if( gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[ bSeatIndex ].fBlockedView )
{
return( 0 );
}
}
if ( bFacingDir == DIRECTION_IRRELEVANT && ARMED_VEHICLE( 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 ( !ARMED_VEHICLE( 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 == ANGLE && (pSoldier->bTeam == OUR_TEAM || pSoldier->aiData.bAlertStatus >= STATUS_RED ) )
{
sDistVisible = STRAIGHT;
}
if ( sDistVisible != STRAIGHT || ( fLimitedVision && (bFacingDir != bSubjectDir) ) )
{
tunnelVisionInPercent = tunnelVision;
}
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);
}
}
// Flugente: we only apply tunnelvision now, after we've possibly extended the sight range, which results in finer differentiation of effects
if ( tunnelVisionInPercent > 0 )
{
sideViewLimit = TRUE;
sDistVisible = sDistVisible * (100 - tunnelVisionInPercent) / 100;
}
}
}
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 )
{
// Make sure character is cowering.
if (isCowering)
{
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 ( (ARMED_VEHICLE( pSoldier ) && sDistVisible > 0) || (pSubject && ARMED_VEHICLE( pSubject )) )
{
#if 0
if ( ARMED_VEHICLE(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 ( ARMED_VEHICLE( pSoldier ) || ENEMYROBOT( 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;
if (HAS_SKILL_TRAIT( pSoldier, SNITCH_NT ))
bHearing += gSkillTraitValues.ubSNTHearingRangeBonus;
}
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;
}
// adjust for weather
if ( !pSoldier->bSectorZ )
{
FLOAT weatherpenalty = gGameExternalOptions.dHearingReduction[SectorInfo[SECTOR( pSoldier->sSectorX, pSoldier->sSectorY )].usWeather];
// Added a feature to reduce rain effect on regaining breath with Ranger trait - SANDRO
FLOAT appliedpenalty = 1.0f;
if ( HAS_SKILL_TRAIT( pSoldier, SURVIVAL_NT ) && gGameOptions.fNewTraitSystem )
appliedpenalty = min( 1.0f, max( 0.0f, appliedpenalty - gSkillTraitValues.dSVWeatherPenaltiesReduction * NUM_SKILL_TRAITS( pSoldier, SURVIVAL_NT ) ) );
bHearing -= (INT16)(bHearing * weatherpenalty * appliedpenalty);
}
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
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: 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, pSoldier->IsCowering(), GetPercentTunnelVision(pSoldier));
//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
if ( pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
{
// Flugente: note that this enemy has been seen by mercs this turn
if ( pOpponent->bTeam == ENEMY_TEAM && pSoldier->bTeam == OUR_TEAM )
pOpponent->usSoldierFlagMask |= SOLDIER_ENEMY_OBSERVEDTHISTURN;
}
// sevenfm: if soldier is unconscious, he can't see anybody
if ( pSoldier->bCollapsed && pSoldier->bBreath == 0 )
{
return;
}
// 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!
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: NPC with profile: change orders, reset action"));
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 ) )
{
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: NPC: Angel code"));
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->usSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) )
{
// only if this guy isn't disguised himself!
if ( (pOpponent->usSoldierFlagMask & (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!
DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: assasin: 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);
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);
if ( ! (gTacticalStatus.uiFlags & INCOMBAT) )
{
EnterCombatMode( pSoldier->bTeam );
}
}
}
}
else if ( pSoldier->ubCivilianGroup == HICKS_CIV_GROUP && CheckFact( FACT_HICKS_MARRIED_PLAYER_MERC, 0 ) == FALSE && pSoldier->RecognizeAsCombatant( pOpponent->ubID ) )
{
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);
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.
UINT8 DiffLevel;
if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
DiffLevel = 1;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
DiffLevel = 2;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
DiffLevel = 3;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
DiffLevel = 4;
else
DiffLevel = 1;
if ( gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ 0 ].PlacementType != BLOODCAT_PLACEMENT_STATIC ||
gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ DiffLevel - 1 ].ubFactionAffiliation == NON_CIV_GROUP ||
gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ DiffLevel - 1 ].ubFactionAffiliation == QUEENS_CIV_GROUP )
/*
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->IsAssassin() && pSoldier->usSoldierFlagMask & (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->usSoldierFlagMask & 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->ubID );
}
// 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->ubID );
}
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
// sevenfm: only call SetNewSituation if location is different to reduce frequency of AI re-evaluation
//if ((pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_THIS_TURN) || (gsLastKnownOppLoc[pSoldier->ubID][pOpponent->ubID] != sOppGridNo))
if (KnownLocation(pSoldier, pOpponent->ubID) != sOppGridNo || KnownLevel(pSoldier, pOpponent->ubID) != bOppLevel)
{
SetNewSituation( pSoldier ); // force the looker to re-evaluate
// anv: simulate informing buddies about detected enemy's position
// sevenfm: check that he is really new
//if( gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] != SEEN_CURRENTLY && gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] != SEEN_THIS_TURN )
if (gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] < 1 && gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] < SEEN_CURRENTLY)
PossiblyStartEnemyTaunt( pSoldier, TAUNT_INFORM_ABOUT, pOpponent->ubID );
}
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->usSoldierFlagMask & 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, TOTAL_SOLDIERS);
}
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->usSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) ) == 0 )
{
// Flugente: apparently the goal was to have mercs only announce enemies shorter occasionally
if ( Chance( gGameExternalOptions.iChanceSayAnnoyingPhrase ) )
{
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
}
else
{
pSoldier->DoMercBattleSound( BATTLE_SOUND_ENEMY );
}
}
}
}
}
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->usSoldierFlagMask & (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 && pSoldier->ubProfile != NO_PROFILE && (
gMercProfiles[MercPtrs[gusSelectedSoldier]->ubProfile].Type == PROFILETYPE_AIM ||
gMercProfiles[MercPtrs[gusSelectedSoldier]->ubProfile].Type == PROFILETYPE_MERC ||
gMercProfiles[MercPtrs[gusSelectedSoldier]->ubProfile].Type == PROFILETYPE_RPC ||
gMercProfiles[MercPtrs[gusSelectedSoldier]->ubProfile].Type == PROFILETYPE_IMP ) )
{
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;
case SOLDIER_CLASS_ZOMBIE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" ); break;
case SOLDIER_CLASS_BANDIT: gprintf( 320, LINE_HEIGHT * ubLine, L"(Bandit)" ); break;
case SOLDIER_CLASS_ROBOT: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Robot)" ); break;
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
#define VEHICLE_FAST_MOVEMENT_NOISE 25
#define VEHICLE_NORMAL_MOVEMENT_NOISE 15
UINT8 MovementNoise(SOLDIERTYPE *pSoldier)
{
INT32 iStealthSkill, iRoll;
INT16 sMaxVolume, sVolume;
INT8 bBandaged, bEffLife;
// anv: vehicle and passengers
if (pSoldier->flags.uiStatusFlags & (SOLDIER_DRIVER | SOLDIER_PASSENGER))
{
return(0);
}
else if (pSoldier->flags.uiStatusFlags & (SOLDIER_VEHICLE))
{
if (pSoldier->usAnimState == RUNNING)
{
// driving fast makes engine work louder
return(VEHICLE_FAST_MOVEMENT_NOISE);
}
else
{
return(VEHICLE_NORMAL_MOVEMENT_NOISE);
}
}
// anv: additional tile properties
// modify amount of noise and stealth difficulty depending on surface type
INT8 bGroundVolumeModifier = 0;
INT8 bGroundStealthDifficultyModifier = 0;
ADDITIONAL_TILE_PROPERTIES_VALUES zGivenTileProperties;
memset(&zGivenTileProperties, 0, sizeof(zGivenTileProperties));
if (gGameExternalOptions.fAdditionalTileProperties)
{
zGivenTileProperties = GetAllAdditonalTilePropertiesForGrid(pSoldier->sGridNo, pSoldier->pathing.bLevel);
bGroundVolumeModifier = zGivenTileProperties.bSoundModifier;
bGroundStealthDifficultyModifier = zGivenTileProperties.bStealthDifficultyModifer;
}
if (pSoldier->bTeam == ENEMY_TEAM)
{
return((UINT8)(MAX_MOVEMENT_NOISE - PreRandom(2)) + bGroundVolumeModifier);
}
// CHANGED BY SANDRO - LET'S MAKE THE STEALTH BASED ON AGILITY LIKE IT SHOULD BE
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;
bBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding;
bEffLife = pSoldier->stats.bLife + (bBandaged / 2);
// IF "SNEAKER'S" "EFFECTIVE LIFE" IS AT LESS THAN 50
if (bEffLife < 50)
{
// reduce effective stealth skill by up to 50% for low life
iStealthSkill -= (iStealthSkill * (50 - bEffLife)) / 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, pSoldier->pathing.bLevel))
{
iStealthSkill -= 10; // 10% penalty
}
else if (DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel))
{
iStealthSkill -= 20; // 20% penalty
}
iStealthSkill = __max(iStealthSkill, 0);
if (!pSoldier->bStealthMode) // REGULAR movement
{
//ubMaxVolume = MAX_MOVEMENT_NOISE - (iStealthSkill / 16); // 9 - (0 to 6) => 3 to 9
sMaxVolume = MAX_MOVEMENT_NOISE - (iStealthSkill / 16) + bGroundVolumeModifier; // 9 - (0 to 6) => 3 to 9
if (Water(pSoldier->sGridNo, pSoldier->pathing.bLevel))
{
sMaxVolume++; // in water, can be even louder
}
switch (pSoldier->usUIMovementMode)
{
case CRAWLING:
sMaxVolume -= 2;
break;
case SWATTING:
case SWATTING_WK:
sMaxVolume -= 1;
break;
case RUNNING:
sMaxVolume += 3;
break;
}
if (sMaxVolume < 2)
{
sVolume = sMaxVolume;
}
else
{
sVolume = 1 + (UINT8)PreRandom(sMaxVolume); // actual volume is 1 to max volume
}
}
else // in STEALTH mode
{
iRoll = (INT32)PreRandom(100) + bGroundStealthDifficultyModifier; // roll them bones!
if (iRoll >= iStealthSkill) // v1.13 modification: give a second chance!
{
iRoll = (INT32)PreRandom(100) + bGroundStealthDifficultyModifier;
}
if (iRoll < iStealthSkill)
{
sVolume = 0; // made it, stayed quiet moving through this tile
}
else // OOPS!
{
sVolume = 1 + ((iRoll - iStealthSkill + 1) / 16); // volume is 1 - 7 ...
switch (pSoldier->usUIMovementMode)
{
case CRAWLING:
sVolume -= 2;
break;
case SWATTING:
case SWATTING_WK:
sVolume -= 1;
break;
case RUNNING:
sVolume += 3;
break;
}
}
}
// sevenfm: if dragging something, add dragging sound volume
if(pSoldier->IsDragging())
{
sVolume = max(sVolume, MAX_MOVEMENT_NOISE / 2 + Random(MAX_MOVEMENT_NOISE) + bGroundVolumeModifier);
}
sVolume = max(0, sVolume);
sVolume = min(255, sVolume);
return (UINT8)sVolume;
}
UINT8 DoorOpeningNoise( SOLDIERTYPE *pSoldier )
{
// door being opened gridno is always the pending-action-data2 value
INT32 sGridNo = pSoldier->aiData.sPendingActionData2;
DOOR_STATUS *pDoorStatus = GetDoorStatus( sGridNo );
UINT8 ubDoorNoise = 0;
// Find the base tile for the door structure and use that gridno
STRUCTURE *pStructure = FindStructure(sGridNo, STRUCTURE_ANYDOOR);
if (pStructure)
{
ubDoorNoise = 8;//shadooow: this indicates at how many tiles can be the noise heard (was 2 originally)
// OK, check if this door is sliding and is multi-tiled...
if (pStructure->fFlags & STRUCTURE_SLIDINGDOOR)
{
// Get database value...
if (pStructure->pDBStructureRef->pDBStructure->ubNumberOfTiles > 1)
{
// garage doors
ubDoorNoise += 4;
}
else if (pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_CLOTH)
{
// curtains
ubDoorNoise -= 4;
}
}
else if (pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_LIGHT_METAL ||
pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_THICKER_METAL ||
pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_HEAVY_METAL)
{
// metal doors
ubDoorNoise += 2;
}
if (pDoorStatus && pDoorStatus->ubFlags & DOOR_HAS_TIN_CAN)
{
//shadooow: do not allow stealth to work if there is can attached to doors
ubDoorNoise += 4;
}
else if (pSoldier->bStealthMode)
{
// CHANGED BY SANDRO - LET'S MAKE THE STEALTH BASED ON AGILITY LIKE IT SHOULD BE
INT32 iStealthSkill = 20 + 4 * EffectiveExpLevel(pSoldier) + ((EffectiveAgility(pSoldier, FALSE) * 4) / 10); // 24-100
INT8 bEffLife = pSoldier->stats.bLife + ((pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding) / 2);
// IF "SNEAKER'S" "EFFECTIVE LIFE" IS AT LESS THAN 50
if (bEffLife < 50)
{
// reduce effective stealth skill by up to 50% for low life
iStealthSkill -= (iStealthSkill * (50 - bEffLife)) / 100;
}
// if breath is below 50%
if (pSoldier->bBreath < 50)
{
// reduce effective stealth skill by up to 50%
iStealthSkill -= (iStealthSkill * (50 - pSoldier->bBreath)) / 100;
}
iStealthSkill = __max(iStealthSkill, 0);
INT32 iRoll = (INT32)PreRandom(100); // roll them bones!
if (iRoll >= iStealthSkill) // v1.13 modification: give a second chance!
{
iRoll = (INT32)PreRandom(100);
}
// succeeded in being stealthy!
if (iRoll < iStealthSkill)
{
ubDoorNoise = 0;
}
}
}
return( ubDoorNoise );
}
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;
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)];
}
*/
// 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:
case NOISE_CREAKING://shadooow: doors will make sound of being opened/closed so I see no reason to write it to player
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 || pSoldier->bAssignment == ASSIGNMENT_MINIEVENT) )
{
// POWs should not be processed for noise
continue;
}
// Can the listener hear noise of that volume given his circumstances?
ubEffVolume = CalcEffVolume(pSoldier, sGridNo, bLevel, ubNoiseType, ubBaseVolume, pSoldier->bOverTerrainType, ubSourceTerrType);
// 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
// sevenfm: allow taunts from militia
if (pSoldier->bTeam == OUR_TEAM && MercPtrs[ubNoiseMaker]->bSide == 0 && (ubNoiseType != NOISE_VOICE || !gTauntsSettings.fTauntVoice))
//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;
UINT8 DiffLevel;
if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
DiffLevel = 1;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
DiffLevel = 2;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
DiffLevel = 3;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
DiffLevel = 4;
else
DiffLevel = 1;
if (PlacementType == BLOODCAT_PLACEMENT_STATIC)
{
if (gBloodcatPlacements[ ubSectorID ][ DiffLevel-1 ].ubFactionAffiliation == QUEENS_CIV_GROUP)
//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 ][ DiffLevel-1 ].ubFactionAffiliation > NON_CIV_GROUP)
//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;
}
#ifdef RECORDOPPLIST
fprintf(OpplistFile,"PN: guy %d - effVol=%d,pSoldier->tType=%d,srcTType=%d\n",
bLoop,effVolume,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);
}
}
else if (ubNoiseType == NOISE_CREAKING)
{
DOOR_STATUS *pDoorStatus = GetDoorStatus(sGridNo);
//shadooow: show locator when there is can with string attached to doors
if (pDoorStatus && pDoorStatus->ubFlags & DOOR_HAS_TIN_CAN)
BeginMultiPurposeLocator(sGridNo, bLevel, (INT8)((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT)));
}
//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
}
else if(bTeam == OUR_TEAM && ubNoiseType == NOISE_CREAKING)
{
//shadooow: this will indicate doors not to make animation/sound of doors opening or closing
Menptr[ubNoiseMaker].ubDoorOpeningNoise = 0;
}
// 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 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{ civilians have bad hearing ;)
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 )
if( pSoldier->flags.fMercAsleep )
{
// 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, 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 ) );
// sevenfm: scale ubVolume to remember noise
UINT8 ubVolumeScaled = (UINT8)sqrt((float)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 && ARMED_VEHICLE( 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);
}
}
}
// sevenfm: remember noise even for seen opponents
if( pSoldier->flags.uiStatusFlags & SOLDIER_PC && ubVolumeScaled > 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 more than 12 turns!
pSoldier->aiData.ubNoiseVolume = min(ubVolumeScaled, MAX_MISC_NOISE_DURATION);
}
}
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);
// sevenfm: increment watched location when soldier hears enemy
if ((ubNoiseType == NOISE_GUNFIRE || ubNoiseType == NOISE_MOVEMENT || ubNoiseType == NOISE_SCREAM || ubNoiseType == NOISE_VOICE) &&
!TileIsOutOfBounds(sGridNo) &&
!(pSoldier->flags.uiStatusFlags & SOLDIER_PC) &&
!pSoldier->aiData.bNeutral &&
MercPtrs[ubNoiseMaker] &&
!MercPtrs[ubNoiseMaker]->aiData.bNeutral &&
!pSoldier->IsFlanking())
{
// check that we can see enemy if we raise weapon
gbForceWeaponReady = TRUE;
if (SoldierToVirtualSoldierLineOfSightTest(pSoldier, sGridNo, bLevel, ANIM_STAND, TRUE, CALC_FROM_ALL_DIRS))
IncrementWatchedLoc(pSoldier->ubID, sGridNo, bLevel);
gbForceWeaponReady = FALSE;
}
// 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 (ubVolumeScaled >= 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 more than 12 turns!
pSoldier->aiData.ubNoiseVolume = min(ubVolumeScaled, 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 (ubVolumeScaled >= 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 more than 12 turns!
pSoldier->aiData.ubNoiseVolume = min(ubVolumeScaled, 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)
{
// sevenfm: allow player mercs to hear all noises
if ( pSoldier->flags.uiStatusFlags & SOLDIER_PC && ubVolumeScaled > 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 more than 12 turns!
pSoldier->aiData.ubNoiseVolume = min(ubVolumeScaled, MAX_MISC_NOISE_DURATION);
}
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 && ubNoiseMaker != NOBODY)
{
// information about direction etc. only displayed if we don't see noise maker
// sevenfm: don't show noise messages from militia (if on our side)
if (gbPublicOpplist[gbPlayerNum][ubNoiseMaker] != SEEN_CURRENTLY && pSoldier->aiData.bOppList[ubNoiseMaker] != SEEN_CURRENTLY &&
!(MercPtrs[ubNoiseMaker]->bTeam == MILITIA_TEAM && MercPtrs[ubNoiseMaker]->bSide == 0))
//if( gbPublicOpplist[gbPlayerNum][ubNoiseMaker] != SEEN_CURRENTLY && pSoldier->aiData.bOppList[ubNoiseMaker] != SEEN_CURRENTLY )
{
if (bLevel == pSoldier->pathing.bLevel)
{
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
{
CHAR8 filename[1024];
if (gTauntsSettings.fTauntVoiceShowInfo)
ScreenMsg(FONT_ORANGE, MSG_INTERFACE, zNoiseMessage);
// convert wchar to char
wcstombs(filename, zNoiseMessage, wcslen(zNoiseMessage) + 1);
// sevenfm: play voice taunt (check that noise string is a filename)
if (gTauntsSettings.fTauntVoice &&
strlen(filename) != 0 &&
strstr(filename, "VoiceTaunts\\") != NULL)
{
UINT32 playResult = PlayJA2SampleFromFile(filename, RATE_11025, SoundVolume(HIGHVOLUME, pSoldier->sGridNo), 1, SoundDir(pSoldier->sGridNo));
if (playResult == SOUND_ERROR && gTauntsSettings.fTauntVoiceShowInfo)
ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Noise: Failed to play taunt");
}
else
{
// 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 have an extended ear
if(ubVolumeIndex >= 2)
{
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 < MAX_NUM_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 (AmmoTypes[pAttacker->inv[pAttacker->ubAttackingHand][0]->data.gun.ubGunAmmoType].dart)
{
// 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 ( !UsingImprovedInterruptSystem() || 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, pSoldier->IsCowering(), GetPercentTunnelVision(pSoldier));
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!
// sevenfm: the original code is ok, as we search for unused WatchedLoc which is initialized with NOWHERE value
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