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

📄 ainpc.cpp

📁 网络游戏魔域的服务端与客户端完整源代码 包括详细的说明文档与开发日志
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// AINpc.cpp: implementation of the CMonster class.
//
//////////////////////////////////////////////////////////////////////

#include "AllMsg.h"
#include "GameMap.h"
#include "AINpc.h"
#include "MapGroup.h"
#include "MapItem.h"
#include "basefunc.h"
#include "ActionDefine.h"
#include "MapTrap.h"
#include "UserTable.h"
#include "Item.h"
#include "DeadLoop.h"

#include "DropRuleMap.h"	//add by zlong 2003-11-15

//////////////////////////////////////////////////////////////////////
const int	RECRUITMAGIC_SECS					= 10;			// 每10秒使用一次加血魔法
const int	DEFAULT_MONSTER_MAGIC_LEVEL			= 0;
const int	UNIDENT_PERCENT						= 20;			// 掉普通物品时,未鉴定的比率

const int	AUTO_INC_LIFE_SECS					= 10;			// 每10秒自动增长生命
const int	AUTO_INC_LIFE_PERCENT				= 10;			// 每次增长最大生命的一半

const int	SORB_REFLECT_SECS					= 6;			// 吸收反射状态每隔6秒作用一次

//////////////////////////////////////////////////////////////////////
//---jinggy---begin
#define EXPLODEMONEY_RATE	4	//暴钱几率 
#define EXPLODEMONEY_DOUBLE	15  //暴钱时的倍数
//---jinggy---end
//////////////////////////////////////////////////////////////////////
MYHEAP_IMPLEMENTATION(CMonster,s_heap)
char	szPetTable[] = _TBL_PET;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMonster::CMonster()
{
	SetObjType(OBJ_MONSTER);
	m_pType			= NULL;
	m_idNpc			= ID_NONE;
	m_pBattleSystem	= NULL;
	m_pData			= NULL;

	m_tFootPrint	= 0;
	m_posFootPrint.x	= 0;
	m_posFootPrint.y	= 0;

	m_link.Init(this);
	m_pMagicType	= NULL;
	m_pMagic		= NULL;

	m_pEudemonItem	= NULL;
//	memset(&m_AddInfo, 0, sizeof(m_AddInfo));
	m_nPotential	= DEFAULT_EUDEMON_POTENTIAL;
	m_dwMaskData	= 0;

	m_bDecRole		= false;

	m_nKillNum		= 0;
	m_nKillNum4Potential	= 0;
	m_nKillNum4RelationShip	= 0;
	
	m_nAtkMode		= EATK_MODE_NONE;		// 默认攻击类型为无	
}

//////////////////////////////////////////////////////////////////////
CMonster::~CMonster()
{
	if(m_pData)
	{
		if(IsSynPet())
			MapManager()->RecyclePetID(GetID());
		else if(IsCallPet())
			MapManager()->RecycleCallPetID(GetID());

		if(m_pData->GetInt(PETDATA_LIFE) > 0)		// flag to die
			SaveInfo();
		else
			m_pData->DeleteRecord();
		m_pData->Release();
	}
	if(m_idNpc != ID_NONE)
	{
		LeaveMapGroup();
		m_idNpc = ID_NONE;
	}
	if (m_pBattleSystem)
	{
		delete m_pBattleSystem;
		m_pBattleSystem	= NULL;
	}
	
	if (m_pMagic)
		m_pMagic->ReleaseByOwner();
	
	SAFE_RELEASE (m_setStatus);
}

