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

📄 ainpc.cpp

📁 网络游戏魔域的服务端与客户端完整源代码 包括详细的说明文档与开发日志
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	CGameMap* pMap = this->GetMap();
	if (pMap && m_pOwner)
	{
		// crime
		if (!pTarget->IsEvil()				// 只有pk白名才闪蓝
			&& !pMap->IsDeadIsland())	// 死亡岛杀人不闪蓝
		{
			if (!m_pOwner->QueryStatus(STATUS_CRIME))
				m_pOwner->SetCrimeStatus();
		}
	}

	IStatus* pStatus = QueryStatus(STATUS_DMG2LIFE);
	if (pStatus)
	{
		int nLifeGot = ::CutTrail(0, MulDiv(nDamage, pStatus->GetPower(), 100));
		if (nLifeGot > 0)
			this->AddAttrib(_USERATTRIB_LIFE, nLifeGot, SYNCHRO_TRUE);
	}

	return nDamage;
}

//////////////////////////////////////////////////////////////////////
bool CMonster::BeAttack(bool bMagic, IRole* pTarget, int nPower, bool bReflectEnable/*=true*/)
{
	if (m_pType->GetInt(NPCTYPEDATA_MAGIC_TYPE) == SIMPLEMAGIC_RECRUIT && !m_tAddLife.IsActive())
		m_tAddLife.Startup(RECRUITMAGIC_SECS);
	
	CRole::DetachStatus(this->QueryRole(), STATUS_FREEZE);
	
	if (QueryStatus(STATUS_SORB_REFLECT))
		m_nTotalDamage += nPower;

	return true;
}

//////////////////////////////////////////////////////////////////////
void CMonster::Kill(IRole* pTarget, DWORD dwDieWay)
{
	CHECK(pTarget);

	CMsgInteract msg;
	if(msg.Create(INTERACT_KILL, this->GetID(), pTarget->GetID(), pTarget->GetPosX(), pTarget->GetPosY(), dwDieWay))
		pTarget->BroadcastRoomMsg(&msg, true);

#ifdef	LOCAL_DEBUG
	CMonster* pMonster;
	if(pTarget->QueryObj(OBJ_NPC, IPP_OF(pMonster)))
		LOGERROR("怪物[%s][%d]在[%d,%d]杀死了[%s][%d]", GetName(), GetType(), 
						GetPosX(), GetPosY(), pMonster->GetName(), pMonster->GetType());
#endif

	if(m_pOwner)
	{
		CUser*	pTargetUser=NULL;
		if(pTarget->QueryObj(OBJ_USER, IPP_OF(pTargetUser)))
			m_pOwner->ProcessPk(pTargetUser);
	}

	if (QueryStatus(STATUS_FRENZY2))
		++m_nKillNum;

	if (this->IsEudemon())
	{
		++m_nKillNum4Potential;
		if (m_nKillNum4Potential >= ADD_POTENTIAL_KILLNUM)
		{
			m_nKillNum4Potential = 0;
			AddAttrib(_USERATTRIB_POTENTIAL, ADD_POTENTIAL_PER_KILLNUM, SYNCHRO_TRUE);
		}

		++m_nKillNum4RelationShip;
		if (m_nKillNum4RelationShip >= ADD_RELATIONSHIP_KILLNUM)
		{
			// TODO: 增加/减少关系值
			if (QueryOwnerUser())
			{
				UCHAR setDivine[10];
				memset(setDivine, 0, sizeof(setDivine));
				for (int i=0; i<m_pOwner->GetEudemonAmount(); i++)
				{
					CMonster* pEudemon = m_pOwner->QueryEudemonByIndex(i);
					if (pEudemon && pEudemon->GetID() != this->GetID())
					{
						OBJID idDivine = pEudemon->GetDivineID();
						++setDivine[idDivine];
					}
				}
				for (i=1; i<=8; i++)
				{
					if (setDivine[i] > 0)
					{
						if (::RandGet(1000) < 10)
							this->AddRelationShip(i, ADD_RELATIONSHIP_PER_TIME);
					}
					else
					{
						if (::RandGet(1000) < 5)
							this->AddRelationShip(i, -1*ADD_RELATIONSHIP_PER_TIME);
					}
				}
			}
		}
	}

	pTarget->BeKill((IRole*)this);
}

