// Framework headers #include "fwmaths/angle.h" #include "fwmaths/Vector.h" // Game headers #include "camera/CamInterface.h" #include "frontend/MiniMap.h" #include "frontend/Map/BlipEnums.h" #include "peds/PedIntelligence.h" #include "scene/world/GameWorld.h" #include "game/ModelIndices.h" #include "task/System/TaskTypes.h" // Network headers #include "network/NetworkInterface.h" #include "network/Live/livemanager.h" #include "network/objects/entities/NetObjPlayer.h" #include "script/script.h" #include "script/script_hud.h" #include "script/script_helper.h" #include "audio/scriptaudioentity.h" #include "script_ai_blips.h" // DON'T COMMIT //OPTIMISATIONS_OFF() ////////////////////////// // CScriptPedAIBlips ////////////////////////// // TODO: Make tunable? float CScriptPedAIBlips::WEAPON_RANGE_MULTIPLIER_FOR_BLIPS = 2.5f; float CScriptPedAIBlips::HEARD_RADIUS = 100.0f; float CScriptPedAIBlips::BLIP_SIZE_VEHICLE = 1.0f; float CScriptPedAIBlips::BLIP_SIZE_NETWORK_VEHICLE = 1.0f; float CScriptPedAIBlips::BLIP_SIZE_PED = 0.7f; float CScriptPedAIBlips::BLIP_SIZE_NETWORK_PED = 0.7f; float CScriptPedAIBlips::BLIP_SIZE_OBJECT = 0.7f; float CScriptPedAIBlips::BLIP_SIZE_NETWORK_OBJECT = 0.85f; int CScriptPedAIBlips::NOTICABLE_TIME = 3500; int CScriptPedAIBlips::BLIP_FADE_PERIOD = 1400; atArray CScriptPedAIBlips::m_PedsAndBlips; void CScriptPedAIBlips::Init(unsigned UNUSED_PARAM(initMode)) { // Remove all registered blips/peds Reset(); } void CScriptPedAIBlips::Shutdown(unsigned UNUSED_PARAM(shutdownMode)) { // Remove all registered blips/peds Reset(); } void CScriptPedAIBlips::Update() { UpdatePedAIBlips(); } void CScriptPedAIBlips::UpdatePedAIBlips() { for(int i=m_PedsAndBlips.size()-1; i>=0; i--) { AIBlip &theBlip = m_PedsAndBlips[i]; bool bRemove = true; // Assume we want to remove this ped unless we find otherwise //Check if the script has gone, if so, delete this reference. scrThread *pScriptThread = scrThread::GetThread(static_cast(theBlip.scrThreadID)); // If no thread, remove == true, otherwise, remove == whether the ped is dead or not if( pScriptThread ) { bRemove = theBlip.Update(); // Returns true if the ped is dead or otherwise gone. } if(bRemove) { theBlip.CleanupBlip(); m_PedsAndBlips.DeleteFast( i ); } } } bool CScriptPedAIBlips::IsExclusiveOwnerOfBlip(const AIBlip* referencingObject, s32 iBlipId) { for(int i=m_PedsAndBlips.size()-1; i>=0; i--) { AIBlip &theBlip = m_PedsAndBlips[i]; if( &theBlip == referencingObject ) continue; if( theBlip.VehicleBlipID == iBlipId || theBlip.BlipID == iBlipId ) return false; } return true; } // Sets a Ped to use AI blips (or not) void CScriptPedAIBlips::SetPedHasAIBlip(s32 threadId, s32 PedID, bool bSet, s32 colourOverride) { // Check if this ped is already registered for ai blips int index = FindPedIDIndex(PedID); if( bSet && index == -1 ) { // We want to register a ped AI Blip, it's not already registered AIBlip &thisBlip = m_PedsAndBlips.Grow(); thisBlip.Init( PedID, threadId, colourOverride ); } else if( !bSet && index != -1 ) { AIBlip &thisBlip = m_PedsAndBlips[index]; thisBlip.CleanupBlip(); m_PedsAndBlips.DeleteFast( index ); } } bool CScriptPedAIBlips::DoesPedhaveAIBlip(s32 PedID) { int index = FindPedIDIndex(PedID); if( index != -1 ) { return true; } return false; } void CScriptPedAIBlips::SetPedAIBlipGangID(s32 PedID, s32 GangID) { int index = FindPedIDIndex(PedID); if(index != -1) { AIBlip &theBlip = m_PedsAndBlips[index]; theBlip.iBlipGang = GangID; } } void CScriptPedAIBlips::SetPedHasConeAIBlip(s32 PedID, bool bSet) { int index = FindPedIDIndex(PedID); if(index != -1) { AIBlip &theBlip = m_PedsAndBlips[index]; theBlip.bShowCone = bSet; } } void CScriptPedAIBlips::SetPedHasForcedBlip(s32 PedID, bool bOnOff) { int index = FindPedIDIndex(PedID); if(index != -1) { AIBlip &theBlip = m_PedsAndBlips[index]; theBlip.bForceBlipOn = bOnOff; } } void CScriptPedAIBlips::SetPedAIBlipNoticeRange(s32 PedID, float range) { int index = FindPedIDIndex(PedID); if(index != -1) { AIBlip &theBlip = m_PedsAndBlips[index]; theBlip.fNoticableRadius = range; } } void CScriptPedAIBlips::SetPedAIBlipChangeColour(s32 PedID) { int index = FindPedIDIndex(PedID); if(index != -1) { AIBlip &theBlip = m_PedsAndBlips[index]; theBlip.bChangeColour = true; } } void CScriptPedAIBlips::SetPedAIBlipSprite(s32 PedID, int spriteID) { int index = FindPedIDIndex(PedID); if(index != -1) { AIBlip &theBlip = m_PedsAndBlips[index]; bool bShowHeight = false; // retain the flag when we change the sprite CMiniMapBlip *pBlip = CMiniMap::GetBlip(theBlip.BlipID); if (pBlip) { bShowHeight = CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_SHOW_HEIGHT); } CMiniMap::SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, theBlip.BlipID, spriteID); CMiniMap::SetBlipParameter(BLIP_CHANGE_SHOW_HEIGHT, theBlip.BlipID, bShowHeight); } } s32 CScriptPedAIBlips::GetAIBlipPedBlipIDX(s32 PedID) { int index = FindPedIDIndex(PedID); if(index != -1) { AIBlip &theBlip = m_PedsAndBlips[index]; return theBlip.BlipID; } return INVALID_BLIP_ID; } s32 CScriptPedAIBlips::GetAIBlipVehicleBlipIDX(s32 PedID) { int index = FindPedIDIndex(PedID); if(index != -1) { AIBlip &theBlip = m_PedsAndBlips[index]; return theBlip.VehicleBlipID; } return INVALID_BLIP_ID; } void CScriptPedAIBlips::Reset() { for(int i=0;i(pedID, 0); if( pPed ) { // If the ped already has a blip, make sure we know about it BlipID = GetBlipFromEntity(pPed); if (NetworkInterface::IsGameInProgress() && pPed->GetNetworkObject()) { scriptDebugf1("Adding network ped blip : %s (%p)",pPed->GetNetworkObject()->GetLogName(), pPed); } } } // returns TRUE if the ped is injured/doesn't exist, FALSE if the ped is still uninjured. bool CScriptPedAIBlips::AIBlip::Update() { CPed *pFocusPed = NULL; if ( NetworkInterface::IsGameInProgress() && NetworkInterface::IsInSpectatorMode() ) { pFocusPed = const_cast(camInterface::FindFollowPed()); } else { pFocusPed = CGameWorld::GetMainPlayerInfo()->GetPlayerPed(); } CPed *pPed = CTheScripts::GetEntityToModifyFromGUID(pedID, 0); // If there's no entity then there's not a lot that can be done. if( pPed && pFocusPed) { if(!pPed->IsInjured()) { if(!bIsFadingOut && (bForceBlipOn || IsPedNoticableToPlayer(pPed, pFocusPed, fNoticableRadius, bRespondingToSpecialAbility, iResponseTimer, iResponseTime))) { if( pPed->GetIsInVehicle() ) { eBLIP_COLOURS blipColour = BLIP_COLOUR_MAX; //if ped is in any vehicle if( DoesBlipExist(BlipID) ) { // cache off the ped blip for when we recreate it blipColour = CMiniMap::GetBlipColourValue( CMiniMap::GetBlip(BlipID) ); RemoveBlip(BlipID); } if( !DoesBlipExist(BlipID) ) { if( !DoesBlipExist(VehicleBlipID) ) { CVehicle *pVehicle = pPed->GetVehiclePedInside(); if(pVehicle) { if( !DoesBlipExist( GetBlipFromEntity(pVehicle) ) ) { VehicleBlipID = CreateBlipForVehicle(pVehicle, true); if( NetworkInterface::IsGameInProgress() ) { CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(pVehicle->GetModelId()); if( blipColour == BLIP_COLOUR_MAX ) blipColour = CMiniMap::GetBlipColourValue( CMiniMap::GetBlip(VehicleBlipID) ); if(pModelInfo && pModelInfo->GetModelType()==MI_TYPE_VEHICLE && ((CVehicleModelInfo*)pModelInfo)->GetVehicleType()==VEHICLE_TYPE_HELI) { CMiniMap::SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, VehicleBlipID, RADAR_TRACE_PLAYER_HELI); // RADAR_TRACE_ENEMY_HELI_SPIN can't be recolored } else if(pModelInfo && pModelInfo->GetModelType()==MI_TYPE_VEHICLE && ((CVehicleModelInfo*)pModelInfo)->GetVehicleType()==VEHICLE_TYPE_PLANE) { CMiniMap::SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, VehicleBlipID, BLIP_POLICE_PLANE_MOVE); CMiniMap::SetBlipParameter(BLIP_CHANGE_SHOW_HEIGHT, VehicleBlipID, true); // always show height } else { CMiniMap::SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, VehicleBlipID, RADAR_TRACE_AI); CMiniMap::SetBlipParameter(BLIP_CHANGE_SHOW_HEIGHT, VehicleBlipID, true); // always show height } CMiniMap::SetBlipParameter(BLIP_CHANGE_COLOUR, VehicleBlipID, blipColourOverride != BLIP_COLOUR_MAX ? blipColourOverride : (int)blipColour); } } else { VehicleBlipID = GetBlipFromEntity(pVehicle); } } } // blip DOES exist: // maintain directional blips else if( NetworkInterface::IsGameInProgress() ) { if( CMiniMap::GetBlipObjectNameId( CMiniMap::GetBlip(VehicleBlipID) ) == BLIP_POLICE_PLANE_MOVE ) { if( CVehicle *pVehicle = pPed->GetVehiclePedInside() ) { Matrix34 mat = MAT34V_TO_MATRIX34( pVehicle->GetMatrix() ); Vector3 eulers; mat.ToEulersYXZ( eulers ); // MAY need to check for Gimbal Lock, but currently script isn't either in the place it's faking it, so... fuck it? // also, the AI won't ascend/descend steeply, so for us, this works fine. float fHeading = rage::Wrap( (RtoD * eulers.z), 0.0f, 360.0f ); CMiniMap::SetBlipParameter( BLIP_CHANGE_DIRECTION, VehicleBlipID, fHeading); } } // Make sure the blip is visible CMiniMap::SetBlipParameter(BLIP_CHANGE_ALPHA, VehicleBlipID, 255); } } } else { eBLIP_COLOURS blipColour = BLIP_COLOUR_MAX; //if ped is not in any vehicle if( DoesBlipExist(VehicleBlipID) ) { // cache off the vehicle blip for when we recreate it blipColour = CMiniMap::GetBlipColourValue( CMiniMap::GetBlip(VehicleBlipID) ); RemoveBlip(VehicleBlipID, true); if (!DoesBlipExist(BlipID)) { pPed->SetCreatedBlip(false); // ped blip doesn't currently exist but it should - clear flag to ensure that happens now. } } if( !DoesBlipExist(BlipID) ) { if(!pPed->GetCreatedBlip()) { BlipID = AddBlipForEntity(pPed); CMiniMap::SetBlipParameter(BLIP_CHANGE_SCALE, BlipID, NetworkInterface::IsGameInProgress() ? CScriptPedAIBlips::BLIP_SIZE_NETWORK_PED : CScriptPedAIBlips::BLIP_SIZE_PED); CMiniMap::SetBlipParameter(BLIP_CHANGE_PRIORITY, BlipID, GetCorrectBlipPriority(BLIP_PRIORITY_ENEMY_AI)); if( NetworkInterface::IsGameInProgress() ) { if( blipColour == BLIP_COLOUR_MAX ) blipColour = CMiniMap::GetBlipColourValue( CMiniMap::GetBlip(BlipID) ); CMiniMap::SetBlipParameter(BLIP_CHANGE_OBJECT_NAME, BlipID, RADAR_TRACE_AI); CMiniMap::SetBlipParameter(BLIP_CHANGE_COLOUR, BlipID, blipColourOverride != BLIP_COLOUR_MAX ? blipColourOverride : (int)blipColour); SetBlipNameFromTextFile(BlipID, "BN_ENEMY"); } } } if( DoesBlipExist(BlipID) ) { switch( iBlipGang ) { case BLIP_GANG_PROFESSIONAL: { CRGBA rgba = CHudColour::GetRGBA((eHUD_COLOURS)HUD_COLOUR_NET_PLAYER29); CMiniMap::SetBlipParameter(BLIP_CHANGE_COLOUR, BlipID, blipColourOverride != BLIP_COLOUR_MAX ? blipColourOverride : (int)rgba.GetColor()); SetBlipNameFromTextFile(BlipID, "PROFESSIONAL_BLIP"); } break; case BLIP_GANG_FRIENDLY: CMiniMap::SetBlipParameter(BLIP_CHANGE_FRIENDLY, BlipID, true); break; case BLIP_GANG_ENEMY: CMiniMap::SetBlipParameter(BLIP_CHANGE_FRIENDLY, BlipID, false); break; } // turn blip cone on or off CMiniMap::SetBlipParameter(BLIP_CHANGE_SHOW_CONE, BlipID, bShowCone); // make sure blip is fully faded in CMiniMap::SetBlipParameter(BLIP_CHANGE_ALPHA, BlipID, 255); CMiniMap::SetBlipParameter(BLIP_CHANGE_SHOW_HEIGHT, BlipID, true); // always show height CScriptHud::GetBlipFades().RemoveBlipFade(BlipID); } } bIsFadingOut = false; bChangeColour = false; // reset timers if( NetworkInterface::IsGameInProgress() ) { iNoticableTimer = GetNetworkGameTimer(); } else { iNoticableTimer_SP = GetGameTimer(); } } else { if( DoesBlipExist(VehicleBlipID) ) { HandleBlipFade(true); } if( DoesBlipExist(BlipID) ) { switch( iBlipGang ) { case BLIP_GANG_PROFESSIONAL: { CRGBA rgba = CHudColour::GetRGBA((eHUD_COLOURS)HUD_COLOUR_NET_PLAYER29); CMiniMap::SetBlipParameter(BLIP_CHANGE_COLOUR, BlipID, blipColourOverride != BLIP_COLOUR_MAX ? blipColourOverride : (int)rgba.GetColor()); SetBlipNameFromTextFile(BlipID, "PROFESSIONAL_BLIP"); } break; case BLIP_GANG_FRIENDLY: CMiniMap::SetBlipParameter(BLIP_CHANGE_FRIENDLY, BlipID, true); break; case BLIP_GANG_ENEMY: CMiniMap::SetBlipParameter(BLIP_CHANGE_FRIENDLY, BlipID, false); break; } HandleBlipFade(false); if( bChangeColour ) { if( NetworkInterface::IsGameInProgress() ) { CMiniMap::SetBlipParameter(BLIP_CHANGE_COLOUR, BlipID, BLIP_COLOUR_RED); } bChangeColour = false; } } } } else { // Dead or injured // delete blip return true; } // Not injured or dead return false; } // No ped to reference return true; } void CScriptPedAIBlips::AIBlip::HandleBlipFade( bool isVehicle ) { float fPhase = 0.0f; if( bIsFadingOut == false ) { bool bShouldFadeOut = false; if( NetworkInterface::IsGameInProgress() ) { int time = GetNetworkGameTimer(); if( (time - iNoticableTimer) > NOTICABLE_TIME ) { bShouldFadeOut = true; } } else { if( (GetGameTimer() - iNoticableTimer_SP) > NOTICABLE_TIME ) { bShouldFadeOut = true; } } if(bShouldFadeOut) { // time to start fading out if( NetworkInterface::IsGameInProgress() ) { iFadeOutTimer = GetNetworkGameTimer(); } else { iFadeOutTimer_SP = GetGameTimer(); } bIsFadingOut = true; } } else { // set alpha if( NetworkInterface::IsGameInProgress() ) { fPhase = (float)( GetNetworkGameTimer() - iFadeOutTimer ) / BLIP_FADE_PERIOD; } else { fPhase = (float)( GetGameTimer() - iFadeOutTimer_SP ) / BLIP_FADE_PERIOD; } if( fPhase > 1.0f ) { // delete blip when fully faded out CleanupBlip(); } else { int intAlpha = (int)(255.0f*(1.0f-fPhase)); intAlpha = MAX(0, intAlpha); intAlpha = MIN(255, intAlpha); CMiniMap::SetBlipParameter(BLIP_CHANGE_ALPHA, isVehicle ? VehicleBlipID : BlipID, intAlpha ); } } } bool CScriptPedAIBlips::AIBlip::IsPlayerFreeAimingAtEntity( CPed *pPlayer, CEntity *pTarget ) { if (pPlayer && pTarget) { if( !pPlayer->IsFatallyInjured() ) { if(!NetworkInterface::IsGameInProgress() || !pPlayer->IsNetworkClone()) { if(pPlayer->GetPlayerInfo()) { const CPlayerPedTargeting & rPlayerTargeting = pPlayer->GetPlayerInfo()->GetTargeting(); return (rPlayerTargeting.GetFreeAimTarget() == pTarget) || (rPlayerTargeting.GetFreeAimTargetRagdoll() == pTarget); } } else { CNetObjPlayer* netObjPlayer = SafeCast(CNetObjPlayer, pPlayer->GetNetworkObject()); return ( netObjPlayer->IsFreeAimingLockedOnTarget() && pTarget == netObjPlayer->GetAimingTarget() ); } } } return false; } bool CScriptPedAIBlips::AIBlip::IsPlayerTargettingEntity( CPed *pPlayer, CEntity *pTarget ) { if (pPlayer && pTarget && pPlayer->GetPlayerInfo()) { if( !pPlayer->IsFatallyInjured() ) { if (pPlayer->GetPlayerInfo()->GetTargeting().GetLockOnTarget() == pTarget) { return true; } } } return false; } float CScriptPedAIBlips::AIBlip::GetMaxRangeOfCurrentPedWeaponBlip(CPed *pPed) { float range = -1.0f; if(pPed) { if(Verifyf( pPed->GetWeaponManager(), "Ped %s requires a weapon manager", pPed->GetModelName() ) ) { const CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon(); if(pWeapon) { const CWeaponInfo* pWeaponInfo = CWeaponInfoManager::GetInfo(pWeapon->GetWeaponHash()); if(pWeaponInfo) { range = pWeaponInfo->GetRange() * CScriptPedAIBlips::WEAPON_RANGE_MULTIPLIER_FOR_BLIPS; } } } } if( range > 400.0f ) range = 400.0; return range; } bool CScriptPedAIBlips::AIBlip::DoesBlipExist(int iBlipIndex) { if (iBlipIndex != INVALID_BLIP_ID) { return CMiniMap::IsBlipIdInUse(iBlipIndex); } return false; } int CScriptPedAIBlips::AIBlip::GetBlipFromEntity(CEntity *pEntity) { if(pEntity) { CMiniMapBlip* pBlip = NULL; if (pEntity->GetIsTypePed()) { pBlip = CMiniMap::GetBlipAttachedToEntity(pEntity, BLIP_TYPE_CHAR, 0); } else if (pEntity->GetIsTypeVehicle()) { pBlip = CMiniMap::GetBlipAttachedToEntity(pEntity, BLIP_TYPE_CAR, 0); } else if (pEntity->GetIsTypeObject()) { CObject *pObject = static_cast(pEntity); if(pObject->m_nObjectFlags.bIsPickUp) { pBlip = CMiniMap::GetBlipAttachedToEntity(pObject, BLIP_TYPE_PICKUP_OBJECT, 0); } else { pBlip = CMiniMap::GetBlipAttachedToEntity(pObject, BLIP_TYPE_OBJECT, 0); } } if (pBlip) { //if we found a blip that's not in use, look again but for one that is in use if(pEntity->GetIsTypeVehicle() && !CMiniMap::IsBlipIdInUse(pBlip->m_iUniqueId)) { pBlip = CMiniMap::GetBlipAttachedToEntity(pEntity, BLIP_TYPE_CAR, 0, true); } } if (pBlip) { return (CMiniMap::GetUniqueBlipUsed(pBlip)); } } return INVALID_BLIP_ID; } int CScriptPedAIBlips::AIBlip::CreateBlipForVehicle(CVehicle *pVehicle, bool isEnemyVehicle, bool useGreenVehicleBlip) { return CreateBlipOnEntity(pVehicle, !isEnemyVehicle, useGreenVehicleBlip); } int CScriptPedAIBlips::AIBlip::CreateBlipOnEntity(CEntity *pEntity, bool bIsFriendly, bool useGreenVehicleBlip) { if( pEntity == NULL ) { return INVALID_BLIP_ID; } int blipIDX = AddBlipForEntity(pEntity); if( pEntity->GetIsTypeVehicle() ) { CMiniMap::SetBlipParameter(BLIP_CHANGE_SCALE, blipIDX, NetworkInterface::IsGameInProgress() ? CScriptPedAIBlips::BLIP_SIZE_NETWORK_VEHICLE : CScriptPedAIBlips::BLIP_SIZE_VEHICLE); if( !useGreenVehicleBlip ) { CMiniMap::SetBlipParameter(BLIP_CHANGE_FRIENDLY, blipIDX, bIsFriendly); } else { CMiniMap::SetBlipParameter(BLIP_CHANGE_COLOUR, blipIDX, blipColourOverride != BLIP_COLOUR_MAX ? blipColourOverride : BLIP_COLOUR_GREEN); } } else if( pEntity->GetIsTypePed() ) { CMiniMap::SetBlipParameter(BLIP_CHANGE_SCALE, blipIDX, NetworkInterface::IsGameInProgress() ? CScriptPedAIBlips::BLIP_SIZE_NETWORK_PED : CScriptPedAIBlips::BLIP_SIZE_PED); CMiniMap::SetBlipParameter(BLIP_CHANGE_FRIENDLY, blipIDX, bIsFriendly); } else if( pEntity->GetIsTypeObject() ) { CMiniMap::SetBlipParameter(BLIP_CHANGE_SCALE, blipIDX, NetworkInterface::IsGameInProgress() ? CScriptPedAIBlips::BLIP_SIZE_NETWORK_OBJECT : CScriptPedAIBlips::BLIP_SIZE_OBJECT); } #if __BANK else { Assertf(0,"CScriptPedAIBlips::AIBlip::CreateBlipOnEntity() - Unknown Entity Type"); } #endif return blipIDX; } int CScriptPedAIBlips::AIBlip::AddBlipForEntity(CEntity *pEntity) { int iNewBlipIndex = INVALID_BLIP_ID; if(pEntity) { eBLIP_TYPE blipType = BLIP_TYPE_UNUSED; float scale = 0.0f; CEntityPoolIndexForBlip entityPoolIndex; if (pEntity->GetIsTypePed()) { blipType = BLIP_TYPE_CHAR; static_cast(pEntity)->SetPedConfigFlag( CPED_CONFIG_FLAG_BlippedByScript, true ); entityPoolIndex = CEntityPoolIndexForBlip(pEntity, blipType); } else if (pEntity->GetIsTypeVehicle()) { blipType = BLIP_TYPE_CAR; scale = 1.0f; entityPoolIndex = CEntityPoolIndexForBlip(pEntity, blipType); } else if (pEntity->GetIsTypeObject()) { CObject *pObject = static_cast(pEntity); if(pObject->m_nObjectFlags.bIsPickUp) { blipType = BLIP_TYPE_PICKUP_OBJECT; } else { blipType = BLIP_TYPE_OBJECT; } entityPoolIndex = CEntityPoolIndexForBlip(pEntity, blipType); } else { Assertf(0, "CScriptPedAIBlips::AIBlip::AddBlipForEntity() - unrecognised entity type"); } if ( (blipType != BLIP_TYPE_UNUSED) && (entityPoolIndex.IsValid()) ) { // Allocate this as a script resource GtaThread *pGtaThread = static_cast(scrThread::GetThread(static_cast(scrThreadID))); if ( Verifyf((pGtaThread != NULL) && (pGtaThread->GetState() != scrThread::ABORTED),"CScriptPedAIBlips::AIBlip::AddBlipForEntity() - Trying to create a script resource on terminated script thread") ) { CScriptResource_RadarBlip blip(blipType, entityPoolIndex, BLIP_DISPLAY_BOTH, pGtaThread->GetScriptName(), scale); iNewBlipIndex = pGtaThread->m_Handler->RegisterScriptResourceAndGetRef(blip); } } } Assertf(iNewBlipIndex != INVALID_BLIP_ID, " CScriptPedAIBlips::AIBlip::AddBlipForEntity - Failed to create blip for entity %s", pEntity->GetModelName()); return iNewBlipIndex; } void CScriptPedAIBlips::AIBlip::RemoveBlip(s32 &blipID, bool bCheckExclusivity /* = false */) { GtaThread *pGtaThread = static_cast(scrThread::GetThread(static_cast(scrThreadID))); if( (pGtaThread != NULL) && (pGtaThread->GetState() != scrThread::ABORTED) ) { if( !bCheckExclusivity || CScriptPedAIBlips::IsExclusiveOwnerOfBlip(this, blipID) ) { if( pGtaThread->bThisScriptCanRemoveBlipsCreatedByAnyScript ) { CTheScripts::GetScriptHandlerMgr().RemoveScriptResource(CGameScriptResource::SCRIPT_RESOURCE_RADAR_BLIP, blipID); // searches all the script handler lists for the blip } else { if (!pGtaThread->m_Handler->RemoveScriptResource(CGameScriptResource::SCRIPT_RESOURCE_RADAR_BLIP, blipID)) { if (blipID != 0) { Warningf("CScriptPedAIBlips::AIBlip::RemoveBlip() - failed to find a blip with id %d for this script. Maybe the blip was created by another script or has already been deleted. It could also be that the blip was attached to a pickup or entity that has already been deleted.", blipID); } } } } } blipID = INVALID_BLIP_ID; } //This function should match script command GET_CORRECT_BLIP_PRIORITY() - but it doesn't. //I'm only fixing known bugs at this point -JW s32 CScriptPedAIBlips::AIBlip::GetCorrectBlipPriority(eBLIP_PRIORITY_TYPE type) { switch(type) { case BLIP_PRIORITY_HIGHLIGHTED: // highest return BLIP_PRIORITY_HIGHEST; break; // high - highest // high case BLIP_PRIORITY_OTHER_TEAM: return BLIP_PRIORITY_HIGH; break; // med - high case BLIP_PRIORITY_SAME_TEAM: case BLIP_PRIORITY_ENEMY_AI: return BLIP_PRIORITY_MED_HIGH; break; // med - default - reserved for mission blips // low - med case BLIP_PRIORITY_CUFFED_OR_KEYS: return BLIP_PRIORITY_LOW_MED; //break; // low // lowest-low case BLIP_PRIORITY_DEFAULT: case BLIP_PRIORITY_WANTED: return BLIP_PRIORITY_LOW_LOWEST; //break; default: break; } return BLIP_PRIORITY_LOWEST; } eHUD_COLOURS CScriptPedAIBlips::AIBlip::GetBlipHudColour(s32 iBlipIndex) { eHUD_COLOURS iReturnHudColour = HUD_COLOUR_WHITE; if (Verifyf(iBlipIndex != INVALID_BLIP_ID, " - Blip %d doesn't exist", iBlipIndex)) { CMiniMapBlip *pBlip = CMiniMap::GetBlip(iBlipIndex); if (pBlip) { CMiniMap_Common::GetColourFromBlipSettings(CMiniMap::GetBlipColourValue(pBlip), CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_BRIGHTNESS), &iReturnHudColour); } } return iReturnHudColour; } void CScriptPedAIBlips::AIBlip::SetBlipNameFromTextFile(s32 iBlipIndex, const char *pTextLabel) { if (Verifyf(iBlipIndex != INVALID_BLIP_ID, "SetBlipNameFromTextFile - Blip %d doesn't exist", iBlipIndex)) { if (Verifyf(strlen(pTextLabel) < MAX_BLIP_NAME_SIZE, "SET_BLIP_NAME_FROM_TEXT_FILE - text label is too long")) { CMiniMap::SetBlipParameter(BLIP_CHANGE_NAME, iBlipIndex, pTextLabel); } } } void CScriptPedAIBlips::AIBlip::CleanupBlip() { CPed *pPed = CTheScripts::GetEntityToModifyFromGUID(pedID, 0); if( pPed ) { if (NetworkInterface::IsGameInProgress() && pPed->GetNetworkObject()) { scriptDebugf1("Removing network ped blip : %s (%p)",pPed->GetNetworkObject()->GetLogName(), pPed); } } if(DoesBlipExist(BlipID)) { RemoveBlip(BlipID); } if(DoesBlipExist(VehicleBlipID)) { RemoveBlip(VehicleBlipID, true); } BlipID = INVALID_BLIP_ID; VehicleBlipID = INVALID_BLIP_ID; // clear fading flag, otherwise system will never re-create the blip bIsFadingOut = false; } bool CScriptPedAIBlips::AIBlip::IsPedNoticableToPlayer(CPed *pPed, CPed *pPlayerPed, float fNoticableRadius, bool bRespondingToSpecialAbility, int iResponseTimer, int iResponseTime) { if( pPed && pPlayerPed ) // Should not be required { if( !pPed->IsInjured() && !pPlayerPed->IsInjured() ) { Vector3 deltaV = VEC3V_TO_VECTOR3(pPlayerPed->GetTransform().GetPosition() - pPed->GetTransform().GetPosition()); float dist = deltaV.Mag(); // if ped is shooting and within range of the player then blip them if( pPed->GetPedResetFlag( CPED_RESET_FLAG_FiringWeapon ) ) { if( dist < GetMaxRangeOfCurrentPedWeaponBlip(pPed) ) { return true; } } // if ped is running or shoot and within range of the player them blip them if( pPed->GetMotionData()->GetIsSprinting() || pPed->GetMotionData()->GetIsRunning() ) { if( dist < fNoticableRadius ) { return true; } } // if ped is involved in currently ongoing scripted conversation (in shootouts it might mean one line random dialogue) if( ( (g_ScriptAudioEntity.IsScriptedConversationOngoing() && !g_ScriptAudioEntity.IsScriptedConversationAMobileCall() ) && g_ScriptAudioEntity.IsPedInCurrentConversation(pPed) ) || ( pPed->GetSpeechAudioEntity() && pPed->GetSpeechAudioEntity()->IsAmbientSpeechPlaying() ) ) { if(dist < CScriptPedAIBlips::HEARD_RADIUS) { return true; } } // if the player is pointing their weapon at the ped within range if( dist < fNoticableRadius ) { if( IsPlayerFreeAimingAtEntity(pPlayerPed, pPed) || IsPlayerTargettingEntity(pPlayerPed, pPed) ) { return true; } } // if ped is any vehicle if( pPed->GetIsInVehicle() ) { // Always noticeable in a heli CVehicle *pVehicle = pPed->GetVehiclePedInside(); if( pVehicle ) { if ( pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI || pVehicle->GetVehicleType() == VEHICLE_TYPE_PLANE ) { return true; } } const bool bSuppressNonHostileInVehicle = ( NetworkInterface::IsGameInProgress() && !pPed->GetPedIntelligence()->GetQueriableInterface()->IsTaskCurrentlyRunning(CTaskTypes::TASK_COMBAT) ); if (( dist < fNoticableRadius ) && !bSuppressNonHostileInVehicle) { return true; } } /////////////////////////////////////////////////////////////////////////////// // if is ped responding to Trevor's special ability, singleplayer only // THIS ISN'T REALLY BLIPS TBH, reproduced for fidelity, not sure if this'll be an issue. if( !NetworkInterface::IsGameInProgress() ) { if( bRespondingToSpecialAbility == false) { if (pPlayerPed && CTheScripts::IsPlayerPlaying(pPlayerPed)) { if(!pPlayerPed->IsInjured()) { CBaseModelInfo* pModel = CModelInfo::GetBaseModelInfo(pPlayerPed->GetModelId()); u32 hashKey = pModel->GetHashKey(); if(hashKey == MI_PLAYERPED_PLAYER_TWO.GetName().GetHash()) { pPlayerPed->SetPedResetFlag( CPED_RESET_FLAG_ForceCombatTaunt, true ); CPlayerSpecialAbility* specialAbility = pPlayerPed->GetSpecialAbility(); if(specialAbility && specialAbility->IsActive()) { if(pPlayerPed->GetSpeechAudioEntity() && !pPlayerPed->GetSpeechAudioEntity()->IsAmbientSpeechPlaying()) { iResponseTime = 1000 + CRandomScripts::GetRandomNumberInRange(0, 501); iResponseTimer = GetGameTimer(); bRespondingToSpecialAbility = true; } } } } } } else { if(GetGameTimer() - iResponseTimer > iResponseTime) { bRespondingToSpecialAbility = false; return true; } } } /////////////////////////////////////////////////////////////////////////////// } } return false; }