Files
Sun1602/Server/Common/DropRatioInfoList.cpp
git 9cb257e7ae Add GameClients drops and keep current 1602 source work.
CN1602 is the local client. KR is the official tree with unpacked Data, System, and Sound. Packed .wpk files stay off git.
2026-08-30 23:24:31 +03:00

479 lines
18 KiB
C++

#include "stdafx.h"
#include "./DropRatioInfoList.h"
#include <ItemInfoParser.h>
#include <LimitedItemInfoParser.h>
//==================================================================================================
DropRatioInfoList* DropRatioInfoList::drop_ratio_info_list_static_ = NULL;
DropRatioInfoList* DropRatioInfoList::CreateInstance()
{
// (NOTE) thread-unsafe singleton
drop_ratio_info_list_static_ = new DropRatioInfoList;
return drop_ratio_info_list_static_;
}
void DropRatioInfoList::DestroyInstance()
{
SAFE_DELETE(drop_ratio_info_list_static_);
}
COMPILE_ASSERTION_CHECK_METHOD_IMPL()
{
DropItemObj item_obj;
DropMoneyObj money_obj;
const size_t kInterMaxSharedDropObjectSize = max(sizeof(item_obj), sizeof(money_obj));
BOOST_STATIC_ASSERT(sizeof(item_obj) == sizeof(money_obj) &&
(kInterMaxSharedDropObjectSize ==
DropRatioInfoList::kMaxSharedDropObjectSize));
}
COMPILE_ASSERTION_CHECK_METHOD_END();
//==================================================================================================
DropRatioInfoList::DropRatioInfoList(void)
: randomizer_array_(NULL),
drop_object_free_chunk_(NULL)
{
util::LList::Init(&drop_object_alloc_root_);
}
DropRatioInfoList::~DropRatioInfoList(void)
{
Unload();
}
void
DropRatioInfoList::Release()
{
Unload();
}
void
DropRatioInfoList::Reload()
{
}
BOOL
DropRatioInfoList::LoadScript(eSCRIPT_CODE script_code, BOOL reloaded)
{
switch(script_code)
{
case SCRIPT_DROPRATIOINFO:
return _Load(reloaded);
}
return false;
}
void
DropRatioInfoList::Unload()
{
if (randomizer_array_ == NULL) {
return;
}
SAFE_DELETE(drop_object_free_chunk_);
while (util::LList::IsEmpty(&drop_object_alloc_root_) == false)
{
DropObjPoolChunk* it = drop_object_alloc_root_.next;
util::LList::Delete(it);
delete it;
};
::free(randomizer_array_);
randomizer_array_ = NULL;
random_drop_type_selector_.clear();
}
// (f100612.3L) use only in loading
DropObj* DropRatioInfoList::AllocDropObject(eDROP_OBJ_TYPES drop_obj_type)
{
if (drop_object_free_chunk_ == NULL) {
drop_object_free_chunk_ = new DropObjPoolChunk;
}
if (drop_object_free_chunk_->number_of_allocations_ >=
_countof(drop_object_free_chunk_->array_))
{
util::LList::AddPrev(drop_object_free_chunk_, &drop_object_alloc_root_);
drop_object_free_chunk_ = new DropObjPoolChunk;
}
//
DropObjPoolChunk::node_type* const node = \
&drop_object_free_chunk_->array_[drop_object_free_chunk_->number_of_allocations_];
++drop_object_free_chunk_->number_of_allocations_;
if (drop_obj_type == DROP_OBJ_ITEM)
{
return new (node) DropItemObj;
}
else if (drop_obj_type == DROP_OBJ_MONEY)
{
return new (node) DropMoneyObj;
}
ASSERT(!"|request invalid drop object type|");
return NULL;
}
// (f100612.3L)
bool DropRatioInfoList::_BuildReference(int added_number_of_nodes)
{
if (added_number_of_nodes <= 0) {
return false;
}
if (randomizer_array_) {
::free(randomizer_array_);
}
const size_t randomizer_array_size = sizeof(randomizer_array_[0]) * added_number_of_nodes;
randomizer_array_ = reinterpret_cast<RANDOMIZER*>(::malloc(randomizer_array_size));
ZeroMemory(randomizer_array_, randomizer_array_size);
;{
RANDOMIZER* it = randomizer_array_;
RANDOMIZER* const end = randomizer_array_ + added_number_of_nodes;
for (; it < end; ++it) {
new (it) RANDOMIZER;
}
};
return true;
}
BOOL
DropRatioInfoList::_Load(BOOL reloaded)
{
__UNUSED(reloaded);
//char description_for_debug[512];
static int index_for_debug = 0;
static int last_index_for_debug = 0;
//
BOOST_STATIC_ASSERT(kNumberOfMoneyColumns == 5);
static const char* kMoneyColumns[kNumberOfMoneyColumns] = {
"Money1", "Money2", "Money3", "Money4", "Money5"
};
BOOST_STATIC_ASSERT(kNumberOfItemProbabilityColumns == 30);
static const char* kGroupColumns[kNumberOfItemProbabilityColumns] = {
"bG1", "bG2", "bG3", "bG4", "bG5", "bG6", "bG7", "bG8", "bG9", "bG10",
"bG11", "bG12", "bG13", "bG14", "bG15", "bG16", "bG17", "bG18", "bG19", "bG20",
"bG21", "bG22", "bG23", "bG24", "bG25", "bG26", "bG27", "bG28", "bG29", "bG30",
};
static const char* kItemCodeColumns[kNumberOfItemProbabilityColumns] = {
"IC1", "IC2", "IC3", "IC4", "IC5", "IC6", "IC7", "IC8", "IC9", "IC10",
"IC11", "IC12", "IC13", "IC14", "IC15", "IC16", "IC17", "IC18", "IC19", "IC20",
"IC21", "IC22", "IC23", "IC24", "IC25", "IC26", "IC27", "IC28", "IC29", "IC30",
};
static const char* kLimitedIndexColumns[kNumberOfItemProbabilityColumns] = {
"LM1", "LM2", "LM3", "LM4", "LM5", "LM6", "LM7", "LM8", "LM9", "LM10",
"LM11", "LM12", "LM13", "LM14", "LM15", "LM16", "LM17", "LM18", "LM19", "LM20",
"LM21", "LM22", "LM23", "LM24", "LM25", "LM26", "LM27", "LM28", "LM29", "LM30",
};
static const char* kProbabilityColumns[kNumberOfItemProbabilityColumns] = {
"IP1", "IP2", "IP3", "IP4", "IP5", "IP6", "IP7", "IP8", "IP9", "IP10",
"IP11", "IP12", "IP13", "IP14", "IP15", "IP16", "IP17", "IP18", "IP19", "IP20",
"IP21", "IP22", "IP23", "IP24", "IP25", "IP26", "IP27", "IP28", "IP29", "IP30",
};
static const char* kReservedColumns[kNumberOfItemProbabilityColumns] = {
"TV1", "TV2", "TV3", "TV4", "TV5", "TV6", "TV7", "TV8", "TV9", "TV10",
"TV11", "TV12", "TV13", "TV14", "TV15", "TV16", "TV17", "TV18", "TV19", "TV20",
"TV21", "TV22", "TV23", "TV24", "TV25", "TV26", "TV27", "TV28", "TV29", "TV30",
};
//
ItemInfoParser* const item_parser = ItemInfoParser::Instance();
LimitedItemInfoParser* const limited_parser = LimitedItemInfoParser::Instance();
//
const int max_rows = GetRowSize();
if (_BuildReference(max_rows) == false) {
return false;
}
RANDOMIZER* randomizer_it = randomizer_array_;
//
for (int row = 0; row < max_rows; ++row)
{
const int drop_index = GetDataInt("Index", row);
index_for_debug = drop_index;
//strncpy(description_for_debug, GetDataString("Description", row), 512);
const int standard_value = GetDataInt("P_Amount", row);
if (standard_value <= 0)
{
SUNLOG(eCRITICAL_LOG, _T("|[%s]|Index=%d|Msg=invalid standard value(%d)|"),
__FUNCTION__, drop_index, standard_value);
continue;
}
const bool desired_unique_drop_index_check_passed = \
random_drop_type_selector_.find(drop_index) == random_drop_type_selector_.end();
if (!FlowControl::FCAssert(desired_unique_drop_index_check_passed))
{
SUNLOG(eCRITICAL_LOG, _T("|[%s]|Index=%d|Msg=duplicated drop index|"),
__FUNCTION__, drop_index);
continue;
}
//
RANDOMIZER* const randomizer = randomizer_it++;
random_drop_type_selector_[drop_index] = randomizer;
const int min_money_seed = GetDataInt("DropMoney_Min", row);
const int max_money_seed = GetDataInt("DropMoney_Max", row);
// 돈 확률 처리
BOOST_STATIC_ASSERT(kNumberOfMoneyColumns == 5);
for (int i = 0; i < kNumberOfMoneyColumns; ++i)
{
const int money_ratio = GetDataInt(kMoneyColumns[i], row);
if (money_ratio == 0) {
continue;
}
DropMoneyObj* const drop_money_obj = \
static_cast<DropMoneyObj*>(this->AllocDropObject(DROP_OBJ_MONEY));
//drop_list_hash_[drop_index].push_back(drop_money_obj);
//
DropObj::DropMoneyInfo* const drop_money_info = drop_money_obj->GetInfo();
drop_money_info->min_money_seed = min_money_seed;
drop_money_info->max_money_seed = max_money_seed;
switch (i + 1)
{
case 1:
drop_money_info->min_multiple = 1;
drop_money_info->max_multiple = 1;
break;
case 2:
drop_money_info->min_multiple = 450;
drop_money_info->max_multiple = 550;
break;
case 3:
drop_money_info->min_multiple = 4500;
drop_money_info->max_multiple = 5500;
break;
case 4:
drop_money_info->min_multiple = 100000;
drop_money_info->max_multiple = 200000;
break;
case 5:
drop_money_info->min_multiple = 1000000;
drop_money_info->max_multiple = 2000000;
break;
}
const bool desired_randomizer_add_ratio_success = \
randomizer->AddRatio(drop_money_obj, money_ratio, standard_value) != false;
if (!FlowControl::FCAssert(desired_randomizer_add_ratio_success))
{
SUNLOG(eCRITICAL_LOG,
_T("|[%s]|Index=%d|Msg=invalid money drop ratio|Action=passed|"),
__FUNCTION__, drop_index);
}
}
BOOST_STATIC_ASSERT(kNumberOfItemProbabilityColumns == 30);
// referenced column names
//kGroupColumns[kNumberOfItemProbabilityColumns];
//kItemCodeColumns[kNumberOfItemProbabilityColumns];
//kLimitedIndexColumns[kNumberOfItemProbabilityColumns];
//kProbabilityColumns[kNumberOfItemProbabilityColumns];
//kReservedColumns[kNumberOfItemProbabilityColumns];
// 아이템 확률 처리
for (int i = 0; i < kNumberOfItemProbabilityColumns; ++i)
{
const DWORD item_code = GetDataInt(kItemCodeColumns[i], row);
if (item_code == 0) {
continue;
}
const DWORD probability_ratio = GetDataDWORD(kProbabilityColumns[i], row);
if (probability_ratio == 0) {
continue;
}
BYTE group = GetDataBYTE(kGroupColumns[i], row);
const WORD limited_item_index = GetDataWORD(kLimitedIndexColumns[i], row);
if (limited_item_index != 0)
{
const sLIMITED_ITEM_INFO* limited_item_info = \
limited_parser->GetLimitedItemInfo(limited_item_index);
if (limited_item_info == NULL)
{
SUNLOG(eCRITICAL_LOG,
_T("|[%s]|Index=%d|Msg=item limit index not found for '%s' (%d)|"),
__FUNCTION__, drop_index, kLimitedIndexColumns[i], limited_item_index);
continue;
}
}
//--------------------------------------------------------------------
// control flow diagram
//
// group | item | Condition
// 0 | NULL | FAIL
// 0 | !NULL | IsOverlap | Reserved
// false | use 'number'
// true | ItemTypeIndex in ItemTypeList.txt
// 1 | X | next drop index
//--------------------------------------------------------------------
// changed logic to support _NA_0_20110318_ITEM_EXPIRATION_PERIOD
switch (group)
{
case 0: group = DROP_GROUP::LINK_ITEM;
break;
case 1: group = DROP_GROUP::LINK_DROP;
break;
case 2: group = DROP_GROUP::LINK_ITEM | DROP_GROUP::LIMIT_TIME;
break;
case 3: group = DROP_GROUP::LINK_ITEM | DROP_GROUP::LIMIT_DATE;
break;
case 4: group = DROP_GROUP::LINK_ITEM
| DROP_GROUP::LIMIT_DISTRIBUTE //_NA002479_20110401_OVERLAPPING_ITEM_DISTRIBUTION_CHANGES
;
break;
default:
SUNLOG(eCRITICAL_LOG, _T("Index[%d] bG value invalid![%d][must be 0~4]"),
drop_index, group);
continue;
}
const BASE_ITEMINFO* base_item_info = NULL;
DWORD item_reserved = 0;
if ((group & DROP_GROUP::LINK_ITEM) == DROP_GROUP::LINK_ITEM)
{
item_reserved = GetDataDWORD(kReservedColumns[i], row);
base_item_info = item_parser->GetItemInfo(item_code);
if (base_item_info == NULL)
{
#if !defined(_JAPAN)
SUNLOG(eCRITICAL_LOG,
_T("|[%s]|Index=%d|Msg=item '%s' (%d) not found in item script|"),
__FUNCTION__, drop_index, kItemCodeColumns[i], item_code);
#endif
continue;
}
const DURATYPE duplicable_number = base_item_info->m_byDupNum;
if (duplicable_number > 1) // overlapped item
{
// use 'number' by item_reserved
if (item_reserved == 0 ||
((group & DROP_GROUP::LIMIT_DISTRIBUTE) == 0 &&
item_reserved > duplicable_number))
{
SUNLOG(eCRITICAL_LOG,
_T("|[%s]|Index=%d|Msg='%s' value (%d) conflicts with item(%d) m_byDupNum(%d)|Action=modified|"),
__FUNCTION__, drop_index,
kReservedColumns[i],item_reserved,
item_code,duplicable_number);
// modified by an item script information
item_reserved = duplicable_number;
}
}
else
{ // assert(duplicable_number == 1)
// use ItemTypeIndex in ItemTypeList.txt
}
}
//
DropItemObj* const drop_item_obj = \
static_cast<DropItemObj*>(this->AllocDropObject(DROP_OBJ_ITEM));
//drop_list_hash_[drop_index].push_back(drop_item_obj);
DropObj::DropItemInfo* const drop_item_info = drop_item_obj->GetInfo();
//declared by _NA_1419_20100121_ACCUMULATE_POINT
drop_item_info->drop_item_order = static_cast<BYTE>(i);
drop_item_info->group_code = group;
drop_item_info->item_code = item_code;
drop_item_info->limited_item_index = limited_item_index;
drop_item_info->probability_ratio = probability_ratio;
drop_item_info->reserved = item_reserved;
const bool desired_randomizer_add_ratio_success = \
randomizer->AddRatio(drop_item_obj, probability_ratio, standard_value) != false;
if (desired_randomizer_add_ratio_success == false)
{
SUNLOG(eCRITICAL_LOG,
_T("|[%s]|Index=%d|Msg=invalid item drop ratio, ")
_T("'%s' rate (%d) vs standard (%d)|Action=passed|"),
__FUNCTION__, drop_index,
kProbabilityColumns[i],probability_ratio, standard_value);
}
}
last_index_for_debug = drop_index;
}
return true;
}
// (CHANGES) (WAVERIX) (091127) move from header to code file, changes codes for debugging factility
DropObj*
DropRatioInfoList::PopRandomItemTypeIndex(DWORD first_drop_index)
{
const int MaxDepth = 6;
// backup for debugging facility
DWORD drop_index = first_drop_index;
int depth = 0;
DropObj* drop_object_array[MaxDepth] = { 0, };
do
{
RANDOMIZER_HASH::const_iterator it = random_drop_type_selector_.find(drop_index);
if (it == random_drop_type_selector_.end()) {
return NULL;
}
RANDOMIZER* const randomizer = it->second;
DropObj* drop_object = drop_object_array[depth] = randomizer->RandomizedKey();
if (drop_object == NULL) {
return NULL;
}
if (drop_object->kDropObjType == DROP_OBJ_ITEM) {
DropItemObj* drop_item_obj = static_cast<DropItemObj*>(drop_object);
// if group_code == 0 then drop item code
// else then drop index (need recursively call)
if (DROP_GROUP::LINK_ITEM & drop_item_obj->GetGroupCode())
{
return drop_item_obj;
}
else
{
drop_index = drop_item_obj->GetItemCode();
}
}
else {
return drop_object;
}
++depth;
}
while (depth < MaxDepth);
SUNLOG(eCRITICAL_LOG, "|WARNING|Msg=too many loop iterations!|DropIndex=%d|", first_drop_index);
return NULL;
}
UINT DropRatioInfoList::PopDropItemCodeArray(DWORD drop_index, SLOTCODE* OUT item_code_array, UINT item_code_array_count)
{
if (random_drop_type_selector_.empty()) {
return 0;
}
RANDOMIZER_HASH::const_iterator it_find = random_drop_type_selector_.find(drop_index);
if (it_find == random_drop_type_selector_.end()) {
return 0;
}
uint32_t result_of_count = 0;
const RANDOMIZER* randomizer = it_find->second;
const RANDOMIZER::KeyTypeArray& drop_obj_array = randomizer->GetKeyTypeArray();
const RANDOMIZER::key_type* it = &drop_obj_array[0];
const RANDOMIZER::key_type* const end = &drop_obj_array[_countof(drop_obj_array)];
for (; it != end; ++it)
{
const DropObj* drop_obj = *it;
if (drop_obj == NULL) {
continue;
}
if (result_of_count >= item_code_array_count) {
break;
}
if (drop_obj->kDropObjType == DROP_OBJ_ITEM)
{
const DropItemObj* drop_item_obj = static_cast<const DropItemObj*>(drop_obj);
DWORD item_code = drop_item_obj->GetItemCode();
assert(SAFE_NUMERIC_TYPECAST(DWORD, item_code, SLOTCODE));
item_code_array[result_of_count] = static_cast<SLOTCODE>(item_code);
++result_of_count;
}
}
return result_of_count;
}