313 lines
10 KiB
C++
313 lines
10 KiB
C++
#include "StdAfx.h"
|
|
#include "DropFormulaCore.h"
|
|
#include "DropItemRatioCalc.h"
|
|
#include <SCItemSlot.h>
|
|
#include <ItemInfoParser.h>
|
|
#include <FormulaRatioParser.h>
|
|
|
|
DropFormulaCore::DropFormulaCore(void)
|
|
{
|
|
m_pItemDropRatio = new DropItemRatioCalc;
|
|
}
|
|
|
|
DropFormulaCore::~DropFormulaCore(void)
|
|
{
|
|
SAFE_RELEASENDELETE(m_pItemDropRatio);
|
|
}
|
|
|
|
VOID DropFormulaCore::_InitRatio()
|
|
{
|
|
BOOL rt = FALSE;
|
|
// 드랍 확률 선택기
|
|
for( int Grade = eNPC_GENERAL ; Grade < eNPC_GRADE_MAX ; ++Grade )
|
|
{
|
|
for( int num = 1 ; num < MAX_PARTYMEMBER_NUM+1 ; ++num )
|
|
{
|
|
m_DropRatioSelecter[Grade][num].Clear();
|
|
for( int Step = 0 ; Step < MAX_DROP_ITEM_STEP_NUM ; ++Step )
|
|
{
|
|
DROP_ITEM_RATIO * pInfo = m_ItemDropParser.GetDropItemRatio( (eNPC_GRADE)Grade, Step );
|
|
|
|
DWORD StandardAmount = pInfo->m_DropStandardAmount;
|
|
DWORD Amount = pInfo->m_DropAmount[num];
|
|
if( 0 == StandardAmount || 0 == Amount ) continue;
|
|
ASSERT( pInfo->m_Index <= DROP_ITEM_10 );
|
|
rt = m_DropRatioSelecter[Grade][num].AddRatio( pInfo->m_Index, Amount, StandardAmount ); ASSERT(rt);
|
|
}
|
|
rt = m_DropRatioSelecter[Grade][num].AddRatio( DROP_RARE_ITEM, 100000, 1000000 ); ASSERT(rt);
|
|
}
|
|
}
|
|
|
|
|
|
// 레어 아이템 확률 선택기
|
|
// 가정 m_bPrior == 0 인것은 key가 0이어야 한다.
|
|
// 레벨사이의 간격이 빈곳이 없어야 한다.
|
|
memset( m_Section, 0, sizeof(BYTE)*MAX_LEVEL_STEP_NUM );
|
|
|
|
for( int LVStep = 0 ; LVStep < MAX_LEVEL_STEP_NUM ; ++LVStep )
|
|
{
|
|
RAREITEM_DROP_INFO * pTmpInfo = m_RareItemDropParser.GetRareItemDropInfo(LVStep, (eNPC_GRADE)1, 1);
|
|
m_Section[LVStep] = pTmpInfo->m_MaxLV;
|
|
for( int Grade = eNPC_GENERAL ; Grade < eNPC_GRADE_MAX ; ++Grade )
|
|
{
|
|
for( int num = 1 ; num < MAX_PARTYMEMBER_NUM+1 ; ++num )
|
|
{
|
|
m_RareItemDropRatioSelecter[LVStep][Grade][num].Clear();
|
|
for( int ele = 1 ; ele < MAX_ELEMENT_PER_LEVEL_NUM ; ++ele )
|
|
{
|
|
RAREITEM_DROP_INFO * pInfo = m_RareItemDropParser.GetRareItemDropInfo(LVStep, (eNPC_GRADE)Grade, ele);
|
|
ASSERT(pInfo);
|
|
if( !pInfo ) continue;
|
|
if( 0 == pInfo->m_StandardAmount || 0 == pInfo->m_ItemCode || 0 == pInfo->m_Amount[num] ) continue;
|
|
ASSERT( pInfo->m_bPrior );
|
|
BOOL rt = m_RareItemDropRatioSelecter[LVStep][Grade][num].AddRatio( ele,
|
|
pInfo->m_Amount[num],
|
|
pInfo->m_StandardAmount ); ASSERT(rt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
SUNLOG( eFULL_LOG, "");
|
|
for( int i = 0 ; i < 40 ; ++i )
|
|
{
|
|
for( int i = 0 ; i < 20 ; ++i )
|
|
{
|
|
INT Index = m_RareItemDropRatioSelecter[1][eNPC_GENERAL][1].RandomizedKey();
|
|
RAREITEM_DROP_INFO * pInfo = m_RareItemDropParser.GetRareItemDropInfo( 1, eNPC_GENERAL, Index );
|
|
if( !pInfo ) continue;
|
|
|
|
SLOTCODE Code = pInfo->m_ItemCode;
|
|
SUNLOG( eFULL_LOG, "%d\t", Code);
|
|
}
|
|
SUNLOG( eFULL_LOG, "");
|
|
}
|
|
*/
|
|
}
|
|
|
|
VOID DropFormulaCore::Reload()
|
|
{
|
|
m_ItemDropParser.Reload();
|
|
m_RareItemDropParser.Reload();
|
|
m_pItemDropRatio->Reload();
|
|
_InitRatio();
|
|
m_fPlusScriptPercent = FormulaRatioParser::Instance()->GetFormulaRatio(RATIO_TYPE_DROP)->m_fRatio;
|
|
}
|
|
|
|
// ItemDropPerGrade.txt,
|
|
VOID DropFormulaCore::Init( TCHAR * tszItemDropPerGradeFile, TCHAR * tszItemDropInfoFile, TCHAR * tszRareItemDropInfoFile )
|
|
{
|
|
BOOL rt = m_ItemDropParser.Load( tszItemDropInfoFile ); ASSERT(rt);
|
|
rt = m_RareItemDropParser.Load( tszRareItemDropInfoFile ); ASSERT(rt);
|
|
|
|
m_pItemDropRatio->Init(tszItemDropPerGradeFile);
|
|
_InitRatio();
|
|
m_fPlusScriptPercent = FormulaRatioParser::Instance()->GetFormulaRatio(RATIO_TYPE_DROP)->m_fRatio;
|
|
}
|
|
|
|
|
|
BOOL DropFormulaCore::Drop( DWORD PlayerNum, eNPC_GRADE MonsterGrade, LEVELTYPE MonsterDisplayLV,
|
|
FLOAT fBonusPercent,
|
|
LEVELTYPE LVAverage,
|
|
eDROP_TYPE & OUT DropTypeOut, MONEY & OUT rDroppedMoneyOut, SCItemSlot & OUT rDroppedItemSlotOut )
|
|
{
|
|
DropTypeOut = (eDROP_TYPE)m_DropRatioSelecter[MonsterGrade][PlayerNum].RandomizedKey();
|
|
switch(DropTypeOut)
|
|
{
|
|
case DROP_MONEY_1:
|
|
case DROP_MONEY_40:
|
|
case DROP_MONEY_400:
|
|
return DropMoneyFunc( fBonusPercent, LVAverage, DropTypeOut, MonsterGrade, MonsterDisplayLV, rDroppedMoneyOut );
|
|
case DROP_ITEM_0:
|
|
case DROP_ITEM_1:
|
|
case DROP_ITEM_2:
|
|
case DROP_ITEM_3:
|
|
case DROP_ITEM_4:
|
|
case DROP_ITEM_5:
|
|
case DROP_ITEM_6:
|
|
case DROP_ITEM_7:
|
|
case DROP_ITEM_8:
|
|
case DROP_ITEM_9:
|
|
case DROP_ITEM_10:
|
|
return DropItemFunc( DropTypeOut, MonsterDisplayLV, rDroppedItemSlotOut );
|
|
case DROP_RARE_ITEM:
|
|
return DropRareItemFunc( PlayerNum, MonsterGrade, MonsterDisplayLV, rDroppedItemSlotOut );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DropFormulaCore::AdditionalItemDrop( BOOL IsItemDrop, INT MaxArrayNum, WORD * pDropItemRate, WORD * pDropItemCode, SCItemSlot & OUT rDroppedItemSlotOut )
|
|
{
|
|
// 추가적인 상위 몬스터 아이템 드랍
|
|
if( IsItemDrop )
|
|
{
|
|
return DropHigherMonsterItemFunc( MaxArrayNum, pDropItemRate, pDropItemCode, rDroppedItemSlotOut );
|
|
}
|
|
return FALSE;
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
// 돈 드랍
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
BOOL DropFormulaCore::DropMoneyFunc( FLOAT fBonusPercent, LEVELTYPE LVAverage, eDROP_TYPE DropType, eNPC_GRADE MonsterGrade, LEVELTYPE MonsterDisplayLV,
|
|
MONEY & OUT rDropMoney )
|
|
{
|
|
// 추가 배율
|
|
FLOAT PlusScriptPercent = m_fPlusScriptPercent;
|
|
FLOAT PlusBonusPercent = 1.0f;
|
|
FLOAT PlusGradePercent = 1.0f;
|
|
|
|
// 등급에 따른 가중치
|
|
switch(MonsterGrade)
|
|
{
|
|
case eNPC_GENERAL: PlusGradePercent = 1.0f; break;
|
|
case eNPC_LEADER: PlusGradePercent = 1.1f; break;
|
|
case eNPC_ELITE: PlusGradePercent = 1.3f; break;
|
|
case eNPC_MIDDLEBOSS: PlusGradePercent = 1.5f; break;
|
|
case eNPC_BOSS: PlusGradePercent = 2.0f; break;
|
|
default: { /*SASSERT( NULL, "잘못된 몬스터 등급입니다." );*/ return FALSE; }
|
|
}
|
|
|
|
// 돈 액수 계산
|
|
MONEY SeedMoney = (MONEY)(MonsterDisplayLV*MonsterDisplayLV*6/LVAverage*PlusGradePercent*PlusBonusPercent*PlusScriptPercent);
|
|
MONEY Seed = SeedMoney/4;
|
|
MONEY MinSeed = SeedMoney - Seed;
|
|
if(MinSeed == 0) return FALSE;
|
|
MONEY MaxSeed = SeedMoney + Seed;
|
|
MONEY RealMoney = (MONEY)dRandom( MinSeed, MaxSeed );
|
|
if(RealMoney == 0) return FALSE;
|
|
|
|
// 씨드 배수에 따른 DROP
|
|
WORD SeedMultiple = 0;
|
|
switch(DropType)
|
|
{
|
|
case DROP_MONEY_1: SeedMultiple = random(1,3); break;
|
|
case DROP_MONEY_40: SeedMultiple = random(40,60); break;
|
|
case DROP_MONEY_400: SeedMultiple = random(400,600); break;
|
|
default:
|
|
{
|
|
// SUNLOG( eFULL_LOG, "[DropFormulaCore::DropMoneyFunc] 잘못된 DROPTYPE 이 넘어왔다!" );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
RealMoney *= SeedMultiple;
|
|
rDropMoney = RealMoney;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
// 기본 몬스터 아이템 드랍
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
BOOL DropFormulaCore::DropItemFunc( eDROP_TYPE DropType, LEVELTYPE MonsterDisplayLV, SCItemSlot & OUT rDropItemSlot )
|
|
{
|
|
// -5 <= LVInterval <= 5
|
|
// DROP_ITEM_0 ~ DROP_ITEM_11 : 안좋은 아이템 ~ 좋은 아이템
|
|
INT LVInterval = DropType - DROP_ITEM_0 - 5;
|
|
INT DropItemLV = MonsterDisplayLV + LVInterval;
|
|
|
|
// 떨어 뜨리지 않는다.
|
|
if( DropItemLV <= 0 ) return FALSE;
|
|
|
|
if( DropItemLV >= MAX_LEVEL )
|
|
{
|
|
//SUNLOG( eFULL_LOG, "[DropFormulaCore::DropItemFunc] MAX Drop Level을 넘어섰다." );
|
|
return FALSE;
|
|
}
|
|
|
|
DropItemInfo * rDropItem = m_pItemDropRatio->PopRandomDropItemForLevel( (LEVELTYPE)DropItemLV );
|
|
if( !rDropItem ) return FALSE;
|
|
|
|
rDropItemSlot.Clear();
|
|
rDropItemSlot.SetCode( rDropItem->GetCode() );
|
|
rDropItemSlot.SetEnchant( rDropItem->GetEnchant() );
|
|
rDropItemSlot.SetRank( rDropItem->GetRank() );
|
|
rDropItemSlot.SetSet( rDropItem->GetSet() );
|
|
// TEMP : 내구도 임시!!!!!
|
|
if( rDropItemSlot.IsOverlap() )
|
|
rDropItemSlot.SetDura(1);
|
|
else
|
|
rDropItemSlot.SetDura(0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
// 레어 아이템 드랍
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
BOOL DropFormulaCore::DropRareItemFunc( DWORD PlayerNum, eNPC_GRADE MonsterGrade, LEVELTYPE MonsterDisplayLV, SCItemSlot & OUT rDropItemSlot )
|
|
{
|
|
ASSERT( MonsterDisplayLV > 0 );
|
|
ASSERT( PlayerNum <= MAX_PARTYMEMBER_NUM );
|
|
// 레벨별 구간 선택
|
|
INT FromPercent = 0;
|
|
INT ToPercent = 0;
|
|
LEVELTYPE LVStep = 0;
|
|
for( LEVELTYPE i = 0 ; i < MAX_LEVEL_STEP_NUM ; ++i )
|
|
{
|
|
FromPercent = ToPercent;
|
|
ToPercent += m_Section[i];
|
|
if(FromPercent <= MonsterDisplayLV && MonsterDisplayLV < ToPercent)
|
|
{
|
|
LVStep = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 구간안에서 확률 선택
|
|
INT Index = m_RareItemDropRatioSelecter[LVStep][MonsterGrade][PlayerNum].RandomizedKey();
|
|
RAREITEM_DROP_INFO * pInfo = m_RareItemDropParser.GetRareItemDropInfo( LVStep, MonsterGrade, Index );
|
|
if( !pInfo ) return FALSE;
|
|
DEBUG_CODE( if(Index==0) ASSERT( pInfo->m_bPrior == FALSE ); );
|
|
|
|
rDropItemSlot.Clear();
|
|
rDropItemSlot.SetCode( pInfo->m_ItemCode );
|
|
if( rDropItemSlot.IsOverlap() )
|
|
rDropItemSlot.SetDura(1);
|
|
else
|
|
rDropItemSlot.SetDura(0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
// 상위 몬스터 아이템 드랍
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
BOOL DropFormulaCore::DropHigherMonsterItemFunc( INT MaxArrayNum, WORD * pDropItemRate, WORD * pDropItemCode, SCItemSlot & OUT rDropItemSlot )
|
|
{
|
|
if( MaxArrayNum <= 0) return FALSE;
|
|
if( !pDropItemRate || !pDropItemCode ) return FALSE;
|
|
ASSERT( !IsBadReadPtr( pDropItemRate, sizeof(WORD)*MaxArrayNum ) );
|
|
ASSERT( !IsBadReadPtr( pDropItemCode, sizeof(WORD)*MaxArrayNum ) );
|
|
|
|
BOOL bDrop = FALSE;
|
|
|
|
INT FromPercent = 0;
|
|
INT ToPercent = 0;
|
|
INT seed = random( 0, MAX_HIGHER_MONSTER_ITEM_DROP_UNIT );
|
|
|
|
for( INT i = 0 ; i < MaxArrayNum ; ++i )
|
|
{
|
|
FromPercent = ToPercent;
|
|
ToPercent += pDropItemRate[i];
|
|
if(FromPercent <= seed && seed < ToPercent)
|
|
{
|
|
bDrop = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( bDrop )
|
|
{
|
|
rDropItemSlot.Clear();
|
|
rDropItemSlot.SetCode( pDropItemCode[i] );
|
|
if( rDropItemSlot.IsOverlap() )
|
|
rDropItemSlot.SetDura(1);
|
|
else
|
|
rDropItemSlot.SetDura(0);
|
|
}
|
|
|
|
return bDrop;
|
|
}
|