#include "builddefines.h" #include #include #include "stdlib.h" #include "debug.h" #include "math.h" #include "worlddef.h" #include "renderworld.h" #include "Assignments.h" #include "merc entering.h" #include "Animation Control.h" #include "Animation Data.h" #include "Isometric Utils.h" #include "Event Pump.h" #include "Render Fun.h" #include "interface.h" #include "sysutil.h" #include "FileMan.h" #include "Random.h" #include "ai.h" #include "Interactive Tiles.h" #include "english.h" #include "overhead.h" #include "Soldier Profile.h" #include "Game Clock.h" #include "soldier create.h" #include "Merc Hiring.h" #include "Game Event Hook.h" #include "message.h" #include "strategicmap.h" #include "strategic.h" #include "items.h" #include "Soldier Add.h" #include "History.h" #include "Squads.h" #include "Strategic Merc Handler.h" #include "Dialogue Control.h" #include "Map Screen Interface.h" #include "Map Screen Interface Map.h" #include "screenids.h" #include "jascreens.h" #include "text.h" #include "Merc Contract.h" #include "LaptopSave.h" #include "personnel.h" #include "Auto Resolve.h" #include "Map Screen Interface Bottom.h" #include "Quests.h" #include "GameSettings.h" #include "DynamicDialogue.h"// added by Flugente #include "Dialogue Control.h" // added by Flugente #include "connect.h" #include "Map Information.h" #ifdef JA2UB #include "Soldier Control.h" #include "Ja25 Strategic Ai.h" #include "Ja25_Tactical.h" #include "Campaign Types.h" #include "MapScreen Quotes.h" #include "opplist.h" #include "Ja25Update.h" #include "ub_config.h" #endif #ifdef JA2UB #else // anv: for Kulba's odyssey #include "email.h" #endif //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; #define MIN_FLIGHT_PREP_TIME 6 #ifdef JA2TESTVERSION BOOLEAN gForceHireMerc=FALSE; void SetFlagToForceHireMerc( BOOLEAN fForceHire ); #endif extern BOOLEAN gfTacticalDoHeliRun; extern BOOLEAN gfFirstHeliRun; // ATE: Globals that dictate where the mercs will land once being hired // Default to Omerta // Saved in general saved game structure // HEADROCK HAM 3.5: Externalized coordinates INT16 gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX; INT16 gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY; void CheckForValidArrivalSector( ); #ifdef JA2UB void AddItemToMerc( UINT8 ubNewMerc, INT16 sItemType ); #define NUM_INITIAL_GRIDNOS_FOR_HELI_CRASH 7 UINT32 gsInitialHeliGridNo[ NUM_INITIAL_GRIDNOS_FOR_HELI_CRASH ] = { 0, 0, 0, 0, 0, 0, 0, }; INT16 gsInitialHeliRandomTimes[ NUM_INITIAL_GRIDNOS_FOR_HELI_CRASH ] = { 0, 0, 0, 0, 0, 0, 0 }; UINT32 GetInitialHeliGridNo( ); UINT16 GetInitialHeliRandomTime(); #endif INT8 HireMerc( MERC_HIRE_STRUCT *pHireMerc) { SOLDIERTYPE *pSoldier; UINT8 iNewIndex; UINT8 ubCurrentSoldier = pHireMerc->ubProfileID; MERCPROFILESTRUCT *pMerc; SOLDIERCREATE_STRUCT MercCreateStruct; BOOLEAN fReturn = FALSE; pMerc = &gMercProfiles[ ubCurrentSoldier ]; //If we are to disregard the ststus of the merc #ifdef JA2TESTVERSION if( !gForceHireMerc ) #endif //If the merc is away, Dont hire him, or if the merc is only slightly annoyed at the player if( ( pMerc->bMercStatus != 0 ) && (pMerc->bMercStatus != MERC_ANNOYED_BUT_CAN_STILL_CONTACT ) && ( pMerc->bMercStatus != MERC_HIRED_BUT_NOT_ARRIVED_YET ) ) return( MERC_HIRE_FAILED ); //hayden, 7 member team limit setable in ini if( NumberOfMercsOnPlayerTeam() >= OUR_TEAM_SIZE_NO_VEHICLE || (is_client && NumberOfMercsOnPlayerTeam() >= cMaxMercs) ) return( MERC_HIRE_OVER_PLAYER_LIMIT ); // ATE: if we are to use landing zone, update to latest value // they will be updated again just before arrival... if ( pHireMerc->fUseLandingZoneForArrival ) { pHireMerc->sSectorX = gsMercArriveSectorX; pHireMerc->sSectorY = gsMercArriveSectorY; pHireMerc->bSectorZ = 0; } // BUILD STRUCTURES MercCreateStruct.initialize(); MercCreateStruct.ubProfile = ubCurrentSoldier; MercCreateStruct.fPlayerMerc = TRUE; MercCreateStruct.sSectorX = pHireMerc->sSectorX; MercCreateStruct.sSectorY = pHireMerc->sSectorY; MercCreateStruct.bSectorZ = pHireMerc->bSectorZ; MercCreateStruct.bTeam = SOLDIER_CREATE_AUTO_TEAM; MercCreateStruct.fCopyProfileItemsOver= pHireMerc->fCopyProfileItemsOver; if(!cAllowMercEquipment && is_networked) MercCreateStruct.fCopyProfileItemsOver=0;//hayden : server overide if ( !TacticalCreateSoldier( &MercCreateStruct, &iNewIndex ) ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "TacticalCreateSoldier in HireMerc(): Failed to Add Merc"); return( MERC_HIRE_FAILED ); } #ifdef JA2UB //JA25 UB //MErc mercs come with an umbrella if ( gMercProfiles[ubCurrentSoldier].Type == PROFILETYPE_MERC ) { AddItemToMerc( iNewIndex, MERC_UMBRELLA ); //Data-1.13\TableData\Items\items.xml, uiIndex = 1361 or Data\TableData\Items\items.xml, uiIndex = 336 } //if this is an AIM or MERC merc if( gJa25SaveStruct.fHaveAimandMercOffferItems ) { //if its an aim merc if ( gMercProfiles[ubCurrentSoldier].Type == PROFILETYPE_AIM ) { //give the mercs one of the promo items AddItemToMerc( iNewIndex, SAM_GARVER_COMBAT_KNIFE ); //1353 } // if its a merc merc else if ( gMercProfiles[ubCurrentSoldier].Type == PROFILETYPE_MERC ) { //give the mercs one of the promo items AddItemToMerc( iNewIndex, CHE_GUEVARA_CANTEEN ); //1359 AddItemToMerc( iNewIndex, MERC_WRISTWATCH ); //1360 AddItemToMerc( iNewIndex, SAM_GARVER_COMBAT_KNIFE ); //1353 } } #else //ja25: No enrico, therefore, no email if( DidGameJustStart() ) { // OK, CHECK FOR FIRST GUY, GIVE HIM SPECIAL ITEM! if ( iNewIndex == 0 ) { // OK, give this item to our merc! // make an objecttype CreateItem(LETTER, 100, &gTempObject); // Give it fReturn = AutoPlaceObject( MercPtrs[iNewIndex], &gTempObject, FALSE ); // CHRISL: This condition should resolve the issue of the letter not being issued to the first merc if(!fReturn) { if (UsingNewInventorySystem()) { (MercPtrs[iNewIndex]->inv[NUM_INV_SLOTS-1]) = gTempObject; fReturn=TRUE; } else { (MercPtrs[iNewIndex]->inv[SMALLPOCK8POS]) = gTempObject; fReturn = TRUE; } } Assert( fReturn ); } // Set insertion for first time in chopper // ATE: Insert for demo , not using the heli sequence.... pHireMerc->ubInsertionCode = INSERTION_CODE_CHOPPER; } #endif //record how long the merc will be gone for pMerc->bMercStatus = (UINT8)pHireMerc->iTotalContractLength; pSoldier = &Menptr[iNewIndex]; //Copy over insertion data.... pSoldier->ubStrategicInsertionCode = pHireMerc->ubInsertionCode; pSoldier->usStrategicInsertionData = pHireMerc->usInsertionData; // ATE: Copy over value for using alnding zone to soldier type pSoldier->flags.fUseLandingZoneForArrival = pHireMerc->fUseLandingZoneForArrival; // Set assignment //ATE: If first time, make ON_DUTY, otherwise GUARD if( ( pSoldier->bAssignment != IN_TRANSIT ) ) { SetTimeOfAssignmentChangeForMerc( pSoldier ); } ChangeSoldiersAssignment( pSoldier, IN_TRANSIT ); //set the contract length pSoldier->iTotalContractLength = pHireMerc->iTotalContractLength; //reset the insurance values pSoldier->iStartOfInsuranceContract = 0; pSoldier->iTotalLengthOfInsuranceContract = 0; //Init the contract charge // pSoldier->iTotalContractCharge = 0; // store arrival time in soldier structure so map screen can display it pSoldier->uiTimeSoldierWillArrive = pHireMerc->uiTimeTillMercArrives; //Set the type of merc if (!is_networked) { if( DidGameJustStart() ) { #ifdef JA2UB //ja25ub //set a flag so we know we are doing the heli crash if ( gGameUBOptions.InGameHeliCrash == TRUE || gGameUBOptions.InGameHeli == FALSE) gfFirstTimeInGameHeliCrash = TRUE; //AA FALSE ?? else gfFirstTimeInGameHeliCrash = FALSE; // Set time of initial merc arrival in minutes #endif pHireMerc->uiTimeTillMercArrives = ( gGameExternalOptions.iGameStartingTime + gGameExternalOptions.iFirstArrivalDelay ) / NUM_SEC_IN_MIN; #ifdef JA2UB if ( gGameUBOptions.InGameHeli == FALSE ) { // Set the gridno for the soldier pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; pSoldier->usStrategicInsertionData = GetInitialHeliGridNo( ); //Set a "code" to enable the merc to be in the direction we set! pSoldier->ubInsertionDirection = Random( NUM_WORLD_DIRECTIONS ) + 100; if( pSoldier->ubStrategicInsertionCode == 0 ) { Assert( 0 ); } pSoldier->fWaitingToGetupFromJA25Start = TRUE; pSoldier->fIgnoreGetupFromCollapseCheck = TRUE; RESETTIMECOUNTER( pSoldier->GetupFromJA25StartCounter, GetInitialHeliRandomTime() ); } else { pHireMerc->ubInsertionCode = INSERTION_CODE_CHOPPER; } #else // Set insertion for first time in chopper pHireMerc->ubInsertionCode = INSERTION_CODE_CHOPPER; #endif //set when the merc's contract is finished pSoldier->iEndofContractTime = GetMidnightOfFutureDayInMinutes( pSoldier->iTotalContractLength ) + ( GetHourWhenContractDone( pSoldier ) * 60 ); } else { //set when the merc's contract is finished ( + 1 cause it takes a day for the merc to arrive ) pSoldier->iEndofContractTime = GetMidnightOfFutureDayInMinutes( 1 + pSoldier->iTotalContractLength ) + ( GetHourWhenContractDone( pSoldier ) * 60 ); } } // WANNE - MP: We need this, so the merc contract is correct! else { pSoldier->iEndofContractTime = GetMidnightOfFutureDayInMinutes( pSoldier->iTotalContractLength ) + ( GetHourWhenContractDone( pSoldier ) * 60 ); } //Set the time and ID of the last hired merc will arrive LaptopSaveInfo.sLastHiredMerc.iIdOfMerc = pHireMerc->ubProfileID; LaptopSaveInfo.sLastHiredMerc.uiArrivalTime = pHireMerc->uiTimeTillMercArrives; if (!is_client) { //if we are trying to hire a merc that should arrive later, put the merc in the queue if( pHireMerc->uiTimeTillMercArrives != 0 ) { AddStrategicEvent( EVENT_DELAYED_HIRING_OF_MERC, pHireMerc->uiTimeTillMercArrives, pSoldier->ubID ); //specify that the merc is hired but hasnt arrived yet pMerc->bMercStatus = MERC_HIRED_BUT_NOT_ARRIVED_YET; } } else { if(is_client)send_hire( iNewIndex, ubCurrentSoldier, pHireMerc->iTotalContractLength, MercCreateStruct.fCopyProfileItemsOver ); //send off hire info to network, also avail possibility for net-game exclusive hired pSoldier changes... } //if the merc is an AIM merc if ( gMercProfiles[ubCurrentSoldier].Type == PROFILETYPE_AIM ) { pSoldier->ubWhatKindOfMercAmI = MERC_TYPE__AIM_MERC; //determine how much the contract is, and remember what type of contract he got if( pHireMerc->iTotalContractLength == 1 ) { //pSoldier->iTotalContractCharge = gMercProfiles[ pSoldier->ubProfile ].sSalary; pSoldier->bTypeOfLastContract = CONTRACT_EXTEND_1_DAY; pSoldier->iTimeCanSignElsewhere = GetWorldTotalMin(); } else if( pHireMerc->iTotalContractLength == 7 ) { //pSoldier->iTotalContractCharge = gMercProfiles[ pSoldier->ubProfile ].uiWeeklySalary; pSoldier->bTypeOfLastContract = CONTRACT_EXTEND_1_WEEK; pSoldier->iTimeCanSignElsewhere = GetWorldTotalMin(); } else if( pHireMerc->iTotalContractLength == 14 ) { //pSoldier->iTotalContractCharge = gMercProfiles[ pSoldier->ubProfile ].uiBiWeeklySalary; pSoldier->bTypeOfLastContract = CONTRACT_EXTEND_2_WEEK; // These luck fellows need to stay the whole duration! pSoldier->iTimeCanSignElsewhere = pSoldier->iEndofContractTime; } // remember the medical deposit we PAID. The one in his profile can increase when he levels! pSoldier->usMedicalDeposit = gMercProfiles[ pSoldier->ubProfile ].sMedicalDepositAmount; } //if the merc is from M.E.R.C. else if ( gMercProfiles[ubCurrentSoldier].Type == PROFILETYPE_MERC ) { pSoldier->ubWhatKindOfMercAmI = MERC_TYPE__MERC; //pSoldier->iTotalContractCharge = -1; gMercProfiles[ pSoldier->ubProfile ].iMercMercContractLength = 1; //Set starting conditions for the merc pSoldier->iStartContractTime = GetWorldDay( ); if(!is_client)AddHistoryToPlayersLog(HISTORY_HIRED_MERC_FROM_MERC, ubCurrentSoldier, GetWorldTotalMin(), -1, -1 ); } //If the merc is from IMP, (ie a player character) else if ( gMercProfiles[ubCurrentSoldier].Type == PROFILETYPE_IMP ) { pSoldier->ubWhatKindOfMercAmI = MERC_TYPE__PLAYER_CHARACTER; //pSoldier->iTotalContractCharge = -1; } //else its a NPC merc else { pSoldier->ubWhatKindOfMercAmI = MERC_TYPE__NPC; //pSoldier->iTotalContractCharge = -1; } #ifdef JA2UB //Ja25: Need to set start time for all mercs pSoldier->iStartContractTime = GetWorldDay( ); #endif //remove the merc from the Personnel screens departed list ( if they have never been hired before, its ok to call it ) RemoveNewlyHiredMercFromPersonnelDepartedList( pSoldier->ubProfile ); // Flugente: dynamic opinions if (gGameExternalOptions.fDynamicOpinions) { CheckForFriendsofHated(pSoldier); } gfAtLeastOneMercWasHired = TRUE; return( MERC_HIRE_OK ); } void MercArrivesCallback( UINT8 ubSoldierID ) { MERCPROFILESTRUCT *pMerc; SOLDIERTYPE *pSoldier; UINT32 uiTimeOfPost; if (!is_networked) { // hayden - maybe you want to duke it out in omerta ;) // HEADROCK HAM 3.5: Externalized starting (safe) sector // HEADROCK HAM 3.5: Actually, this is really ridiculous. Why should enemies at the LZ be eliminated at all? // I'm taking the initiative and removing this from the code. Mainly because it ends up interfering with // externalized LZs combined with other features like "Always Real Time" and "Forced Turn Based". //if( !DidGameJustStart() && gsMercArriveSectorX == gGameExternalOptions.ubDefaultArrivalSectorX && gsMercArriveSectorY == gGameExternalOptions.ubDefaultArrivalSectorY ) // { // //Mercs arriving in A9. This sector has been deemed as the always safe sector. // //Seeing we don't support entry into a hostile sector (except for the beginning), // //we will nuke any enemies in this sector first. // if( gWorldSectorX != gGameExternalOptions.ubDefaultArrivalSectorX || gWorldSectorY != gGameExternalOptions.ubDefaultArrivalSectorY || gbWorldSectorZ ) // { // EliminateAllEnemies( (UINT8)gsMercArriveSectorX, (UINT8)gsMercArriveSectorY ); // } // } } // This will update ANY soldiers currently schedules to arrive too CheckForValidArrivalSector( ); // stop time compression until player restarts it StopTimeCompression(); pSoldier = &Menptr[ ubSoldierID ]; pMerc = &gMercProfiles[ pSoldier->ubProfile ]; // anv: handle Kulba's odyssey #ifdef JA2UB // too many Kulbas #else if(pSoldier->ubProfile == JOHN_MERC) { // just in case if( LaptopSaveInfo.ubJohnPossibleMissedFlights > 3 ) LaptopSaveInfo.ubJohnPossibleMissedFlights = 3; // every time Kulba delays his arrival, chances of next delay decrease if( Random( 100 ) < LaptopSaveInfo.ubJohnPossibleMissedFlights * 25 ) { pSoldier->uiTimeSoldierWillArrive = pSoldier->uiTimeSoldierWillArrive + 720 + Random ( 720 ); AddStrategicEvent( EVENT_DELAYED_HIRING_OF_MERC, pSoldier->uiTimeSoldierWillArrive, pSoldier->ubID ); if(LaptopSaveInfo.ubJohnPossibleMissedFlights == 3 ) AddEmail( JOHN_KULBA_MISSED_FLIGHT_1, JOHN_KULBA_MISSED_FLIGHT_1_LENGTH, JOHN_KULBA, GetWorldTotalMin(), -1, -1, TYPE_EMAIL_EMAIL_EDT ); else if(LaptopSaveInfo.ubJohnPossibleMissedFlights == 2 ) AddEmail( JOHN_KULBA_MISSED_FLIGHT_2, JOHN_KULBA_MISSED_FLIGHT_2_LENGTH, JOHN_KULBA, GetWorldTotalMin(), -1, -1, TYPE_EMAIL_EMAIL_EDT ); else if(LaptopSaveInfo.ubJohnPossibleMissedFlights == 1 ) AddEmail( JOHN_KULBA_MISSED_FLIGHT_3, JOHN_KULBA_MISSED_FLIGHT_3_LENGTH, JOHN_KULBA, GetWorldTotalMin(), -1, -1, TYPE_EMAIL_EMAIL_EDT ); LaptopSaveInfo.ubJohnPossibleMissedFlights--; return; } else { // reset possible missed flights, for the future Kulba's adventures LaptopSaveInfo.ubJohnPossibleMissedFlights = 3; } } #endif //shadooow: if all mercs were killed or captured and default arrival sector is Omerta, force helidrop arrival animation if (guiCurrentScreen == MAP_SCREEN && pSoldier->flags.fUseLandingZoneForArrival && !gWorldSectorX && !gWorldSectorY && gbWorldSectorZ == -1 && gsMercArriveSectorX == gGameExternalOptions.ubDefaultArrivalSectorX && gsMercArriveSectorY == gGameExternalOptions.ubDefaultArrivalSectorY) { bool force_helidrop = true; SOLDIERTYPE *pTeamSoldier; for (UINT8 cnt = 0; cnt < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; cnt++) { if (gCharactersList[cnt].fValid) { pTeamSoldier = &Menptr[gCharactersList[cnt].usSolID]; if (pTeamSoldier != pSoldier && pTeamSoldier->bAssignment != ASSIGNMENT_DEAD && pTeamSoldier->bAssignment != ASSIGNMENT_POW && pTeamSoldier->bAssignment != IN_TRANSIT && pSoldier->ubStrategicInsertionCode != INSERTION_CODE_CHOPPER) { force_helidrop = false; } } } if (force_helidrop) { SetCurrentWorldSector(gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, 0); } } // add the guy to a squad AddCharacterToAnySquad( pSoldier ); // ATE: Make sure we use global..... if ( pSoldier->flags.fUseLandingZoneForArrival ) { pSoldier->sSectorX = gsMercArriveSectorX; pSoldier->sSectorY = gsMercArriveSectorY; pSoldier->bSectorZ = 0; } // Add merc to sector ( if it's the current one ) if ( gWorldSectorX == pSoldier->sSectorX && gWorldSectorY == pSoldier->sSectorY && pSoldier->bSectorZ == gbWorldSectorZ ) { // OK, If this sector is currently loaded, and guy does not have CHOPPER insertion code.... // ( which means we are at beginning of game if so ) // Setup chopper.... #ifdef JA2UB if ( pSoldier->ubStrategicInsertionCode != INSERTION_CODE_CHOPPER && pSoldier->sSectorX == gGameExternalOptions.ubDefaultArrivalSectorX && pSoldier->sSectorY == gGameExternalOptions.ubDefaultArrivalSectorY && gGameUBOptions.InGameHeli == TRUE ) #else if (pSoldier->ubStrategicInsertionCode != INSERTION_CODE_CHOPPER ) #endif { gfTacticalDoHeliRun = TRUE; if (gfFirstHeliRun) { SetHelicopterDroppoint(gGameExternalOptions.iInitialMercArrivalLocation); } else { SetHelicopterDroppoint(gMapInformation.sCenterGridNo); } // OK, If we are in mapscreen, get out... if ( guiCurrentScreen == MAP_SCREEN ) { // ATE: Make sure the current one is selected! ChangeSelectedMapSector( gWorldSectorX, gWorldSectorY, 0 ); RequestTriggerExitFromMapscreen( MAP_EXIT_TO_TACTICAL ); } pSoldier->ubStrategicInsertionCode = INSERTION_CODE_CHOPPER; } UpdateMercInSector( pSoldier, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); } // Strategic map arrival to a sector that's not loaded else { #ifdef JA2UB pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; pSoldier->usStrategicInsertionData = gGameUBOptions.LOCATEGRIDNO; #else pSoldier->ubStrategicInsertionCode = INSERTION_CODE_CENTER; #endif } if ( pSoldier->ubStrategicInsertionCode != INSERTION_CODE_CHOPPER ) { ScreenMsg( FONT_MCOLOR_WHITE, MSG_INTERFACE, TacticalStr[ MERC_HAS_ARRIVED_STR ], pSoldier->GetName() ); // ATE: He's going to say something, now that they've arrived... if ( gTacticalStatus.bMercArrivingQuoteBeingUsed == FALSE && !gfFirstHeliRun ) { gTacticalStatus.bMercArrivingQuoteBeingUsed = TRUE; //Setup the highlight sector value (note this isn't for mines but using same system) gsSectorLocatorX = pSoldier->sSectorX; gsSectorLocatorY = pSoldier->sSectorY; TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT, 2, 0 ); //ja25ub #ifdef JA2UB //if its the first time in, dont say anything if( !gfFirstTimeInGameHeliCrash ) #endif TacticalCharacterDialogue( pSoldier, QUOTE_MERC_REACHED_DESTINATION ); TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT, 3, 0 ); TacticalCharacterDialogueWithSpecialEventEx( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_UNSET_ARRIVES_FLAG, 0, 0, 0 ); } } //record how long the merc will be gone for pMerc->bMercStatus = (UINT8)pSoldier->iTotalContractLength; // remember when excatly he ARRIVED in Arulco, in case he gets fired early pSoldier->uiTimeOfLastContractUpdate = GetWorldTotalMin(); //set when the merc's contract is finished pSoldier->iEndofContractTime = GetMidnightOfFutureDayInMinutes( pSoldier->iTotalContractLength ) + ( GetHourWhenContractDone( pSoldier ) * 60 ); // Do initial check for bad items if ( pSoldier->bTeam == gbPlayerNum ) { //ATE: Try to see if our equipment sucks! if ( SoldierHasWorseEquipmentThanUsedTo( pSoldier ) ) { // Randomly anytime between 9:00, and 10:00 uiTimeOfPost = 540 + Random( 660 ); if ( GetWorldMinutesInDay() < uiTimeOfPost ) { AddSameDayStrategicEvent( EVENT_MERC_COMPLAIN_EQUIPMENT, uiTimeOfPost , pSoldier->ubProfile ); } } } HandleMercArrivesQuotes( pSoldier ); fTeamPanelDirty = TRUE; // if the currently selected sector has no one in it, select this one instead if ( !CanGoToTacticalInSector( sSelMapX, sSelMapY, ( UINT8 )iCurrentMapSectorZ ) ) { ChangeSelectedMapSector( pSoldier->sSectorX, pSoldier->sSectorY, 0 ); } return; } BOOLEAN IsMercHireable( UINT8 ubMercID ) { //If the merc has an .EDT file, is not away on assignment, and isnt already hired (but not arrived yet), he is not DEAD and he isnt returning home if( ( gMercProfiles[ ubMercID ].bMercStatus == MERC_HAS_NO_TEXT_FILE ) || ( gMercProfiles[ ubMercID ].bMercStatus > 0 ) || ( gMercProfiles[ ubMercID ].bMercStatus == MERC_HIRED_BUT_NOT_ARRIVED_YET ) || ( gMercProfiles[ ubMercID ].bMercStatus == MERC_IS_DEAD ) || ( gMercProfiles[ ubMercID ].uiDayBecomesAvailable > 0 ) || ( gMercProfiles[ ubMercID ].bMercStatus == MERC_WORKING_ELSEWHERE ) || ( gMercProfiles[ ubMercID ].bMercStatus == MERC_FIRED_AS_A_POW ) || ( gMercProfiles[ ubMercID ].bMercStatus == MERC_RETURNING_HOME ) ) return(FALSE); else return(TRUE); } BOOLEAN IsMercDead( UINT8 ubMercID ) { if( gMercProfiles[ ubMercID ].bMercStatus == MERC_IS_DEAD ) return(TRUE); else return(FALSE); } BOOLEAN IsTheSoldierAliveAndConcious( SOLDIERTYPE *pSoldier ) { if( pSoldier->stats.bLife >= CONSCIOUSNESS ) return(TRUE); else return(FALSE); } UINT8 NumberOfMercsOnPlayerTeam() { INT8 cnt; SOLDIERTYPE *pSoldier; INT16 bLastTeamID; UINT8 ubCount=0; // Set locator to first merc cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; bLastTeamID = gTacticalStatus.Team[ gbPlayerNum ].bLastID; if (! MercPtrs[cnt]) return 0; for ( pSoldier = MercPtrs[ cnt ]; cnt <= bLastTeamID; cnt++,pSoldier++) { AssertNotNIL(pSoldier); //if the is active, and is not a vehicle if( pSoldier->bActive && !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) { ubCount++; } } return( ubCount ); } void HandleMercArrivesQuotes( SOLDIERTYPE *pSoldier ) { UINT8 cnt, usLastTeamID; INT8 bHated; SOLDIERTYPE *pTeamSoldier; #ifdef JA2UB //if we are at the begining of the game going through the initial heli scequence if( pSoldier->fWaitingToGetupFromJA25Start ) { //we can "leave" this function cause we dont want to do anything with buddy system return; } #endif // If we are approaching with helicopter, don't say any ( yet ) if ( pSoldier->ubStrategicInsertionCode != INSERTION_CODE_CHOPPER ) { // if we haven't met the rebels yet, characters issue some comments if ( gubQuest[QUEST_DELIVER_LETTER] == QUESTINPROGRESS ) { // Player-generated characters issue a comment about arriving in Omerta. if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER ) { TacticalCharacterDialogue( pSoldier, QUOTE_PC_DROPPED_OMERTA ); } } // Check to see if anyone hates this merc and will now complain cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; usLastTeamID = gTacticalStatus.Team[ gbPlayerNum ].bLastID; //loop though all the mercs for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= usLastTeamID; ++cnt, ++pTeamSoldier) { if ( pTeamSoldier->bActive ) { if ( pTeamSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) { bHated = WhichHated( pTeamSoldier->ubProfile, pSoldier->ubProfile ); if ( bHated != -1 ) { // hates the merc who has arrived and is going to gripe about it! switch( bHated ) { case 0: TacticalCharacterDialogue( pTeamSoldier, QUOTE_HATED_1_ARRIVES ); break; case 1: TacticalCharacterDialogue( pTeamSoldier, QUOTE_HATED_2_ARRIVES ); break; case 2: TacticalCharacterDialogue( pTeamSoldier, QUOTE_HATED_3_ARRIVES ); break; case 3: TacticalCharacterDialogue( pTeamSoldier, QUOTE_HATED_4_ARRIVES ); break; case 4: TacticalCharacterDialogue( pTeamSoldier, QUOTE_HATED_5_ARRIVES ); break; default: break; } } } // Flugente: additional dialogue AdditionalTacticalCharacterDialogue_CallsLua( pTeamSoldier, ADE_MERC_ARRIVES, pSoldier->ubProfile, ( gubQuest[QUEST_DELIVER_LETTER] == QUESTINPROGRESS ) ? 1 : 0 ); } } } } #ifdef JA2TESTVERSION void SetFlagToForceHireMerc( BOOLEAN fForceHire ) { gForceHireMerc = fForceHire; } #endif UINT32 GetMercArrivalTimeOfDay( ) { UINT32 uiCurrHour; UINT32 uiMinHour; // Pick a time... // First get the current time of day..... uiCurrHour = GetWorldHour( ); // Subtract the min time for any arrival.... uiMinHour = uiCurrHour + MIN_FLIGHT_PREP_TIME; // OK, first check if we need to advance a whole day's time... // See if we have missed the last flight for the day... if ( ( uiCurrHour ) > 13 ) // ( > 1:00 pm - too bad ) { // 7:30 flight.... return( GetMidnightOfFutureDayInMinutes( 1 ) + MERC_ARRIVE_TIME_SLOT_1 ); } // Well, now we can handle flights all in one day.... // Find next possible flight if ( uiMinHour <= 7 ) { return( GetWorldDayInMinutes() + MERC_ARRIVE_TIME_SLOT_1 ); // 7:30 am } else if ( uiMinHour <= 13 ) { return( GetWorldDayInMinutes() + MERC_ARRIVE_TIME_SLOT_2 ); // 1:30 pm } else { return( GetWorldDayInMinutes() + MERC_ARRIVE_TIME_SLOT_3 ); // 7:30 pm } } void UpdateAnyInTransitMercsWithGlobalArrivalSector( ) { INT32 cnt; SOLDIERTYPE *pSoldier; cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // look for all mercs on the same team, for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pSoldier++) { if ( pSoldier->bActive ) { if ( pSoldier->bAssignment == IN_TRANSIT ) { if ( pSoldier->flags.fUseLandingZoneForArrival ) { pSoldier->sSectorX = gsMercArriveSectorX; pSoldier->sSectorY = gsMercArriveSectorY; pSoldier->bSectorZ = 0; } } } } } INT16 StrategicPythSpacesAway(INT16 sOrigin, INT16 sDest) { INT16 sRows,sCols,sResult; sRows = abs((sOrigin / MAP_WORLD_X) - (sDest / MAP_WORLD_X)); sCols = abs((sOrigin % MAP_WORLD_X) - (sDest % MAP_WORLD_X)); // apply Pythagoras's theorem for right-handed triangle: // dist^2 = rows^2 + cols^2, so use the square root to get the distance sResult = (INT16)sqrt((double)(sRows * sRows) + (sCols * sCols)); return(sResult); } // ATE: This function will check if the current arrival sector // is valid // if there are enemies present, it's invalid // if so, search around for nearest non-occupied sector. void CheckForValidArrivalSector( ) { INT16 sTop, sBottom; INT16 sLeft, sRight; INT16 cnt1, cnt2, sGoodX, sGoodY; UINT8 ubRadius = 4; UINT32 leftmost; UINT32 sSectorGridNo, sSectorGridNo2; INT32 uiRange, uiLowestRange = 999999; BOOLEAN fFound = FALSE; CHAR16 sString[ 1024 ]; CHAR16 zShortTownIDString1[ 50 ]; CHAR16 zShortTownIDString2[ 50 ]; sSectorGridNo = CALCULATE_STRATEGIC_INDEX( gsMercArriveSectorX, gsMercArriveSectorY ); // Check if valid... if ( !StrategicMap[ sSectorGridNo ].fEnemyControlled ) { return; } GetShortSectorString( gsMercArriveSectorX ,gsMercArriveSectorY, zShortTownIDString1 ); // If here - we need to do a search! sTop = ubRadius; sBottom = -ubRadius; sLeft = - ubRadius; sRight = ubRadius; for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ ) { leftmost = ( ( sSectorGridNo + ( MAP_WORLD_X * cnt1 ) )/ MAP_WORLD_X ) * MAP_WORLD_X; for( cnt2 = sLeft; cnt2 <= sRight; cnt2++ ) { sSectorGridNo2 = sSectorGridNo + ( MAP_WORLD_X * cnt1 ) + cnt2; if( sSectorGridNo2 >=1 && sSectorGridNo2 < ( ( MAP_WORLD_X - 1 ) * ( MAP_WORLD_X - 1 ) ) && sSectorGridNo2 >= leftmost && sSectorGridNo2 < ( leftmost + MAP_WORLD_X ) ) { if ( !StrategicMap[ sSectorGridNo2 ].fEnemyControlled && (StrategicMap[ sSectorGridNo2 ].usAirType & AIRSPACE_ENEMY_ACTIVE) ) { uiRange = StrategicPythSpacesAway( sSectorGridNo2, sSectorGridNo ); if ( uiRange < uiLowestRange ) { sGoodY = cnt1; sGoodX = cnt2; uiLowestRange = uiRange; fFound = TRUE; } } } } } if ( fFound ) { gsMercArriveSectorX = gsMercArriveSectorX + sGoodX; gsMercArriveSectorY = gsMercArriveSectorY + sGoodY; UpdateAnyInTransitMercsWithGlobalArrivalSector( ); GetShortSectorString( gsMercArriveSectorX ,gsMercArriveSectorY, zShortTownIDString2 ); // swprintf( sString, L"Arrival of new recruits is being rerouted to sector %s, as scheduled drop-off point of sector %s is enemy occupied.", zShortTownIDString2, zShortTownIDString1 ); swprintf( sString, New113Message[MSG113_ARRIVINGREROUTED], zShortTownIDString2, zShortTownIDString1 ); DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL ); } } #ifdef JA2UB UINT32 GetInitialHeliGridNo( ) { UINT8 ubCnt; UINT32 sGridNo; for( ubCnt=0; ubCnt 1000 ) fDone = TRUE; usCounter++; } return( 1000 + Random( 2000 ) ); } void InitializeHeliGridnoAndTime( BOOLEAN fLoading ) { Assert( NUM_INITIAL_GRIDNOS_FOR_HELI_CRASH == 7 ); if( !fLoading ) { gfFirstTimeInGameHeliCrash = FALSE; } gsInitialHeliGridNo[ 0 ] = gGameUBOptions.InitialHeliGridNo[ 0 ];//14947; gsInitialHeliGridNo[ 1 ] = gGameUBOptions.InitialHeliGridNo[ 1 ];//15584;//16067; gsInitialHeliGridNo[ 2 ] = gGameUBOptions.InitialHeliGridNo[ 2 ];//15754; gsInitialHeliGridNo[ 3 ] = gGameUBOptions.InitialHeliGridNo[ 3 ];//16232; gsInitialHeliGridNo[ 4 ] = gGameUBOptions.InitialHeliGridNo[ 4 ];//16067; gsInitialHeliGridNo[ 5 ] = gGameUBOptions.InitialHeliGridNo[ 5 ];//16230; gsInitialHeliGridNo[ 6 ] = gGameUBOptions.InitialHeliGridNo[ 6 ];//15272; gsInitialHeliRandomTimes[ 0 ] = gGameUBOptions.InitalHeliRandomTimes[ 0 ];//1300; gsInitialHeliRandomTimes[ 1 ] = gGameUBOptions.InitalHeliRandomTimes[ 1 ];//2000; gsInitialHeliRandomTimes[ 2 ] = gGameUBOptions.InitalHeliRandomTimes[ 2 ];//2750; gsInitialHeliRandomTimes[ 3 ] = gGameUBOptions.InitalHeliRandomTimes[ 3 ];//3400; gsInitialHeliRandomTimes[ 4 ] = gGameUBOptions.InitalHeliRandomTimes[ 4 ];//4160; gsInitialHeliRandomTimes[ 5 ] = gGameUBOptions.InitalHeliRandomTimes[ 5 ];//4700; gsInitialHeliRandomTimes[ 6 ] = gGameUBOptions.InitalHeliRandomTimes[ 6 ];//5630; } void InitJerryMiloInfo() { if ( gGameUBOptions.InJerry == TRUE ) { // return; //AA //Set Jerry Milo's Gridno h7 gMercProfiles[ JERRY_MILO_UB ].sSectorX = JA2_5_START_SECTOR_X; gMercProfiles[ JERRY_MILO_UB ].sSectorY = JA2_5_START_SECTOR_Y; gMercProfiles[ JERRY_MILO_UB ].bSectorZ = 0; gMercProfiles[ JERRY_MILO_UB ].sGridNo = gGameUBOptions.JerryGridNo; //15109; gMercProfiles[ JERRY_MILO_UB ].fUseProfileInsertionInfo = TRUE; gMercProfiles[ JERRY_MILO_UB ].ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; gMercProfiles[ JERRY_MILO_UB ].usStrategicInsertionData = gGameUBOptions.JerryGridNo; //15109; } if ( gGameUBOptions.InGameHeliCrash == TRUE ) { //init Jerry Milo quotes InitJerryQuotes(); } } void UpdateJerryMiloInInitialSector() { SOLDIERTYPE *pSoldier = NULL; SOLDIERTYPE *pJerrySoldier=NULL; //SectorInfo[ SEC_H7 ].fSurfaceWasEverPlayerControlled = TRUE; SectorInfo[ (UINT8)SECTOR( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY ) ].fSurfaceWasEverPlayerControlled = TRUE; //SectorInfo[ SEC_H7 ].ubNumAdmins = 2; StrategicMap[ (UINT8)SECTOR( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY ) ].fEnemyControlled = FALSE; if ( gGameUBOptions.InGameHeli == TRUE ) return; //AA if ( gGameUBOptions.InGameHeliCrash == TRUE ) { //if it is the first sector we are loading up, place Jerry in the map if( !gfFirstTimeInGameHeliCrash ) return; if ( gGameUBOptions.InJerry == TRUE ) { pSoldier = FindSoldierByProfileID( JERRY_MILO_UB, FALSE ); //JERRY if( pSoldier == NULL ) { Assert( 0 ); } } //the internet part of the laptop isnt working. It gets broken in the heli crash. if ( gGameUBOptions.LaptopQuestEnabled == TRUE ) StartQuest( QUEST_FIX_LAPTOP, -1, -1 ); //Record the initial sector as ours //SectorInfo[ SEC_H7 ].fSurfaceWasEverPlayerControlled = TRUE; SectorInfo[ (UINT8)SECTOR( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY ) ].fSurfaceWasEverPlayerControlled = TRUE; StrategicMap[ (UINT8)SECTOR( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY ) ].fEnemyControlled = FALSE; if ( gGameUBOptions.InJerry == TRUE ) { //Set some variable so Jerry will be on the ground pSoldier->fWaitingToGetupFromJA25Start = TRUE; pSoldier->fIgnoreGetupFromCollapseCheck = TRUE; //pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; //to było wyłączone //pSoldier->usStrategicInsertionData = GetInitialHeliGridNo( ); //to było wyłączone RESETTIMECOUNTER( pSoldier->GetupFromJA25StartCounter, gsInitialHeliRandomTimes[ 6 ] + 800 + Random( 400 ) ); //should we be on our back or tummy if( Random( 100 ) < 50 ) pSoldier->EVENT_InitNewSoldierAnim( STAND_FALLFORWARD_STOP, 1, TRUE ); else pSoldier->EVENT_InitNewSoldierAnim( FALLBACKHIT_STOP, 1, TRUE ); } //Wont work cause it gets reset every frame //make sure we can see Jerry if ( gGameUBOptions.InJerry == TRUE ) { pJerrySoldier = FindSoldierByProfileID(JERRY_MILO_UB, FALSE );//JERRY if( pJerrySoldier != NULL ) { //Make sure we can see the pilot gbPublicOpplist[OUR_TEAM][ pJerrySoldier->ubID ] = SEEN_CURRENTLY; pJerrySoldier->bVisible = TRUE; } } //Lock the interface guiPendingOverrideEvent = LU_BEGINUILOCK; } } void AddItemToMerc( UINT8 ubNewMerc, INT16 sItemType ) { // OK, give this item to our merc! OBJECTTYPE gTempObject; BOOLEAN fReturn=FALSE; // make an objecttype CreateItem(sItemType, 100, &gTempObject); // Give it fReturn = AutoPlaceObject( MercPtrs[ ubNewMerc ], &gTempObject, FALSE ); if(!fReturn && (UsingNewInventorySystem() == true)) { (MercPtrs[ubNewMerc]->inv[NUM_INV_SLOTS-1]) = gTempObject; fReturn=TRUE; } Assert( fReturn ); } #endif