//////////////////////////////////////////////////////////////////////
bool CMonster::Create(PROCESS_ID idProcess, IRecordset* pRes)
{
	m_idProcess		= idProcess;

	ASSERT(!m_pData);

	m_pData = CPetData::CreateNew();
	CHECKF(m_pData);
	IF_NOT(m_pData->Create(pRes))
		return false;

	OBJID idType = m_pData->GetInt(PETDATA_TYPE);
	m_pType			= MonsterType()->GetObj(idType);
	CHECKF(m_pType);

	m_nDir			= ::RandGet(8);
	m_pMap			= MapManager()->GetGameMap(m_pData->GetInt(PETDATA_MAPID), false);		// false: not load dynamic map
	if(!m_pMap)
	{
		m_pData->Release();
		m_pData = NULL;
		return false;		// not this map group, or in dynamic map
	}

	m_idNpc			= MapManager()->SpawnNewPetID();		//? mast follow m_pMap
	m_nPosX			= m_pData->GetInt(PETDATA_RECORD_X);
	m_nPosY			= m_pData->GetInt(PETDATA_RECORD_Y);
//	m_dwStatus		= STATUS_NORMAL;
	m_i64Effect		= KEEPEFFECT_NORMAL;
//	if((m_pType->GetInt(NPCTYPEDATA_ATKUSER) & ATKUSER_WING))
//		m_i64Effect		= KEEPEFFECT_WING;
	m_nPose			= POSE_STAND;
	m_idGen			= m_pData->GetInt(PETDATA_GENID);

	m_nCurrLife		= m_pData->GetInt(PETDATA_LIFE);
	m_nCurrMana		= m_pData->GetInt(PETDATA_MANA);
	m_tFight.SetInterval(m_pType->GetInt(NPCTYPEDATA_ATKSPEED));
	m_tFight.Update();

	m_tSorbReflect.Clear();
	m_nTotalDamage	= 0;
	
	m_pBattleSystem	= new CBattleSystem(this->m_idProcess, this);
	CHECKF(m_pBattleSystem);
	m_setStatus = CStatusSet::CreateNew(true);
	CHECKF(m_setStatus);

	// synchro
	ST_CREATENEWNPC	info;
	memset(&info, 0, sizeof(ST_CREATENEWNPC));
	info.id				= GetID();
	info.usAction		= MSGAINPCINFO_CREATENEW;
	info.usType			= GetType();
	info.ucOwnerType	= m_pData->GetInt(PETDATA_OWNERTYPE);
	info.idOwner		= m_pData->GetInt(PETDATA_OWNERID);
	info.idMap			= GetMap()->GetID();
	info.usPosX			= GetPosX();
	info.usPosY			= GetPosY();
	info.idData			= m_pData->GetInt(PETDATA_GENID);
	info.nData			= GetData();
	CMsgMonsterInfo	msg;
	IF_OK(msg.Create(&info))
		this->SendMsg(&msg);

	return true;
}

//////////////////////////////////////////////////////////////////////
bool CMonster::Create(PROCESS_ID idProcess, CNpcType* pType, const ST_CREATENEWNPC* pInfo, CUser* pUser, OBJID idItem)
{
	CHECKF(pType && pInfo && pUser);

	IF_OK(Create(idProcess, pType, pInfo, pUser->GetName()))
	{
		CHECKF(IsCallPet() || IsEudemon());

		if(IsMagicAtk())
		{
			m_pMagicType	= CMagic::FindMagicType(GetMagicType(), DEFAULT_MONSTER_MAGIC_LEVEL);
			IF_NOT(m_pMagicType)
			{
				LOGERROR("Can't find magic type [%d] in monster type [%d]", GetMagicType(), pType->GetID());
				return false;
			}
		}

		m_pMagic = CMagic::CreateNew(idProcess, this->QueryRole());
		if (!m_pMagic || !m_pMagic->CreateAll())
			return false;

		// synchro
		CMsgCallPetInfo	msg;
		IF_OK(msg.Create(GetID(), GetLookFace(), pType->GetInt(NPCTYPEDATA_AITYPE), GetPosX(), GetPosY(), idItem))
			pUser->SendMsg(&msg);

		m_pOwner		= pUser->QueryLink();

		if (IsEudemon())
		{
			CMsgUserAttrib msg;
			if (msg.Create(this->GetID(), _USERATTRIB_POTENTIAL, this->GetPotential()))
				this->SendMsg(&msg);
		}
		return true;
	}
	return false;
}

