先从OnDie事件看起:
VOID Obj_Monster::OnDie_Before( ObjID_t idKiller ) { //计算怪物掉落情况(即:谁拥有掉落物品) m_DropRuler = MonsterDropRuler::GetMonsterDropRuler(this); switch(m_DropRuler) { case BDR_UNKNOW: case BDR_COMMON: case BDR_BOSS: { MonsterDropRuler::CaculateBossOwnerList(this); } break; //{ // MonsterDropRuler::CaculateCommOwnerList(this); //} //break; //{ // MonsterDropRuler::CaculateCommOwnerList(this); //} //break; default: Assert(FALSE); break; } } VOID Obj_Monster::OnDie( ObjID_t idKiller ) { __ENTER_FUNCTION OnDie_Before( idKiller ) ; Obj_Character::OnDie( idKiller ); OnDie_After( idKiller ) ; __LEAVE_FUNCTION } VOID Obj_Monster::OnDie_After( ObjID_t idKiller ) { __ENTER_FUNCTION // 确定有多少个队友可以分配到经验 INT nOwnerCount = GetOwnerList().OwnerCount; INT nValidMemberCount = 0; Obj_Human *apValidMember[MAX_TEAM_MEMBER]; // 是否需要进行善恶值分配 Obj_Human* pTeamLeader = NULL; INT nValidNewbieMemberCount = 0; // 有效范围内符合级别条件的玩家数量 for( INT i=0; i<nOwnerCount; i++ ) { Obj_Human *pMember = (Obj_Human*)(getScene()->GetObjManager()->GetObj( GetOwnerList().OwnerDropList[i].HumanID )); if( pMember==NULL ) { Assert(FALSE); break; } if( !pMember->IsAlive() )//活的人才能得到经验 continue ; apValidMember[nValidMemberCount++] = pMember; // 判断是否队长,For 善恶值 if( pMember->GetTeamInfo()->IsLeader() && pMember->GetLevel() >= g_Config.m_ConfigInfo.m_nLevelNeeded ) { pTeamLeader = pMember; } if( nValidMemberCount>MAX_TEAM_MEMBER ) { break; } } MonsterExpCaculateRuler CaculateExp; // 多个玩家都可以得到经验 if ( nValidMemberCount > 1 ) { INT nExp = (m_BaseExp + (m_BaseExp*(nValidMemberCount-1))/10) / nValidMemberCount; UINT auExp[MAX_TEAM_MEMBER]; INT i; for ( i = 0; i < nValidMemberCount; i++ ) { // 计算每个人应得的经验值 auExp[i] = CaculateExp.CaculateBaseExp(GetLevel(),apValidMember[i]->GetLevel(),nExp); // 判断是否符合条件的队员,For 善恶值 if( pTeamLeader != NULL && nExp == auExp[i] && apValidMember[i]->GetLevel() <= g_Config.m_ConfigInfo.m_nMemberLevel && apValidMember[i]->IsInValidRadius( pTeamLeader, g_Config.m_ConfigInfo.m_fGoodBadRadius ) ) { ++nValidNewbieMemberCount; } } // 增加善恶值 //if( pTeamLeader != NULL ) //{ // INT nBonus; // nBonus = nValidNewbieMemberCount * g_Config.m_ConfigInfo.m_nBonusPerMember; // if( nBonus > g_Config.m_ConfigInfo.m_nMaxBonus ) // { // nBonus = g_Config.m_ConfigInfo.m_nMaxBonus; // } // if( nBonus > 0 ) // { // nBonus = pTeamLeader->IncGoodBadValue( nBonus ); // // nBonus 是实际增加值 // // 发送消息给客户端,以显示信息提示 // GCNotifyGoodBad Msg; // Msg.SetNotifyMode( NOTIFY_GOODBAD_HELPNEWBIE ); // Msg.SetValue( nBonus ); // pTeamLeader->GetPlayer()->SendPacket( &Msg ); // } //} for ( i = 0; i < nValidMemberCount; i++ ) { // 增加经验值 if(auExp[i]>0) { apValidMember[i]->SetMonsterAlterExp(auExp[i]); } apValidMember[i]->OnKillObject( GetID() ); // 在此加入玩家的宠物增加经验的Section Obj_Pet* pPet = apValidMember[i]->GetPet(); if (pPet) { UINT iAddExp = CaculateExp.CaculateBaseExp(GetLevel(), pPet->GetLevel(), nExp); if (iAddExp > 0) pPet->IncrementExp(iAddExp); } UINT uExpPoint = (g_Config.m_ConfigInfo.m_nExpPoint >= 0) ? g_Config.m_ConfigInfo.m_nExpPoint : 0; GUID_t MyGUID = apValidMember[i]->GetGUID(); HumanRelation* pRelation = apValidMember[i]->GetHumanRelation(); if( pRelation == NULL ) continue; //Assert( pRelation ); // 增加友好度 for ( INT j = i+1; j < nValidMemberCount; ++j ) { GUID_t FriendGUID; HumanRelation* pFriendRelation; FriendGUID = apValidMember[j]->GetGUID(); pFriendRelation = apValidMember[j]->GetHumanRelation(); //Assert(pFriendRelation); if ( pFriendRelation && pRelation->IsFriend( FriendGUID ) && pFriendRelation->IsFriend( MyGUID ) ) { // 如果是好友 if ( auExp[i] >= uExpPoint || auExp[j] >= uExpPoint ) { // 符合条件 pRelation->IncFriendPoint( FriendGUID ); pFriendRelation->IncFriendPoint( MyGUID ); } } } } } // 单个玩家得到经验 else if( nValidMemberCount==1 ) { UINT iAddExp = CaculateExp.CaculateBaseExp(GetLevel(),apValidMember[0]->GetLevel(),m_BaseExp); if(iAddExp>0) { apValidMember[0]->SetMonsterAlterExp(iAddExp); } apValidMember[0]->OnKillObject( GetID() ) ; // 在此加入玩家的宠物增加经验的Section Obj_Pet* pPet = apValidMember[0]->GetPet(); if (pPet) { iAddExp = CaculateExp.CaculateBaseExp(GetLevel(), pPet->GetLevel(), m_BaseExp); if (iAddExp > 0) pPet->IncrementExp(iAddExp); } } //根据掉落规则,计算掉落包掉落处理 switch(m_DropRuler) { case BDR_COMMON: case BDR_BOSS: case BDR_UNKNOW: { MonsterDropRuler::CaculateBossDropRuler(this,m_DropRuler); } break; //{ // MonsterDropRuler::CaculateCommDropRuler(this); //} //break; //break; //{ // MonsterDropRuler::CaculateCommDropRuler(this); //} default: Assert(FALSE); break; } __LEAVE_FUNCTION }
在死亡后会调用 MonsterDropRuler::GetMonsterDropRuler(this);
MonsterDropRuler::GetMonsterDropRuler(Obj_Monster* pMonster) { __ENTER_FUNCTION Assert(pMonster); INT iDataID = pMonster->GetDataID(); MONSTER_DROPBOX_TB* pDropBoxs = g_ItemTable.GetMonsterDropTB(iDataID); if(pDropBoxs) { return (BOX_DISTRIBUTE_RULER)pDropBoxs->m_DropType; } return BDR_UNKNOW; __LEAVE_FUNCTION return BDR_UNKNOW; }
如果是BOSS掉落调用:MonsterDropRuler::CaculateBossOwnerList(this);
BOOL MonsterDropRuler::CaculateBossOwnerList(Obj_Monster* pMonster) { __ENTER_FUNCTION if(!pMonster) { Assert(pMonster); return FALSE; } Scene* pScene = pMonster->getScene(); if(!pScene) { Assert(pScene); return FALSE; } Obj_Human* pFinalOwner; //查找有效团队 BOOL bFindTeam = FALSE; UINT iCurrentDTIndex = 0; UINT uMaxTeamCount = pMonster->GetDropTeamCount(); INT nPercent = pMonster->GetMinDamagePercent(); FLOAT fSearchLength = pMonster->GetDropSearchRange(); //Boss怪可以选择多个队伍 DAMAGE_MEM_LIST DRecord = pMonster->GetKillerRec(uMaxTeamCount,nPercent); if(DRecord.m_uCount==0) //没有找到队伍 return FALSE; UINT uTeamCount = DRecord.m_uCount;//参与拾取的队伍个数 Assert(uTeamCount<MAX_DAMAGE_REC_COUNT); ScanOperator_ActiveTeammates ScanOpAT; for(UINT i =0;i<uTeamCount;i++) //遍历每个合法队伍,并且创建对应掉落包 { //查找激活的成员 SCANOPERATOR_ACTIVETEAMMATES_INIT SA_Init; //SA_Init.m_TeamID = DRecord.m_DamageRec[iCurrentDTIndex].m_TeamID; //SA_Init.m_MemberObjID = DRecord.m_DamageRec[iCurrentDTIndex].m_Killer; SA_Init.m_TeamID = pMonster->GetOccupantTeamID() ; SA_Init.m_MemberGUID = pMonster->GetOccupantGUID() ; SA_Init.m_fRadius = fSearchLength; SA_Init.m_nZoneRadius = 5; SA_Init.m_bScanHuman = TRUE; SA_Init.m_Position = *pMonster->getWorldPos(); SA_Init.m_ZoneID = pMonster->getZoneID(); SA_Init.m_pScene = pMonster->getScene(); ScanOpAT.Init(&SA_Init); pScene->Scan(&ScanOpAT); iCurrentDTIndex++; if(ScanOpAT.m_nActiveTeammateCount<1) //没有找到 { break ; // continue; } else if(ScanOpAT.m_nActiveTeammateCount==1)//找到一个 { pFinalOwner = ScanOpAT.m_aActiveTeammate[0]; //if(pFinalOwner->IsInValidRadius(pMonster->getWorldPos(),fSearchLength) == FALSE) //{ // continue; //} pMonster->GetOwnerList().AddOwner(pFinalOwner->GetID()); break ; } else//找到多个 { INT iActivePlayerCount = ScanOpAT.m_nActiveTeammateCount; for(UINT iDropBox =0;iDropBox<(UINT)iActivePlayerCount;iDropBox++) { pFinalOwner = ScanOpAT.m_aActiveTeammate[iDropBox]; if(pFinalOwner) { pMonster->GetOwnerList().AddOwner(pFinalOwner->GetID()); } } break ; } } return TRUE; __LEAVE_FUNCTION return FALSE; }
然后就根据DropRule创建掉落包:MonsterDropRuler::CaculateCommDropRuler(this);同样,分为BOSS跟普通怪物两个函数。
#define MD_PICK_RANGE (100.0f) BOOL MonsterDropRuler::CaculateCommDropRuler(Obj_Monster* pMonster) { __ENTER_FUNCTION if(!pMonster) { Assert(FALSE); return FALSE; } Scene* pScene = pMonster->getScene(); if(!pScene) { Assert(pScene); return FALSE; } Obj_Human* pFinalOwner = 0; if(pMonster->GetOwnerList().OwnerCount<1) { return FALSE; } INT randown = rand()%pMonster->GetOwnerList().OwnerCount ; ObjID_t OwnerID = pMonster->GetOwnerList().OwnerDropList[randown].HumanID; CHAR_OWNER_DROP_LIST TaskDropList = pMonster->GetOwnerList().OwnerDropList[randown]; pFinalOwner = pScene->GetHumanManager()->GetHuman(OwnerID); if(!pFinalOwner) { Assert(FALSE); return FALSE; } ItemBoxManager* pIBManager = pScene->GetItemBoxManager(); if(!pIBManager) { Assert(pIBManager); return FALSE; } UINT iMonsterLevel = pMonster->GetLevel(); UINT iKillerLevel = pFinalOwner->GetLevel(); INT iDataID = pMonster->GetDataID(); FLOAT fWallow = pFinalOwner->GetWallow(); ItemBoxContaner IBContaner = pIBManager->CaculateItemDropFromMonster(iMonsterLevel, iKillerLevel,iDataID,fWallow); WORLD_POS Pos = *pMonster->getWorldPos(); if((IBContaner.m_nCount<=0) && (TaskDropList.DropCount==0)) //判断是否掉出物品 { pMonster->GetOwnerList().CleanUp(); return FALSE; } Obj_ItemBox* pItemBox = pIBManager->CreateMonsterDropItembox(&Pos); //创建ItemBox; for(INT i=0;i<IBContaner.m_nCount;i++) { pItemBox->AddItem(&IBContaner,i); } ITEM_LOG_PARAM ItemLogParam; ItemLogParam.OpType = ITEM_CREATE_FROM_MONSTER; ItemLogParam.SceneID = pScene->SceneID(); ItemLogParam.NpcType = iDataID; ItemLogParam.XPos = Pos.m_fX; ItemLogParam.ZPos = Pos.m_fZ; for(UINT i =0;i<TaskDropList.DropCount;i++) { INT iQuality = 1; pItemBox->CreateItem(&ItemLogParam,TaskDropList.DropItemIndex[i],iQuality); SaveItemLog(&ItemLogParam); } pMonster->GetOwnerList().CleanUp(); pItemBox->SetOwner(pFinalOwner->GetGUID()); pItemBox->SetDropMonsterID(pMonster->GetID()); pItemBox->SetActiveFlag(TRUE); return TRUE; __LEAVE_FUNCTION return FALSE; } BOOL MonsterDropRuler::CaculateBossDropRuler(Obj_Monster* pMonster, BOX_DISTRIBUTE_RULER DropRuler) { __ENTER_FUNCTION Assert(pMonster); Scene* pScene = pMonster->getScene(); Assert(pScene); ItemBoxManager* pIBManager = pScene->GetItemBoxManager(); Assert(pIBManager); UINT randomindex=0 ; UINT OwnerCount = pMonster->GetOwnerList().OwnerCount; if( OwnerCount==0 ) return TRUE ; if( DropRuler!=BDR_BOSS ) { randomindex = rand()%OwnerCount ; } for(UINT iDropBox =0;iDropBox<(UINT)OwnerCount;iDropBox++) { ObjID_t OwnerID = pMonster->GetOwnerList().OwnerDropList[iDropBox].HumanID; UINT OwnerItemCount = pMonster->GetOwnerList().OwnerDropList[iDropBox].DropCount; CHAR_OWNER_DROP_LIST TaskDropList = pMonster->GetOwnerList().OwnerDropList[iDropBox]; Obj_Human* pFinalOwner = pScene->GetHumanManager()->GetHuman(OwnerID); if(!pFinalOwner) { continue; } UINT iMonsterLevel = pMonster->GetLevel(); UINT iKillerLevel = pFinalOwner->GetLevel(); INT iDataID = pMonster->GetDataID(); FLOAT fWallow = pFinalOwner->GetWallow(); ItemBoxContaner IBContaner = pIBManager->CaculateItemDropFromMonster(iMonsterLevel, iKillerLevel,iDataID,fWallow); WORLD_POS Pos = *pMonster->getWorldPos(); if((IBContaner.m_nCount<=0) && (TaskDropList.DropCount==0)) //判断是否掉出物品 continue; if( DropRuler!=BDR_BOSS && randomindex!=iDropBox && TaskDropList.DropCount==0 ) { continue ; } //尝试找对应的ItemBox Obj_ItemBox* pItemBox = pIBManager->CreateMonsterDropItembox(&Pos); //创建ItemBox; if( DropRuler==BDR_BOSS ) {//如果是boss类型的,则都会生成 for(int i=0;i<IBContaner.m_nCount;i++) { pItemBox->AddItem(&IBContaner,i); } } else if( randomindex==iDropBox ) {//如果不是boss型怪,则只有一个能被生成 for(int i=0;i<IBContaner.m_nCount;i++) { pItemBox->AddItem(&IBContaner,i); } } ITEM_LOG_PARAM ItemLogParam; ItemLogParam.OpType = ITEM_CREATE_FROM_MONSTER; ItemLogParam.SceneID = pScene->SceneID(); ItemLogParam.NpcType = iDataID; ItemLogParam.XPos = Pos.m_fX; ItemLogParam.ZPos = Pos.m_fZ; for(UINT i=0;i<TaskDropList.DropCount;i++) { INT iQuality = 1; pItemBox->CreateItem(&ItemLogParam,TaskDropList.DropItemIndex[i],iQuality); SaveItemLog(&ItemLogParam); } //pScene->ObjectEnterScene(pItemBox); pItemBox->SetOwner(pFinalOwner->GetGUID()); pItemBox->SetDropMonsterID(pMonster->GetID()); pItemBox->SetActiveFlag(TRUE); } pMonster->GetOwnerList().CleanUp(); return TRUE; __LEAVE_FUNCTION return FALSE; }
然后就开始计算要掉落的物品: ItemBoxManager::CaculateItemDropFromMonster
ItemBoxContaner ItemBoxManager::CaculateItemDropFromMonster( UINT iMonsterLevel, UINT iKillerLevel, INT iMonsterType, FLOAT fWallow) { ItemBoxContaner IBContaner; __ENTER_FUNCTION MONSTER_DROPBOX_TB* pDropBoxs = g_ItemTable.GetMonsterDropTB(iMonsterType); if(pDropBoxs) { ItemBoxRuler ibr; IBContaner.m_uDropType = pDropBoxs->m_DropType; ibr.CreateItemFromMonsterDrop(pDropBoxs->m_MonsterValue, pDropBoxs->m_DropBoxs, iKillerLevel, iMonsterLevel, 1.0f, IBContaner, fWallow); if(IBContaner.m_nCount>0) { for(INT i =0;i<IBContaner.m_nCount;i++) { ITEM_LOG_PARAM ItemLogParam; ItemLogParam.OpType = ITEM_CREATE_FROM_MONSTER; ItemLogParam.NpcType = iMonsterType; ItemLogParam.ItemType = IBContaner.m_Item[i].m_ItemIndex; BOOL bRet = g_pItemManager->CreateItem( &ItemLogParam, IBContaner.m_Item[i].m_ItemIndex, IBContaner.m_Item[i], IBContaner.m_nQuality[i]); if(!bRet) { CHAR ErrorMsg[255]; sprintf(ErrorMsg,"掉落包中物品创建失败,请检查策划填写的掉落包内容!, MonsterType = %d, m_ItemIndex = %d ", iMonsterType,IBContaner.m_Item[i].m_ItemIndex); AssertEx(bRet,ErrorMsg); } SaveItemLog(&ItemLogParam); } } } return IBContaner; __LEAVE_FUNCTION return IBContaner; }
最后体现在这里了:
VOID ItemBoxRuler::CreateItemFromMonsterDrop( INT iMonsterValue, //怪物价值 MONSTER_DROPBOXS& mDrop, //掉落包序列 INT iPlayerLvl, //玩家级别 INT iMonsterLvl, //怪物级别 FLOAT fControlValue, //监控系数 ItemBoxContaner& OutBox, //产生的Obj_ItemBox容器 FLOAT fWallow) { __ENTER_FUNCTION double dBaseDropRate; //基本掉落率 double dDeltaDropRate = 1.0; //级别修正率 double dCurrentRate; //当前掉落率随机数 FLOAT fCurrentRate; //当前物品选取随机数 UINT iCanDropItemNumber; //可以掉落的物品数 for(INT i =0;i<MAX_MONSTER_DROPBOX;i++) { if(mDrop.m_DropBox[i]!= -1) { DROP_BOX_TB* pTb = g_ItemTable.GetDropBoxTB(mDrop.m_DropBox[i]); if(pTb) { dBaseDropRate = (double)iMonsterValue/(double)pTb->m_DropValue; DROP_ATT_TB* pDropAtt = g_ItemTable.GetDropAttTB(iMonsterLvl-iPlayerLvl); if(pDropAtt) { dDeltaDropRate = pDropAtt->m_AttValue; } dBaseDropRate = dBaseDropRate*dDeltaDropRate*g_Config.m_ConfigInfo.m_DropParam*fWallow; dCurrentRate = ItemRander::DoubleRand() ; if(dCurrentRate<dBaseDropRate) { iCanDropItemNumber = 0; for(INT j = 0;j<MAX_DROPBOX_CARRAGE;j++) { if(pTb->m_DropItem[j].ToUINT() > 0 ) iCanDropItemNumber++; else j = MAX_DROPBOX_CARRAGE; } if(iCanDropItemNumber>0 ) { fCurrentRate = (FLOAT)rand()/RAND_MAX; UINT iIndex = (UINT)(fCurrentRate*iCanDropItemNumber); Assert(iIndex<MAX_DROPBOX_CARRAGE); OutBox.AddItemType(pTb->m_DropItem[iIndex],pTb->m_Quality[iIndex]); } } } } else i = MAX_MONSTER_DROPBOX; } __LEAVE_FUNCTION }
fWallow:
pFinalOwner = pScene->GetHumanManager()->GetHuman(OwnerID); if(!pFinalOwner) { Assert(FALSE); return FALSE; } ItemBoxManager* pIBManager = pScene->GetItemBoxManager(); if(!pIBManager) { Assert(pIBManager); return FALSE; } UINT iMonsterLevel = pMonster->GetLevel(); UINT iKillerLevel = pFinalOwner->GetLevel(); INT iDataID = pMonster->GetDataID(); FLOAT fWallow = pFinalOwner->GetWallow();