关于掉落的详细分析。

先从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;

        
}
View Code

如果是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;
}
View Code

然后就根据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;
}
View Code

然后就开始计算要掉落的物品: 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;
}
View Code

最后体现在这里了:

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
}
View Code

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();
View Code

原文地址:https://www.cnblogs.com/dieangel/p/3378136.html