//////////////////////////////////////////////////////////////////////
bool CMonster::Create(PROCESS_ID idProcess, CNpcType* pType, const ST_CREATENEWNPC* pInfo, LPCTSTR pszName/*=NULL*/)
{
	m_idProcess		= idProcess;

	CHECKF(pType);

	m_idNpc			= pInfo->id;
	m_nDir			= ::RandGet(8);
	m_pMap			= MapManager()->GetGameMap(pInfo->idMap);
	m_nPosX			= pInfo->usPosX;
	m_nPosY			= pInfo->usPosY;
//	m_dwStatus		= STATUS_NORMAL;
	m_i64Effect		= KEEPEFFECT_NORMAL;
	m_nPose			= POSE_STAND;
	m_idGen			= pInfo->idData;

	m_pType			= pType;

	m_nCurrLife		= m_pType->GetInt(NPCTYPEDATA_LIFE);
	m_nCurrMana		= m_pType->GetInt(NPCTYPEDATA_MANA);
	m_tFight.SetInterval(m_pType->GetInt(NPCTYPEDATA_ATKSPEED));
	m_tFight.Update();

	if(!m_pMap)
		return false;

	m_pBattleSystem	= new CBattleSystem(this->m_idProcess, this);
	CHECKF(m_pBattleSystem);
	m_setStatus = CStatusSet::CreateNew(true);
	CHECKF(m_setStatus);

	if(!IsCallPet() && !IsEudemon())	// synchro outside
	{
		CMsgMonsterInfo	msg;
		IF_OK(msg.Create(pInfo))
			this->SendMsg(&msg);
	}

	if(!IsSynPet() || pInfo->idOwner == ID_NONE)		// need not save to database
		return true;

	/////////////////////////////////////////////////////////////////////////
	// create record
	m_pData = CPetData::CreateNew();
	IF_OK(m_pData)
	{
		IF_OK(m_pData->Create(GameDataDefault()->GetPetData(), ID_NONE))
		{
			m_pData->SetInt(PETDATA_OWNERID, pInfo->idOwner);
			m_pData->SetInt(PETDATA_OWNERTYPE, pInfo->ucOwnerType);
			m_pData->SetInt(PETDATA_GENID, pInfo->idData);
			m_pData->SetInt(PETDATA_TYPE, pInfo->usType);
			if(pszName)
				m_pData->SetStr(PETDATA_NAME, pszName, _MAX_NAMESIZE);
			else
				m_pData->SetStr(PETDATA_NAME, pType->GetStr(NPCTYPEDATA_NAME), _MAX_NAMESIZE);
			m_pData->SetInt(PETDATA_LIFE, m_nCurrLife);
			m_pData->SetInt(PETDATA_MANA, m_nCurrMana);
			m_pData->SetInt(PETDATA_MAPID, pInfo->idMap);
			m_pData->SetInt(PETDATA_RECORD_X, pInfo->usPosX);
			m_pData->SetInt(PETDATA_RECORD_Y, pInfo->usPosY);
			m_pData->SetInt(PETDATA_DATA, pInfo->nData);
			OBJID idPet = m_pData->InsertRecord();

			return idPet != ID_NONE;
		}
		else
		{
			SAFE_RELEASE(m_pData);
		}
	}
	return false;
}

