#include "items.h" #include "weapons.h" #include "Soldier Control.h" #include "overhead.h" #include "Handle UI.h" #include "Animation Control.h" #include "Isometric Utils.h" #include "Animation Data.h" #include "Random.h" #include "Campaign.h" #include "interface.h" #include "Keys.h" #include "soldier profile.h" #include "SkillCheck.h" #include "los.h" #include "message.h" #include "text.h" #include "MessageBoxScreen.h" #include "ShopKeeper Interface.h" #include "GameSettings.h" #include "Auto Resolve.h" #include "Interface Items.h" #include "Campaign Types.h" #include "strategicmap.h" #include "Inventory Choosing.h" #include "Soldier macros.h" #include "Smell.h" #include "lighting.h" #include "utilities.h" #include "english.h" #include "debug control.h" #ifdef JA2UB #include "worldman.h" #include "Game Clock.h" #include "Sound Control.h" #include "Ja25 Strategic Ai.h" #include "MapScreen Quotes.h" #include "Ja25_Tactical.h" #include "Dialogue Control.h" #include "interface Dialogue.h" #include "Quests.h" #include "SaveLoadMap.h" #include "renderworld.h" #include "qarray.h" #include "Soldier Init List.h" #include "Soldier Control.h" #include "End Game.h" #include "structure.h" #include "Explosion Control.h" #include "ub_config.h" #include "GameInitOptionsScreen.h" //******************************************************************* // // Local Defines // //******************************************************************* #define TCTL__DELAY_BETWEEN_ALARM_SOUNDS 4000 #define NUM_NEW_GUN_QUOTES 15 #define PGF__NUM_TURNS_TILL_START_FAN_BACK_UP_EASY 2 #define PGF__NUM_TURNS_TILL_START_FAN_BACK_UP_NORMAL 2 #define PGF__NUM_TURNS_TILL_START_FAN_BACK_UP_HARD 1 typedef struct { INT16 sItem; BOOLEAN fHasBeenSaid; } NEW_GUN_QUOTES_STRUCT; //Morris items //UINT32 MORRIS_INSTRUCTION_NOTE = 1362; UINT8 Get3RandomQualifiedMercs( SoldierID *pSoldierId1, SoldierID *pSoldierId2, SoldierID *pSoldierId3 ); //******************************************************************* // // Global Variables // //******************************************************************* NEW_GUN_QUOTES_STRUCT gNewGunQuotes[ NUM_NEW_GUN_QUOTES ]; //******************************************************************* // // Function Prototypes // //******************************************************************* void StopPowerGenFan(); void SetNewGunQuoteToBePlayedForThisGun( INT32 iItemIndex ); BOOLEAN HasNewGunQuoteBeenPlayedForThisGun( INT32 iItemIndex ); BOOLEAN IsThisGunANewJa25Gun( INT32 iItemIndex ); BOOLEAN SaveNewGunQuotesArrayToSaveGameFile( HWFILE hFile ); BOOLEAN LoadNewGunQuotesArrayToSaveGameFile( HWFILE hFile ); void HandlePickingUpMorrisInstructionNote( SOLDIERTYPE *pSoldier, INT32 iIndex ); BOOLEAN IsSoldierAliveWithInitListGridNo( INT16 sInitListID ); void Ja25ScaleAllEnemiesByValue( INT8 bExpScaleValue ); INT8 JA25SecondHighestExpLevelOnPlayersTeam( ); INT8 JA25HighestExpLevelOnTeam( INT8 bTeam ); INT8 JA25SecondHighestExpLevelOnEnemiesTeam( ); INT8 CountNumberOfMercsOnSameTeamOfSameExpLevel( INT8 bTeam, INT8 bExpLevel ); BOOLEAN IsSoldierQualifiedGunCommenterMerc( SOLDIERTYPE *pSoldier ); UINT32 GetNumberOfTurnsPowerGenFanWillBeStoppedFor(); void HandleInitialEventsInHeliCrash(); BOOLEAN gfFirstTimeInGameHeliCrash = FALSE; void HandleHowPlayerGotThroughFan(); //ppp //******************************************************************* // // Functions // //******************************************************************* BOOLEAN useOldJA2Inventory = TRUE; //inshy: chenge index of items to 1.13 version. Now we dont need Items.xml in UB-113 folder /* UINT32 BARRETT_UB = 335; UINT32 CALICO_960_UB = 69; UINT32 PSG1_UB =334; UINT32 L85_UB =331; UINT32 TAR21_UB =332; UINT32 VAL_SILENT_UB =333; UINT32 MICRO_UZI_UB = 330; UINT32 CALICO_950_UB = 67; UINT32 CALICO_900_UB = 68; UINT32 CLIP_CANNON_BALL = 1354; UINT32 MERC_UMBRELLA = 1361; UINT32 HAND_CANNON = 1352; UINT32 HARTFORD_6_SHOOTER = 66; UINT32 TEX_MOVIE_ATTACK_CLYDESDALES = 1356; UINT32 TEX_MOVIE_WILD_EAST = 1357; UINT32 TEX_MOVIE_HAVE_HONDA = 1358; UINT32 LAPTOP_TRANSMITTER = 1355; UINT32 CHE_GUEVARA_CANTEEN = 1359; UINT32 MERC_WRISTWATCH = 1360; UINT32 SAM_GARVER_COMBAT_KNIFE = 1353; UINT32 MERC_UMBRELLA_OLD = 1361; //not used??? UINT32 MORRIS_INSTRUCTION_NOTE = 1362; //inshy: chenge index of items to 1.13 version. Now we dont need Items.xml in UB-113 folder UINT32 BARRETT_UB = 43; UINT32 CALICO_960_UB = 44; UINT32 PSG1_UB =45; UINT32 L85_UB =46; UINT32 TAR21_UB =47; UINT32 VAL_SILENT_UB =48; UINT32 MICRO_UZI_UB = 57; UINT32 CALICO_950_UB = 66; UINT32 CALICO_900_UB = 67; UINT32 CLIP_CANNON_BALL = 115; UINT32 MERC_UMBRELLA = 70; UINT32 HAND_CANNON = 63; UINT32 HARTFORD_6_SHOOTER = 68; UINT32 TEX_MOVIE_ATTACK_CLYDESDALES = 328; UINT32 TEX_MOVIE_WILD_EAST = 329; UINT32 TEX_MOVIE_HAVE_HONDA = 330; UINT32 LAPTOP_TRANSMITTER = 331; UINT32 CHE_GUEVARA_CANTEEN = 332; UINT32 MERC_WRISTWATCH = 333; UINT32 SAM_GARVER_COMBAT_KNIFE = 69; UINT32 MERC_UMBRELLA_OLD = 335; UINT32 MORRIS_INSTRUCTION_NOTE = 336; */ UINT32 TEX_MOVIE_ATTACK_CLYDESDALES; UINT32 TEX_MOVIE_WILD_EAST; UINT32 TEX_MOVIE_HAVE_HONDA; UINT32 LAPTOP_TRANSMITTER; UINT32 CHE_GUEVARA_CANTEEN; UINT32 MERC_WRISTWATCH; UINT32 SAM_GARVER_COMBAT_KNIFE; UINT32 MERC_UMBRELLA_OLD; UINT32 MORRIS_INSTRUCTION_NOTE; UINT32 HAND_CANNON; UINT32 HARTFORD_6_SHOOTER; UINT32 MERC_UMBRELLA; UINT32 BARRETT_UB; UINT32 CALICO_960_UB; UINT32 PSG1_UB; UINT32 L85_UB; UINT32 TAR21_UB; UINT32 VAL_SILENT_UB; UINT32 MICRO_UZI_UB; UINT32 CALICO_950_UB; UINT32 CALICO_900_UB; UINT32 CLIP_CANNON_BALL; UINT8 MANUEL_UB; UINT8 BIGGENS_UB; UINT8 JOHN_K_UB; UINT8 TEX_UB; UINT8 GASTON_UB; UINT8 STOGIE_UB; UINT8 JERRY_MILO_UB; UINT8 PGMALE4_UB; UINT8 BETTY_UB; UINT8 RAUL_UB; UINT8 MORRIS_UB; UINT8 RUDY_UB; void Old_UB_Inventory (); void New_UB_Inventory (); void Old_UB_Inventory () { BARRETT_UB = 43; CALICO_960_UB = 44; PSG1_UB =45; L85_UB =46; TAR21_UB =47; VAL_SILENT_UB =48; MICRO_UZI_UB = 57; CALICO_950_UB = 66; CALICO_900_UB = 67; CLIP_CANNON_BALL = 115; MERC_UMBRELLA = 70; HAND_CANNON = 63; HARTFORD_6_SHOOTER = 68; TEX_MOVIE_ATTACK_CLYDESDALES = 328; TEX_MOVIE_WILD_EAST = 329; TEX_MOVIE_HAVE_HONDA = 330; LAPTOP_TRANSMITTER = 331; CHE_GUEVARA_CANTEEN = 332; MERC_WRISTWATCH = 333; SAM_GARVER_COMBAT_KNIFE = 69; MERC_UMBRELLA_OLD = 335; MORRIS_INSTRUCTION_NOTE = 336; } void New_UB_Inventory () { //inshy: chenge index of items to 1.13 version. Now we dont need Items.xml in UB-113 folder BARRETT_UB = 335; CALICO_960_UB = 69; PSG1_UB =334; L85_UB =331; TAR21_UB =332; VAL_SILENT_UB =333; MICRO_UZI_UB = 330; CALICO_950_UB = 67; CALICO_900_UB = 68; CLIP_CANNON_BALL = 1354; MERC_UMBRELLA = 1361; HAND_CANNON = 1352; HARTFORD_6_SHOOTER = 66; TEX_MOVIE_ATTACK_CLYDESDALES = 1356; TEX_MOVIE_WILD_EAST = 1357; TEX_MOVIE_HAVE_HONDA = 1358; LAPTOP_TRANSMITTER = 1355; CHE_GUEVARA_CANTEEN = 1359; MERC_WRISTWATCH = 1360; SAM_GARVER_COMBAT_KNIFE = 1353; MERC_UMBRELLA_OLD = 1361; //not used??? MORRIS_INSTRUCTION_NOTE = 1362; } //GridNo UINT32 SWITCHINMORRISAREA_GRIDNO = 15231; UINT32 SWITCHTOLAUNCHMISSLES_GRIDNO1 = 14268; UINT32 SWITCHTOLAUNCHMISSLES_GRIDNO2 = 15708; UINT32 RADIOLOCATORS_GRIDNO1 = 15070; UINT32 RADIOLOCATORS_GRIDNO2 = 14744; UINT32 POWERGENSECTOR_GRIDNO1 = 15100; UINT32 POWERGENSECTOR_GRIDNO2 = 12220; UINT32 POWERGENSECTOR_GRIDNO3 = 14155; UINT32 POWERGENSECTOR_GRIDNO4 = 13980; UINT32 POWERGENSECTOREXITGRID_GRIDNO1 = 19749; UINT32 POWERGENFANSOUND_GRIDNO1 = 10979; UINT32 POWERGENFANSOUND_GRIDNO2 = 19749; UINT32 STARTFANBACKUPAGAIN_GRIDNO = 10980; UINT32 STOPPOWERGENFAN_GRIDNO = 10980; //L15-3 UINT32 SECTOR_LAUNCH_MISSLES_X = 15; UINT32 SECTOR_LAUNCH_MISSLES_Y = 12; UINT32 SECTOR_LAUNCH_MISSLES_Z = 3; //J13-0 UINT32 SECTOR_FAN_X = 13; UINT32 SECTOR_FAN_Z = 10; UINT32 SECTOR_FAN_Y = 0; //K14-1 UINT32 SECTOR_OPEN_GATE_IN_TUNNEL_X = 14; UINT32 SECTOR_OPEN_GATE_IN_TUNNEL_Y = 11; UINT32 SECTOR_OPEN_GATE_IN_TUNNEL_Z = 1; //J14-1 UINT32 EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_X = 14; UINT32 EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_Y = 10; UINT32 EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_Z = 1; void InitGridNoUB() { SWITCHINMORRISAREA_GRIDNO = gGameUBOptions.SwitchInMorrisAreaGridNo; //= 15231; SWITCHTOLAUNCHMISSLES_GRIDNO1 = gGameUBOptions.SwitchToLaunchMisslesGridNo1; //= 14268; SWITCHTOLAUNCHMISSLES_GRIDNO2 = gGameUBOptions.SwitchToLaunchMisslesGridNo2; //= 15708; RADIOLOCATORS_GRIDNO1 = gGameUBOptions.RadioLocatorsGridNo1; //= 15070; RADIOLOCATORS_GRIDNO2 = gGameUBOptions.RadioLocatorsGridNo2; //= 14744; POWERGENSECTOR_GRIDNO1 = gGameUBOptions.PowergenSectorGridNo1; //= 15100; POWERGENSECTOR_GRIDNO2 = gGameUBOptions.PowergenSectorGridNo2; //= 12220; POWERGENSECTOR_GRIDNO3 = gGameUBOptions.PowergenSectorGridNo3; //= 14155; POWERGENSECTOR_GRIDNO4 = gGameUBOptions.PowergenSectorGridNo4; //= 13980; POWERGENSECTOREXITGRID_GRIDNO1 = gGameUBOptions.PowergenSectorExitgridGridNo; // = 19749; POWERGENFANSOUND_GRIDNO1 = gGameUBOptions.PowergenFanSoundGridNo1; //= 10979; POWERGENFANSOUND_GRIDNO2 = gGameUBOptions.PowergenFanSoundGridNo2; //= 19749; STARTFANBACKUPAGAIN_GRIDNO = gGameUBOptions.StartFanbackupAgainGridNo; //= 10980; STOPPOWERGENFAN_GRIDNO = gGameUBOptions.StopPowergenFanGridNo; //= 10980; //L15-3 SECTOR_LAUNCH_MISSLES_X = gGameUBOptions.SectorLaunchMisslesX; // 15; SECTOR_LAUNCH_MISSLES_Y = gGameUBOptions.SectorLaunchMisslesY; // 12; SECTOR_LAUNCH_MISSLES_Z = gGameUBOptions.SectorLaunchMisslesZ; //3; //J13-0 SECTOR_FAN_X = gGameUBOptions.SectorFanX; //13; SECTOR_FAN_Z = gGameUBOptions.SectorFanY; //10; SECTOR_FAN_Y = gGameUBOptions.SectorFanZ; //0; //K14-1 SECTOR_OPEN_GATE_IN_TUNNEL_X = gGameUBOptions.SectorOpenGateInTunnelX; //14; SECTOR_OPEN_GATE_IN_TUNNEL_Y = gGameUBOptions.SectorOpenGateInTunnelY; //11; SECTOR_OPEN_GATE_IN_TUNNEL_Z = gGameUBOptions.SectorOpenGateInTunnelZ; //1; //J14-1 EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_X = gGameUBOptions.ExitForFanToPowerGenSectorX; //14; EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_Y = gGameUBOptions.ExitForFanToPowerGenSectorY; //10; EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_Z = gGameUBOptions.ExitForFanToPowerGenSectorZ; //1; MANUEL_UB = gGameUBOptions.ubMANUEL_UB; BIGGENS_UB = gGameUBOptions.ubBIGGENS_UB; JOHN_K_UB = gGameUBOptions.ubJOHN_K_UB; TEX_UB = gGameUBOptions.ubTEX_UB; GASTON_UB = gGameUBOptions.ubGASTON_UB; STOGIE_UB = gGameUBOptions.ubSTOGIE_UB; JERRY_MILO_UB = gGameUBOptions.ubJERRY_MILO_UB; PGMALE4_UB = gGameUBOptions.ubPGMALE4_UB; BETTY_UB = gGameUBOptions.ubBETTY_UB; RAUL_UB = gGameUBOptions.ubRAUL_UB; MORRIS_UB = gGameUBOptions.ubMORRIS_UB; RUDY_UB = gGameUBOptions.ubRUDY_UB; TEX_MOVIE_ATTACK_CLYDESDALES = gGameUBOptions.ubTEX_MOVIE_ATTACK_CLYDESDALES; TEX_MOVIE_WILD_EAST = gGameUBOptions.ubTEX_MOVIE_WILD_EAST; TEX_MOVIE_HAVE_HONDA = gGameUBOptions.ubTEX_MOVIE_HAVE_HONDA; LAPTOP_TRANSMITTER = gGameUBOptions.ubLAPTOP_TRANSMITTER; CHE_GUEVARA_CANTEEN = gGameUBOptions.ubCHE_GUEVARA_CANTEEN; MERC_WRISTWATCH = gGameUBOptions.ubMERC_WRISTWATCH; SAM_GARVER_COMBAT_KNIFE = gGameUBOptions.ubSAM_GARVER_COMBAT_KNIFE; MERC_UMBRELLA_OLD = gGameUBOptions.ubMERC_UMBRELLA_OLD; MORRIS_INSTRUCTION_NOTE = gGameUBOptions.ubMORRIS_INSTRUCTION_NOTE; HAND_CANNON = gGameUBOptions.ubHAND_CANNON; HARTFORD_6_SHOOTER = gGameUBOptions.ubHARTFORD_6_SHOOTER; MERC_UMBRELLA = gGameUBOptions.ubMERC_UMBRELLA; CLIP_CANNON_BALL = gGameUBOptions.ubCLIP_CANNON_BALL; BARRETT_UB = gGameUBOptions.ubBARRETT_UB; CALICO_960_UB = gGameUBOptions.ubCALICO_960_UB; PSG1_UB = gGameUBOptions.ubPSG1_UB; L85_UB = gGameUBOptions.ubL85_UB; TAR21_UB = gGameUBOptions.ubTAR21_UB; VAL_SILENT_UB = gGameUBOptions.ubVAL_SILENT_UB; MICRO_UZI_UB = gGameUBOptions.ubMICRO_UZI_UB; CALICO_950_UB = gGameUBOptions.ubCALICO_950_UB; CALICO_900_UB = gGameUBOptions.ubCALICO_900_UB; } BOOLEAN IsSoldierQualifiedMerc( SOLDIERTYPE *pSoldier ) { if( pSoldier->ubProfile == GASTON_UB || /// GASTON pSoldier->ubProfile == STOGIE_UB || // STOGIE pSoldier->ubProfile == TEX_UB ||// TEX || pSoldier->ubProfile == JOHN_K_UB || //JOHN_K || pSoldier->ubProfile == BIGGENS_UB || //BIGGENS || pSoldier->ubProfile == MANUEL_UB || //MANUEL || pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER ) { return( TRUE ); } else { return( FALSE ); } } BOOLEAN IsSoldierQualifiedMercForSeeingPowerGenFan( SOLDIERTYPE *pSoldier ) { if( pSoldier->ubProfile == MANUEL_UB ||//MANUEL || pSoldier->ubProfile == 53 || //PGCMale3 pSoldier->ubProfile == 55 || //PGCFem2 pSoldier->ubProfile == PGMALE4_UB //PGCMale4 ) { return( TRUE ); } else { return( FALSE ); } } BOOLEAN IsSoldierQualifiedGunCommenterMerc( SOLDIERTYPE *pSoldier ) { if( pSoldier->ubProfile == GASTON_UB || // GASTON pSoldier->ubProfile == STOGIE_UB || // STOGIE pSoldier->ubProfile == TEX_UB || // TEX pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER ) { return( TRUE ); } else { return( FALSE ); } } BOOLEAN IsSoldierQualifiedInitialHireMerc( SOLDIERTYPE *pSoldier ) { if( pSoldier->ubProfile == GASTON_UB || // GASTON pSoldier->ubProfile == STOGIE_UB || // STOGIE pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER ) { return( TRUE ); } else { return( FALSE ); } } UINT8 GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( SoldierID *pSoldierIdArray, UINT8 *pProfileIdArray ) { SOLDIERTYPE *pSoldier=NULL; UINT8 usNumMercsPresent=0; if( pSoldierIdArray ) memset( pSoldierIdArray, NOBODY, NUM_MERCS_WITH_NEW_QUOTES ); if( pProfileIdArray ) memset( pProfileIdArray, NO_PROFILE, NUM_MERCS_WITH_NEW_QUOTES ); INT32 cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; //Check to see if Gaston, Stogie or the PGC is on the team for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; ++cnt, ++pSoldier ) { //if the merc is alive, in sector, etc... //Note: cant do the OK_CONTROLLABLE_MERC() cause it does bInSector which is not set when EnterSector is finshed ( we need it then ) if( pSoldier->bActive && pSoldier->sSectorX == gWorldSectorX && pSoldier->sSectorY == gWorldSectorY && pSoldier->bSectorZ == gbWorldSectorZ && pSoldier->stats.bLife >= OKLIFE && !pSoldier->flags.fBetweenSectors ) { //if the merc is one of the mercs we are looking for if( IsSoldierQualifiedMerc( pSoldier ) ) { //if we are to return an array of the mercs if( pProfileIdArray != NULL ) { //record the profile num of the merc pProfileIdArray[ usNumMercsPresent ] = pSoldier->ubProfile; } //if we are to return an array of the mercs if( pSoldierIdArray != NULL ) { //record the soldier num of the merc pSoldierIdArray[ usNumMercsPresent ] = pSoldier->ubID; } ++usNumMercsPresent; } } } return usNumMercsPresent; } INT16 RandomProfileIdFromNewMercsOnPlayerTeam() { UINT8 usNumMercsPresent; UINT8 ProfileIdArray[NUM_MERCS_WITH_NEW_QUOTES]; //Get the number and array of the new soldiers usNumMercsPresent = GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( NULL, ProfileIdArray ); Assert( usNumMercsPresent < NUM_MERCS_WITH_NEW_QUOTES ); if( usNumMercsPresent > 0 ) { //return a random merc from the array return( (INT16)(ProfileIdArray[ Random( usNumMercsPresent ) ]) ); } else { return( -1 ); } } SoldierID RandomSoldierIdFromNewMercsOnPlayerTeam() { UINT8 usNumMercsPresent; SoldierID SoldierIdArray[NUM_MERCS_WITH_NEW_QUOTES]; //Get the number and array of the new soldiers usNumMercsPresent = GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( SoldierIdArray, NULL ); Assert( usNumMercsPresent < NUM_MERCS_WITH_NEW_QUOTES ); if( usNumMercsPresent > 0 ) { //return a random merc from the array return( ( SoldierIdArray[ Random( usNumMercsPresent ) ] )); } else { return( NOBODY ); } } UINT8 RandomArrayOfQualifiedMercs( UINT8 *pRandomSoldierIdArray ) { UINT8 usNumMercsPresent; SoldierID SoldierIdArray[NUM_MERCS_WITH_NEW_QUOTES]; BOOLEAN UsedArray[NUM_MERCS_WITH_NEW_QUOTES]; BOOLEAN fFound=FALSE; UINT8 ubRand; memset( UsedArray, 0, NUM_MERCS_WITH_NEW_QUOTES ); memset( pRandomSoldierIdArray, NOBODY, NUM_MERCS_WITH_NEW_QUOTES ); //Get the number and array of the new soldiers usNumMercsPresent = GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( SoldierIdArray, NULL ); Assert( usNumMercsPresent < NUM_MERCS_WITH_NEW_QUOTES ); if( usNumMercsPresent > 0 ) { //loop through all the available mercs for( UINT8 ubCnt=0; ubCnt= 1 && pSoldierId1 != NULL ) { *pSoldierId1 = RandomSoldierIdArray[ 0 ]; ubNumberDifMercsAssigned++; } if( usNumMercs >= 2 && pSoldierId2 != NULL ) { *pSoldierId2 = RandomSoldierIdArray[ 1 ]; ubNumberDifMercsAssigned++; } else { *pSoldierId2 = RandomSoldierIdArray[ 0 ]; } if( pSoldierId3 != NULL ) { if( usNumMercs >= 3 ) { *pSoldierId3 = RandomSoldierIdArray[ 2 ]; ubNumberDifMercsAssigned++; } else if( usNumMercs >= 2 ) { if( Chance( 50 ) ) *pSoldierId3 = RandomSoldierIdArray[ 1 ]; else *pSoldierId3 = RandomSoldierIdArray[ 0 ]; } } return( ubNumberDifMercsAssigned ); } void HandleWhenCertainPercentageOfEnemiesDie() { UINT32 uiPercentEnemiesKilled; UINT8 ubSectorID; //if there isnt enemies in the sector if( ( gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector + gTacticalStatus.ubArmyGuysKilled ) == 0 ) { //get out return; } uiPercentEnemiesKilled = (UINT32)( 100 * (UINT32)(gTacticalStatus.ubArmyGuysKilled + 1) / (UINT32)( gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector + gTacticalStatus.ubArmyGuysKilled ) ); ubSectorID = SECTOR( gWorldSectorX, gWorldSectorY ); switch( gbWorldSectorZ ) { case 0: switch( ubSectorID ) { case SEC_K15: //all enemies are dead and if the quote hasnt been said yet if( uiPercentEnemiesKilled >= 100 && !( gJa25SaveStruct.uiJa25GeneralFlags & JA_GF__ALL_DEAD_TOP_LEVEL_OF_COMPLEX ) ) { INT16 bProfile = RandomProfileIdFromNewMercsOnPlayerTeam(); if( bProfile != -1 ) DelayedMercQuote( (UINT16)bProfile, QUOTE_WONT_RENEW_CONTRACT_LAME_REFUSAL, GetWorldTotalSeconds() + 5 ); gJa25SaveStruct.uiJa25GeneralFlags |= JA_GF__ALL_DEAD_TOP_LEVEL_OF_COMPLEX; } break; } } } void StopPowerGenFan() { UINT16 usTileIndex; SOLDIERTYPE *pSoldier=NULL; // ATE: If destroyed, don't go into here if( gJa25SaveStruct.ubStateOfFanInPowerGenSector == PGF__BLOWN_UP ) { return; } //If the fan is already stopped, or has been stopped in the past if( gJa25SaveStruct.ubStateOfFanInPowerGenSector == PGF__STOPPED || IsJa25GeneralFlagSet( JA_GF__POWER_GEN_FAN_HAS_BEEN_STOPPED ) ) { //leave return; } //if we are in turn based combat if( !((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT)) ) { return; } //Remeber how the player got through SetJa25GeneralFlag( JA_GF__POWER_GEN_FAN_HAS_BEEN_STOPPED ); gJa25SaveStruct.ubStateOfFanInPowerGenSector = PGF__STOPPED; //Set the fact that player stopped the fan SetFactTrue( FACT_FAN_STOPPPED ); //Is biggens on the team pSoldier = FindSoldierByProfileID( BIGGENS_UB, TRUE ); // BIGGENS if( pSoldier != NULL ) { SetFactTrue( FACT_BIGGENS_ON_TEAM_AND_FAN_STOPPED ); } //Turn off the power gen fan sound HandleRemovingPowerGenFanSound(); //remeber which turn the fan stopped on gJa25SaveStruct.uiTurnPowerGenFanWentDown = gJa25SaveStruct.uiTacticalTurnCounter; // // Replace the Fan graphic // // Turn on permenant changes.... ApplyMapChangesToMapTempFile( TRUE ); //Add the exit grid to the power gen fan AddExitGridForFanToPowerGenSector(); // Remove it! // Get index for it... GetTileIndexFromTypeSubIndex( FIFTHOSTRUCT, (INT8)( 1 ), &usTileIndex ); RemoveStruct( STOPPOWERGENFAN_GRIDNO, usTileIndex ); // Add the new one // Get index for it... GetTileIndexFromTypeSubIndex( FIFTHOSTRUCT, (INT8)( 7 ), &usTileIndex ); AddStructToHead( STOPPOWERGENFAN_GRIDNO, usTileIndex ); ApplyMapChangesToMapTempFile( FALSE ); //Recompile the movement costs since we have added a exit grid RecompileLocalMovementCosts( STOPPOWERGENFAN_GRIDNO ); gpWorldLevelData[ STOPPOWERGENFAN_GRIDNO ].uiFlags |= MAPELEMENT_REVEALED; // Re-render the world! gTacticalStatus.uiFlags |= NOHIDE_REDUNDENCY; // FOR THE NEXT RENDER LOOP, RE-EVALUATE REDUNDENT TILES SetRenderFlags(RENDER_FLAG_FULL); } void HandleStartingFanBackUp() { //if the fan has been stopped for the right amount of time if( gJa25SaveStruct.uiTacticalTurnCounter == ( gJa25SaveStruct.uiTurnPowerGenFanWentDown + GetNumberOfTurnsPowerGenFanWillBeStoppedFor() ) ) { //if it is stopped if( gJa25SaveStruct.ubStateOfFanInPowerGenSector == PGF__STOPPED ) { StartFanBackUpAgain(); } } } void StartFanBackUpAgain() { UINT16 usTileIndex; // ATE: If destroyed, don't go into here if( gJa25SaveStruct.ubStateOfFanInPowerGenSector == PGF__BLOWN_UP ) { return; } //Remeber how the player got through gJa25SaveStruct.ubStateOfFanInPowerGenSector = PGF__RUNNING_NORMALLY; //Start the fan sound HandleAddingPowerGenFanSound(); // // Replace the Fan graphic // // Turn on permenant changes.... ApplyMapChangesToMapTempFile( TRUE ); // Remove it! // Get index for it... GetTileIndexFromTypeSubIndex( FIFTHOSTRUCT, (INT8)( 7 ), &usTileIndex ); RemoveStruct( STARTFANBACKUPAGAIN_GRIDNO, usTileIndex ); // Add the new one // Get index for it... GetTileIndexFromTypeSubIndex( FIFTHOSTRUCT, (INT8)( 1 ), &usTileIndex ); AddStructToHead( STARTFANBACKUPAGAIN_GRIDNO, usTileIndex ); ApplyMapChangesToMapTempFile( FALSE ); //Recompile the movement costs since we have added a exit grid RecompileLocalMovementCosts( STARTFANBACKUPAGAIN_GRIDNO ); gpWorldLevelData[ STARTFANBACKUPAGAIN_GRIDNO ].uiFlags |= MAPELEMENT_REVEALED; // Re-render the world! gTacticalStatus.uiFlags |= NOHIDE_REDUNDENCY; //Remove the exit grid RemoveExitGridFromWorld( PGF__FAN_EXIT_GRID_GRIDNO ); // FOR THE NEXT RENDER LOOP, RE-EVALUATE REDUNDENT TILES SetRenderFlags(RENDER_FLAG_FULL); } void HandlePowerGenAlarm() { static UINT32 uiLastTime=0; static UINT32 uiAlarmCounter=0; UINT32 uiCurTime=0; //if its not the right sector J13-0 if( !( gWorldSectorX == SECTOR_FAN_X && gWorldSectorY == SECTOR_FAN_Y && gbWorldSectorZ == SECTOR_FAN_Z ) ) { //leave return; } //if the fan is not stopped if( gJa25SaveStruct.ubStateOfFanInPowerGenSector != PGF__STOPPED ) { uiAlarmCounter = 0; //leave return; } uiCurTime = GetJA2Clock(); if( ( uiCurTime - uiLastTime ) >= TCTL__DELAY_BETWEEN_ALARM_SOUNDS ) { uiAlarmCounter++; PlayJA2SampleFromFile( "SOUNDS\\AlarmFan.wav", RATE_11025, MIDVOLUME, 1, MIDDLE ); uiLastTime = uiCurTime; if( uiAlarmCounter == 2 && !IsJa25GeneralFlagSet( JA_GF__BIGGENS_SAID_QUOTE_117 ) ) { // // Have merc say the quote, if the conditions are right // if( gubFact[ FACT_PLAYER_KNOWS_ABOUT_FAN_STOPPING ] ) { INT16 bID = RandomSoldierIdFromNewMercsOnPlayerTeam(); if( bID != -1 ) { TacticalCharacterDialogue( &Menptr[ bID ], QUOTE_HATED_2_ON_TEAM_LONGTIMETOHATE ); } } else { SoldierID bSoldierId1, bSoldierId2, bSoldierId3; Get3RandomQualifiedMercs( &bSoldierId1, &bSoldierId2, &bSoldierId3 ); if( bSoldierId1 != NOBODY && bSoldierId1->ubProfile != BIGGENS_UB ) //BIGGENS { TacticalCharacterDialogue( bSoldierId1, QUOTE_HATED_1_ON_TEAM_LONGTIMETOHATE ); } else if( bSoldierId2 != NOBODY && bSoldierId2->ubProfile != BIGGENS_UB ) //BIGGENS { TacticalCharacterDialogue( bSoldierId2, QUOTE_HATED_1_ON_TEAM_LONGTIMETOHATE ); } else if( bSoldierId3 != NOBODY && bSoldierId3->ubProfile != BIGGENS_UB ) // BIGGENS { TacticalCharacterDialogue( bSoldierId3, QUOTE_HATED_1_ON_TEAM_LONGTIMETOHATE ); } } } } } void HandleAddingPowerGenFanSound() { UINT32 sGridNo; //if its not already playing if( gJa25SaveStruct.iPowerGenFanPositionSndID != -1 ) { return; } if( gbWorldSectorZ == 0 ) sGridNo = POWERGENFANSOUND_GRIDNO1; else sGridNo = POWERGENFANSOUND_GRIDNO2; //Create the new ambient fan sound //gJa25SaveStruct.iPowerGenFanPositionSndID = NewPositionSnd( sGridNo, POSITION_SOUND_STATIONATY_OBJECT, 0, POWER_GEN_FAN_SOUND ); SetPositionSndsInActive( ); SetPositionSndsActive( ); } void HandleRemovingPowerGenFanSound() { //if there is an ambience sound playing if( gJa25SaveStruct.iPowerGenFanPositionSndID != -1 ) { //delete it DeletePositionSnd( gJa25SaveStruct.iPowerGenFanPositionSndID ); gJa25SaveStruct.iPowerGenFanPositionSndID = -1; } } void AddExitGridForFanToPowerGenSector() { EXITGRID ExitGrid; memset( &ExitGrid, 0, sizeof( EXITGRID ) ); ExitGrid.ubGotoSectorX = EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_X; //14; ExitGrid.ubGotoSectorY = EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_Y; //MAP_ROW_J; ExitGrid.ubGotoSectorZ = EXIT_FOR_FAN_TO_POWER_GEN_SECTOR_Z; //1; ExitGrid.usGridNo = POWERGENSECTOREXITGRID_GRIDNO1; //Add the exit grid when the fan is either stopped or blown up AddExitGridToWorld( PGF__FAN_EXIT_GRID_GRIDNO, &ExitGrid ); } BOOLEAN HandlePlayerSayingQuoteWhenFailingToOpenGateInTunnel( SOLDIERTYPE *pSoldierAtDoor, BOOLEAN fSayQuoteOnlyOnce ) { INT8 bSlot; UINT32 cnt; SOLDIERTYPE *pSoldier; //is this the right sector K14-1 if( !( gWorldSectorX == SECTOR_OPEN_GATE_IN_TUNNEL_X && gWorldSectorY == SECTOR_OPEN_GATE_IN_TUNNEL_Y && gbWorldSectorZ == SECTOR_OPEN_GATE_IN_TUNNEL_Z ) ) { //wrong door return( FALSE ); } //if the player has already said the quote if( IsJa25GeneralFlagSet( JA_GF__PLAYER_SAID_GATE_LOCKED_QUOTE ) ) { return( FALSE ); } // // look to see if anyone on the team has wire cutters // // loop throught the team and see if anyone in this sector has the wire cutter cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pSoldier++) { //if the soldier is in the sector if( pSoldier->bActive && pSoldier->bInSector && ( pSoldier->stats.bLife >= CONSCIOUSNESS ) && !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !AM_A_ROBOT( pSoldier ) ) { bSlot = FindObj( pSoldier, WIRECUTTERS ); if( bSlot != NO_SLOT ) { //the merc has wire cutters return( FALSE ); } } } INT16 bID = RandomSoldierIdFromNewMercsOnPlayerTeam(); if( bID != -1 ) { //have the merc say the quote about the tough gate TacticalCharacterDialogue( &Menptr[ bID ], QUOTE_IMPATIENT_QUOTE ); } //remeber we said the quote if( fSayQuoteOnlyOnce ) { SetJa25GeneralFlag( JA_GF__PLAYER_SAID_GATE_LOCKED_QUOTE ); } return( TRUE ); } void HandleHowPlayerGotThroughFan() { switch( gJa25SaveStruct.ubStateOfFanInPowerGenSector ) { case PGF__STOPPED: gJa25SaveStruct.ubHowPlayerGotThroughFan = PG__PLAYER_STOPPED_FAN_TO_GET_THROUGH; break; case PGF__BLOWN_UP: gJa25SaveStruct.ubHowPlayerGotThroughFan = PG__PLAYER_BLEW_UP_FAN_TO_GET_THROUGH; //If the player blew up the fan, then the enemies can hear it in the tunnel and prepare for it. gJa25SaveStruct.uiJa25GeneralFlags |= JA_GF__DID_PLAYER_MAKE_SOUND_GOING_THROUGH_TUNNEL_GATE; break; } } /* void RevealAllDroppedEnemyItems() { UINT32 uiCnt=0; //loop through all the items for(uiCnt=0; uiCntsSectorX == gWorldSectorX && pSoldier->sSectorY == gWorldSectorY && pSoldier->bSectorZ == gbWorldSectorZ ) { TacticalCharacterDialogue( pSoldier, (UINT16)uiQuoteNum ); } //Say the quote of the newly hired person pSoldier = FindSoldierByProfileID( ubProfile, TRUE ); if( pSoldier ) { TacticalCharacterDialogue( pSoldier, (UINT16)uiQuoteNum ); } return( TRUE ); } //returns false if a new merc is not going to handle saying the new quote BOOLEAN HandleNewGunComment( SOLDIERTYPE *pSoldier, INT32 iItemIndex, BOOLEAN fFromGround ) { BOOLEAN fNewMerc = IsSoldierQualifiedGunCommenterMerc( pSoldier ); if( !fFromGround ) { //if this is morris's note, handle it HandlePickingUpMorrisInstructionNote( pSoldier, iItemIndex ); } //if the quote has already been said if( HasNewGunQuoteBeenPlayedForThisGun( iItemIndex ) ) { //get out return( TRUE ); } //if we are not in tactical or map screen, if( guiCurrentScreen != GAME_SCREEN && guiCurrentScreen != MAP_SCREEN ) { //only remeber that we have picked up the gun at some point SetNewGunQuoteToBePlayedForThisGun( iItemIndex ); return( FALSE ); } //if the soldier is a NOT new merc AND this item is from the ground AND the merc didnt say this quote recently if( !fNewMerc && fFromGround && ( pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_FOUND_SOMETHING_NICE ) == 0 ) { //if the merc can say it if( QuoteExp_GotGunOrUsedGun[ pSoldier->ubProfile ] == QUOTE_FOUND_SOMETHING_SPECIAL ) { //Have the merc say his cool item quote TacticalCharacterDialogue( pSoldier, QUOTE_FOUND_SOMETHING_SPECIAL ); pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_FOUND_SOMETHING_NICE; } } //if it is a new merc if( fNewMerc ) { //if the item is the hand cannon if( iItemIndex == HAND_CANNON ) //4498 { //say the new gun quote TacticalCharacterDialogue( pSoldier, QUOTE_PRECEDENT_TO_REPEATING_ONESELF_RENEW ); } else { //say the new gun quote TacticalCharacterDialogue( pSoldier, QUOTE_HATED_1_ON_TEAM_WONT_RENEW ); } //rememeber we have played the quote SetNewGunQuoteToBePlayedForThisGun( iItemIndex ); } return( TRUE ); } BOOLEAN SaveJa25TacticalInfoToSaveGame( HWFILE hFile ) { if( !SaveNewGunQuotesArrayToSaveGameFile( hFile ) ) { return( FALSE ); } return( TRUE ); } BOOLEAN LoadJa25TacticalInfoFromSavedGame( HWFILE hFile ) { if( !LoadNewGunQuotesArrayToSaveGameFile( hFile ) ) { return( FALSE ); } return( TRUE ); } BOOLEAN SaveNewGunQuotesArrayToSaveGameFile( HWFILE hFile ) { UINT32 uiNumBytesWritten; UINT32 uiSize = sizeof( NEW_GUN_QUOTES_STRUCT ) * NUM_NEW_GUN_QUOTES; FileWrite( hFile, &gNewGunQuotes, uiSize, &uiNumBytesWritten ); if( uiNumBytesWritten != uiSize ) { return( FALSE ); } return( TRUE ); } BOOLEAN LoadNewGunQuotesArrayToSaveGameFile( HWFILE hFile ) { UINT32 uiNumBytesRead; UINT32 uiSize = sizeof( NEW_GUN_QUOTES_STRUCT ) * NUM_NEW_GUN_QUOTES; FileRead( hFile, &gNewGunQuotes, uiSize, &uiNumBytesRead ); if( uiNumBytesRead != uiSize ) { return( FALSE ); } InitNewGunArray(); return( TRUE ); } void InitNewGunArray() { INT32 iCnt=0; gNewGunQuotes[iCnt++].sItem = BARRETT_UB; gNewGunQuotes[iCnt++].sItem = CALICO_960_UB; gNewGunQuotes[iCnt++].sItem = PSG1_UB; gNewGunQuotes[iCnt++].sItem = L85_UB; gNewGunQuotes[iCnt++].sItem = TAR21_UB; gNewGunQuotes[iCnt++].sItem = VAL_SILENT_UB; gNewGunQuotes[iCnt++].sItem = MICRO_UZI_UB; gNewGunQuotes[iCnt++].sItem = HAND_CANNON; gNewGunQuotes[iCnt++].sItem = CALICO_950_UB; gNewGunQuotes[iCnt++].sItem = CALICO_900_UB; } BOOLEAN IsThisGunANewJa25Gun( INT32 iItemIndex ) { //if this gun ISNT a new gun if( !( iItemIndex == BARRETT_UB || iItemIndex == CALICO_960_UB || iItemIndex == PSG1_UB || iItemIndex == L85_UB || iItemIndex == TAR21_UB || iItemIndex == VAL_SILENT_UB || iItemIndex == MICRO_UZI_UB || iItemIndex == HAND_CANNON || iItemIndex == CALICO_950_UB || iItemIndex == CALICO_900_UB ) ) { return( FALSE ); } return( TRUE ); } BOOLEAN HasNewGunQuoteBeenPlayedForThisGun( INT32 iItemIndex ) { INT32 iCnt; for( iCnt=0; iCntubProfile, DQ__NEW_MERC_SAY_NOTE_QUOTES, GetWorldTotalSeconds()+1 ); } //else if there is a new merc on the team else if( bID != -1 ) { UINT32 uiTime=0; if( gJa25SaveStruct.ubMorrisNoteState == MN__PICKED_UP_BY_OLD_MERC_SAID_QUOTE_ALREADY ) { return; } //the merc is not a new merc gJa25SaveStruct.ubMorrisNoteState = MN__PICKED_UP_BY_OLD_MERC_SAID_QUOTE_ALREADY; TacticalCharacterDialogue( &Menptr[ bID ], QUOTE_RENEWING_CAUSE_BUDDY_1_ON_TEAM ); gJa25SaveStruct.bNewMercProfileIDForSayingMorrisNote = bID; //if we are in turnbased combat if( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) ) { uiTime = GetWorldTotalSeconds() + 3; } else { uiTime = GetWorldTotalSeconds() + 10; } DelayedMercQuote( NOBODY, DQ__MORRIS_NOTE_NEW_MERC_DELAY, uiTime ); } else { // // Create a merc popup box that will display a message telling player what to do // gJa25SaveStruct.bNewMercProfileIDForSayingMorrisNote = pSoldier->ubProfile; DelayedMercQuote( pSoldier->ubProfile, DQ__MORRIS_NOTE_DISPLAY_NOTE_1, GetWorldTotalSeconds() + 1 ); gJa25SaveStruct.ubMorrisNoteState = MN__FINISHED; } } void HandleDeathInPowerGenSector( SOLDIERTYPE *pSoldier ) { //if this is NOT the power gen sector J13 if( gWorldSectorX != SECTOR_FAN_X || gWorldSectorY != SECTOR_FAN_Y || gbWorldSectorZ != SECTOR_FAN_Z ) { return; } else { BOOLEAN fFoundValidEnemy=FALSE; UINT8 ubNumFlagedEnemiesInSector=0; UINT32 sRandomSlotGridNo; UINT8 uiCnt; //SOLDIERINITNODE *pInitListSoldier; #define NUM_ENEMIES_SLOTS 4 UINT32 sEnemyPlacementGridNo[ NUM_ENEMIES_SLOTS ]= { POWERGENSECTOR_GRIDNO1, POWERGENSECTOR_GRIDNO2, POWERGENSECTOR_GRIDNO3, POWERGENSECTOR_GRIDNO4, }; // // Count number of Flaged guys still left // for( uiCnt=0; uiCntubID ); //is this the same soldier if( pInitListSoldier && pInitListSoldier->pBasicPlacement->usStartingGridNo == sRandomSlotGridNo ) { fFoundValidEnemy = TRUE; } //we are done, break; } } */ // if we found an enemy, or this is the 2nd last enemy in the sector if( fFoundValidEnemy || ubNumFlagedEnemiesInSector <= 2 ) { StopPowerGenFan(); } } } BOOLEAN IsSoldierAliveWithInitListGridNo( INT16 sInitListGridNo ) { SOLDIERINITNODE *curr; curr = gSoldierInitHead; while( curr ) { if( curr->pBasicPlacement->usStartingGridNo == sInitListGridNo && curr->pSoldier != NULL ) { if ( curr->pSoldier->stats.bLife >= OKLIFE ) { return( TRUE ); } } curr = curr->next; } return( FALSE ); } #define JA25__MAX_EXP_DECREASE (-2) #define JA25__MIN_EXP_LEVEL_AFTER_CHANGE (2) void HandleJa25EnemyExpLevelModifier( ) { INT8 bPlayerExpLevel=0; INT8 bEnemyExpLevel=0; INT8 bDifference=0; if( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) { return; } //if there are no enemies if( NumEnemyInSector() == 0 ) { //get out return; } switch( gGameOptions.ubDifficultyLevel ) { case DIF_LEVEL_EASY: //Get the 2nd highest player exp level bPlayerExpLevel = JA25SecondHighestExpLevelOnPlayersTeam( ); //get the enemies exp level bEnemyExpLevel = JA25SecondHighestExpLevelOnEnemiesTeam( ); //get the difference b/n the 2 bDifference = bPlayerExpLevel - bEnemyExpLevel; //if the players exp level is less then enemies if( bDifference < 0 ) { //if the difference if( bDifference < JA25__MAX_EXP_DECREASE ) { bDifference = JA25__MAX_EXP_DECREASE; } //Degrade all the enemies exp levels by difference Ja25ScaleAllEnemiesByValue( bDifference ); } break; case DIF_LEVEL_MEDIUM: //if the player imported the save if( gJa25SaveStruct.fImportCharactersFromOldJa2Save ) { //Get the 2nd highest player exp level bPlayerExpLevel = JA25SecondHighestExpLevelOnPlayersTeam( ); //get the best enemies exp level bEnemyExpLevel = JA25HighestExpLevelOnTeam( ENEMY_TEAM ); //get the difference b/n the 2 bDifference = bPlayerExpLevel - bEnemyExpLevel; //if the players exp level is greater then enemies if( bDifference > 0 ) { //Upgrade all the enemies exp levels by difference Ja25ScaleAllEnemiesByValue( bDifference ); } } break; case DIF_LEVEL_HARD: //Get the highest player exp level bPlayerExpLevel = JA25HighestExpLevelOnTeam( OUR_TEAM ); //get the best enemies exp level bEnemyExpLevel = JA25HighestExpLevelOnTeam( ENEMY_TEAM ); //get the difference b/n the 2 bDifference = bPlayerExpLevel - bEnemyExpLevel; //if the players exp level is greater then enemies if( bDifference > 0 ) { //if the player imported the save if( gJa25SaveStruct.fImportCharactersFromOldJa2Save ) { //Upgrade all the enemies exp levels by difference Ja25ScaleAllEnemiesByValue( bDifference ); } else { //Upgrade all the enemies exp levels by 1 Ja25ScaleAllEnemiesByValue( 1 ); } } break; default: //Get the 2nd highest player exp level bPlayerExpLevel = JA25SecondHighestExpLevelOnPlayersTeam( ); //get the enemies exp level bEnemyExpLevel = JA25SecondHighestExpLevelOnEnemiesTeam( ); //get the difference b/n the 2 bDifference = bPlayerExpLevel - bEnemyExpLevel; //if the players exp level is less then enemies if( bDifference < 0 ) { //if the difference if( bDifference < JA25__MAX_EXP_DECREASE ) { bDifference = JA25__MAX_EXP_DECREASE; } //Degrade all the enemies exp levels by difference Ja25ScaleAllEnemiesByValue( bDifference ); } break; } } INT8 JA25HighestExpLevelOnTeam( INT8 bTeam ) { INT32 cnt; SOLDIERTYPE *pSoldier=NULL; INT8 bHighestExpLevel=0; cnt = gTacticalStatus.Team[ bTeam ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ bTeam ].bLastID; cnt++, pSoldier++) { if( pSoldier->bActive ) { if( bHighestExpLevel < pSoldier->stats.bExpLevel ) { bHighestExpLevel = pSoldier->stats.bExpLevel; } } } return( bHighestExpLevel ); } INT8 JA25SecondHighestExpLevelOnPlayersTeam( ) { INT32 cnt; SOLDIERTYPE *pSoldier=NULL; INT8 bHighestExpLevel=0; INT8 b2ndHighestExpLevel=0; INT8 bNumber=0; cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++, pSoldier++) { if( pSoldier->bActive ) { if( bHighestExpLevel < pSoldier->stats.bExpLevel ) { bHighestExpLevel = pSoldier->stats.bExpLevel; } else if( b2ndHighestExpLevel < pSoldier->stats.bExpLevel ) { b2ndHighestExpLevel = pSoldier->stats.bExpLevel; } } } //Count number of people on team with same EXP level bNumber = CountNumberOfMercsOnSameTeamOfSameExpLevel( OUR_TEAM, bHighestExpLevel ); //if there are more then 2 mercs on the team with the same high exp level if( bNumber >= 2 ) { //use the highest exp level b2ndHighestExpLevel = bHighestExpLevel; } else { //else we are to only decuct 1 exp level from the main guy so there isnt a HUGE descrepincy b/n 1 super merc //and a bunch of low level losers on a team b2ndHighestExpLevel = bHighestExpLevel - 1; } return( b2ndHighestExpLevel ); } INT8 JA25SecondHighestExpLevelOnEnemiesTeam( ) { INT32 cnt; SOLDIERTYPE *pSoldier=NULL; INT8 bHighestExpLevel=0; INT8 b2ndHighestExpLevel=0; INT8 bNumber=0; //Get the highest exp level on the enemy team bHighestExpLevel = JA25HighestExpLevelOnTeam( ENEMY_TEAM ); //Count number of people on team with same EXP level bNumber = CountNumberOfMercsOnSameTeamOfSameExpLevel( ENEMY_TEAM, bHighestExpLevel ); //if there are more then 2 enemies at the high exp level if( bNumber > 2 ) { //use the highest value b2ndHighestExpLevel = bHighestExpLevel; } else { //otherwise loop through and determine the second highest exp level cnt = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; cnt++, pSoldier++) { if( pSoldier->bActive ) { //if the exp level is less then the highest if( pSoldier->stats.bExpLevel < bHighestExpLevel ) { //is this a new second highest level if( b2ndHighestExpLevel < pSoldier->stats.bExpLevel ) { b2ndHighestExpLevel = pSoldier->stats.bExpLevel; } } } } } return( b2ndHighestExpLevel ); } void Ja25ScaleAllEnemiesByValue( INT8 bExpScaleValue ) { INT32 cnt; SOLDIERTYPE *pSoldier=NULL; INT8 bNewExpLevel=0; cnt = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; cnt++, pSoldier++) { if( pSoldier->bActive ) { bNewExpLevel = pSoldier->stats.bExpLevel + bExpScaleValue; if( bNewExpLevel > 10 ) { bNewExpLevel = 10; } //else if the new value will bring it below 1 else if( bNewExpLevel < 1 ) { bNewExpLevel = 1; } //if the enemy originally had a higher exp level AND will now go below set level else if( pSoldier->stats.bExpLevel > JA25__MIN_EXP_LEVEL_AFTER_CHANGE && bNewExpLevel < JA25__MIN_EXP_LEVEL_AFTER_CHANGE ) { bNewExpLevel = JA25__MIN_EXP_LEVEL_AFTER_CHANGE; } pSoldier->stats.bExpLevel = bNewExpLevel; } } } INT8 CountNumberOfMercsOnSameTeamOfSameExpLevel( INT8 bTeam, INT8 bExpLevel ) { INT8 bNumber=0; SOLDIERTYPE *pSoldier=NULL; INT32 cnt; cnt = gTacticalStatus.Team[ bTeam ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ bTeam ].bLastID; cnt++, pSoldier++) { if( pSoldier->bActive ) { if( bExpLevel == pSoldier->stats.bExpLevel ) { bNumber++; } } } return( bNumber ); } INT8 RandomSoldierIdForAnyMercInSector() { UINT8 SoldierIdArray[18]; UINT8 ubNumMercsInSector=0; INT32 cnt; SOLDIERTYPE *pSoldier=NULL; UINT8 ubCount=0; ubNumMercsInSector = PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, gbWorldSectorZ ); if( ubNumMercsInSector == 0 ) { return( -1 ); } memset( SoldierIdArray, 0, 18 ); //loop through the merc array and fill in the soldier id cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pSoldier++) { //if the soldier is in the sector if( pSoldier->bActive && pSoldier->bInSector && ( pSoldier->stats.bLife >= CONSCIOUSNESS ) && !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !AM_A_ROBOT( pSoldier ) ) { SoldierIdArray[ ubCount++ ] = cnt; } } return( SoldierIdArray[ Random( ubCount ) ] ); } void HandleFanStartingAtEndOfCombat() { //if its not the right sector if( !( gWorldSectorX == SECTOR_FAN_X && gWorldSectorY == SECTOR_FAN_Y && gbWorldSectorZ == SECTOR_FAN_Z ) ) { //leave return; } //if the fan is not stopped if( gJa25SaveStruct.ubStateOfFanInPowerGenSector != PGF__STOPPED ) { //leave return; } StartFanBackUpAgain(); } void HandleInitialEventsInHeliCrash() { SOLDIERTYPE *pSoldier=NULL; INT32 cnt; //first, loop through all the mercs and injure them cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pSoldier++) { //if the merc is alive if( pSoldier->bActive ) { pSoldier->stats.bLife -= ( 3 + Random( 5 ) ); pSoldier->sBreathRed = ( 15 + Random( 15 ) ) * 100; pSoldier->bActionPoints = 0; } } /* #ifdef JA2TESTVERSION //Add a smoke effect behind the heli NewSmokeEffect( 15102, SMOKE_GRENADE, 0, NOBODY ); #endif */ } UINT32 GetNumberOfTurnsPowerGenFanWillBeStoppedFor() { return( zDiffSetting[gGameOptions.ubDifficultyLevel].iGetNumberOfTurnsPowerGenFanWillBeStoppedFor ); } void DisplayCommanderMorrisNote( SOLDIERTYPE *pSoldier ) { CHAR16 zString[1024]; if( gJa25SaveStruct.ubDisplayCommanderMorrisNote == DMN__FINISHED ) { return; } if( pSoldier == NULL ) { return; } //if it si the first part of the note to be displayed if( gJa25SaveStruct.ubDisplayCommanderMorrisNote == DMN__NOT_TO_DISPLAY_IT ) { gJa25SaveStruct.ubDisplayCommanderMorrisNote = DMN__DISPLAY_PART_1; swprintf( zString, zNewTacticalMessages[ TCTL_MSG__END_GAME_POPUP_TXT_1 ], pSoldier->GetName() ); } //if it si the second part of the note to be displayed else if( gJa25SaveStruct.ubDisplayCommanderMorrisNote == DMN__DISPLAY_PART_1 ) { gJa25SaveStruct.ubDisplayCommanderMorrisNote = DMN__DISPLAY_PART_2; swprintf( zString, zNewTacticalMessages[ TCTL_MSG__END_GAME_POPUP_TXT_2 ], pSoldier->GetName(), pSoldier->GetName() ); } //Display it ExecuteTacticalTextBox( 110, zString ); } void HandleCommanderMorrisNewMercWantsNoteDelayedSpeech() { //if the note has already been picked up by a new merc, or the note has been displayed if( gJa25SaveStruct.ubMorrisNoteState == MN__PICKED_UP_BY_NEW_MERC || gJa25SaveStruct.ubMorrisNoteState == MN__FINISHED ) { return; } //if the original merc who said the quote is valid INT16 bID = gJa25SaveStruct.bNewMercProfileIDForSayingMorrisNote; if( bID != -1 && IsSoldierQualifiedMerc( &Menptr[ bID ] ) ) { } else { bID = RandomSoldierIdFromNewMercsOnPlayerTeam(); if( bID != -1 ) { gJa25SaveStruct.bNewMercProfileIDForSayingMorrisNote = bID; } else { return; } } TacticalCharacterDialogue( &Menptr[ bID ], QUOTE_RENEWING_CAUSE_BUDDY_1_ON_TEAM ); } void HandleShowingRadioLocatorsInMorrisArea() { //Reveal the switch in Morris area HandleOpenControlPanelToRevealSwitchInMorrisArea(); //control panel locater BeginMultiPurposeLocator( RADIOLOCATORS_GRIDNO1, 0, TRUE ); //if we are not in combat if( !((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT)) ) { DelayedMercQuote( RADIOLOCATORS_GRIDNO2, DQ__SHOW_RADIO_LOCATOR, GetWorldTotalSeconds() + 3 ); } } void HandleNewMercSayingContentsOfMorrisNote( SOLDIERTYPE *pSoldier ) { TacticalCharacterDialogue( pSoldier, QUOTE_MERC_LEAVING_ALSUCO_SOON ); TacticalCharacterDialogue( pSoldier, QUOTE_MERC_GONE_UP_IN_PRICE ); SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_JERRY_MILO, JM_SE__SHOW_RADIO_LOCATOR, 0, 0, 0, DIALOGUE_TACTICAL_UI ); } void HandlePlayerHittingSwitchToLaunchMissles() { INT32 cnt; SOLDIERTYPE *pSoldier=NULL; // // The player Just won the game, remeber this // gGameSettings.fPlayerFinishedTheGame = TRUE; SaveGameSettings(); SaveFeatureFlags(); //Update the quest log InternalEndQuest( QUEST_DESTROY_MISSLES, -1, -1, TRUE ); //lock the interface guiPendingOverrideEvent = LU_BEGINUILOCK; HandleTacticalUI( ); // // Loop through all the mercs in the sector and make them run to the elevator // cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pSoldier++) { // if the soldier was in the complex if( pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE && pSoldier->bInSector && pSoldier->sSectorX == SECTOR_LAUNCH_MISSLES_X && pSoldier->sSectorY == SECTOR_LAUNCH_MISSLES_Y && pSoldier->bSectorZ == SECTOR_LAUNCH_MISSLES_Z ) { if( PythSpacesAway( pSoldier->sGridNo, SWITCHTOLAUNCHMISSLES_GRIDNO1 ) < PythSpacesAway( pSoldier->sGridNo, SWITCHTOLAUNCHMISSLES_GRIDNO2 ) ) pSoldier->EVENT_InternalGetNewSoldierPath( SWITCHTOLAUNCHMISSLES_GRIDNO1, RUNNING, TRUE, TRUE ); else pSoldier->EVENT_InternalGetNewSoldierPath( SWITCHTOLAUNCHMISSLES_GRIDNO2, RUNNING, TRUE, TRUE ); } } //Start a timer so we can fade out DelayedMercQuote( NOBODY, DQ__FADE_OUT_TO_END_GAME_CINEMATIC, GetWorldTotalSeconds()+2 ); } void HandleFadingOutToEndGameCinematics() { gFadeOutDoneCallback = DoneFadeOutEndCinematic; FadeOutGameScreen( ); // UnLock UI! guiPendingOverrideEvent = LU_ENDUILOCK; HandleTacticalUI( ); } void HandleOpenControlPanelToRevealSwitchInMorrisArea() { //if the note has already been picked up by a new merc, or the note has been displayed if( gJa25SaveStruct.ubMorrisNoteState == MN__PICKED_UP_BY_NEW_MERC || gJa25SaveStruct.ubMorrisNoteState == MN__FINISHED ) { STRUCTURE * pStructure; INT32 iItemIndex; ITEM_POOL * pItemPool; // first, find the switch item and turn off its trap level if ( ItemTypeExistsAtLocation( SWITCHINMORRISAREA_GRIDNO, SWITCH, 0, &iItemIndex ) ) { //gWorldItems[ iItemIndex ]->data.bTrap = 0; gWorldItems[ iItemIndex ].object[0]->data.bTrap = 0; GetItemPool( SWITCHINMORRISAREA_GRIDNO, &pItemPool, 0 ); if ( pItemPool ) { SetItemPoolVisibilityOn( pItemPool, ANY_VISIBILITY_VALUE, FALSE ); } } //Open up the Control Panel so the switch is visibile pStructure = FindStructure( SWITCHINMORRISAREA_GRIDNO, STRUCTURE_GENERIC ); if( pStructure == NULL ) { return; } if( SwapStructureForPartnerForcingGraphicalChange( SWITCHINMORRISAREA_GRIDNO, pStructure ) == NULL ) { //an error occured return; } } } #endif