#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 bCheckTerrain, UINT8 ubTerrType1, UINT8 ubTerrType2); void HearNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 *ubSeen); void TellPlayerAboutNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 ubNoiseDir, STR16 zNoiseMessage = NULL ); void OurTeamSeesSomeone( SOLDIERTYPE * pSoldier, INT8 bNumReRevealed, INT8 bNumNewEnemies ); void IncrementWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel ); void SetWatchedLocAsUsed( UINT8 ubID, INT32 sGridNo, INT8 bLevel ); void DecayWatchedLocs( INT8 bTeam ); void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT8 * pPersOL, INT8 * pbPublOL ); // The_Bob - real time sneaking code 01/06/09 extern void CancelItemPointer(void); extern BOOLEAN NobodyAlerted(void); extern void ShowRadioLocator( UINT8 ubID, UINT8 ubLocatorSpeed ); //#define TESTOPPLIST // for ManSeesMan() #define MANLOOKSFORMAN 0 #define HEARNOISE 1 #define NOTICEUNSEENATTACKER 2 // for ManLooksForMan() #define MANLOOKSFOROTHERTEAMS 0 #define OTHERTEAMSLOOKFORMAN 1 #define VERIFYANDDECAYOPPLIST 2 #define HANDLESTEPPEDLOOKAT 3 #define LOOKANDLISTEN 4 #define UPDATEPUBLIC 5 #define CALLER_UNKNOWN 6 // this variable is a flag used in HandleSight to determine whether (while in non-combat RT) // someone has just been seen, EITHER THE MOVER OR SOMEONE THE MOVER SEES BOOLEAN gfPlayerTeamSawCreatures = FALSE; BOOLEAN gfPlayerTeamSawJoey = FALSE; BOOLEAN gfMikeShouldSayHi = FALSE; #ifdef JA2UB //JA25 UB BOOLEAN gfMorrisShouldSayHi = FALSE; #endif UINT8 gubBestToMakeSighting[BEST_SIGHTING_ARRAY_SIZE]; UINT8 gubBestToMakeSightingSize = 0; //BOOLEAN gfHumanSawSomeoneInRealtime; BOOLEAN gfDelayResolvingBestSightingDueToDoor = FALSE; #define SHOULD_BECOME_HOSTILE_SIZE 32 UINT8 gubShouldBecomeHostileOrSayQuote[ SHOULD_BECOME_HOSTILE_SIZE ]; UINT8 gubNumShouldBecomeHostileOrSayQuote; // NB this ID is set for someone opening a door UINT8 gubInterruptProvoker = NOBODY; INT8 gbPublicOpplist[MAXTEAMS][TOTAL_SOLDIERS]; INT8 gbSeenOpponents[TOTAL_SOLDIERS][TOTAL_SOLDIERS]; INT32 gsLastKnownOppLoc[TOTAL_SOLDIERS][TOTAL_SOLDIERS]; // merc vs. merc INT8 gbLastKnownOppLevel[TOTAL_SOLDIERS][TOTAL_SOLDIERS]; INT32 gsPublicLastKnownOppLoc[MAXTEAMS][TOTAL_SOLDIERS]; // team vs. merc INT8 gbPublicLastKnownOppLevel[MAXTEAMS][TOTAL_SOLDIERS]; UINT8 gubPublicNoiseVolume[MAXTEAMS]; INT32 gsPublicNoiseGridNo[MAXTEAMS]; INT8 gbPublicNoiseLevel[MAXTEAMS]; UINT8 gubKnowledgeValue[10][10] = { // P E R S O N A L O P P L I S T // // -4 -3 -2 -1 0 1 2 3 4 5 // { 0, 1, 2, 3, 0, 5, 4, 3, 2, 1}, // -4 { 0, 0, 1, 2, 0, 4, 3, 2, 1, 0}, // -3 O { 0, 0, 0, 1, 0, 3, 2, 1, 0, 0}, // -2 P P { 0, 0, 0, 0, 0, 2, 1, 0, 0, 0}, // -1 U P { 0, 1, 2, 3, 0, 5, 4, 3, 2, 1}, // 0 B L { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 1 L I { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, // 2 I S { 0, 0, 0, 1, 0, 2, 1, 0, 0, 0}, // 3 C T { 0, 0, 1, 2, 0, 3, 2, 1, 0, 0}, // 4 { 0, 1, 2, 3, 0, 4, 3, 2, 1, 0} // 5 /* // P E R S O N A L O P P L I S T // // -3 -2 -1 0 1 2 3 4 // { 0, 1, 2, 0, 4, 3, 2, 1 }, // -3 O { 0, 0, 1, 0, 3, 2, 1, 0 }, // -2 P P { 0, 0, 0, 0, 2, 1, 0, 0 }, // -1 U P { 1, 2, 3, 0, 5, 4, 3, 2 }, // 0 B L { 0, 0, 0, 0, 0, 0, 0, 0 }, // 1 L I { 0, 0, 0, 0, 1, 0, 0, 0 }, // 2 I S { 0, 0, 1, 0, 2, 1, 0, 0 }, // 3 C T { 0, 1, 2, 0, 3, 2, 1, 0 } // 4 */ }; #define MAX_WATCHED_LOC_POINTS 4 #define WATCHED_LOC_RADIUS 1 INT32 gsWatchedLoc[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; INT8 gbWatchedLocLevel[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; UINT8 gubWatchedLocPoints[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; BOOLEAN gfWatchedLocReset[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; BOOLEAN gfWatchedLocHasBeenIncremented[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; INT8 gbLookDistance[8][8]; INT8 BEHIND; INT8 SBEHIND; INT8 SIDE; INT8 ANGLE; INT8 STRAIGHT; void InitSightRange() { BEHIND = (INT8)( BEHIND_RATIO * gGameExternalOptions.ubStraightSightRange ); SBEHIND = (INT8)( SBEHIND_RATIO * gGameExternalOptions.ubStraightSightRange ); SIDE = (INT8)( SIDE_RATIO * gGameExternalOptions.ubStraightSightRange ); ANGLE = (INT8)( ANGLE_RATIO * gGameExternalOptions.ubStraightSightRange ); STRAIGHT = (INT8)( STRAIGHT_RATIO * gGameExternalOptions.ubStraightSightRange ); INT8 dummy[15][15]; { //Pulmu: VC6 compatibility for (int i=0; i<8; i++) { dummy[i][i]=STRAIGHT; dummy[i][i+1]=ANGLE; dummy[i+1][i]=ANGLE; dummy[i][i+2]=SIDE; dummy[i+2][i]=SIDE; dummy[i][i+3]=SBEHIND; dummy[i+3][i]=SBEHIND; dummy[i][i+4]=BEHIND; dummy[i+4][i]=BEHIND; dummy[i][i+5]=SBEHIND; dummy[i+5][i]=SBEHIND; dummy[i][i+6]=SIDE; dummy[i+6][i]=SIDE; dummy[i][i+7]=ANGLE; dummy[i+7][i]=ANGLE; } } for (int i=0; i<8; i++) { for (int j=0; j<8; j++) { gbLookDistance[i][j] = dummy[i][j]; } } //gbLookDistance[8][8] = //{ // // LOOKER DIR LOOKEE DIR // // NORTH | NORTHEAST | EAST | SOUTHEAST | SOUTH | SOUTHWEST | WEST | NORTHWEST // /* NORTH */ STRAIGHT, ANGLE, SIDE, SBEHIND, BEHIND, SBEHIND, SIDE, ANGLE, // /* NORTHEAST */ ANGLE, STRAIGHT, ANGLE, SIDE, SBEHIND, BEHIND, SBEHIND, SIDE, // /* EAST */ SIDE, ANGLE, STRAIGHT, ANGLE, SIDE, SBEHIND, BEHIND, SBEHIND, // /* SOUTHEAST */ SBEHIND, SIDE, ANGLE, STRAIGHT, ANGLE, SIDE, SBEHIND, BEHIND, // /* SOUTH */ BEHIND, SBEHIND, SIDE, ANGLE, STRAIGHT, ANGLE, SIDE, SBEHIND, // /* SOUTHWEST */ SBEHIND, BEHIND, SBEHIND, SIDE, ANGLE, STRAIGHT, ANGLE, SIDE, // /* WEST */ SIDE, SBEHIND, BEHIND, SBEHIND, SIDE, ANGLE, STRAIGHT, ANGLE, // /* NORTHWEST */ ANGLE, SIDE, SBEHIND, BEHIND, SBEHIND, SIDE, ANGLE, STRAIGHT // }; } INT8 gbSmellStrength[3] = { NORMAL_HUMAN_SMELL_STRENGTH, // normal NORMAL_HUMAN_SMELL_STRENGTH + 2, // slob NORMAL_HUMAN_SMELL_STRENGTH - 1 // snob }; UINT16 gsWhoThrewRock = NOBODY; // % values of sighting distance at various light levels //DBrot: use gGameExternalOptions.ubBrightnessVisionMod instead /* INT8 gbLightSighting[1][SHADE_MIN+1] = { { // human 80, // brightest 86, 93, 100, // normal daylight, 3 94, 88, 82, 76, 70, // mid-dawn, 8 64, 58, 51, 43, // normal nighttime, 12 (11 tiles) 30, 17, 9 } };*/ /* { { // human 80, // brightest 86, 93, 100, // normal daylight, 3 93, 86, 79, 72, 65, // mid-dawn, 8 58, 53, 43, // normal nighttime, 11 (11 tiles) 35, 26, 17, 9 } }; */ UINT8 gubSightFlags = 0; void DECAY_OPPLIST_VALUE( INT8& value ) { if ( (value) >= SEEN_THIS_TURN) { (value)++; if ( (value) > OLDEST_SEEN_VALUE ) { (value) = NOT_HEARD_OR_SEEN; } } else { if ( (value) <= HEARD_THIS_TURN) { (value)--; if ( (value) < OLDEST_HEARD_VALUE) { (value) = NOT_HEARD_OR_SEEN; } } } } //rain extern 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, 2 ); // make civ group, if any, hostile if ( pSoldier->bTeam == CIV_TEAM && pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] == CIV_GROUP_WILL_BECOME_HOSTILE ) { gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] = CIV_GROUP_HOSTILE; } // reevaluate sight - we might already see people that weren't enemies until now ManLooksForOtherTeams(pSoldier); pSoldier->aiData.bAlertStatus = STATUS_RED; } } // unpause all AI UnPauseAI(); // reset the list memset( &gubShouldBecomeHostileOrSayQuote, NOBODY, SHOULD_BECOME_HOSTILE_SIZE ); gubNumShouldBecomeHostileOrSayQuote = 0; //and return/go into combat if ( !(gTacticalStatus.uiFlags & INCOMBAT ) ) { EnterCombatMode( CIV_TEAM ); } } else { // pause all AI PauseAIUntilManuallyUnpaused(); // stop everyone? // We want to make this guy visible to the player. if ( MercPtrs[ ubSpeaker ]->bVisible != TRUE ) { gbPublicOpplist[ gbPlayerNum ][ ubSpeaker ] = HEARD_THIS_TURN; HandleSight( MercPtrs[ ubSpeaker ], SIGHT_LOOK | SIGHT_RADIO ); } // trigger hater TriggerNPCWithIHateYouQuote( MercPtrs[ ubSpeaker ]->ubProfile ); } } } void HandleSight(SOLDIERTYPE *pSoldier, UINT8 ubSightFlags) { UINT32 uiLoop; SOLDIERTYPE *pThem; INT8 bTempNewSituation; if (!pSoldier->bActive || !pSoldier->bInSector || pSoldier->flags.uiStatusFlags & SOLDIER_DEAD ) { // I DON'T THINK SO! return; } gubSightFlags = ubSightFlags; if ( gubBestToMakeSightingSize != BEST_SIGHTING_ARRAY_SIZE_ALL_TEAMS_LOOK_FOR_ALL ) { // if this is not being called as a result of all teams look for all, reset array size if ( (gTacticalStatus.uiFlags & INCOMBAT) ) { // NB the incombat size is 0 gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_INCOMBAT; } else { gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_NONCOMBAT; } InitSightArrays(); } for ( uiLoop = 0; uiLoop < NUM_WATCHED_LOCS; ++uiLoop ) { gfWatchedLocHasBeenIncremented[ pSoldier->ubID ][ uiLoop ] = FALSE; } gfPlayerTeamSawCreatures = FALSE; // store new situation value bTempNewSituation = pSoldier->aiData.bNewSituation; pSoldier->aiData.bNewSituation = FALSE; // if we've been told to make this soldier look (& others look back at him) if (ubSightFlags & SIGHT_LOOK) { // if this soldier's under our control and well enough to look if (pSoldier->stats.bLife >= OKLIFE ) { /* #ifdef RECORDOPPLIST fprintf(OpplistFile,"ManLooksForOtherTeams (HandleSight/Look) for %d\n",pSoldier->guynum); #endif */ // he looks for all other soldiers not on his own team ManLooksForOtherTeams(pSoldier); // if "Show only enemies seen" option is ON and it's this guy looking //if (pSoldier->ubID == ShowOnlySeenPerson) //NewShowOnlySeenPerson(pSoldier); // update the string } /* #ifdef RECORDOPPLIST fprintf(OpplistFile,"OtherTeamsLookForMan (HandleSight/Look) for %d\n",ptr->guynum); #endif */ // all soldiers under our control but not on ptr's team look for him OtherTeamsLookForMan(pSoldier); } // end of SIGHT_LOOK // if we've been told that interrupts are possible as a result of sighting if ((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && (ubSightFlags & SIGHT_INTERRUPT) && (!gGameOptions.fImprovedInterruptSystem || (gGameOptions.fImprovedInterruptSystem && gGameExternalOptions.fAllowInstantInterruptsOnSight) ) ) { ResolveInterruptsVs( pSoldier, SIGHTINTERRUPT ); } if ( gubBestToMakeSightingSize == BEST_SIGHTING_ARRAY_SIZE_NONCOMBAT ) { HandleBestSightingPositionInRealtime(); } if ( pSoldier->aiData.bNewSituation && !(pSoldier->flags.uiStatusFlags & SOLDIER_PC) ) { pSoldier->HaultSoldierFromSighting( TRUE ); } pSoldier->aiData.bNewSituation = __max( pSoldier->aiData.bNewSituation, bTempNewSituation ); // if we've been told to radio the results if (ubSightFlags & SIGHT_RADIO) { if (pSoldier->flags.uiStatusFlags & SOLDIER_PC ) { // update our team's public knowledge RadioSightings(pSoldier,EVERYBODY, pSoldier->bTeam ); /* comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA RadioSightings(pSoldier,EVERYBODY, MILITIA_TEAM); #endif*/ //ddd{ if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) RadioSightings(pSoldier,EVERYBODY, MILITIA_TEAM); #ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV //haydent if(is_networked && pSoldier->bSide == 0 && pSoldier->bTeam != OUR_TEAM) RadioSightings(pSoldier,EVERYBODY, OUR_TEAM); #endif //ddd} // if it's our local player's merc if (PTR_OURTEAM) // revealing roofs and looking for items handled here, too RevealRoofsAndItems(pSoldier,TRUE, TRUE, pSoldier->pathing.bLevel, FALSE ); } // unless in easy mode allow alerted enemies to radio else if ( 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 ); } return DistanceVisible( this, (SoldierHasLimitedVision(this) ? this->pathing.bDesiredDirection : DIRECTION_IRRELEVANT), DIRECTION_IRRELEVANT, sGridNo, bLevel ); } INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, INT32 sSubjectGridNo, INT8 bLevel ) { INT16 sDistVisible; INT8 bLightLevel; BOOLEAN sideViewLimit = FALSE; SOLDIERTYPE* pSubject = SimpleFindSoldier( sSubjectGridNo, bLevel ); 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 = GetPercentTunnelVision( pSoldier ); } 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 ( CoweringShockLevel(pSoldier) ) { 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 ) ) { 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 CancelAIAction( pSoldier, TRUE ); RESETTIMECOUNTER( pSoldier->timeCounters.AICounter, 0 ); pSoldier->aiData.bNextAction = AI_ACTION_RUN; pSoldier->aiData.usNextActionData = 13250; } } // if opponent was seen publicly last time if (*pbPublOL == SEEN_CURRENTLY) { // check if I was the only one who was seeing this guy (exlude ourselves) // THIS MUST HAPPEN EVEN FOR ENEMIES, TO MAKE THEIR PUBLIC opplist DECAY! if (TeamNoLongerSeesMan(pSoldier->bTeam,pOpponent,pSoldier->ubID, 0 )) { #ifdef TESTOPPLIST DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "TeamNoLongerSeesMan: ID %d(%S) to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) ); #endif #ifdef RECORDOPPLIST fprintf(OpplistFile,"TeamNoLongerSeesMan returns TRUE for team %d, opp %d\n",ptr->team,oppPtr->guynum); fprintf(OpplistFile,"ManLooksForMan: changing publicOpplist to %d for team %d, opp %d\n",SEEN_THIS_TURN,ptr->team,oppPtr->guynum); #endif // don't use UpdatePublic() here, because we're changing to a *lower* // opplist value (which UpdatePublic ignores) and we're not updating // the lastKnown gridno at all, we're keeping it at its previous value *pbPublOL = SEEN_THIS_TURN; // ATE: Set visiblity to 0 /*comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA if ( (pSoldier->bTeam == gbPlayerNum || pSoldier->bTeam == MILITIA_TEAM) && !(pOpponent->bTeam == gbPlayerNum || pOpponent->bTeam == MILITIA_TEAM ) ) #else if ( pSoldier->bTeam == gbPlayerNum && pOpponent->bTeam != gbPlayerNum ) #endif { pOpponent->bVisible = 0; } */ #ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV //haydent if(is_networked && pSoldier->bSide == 0) { //stay visible } else #endif { if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) { if ( (pSoldier->bTeam == gbPlayerNum || pSoldier->bTeam == MILITIA_TEAM) && !(pOpponent->bTeam == gbPlayerNum || pOpponent->bTeam == MILITIA_TEAM ) ) pOpponent->bVisible = 0; } else { if ( pSoldier->bTeam == gbPlayerNum && pOpponent->bTeam != gbPlayerNum ) pOpponent->bVisible = 0; } }//haydent } } #ifdef TESTOPPLIST else DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("ManLooksForMan: ID %d(%S) to ID %d Personally seen, public %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pbPublOL) ); #endif // if we had only seen the guy for an instant and now lost sight of him if (gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] == -1) // we can't leave it -1, because InterruptDuel() uses the special -1 // value to know if we're only JUST seen the guy and screw up otherwise // it's enough to know we have seen him before gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] = TRUE; } INT16 ManLooksForMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, UINT8 ubCaller) { INT8 bDir,bAware = FALSE,bSuccess = FALSE; INT16 sDistVisible,sDistAway; INT8 *pPersOL,*pbPublOL; /* if (ptr->guynum >= TOTAL_SOLDIERS) { #ifdef BETAVERSION NumMessage("ManLooksForMan: ERROR - ptr->guynum = ",ptr->guynum); #endif return(success); } if (oppPtr->guynum >= TOTAL_SOLDIERS) { #ifdef BETAVERSION NumMessage("ManLooksForMan: ERROR - oppPtr->guynum = ",oppPtr->guynum); #endif return(success); } */ // if we're somehow looking while inactive, at base, dead or dying if (!pSoldier->bActive || !pSoldier->bInSector || (pSoldier->stats.bLife < OKLIFE)) { /* #ifdef BETAVERSION sprintf(tempstr,"ManLooksForMan: ERROR - %s is looking while inactive/at base/dead/dying. Caller %s", ExtMen[ptr->guynum].name,LastCaller2Text[caller]); #ifdef RECORDNET fprintf(NetDebugFile,"\n\t%s\n\n",tempstr); #endif PopMessage(tempstr); #endif */ #ifdef TESTOPPLIST DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("ERROR: ManLooksForMan - WE are inactive/dead etc ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) ); #endif return(FALSE); } // if we're somehow looking for a guy who is inactive, at base, or already dead if (!pOpponent->bActive || !pOpponent->bInSector || pOpponent->stats.bLife <= 0 || TileIsOutOfBounds(pOpponent->sGridNo)) { /* #ifdef BETAVERSION sprintf(tempstr,"ManLooksForMan: ERROR - %s looks for %s, who is inactive/at base/dead. Caller %s", ExtMen[ptr->guynum].name,ExtMen[oppPtr->guynum].name,LastCaller2Text[caller]); #ifdef RECORDNET fprintf(NetDebugFile,"\n\t%s\n\n",tempstr); #endif PopMessage(tempstr); #endif */ #ifdef TESTOPPLIST DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("ERROR: ManLooksForMan - TARGET is inactive etc ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) ); #endif return(FALSE); } // if he's looking for a guy who is on the same team if (pSoldier->bTeam == pOpponent->bTeam) { /* #ifdef BETAVERSION sprintf(tempstr,"ManLooksFormMan: ERROR - on SAME TEAM. ptr->guynum = %d, oppPtr->guynum = %d", ptr->guynum,oppPtr->guynum); #ifdef RECORDNET fprintf(NetDebugFile,"\n\t%s\n\n",tempstr); #endif PopMessage(tempstr); #endif */ #ifdef TESTOPPLIST DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("ERROR: ManLooksForMan - SAME TEAM ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) ); #endif return(FALSE); } // Flugente: we already checked for OKLIFE above.. if ( pSoldier->flags.fMercAsleep ) { return( FALSE ); } // NEED TO CHANGE THIS /* // don't allow unconscious persons to look, but COLLAPSED, etc. is OK if (ptr->anitype[ptr->anim] == UNCONSCIOUS) return(success); */ if ( pSoldier->ubBodyType == LARVAE_MONSTER || (pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->bTeam == OUR_TEAM) ) { // don't do sight for these return( FALSE ); } /* if (ptrProjected) { // use looker's PROJECTED x,y co-ordinates (those of his next gridno) fromX = ptr->destx; fromY = ptr->desty; fromGridno = ExtMen[ptr->guynum].nextGridno; } else { // use looker's ACTUAL x,y co-ordinates (those of gridno he's in now) fromX = ptr->x; fromY = ptr->y; fromGridno = ptr->sGridNo; } if (oppPtrProjected) { // use target's PROJECTED x,y co-ordinates (those of his next gridno) toX = oppPtr->destx; toY = oppPtr->desty; toGridno = ExtMen[oppPtr->guynum].nextGridno; } else { // use target's ACTUAL x,y co-ordinates (those of gridno he's in now) toX = oppPtr->x; toY = oppPtr->y; toGridno = oppPtr->gridno; } */ pPersOL = &(pSoldier->aiData.bOppList[pOpponent->ubID]); pbPublOL = &(gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID]); // if soldier is known about (SEEN or HEARD within last few turns) if (*pPersOL || *pbPublOL) { bAware = TRUE; // then we look for him full viewing distance in EVERY direction //ADB the comment above says EVERY direction but the code used to be: //sDistVisible = DistanceVisible(pSoldier, (SoldierHasLimitedVision(pSoldier) ? pSoldier->bDesiredDirection : DIRECTION_IRRELEVANT), 0, pOpponent->sGridNo, pOpponent->bLevel, pOpponent ); //if the code below says CALC_FROM_ALL_DIRS, then the opponent will NOT be greyed out if a merc sees him and a second merc turns away from him //calcing from the wanted dir will make the opponent be greyed out, which I think is the intended effect sDistVisible = pSoldier->GetMaxDistanceVisible( pOpponent->sGridNo, pOpponent->pathing.bLevel, CALC_FROM_WANTED_DIR ); //if (pSoldier->ubID == 0) //sprintf(gDebugStr,"ALREADY KNOW: ME %d him %d val %d",pSoldier->ubID,pOpponent->ubID,pSoldier->bOppList[pOpponent->ubID]); } else // soldier is not currently known about { // distance we "see" then depends on the direction he is located from us bDir = atan8(pSoldier->sX,pSoldier->sY,pOpponent->sX,pOpponent->sY); // BIG NOTE: must use desdir instead of direction, since in a projected // situation, the direction may still be changing if it's one of the first // few animation steps when this guy's turn to do his stepped look comes up sDistVisible = DistanceVisible(pSoldier,pSoldier->pathing.bDesiredDirection,bDir, pOpponent->sGridNo, pOpponent->pathing.bLevel ); //if (pSoldier->ubID == 0) //sprintf(gDebugStr,"dist visible %d: my dir %d to him %d",sDistVisible,pSoldier->bDesiredDirection,bDir); } // calculate how many spaces away soldier is (using Pythagoras' theorem) sDistAway = PythSpacesAway(pSoldier->sGridNo,pOpponent->sGridNo); #ifdef TESTOPPLIST DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "MANLOOKSFORMAN: ID %d(%S) to ID %d: sDistAway %d sDistVisible %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,sDistAway,sDistVisible) ); #endif // if we see close enough to see the soldier if (sDistAway <= sDistVisible) { // and we can trace a line of sight to his x,y coordinates // must use the REAL opplist value here since we may or may not know of him if (SoldierToSoldierLineOfSightTest(pSoldier,pOpponent,bAware,sDistVisible)) { ManSeesMan(pSoldier,pOpponent,pOpponent->sGridNo,pOpponent->pathing.bLevel,MANLOOKSFORMAN,ubCaller); bSuccess = TRUE; } #ifdef TESTOPPLIST else DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("FAILED LINEOFSIGHT: ID %d (%S)to ID %d Personally %d, public %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL) ); #endif /* // if we're looking for a local merc, and changed doors were in the way if (PTR_OURTEAM && (NextFreeDoorIndex > 0)) // make or fail, if we passed through any "changed" doors along the way, // reveal their true status (change the structure to its real value) // (do this even if we don't have LOS, to close doors that *BREAK* LOS) RevealDoorsAlongLOS(); */ } /* #ifdef RECORDOPPLIST fprintf(OpplistFile,"MLFM: %s by %2d(g%4d,x%3d,y%3d,%s) at %2d(g%4d,x%3d,y%3d,%s), aware %d, dA=%d,dV=%d, desDir=%d, %s\n", (success) ? "SCS" : "FLR", ptr->guynum,fromGridno,fromX,fromY,(ptrProjected)?"PROJ":"REG.", oppPtr->guynum,toGridno,toX,toY,(oppPtrProjected)?"PROJ":"REG.", aware,distAway,distVisible,ptr->desdir, LastCaller2Text[caller]); #endif */ // if soldier seen personally LAST time could not be seen THIS time if (!bSuccess && (*pPersOL == SEEN_CURRENTLY)) { HandleManNoLongerSeen( pSoldier, pOpponent, pPersOL, pbPublOL ); } #ifdef TESTOPPLIST else { if (!bSuccess) { DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("NO LONGER VISIBLE ID %d (%S)to ID %d Personally %d, public %d success: %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL,bSuccess) ); // we didn't see the opponent, but since we didn't last time, we should be //if (*pbPublOL) //pOpponent->bVisible = TRUE; } else DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("COOL. STILL VISIBLE ID %d (%S)to ID %d Personally %d, public %d success: %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL,bSuccess) ); } #endif return(bSuccess); } void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, INT8 bOppLevel, UINT8 ubCaller, UINT8 ubCaller2) { INT8 bDoLocate = FALSE; BOOLEAN fNewOpponent = FALSE; BOOLEAN fNotAddedToList = TRUE; INT8 bOldOppList = pSoldier->aiData.bOppList[pOpponent->ubID]; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"ManSeesMan"); if (pSoldier->ubID >= TOTAL_SOLDIERS) return; if (pOpponent->ubID >= TOTAL_SOLDIERS) return; // if we're somehow looking while inactive, at base, dying or already dead if (!pSoldier->bActive || !pSoldier->bInSector || (pSoldier->stats.bLife < OKLIFE)) return; // if we're somehow seeing a guy who is inactive, at base, or already dead if (!pOpponent->bActive || !pOpponent->bInSector || pOpponent->stats.bLife <= 0) return; // if we're somehow seeing a guy who is on the same team if (pSoldier->bTeam == pOpponent->bTeam) return; // Flugente: if the other guy is in med or deep water and wearing scua gear, then we cannot see him as he is submerged if ( pOpponent->UsesScubaGear() ) return; // Flugente: update our sight concerning this guy, otherwise we could get way with open attacks because this does not get updated 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! CancelAIAction( pSoldier, TRUE ); SetNewSituation( pSoldier ); } } break; case ANGEL: if ( pOpponent->ubProfile == MARIA ) { if ( CheckFact( FACT_MARIA_ESCORTED_AT_LEATHER_SHOP, MARIA ) == TRUE ) { // she was rescued! yay! TriggerNPCRecord( ANGEL, 12 ); } } else if ( ( CheckFact( FACT_ANGEL_LEFT_DEED, ANGEL ) == TRUE ) && ( CheckFact( FACT_ANGEL_MENTIONED_DEED, ANGEL ) == FALSE ) ) { CancelAIAction( pSoldier, TRUE ); pSoldier->sAbsoluteFinalDestination = NOWHERE; pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection ); TriggerNPCRecord( ANGEL, 20 ); // trigger Angel to walk off afterwards //TriggerNPCRecord( ANGEL, 24 ); } break; //case QUEEN: #ifdef JA2UB //Ja25 //No Queen,Joe, or elliot #else case JOE: case ELLIOT: if ( ! ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) ) { if ( !AreInMeanwhile() ) { TriggerNPCRecord( pSoldier->ubProfile, 4 ); gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE; } } break; #endif default: break; } } } else { switch( pSoldier->ubProfile ) { case IGGY: if ( ! ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) ) { TriggerNPCRecord( pSoldier->ubProfile, 9 ); gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE; gbPublicOpplist[ gbPlayerNum ][ pSoldier->ubID ] = HEARD_THIS_TURN; } break; } } } // Flugente: for assassins without profiles else if ( pSoldier->IsAssassin() && pSoldier->bTeam == CIV_TEAM ) { // if we are an assassin and still neutral and undercover, approach target and then become hostile if ( pSoldier->aiData.bNeutral && pSoldier->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! CancelAIAction( pSoldier, TRUE ); SetNewSituation( pSoldier ); } } } } else { if ( pSoldier->bTeam == CIV_TEAM ) { if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] >= CIV_GROUP_WILL_BECOME_HOSTILE && pSoldier->aiData.bNeutral ) { AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID ); } else if ( pSoldier->ubCivilianGroup == KINGPIN_CIV_GROUP ) { // generic kingpin goon... // check to see if we are looking at Maria or unauthorized personnel in the brothel if (pOpponent->ubProfile == MARIA) { MakeCivHostile( pSoldier, 2 ); if ( ! (gTacticalStatus.uiFlags & INCOMBAT) ) { EnterCombatMode( pSoldier->bTeam ); } SetFactTrue( FACT_MARIA_ESCAPE_NOTICED ); } else { //DBrot: More Rooms //UINT8 ubRoom; UINT16 usRoom; // JA2 Gold: only go hostile if see player IN guard room //if ( InARoom( pOpponent->sGridNo, &ubRoom ) && IN_BROTHEL( ubRoom ) && ( gMercProfiles[ MADAME ].bNPCData == 0 || IN_BROTHEL_GUARD_ROOM( ubRoom ) ) ) if ( InARoom( pOpponent->sGridNo, &usRoom ) && IN_BROTHEL_GUARD_ROOM( usRoom ) ) { // unauthorized! MakeCivHostile( pSoldier, 2 ); if ( ! (gTacticalStatus.uiFlags & INCOMBAT) ) { EnterCombatMode( pSoldier->bTeam ); } } } } else if ( pSoldier->ubCivilianGroup == HICKS_CIV_GROUP && CheckFact( FACT_HICKS_MARRIED_PLAYER_MERC, 0 ) == FALSE && 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, 2 ); if ( ! (gTacticalStatus.uiFlags & INCOMBAT) ) { EnterCombatMode( pSoldier->bTeam ); LocateSoldier( pSoldier->ubID, TRUE ); GetSoldierScreenPos( pSoldier, &sX, &sY ); // begin quote BeginCivQuote( pSoldier, CIV_QUOTE_HICKS_SEE_US_AT_NIGHT, 0, sX, sY ); } } } } } } else if ( pSoldier->bTeam == gbPlayerNum ) { #ifdef JA2UB if ( (pOpponent->ubProfile == MORRIS_UB ) && ( GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( NULL, NULL ) > 0 ) && !( pSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_EXT_MORRIS ) && !( gMercProfiles[ MORRIS_UB ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) ) { gfMorrisShouldSayHi = TRUE; } #else if ( (pOpponent->ubProfile == MIKE) && ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC || pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__MERC ) && !(pSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_EXT_MIKE) ) { if (gfMikeShouldSayHi == FALSE) { gfMikeShouldSayHi = TRUE; } TacticalCharacterDialogue( pSoldier, QUOTE_AIM_SEEN_MIKE ); pSoldier->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_EXT_MIKE; } #endif else if ( pOpponent->ubProfile == JOEY && gfPlayerTeamSawJoey == FALSE ) { TacticalCharacterDialogue( pSoldier, QUOTE_SPOTTED_JOEY ); gfPlayerTeamSawJoey = TRUE; } } // as soon as a bloodcat sees someone, it becomes hostile // this is safe to do here because we haven't made this new person someone we've seen yet // (so we are assured we won't count 'em twice for oppcnt purposes) if ( pSoldier->ubBodyType == BLOODCAT ) { if ( pSoldier->aiData.bNeutral ) { MakeBloodcatsHostile(); /* SetSoldierNonNeutral( pSoldier ); RecalculateOppCntsDueToNoLongerNeutral( pSoldier ); if ( ( gTacticalStatus.uiFlags & INCOMBAT ) ) { CheckForPotentialAddToBattleIncrement( pSoldier ); } */ //PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, MIDVOLUME +10, 1, MIDDLEPAN ); } else { if ( pSoldier->aiData.bOppCnt == 0 ) { if ( Random( 2 ) == 0 ) { //PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, MIDVOLUME + 10, 1, MIDDLEPAN ); } } } } else if ( pOpponent->ubBodyType == BLOODCAT && pOpponent->aiData.bNeutral) { // HEADROCK HAM 3.6: If bloodcats are set as affiliated with civilians, do not trigger hostilities. 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 if ((pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_THIS_TURN) || (gsLastKnownOppLoc[pSoldier->ubID][pOpponent->ubID] != sOppGridNo)) { SetNewSituation( pSoldier ); // force the looker to re-evaluate // anv: simulate informing buddies about detected enemy's position // sevenfm: check that he is really new if( gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] != SEEN_CURRENTLY && gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] != SEEN_THIS_TURN ) 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,MAXMERCS); } void BetweenTurnsVisibilityAdjustments(void) { INT32 cnt; SOLDIERTYPE *pSoldier; // make all soldiers on other teams that are no longer seen not visible for (cnt = 0, pSoldier = Menptr; cnt < MAXMERCS; cnt++,pSoldier++) { if (pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife) { BOOLEAN SEE_MENT = FALSE; #ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV if(is_networked && pSoldier->bSide == 0)//haydent { //stay visible } else #endif { if (gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) {if (!PTR_OURTEAM && pSoldier->bTeam != MILITIA_TEAM) SEE_MENT = TRUE; } else { if (!PTR_OURTEAM) SEE_MENT = TRUE; } }//haydent /*comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA if (!PTR_OURTEAM && pSoldier->bTeam != MILITIA_TEAM) #else if (!PTR_OURTEAM) #endif */ if(SEE_MENT) { // check if anyone on our team currently sees him (exclude NOBODY) if (TeamNoLongerSeesMan(gbPlayerNum,pSoldier,NOBODY,0)) { // then our team has lost sight of him pSoldier->bVisible = -1; // make him fully invisible // Allow fade to adjust anim speed } } } } } void SaySeenQuote( SOLDIERTYPE *pSoldier, BOOLEAN fSeenCreature, BOOLEAN fVirginSector, BOOLEAN fSeenJoey ) { SOLDIERTYPE *pTeamSoldier; UINT8 ubNumEnemies = 0; UINT8 ubNumAllies = 0; UINT32 cnt; #ifdef JA2UB //Ja25 No meanwhiles #else if ( AreInMeanwhile( ) ) { return; } #endif // Check out for our under large fire quote if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_IN_SHIT ) ) { // Get total enemies. // Loop through all mercs in sector and count # of enemies for ( cnt = 0; cnt < guiNumMercSlots; ++cnt ) { pTeamSoldier = MercSlots[ cnt ]; if ( pTeamSoldier != NULL ) { if ( OK_ENEMY_MERC( pTeamSoldier ) ) { ++ubNumEnemies; } } } // OK, after this, check our guys for ( cnt = 0; cnt < guiNumMercSlots; ++cnt ) { pTeamSoldier = MercSlots[ cnt ]; if ( pTeamSoldier != NULL ) { if ( !OK_ENEMY_MERC( pTeamSoldier ) ) { if ( pTeamSoldier->aiData.bOppCnt >= ( ubNumEnemies / 2 ) ) { ++ubNumAllies; } } } } // now check! if ( ( pSoldier->aiData.bOppCnt - ubNumAllies ) > 2 ) { // Say quote! TacticalCharacterDialogue( pSoldier, QUOTE_IN_TROUBLE_SLASH_IN_BATTLE ); //pSoldier->ubLastEnemyAttackingProvokingQuote = pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_IN_SHIT; return; } } if ( fSeenCreature == 1 ) { // Is this our first time seeing them? if ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags & PROFILE_MISC_FLAG_HAVESEENCREATURE ) { // Are there multiplaes and we have not said this quote during this battle? if ( !( pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_MULTIPLE_CREATURES ) ) { // Check for multiples! ubNumEnemies = 0; // Get total enemies. // Loop through all mercs in sector and count # of enemies for ( cnt = 0; cnt < guiNumMercSlots; cnt++ ) { pTeamSoldier = MercSlots[ cnt ]; if ( pTeamSoldier != NULL ) { if ( OK_ENEMY_MERC( pTeamSoldier ) ) { if ( pTeamSoldier->flags.uiStatusFlags & SOLDIER_MONSTER && pSoldier->aiData.bOppList[ pTeamSoldier->ubID ] == SEEN_CURRENTLY ) { ubNumEnemies++; } } } } if ( ubNumEnemies > 2 ) { // Yes, set flag pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_MULTIPLE_CREATURES; // Say quote TacticalCharacterDialogue( pSoldier, QUOTE_ATTACKED_BY_MULTIPLE_CREATURES ); } else { TacticalCharacterDialogue( pSoldier, QUOTE_SEE_CREATURE ); } } else { TacticalCharacterDialogue( pSoldier, QUOTE_SEE_CREATURE ); } } else { // Yes, set flag gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_HAVESEENCREATURE; TacticalCharacterDialogue( pSoldier, QUOTE_FIRSTTIME_GAME_SEE_CREATURE ); } } // 2 is for bloodcat... else if ( fSeenCreature == 2 ) { TacticalCharacterDialogue( pSoldier, QUOTE_SPOTTED_BLOODCAT ); } else { if ( fVirginSector ) { // First time we've seen a guy this sector TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY_VARIATION ); } else { // Flugente: no quotes on seeing enemy when covert if ( (pSoldier->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 && ( MercPtrs[ gusSelectedSoldier ]->ubProfile < FIRST_NPC ) && pSoldier->ubProfile != NO_PROFILE ) //new profiles by Jazz if ( gusSelectedSoldier != NOBODY && ( gProfilesIMP[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesRPC[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesAIM[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesMERC[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile ) && pSoldier->ubProfile != NO_PROFILE ) { SetFontShade(LARGEFONT1, FONT_SHADE_GREEN); gprintf( 0, LINE_HEIGHT * ubLine, L"NPC Opinion:"); SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL); if (OKToCheckOpinion(MercPtrs[ gusSelectedSoldier ]->ubProfile)) gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gMercProfiles[ pSoldier->ubProfile ].bMercOpinion[ MercPtrs[ gusSelectedSoldier ]->ubProfile ] ); ubLine++; } } else if ( GetMouseMapPos( &usMapPos ) ) { DOOR_STATUS *pDoorStatus; STRUCTURE *pStructure; SetFont( LARGEFONT1 ); gprintf( 0,0,L"DEBUG LAND PAGE THREE" ); SetFont( LARGEFONT1 ); // OK, display door information here..... pDoorStatus = GetDoorStatus( usMapPos ); ubLine = 1; if ( pDoorStatus == NULL ) { SetFontColors(COLOR1); mprintf( 0, LINE_HEIGHT * ubLine, L"No Door Status"); ubLine++; ubLine++; ubLine++; } else { SetFontColors(COLOR1); mprintf( 0, LINE_HEIGHT * ubLine, L"Door Status Found:"); SetFontColors(COLOR2); mprintf( 150, LINE_HEIGHT * ubLine, L" %d", usMapPos ); ubLine++; SetFontColors(COLOR1); mprintf( 0, LINE_HEIGHT * ubLine, L"Actual Status:"); SetFontColors(COLOR2); if ( pDoorStatus->ubFlags & DOOR_OPEN ) { mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" ); } else { mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" ); } ubLine++; SetFontColors(COLOR1); mprintf( 0, LINE_HEIGHT * ubLine, L"Perceived Status:"); SetFontColors(COLOR2); if ( pDoorStatus->ubFlags & DOOR_PERCEIVED_NOTSET ) { mprintf( 200, LINE_HEIGHT * ubLine, L"NOT SET" ); } else { if ( pDoorStatus->ubFlags & DOOR_PERCEIVED_OPEN ) { mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" ); } else { mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" ); } } ubLine++; } //Find struct data and se what it says...... pStructure = FindStructure( usMapPos, STRUCTURE_ANYDOOR ); if ( pStructure == NULL ) { SetFontColors(COLOR1); mprintf( 0, LINE_HEIGHT * ubLine, L"No Door Struct Data"); ubLine++; } else { SetFontColors(COLOR1); mprintf( 0, LINE_HEIGHT * ubLine, L"State:"); SetFontColors(COLOR2); if ( !(pStructure->fFlags & STRUCTURE_OPEN) ) { mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" ); } else { mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" ); } ubLine++; } } } void AppendAttachmentCode( UINT16 usItem, STR16 str ) { switch( usItem ) { case SILENCER: wcscat( str, L" Sil" ); break; case SNIPERSCOPE: wcscat( str, L" Scp" ); break; case BIPOD: wcscat( str, L" Bip" ); break; case LASERSCOPE: wcscat( str, L" Las" ); break; } } void WriteQuantityAndAttachments( OBJECTTYPE *pObject, INT32 yp ) { CHAR16 szAttach[30]; BOOLEAN fAttachments; //100% Qty: 2 Attach: //100% Qty: 2 //100% Attach: //100% if( pObject->exists() == false ) return; //Build attachment string fAttachments = FALSE; if( (*pObject)[0]->AttachmentListSize() > 0 ) { fAttachments = TRUE; swprintf( szAttach, L"(" ); for (attachmentList::iterator iter = (*pObject)[0]->attachments.begin(); iter != (*pObject)[0]->attachments.end(); ++iter) { if(iter->exists()) AppendAttachmentCode( iter->usItem, szAttach ); } wcscat( szAttach, L" )" ); } if( Item[pObject->usItem].usItemClass == IC_AMMO ) { //ammo if( pObject->ubNumberOfObjects > 1 ) { CHAR16 str[100]; CHAR16 temp[10]; UINT8 i; swprintf( str, L"Clips: %d (%d", pObject->ubNumberOfObjects, (*pObject)[0]->data.objectStatus ); for( i = 1; i < pObject->ubNumberOfObjects; i++ ) { swprintf( temp, L", %d", (*pObject)[0]->data.objectStatus ); wcscat( str, temp ); } wcscat( str, L")" ); gprintf( 320, yp, str ); } else gprintf( 320, yp, L"%d rounds", (*pObject)[0]->data.objectStatus ); return; } if( pObject->ubNumberOfObjects > 1 && fAttachments ) { //everything gprintf( 320, yp, L"%d%% Qty: %d %s", (*pObject)[0]->data.objectStatus, pObject->ubNumberOfObjects, szAttach ); } else if( pObject->ubNumberOfObjects > 1 ) { //condition and quantity gprintf( 320, yp, L"%d%% Qty: %d ", (*pObject)[0]->data.objectStatus, pObject->ubNumberOfObjects ); } else if( fAttachments ) { //condition and attachments gprintf( 320, yp, L"%d%% %s", (*pObject)[0]->data.objectStatus, szAttach ); } else { //condition gprintf( 320, yp, L"%d%%", (*pObject)[0]->data.objectStatus ); } } void DebugSoldierPage4( ) { SOLDIERTYPE *pSoldier; UINT32 uiMercFlags; CHAR16 szOrders[20]; CHAR16 szAttitude[20]; UINT16 usSoldierIndex; UINT8 ubLine; if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) ) { // Get Soldier GetSoldier( &pSoldier, usSoldierIndex ); SetFont( LARGEFONT1 ); gprintf( 0,0,L"DEBUG SOLDIER PAGE FOUR, GRIDNO %d", pSoldier->sGridNo ); SetFont( LARGEFONT1 ); ubLine = 2; SetFontShade(LARGEFONT1, FONT_SHADE_GREEN); gprintf( 0, LINE_HEIGHT * ubLine, L"Exp. Level:"); SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL); gprintf( 150, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bExpLevel, EffectiveExpLevel(pSoldier) ); // SANDRO - added effective level calc switch( pSoldier->ubSoldierClass ) { case SOLDIER_CLASS_ADMINISTRATOR: gprintf( 320, LINE_HEIGHT * ubLine, L"(Administrator)" ); break; case SOLDIER_CLASS_ELITE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Elite)" ); break; case SOLDIER_CLASS_ARMY: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Troop)" ); break; case SOLDIER_CLASS_CREATURE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Creature)" ); break; case SOLDIER_CLASS_GREEN_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Green Militia)" ); break; case SOLDIER_CLASS_REG_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Reg Militia)" ); break; case SOLDIER_CLASS_ELITE_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Elite Militia)" ); break; case SOLDIER_CLASS_MINER: gprintf( 320, LINE_HEIGHT * ubLine, L"(Miner)" ); break; case SOLDIER_CLASS_ZOMBIE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" ); break; case SOLDIER_CLASS_BANDIT: gprintf( 320, LINE_HEIGHT * ubLine, L"(Bandit)" ); 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; UINT8 ubMaxVolume, ubVolume, ubBandaged, ubEffLife; INT8 bInWater = FALSE; // 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 ) + ((EffectiveDexterity( pSoldier ) * 4) / 10); // 24-100 iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveAgility( pSoldier, FALSE ) * 4) / 10); // 24-100 // big bonus for those "extra stealthy" mercs if ( pSoldier->ubBodyType == BLOODCAT ) { iStealthSkill += 50; } // SANDRO - new/old traits else if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT )) { iStealthSkill += gSkillTraitValues.ubSTBonusToMoveQuietly; } else if ( !gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_OT )) { iStealthSkill += 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY_OT ); } INT16 wornstealth = GetWornStealth(pSoldier); if ( wornstealth > 0 ) iStealthSkill += wornstealth / 2; //NumMessage("Base Stealth = ",stealthSkill); ubBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding; ubEffLife = pSoldier->stats.bLife + (ubBandaged / 2); // IF "SNEAKER'S" "EFFECTIVE LIFE" IS AT LESS THAN 50 if (ubEffLife < 50) { // reduce effective stealth skill by up to 50% for low life iStealthSkill -= (iStealthSkill * (50 - ubEffLife)) / 100; } // if breath is below 50% if (pSoldier->bBreath < 50) { // reduce effective stealth skill by up to 50% iStealthSkill -= (iStealthSkill * (50 - pSoldier->bBreath)) / 100; } // if sneaker is moving through water if (Water( pSoldier->sGridNo, pSoldier->pathing.bLevel ) ) { iStealthSkill -= 10; // 10% penalty } else if (DeepWater( pSoldier->sGridNo, pSoldier->pathing.bLevel ) ) { iStealthSkill -= 20; // 20% penalty } // Flugente: deleting this /*if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ADRENALINE ] ) { // minus 3 percent per bonus AP from adrenaline iStealthSkill -= 3 * pSoldier->drugs.bDrugEffect[ DRUG_TYPE_ADRENALINE ]; }*/ /* // if sneaker is too eager and impatient to "do it right" if ((pSoldier->bTrait == OVER_ENTHUS) || (pSoldier->aiData.bAttitude == AGGRESSIVE)) { ubStealthSkill -= 10; // 10% penalty } */ //NumMessage("Modified Stealth = ",stealthSkill); iStealthSkill = __max( iStealthSkill, 0 ); if (!pSoldier->bStealthMode) // REGULAR movement { //ubMaxVolume = MAX_MOVEMENT_NOISE - (iStealthSkill / 16); // 9 - (0 to 6) => 3 to 9 ubMaxVolume = MAX_MOVEMENT_NOISE - (iStealthSkill / 16) + bGroundVolumeModifier; // 9 - (0 to 6) => 3 to 9 if (bInWater) { ubMaxVolume++; // in water, can be even louder } switch (pSoldier->usAnimState) { case CRAWLING: ubMaxVolume -= 2; break; case SWATTING: ubMaxVolume -= 1; break; case RUNNING: ubMaxVolume += 3; break; } if (ubMaxVolume < 2) { ubVolume = ubMaxVolume; } else { ubVolume = 1 + (UINT8) PreRandom(ubMaxVolume); // actual volume is 1 to max volume } } else // in STEALTH mode { //iRoll = (INT32) PreRandom(100); // roll them bones! iRoll = (INT32) PreRandom(100) + bGroundStealthDifficultyModifier; // roll them bones! if (iRoll >= iStealthSkill) // v1.13 modification: give a second chance! { //iRoll = (INT32) PreRandom(100); iRoll = (INT32) PreRandom(100) + bGroundStealthDifficultyModifier; } if (iRoll < iStealthSkill) { ubVolume = 0; // made it, stayed quiet moving through this tile } else // OOPS! { ubVolume = 1 + ((iRoll - iStealthSkill + 1) / 16); // volume is 1 - 7 ... switch (pSoldier->usAnimState) { case CRAWLING: ubVolume -= 2; break; case SWATTING: ubVolume -= 1; break; case RUNNING: ubVolume += 3; break; } if (ubVolume < 1) { ubVolume = 0; } // randomize at which movement step the sneaking failure will happen // Status.stepsTilNoise = Random(MAXMOVESTEPS); // 0 - 6 } } //NumMessage("Volume = ",volume); // save noise volume where stepped HandleSteppedLook can back get at it later // Status.moveNoiseVolume = ubVolume; return( ubVolume ); } UINT8 DoorOpeningNoise( SOLDIERTYPE *pSoldier ) { INT32 sGridNo; DOOR_STATUS * pDoorStatus; UINT8 ubDoorNoise; // door being opened gridno is always the pending-action-data2 value sGridNo = pSoldier->aiData.sPendingActionData2; pDoorStatus = GetDoorStatus( sGridNo ); if ( pDoorStatus && pDoorStatus->ubFlags & DOOR_HAS_TIN_CAN ) { // double noise possible! ubDoorNoise = DOOR_NOISE_VOLUME * 3; } else { ubDoorNoise = DOOR_NOISE_VOLUME; } if ( MovementNoise( pSoldier ) ) { // failed any stealth checks return( ubDoorNoise ); } // succeeded in being stealthy! return( 0 ); } void MakeNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage ) { EV_S_NOISE SNoise; SNoise.ubNoiseMaker = ubNoiseMaker; SNoise.sGridNo = sGridNo; SNoise.bLevel = bLevel; SNoise.ubTerrType = ubTerrType; SNoise.ubVolume = ubVolume; SNoise.ubNoiseType = ubNoiseType; swprintf( SNoise.zNoiseMessage, L"%s", zNoiseMessage ); //SNoise.zNoiseMessage = zNoiseMessage; if ( gTacticalStatus.ubAttackBusyCount ) { // delay these events until the attack is over! AddGameEvent( S_NOISE, DEMAND_EVENT_DELAY, &SNoise ); } else { // AddGameEvent( S_NOISE, 0, &SNoise ); // now call directly OurNoise( SNoise.ubNoiseMaker, SNoise.sGridNo, SNoise.bLevel, SNoise.ubTerrType, SNoise.ubVolume, SNoise.ubNoiseType, SNoise.zNoiseMessage ); } /* INT8 bWeControlNoise = FALSE; if (ubNoiseMode == UNEXPECTED) { bWeControlNoise = TRUE; } else // EXPECTED noise { if (ubNoiseMaker < TOTAL_SOLDIERS) { if (Menptr[ubNoiseMaker].controller == Net.pnum) { bWeControlNoise = TRUE; } } else { // expected noise by NOBODY is sent by LEADER, received by others if (Net.pnum == LEADER) { bWeControlNoise = TRUE; } } } if (bWeControlNoise) { OurNoise(ubNoiseMaker,sGridNo,ubTerrType,ubVolume,ubNoiseType,ubNoiseMode); } else { // can't be UNEXPECTED, check if it's a SEND or NO_SEND if (ubNoiseMode == EXPECTED_NOSEND) { // no NET_NOISE message is required, trigger TheirNoise() right here TheirNoise(ubNoiseMaker,sGridNo,ubTerrType,ubVolume,ubNoiseType,ubNoiseMode); } else { // EXPECTED_SEND, TheirNoise() will be triggered by the arrival of the // NET_NOISE message, not by us. Wait here until that's all done... // wait for the NET_NOISE to arrive (it will set noiseReceived flag) //stopAction = TRUE; // prevent real-time events from passing us by MarkTime(&LoopTime); while (Status.noiseReceived != ubNoiseType) { LoopTimePast = Elapsed(&LoopTime); if (LoopTimePast > 50 && LoopTimePast < 2000) { KeepInterfaceGoing(19); // xxx yyy zzz experimental Aug 16/96 9:15 pm } else { KeyHitReport("MakeNoise: Waiting for NET_NOISE, need ubNoiseType ",ubNoiseType); } CheckForNetIncoming(); }; //stopAction = FALSE; // re-enable real-time events // turn off the oppChk flag again Status.noiseReceived = -1; } } */ } void OurNoise( UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage ) { #ifdef BYPASSNOISE return; #endif #ifdef BETAVERSION tempstr = String("OurNoise: ubNoiseType = %s, ubNoiseMaker = %d, ubNoiseMode = %d, sGridNo = %d, ubVolume = %d", NoiseTypeStr[ubNoiseType],ubNoiseMaker,ubNoiseMode,sGridNo,ubVolume); #ifdef RECORDNET fprintf(NetDebugFile,"\t%s\n",tempstr); #endif #ifdef TESTNOISE PopMessage(tempstr); #endif #endif // see if anyone actually hears this noise, sees ubNoiseMaker, etc. ProcessNoise(ubNoiseMaker, sGridNo, bLevel, ubTerrType, ubVolume, ubNoiseType, zNoiseMessage ); if ((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && (ubNoiseMaker < TOTAL_SOLDIERS) && !gfDelayResolvingBestSightingDueToDoor ) { // interrupts are possible, resolve them now (we're in control here) // (you can't interrupt NOBODY, even if you hear the noise) ResolveInterruptsVs(MercPtrs[ubNoiseMaker],NOISEINTERRUPT); } } void TheirNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage ) { // SOLDIERTYPE *pSoldier; #ifdef BYPASSNOISE return; #endif #ifdef BETAVERSION tempstr = String("TheirNoise: ubNoiseType = %s, ubNoiseMaker = %d, ubNoiseMode = %d, sGridNo = %d, ubVolume = %d", NoiseTypeStr[ubNoiseType],ubNoiseMaker,ubNoiseMode,sGridNo,ubVolume); #ifdef RECORDNET fprintf(NetDebugFile,"\t%s\n",tempstr); #endif #ifdef TESTNOISE PopMessage(tempstr); #endif #endif // see if anyone actually hears this noise, sees noiseMaker, etc. ProcessNoise(ubNoiseMaker,sGridNo,bLevel,ubTerrType,ubVolume,ubNoiseType,zNoiseMessage); // if noiseMaker is SOMEBODY if (ubNoiseMaker < TOTAL_SOLDIERS) { /* pSoldier = MercPtrs[ubNoiseMaker]; //stopAction = TRUE; // prevent real-time events from passing us by MarkTime(&LoopTime); do { LoopTimePast = Elapsed(&LoopTime); if (LoopTimePast > 50 && LoopTimePast < 2000) { KeepInterfaceGoing(20); // xxx yyy zzz experimental Aug 16/96 9:15 pm } else { // the gridno is added to end of the string by KeyHitReport itself... tempstr = String("TheirNoise: Waiting for NOISE_INT_DONE for guynum %d, ubNoiseType %d(%s), sGridNo ", pSoldier->guynum,ubNoiseType,NoiseTypeStr[ubNoiseType]); KeyHitReport(tempstr,sGridNo); } CheckForNetIncoming(); } while ((ExtMen[pSoldier->guynum].noiseRcvdGridno[ubNoiseType] != sGridNo) && pSoldier->in_sector); //stopAction = FALSE; // re-enable real-time events // reset the gridno flag for next time ExtMen[pSoldier->guynum].noiseRcvdGridno[ubNoiseType] = NOWHERE; */ } // else if noiseMaker's NOBODY, no opplist changes or interrupts are possible } void ProcessNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubBaseVolume, UINT8 ubNoiseType, STR16 zNoiseMessage ) { SOLDIERTYPE *pSoldier; UINT8 bLoop, bTeam; UINT8 ubLoudestEffVolume, ubEffVolume; // UINT8 ubPlayVolume; INT8 bCheckTerrain = FALSE; UINT8 ubSourceTerrType, ubSource; INT8 bTellPlayer = FALSE, bHeard, bSeen; UINT8 ubHeardLoudestBy = NOBODY, ubNoiseDir = 0xff, ubLoudestNoiseDir = 0xff; #ifdef RECORDOPPLIST fprintf(OpplistFile,"PN: nType=%s, nMaker=%d, g=%d, tType=%d, bVol=%d\n", NoiseTypeStr[noiseType],ubNoiseMaker,sGridNo,ubTerrType,baseVolume); #endif // if the base volume itself was negligible if (!ubBaseVolume) return; // EXPLOSIONs are special, because they COULD be caused by a merc who is // no longer alive (but he placed the bomb or flaky grenade in the past). // Later noiseMaker gets whacked to NOBODY anyway, so that's OK. So a // dead noiseMaker is only used here to decide WHICH soldiers HearNoise(). // if noise is made by a person, AND it's not noise from an explosion if ((ubNoiseMaker < TOTAL_SOLDIERS) && (ubNoiseType != NOISE_EXPLOSION)) { // inactive/not in sector/dead soldiers, shouldn't be making noise! if (!Menptr[ubNoiseMaker].bActive || !Menptr[ubNoiseMaker].bInSector || Menptr[ubNoiseMaker].flags.uiStatusFlags & SOLDIER_DEAD) { #ifdef BETAVERSION NumMessage("ProcessNoise: ERROR - Noisemaker is inactive/not in sector/dead, Guy #",ubNoiseMaker); #endif return; } // if he's out of life, and this isn't just his "dying scream" which is OK if (!Menptr[ubNoiseMaker].stats.bLife && (ubNoiseType != NOISE_SCREAM)) { #ifdef BETAVERSION NumMessage("ProcessNoise: ERROR - Noisemaker is lifeless, Guy #",ubNoiseMaker); #endif return; } } // DETERMINE THE TERRAIN TYPE OF THE GRIDNO WHERE NOISE IS COMING FROM ubSourceTerrType = gpWorldLevelData[sGridNo].ubTerrainID; /* // start with the terrain type passed in to us ubSourceTerrType = ubTerrType; // if this isn't enough to get a valid terrain type if ((ubSourceTerrType < GROUNDTYPE) || (ubSourceTerrType > OCEANTYPE)) { // use the source gridno of the noise itself ubSourceTerrType = TTypeList[Terrain(sGridNo)]; } */ // if we have now somehow obtained a valid terrain type if ((ubSourceTerrType >= FLAT_GROUND) || (ubSourceTerrType <= DEEP_WATER)) { //NumMessage("Source Terrain Type = ",ubSourceTerrType); bCheckTerrain = TRUE; } // else give up trying to get terrain type, just assume sound isn't muffled // DETERMINE THE *PERCEIVED* SOURCE OF THE NOISE switch (ubNoiseType) { // for noise generated by an OBJECT shot/thrown/dropped by the noiseMaker case NOISE_ROCK_IMPACT: gsWhoThrewRock = ubNoiseMaker; //fall through here!!! case NOISE_BULLET_IMPACT: case NOISE_GRENADE_IMPACT: case NOISE_EXPLOSION: // the source of the noise is not at all obvious, so hide it from // the listener and maintain noiseMaker's cover by making source NOBODY ubSource = NOBODY; break; default: // normal situation: the noiseMaker is obviously the source of the noise ubSource = ubNoiseMaker; break; } // LOOP THROUGH EACH TEAM for (bTeam = 0; bTeam < MAXTEAMS; bTeam++) { // skip any inactive teams if (!gTacticalStatus.Team[bTeam].bTeamActive) { continue; } // if a the noise maker is a person, not just NOBODY if (ubNoiseMaker < TOTAL_SOLDIERS) { // if this team is the same TEAM as the noise maker's // (for now, assume we will report noises by unknown source on same SIDE) // OR, if the noise maker is currently in sight to this HUMAN team // CJC: changed to if the side is the same side as the noise maker's! // CJC: changed back! if (bTeam == Menptr[ubNoiseMaker].bTeam) { continue; } if (gTacticalStatus.Team[bTeam].bHuman) { if (gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_CURRENTLY && ubNoiseType != NOISE_VOICE) { continue; } } } #ifdef REPORTTHEIRNOISE // if this is any team if (TRUE) #else // if this is our team if (TRUE) //if (bTeam == Net.pnum) #endif { // tell player about noise if enemies are present bTellPlayer = gTacticalStatus.fEnemyInSector && ( !(gTacticalStatus.uiFlags & INCOMBAT) || (gTacticalStatus.ubCurrentTeam) ); #ifndef TESTNOISE switch (ubNoiseType) { case NOISE_GUNFIRE: case NOISE_BULLET_IMPACT: case NOISE_ROCK_IMPACT: case NOISE_GRENADE_IMPACT: // It's noise caused by a projectile. If the projectile was seen by // the local player while in flight (PublicBullet), then don't bother // giving him a message about the noise it made, he's obviously aware. if (1 /*PublicBullet*/) { bTellPlayer = FALSE; } break; case NOISE_EXPLOSION: // if center of explosion is in visual range of team, don't report // noise, because the player is already watching the thing go BOOM! if (TeamMemberNear(bTeam,sGridNo,STRAIGHT)) { bTellPlayer = FALSE; } break; case NOISE_SILENT_ALARM: bTellPlayer = FALSE; break; } // if noise was made by a person if (ubNoiseMaker < TOTAL_SOLDIERS) { // if noisemaker has been *PUBLICLY* SEEN OR HEARD during THIS TURN if ((gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_CURRENTLY) || // seen now (gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_THIS_TURN) || // seen this turn (gbPublicOpplist[bTeam][ubNoiseMaker] == HEARD_THIS_TURN)) // heard this turn { // then don't bother reporting any noise made by him to the player bTellPlayer = FALSE; } /* else if ( (Menptr[ubNoiseMaker].bVisible == TRUE) && (bTeam == gbPlayerNum) ) { ScreenMsg( MSG_FONT_YELLOW, MSG_TESTVERSION, L"Handling noise from person not currently seen in player's public opplist" ); } */ // anv: special exception: we want to report enemy taunt, because of text content if ( ubNoiseType == NOISE_VOICE ) { bTellPlayer = TRUE; } if ( MercPtrs[ ubNoiseMaker ]->stats.bLife == 0 ) { // this guy is dead (just dying) so don't report to player bTellPlayer = FALSE; } } } #endif // refresh flags for this new team bHeard = FALSE; bSeen = FALSE; ubLoudestEffVolume = 0; ubHeardLoudestBy = NOBODY; // All mercs on this team check if they are eligible to hear this noise for (bLoop = gTacticalStatus.Team[bTeam].bFirstID,pSoldier = Menptr + bLoop; bLoop <= gTacticalStatus.Team[bTeam].bLastID; bLoop++,pSoldier++) { // if this "listener" is inactive, or in no condition to care if (!pSoldier->bActive || !pSoldier->bInSector || pSoldier->flags.uiStatusFlags & SOLDIER_DEAD || (pSoldier->stats.bLife < OKLIFE) || pSoldier->ubBodyType == LARVAE_MONSTER) { continue; // skip him! } if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->bTeam == OUR_TEAM ) { continue; // skip } if ( bTeam == gbPlayerNum && pSoldier->bAssignment == ASSIGNMENT_POW ) { // POWs should not be processed for noise continue; } // if a the noise maker is a person, not just NOBODY if (ubNoiseMaker < TOTAL_SOLDIERS) { // if this listener can see this noise maker if (pSoldier->aiData.bOppList[ubNoiseMaker] == SEEN_CURRENTLY) { // civilians care about gunshots even if they come from someone they can see // ChrisL: Crows will fly away if they hear any noise if ( !( pSoldier->aiData.bNeutral && ubNoiseType == NOISE_GUNFIRE ) && pSoldier->ubBodyType != CROW ) { // anv: we want to report taunt even if we see noisemaker if(ubNoiseType != NOISE_VOICE) { continue; // then who cares whether he can also hear the guy? } } } // screen out allied militia from hearing us switch( MercPtrs[ ubNoiseMaker ]->bTeam ) { case OUR_TEAM: // if the listener is militia and still on our side, ignore noise from us if ( pSoldier->bTeam == MILITIA_TEAM && pSoldier->bSide == 0 ) { continue; } break; case ENEMY_TEAM: switch( pSoldier->ubProfile ) { case WARDEN: case GENERAL: case SERGEANT: case CONRAD: // WANNE: This fixes the bug, that Conrad, when he is in OUR team, cannot interrupt enemies!!! if (pSoldier->bTeam == OUR_TEAM) { // WANNE: Allow interrupt, if one of those guys is in OUR team! break; } else { // No interrupt for those 4 guys continue; } default: break; } break; case MILITIA_TEAM: // if the noisemaker is militia and still on our side, ignore noise if we're listening if ( pSoldier->bTeam == OUR_TEAM && MercPtrs[ ubNoiseMaker ]->bSide == 0 ) { continue; } break; } // HEADROCK HAM 3.6: Bloodcat "static" sectors have been externalized, and there can be more than one. // Also, there's a toggle that determines whether or not bloodcats can sense enemies in this sector. UINT8 ubSectorID = SECTOR(gWorldSectorX, gWorldSectorY); UINT8 PlacementType = gBloodcatPlacements[ ubSectorID ][0].PlacementType; 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; } // Can the listener hear noise of that volume given his circumstances? ubEffVolume = CalcEffVolume(pSoldier,sGridNo,bLevel,ubNoiseType,ubBaseVolume,bCheckTerrain,pSoldier->bOverTerrainType,ubSourceTerrType); #ifdef RECORDOPPLIST fprintf(OpplistFile,"PN: guy %d - effVol=%d,chkTer=%d,pSoldier->tType=%d,srcTType=%d\n", bLoop,effVolume,bCheckTerrain,pSoldier->terrtype,ubSourceTerrType); #endif if (ubEffVolume > 0) { // ALL RIGHT! Passed all the tests, this listener hears this noise!!! HearNoise(pSoldier,ubSource,sGridNo,bLevel,ubEffVolume,ubNoiseType, (UINT8 *)&bSeen); bHeard = TRUE; ubNoiseDir = atan8(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(sGridNo),CenterY(sGridNo)); // check the 'noise heard & reported' bit for that soldier & direction if ( ubNoiseType != NOISE_MOVEMENT || bTeam != OUR_TEAM || (pSoldier->aiData.bInterruptDuelPts != NO_INTERRUPT) || !(pSoldier->ubMovementNoiseHeard & (1 << ubNoiseDir) ) ) { if (ubEffVolume > ubLoudestEffVolume) { ubLoudestEffVolume = ubEffVolume; ubHeardLoudestBy = pSoldier->ubID; ubLoudestNoiseDir = ubNoiseDir; } } } else { //NameMessage(pSoldier," can't hear this noise",2500); ubEffVolume = 0; } } // if the noise was heard at all if (bHeard) { // and we're doing our team if (bTeam == OUR_TEAM) /* if (team == Net.pnum) */ { // if we are to tell the player about this type of noise if (bTellPlayer && ubHeardLoudestBy != NOBODY ) { // the merc that heard it the LOUDEST is the one to comment // should add level to this function call TellPlayerAboutNoise(MercPtrs[ubHeardLoudestBy],ubNoiseMaker,sGridNo,bLevel,ubLoudestEffVolume,ubNoiseType, ubLoudestNoiseDir, zNoiseMessage); if ( ubNoiseType == NOISE_MOVEMENT) { MercPtrs[ ubHeardLoudestBy ]->ubMovementNoiseHeard |= (1 << ubNoiseDir); } } //if ( !(pSoldier->ubMovementNoiseHeard & (1 << ubNoiseDir) ) ) } #ifdef REPORTTHEIRNOISE else // debugging: report noise heard by other team's soldiers { if (bTellPlayer) { TellPlayerAboutNoise(MercPtrs[ubHeardLoudestBy],ubNoiseMaker,sGridNo,bLevel,ubLoudestEffVolume,ubNoiseType, ubLoudestNoiseDir); } } #endif } // if the listening team is human-controlled AND // the noise's source is another soldier // (computer-controlled teams don't radio or automatically report NOISE) if (gTacticalStatus.Team[bTeam].bHuman && (ubSource < TOTAL_SOLDIERS)) { // if ubNoiseMaker was seen by at least one member of this team if (bSeen) { // Temporary for opplist synching - disable random order radioing #ifdef RECORDOPPLIST // insure all machines radio in synch to keep logs the same for (bLoop = Status.team[team].guystart,pSoldier = Menptr + bLoop; bLoop < Status.team[team].guyend; bLoop++,pSoldier++) { // if this merc is active, in this sector, and well enough to look if (pSoldier->active && pSoldier->in_sector && (pSoldier->life >= OKLIFE)) { RadioSightings(pSoldier,ubSource); pSoldier->newOppCnt = 0; } } #else // if this human team is OURS if (1 /* bTeam == Net.pnum */) { // this team is now allowed to report sightings and set Public flags OurTeamRadiosRandomlyAbout(ubSource); } else // noise was heard by another human-controlled team (not ours) { // mark noise maker as being seen currently //UpdatePublic(bTeam,ubSource,SEEN_CURRENTLY,sGridNo,NOUPDATE,ACTUAL); UpdatePublic(bTeam,ubSource,SEEN_CURRENTLY,sGridNo,bLevel); } #endif } else // not seen { if (bHeard) { #ifdef RECORDOPPLIST fprintf(OpplistFile,"UpdatePublic (ProcessNoise/heard) for team %d about %d\n",team,ubSource); #endif // mark noise maker as having been PUBLICLY heard THIS TURN //UpdatePublic(team,ubSource,HEARD_THIS_TURN,sGridNo,NOUPDATE,ACTUAL); UpdatePublic(bTeam,ubSource,HEARD_THIS_TURN,sGridNo,bLevel); } } } } gsWhoThrewRock = NOBODY; } UINT8 CalcEffVolume(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT8 ubNoiseType, UINT8 ubBaseVolume, UINT8 bCheckTerrain, UINT8 ubTerrType1, UINT8 ubTerrType2) { INT32 iEffVolume, iDistance; // Lesh: deafness if ( pSoldier->bDeafenedCounter > 0 ) { return( 0 ); } if ( FindWalkman(pSoldier) != ITEM_NOT_FOUND ) { return( 0 ); } if ( gTacticalStatus.uiFlags & INCOMBAT ) { // ATE: Funny things happen to ABC stuff if bNewSituation set.... // anv: added exception to NOISE_VOICE if ( gTacticalStatus.ubCurrentTeam == pSoldier->bTeam && ubNoiseType != NOISE_VOICE ) { return( 0 ); } } //sprintf(tempstr,"CalcEffVolume BY %s for gridno %d, baseVolume = %d",pSoldier->name,gridno,baseVolume); //PopMessage(tempstr); // adjust default noise volume by listener's hearing capability iEffVolume = (INT32) ubBaseVolume + (INT32) DecideHearing( pSoldier ); // effective volume reduced by listener's number of opponents in sight iEffVolume -= pSoldier->aiData.bOppCnt; // calculate the distance (in adjusted pixels) between the source of the // noise (gridno) and the location of the would-be listener (pSoldier->gridno) iDistance = (INT32) PythSpacesAway( pSoldier->sGridNo, sGridNo ); /* distance = AdjPixelsAway(pSoldier->x,pSoldier->y,CenterX(sGridNo),CenterY(sGridNo)); distance /= 15; // divide by 15 to convert from adj. pixels to tiles */ //NumMessage("Distance = ",distance); // effective volume fades over distance beyond 1 tile away iEffVolume -= (iDistance - 1); //ddd{ 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 (bCheckTerrain) { // if, between noise and listener, one is outside and one is inside // NOTE: This is a pretty dumb way of doing things, since it won't detect // the presence of walls between 2 spots both inside or both outside, but // given our current system it's the best that we can do if (((ubTerrType1 == FLAT_FLOOR) && (ubTerrType2 != FLAT_FLOOR)) || ((ubTerrType1 != FLAT_FLOOR) && (ubTerrType2 == FLAT_FLOOR))) { //PopMessage("Sound is muffled by wall(s)"); // sound is muffled, reduce the effective volume of the noise iEffVolume -= 5; } } } //NumMessage("effVolume = ",ubEffVolume); if (iEffVolume > 0) { return( (UINT8) iEffVolume ); } else { return( 0 ); } } void HearNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 *ubSeen) { INT16 sNoiseX, sNoiseY; INT8 bHadToTurn = FALSE, bSourceSeen = FALSE; INT8 bOldOpplist; INT8 bDirection; BOOLEAN fMuzzleFlash = FALSE; if ( pSoldier->ubBodyType == CROW ) { CrowsFlyAway( pSoldier->bTeam ); return; } // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "%d hears noise from %d (%d/%d) volume %d", pSoldier->ubID, ubNoiseMaker, sGridNo, bLevel, ubVolume ) ); // "Turn head" towards the source of the noise and try to see what's there // don't use DistanceVisible here, but use maximum visibility distance // in as straight line instead. Represents guy "turning just his head" // CJC 97/10: CHANGE! Since STRAIGHT can not reliably be used as a // max sighting distance (varies based on realtime/turnbased), call // the function with the new DIRECTION_IRRELEVANT define // is he close enough to see that gridno if he turns his head? // ignore muzzle flashes when turning head to see noise if ( ubNoiseType == NOISE_GUNFIRE && ubNoiseMaker != NOBODY && MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash ) { sNoiseX = CenterX(sGridNo); sNoiseY = CenterY(sGridNo); bDirection = atan8(pSoldier->sX,pSoldier->sY,sNoiseX,sNoiseY); if ( pSoldier->ubDirection != bDirection && pSoldier->ubDirection != gOneCDirection[ bDirection ] && pSoldier->ubDirection != gOneCCDirection[ bDirection ] ) { // temporarily turn off muzzle flash so DistanceVisible can be calculated without it MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash = FALSE; fMuzzleFlash = TRUE; } } int sDistVisible = pSoldier->GetMaxDistanceVisible(sGridNo, bLevel, CALC_FROM_WANTED_DIR ); if ( fMuzzleFlash ) { // turn flash on again MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash = TRUE; } if (PythSpacesAway(pSoldier->sGridNo,sGridNo) <= sDistVisible ) { // just use the XXadjustedXX center of the gridno sNoiseX = CenterX(sGridNo); sNoiseY = CenterY(sGridNo); if (pSoldier->ubDirection != atan8(pSoldier->sX,pSoldier->sY,sNoiseX,sNoiseY)) { bHadToTurn = TRUE; } else { bHadToTurn = FALSE; } // and we can trace a line of sight to his x,y coordinates? // (taking into account we are definitely aware of this guy now) // skip LOS check if we had to turn and we're a tank. sorry Mr Tank, no looking out of the sides for you! if ( !(bHadToTurn && 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); } } } } else // noise maker still can't be seen { SetNewSituation( pSoldier ); // re-evaluate situation // if noise type was unmistakably that of gunfire if (((ubNoiseType == NOISE_GUNFIRE) || (ubNoiseType == NOISE_BULLET_IMPACT)) && (ubVolume >= 3)) { // if status is only GREEN or YELLOW if (pSoldier->aiData.bAlertStatus < STATUS_RED) { // then this soldier goes to status RED, has proof of enemy presence pSoldier->aiData.bAlertStatus = STATUS_RED; CheckForChangingOrders(pSoldier); } } // remember that the soldier has been heard and his new location UpdatePersonal(pSoldier,ubNoiseMaker,HEARD_THIS_TURN,sGridNo, bLevel); // Public info is not set unless EVERYONE on the team fails to see the // ubnoisemaker, leaving the 'seen' flag FALSE. See ProcessNoise(). // CJC: set the noise gridno for the soldier, if appropriate - this is what is looked at by the AI! if (ubVolume >= pSoldier->aiData.ubNoiseVolume) { // yes it is, so remember this noise INSTEAD (old noise is forgotten) pSoldier->aiData.sNoiseGridno = sGridNo; pSoldier->bNoiseLevel = bLevel; // no matter how loud noise was, don't remember it for than 12 turns! if (ubVolume < MAX_MISC_NOISE_DURATION) { pSoldier->aiData.ubNoiseVolume = ubVolume; } else { pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION; } SetNewSituation( pSoldier ); // force a fresh AI decision to be made } } if ( pSoldier->aiData.fAIFlags & AI_ASLEEP ) { switch( ubNoiseType ) { case NOISE_BULLET_IMPACT: case NOISE_GUNFIRE: case NOISE_EXPLOSION: case NOISE_SCREAM: case NOISE_WINDOW_SMASHING: case NOISE_DOOR_SMASHING: // WAKE UP! pSoldier->aiData.fAIFlags &= (~AI_ASLEEP); break; default: break; } } // FIRST REQUIRE MUTUAL HOSTILES! if (!CONSIDERED_NEUTRAL( MercPtrs[ ubNoiseMaker ], pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, MercPtrs[ ubNoiseMaker ] ) && (pSoldier->bSide != MercPtrs[ ubNoiseMaker ]->bSide)) { // regardless of whether the noisemaker (who's not NOBODY) was seen or not, // as long as listener meets minimum interrupt conditions if ( gfDelayResolvingBestSightingDueToDoor) { if ( bSourceSeen && (!( (gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) ) || (gubSightFlags & SIGHTINTERRUPT && StandardInterruptConditionsMet(pSoldier,ubNoiseMaker,bOldOpplist)) ) ) { // we should be adding this to the array for the AllTeamLookForAll to handle // since this is a door opening noise, add a bonus equal to half the door volume UINT8 ubPoints; ubPoints = CalcInterruptDuelPts( pSoldier, ubNoiseMaker, TRUE ); if ( ubPoints != NO_INTERRUPT ) { // require the enemy not to be dying if we are the sighter; in other words, // always add for AI guys, and always add for people with life >= OKLIFE if ( pSoldier->bTeam != gbPlayerNum || MercPtrs[ ubNoiseMaker ]->stats.bLife >= OKLIFE ) { ReevaluateBestSightingPosition( pSoldier, (UINT8) (ubPoints + (ubVolume / 2)) ); } } } } else { if ( (gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) ) { if (StandardInterruptConditionsMet(pSoldier,ubNoiseMaker,bOldOpplist)) { // he gets a chance to interrupt the noisemaker pSoldier->aiData.bInterruptDuelPts = CalcInterruptDuelPts(pSoldier,ubNoiseMaker, TRUE ); DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Calculating int duel pts in noise code, %d has %d points", pSoldier->ubID, pSoldier->aiData.bInterruptDuelPts ) ); } else { pSoldier->aiData.bInterruptDuelPts = NO_INTERRUPT; } } else if ( bSourceSeen ) { // seen source, in realtime, so check for sighting stuff HandleBestSightingPositionInRealtime(); } } } } else // noise made by NOBODY { // if noise type was unmistakably that of an explosion (seen or not) or alarm if (!(pSoldier->flags.uiStatusFlags & SOLDIER_PC)) { if ( ( ubNoiseType == NOISE_EXPLOSION || ubNoiseType == NOISE_SILENT_ALARM ) && (ubVolume >= 3) ) { if ( ubNoiseType == NOISE_SILENT_ALARM ) { WearGasMaskIfAvailable( pSoldier ); } // if status is only GREEN or YELLOW if (pSoldier->aiData.bAlertStatus < STATUS_RED) { // then this soldier goes to status RED, has proof of enemy presence pSoldier->aiData.bAlertStatus = STATUS_RED; CheckForChangingOrders(pSoldier); } } } // if the source of the noise can't be seen, // OR if it's a rock and the listener had to turn so that by the time he // looked all his saw was a bunch of rocks lying still if (!bSourceSeen || ((ubNoiseType == NOISE_ROCK_IMPACT) && (bHadToTurn) ) || ubNoiseType == NOISE_SILENT_ALARM ) { // check if the effective volume of this new noise is greater than or at // least equal to the volume of the currently noticed noise stored if (ubVolume >= pSoldier->aiData.ubNoiseVolume) { // yes it is, so remember this noise INSTEAD (old noise is forgotten) pSoldier->aiData.sNoiseGridno = sGridNo; pSoldier->bNoiseLevel = bLevel; // no matter how loud noise was, don't remember it for than 12 turns! if (ubVolume < MAX_MISC_NOISE_DURATION) { pSoldier->aiData.ubNoiseVolume = ubVolume; } else { pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION; } SetNewSituation( pSoldier ); // force a fresh AI decision to be made } } else // if listener sees the source of the noise, AND it's either a grenade, // or it's a rock that he watched land (didn't need to turn) { SetNewSituation( pSoldier ); // re-evaluate situation // if status is only GREEN or YELLOW if (pSoldier->aiData.bAlertStatus < STATUS_RED) { // then this soldier goes to status RED, has proof of enemy presence pSoldier->aiData.bAlertStatus = STATUS_RED; CheckForChangingOrders(pSoldier); } } if ( gubBestToMakeSightingSize == BEST_SIGHTING_ARRAY_SIZE_INCOMBAT ) { // if the noise heard was the fall of a rock if ((gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) && ubNoiseType == NOISE_ROCK_IMPACT ) { // give every ELIGIBLE listener an automatic interrupt, since it's // reasonable to assume the guy throwing wants to wait for their reaction! if (StandardInterruptConditionsMet(pSoldier,NOBODY,FALSE)) { pSoldier->aiData.bInterruptDuelPts = AUTOMATIC_INTERRUPT; // force automatic interrupt DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Calculating int duel pts in noise code, %d has %d points", pSoldier->ubID, pSoldier->aiData.bInterruptDuelPts ) ); } else { pSoldier->aiData.bInterruptDuelPts = NO_INTERRUPT; } } } } AI::tactical::AIInputData ai_input(AI::tactical::AIInputData::Auditive(), ubNoiseMaker, sGridNo, bLevel, ubVolume, ubNoiseType); AI::tactical::PlanInputData plan_input((gTacticalStatus.uiFlags & TURNBASED)!=0, gTacticalStatus); AI::tactical::PlanFactoryLibrary* plan_lib(AI::tactical::PlanFactoryLibrary::instance()); plan_lib->update_plan(pSoldier->bAIIndex, pSoldier, ai_input); } void TellPlayerAboutNoise( SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 ubNoiseDir, STR16 zNoiseMessage ) { UINT8 ubVolumeIndex; // CJC: tweaked the noise categories upwards a bit because our movement noises can be louder now. if (ubVolume < 4) { ubVolumeIndex = 0; // 1-3: faint noise } else if (ubVolume < 8) // 4-7: definite noise { ubVolumeIndex = 1; } else if (ubVolume < 12) // 8-11: loud noise { ubVolumeIndex = 2; } else // 12+: very loud noise { ubVolumeIndex = 3; } // display a message about a noise... // e.g. Sidney hears a loud splash from/to? the north. if ( ubNoiseMaker != NOBODY && pSoldier->bTeam == gbPlayerNum && pSoldier->bTeam == Menptr[ubNoiseMaker].bTeam ) { #ifdef JA2BETAVERSION ScreenMsg( MSG_FONT_RED, MSG_ERROR, L"ERROR! TAKE SCREEN CAPTURE AND TELL CAMFIELD NOW!" ); ScreenMsg( MSG_FONT_RED, MSG_ERROR, L"%s (%d) heard noise from %s (%d), noise at %dL%d, type %d", pSoldier->name, pSoldier->ubID, Menptr[ubNoiseMaker].name, ubNoiseMaker, sGridNo, bLevel, ubNoiseType ); #endif } // anv: special treatment of NOISE_VOICE - also display taunt message if( ubNoiseType == NOISE_VOICE ) { // information about direction etc. only displayed if we don't see noise maker if( gbPublicOpplist[gbPlayerNum][ubNoiseMaker] != SEEN_CURRENTLY && pSoldier->aiData.bOppList[ubNoiseMaker] != SEEN_CURRENTLY ) { if( bLevel == pSoldier->pathing.bLevel && ubNoiseType == NOISE_VOICE ) { ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], pDirectionStr[ubNoiseDir] ); } else if ( bLevel > pSoldier->pathing.bLevel ) { // from above! ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[6] ); } else { // from below! ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[7] ); } } if( ubVolumeIndex > 0 ) // definite noise - we're able to recognize words { // do we know who said that? if( gbPublicOpplist[gbPlayerNum][ubNoiseMaker] == SEEN_CURRENTLY || pSoldier->aiData.bOppList[ubNoiseMaker] == SEEN_CURRENTLY ) { if( gTauntsSettings.fTauntShowPopupBox == TRUE ) ShowTauntPopupBox( MercPtrs[ubNoiseMaker], zNoiseMessage ); if( gTauntsSettings.fTauntShowInLog == TRUE ) ScreenMsg( FONT_GRAY2, MSG_INTERFACE, L"%s: %s", MercPtrs[ubNoiseMaker]->GetName(), zNoiseMessage ); } else { if( gTauntsSettings.fTauntShowPopupBox == TRUE && gTauntsSettings.fTauntShowPopupBoxIfHeard == TRUE ) ShowTauntPopupBox( MercPtrs[ubNoiseMaker], zNoiseMessage ); if( gTauntsSettings.fTauntShowInLog == TRUE && gTauntsSettings.fTauntShowInLogIfHeard == TRUE ) ScreenMsg( FONT_GRAY2, MSG_INTERFACE, L"%s: %s", pTauntUnknownVoice[0], zNoiseMessage ); } } } else if ( bLevel == pSoldier->pathing.bLevel || ubNoiseType == NOISE_EXPLOSION || ubNoiseType == NOISE_SCREAM || ubNoiseType == NOISE_ROCK_IMPACT || ubNoiseType == NOISE_GRENADE_IMPACT ) { ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], pDirectionStr[ubNoiseDir] ); } else if ( bLevel > pSoldier->pathing.bLevel ) { // from above! ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[6] ); } else { // from below! ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[7] ); } // if the quote was faint, say something if (ubVolumeIndex == 0) { #ifdef JA2UB //Ja25 No meanwhiles #else if ( !AreInMeanwhile( ) && !( gTacticalStatus.uiFlags & ENGAGED_IN_CONV) && pSoldier->ubTurnsUntilCanSayHeardNoise == 0) #endif { TacticalCharacterDialogue( pSoldier, QUOTE_HEARD_SOMETHING ); if ( gTacticalStatus.uiFlags & INCOMBAT ) { pSoldier->ubTurnsUntilCanSayHeardNoise = 2; } else { pSoldier->ubTurnsUntilCanSayHeardNoise = 5; } } } //DIGICRAB: Loud Sound Locator //show a locator for very loud noises if we are in PLATINUM mode and have an extended ear //Madd: if(gGameOptions.ubGameStyle == STYLE_PLATINUM && ubVolumeIndex >= 2) if(ubVolumeIndex >= 2) { // INT8 bSlot; //bSlot = FindObj( pSoldier, EXTENDEDEAR ); //if ( bSlot == HEAD1POS || bSlot == HEAD2POS) if ( FindHearingAid(pSoldier) ) BeginMultiPurposeLocator(sGridNo, bLevel, (INT8)((gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ))); } // flag soldier as having reported noise in a particular direction } void VerifyAndDecayOpplist(SOLDIERTYPE *pSoldier) { UINT32 uiLoop; INT8 *pPersOL; // pointer into soldier's opponent list SOLDIERTYPE *pOpponent; // reduce all seen/known opponent's turn counters by 1 (towards 0) // 1) verify accuracy of the opplist by testing sight vs known opponents // 2) increment opplist value if opponent is known but not currenly seen // 3) forget about known opponents who haven't been noticed in some time // if soldier is unconscious, make sure his opplist is wiped out & bail out if (pSoldier->stats.bLife < OKLIFE) { memset(pSoldier->aiData.bOppList,NOT_HEARD_OR_SEEN,sizeof(pSoldier->aiData.bOppList)); pSoldier->aiData.bOppCnt = 0; return; } // if any new opponents were seen earlier and not yet radioed if (pSoldier->bNewOppCnt) { #ifdef BETAVERSION tempstr = String("VerifyAndDecayOpplist: WARNING - %d(%s) still has %d NEW OPPONENTS - lastCaller %s/%s", pSoldier->guynum,ExtMen[pSoldier->guynum].name,pSoldier->newOppCnt, LastCallerText[ExtMen[pSoldier->guynum].lastCaller], LastCaller2Text[ExtMen[pSoldier->guynum].lastCaller2]); #ifdef TESTVERSION // make this ERROR/BETA again when it's fixed! PopMessage(tempstr); #endif #ifdef RECORDNET fprintf(NetDebugFile,"\n\t%s\n\n",tempstr); #endif #endif if (pSoldier->flags.uiStatusFlags & SOLDIER_PC) { RadioSightings(pSoldier,EVERYBODY,pSoldier->bTeam); } pSoldier->bNewOppCnt = 0; } // man looks for each of his opponents WHO ARE ALREADY KNOWN TO HIM for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++) { pOpponent = MercSlots[ uiLoop ]; // if this merc is active, here, and alive if (pOpponent != NULL && pOpponent->stats.bLife) { // if this merc is on the same team, he's no opponent, so skip him if (pSoldier->bTeam == pOpponent->bTeam) { continue; } pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID; // if this opponent is "known" in any way (seen or heard recently) if (*pPersOL != NOT_HEARD_OR_SEEN) { // use both sides actual x,y co-ordinates (neither side's moving) ManLooksForMan(pSoldier,pOpponent,VERIFYANDDECAYOPPLIST); // decay opplist value if necessary DECAY_OPPLIST_VALUE( *pPersOL ); /* // if opponent was SEEN recently but is NOT visible right now if (*pPersOL >= SEEN_THIS_TURN) { (*pPersOL)++; // increment #turns it's been since last seen // if it's now been longer than the maximum we care to remember if (*pPersOL > SEEN_2_TURNS_AGO) *pPersOL = 0; // forget that we knew this guy } else { // if opponent was merely HEARD recently, not actually seen if (*pPersOL <= HEARD_THIS_TURN) { (*pPersOL)--; // increment #turns it's been since last heard // if it's now been longer than the maximum we care to remember if (*pPersOL < HEARD_2_TURNS_AGO) *pPersOL = 0; // forget that we knew this guy } } */ } } } // if any new opponents were seen if (pSoldier->bNewOppCnt) { // turns out this is NOT an error! If this guy was gassed last time he // looked, his sight limit was 2 tiles, and now he may no longer be gassed // and thus he sees opponents much further away for the first time! // - Always happens if you STUNGRENADE an opponent by surprise... #ifdef RECORDNET fprintf(NetDebugFile,"\tVerifyAndDecayOpplist: d(%s) saw %d new opponents\n", pSoldier->guynum,ExtMen[pSoldier->guynum].name,pSoldier->newOppCnt); #endif if (pSoldier->flags.uiStatusFlags & SOLDIER_PC) RadioSightings(pSoldier,EVERYBODY,pSoldier->bTeam); pSoldier->bNewOppCnt = 0; } } void DecayIndividualOpplist(SOLDIERTYPE *pSoldier) { UINT32 uiLoop; INT8 *pPersOL; // pointer into soldier's opponent list SOLDIERTYPE *pOpponent; // reduce all currently seen opponent's turn counters by 1 (towards 0) // if soldier is unconscious, make sure his opplist is wiped out & bail out if (pSoldier->stats.bLife < OKLIFE) { // must make sure that public opplist is kept to match... for ( uiLoop = 0; uiLoop < TOTAL_SOLDIERS; ++uiLoop ) { if ( pSoldier->aiData.bOppList[ uiLoop ] == SEEN_CURRENTLY ) { HandleManNoLongerSeen( pSoldier, MercPtrs[ uiLoop ], &(pSoldier->aiData.bOppList[ uiLoop ]), &(gbPublicOpplist[ pSoldier->bTeam ][ uiLoop ]) ); } } //void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT8 * pPersOL, INT8 * pbPublOL ) memset(pSoldier->aiData.bOppList,NOT_HEARD_OR_SEEN,sizeof(pSoldier->aiData.bOppList)); pSoldier->aiData.bOppCnt = 0; return; } // man looks for each of his opponents WHO IS CURRENTLY SEEN for (uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop) { pOpponent = MercSlots[ uiLoop ]; // if this merc is active, here, and alive if (pOpponent != NULL && pOpponent->stats.bLife) { // if this merc is on the same team, he's no opponent, so skip him if (pSoldier->bTeam == pOpponent->bTeam) { continue; } pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID; // if this opponent is seen currently if (*pPersOL == SEEN_CURRENTLY) { // they are NOT visible now! (*pPersOL)++; if (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) ) { RemoveOneOpponent(pSoldier); } } } } } void VerifyPublicOpplistDueToDeath(SOLDIERTYPE *pSoldier) { UINT32 uiLoop,uiTeamMateLoop; INT8 *pPersOL,*pMatePersOL; // pointers into soldier's opponent list SOLDIERTYPE *pOpponent,*pTeamMate; BOOLEAN bOpponentStillSeen; // OK, someone died. Anyone that the deceased ALONE saw has to decay // immediately in the Public Opplist. // If deceased didn't see ANYONE, don't bother if (pSoldier->aiData.bOppCnt == 0) { return; } // Deceased looks for each of his opponents who is "seen currently" for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++) { // first, initialize flag since this will be a "new" opponent bOpponentStillSeen = FALSE; // grab a pointer to the "opponent" pOpponent = MercSlots[ uiLoop ]; // if this opponent is active, here, and alive if (pOpponent != NULL && pOpponent->stats.bLife) { // if this opponent is on the same team, he's no opponent, so skip him if (pSoldier->bTeam == pOpponent->bTeam) { continue; } // point to what the deceased's personal opplist value is pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID; // if this opponent was CURRENTLY SEEN by the deceased (before his // untimely demise) if (*pPersOL == SEEN_CURRENTLY) { // then we need to know if any teammates ALSO see this opponent, so loop through // trying to find ONE witness to the death... for (uiTeamMateLoop = 0; uiTeamMateLoop < guiNumMercSlots; uiTeamMateLoop++) { // grab a pointer to the potential teammate pTeamMate = MercSlots[ uiTeamMateLoop ]; // if this teammate is active, here, and alive if (pTeamMate != NULL && pTeamMate->stats.bLife) { // if this opponent is NOT on the same team, then skip him if (pTeamMate->bTeam != pSoldier->bTeam) { continue; } // point to what the teammate's personal opplist value is pMatePersOL = pTeamMate->aiData.bOppList + pOpponent->ubID; // test to see if this value is "seen currently" if (*pMatePersOL == SEEN_CURRENTLY) { // this opponent HAS been verified! bOpponentStillSeen = TRUE; // we can stop looking for other witnesses now break; } } } } // if no witnesses for this opponent, then decay the Public Opplist if ( !bOpponentStillSeen ) { DECAY_OPPLIST_VALUE( gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] ); } } } } void DecayPublicOpplist(INT8 bTeam) { UINT32 uiLoop; INT8 bNoPubliclyKnownOpponents = TRUE; SOLDIERTYPE *pSoldier; INT8 *pbPublOL; //NumMessage("Decay for team #",team); // decay the team's public noise volume, forget public noise gridno if <= 0 // used to be -1 per turn but that's not fast enough! if (gubPublicNoiseVolume[bTeam] > 0) { if ( gTacticalStatus.uiFlags & INCOMBAT ) { gubPublicNoiseVolume[bTeam] = (UINT8) ( (UINT32) (gubPublicNoiseVolume[bTeam] * 7) / 10 ); } else { gubPublicNoiseVolume[bTeam] = gubPublicNoiseVolume[bTeam] / 2; } if (gubPublicNoiseVolume[bTeam] <= 0) { gsPublicNoiseGridNo[bTeam] = NOWHERE; } } // decay the team's Public Opplist for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++) { pSoldier = MercSlots[uiLoop]; // for every active, living soldier on ANOTHER team if (pSoldier && pSoldier->stats.bLife && (pSoldier->bTeam != bTeam)) { // hang a pointer to the byte holding team's public opplist for this merc pbPublOL = &gbPublicOpplist[bTeam][pSoldier->ubID]; if (*pbPublOL == NOT_HEARD_OR_SEEN) { continue; } // well, that make this a "publicly known opponent", so nuke that flag bNoPubliclyKnownOpponents = FALSE; // if this person has been SEEN recently, but is not currently visible if (*pbPublOL >= SEEN_THIS_TURN) { (*pbPublOL)++; // increment how long it's been } else { // if this person has been only HEARD recently if (*pbPublOL <= HEARD_THIS_TURN) { (*pbPublOL)--; // increment how long it's been } } // if it's been longer than the maximum we care to remember if ((*pbPublOL > OLDEST_SEEN_VALUE) || (*pbPublOL < OLDEST_HEARD_VALUE)) { #ifdef RECORDOPPLIST fprintf(OpplistFile,"UpdatePublic (DecayPublicOpplist) for team %d about %d\n",team,pSoldier->guynum); #endif // forget about him, // and also forget where he was last seen (it's been too long) // this is mainly so POINT_PATROL guys don't SEEK_OPPONENTs forever UpdatePublic(bTeam,pSoldier->ubID,NOT_HEARD_OR_SEEN,NOWHERE,0); } } } // if all opponents are publicly unknown (NOT_HEARD_OR_SEEN) if (bNoPubliclyKnownOpponents) { // forget about the last radio alert (ie. throw away who made the call) // this is mainly so POINT_PATROL guys don't SEEK_FRIEND forever after gTacticalStatus.Team[bTeam].ubLastMercToRadio = NOBODY; } // decay watched locs as well DecayWatchedLocs( bTeam ); } // bit of a misnomer; this is now decay all opplists void NonCombatDecayPublicOpplist( UINT32 uiTime ) { UINT32 cnt; if ( uiTime - gTacticalStatus.uiTimeSinceLastOpplistDecay >= TIME_BETWEEN_RT_OPPLIST_DECAYS) { // decay! for ( cnt = 0; cnt < guiNumMercSlots; cnt++ ) { if ( MercSlots[ cnt ] ) { VerifyAndDecayOpplist( MercSlots[ cnt ] ); } } for( cnt = 0; cnt < MAXTEAMS; cnt++ ) { if ( gTacticalStatus.Team[ cnt ].bMenInSector > 0 ) { // decay team's public opplist DecayPublicOpplist( (INT8)cnt ); } } // update time gTacticalStatus.uiTimeSinceLastOpplistDecay = uiTime; } } void RecalculateOppCntsDueToNoLongerNeutral( SOLDIERTYPE * pSoldier ) { UINT32 uiLoop; SOLDIERTYPE * pOpponent; pSoldier->aiData.bOppCnt = 0; if (!pSoldier->aiData.bNeutral) { for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++) { pOpponent = MercSlots[uiLoop]; // for every active, living soldier on ANOTHER team if (pOpponent && pOpponent->stats.bLife && !pOpponent->aiData.bNeutral && (pOpponent->bTeam != pSoldier->bTeam) && (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide)) ) { if ( pSoldier->aiData.bOppList[pOpponent->ubID] == SEEN_CURRENTLY ) { AddOneOpponent( pSoldier ); } if ( pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY ) { // WANNE: Chris, I reverted BUGZILLA #338 fix, because this leads to big problems on opponent count with enemies! // have to add to opponent's oppcount as well since we just became non-neutral //CHRISL: If we do this, Bloodcats get counted at opponents multiple times and never get removed from the OppCnt variable. AddOneOpponent( pOpponent ); } } } } } void RecalculateOppCntsDueToBecomingNeutral( SOLDIERTYPE * pSoldier ) { UINT32 uiLoop; SOLDIERTYPE * pOpponent; if (pSoldier->aiData.bNeutral) { pSoldier->aiData.bOppCnt = 0; for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++) { pOpponent = MercSlots[uiLoop]; // for every active, living soldier on ANOTHER team if (pOpponent && pOpponent->stats.bLife && !pOpponent->aiData.bNeutral && (pOpponent->bTeam != pSoldier->bTeam) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) ) { if ( pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY ) { // have to rem from opponent's oppcount as well since we just became neutral RemoveOneOpponent( pOpponent ); } } } } } void NoticeUnseenAttacker( SOLDIERTYPE * pAttacker, SOLDIERTYPE * pDefender, INT8 bReason ) { INT8 bOldOppList; BOOLEAN fSeesAttacker = FALSE; INT8 bDirection; BOOLEAN fMuzzleFlash = FALSE; if ( !(gTacticalStatus.uiFlags & INCOMBAT) ) { return; } if ( pAttacker->usAttackingWeapon == DART_GUN ) { // rarely noticed if ( SkillCheck( pDefender, NOTICE_DART_CHECK, 0 ) < 0) { return; } } // do we need to do checks for life/breath here? if ( pDefender->ubBodyType == LARVAE_MONSTER || (pDefender->flags.uiStatusFlags & SOLDIER_VEHICLE && pDefender->bTeam == OUR_TEAM) ) { return; } bOldOppList = pDefender->aiData.bOppList[ pAttacker->ubID ]; // check LOS, considering we are now aware of the attacker // ignore muzzle flashes when must turning head if ( pAttacker->flags.fMuzzleFlash ) { bDirection = atan8( pDefender->sX,pDefender->sY, pAttacker->sX, pAttacker->sY ); if ( pDefender->ubDirection != bDirection && pDefender->ubDirection != gOneCDirection[ bDirection ] && pDefender->ubDirection != gOneCCDirection[ bDirection ] ) { // temporarily turn off muzzle flash so DistanceVisible can be calculated without it pAttacker->flags.fMuzzleFlash = FALSE; fMuzzleFlash = TRUE; } } if (SoldierToSoldierLineOfSightTest( pDefender, pAttacker, TRUE, CALC_FROM_WANTED_DIR ) != 0) { fSeesAttacker = TRUE; } if ( fMuzzleFlash ) { pAttacker->flags.fMuzzleFlash = TRUE; } if (fSeesAttacker) { ManSeesMan( pDefender, pAttacker, pAttacker->sGridNo, pAttacker->pathing.bLevel, NOTICEUNSEENATTACKER, CALLER_UNKNOWN ); // newOppCnt not needed here (no radioing), must get reset right away // CJC: Huh? well, leave it in for now pDefender->bNewOppCnt = 0; if (pDefender->bTeam == gbPlayerNum) { // EXPERIENCE GAIN (5): Victim notices/sees a previously UNSEEN attacker StatChange( pDefender, EXPERAMT, 5, FALSE ); // mark attacker as being SEEN right now RadioSightings( pDefender, pAttacker->ubID, pDefender->bTeam ); } // NOTE: ENEMIES DON'T REPORT A SIGHTING PUBLICLY UNTIL THEY RADIO IT IN! else { // go to threatening stance ReevaluateEnemyStance( pDefender, pDefender->usAnimState ); } } else // victim NOTICED the attack, but CAN'T SEE the actual attacker { SetNewSituation( pDefender ); // re-evaluate situation // if victim's alert status is only GREEN or YELLOW if (pDefender->aiData.bAlertStatus < STATUS_RED) { // then this soldier goes to status RED, has proof of enemy presence pDefender->aiData.bAlertStatus = STATUS_RED; CheckForChangingOrders( pDefender ); } UpdatePersonal( pDefender, pAttacker->ubID, HEARD_THIS_TURN, pAttacker->sGridNo, pAttacker->pathing.bLevel ); // if the victim is a human-controlled soldier, instantly report publicly if (pDefender->flags.uiStatusFlags & SOLDIER_PC) { // mark attacker as having been PUBLICLY heard THIS TURN & remember where UpdatePublic( pDefender->bTeam, pAttacker->ubID, HEARD_THIS_TURN, pAttacker->sGridNo, pAttacker->pathing.bLevel ); } } if ( !gGameOptions.fImprovedInterruptSystem || (gGameOptions.fImprovedInterruptSystem && gGameExternalOptions.fAllowInstantInterruptsOnSight) ) { if ( StandardInterruptConditionsMet( pDefender, pAttacker->ubID, bOldOppList ) ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, standard conditions are met; defender %d, attacker %d", pDefender->ubID, pAttacker->ubID ) ); // calculate the interrupt duel points DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for defender in NUA" ); pDefender->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pDefender, pAttacker->ubID, FALSE); } else { pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT; } // say quote if (pDefender->aiData.bInterruptDuelPts != NO_INTERRUPT) { // check for possible interrupt and handle control change if it happens // this code is basically ResolveInterruptsVs for 1 man only... // calculate active soldier's dueling pts for the upcoming interrupt duel DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for attacker in NUA" ); pAttacker->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pAttacker, pDefender->ubID, FALSE ); if ( InterruptDuel( pDefender, pAttacker ) ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, defender pts %d, attacker pts %d, defender gets interrupt", pDefender->aiData.bInterruptDuelPts, pAttacker->aiData.bInterruptDuelPts ) ); AddToIntList( pAttacker->ubID, FALSE, TRUE); AddToIntList( pDefender->ubID, TRUE, TRUE); DoneAddingToIntList( pDefender, TRUE, SIGHTINTERRUPT ); } // either way, clear out both sides' duelPts fields to prepare next duel pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT; #ifdef DEBUG_INTERRUPTS DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pDefender->ubID ) ); #endif pAttacker->aiData.bInterruptDuelPts = NO_INTERRUPT; #ifdef DEBUG_INTERRUPTS DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pAttacker->ubID ) ); #endif } } } void CheckForAlertWhenEnemyDies( SOLDIERTYPE * pDyingSoldier ) { UINT8 ubID; SOLDIERTYPE * pSoldier; INT8 bDir; INT16 sDistAway, sDistVisible; for ( ubID = gTacticalStatus.Team[ pDyingSoldier->bTeam ].bFirstID; ubID <= gTacticalStatus.Team[ pDyingSoldier->bTeam ].bLastID; ubID++ ) { pSoldier = MercPtrs[ ubID ]; if ( pSoldier->bActive && pSoldier->bInSector && (pSoldier != pDyingSoldier) && (pSoldier->stats.bLife >= OKLIFE) && (pSoldier->aiData.bAlertStatus < STATUS_RED ) ) { // this guy might have seen the man die // distance we "see" then depends on the direction he is located from us bDir = atan8(pSoldier->sX,pSoldier->sY,pDyingSoldier->sX,pDyingSoldier->sY); sDistVisible = DistanceVisible( pSoldier, pSoldier->pathing.bDesiredDirection, bDir, pDyingSoldier->sGridNo, pDyingSoldier->pathing.bLevel ); sDistAway = PythSpacesAway( pSoldier->sGridNo, pDyingSoldier->sGridNo ); // if we see close enough to see the soldier if (sDistAway <= sDistVisible) { // and we can trace a line of sight to his x,y coordinates // assume enemies are always aware of their buddies... if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pDyingSoldier->sGridNo, pDyingSoldier->pathing.bLevel, 0, TRUE, sDistVisible ) ) { pSoldier->aiData.bAlertStatus = STATUS_RED; CheckForChangingOrders( pSoldier ); } } } } } BOOLEAN ArmyKnowsOfPlayersPresence( void ) { UINT8 ubID; SOLDIERTYPE * pSoldier; // if anyone is still left... if (gTacticalStatus.Team[ ENEMY_TEAM ].bTeamActive && gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector > 0 ) { for ( ubID = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; ubID <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; ubID++ ) { pSoldier = MercPtrs[ ubID ]; if ( pSoldier->bActive && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE) && (pSoldier->aiData.bAlertStatus >= STATUS_RED ) ) { return( TRUE ); } } } return( FALSE ); } BOOLEAN MercSeesCreature( SOLDIERTYPE * pSoldier ) { UINT8 ubID; if (pSoldier->aiData.bOppCnt > 0) { for ( ubID = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; ubID <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; ubID++ ) { if ( (pSoldier->aiData.bOppList[ ubID ] == SEEN_CURRENTLY) && (MercPtrs[ ubID ]->flags.uiStatusFlags & SOLDIER_MONSTER) ) { return( TRUE ); } } } return( FALSE ); } INT8 FindUnusedWatchedLoc( UINT8 ubID ) { INT8 bLoop; for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ ) { // WANNE: I think this was a bug, should be != NOWHERE! // 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