⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 npc.cpp

📁 网络游戏魔域的服务端与客户端完整源代码 包括详细的说明文档与开发日志
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		ClearPath();
		return m_nPathLen != 0;
	}

	if(!FindPath(pRole->GetPosX(), pRole->GetPosY(), nEscapeSteps))
		return false;

	// 检查寻路是否有效
	if(m_nPathLen > 0)
	{
		int nDir	= m_bufPath[0] % MAX_DIRSIZE;
		if(!GetMap()->IsMoveEnable(GetPosX(), GetPosY(), nDir, GetSizeAdd()))
		{
			DetectPath(nDir);
			return m_nPathLen != 0;
		}

		if(m_bAheadPath && pRole->Distance(m_posTarget.x, m_posTarget.y)
						>= pRole->Distance(GetPosX(), GetPosY())
				|| !m_bAheadPath && pRole->Distance(m_posTarget.x, m_posTarget.y)
						<= pRole->Distance(GetPosX(), GetPosY()) )
		{
			ClearPath();
			return m_nPathLen != 0;
		}
	}

	return m_nPathLen != 0;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::FindPath(int x, int y, int nEscapeSteps /*= 0*/)
{
	ClearPath();

	if(x == GetPosX() && y == GetPosY())
		return false;

	char	buf[_MAX_PATHSTEP + sizeof(PASSPATH0)];
	PASSPATH0* pPath = (PASSPATH0*)buf;
	POINT	posSource, posTarget;
	posSource.x	= GetPosX();
	posSource.y	= GetPosY();
	posTarget.x	= x;
	posTarget.y	= y;
	GetMap()->QueryMapData()->FindPath(pPath, sizeof(buf), posSource, posTarget, QueryRoleAttr(), nEscapeSteps);
	m_posTarget		= pPath->posStop;
	memcpy(m_bufPath, pPath->pPath, pPath->nSize);
	m_nPathLen		= pPath->nSize;

	return m_nPathLen > 0;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::DetectPath(int nNoDir)		// -1: 全允许
{
	ClearPath();

	POINT posTarget;
	if(m_idMoveTarget != ID_NONE)
	{
		IRole* pRole = UserManager()->QueryRole(m_idMoveTarget);		//@ 只打玩家
		if(pRole)
		{
			posTarget.x = pRole->GetPosX();
			posTarget.y = pRole->GetPosY();
		}
	}
	else
	{
		posTarget = m_pGenerator->GetCenter();
	}
	int nDistOld = Distance(posTarget.x, posTarget.y);
	int nBestDist = nDistOld;
	int	nBestDir	= -1;			// -1: invalid dir
	int	nFirstDir	= ::RandGet(MAX_DIRSIZE);
	for(int i = nFirstDir; i < nFirstDir + MAX_DIRSIZE; i++)
	{
		int nDir = i % MAX_DIRSIZE;
		if(nDir != nNoDir)
		{
			if(GetMap() && GetMap()->IsMoveEnable(GetPosX(), GetPosY(), nDir, GetSizeAdd(), NPC_CLIMBCAP))
			{
				int nNewX = GetPosX() + _DELTA_X[nDir];
				int nNewY = GetPosY() + _DELTA_Y[nDir];
				int nDist = ::Distance(nNewX, nNewY, posTarget.x, posTarget.y);
				if((nBestDist-nDist) * (m_bAheadPath?1:-1) > 0)
				{
					nBestDist	= nDist;
					nBestDir	= nDir;
				}
			}
		}
	}

	if(nBestDir != -1)			// -1: invalid dir
	{
		m_bufPath[0]	= nBestDir;
		m_nPathLen		= 1;
		return true;
	}

	return false;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::TestPath(int nDir)
{
	CHECKF(nDir >= 0 && nDir < MAX_DIRSIZE);

	if(GetMap() && GetMap()->IsMoveEnable(GetPosX(), GetPosY(), nDir, GetSizeAdd(), NPC_CLIMBCAP))
	{
		m_bufPath[0]	= nDir;
		m_nPathLen		= 1;
		return true;
	}
	return false;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::PathMove(int nMode)		// false: 没路了
{
	if(nMode == WALKMODE_MOVE)
	{
		if(!m_tMove.ToNextTick(GetInt(NPCTYPEDATA_MOVESPEED)))
			return true;
	}
	else
	{
		if(!m_tMove.ToNextTick(GetInt(NPCTYPEDATA_RUNSPEED)))
			return true;
	}

	if(m_nPathLen <= 0)
		return false;

	int nDir	= m_bufPath[0] % MAX_DIRSIZE;
	m_nPathLen--;
	if(m_nPathLen)
		memcpy(m_bufPath, m_bufPath+1, m_nPathLen);

	if(MoveForward(nDir, nMode))
	{
		return true;
	}

	if(DetectPath(nDir) && m_nPathLen)
	{
		m_nPathLen =0;
		return MoveForward(m_bufPath[0], nMode);
	}

	if(IsJumpEnable())
	{
		POINT pos = m_pGenerator->GetCenter();
		return JumpBlock(pos.x, pos.y, GetDir());
	}

	return false;
}

//////////////////////////////////////////////////////////////////////
void CNpc::JumpPos(int nPosX, int nPosY, int nDir)
{
	IF_NOT(GetMap()->IsValidPoint(nPosX, nPosY))
		return ;

	ClearPath();
	SetPos(nPosX, nPosY);
	SetDir(nDir);

	{
		CMsgAction	msg;
		if(msg.Create(GetID(), GetPosX(), GetPosY(), nDir, actionJump, nPosX, nPosY))
			SendMsg(&msg);
	}
}

//////////////////////////////////////////////////////////////////////
OBJID CNpc::GetMapID()
{
	if(GetMap())
		return GetMap()->GetID();
	return ID_NONE;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::MoveForward(int nDir, int nMode /*= WALKMODE_MOVE*/)
{
	m_nDir	= nDir % MAX_DIRSIZE;
	int	nDirX	= _DELTA_X[m_nDir];
	int	nDirY	= _DELTA_Y[m_nDir];

	int nNewPosX = GetPosX() + nDirX;
	int nNewPosY = GetPosY() + nDirY;
	IF_NOT(GetMap()->IsValidPoint(nNewPosX, nNewPosY))
		return false;

	if(GetMap() && GetMap()->IsMoveEnable(GetPosX(), GetPosY(), GetDir(), GetSizeAdd()))
	{
		CMsgWalk	msg;
		CHECKF(msg.Create(GetID(), nDir, nMode));
		SendMsg(&msg);

		SetPos(m_nPosX + nDirX, m_nPosY + nDirY);
#ifdef	PALED_DEBUG_X
		MSGBUF	szMsg;
		sprintf(szMsg, "(%d,%d)-%u", m_nPosX, m_nPosY, GetID());
		SendMsg(szMsg);
#endif
		return true;
	}
	else
		return false;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::KickBack(int nTargX, int nTargY)
{
	IF_NOT(GetMap()->IsValidPoint(nTargX, nTargY))
		return false;

//!	if(GetPosX() != nTargX || GetPosY() != nTargY)
	{
		CMsgAction	msg;
		IF_OK(msg.Create(GetID(), nTargX, nTargY, GetDir(), actionSynchro, nTargX, nTargY))
			SendMsg(&msg);
	}

	ClearPath();
	SetPos(nTargX, nTargY);
	return true;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::SynchroPos(int nSourX, int nSourY, int nTargX, int nTargY)
{
	if(GetPosX() != nSourX || GetPosY() != nSourY)
	{
		CMsgAction	msg;
		IF_OK(msg.Create(GetID(), GetPosX(), GetPosY(), GetDir(), actionSynchro, GetPosX(), GetPosY()))
			SendMsg(&msg);
	}
	else if(GetPosX() != nTargX || GetPosY() != nTargY)
	{
		IF_NOT(GetMap()->IsValidPoint(nTargX, nTargY))
			return false;

		ClearPath();
		SetPos(nTargX, nTargY);
	}
	return true;
}

//////////////////////////////////////////////////////////////////////
void CNpc::SetPos(int nPosX, int nPosY)
{
	IF_OK(GetMap())
		GetMap()->MoveTo(this, nPosX, nPosY);

	m_nPosX = nPosX;
	m_nPosY = nPosY;
}

//////////////////////////////////////////////////////////////////////
void CNpc::Attack()
{
	if (m_idActTarget == ID_NONE)
		return;

	CMsgInteract	msg;
	if(msg.Create(INTERACT_ATTACK, GetID(), m_idActTarget, GetPosX(), GetPosY()))
		SendMsg(&msg);

	if(m_idAtkMe != m_idActTarget)
		m_bAtkFirst = true;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::CheckTarget()
{
	if(m_idActTarget == ID_NONE)
	{
		m_idActTarget	= ID_NONE;
		m_idMoveTarget	= m_idActTarget;
		return false;
	}
	IRole* pRole = UserManager()->QueryRole(m_idActTarget);
	if(!pRole || !pRole->IsAlive())
	{
		m_idActTarget	= ID_NONE;
		m_idMoveTarget	= m_idActTarget;
		return false;
	}
	if(pRole->IsWing() && !IsWing() && IsCloseAttack())
		return false;
	int	nDistance	= GetInt(NPCTYPEDATA_VIEWRANGE);
	int	nAtkDistance = ::CutOverflow(nDistance, GetAttackRange(pRole->GetSizeAdd()));
	int nDist =  this->Distance(pRole->GetPosX(), pRole->GetPosY());
	if(!( nDist <= nDistance && !pRole->IsLurker() || nDist <= nAtkDistance && GetAttackRange(0) > 1 ))
	{
		m_idActTarget	= ID_NONE;
		m_idMoveTarget	= m_idActTarget;
		return false;
	}

	return true;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::FindNewTarget()
{
	if(!GetMap())
		return false;

	// lock target
	if(IsLockUser() || IsLockOne())
	{
		if(CheckTarget())
		{
			if(IsLockOne())
				return true;
		}
		else
		{
			if(IsLockUser())
				return false;
		}
	}

	OBJID idOldTarget =  m_idActTarget;
	m_idActTarget = ID_NONE;
	m_idMoveTarget	= m_idActTarget;
	CUserPtr	pTargetUser = NULL;
// no_profession	CUserPtr	pProfession = NULL;

	///////////////////////////////////////////////////////////////////////////////////////////////
	// 修改:
	//     为了支持“吸引怪物”的效果,不论是否主动攻击怪物都主动搜索目标
	//     这样会降低NPC服务器的效率
	//     -- zlong 2005-01-04
	///////////////////////////////////////////////////////////////////////////////////////////////
//	if((GetInt(NPCTYPEDATA_ATKUSER) & ATKUSER_ACTIVE) != 0)
	{
//		IRole* pRole = UserManager()->QueryRole(m_idActTarget);
//		if(!( pRole && pRole->IsAlive() 
//				&& this->Distance(pRole->GetPosX(), pRole->GetPosY()) <= GetInt(NPCTYPEDATA_VIEWRANGE) ))
//			m_idActTarget	= ID_NONE;

		int x,y;
		int	nDistance	= GetInt(NPCTYPEDATA_VIEWRANGE);
// no_profession		int nProfDistance	= nDistance;
		FOR_9_BLOCKS(GetMap(), GetPosX(), GetPosY())
		{
			IUserSet* pUserSet	= GetMap()->BlockByIndex(x,y).QueryUserSet();
			for(int i = 0; i < pUserSet->GetAmount(); i++)
			{
				CUserPtr pUser = pUserSet->GetObjByIndex(i);
				if(pUser && pUser->IsAlive() && (pUser->GetEffect() & KEEPEFFECT_LURKER)==0
					&& pUser->GetID() != this->GetID())
				{
					if(	IsGuard() && pUser->IsCrime() 
							|| IsPkKiller() && pUser->IsPker() 
							|| IsEvilKiller() && pUser->IsVirtuous()
							|| IsEvil() && !(IsPkKiller()||IsEvilKiller())
							|| IsSynPet() && (IsOpposedSyn(pUser->GetSynID())||(pUser->GetEffect()&KEEPEFFECT_SYNCRIME))
							|| (pUser->GetEffect()&KEEPEFFECT_ATTRACT_MONSTER)	// 目标带吸引怪物的状态
							|| (GetEffect()&KEEPEFFECT_CONFUSION))		// 自己是混乱状态
					{
						if(!IsAttackEnable(pUser->QueryRole()))
							continue;

						int	nAtkDistance = ::CutOverflow(nDistance, GetAttackRange(pUser->GetSizeAdd()));
						int nDist =  this->Distance(pUser->GetPosX(), pUser->GetPosY());
						if(nDist <= nDistance && !pUser->IsLurker() 
							|| nDist <= nAtkDistance && GetAttackRange(0) > 1
							|| ((pUser->GetEffect()&KEEPEFFECT_ATTRACT_MONSTER) && (!pTargetUser || 0 == (pTargetUser->GetEffect()&KEEPEFFECT_ATTRACT_MONSTER))))	// 带吸引怪物状态且距离近的目标优先攻击
						{
							nDistance	= nDist;

							m_idActTarget	= pUser->GetID();			// 新目标
							m_idMoveTarget	= m_idActTarget;
							pTargetUser		= pUser;
						}
/* no_profession
						if((IsFighterFirst() && pUser->IsFighter() || IsWizardFirst() && pUser->IsWizard() || IsBowmanFirst() && pUser->IsBowman()))
						{
							if(nDist <= nProfDistance && !pUser->IsLurker() || nDist <= nAtkDistance && GetAttackRange(0) > 1)
							{
								nProfDistance	= nDist;
								pProfession		= pUser;
							}
						}*/
					}
				}
			}
			INpcSet* pNpcSet	= GetMap()->BlockByIndex(x,y).QueryNpcSet();
			for( i = 0; i < pNpcSet->GetAmount(); i++)
			{
				CNpcPtr pNpc = pNpcSet->GetObjByIndex(i);
				if(Cast<CAgent>(pNpc))
					pNpc->GetID();
				if(pNpc && pNpc->IsAlive() && pNpc->GetID()!=this->GetID()
					&& (pNpc->GetEffect() & KEEPEFFECT_LURKER)==0
					&& (IsEvil() && pNpc->IsRighteous() 
						|| IsRighteous() && pNpc->IsEvil()
						|| (GetEffect()&KEEPEFFECT_CONFUSION)))		// 自己是混乱状态
				{
					if(pNpc->IsWing() && !IsWing() && IsCloseAttack())
						continue;

					int nDist =  this->Distance(pNpc->GetPosX(), pNpc->GetPosY());
					if(nDist <= nDistance)
					{
						nDistance	= nDist;
						m_idActTarget	= pNpc->GetID();			// 新目标
						m_idMoveTarget	= m_idActTarget;
#ifdef	LOCAL_DEBUG
						CNpc* pMonster = Cast<CNpc>(pNpc);
						if(pMonster)
							LOGERROR("正邪怪物区域冲突。怪物(类型[%d]发生器[%d])开始攻击怪物(类型[%d]发生器[%d])", 
									GetType(), GetGenerator()->GetID(), pMonster->GetType(), pMonster->GetGenerator()->GetID());
#endif
					}
				}
			}
		}
	} // 主动攻击
/* no_profession
	if(pProfession)		// && (IsFighterFirst() || IsWizardFirst() || IsBowmanFirst()) 
		m_idActTarget	= pProfession->GetID();
*/
	if(m_idActTarget != ID_NONE)
	{
		if(pTargetUser && idOldTarget != pTargetUser->GetID())
		{
			if(IsGuard() && pTargetUser->IsCrime())
			{
				MSGBUF	szMsg;
				sprintf(szMsg, STR_GUARD_CALL_s, pTargetUser->GetName());
				SendMsg(szMsg);
			}
			else if(IsPkKiller() && pTargetUser->IsPker() && m_nActMode == MODE_IDLE)
			{
				MSGBUF	szMsg;
				sprintf(szMsg, STR_PPKER_CALL_s, pTargetUser->GetName());
				SendMsg(szMsg);
			}
		}

		FindPath();					// 没有PATH也返回TRUE

		if ((GetInt(NPCTYPEDATA_ATKUSER) & ATKUSER_ACTIVE) == 0		// 不是主动攻击怪物
			&& (GetEffect() & KEEPEFFECT_CONFUSION) == 0)			// 并且不是混乱状态,清除目标
		{
			m_idActTarget = ID_NONE;
		}
//		return m_idActTarget != ID_NONE;
		return m_idMoveTarget != ID_NONE;
	}

	return false;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::SendMsg(CNetMsg* pMsg)
{
	return NpcWorld()->SendMsg(GetID(), pMsg);
}

//////////////////////////////////////////////////////////////////////
bool CNpc::SendMsg(LPCTSTR szMsg)
{
	CHECKF(szMsg);

	CMsgTalk	msg;
	if(msg.Create(GetStr(NPCTYPEDATA_NAME), ALLUSERS_NAME, szMsg))
		return NpcWorld()->SendMsg(GetID(), &msg);

	return false;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::JumpBlock(int x, int y, int dir)
{
	int nSteps = Distance(x, y);
//	ASSERT(nSteps <= GUARD_LEAVEDISTANCE*2);
	if(nSteps <= 0)
		return true;

	for(int i = 1; i < nSteps + 1; i++)
	{
		POINT pos;
		pos.x = GetPosX() + (x - GetPosX()) * i / nSteps;
		pos.y = GetPosY() + (y - GetPosY()) * i / nSteps;

		if(GetMap()->IsStandEnable(pos.x, pos.y))
		{
			JumpPos(pos.x, pos.y, dir);
			return true;
		}
	}

	if(GetMap()->IsStandEnable(x, y))
	{
		JumpPos(x, y, dir);
		return true;
	}
	return false;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::FarJump(int x, int y, int dir)
{
	int nSteps = Distance(x, y);
//	ASSERT(nSteps <= GUARD_LEAVEDISTANCE*2);
	if(nSteps <= 0)
		return true;

	if(GetMap()->IsStandEnable(x, y))
	{
		JumpPos(x, y, dir);
		return true;
	}

	for(int i = 1; i < nSteps + 1; i++)
	{
		POINT pos;
		pos.x = x + (GetPosX() - x) * i / nSteps;
		pos.y = y + (GetPosY() - y) * i / nSteps;

		if(GetMap()->IsStandEnable(pos.x, pos.y))
		{
			JumpPos(pos.x, pos.y, dir);
			return true;
		}
	}
	return false;
}

//////////////////////////////////////////////////////////////////////
bool CNpc::IsOpposedSyn(OBJID idSyn)
{
	CHECKF(IsSynPet());

	CSyndicate* pSyn = SynManager()->QuerySyndicate(GetOwnerID());
	CHECKF(pSyn);
	if(GetMap()->IsWarTime())
		return !pSyn->IsFriendly(idSyn);
	else
		return pSyn->IsHostile(idSyn);
}

/*/////////////////////////////////////////////////////////////////////
bool CNpc::IsAttackEnable(IRole* pRole)
{
	int	nDistance	= GetInt(NPCTYPEDATA_VIEWRANGE);
	int	nAtkDistance = ::CutOverflow(nDistance, GetAttackRange(pRole->GetSizeAdd()));
	if(pRole->IsLurker())
	{
		if(GetAttackRange(0) > 1 && Distance(pRole->GetPosX(), pRole->GetPosY()) <= nAtkDistance)
			return false;
	}
	else if(nDist < nDistance)
		return false;

	if(pRole->IsWing() && !IsWing() && IsCloseAttack())
		return false;

	return true;
}*/

//////////////////////////////////////////////////////////////////////
void CNpc::LockMove(int nMilliSecs)
{
	m_tMove.IncInterval(nMilliSecs, nMilliSecs);
}

//////////////////////////////////////////////////////////////////////
bool CNpc::IsAttackEnable(IRole* pTarget)
{
	if(pTarget->IsWing() && !IsWing() && IsCloseAttack())
		return false;
//	if(pTarget->GetEffect()&KEEPEFFECT_INSTEAD)
//		return false;

	return true;
}

bool CNpc::IsActive()
{
	return ((GetEffect() & KEEPEFFECT_FREEZE) == 0 
			&& (GetEffect()&KEEPEFFECT_FAINT) == 0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -