Files
source/Strategic/Merc Contract.cpp
T

1635 lines
49 KiB
C++

#include "builddefines.h"
#include "types.h"
#include "Merc Contract.h"
#include "Soldier Profile.h"
#include "history.h"
#include "finances.h"
#include "Game Clock.h"
#include "Soldier Add.h"
#include "Dialogue Control.h"
#include "Soldier Create.h"
#include "message.h"
#include "Font Control.h"
#include "personnel.h"
#include "LaptopSave.h"
#include "Map Screen Interface.h"
#include "strategic.h"
#include "strategicmap.h"
#include "Quests.h"
#include "worlddef.h"
#include "Animation Control.h"
#include "Tactical Save.h"
#include "Interface Control.h"
#include "gamescreen.h"
#include "jascreens.h"
#include "random.h"
#include "Assignments.h"
#include "Strategic Movement.h"
#include "Squads.h"
#include "gameloop.h"
#include "Text.h"
#include "Strategic Status.h"
#include "mercs.h"
#include "insurance Contract.h"
#include "Vehicles.h"
#include "email.h"
#include "Map Screen Helicopter.h"
#include "GameSettings.h"
#include "connect.h"
#ifdef JA2UB
#include "ub_config.h"
#endif
void CalculateMedicalDepositRefund( SOLDIERTYPE *pSoldier );
void NotifyPlayerOfMercDepartureAndPromptEquipmentPlacement( SOLDIERTYPE *pSoldier, BOOLEAN fAddRehireButton );
void MercDepartEquipmentBoxCallBack( UINT8 bExitValue );
BOOLEAN HandleFiredDeadMerc( SOLDIERTYPE *pSoldier );
void HandleExtendMercsContract( SOLDIERTYPE *pSoldier );
void HandleSoldierLeavingWithLowMorale( SOLDIERTYPE *pSoldier );
void HandleBuddiesReactionToFiringMerc(SOLDIERTYPE *pFiredSoldier, INT8 bMoraleEvent );
void HandleSoldierLeavingForAnotherContract( SOLDIERTYPE *pSoldier );
//BOOLEAN SoldierWantsToDelayRenewalOfContract( SOLDIERTYPE *pSoldier );
void HandleNotifyPlayerCantAffordInsurance( void );
void HandleNotifyPlayerCanAffordInsurance( SOLDIERTYPE *pSoldier, UINT8 ubLength, INT32 iCost );
void ExtendMercInsuranceContractCallBack( UINT8 bExitValue );
void HandleUniqueEventWhenPlayerLeavesTeam( SOLDIERTYPE *pSoldier );
UINT32 uiContractTimeMode = 0;
SOLDIERTYPE *pLeaveSoldier = NULL;
BOOLEAN fEnterMapDueToContract = FALSE;
extern BOOLEAN fOneFrame;
extern BOOLEAN fPausedTimeDuringQuote;
UINT8 ubQuitType = 0;
BOOLEAN gfFirstMercSayQuote = FALSE;
extern BOOLEAN gfFirstMercSayingQuoteWillLeaveNoMatterWhat;
extern CHAR16 gzUserDefinedButton1[ 128 ];
extern CHAR16 gzUserDefinedButton2[ 128 ];
SOLDIERTYPE *pContractReHireSoldier = NULL;
UINT8 gubContractLength = 0; //used when extending a mercs insurance contract
SOLDIERTYPE *gpInsuranceSoldier=NULL;
// WDS - make number of mercenaries, etc. be configurable
// The values need to be saved!
std::vector<CONTRACT_NEWAL_LIST_NODE> ContractRenewalList (CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS);
UINT8 ubNumContractRenewals = 0;
// end
UINT8 ubCurrentContractRenewal = 0;
UINT8 ubCurrentContractRenewalInProgress = FALSE;
BOOLEAN gfContractRenewalSquenceOn = FALSE;
BOOLEAN gfInContractMenuFromRenewSequence = FALSE;
BOOLEAN SaveContractRenewalDataToSaveGameFile( HWFILE hFile )
{
UINT32 uiNumBytesWritten;
for (int idx=0; idx < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; idx++) {
FileWrite( hFile, &ContractRenewalList[idx], sizeof( CONTRACT_NEWAL_LIST_NODE ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( CONTRACT_NEWAL_LIST_NODE ) )
{
return( FALSE );
}
}
//FileWrite( hFile, ContractRenewalList, sizeof( ContractRenewalList ), &uiNumBytesWritten );
//if( uiNumBytesWritten != sizeof( ContractRenewalList ) )
//{
// return( FALSE );
//}
FileWrite( hFile, &ubNumContractRenewals, sizeof( ubNumContractRenewals ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( ubNumContractRenewals ) )
{
return( FALSE );
}
return( TRUE );
}
BOOLEAN LoadContractRenewalDataFromSaveGameFile( HWFILE hFile )
{
UINT32 uiNumBytesRead;
for (int idx=0; idx < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; idx++) {
FileRead( hFile, &ContractRenewalList[idx], sizeof( CONTRACT_NEWAL_LIST_NODE ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( CONTRACT_NEWAL_LIST_NODE ) )
{
return( FALSE );
}
}
//FileRead( hFile, ContractRenewalList, sizeof( ContractRenewalList ), &uiNumBytesRead );
//if( uiNumBytesRead != sizeof( ContractRenewalList ) )
//{
// return( FALSE );
//}
FileRead( hFile, &ubNumContractRenewals, sizeof( ubNumContractRenewals ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( ubNumContractRenewals ) )
{
return( FALSE );
}
return( TRUE );
}
void BeginContractRenewalSequence( )
{
INT32 cnt;
SOLDIERTYPE *pSoldier;
BOOLEAN fFoundAtLeastOne = FALSE;
if ( ubNumContractRenewals > 0)
{
for ( cnt = 0; cnt < ubNumContractRenewals; cnt++ )
{
// Get soldier - if there is none, adavance to next
pSoldier = FindSoldierByProfileID( ContractRenewalList[ cnt ].ubProfileID, FALSE ); // Steve Willis, 80
if ( pSoldier )
{
if( ( pSoldier->bActive == FALSE ) || ( pSoldier->stats.bLife == 0 ) || ( pSoldier->bAssignment == IN_TRANSIT ) ||( pSoldier->bAssignment == ASSIGNMENT_POW ) )
{
// no
continue;
}
// Double check there are valid people here that still want to renew...
//if the user hasnt renewed yet, and is still leaving today
if ( ContractIsExpiring( pSoldier ) )
{
fFoundAtLeastOne = TRUE;
}
}
}
if ( fFoundAtLeastOne )
{
// Set sequence on...
gfContractRenewalSquenceOn = TRUE;
// Start at first one....
ubCurrentContractRenewal = 0;
ubCurrentContractRenewalInProgress = 0;
PauseGame( );
LockPauseState( 7 );
InterruptTime( );
// Go into mapscreen if not already...
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_ENTER_MAPSCREEN,0,0,0,0,0 );
}
}
}
void HandleContractRenewalSequence( )
{
SOLDIERTYPE *pSoldier;
if ( gfContractRenewalSquenceOn )
{
// Should we stop now?
if ( ubCurrentContractRenewal == ubNumContractRenewals )
{
// Stop and clear any on list...
ubNumContractRenewals = 0;
gfContractRenewalSquenceOn = FALSE;
}
// Get soldier - if there is none, adavance to next
pSoldier = FindSoldierByProfileID( ContractRenewalList[ ubCurrentContractRenewal ].ubProfileID, FALSE ); // Steve Willis, 80
if ( pSoldier == NULL )
{
// Advance to next guy!
EndCurrentContractRenewal( );
return;
}
// OK, check if it's in progress...
if ( !ubCurrentContractRenewalInProgress )
{
// Double check contract situation....
if ( ContractIsExpiring( pSoldier ) )
{
// Set this one in motion!
ubCurrentContractRenewalInProgress = 1;
// Handle start here...
// Determine what quote to use....
if( !WillMercRenew( pSoldier, FALSE ) )
{
// OK, he does not want to renew.......
HandleImportantMercQuote( pSoldier, QUOTE_MERC_LEAVING_ALSUCO_SOON );
// Do special dialogue event...
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_CONTRACT_NOGO_TO_RENEW , pSoldier->ubID,0 ,0 ,0 ,0 );
}
else
{
// OK check what dialogue to play
// If we have not used this one before....
if ( pSoldier->ubContractRenewalQuoteCode == SOLDIER_CONTRACT_RENEW_QUOTE_NOT_USED )
{
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
HandleImportantMercQuote( pSoldier, QUOTE_CONTRACTS_OVER );
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
}
// Else if we have said 89 already......
else if ( pSoldier->ubContractRenewalQuoteCode == SOLDIER_CONTRACT_RENEW_QUOTE_89_USED )
{
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
HandleImportantMercQuote( pSoldier, QUOTE_MERC_LEAVING_ALSUCO_SOON );
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
}
// Do special dialogue event...
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_CONTRACT_WANTS_TO_RENEW , pSoldier->ubID,0 ,0 ,0 ,0 );
}
}
else
{
// Skip to next guy!
EndCurrentContractRenewal( );
}
}
}
}
void EndCurrentContractRenewal( )
{
// Are we in the requence?
if ( gfContractRenewalSquenceOn )
{
// OK stop this one and increment current one
ubCurrentContractRenewalInProgress = FALSE;
gfInContractMenuFromRenewSequence = FALSE;
ubCurrentContractRenewal++;
}
}
void HandleMercIsWillingToRenew( SoldierID ubID )
{
SOLDIERTYPE *pSoldier = ubID;
// We wish to lock interface
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1,MAP_SCREEN,0,0,0 );
CheckIfSalaryIncreasedAndSayQuote( pSoldier, FALSE );
// Setup variable for this....
gfInContractMenuFromRenewSequence = TRUE;
// Show contract menu
TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_SHOW_CONTRACT_MENU, 0,0 );
// Unlock now
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
}
void HandleMercIsNotWillingToRenew( SoldierID ubID )
{
SOLDIERTYPE *pSoldier = ubID;
// We wish to lock interface
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1,MAP_SCREEN,0,0,0 );
// Setup variable for this....
gfInContractMenuFromRenewSequence = TRUE;
// Show contract menu
TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_SHOW_CONTRACT_MENU, 0,0 );
// Unlock now
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
}
// This is used only to EXTEND the contract of an AIM merc already on the team
BOOLEAN MercContractHandling( SOLDIERTYPE *pSoldier, UINT8 ubDesiredAction )
{
INT32 iContractCharge=0;
INT32 iContractLength=0;
UINT8 ubHistoryContractType=0;
UINT8 ubFinancesContractType=0;
INT32 iCostOfInsurance = 0;
//determins what kind of merc the contract is being extended for (only aim mercs can extend contract)
if( pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
return(FALSE);
switch( ubDesiredAction )
{
case CONTRACT_EXTEND_1_DAY:
//check to see if the merc has enough money
iContractCharge = gMercProfiles[ pSoldier->ubProfile ].sSalary;
//set the contract length and the charge
iContractLength = 1;
ubHistoryContractType = HISTORY_EXTENDED_CONTRACT_1_DAY;
ubFinancesContractType = EXTENDED_CONTRACT_BY_1_DAY;
break;
case CONTRACT_EXTEND_1_WEEK:
iContractCharge = gMercProfiles[ pSoldier->ubProfile ].uiWeeklySalary;
//set the contract length and the charge
iContractLength = 7;
ubHistoryContractType = HISTORY_EXTENDED_CONTRACT_1_WEEK;
ubFinancesContractType = EXTENDED_CONTRACT_BY_1_WEEK;
break;
case CONTRACT_EXTEND_2_WEEK:
iContractCharge = gMercProfiles[ pSoldier->ubProfile ].uiBiWeeklySalary;
//set the contract length and the charge
iContractLength = 14;
ubHistoryContractType = HISTORY_EXTENDED_CONTRACT_2_WEEK;
ubFinancesContractType = EXTENDED_CONTRACT_BY_2_WEEKS;
break;
default:
return(FALSE);
break;
}
//check to see if the merc has enough money
if( LaptopSaveInfo.iCurrentBalance < iContractCharge )
return(FALSE);
//Check to see if merc will renew
if( !WillMercRenew( pSoldier, TRUE ) )
{
// Remove soldier.... ( if this is setup because normal contract ending dequence... )
if ( ContractIsExpiring( pSoldier ) )
{
TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_CONTRACT_ENDING, 1,0 );
}
return(FALSE);
}
fPausedTimeDuringQuote = TRUE;
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
//
// These calcs need to be done before Getting/Calculating the insurance costs
//
//set the contract length and the charge
pSoldier->iTotalContractLength += iContractLength;
// pSoldier->iTotalContractCharge = iContractCharge;
pSoldier->bTypeOfLastContract = ubDesiredAction;
//determine the end of the contract
pSoldier->iEndofContractTime += ( iContractLength * 1440 );
if( ( pSoldier->usLifeInsurance ) && ( pSoldier->bAssignment != ASSIGNMENT_POW ) ) // DEF: Removed cause they can extend a 1 day contract && ( iContractLength > 1 )
{
// check if player can afford insurance, if not, tell them
iCostOfInsurance = CalculateInsuranceContractCost( iContractLength, pSoldier->ubProfile );
HandleImportantMercQuote( pSoldier, QUOTE_ACCEPT_CONTRACT_RENEWAL );
if( iCostOfInsurance > LaptopSaveInfo.iCurrentBalance )
{
// no can afford
HandleNotifyPlayerCantAffordInsurance( );
// OK, handle ending of renew session
if ( gfInContractMenuFromRenewSequence )
{
EndCurrentContractRenewal( );
}
}
else
{
// can afford ask if they want it
HandleNotifyPlayerCanAffordInsurance( pSoldier, ( UINT8 )( iContractLength ), iCostOfInsurance );
}
}
else
{
// no need to query for life insurance
HandleImportantMercQuote( pSoldier, QUOTE_ACCEPT_CONTRACT_RENEWAL );
// OK, handle ending of renew session
if ( gfInContractMenuFromRenewSequence )
{
EndCurrentContractRenewal( );
}
}
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
// ATE: Setup when they can be signed again!
// If they are 2-weeks this can be extended
// otherwise don't change from current
if ( pSoldier->bTypeOfLastContract == CONTRACT_EXTEND_2_WEEK )
{
pSoldier->iTimeCanSignElsewhere = pSoldier->iEndofContractTime;
}
// ARM: Do not reset because of renewal! The quote is for early dismissal from *initial* time of hiring
// pSoldier->uiTimeOfLastContractUpdate = GetWorldTotalMin();
// ARM: Do not reset because of renewal! The deposit in the profile goes up when merc levels, but the one in the soldier
// structure must always reflect the deposit actually paid (which does NOT change when a merc levels).
// pSoldier->usMedicalDeposit = gMercProfiles[ pSoldier->ubProfile ].sMedicalDepositAmount;
//add an entry in the finacial page for the extending of the mercs contract
AddTransactionToPlayersBook( ubFinancesContractType, pSoldier->ubProfile, GetWorldTotalMin(), -iContractCharge );
//add an entry in the history page for the extending of the merc contract
AddHistoryToPlayersLog( ubHistoryContractType, pSoldier->ubProfile, GetWorldTotalMin(), pSoldier->sSectorX, pSoldier->sSectorY );
return( TRUE );
}
BOOLEAN WillMercRenew( SOLDIERTYPE *pSoldier, BOOLEAN fSayQuote )
{
UINT8 i;
UINT8 bMercID;
BOOLEAN fBuddyAround = FALSE;
BOOLEAN fUnhappy = FALSE;
UINT16 usBuddyQuote=0;
UINT16 usReasonQuote=0;
BOOLEAN fSayPrecedent = FALSE;
SOLDIERTYPE * pHated;
if( pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
return( FALSE );
// Flugente: an unconscious merc can't say 'yes' to a contract renewal
if ( pSoldier->stats.bLife < CONSCIOUSNESS )
return( FALSE );
// does the merc have another contract already lined up?
if( pSoldier->flags.fSignedAnotherContract )
{
// NOTE: Having a buddy around will NOT stop a merc from leaving on another contract (IC's call)
if( fSayQuote == TRUE )
{
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
HandleImportantMercQuote( pSoldier, QUOTE_WONT_RENEW_CONTRACT_LAME_REFUSAL );
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
}
return( FALSE );
}
// find out if the merc has a buddy working for the player
// loop through the list of people the merc considers buddies
for(i=0; i<6; i++)
{
if( i<5 )
{
bMercID = gMercProfiles[ pSoldier->ubProfile ].bBuddy[i];
}
else
{
bMercID = gMercProfiles[ pSoldier->ubProfile ].bLearnToLike;
// ignore learn to like, if he's not a buddy yet
if( gMercProfiles[ pSoldier->ubProfile ].bLearnToLikeCount > 0 )
continue;
}
if( bMercID < 0 )
continue;
// is this buddy on the team?
if( IsMercOnTeam( (UINT8) bMercID, FALSE, FALSE ) )
{
fBuddyAround = TRUE;
if( i == 0 )
usBuddyQuote = QUOTE_RENEWING_CAUSE_BUDDY_1_ON_TEAM;
else if( i == 1 )
usBuddyQuote = QUOTE_RENEWING_CAUSE_BUDDY_2_ON_TEAM;
else if( i == 2 )
usBuddyQuote = QUOTE_RENEWING_CAUSE_BUDDY_3_ON_TEAM;
else if( i == 3 )
usBuddyQuote = QUOTE_RENEWING_CAUSE_BUDDY_4_ON_TEAM;
else if( i == 4 )
usBuddyQuote = QUOTE_RENEWING_CAUSE_BUDDY_5_ON_TEAM;
else
usBuddyQuote = QUOTE_RENEWING_CAUSE_LEARNED_TO_LIKE_BUDDY_ON_TEAM;
// use first buddy in case there are multiple
break;
}
}
// WE CHECK FOR SOURCES OF UNHAPPINESS IN ORDER OF IMPORTANCE, which is:
// 1) Hated Mercs (Highest), 2) Death Rate, 3) Morale (lowest)
// see if someone the merc hates is on the team
// loop through the list of people the merc hates
for(i=0; i<5; i++)
{
bMercID = gMercProfiles[ pSoldier->ubProfile ].bHated[ i ];
if( bMercID < 0 )
continue;
if( IsMercOnTeam( (UINT8) bMercID, TRUE, TRUE ) )
{
if ( gMercProfiles[ pSoldier->ubProfile ].bHatedCount[ i ] == 0 )
{
// our tolerance has run out!
fUnhappy = TRUE;
}
else // else tolerance is > 0, only gripe if in same sector
{
pHated = FindSoldierByProfileID( bMercID, TRUE );
if ( pHated && pHated->sSectorX == pSoldier->sSectorX &&
pHated->sSectorY == pSoldier->sSectorY &&
pHated->bSectorZ == pSoldier->bSectorZ )
{
fUnhappy = TRUE;
}
}
if ( fUnhappy )
{
if( i == 0 )
usReasonQuote = QUOTE_HATED_1_ON_TEAM_WONT_RENEW;
else if( i == 1 )
usReasonQuote = QUOTE_HATED_2_ON_TEAM_WONT_RENEW;
else if( i == 2 )
usReasonQuote = QUOTE_HATED_3_ON_TEAM_WONT_RENEW;
else if( i == 3 )
usReasonQuote = QUOTE_HATED_4_ON_TEAM_WONT_RENEW;
else if( i == 4 )
usReasonQuote = QUOTE_HATED_5_ON_TEAM_WONT_RENEW;
// use first hated in case there are multiple
break;
}
}
}
if ( !fUnhappy )
{
// now check for learn to hate
bMercID = gMercProfiles[ pSoldier->ubProfile ].bLearnToHate;
if ( bMercID >= 0 )
{
if ( IsMercOnTeam( (UINT8) bMercID, TRUE, TRUE ) )
{
if ( gMercProfiles[ pSoldier->ubProfile ].bLearnToHateCount == 0 )
{
// our tolerance has run out!
fUnhappy = TRUE;
usReasonQuote = QUOTE_LEARNED_TO_HATE_ON_TEAM_WONT_RENEW;
}
else if ( gMercProfiles[ pSoldier->ubProfile ].bLearnToHateCount <= gMercProfiles[ pSoldier->ubProfile ].bLearnToHateTime / 2 )
{
pHated = FindSoldierByProfileID( bMercID, TRUE );
if ( pHated && pHated->sSectorX == pSoldier->sSectorX &&
pHated->sSectorY == pSoldier->sSectorY &&
pHated->bSectorZ == pSoldier->bSectorZ )
{
fUnhappy = TRUE;
usReasonQuote = QUOTE_LEARNED_TO_HATE_ON_TEAM_WONT_RENEW;
}
}
}
}
}
// happy so far?
if (!fUnhappy)
{
// check if death rate is too high
if( MercThinksDeathRateTooHigh( pSoldier->ubProfile ) )
{
fUnhappy = TRUE;
usReasonQuote = QUOTE_DEATH_RATE_RENEWAL;
}
}
// happy so far?
if (!fUnhappy)
{
// check if morale is too low
if( MercThinksHisMoraleIsTooLow( pSoldier ) )
{
fUnhappy = TRUE;
usReasonQuote = QUOTE_REFUSAL_RENEW_DUE_TO_MORALE;
}
}
// say the precedent?
fSayPrecedent = FALSE;
// check if we say the precdent for merc
if( fSayQuote )
{
if (fUnhappy)
{
if (fBuddyAround)
{
if( GetMercPrecedentQuoteBitStatus( pSoldier->ubProfile , GetQuoteBitNumberFromQuoteID( ( UINT32 ) ( usBuddyQuote ) ) ) == TRUE )
{
fSayPrecedent = TRUE;
}
else
{
SetMercPrecedentQuoteBitStatus( pSoldier->ubProfile , GetQuoteBitNumberFromQuoteID( ( UINT32 ) ( usBuddyQuote ) ) );
}
}
else
{
if( GetMercPrecedentQuoteBitStatus( pSoldier->ubProfile , GetQuoteBitNumberFromQuoteID( ( UINT32 ) ( usReasonQuote ) ) ) == TRUE )
{
fSayPrecedent = TRUE;
}
else
{
SetMercPrecedentQuoteBitStatus( pSoldier->ubProfile , GetQuoteBitNumberFromQuoteID( ( UINT32 ) ( usReasonQuote ) ) );
}
}
}
}
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
if( fSayPrecedent )
{
HandleImportantMercQuote( pSoldier, QUOTE_PRECEDENT_TO_REPEATING_ONESELF_RENEW );
}
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
// OK, we got all our info, let's make some decisions!
if (fUnhappy)
{
if (fBuddyAround)
{
// unhappy, but buddy's around, so will agree to renew, but tell us why we're doing it
if( fSayQuote == TRUE )
{
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1,MAP_SCREEN,0,0,0 );
HandleImportantMercQuote( pSoldier, usBuddyQuote);
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0,MAP_SCREEN,0,0,0 );
}
return( TRUE );
}
else
{
// unhappy, no buddies, will refuse to renew
if( fSayQuote == TRUE )
{
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
/* ARM: Delay quote too vague, no longer to be used
if( ( SoldierWantsToDelayRenewalOfContract( pSoldier ) ) )
{
// has a new job lined up
HandleImportantMercQuote( pSoldier, QUOTE_DELAY_CONTRACT_RENEWAL );
}
else
*/
{
Assert( usReasonQuote != 0 );
HandleImportantMercQuote( pSoldier, usReasonQuote );
}
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
}
return(FALSE);
}
}
else
{
// happy, no problem
return( TRUE );
}
}
void HandleBuddiesReactionToFiringMerc(SOLDIERTYPE *pFiredSoldier, INT8 bMoraleEvent )
{
SoldierID bMercID = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
SoldierID bLastTeamID = gTacticalStatus.Team[ gbPlayerNum ].bLastID;
// loop through all mercs to find buddies
for ( ; bMercID <= bLastTeamID; ++bMercID)
{
SOLDIERTYPE *pSoldier = bMercID;
//if the merc is active, in Arulco, not POW and is a buddy
if ( WhichBuddy(pSoldier->ubProfile,pFiredSoldier->ubProfile) != (-1) &&
pSoldier->bActive && pSoldier->ubProfile != NO_PROFILE &&
!(pSoldier->bAssignment == IN_TRANSIT ||
pSoldier->bAssignment == ASSIGNMENT_DEAD ||
pSoldier->bAssignment == ASSIGNMENT_POW) )
{
HandleMoraleEvent(pSoldier, bMoraleEvent, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ);
}
}
}
void HandleSoldierLeavingWithLowMorale( SOLDIERTYPE *pSoldier )
{
if( MercThinksHisMoraleIsTooLow( pSoldier ) )
{
// this will cause him give us lame excuses for a while until he gets over it
// 3-6 days (but the first 1-2 days of that are spent "returning" home)
gMercProfiles[ pSoldier->ubProfile ].ubDaysOfMoraleHangover = (UINT8) (3 + Random(4));
// piss off his buddies too
HandleBuddiesReactionToFiringMerc(pSoldier, MORALE_BUDDY_FIRED_ON_BAD_TERMS);
}
}
void HandleSoldierLeavingForAnotherContract( SOLDIERTYPE *pSoldier )
{
if (pSoldier->flags.fSignedAnotherContract)
{
// merc goes to work elsewhere
gMercProfiles[ pSoldier->ubProfile ].bMercStatus = MERC_WORKING_ELSEWHERE;
gMercProfiles[ pSoldier->ubProfile ].uiDayBecomesAvailable += 1 + Random(6 + (pSoldier->stats.bExpLevel / 2) ); // 1-(6 to 11) days
}
}
/*
BOOLEAN SoldierWantsToDelayRenewalOfContract( SOLDIERTYPE *pSoldier )
{
INT8 bTypeOfCurrentContract = 0; // what kind of contract the merc has..1 day, week or 2 week
INT32 iLeftTimeOnContract = 0; // how much time til contract expires..in minutes
INT32 iToleranceLevelForContract = 0; // how much time before contract ends before merc actually speaks thier mind
// does the soldier want to delay renew of contract, possibly due to poor performance by player
if( pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
return( FALSE );
// type of contract the merc had
bTypeOfCurrentContract = pSoldier->bTypeOfLastContract;
iLeftTimeOnContract = pSoldier->iEndofContractTime - GetWorldTotalMin();
// grab tolerance
switch( bTypeOfCurrentContract )
{
case( CONTRACT_EXTEND_1_DAY ):
// 20 hour tolerance on 24 hour contract
iToleranceLevelForContract = 20 * 60;
break;
case( CONTRACT_EXTEND_1_WEEK ):
// two day tolerance for 1 week
iToleranceLevelForContract = 2 * 24 * 60;
break;
case( CONTRACT_EXTEND_2_WEEK ):
// three day on 2 week contract
iToleranceLevelForContract = 3 * 24 * 60;
break;
}
if( iLeftTimeOnContract > iToleranceLevelForContract )
{
return( TRUE );
}
else
{
return( FALSE );
}
}
*/
// this is called once a day (daily update) for every merc working for the player
void CheckIfMercGetsAnotherContract( SOLDIERTYPE *pSoldier )
{
UINT32 uiFullDaysRemaining = 0;
INT32 iChance = 0;
// aim merc?
if( pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
return;
// ATE: check time we have and see if we can accept new contracts....
if ( GetWorldTotalMin() <= (UINT32) pSoldier->iTimeCanSignElsewhere )
{
return;
}
// if he doesn't already have another contract
if (!pSoldier->flags.fSignedAnotherContract)
{
// chance depends on how much time he has left in his contract, and his experience level (determines demand)
uiFullDaysRemaining = (pSoldier->iEndofContractTime - GetWorldTotalMin()) / (24 * 60);
if (uiFullDaysRemaining == 0)
{
// less than a full day left on contract
// calc the chance merc will get another contract while working for ya (this is rolled once/day)
iChance = 3;
}
else
if (uiFullDaysRemaining == 1)
{
// < 2 days left
iChance = 2;
}
else
if (uiFullDaysRemaining == 2)
{
// < 3 days left
iChance = 1;
}
else
{
// 3+ days
iChance = 0;
}
// multiply by experience level
iChance *= pSoldier->stats.bExpLevel;
//tais: disabled mercs going on other assignment after being fired..
if( (INT32) Random( 100 ) < iChance && gGameExternalOptions.fMercsOnAssignment < 2 )
{
// B'bye!
pSoldier->flags.fSignedAnotherContract = TRUE;
}
}
}
//for ubRemoveType pass in the enum from the .h, ( MERC_QUIT, MERC_FIRED )
BOOLEAN BeginStrategicRemoveMerc( SOLDIERTYPE *pSoldier, BOOLEAN fAddRehireButton )
{
InterruptTime( );
PauseGame();
LockPauseState( 8 );
//if the soldier may have some special action when he/she leaves the party, handle it
HandleUniqueEventWhenPlayerLeavesTeam( pSoldier );
// IF the soldier is an EPC, don't ask about equipment
if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__EPC )
{
UnEscortEPC( pSoldier );
}
else
{
if (!is_networked)
NotifyPlayerOfMercDepartureAndPromptEquipmentPlacement( pSoldier, fAddRehireButton );
else
{
// WANNE - MP: Skip all the dialog boxes that appear. Just dismiss the merc
StrategicRemoveMerc( pSoldier );
pLeaveSoldier = NULL;
}
}
return( TRUE );
}
BOOLEAN StrategicRemoveMerc( SOLDIERTYPE *pSoldier )
{
UINT8 ubHistoryCode=0;
if ( gfInContractMenuFromRenewSequence )
{
EndCurrentContractRenewal( );
}
// Flugente: if this is Buns alternate personality, change her back.
// This way we don't have to deal with her transformation while she is absent (and we don't need additional laptop soundfiles).
if ( pSoldier->ubProfile == BUNS_CHAOTIC )
{
gMercProfiles[BUNS].bNPCData = 0;
SwapToProfile( pSoldier, BUNS );
}
// anv: let buddies react
HandleBuddiesReactionToFiringMerc(pSoldier, MORALE_BUDDY_FIRED);
// ATE: Determine which HISTORY ENTRY to use...
if ( pSoldier->ubLeaveHistoryCode == 0 )
{
// Default use contract expired reason...
pSoldier->ubLeaveHistoryCode = HISTORY_MERC_CONTRACT_EXPIRED;
}
ubHistoryCode = pSoldier->ubLeaveHistoryCode;
//if the soldier is DEAD
if( pSoldier->stats.bLife <= 0 )
{
AddCharacterToDeadList( pSoldier );
}
//else if the merc was fired
else if( ubHistoryCode == HISTORY_MERC_FIRED || pSoldier->bAssignment == ASSIGNMENT_POW )
{
AddCharacterToFiredList( pSoldier );
}
//The merc is leaving for some other reason
else
{
AddCharacterToOtherList( pSoldier );
}
if( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__NPC )
{
SetupProfileInsertionDataForSoldier( pSoldier );
}
if (IsVehicle(pSoldier))
{
// for some reason, vehicles have their own idea of handling group ids
RemovePlayerFromGroup(pVehicleList[ pSoldier->bVehicleID ].ubMovementGroup, pSoldier);
}
//remove him from the soldier structure
if( pSoldier->bAssignment >= ON_DUTY )
{
// is he/she in a mvt group, if so, remove and destroy the group
if( pSoldier->ubGroupID )
{
// anv: dead people are on "dead" assignment even if they were in vehicle pre-mortem, check flags too
if( ( pSoldier->bAssignment != VEHICLE ) && !( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) )
//if ( pSoldier->bAssignment != VEHICLE )
{ //Can only remove groups if they aren't persistant (not in a squad or vehicle)
RemovePlayerFromGroup(pSoldier->ubGroupID, pSoldier);
}
else
{
// remove him from any existing merc slot he could be in
RemoveMercSlot( pSoldier );
TakeSoldierOutOfVehicle( pSoldier );
}
}
}
else
{
RemoveCharacterFromSquads( pSoldier );
}
// if the merc is not dead
if( gMercProfiles[ pSoldier->ubProfile ].bMercStatus != MERC_IS_DEAD )
{
//shadooow: this allows RPCs to re-appear in the areas we recruited them initially after being fired
if (pSoldier->ubProfile != SLAY || gGameExternalOptions.fEnableSlayForever)
{
gMercProfiles[pSoldier->ubProfile].ubMiscFlags &= (~PROFILE_MISC_FLAG_RECRUITED);
}
//Set the status to returning home ( delay the merc for rehire )
gMercProfiles[ pSoldier->ubProfile ].bMercStatus = MERC_RETURNING_HOME;
// specify how long the merc will continue to be unavailable
gMercProfiles[ pSoldier->ubProfile ].uiDayBecomesAvailable = 1 + Random(2); // 1-2 days
HandleSoldierLeavingWithLowMorale( pSoldier );
HandleSoldierLeavingForAnotherContract( pSoldier );
}
//add an entry in the history page for the firing/quiting of the merc
// ATE: Don't do this if they are already dead!
if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_DEAD ) )
{
AddHistoryToPlayersLog( ubHistoryCode, pSoldier->ubProfile, GetWorldTotalMin(), pSoldier->sSectorX, pSoldier->sSectorY );
}
//if the merc was a POW, remember it becuase the merc cant show up in AIM or MERC anymore
if( pSoldier->bAssignment == ASSIGNMENT_POW )
{
gMercProfiles[ pSoldier->ubProfile ].bMercStatus = MERC_FIRED_AS_A_POW;
}
//else the merc CAN get his medical deposit back
else
{
//Determine how much of a Medical deposit is going to be refunded to the player
CalculateMedicalDepositRefund( pSoldier );
}
//remove the merc from the tactical
TacticalRemoveSoldier( pSoldier->ubID );
// Check if we should remove loaded world...
CheckAndHandleUnloadingOfCurrentWorld();
if ( guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN )
{
ReBuildCharactersList( );
}
fMapPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
// stop time compression so player can react to the departure
StopTimeCompression();
// WDS: This allows for replacing dead IMP mercs. See "BtnIMPBeginScreenDoneCallback" in "IMP Begin Screen.cpp"
if( ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER ) &&
( gMercProfiles[ pSoldier->ubProfile ].bMercStatus == MERC_IS_DEAD ) ) {
// Replace the name with an empty string
wcsncpy( gMercProfiles[ pSoldier->ubProfile ].zName, L"", 1 );
}
// ATE: update team panels....
UpdateTeamPanelAssignments( );
// And unpause the @#$@#$ interface
UnLockPauseState();
UnPauseGame();
if (is_client)
send_dismiss(pSoldier->ubID);
return( TRUE );
}
void CalculateMedicalDepositRefund( SOLDIERTYPE *pSoldier )
{
INT32 iRefundAmount=0;
//if the merc didnt have any medical deposit, exit
if( !gMercProfiles[ pSoldier->ubProfile ].bMedicalDeposit )
return;
//if the merc is at full health, refund the full medical deposit
if( pSoldier->stats.bLife == pSoldier->stats.bLifeMax )
{
//add an entry in the finacial page for the FULL refund of the medical deposit
// use the medical deposit in pSoldier, not in profile, which goes up with leveling
AddTransactionToPlayersBook(FULL_MEDICAL_REFUND, pSoldier->ubProfile, GetWorldTotalMin(), pSoldier->usMedicalDeposit );
//add an email
#ifdef JA2UB
//no UB
if( gubQuest[ QUEST_FIX_LAPTOP ] == QUESTDONE || gGameUBOptions.LaptopQuestEnabled == FALSE )
{
if ( gGameUBOptions.fDeadMerc == TRUE )
AddEmailWithSpecialData( 27, AIM_MEDICAL_DEPOSIT_REFUND_LENGTH, AIM_SITE, GetWorldTotalMin(), pSoldier->usMedicalDeposit, pSoldier->ubProfile, TYPE_EMAIL_DEAD_MERC_AIM_SITE_EMAIL_JA2_EDT, TYPE_E_AIM_L2 );
}
#else
AddEmailWithSpecialData( AIM_MEDICAL_DEPOSIT_REFUND, AIM_MEDICAL_DEPOSIT_REFUND_LENGTH, AIM_SITE, GetWorldTotalMin(), pSoldier->usMedicalDeposit, pSoldier->ubProfile, TYPE_EMAIL_EMAIL_EDT, TYPE_E_NONE );
#endif
}
//else if the merc is a dead, refund NOTHING!!
else if( pSoldier->stats.bLife <= 0 )
{
//add an entry in the finacial page for NO refund of the medical deposit
//AddTransactionToPlayersBook( NO_MEDICAL_REFUND, pSoldier->ubProfile, GetWorldTotalMin(), 0 );
//add an email
#ifdef JA2UB
//no UB
if( gubQuest[ QUEST_FIX_LAPTOP ] == QUESTDONE || gGameUBOptions.LaptopQuestEnabled == FALSE )
{
if ( gGameUBOptions.fDeadMerc == TRUE )
AddEmailWithSpecialData( 217, AIM_MEDICAL_DEPOSIT_NO_REFUND_LENGTH, AIM_SITE, GetWorldTotalMin(), pSoldier->usMedicalDeposit, pSoldier->ubProfile, TYPE_EMAIL_DEAD_MERC_AIM_SITE_EMAIL_JA2_EDT, TYPE_E_AIM_L3 );
}
#else
AddEmailWithSpecialData( AIM_MEDICAL_DEPOSIT_NO_REFUND, AIM_MEDICAL_DEPOSIT_NO_REFUND_LENGTH, AIM_SITE, GetWorldTotalMin(), pSoldier->usMedicalDeposit, pSoldier->ubProfile, TYPE_EMAIL_EMAIL_EDT, TYPE_E_NONE );
#endif
}
//else the player is injured, refund a partial amount
else
{
// use the medical deposit in pSoldier, not in profile, which goes up with leveling
iRefundAmount = (INT32) ( ( pSoldier->stats.bLife / ( FLOAT ) pSoldier->stats.bLifeMax ) * pSoldier->usMedicalDeposit + 0.5 );
//add an entry in the finacial page for a PARTIAL refund of the medical deposit
AddTransactionToPlayersBook( PARTIAL_MEDICAL_REFUND, pSoldier->ubProfile, GetWorldTotalMin(), iRefundAmount );
//add an email
#ifdef JA2UB
// no UB
if( gubQuest[ QUEST_FIX_LAPTOP ] == QUESTDONE || gGameUBOptions.LaptopQuestEnabled == FALSE )
{
if ( gGameUBOptions.fDeadMerc == TRUE )
AddEmailWithSpecialData( 214, AIM_MEDICAL_DEPOSIT_PARTIAL_REFUND_LENGTH, AIM_SITE, GetWorldTotalMin(), iRefundAmount, pSoldier->ubProfile, TYPE_EMAIL_DEAD_MERC_AIM_SITE_EMAIL_JA2_EDT, TYPE_E_AIM_L4 );
}
#else
AddEmailWithSpecialData( AIM_MEDICAL_DEPOSIT_PARTIAL_REFUND, AIM_MEDICAL_DEPOSIT_PARTIAL_REFUND_LENGTH, AIM_SITE, GetWorldTotalMin(), iRefundAmount, pSoldier->ubProfile, TYPE_EMAIL_EMAIL_EDT, TYPE_E_NONE );
#endif
}
}
void NotifyPlayerOfMercDepartureAndPromptEquipmentPlacement( SOLDIERTYPE *pSoldier, BOOLEAN fAddRehireButton )
{
// will tell player this character is leaving and ask where they want the equipment left
CHAR16 sString[ 1024 ];
BOOLEAN fInSector = FALSE;
// INT16 zTownIDString[50];
CHAR16 zShortTownIDString[ 50 ], zShortDropOffString[ 50 ], zDropOffString[ 50 ];
// use YES/NO Pop up box, settup for particular screen
SGPRect pCenteringRect= {0 + xResOffset, 0 + yResOffset, SCREEN_WIDTH - xResOffset, SCREEN_HEIGHT - yResOffset};
//GetSectorIDString( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ, zTownIDString, TRUE );
GetShortSectorString( pSoldier->sSectorX ,pSoldier->sSectorY, zShortTownIDString );
// Set string for generic button
swprintf( gzUserDefinedButton1, L"%s", zShortTownIDString );
pLeaveSoldier = pSoldier;
if( pSoldier->flags.fSignedAnotherContract == TRUE )
{
fAddRehireButton = FALSE;
}
if( pSoldier->flags.fSignedAnotherContract == TRUE )
{
fAddRehireButton = FALSE;
}
if( pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
{
fAddRehireButton = FALSE;
}
//if the character is an RPC
if ( gMercProfiles[pSoldier->ubProfile].Type == PROFILETYPE_RPC )
{
if( gMercProfiles[ pSoldier->ubProfile ].bSex == MALE )
{
swprintf( sString, pMercHeLeaveString[ 1 ], pSoldier->GetName(), zShortTownIDString );
}
else
{
swprintf( sString, pMercSheLeaveString[ 1 ], pSoldier->GetName(), zShortTownIDString );
}
fInSector = TRUE;
}
// check if drassen controlled
else if( StrategicMap[CALCULATE_STRATEGIC_INDEX( AIRPORT_X, AIRPORT_Y )].fEnemyControlled == FALSE )
{
GetSectorIDString( AIRPORT_X, AIRPORT_Y, 0, zDropOffString, FALSE );
if( ( pSoldier->sSectorX == AIRPORT_X ) && ( pSoldier->sSectorY == AIRPORT_Y ) && ( pSoldier->bSectorZ == 0 ) )
{
if( gMercProfiles[ pSoldier->ubProfile ].bSex == MALE )
{
swprintf( sString, pMercHeLeaveString[ 1 ], pSoldier->GetName(), zDropOffString );
}
else
{
swprintf( sString, pMercSheLeaveString[ 1 ], pSoldier->GetName(), zDropOffString );
}
fInSector = TRUE;
}
else
{
// Set string for generic button
GetShortSectorString( AIRPORT_X, AIRPORT_Y, zShortDropOffString );
swprintf( gzUserDefinedButton2, L"%s", zShortDropOffString ); //B13
if( gMercProfiles[ pSoldier->ubProfile ].bSex == MALE )
{
swprintf( sString, pMercHeLeaveString[ 0 ], pSoldier->GetName(), zShortTownIDString, zDropOffString );
}
else
{
swprintf( sString, pMercSheLeaveString[ 0 ], pSoldier->GetName(), zShortTownIDString, zDropOffString );
}
}
}
else
{
GetSectorIDString( OMERTA_LEAVE_EQUIP_SECTOR_X, OMERTA_LEAVE_EQUIP_SECTOR_Y, 0, zDropOffString, FALSE );
if( ( pSoldier->sSectorX == OMERTA_LEAVE_EQUIP_SECTOR_X ) && ( pSoldier->sSectorY == OMERTA_LEAVE_EQUIP_SECTOR_Y ) && ( pSoldier->bSectorZ == 0 ) )
{
if( gMercProfiles[ pSoldier->ubProfile ].bSex == MALE )
{
swprintf( sString, pMercHeLeaveString[ 1 ], pSoldier->GetName(), zDropOffString );
}
else
{
swprintf( sString, pMercSheLeaveString[ 1 ], pSoldier->GetName() , zDropOffString );
}
fInSector = TRUE;
}
else
{
// Set string for generic button
GetShortSectorString( OMERTA_LEAVE_EQUIP_SECTOR_X, OMERTA_LEAVE_EQUIP_SECTOR_Y, zShortDropOffString );
swprintf( gzUserDefinedButton2, L"%s", zShortDropOffString ); //A9
if( gMercProfiles[ pSoldier->ubProfile ].bSex == MALE )
{
swprintf( sString, pMercHeLeaveString[ 0 ], pSoldier->GetName(), zShortTownIDString, zDropOffString );
}
else
{
swprintf( sString, pMercSheLeaveString[ 0 ], pSoldier->GetName(), zShortTownIDString, zDropOffString );
}
}
}
/// which screen are we in?
if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
{
if( fInSector == FALSE )
{
// set up for mapscreen
DoMapMessageBox( MSG_BOX_BASIC_STYLE, sString, MAP_SCREEN, ( UINT16 )( ( fAddRehireButton ? MSG_BOX_FLAG_GENERICCONTRACT : MSG_BOX_FLAG_GENERIC_TWO_BUTTONS ) ), MercDepartEquipmentBoxCallBack );
}
else
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, sString, MAP_SCREEN, ( UINT16 )( ( fAddRehireButton ? MSG_BOX_FLAG_OKCONTRACT : MSG_BOX_FLAG_OK ) ), MercDepartEquipmentBoxCallBack );
}
}
else
{
if( fInSector == FALSE )
{
// set up for all otherscreens
DoMessageBox( MSG_BOX_BASIC_STYLE, sString, guiCurrentScreen, ( UINT16 ) ( MSG_BOX_FLAG_USE_CENTERING_RECT | ( fAddRehireButton ? MSG_BOX_FLAG_GENERICCONTRACT : MSG_BOX_FLAG_GENERIC_TWO_BUTTONS ) ), MercDepartEquipmentBoxCallBack, &pCenteringRect );
}
else
{
DoMessageBox( MSG_BOX_BASIC_STYLE, sString, guiCurrentScreen, ( UINT16 ) ( MSG_BOX_FLAG_USE_CENTERING_RECT | ( fAddRehireButton ? MSG_BOX_FLAG_OKCONTRACT : MSG_BOX_FLAG_OK ) ) , MercDepartEquipmentBoxCallBack, &pCenteringRect );
}
}
if( pSoldier->flags.fSignedAnotherContract == TRUE )
{
//fCurrentMercFired = FALSE;
}
}
void MercDepartEquipmentBoxCallBack( UINT8 bExitValue )
{
// gear left in current sector?
if( pLeaveSoldier == NULL )
{
return;
}
if( bExitValue == MSG_BOX_RETURN_OK )
{
// yep (NOTE that this passes the SOLDIER index, not the PROFILE index as the others do)
HandleLeavingOfEquipmentInCurrentSector( pLeaveSoldier->ubID );
// aim merc will say goodbye when leaving
if( ( pLeaveSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) && ( ubQuitType != HISTORY_MERC_FIRED ) )
{
// TacticalCharacterDialogue( pLeaveSoldier, QUOTE_MERC_LEAVING_ALSUCO_SOON );
}
}
else if( bExitValue == MSG_BOX_RETURN_CONTRACT )
{
HandleExtendMercsContract( pLeaveSoldier );
UnLockPauseState();
return;
}
else if( bExitValue == MSG_BOX_RETURN_YES )
{
// yep (NOTE that this passes the SOLDIER index, not the PROFILE index as the others do)
HandleLeavingOfEquipmentInCurrentSector( pLeaveSoldier->ubID );
// aim merc will say goodbye when leaving
if( ( pLeaveSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) && ( ubQuitType != HISTORY_MERC_FIRED ) )
{
// TacticalCharacterDialogue( pLeaveSoldier, QUOTE_MERC_LEAVING_ALSUCO_SOON );
}
}
else
{
// no
if( StrategicMap[CALCULATE_STRATEGIC_INDEX( AIRPORT_X, AIRPORT_Y )].fEnemyControlled == FALSE )
{
HandleMercLeavingEquipmentInDrassen( pLeaveSoldier->ubID );
}
else
{
HandleMercLeavingEquipmentInOmerta( pLeaveSoldier->ubID );
}
}
StrategicRemoveMerc( pLeaveSoldier );
pLeaveSoldier = NULL;
return;
}
BOOLEAN HandleFiredDeadMerc( SOLDIERTYPE *pSoldier )
{
AddCharacterToDeadList( pSoldier );
return( TRUE );
}
void HandleExtendMercsContract( SOLDIERTYPE *pSoldier )
{
if ( !(guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
{
gfEnteringMapScreen = TRUE;
fEnterMapDueToContract = TRUE;
pContractReHireSoldier = pSoldier;
LeaveTacticalScreen( MAP_SCREEN );
uiContractTimeMode = TIME_COMPRESS_5MINS;
}
else
{
FindAndSetThisContractSoldier( pSoldier );
pContractReHireSoldier = pSoldier;
uiContractTimeMode = giTimeCompressMode;
}
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE, 1, MAP_SCREEN, 0, 0, 0 );
CheckIfSalaryIncreasedAndSayQuote( pSoldier, TRUE );
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE, 0 ,MAP_SCREEN, 0, 0, 0 );
return;
}
void FindOutIfAnyMercAboutToLeaveIsGonnaRenew( void )
{
// find out is something was said
SOLDIERTYPE *pSoldier = NULL, *pSoldierWhoWillQuit = NULL;
INT32 iCounter= 0, iNumberOnTeam = 0;
// WDS - make number of mercenaries, etc. be configurable
SoldierID ubPotentialMercs[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ] = { 0 };
UINT16 ubNumMercs = 0;
UINT16 ubChosenMerc;
gfFirstMercSayQuote = FALSE;
pSoldier = &Menptr[ 0 ];
iNumberOnTeam =gTacticalStatus.Team[ OUR_TEAM ].bLastID;
// run through list of grunts whoose contract are up in the next 2 hours
// ATE: AND - build list THEN choose one!
// What we will do here is make a list of mercs that will want
// to stay if offered. Durning that process, also check if there
// is any merc that does not want to stay and only display that quote
// if they are the only one here....
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
{
pSoldier = &Menptr[ iCounter ];
// valid soldier?
if( ( pSoldier->bActive == FALSE ) || ( pSoldier->stats.bLife == 0 ) || ( pSoldier->bAssignment == IN_TRANSIT ) ||( pSoldier->bAssignment == ASSIGNMENT_POW ) )
{
// no
continue;
}
if( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC )
{
//if the user hasnt renewed yet, and is still leaving today
if ( ContractIsGoingToExpireSoon( pSoldier ) )
{
// OK, default value for quote said
pSoldier->ubContractRenewalQuoteCode = SOLDIER_CONTRACT_RENEW_QUOTE_NOT_USED;
// Add this guy to the renewal list
ContractRenewalList[ ubNumContractRenewals ].ubProfileID = pSoldier->ubProfile;
ubNumContractRenewals++;
if( WillMercRenew( pSoldier, FALSE ) )
{
ubPotentialMercs[ ubNumMercs ] = pSoldier->ubID;
ubNumMercs++;
}
else
{
pSoldierWhoWillQuit = pSoldier;
}
// Add to list!
AddSoldierToWaitingListQueue( pSoldier );
}
}
else
{
if( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__MERC )
{
// Do nothing here for now...
}
}
}
// OK, check if we should display line for the guy who does not want
// to stay
if ( ubNumMercs == 0 && pSoldierWhoWillQuit != NULL )
{
// OK, he does not want to renew.......
HandleImportantMercQuote( pSoldierWhoWillQuit, QUOTE_MERC_LEAVING_ALSUCO_SOON );
AddReasonToWaitingListQueue( CONTRACT_EXPIRE_WARNING_REASON );
TacticalCharacterDialogueWithSpecialEvent( pSoldierWhoWillQuit, 0, DIALOGUE_SPECIAL_EVENT_SHOW_UPDATE_MENU, 0,0 );
pSoldierWhoWillQuit->ubContractRenewalQuoteCode = SOLDIER_CONTRACT_RENEW_QUOTE_115_USED;
}
else
{
// OK, pick one....
if ( ubNumMercs > 0 )
{
ubChosenMerc = (UINT16)Random( ubNumMercs );
SOLDIERTYPE *pChosenSoldier = ubPotentialMercs[ubChosenMerc];
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
HandleImportantMercQuote( pChosenSoldier, QUOTE_CONTRACTS_OVER );
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
AddReasonToWaitingListQueue( CONTRACT_EXPIRE_WARNING_REASON );
TacticalCharacterDialogueWithSpecialEvent( pChosenSoldier, 0, DIALOGUE_SPECIAL_EVENT_SHOW_UPDATE_MENU, 0,0 );
pChosenSoldier->ubContractRenewalQuoteCode = SOLDIER_CONTRACT_RENEW_QUOTE_89_USED;
}
}
}
void HandleNotifyPlayerCantAffordInsurance( void )
{
DoScreenIndependantMessageBox( zMarksMapScreenText[ 9 ], MSG_BOX_FLAG_OK, NULL );
}
void HandleNotifyPlayerCanAffordInsurance( SOLDIERTYPE *pSoldier, UINT8 ubLength, INT32 iCost )
{
CHAR16 sString[ 128 ];
swprintf( sString, zMarksMapScreenText[ 10 ], pSoldier->GetName(), FormatMoney(iCost).data(), ubLength );
//Set the length to the global variable ( so we know how long the contract is in the callback )
gubContractLength = ubLength;
gpInsuranceSoldier = pSoldier;
//Remember the soldier aswell
pContractReHireSoldier = pSoldier;
// now pop up the message box
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_YESNO, ExtendMercInsuranceContractCallBack );
return;
}
void ExtendMercInsuranceContractCallBack( UINT8 bExitValue )
{
if( bExitValue == MSG_BOX_RETURN_YES )
{
PurchaseOrExtendInsuranceForSoldier( gpInsuranceSoldier, gubContractLength );
}
// OK, handle ending of renew session
if ( gfInContractMenuFromRenewSequence )
{
EndCurrentContractRenewal( );
}
gpInsuranceSoldier = NULL;
}
void HandleUniqueEventWhenPlayerLeavesTeam( SOLDIERTYPE *pSoldier )
{
if (!is_networked)
{
switch( pSoldier->ubProfile )
{
//When iggy leaves the players team,
case IGGY:
//if he is owed money ( ie the player didnt pay him )
if( gMercProfiles[ pSoldier->ubProfile ].iBalance < 0 )
{
//iggy is now available to be handled by the enemy
gubFact[ FACT_IGGY_AVAILABLE_TO_ARMY ] = TRUE;
}
break;
}
}
}
UINT32 GetHourWhenContractDone( SOLDIERTYPE *pSoldier )
{
UINT32 uiArriveHour;
// Get the arrival hour - that will give us when they arrived....
if (!is_networked)
{
uiArriveHour = ( ( pSoldier->uiTimeSoldierWillArrive ) - ( ( ( pSoldier->uiTimeSoldierWillArrive ) / 1440 ) * 1440 ) ) / 60;
}
else
{
// WANNE - MP: For multiplayer game, the merc arrive hour is always the game starting time which is now in multiplayer = GameStartingTime + FirstArrivalDelay
// Default value: 07:00
uiArriveHour = (gGameExternalOptions.iGameStartingTime + gGameExternalOptions.iFirstArrivalDelay - NUM_SEC_IN_DAY) / 3600;
}
return( uiArriveHour );
}
BOOLEAN ContractIsExpiring( SOLDIERTYPE *pSoldier )
{
UINT32 uiCheckHour;
// First at least make sure same day....
if( ( pSoldier->iEndofContractTime /1440 ) <= (INT32)GetWorldDay( ) )
{
uiCheckHour = GetHourWhenContractDone( pSoldier );
// See if the hour we are on is the same....
if ( GetWorldHour( ) == uiCheckHour )
{
// All's good for go!
return( TRUE );
}
}
return( FALSE );
}
BOOLEAN ContractIsGoingToExpireSoon( SOLDIERTYPE *pSoldier )
{
// get hour contract is going to expire....
UINT32 uiCheckHour;
// First at least make sure same day....
if( ( pSoldier->iEndofContractTime /1440 ) <= (INT32)GetWorldDay( ) )
{
uiCheckHour = GetHourWhenContractDone( pSoldier );
// If we are <= 2 hours from expiry.
if ( GetWorldHour( ) >= ( uiCheckHour - 2 ) )
{
// All's good for go!
return( TRUE );
}
}
return( FALSE );
}