//////////////////////////////////////////////////////////////////////
void CMonster::BeKill(IRole* pRole /*= NULL*/)
{
	if(IsDeleted())
		return ;

	// pet
	if(m_pData)
	{
		m_pData->SetInt(PETDATA_LIFE, 0);		// set flag to die
	}

	// 幻兽死亡扣亲密度,并且加仇人
	if (this->IsEudemon() && m_pEudemonItem && m_pOwner)
	{
		int nFidelity = __max(0, m_pEudemonItem->GetInt(ITEMDATA_FIDELITY) - EUDEMON_DEC_FIDELITY_WHEN_DIE);
		m_pEudemonItem->SetInt(ITEMDATA_FIDELITY, nFidelity, true);

		CMsgItemAttrib msg;
		if (msg.Create(m_pEudemonItem->GetID(), _ITEMATTRIB_FIDELITY, m_pEudemonItem->GetInt(ITEMDATA_FIDELITY)))
			m_pOwner->SendMsg(&msg);

		// 被别人或者别人的幻兽杀死,加入主人的仇人名单
		CUser* pAtkUser = NULL;
		CMonster* pMonster = NULL;
		if (pRole->QueryObj(OBJ_MONSTER, IPP_OF(pMonster)) && pMonster->IsEudemon())
			pAtkUser = pMonster->QueryOwnerUser();
		else
			pRole->QueryObj(OBJ_USER, IPP_OF(pAtkUser));

		if (pAtkUser && pAtkUser->GetID() != m_pOwner->GetID())
		{
			m_pOwner->QueryEnemy()->Add(pAtkUser->GetID(), pAtkUser->GetName(), SYNCHRO_TRUE, UPDATE_TRUE);
		}
	}

	CUser* pActionUser = NULL;
	if(pRole)
		pActionUser = pRole->QueryOwnerUser();			// pActionUser for call action
	OBJID idMapItemOwner = NULL;		// idMapItemOwner for map item owner
	if(pActionUser)
		idMapItemOwner = pActionUser->GetID();

	// bomb
	if((IsCallPet()/* || IsEudemon()*/) && IsMagicAtk() && m_pMagicType && m_pMagicType->GetInt(MAGICTYPEDATA_SORT) == MAGICSORT_BOMB)
	{
		DEBUG_TRY
		ProcessBomb();
		DEBUG_CATCH("CMonster::ProcessBomb()")
	}

	////////////////////////////////////////////////////////////////////
	// 怪物死亡后掉宝规则修改:
	// 取消原来的掉钱或者掉药品代码,改用新的掉物品规则
	// 若Action不存在,则根据cq_dropitemrule表中相应的规则掉宝
	//
	// 冷紫龙 2003-11-13
	////////////////////////////////////////////////////////////////////

	IStatus * pStatus = pRole->QueryStatus(STATUS_ADJUST_DROPMONEY);

	//drop money
	int nChanceAdjust = 100;
	CUser* pUser = NULL;
	// 玩家攻击绿名则掉钱/爆钱率调整为原来的20%
	if (pRole->QueryObj(OBJ_USER, IPP_OF(pUser)) && (NAME_GREEN == CMonster::GetNameType(pRole->GetLev(), this->GetLev())))
		nChanceAdjust = 20;

	if (::RandGet(100) < (m_pType->GetInt(NPCTYPEDATA_DROP_MONEY_CHANCE)*nChanceAdjust/100))
	{
		DWORD dwMoneyMin = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MIN);
		DWORD dwMoneyMax = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MAX);
		DWORD dwMoney = dwMoneyMin + ::RandGet(dwMoneyMax - dwMoneyMin + 1);
		//---jinggy---begin
		//玩家特殊状态调节掉钱数量
		if (pStatus)
			dwMoney = ::CutTrail(0, AdjustData(dwMoney, pStatus->GetPower()));						
		//---jinggy---end

		this->DropMoney(dwMoney, idMapItemOwner);
	}
	//---jinggy---暴钱---begin
	if (::RandGet(100) < (EXPLODEMONEY_RATE*nChanceAdjust/100))
	{
		DWORD dwMoneyMin = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MIN);
		DWORD dwMoneyMax = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MAX);
		DWORD dwMoney = (dwMoneyMin + ::RandGet(dwMoneyMax - dwMoneyMin + 1)) * EXPLODEMONEY_DOUBLE;
		
		//玩家特殊状态调节掉钱数量
		if (pStatus)
			dwMoney = ::CutTrail(0, AdjustData(dwMoney, pStatus->GetPower()));						

		int nHeapNum = 5 + ::RandGet(4); //堆数
		DWORD dwMoneyAve = dwMoney / nHeapNum;
		for(int i=0; i<nHeapNum; i++)
		{
			DWORD dwMoneyTmp = MulDiv(dwMoneyAve, 90 + RandGet(21), 100);
			this->DropMoney(dwMoneyTmp, idMapItemOwner);
		}
	}
	//---jinggy---暴钱---end

	// do action...
	if (m_pType->GetInt(NPCTYPEDATA_ACTION))
	{
		GameAction()->ProcessAction(m_pType->GetInt(NPCTYPEDATA_ACTION), pActionUser, this);
	}