//////////////////////////////////////////////////////////////////////
void CMonster::OnTimer(time_t tCurr)
{
	if(!this->IsAlive() && !m_bLeaveMap)
	{
		if ((m_tDie.IsActive() && m_tDie.GetRemain() < NPCDIEDELAY_SECS/2)			// 
			&& !(m_i64Effect & KEEPEFFECT_DISAPPEARING)		// 已经设置了尸体消失状态,避免重复设置
			&& !this->QueryStatus(STATUS_LOCK))				// 如果处于锁定状态则不消失
		{
			this->SetStatus(STATUS_DISAPPEARING);
		}
	}
	if(IsDeleted())
		return ;	// no timer

	// add life ------------------------------------------------------
	DEBUG_TRY
	if (IsAlive() && m_pType->GetInt(NPCTYPEDATA_MAGIC_TYPE) == SIMPLEMAGIC_RECRUIT && m_tAddLife.IsActive() && m_tAddLife.ToNextTime(RECRUITMAGIC_SECS))
	{
		if(GetLife() < GetMaxLife())
		{
			int nAddLife = GetMaxLife() * GetRecruitMagicPercent() / 100;
			int nLoseLife = ::CutRange((int)GetMaxLife() - (int)GetLife(), (int)0, (int)GetMaxLife());
			nAddLife = ::CutOverflow(nAddLife, nLoseLife);
			AddAttrib(_USERATTRIB_LIFE, nAddLife, SYNCHRO_TRUE);

			// synchro
			CMsgMagicEffect	msg;
			IF_OK(msg.Create(GetID(), SIMPLEMAGIC_RECRUIT, 0, GetID(), nAddLife, GetDir()))
				BroadcastRoomMsg(&msg, EXCLUDE_SELF);

			m_nFightPause	+= 1000;		// delay
		}
		else
		{
			m_tAddLife.Clear();
		}
	}
	DEBUG_CATCH("CMonster add life");
	
	// 幻兽生命自动回复 -----------------------------------------------
	DEBUG_TRY
	if (IsAlive() && IsEudemon() && m_pEudemonItem)
	{
		if (!m_tIncLife.IsActive())
			m_tIncLife.Startup(AUTO_INC_LIFE_SECS);
		else
		{
			 if (m_tIncLife.ToNextTime() && GetLife() < GetMaxLife())
			 {
				 int nAddLife = GetMaxLife()*AUTO_INC_LIFE_PERCENT/100;
				 AddAttrib(_USERATTRIB_LIFE, nAddLife, SYNCHRO_TRUE);
			 }
		}
	}
	DEBUG_CATCH("CMonster increase life");

	// 吸收伤害反射 -------------------------------------------------
	DEBUG_TRY
	if (m_tSorbReflect.IsActive() && m_tSorbReflect.ToNextTime())
	{
		if (m_pBattleSystem && m_pBattleSystem->IsActived() && m_nTotalDamage>0)
		{
			IRole* pTarget = this->FindAroundRole(m_pBattleSystem->GetTargetID());
			if (pTarget)
			{
				int nLifeLost = __min(m_nTotalDamage, pTarget->GetLife());
				pTarget->AddAttrib(_USERATTRIB_LIFE, -1*nLifeLost, SYNCHRO_TRUE);
				pTarget->BeAttack(BY_WEAPON, this, nLifeLost);
				if (!pTarget->IsAlive())
					this->Kill(pTarget, DIE_NORMAL);
			}
		}

		m_nTotalDamage = 0;		// 无论成功与否,一定要记得清0
	}
	DEBUG_CATCH("CMonster sorb reflect timer crash.")

	// 自动攻击 ------------------------------------------------------
	DEBUG_TRY
	if (m_pBattleSystem && m_pBattleSystem->IsActived() 
		&& m_tFight.ToNextTick(GetInterAtkRate() + m_nFightPause)
		&& (!QueryMagic() || !QueryMagic()->IsActive()))
	{
		m_pBattleSystem->ProcAttack_Hand2Hand();
		m_nFightPause	= 0;
	}
	DEBUG_CATCH("CMonster ProcAttack_Hand2Hand");

	if (m_pMagic)
	{
		DEBUG_TRY
		DEADLOOP_CHECK(PID, "QueryMagic()->OnTimer")
		m_pMagic->OnTimer(tCurr);
		DEBUG_CATCH("CMonster magic timer crash.")
	}

	// status --------------------------------------------------------
	DEBUG_TRY
	// 以下增加部分代码用于判断是否解除结界系统状态
	// bDetachTeamStatus = true 表示需要解除所有与结界相关的状态
	bool	bDetachTeamStatus = true;
	bool	bDetachAddExpStatus = true;		// 是否解除STATUS_ADD_EXP
	if (IsAlive())
	{
		if (m_pOwner)
		{
			CTeam* pTeam = m_pOwner->GetTeam();
			if (pTeam)
			{
				CUser* pLeader = UserManager()->GetUser(pTeam->GetLeader());
				if (pLeader && pLeader->IsAlive()
					&& this->GetMap()->GetID() == pLeader->GetMap()->GetID()
					&& this->GetDistance(pLeader->QueryMapThing()) <= _RANGE_TEAM_STATUS)
				{
					bDetachTeamStatus = false;
				}
				if (pLeader && pLeader->QueryStatus(STATUS_ADD_EXP))
					bDetachAddExpStatus = false;
			}
		}
	}

	for(int i = QueryStatusSet()->GetAmount()-1; i >= 0; i--)
	{
		IStatus* pStatus = QueryStatusSet()->GetObjByIndex(i);
		if(pStatus)
		{
			pStatus->OnTimer(tCurr);
			if(!pStatus->IsValid()
				|| (bDetachTeamStatus && pStatus->GetID() >= STATUS_TEAM_BEGIN && pStatus->GetID() <= STATUS_TEAM_END)
				|| (bDetachAddExpStatus && pStatus->GetID() == STATUS_ADD_EXP))
			{
				QueryStatusSet()->DelObj(pStatus->GetID());
			}
		}
	}
	DEBUG_CATCH("monster magic poison")

	// 死亡 -----------------------------------------------------
	DEBUG_TRY
	if((IsCallPet() || IsEudemon()) && m_pOwner == NULL)
	{
		if(!IsDeleted())
		{
			LOGERROR("Call pet don't find owner! del self.");
			DelMonster(DEL_NOW);
		}
	}
	DEBUG_CATCH("RoleManager()->QuerySet()->DelObj")
}

