Files
2022-10-26 12:25:11 +08:00

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;
}