//	else
	{
		// TODO: 增加采用新规则计算掉物品金钱代码
		/////////// 如果Action不存在,则采用新规则计算掉物品、金钱 <- Action用于其他用途,因此Action与掉物品并行执行
		// 冷紫龙 2003-11-13
		OBJID	idRuleGroup = m_pType->GetInt(NPCTYPEDATA_DROP_ITEM_RULE);
		CDropRuleGroup*	pDropRuleGroup = NULL;
		if ((ID_NONE != idRuleGroup) && (pDropRuleGroup	= DropRuleMap()->GetObjByIndex(idRuleGroup)))
		{
			int nDropNum = 0;
			int nAtkLev = this->GetLev();
			if(pRole)
				nAtkLev = pRole->GetLev();

			int nRate = ::RandGet(10000);

			//需要根据等级调整实际的掉宝几率
			int nChance = CBattleSystem::AdjustDrop(m_pType->GetInt(NPCTYPEDATA_EXPLODE_ITEM_CHANCE3), nAtkLev, this->GetLev());
			if (nRate < __min(10000, nChance))
			{
				nDropNum = 10 + ::RandGet(6);	//大爆drop 10 ~ 15 item
			} else {
				nChance += CBattleSystem::AdjustDrop(m_pType->GetInt(NPCTYPEDATA_EXPLODE_ITEM_CHANCE2), nAtkLev, this->GetLev());
				if (nRate < __min(10000, nChance))
				{
					nDropNum = 6 + ::RandGet(4);	//中爆drop 6 ~ 9 item
				} else {
					nChance += CBattleSystem::AdjustDrop(m_pType->GetInt(NPCTYPEDATA_EXPLODE_ITEM_CHANCE1), nAtkLev, this->GetLev());
					if (nRate < __min(10000, nChance))
					{
						nDropNum = 2 + ::RandGet(4);	//小爆drop 2 ~ 5 item
					} else {
						nChance += CBattleSystem::AdjustDrop(m_pType->GetInt(NPCTYPEDATA_DROP_ITEM_CHANCE), nAtkLev, this->GetLev());
						if (nRate < __min(10000, nChance))
							nDropNum = 1;	//普通drop 1 item
					}
				}
			}

			//??如果掉物品规则不是百分百掉,则实际掉的物品数有可能少于nDropNum
			for (int i=0; i<nDropNum; i++)
			{
				OBJID	idItemType = pDropRuleGroup->GetDropItem();
				if (idItemType != ID_NONE)
				{
					int nAddLuck = 0;
					int nAddAtk = 0;
/*
					if (CItem::IsEquipment(idItemType) && !CItem::IsMount(idItemType) && !CItem::IsSprite(idItemType))
					{
						//仅对除了座骑、精灵以外的其他装备加成
						int nRate = ::RandGet(1000);
						if (nRate < 1)				// 0.10% chance +3 luck
							nAddLuck = 3;
						else if (nRate < 5+1)			// 0.50% chance +2 luck
							nAddLuck = 2;
						else if (nRate < 25+5+1)		// 2.50% chance +1 luck
							nAddLuck = 1;

						if (::RandGet(1000) < 25)	// 2.50% chance + atk/def
						{
							CItemTypeData* pType = ItemType()->QueryItemType(idItemType);
							if(!pType)
							{
								LOGWARNING("怪物掉物品错误:错误的item_type[%u]!", idItemType);
								break;
							}
							int nLev = pType->GetInt(ITEMTYPEDATA_LEVEL);
							nAddAtk = __min(99, nLev*10) - (int)sqrt(::RandGet(__min(9801, nLev*nLev*100)));
							ASSERT(nAddAtk > 0 && nAddAtk < 100);
						}
					}
*/

					int	nUserLuck = 0;
					if(pRole)
						nUserLuck = pRole->GetLuck();
					if (!this->DropItem(idItemType, idMapItemOwner, nAddLuck, nAddAtk, nUserLuck,true))
						break;
				}
			}
		}
	}

	this->SetStatus(STATUS_DIE);
	if (this->IsEudemon() && m_pEudemonItem)
		m_pOwner->CallBackEudemon(m_pEudemonItem->GetID(), false);
	else
		DelMonster();

	DEBUG_TRY
	if(IsInsteadMagic() && m_pOwner)
	{
		m_pOwner->BeKill();		// BeKill(pRole)
	}
	DEBUG_CATCH("instead kill!")
}

