📄 npc.cpp
字号:
// Npc.cpp: implementation of the CNpc class.
//
//////////////////////////////////////////////////////////////////////
#include "AllMsg.h"
#include "Npc.h"
#include "NpcWorld.h"
#include "DynaNpcGen.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CNpc::CNpc()
: m_bLocked(false)
{
SetObjType(OBJ_NPC);
m_id = ID_NONE;
m_pType = NULL;
m_nActMode = MODE_IDLE;
m_tAction.SetInterval(0); // 休眠状态不检查超时
m_pMap = NULL;
m_nPosX, m_nPosY = 0;
m_i64Effect = 0;
m_nDir = 0;
m_nPose = 0;
m_idAtkMe = ID_NONE;
m_bAtkFirst = ID_NONE;
m_idActTarget = ID_NONE;
m_idMoveTarget = ID_NONE;
// m_pGenerator = NULL;
m_bAheadPath = true;
m_nPathLen = 0;
m_tMove.SetInterval(0);
m_pMap = NULL;
m_bDie = false;
m_lnkThis.Init(Cast<IRole>(this));
}
//////////////////////////////////////////////////////////////////////
CNpc::~CNpc()
{
if(GetMap())
GetMap()->LeaveMap(this);
if(m_pGenerator != NULL)
{
if(this->GetID() != MONSTERID_FIRST)
NpcManager()->QueryRecycle()->push(this->GetID());
if(!m_bDie)
m_pGenerator->DeleteNpc(this->GetID());
}
}
//////////////////////////////////////////////////////////////////////
bool CNpc::Create(OBJID idNpc, int nType, OBJID idMap, int nPosX, int nPosY, OBJID idGenerator,
OBJID idOwner, int nOwnerType, int nData)
{
CHECKF(idNpc != ID_NONE);
m_pType = NpcManager()->QueryNpcTypeSet()->GetObj(nType);
CHECKF(m_pType);
IGenerator* pGenerator = NpcManager()->QueryGenSet()->GetObj(idGenerator)->QueryInterface();
CHECKF(pGenerator);
if(!IsMonsterID(idNpc) && pGenerator->GetPosX() == 0 && pGenerator->GetPosY())
{
m_pGenerator = CDynaNpcGen::CreateNew(pGenerator, idMap, nPosX, nPosY);
CHECKF(m_pGenerator);
}
else
{
m_pGenerator = pGenerator;
}
m_id = idNpc;
m_pMap = MapManager()->QueryMap(idMap);
m_nPosX = nPosX;
m_nPosY = nPosY;
m_i64Effect = KEEPEFFECT_NORMAL;
m_nCurrLife = m_pType->GetInt(NPCTYPEDATA_LIFE);
m_nCurrPower = m_pType->GetInt(NPCTYPEDATA_MANA);
m_tAction.SetInterval(::CutTrail((m_pType->GetInt(NPCTYPEDATA_ATKSPEED)*3)/1000, THINK_SECS));
m_tAction.Update();
m_tMove.SetInterval(m_pType->GetInt(NPCTYPEDATA_MOVESPEED));
m_tMove.Update();
m_tDormancy.SetInterval(DORMANCY_SECS);
m_tDormancy.Update();
m_idOwner = idOwner;
m_nOwnerType = nOwnerType;
if(m_idOwner == ID_NONE)
m_nOwnerType = OWNER_NONE;
if(IsLockUser())
{
m_idActTarget = (OBJID)nData;
m_idMoveTarget = m_idActTarget;
m_nActMode = MODE_ATTACK;
}
if(!GetMap())
return false;
GetMap()->EnterMap(this);
if(IsDormancyEnable())
{
if(GetMap()->SetDormancy(GetPosX(), GetPosY()))
this->ChangeMode(MODE_DORMANCY);
}
m_pGenerator->GeneratorOK(this->GetID());
return true;
}
//////////////////////////////////////////////////////////////////////
bool CNpc::ProcessEscape()
{
if(!IsEscapeEnable())
{
ASSERT(!"CNpc::ProcessEscape()");
ChangeMode(MODE_IDLE);
return true;
}
{
IRole* pRole = UserManager()->QueryRole(m_idActTarget);
if((IsGuard()||IsPkKiller()) && pRole)
{
JumpPos(pRole->GetPosX(), pRole->GetPosY(), GetDir());
this->ChangeMode(MODE_FORWARD);
return true;
}
}
if(m_nPathLen == 0)
FindPath(GetInt(NPCTYPEDATA_VIEWRANGE)*2); // range : escape。如果目标消失或越逃越近,path_len置为0
if(m_idActTarget == ID_NONE) // 目标消失->休息状态
{
ChangeMode(MODE_IDLE);
return true;
}
else if(m_idActTarget != ID_NONE && m_nPathLen == 0) // 逃不了,有目标->冲锋状态
{
ChangeMode(MODE_FORWARD);
return true;
}
else // if(m_idActTarget != ID_NONE && m_nPathLen != 0)
{
PathMove(WALKMODE_RUN);
return true;
}
}
//////////////////////////////////////////////////////////////////////
bool CNpc::ProcessAttack()
{
// keep attack
IRole* pRole = UserManager()->QueryRole(m_idActTarget);
if(pRole && pRole->IsAlive() && (pRole->GetEffect() & KEEPEFFECT_LURKER)==0
&& this->Distance(pRole->GetPosX(), pRole->GetPosY()) <= GetAttackRange(pRole->GetSizeAdd()))
{
if(m_tAction.ToNextTime())
{
if(GetMap()->IsSuperposition(QueryRole()))
{
m_bAheadPath = false;
DetectPath(-1);
m_bAheadPath = true;
if(m_nPathLen)
{
PathMove(WALKMODE_SHIFT);
}
}
if(m_bAttackFlag)
{
m_bAttackFlag = false; // 正在攻击
}
else
{
ChangeMode(MODE_FORWARD); // MODE_IDLE // 不休息,否则被震晕后会逃
return true;
}
}
return true;
}
// change mode
if(FindNewTarget())
{
IRole* pRole = UserManager()->QueryRole(m_idMoveTarget);
if(pRole && pRole->IsAlive()
&& this->Distance(pRole->GetPosX(), pRole->GetPosY()) > GetAttackRange(pRole->GetSizeAdd()))
{
if(m_nPathLen != 0 && IsMoveEnable()) // 有路,目标可见->冲锋
{
ChangeMode(MODE_FORWARD);
return true;
}
else // if(m_nPathLen == 0)
{
ChangeMode(MODE_IDLE);
return true;
}
}
return true;
}
// not target
ChangeMode(MODE_IDLE);
return true;
}
//////////////////////////////////////////////////////////////////////
bool CNpc::ProcessForward()
{
// test attack enable
IRole* pRole = UserManager()->QueryRole(m_idMoveTarget);
if(pRole && pRole->IsAlive() && (pRole->GetEffect() & KEEPEFFECT_LURKER)==0
&& this->Distance(pRole->GetPosX(), pRole->GetPosY()) <= GetAttackRange(pRole->GetSizeAdd()))
{
if(!IsGuard() && !IsMoveEnable() && IsFarWeapen()&& !m_bAheadPath && m_nPathLen > 0) // 处理弓箭手后撤
{
if(PathMove(WALKMODE_RUN))
return true;
}
ChangeMode(MODE_ATTACK);
return true;
}
// process forward
// too far
POINT pos = m_pGenerator->GetCenter();
if((IsGuard()||IsPkKiller()||IsFastBack()) && m_pGenerator->IsTooFar(GetPosX(), GetPosY(), GUARD_LEAVEDISTANCE))
{
m_idActTarget = ID_NONE; // 清除攻击者
m_idMoveTarget = m_idActTarget;
FarJump(pos.x, pos.y, GetDir());
ClearPath();
ChangeMode(MODE_IDLE);
return true;
}
// guard jump
if((IsGuard()||IsPkKiller()||IsEvilKiller()) && pRole && Distance(pRole->GetPosX(), pRole->GetPosY()) >= PKKILLER_JUMPDISTANCE)
{
JumpPos(pRole->GetPosX(), pRole->GetPosY(), GetDir());
return true;
}
// forward
if(m_nPathLen == 0)
{
if(FindNewTarget()) // 同时FindPath()
{
if(m_nPathLen == 0) // 无路,目标可见->逃跑状态
{
if(IsJumpEnable())
{
IRole* pRole = UserManager()->QueryRole(m_idMoveTarget);
IF_OK(pRole)
JumpBlock(pRole->GetPosX(), pRole->GetPosY(), GetDir());
return true;
}
else
{
ChangeMode(MODE_IDLE);
return true;
}
}
else // if(m_nPathLen != 0)
{
return false; // 重新调用
}
}
else
{
ChangeMode(MODE_IDLE);
return true;
}
}
else // if(m_nPathLen != 0) // 有路,就要走
{
if(m_idMoveTarget != ID_NONE)
PathMove(WALKMODE_RUN);
else
PathMove(WALKMODE_MOVE);
return true;
}
}
//////////////////////////////////////////////////////////////////////
bool CNpc::ProcessIdle()
{
if(IsLockUser())
{
CMsgAction msg;
IF_OK(msg.Create(GetID(), GetPosX(), GetPosY(), GetDir(), actionDie))
SendMsg(&msg);
}
if(!( IsGuard()||IsPkKiller()||IsEvilKiller() ))
{
// walk pass path
if(m_nPathLen > 0)
{
PathMove(WALKMODE_MOVE);
return true;
}
if(!( IsFastBack() && !m_pGenerator->IsInRegion(GetPosX(), GetPosY()) ))
{
if(!m_tAction.ToNextTime())
return true;
}
}
// change to other mode
m_idAtkMe = ID_NONE;
m_bAtkFirst = false;
if(IsActiveEnable() && FindNewTarget())
{
IRole* pRole = UserManager()->QueryRole(m_idMoveTarget);
ASSERT(pRole);
if(pRole)
{
int nDistance = this->Distance(pRole->GetPosX(), pRole->GetPosY());
if(nDistance <= GetAttackRange(pRole->GetSizeAdd()))
{
ChangeMode(MODE_ATTACK);
return false;
}
else if(IsMoveEnable())
{
if(m_nPathLen == 0) // 无路,目标可见->逃跑状态
{
if(!IsEscapeEnable() || ::RandGet(100) < 80) // keep idel
return true;
ChangeMode(MODE_ESCAPE);
return false;
}
else //if(m_nPathLen != 0)
{
ChangeMode(MODE_FORWARD);
return false;
}
}
}
else
{
// DEBUG???@@@
LOGWARNING("npc: [%d][%d], target id: [%d]", GetID(), m_pType->GetID(), m_idMoveTarget);
}
}
if(( IsGuard()||IsPkKiller()||IsEvilKiller() ))
{
// walk pass path
if(m_nPathLen > 0)
{
PathMove(WALKMODE_MOVE);
return true;
}
if(!m_tAction.ToNextTime())
return true;
}
if(!IsMoveEnable())
return true;
// keep idle
if(m_pGenerator->IsInRegion(GetPosX(), GetPosY()))
{
if(IsGuard()||IsPkKiller()||IsEvilKiller())
{
// patrol
if(::RandGet(GUARD_RANDOMMOVE_RATE) == 0
&& m_pGenerator->GetWidth()>1 || m_pGenerator->GetHeight()>1)
{
int x = ::RandGet(m_pGenerator->GetWidth()) + m_pGenerator->GetPosX();
int y = ::RandGet(m_pGenerator->GetHeight()) + m_pGenerator->GetPosY();
if(FindPath(x, y))
PathMove(WALKMODE_MOVE);
}
}
else
{
if(::RandGet(RANDOMMOVE_RATE) == 0)
{
int nDir = ::RandGet(MAX_DIRSIZE);
if(TestPath(nDir))
PathMove(WALKMODE_MOVE);
}
}
}
else // out of range
{
// move back
if((IsGuard()||IsPkKiller()||IsFastBack()) || ::RandGet(RANDOMMOVE_RATE) == 0)
{
POINT pos;
pos = m_pGenerator->GetCenter();
if(FindPath(pos.x, pos.y))
{
PathMove(WALKMODE_MOVE);
}
else if(IsGuard()||IsPkKiller()||IsJumpEnable())
{
JumpBlock(pos.x, pos.y, GetDir());
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////
bool CNpc::CheckDormancy()
{
if(!m_tDormancy.ToNextTime())
return false;
if(GetMap() && GetMap()->SetDormancy(GetPosX(), GetPosY()))
{
ChangeMode(MODE_DORMANCY);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////
void CNpc::BeAttack(IRole* pRole)
{
m_idAtkMe = pRole->GetID();
if(!IsAlive())
return ;
if(!IsMoveEnable())
return ;
if(IsEscapeEnable())
{
// 只会逃跑
if((GetInt(NPCTYPEDATA_ATKUSER) & ATKUSER_PASSIVE) == 0)
{
m_idActTarget = pRole->GetID(); // 新目标
m_idMoveTarget = m_idActTarget;
ChangeMode(MODE_ESCAPE);
return ;
}
// 血少逃跑
if(GetLife() < GetInt(NPCTYPEDATA_ESCAPELIFE))
{
ChangeMode(MODE_ESCAPE);
return ;
}
}
// 弓箭手回撤
int nDistance = this->Distance(pRole->GetPosX(), pRole->GetPosY());
if(IsFarWeapen() && !pRole->IsFarWeapen() && nDistance <= SHORTWEAPON_RANGE_LIMIT)
{
m_idActTarget = pRole->GetID(); // 新目标
m_idMoveTarget = m_idActTarget;
int nSteps = GetAttackRange(pRole->GetSizeAdd()) - nDistance;
FindPath(nSteps);
if(m_nPathLen > nSteps)
m_nPathLen = nSteps;
ChangeMode(MODE_FORWARD);
return;
}
// 冲锋
if(!IsAttackEnable(pRole))
return ;
if(m_nActMode < MODE_FORWARD)
{
if(m_nActMode == MODE_ESCAPE && ::RandGet(100) < 80) // 20% 机会反击
return ;
m_idActTarget = pRole->GetID(); // 新目标
m_idMoveTarget = m_idActTarget;
if(::RandGet(100) < 80)
{
ChangeMode(MODE_FORWARD);
FindPath(pRole->GetPosX(), pRole->GetPosY()); // 不检查可视范围,直接Find坐标。
if(m_nPathLen > 0)
return ;
}
if(IsEscapeEnable())
{
ChangeMode(MODE_ESCAPE);
FindPath(pRole->GetPosX(), pRole->GetPosY(), GetInt(NPCTYPEDATA_VIEWRANGE)); // 不检查可视范围,直接Find坐标。
}
return ;
}
}
//////////////////////////////////////////////////////////////////////
void CNpc::OnTimer()
{
if(CheckDormancy()) // 如超时,休眠
return ;
if(!IsAlive() || IsLocked() || !IsActive()) // 死亡或被锁定状态或不能活动状态
return;
for(int i = 0; i < 10; i++) // 10 : 每次最多10 个AI分析,防死循环
{
switch(m_nActMode)
{
case MODE_ESCAPE:
if(ProcessEscape())
return;
break;
case MODE_ATTACK:
if(ProcessAttack())
return;
break;
case MODE_FORWARD:
if(ProcessForward())
return;
break;
case MODE_IDLE:
if(ProcessIdle())
return;
break;
}
}
}
//////////////////////////////////////////////////////////////////////
bool CNpc::ChangeMode(int nNewMode) // return false : 失败
{
switch(nNewMode)
{
case MODE_DORMANCY:
{
m_nCurrLife = m_pType->GetInt(NPCTYPEDATA_LIFE);
m_nCurrPower = m_pType->GetInt(NPCTYPEDATA_MANA);
}
break;
case MODE_ATTACK:
{
Attack();
}
break;
case MODE_IDLE:
{
// m_tAction.SetInterval(THINK_SECS);
// m_tAction.Update();
}
break;
}
if(nNewMode != MODE_FORWARD)
ClearPath();
m_nActMode = nNewMode;
return true;
}
//////////////////////////////////////////////////////////////////////
bool CNpc::FindPath(int nEscapeSteps /*= 0*/)
{
CHECKF(GetMap());
m_bAheadPath = (nEscapeSteps == 0);
ClearPath();
// 检查目标是否有效
IRole* pRole = UserManager()->QueryRole(m_idMoveTarget);
if(!pRole || !pRole->IsAlive() || this->Distance(pRole->GetPosX(), pRole->GetPosY()) > GetInt(NPCTYPEDATA_VIEWRANGE))
{
m_idActTarget = ID_NONE;
m_idMoveTarget = m_idActTarget;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -