static bool ActivateFilterFn(HOBJECT hTest, void *pUserData) { // [KLS 6/26/02] - Make sure we filter out client related objects first... HOBJECT hClientHitBox = LTNULL; CCharacterFX* pCharacter = g_pGameClientShell->GetSFXMgr()->GetCharacterFX(g_pLTClient->GetClientObject()); if (pCharacter) { hClientHitBox = pCharacter->GetHitBox(); } HOBJECT hFilterList[] = { g_pLTClient->GetClientObject(), g_pPlayerMgr->GetMoveMgr()->GetObject(), hClientHitBox, LTNULL }; if (!ObjListFilterFn(hTest, (void*) hFilterList)) { return false; } // Always keep gadget targets... if (g_pPlayerMgr->GetTargetMgr()->IsGadgetActivatable(hTest)) { return true; } // Always keep our locked target... if (g_pPlayerMgr->GetTargetMgr()->GetLockedTarget() == hTest) { return true; } // Look to see if it is a DoomsDayPiece. This should take precedence over characters and bodies... CDoomsdayPieceFX *pDDPiece = dynamic_cast<CDoomsdayPieceFX*>(g_pGameClientShell->GetSFXMgr()->FindSpecialFX( SFX_DOOMSDAYPIECE_ID, hTest )); if( pDDPiece ) { // If the piece is planted on our teams bse we no longer care about it... if( pDDPiece->IsPlanted() && (pDDPiece->GetTeam() != INVALID_TEAM) ) { CLIENT_INFO *pLocalCI = g_pInterfaceMgr->GetClientInfoMgr()->GetLocalClient(); if( !pLocalCI ) return false; if( pLocalCI->nTeamID == pDDPiece->GetTeam() ) { return false; } } return true; } // If it's a body, ignore it (we only care about its hit box) CBodyFX* pBody = g_pGameClientShell->GetSFXMgr()->GetBodyFX(hTest); if (pBody) { return false; } // If it's a hitbox associated with a body we care. pBody = g_pGameClientShell->GetSFXMgr()->GetBodyFromHitBox(hTest); if (pBody) { // Save body for later since it may overlap a higher priority object SetFallbackActivationObject(hTest, (IntersectQuery*)pUserData); return false; } // If it's a Character and it has a hitbox, ignore it (we only care about its hit box) pCharacter = g_pGameClientShell->GetSFXMgr()->GetCharacterFX(hTest); if (pCharacter) { if (pCharacter->GetHitBox()) { return false; } // Save character for later if unconscious since it may overlap a // higher priority object if (pCharacter->IsUnconscious()) { SetFallbackActivationObject(hTest, (IntersectQuery*)pUserData); return false; } return true; // "Solid" object so we're done } // If it's a hitbox associated with a Character we care about it... pCharacter = g_pGameClientShell->GetSFXMgr()->GetCharacterFromHitBox(hTest); if (pCharacter) { if (pCharacter->IsUnconscious()) { // Save character for later since it may overlap a higher priority object SetFallbackActivationObject(hTest, (IntersectQuery*)pUserData); return false; } return true; // "Solid" object so we're done } // Ignore non-solid objects that can't be activated... uint32 dwFlags; g_pCommonLT->GetObjectFlags(hTest, OFT_Flags, dwFlags); if (!(dwFlags & FLAG_SOLID)) { // This object is most likely a pickup of some type and it should // take priority over all the above objects types...however, since all // we can test are its flags we have to filter out the above objects // first (instead of testing for this type of object at the top of // the function ;) return IsUserFlagSet(hTest, (USRFLG_CAN_ACTIVATE | USRFLG_CAN_SEARCH)); } // Hit something solid, so we're done... return true; }
void CTargetMgr::Update() { // Do any necessary initialization... if (m_bFirstUpdate) { FirstUpdate(); m_bFirstUpdate = false; } if (m_hLockedTarget && m_hTarget == m_hLockedTarget) { //are we disabling a GadgetTarget? if (g_pPlayerMgr->IsDisabling()) { SetGadgetTarget( true ); return; } //are we searching something? if (g_pPlayerMgr->IsSearching()) { m_bSearchTarget = true; SetTargetStringID(IDS_TARGET_SEARCHING); float fDistAway = 10000.0f; CheckForIntersect(fDistAway); return; } } g_pPlayerStats->UpdateMaxProgress( 0 ); g_pPlayerStats->UpdateProgress( 0 ); g_pHUDMgr->QueueUpdate( kHUDProgressBar ); // If we currently have a target, see if it is a body and if so remove the // glow flag (it may be set again below)... if (m_hTarget) { CBodyFX* pBody = g_pGameClientShell->GetSFXMgr()->GetBodyFX(m_hTarget); if (pBody) { g_pCommonLT->SetObjectFlags(m_hTarget, OFT_User, 0, USRFLG_GLOW); } } // Start fresh ClearTargetInfo(); //see what we've looking at float fDistAway = 10000.0f; CheckForIntersect(fDistAway); if (!m_hTarget) { //nothing to see here return; } m_fTargetRange = fDistAway; //if its a body's hitbox, check the body instead CBodyFX* pBody = g_pGameClientShell->GetSFXMgr()->GetBodyFromHitBox(m_hTarget); if (pBody) { m_hTarget = pBody->GetServerObj(); m_ActivationData.m_hTarget = m_hTarget; if (!m_hTarget) return; } //if its a Character's hitbox and it is searchable, check the Character instead CCharacterFX* pCharacter = g_pGameClientShell->GetSFXMgr()->GetCharacterFromHitBox(m_hTarget); if (pCharacter) { m_hTarget = pCharacter->GetServerObj(); m_ActivationData.m_hTarget = m_hTarget; if (!m_hTarget) return; } uint32 dwUserFlags = 0; g_pCommonLT->GetObjectFlags(m_hTarget, OFT_User, dwUserFlags); // If we're on a vehicle (or if we are dead) all we care about is other players in a multiplayer game... // Some vehicles (like the PlayerLure) let you activate, so we'll just check if the // vehicle will let us show a crosshair to see if we're on a "true" vehicle or not... // It would be great if we didn't have to do all these checks, but such is life... bool bPlayersOnly = g_pPlayerMgr->IsPlayerDead() || (g_pPlayerMgr->GetMoveMgr()->GetVehicleMgr()->CanShowCrosshair() ? false : true); if (!bPlayersOnly) { //special case handling for bodies if (pBody || pCharacter) { bool bCanSearch = !!(dwUserFlags & USRFLG_CAN_SEARCH); if (pBody) { if (fDistAway <= g_vtActivationDistance.GetFloat()) { // Make target glow, so it stands out more... g_pCommonLT->SetObjectFlags(m_hTarget, OFT_User, USRFLG_GLOW, USRFLG_GLOW); } if (pBody->CanBeRevived() && fDistAway <= g_vtReviveDistance.GetFloat() && IsRevivePlayerGameType( )) { // Get the client information of the body and us. uint32 nId = pBody->GetClientId(); CClientInfoMgr* pCIMgr = g_pInterfaceMgr->GetClientInfoMgr(); CLIENT_INFO* pCI = pCIMgr->GetClientByID(nId); CLIENT_INFO *pLocalCI = g_pInterfaceMgr->GetClientInfoMgr()->GetLocalClient(); // Only allow us to revive people on the same team. For non-team games, // the teamid will be set to the same invalid value anyway. if( pCI && pLocalCI ) { if (pCI->nTeamID == pLocalCI->nTeamID) { m_nString = 0; FormatString(IDS_TARGET_REVIVE, m_szString, ARRAY_LEN(m_szString), pCI->sName.c_str()); LTVector vObjPos, vDims; g_pLTClient->GetObjectPos(pBody->GetServerObj(), &vObjPos); g_pPhysicsLT->GetObjectDims(pBody->GetServerObj(), &vDims); // Players are non-solid to each other so you can revive right on top of them. m_bCanActivate = true; //!CheckForCharacters(vObjPos, vDims, pBody->GetClientId()); m_bMoveTarget = true; m_ActivationData.m_nType = MID_ACTIVATE_REVIVE; } else { m_nString = 0; m_bCanActivate = false; m_bMoveTarget = false; LTStrCpy(m_szString, pCI->sName.c_str(), ARRAY_LEN(m_szString)); } return; } } else { m_bMoveTarget = (pBody->CanBeCarried() && g_pPlayerMgr->CanDropCarriedObject()); } } else if (pCharacter) { if( (pCharacter->m_cs.eCrosshairCharacterClass != BAD) && (pCharacter->CanWake()) && (pCharacter->IsUnconscious() || (pCharacter->Slipped() && !pCharacter->m_cs.bIsPlayer)) ) { SetTargetStringID( IDS_TARGET_WAKEUP ); m_bCanActivate = true; m_bMoveTarget = g_pPlayerMgr->CanDropCarriedObject() && pCharacter->CanBeCarried(); m_ActivationData.m_nType = MID_ACTIVATE_WAKEUP; return; } m_bMoveTarget = g_pPlayerMgr->CanDropCarriedObject() && pCharacter->CanBeCarried(); } else { m_bMoveTarget = false; } if (bCanSearch && fDistAway <= g_vtActivationDistance.GetFloat()) { // we can search this body m_bSearchTarget = true; m_ActivationData.m_nType = MID_ACTIVATE_SEARCH; SetTargetStringID(IDS_TARGET_SEARCH); uint8 nProgress = g_pPlayerMgr->GetSearcher()->GetMaxProgress(); g_pPlayerStats->UpdateMaxProgress( nProgress ); g_pPlayerStats->UpdateProgress( nProgress ); g_pHUDMgr->QueueUpdate( kHUDProgressBar ); return; } else if (pBody) { return; } } else { float fGadgetDistance = g_vtActivationDistance.GetFloat(); if( dwUserFlags & USRFLG_GADGET_CAMERA ) { fGadgetDistance = g_vtCamZoom1MaxDist.GetFloat(); } // is this a gadget target if (IsGadgetActivatable(m_hTarget) && (fDistAway <= fGadgetDistance)) { // looks like we can use a gadget on it... SetGadgetTarget( false ); return; } } } //are we aiming at a person? if (dwUserFlags & USRFLG_CHARACTER) { CCharacterFX* const pFX = (CCharacterFX*)g_pGameClientShell->GetSFXMgr()->FindSpecialFX(SFX_CHARACTER_ID, m_hTarget); // All we care about if we're on a vehicle (or if we are dead) is the Multiplayer check below... if (!bPlayersOnly) { //display debug info if we have any if( pFX && pFX->GetInfoString() && *pFX->GetInfoString() ) { SAFE_STRCPY(m_szDebugString,pFX->GetInfoString()); } else { m_szDebugString[0] = NULL; } // is this a person we can talk to? if (dwUserFlags & USRFLG_CAN_ACTIVATE) { if (fDistAway <= g_vtActivationDistance.GetFloat()) { SetTargetStringID(IDS_TARGET_TALK); return; } } } // This is the only thing we care about if we're dead or on a vehicle...(we care // if we're off a vehicle too) if (IsMultiplayerGame() && pFX && pFX->m_cs.bIsPlayer ) { uint32 nId = pFX->m_cs.nClientID; CClientInfoMgr* pCIMgr = g_pInterfaceMgr->GetClientInfoMgr(); CLIENT_INFO* pCI = pCIMgr->GetClientByID(nId); if (pCI) { m_nString = 0; SAFE_STRCPY(m_szString,pCI->sName.c_str()); if (IsTeamGameType()) { m_nTargetTeam = pCI->nTeamID; } } return; } // All we care about if we're dead or on a vehicle is the Multiplayer check above... if (!bPlayersOnly) { if( (fDistAway <= g_vtTargetDistance.GetFloat()) && pFX ) { // If a nameid was specified for the model display the name... uint16 nNameId = g_pModelButeMgr->GetModelNameId( pFX->m_cs.eModelId ); if( nNameId != (uint16)-1 ) { if( nNameId > 0 ) { SetTargetStringID( nNameId ); return; } // warn the player if we are pointing at a friend... if( pFX->m_cs.eCrosshairCharacterClass != BAD ) { SetTargetStringID( IDS_TARGET_INNOCENT ); return; } } } } } // All we care about if we're dead or on a vehicle is the above Multiplayer check... if (bPlayersOnly) { // Didn't see another player in Multiplayer, so we have no target... ClearTargetInfo(); return; } //is this a searchable object? if (dwUserFlags & USRFLG_CAN_SEARCH && (fDistAway <= g_vtActivationDistance.GetFloat())) { m_bSearchTarget = true; m_ActivationData.m_nType = MID_ACTIVATE_SEARCH; SetTargetStringID(IDS_TARGET_SEARCH); uint8 nProgress = g_pPlayerMgr->GetSearcher()->GetMaxProgress(); g_pPlayerStats->UpdateMaxProgress( nProgress ); g_pPlayerStats->UpdateProgress( nProgress ); g_pHUDMgr->QueueUpdate( kHUDProgressBar ); return; } // See if this object is part of the activate object list with it's own string ID's... if( fDistAway <= g_vtActivationDistance.GetFloat() ) { CActivateObjectHandler *pActivateObj = LTNULL; CActivateObjectHandler::ActivateObjList::const_iterator iter = CActivateObjectHandler::GetActivateObjectList().begin(); while( iter != CActivateObjectHandler::GetActivateObjectList().end() ) { pActivateObj = *iter; if( pActivateObj->GetHOBJECT() == m_hTarget ) { ACTIVATETYPE *pType = g_pActivateTypeMgr->GetActivateType( pActivateObj->m_nId ); if( pType ) { // Set whether or not it's disabled and set the string based on the state... m_bCanActivate = !pActivateObj->m_bDisabled; uint32 dwStringID = pType->dwStateID[pActivateObj->m_eState]; if( dwStringID != (uint32)-1 ) { SetTargetStringID( dwStringID ); } return; } } ++iter; } } //can we pick up or activate it? if (dwUserFlags & USRFLG_CAN_ACTIVATE && (fDistAway <= g_vtActivationDistance.GetFloat())) { //special case for bombs to defuse CGadgetTargetFX* const pGTFX = (CGadgetTargetFX*)g_pGameClientShell->GetSFXMgr()->FindSpecialFX(SFX_GADGETTARGET_ID, m_hTarget); if (pGTFX) { GadgetTargetType eGadgetType = pGTFX->GetType(); if (eBombable == eGadgetType) { // Can only defuse a bomb that doesn't belong to your team... if( IsTeamGameType() ) { CLIENT_INFO *pLocalCI = g_pInterfaceMgr->GetClientInfoMgr()->GetLocalClient(); if( !pLocalCI ) return; if( pGTFX->GetTeamID() != INVALID_TEAM ) { if( pLocalCI->nTeamID == pGTFX->GetTeamID() ) { m_bCanActivate = false; } } } SetTargetStringID(IDS_TARGET_DEFUSE); return; } } CPickupItemFX* const pFX = (CPickupItemFX*)g_pGameClientShell->GetSFXMgr()->FindSpecialFX(SFX_PICKUPITEM_ID, m_hTarget); // If this is a pickupitem, then display any team association it has. if( IsTeamGameType() && pFX ) { m_nTargetTeam = pFX->GetTeamId( ); } // If we're looking at a pickup, use the take string, otherwise it's just something to interact with. SetTargetStringID(pFX ? IDS_TARGET_TAKE : IDS_TARGET_USE); return; } // Are we looking at a doomsday piece... CDoomsdayPieceFX *pDDPiece = dynamic_cast<CDoomsdayPieceFX*>(g_pGameClientShell->GetSFXMgr()->FindSpecialFX( SFX_DOOMSDAYPIECE_ID, m_hTarget )); if( pDDPiece && (fDistAway <= g_vtActivationDistance.GetFloat()) ) { m_bCanActivate = false; m_bMoveTarget = true; } }