//////////////////////////////////////////////////////////////////////
void CMonster::DelMonster(bool bNow/*=false*/)			// call this mast !IsDeleted()
{
	CHECK(!IsDeleted());

	// 必须设置为NULL,否则如果是角色离线,将导致后面的取属性异常
	if (m_pEudemonItem)
		m_pEudemonItem = NULL;

	// 因为打开了WITH_BLOCK开关,为了在死亡后尸体允许穿透,需要减地图上的角色数
	//if (GetMap() && !this->IsAlive())
	if (!m_bDecRole)
	{
		m_bDecRole	= true;
		GetMap()->DecRole(this->GetPosX(), this->GetPosY());
	}

	// pet
	if(m_pData)
	{
		m_pData->SetInt(PETDATA_LIFE, 0);		// set flag to die
	}

	// synchro npc server to del npc object
	if(bNow)
	{
		m_tDie.Startup(0);
		SendLeaveFromBlock();

		ClrBroadcastSet();
	}
	else
		// die status
		m_tDie.Startup(NPCDIEDELAY_SECS);
}

//////////////////////////////////////////////////////////////////////
void CMonster::SendDamageMsg(OBJID idTarget, int nDamage)
{
	if(IsSimpleMagicAtk())
	{
		CMsgMagicEffect	msg;
		IF_OK(msg.Create(GetID(), m_pType->GetInt(NPCTYPEDATA_MAGIC_TYPE), 0, idTarget, nDamage, GetDir()))
			BroadcastRoomMsg(&msg, INCLUDE_SELF);
	}
	else if(IsBowman())
	{
		CMsgInteract msg;
		IF_OK(msg.Create(INTERACT_SHOOT, GetID(), idTarget, GetPosX(), GetPosY(), nDamage))
			BroadcastRoomMsg(&msg, INCLUDE_SELF);
	}
	else
	{
		CMsgInteract msg;
		IF_OK(msg.Create(INTERACT_ATTACK, GetID(), idTarget, GetPosX(), GetPosY(), nDamage))
			BroadcastRoomMsg(&msg, INCLUDE_SELF);
	}
}

////////////////////////////////////////////////////////////////////////////////////
DWORD CMonster::GetDropMoneyAvg()
{
	DWORD dwMoneyMin = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MIN);
	DWORD dwMoneyMax = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MAX);
	return (dwMoneyMin+dwMoneyMax)/2;
}

