mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
1815 lines
55 KiB
C++
1815 lines
55 KiB
C++
#include "sgp.h"
|
|
#include "message.h"
|
|
#include "quests.h"
|
|
#include "game clock.h"
|
|
#include "StrategicMap.h"
|
|
#include "soldier profile.h"
|
|
#include "LaptopSave.h"
|
|
#include "Handle Items.h"
|
|
#include "overhead.h"
|
|
#include "Interface Dialogue.h"
|
|
#include "Soldier Profile.h"
|
|
#include "Isometric Utils.h"
|
|
#include "Render Fun.h"
|
|
#include "History.h"
|
|
#include "Map Screen Helicopter.h"
|
|
#include "Overhead.h"
|
|
#include "Strategic Mines.h"
|
|
#include "Boxing.h"
|
|
#include "Campaign Types.h"
|
|
#include "Strategic Town Loyalty.h"
|
|
#include "Queen Command.h"
|
|
#include "Campaign.h"
|
|
#include "GameSettings.h"
|
|
#include "Arms Dealer Init.h"
|
|
#include "GameSettings.h"
|
|
#include "Random.h"
|
|
#include "Assignments.h"
|
|
#include "strategic.h"
|
|
#include "Strategic Event Handler.h"
|
|
#include "Soldier Control.h"
|
|
|
|
#include "BobbyRMailOrder.h"
|
|
#include "connect.h"
|
|
|
|
#ifdef JA2UB
|
|
#include "email.h"
|
|
#include "Strategic Merc Handler.h"
|
|
#include "laptop.h"
|
|
#include "Ja25 Strategic Ai.h"
|
|
#include "ub_config.h"
|
|
#include "Ja25_Tactical.h"
|
|
#endif
|
|
|
|
#include "LuaInitNPCs.h"
|
|
|
|
#include "Luaglobal.h"
|
|
|
|
// anv: Waldo The Mechanic - for fact checking with helicopter
|
|
#include "Vehicles.h"
|
|
|
|
#define TESTQUESTS
|
|
|
|
extern SOLDIERTYPE * gpSrcSoldier;
|
|
extern SOLDIERTYPE * gpDestSoldier;
|
|
|
|
UINT8 gubQuest[MAX_QUESTS];
|
|
UINT8 gubFact[ NUM_FACTS ]; // this has to be updated when we figure out how many facts we have
|
|
|
|
// Flugente: we save and load this array. It is to be used exclusively by modders, who can set this in lua scripts
|
|
INT32 gubModderLuaData[MODDER_LUA_DATA_MAX]; // this has to be updated when we figure out how many facts we have
|
|
|
|
INT16 gsFoodQuestSectorX;
|
|
INT16 gsFoodQuestSectorY;
|
|
|
|
extern void GuaranteeAtLeastXItemsOfIndex( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubHowMany );
|
|
|
|
extern void GiveQuestRewardPoint( INT16 sQuestSectorX, INT16 sQuestsSectorY, INT8 bExpReward, UINT8 bException );
|
|
|
|
extern void DebugQuestInfo(STR szOutput);
|
|
|
|
void SetFactTrue( UINT16 usFact )
|
|
{
|
|
// This function is here just for control flow purposes (debug breakpoints)
|
|
// and code is more readable that way
|
|
|
|
// must intercept when Jake is first triggered to start selling fuel
|
|
if ( ( usFact == FACT_ESTONI_REFUELLING_POSSIBLE ) && ( CheckFact( usFact, 0 ) == FALSE ) )
|
|
{
|
|
// give him some gas...
|
|
GuaranteeAtLeastXItemsOfIndex( ARMS_DEALER_JAKE, GAS_CAN, ( UINT8 ) ( 4 + Random( 3 ) ) );
|
|
DebugQuestInfo(String("guarantee X items of %d (GAS_CAN) for dealer %d (ARMS_DEALER_JAKE)", GAS_CAN, ARMS_DEALER_JAKE));
|
|
}
|
|
|
|
gubFact[usFact] = TRUE;
|
|
}
|
|
|
|
void SetFactFalse( UINT16 usFact )
|
|
{
|
|
gubFact[usFact] = FALSE;
|
|
DebugQuestInfo(String("fact %d false", usFact));
|
|
}
|
|
|
|
BOOLEAN CheckForNewShipment( void )
|
|
{
|
|
ITEM_POOL * pItemPool;
|
|
|
|
if ( ( gWorldSectorX == BOBBYR_SHIPPING_DEST_SECTOR_X ) && ( gWorldSectorY == BOBBYR_SHIPPING_DEST_SECTOR_Y ) && ( gbWorldSectorZ == BOBBYR_SHIPPING_DEST_SECTOR_Z ) )
|
|
{
|
|
if ( GetItemPoolFromGround( BOBBYR_SHIPPING_DEST_GRIDNO, &pItemPool ) )
|
|
{
|
|
return( !( ITEMPOOL_VISIBLE( pItemPool ) ) );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN CheckNPCWounded( UINT8 ubProfileID, BOOLEAN fByPlayerOnly )
|
|
{
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
// is the NPC is wounded at all?
|
|
pSoldier = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if (pSoldier && pSoldier->stats.bLife < pSoldier->stats.bLifeMax)
|
|
{
|
|
if (fByPlayerOnly)
|
|
{
|
|
if (gMercProfiles[ubProfileID].ubMiscFlags & PROFILE_MISC_FLAG_WOUNDEDBYPLAYER)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
|
|
}
|
|
}
|
|
|
|
BOOLEAN CheckNPCInOkayHealth( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
// is the NPC at better than half health?
|
|
pSoldier = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if (pSoldier && pSoldier->stats.bLife > (pSoldier->stats.bLifeMax / 2) && pSoldier->stats.bLife > 30)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
BOOLEAN CheckNPCBleeding( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
// the NPC is wounded...
|
|
pSoldier = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if (pSoldier && pSoldier->stats.bLife > 0 && pSoldier->bBleeding > 0)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
}
|
|
|
|
BOOLEAN CheckNPCWithin( UINT8 ubFirstNPC, UINT8 ubSecondNPC, UINT8 ubMaxDistance )
|
|
{
|
|
SOLDIERTYPE * pFirstNPC, * pSecondNPC;
|
|
|
|
pFirstNPC = FindSoldierByProfileID( ubFirstNPC, FALSE );
|
|
pSecondNPC = FindSoldierByProfileID( ubSecondNPC, FALSE );
|
|
if (!pFirstNPC || !pSecondNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( PythSpacesAway( pFirstNPC->sGridNo, pSecondNPC->sGridNo ) <= ubMaxDistance );
|
|
}
|
|
|
|
BOOLEAN CheckGuyVisible( UINT16 ubNPC, UINT16 ubGuy )
|
|
{
|
|
// NB ONLY WORKS IF ON DIFFERENT TEAMS
|
|
SOLDIERTYPE * pNPC, * pGuy;
|
|
|
|
pNPC = FindSoldierByProfileID( ubNPC, FALSE );
|
|
pGuy = FindSoldierByProfileID( ubGuy, FALSE );
|
|
if (!pNPC || !pGuy)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if (pNPC->aiData.bOppList[ pGuy->ubID ] == SEEN_CURRENTLY )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
BOOLEAN CheckNPCAt( UINT8 ubNPC, INT32 sGridNo )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
pNPC = FindSoldierByProfileID( ubNPC, FALSE );
|
|
if (!pNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( pNPC->sGridNo == sGridNo );
|
|
}
|
|
|
|
BOOLEAN CheckNPCIsEnemy( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if (!pNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if (pNPC->bSide == gbPlayerNum || pNPC->aiData.bNeutral)
|
|
{
|
|
if (pNPC->ubCivilianGroup != NON_CIV_GROUP)
|
|
{
|
|
// although the soldier is NOW the same side, this civ group could be set to "will become hostile"
|
|
return( gTacticalStatus.fCivGroupHostile[ pNPC->ubCivilianGroup ] >= CIV_GROUP_WILL_BECOME_HOSTILE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
BOOLEAN CheckIfMercIsNearNPC( SOLDIERTYPE *pMerc, UINT8 ubProfileId )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
INT32 sGridNo;
|
|
|
|
// no merc nearby?
|
|
if ( pMerc == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileId, FALSE );
|
|
if ( pNPC == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
sGridNo = pNPC->sGridNo;
|
|
|
|
// is the merc and NPC close enough?
|
|
if (PythSpacesAway( sGridNo, pMerc->sGridNo ) <= 9)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
UINT32 NumWoundedMercsNearby( UINT8 ubProfileID )
|
|
{
|
|
UINT32 bNumber = 0;
|
|
SOLDIERTYPE* pSoldier;
|
|
|
|
SOLDIERTYPE* pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if (!pNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
INT32 sGridNo = pNPC->sGridNo;
|
|
|
|
for ( UINT32 uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop )
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
if ( pSoldier && pSoldier->bTeam == gbPlayerNum && pSoldier->stats.bLife > 0 && (pSoldier->stats.bLife < pSoldier->stats.bLifeMax || NumberOfDamagedStats(pSoldier) > 0) && pSoldier->bAssignment != ASSIGNMENT_HOSPITAL
|
|
&& pSoldier->sSectorX == pNPC->sSectorX && pSoldier->sSectorY == pNPC->sSectorY && pSoldier->bSectorZ == pNPC->bSectorZ )
|
|
{
|
|
if (PythSpacesAway( sGridNo, pSoldier->sGridNo ) <= HOSPITAL_PATIENT_DISTANCE)
|
|
{
|
|
++bNumber;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bNumber );
|
|
}
|
|
|
|
UINT16 NumMercsNear( UINT8 ubProfileID, UINT8 ubMaxDist )
|
|
{
|
|
UINT16 bNumber = 0;
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE *pNPC;
|
|
SOLDIERTYPE *pSoldier;
|
|
INT32 sGridNo;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if (!pNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
sGridNo = pNPC->sGridNo;
|
|
|
|
for ( uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
if ( pSoldier && pSoldier->bTeam == gbPlayerNum && pSoldier->stats.bLife >= OKLIFE )
|
|
{
|
|
if (PythSpacesAway( sGridNo, pSoldier->sGridNo ) <= ubMaxDist)
|
|
{
|
|
bNumber++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bNumber );
|
|
}
|
|
|
|
BOOLEAN CheckNPCIsEPC( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
if ( gMercProfiles[ ubProfileID ].bMercStatus == MERC_IS_DEAD )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, TRUE );
|
|
if (!pNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( (pNPC->ubWhatKindOfMercAmI == MERC_TYPE__EPC ) );
|
|
}
|
|
|
|
BOOLEAN CheckNPCIsRPC( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
if ( gMercProfiles[ ubProfileID ].bMercStatus == MERC_IS_DEAD )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, TRUE );
|
|
if (!pNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( (pNPC->ubWhatKindOfMercAmI == MERC_TYPE__NPC ) );
|
|
}
|
|
//DBrot: More Rooms
|
|
BOOLEAN NPCInRoom( UINT8 ubProfileID, UINT16 usRoomID )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if ( !pNPC || (gusWorldRoomInfo[ pNPC->sGridNo ] != usRoomID) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
//DBrot: More Rooms
|
|
BOOLEAN NPCInRoomRange( UINT8 ubProfileID, UINT16 usRoomID1, UINT16 usRoomID2 )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if ( !pNPC || (gusWorldRoomInfo[ pNPC->sGridNo ] < usRoomID1) || (gusWorldRoomInfo[ pNPC->sGridNo ] > usRoomID2) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN PCInSameRoom( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
//DBrot: More Rooms
|
|
//UINT8 ubRoom;
|
|
UINT16 usRoom;
|
|
UINT16 bLoop;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if ( !pNPC )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
usRoom = gusWorldRoomInfo[ pNPC->sGridNo ];
|
|
|
|
for ( bLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; bLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; bLoop++ )
|
|
{
|
|
pSoldier = MercPtrs[ bLoop ];
|
|
if ( pSoldier && pSoldier->bActive && pSoldier->bInSector )
|
|
{
|
|
if ( gusWorldRoomInfo[ pSoldier->sGridNo ] == usRoom )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN CheckTalkerStrong( void )
|
|
{
|
|
if (gpSrcSoldier && gpSrcSoldier->bTeam == gbPlayerNum)
|
|
{
|
|
return( gpSrcSoldier->stats.bStrength >= 84 );
|
|
}
|
|
else if (gpDestSoldier && gpDestSoldier->bTeam == gbPlayerNum)
|
|
{
|
|
return( gpDestSoldier->stats.bStrength >= 84 );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN CheckTalkerFemale( void )
|
|
{
|
|
if (gpSrcSoldier && gpSrcSoldier->bTeam == gbPlayerNum && gpSrcSoldier->ubProfile != NO_PROFILE)
|
|
{
|
|
return( gMercProfiles[ gpSrcSoldier->ubProfile ].bSex == FEMALE );
|
|
}
|
|
else if (gpDestSoldier && gpDestSoldier->bTeam == gbPlayerNum && gpDestSoldier->ubProfile != NO_PROFILE)
|
|
{
|
|
return( gMercProfiles[ gpDestSoldier->ubProfile ].bSex == FEMALE );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN CheckTalkerUnpropositionedFemale( void )
|
|
{
|
|
if (gpSrcSoldier && gpSrcSoldier->bTeam == gbPlayerNum && gpSrcSoldier->ubProfile != NO_PROFILE)
|
|
{
|
|
if ( !(gMercProfiles[ gpSrcSoldier->ubProfile ].ubMiscFlags2 & PROFILE_MISC_FLAG2_ASKED_BY_HICKS) )
|
|
{
|
|
return( gMercProfiles[ gpSrcSoldier->ubProfile ].bSex == FEMALE );
|
|
}
|
|
}
|
|
else if (gpDestSoldier && gpDestSoldier->bTeam == gbPlayerNum && gpDestSoldier->ubProfile != NO_PROFILE)
|
|
{
|
|
if ( !(gMercProfiles[ gpDestSoldier->ubProfile ].ubMiscFlags2 & PROFILE_MISC_FLAG2_ASKED_BY_HICKS) )
|
|
{
|
|
return( gMercProfiles[ gpDestSoldier->ubProfile ].bSex == FEMALE );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
INT8 NumMalesPresent( UINT8 ubProfileID )
|
|
{
|
|
INT8 bNumber = 0;
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE * pNPC;
|
|
SOLDIERTYPE * pSoldier;
|
|
INT32 sGridNo;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if (!pNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
sGridNo = pNPC->sGridNo;
|
|
|
|
for ( uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
if ( pSoldier && pSoldier->bTeam == gbPlayerNum && pSoldier->stats.bLife >= OKLIFE)
|
|
{
|
|
if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile].bSex == MALE )
|
|
{
|
|
if (PythSpacesAway( sGridNo, pSoldier->sGridNo ) <= 8)
|
|
{
|
|
bNumber++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bNumber );
|
|
}
|
|
|
|
|
|
BOOLEAN FemalePresent( UINT8 ubProfileID )
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE * pNPC;
|
|
SOLDIERTYPE * pSoldier;
|
|
INT32 sGridNo;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if (!pNPC)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
sGridNo = pNPC->sGridNo;
|
|
|
|
for ( uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
if ( pSoldier && pSoldier->bTeam == gbPlayerNum && pSoldier->stats.bLife >= OKLIFE)
|
|
{
|
|
if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile].bSex == FEMALE )
|
|
{
|
|
if (PythSpacesAway( sGridNo, pSoldier->sGridNo ) <= 10)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN CheckPlayerHasHead( void )
|
|
{
|
|
UINT16 bLoop;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
for ( bLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; bLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; bLoop++ )
|
|
{
|
|
pSoldier = MercPtrs[ bLoop ];
|
|
|
|
if ( pSoldier->bActive && pSoldier->stats.bLife > 0 )
|
|
{
|
|
if ( FindObjInObjRange( pSoldier, HEAD_2, HEAD_7 ) != NO_SLOT )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
BOOLEAN CheckNPCSector( UINT8 ubProfileID, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ )
|
|
{
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
pSoldier = FindSoldierByProfileID( ubProfileID, TRUE );
|
|
|
|
if( pSoldier )
|
|
{
|
|
if (pSoldier->sSectorX == sSectorX &&
|
|
pSoldier->sSectorY == sSectorY &&
|
|
pSoldier->bSectorZ == bSectorZ )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
else if (gMercProfiles[ubProfileID].sSectorX == sSectorX &&
|
|
gMercProfiles[ubProfileID].sSectorY == sSectorY &&
|
|
gMercProfiles[ubProfileID].bSectorZ == bSectorZ )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
BOOLEAN AIMMercWithin( INT32 sGridNo, INT16 sDistance )
|
|
{
|
|
UINT32 uiLoop;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
for ( uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
|
{
|
|
pSoldier = MercSlots[ uiLoop ];
|
|
|
|
if ( pSoldier && (pSoldier->bTeam == gbPlayerNum) && (pSoldier->stats.bLife >= OKLIFE) && ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) )
|
|
{
|
|
if (PythSpacesAway( sGridNo, pSoldier->sGridNo ) <= sDistance)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN CheckNPCCowering( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if ( !pNPC )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( ( (pNPC->flags.uiStatusFlags & SOLDIER_COWERING) != 0) );
|
|
}
|
|
|
|
UINT8 CountBartenders( void )
|
|
{
|
|
UINT8 ubLoop;
|
|
UINT8 ubBartenders = 0;
|
|
|
|
for( ubLoop = HERVE; ubLoop <= CARLO; ubLoop++ )
|
|
{
|
|
if (gMercProfiles[ ubLoop ].bNPCData != 0 )
|
|
{
|
|
ubBartenders++;
|
|
}
|
|
}
|
|
return( ubBartenders );
|
|
}
|
|
|
|
BOOLEAN CheckNPCIsUnderFire( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if ( !pNPC )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( pNPC->aiData.bUnderFire != 0 );
|
|
}
|
|
|
|
BOOLEAN NPCHeardShot( UINT8 ubProfileID )
|
|
{
|
|
SOLDIERTYPE * pNPC;
|
|
|
|
pNPC = FindSoldierByProfileID( ubProfileID, FALSE );
|
|
if ( !pNPC )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( pNPC->ubMiscSoldierFlags & SOLDIER_MISC_HEARD_GUNSHOT );
|
|
}
|
|
|
|
BOOLEAN InTownSectorWithTrainingLoyalty( INT16 sSectorX, INT16 sSectorY )
|
|
{
|
|
UINT8 ubTown;
|
|
INT32 iMinLoyaltyToTrain = gGameExternalOptions.iMinLoyaltyToTrain;
|
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Quests");
|
|
|
|
ubTown = GetTownIdForSector( sSectorX, sSectorY );
|
|
if ( ( ubTown != BLANK_SECTOR ) && gTownLoyalty[ ubTown ].fStarted && gfTownUsesLoyalty[ ubTown ])
|
|
{
|
|
return( gTownLoyalty[ ubTown ].ubRating >= iMinLoyaltyToTrain );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
BOOLEAN CheckFact( UINT16 usFact, UINT8 ubProfileID )
|
|
{
|
|
|
|
|
|
// LuaCheckFact ( usFact, ubProfileID, 0 );
|
|
|
|
//#if 0
|
|
INT8 bTown = -1;
|
|
|
|
|
|
switch( usFact )
|
|
{
|
|
#ifdef JA2UB
|
|
//Ja25 No dimitri
|
|
#else
|
|
case FACT_DIMITRI_DEAD:
|
|
gubFact[ usFact ] = (gMercProfiles[ DIMITRI ].bMercStatus == MERC_IS_DEAD );
|
|
break;
|
|
#endif
|
|
case FACT_CURRENT_SECTOR_IS_SAFE:
|
|
gubFact[FACT_CURRENT_SECTOR_IS_SAFE] = !( ( (gTacticalStatus.fEnemyInSector && NPCHeardShot( ubProfileID ) ) || gTacticalStatus.uiFlags & INCOMBAT ) );
|
|
break;
|
|
case FACT_BOBBYRAY_SHIPMENT_IN_TRANSIT:
|
|
case FACT_NEW_BOBBYRAY_SHIPMENT_WAITING:
|
|
if ( gubFact[FACT_PABLO_PUNISHED_BY_PLAYER] == TRUE && gubFact[FACT_PABLO_RETURNED_GOODS] == FALSE && gMercProfiles[ PABLO ].bMercStatus != MERC_IS_DEAD )
|
|
{
|
|
gubFact[FACT_BOBBYRAY_SHIPMENT_IN_TRANSIT] = FALSE;
|
|
gubFact[FACT_NEW_BOBBYRAY_SHIPMENT_WAITING] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (CheckForNewShipment()) // if new stuff waiting unseen in Drassen
|
|
{
|
|
gubFact[FACT_BOBBYRAY_SHIPMENT_IN_TRANSIT] = FALSE;
|
|
gubFact[FACT_NEW_BOBBYRAY_SHIPMENT_WAITING] = TRUE;
|
|
}
|
|
else if ( CountNumberOfBobbyPurchasesThatAreInTransit() > 0) // if stuff in transit
|
|
{
|
|
if ( gubFact[ FACT_PACKAGE_DAMAGED ] == TRUE )
|
|
{
|
|
gubFact[FACT_BOBBYRAY_SHIPMENT_IN_TRANSIT] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
gubFact[FACT_BOBBYRAY_SHIPMENT_IN_TRANSIT] = TRUE;
|
|
}
|
|
gubFact[FACT_NEW_BOBBYRAY_SHIPMENT_WAITING] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
gubFact[FACT_BOBBYRAY_SHIPMENT_IN_TRANSIT] = FALSE;
|
|
gubFact[FACT_NEW_BOBBYRAY_SHIPMENT_WAITING] = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
case FACT_NPC_WOUNDED:
|
|
gubFact[FACT_NPC_WOUNDED] = CheckNPCWounded( ubProfileID, FALSE );
|
|
break;
|
|
case FACT_NPC_WOUNDED_BY_PLAYER:
|
|
gubFact[FACT_NPC_WOUNDED_BY_PLAYER] = CheckNPCWounded( ubProfileID, TRUE );
|
|
break;
|
|
#ifdef JA2UB
|
|
// no ja25 UB
|
|
#else
|
|
case FACT_IRA_NOT_PRESENT:
|
|
gubFact[FACT_IRA_NOT_PRESENT] = !CheckNPCWithin( ubProfileID, IRA, 10 );
|
|
break;
|
|
case FACT_IRA_TALKING:
|
|
gubFact[FACT_IRA_TALKING] = ( gubSrcSoldierProfile == IRA );
|
|
break;
|
|
case FACT_IRA_UNHIRED_AND_ALIVE:
|
|
if ( gMercProfiles[ IRA ].bMercStatus != MERC_IS_DEAD && CheckNPCSector( IRA, 10, 1, 1) && !(gMercProfiles[IRA].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED) )
|
|
{
|
|
gubFact[FACT_IRA_UNHIRED_AND_ALIVE] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
gubFact[FACT_IRA_UNHIRED_AND_ALIVE] = FALSE;
|
|
}
|
|
break;
|
|
#endif
|
|
case FACT_NPC_BLEEDING:
|
|
gubFact[FACT_NPC_BLEEDING] = CheckNPCBleeding( ubProfileID );
|
|
break;
|
|
case FACT_NPC_BLEEDING_BUT_OKAY:
|
|
if ( CheckNPCBleeding( ubProfileID ) && CheckNPCInOkayHealth( ubProfileID ) )
|
|
{
|
|
gubFact[FACT_NPC_BLEEDING_BUT_OKAY] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
gubFact[FACT_NPC_BLEEDING_BUT_OKAY] = FALSE;
|
|
}
|
|
break;
|
|
#ifdef JA2UB
|
|
//Ja25: NO Carmen
|
|
#else
|
|
case FACT_PLAYER_HAS_HEAD_AND_CARMEN_IN_SAN_MONA:
|
|
gubFact[usFact] = (CheckNPCSector( CARMEN, 5, MAP_ROW_C, 0 ) && CheckPlayerHasHead() );
|
|
break;
|
|
|
|
case FACT_PLAYER_HAS_HEAD_AND_CARMEN_IN_CAMBRIA:
|
|
gubFact[usFact] = (CheckNPCSector( CARMEN, 9, MAP_ROW_G, 0 ) && CheckPlayerHasHead() );
|
|
break;
|
|
|
|
case FACT_PLAYER_HAS_HEAD_AND_CARMEN_IN_DRASSEN:
|
|
gubFact[usFact] = (CheckNPCSector( CARMEN, 13, MAP_ROW_C, 0 ) && CheckPlayerHasHead() );
|
|
break;
|
|
#endif
|
|
case FACT_NPC_OWED_MONEY:
|
|
gubFact[FACT_NPC_OWED_MONEY] = (gMercProfiles[ubProfileID].iBalance < 0);
|
|
break;
|
|
|
|
case FACT_FATHER_DRUNK:
|
|
gubFact[FACT_FATHER_DRUNK] = ( gMercProfiles[ FATHER ].bNPCData >= 5 );
|
|
break;
|
|
|
|
case FACT_MICKY_DRUNK:
|
|
gubFact[FACT_MICKY_DRUNK] = ( gMercProfiles[ MICKY ].bNPCData >= 5 );
|
|
break;
|
|
|
|
case FACT_BRENDA_IN_STORE_AND_ALIVE:
|
|
// ensure alive
|
|
if ( gMercProfiles[ BRENDA ].bMercStatus == MERC_IS_DEAD)
|
|
{
|
|
gubFact[FACT_BRENDA_IN_STORE_AND_ALIVE] = FALSE;
|
|
}
|
|
// ensure in a building and nearby
|
|
else if ( !(NPCInRoom( BRENDA, gModSettings.usPornShopRoomBrenda ) ) )
|
|
{
|
|
gubFact[FACT_BRENDA_IN_STORE_AND_ALIVE] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
gubFact[FACT_BRENDA_IN_STORE_AND_ALIVE] = CheckNPCWithin( ubProfileID, BRENDA, 12 );
|
|
}
|
|
break;
|
|
case FACT_BRENDA_DEAD:
|
|
gubFact[FACT_BRENDA_DEAD] = (gMercProfiles[ BRENDA ].bMercStatus == MERC_IS_DEAD);
|
|
break;
|
|
case FACT_NPC_IS_ENEMY:
|
|
gubFact[FACT_NPC_IS_ENEMY] = CheckNPCIsEnemy( ubProfileID ) || gMercProfiles[ ubProfileID ].ubMiscFlags2 & PROFILE_MISC_FLAG2_NEEDS_TO_SAY_HOSTILE_QUOTE;
|
|
break;
|
|
/*
|
|
case FACT_SKYRIDER_CLOSE_TO_CHOPPER:
|
|
SetUpHelicopterForPlayer( 13, MAP_ROW_B, gNewVehicle[ HELICOPTER ].NewPilot, HELICOPTER );
|
|
break;
|
|
*/
|
|
case FACT_SPIKE_AT_DOOR:
|
|
gubFact[FACT_SPIKE_AT_DOOR] = CheckNPCAt( SPIKE, 9817 );
|
|
break;
|
|
case FACT_WOUNDED_MERCS_NEARBY:
|
|
gubFact[usFact] = (NumWoundedMercsNearby( ubProfileID ) > 0);
|
|
break;
|
|
case FACT_ONE_WOUNDED_MERC_NEARBY:
|
|
gubFact[usFact] = (NumWoundedMercsNearby( ubProfileID ) == 1);
|
|
break;
|
|
case FACT_MULTIPLE_WOUNDED_MERCS_NEARBY:
|
|
gubFact[usFact] = (NumWoundedMercsNearby( ubProfileID ) > 1);
|
|
break;
|
|
case FACT_HANS_AT_SPOT:
|
|
gubFact[usFact] = CheckNPCAt( HANS, gModSettings.iHansGridNo );
|
|
break;
|
|
case FACT_MULTIPLE_MERCS_CLOSE:
|
|
gubFact[usFact] = ( NumMercsNear( ubProfileID, 3 ) > 1 );
|
|
break;
|
|
case FACT_SOME_MERCS_CLOSE:
|
|
gubFact[usFact] = ( NumMercsNear( ubProfileID, 3 ) > 0 );
|
|
break;
|
|
case FACT_MARIA_ESCORTED:
|
|
gubFact[usFact] = CheckNPCIsEPC( MARIA );
|
|
break;
|
|
case FACT_JOEY_ESCORTED:
|
|
gubFact[usFact] = CheckNPCIsEPC( JOEY );
|
|
break;
|
|
case FACT_ESCORTING_SKYRIDER:
|
|
gubFact[usFact] = CheckNPCIsEPC( SKYRIDER );
|
|
break;
|
|
case FACT_MARIA_ESCORTED_AT_LEATHER_SHOP:
|
|
gubFact[usFact] = ( CheckNPCIsEPC( MARIA ) && (NPCInRoom( MARIA, gModSettings.usLeatherShop )) );
|
|
break;
|
|
case FACT_PC_STRONG_AND_LESS_THAN_3_MALES_PRESENT:
|
|
gubFact[usFact] = ( CheckTalkerStrong() && (NumMalesPresent( ubProfileID ) < 3) );
|
|
break;
|
|
case FACT_PC_STRONG_AND_3_PLUS_MALES_PRESENT:
|
|
gubFact[usFact] = ( CheckTalkerStrong() && (NumMalesPresent( ubProfileID ) >= 3) );
|
|
break;
|
|
case FACT_FEMALE_SPEAKING_TO_NPC:
|
|
gubFact[usFact] = CheckTalkerFemale();
|
|
break;
|
|
case FACT_CARMEN_IN_C5:
|
|
gubFact[usFact] = CheckNPCSector( CARMEN, 5, MAP_ROW_C, 0 );
|
|
break;
|
|
case FACT_JOEY_IN_C5:
|
|
gubFact[usFact] = CheckNPCSector( JOEY, 5, MAP_ROW_C, 0 );
|
|
break;
|
|
case FACT_JOEY_NEAR_MARTHA:
|
|
gubFact[usFact] = CheckNPCWithin( JOEY, MARTHA, 5 ) && ( CheckGuyVisible( MARTHA, JOEY ) || CheckGuyVisible( JOEY, MARTHA ) );
|
|
break;
|
|
case FACT_JOEY_DEAD:
|
|
gubFact[usFact] = gMercProfiles[ JOEY ].bMercStatus == MERC_IS_DEAD;
|
|
break;
|
|
case FACT_MERC_NEAR_MARTHA:
|
|
gubFact[usFact] = ( NumMercsNear( ubProfileID, 5 ) > 0 );
|
|
break;
|
|
case FACT_REBELS_HATE_PLAYER:
|
|
gubFact[usFact] = (gTacticalStatus.fCivGroupHostile[ REBEL_CIV_GROUP ] == CIV_GROUP_HOSTILE);
|
|
break;
|
|
case FACT_CURRENT_SECTOR_G9:
|
|
gubFact[usFact] = ( gWorldSectorX == 9 && gWorldSectorY == MAP_ROW_G && gbWorldSectorZ == 0 );
|
|
break;
|
|
case FACT_CURRENT_SECTOR_C5:
|
|
gubFact[usFact] = ( gWorldSectorX == 5 && gWorldSectorY == MAP_ROW_C && gbWorldSectorZ == 0 );
|
|
break;
|
|
case FACT_CURRENT_SECTOR_C13:
|
|
gubFact[usFact] = ( gWorldSectorX == 13 && gWorldSectorY == MAP_ROW_C && gbWorldSectorZ == 0 );
|
|
break;
|
|
case FACT_CARMEN_HAS_TEN_THOUSAND:
|
|
gubFact[usFact] = ( gMercProfiles[ CARMEN ].uiMoney >= 10000 );
|
|
break;
|
|
case FACT_SLAY_IN_SECTOR:
|
|
gubFact[usFact] = (gMercProfiles[ SLAY ].sSectorX == gWorldSectorX && gMercProfiles[ SLAY ].sSectorY == gWorldSectorY && gMercProfiles[ SLAY ].bSectorZ == gbWorldSectorZ );
|
|
break;
|
|
case FACT_SLAY_HIRED_AND_WORKED_FOR_48_HOURS:
|
|
gubFact[usFact] = ( ( gMercProfiles[ SLAY ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) && ( gMercProfiles[ SLAY ].usTotalDaysServed > 1 ) );
|
|
break;
|
|
case FACT_SHANK_IN_SQUAD_BUT_NOT_SPEAKING:
|
|
gubFact[usFact] = ( ( FindSoldierByProfileID( SHANK, TRUE ) != NULL) && ( gMercProfiles[ SHANK ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) && ( gpSrcSoldier == NULL || gpSrcSoldier->ubProfile != SHANK ) );
|
|
break;
|
|
case FACT_SHANK_NOT_IN_SECTOR:
|
|
gubFact[usFact] = ( FindSoldierByProfileID( SHANK, FALSE ) == NULL );
|
|
break;
|
|
#ifdef JA2UB
|
|
//Ja25 No queen
|
|
#else
|
|
case FACT_QUEEN_DEAD:
|
|
gubFact[usFact] = (gMercProfiles[ QUEEN ].bMercStatus == MERC_IS_DEAD);
|
|
break;
|
|
#endif
|
|
case FACT_MINE_EMPTY:
|
|
gubFact[usFact] = IsHisMineEmpty( ubProfileID );
|
|
break;
|
|
case FACT_MINE_RUNNING_OUT:
|
|
gubFact[usFact] = IsHisMineRunningOut( ubProfileID );
|
|
break;
|
|
case FACT_MINE_PRODUCING_BUT_LOYALTY_LOW:
|
|
gubFact[usFact] = HasHisMineBeenProducingForPlayerForSomeTime( ubProfileID ) && IsHisMineDisloyal( ubProfileID );
|
|
break;
|
|
case FACT_CREATURES_IN_MINE:
|
|
gubFact[usFact] = IsHisMineInfested( ubProfileID );
|
|
break;
|
|
case FACT_PLAYER_LOST_MINE:
|
|
gubFact[usFact] = IsHisMineLostAndRegained( ubProfileID );
|
|
break;
|
|
case FACT_MINE_AT_FULL_PRODUCTION:
|
|
gubFact[usFact] = IsHisMineAtMaxProduction( ubProfileID );
|
|
break;
|
|
case FACT_DYNAMO_IN_J9:
|
|
gubFact[usFact] = CheckNPCSector( DYNAMO, gModSettings.ubDyanmoCaptiveSectorX, gModSettings.ubDyanmoCaptiveSectorY, gModSettings.ubDyanmoCaptiveSectorZ ) &&
|
|
NumEnemiesInAnySector( gModSettings.ubDyanmoCaptiveSectorX, gModSettings.ubDyanmoCaptiveSectorY, gModSettings.ubDyanmoCaptiveSectorZ ); //( 9, 10, 0 )
|
|
break;
|
|
case FACT_DYNAMO_ALIVE:
|
|
gubFact[usFact] = ( gMercProfiles[ DYNAMO ].bMercStatus != MERC_IS_DEAD );
|
|
break;
|
|
case FACT_DYNAMO_SPEAKING_OR_NEARBY:
|
|
gubFact[usFact] = ( gpSrcSoldier != NULL && (gpSrcSoldier->ubProfile == DYNAMO || ( CheckNPCWithin( gpSrcSoldier->ubProfile, DYNAMO, 10 ) && CheckGuyVisible( gpSrcSoldier->ubProfile, DYNAMO ) ) ) );
|
|
break;
|
|
case FACT_JOHN_EPC:
|
|
gubFact[usFact] = CheckNPCIsEPC( JOHN );
|
|
break;
|
|
case FACT_MARY_EPC:
|
|
gubFact[usFact] = CheckNPCIsEPC( MARY );
|
|
break;
|
|
case FACT_JOHN_AND_MARY_EPCS:
|
|
gubFact[usFact] = CheckNPCIsEPC( JOHN ) && CheckNPCIsEPC( MARY );
|
|
break;
|
|
case FACT_MARY_ALIVE:
|
|
gubFact[usFact] = ( gMercProfiles[ MARY ].bMercStatus != MERC_IS_DEAD );
|
|
break;
|
|
case FACT_MARY_BLEEDING:
|
|
gubFact[usFact] = CheckNPCBleeding( MARY );
|
|
break;
|
|
case FACT_JOHN_ALIVE:
|
|
gubFact[usFact] = ( gMercProfiles[ JOHN ].bMercStatus != MERC_IS_DEAD );
|
|
break;
|
|
case FACT_JOHN_BLEEDING:
|
|
gubFact[usFact] = CheckNPCBleeding( JOHN );
|
|
break;
|
|
case FACT_MARY_DEAD:
|
|
gubFact[usFact] = ( gMercProfiles[ MARY ].bMercStatus == MERC_IS_DEAD );
|
|
break;
|
|
|
|
case FACT_ANOTHER_FIGHT_POSSIBLE:
|
|
gubFact[usFact] = AnotherFightPossible();
|
|
break;
|
|
|
|
case FACT_RECEIVING_INCOME_FROM_DCAC:
|
|
gubFact[usFact] = (
|
|
( PredictDailyIncomeFromAMine( MINE_DRASSEN, TRUE ) > 0 ) &&
|
|
( PredictDailyIncomeFromAMine( MINE_ALMA, TRUE ) > 0 ) &&
|
|
( PredictDailyIncomeFromAMine( MINE_CAMBRIA, TRUE ) > 0 ) &&
|
|
( PredictDailyIncomeFromAMine( MINE_CHITZENA, TRUE ) > 0 ) );
|
|
break;
|
|
|
|
case FACT_PLAYER_BEEN_TO_K4:
|
|
{
|
|
UNDERGROUND_SECTORINFO * pUnderGroundSector;
|
|
|
|
pUnderGroundSector = FindUnderGroundSector( 4, MAP_ROW_K, 1 );
|
|
gubFact[usFact] = pUnderGroundSector->fVisited;
|
|
}
|
|
break;
|
|
case FACT_WARDEN_DEAD:
|
|
gubFact[usFact] = ( gMercProfiles[ WARDEN ].bMercStatus == MERC_IS_DEAD );
|
|
break;
|
|
|
|
case FACT_PLAYER_PAID_FOR_TWO_IN_BROTHEL:
|
|
gubFact[usFact] = (gMercProfiles[ MADAME ].bNPCData > 1);
|
|
break;
|
|
|
|
case FACT_LOYALTY_OKAY:
|
|
bTown = gMercProfiles[ ubProfileID ].bTown;
|
|
if( ( bTown != BLANK_SECTOR ) && gTownLoyalty[ bTown ].fStarted && gfTownUsesLoyalty[ bTown ])
|
|
{
|
|
gubFact[usFact] = ( (gTownLoyalty[ bTown ].ubRating >= LOYALTY_LOW_THRESHOLD ) && (gTownLoyalty[ bTown ].ubRating < LOYALTY_OK_THRESHOLD ) );
|
|
}
|
|
else
|
|
{
|
|
gubFact[usFact] = FALSE;
|
|
}
|
|
break;
|
|
|
|
case FACT_LOYALTY_LOW:
|
|
bTown = gMercProfiles[ ubProfileID ].bTown;
|
|
if( ( bTown != BLANK_SECTOR ) && gTownLoyalty[ bTown ].fStarted && gfTownUsesLoyalty[ bTown ])
|
|
{
|
|
// if Skyrider, ignore low loyalty until he has monologues, and wait at least a day since the latest monologue to avoid a hot/cold attitude
|
|
if ( ( ubProfileID == SKYRIDER ) &&
|
|
( ( guiHelicopterSkyriderTalkState == 0 ) || ( ( GetWorldTotalMin() - guiTimeOfLastSkyriderMonologue ) < ( 24 * 60 ) ) ||
|
|
( gHelicopterSettings.fHelicopterTownLoyaltyCheck == FALSE ) ) )
|
|
{
|
|
gubFact[usFact] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
gubFact[usFact] = (gTownLoyalty[ bTown ].ubRating < LOYALTY_LOW_THRESHOLD );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gubFact[usFact] = FALSE;
|
|
}
|
|
break;
|
|
|
|
case FACT_LOYALTY_HIGH:
|
|
bTown = gMercProfiles[ ubProfileID ].bTown;
|
|
if( ( bTown != BLANK_SECTOR ) && gTownLoyalty[ bTown ].fStarted && gfTownUsesLoyalty[ bTown ])
|
|
{
|
|
gubFact[usFact] = (gTownLoyalty[ gMercProfiles[ ubProfileID ].bTown ].ubRating >= LOYALTY_HIGH_THRESHOLD );
|
|
}
|
|
else
|
|
{
|
|
gubFact[usFact] = FALSE;
|
|
}
|
|
break;
|
|
|
|
case FACT_ELGIN_ALIVE:
|
|
gubFact[usFact] = ( gMercProfiles[ DRUGGIST ].bMercStatus != MERC_IS_DEAD );
|
|
break;
|
|
|
|
case FACT_SPEAKER_AIM_OR_AIM_NEARBY:
|
|
gubFact[usFact] = gpDestSoldier && AIMMercWithin( gpDestSoldier->sGridNo, 10 );
|
|
break;
|
|
|
|
case FACT_MALE_SPEAKING_FEMALE_PRESENT:
|
|
gubFact[usFact] = ( !CheckTalkerFemale() && FemalePresent( ubProfileID ) );
|
|
break;
|
|
|
|
case FACT_PLAYER_OWNS_2_TOWNS_INCLUDING_OMERTA:
|
|
#ifdef JA2UB
|
|
//UB
|
|
#else
|
|
gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() == gGameExternalOptions.ubEarlyRebelsRecruitment[1] || gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 1
|
|
|| ( gubQuest[QUEST_FOOD_ROUTE] == QUESTDONE && gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 4 ) ) && IsTownUnderCompleteControlByPlayer( OMERTA ) );
|
|
#endif
|
|
break;
|
|
|
|
case FACT_PLAYER_OWNS_3_TOWNS_INCLUDING_OMERTA:
|
|
#ifdef JA2UB
|
|
//UB
|
|
#else
|
|
gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() == gGameExternalOptions.ubEarlyRebelsRecruitment[2] || gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 1
|
|
|| ( gubQuest[QUEST_FOOD_ROUTE] == QUESTDONE && gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 4 ) ) && IsTownUnderCompleteControlByPlayer( OMERTA ) );
|
|
#endif
|
|
break;
|
|
|
|
case FACT_PLAYER_OWNS_4_TOWNS_INCLUDING_OMERTA:
|
|
#ifdef JA2UB
|
|
//UB
|
|
#else
|
|
gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() >= gGameExternalOptions.ubEarlyRebelsRecruitment[3] || gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 1
|
|
|| ( gubQuest[QUEST_FOOD_ROUTE] == QUESTDONE && gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 4 ) ) && IsTownUnderCompleteControlByPlayer( OMERTA ) );
|
|
// silversurfer: this is the highest requirement and therefore we will automatically enable recruitment of Miguel
|
|
if ( gubFact[usFact] )
|
|
SetFactTrue(FACT_MIGUEL_AND_ALL_REBELS_CAN_BE_RECRUITED); // Miguel will now be willing to join and so will the other RPC
|
|
#endif
|
|
break;
|
|
|
|
case FACT_PLAYER_FOUGHT_THREE_TIMES_TODAY:
|
|
gubFact[usFact] = !BoxerAvailable();
|
|
break;
|
|
|
|
case FACT_PLAYER_DOING_POORLY:
|
|
gubFact[usFact] = ( CurrentPlayerProgressPercentage() < 20 );
|
|
break;
|
|
|
|
case FACT_PLAYER_DOING_WELL:
|
|
gubFact[usFact] = ( CurrentPlayerProgressPercentage() > 50 );
|
|
break;
|
|
|
|
case FACT_PLAYER_DOING_VERY_WELL:
|
|
gubFact[usFact] = ( CurrentPlayerProgressPercentage() > 80 );
|
|
break;
|
|
|
|
case FACT_FATHER_DRUNK_AND_SCIFI_OPTION_ON:
|
|
gubFact[usFact] = ( ( gMercProfiles[ FATHER ].bNPCData >= 5 ) && gGameOptions.ubGameStyle == STYLE_SCIFI && gGameExternalOptions.fEnableCrepitus);
|
|
break;
|
|
|
|
case FACT_BLOODCAT_QUEST_STARTED_TWO_DAYS_AGO:
|
|
gubFact[usFact] = ( (gubQuest[ QUEST_BLOODCATS ] != QUESTNOTSTARTED) && (GetWorldTotalMin() - GetTimeQuestWasStarted( QUEST_BLOODCATS ) > 2 * NUM_SEC_IN_DAY / NUM_SEC_IN_MIN) );
|
|
break;
|
|
|
|
case FACT_NOTHING_REPAIRED_YET:
|
|
gubFact[usFact] = RepairmanIsFixingItemsButNoneAreDoneYet( ubProfileID );
|
|
break;
|
|
|
|
case FACT_NPC_COWERING:
|
|
gubFact[usFact] = CheckNPCCowering( ubProfileID );
|
|
break;
|
|
|
|
case FACT_TOP_AND_BOTTOM_LEVELS_CLEARED:
|
|
gubFact[usFact] = ( gubFact[ FACT_TOP_LEVEL_CLEARED ] && gubFact[ FACT_BOTTOM_LEVEL_CLEARED ] );
|
|
break;
|
|
|
|
case FACT_FIRST_BARTENDER:
|
|
gubFact[ usFact ] = ( gMercProfiles[ubProfileID].bNPCData == 1 || (gMercProfiles[ubProfileID].bNPCData == 0 && CountBartenders() == 0) );
|
|
break;
|
|
|
|
case FACT_SECOND_BARTENDER:
|
|
gubFact[ usFact ] = ( gMercProfiles[ubProfileID].bNPCData == 2 || (gMercProfiles[ubProfileID].bNPCData == 0 && CountBartenders() == 1) );
|
|
break;
|
|
|
|
case FACT_THIRD_BARTENDER:
|
|
gubFact[ usFact ] = ( gMercProfiles[ubProfileID].bNPCData == 3 || (gMercProfiles[ubProfileID].bNPCData == 0 && CountBartenders() == 2) );
|
|
break;
|
|
|
|
case FACT_FOURTH_BARTENDER:
|
|
gubFact[ usFact ] = ( gMercProfiles[ubProfileID].bNPCData == 4 || (gMercProfiles[ubProfileID].bNPCData == 0 && CountBartenders() == 3) );
|
|
break;
|
|
|
|
case FACT_NPC_NOT_UNDER_FIRE:
|
|
gubFact[usFact] = !CheckNPCIsUnderFire( ubProfileID );
|
|
break;
|
|
|
|
case FACT_KINGPIN_NOT_IN_OFFICE:
|
|
gubFact[usFact] = !( gWorldSectorX == gModSettings.ubKingpinHouseSectorX && gWorldSectorY == gModSettings.ubKingpinHouseSectorY && NPCInRoomRange( KINGPIN, gModSettings.usKingpinRoomRangeStart, gModSettings.usKingpinRoomRangeEnd ) );
|
|
// 30 to 39
|
|
break;
|
|
|
|
case FACT_DONT_OWE_KINGPIN_MONEY:
|
|
gubFact[usFact] = (gubQuest[ QUEST_KINGPIN_MONEY ] != QUESTINPROGRESS);
|
|
break;
|
|
|
|
case FACT_NO_CLUB_FIGHTING_ALLOWED:
|
|
// anv: added !BoxersAvailable, otherwise van Haussen would offer fight even when all boxers are dead
|
|
// silversurfer: additional fix - the check below failed when we killed all boxers because BoxersAvailable() returns 0 in this case.
|
|
// Added additional check for Kingpins location so that the three initial fights can be completed. As soon as Kingpin is gone the original check will apply again.
|
|
SOLDIERTYPE * pKingpin;
|
|
pKingpin = FindSoldierByProfileID( KINGPIN, FALSE );
|
|
if ( pKingpin )
|
|
gubFact[usFact] = ( gubQuest[ QUEST_KINGPIN_MONEY ] == QUESTINPROGRESS || gfBoxersResting || ( !BoxersAvailable() && PythSpacesAway(pKingpin->sGridNo, gModSettings.iKingpinRingTile) > 2 ) );// plus other conditions
|
|
else
|
|
gubFact[usFact] = TRUE;
|
|
break;
|
|
|
|
case FACT_MADDOG_IS_SPEAKER:
|
|
gubFact[usFact] = ( gubSrcSoldierProfile == MADDOG );
|
|
break;
|
|
|
|
case FACT_PC_HAS_CONRADS_RECRUIT_OPINION:
|
|
gubFact[usFact] = ( gpDestSoldier && (CalcDesireToTalk( gpDestSoldier->ubProfile, gubSrcSoldierProfile, APPROACH_RECRUIT ) >= 50) );
|
|
break;
|
|
|
|
case FACT_NPC_HOSTILE_OR_PISSED_OFF:
|
|
gubFact[usFact] = CheckNPCIsEnemy( ubProfileID ) || (gMercProfiles[ ubProfileID ].ubMiscFlags3 & PROFILE_MISC_FLAG3_NPC_PISSED_OFF);
|
|
break;
|
|
|
|
case FACT_TONY_IN_BUILDING:
|
|
gubFact[usFact] = CheckNPCSector( TONY, gModSettings.ubPornShopTonySectorX, gModSettings.ubPornShopTonySectorY, gModSettings.ubPornShopTonySectorZ ) &&
|
|
NPCInRoom( TONY, gModSettings.usPornShopRoomTony );
|
|
break;
|
|
|
|
case FACT_SHANK_SPEAKING:
|
|
gubFact[usFact] = ( gpSrcSoldier && gpSrcSoldier->ubProfile == SHANK );
|
|
break;
|
|
|
|
case FACT_ROCKET_RIFLE_EXISTS:
|
|
gubFact[usFact] = ItemTypeExistsAtLocation( gModSettings.sRocketRifleGridNo, ROCKET_RIFLE, 0, NULL );
|
|
break;
|
|
|
|
case FACT_PABLO_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ PABLO ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
|
|
case FACT_DOREEN_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ DOREEN ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
|
|
case FACT_WALDO_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ WALDO ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
#ifdef JA2UB
|
|
//UB
|
|
#else
|
|
case FACT_PERKO_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ PERKO ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
#endif
|
|
case FACT_TONY_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ TONY ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
|
|
case FACT_VINCE_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ VINCE ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
|
|
case FACT_JENNY_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ JENNY ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
|
|
case FACT_ARNOLD_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ ARNIE ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
|
|
// HEADROCK HAM 3.6: No longer necessarily I16.
|
|
case FACT_BLOODCAT_LAIR_CLEANED:
|
|
gubFact[usFact] = (SectorInfo[ gubBloodcatLairSectorId ].bBloodCats == 0);
|
|
break;
|
|
|
|
case FACT_NPC_BANDAGED_TODAY:
|
|
gubFact[usFact] = (gMercProfiles[ ubProfileID ].ubMiscFlags2 & PROFILE_MISC_FLAG2_BANDAGED_TODAY) != 0;
|
|
break;
|
|
|
|
case FACT_PLAYER_IN_SAME_ROOM:
|
|
gubFact[usFact] = PCInSameRoom( ubProfileID );
|
|
break;
|
|
|
|
case FACT_PLAYER_SPOKE_TO_DRASSEN_MINER:
|
|
gubFact[usFact] = SpokenToHeadMiner( MINE_DRASSEN );
|
|
break;
|
|
case FACT_PLAYER_IN_CONTROLLED_DRASSEN_MINE:
|
|
gubFact[usFact] = ( GetIdOfMineForSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) == MINE_DRASSEN && !(StrategicMap[CALCULATE_STRATEGIC_INDEX(gWorldSectorX, gWorldSectorY)].fEnemyControlled) );
|
|
break;
|
|
case FACT_PLAYER_SPOKE_TO_CAMBRIA_MINER:
|
|
gubFact[usFact] = SpokenToHeadMiner( MINE_CAMBRIA );
|
|
break;
|
|
case FACT_PLAYER_IN_CONTROLLED_CAMBRIA_MINE:
|
|
gubFact[usFact] = ( GetIdOfMineForSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) == MINE_CAMBRIA && !(StrategicMap[CALCULATE_STRATEGIC_INDEX( gWorldSectorX, gWorldSectorY )].fEnemyControlled) );
|
|
break;
|
|
case FACT_PLAYER_SPOKE_TO_CHITZENA_MINER:
|
|
gubFact[usFact] = SpokenToHeadMiner( MINE_CHITZENA );
|
|
break;
|
|
case FACT_PLAYER_IN_CONTROLLED_CHITZENA_MINE:
|
|
gubFact[usFact] = ( GetIdOfMineForSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) == MINE_CHITZENA && !(StrategicMap[CALCULATE_STRATEGIC_INDEX( gWorldSectorX, gWorldSectorY )].fEnemyControlled) );
|
|
break;
|
|
case FACT_PLAYER_SPOKE_TO_ALMA_MINER:
|
|
gubFact[usFact] = SpokenToHeadMiner( MINE_ALMA );
|
|
break;
|
|
case FACT_PLAYER_IN_CONTROLLED_ALMA_MINE:
|
|
gubFact[usFact] = ( GetIdOfMineForSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) == MINE_ALMA && !(StrategicMap[CALCULATE_STRATEGIC_INDEX( gWorldSectorX, gWorldSectorY )].fEnemyControlled) );
|
|
break;
|
|
case FACT_PLAYER_SPOKE_TO_GRUMM_MINER:
|
|
gubFact[usFact] = SpokenToHeadMiner( MINE_GRUMM );
|
|
break;
|
|
case FACT_PLAYER_IN_CONTROLLED_GRUMM_MINE:
|
|
gubFact[usFact] = ( GetIdOfMineForSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) == MINE_GRUMM && !(StrategicMap[CALCULATE_STRATEGIC_INDEX( gWorldSectorX, gWorldSectorY )].fEnemyControlled) );
|
|
break;
|
|
|
|
case FACT_ENOUGH_LOYALTY_TO_TRAIN_MILITIA:
|
|
gubFact[usFact] = InTownSectorWithTrainingLoyalty( gWorldSectorX, gWorldSectorY );
|
|
break;
|
|
|
|
case FACT_WALKER_AT_BAR:
|
|
gubFact[usFact] = (gMercProfiles[ FATHER ].sSectorX == 13 && gMercProfiles[ FATHER ].sSectorY == MAP_ROW_C);
|
|
break;
|
|
|
|
case FACT_JOEY_ALIVE:
|
|
gubFact[usFact] = gMercProfiles[ JOEY ].bMercStatus != MERC_IS_DEAD;
|
|
break;
|
|
|
|
case FACT_UNPROPOSITIONED_FEMALE_SPEAKING_TO_NPC:
|
|
gubFact[usFact] = CheckTalkerUnpropositionedFemale();
|
|
break;
|
|
|
|
case FACT_84_AND_85_TRUE:
|
|
gubFact[usFact] = CheckFact( 84, ubProfileID ) && CheckFact( FACT_HANS_AT_SPOT, ubProfileID );
|
|
break;
|
|
|
|
case FACT_SKYRIDER_IN_B15:
|
|
gubFact[ usFact ] = CheckNPCSector( SKYRIDER, 15, MAP_ROW_B, 0 );
|
|
break;
|
|
|
|
case FACT_SKYRIDER_IN_C16:
|
|
gubFact[ usFact ] = CheckNPCSector( SKYRIDER, 16, MAP_ROW_C, 0 );
|
|
break;
|
|
case FACT_SKYRIDER_IN_E14:
|
|
gubFact[ usFact ] = CheckNPCSector( SKYRIDER, 14, MAP_ROW_E, 0 );
|
|
break;
|
|
case FACT_SKYRIDER_IN_D12:
|
|
gubFact[ usFact ] = CheckNPCSector( SKYRIDER, 12, MAP_ROW_D, 0 );
|
|
break;
|
|
|
|
case FACT_KINGPIN_IS_ENEMY:
|
|
gubFact[usFact] = (gTacticalStatus.fCivGroupHostile[ KINGPIN_CIV_GROUP ] >= CIV_GROUP_WILL_BECOME_HOSTILE);
|
|
break;
|
|
|
|
case FACT_DYNAMO_NOT_SPEAKER:
|
|
gubFact[usFact] = !( gpSrcSoldier != NULL && (gpSrcSoldier->ubProfile == DYNAMO ) );
|
|
break;
|
|
|
|
case FACT_PABLO_BRIBED:
|
|
gubFact[usFact] = !CheckFact( FACT_PABLOS_BRIBED, ubProfileID );
|
|
break;
|
|
|
|
case FACT_VEHICLE_PRESENT:
|
|
gubFact[usFact] = CheckFact( FACT_OK_USE_HUMMER, ubProfileID ) && ( (FindSoldierByProfileID( PROF_HUMMER, TRUE ) != NULL) || (FindSoldierByProfileID( PROF_ICECREAM, TRUE ) != NULL) );
|
|
break;
|
|
|
|
case FACT_PLAYER_KILLED_BOXERS:
|
|
gubFact[usFact] = !BoxerExists();
|
|
break;
|
|
|
|
case FACT_DIMITRI_CAN_BE_RECRUITED: // Can dimitri be recruited? should be true if already true, OR if Miguel has been recruited already OR is available for recruitment
|
|
gubFact[usFact] = ( gubFact[usFact] || FindSoldierByProfileID( MIGUEL, TRUE ) || gubFact[FACT_MIGUEL_AND_ALL_REBELS_CAN_BE_RECRUITED] );
|
|
break;
|
|
/*
|
|
case FACT_:
|
|
gubFact[usFact] = ;
|
|
break;
|
|
*/
|
|
// anv: facts for checking if Waldo can repair helicopter
|
|
|
|
case FACT_HELI_DAMAGED_CAN_START_REPAIR:
|
|
gubFact[usFact] = ( gGameExternalOptions.fWaldoCanRepairHelicopter &&
|
|
!fHelicopterDestroyed && !fHelicopterIsAirBorne && gubHelicopterHitsTaken == 1 &&
|
|
pVehicleList[ iHelicopterVehicleId ].sSectorX == gMercProfiles[ WALDO ].sSectorX && pVehicleList[ iHelicopterVehicleId ].sSectorY == gMercProfiles[ WALDO ].sSectorY &&
|
|
LaptopSaveInfo.iCurrentBalance >= CalculateHelicopterRepairCost( FALSE ) &&
|
|
gubHelicopterHoursToRepair == 0 && CheckFact( FACT_WALDO_MET, 0 ) );
|
|
break;
|
|
|
|
case FACT_HELI_SERIOUSLY_DAMAGED_CAN_START_REPAIR:
|
|
gubFact[usFact] = ( gGameExternalOptions.fWaldoCanRepairHelicopter &&
|
|
!fHelicopterDestroyed && !fHelicopterIsAirBorne && gubHelicopterHitsTaken == 2 &&
|
|
pVehicleList[ iHelicopterVehicleId ].sSectorX == gMercProfiles[ WALDO ].sSectorX && pVehicleList[ iHelicopterVehicleId ].sSectorY == gMercProfiles[ WALDO ].sSectorY &&
|
|
LaptopSaveInfo.iCurrentBalance >= CalculateHelicopterRepairCost( TRUE ) &&
|
|
gubHelicopterHoursToRepair == 0 && CheckFact( FACT_WALDO_MET, 0 ) );
|
|
break;
|
|
|
|
case FACT_HELI_GIVEN_MONEY_CAN_START_REPAIR:
|
|
gubFact[usFact] = ( ( gGameExternalOptions.fWaldoCanRepairHelicopter &&
|
|
!fHelicopterDestroyed && !fHelicopterIsAirBorne && gubHelicopterHitsTaken > 0 &&
|
|
pVehicleList[ iHelicopterVehicleId ].sSectorX == gMercProfiles[ WALDO ].sSectorX && pVehicleList[ iHelicopterVehicleId ].sSectorY == gMercProfiles[ WALDO ].sSectorY &&
|
|
gubHelicopterHoursToRepair == 0 ) &&
|
|
( CheckFact(FACT_GIVEN_ENOUGH_TO_REPAIR_HELI, 0) || CheckFact(FACT_GIVEN_ENOUGH_TO_SERIOUSLY_REPAIR_HELI, 0) ) && CheckFact( FACT_WALDO_MET, 0 ) );
|
|
break;
|
|
|
|
case FACT_HELI_CANT_START_REPAIR:
|
|
gubFact[usFact] = ( !CheckFact(FACT_HELI_GIVEN_MONEY_CAN_START_REPAIR, 0) && !CheckFact(FACT_HELICOPTER_IN_PERFECT_CONDITION, 0));
|
|
break;
|
|
|
|
case FACT_HELICOPTER_IN_PERFECT_CONDITION:
|
|
gubFact[usFact] = ( gubHelicopterHitsTaken == 0 );
|
|
break;
|
|
|
|
case FACT_HELICOPTER_LOST:
|
|
gubFact[usFact] = fHelicopterDestroyed;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//#endif
|
|
return( gubFact[usFact] );
|
|
}
|
|
|
|
void SetFact( UINT16 usFact, UINT8 aVal )
|
|
{
|
|
if ( usFact < NUM_FACTS )
|
|
gubFact[usFact] = aVal;
|
|
}
|
|
|
|
UINT8 GetFact( UINT16 usFact )
|
|
{
|
|
return gubFact[usFact];
|
|
}
|
|
|
|
void StartQuest( UINT8 ubQuest, INT16 sSectorX, INT16 sSectorY )
|
|
{
|
|
DebugQuestInfo(String("start quest %d sector %d %d", ubQuest, sSectorX, sSectorY));
|
|
InternalStartQuest( ubQuest, sSectorX, sSectorY, TRUE );
|
|
}
|
|
|
|
|
|
void InternalStartQuest( UINT8 ubQuest, INT16 sSectorX, INT16 sSectorY, BOOLEAN fUpdateHistory )
|
|
{
|
|
#ifdef LUA_QUESTS
|
|
LuaInternalQuest( ubQuest, sSectorX, sSectorY, fUpdateHistory, 1);
|
|
#else
|
|
if ( gubQuest[ubQuest ] == QUESTNOTSTARTED )
|
|
{
|
|
gubQuest[ubQuest] = QUESTINPROGRESS;
|
|
|
|
if ( fUpdateHistory )
|
|
{
|
|
if (!is_networked)
|
|
SetHistoryFact( HISTORY_QUEST_STARTED, ubQuest, GetWorldTotalMin(), sSectorX, sSectorY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gubQuest[ubQuest] = QUESTINPROGRESS;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void EndQuest( UINT8 ubQuest, INT16 sSectorX, INT16 sSectorY )
|
|
{
|
|
DebugQuestInfo(String("end quest %d sector %d %d", ubQuest, sSectorX, sSectorY));
|
|
InternalEndQuest( ubQuest, sSectorX, sSectorY, TRUE );
|
|
}
|
|
|
|
void InternalEndQuest( UINT8 ubQuest, INT16 sSectorX, INT16 sSectorY, BOOLEAN fUpdateHistory )
|
|
{
|
|
|
|
#ifdef LUA_QUESTS
|
|
LuaInternalQuest( ubQuest, sSectorX, sSectorY, fUpdateHistory, 0);
|
|
#else
|
|
|
|
// SANDRO merc records - quests handled counter
|
|
if ( gubQuest[ubQuest] != QUESTDONE && fUpdateHistory ) // only public quests
|
|
{
|
|
switch (ubQuest)
|
|
{
|
|
case QUEST_FOOD_ROUTE :
|
|
// food quest is handled differently (completing when spoken to father Walker)
|
|
break;
|
|
case QUEST_DELIVER_LETTER :
|
|
case QUEST_LEATHER_SHOP_DREAM :
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 3, NO_PROFILE );
|
|
break;
|
|
case QUEST_ESCORT_SKYRIDER :
|
|
case QUEST_CHOPPER_PILOT :
|
|
case QUEST_FREE_CHILDREN :
|
|
case QUEST_RESCUE_MARIA :
|
|
case QUEST_FIND_SCIENTIST :
|
|
case QUEST_DELIVER_VIDEO_CAMERA :
|
|
case QUEST_FIND_HERMIT :
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 4, NO_PROFILE );
|
|
break;
|
|
case QUEST_FREE_DYNAMO :
|
|
// don't give Dynamo reward for himself
|
|
if( gMercProfiles[ DYNAMO ].bMercStatus != MERC_IS_DEAD )
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 4, DYNAMO );
|
|
break;
|
|
case QUEST_KINGPIN_IDOL :
|
|
case QUEST_CHITZENA_IDOL :
|
|
case QUEST_HELD_IN_ALMA :
|
|
case QUEST_HELD_IN_TIXA :
|
|
case QUEST_RUNAWAY_JOEY :
|
|
case QUEST_ESCORT_TOURISTS :
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 5, NO_PROFILE );
|
|
break;
|
|
case QUEST_ARMY_FARM :
|
|
case QUEST_KINGPIN_MONEY :
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 6, NO_PROFILE );
|
|
break;
|
|
case QUEST_BLOODCATS :
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 7, NO_PROFILE );
|
|
break;
|
|
case QUEST_INTERROGATION : // we get here only if wiped out enemies after interrogation
|
|
case QUEST_CREATURES :
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 8, NO_PROFILE );
|
|
break;
|
|
case QUEST_KILL_TERRORISTS : // only reduced experiences if we chosen Slay over Carmen
|
|
if( gMercProfiles[ CARMEN ].bMercStatus == MERC_IS_DEAD )
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 5, NO_PROFILE );
|
|
else
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 9, NO_PROFILE );
|
|
break;
|
|
#ifdef JA2UB
|
|
//off
|
|
#else
|
|
case QUEST_KILL_DEIDRANNA :
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 25, NO_PROFILE );
|
|
break;
|
|
#endif
|
|
default :
|
|
GiveQuestRewardPoint( sSectorX, sSectorY, 4, NO_PROFILE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( gubQuest[ubQuest ] == QUESTINPROGRESS )
|
|
{
|
|
gubQuest[ubQuest] = QUESTDONE;
|
|
|
|
if ( fUpdateHistory )
|
|
{
|
|
ResetHistoryFact( ubQuest, sSectorX, sSectorY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gubQuest[ubQuest] = QUESTDONE;
|
|
}
|
|
|
|
if ( ubQuest == QUEST_RESCUE_MARIA )
|
|
{
|
|
// cheap hack to try to prevent Madame Layla from thinking that you are
|
|
// still in the brothel with Maria...
|
|
gMercProfiles[ MADAME ].bNPCData = 0;
|
|
gMercProfiles[ MADAME ].bNPCData2 = 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef JA2UB
|
|
//if the quest is the FIX LAPTOP quest
|
|
if( ubQuest == QUEST_FIX_LAPTOP && gGameUBOptions.LaptopQuestEnabled == TRUE )
|
|
{
|
|
//Set the fact that AIM and MERC should start selling
|
|
gJa25SaveStruct.fHaveAimandMercOffferItems = TRUE;
|
|
|
|
//Remeber that we should send email in the next sector
|
|
gJa25SaveStruct.fSendEmail_10_NextSector = TRUE;
|
|
|
|
AddEmail( EMAIL_PILOTMISSING, EMAIL_PILOTMISSING_LENGTH, MAIL_ENRICO, GetWorldTotalMin() ,-1,-1, TYPE_EMAIL_EMAIL_EDT);
|
|
AddEmail( EMAIL_MAKECONTACT, EMAIL_MAKECONTACT_LENGTH, MAIL_ENRICO, GetWorldTotalMin() ,-1,-1, TYPE_EMAIL_EMAIL_EDT);
|
|
|
|
//Merc and Aim emails
|
|
AddEmail( EMAIL_AIM_PROMOTION_1, EMAIL_AIM_PROMOTION_1_LENGTH, AIM_SITE, GetWorldTotalMin(),-1 ,-1, TYPE_EMAIL_EMAIL_EDT);
|
|
AddEmail( EMAIL_MERC_PROMOTION_1, EMAIL_MERC_PROMOTION_1_LENGTH, SPECK_FROM_MERC, GetWorldTotalMin(),-1,-1, TYPE_EMAIL_EMAIL_EDT);
|
|
AddEmail( EMAIL_AIM_PROMOTION_2, EMAIL_AIM_PROMOTION_2_LENGTH, AIM_SITE, GetWorldTotalMin(),-1 ,-1, TYPE_EMAIL_EMAIL_EDT);
|
|
|
|
//Manuel
|
|
{
|
|
SOLDIERTYPE *pSoldier=NULL;
|
|
|
|
pSoldier = FindSoldierByProfileID( MANUEL_UB , TRUE ); //MANUEL
|
|
|
|
if( pSoldier != NULL )
|
|
{
|
|
//Add the Manuel email
|
|
AddEmail( EMAIL_MANUEL, EMAIL_MANUEL_LENGTH, MAIL_ENRICO, GetWorldTotalMin() ,-1, -1, TYPE_EMAIL_EMAIL_EDT);
|
|
}
|
|
}
|
|
|
|
//Miguel
|
|
{
|
|
//if miguel was dead, when importing the save
|
|
if( gubFact[ FACT_PLAYER_IMPORTED_SAVE_MIGUEL_DEAD ] == FALSE )
|
|
{
|
|
//Add the miguel email
|
|
AddEmail( EMAIL_MIGUELHELLO, EMAIL_MIGUELHELLO_LENGTH, MAIL_MIGUEL, GetWorldTotalMin(),-1, -1, TYPE_EMAIL_EMAIL_EDT);
|
|
}
|
|
}
|
|
|
|
//If any aim mercs were asked to send emails when the get back from duty elsewhere
|
|
HandleAddingAnyAimAwayEmailsWhenLaptopGoesOnline();
|
|
|
|
//Should we send the IMP reminder email when we go back online
|
|
ShouldImpReminderEmailBeSentWhenLaptopBackOnline();
|
|
|
|
//Force which ever of these emails that needed to be sent, to be sent
|
|
HandleEmailBeingSentWhenEnteringSector( 0, 0, 0, TRUE );
|
|
}
|
|
#endif
|
|
};
|
|
|
|
void InitQuestEngine()
|
|
{
|
|
memset(gubQuest, 0, sizeof(gubQuest));
|
|
memset(gubFact, 0, sizeof(gubFact));
|
|
|
|
DebugQuestInfo(String("\nInit Quest Engine"));
|
|
|
|
// semi-hack to make the letter quest start right away
|
|
CheckForQuests( 1 );
|
|
|
|
if ( gGameOptions.ubGameStyle == STYLE_SCIFI )
|
|
{
|
|
// 3 medical boosters
|
|
gubCambriaMedicalObjects = 21;
|
|
}
|
|
else
|
|
{
|
|
gubCambriaMedicalObjects = 18;
|
|
}
|
|
|
|
gubBoxingMatchesWon = 0;
|
|
gubBoxersRests = 0;
|
|
gfBoxersResting = FALSE;
|
|
|
|
InitLUAModderData( );
|
|
|
|
DebugQuestInfo(String("reset gubBoxersRests 0, gubBoxingMatchesWon 0, gfBoxersResting FALSE gubCambriaMedicalObjects %d", gubCambriaMedicalObjects));
|
|
}
|
|
|
|
|
|
|
|
void CheckForQuests( UINT32 uiDay )
|
|
{
|
|
// This function gets called at 8:00 AM time of the day
|
|
|
|
ScreenMsg( MSG_FONT_RED, MSG_DEBUG, L"Checking For Quests, Day %d", uiDay );
|
|
|
|
#ifdef JA2UB
|
|
// -------------------------------------------------------------------------------
|
|
// QUEST 23 : Detroy missles
|
|
// -------------------------------------------------------------------------------
|
|
// The game always starts with destrouy missles quest, so turn it on if it hasn't
|
|
// already started
|
|
if( gubQuest[ QUEST_DESTROY_MISSLES ] == QUESTNOTSTARTED )
|
|
{
|
|
StartQuest( QUEST_DESTROY_MISSLES, -1, -1 );
|
|
ScreenMsg( MSG_FONT_RED, MSG_DEBUG, L"Started DESTORY MISSLES quest");
|
|
}
|
|
//Ja25: No deliver letter quest, dont start it
|
|
#else
|
|
// -------------------------------------------------------------------------------
|
|
// QUEST 0 : DELIVER LETTER
|
|
// -------------------------------------------------------------------------------
|
|
// The game always starts with DELIVER LETTER quest, so turn it on if it hasn't
|
|
// already started
|
|
if (gubQuest[QUEST_DELIVER_LETTER] == QUESTNOTSTARTED)
|
|
{
|
|
StartQuest( QUEST_DELIVER_LETTER, -1, -1 );
|
|
|
|
if (!is_networked)
|
|
ScreenMsg( MSG_FONT_RED, MSG_DEBUG, L"Started DELIVER LETTER quest");
|
|
}
|
|
#endif
|
|
// This quest gets turned OFF through conversation with Miguel - when user hands
|
|
// Miguel the letter
|
|
}
|
|
|
|
|
|
BOOLEAN SaveQuestInfoToSavedGameFile( HWFILE hFile )
|
|
{
|
|
UINT32 uiNumBytesWritten;
|
|
|
|
//Save all the states if the Quests
|
|
FileWrite( hFile, gubQuest, MAX_QUESTS, &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != MAX_QUESTS )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
//Save all the states for the facts
|
|
FileWrite( hFile, gubFact, NUM_FACTS, &uiNumBytesWritten );
|
|
if( uiNumBytesWritten != NUM_FACTS )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN LoadQuestInfoFromSavedGameFile( HWFILE hFile, UINT8 MaxQuest )
|
|
{
|
|
UINT32 uiNumBytesRead;
|
|
|
|
//Save all the states if the Quests
|
|
//FileRead( hFile, gubQuest, MAX_QUESTS, &uiNumBytesRead );
|
|
//if( uiNumBytesRead != MAX_QUESTS )
|
|
FileRead( hFile, gubQuest, MaxQuest, &uiNumBytesRead );
|
|
if( uiNumBytesRead != MaxQuest )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
//Save all the states for the facts
|
|
FileRead( hFile, gubFact, NUM_FACTS, &uiNumBytesRead );
|
|
if( uiNumBytesRead != NUM_FACTS )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
// Flugente: a huge array that can be used exclusively by modders
|
|
BOOLEAN SaveLUAModderDataToSavedGameFile( HWFILE hFile )
|
|
{
|
|
UINT32 uiNumBytesWritten;
|
|
|
|
//Save all the states for the facts
|
|
FileWrite( hFile, gubModderLuaData, sizeof(INT32)* MODDER_LUA_DATA_MAX, &uiNumBytesWritten );
|
|
if ( uiNumBytesWritten != sizeof(INT32)* MODDER_LUA_DATA_MAX )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOLEAN LoadLUAModderDataFromSavedGameFile( HWFILE hFile )
|
|
{
|
|
UINT32 uiNumBytesRead;
|
|
|
|
//Save all the states for the facts
|
|
FileRead( hFile, gubModderLuaData, sizeof(INT32)* MODDER_LUA_DATA_MAX, &uiNumBytesRead );
|
|
if ( uiNumBytesRead != sizeof(INT32)* MODDER_LUA_DATA_MAX )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
void InitLUAModderData( )
|
|
{
|
|
memset( gubModderLuaData, 0, sizeof(gubModderLuaData) );
|
|
}
|
|
|
|
|
|
// SANDRO - a function to add quest-done point to merc records, and award some exp possibly
|
|
void GiveQuestRewardPoint( INT16 sQuestSectorX, INT16 sQuestsSectorY, INT8 bExpReward, UINT8 bException )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTBLUE, MSG_TESTVERSION, L"QUEST COMPLETED - Adding to merc records and awarding experiences (%d).", (bExpReward * gGameExternalOptions.usAwardSpecialExpForQuests) );
|
|
|
|
for ( UINT16 i = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; i <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; i++ )
|
|
{
|
|
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife >= CONSCIOUSNESS && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) && MercPtrs[ i ]->ubProfile != NO_PROFILE &&
|
|
MercPtrs[ i ]->sSectorX == sQuestSectorX && MercPtrs[ i ]->sSectorY == sQuestsSectorY && !MercPtrs[ i ]->flags.fBetweenSectors && MercPtrs[ i ]->bTeam == gbPlayerNum &&
|
|
MercPtrs[ i ]->bAssignment != IN_TRANSIT && MercPtrs[ i ]->bAssignment != ASSIGNMENT_DEAD && gMercProfiles[ MercPtrs[ i ]->ubProfile ].ubBodyType != 21 ) // != ROBOTNOWEAPON )
|
|
{
|
|
if ( MercPtrs[ i ]->ubProfile != bException )
|
|
{
|
|
gMercProfiles[ MercPtrs[ i ]->ubProfile ].records.ubQuestsHandled++;
|
|
|
|
if ( bExpReward > 0 && gGameExternalOptions.usAwardSpecialExpForQuests > 0 )
|
|
StatChange( MercPtrs[ i ], EXPERAMT, (bExpReward * gGameExternalOptions.usAwardSpecialExpForQuests), FALSE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlePOWQuestState(PowQuestState state, Quests quest, INT16 mapX, INT16 mapY, INT8 mapZ)
|
|
{
|
|
#ifndef JA2UB
|
|
bool correctSector = false;
|
|
switch (quest)
|
|
{
|
|
case QUEST_HELD_IN_ALMA:
|
|
correctSector = (mapX == gModSettings.ubInitialPOWSectorX && mapY == gModSettings.ubInitialPOWSectorY && mapZ == 0);
|
|
break;
|
|
case QUEST_INTERROGATION:
|
|
correctSector = (mapX == gModSettings.ubMeanwhileInterrogatePOWSectorX && mapY == gModSettings.ubMeanwhileInterrogatePOWSectorY && mapZ == 0);
|
|
break;
|
|
case QUEST_HELD_IN_TIXA:
|
|
correctSector = (mapX == gModSettings.ubTixaPrisonSectorX && mapY == gModSettings.ubTixaPrisonSectorY && mapZ == 0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (correctSector)
|
|
{
|
|
switch (state)
|
|
{
|
|
case Q_FAIL:
|
|
// End quest if player loses prison
|
|
if (gubQuest[quest] == QUESTINPROGRESS)
|
|
{
|
|
// Quest failed
|
|
InternalEndQuest(quest, mapX, mapY, FALSE);
|
|
}
|
|
else if (gubQuest[quest] == QUESTCANNOTSTART)
|
|
{
|
|
// Re-enable quest if player loses control of the prison and quest was disabled previously
|
|
gubQuest[quest] = QUESTNOTSTARTED;
|
|
}
|
|
break;
|
|
case Q_SUCCESS:
|
|
// End quest if player takes control of the prison
|
|
if (gubQuest[quest] == QUESTINPROGRESS)
|
|
{
|
|
// Complete quest
|
|
EndQuest(quest, mapX, mapY);
|
|
}
|
|
else if (gubQuest[quest] == QUESTNOTSTARTED)
|
|
{
|
|
// Disable quest if player takes control of the prison
|
|
gubQuest[quest] = QUESTCANNOTSTART;
|
|
}
|
|
break;
|
|
case Q_RESET:
|
|
// Re-enable quest if player loses control of the prison and quest was disabled previously
|
|
if (gubQuest[quest] == QUESTCANNOTSTART)
|
|
{
|
|
gubQuest[quest] = QUESTNOTSTARTED;
|
|
}
|
|
break;
|
|
case Q_END:
|
|
if (gubQuest[quest] == QUESTINPROGRESS)
|
|
{
|
|
EndQuest(quest, mapX, mapY);
|
|
HandleNPCDoAction(0, NPC_ACTION_GRANT_EXPERIENCE_3, 0);
|
|
}
|
|
break;
|
|
case Q_LEFT_SECTOR:
|
|
// End interrogation quest if we left the sector, but haven't killed all enemies
|
|
if (gubQuest[quest] == QUESTINPROGRESS)
|
|
{
|
|
// Finish quest, although not give points here...
|
|
InternalEndQuest(quest, mapX, mapY, FALSE);
|
|
// ... give them manually, but halved
|
|
GiveQuestRewardPoint(mapX, mapY, 4, NO_PROFILE);
|
|
// Also let us know we finished the quest
|
|
ResetHistoryFact(quest, mapX, mapY);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|