//////////////////////////////////////////////////////////////////////
void CMonster::ClearAllStatus()
{
	for(int i = QueryStatusSet()->GetAmount() - 1; i >= 0; i--)
	{
		IStatus* pStatus = QueryStatusSet()->GetObjByIndex(i);
		if(pStatus)
			QueryStatusSet()->DelObj(pStatus->GetID());
	}
}

//////////////////////////////////////////////////////////////////////
/*
int	 CMonster::AdjustData(int nData, int nAdjust, int nMaxData/ *=0* /)
{
	if(nAdjust>=ADJUST_PERCENT)
		return MulDiv(nData, nAdjust-ADJUST_PERCENT, 100);

	if(nAdjust<=ADJUST_SET)
		return -1*nAdjust + ADJUST_SET;

	if(nAdjust==ADJUST_FULL)
	{
		ASSERT(nMaxData != 0);
		return nMaxData;
	}

	return nData + nAdjust;
}
*/

//////////////////////////////////////////////////////////////////////
bool CMonster::SendMsg(CNetMsg* pMsg)
{
	if ((this->IsEudemon() || this->IsCallPet()) && m_pOwner)
		return m_pOwner->SendMsg(pMsg);
	else
		return MapGroup(PID)->QueryIntraMsg()->SendNpcMsg(m_idNpc, pMsg);
}

//////////////////////////////////////////////////////////////////////
void CMonster::BroadcastRoomMsg(CNetMsg* pMsg, bool bSendSelf /*= false*/)
{
	CRole::BroadcastRoomMsg(pMsg, bSendSelf);
}

//////////////////////////////////////////////////////////////////////
void CMonster::BroadcastRoomMsg(LPCTSTR szMsg, bool bSendSelf /*= false*/)		
{
	CMsgTalk	msg;
	if(msg.Create(GetName(), ALLUSERS_NAME, szMsg, NULL, 0xff0000, _TXTATR_SYSTEM))
		this->BroadcastRoomMsg(&msg, bSendSelf);
}

//////////////////////////////////////////////////////////////////////
void CMonster::BroadcastMapMsg(CNetMsg* pMsg, bool bSendSelf /*= false*/)		
{ 
	CMapPtr pMap = this->GetMap();
	if(pMap)
		UserManager()->BroadcastMapMsg(pMap->GetID(), pMsg);
	if(bSendSelf)

⌨️ 快捷键说明

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