////////////////////////////////////////////////////////////////////////////////////
// drop
////////////////////////////////////////////////////////////////////////////////////
bool CMonster::DropMoney(DWORD dwMoney, OBJID idOwner)
{
	if (dwMoney <= 0)
		return true;

	if (this->GetLev() >= 80 && dwMoney <= 10)
		return true;

#ifdef _DEBUG
	// temp code
	FILE* fp = fopen("money.ini", "a+");
	if (fp)
	{
		fprintf(fp, "monster:%03u money ,%06u\n", 
			this->GetID(), dwMoney);
	}
	fclose(fp);
#endif

	POINT	pos;
	pos.x	= GetPosX();
	pos.y	= GetPosY();
	if(GetMap()->FindDropItemCell(MONSTERDROPITEM_RANGE, &pos))
	{
		CMapItem* pMapItem = CMapItem::CreateNew();
		if(pMapItem)
		{
			if(pMapItem->CreateMoney(MapManager()->SpawnMapItemID(), GetMap(), pos, dwMoney, idOwner))
			{
				MapManager()->QueryMapItemSet()->AddObj(pMapItem);
				return true;
			}
			else
				pMapItem->ReleaseByOwner();
		}
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////////////
bool CMonster::DropItem(OBJID idItemType, OBJID idOwner, int nMagic2, int nMagic3, int nUserLuck,bool bIsAllowDropUnident)
{
	if (idItemType == ID_NONE)
		return true;

	POINT	pos;
	pos.x	= GetPosX();
	pos.y	= GetPosY();
	if(GetMap()->FindDropItemCell(MONSTERDROPITEM_RANGE, &pos))
	{
		CMapItem* pMapItem = CMapItem::CreateNew();
		if(pMapItem)
		{
			bool bUnIdent = false,bSetIdentFlag=false;
			//---判断是否进行转换为未鉴定的判断---begin
			if(bIsAllowDropUnident)
			{
				int nSort = CItem::GetItemSort(idItemType);
				int nType = CItem::GetItemType(idItemType);
				if(nSort==IETMSORT_FINERY)
				{
					if(nType==ITEMTYPE_HELMET || nType ==ITEMTYPE_NECKLACE || nType ==ITEMTYPE_ARMOR 
						||nType ==ITEMTYPE_BANGLE || nType == ITEMTYPE_SHOES)
					{
						bSetIdentFlag=true;
					}		
				}
				else if(nSort == ITEMSORT_WEAPON1 )
				{
					bSetIdentFlag=true;
				}

				//转变为未鉴定物品
				if (bSetIdentFlag)
				{
					//根据品质计算转换为鉴定的成功概率
					int  nQuality = CItem::GetQuality(idItemType);
					int  nRate=0;
					
					if(nQuality==QUALITY_ZERO)
						nRate = 5;
					else if(nQuality==QUALITY_ONE)
						nRate = 30;
					else if(nQuality==QUALITY_TWO)
						nRate = 50;
					else if(nQuality==QUALITY_THREE)
						nRate = 70;
					else if(nQuality==QUALITY_FOUR)
						nRate = 80;

					if(::RandGet(100) < nRate)
					{
						bUnIdent = true;
					}				
				}

			}
			//---判断是否进行转换为未鉴定的判断---end
			
//			bool bUnIdent = (nQuality <= NORMAL_QUALITY && ::RandGet(100) < UNIDENT_PERCENT && !CItem::IsMedicine(idItemType) && !CItem::IsArrowSort(idItemType)
//							|| nQuality > NORMAL_QUALITY || nMagic2 || nMagic3);
			if(pMapItem->Create(MapManager()->SpawnMapItemID(), GetMap(), pos, idItemType, idOwner, nMagic2, nMagic3, bUnIdent, nUserLuck))
			{
				MapManager()->QueryMapItemSet()->AddObj(pMapItem);
				return true;
			}
			else
				pMapItem->ReleaseByOwner();
		}
	}

#ifdef _DEBUG
		// temp code
		FILE* fp = fopen("item.ini", "a+");
		if (fp)

⌨️ 快捷键说明

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