/** * CAIManager::CAIManager * @date Modified March 30, 2006 */ CAIManager::CAIManager(void) : m_bUpdateGoalLinks(true), m_bSkipCurrentObjective(false) { // go to the object manager and get the players and create nodes for them CObjectManager* poObjectManager = CObjectManager::getInstancePtr(); CObjectManager::ObjectList loPlayers; poObjectManager->getObjects(OBJ_PLAYER, &loPlayers); CObjectManager::ObjectList::iterator oPlayerIter = loPlayers.begin(); while (oPlayerIter != loPlayers.end()) { CAINode* newNode = new CAINode; newNode->setPosition(ACTOR_PTR(oPlayerIter)->getBV().centerPt); newNode->setRadius(1.0f); m_loGoals.push_back(newNode); oPlayerIter++; } m_oLeaderTimer.setInterval(0.1f); m_oObjectiveTimer.setInterval(0.15f); m_poCurrentObjective = NULL; m_poObjectiveEmitter = (CParticleEmitter*)CObjectManager::getInstance().createObject(OBJ_PARTICLE_EMITTER); m_poObjectiveEmitter->setSystem((CParticleSystem*)CResourceManager::getInstance().loadResource(RES_PARTICLEEMITTER, "objective.xml")); }
/** * CAIStateQBRangeAttack::update * @date Modified May 9, 2006 */ void CAIStateQBRangeAttack::update(CAIEntity* poAIEntity, CCharacter* poCharacter) { ((CAnimatedMesh*)poCharacter->getMesh())->setAnimationSetByName("Attack"); // look at the player D3DXVECTOR3 vAtGoal; CAINode* poGoalNode = CAIManager::getInstancePtr()->findBestGoal(poCharacter); D3DXVec3Subtract(&vAtGoal, &poGoalNode->getPosition(), &poCharacter->getPosition()); D3DXVec3Normalize(&vAtGoal, &vAtGoal); poCharacter->setOrientation(vAtGoal); // wait for the animation to play if (poAIEntity->getCurrentStateTime() < ((CAnimatedMesh*)poCharacter->getMesh())->getAnimationLength()) return; // spawn projectile CFootBall* poBall = (CFootBall*)CObjectManager::getInstancePtr()->createObject(OBJ_WEAPONPROJ_FOOTBALL); vAtGoal = poCharacter->getBV().centerPt; vAtGoal.y += 10.0f; poBall->setPosition(vAtGoal); D3DXVec3Subtract(&vAtGoal, &poGoalNode->getPosition(), &vAtGoal); D3DXVec3Normalize(NULL, &vAtGoal, &vAtGoal); poBall->setOrientation(vAtGoal); poBall->setVelocity(*D3DXVec3Scale(&vAtGoal, &vAtGoal, 50.0f)); poBall->setBV(poBall->getPosition(), 2.0f); poBall->setPlayer((CPlayer*)poCharacter); ((CEnemy*)(poCharacter))->setAIState(CAIStateQBMeleeAttack::getInstancePtr()); }
void CAIVolume::EnumerateSearchNodes(uint32* aiSearchNodes, uint32* pcSearchNodes, const uint32 nMaxSearchNodes) const { for ( uint32 iNode = 0 ; iNode < g_pAINodeMgr->GetNumNodes() && *pcSearchNodes < nMaxSearchNodes ; iNode++ ) { CAINode* pNode = g_pAINodeMgr->GetNode(iNode); if ( pNode && pNode->IsSearchable() && Inside(pNode->GetPos(), 53.0f) ) { aiSearchNodes[(*pcSearchNodes)++] = pNode->GetID(); } } }
CAINode* CAIVolume::FindViewNode() const { for ( uint32 iViewNode = 0 ; iViewNode < kMaxViewNodes ; iViewNode++ ) { uint32 dwViewNode = m_adwViewNodes[iViewNode]; CAINode* pNode = (dwViewNode == CAINode::kInvalidNodeID ? LTNULL : g_pAINodeMgr->GetNode(dwViewNode)); if ( pNode ) { if ( !pNode->IsLocked() ) { return pNode; } } } return LTNULL; }
void CAIHelicopterStateGoto::HandleNameValuePair(char *szName, char *szValue) { CAIHelicopterState::HandleNameValuePair(szName, szValue); if ( !_stricmp(szName, "PT") ) { sscanf(szValue, "%f,%f,%f", &m_vDest.x, &m_vDest.y, &m_vDest.z); m_cNodes = 0; } else if ( !_stricmp(szName, "PTS") ) { m_cNodes = 0; char *szPoint = strtok(szValue, ","); while ( szPoint ) { if ( m_cNodes == kMaxGotoNodes ) { g_pLTServer->CPrint("Max # Goto waypoints exceeded %s=%s", szName, szValue); } CAINode* pNode = g_pAINodeMgr->GetNode(szPoint); if ( pNode ) { m_adwNodes[m_cNodes++] = pNode->GetID(); } else { g_pLTServer->CPrint("Unknown Goto waypoint ''%s''", szPoint); } szPoint = strtok(NULL, ","); } } else if ( !_stricmp(szName, "LOOP") ) { m_bLoop = IsTrueChar(*szValue); } }
/** * CAIStateAcidicAttack::update * @date Modified May 4, 2006 */ void CAIStateAcidicAttack::update(CAIEntity* poAIEntity, CCharacter* poCharacter) { D3DCOLOR color = poCharacter->getColor(); if (color == 0xff000000) poCharacter->setColor(0xff005555); else poCharacter->setColor(0xff000000); // look at the player D3DXVECTOR3 vAtGoal; CAINode* poGoalNode = CAIManager::getInstancePtr()->findBestGoal(poCharacter); D3DXVec3Subtract(&vAtGoal, &poGoalNode->getPosition(), &poCharacter->getPosition()); D3DXVec3Normalize(&vAtGoal, &vAtGoal); poCharacter->setOrientation(vAtGoal); // wait so we can flash a bit and then throw if (poAIEntity->getCurrentStateTime() < 0.5) return; ((CAnimatedMesh*)poCharacter->getMesh())->setAnimationSetByName("Attack"); // wait for the animation to play if (poAIEntity->getCurrentStateTime() < (((CAnimatedMesh*)poCharacter->getMesh())->getAnimationLength() + 0.5)) return; // spawn projectile CIceCream* poBall = (CIceCream*)CObjectManager::getInstancePtr()->createObject(OBJ_WEAPONPROJ_ACIDICE); vAtGoal = poCharacter->getBV().centerPt; vAtGoal.y += 10.0f; poBall->setPosition(vAtGoal); D3DXVec3Subtract(&vAtGoal, &poGoalNode->getPosition(), &vAtGoal); D3DXVec3Normalize(NULL, &vAtGoal, &vAtGoal); poBall->setOrientation(vAtGoal); poBall->setVelocity(*D3DXVec3Scale(&vAtGoal, &vAtGoal, 50.0f)); poBall->setBV(poBall->getPosition(), 2.0f); poBall->setPlayer((CPlayer*)poCharacter); ((CEnemy*)(poCharacter))->setAIState(CAIStateAcidicFollow::getInstancePtr()); }
/** * CAIGroup::disband * @date Modified April 26, 2006 */ void CAIGroup::disband(bool bDisperse) { std::list<CEnemy*>::iterator oEnemyIter = m_loEnemies.begin(); CAIStatePathPlan* poPlan = CAIStatePathPlan::getInstancePtr(); // for dispersal CAIStateMove* poMove = NULL; D3DXVECTOR3 vFrontBack(0.0f, 0.0f, 0.0f), vLeftRight(0.0f, 0.0f, 0.0f), vTemp(0.0f, 0.0f, 0.0f); CAINode* poGoalNode = NULL; float fDot = 0.0f; // if the enemies are to disperse, this information is needed if (bDisperse) { poMove = CAIStateMove::getInstancePtr(); calculateAvgPos(); poGoalNode = CAIManager::getInstancePtr()->findBestGoal(*oEnemyIter); // calculate vectors to perform a halfspace tests to determine members' position in the group D3DXVec3Subtract(&vFrontBack, &poGoalNode->getPosition(), &m_vAvgPos); D3DXVec3Normalize(NULL, &vFrontBack, &vFrontBack); D3DXVec3Cross(&vLeftRight, &D3DXVECTOR3(0.0f, 1.0f, 0.0f), &vLeftRight); D3DXVec3Normalize(NULL, &vLeftRight, &vLeftRight); } while (oEnemyIter != m_loEnemies.end()) { (*oEnemyIter)->getAI()->setGroup(NULL); if (bDisperse) { if ((*oEnemyIter)->getType() == OBJ_ENEMY_ZOMBIECITIZEN) { D3DXVec3Subtract(&vTemp, &ENEMY_PTR(oEnemyIter)->getBV().centerPt, &m_vAvgPos); D3DXVec3Normalize(NULL, &vTemp, &vTemp); fDot = D3DXVec3Dot(&vTemp, &vFrontBack); // if this enemy is in back send him straight to the goal if (fDot <= 0.0f) { (*oEnemyIter)->setAIState(poPlan); } // if this enemy is in front, make him move forward else { ENEMY_PTR(oEnemyIter)->setOrientation(vTemp); D3DXVec3Scale(&vTemp, &vFrontBack, 10.0f); ENEMY_PTR(oEnemyIter)->setVelocity(vTemp); (*oEnemyIter)->setAIState(poMove); } } else { (*oEnemyIter)->setAIState(poPlan); } } else { (*oEnemyIter)->setAIState(poPlan); } oEnemyIter = m_loEnemies.erase(oEnemyIter); } }
void CAIBrain::GetDodgeStatus(DodgeStatus* peDodgeStatus, Direction* peDirection, DodgeAction* peDodgeAction, uint32* pdwNode) { if ( !GetAI()->HasTarget() || !GetAI()->HasLastVolume() ) { *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusOk; return; } if ( g_pLTServer->GetTime() >= m_fDodgeStatusCheckTimeVector ) { m_fDodgeStatusCheckTimeVector = g_pLTServer->GetTime() + LOWER_BY_DIFFICULTY(m_pBrain->fDodgeVectorCheckTime); if ( GetRandom(0.0f, 1.0f) <= RAISE_BY_DIFFICULTY(m_pBrain->fDodgeVectorCheckChance) ) { if ( GetAI()->GetTarget()->IsVisiblePartially() ) { CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(GetAI()->GetTarget()->GetObject()); if ( pCharacter->HasDangerousWeapon() ) { LTRotation rRot; LTVector vNull, vForward; g_pLTServer->GetObjectRotation(GetAI()->GetTarget()->GetObject(), &rRot); g_pMathLT->GetRotationVectors(rRot, vNull, vNull, vForward); LTVector vDir; vDir = GetAI()->GetPosition() - GetAI()->GetTarget()->GetPosition(); vDir.y = 0; vDir.Norm(); // TODO: bute this const static LTFLOAT fThreshhold = 0.95f; if ( (vDir.Dot(vForward) > fThreshhold) && (GetAI()->GetForwardVector().Dot(vForward) < -fThreshhold) ) { LTFLOAT fCheckDistance; LTFLOAT fRandom = GetRandom(0.0f, 1.0f); if ( fRandom > m_pBrain->fDodgeVectorCoverChance ) { if ( fRandom > (m_pBrain->fDodgeVectorCoverChance + m_pBrain->fDodgeVectorRollChance) ) { *peDodgeAction = eDodgeActionShuffle; fCheckDistance = 109.0f; } else { *peDodgeAction = eDodgeActionRoll; fCheckDistance = 140.0f; } // MAKE SURE WE WON'T DODGE OUT OF THE VOLUME if ( GetAI()->GetLastVolume()->Inside2d(GetAI()->GetPosition()+GetAI()->GetRightVector()*fCheckDistance, GetAI()->GetRadius()) ) { *peDirection = eDirectionRight; *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusVector; return; } else if ( GetAI()->GetLastVolume()->Inside2d(GetAI()->GetPosition()-GetAI()->GetRightVector()*fCheckDistance, GetAI()->GetRadius()) ) { *peDirection = eDirectionLeft; *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusVector; return; } else { *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusOk; return; } } else { CAINode* pNode = g_pAINodeMgr->FindNearestCoverFromThreat(GetAI()->GetPosition(), GetAI()->GetTarget()->GetObject()); if ( pNode ) { *peDodgeAction = eDodgeActionCover; *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusVector; *pdwNode = pNode->GetID(); } else { *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusOk; } return; } } } } } } if ( g_pLTServer->GetTime() >= m_fDodgeStatusCheckTimeProjectile ) { m_fDodgeStatusCheckTimeProjectile = g_pLTServer->GetTime() + RAISE_BY_DIFFICULTY(m_pBrain->fDodgeProjectileCheckTime); if ( GetRandom(0.0f, 1.0f) <= RAISE_BY_DIFFICULTY(m_pBrain->fDodgeProjectileCheckChance) ) { CGrenade* pGrenade; if ( FindGrenadeDangerPosition(GetAI()->GetPosition(), 40000.0f, &m_vDodgeProjectilePosition, &pGrenade) ) { FREE_HSTRING(m_hstrDodgeProjectileName); // $STRING m_hstrDodgeProjectileName = g_pLTServer->CreateString(g_pLTServer->GetObjectName(pGrenade->m_hObject)); *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusProjectile; *peDodgeAction = eDodgeActionFlee; return; } } } *peDodgeStatus = m_eDodgeStatusLast = eDodgeStatusOk; return; }
/** * CAIManager::update * @date Modified April 26, 2006 */ void CAIManager::update(void) { // go to the object manager and get the players and update the nodes corresponding to them CObjectManager* poObjectManager = CObjectManager::getInstancePtr(); CObjectManager::ObjectList loPlayers; poObjectManager->getObjects(OBJ_PLAYER, &loPlayers); CObjectManager::ObjectList::iterator oPlayerIter = loPlayers.begin(); // now that we have the players, check to see it there are any cluckin bombs to add as goals CObjectManager::ObjectList loBombs; poObjectManager->getObjects(OBJ_WEAPON_BIGCLUCKINGBOMB, &loBombs); CObjectManager::ObjectList::iterator oBombIter = loBombs.begin(); while (oBombIter != loBombs.end()) { loPlayers.push_back((*oBombIter)); oBombIter++; } std::list<CAINode*>::iterator oNodeIter = m_loGoals.begin(); bool bUpdateGoalLinks = false; if (m_bUpdateGoalLinks) { bUpdateGoalLinks = true; m_bUpdateGoalLinks = false; } while (oNodeIter != m_loGoals.end() && oPlayerIter != loPlayers.end()) { // to cover the case of a big cluckin bomb, keep the goal node off the ground (*oNodeIter)->setPosition(D3DXVECTOR3(ACTOR_PTR(oPlayerIter)->getBV().centerPt.x, ((CPlayer*)loPlayers.front())->getBV().centerPt.y, ACTOR_PTR(oPlayerIter)->getBV().centerPt.z)); if (bUpdateGoalLinks) { unlinkNode(*oNodeIter); linkNode(*oNodeIter); } oNodeIter++; oPlayerIter++; } // cases where a player quits if (oNodeIter != m_loGoals.end()) { while (oNodeIter != m_loGoals.end()) { unlinkNode(*oNodeIter); delete *oNodeIter; oNodeIter = m_loGoals.erase(oNodeIter); } } // case where a player joins if (oPlayerIter != loPlayers.end()) { while (oPlayerIter != loPlayers.end()) { CAINode* newNode = new CAINode; // to cover the case of a big cluckin bomb, keep the goal node off the ground newNode->setPosition(D3DXVECTOR3(ACTOR_PTR(oPlayerIter)->getBV().centerPt.x, ((CPlayer*)loPlayers.front())->getBV().centerPt.y, ACTOR_PTR(oPlayerIter)->getBV().centerPt.z)); newNode->setRadius(1.0f); m_loGoals.push_back(newNode); linkNode(newNode); oPlayerIter++; } } updateGroupLeaders(); updateSpawnTriggers(); updateCurrentObjective(); // make sure this gets reset every time or the objectives will skip to gameover m_bSkipCurrentObjective = false; }
void CAIVolume::Init(int32 iVolume, const AIVolume& vol) { char szName[128]; g_pLTServer->GetObjectName(vol.m_hObject, szName, 127); m_hstrName = g_pLTServer->CreateString(szName); m_iVolume = iVolume; LTVector vVolumePos; LTVector vVolumeDims; g_pLTServer->GetObjectPos(vol.m_hObject, &vVolumePos); g_pLTServer->GetObjectDims(vol.m_hObject, &vVolumeDims); m_vFrontTopRight = vVolumePos + LTVector(vVolumeDims.x, vVolumeDims.y, vVolumeDims.z); m_vFrontTopLeft = vVolumePos + LTVector(-vVolumeDims.x, vVolumeDims.y, vVolumeDims.z); m_vBackTopRight = vVolumePos + LTVector(vVolumeDims.x, vVolumeDims.y, -vVolumeDims.z); m_vBackTopLeft = vVolumePos + LTVector(-vVolumeDims.x, vVolumeDims.y, -vVolumeDims.z); m_vFrontBottomRight = vVolumePos + LTVector(vVolumeDims.x, -vVolumeDims.y, vVolumeDims.z); m_vFrontBottomLeft = vVolumePos + LTVector(-vVolumeDims.x, -vVolumeDims.y, vVolumeDims.z); m_vBackBottomRight = vVolumePos + LTVector(vVolumeDims.x, -vVolumeDims.y, -vVolumeDims.z); m_vBackBottomLeft = vVolumePos + LTVector(-vVolumeDims.x, -vVolumeDims.y, -vVolumeDims.z); // Get the view volumes for ( uint32 iViewNode = 0 ; iViewNode < kMaxViewNodes ; iViewNode++ ) { if ( vol.GetViewNode(iViewNode) ) { CAINode* pNode = g_pAINodeMgr->GetNode(vol.GetViewNode(iViewNode)); if ( pNode ) { m_adwViewNodes[iViewNode] = pNode->GetID(); } else { g_pLTServer->CPrint("********** Volume ''%s'' has a view node that does not exist!", GetName()); } } } // Find any doors located in our volume HCLASS hDoor = g_pLTServer->GetClass("Door"); HCLASS hSwitch = g_pLTServer->GetClass("Switch"); HOBJECT hCurObject = LTNULL; while (hCurObject = g_pLTServer->GetNextObject(hCurObject)) { if (g_pLTServer->IsKindOf(g_pLTServer->GetObjectClass(hCurObject), hDoor) && !g_pLTServer->IsKindOf(g_pLTServer->GetObjectClass(hCurObject), hSwitch)) { Door* pDoor = (Door*)g_pLTServer->HandleToObject(hCurObject); if ( !pDoor->IsAITriggerable() ) continue; LTVector vPos; LTVector vDims; g_pLTServer->GetObjectPos(hCurObject, &vPos); g_pLTServer->GetObjectDims(hCurObject, &vDims); if ( Inside(vPos, vDims.y*2.0f) ) { if ( m_cDoors == cm_nMaxDoors ) { _ASSERT(!"Max number of doors in a volume exceeded!!!!"); g_pLTServer->CPrint("Max number of doors in a volume exceeded!!!!"); } else { m_bHadDoors = LTTRUE; g_pAIVolumeMgr->Link(hCurObject); m_ahDoors[m_cDoors++] = hCurObject; } } } } hCurObject = LTNULL; while (hCurObject = g_pLTServer->GetNextInactiveObject(hCurObject)) { if (g_pLTServer->IsKindOf(g_pLTServer->GetObjectClass(hCurObject), hDoor) && !g_pLTServer->IsKindOf(g_pLTServer->GetObjectClass(hCurObject), hSwitch)) { Door* pDoor = (Door*)g_pLTServer->HandleToObject(hCurObject); if ( !pDoor->IsAITriggerable() ) continue; LTVector vPos; LTVector vDims; g_pLTServer->GetObjectPos(hCurObject, &vPos); g_pLTServer->GetObjectDims(hCurObject, &vDims); if ( Inside(vPos, vDims.y*2.0f) ) { if ( m_cDoors == cm_nMaxDoors ) { _ASSERT(!"Max number of doors in a volume exceeded!!!!"); g_pLTServer->CPrint("Max number of doors in a volume exceeded!!!!"); } else { m_bHadDoors = LTTRUE; g_pAIVolumeMgr->Link(hCurObject); m_ahDoors[m_cDoors++] = hCurObject; } } } } // Validate volume dims. Must be 64x64 if there's no doors. One side must be <= 128 if there are doors #ifndef _FINAL // Don't spam multiplayer server with warnings... if ( m_cDoors == 0 ) { if ( vVolumeDims.x < 32 ) g_pLTServer->CPrint("WARNING: Volume \"%s\" is only %d units wide/x (should be at least 64)", GetName(), (int)vVolumeDims.x*2); if ( vVolumeDims.z < 32 ) g_pLTServer->CPrint("WARNING: Volume \"%s\" is only %d units deep/z (should be at least 64)", GetName(), (int)vVolumeDims.z*2); } else // if ( m_cDoors != 0 ) { if ( vVolumeDims.x >= 128 && vVolumeDims.z >= 128 ) g_pLTServer->CPrint("WARNING: Volume \"%s\" is a suspiciously large door volume!", GetName()); } #endif // Misc flags that have been set m_bStairs = vol.HasStairs(); m_vStairsDir = vol.GetStairsDir(); m_bLedge = vol.HasLedge(); m_vLedgeDir = vol.GetLedgeDir(); m_bVertical = vol.IsVertical(); }