675 lines
27 KiB
C++
675 lines
27 KiB
C++
#include "stdafx.h"
|
|
#include "./ItemManager.h"
|
|
|
|
#include "ItemTypeList.h"
|
|
#include "ItemCrystalizeListParser.h"
|
|
|
|
#include "InventorySlotContainer.h"
|
|
#include "SlotManager.h"
|
|
|
|
#include "GameZone.h"
|
|
|
|
#include "RewardManager.h"
|
|
#include "AchievementManager.h"
|
|
|
|
#include "ChaoState.h"
|
|
|
|
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
#include "SCItemSlotContainer.h"
|
|
#include "SCItemSlot.h"
|
|
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
|
|
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
|
|
#include "NotificationInfoParser.h"
|
|
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// @history
|
|
// 09/06/25|~~~
|
|
// 09/07/16|shogen|enchant facility uniformity|<- 적용하긴 하는 걸까?
|
|
// 09/10/22|namka199|rank facility improvement|(WARNING) 인첸트 일원화 작업이 일부 누락된 듯.
|
|
// 10/01/28|waverix|code arrangement
|
|
// |delete macros '__NA_676_PK_SYSTEM_IMPROVEMENT'
|
|
// | '__NA_977_PREVENTION_PARTY_RETURN_ABUSE'
|
|
// | '__NA_1339_ENCHANT_RENEWAL_EX'
|
|
// | '__NA_1168_ADD_CONTENTS_ADD_LOG'
|
|
// | '__BUG_35162_COMPOSE_BUG_BY_FULL_IVEN'
|
|
// | '__CN_1194__ELITE_1_5_ITEM'
|
|
// | '__MOD_CRYSTALIZE_MAX_CREATE_ITEM_NUM'
|
|
// 10/02/23|hukim|remove warnings level 4... etc...
|
|
// |(waverix: i think this changes have fragmentary knowledge)
|
|
// 10/02/24|waverix|rollback to revision 46727|
|
|
// |현웅씨, 다시 한 번 재검토 해보시구랴. 물론 경고를 무시하는 것은 나쁜 거지만,
|
|
// warning level 4라는 녀석의 함정에 빠져 무리한 변경을 수행한 걸로 생각됩니다.
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
|
//==================================================================================================
|
|
//==================================================================================================
|
|
//==================================================================================================
|
|
|
|
void ItemManager::SendItemChange(SCItemSlot& target_slot)
|
|
{
|
|
MSG_CG_ITEM_CHANGE_ITEM_INFO_CMD cmdMsg;
|
|
cmdMsg.m_SlotIndex = SI_INVENTORY;
|
|
cmdMsg.m_SlotPos = target_slot.GetPos();
|
|
target_slot.CopyOut(cmdMsg.m_ItemStream);
|
|
player_->SendPacket(&cmdMsg, sizeof(cmdMsg));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
RC::eITEM_RESULT
|
|
ItemManager::Compose(SLOTCODE compose_list_code, BYTE making_num,
|
|
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
INVENTORY_TOTAL_INFO* OUT inven_total_info, DURATYPE& success_num_out, DURATYPE& byPreventNum)
|
|
#else // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
INVENTORY_TOTAL_INFO* OUT inven_total_info, BYTE& success_num_out)
|
|
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
{
|
|
if (IsRestrictFunction(eFUNCTIONALRESTRICT_COMPOSE)) {
|
|
return RC::RC_ITEM_UNUSABLE_FUNCTION;
|
|
}
|
|
if (player_->GetChaoState().CanUseFuction(CHAO_USE_COMPOSE) == false) {
|
|
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CHAOSTATE;
|
|
}
|
|
if (player_->GetBehave() == PLAYER_BEHAVE_UNEXPECTED_WAITING) {
|
|
return RC::RC_ITEM_INVALIDSTATEOFPLAYER;
|
|
}
|
|
|
|
if (ValidState() == false) {
|
|
return RC::RC_ITEM_INVALIDSTATE;
|
|
}
|
|
if (0 == making_num) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
|
|
ItemComposeListParser* compose_list_parser = ItemComposeListParser::Instance();
|
|
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
const sITEM_COMPOSE_LIST* compose_list_from_parser = \
|
|
compose_list_parser->GetComposeListInfo(compose_list_code);
|
|
if (compose_list_from_parser == NULL) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
sITEM_COMPOSE_LIST temp_compose_list = *compose_list_from_parser;
|
|
sITEM_COMPOSE_LIST* compose_list = &temp_compose_list;
|
|
//제작 비용 감소 효과 적용
|
|
compose_list->m_Money = \
|
|
player_->GetAttr().GetValueAppliedAttr(compose_list_from_parser->m_Money, eATTR_CRAFT_COST_RATIO);
|
|
#else // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
const sITEM_COMPOSE_LIST* compose_list = \
|
|
compose_list_parser->GetComposeListInfo(compose_list_code);
|
|
if (compose_list == NULL) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
// 제한 클래스 여부
|
|
// if (0 != pListInfo->m_LimitCharClass && pListInfo->m_LimitCharClass == player_->GetCharType())
|
|
// return RC::RC_ITEM_COMPOSE_LIMIT_CLASS;
|
|
|
|
switch (compose_list->m_ItemType)
|
|
{
|
|
case eITEMTYPE_RING:
|
|
case eITEMTYPE_NECKLACE:
|
|
if (player_->GetLevel() < LIMIT_LEVEL_ACCESSORY)
|
|
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CURR_LEVEL;
|
|
break;
|
|
// 클래스별 특수 악세서리로 변경
|
|
case eITEMTYPE_BERSERKER_SACCESSORY:
|
|
case eITEMTYPE_DRAGON_SACCESSORY:
|
|
case eITEMTYPE_VALKYRIE_SACCESSORY:
|
|
case eITEMTYPE_SHADOW_SACCESSORY:
|
|
case eITEMTYPE_ELEMENTALIST_SACCESSORY:
|
|
case eITEMTYPE_MYSTIC_SPECIAL_ACCESSORY1: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
|
|
case eITEMTYPE_HELLROID_SPECIAL_ACCESSORY1: // _NA_000000_20130812_NEW_CHARACTER_HELLROID
|
|
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
|
|
case eITEMTYPE_WITCHBLADE_SPECIAL_ACCESSORY1:
|
|
#endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
|
|
case eITEMTYPE_ALLCLASS_CHAOSEYE: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
|
|
case eITEMTYPE_ELEMENTALIST_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
|
|
case eITEMTYPE_BERSERKER_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
|
|
case eITEMTYPE_DRAGON_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
|
|
case eITEMTYPE_VALKYRIE_SHADOW_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
|
|
case eITEMTYPE_MYSTIC_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
|
|
case eITEMTYPE_HELLROID_WITCHBLADE_KALVUS_ACCESSORY: //_NA_007827_20141117_ADD_ACCESSORY_TYPE
|
|
if (player_->GetLevel() < LIMIT_LEVEL_SACCESSORY)
|
|
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CURR_LEVEL;
|
|
break;
|
|
// (WARNING) it is has not default logic... thinking... miss?
|
|
}
|
|
|
|
// 돈 체크
|
|
if (player_->GetMoney() < compose_list->m_Money * making_num) {
|
|
return RC::RC_ITEM_HAVENOTMONEY;
|
|
}
|
|
|
|
GameZone* game_zone = player_->GetGameZonePtr();
|
|
if (game_zone == NULL) {
|
|
return RC::RC_ITEM_COMPOSE_INVALID_LOCATION;
|
|
}
|
|
|
|
// 맵 체크
|
|
{
|
|
const MAPCODE current_map_code = game_zone->GetMapCode();
|
|
int index = 0;
|
|
for ( ; index < _countof(compose_list->m_MapCode); ++index)
|
|
{
|
|
MAPCODE map_code = compose_list->m_MapCode[index];
|
|
if (map_code != 0 && map_code == current_map_code) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index == _countof(compose_list->m_MapCode)) {
|
|
return RC::RC_ITEM_COMPOSE_INVALID_LOCATION;
|
|
}
|
|
};
|
|
|
|
// 재료 체크
|
|
const sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE* materials = compose_list->m_pMaterial;
|
|
for (POSTYPE i = 0; i < compose_list->m_byMatCount; ++i)
|
|
{
|
|
const sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE& material = materials[i];
|
|
if (0 == material.m_ItemCode || 0 == material.m_byItemNum) {
|
|
continue;
|
|
}
|
|
ns_functor::ComposeMaterialItemCheck empty_check(\
|
|
material.m_ItemCode, material.m_ItemTypeIndex,
|
|
material.m_byItemNum * making_num);
|
|
if (ForeachSlot(SI_INVENTORY, &empty_check) == false) {
|
|
return RC::RC_ITEM_ENCHANT_HAVENOTMETERIALS;
|
|
}
|
|
}
|
|
|
|
RC::eITEM_RESULT compose_result = RC::RC_ITEM_COMPOSE_SUCCESS;
|
|
|
|
//조합 요청 갯수만큼 루풍~
|
|
success_num_out = 0;
|
|
for (BYTE loop = making_num; loop; --loop)
|
|
{ //조합
|
|
#ifdef _NA_000000_20130612_RANDOMIZER_CHANGE
|
|
RandomManager* const random_manager = player_->GetRandomManager();
|
|
int random_result = random_manager->randomizer_compose_.Rand();
|
|
int success_ratio = player_->GetAttr().GetCompositeIncRatio();
|
|
; success_ratio += compose_list->m_byCreateRatio;
|
|
if (random_result <= success_ratio*10) {
|
|
++success_num_out;
|
|
}
|
|
#else
|
|
int ratio = random(1, 100);
|
|
// CHANGES: f110125.3L, rollback from sun:r51762 because this attribute is a ratio type.
|
|
// the solving methodology is to modify script data not access a ratio section.
|
|
int success_ratio = player_->GetAttr().GetCompositeIncRatio();
|
|
; success_ratio += compose_list->m_byCreateRatio;
|
|
// 결과물 아이템 습득
|
|
if (ratio <= success_ratio) {
|
|
++success_num_out;
|
|
}
|
|
#endif //_NA_000000_20130612_RANDOMIZER_CHANGE
|
|
}
|
|
|
|
if (success_num_out != 0)
|
|
{
|
|
// 성공
|
|
if (compose_list->m_byResultType == compose_list->RESULTTYPE_ITEMCODE)
|
|
{
|
|
// 결과물 아이템 습득
|
|
// (CHANGES) (100129) (WAVERIX) fix up invalid result, if not success status
|
|
// (WARNING) occurred large block code renewal
|
|
RC::eITEM_RESULT obtain_result = RC::RC_ITEM_INVALID_VALUE;
|
|
if (compose_list->m_Result.m_ItemTypeIndex == 0)
|
|
{
|
|
obtain_result = Obtain(compose_list->m_Result.m_ItemCode,
|
|
compose_list->m_Result.m_byItemNum * success_num_out,
|
|
inven_total_info);
|
|
}
|
|
else
|
|
{
|
|
ItemTypeList* const item_type_list = ItemTypeList::Instance();
|
|
ItemType* item_type = \
|
|
item_type_list->FindItemType(compose_list->m_Result.m_ItemTypeIndex);
|
|
if (item_type == NULL)
|
|
{
|
|
SUNLOG(eCRITICAL_LOG, "["__FUNCTION__"]|斤口=can't find index|value=%d",
|
|
compose_list->m_Result.m_ItemTypeIndex);
|
|
obtain_result = RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
else
|
|
{
|
|
BYTE enchant = item_type->GetEnchant();
|
|
// (CHANGES) (f100525.1L)
|
|
BYTE item_type_value = item_type->GetItemType();
|
|
BYTE rank = item_type->GetRank();
|
|
obtain_result = ObtainAllKindOfItem(1,
|
|
&compose_list->m_Result.m_ItemCode, &success_num_out,
|
|
&enchant, &item_type_value, &rank, inven_total_info);
|
|
}
|
|
}
|
|
//
|
|
if (obtain_result != RC::RC_ITEM_SUCCESS) {
|
|
return obtain_result;
|
|
}
|
|
}
|
|
else if (compose_list->m_byResultType == compose_list->RESULTTYPE_REWARDCODE)
|
|
{
|
|
if (making_num > 1) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
|
|
RC::eREWARD_RESULT reward_result;
|
|
reward_result = g_RewardManager.RewardItem(RewardManager::eREWARD_COMPOSE, \
|
|
compose_list->m_Result.m_ItemCode, 0, player_, *inven_total_info);
|
|
|
|
if (reward_result != RC::RC_REWARD_SUCCESS) {
|
|
return RC::RC_ITEM_ISNOTEMPTYSLOT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return RC::RC_ITEM_FAILED;
|
|
}
|
|
|
|
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
|
|
if (NotificationInfoParser::Instance()->IsNotificationItem(
|
|
compose_list->m_Result.m_ItemCode, eNotificationCraft, 0, 0) == true)
|
|
{
|
|
MSG_DG_NOTIFICATION_ITEM_SYN msg;
|
|
msg.info.SetInfo(player_->GetCharName(),
|
|
(player_->GetGameZonePtr() != NULL) ? player_->GetGameZonePtr()->GetMapCode() : 0,
|
|
GetTickCount(), eNotificationCraft, compose_list->m_Result.m_ItemCode);
|
|
g_pGameServer->SendToSessionType(GAME_DBPROXY, &msg, sizeof(MSG_DG_NOTIFICATION_ITEM_SYN));
|
|
}
|
|
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
|
|
|
|
//(lst1024) 비정상 조합로그 수정
|
|
// (CHANGES) (100131) (WAVERIX) change pointer calculation that \
|
|
// slot position array is continuous sequence
|
|
POSTYPE total = 0;
|
|
#if SUN_CODE_BACKUP
|
|
SCSlotContainer* temp_inventory = GetItemSlotContainer(SI_TEMPINVENTORY);
|
|
#endif
|
|
SCSlotContainer* inventory = GetItemSlotContainer(SI_INVENTORY);
|
|
|
|
INVENTORY_TOTAL_INFO::SLOT_TYPE* slot = inven_total_info->m_Slot;
|
|
for (POSTYPE loop = inven_total_info->m_InvenCount; loop; --loop)
|
|
{
|
|
SCItemSlot& target_item = static_cast<SCItemSlot&>(inventory->GetSlot(slot->m_Pos));
|
|
#ifdef _NA_007257_20140527_GAMELOG_ITEM_COMPOSE_SUCCESS_COUNT
|
|
GAMELOG->LogCompose(true, player_, &target_item, 0, NULL, compose_list->m_Money, NULL, success_num_out);
|
|
#else
|
|
GAMELOG->LogCompose(true, player_, &target_item, 0, NULL, compose_list->m_Money);
|
|
#endif //_NA_007257_20140527_GAMELOG_ITEM_COMPOSE_SUCCESS_COUNT
|
|
++slot;
|
|
}
|
|
#if SUN_CODE_BACKUP
|
|
for (POSTYPE loop = inven_total_info->m_TmpInvenCount; loop; --loop)
|
|
{
|
|
SCItemSlot& target_item = static_cast<SCItemSlot&>(temp_inventory->GetSlot(slot->m_Pos));
|
|
GAMELOG->LogCompose(true, player_, &target_item, 0, NULL, compose_list->m_Money);
|
|
++slot;
|
|
}
|
|
#endif
|
|
// 성공 로그
|
|
}
|
|
|
|
//삭제되는 아이템 시리얼 담을려고...
|
|
DBWLDSERIAL item_serial_static[compose_list->MAX_COMPOSE_ITEM_NUM];
|
|
// (CHANGES) (WAVERIX) fix up clear stream based on invalid size
|
|
// old code: clear size = { sizeof(DWORD) * MAX_COMPOSE_ITEM_NUM }
|
|
ZeroMemory(item_serial_static, sizeof(item_serial_static));
|
|
|
|
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
// 제작 실패 시 재료 소멸 방지 어트리뷰트 적용
|
|
int prevent_delete_ratio = player_->GetAttr().GetCraftPreventExtinctionMaterialRatio();
|
|
int delete_num = making_num;
|
|
int prevent_num = 0;
|
|
if (prevent_delete_ratio > 0
|
|
&& (making_num - success_num_out) > 0)
|
|
{
|
|
for (int i = 0; i < making_num - success_num_out; ++i)
|
|
{
|
|
if (random_percent(prevent_delete_ratio))
|
|
{
|
|
++prevent_num;
|
|
}
|
|
}
|
|
delete_num -= prevent_num;
|
|
byPreventNum = prevent_num;
|
|
}
|
|
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
|
|
// 재료 없애기
|
|
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
MSG_CG_ITEM_LOSE_ACK delete_msg;
|
|
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
for (POSTYPE i = 0; i < compose_list->m_byMatCount; ++i)
|
|
{
|
|
const sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE& material = materials[i];
|
|
if (0 == material.m_ItemCode || 0 == material.m_byItemNum) {
|
|
continue;
|
|
}
|
|
|
|
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
ns_functor::DeleteComposeMaterialItem delete_operator(\
|
|
material.m_ItemCode, material.m_ItemTypeIndex,
|
|
material.m_byItemNum * delete_num);
|
|
#else
|
|
ns_functor::DeleteComposeMaterialItem delete_operator(\
|
|
material.m_ItemCode, material.m_ItemTypeIndex,
|
|
material.m_byItemNum * making_num);
|
|
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
|
|
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
BOOL delete_result = DeleteComposeMaterials(&delete_operator, &delete_msg.m_ItemInfo);
|
|
#else
|
|
BOOL delete_result = ForeachSlot(SI_INVENTORY, &delete_operator);
|
|
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
ASSERT(delete_result);
|
|
item_serial_static[i] = delete_operator.GetItemSerial();
|
|
}
|
|
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
player_->SendPacket( &delete_msg, sizeof(delete_msg) );
|
|
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
|
|
if (success_num_out != 0)
|
|
{
|
|
GAMELOG->LogCompose(true, player_, NULL,
|
|
compose_list->m_byMatCount,
|
|
const_cast<sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE*>(materials),
|
|
compose_list->m_Money,
|
|
item_serial_static, success_num_out);
|
|
}
|
|
|
|
// 실패 로그
|
|
// TODO(WAVERIX) (WARNING) 하기 실패 로그 뭐냥? item_serial_static의 연산 부분 문제있다.
|
|
assert(making_num >= success_num_out);
|
|
BYTE fail_num = making_num - success_num_out;
|
|
if (fail_num > 0) {
|
|
GAMELOG->LogCompose(false, player_, NULL,
|
|
compose_list->m_byMatCount,
|
|
const_cast<sITEM_COMPOSE_LIST::sITEM_FOR_COMPOSE*>(materials),
|
|
compose_list->m_Money,
|
|
item_serial_static, fail_num);
|
|
}
|
|
|
|
if (making_num == fail_num) {
|
|
compose_result = RC::RC_ITEM_COMPOSE_FAILED;
|
|
}
|
|
|
|
// 돈차감 (CHANGES) change type 'DWORD64'->'MONEY'
|
|
MONEY composition_fee = compose_list->m_Money * making_num;
|
|
{
|
|
player_->MinusMoney(composition_fee);
|
|
GAMELOG->LogMoney(MONEY_COMPOSE, player_, composition_fee);
|
|
};
|
|
|
|
g_pGameServer->NotifyHeimConsumption(player_->GetCharGuid(),
|
|
eHEIM_CONSUMPTION_COMPOSITION, composition_fee);
|
|
|
|
//_NA_001990_ACSYSTEM_ADD
|
|
if(compose_list->m_byResultType != compose_list->RESULTTYPE_REWARDCODE)
|
|
{
|
|
const BASE_ITEMINFO* item_info = \
|
|
ItemInfoParser::Instance()->GetItemInfo(compose_list->m_Result.m_ItemCode);
|
|
|
|
if (item_info && item_info->m_wACCode)
|
|
{
|
|
player_->GetACManager()->ProcessItemObtain(item_info->m_Code, item_info->m_wACCode,
|
|
item_info->m_byACReferenceID, compose_list->m_Result.m_byItemNum * success_num_out);
|
|
}
|
|
}
|
|
|
|
return compose_result;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
#ifdef _NA_007408_20140711_MODIFY_CRYSTALLIZE
|
|
// ItemManager::Crystalize는 사용하지 않는 함수이다 (CrystallizeImplement를 사용함)
|
|
#else
|
|
RC::eITEM_RESULT
|
|
ItemManager::Crystalize(SLOTCODE crystalize_list_code, POSTYPE target_pos,
|
|
INVENTORY_TOTAL_INFO* OUT inven_total_info)
|
|
{
|
|
if (IsRestrictFunction(eFUNCTIONALRESTRICT_CRYSTALIZE)) {
|
|
return RC::RC_ITEM_UNUSABLE_FUNCTION;
|
|
}
|
|
if (!player_->GetChaoState().CanUseFuction(CHAO_USE_CRYSTALIZE)) {
|
|
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CHAOSTATE;
|
|
}
|
|
if (player_->GetBehave() == PLAYER_BEHAVE_UNEXPECTED_WAITING) {
|
|
return RC::RC_ITEM_INVALIDSTATEOFPLAYER;
|
|
}
|
|
if (player_->GetLevel() < LIMIT_LEVEL_CRYSTALIZE) {
|
|
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CURR_LEVEL;
|
|
}
|
|
if (ValidState() == false) {
|
|
return RC::RC_ITEM_INVALIDSTATE;
|
|
}
|
|
if (ValidPos(SI_INVENTORY, target_pos) == false) {
|
|
return RC::RC_ITEM_INVALIDPOS;
|
|
}
|
|
|
|
ItemCrystalizeListParser* const crystalize_list_parser = ItemCrystalizeListParser::Instance();
|
|
const sITEM_CRYSTALIZE_LIST* crystalize_list = \
|
|
crystalize_list_parser->GetCrystalizeListInfo(crystalize_list_code);
|
|
if (crystalize_list == NULL) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
|
|
SCSlotContainer* inventory = GetItemSlotContainer(SI_INVENTORY);
|
|
SCItemSlot& target_item = static_cast<SCItemSlot&>(inventory->GetSlot(target_pos));
|
|
const BASE_ITEMINFO* item_info = target_item.GetItemInfo();
|
|
//FASSERT(item_info); remove 'FASSERT', assert(item_info)
|
|
|
|
if (crystalize_list->m_ItemType != item_info->m_wType) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
if (target_item.CanUseMixture(MIXTURE_CRYSTALIZE) == false) {
|
|
return RC::RC_ITEM_NOT_MIXTURE;
|
|
}
|
|
// 일반적인 아이템인 경우 1레벨 0랭크 E인챈트인 무기는 분해 불가능
|
|
if (item_info->m_wSubType == eITEMSUBTYPE_GENERAL)
|
|
{
|
|
if (item_info->m_LV == 1 && target_item.GetRank() == RANK_E && target_item.GetEnchant() == 0)
|
|
{
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
}
|
|
|
|
// 기본적으로 pListInfo->m_ItemLevel = 0값을 가지며, 악세사리의 경우 1, 2의 Level값을 가진다.
|
|
if (crystalize_list->m_ItemLevel && item_info->m_LV != crystalize_list->m_ItemLevel) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
if (crystalize_list->m_EnchantLv != target_item.GetEnchant()) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
|
|
static SLOTCODE obtain_code_list[MAX_INVENTORY_SLOT_NUM];
|
|
static POSTYPE obtain_counts_list[MAX_INVENTORY_SLOT_NUM];
|
|
ZeroMemory(obtain_code_list, sizeof(obtain_code_list));
|
|
ZeroMemory(obtain_counts_list, sizeof(obtain_counts_list));
|
|
// TODO(WAVERIX) (NOTE) #97 하단부 로직이 buffer boundary에 적합한지 정적 분석만으론 확인되지 않았다. 검증할 것.
|
|
|
|
POSTYPE total_count = 0;
|
|
MONEY number_of_obtains = 0;
|
|
|
|
// 1차 결정체 획득 확률
|
|
for (int i = 0; i < crystalize_list->MAX_RESULT; ++i)
|
|
{
|
|
const sITEM_CRYSTALIZE_LIST::sITEM_FOR_CRYSTALIZE& crystal_result = \
|
|
crystalize_list->m_pResult[i];
|
|
|
|
DWORD seed = random(1, 100);
|
|
if (seed > crystal_result.m_ResultRatio) {
|
|
continue;
|
|
}
|
|
if (crystal_result.m_MaterialCode == 0) {
|
|
continue;
|
|
}
|
|
number_of_obtains = crystal_result.m_MaterialCount;
|
|
|
|
// 결정체의 금액이 0 이 아닌 경우 아이템의 상점 구입 가격/
|
|
// MaterialMoney로 추가되는 결정체의 갯수가 결정된다.
|
|
if (0 != crystal_result.m_MaterialMoney) {
|
|
number_of_obtains += target_item.GetPriceForBuy() / crystal_result.m_MaterialMoney;
|
|
}
|
|
|
|
// 결정체의 갯수가 255가 넘을 경우 다음 슬롯으로 넘긴다.
|
|
// 한 슬롯당 최대 255개의 동일 아이템 수용 가능.
|
|
// 또한 최대 가질 수 있는 결정체의 갯수를 총 2개의 슬롯으로 제한 시킨다.
|
|
number_of_obtains = min(number_of_obtains, UCHAR_MAX*2);
|
|
while(number_of_obtains > UCHAR_MAX)
|
|
{
|
|
obtain_code_list[total_count] = crystal_result.m_MaterialCode;
|
|
obtain_counts_list[total_count] = UCHAR_MAX;
|
|
number_of_obtains -= UCHAR_MAX;
|
|
++total_count;
|
|
}
|
|
|
|
if (number_of_obtains > 0)
|
|
{
|
|
obtain_code_list[total_count] = crystal_result.m_MaterialCode;
|
|
obtain_counts_list[total_count] = static_cast<POSTYPE>(number_of_obtains);
|
|
++total_count;
|
|
}
|
|
}
|
|
|
|
// 랜덤 결정체 획득 확률
|
|
for (int i = 0; i < crystalize_list->MAX_RANDOMRESULT; ++i)
|
|
{
|
|
const sITEM_CRYSTALIZE_LIST::sITEM_FOR_RANDOM_CRYSTALIZE& crystal_random_result = \
|
|
crystalize_list->m_pRandomResult[i];
|
|
|
|
DWORD seed = (DWORD)dRandom(1, crystal_random_result.m_RandomStandardRatio);
|
|
if (seed > crystal_random_result.m_RandomRatio) {
|
|
continue;
|
|
}
|
|
if (crystal_random_result.m_MaterialCode == 0) {
|
|
continue;
|
|
}
|
|
// 결정체의 갯수가 255가 넘을 경우 다음 슬롯으로 넘긴다.
|
|
// 한 슬롯당 최대 255개의 동일 아이템 수용 가능.
|
|
// 또한 최대 가질 수 있는 결정체의 갯수를 총 1개의 슬롯으로 제한 시킨다.
|
|
number_of_obtains = min(crystal_random_result.m_MaterialCount, UCHAR_MAX);
|
|
|
|
if (number_of_obtains > 0)
|
|
{
|
|
obtain_code_list[total_count] = crystal_random_result.m_MaterialCode;
|
|
obtain_counts_list[total_count] = number_of_obtains;
|
|
++total_count;
|
|
}
|
|
}
|
|
|
|
ASSERT(total_count <= MAX_INVENTORY_SLOT_NUM);
|
|
|
|
RC::eITEM_RESULT crystalize_result = RC::RC_ITEM_CRYSTALIZE_FAILED;
|
|
if (0 == total_count)
|
|
{
|
|
// 결정화 실패 로그
|
|
GAMELOG->LogItem(ITEM_CRYSTALIZE_FAILED, player_, &target_item);
|
|
inventory->DeleteSlot(target_pos, NULL);
|
|
}
|
|
else
|
|
{
|
|
crystalize_result = ObtainAllKindOfItem(total_count,
|
|
obtain_code_list, obtain_counts_list,
|
|
inven_total_info);
|
|
if (crystalize_result == RC::RC_ITEM_SUCCESS)
|
|
{
|
|
// 결정화 성공 로그
|
|
GAMELOG->LogCrystalizeSuccess(player_, target_item,
|
|
total_count, obtain_code_list, obtain_counts_list);
|
|
inventory->DeleteSlot(target_pos, NULL);
|
|
|
|
crystalize_result = RC::RC_ITEM_CRYSTALIZE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return crystalize_result;
|
|
}
|
|
#endif //_NA_007408_20140711_MODIFY_CRYSTALLIZE
|
|
|
|
#ifdef _NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|
|
bool Sorting_PairVector(const std::pair<POSTYPE, INT> &fst, const std::pair<POSTYPE, INT> &sec)
|
|
{
|
|
return (fst.second < sec.second);
|
|
}
|
|
BOOL ItemManager::DeleteComposeMaterials( ns_functor::DeleteComposeMaterialItem* functor,
|
|
INVEN_DELETE_TOTAL_INFO* OUT delete_item_info)
|
|
{
|
|
SLOTIDX slot_index = SI_INVENTORY;
|
|
|
|
SCItemSlotContainer* slot_container = static_cast<SCItemSlotContainer*>(slot_manager_->GetSlotContainer(slot_index));
|
|
const SLOTCODE item_code = functor->GetItemCode();
|
|
BASE_ITEMINFO* item_info = ItemInfoParser::Instance()->GetItemInfo(item_code);
|
|
|
|
if(item_info == NULL) {
|
|
return false;
|
|
}
|
|
|
|
|
|
if (item_info->m_wEqPos == eEQUIPCONTAINER_INVALID)
|
|
{
|
|
// 장비아이템이 아닌 경우
|
|
typedef SCItemSlotContainer::SLOT_LINEAR_LIST SLOT_LINEAR_LIST;
|
|
const SLOT_LINEAR_LIST& slot_list = slot_container->GetSlotList();
|
|
SLOT_LINEAR_LIST::const_iterator it = slot_list.begin();
|
|
for ( ; it != slot_list.end(); ++it)
|
|
{
|
|
const SCItemSlot& item_slot = static_cast<const SCItemSlot&>(*it->slot);
|
|
if (item_slot.GetItemCode() == 0) {
|
|
continue;
|
|
};
|
|
if (functor->operator()(slot_container, item_slot, delete_item_info) == false) {
|
|
continue;
|
|
};
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
STLX_VECTOR< std::pair<POSTYPE, INT> > found_item;
|
|
|
|
// 장비아이템인 경우
|
|
const DWORD item_type_index = functor->GetItemTypeIndex();
|
|
INT minimum_enchant_value = 0;
|
|
|
|
ItemType* item_type = ItemTypeList::Instance()->FindItemType(item_type_index);
|
|
if (item_type != NULL) {
|
|
// NULL이면 0 유지
|
|
minimum_enchant_value = item_type->GetEnchant();
|
|
}
|
|
if (FlowControl::FCAssert(slot_container != NULL) == false) {
|
|
return false;
|
|
};
|
|
|
|
const POSTYPE max_number_of_slots = slot_container->GetMaxSlotNum();
|
|
// 인챈트 조건의 맞으면서 가장 낮은값을 가진 아이템의 좌표를 찾는다
|
|
for (POSTYPE pos = 0; pos < max_number_of_slots; ++pos)
|
|
{
|
|
if (slot_container->IsEmpty(pos)) {
|
|
continue;
|
|
}
|
|
SCItemSlot& slot = static_cast<SCItemSlot&>(slot_container->GetSlot(pos));
|
|
if (slot.GetItemCode() == item_code && slot.GetEnchant() >= minimum_enchant_value)
|
|
{
|
|
// 조건에 맞는 아이템들을 찾아서 vector에 삽입
|
|
found_item.push_back(std::make_pair(pos, slot.GetEnchant()));
|
|
}
|
|
}
|
|
sort(found_item.begin(), found_item.end(), Sorting_PairVector);
|
|
STLX_VECTOR< std::pair<POSTYPE,INT> >::iterator viter = found_item.begin();
|
|
for (viter; viter != found_item.end(); ++viter)
|
|
{
|
|
POSTYPE targetpos = viter->first;
|
|
SCItemSlot& target_slot = static_cast<SCItemSlot&>( slot_container->GetSlot(targetpos) );
|
|
if (functor->operator()(slot_container, target_slot, delete_item_info) == true) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
#endif //_NA_007435_20140718_MODIFY_ITEMCOMPOSE_MATERIAL_CONDITION
|