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

📄 npc.cpp

📁 网络游戏魔域的服务端与客户端完整源代码 包括详细的说明文档与开发日志
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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 + -