📄 ai_mgr.cpp
字号:
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: SetAnimation
//
// PURPOSE: Set the current animation
//
// ----------------------------------------------------------------------- //
DBOOL AI_Mgr::SetAnimation(DDWORD nAni)
{
if(nAni == m_nCurAnimation)
{
m_pServerDE->ResetModelAnimation(m_hObject);
// pServerDE->SetObjectDims(m_hObject,&m_vDims);
}
else
{
DVector vDims;
VEC_COPY(vDims, m_vDims); //safety
if(m_pServerDE->GetModelAnimUserDims(m_hObject, &vDims, nAni) == DE_OK)
{
vDims.x *= m_vScale.x;
vDims.y *= m_vScale.y;
vDims.z *= m_vScale.z;
}
m_pServerDE->SetObjectDims2(m_hObject,&vDims);
m_pServerDE->SetModelAnimation(m_hObject,nAni);
VEC_COPY(m_vDims,vDims);
m_nCurAnimation = nAni;
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
// ROUTINE : AI_Mgr::HandleTouch
// DESCRIPTION : Handle MID_TOUCHNOTIFY messages
// RETURN TYPE : void
// PARAMS : HOBJECT hObj
// ----------------------------------------------------------------------- //
void AI_Mgr::HandleTouch(HOBJECT hObj)
{
if (!m_hObject || !hObj) return;
HCLASS hClass = m_pServerDE->GetObjectClass(hObj);
return;
}
// ----------------------------------------------------------------------- //
// ROUTINE : AI_Mgr::InsertMe
// DESCRIPTION : Insert to appropriate list
// RETURN TYPE : void
// ----------------------------------------------------------------------- //
void AI_Mgr::InsertMe()
{
// insert it into the list
if(m_bCabal)
{
dl_Insert( &m_CabalHead, &m_Link );
m_Link.m_pData = ( void * )this;
m_dwNumCabal++;
}
else
{
dl_Insert( &m_MonsterHead, &m_Link );
m_Link.m_pData = ( void * )this;
m_dwNumMonster++;
}
}
// ----------------------------------------------------------------------- //
// ROUTINE : AI_Mgr::AI_Init
// DESCRIPTION : Initial update
// RETURN TYPE : void
// ----------------------------------------------------------------------- //
void AI_Mgr::InitialUpdate(int nData)
{
//initialize the inventory aggregate
m_InventoryMgr.Init(m_hObject);
//initialize the damage aggregate
m_damage.Init(m_hObject, &m_InventoryMgr, m_pAnim_Sound);
// Only init stuff needed when restoring a savegame.
if (nData == INITIALUPDATE_SAVEGAME)
{
return;
}
m_InventoryMgr.SetStrength(m_nAIStrength);
for(int i =0; i < 5; i++)
{
int nWeap = WeaponStrToInt(m_szAIWeapon[i]);
if(!m_InventoryMgr.HasWeapon(nWeap))
m_InventoryMgr.ObtainWeapon(nWeap);
}
m_InventoryMgr.ChangeWeapon(WeaponStrToInt(m_szAIWeapon[0]));
m_InventoryMgr.AddAmmo(AMMO_BULLET, m_fAIBullets);
m_InventoryMgr.AddAmmo(AMMO_BMG, m_fAIBMG);
m_InventoryMgr.AddAmmo(AMMO_SHELL, m_fAIShells);
m_InventoryMgr.AddAmmo(AMMO_DIEBUGDIE, m_fAIGrenades);
m_InventoryMgr.AddAmmo(AMMO_HOWITZER, m_fAIRockets);
m_InventoryMgr.AddAmmo(AMMO_FLARE, m_fAIFlares);
m_InventoryMgr.AddAmmo(AMMO_BATTERY, m_fAICharges);
m_InventoryMgr.AddAmmo(AMMO_BATTERY, m_fAICells);
m_InventoryMgr.AddAmmo(AMMO_FUEL, m_fAIFuel);
m_InventoryMgr.AddAmmo(AMMO_FOCUS, 200.0f);
m_InventoryMgr.AddInventoryWeapon(INV_PROXIMITY, (int)m_fProxBombs);
switch(GetGameDifficulty())
{
case DIFFICULTY_EASY: m_InventoryMgr.AddDamageMultiplier(0.25f); break;
case DIFFICULTY_MEDIUM: m_InventoryMgr.AddDamageMultiplier(1.0f); break;
case DIFFICULTY_HARD: m_InventoryMgr.AddDamageMultiplier(1.5f); break;
}
//Set hit points
DFLOAT fHP = m_fAIHitPoints + m_pServerDE->Random(1,m_fAIRandomHP);
switch(GetGameDifficulty())
{
case DIFFICULTY_EASY: fHP *= 0.25f; break;
case DIFFICULTY_MEDIUM: fHP *= 1.0f; break;
case DIFFICULTY_HARD: fHP *= 1.5f; break;
}
m_damage.SetHitPoints(fHP);
m_damage.SetMaxHitPoints(m_damage.GetHitPoints());
m_damage.SetMaxMegaHitPoints(m_damage.GetHitPoints());
//Set armor point
switch(GetGameDifficulty())
{
case DIFFICULTY_EASY: m_fAIArmorPoints *= 0.25f; break;
case DIFFICULTY_MEDIUM: m_fAIArmorPoints *= 1.0f; break;
case DIFFICULTY_HARD: m_fAIArmorPoints *= 1.5f; break;
}
m_damage.SetArmorPoints(m_fAIArmorPoints);
m_damage.SetMaxArmorPoints(m_fAIArmorPoints);
m_damage.SetMaxNecroArmorPoints(m_fAIArmorPoints);
m_damage.SetMass(m_fAIMass);
// Added by Kevin S. 9/29/98 to better support scripted AIs...
m_pServerDE->SetBlockingPriority(m_hObject, BLOCKPRIORITY_AI);
m_MoveObj.Init(m_hObject);
// Set the State
m_nState = StateStrToInt(m_szAIState);
if(m_nState == STATE_GuardLocation)
m_pServerDE->GetObjectPos(m_hObject, &m_vGuardPos);
DDWORD dwFlags = m_pServerDE->GetObjectFlags(m_hObject);
dwFlags |= FLAG_VISIBLE | FLAG_SOLID | FLAG_TOUCH_NOTIFY | FLAG_GRAVITY | FLAG_STAIRSTEP |
FLAG_SHADOW | FLAG_MODELKEYS | FLAG_REMOVEIFOUTSIDE;
m_pServerDE->SetObjectFlags(m_hObject, dwFlags);
// insert it into the list
if(m_bCabal)
{
dl_Insert( &m_CabalHead, &m_Link );
m_Link.m_pData = ( void * )this;
m_dwNumCabal++;
}
else
{
dl_Insert( &m_MonsterHead, &m_Link );
m_Link.m_pData = ( void * )this;
m_dwNumMonster++;
}
//randomize the size/weight
DFLOAT fScale = m_pServerDE->Random(-0.05f, 0.1f);
VEC_SET(m_vScale,m_vScale.x - fScale, m_vScale.y + fScale, m_vScale.z - fScale);
m_pServerDE->ScaleObject(m_hObject,&m_vScale);
SetAnimation(0);
m_pServerDE->SetNextUpdate(m_hObject, 0.001f);
//SCHLEGZ 4/27/98 2:51:47 PM: for vis list activation
m_bSetShutdown = DFALSE;
// Greg 9/28/98 Move this object to the ground
if (m_bMoveToGround)
MoveObjectToGround(m_hObject);
m_fLastUpdate = m_pServerDE->GetTime();
return;
}
// ----------------------------------------------------------------------- //
// ROUTINE : AI_Mgr::AI_Update
// DESCRIPTION : Main update function
// RETURN TYPE : DBOOL
// ----------------------------------------------------------------------- //
DBOOL AI_Mgr::AI_Update()
{
if (!m_hObject || m_bRemoveMe) return DFALSE;
//this is so we can desync activating AI and lessen tick spikes
if(m_pServerDE->GetTime() - m_fLastUpdate >= 1.0f && m_bSetShutdown)
{
m_fLastUpdate = m_pServerDE->GetTime();
m_pServerDE->SetNextUpdate(m_hObject, m_pServerDE->Random(0.01f,0.5f));
return DTRUE;
}
//de-sync method for optimizing AI ticks per frame
/* DFLOAT fFrameTime = m_pServerDE->GetFrameTime();
if(fFrameTime == m_fLastFrame)
{
m_pServerDE->SetNextUpdate(m_hObject, m_pServerDE->Random(fFrameTime,fFrameTime * 10));
return DTRUE;
}
m_fLastFrame = fFrameTime;
*/ m_fLastUpdate = m_pServerDE->GetTime();
m_pServerDE->SetNextUpdate(m_hObject, 0.001f);
//scripted scene? disable!!
if(g_hActiveCamera && m_nState != STATE_Script && m_nState != STATE_Passive && m_nState != STATE_Idle)
{
CameraObj* pCameraObj = (CameraObj*)m_pServerDE->HandleToObject(g_hActiveCamera);
if(!pCameraObj->AllowPlayerMovement())
{
StopVelocity();
return DTRUE;
}
}
//SCHLEGZ 4/27/98 2:51:47 PM: for vis list activation
if(!m_bSetShutdown)
{
m_pServerDE->SetDeactivationTime(m_hObject,3.0f);
m_pServerDE->SetObjectState(m_hObject, OBJSTATE_AUTODEACTIVATE_NOW);
m_bSetShutdown = DTRUE;
}
if(m_hTarget)
{
// This stuff helps the ai keep the target. It was getting too easy to lose the target.
m_bHasTargeted = DTRUE;
if( m_fSeeingDist > m_fSensingDist && m_fSensingDist > 0.0f )
m_fSensingDist = m_fSeeingDist;
m_pServerDE->GetObjectPos(m_hTarget,&m_vTargetPos);
CBaseCharacter* pAI = (CBaseCharacter*)m_pServerDE->HandleToObject(m_hTarget);
if(pAI->IsDead())
{
m_hTarget = DNULL;
SetNewState(STATE_Idle);
}
else
{
if (!(m_dwFlags & FLAG_ALWAYSCLEAR))
{
if( !CanSee( m_hTarget ))
{
m_hTarget = DNULL;
}
}
}
}
if(m_hTrackObject)
m_pServerDE->GetObjectPos(m_hTrackObject,&m_vTrackObjPos);
// If we are DYING... then start that STATE!
if(m_damage.GetHitPoints() <= 0.0f && m_nState != STATE_Dying)
SetNewState(STATE_Dying);
//see what we are standing on
CollisionInfo collisionInfo;
m_pServerDE->GetStandingOn(m_hObject, &collisionInfo);
if(collisionInfo.m_hObject && (collisionInfo.m_hObject != m_pServerDE->GetWorldObject()))
{
HCLASS hCollClass = m_pServerDE->GetObjectClass(collisionInfo.m_hObject);
HCLASS hBaseChar = m_pServerDE->GetClass("CBaseCharacter");
DDWORD dwFlags = m_pServerDE->GetObjectFlags(m_hObject);
if(m_pServerDE->IsKindOf(hCollClass, hBaseChar))
{
dwFlags |= FLAG_DONTFOLLOWSTANDING;
}
else
{
dwFlags &= ~FLAG_DONTFOLLOWSTANDING;
}
m_pServerDE->SetObjectFlags(m_hObject, dwFlags);
}
//sanity check
if(Metacmd <= 0)
Metacmd = 1;
switch(m_nState)
{
case STATE_AttackClose: AI_STATE_AttackClose(); break;
case STATE_AttackFar: AI_STATE_AttackFar(); break;
case STATE_SearchVisualTarget: AI_STATE_SearchVisualTarget(); break;
case STATE_Escape_Hide: AI_STATE_Escape_Hide(); break;
case STATE_Escape_RunAway: AI_STATE_Escape_RunAway(); break;
case STATE_GuardLocation: AI_STATE_GuardLocation(); break;
case STATE_Idle: AI_STATE_Idle(); break;
case STATE_Dodge: AI_STATE_Dodge(); break;
case STATE_Teleport: AI_STATE_Teleport(); break;
case STATE_EnemyAttach: AI_STATE_EnemyAttach(); break;
case STATE_AssistAlly: AI_STATE_AssistAlly(); break;
case STATE_SearchSmellTarget: AI_STATE_SearchSmellTarget(); break;
case STATE_FindAmmo: AI_STATE_FindAmmo(); break;
case STATE_FindHealth: AI_STATE_FindHealth(); break;
case STATE_Special1: AI_STATE_Special1(); break;
case STATE_Special2: AI_STATE_Special2(); break;
case STATE_Special3: AI_STATE_Special3(); break;
case STATE_Special4: AI_STATE_Special4(); break;
case STATE_Special5: AI_STATE_Special5(); break;
case STATE_Special6: AI_STATE_Special6(); break;
case STATE_Special7: AI_STATE_Special7(); break;
case STATE_Special8: AI_STATE_Special8(); break;
case STATE_Passive: AI_STATE_Passive(); break;
case STATE_Dying: AI_STATE_Dying(); break;
case STATE_Recoil: AI_STATE_Recoil(); break;
case STATE_WalkAroundObj: AI_STATE_WalkAroundObj(); break;
case STATE_RunAroundObj: AI_STATE_RunAroundObj(); break;
case STATE_JumpOverObj: AI_STATE_JumpOverObj(); break;
case STATE_CrawlUnderObj: AI_STATE_CrawlUnderObj(); break;
case STATE_WalkToPos: AI_STATE_WalkToPos(); break;
case STATE_RunToPos: AI_STATE_RunToPos(); break;
case STATE_Script: AI_STATE_Script(); break;
case STATE_Inactive: return DTRUE; break;
default: AI_STATE_Idle(); break;
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
// ROUTINE : AI_Mgr::ComputeStimuli
// DESCRIPTION : fill in stimuli set
// RETURN TYPE : DBOOL
// ----------------------------------------------------------------------- //
int AI_Mgr::ComputeStimuli()
{
if (!m_hObject) return DFALSE;
HOBJECT hSightTarget = DNULL,hSmellTarget = DNULL, hSenseTarget = DNULL;
DVector vSight, vSmell, vSense;
HOBJECT hNewTarget = DNULL;
int nStimType = 0;
//Check if hit recently
if(( hNewTarget = m_damage.GetLastDamager()) != DNULL )
{
if( !IsBaseCharacter( hNewTarget ))
m_damage.ClearLastDamager( );
nStimType = STIM_SIGHT;
}
else
{
VEC_COPY(vSight, m_MoveObj.GetPos());
VEC_COPY(vSmell, m_MoveObj.GetPos());
VEC_COPY(vSense, m_MoveObj.GetPos());
//Zero out the stimulus set
memset(&m_fStimuli,0,sizeof(m_fStimuli));
// Release current target if any
SetNewTarget(DNULL);
HCLASS hEnemyTest = DNULL;
HCLASS hThis = m_pServerDE->GetObjectClass(m_hObject);
if(m_pServerDE->IsKindOf(hThis, m_pServerDE->GetClass("BoneLeech")) ||
m_pServerDE->IsKindOf(hThis, m_pServerDE->GetClass("TheHandAI")) ||
m_pServerDE->IsKindOf(hThis, m_pServerDE->GetClass("Thief")))
{
hEnemyTest = m_pServerDE->GetClass("CPlayerObj");
}
else
{
hEnemyTest = m_pServerDE->GetClass("AI_Mgr");
}
HOBJECT hSightObj = FindObjectInRadius(hEnemyTest, m_fSeeingDist, FIND_VISIBLE | FIND_FACE_OBJECT);
HOBJECT hSmellObj = FindObjectInRadius(m_pServerDE->GetClass("SmellHint"), m_fSmellingDist);
HOBJECT hSenseObj = FindObjectInRadius(hEnemyTest, m_fSensingDist);
if(hSightObj)
m_pServerDE->GetObjectPos(hSightObj, &vSight);
if(hSmellObj)
m_pServerDE->GetObjectPos(hSmellObj, &vSmell);
if(hSenseObj)
m_pServerDE->GetObjectPos(hSenseObj, &vSense);
DFLOAT fSight = VEC_DIST(vSight,m_MoveObj.GetPos());
DFLOAT fSmell = VEC_DIST(vSmell,m_MoveObj.GetPos());
DFLOAT fSense = VEC_DIST(vSense,m_MoveObj.GetPos());
//Check smell
if(hSmellObj && m_fSmellingDist > 0 && fSmell <= m_fSmellingDist)
{
m_fStimuli[SMELL] = 1.0f - (fSmell/m_fSmellingDist);
hNewTarget = hSmellObj;
nStimType = STIM_SMELL;
if(m_fStimuli[SMELL] <= 0.0f)
{
m_fStimuli[SMELL] = 0.0f;
hNewTarget = DNULL;
}
}
//Check sense
if(hSenseObj && m_fSensingDist > 0 && fSense <= m_fSensingDist)
{
m_fStimuli[SENSE] = 1.0f - (fSense/m_fSensingDist);
hNewTarget = hSenseObj;
nStimType = STIM_SENSE;
if(m_fStimuli[SENSE] <= 0.0f)
{
m_fStimuli[SENSE] = 0.0f;
hNewTarget = DNULL;
}
}
//Check sight
if(hSightObj && m_fSeeingDist > 0 && fSight <= m_fSeeingDist)
{
m_fStimuli[SIGHT] = 1.0f - (fSight/m_fSeeingDist);
hNewTarget = hSightObj;
nStimType = STIM_SIGHT;
if(m_fStimuli[SIGHT] <= 0.0f)
{
m_fStimuli[SIGHT] = 0.0f;
hNewTarget = DNULL;
}
}
}
//Health
m_fStimuli[HEALTH] = (DFLOAT)m_damage.GetHitPoints()/(DFLOAT)m_damage.GetMaxHitPoints();
if (hNewTarget)
{
if(nStimType != STIM_SMELL)
{
CBaseCharacter* pB = (CBaseCharacter*)m_pServerDE->HandleToObject(hNewTarget);
if( pB->IsDead())
{
hNewTarget = DNULL;
return 0;
}
SetNewTarget(hNewTarget);
// m_fStimuli[THREAT] = ComputeThr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -