678 lines
27 KiB
C++
678 lines
27 KiB
C++
#include "stdafx.h"
|
|
#include "./ItemManager_ItemFunction.h"
|
|
#include "ItemManager.h"
|
|
|
|
#include "EnchantParser.h"
|
|
#include "BetaKeyImpl.h"
|
|
|
|
#include "InventorySlotContainer.h"
|
|
#include "SlotManager.h"
|
|
|
|
#include "ChaoState.h"
|
|
#include "AchievementManager.h"
|
|
|
|
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
|
|
#include "NotificationInfoParser.h"
|
|
#include "GameZone.h"
|
|
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
|
|
|
|
//==================================================================================================
|
|
namespace nsSlot {
|
|
;
|
|
//--------------------------------------------------------------------------------------------------
|
|
// @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라는 녀석의 함정에 빠져 무리한 변경을 수행한 걸로 생각됩니다.
|
|
// 11/06/11|waverix|show the below description about the changes
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
// NOTE: sub-manager is implemented to decompose ItemManager.
|
|
// this object has not extra members and virtual function table except the instance of ItemManager.
|
|
BOOST_STATIC_ASSERT(sizeof(nsSlot::ItemFunctionEnchant) == sizeof(ItemManager*) * 2);
|
|
|
|
}; //end of namespace
|
|
|
|
//==================================================================================================
|
|
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
RC::eITEM_RESULT
|
|
nsSlot::ItemFunctionEnchant::ChkBlockEnchant() const
|
|
{
|
|
if (root_->IsRestrictFunction(eFUNCTIONALRESTRICT_ENCHANT)) {
|
|
return RC::RC_ITEM_UNUSABLE_FUNCTION;
|
|
}
|
|
if (!root_->player_->GetChaoState().CanUseFuction(CHAO_USE_ENCHANT)) {
|
|
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CHAOSTATE;
|
|
}
|
|
if (root_->player_->GetBehave() == PLAYER_BEHAVE_UNEXPECTED_WAITING) {
|
|
return RC::RC_ITEM_INVALIDSTATEOFPLAYER;
|
|
}
|
|
if (root_->player_->GetLevel() < LIMIT_LEVEL_ENCHANT) {
|
|
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CURR_LEVEL;
|
|
}
|
|
if (root_->ValidState() == false) {
|
|
return RC::RC_ITEM_INVALIDSTATE;
|
|
}
|
|
return RC::RC_ITEM_SUCCESS;
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
RC::eITEM_RESULT
|
|
nsSlot::ItemFunctionEnchant::ChkSlotEnchant(SCItemSlot& target_slot) const
|
|
{
|
|
if (target_slot.CanUseMixture(MIXTURE_ENCHANT) == false) {
|
|
return RC::RC_ITEM_NOT_MIXTURE;
|
|
}
|
|
if (target_slot.GetEnchant() >= MAX_ENCHANT_GRADE) {
|
|
return RC::RC_ITEM_INVALIDSTATE;
|
|
}
|
|
return RC::RC_ITEM_SUCCESS;
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
RC::eITEM_RESULT nsSlot::ItemFunctionEnchant::ChkSuccessRate(
|
|
const uint8_t enchant,
|
|
const int enchant_grade,
|
|
bool is_elite,
|
|
bool is_unique,
|
|
const eENCHANT_OPTION enchant_option
|
|
) const {
|
|
__UNUSED(enchant);
|
|
// 엘리트 아이템은 50%확률만 선택된다.
|
|
if (is_elite) {
|
|
return (enchant_option & eENCHANT_50PER) ? RC::RC_ITEM_SUCCESS
|
|
: RC::RC_ITEM_ENCHANT_INVALID_RATE_INDEX;
|
|
}
|
|
// 유니크 아이템은 25%확률만 선택된다.
|
|
if (is_unique) {
|
|
return (enchant_option & eENCHANT_25PER) ? RC::RC_ITEM_SUCCESS
|
|
: RC::RC_ITEM_ENCHANT_INVALID_RATE_INDEX;
|
|
}
|
|
// 일반 아이템의 캐쉬 조합은 모든 확률 사용 가능.
|
|
if (enchant_option & eENCHANT_CASH) {
|
|
return RC::RC_ITEM_SUCCESS;
|
|
}
|
|
|
|
// 일반 아이템 룰
|
|
switch (enchant_grade)
|
|
{
|
|
case kEnchantLow:
|
|
// 저레벨 인챈트인경우 100%확률만 선택가능.
|
|
if ((enchant_option & eENCHANT_100PER) == 0) {
|
|
return RC::RC_ITEM_ENCHANT_INVALID_RATE_INDEX;
|
|
}
|
|
break;
|
|
case kEnchantMiddle:
|
|
// 중레벨 인챈트인경우 100%확률 선택불가.
|
|
if (enchant_option & eENCHANT_100PER) {
|
|
return RC::RC_ITEM_ENCHANT_INVALID_RATE_INDEX;
|
|
}
|
|
break;
|
|
case kEnchantHigh:
|
|
// 고레벨 인챈트인 경우 75%, 100%확률 선택불가능.
|
|
// (CHANGES) (100131) (WAVERIX) fix up invalid check condition that \
|
|
// ratio selector have only one
|
|
if ((enchant_option & eENCHANT_100PER) ||
|
|
(enchant_option & eENCHANT_75PER))
|
|
{
|
|
return RC::RC_ITEM_ENCHANT_INVALID_RATE_INDEX;
|
|
}
|
|
break;
|
|
#ifdef _NA_003966_20111227_ADD_ENCHANT
|
|
case kEnchantHighest:
|
|
// 최상위 인첸트 75%, 100% 선택 불가
|
|
if ((enchant_option & eENCHANT_100PER) || (enchant_option & eENCHANT_75PER))
|
|
{
|
|
return RC::RC_ITEM_ENCHANT_INVALID_RATE_INDEX;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
return RC::RC_ITEM_ENCHANT_INVALID_RATE_INDEX;
|
|
}
|
|
|
|
return RC::RC_ITEM_SUCCESS;
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
RC::eITEM_RESULT nsSlot::ItemFunctionEnchant::ChkEnchantCost(
|
|
const MATERIALS_FOR_LEVEL* enchant_info,
|
|
const MONEY enchant_fare,
|
|
const eENCHANT_OPTION enchant_option
|
|
) const {
|
|
// 인첸트 요금은 있는지 체크
|
|
if (root_->player_->GetMoney() < enchant_fare) {
|
|
return RC::RC_ITEM_INSUFFICIENT_MONEY;
|
|
}
|
|
// 소모할 재료가 있는지 체크
|
|
const sFARE_RATIO* fare_ratio = enchant_info->GetFareRatio(enchant_option);
|
|
if (FlowControl::FCAssert(fare_ratio != NULL) == false) {
|
|
return RC::RC_ITEM_ENCHANT_INVALID_ITEMLEVEL;
|
|
}
|
|
const double material_fare = fare_ratio->m_MaterialFare;
|
|
|
|
const EnchantParser* const enchant_parser = EnchantParser::Instance();
|
|
for (int i = 0; i < MATERIALS_FOR_LEVEL::kMaxMaterialNumber; ++i)
|
|
{
|
|
const sMATERIALS* materials = enchant_info->GetMaterials(i);
|
|
if (materials == NULL) {
|
|
continue;
|
|
}
|
|
POSTYPE number_of_material_items = \
|
|
enchant_parser->CalcMaterialNum(materials->m_MaterialItemNum, material_fare);
|
|
|
|
ns_functor::EmptyItemCheck empty_checker(\
|
|
materials->m_MaterialItemCode, number_of_material_items);
|
|
if (root_->ForeachSlot(SI_INVENTORY, &empty_checker) == false) {
|
|
return RC::RC_ITEM_ENCHANT_HAVENOTMETERIALS;
|
|
}
|
|
}
|
|
|
|
return RC::RC_ITEM_SUCCESS;
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
RC::eITEM_RESULT
|
|
nsSlot::ItemFunctionEnchant::DeleteEnchantCost(const MATERIALS_FOR_LEVEL* enchant_info,
|
|
MONEY enchant_fare, eENCHANT_OPTION enchant_option)
|
|
{
|
|
// 재료 없애기 assert(enchant_option) ?
|
|
double material_fare = enchant_info->GetFareRatio(enchant_option)->m_MaterialFare;
|
|
const EnchantParser* const enchant_parser = EnchantParser::Instance();
|
|
for (POSTYPE i = 0; i < MATERIALS_FOR_LEVEL::kMaxMaterialNumber; ++i)
|
|
{
|
|
const sMATERIALS* materials = enchant_info->GetMaterials(i);
|
|
if (materials == NULL) {
|
|
continue;
|
|
}
|
|
POSTYPE number_of_material_items = \
|
|
enchant_parser->CalcMaterialNum(materials->m_MaterialItemNum, material_fare);
|
|
|
|
ns_functor::DeleteItem delete_operator(\
|
|
materials->m_MaterialItemCode, number_of_material_items);
|
|
BOOL foreach_result = root_->ForeachSlot(SI_INVENTORY, &delete_operator);
|
|
ASSERT(foreach_result);
|
|
}
|
|
|
|
// 비용 소모
|
|
BOOL minus_result = root_->player_->MinusMoney(enchant_fare);
|
|
ASSERT(minus_result);
|
|
|
|
GAMELOG->LogMoney(MONEY_ENCHANT, root_->player_, enchant_fare);
|
|
g_pGameServer->NotifyHeimConsumption(root_->player_->GetCharGuid(),
|
|
eHEIM_CONSUMPTION_ENCHANT,
|
|
enchant_fare);
|
|
|
|
return RC::RC_ITEM_SUCCESS;
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
RC::eITEM_RESULT nsSlot::ItemFunctionEnchant::Enchant(
|
|
const POSTYPE target_pos, const POSTYPE down_guard_item_pos, const eENCHANT_OPTION enchant_option)
|
|
{
|
|
const RC::eITEM_RESULT check_block_enchant = ChkBlockEnchant();
|
|
if (RC::RC_ITEM_SUCCESS != check_block_enchant)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 기능을 사용할 수 없습니다.|캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return check_block_enchant;
|
|
}
|
|
if (root_->ValidPos(SI_INVENTORY, target_pos) == false)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 대상 아이템 위치가 올바르지 않습니다.|ItemPosition = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
target_pos,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return RC::RC_ITEM_INVALIDPOS;
|
|
}
|
|
|
|
SCSlotContainer* const inventory = root_->GetItemSlotContainer(SI_INVENTORY);
|
|
SCItemSlot& target_slot = static_cast<SCItemSlot&>(inventory->GetSlot(target_pos));
|
|
const RC::eITEM_RESULT check_slot_enchant = ChkSlotEnchant(target_slot);
|
|
if (check_slot_enchant != RC::RC_ITEM_SUCCESS)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 할수 없는 아이템 입니다.|ItemPosition = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
target_pos,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return check_slot_enchant;
|
|
}
|
|
|
|
const uint8_t enchant = target_slot.GetEnchant();
|
|
const BASE_ITEMINFO* const target_item_info = target_slot.GetItemInfo();
|
|
const bool is_elite = target_item_info->IsElite();
|
|
const bool is_unique = target_item_info->IsUnique();
|
|
|
|
const EnchantParser* const enchant_parser = EnchantParser::Instance();
|
|
const eENCHANT_GRADE enchant_grade = enchant_parser->GetEnchantGrade(enchant);
|
|
const RC::eITEM_RESULT check_success_rate =
|
|
ChkSuccessRate(enchant, enchant_grade, is_elite, is_unique, enchant_option);
|
|
if (check_success_rate != RC::RC_ITEM_SUCCESS)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 확률이 올바르지 않습니다.|ItemPosition = %d, EnchantGrade = %d, EnchantOption = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
target_pos,
|
|
enchant_grade,
|
|
enchant_option,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return check_success_rate;
|
|
}
|
|
|
|
const LEVELTYPE item_level = target_item_info->m_LV;
|
|
const MATERIALS_FOR_LEVEL* const enchant_info = enchant_parser->GetEnchantMatInfo(
|
|
item_level, enchant, target_item_info->IsWeapon(), target_slot.IsLimited(), enchant_option);
|
|
if (enchant_info == NULL)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 정보를 찾을 수 없습니다.|ItemPosition = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
target_pos,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return RC::RC_ITEM_ENCHANT_INVALID_ITEMLEVEL;
|
|
}
|
|
|
|
// 인챈트 하임 비용
|
|
// NOTE: f080903.x, lst1024, 클라와의 계산값에 1 오차가 발생 자료형을 float으로 바꾸고 (+ 0.5f + 0.001f) 식 적용
|
|
// CHANGES: f100130.x, waverix, changes to more generic code using high-level rounding
|
|
MONEY enchant_fare = 0;
|
|
//{
|
|
// double formula_calc = static_cast<double>(target_slot.GetPriceForUpGradeFare());
|
|
// ; formula_calc *= item_level;
|
|
// ; formula_calc *= enchant_info->GetFareRatio(enchant_option)->m_HaimFare;
|
|
// //assertion : enchant비용이 42억을 넘어서는 안된다.
|
|
// enchant_fare = util::LL_Round(formula_calc);
|
|
//};
|
|
{
|
|
enum { kPercent = 100 };
|
|
enum { kHalfPercent = kPercent / 2 };
|
|
const double haim_fare = enchant_info->GetFareRatio(enchant_option)->m_HaimFare * kPercent;
|
|
const int conv_haim_fare = util::LL_Round(haim_fare);
|
|
#ifdef _NA_006589_20120415_ENCHANT_PRICE_MODIFY
|
|
LEVELTYPE touch_item_level = target_item_info->m_LV;
|
|
if (touch_item_level > 22) {
|
|
touch_item_level = 23;
|
|
}
|
|
else if (touch_item_level > 12) {
|
|
touch_item_level = 13;
|
|
}
|
|
else {
|
|
touch_item_level = 3;
|
|
}
|
|
enchant_fare = target_slot.GetPriceForUpGradeFare() * touch_item_level * conv_haim_fare;
|
|
#else
|
|
enchant_fare = target_slot.GetPriceForUpGradeFare() * item_level * conv_haim_fare;
|
|
#endif // _NA_006589_20120415_ENCHANT_PRICE_MODIFY
|
|
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
enchant_fare = root_->player_->GetAttr().GetValueAppliedAttr(enchant_fare, eATTR_ENCHANT_COST_RATIO);
|
|
#endif //_NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
const bool is_round = (enchant_fare % kPercent) >= kHalfPercent;
|
|
enchant_fare /= 100;
|
|
if (is_round == true)
|
|
{
|
|
enchant_fare++;
|
|
}
|
|
}
|
|
const RC::eITEM_RESULT check_enchant_cost =
|
|
ChkEnchantCost(enchant_info, enchant_fare, enchant_option);
|
|
if (check_enchant_cost != RC::RC_ITEM_SUCCESS)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 비용 검사에 실패 했습니다.|ItemPosition = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
target_pos,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return check_enchant_cost;
|
|
}
|
|
|
|
// 다운 방지 아이템 검사를 한다.
|
|
bool use_down_guard = false;
|
|
if (down_guard_item_pos != INVALID_SLOT_POS)
|
|
{
|
|
if (enchant_info->IsDownGrade() == false)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 다운이 가능한 아이템이 아닙니다.|ItemCode = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
target_item_info->m_Code,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return RC::RC_ITEM_INVALID_TYPE;
|
|
}
|
|
if (inventory->ValidPos(down_guard_item_pos) == false)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 다운 방지 아이템 위치가 올바르지 않습니다.|ItemPosition = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
down_guard_item_pos,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return RC::RC_ITEM_INVALIDPOS;
|
|
}
|
|
const SCItemSlot* const down_guard_item =
|
|
static_cast<const SCItemSlot*>(inventory->GetValidSlotPtr(NULL, down_guard_item_pos));
|
|
if (down_guard_item == NULL)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 다운 방지 아이템 위치가 올바르지 않습니다.|ItemPosition = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
down_guard_item_pos,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return RC::RC_ITEM_INVALIDPOS;
|
|
}
|
|
const BASE_ITEMINFO* const down_guard_item_info = down_guard_item->GetItemInfo();
|
|
if (down_guard_item_info->m_wType != eITEMTYPE_ENCHANT)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 다운 방지 아이템 타입이 올바르지 않습니다.|ItemType = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
down_guard_item_info->m_wType,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return RC::RC_ITEM_INVALID_TYPE;
|
|
}
|
|
if (down_guard_item_info->m_wSubType != enchant_info->GetDownGradeType())
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 다운 방지 아이템 사용 대상이 올바르지 않습니다.|SubType = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
down_guard_item_info->m_wSubType,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return RC::RC_ITEM_INVALID_TYPE;
|
|
}
|
|
const RC::eITEM_RESULT using_result = root_->UseItemByType(
|
|
eITEMTYPE_ENCHANT, SI_INVENTORY, down_guard_item_pos, true, __FUNCTION__);
|
|
if (using_result != RC::RC_ITEM_SUCCESS)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 다운 방지 아이템 사용에 실패 했습니다.|UsingResult = %d, ItemCode = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
using_result,
|
|
down_guard_item_info->m_Code,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return using_result;
|
|
}
|
|
use_down_guard = true;
|
|
}
|
|
|
|
const RC::eITEM_RESULT check_delete_cost =
|
|
DeleteEnchantCost(enchant_info, enchant_fare, enchant_option);
|
|
if (check_delete_cost != RC::RC_ITEM_SUCCESS)
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|인첸트 비용 삭제에 실패 했습니다.|ItemPosition = %d, 캐릭터이름 = %s|"),
|
|
__FUNCTION__,
|
|
target_pos,
|
|
root_->player_->GetCharName()
|
|
);
|
|
return check_delete_cost;
|
|
}
|
|
|
|
// 인첸트 확률 처리
|
|
BOOL success = TRUE;
|
|
if (enchant_parser->IsOption100Per(enchant_option) == false)
|
|
{
|
|
int succeed_ratio = enchant_parser->PercentOptionToInt(enchant_option);
|
|
succeed_ratio += root_->player_->GetAttr().GetIncreaseEnchantRatio();
|
|
#ifdef _NA_000000_20130612_RANDOMIZER_CHANGE
|
|
RandomManager* const random_manager = root_->player_->GetRandomManager();
|
|
int random_result = random_manager->randomizer_enchant_.Rand();
|
|
success = (random_result <= succeed_ratio) ? TRUE : FALSE;
|
|
#else
|
|
success = random_percent(succeed_ratio);
|
|
#endif //_NA_000000_20130612_RANDOMIZER_CHANGE
|
|
}
|
|
#ifdef _NA_20100307_BETAKEY_SYSTEM
|
|
enchant_fare = BetaKeyImpl::GetEnchantMoney(
|
|
root_->player_->GetBetaKeyInfo(), enchant_info->GetBetaKeyInfo(), enchant_fare);
|
|
#endif
|
|
|
|
return success ? ApplyEnchantSuccess(target_slot, enchant_info, enchant_fare, enchant_option)
|
|
: ApplyEnchantFail(target_slot, enchant_info, enchant_fare, enchant_option, use_down_guard);
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
RC::eITEM_RESULT nsSlot::ItemFunctionEnchant::ApplyEnchantSuccess(
|
|
SCItemSlot& target_slot, const MATERIALS_FOR_LEVEL* enchant_info,
|
|
MONEY enchant_fare, eENCHANT_OPTION enchant_option)
|
|
{
|
|
const uint8_t new_enchant = target_slot.GetEnchant()+1;
|
|
target_slot.SetEnchantUpdateDura(new_enchant);
|
|
root_->SendItemChange(target_slot);
|
|
LogEnchant(ITEM_ENCHANT_SUCCESS, target_slot, enchant_info, enchant_fare, enchant_option);
|
|
|
|
#ifdef _NA_008283_20150511_NOTIFICATIONS_SYSTEM
|
|
if (NotificationInfoParser::Instance()->IsNotificationItem(
|
|
target_slot, eNotificationEnchant) == true)
|
|
{
|
|
MSG_DG_NOTIFICATION_ITEM_SYN msg;
|
|
msg.info.SetInfo(root_->player_->GetCharName(),
|
|
(root_->player_->GetGameZonePtr() != NULL) ? root_->player_->GetGameZonePtr()->GetMapCode() : 0,
|
|
GetTickCount(), eNotificationEnchant, target_slot.GetItemCode(), target_slot.GetEnchant());
|
|
g_pGameServer->SendToSessionType(GAME_DBPROXY, &msg, sizeof(MSG_DG_NOTIFICATION_ITEM_SYN));
|
|
}
|
|
#endif // _NA_008283_20150511_NOTIFICATIONS_SYSTEM
|
|
|
|
return RC::RC_ITEM_ENCHANT_SUCCESS;
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
RC::eITEM_RESULT nsSlot::ItemFunctionEnchant::ApplyEnchantFail(
|
|
SCItemSlot& target_slot,
|
|
const MATERIALS_FOR_LEVEL* enchant_info,
|
|
const MONEY enchant_fare,
|
|
const eENCHANT_OPTION enchant_option,
|
|
const bool use_down_guard
|
|
) {
|
|
BYTE down_level = 0;
|
|
|
|
//인첸트 실패 아이템 레벨 다운 핸디캡 적용
|
|
if (enchant_info->IsDownGrade() && (use_down_guard == false))
|
|
{
|
|
//아이템 인첸트 다운 불익
|
|
BOOL downed = true;
|
|
if (enchant_info->IsDownGrade100Per() == false)
|
|
{
|
|
BYTE down_ratio = enchant_info->GetDownPer();
|
|
#ifdef _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
// 인챈트 실패 시 아이템 소멸, 다운 방지 어트리뷰트 적용
|
|
int prevent_ratio = root_->player_->GetAttr().GetEnchantPreventDestroyNDowngradeItemRatio();
|
|
if (prevent_ratio > 0 && random_percent(prevent_ratio))
|
|
{
|
|
// 인첸트가 실패했으나 아이템 소멸 및 다운 방지 발동
|
|
LogEnchant(ITEM_ENCHANT_FAILED_PREVENT, target_slot, enchant_info,
|
|
enchant_fare, enchant_option, down_level);
|
|
return RC::RC_ITEM_ENCHANT_FAILED_AND_PREVENT;
|
|
}
|
|
#endif // _NA_007330_20140620_GUILD_SYSTEM_EXTENSION
|
|
downed = random_percent(down_ratio);
|
|
}
|
|
|
|
if (downed)
|
|
{
|
|
const BYTE down_grade_type = enchant_info->GetDownGradeType();
|
|
switch (down_grade_type)
|
|
{
|
|
case 1: //소멸타입이 인첸트 다운이면..
|
|
{
|
|
down_level = enchant_info->GetDownLV();
|
|
int enchant = static_cast<int>(target_slot.GetEnchant()) - down_level;
|
|
if (FlowControl::FCAssert(enchant >= 0))
|
|
{
|
|
//(lst1024)(080918)(2447)인챈트시 내구도를 다시 셋팅 해준다.
|
|
target_slot.SetEnchantUpdateDura(enchant);
|
|
root_->SendItemChange(target_slot);
|
|
}
|
|
LogEnchant(ITEM_ENCHANT_FAILED_DOWN, target_slot, enchant_info,
|
|
enchant_fare, enchant_option, down_level);
|
|
return RC::RC_ITEM_ENCHANT_FAILED_AND_ENCHNAT_DOWN;
|
|
}
|
|
break;
|
|
case 2: //소멸타입이 아이템 소멸이면..
|
|
{
|
|
root_->Delete(target_slot.GetPos());
|
|
LogEnchant(ITEM_ENCHANT_FAILED_DESTROY, target_slot, enchant_info,
|
|
enchant_fare, enchant_option, down_level);
|
|
return RC::RC_ITEM_ENCHANT_FAILED_AND_DESTROY;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 인첸트 실패 로그파일
|
|
LogEnchant(ITEM_ENCHANT_FAILED, target_slot, enchant_info,
|
|
enchant_fare, enchant_option, down_level);
|
|
return RC::RC_ITEM_ENCHANT_FAILED;
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
void nsSlot::ItemFunctionEnchant::LogEnchant(
|
|
int iLogType,
|
|
SCItemSlot& target_slot, const MATERIALS_FOR_LEVEL* enchant_info,
|
|
MONEY enchant_fare, eENCHANT_OPTION enchant_option, BYTE byDownLV)
|
|
{
|
|
// (CHANGES) (WAVERIX) change vector control to more cheap routine
|
|
//로그파일을 남기기 위한 인첸트 정보 vector
|
|
static STLX_VECTOR<COMPOSITEMATERIAL> consumed_materials;
|
|
consumed_materials.resize(0);
|
|
|
|
double material_fare = enchant_info->GetFareRatio(enchant_option)->m_MaterialFare;
|
|
EnchantParser* const enchant_parser = EnchantParser::Instance();
|
|
for (POSTYPE i = 0; i < MATERIALS_FOR_LEVEL::kMaxMaterialNumber; ++i)
|
|
{
|
|
const sMATERIALS* materials = enchant_info->GetMaterials(i);
|
|
if (materials == NULL) {
|
|
continue;
|
|
}
|
|
COMPOSITEMATERIAL info = { 0, };
|
|
info.MaterialCode = materials->m_MaterialItemCode;
|
|
info.MaterialNum = enchant_parser->CalcMaterialNum(materials->m_MaterialItemNum, material_fare);
|
|
consumed_materials.push_back(info);
|
|
}
|
|
|
|
// 인첸트 로그
|
|
GAMELOG->LogEnchant(iLogType, root_->player_, target_slot, enchant_fare, consumed_materials);
|
|
}
|
|
|
|
// CHANGES: f110611.1L, moved from ItemManager_Composite.cpp
|
|
// 엑스트라 스톤 사용
|
|
RC::eITEM_RESULT nsSlot::ItemFunctionEnchant::UseExtraStone(
|
|
POSTYPE extra_stone_pos, POSTYPE target_pos, BYTE& OUT value_index_out)
|
|
{
|
|
if (root_->IsRestrictFunction(eFUNCTIONALRESTRICT_USE_EXTRASTONE)) {
|
|
return RC::RC_ITEM_UNUSABLE_FUNCTION;
|
|
}
|
|
if (root_->player_->GetChaoState().IsChaoState()) {
|
|
return RC::RC_ITEM_UNABLE_FUNCTION_FOR_CHAOSTATE;
|
|
}
|
|
if (root_->ValidState() == false) {
|
|
return RC::RC_ITEM_INVALIDSTATE;
|
|
}
|
|
if (root_->ValidPos(SI_INVENTORY, extra_stone_pos) == false) {
|
|
return RC::RC_ITEM_INVALIDPOS;
|
|
}
|
|
if (root_->ValidPos(SI_INVENTORY, target_pos) == false) {
|
|
return RC::RC_ITEM_INVALIDPOS;
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
SCSlotContainer* inventory = root_->GetItemSlotContainer(SI_INVENTORY);
|
|
SCItemSlot& target_item = static_cast<SCItemSlot&>(inventory->GetSlot(target_pos));
|
|
// 무기, 방어구, 악세서리, 특수 악세서리
|
|
if (target_item.GetItemRuleInfo().IsEnableExtraOption() == false) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
};
|
|
//----------------------------------------------------------------------------------------------
|
|
const BASE_ITEMINFO* target_item_info = target_item.GetItemInfo();
|
|
if (target_item.CanUseMixture(MIXTURE_EXTRASTONE) == false) {
|
|
return RC::RC_ITEM_NOT_MIXTURE;
|
|
}
|
|
ItemCompositeParser* const composite_parser = ItemCompositeParser::Instance();
|
|
const sITEMCOMPOSITE* composite = \
|
|
composite_parser->GetCompositeInfo(eITEMCOPOSITE_EXTRASTONE_USE);
|
|
if (composite == NULL) {
|
|
return RC::RC_ITEM_INVALIDSTATE;
|
|
};
|
|
//----------------------------------------------------------------------------------------------
|
|
SCItemSlot& extra_stone_item = static_cast<SCItemSlot&>(inventory->GetSlot(extra_stone_pos));
|
|
// 엑스트라 스톤 인지 체크
|
|
const SLOTCODE extra_stone_item_code = extra_stone_item.GetItemCode();
|
|
if (extra_stone_item_code != composite->m_sCompositeMaterials[0].m_dwCompositeMaterialCode)
|
|
{
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
|
|
const sEXTRASTONE_OPT_INFO* stone_option = ExtraStoneOptionInfoParser::Instance()->
|
|
GetExtraStoneOptionInfo(target_item_info->m_wType);
|
|
if (stone_option == NULL) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
if (stone_option->m_ItemLV != 0 && stone_option->m_ItemLV != target_item_info->m_LV) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
|
|
int value_index = target_item.GetNOptionValueIndex();
|
|
if (value_index >= sEXTRASTONE_OPT_INFO::MAX_VALUE_NUM - 1) {
|
|
return RC::RC_ITEM_INVALID_VALUE;
|
|
}
|
|
++value_index;
|
|
target_item.SetNOptionAttr(value_index);
|
|
// impilicit value_index value range < 255
|
|
value_index_out = value_index;
|
|
|
|
GAMELOG->LogItem(ITEM_USE_EXTRASTONE, root_->player_, &target_item);
|
|
|
|
// updates extra stone item: delete or discount
|
|
// assert stone_remains != 0
|
|
DURATYPE stone_remains = extra_stone_item.GetNum();
|
|
if (stone_remains == 1) {
|
|
inventory->DeleteSlot(extra_stone_pos, NULL);
|
|
}
|
|
else if (stone_remains > 1) {
|
|
inventory->UpdateSlot(extra_stone_pos, -1);
|
|
}
|
|
|
|
return RC::RC_ITEM_SUCCESS;
|
|
}
|