Files
aixianling 5c9f1dae4a init
2025-01-09 17:45:40 +08:00

1674 lines
52 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "StdAfx.h"
//const int monsterVectResetInterval = 6000; // 怪物归属重置间隔(6s没有打怪清除怪物原来归属)
CUpdateMask *CMonster::s_monsterBroadcastMask = NULL;
void CMonster::InitAi()
{
unsigned int nID = GetProperty<unsigned int>(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<unsigned int>(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<int>(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<unsigned int>(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<unsigned int>(PROP_MONSTER_CIRCLE) : pConfig->nCircle; //怪物的转生等级
if (pConfig->pflags->DenyDieSubExp) {
nExpMonsLv = 0; //不进行经验衰减
}
EntityFlags* pFlag = pConfig->pflags;
if(pActor != NULL && nExp > 0) {
//如果不进行经验衰减的话就直接给原来的经验,否则要进行经验的衰减
//没有队伍,或者没人和自己共享经验,直接添加给自己
int nSelfLevel = pActor->GetProperty<int>(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<DROPGOODS> 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<DROPGOODS> 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<unsigned int>(PROP_ENTITY_ID);
int nPosX,nPosY; //位置
GetPosition(nPosX,nPosY); //获取坐标
unsigned int lv = GetProperty<unsigned int>(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<EntityHandle> *pNode;
CLinkedListIterator<EntityHandle> 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<unsigned int> (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 <<pKillerEntity; //怪物击杀者
GetGlobalLogicEngine()->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<int>( 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<unsigned int>(PROP_CREATURE_LEVEL); // 可能为负数
int oldLevelDiff = GetProperty<unsigned int>(PROP_MONSTER_LEVEL_DIFF);
if (levelDiff != oldLevelDiff)
{
SetProperty<unsigned int>(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<int>(PROP_ENTITY_ID);
PMONSTERCONFIG pConfig =
GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(nMonsterId);
if (pConfig)
{
//((CAnimal*)this)->AddState(esStateDeath); // do a trick for following property change
SetProperty<unsigned int>(PROP_CREATURE_HP,pConfig->cal.m_AttrValues[aMaxHpAdd].uValue);
SetProperty<unsigned int>(PROP_CREATURE_MP,pConfig->cal.m_AttrValues[aMaxMpAdd].uValue);
SetProperty<unsigned int>(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<unsigned int>(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<unsigned int>(PROP_ENTITY_ID));
if ( pMonsterConfig )
{
if ( pMonsterConfig->nAscriptionOpen )
{
CEntity *pVestEntity = GetGlobalLogicEngine()->GetEntityMgr()->GetEntity(m_hVestEntity);
if ( pVestEntity )
{
if ( enActor == pVestEntity->GetType() )
{
SetProperty<unsigned int>(PROP_MONSTER_BELONG_ID, pVestEntity->GetProperty<unsigned int>(PROP_ENTITY_ID));
return;
}
}
}
}
SetProperty<unsigned int>(PROP_MONSTER_BELONG_ID, 0);
}
const EntityHandle& CMonster::GetVestEntity()const
{
return m_hVestEntity;
}
bool CMonster::InBeAttackActorList(unsigned int nActorId)
{
for(int i=0; i<m_BeAccactedActorList.count(); i++)
{
if( nActorId == m_BeAccactedActorList[i] )
{
return true; //已经在列表中
}
}
return false;
}
void CMonster::SetBeAttackActorList(unsigned int nActorId)
{
if(!InBeAttackActorList(nActorId))
{
m_BeAccactedActorList.add(nActorId);
}
}
/*
怪物被攻击
*/
void CMonster::OnAttacked(CAnimal * pEntity, bool bSetVest)
{
//OutputMsg(rmNormal, "CMonster::OnAttacked: nDemage=%d", nDemage);
Inherited::OnAttacked(pEntity);
if (pEntity->GetType() == 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<unsigned int>(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<unsigned int >(PROP_CREATURE_HP);
unsigned int nMaxHp = GetProperty<unsigned int >(PROP_CREATURE_MAXHP);
if(nOldHp > nMaxHp)
nOldHp = nMaxHp;
if (!m_bHasHPChangeSayConfig)
Inherited::ChangeHP(nValue,pKiller,bIgnoreDamageRedure,bIgnoreMaxDropHp,boSkillResult,btHitType);
else
{
unsigned int nOldVal = GetProperty<unsigned int >(PROP_CREATURE_HP);
Inherited::ChangeHP(nValue,pKiller,bIgnoreDamageRedure,bIgnoreMaxDropHp,boSkillResult,btHitType);
unsigned int nCurVal = GetProperty<unsigned int >(PROP_CREATURE_HP);
if (nOldVal <= nCurVal) return;
unsigned int nMaxVal = GetProperty<unsigned int >(PROP_CREATURE_MAXHP);
unsigned int nID = GetProperty<unsigned int>(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<unsigned int >(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<int> &monsterList)
{
unsigned int nID = GetProperty<unsigned int>(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<unsigned int >(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<EntityHandle> 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;
}
}
}