#include "StdAfx.h" //const int monsterVectResetInterval = 6000; // 怪物归属重置间隔(6s没有打怪,清除怪物原来归属) CUpdateMask *CMonster::s_monsterBroadcastMask = NULL; void CMonster::InitAi() { unsigned int nID = GetProperty(PROP_ENTITY_ID); PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nID); if(pConfig ==NULL) return; m_pAI = GetGlobalLogicEngine()->GetAiMgr().CreateAi(pConfig->wAiConfigId,(CAnimal*)this); /*if (pConfig->monsterSayList.vecSayTypeInfo[mstHpLow].nRate > 0) m_bHasHPChangeSayConfig = true; else m_bHasHPChangeSayConfig = false;*/ MonsterSayTypeConfig& hpTypeConfig = pConfig->monsterSayList.vecSayTypeInfo[mstHpLow]; if (hpTypeConfig.nCount > 0) m_bHasHPChangeSayConfig = true; else m_bHasHPChangeSayConfig = false; MonsterSayTypeConfig& idleTypeConfig = pConfig->monsterSayList.vecSayTypeInfo[mstIdle]; if (idleTypeConfig.nCount > 0) { PostponeMonsterIdleSay(); } //if (pConfig->monsterSayList.vecSayTypeInfo[mstIdle].nRate > 0) //{ // if (pConfig->monsterSayList.nUpperInterval - pConfig->monsterSayList.nLowerInterval < 10) // 防止策划配置错误导致发言太频繁 // pConfig->monsterSayList.nUpperInterval = pConfig->monsterSayList.nLowerInterval + 10; // PostponeMonsterIdleSay(); //} /* if(pConfig->btMonsterType ==tagMonsterConfig::mtBoss ) //只有boss怪才使用A*寻路 { GetMoveSystem()->SetUseAstar(true); } */ m_nMonsterType = pConfig->btMonsterType; m_nAttackType = pConfig->btAttackType; m_attriFlag = *(pConfig->pflags); SetAttackInterval(pConfig->nAttackInterval); //设置攻击间隔 SetMaxDropHp(pConfig->nMaxDropHp); //每次掉落的HP SetAttackLevel(pConfig->nattackLevel); } void CMonster::PostponeMonsterIdleSay() { unsigned int nID = GetProperty(PROP_ENTITY_ID); PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nID); if(pConfig ==NULL) return; MonsterSayTypeConfig& idleTypeCfg = pConfig->monsterSayList.vecSayTypeInfo[mstIdle]; if (idleTypeCfg.nCount > 0) { MonsterSayInfo& idle_info = idleTypeCfg.pMonsterSayCfg[0]; // Idle只处理第一个 if (idle_info.nRate > 0) { int nRange = pConfig->monsterSayList.nUpperInterval - pConfig->monsterSayList.nLowerInterval+1; int nNextInterval = wrand(nRange) + pConfig->monsterSayList.nLowerInterval; m_nNextIdleSayTime = GetGlobalLogicEngine()->getTickCount() + nNextInterval * 1000; } } //MonsterSayInfo &idle_info = pConfig->monsterSayList.vecSayInfo[mstIdle]; /*if (idle_info.nRate > 0) { int nRange = pConfig->monsterSayList.nUpperInterval - pConfig->monsterSayList.nLowerInterval+1; int nNextInterval = wrand(nRange) + pConfig->monsterSayList.nLowerInterval; m_nNextIdleSayTime = GetGlobalLogicEngine()->getTickCount() + nNextInterval * 1000; }*/ } //怪物暂时只下发少量的数据 VOID CMonster::InitMonsterBroadcastmask() { if (!s_monsterBroadcastMask) { s_monsterBroadcastMask = new CUpdateMask(); } s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_CREATURE_HP); s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_CREATURE_MP); s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_CREATURE_MAXHP); s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_CREATURE_MOVEONESLOTTIME); //移动速度改变了需要广播的 s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_CREATURE_ATTACK_SPEED); s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_CREATURE_COLOR); s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_ENTITY_MODELID); s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_ENTITY_DIR); //朝向 s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_CREATURE_DIZZY_STATUS); s_monsterBroadcastMask->SetUpdateMaskFlag(PROP_MONSTER_BELONG_ID); } bool CMonster::CanSee(CEntity* pEntity) { if(CEntity::CanSee(pEntity)) { return true; } else { if(pEntity->isAnimal()) { if( ((CAnimal*)pEntity)->GetBuffSystem()->Exists(aHide)) { if (GetMonsterHetred(pEntity) > 0 || GetAttackerHandle() == pEntity->GetHandle() ) { return true; } } } } return false; } void CMonster::Destroy() { Inherited::Destroy(); m_ranking = NULL; //m_digActorIdList.clear(); //m_BeAccactedActorList.clear(); m_sVestEntityName[0] = 0; m_hVestEntity = EntityHandle(); m_nVestAttackTime = 0; m_hasDrop = false; } //销毁一个实体 //怪物死亡,HP为0的地方调用了这个函数 void CMonster::OnEntityDeath() { //加到场景的死亡列表中,会定期清理 Inherited::OnEntityDeath(); } //实体销毁 void CMonster::OnEntityDestroy() { MonsterSay(mstDisappear); if (m_pAI) { m_pAI->EntityDestroy(); } } int CMonster::GetKillMonsterAwardAnger(CActor *pActor,PMONSTERCONFIG pMonster) { /* int nActorLevel = pActor->GetProperty(PROP_CREATURE_LEVEL); //玩家等级 //玩家等级达到45级才能获得怒气值 int minLevel = GetLogicServer()->GetDataProvider()->GetCultureConfig().m_GetAngerMinLevel; if(nActorLevel < minLevel) return 0; int nLevel =pMonster->nLevel; //怪物等级 float nDisValue = GetLogicServer()->GetDataProvider()->GetCultureConfig().GetAngerRate(nActorLevel-nLevel); //等级修正 int nAngerRate = GetLogicServer()->GetDataProvider()->GetCultureConfig().m_KillMonsterAngerRate; //调整系数 float nTypeRate = (pMonster->btMonsterType - 1) * GetLogicServer()->GetDataProvider()->GetCultureConfig().m_fAddAngerByMonsterType + 1.0; int nValue = (int)(nDisValue * nAngerRate * nTypeRate); int nResult = 0; if(nValue > 0) nResult = (int)wrand(nValue+1); return nResult; */ //先屏蔽怒气 return 1; } float CMonster::GetKillMonsterExpRate(int nActorLevel,PMONSTERCONFIG pMonster) { if( !pMonster->pflags->DenyDieSubExp) { int nMonsterLevel = pMonster->nLevel; //怪物等级 //unsigned int nActorLevel = pActor->GetProperty(PROP_CREATURE_LEVEL); //玩家等级 int nLevelDis = nMonsterLevel - nActorLevel; //怪物的等级减玩家的等级 return GetLogicServer()->GetDataProvider()->GetKillMonsterExpReduce().GetKillMonsterExp(nLevelDis); //经验的衰减 } else { return 1.0; } } void CMonster::RealDropItemExp(int nID,CActor * pActor,CScene *pScene, int nPosX,int nPosY,CMonster * pMonster, int nGrowLv) { DECLARE_TIME_PROF("CMonster::RealDropItemExp"); CTeam * pTeam = NULL; CActor *member[MAX_TEAM_MEMBER_COUNT]; //附近的队员列表,最大只能是MAX_TEAM_MEMBER_COUNT个 INT_PTR nTeamMemberCount = 0; PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nID); //static int nNeedpickTime = GetLogicServer()->GetDataProvider()->GetDropItemConfig().nDropItemNeedTime*1000; static int nItemTime = GetLogicServer()->GetDataProvider()->GetDropItemConfig().nDropItemExpireTime; //static int nActorpickTime = GetLogicServer()->GetDataProvider()->GetDropItemConfig().nDropItemMasterProtectTime*1000; if(NULL == pConfig ) return; if(!pScene) return; if (pActor != NULL) { pTeam = pActor->GetTeam(); if(pTeam != NULL) { nTeamMemberCount = pTeam->GetNearTeamMember(pActor,member); } //奖励怒气值 pActor->AddAnger(GetKillMonsterAwardAnger(pActor,pConfig)); } const char* pMonsterName = pMonster ? pMonster->GetEntityName() : pConfig->szName; //怪物的名字 unsigned int nExp = pConfig->nExp; //怪物的经验 int nMonsterLevel = pConfig->nLevel; //怪物的等级 int nExpMonsLv = nMonsterLevel; int nMonsterCircleLevel = pMonster ? pMonster->GetProperty(PROP_MONSTER_CIRCLE) : pConfig->nCircle; //怪物的转生等级 if (pConfig->pflags->DenyDieSubExp) { nExpMonsLv = 0; //不进行经验衰减 } EntityFlags* pFlag = pConfig->pflags; if(pActor != NULL && nExp > 0) { //如果不进行经验衰减的话就直接给原来的经验,否则要进行经验的衰减 //没有队伍,或者没人和自己共享经验,直接添加给自己 int nSelfLevel = pActor->GetProperty(PROP_CREATURE_LEVEL);//玩家的等级 if(pTeam ==NULL || nTeamMemberCount <= 0 ) { pActor->AddExp( nExp ,GameLog::Log_KillMonster, (INT_PTR)nExpMonsLv, 0, (INT_PTR)nMonsterCircleLevel); } else { //float times = GetLogicServer()->GetDataProvider()->GetTeamKillMonsterExp().GetTeamKillMonsterExp(nTeamMemberCount); float times = 1/(float)(nTeamMemberCount +1) ; nExp = (unsigned int )(nExp * times); CActor* pCActor = pTeam->GetCaptin(); //获得队长 //队伍经验的计算公式为 //组队打怪获得经验=怪物经验/附近可共享经验的人 //杀怪者自己获得经验 pActor->AddExp( nExp ,GameLog::Log_KillMonster, (INT_PTR)nExpMonsLv, 0, (INT_PTR)nMonsterCircleLevel); //旁边的人加经验 for (INT_PTR i = 0; i< nTeamMemberCount; i++) { if(member[i]) { member[i]->AddExp( nExp,GameLog::Log_TeamKillMonster, (INT_PTR)nExpMonsLv, 0, (INT_PTR)nMonsterCircleLevel); } } } } //给玩家物品 INT_PTR dropid= pConfig->nDropid;//掉落列表 if(dropid <=0 )return; //没有配置掉落 const CStdItemProvider& itemProvider = GetLogicServer()->GetDataProvider()->GetStdItemProvider(); std::vector dropInfos; GetLogicServer()->GetDataProvider()->GetDropCfg().GetGiftDropInfoByDropGroupId(dropid, dropInfos); int count = dropInfos.size(); std::string broadcastmsg = ""; //散财鹿提示 std::string broadcastCoinMsg = ""; //金币tips if(count > 0) { for(int i = 0; i < count; i++) { DROPGOODS& dropGoods = dropInfos[i]; GIFTDROPTABLE* pDropTable = GetLogicServer()->GetDataProvider()->GetDropCfg().GetDropTableConfig(dropGoods.info.nDropId); if(!pDropTable) continue; //道具奖励 if(broadcastmsg != "") broadcastmsg += ","; if(dropGoods.info.nType == qatEquipment) { const CStdItem* pStdItem = GetLogicServer()->GetDataProvider()->GetStdItemProvider().GetStdItem(dropGoods.info.nId); if(!pStdItem) continue; char cBestAttr[200]; //极品属性 memset(&cBestAttr, 0, sizeof(cBestAttr)); int num = dropGoods.v_bestAttr.size(); for(int j = 0; j < num; j++) { char buf[10]; if(j != 0) strcat(cBestAttr, "|"); DropAttribute data = dropGoods.v_bestAttr[j]; sprintf(buf, "%d,%d", data.nType, data.nValue); strcat(cBestAttr, buf); } cBestAttr[sizeof(cBestAttr)-1]= '\0'; INT_PTR nCount= dropGoods.info.nCount; pMonster->setHasDrop(true); int nNowtime = GetGlobalLogicEngine()->getMiniDateTime(); if(pActor) //掉落无归属 ((CActor*)pActor)->GetAchieveSystem().ActorAchievementComplete(nAchieveDropItem, dropGoods.info.nCount, pStdItem->m_nIndex); //如果掉出多个,要一个一个掉出 --一律掉在地上 for(int j = 0; j < nCount; j++) { CUserItem *pUserItem = GetGlobalLogicEngine()->AllocUserItem(true); //申请一个道具 if(pUserItem ==NULL) continue; pUserItem->wItemId =pStdItem->m_nIndex ; pUserItem->wCount = 1; pUserItem->btQuality = pStdItem->b_showQuality; pUserItem->wPackageType = pStdItem->m_nPackageType; memcpy(&pUserItem->cBestAttr, cBestAttr, sizeof(pUserItem->cBestAttr)); //----- // memcpy(&pUserItem->cSourceName, pMonsterName, sizeof(pUserItem->cSourceName)); if(pActor) pUserItem->setSource(CStdItem::iqKillMonster,nNowtime, pScene->GetSceneId(), nID, pActor->GetEntityName()); else pUserItem->setSource(CStdItem::iqKillMonster,nNowtime, pScene->GetSceneId(), nID); CStdItem::AssignInstance(pUserItem,pStdItem); CDropItemEntity *pDropItem= CDropItemEntity::CreateDropItem(pScene,nPosX,nPosY,GameLog::clKillMonsterItem,pMonsterName, nItemTime); // if(pDropItem) { pDropItem->SetItem(pUserItem); pDropItem->DealDropItemTimeInfo(pActor, pDropTable->nLootType); //统计日志 if(pConfig && pConfig->nMonLog && pActor) { GetGlobalLogicEngine()->AddKillDropToLog((int)(pActor->GetId()), pActor->GetAccount(), pActor->GetEntityName(), pMonsterName,pScene->GetSceneName(),pStdItem->m_sName,pUserItem->wCount,nPosX,nPosY,pActor->getOldSrvId()); } if (pActor && nID != 161 && pStdItem->m_nDropBroadcast != 0 && (pStdItem->m_nDropBroadcast == -1 || pStdItem->m_nDropBroadcast >= GetLogicServer()->GetDaysSinceOpenServer())) { LPTSTR desc = CUserEquipment::getItemColorDesc(pStdItem); if(desc) { char descname[100] = {0}; sprintf_s(descname, sizeof(descname), desc,pStdItem->m_sName); char s2[1024] = {0}; LPCTSTR sFormat2 = GetLogicServer()->GetDataProvider()->GetTipmsgConfig().GetTipmsg(tmDropMonsterBroadItem); if(sFormat2) { char id2str[1024] = {0}; sprintf(id2str,"%lld",pUserItem->series.llId); //actotID,guid sprintf_s(s2, sizeof(s2), sFormat2, dropGoods.info.nId,id2str,(char*)(descname+1)); } char s1[1024] = {0}; LPCTSTR sFormat1 = GetLogicServer()->GetDataProvider()->GetTipmsgConfig().GetTipmsg(tmDropMonsterBroad); if(sFormat1) { sprintf_s(s1, sizeof(s1), sFormat1, pActor->GetEntityName(),pScene->GetSceneName(), pMonsterName, s2); } GetGlobalLogicEngine()->GetEntityMgr()->BroadNotice(s1,tstChatSystem,0); GetGlobalLogicEngine()->GetChatMgr().addShowItem(pUserItem); GetGlobalLogicEngine()->GetEntityMgr()->BroadTipmsgWithParams(tmDropMonsterBroad, tstKillDrop, pActor->GetEntityName(), pScene->GetSceneName(), pMonsterName, descname); } } } else { GetGlobalLogicEngine()->DestroyUserItem(pUserItem); } } broadcastmsg += pStdItem->m_sName; } else if( (dropGoods.info.nType == qatMoney) || (dropGoods.info.nType == qatBindMoney) ) { INT_PTR nMoneyType = mtCoin; int nMonsterDropMaxMoney = 0; if (dropGoods.info.nType == qatMoney) { nMoneyType = mtCoin; nMonsterDropMaxMoney = GetLogicServer()->GetDataProvider()->GetDropItemConfig().nMonsterMaxCoinOneDrop;//GetLogicServer()->GetDataProvider()->GetGlobalConfig().nMonsterMaxCoinOneDrop; } else if (dropGoods.info.nType == qatBindMoney) { nMoneyType = mtBindCoin; nMonsterDropMaxMoney = GetLogicServer()->GetDataProvider()->GetDropItemConfig().nMonsterMaxBindCoinOneDrop; } if (nMonsterDropMaxMoney == 0) // 防止除数为0 continue; int nTotalCount = dropGoods.info.nCount; INT_PTR nDumpCount = nTotalCount/nMonsterDropMaxMoney; //有多少堆最大的 INT_PTR nLeftCount = nTotalCount - nMonsterDropMaxMoney * nDumpCount; //剩下的 CDropItemEntity *pDropItem; INT_PTR nDropCount = 0; pMonster->setHasDrop(true); for(INT_PTR i=0; i<= nDumpCount; i++) { if(i == nDumpCount ) { nDropCount = nLeftCount; } else { nDropCount = nMonsterDropMaxMoney; } if(nDropCount ==0) continue; //没有掉落 pDropItem= CDropItemEntity::CreateDropItem(pScene,nPosX,nPosY,GameLog::clKillMonsterItem,pMonsterName); // if(pDropItem) { pDropItem->SetMoneyCount((int)nDropCount, (int)nMoneyType); pDropItem->DealDropItemTimeInfo(pActor, pDropTable->nLootType); } } LPCTSTR sFormat = GetLogicServer()->GetDataProvider()->GetTipmsgConfig().GetTipmsg(tmMoreCoin); if(sFormat) broadcastCoinMsg = sFormat; } else { if (pActor == NULL) continue; pActor->GiveAward(dropGoods.info.nType, dropGoods.info.nId, dropGoods.info.nCount, 0,0,0,0,GameLog::Log_KillMonster); } } //处理散财鹿tips if(broadcastmsg != "" && broadcastCoinMsg != "") broadcastmsg += ", " + broadcastCoinMsg; if(broadcastmsg != "" && nID == 161 && pActor && pScene) { GetGlobalLogicEngine()->GetEntityMgr()->BroadTipmsgWithParams(tmDropMonsterBroad, tstChatSystem, pActor->GetEntityName(), pScene->GetSceneName(), pMonsterName, broadcastmsg.c_str()); GetGlobalLogicEngine()->GetEntityMgr()->BroadTipmsgWithParams(tmDropMonsterBroad, tstKillDrop, pActor->GetEntityName(), pScene->GetSceneName(), pMonsterName, broadcastmsg.c_str()); } } } bool CMonster::RealDropItemByDropGroupId(CScene *pScene, int nPosX,int nPosY,int dropGroupId,int pick_time, int nDropTips) { DECLARE_TIME_PROF("CMonster::RealDropItemByDropGroupId"); //static int nNeedpickTime = GetLogicServer()->GetDataProvider()->GetDropItemConfig().nDropItemNeedTime*1000; static int nItemTime = GetLogicServer()->GetDataProvider()->GetDropItemConfig().nDropItemExpireTime; //static int nActorpickTime = GetLogicServer()->GetDataProvider()->GetDropItemConfig().nDropItemMasterProtectTime*1000; const char* pLogName = "Activity" ; //给玩家物品 INT_PTR dropid= dropGroupId ;//掉落列表 if(dropid <=0 )return false ; //没有配置掉落 if(!pScene) return false; const CStdItemProvider& itemProvider = GetLogicServer()->GetDataProvider()->GetStdItemProvider(); std::vector dropInfos; GetLogicServer()->GetDataProvider()->GetDropCfg().GetGiftDropInfoByDropGroupId(dropid, dropInfos); int count = dropInfos.size(); if(count > 0) { for(int i = 0; i < count; i++) { DROPGOODS& dropGoods = dropInfos[i]; GIFTDROPTABLE* pDropTable = GetLogicServer()->GetDataProvider()->GetDropCfg().GetDropTableConfig(dropGoods.info.nDropId); if(!pDropTable) continue; //道具奖励 if(dropGoods.info.nType == qatEquipment) { const CStdItem* pStdItem = GetLogicServer()->GetDataProvider()->GetStdItemProvider().GetStdItem(dropGoods.info.nId); if(!pStdItem) continue; char cBestAttr[200]; //极品属性 memset(&cBestAttr, 0, sizeof(cBestAttr)); int num = dropGoods.v_bestAttr.size(); for(int j = 0; j < num; j++) { char buf[10]; if(j != 0) strcat(cBestAttr, "|"); DropAttribute data = dropGoods.v_bestAttr[j]; sprintf(buf, "%d,%d", data.nType, data.nValue); strcat(cBestAttr, buf); } cBestAttr[sizeof(cBestAttr)-1]= '\0'; INT_PTR nCount= dropGoods.info.nCount; //如果掉出多个,要一个一个掉出 --一律掉在地上 int nNowtime = GetGlobalLogicEngine()->getMiniDateTime(); for(int j = 0; j < nCount; j++) { CUserItem *pUserItem = GetGlobalLogicEngine()->AllocUserItem(true); //申请一个道具 if(pUserItem ==NULL) continue; pUserItem->wItemId =pStdItem->m_nIndex ; pUserItem->wCount = 1; pUserItem->btQuality = pStdItem->b_showQuality; pUserItem->wPackageType = pStdItem->m_nPackageType; memcpy(&pUserItem->cBestAttr, cBestAttr, sizeof(pUserItem->cBestAttr)); //----- pUserItem->setSource(CStdItem::iqNPCAward, nNowtime, pScene->GetSceneId()); CStdItem::AssignInstance(pUserItem,pStdItem); CDropItemEntity *pDropItem= CDropItemEntity::CreateDropItem(pScene,nPosX,nPosY,GameLog::cNpcBigTreasure,pLogName, nItemTime,1); //创建item,设置多久以后消失 if(pDropItem) { pDropItem->SetItem(pUserItem); pDropItem->DealDropItemTimeInfo(NULL, 666,pick_time);//设置任何人都可以捡取,时间120秒后可以捡取 if (nDropTips && pStdItem->m_nDropBroadcast != 0 && (pStdItem->m_nDropBroadcast == -1 || pStdItem->m_nDropBroadcast >= GetLogicServer()->GetDaysSinceOpenServer())) { LPTSTR desc = CUserEquipment::getItemColorDesc(pStdItem); if(desc) { char descname[100] = {0}; sprintf_s(descname, sizeof(descname), desc,pStdItem->m_sName); char s2[1024] = {0}; LPCTSTR sFormat2 = GetLogicServer()->GetDataProvider()->GetTipmsgConfig().GetTipmsg(tmDropMonsterBroadItem); if(sFormat2) { char id2str[1024] = {0}; sprintf(id2str,"%lld",pUserItem->series.llId); //actotID,guid sprintf_s(s2, sizeof(s2), sFormat2, dropGoods.info.nId,id2str,(char*)(descname+1)); } char s1[1024] = {0}; LPCTSTR sFormat1 = GetLogicServer()->GetDataProvider()->GetTipmsgConfig().GetTipmsg(nDropTips); if(sFormat1) { sprintf_s(s1, sizeof(s1), sFormat1, s2); } GetGlobalLogicEngine()->GetEntityMgr()->BroadNotice(s1,tstChatSystem,0); GetGlobalLogicEngine()->GetChatMgr().addShowItem(pUserItem); GetGlobalLogicEngine()->GetEntityMgr()->BroadTipmsgWithParams(nDropTips, tstKillDrop,descname); } } } else { GetGlobalLogicEngine()->DestroyUserItem(pUserItem); } } } } }else return false ; return true ; } //怪物掉落一个包裹给玩家,如果是宠物杀死的,就掉落给宠物的主人 void CMonster::DropItemExp(CActor * pActor, int nGrowLv) { DECLARE_TIME_PROF("CMonster::DropItemExp"); unsigned int nID = GetProperty(PROP_ENTITY_ID); int nPosX,nPosY; //位置 GetPosition(nPosX,nPosY); //获取坐标 unsigned int lv = GetProperty(PROP_CREATURE_LEVEL); if (CScene* pScene = GetScene()) RealDropItemExp(nID,pActor,pScene,nPosX,nPosY,this, nGrowLv); } bool CMonster::AddDropTaskItemToVester(CActor *pActor, CUserItemContainer::ItemOPParam *pItem) { DECLARE_TIME_PROF("CMonster::AddDropTaskItemToVester"); CQuestSystem *pQuestSystem = pActor->GetQuestSystem(); // if (pQuestSystem->IsCurrQuestItem(pItem->wItemId)) // { // INT_PTR added_count = pActor->GetBagSystem().AddItem(*pItem, GetEntityName(), GameLog::clKillMonsterItem); // if (added_count != pItem->wCount) // return false; // } return true; } /*杀怪通知周围玩家,触发周围玩家的任务事件 注意, 1、此方法是高频方法,要注意性能; 2、这里会导致如果死亡见证玩家也是队友,会再计算一次,不过为了性能考虑,且新开服表现不明显,暂时不管 */ void CMonster::QuestMonsterToPlayerNearby(CActor* pDoActor) { DECLARE_TIME_PROF("CMonster::QuestMonsterToPlayerNearby"); INT_PTR nCount = m_BeAccactedActorList.count(); if(NULL == pDoActor || nCount <= 0) { return; } unsigned int nMyId = pDoActor->GetId(); unsigned int nMonId = GetId(); GLOBALCONFIG & gloCfg = GetLogicServer()->GetDataProvider()->GetGlobalConfig(); for (INT_PTR i = 0; i < nCount; i++) { unsigned int nPlyId = m_BeAccactedActorList[i]; if(nPlyId == nMyId) { continue; } CActor * pActor = GetGlobalLogicEngine()->GetEntityMgr()->GetEntityPtrByActorID(nPlyId); //以怪物为中心点,判断角色距离此怪物的距离(的平方),过远也不算 int nDistSqare = (int)GetEntityDistanceSquare(pActor); // if (pActor != NULL && nDistSqare <= gloCfg.nSeeKilledDistance) // { // // pActor->GetQuestSystem()->OnQuestEvent(CQuestData::qtMonster, nMonId, 1); // // pActor->GetQuestSystem()->OnQuestEvent(CQuestData::qtSceneKillAnyMon, nMonId, 1); // } } //m_BeAccactedActorList.clear(); } //被杀死的时候调用的 void CMonster::OnKilledByEntity(CEntity * pKillerEntity) { DECLARE_TIME_PROF("CMonster::OnKilledByEntity"); if(!m_hasDeathCall) { CAnimalAI * pAi = GetAI(); if(pAi) { pAi->KillBy(); //被杀死了 } else { OutputMsg(rmError,"OnKilledByEntity pAi=NULL"); } m_hasDeathCall = true; } if(pKillerEntity == NULL) return; INT_PTR nType = pKillerEntity->GetType(); if( nType==enPet) { CPet * pPet = ((CPet*)pKillerEntity); CActor * pOwner = pPet->GetMaster(); if(pOwner && pOwner->IsInited()) { OnKilledByEntity(pOwner); // 递归 } pPet->AddExp(1); //每次杀死一个怪物,给自己加一点经验 return; } else if(nType == enHero) //被英雄杀死的 { CHero * pHero = ((CHero*)pKillerEntity); CActor * pOwner = pHero->GetMaster(); if(pOwner && pOwner->IsInited()) { OnKilledByEntity(pOwner); // 递归 } return; } else if(nType == enMonster) { EntityHandle handle = ((CMonster*)pKillerEntity)->GetOwner(); CEntity *pOwner = GetEntityFromHandle(handle); if(pOwner && pOwner->IsInited()) { OnKilledByEntity(pOwner); // 递归 return; } /* else { INT_PTR nFubenId = pKillerEntity->GetFuBen()->GetFbId(); CScene *pScene = pKillerEntity->GetScene(); if (nFubenId > 0 && pScene) //如果在副本中,则寻找副本其中某位玩家为击杀者 { CEntityList& list = pScene->GetPlayList(); CEntityManager* pEntityMgr = GetGlobalLogicEngine()->GetEntityMgr(); CLinkedNode *pNode; CLinkedListIterator it(list); for (pNode = it.first(); pNode; pNode = it.next()) { CEntity* pEntity = pEntityMgr->GetEntity(pNode->m_Data); if (pEntity && pEntity->GetType() == enActor) { OnKilledByEntity(pEntity); return; } } } } */ } Inherited::OnKilledByEntity(pKillerEntity); MonsterSay(mstDead); //处理boss死亡 int nBossReferId = GetBossReferId(); GetGlobalLogicEngine()->GetBossMgr().BossDeath(nBossReferId); if(m_isInited ==false) return; //调用怪物死亡触发脚本 int nMonId = GetId(); PMONSTERCONFIG pMonConf = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nMonId); if(pMonConf == NULL) return; // 这里计算归属者实体 CEntity *pVester = NULL; if( m_nForceVesterId > 0 ) //存在强制归属玩家 { pVester = GetGlobalLogicEngine()->GetEntityMgr()->GetEntityPtrByActorID(m_nForceVesterId); if( !pVester ) //强制归属玩家不在线 { //无归属,即便一刀不砍的玩家也能拿掉落物品 ChangeShowName(12, pMonConf->szName); //恢复怪物本名 } } else { pVester = GetEntityFromHandle(m_hVestEntity); } if ( m_nForceVesterId == 0 &&( !pVester || pVester->GetType() != enActor )) //前提是没有指定强制归属玩家 { pVester = pKillerEntity; } //计算boss成长 ---不需要了 int nGrowLv = 0; // if (pMonConf->pflags->CanGrowUp && pMonConf->btMonsterType ==tagMonsterConfig::mtBoss) // { // nGrowLv = CBossSystem::OnKillGrowBoss(nMonId, pVester->GetEntityName(), pMonConf); // } // 应策划修改,直接最后一刀杀死怪物,就算作谁杀死怪 //CEntity *pVester = pKillerEntity; if (pVester && pVester->GetType() == enActor) // 要给玩家经验(先通知队友,再通知周围玩家) { CActor * pActor =(CActor *)pVester; DropItemExp(pActor, nGrowLv); pActor->GetQuestSystem()->OnQuestEvent(CQuestData::qtMonster, 1, GetProperty (PROP_ENTITY_ID)); // pActor->GetQuestSystem()->OnQuestEvent(CQuestData::qtKillLevelMonster, pMonConf->nLevel, 1, TRUE, ((CActor *)pActor)); // pActor->GetQuestSystem()->OnQuestEvent(CQuestData::qtSceneKillAnyMon, pActor->GetSceneID(), 1, TRUE, ((CActor *)pActor)); if( GetAttriFlag().AttackSeeKill ) //怪物已配置死亡见证 { QuestMonsterToPlayerNearby(pActor); } pActor->GetAchieveSystem().ActorAchievementComplete(nAchieveKillMonster,1, pMonConf->btMonsterType); //杀怪成就 pActor->GetAchieveSystem().ActorAchievementComplete(nAchievekillOneMonster,1, pMonConf->nEntityId); //击杀某种怪物 // 更新宝物命盘XP值 //((CActor *)pKillerEntity)->GetGemSystem().OnKillEntity(enMonster, (tagMonsterConfig::tagMonsterType)pMonConf->btMonsterType); } else { DropItemExp(NULL, nGrowLv); //掉落无归属 } if (nType == enActor) { CActor* pActor = (CActor*)pKillerEntity; //计算副本中击杀的怪物数量 CFuBen* pfb = pActor->GetFuBen(); if (pfb && pfb->IsFb()) { //如果是boss,记录玩家的名字 if (pMonConf->btMonsterType == MONSTERCONFIG::mtBoss || pMonConf->btMonsterType == MONSTERCONFIG::mtToumu || pMonConf->btMonsterType == MONSTERCONFIG::mtWorldBoss) { pfb->AddKillBossName(pActor->GetEntityName()); } pfb->AddKillMonsterCount(); } pActor->ChangeRecordData(rRecordKillMonster); pActor->GetGuildSystem()->OnGuildTask(gttKillMonster, nMonId, 1); //怪可能是被其他的怪打死的,此次必須判定是玩家 if (pVester && pVester->GetType() == enActor) { CActor * pvActor =(CActor *)pVester; if(pActor != pvActor) { pActor->GetAchieveSystem().ActorAchievementComplete(nAchieveKillMonster,1, pMonConf->btMonsterType); //杀怪成就 pActor->GetAchieveSystem().ActorAchievementComplete(nAchievekillOneMonster,1, pMonConf->nEntityId); //击杀某种怪物 } } } //这段代码放在OnMonsterKilled之前 if( pMonConf->bRecordKillTime) { unsigned int nNow = GetGlobalLogicEngine()->getMiniDateTime(); GetLogicServer()->GetDataProvider()->GetMonsterConfig().SetBossLastKillTime(nMonId, nNow); //设置BOSS被击杀时间 } //怪物死亡,需要触发LUA脚本 if (pMonConf && pMonConf->pflags->bDeathTriggerScript) { CScriptValueList arg; arg << this; arg << pVester; //怪物归属者 arg << nMonId; arg <GetMonFuncNpc()->GetScript().Call("OnMonsterKilled", arg, arg, 0); } if( pMonConf->btMonsterType == tagMonsterConfig::mtBoss || pMonConf->btMonsterType == MONSTERCONFIG::mtToumu || pMonConf->btMonsterType == MONSTERCONFIG::mtWorldBoss ) //BOSS被击杀,记录日志 { //记录日志 if(GetLogicServer()->GetLocalClient()) { } } m_bHasLiveTimeOut = true; //怪物被击杀,就不再执行生命周期到的逻辑 } /* 设置怪物的生命周期, 注意,服务器启动时,GetGlobalLogicEngine()->getMiniDateTime()尚未赋值,可能返回0 所以需要判断一下, 服务器启动后,GetGlobalLogicEngine()->getMiniDateTime()就>0了 VOID CLogicEngine::OnRountine() 方法是先启动运行其他的,然后才设置系统时间 */ void CMonster::SetLiveTime( UINT nTime ) { if (nTime > 0) { unsigned int nNow = GetGlobalLogicEngine()->getMiniDateTime(); if( nNow > 0 ) { m_liveTime = nNow + nTime; } else { SYSTEMTIME mCurSysTime; GetLocalTime(&mCurSysTime); CMiniDateTime mCurMiniDateTime; mCurMiniDateTime = mCurMiniDateTime.encode(mCurSysTime); m_liveTime = mCurMiniDateTime + nTime; } m_BossLiveTime = nTime; } else { m_liveTime =0; m_BossLiveTime = 0; } } VOID CMonster::LogicRun( TICKCOUNT nCurrentTime ) { DECLARE_TIME_PROF("CMonster::LogicRun"); Inherited::LogicRun(nCurrentTime); INT_PTR nType = GetType(); //精英怪和boss定时定量回血 if (nType == enMonster && (m_nMonsterType == tagMonsterConfig::mtBoss || m_nMonsterType == tagMonsterConfig::mtElite)) { if( m_t5s.CheckAndSet(nCurrentTime, true)) { if (!IsDeath()) { if(!GetAttriFlag().DenyAutoAddHp) { int nAddValue = 1;//GetProperty( PROP_MONSTER_HP_RENEW_VALUE); ChangeHP(nAddValue); } } } } // 显示怪物归属名字 if (nType == enMonster || nType == enGatherMonster) { static const int s_monsterVectResetInterval = GetLogicServer()->GetDataProvider()->GetGlobalConfig().nMonsterVectResetInterval; if (m_nVestAttackTime > 0 && GetGlobalLogicEngine()->getTickCount() - m_nVestAttackTime >= s_monsterVectResetInterval) { m_nVestAttackTime = 0; SetVestEntity(EntityHandle()); if (GetAttriFlag().boShowVestEntityName) { SetVestEntityName(""); } } } // 500ms精度刷新 if (m_500Timer.CheckAndSet(nCurrentTime, true)) { if(nType == enMonster || nType == enGatherMonster ) { if (m_updateFBMonsterProp.CheckAndSet(nCurrentTime, true)) { // 添加到死亡列表 if (m_liveTime != 0 && m_liveTime < GetGlobalLogicEngine()->getMiniDateTime()) { CScene* pSc = GetScene(); if (pSc) { pSc->AddDeathEntity(this); //怪物生命期到,需要触发LUA脚本 if( !m_bHasLiveTimeOut ) { m_bHasLiveTimeOut = true; int nMonId = GetId(); PMONSTERCONFIG pMonConf = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nMonId); if (pMonConf && pMonConf->pflags->bLiveTimeOutTriggerScript) { CScriptValueList arg; arg << this; arg << nMonId; arg << GetSceneID(); GetGlobalLogicEngine()->GetMonFuncNpc()->GetScript().Call("OnMonsterLiveTimeOut", arg, arg, 0); } if( pMonConf->btMonsterType == tagMonsterConfig::mtBoss || pMonConf->btMonsterType == tagMonsterConfig::mtToumu || pMonConf->btMonsterType == tagMonsterConfig::mtWorldBoss) //BOSS生命周期到,记录日志 { //记录日志 if(GetLogicServer()->GetLocalClient()) { } } } } //m_BossLiveTime = 0; return; } //死亡10秒以后,如果还没有加到死亡列表里去的话 if(IsDeath() && !GetAttriFlag().CanReuse ) { if( !IsInDeathList() ) { CScene* pSc = GetScene(); if (pSc ) { pSc->AddDeathEntity(this); } } else { if(GetDeathTime() +10 < GetGlobalLogicEngine()->getMiniDateTime()) { CScene* pSc = GetScene(); if (pSc) { pSc->ClearDeathEntity(GetHandle()); } GetGlobalLogicEngine()->GetEntityMgr()->DestroyEntity(GetHandle()); return; } } return; } CScene *pScene = GetScene(); if (!pScene) return; CFuBen *pFB = pScene->GetFuBen(); if (!pFB || !pFB->IsFb()) return; COMMONFUBENCONFIG *pfc = pFB->GetConfig(); // 动态调整怪物属性 if (!pfc->bDisableMonsterPropAdjust) { int fubenRecommendLvl = pfc->nRecommandLevel; int fubenPlayerAverageLvl = pFB->getPlayerAverageLvl(); int fubenPlayerCount = pFB->getPlayerCount(); bool bNeedUpdateProp = false; // 检测副本玩家平均等级,如果大于 if (fubenPlayerAverageLvl > fubenRecommendLvl) // 避免等级不够推荐等级条件时的队伍平均等级变化导致的刷新 { int levelDiff = fubenPlayerAverageLvl - GetProperty(PROP_CREATURE_LEVEL); // 可能为负数 int oldLevelDiff = GetProperty(PROP_MONSTER_LEVEL_DIFF); if (levelDiff != oldLevelDiff) { SetProperty(PROP_MONSTER_LEVEL_DIFF, levelDiff); // 更新怪物所在副本的玩家平均等级 bNeedUpdateProp = true; } } if (fubenPlayerCount != m_nTeamPlayerCnt) { m_nTeamPlayerCnt = fubenPlayerCount; // 更新怪物所在副本的玩家数量 bNeedUpdateProp = true; } if (bNeedUpdateProp) { CollectOperate(CEntityOPCollector::coRefMonsterDynProp); } } } } } } void CMonster::Reuse() { DECLARE_TIME_PROF("CMonster::Reuse"); CScene *pScene = GetScene(); if (!pScene) { OutputMsg(rmError, _T("Monster reuse error, get scene is null")); return; } if (enNpc == GetType()) { OutputMsg(rmError, _T("%s:重用出错,不应该为NPC[%s]"), __FUNCTION__, GetEntityName()); return; } pScene->ExitScene(this); // 复用怪物清除怪物的观察者列表 GetObserverSystem()->Clear(); Inherited::Reuse(); m_liveTime = 0; int nMonsterId = GetProperty(PROP_ENTITY_ID); PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nMonsterId); if (pConfig) { //((CAnimal*)this)->AddState(esStateDeath); // do a trick for following property change SetProperty(PROP_CREATURE_HP,pConfig->cal.m_AttrValues[aMaxHpAdd].uValue); SetProperty(PROP_CREATURE_MP,pConfig->cal.m_AttrValues[aMaxMpAdd].uValue); SetProperty(PROP_CREATURE_STATE,0); m_attriFlag = *(pConfig->pflags);//属性标志位 if (m_attriFlag.DenyAttackedByActor) { AddState(esStateDenyAttackedByActor); } RefreshStateMask(); } SetVestEntity(EntityHandle()); if (GetAttriFlag().boShowVestEntityName) { SetVestEntityName(""); } SetVestAttackTime(0); CEntityManager *em = GetGlobalLogicEngine()->GetEntityMgr(); if (em) em->updateMonsterHandle(this); // 检测此怪物所在场景中的刷新时间为0 SCENECONFIG *pSceneData = pScene->GetSceneData(); unsigned int nBornPointID = GetProperty(PROP_MONSTER_BORNPOINT); if (pSceneData && nBornPointID >=0 && nBornPointID < (unsigned int)pSceneData->vRefreshList.nCount) { REFRESHCONFIG* pSceneRefreshConfig = pSceneData->vRefreshList.pList + nBornPointID; Assert(pSceneRefreshConfig->nNextRefreshTime == 0); //INT_PTR seed = pSceneRefreshConfig->nPointsCount; //if(seed >0) seed =wrand((unsigned long)seed); //随机点 //INT_PTR nMonsterPosX = pSceneRefreshConfig->Points[seed].x; //INT_PTR nMonsterPosY = pSceneRefreshConfig->Points[seed].y; INT_PTR nMonsterPosX = 0; INT_PTR nMonsterPosY = 0; if ( pScene->GetMobMonsterXY(pSceneRefreshConfig,nMonsterPosX,nMonsterPosY) ) { pScene->EnterScene(this, nMonsterPosX, nMonsterPosY); } } if (m_pAI) m_pAI->EnterInitAI(); m_hasDeathCall =false; GetAttriFlag().CanReuse = true; } void CMonster::SetVestEntity(const EntityHandle& handler) { m_hVestEntity = handler; // 设置怪物的归属属性 const PMONSTERCONFIG pMonsterConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(GetProperty(PROP_ENTITY_ID)); if ( pMonsterConfig ) { if ( pMonsterConfig->nAscriptionOpen ) { CEntity *pVestEntity = GetGlobalLogicEngine()->GetEntityMgr()->GetEntity(m_hVestEntity); if ( pVestEntity ) { if ( enActor == pVestEntity->GetType() ) { SetProperty(PROP_MONSTER_BELONG_ID, pVestEntity->GetProperty(PROP_ENTITY_ID)); return; } } } } SetProperty(PROP_MONSTER_BELONG_ID, 0); } const EntityHandle& CMonster::GetVestEntity()const { return m_hVestEntity; } bool CMonster::InBeAttackActorList(unsigned int nActorId) { for(int i=0; iGetType() == enPet) { CPet * pPet = ((CPet*)pEntity); CActor * pOwner = pPet->GetMaster(); if(pOwner && pOwner->IsInited()) { OnAttacked(pOwner); } return; } if (pEntity->GetType() == enHero) { CHero* pHero = ((CHero*)pEntity); CActor * pOwner = pHero->GetMaster(); if(pOwner && pOwner->IsInited()) { OnAttacked(pOwner); } return; } if (pEntity->GetType() == enActor && bSetVest) //被玩家攻击 { if (GetVestEntity().IsNull()) // 第一次被攻击时设置怪物归属 { SetVestEntity(pEntity->GetHandle()); if (GetAttriFlag().boShowVestEntityName) { SetVestEntityName(pEntity->GetEntityName()); } m_nVestAttackTime = GetGlobalLogicEngine()->getTickCount(); } else { EntityHandle hEntity = pEntity->GetHandle(); if (hEntity != m_hVestEntity) { CEntity *pVester = GetEntityFromHandle(m_hVestEntity); if (!pVester || pVester->GetScene() != GetScene()) { SetVestEntity(hEntity); if (GetAttriFlag().boShowVestEntityName) { SetVestEntityName(pEntity->GetEntityName()); } } } else { m_nVestAttackTime = GetGlobalLogicEngine()->getTickCount(); } } m_nAttackedTime = GetGlobalLogicEngine()->getMiniDateTime(); CEntity *pMaster = GetEntityFromHandle(GetOwner()); if (pMaster && pMaster->GetType() == enActor) { ((CActor*)pMaster)->GetPkSystem().SendPkToClient(); } SetBeAttackActorList(pEntity->GetId()); } } void CMonster::MonsterSay(MonsterSayType sayType, INT_PTR nSayIdx) { /*DECLARE_FUN_TIME_PROF()*/ if (sayType == mstInvalid || sayType == mstMax) return; unsigned int nMonsterId = GetProperty(PROP_ENTITY_ID); PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nMonsterId); if (!pConfig) return; MonsterSayList &sayList = pConfig->monsterSayList; MonsterSayTypeConfig &sayTypeInfo = sayList.vecSayTypeInfo[sayType]; if (sayTypeInfo.nCount <= 0 || nSayIdx >= sayTypeInfo.nCount) return; MonsterSayInfo *pSayInfo = NULL; if (sayType != mstHpLow) pSayInfo = &sayTypeInfo.pMonsterSayCfg[0]; else pSayInfo = &sayTypeInfo.pMonsterSayCfg[nSayIdx]; if (pSayInfo->nRate <= 0) return; // Idle time limit if (mstIdle == sayType && GetGlobalLogicEngine()->getTickCount() < m_nNextIdleSayTime) return; if (sayType == mstIdle) PostponeMonsterIdleSay(); // random rate limit if (wrand(101) > (unsigned int)pSayInfo->nRate) return; unsigned int nContentCnt = pSayInfo->nCount; if (nContentCnt <= 0) return; int nIdx = 0; if (nContentCnt <= 1) nIdx = 0; else { nIdx = wrand(nContentCnt); if (sayType == m_nPreSayType) { if (nIdx == m_nPreSayContentIdx) { nIdx++; if (nIdx >= (int)nContentCnt) nIdx = 0; } } else { m_nPreSayType = sayType; } } m_nPreSayContentIdx = nIdx; // 发言内容 const char *pMsg = pSayInfo->pMsgList[nIdx]; char szTransmit[80] = {0}; if (pSayInfo->bTransmit) { int nLimitTime = pSayInfo->nLimitTime; if (0 != nLimitTime) nLimitTime = nLimitTime + GetGlobalLogicEngine()->getMiniDateTime(); int x = pSayInfo->nPosX; int y = pSayInfo->nPosY; if (0 == x || 0 == y) GetPosition(x, y); CScene *pScene = GetScene(); if (pScene) { LPCTSTR sFormat = GetLogicServer()->GetDataProvider()->GetOldTipmsgConfig().GetTipmsg(tpTransmitPattern); sprintf(szTransmit, sFormat, pScene->GetSceneName(), x, y, GetEntityName(), nLimitTime); } } char szMsg[1024] = {0}; sprintf(szMsg, "%s%s", pMsg, szTransmit); Say(pSayInfo->nBCType, szMsg, (tagTipmsgType)(pSayInfo->nTipType), (unsigned int)pSayInfo->nLimitLev); } bool CMonster::SetOwnerName( LPCTSTR sName) { if (sName == NULL) return false; CActor * pActor = GetGlobalLogicEngine()->GetEntityMgr()->GetActorPtrByName(sName); if(pActor ==NULL) return false; m_nOwnerActorId = pActor->GetId(); m_hOwner = pActor->GetHandle(); LPCTSTR sShowName = GetShowName(); char name[128]; strcpy(name,sName); strcat(name,"-"); strcat(name,sShowName); SetShowName(name); //设置名字 if(IsInited()) { //ChangeName(GetEntityName()); ChangeName(GetShowName()); return true; } else { return false; } } void CMonster::ResetShowName(LPCTSTR sName) { if (sName == NULL) return; char *pShowName = (char*)GetShowName(); const char *sPtr = strchr(pShowName, '-'); if (sPtr != NULL) { char name[128]; INT_PTR nLen = sPtr - pShowName + 1; strncpy(name, pShowName, nLen); name[nLen] = _T('\0'); strcat(name, sName); SetShowName(name); //设置名字 } else { SetShowName(sName); //设置名字 } //如果已经进入游戏了,需要广播一下 if(IsInited()) { ChangeName(GetShowName()); } } /* * Comments: 改变HP * Param int nValue: <0 减HP,>0 加HP * Param CEntity * pKiller: * Param bool bIgnoreDamageRedure: * Param bool bIgnoreMaxDropHp: * @Return void: */ void CMonster::ChangeHP(int nValue,CEntity * pKiller,bool bIgnoreDamageRedure, bool bIgnoreMaxDropHp,bool boSkillResult,int btHitType) { PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(GetId()); if (!pConfig) { return; } unsigned int nOldHp = GetProperty(PROP_CREATURE_HP); unsigned int nMaxHp = GetProperty(PROP_CREATURE_MAXHP); if(nOldHp > nMaxHp) nOldHp = nMaxHp; if (!m_bHasHPChangeSayConfig) Inherited::ChangeHP(nValue,pKiller,bIgnoreDamageRedure,bIgnoreMaxDropHp,boSkillResult,btHitType); else { unsigned int nOldVal = GetProperty(PROP_CREATURE_HP); Inherited::ChangeHP(nValue,pKiller,bIgnoreDamageRedure,bIgnoreMaxDropHp,boSkillResult,btHitType); unsigned int nCurVal = GetProperty(PROP_CREATURE_HP); if (nOldVal <= nCurVal) return; unsigned int nMaxVal = GetProperty(PROP_CREATURE_MAXHP); unsigned int nID = GetProperty(PROP_ENTITY_ID); MonsterSayTypeConfig &sayTypeConfig = pConfig->monsterSayList.vecSayTypeInfo[mstHpLow]; if (sayTypeConfig.nCount <= 0) return; for (INT_PTR i = 0; i < sayTypeConfig.nCount; i++) { MonsterSayInfo &si = sayTypeConfig.pMonsterSayCfg[i]; if (si.nRate > 0) { float nRate = si.nParam / 100.0f; unsigned int nDivPos = (unsigned int)(nRate * nMaxVal); if (nOldVal > nDivPos && nCurVal <= nDivPos) { MonsterSay(mstHpLow, i); break; } } } /*MonsterSayInfo &si = pConfig->monsterSayList.vecSayInfo[mstHpLow]; if (si.nRate > 0) { float nRate = si.nParam / 100.0f; unsigned int nDivPos = unsigned int(nRate * nMaxVal); if (nOldVal > nDivPos && nCurVal <= nDivPos) { MonsterSay(mstHpLow); } }*/ } unsigned int nCurHp = GetProperty(PROP_CREATURE_HP); int nDropHp = nOldHp - nCurHp; if(m_nMonsterType == tagMonsterConfig::mtWorldBoss && nDropHp > 0) { if (pKiller && pKiller->GetType() == enActor) { CActor* pActor = ((CActor*)pKiller); CScriptValueList paramList; paramList << nDropHp; //damage int isKiller = 0; if(nCurHp <= 0) isKiller = 1; paramList << isKiller; //isKiller paramList << GetGlobalLogicEngine()->getMiniDateTime(); pActor->OnEvent(aeHurtMonster, paramList,paramList); } } //boss 收到伤害 触发 // if(m_nBossReferId > 0 && nDropHp > 0) // { // CActor *pActor = NULL; // INT_PTR nEntityType = pEntity->GetType(); // if (nEntityType == enPet) // { // pActor = ((CPet*)pEntity)->GetMaster(); //主人 // } // if (nEntityType == enHero) // { // pActor = ((CHero*)pEntity)->GetMaster(); //主人 // } // if (nEntityType == enActor) // { // pActor =(CActor*)pEntity; // } // if (pActor) // { // GetGlobalLogicEngine()->GetBossMgr().BossCallLuaScript(m_nBossReferId, CBossSystem::enOnAttackBoss, pActor); // } // } if (m_ranking && nDropHp > 0) { UpdateMonsterRanking(pKiller, nDropHp); } if ((pConfig->btMonsterType == MONSTERCONFIG::mtBoss || pConfig->btMonsterType == MONSTERCONFIG::mtToumu || pConfig->btMonsterType == MONSTERCONFIG::mtWorldBoss ) && nDropHp > 0) { UpdateMonsterHatred(pKiller, nDropHp); } } void CMonster::InitPriorAttackTarget(CVector &monsterList) { unsigned int nID = GetProperty(PROP_ENTITY_ID); PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nID); if (!pConfig) return; for (INT_PTR i = 0; i < pConfig->priorAttackTarget.nCount; i++) { monsterList.add(pConfig->priorAttackTarget.pTargetIDList[i]); } } static const LPCTSTR g_szMosterRankPattern = _T("monster_rank_%d.txt"); //怪物排行榜名称 必须与脚本保持一致 static const INT_PTR g_nMosterRankItemCount = 100; //怪物排行榜排行数量 static const LPCTSTR g_szMosterRankColumn_0 = _T("username"); //怪物排行榜第一列 static const LPCTSTR g_szMosterRankColumn_1 = _T("param"); //怪物排行榜第一列 void CMonster::RegisterMonsterRank() { // unsigned int nID = GetProperty(PROP_ENTITY_ID); // PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nID); // if (!pConfig || !(pConfig->bCreateRank)) return; // TCHAR name[1024] = {0}; // sprintf(name, g_szMosterRankPattern, nID); //获取玩家的ID,拼接成完整的排行榜名称 // CRankingMgr &RankingMgr = GetGlobalLogicEngine()->GetRankingMgr(); // CRanking *pRanking = RankingMgr.GetRanking(name); // //初始化交给脚本处理 // if (!pRanking) // { // pRanking = RankingMgr.Add(name, g_nMosterRankItemCount, 0); // if (pRanking) // { // if (!pRanking->Load(name)) // { // pRanking->AddColumn(g_szMosterRankColumn_0,-1); // pRanking->AddColumn(g_szMosterRankColumn_1,-1); // } // } // else // { // OutputMsg(rmError, _T("create monster rank error! id = %"), nID); // return; // } // } // m_ranking = pRanking; } void CMonster::UpdateMonsterRanking(CEntity *pEntity, INT_PTR nNewVal) { DECLARE_TIME_PROF("CMonster::UpdateMonsterRanking"); if (!pEntity || !m_ranking) return; CActor *pActor = (CActor *)pEntity; if (pEntity->GetType() == enPet) //如果是宠物打出的伤害 则计算到主人身上 { pActor = ((CPet*)pEntity)->GetMaster(); //主人 } if (pEntity->GetType() == enHero) { pActor = ((CHero*)pEntity)->GetMaster(); //主人 } if (pActor && pActor->GetType() == enActor) { unsigned int nActorId = pActor->GetId(); CRankingItem *pItem = m_ranking->GetPtrFromId(nActorId); if (pItem) { m_ranking->Update(nActorId, nNewVal); } else { pItem = m_ranking->AddItem(nActorId, nNewVal); if (pItem) { pItem->SetSub(0,pActor->GetEntityName()); } } m_ranking->Save(); } } INT_PTR CMonster::GetMonsterHetred(CEntity* pEntity) { if (!pEntity) return 0; CActor *pActor = NULL; INT_PTR nEntityType = pEntity->GetType(); if (nEntityType == enPet) { pActor = ((CPet*)pEntity)->GetMaster(); //主人 } if (nEntityType == enHero) { pActor = ((CHero*)pEntity)->GetMaster(); //主人 } if (nEntityType == enActor) { pActor =(CActor*)pEntity; } if (pActor) { unsigned int nActorId = pActor->GetId(); MONSTERHATRED* pHatred = NULL; for (int i =0 ; i< m_hatredList.count(); i++) { MONSTERHATRED& hatred = m_hatredList[i]; if (hatred.nActorId == nActorId && hatred.nEntityType == nEntityType) { pHatred = &hatred; break; } } unsigned int nHatredKeepTime = GetLogicServer()->GetDataProvider()->GetGlobalConfig().nMonsterHatredKeepTime; unsigned int nCurrTime = GetGlobalLogicEngine()->getMiniDateTime(); if (pHatred && nCurrTime - pHatred->nLastAttackTime <= nHatredKeepTime) { return pHatred->nDamageValue; } } return 0; } void CMonster::UpdateMonsterHatred(CEntity *pEntity, INT_PTR nNewVal) { DECLARE_TIME_PROF("CMonster::UpdateMonsterHatred"); if (!pEntity) return; CActor *pActor = NULL; INT_PTR nEntityType = pEntity->GetType(); unsigned int nHatredKeepTime = GetLogicServer()->GetDataProvider()->GetGlobalConfig().nMonsterHatredKeepTime; unsigned int nCurrTime = GetGlobalLogicEngine()->getMiniDateTime(); if (nEntityType == enPet) { pActor = ((CPet*)pEntity)->GetMaster(); //主人 } if (nEntityType == enHero) { pActor = ((CHero*)pEntity)->GetMaster(); //主人 //战神按比例增加仇恨,其他跟伤害1:1 //nNewVal = (INT_PTR)(nNewVal* GetLogicServer()->GetDataProvider()->GetGlobalConfig().fMonsterHatredHeroRate); } if (nEntityType == enActor) { pActor =(CActor*)pEntity; } if (pActor) { unsigned int nActorId = pActor->GetId(); bool isFind = false; for (int i =0 ; i < m_hatredList.count(); i++) { MONSTERHATRED& hatred = m_hatredList[i]; if (hatred.nActorId == nActorId && hatred.nEntityType == nEntityType) { isFind = true; if (nCurrTime - hatred.nLastAttackTime <= nHatredKeepTime) { hatred.nDamageValue += nNewVal; } else { hatred.nDamageValue = nNewVal; } hatred.nLastAttackTime = nCurrTime; OutputMsg(rmTip,_T("[%s] 攻击boss:%d,时间 %d"),pActor->GetEntityName(),m_nBossReferId,hatred.nLastAttackTime); break; //pActor->GetBossSystem().SetHatredBossData(this, hatred); } } if (!isFind) { MONSTERHATRED newHatred; newHatred.nActorId = nActorId; newHatred.nDamageValue = nNewVal; newHatred.nEntityType =(BYTE)nEntityType; newHatred.nLastAttackTime = nCurrTime; m_hatredList.add(newHatred); //pActor->GetBossSystem().SetHatredBossData(this, newHatred); } } } void CMonster::SetVestEntityName(LPCTSTR sName) { if(sName ==NULL) return; if (m_nForceVesterId > 0) return; if (strcmp(sName,m_sVestEntityName) != 0) { _asncpytA(m_sVestEntityName,sName); //OutputMsg(rmSystem,_T("Vest Name: %s"), m_sVestEntityName); CVector vecNearEntityList; GetNearActorList(vecNearEntityList); INT_PTR nEntityCount = vecNearEntityList.count(); if (nEntityCount > 0) { CEntityManager * pMgr = GetGlobalLogicEngine()->GetEntityMgr(); for (int i = 0; i < nEntityCount; i++) { CEntity * pActor = pMgr->GetEntity(vecNearEntityList[i]); if (pActor && pActor->GetType() == enActor) { CActorPacket ap; CDataPacket & outPack = ((CActor*)pActor)->AllocPacket(ap); outPack << (BYTE)enMiscSystemID << (BYTE)sVestName; outPack.writeString(m_sVestEntityName); ap.flush(); } } } } } LPCSTR CMonster::GetVestEntityName() { return m_sVestEntityName; } void CMonster::SetForceVesterId(unsigned int nForceVesterId) { if( nForceVesterId > 0 ) { CEntity *pVester = NULL; pVester = GetGlobalLogicEngine()->GetEntityMgr()->GetEntityPtrByActorID(nForceVesterId); if( pVester ) { SetVestEntityName(((CActor*)pVester)->GetEntityName()); m_nForceVesterId = nForceVesterId; } } }