Files
Sun1602/SolarSlot/SCItemSlot.cpp
T
2022-10-26 12:25:11 +08:00

2805 lines
92 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "stdafx.h"
#include "./SCItemSlot.h"
#include <time.h>
#include <BitStream.hpp>
#include <NumericValues.h>
#include <ItemFormula.h>
#include <Misc.h>
#include <SolarDateTime.h>
//==================================================================================================
// (Item informations)
#include <ItemInfoParser.h>
#include <FateItemInfoParser.h>
#include <LimitedItemInfoParser.h>
#include <LimitedOptionParser.h>
// _NA_000251_20100727_SOCKET_SYSTEM
#include <SocketSystem/SocketItemRatioParser.h>
//==================================================================================================
//
//==================================================================================================
// 지역 함수 선언
//==================================================================================================
//==================================================================================================
// NOTE: f101221.3L, change namespace
namespace ns_formula {
;
static DWORD
CalcPriceForDura(DWORD item_price, DURATYPE cur_duration, DURATYPE max_duration)
{
if (cur_duration > max_duration) {
return 0;
}
// CHANGES, f100830.3L, fix up an invalid result
// when a value of below the decimal point occur a very small missing error
// in the middle of a formula. for example, when a result of 'item_price * 0.03f' is 'x.49999~'.
float temp_value = (item_price * 3.0f) / (static_cast<float>(max_duration) * 100);
DWORD price_for_repair = util::LL_Round((max_duration - cur_duration) * temp_value);
//DWORD price_for_repair = Round((max_duration - cur_duration) *
// item_price * 0.03f /
// max_duration);
if (price_for_repair > 15000000) {
price_for_repair = 15000000;
}
return price_for_repair;
}
static float
CalcItemPriceForBuy(MONEY drop_level, eRANK rank, BYTE enchant, BYTE divine)
{
float price_weight_for_rank = GetPriceWeightForRank(rank);
float price_weight_for_enchant = GetPriceWeightForEnchant(enchant);
//formula
// item_price = rank_weight * enchant_weight * level * divine_weight;
float item_price = price_weight_for_rank * price_weight_for_enchant;
item_price *= drop_level;
if (divine != 0) {
item_price *= 4.0f;
}
return item_price;
}
// 인챈트시 소모 가격 책정용
static float
CalcItemPriceForUpGradeFare(MONEY drop_level, eRANK rank, BYTE enchant, BYTE divine)
{
float price_weight_for_rank_fare = GetPriceWeightForRankFare(rank);
float price_weight_for_enchant_fare = GetPriceWeightForEnchantFare(enchant);
//formula
// item_price = rank_fare_weight * enchant_fare_weight * level * divine_weight;
float item_price = price_weight_for_rank_fare * price_weight_for_enchant_fare;
item_price *= drop_level;
#ifdef _NA_006589_20120415_ENCHANT_PRICE_MODIFY
#else
if (divine != 0) {
item_price *= 4.0f;
}
#endif // _NA_006589_20120415_ENCHANT_PRICE_MODIFY
return item_price;
}
inline float
CalcItemPriceForSellWithDura(LEVELTYPE item_level, MONEY drop_level,
eRANK rank, BYTE enchant, BYTE divine,
MONEY repair_fare)
{
__UNUSED(item_level);
float item_price_for_buy = CalcItemPriceForBuy(drop_level, rank, enchant, divine);
float money = (item_price_for_buy / 5.0f - repair_fare);
if (money < 0.f) {
return 0.f;
}
return money;
}
inline float
CalcItemPriceForSellWithoutDura(MONEY drop_level, eRANK rank, BYTE enchant, BYTE divine)
{
float item_price_for_buy = CalcItemPriceForBuy(drop_level, rank, enchant, divine);
float price = item_price_for_buy / 5.0f;
return (price < 0 ? 0 : price);
}
__forceinline static MONEY
CalcDropLVForDivine(MONEY item_drop_level)
{
//return (ItemDropLV*28-(ItemDropLV-1)*8+4);
return (item_drop_level + 5);
}
}; //end of namespace
//==================================================================================================
//==================================================================================================
//==================================================================================================
const SCItemSlot
SCItemSlot::Null_Slot;
const BASE_ITEMINFO
SCItemSlot::Null_ItemInfo;
//==================================================================================================
SCItemSlot::SCItemSlot(void) :
SlotType_info_(ST_ITEM)
{
static bool singleton_init_static = _InitializeBinding(this);
Clear();
}
SCItemSlot::~SCItemSlot(void)
{
// (CHANGES) (f100802.4L) remove by implementation
// to acquire multiple list based on type and version
//_DestroyBinding(this);
}
//==================================================================================================
// virtual functions
/*
void
SCItemSlot::SetSlotType(eSlotType type) {
__UNUSED(type);
}
eSlotType
SCItemSlot::GetSlotType() const {
return ST_ITEM;
}
*/
void
SCItemSlot::SetSerial(DBSERIAL serial) {
m_dwSerial = serial;
}
/*
DBSERIAL
SCItemSlot::GetSerial() const {
return m_dwSerial;
}
*/
// (WAVERIX) (NOTE) 아이템 설정시 최초에 설정해야하는 코드 : 코드가 정해져야 다음 정책이 세워진다.
// 전제: SCItemSlot instance가 완료되어 있어야 한다. (즉, 초기화 되어 있어야 한다.)
// 예외: Copy(from server stream, db stream)의 경우라면, SetCode는 내부에서 호출된다.
void
SCItemSlot::SetCode(SLOTCODE item_code)
{
item_code_ = item_code;
image_item_code_ = item_code;
_SetItemInfo();
if (WithDura()) {
SetDura(GetMaxDura());
}
}
/*
SLOTCODE
SCItemSlot::GetCode() const {
return item_code_;
}
*/
//==================================================================================================
/*
void
SCItemSlot::Clear()
{
SCSlot::Clear();
ZeroMemory(item_slot_point_holder_start_, // end
static_cast<size_t>(&item_slot_point_holder_last_[2] - item_slot_point_holder_start_));
}
*/
void
SCItemSlot::SetDura(DURATYPE duration)
{
if (WithDura() != false) {
duration_ = duration;
}
else {
duration_ = 0;
}
}
bool
SCItemSlot::_SetItemInfo()
{
if (item_code_ == 0) {
image_item_info_ = item_info_ = &Null_ItemInfo;
return false;
}
ItemInfoParser* const pItemInfoParser = ItemInfoParser::Instance();
image_item_info_ = item_info_ = pItemInfoParser->GetItemInfo(item_code_);
if (item_info_ == NULL)
{
//SUNLOG(eCRITICAL_LOG, "Can't find item info %d", item_code_);
assert(item_info_ != NULL);
image_item_info_ = item_info_ = &Null_ItemInfo;
return false;
}
// 초기화시에 부여해야 하는 것,
// 아이템 초기 정보를 설정한다.
if (nsSlot::ItemRuleInfo::GetRuleInfo( // 외부 설정용 Limited -
const_cast<nsSlot::ItemRuleInfo*>(&item_rule_info_), item_info_, false) == false)
{
return false; // 아이템 정보가 잘못 되었을 가능성이 높습니다.
}
//
if (!FlowControl::FCAssert(item_rule_info_.is_valid_item)) {
return false;
}
//----------------------------------------------------------------------------------------------
// (NOTE) (WAVERIX) 아이템 설정시 아이템 타입에 따른 설정 내역...
// (NOTE) 하기 내역은 조금 어거지... 그냥 charge_sub_type만으로 평가가 가능할텐데...
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_RIDER_WITH_PART_NOTIMER)
{
if (item_rule_info_.is_rider) {
shared_.rider_info_.is_unlimited_period_ = true;
}
if (item_rule_info_.is_rider_parts) {
shared_.rider_parts_info_.is_unlimited_period_ = true;
}
}
//문상현 룬스톤 아이템 생성시 초기화 수행
if (item_rule_info_.is_waypoint) {
ClearWayPointItem();
}
// f100910.2L, f101101.2L
if (item_info_->m_ChargeType == eCHARGE_CHARGE_PPCARD) {
lock_info_.item_tag_.value = lock_info_.item_tag_.Tag_PCoinPurchase;
}
return true;
}
DURATYPE SCItemSlot::GetMaxDura() const
{
if (WithDura() == false) {
return 0;
}
//
if (item_rule_info_.is_limited)
{
// 리미티드는 인첸트 시 내구도 상승효과 없음 +
// GetDuraEnchantWeightForEnchant(GetEnchant()));
return GetLimitedDuraMax();
}
else if (item_rule_info_.is_fate)
{
// Fate(Lucky) 아이템은 인첸트 시 내구도 상승효과 없음
return GetFateDuraMax();
}
BYTE enchant = GetEnchant();
DWORD bound_check = GetDuraEnchantWeightForEnchant(enchant);
bound_check += item_info_->m_Dura;
bound_check = min(UCHAR_MAX, bound_check);
return BYTE(bound_check);
}
// static function
bool
SCItemSlot::IsOverlap(SLOTCODE item_code)
{
const BASE_ITEMINFO* item_info = ItemInfoParser::Instance()->GetItemInfo(item_code);
if (item_info && item_info->m_byDupNum > 1) {
return true;
}
return false;
}
//==================================================================================================
// item multi-configuration
// (CHANGES) (f100510.1L) redirected interfaces to support the contents of an etheria
bool SCItemSlot::CanEquip() const
{
if (item_rule_info_.is_valid_item == false ||
(item_rule_info_.is_etheria || item_rule_info_.is_shell))
{
return false;
}
if (CanEquip(item_info_) == false) {
return false;
}
// CHANGES: f110329.3L, added filter about 'lucky identification, possession rules'
if (item_rule_info_.is_fate) {
if (shared_.fate_info_.identify_ == false) {
return false;
};
};
if (item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Possession) {
if (equip_info_.is_identify_possession_ == false) {
return false;
};
//__NA_0_POSSESSION_ITEM_DROP
if (equip_info_.is_destroyed_) {
return false;
};
};
// CHANGES: f110331.5L, added filter, ref:f110329.3L
// IsExpiredTime() || IsExpiredWaitTime()
if (item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Timer) {
if (time_info_.is_expired_ || time_info_.is_expired_wait_) {
return false;
};
};
// NOTE: __NA_001062_20080623_STRENGTH_PENALTY
#ifdef _NA_007129_20140327_MODIFY_CAN_EQUIP_ZERODURA
#else
if (WithDura()) {
if (duration_ == 0) {
return false;
}
};
#endif //_NA_007129_20140327_MODIFY_CAN_EQUIP_ZERODURA
return true;
}
// (CHANGES) (f100510.1L) redirected interfaces to support the contents of an etheria
bool SCItemSlot::CanUseMixture(eMIXTURE_FLAG flag) const
{
if (item_rule_info_.is_valid_item == false) {
return false;
}
if (item_rule_info_.is_etheria || item_rule_info_.is_shell) {
return false;
}
// (f100727.1L) add rule
if (lock_info_.history_.value == lock_info_.history_.Combined) {
if (flag & MIXTURE_RANKUP) {
return false;
}
}
if (CanUseMixture(item_info_, flag) == false) {
return false;
}
return true;
}
// (CHANGES) (f100510.1L) whether the 'is_blocked' value is blocked
bool SCItemSlot::CanTradeSell(eITEM_TRADESELL_TYPE is_blocked) const
{
if (item_rule_info_.is_valid_item == false) {
return false;
}
WORD calculated_set = item_info_->trade_sell_type;
if (item_rule_info_.is_etheria || item_rule_info_.is_shell) {
calculated_set |= eITEM_TRADESELL_SELL;
}
// f100909.1L, add rule by _NA000424_GLOBAL_CASH_ITEM_RENEWAL_
if (lock_info_.item_tag_.value == lock_info_.item_tag_.Tag_TradeSkip) {
calculated_set &= ~(eITEM_TRADESELL_TRADE | eITEM_TRADESELL_CASH_PRESENT);
};
#if !defined(_SERVER)
if (is_blocked == eITEM_TRADESELL_DOALL) {
return calculated_set == eITEM_TRADESELL_DOALL;
}
if (is_blocked == eITEM_TRADESELL_DONTALL) {
return calculated_set == eITEM_TRADESELL_DONTALL;
}
#endif
//!~ 복권 아이템은 아이템 내용물 확인을 했을경우 거래/개인상점 불가 - arycoat 2013.02.13
if (item_rule_info_.is_lottery && (GetLottoInfo()->IsIdentity() == TRUE)) {
calculated_set |= (eITEM_TRADESELL_SELL | eITEM_TRADESELL_TRADE);
}
//~!
if (calculated_set & is_blocked) {
return false;
}
return true;
}
// the result is fails,
// if mount(by rider) items or pet items is changed to the shell or the etheria
bool SCItemSlot::CanSummonStatus() const
{
if (item_rule_info_.is_valid_item == false) {
return false;
}
if (item_rule_info_.is_rider == false && item_rule_info_.is_pet == false) {
return false;
}
if (item_rule_info_.is_etheria || item_rule_info_.is_shell) {
return false;
}
if (lock_info_.blocked_ || lock_info_.user_blocked_ || lock_info_.locked_) {
return false;
}
return true;
}
//==================================================================================================
// Time Utilities
BOOL
SCItemSlot::GetDateTimeToSYSTEMTIME(SYSTEMTIME& OUT sys_time)
{
if (item_rule_info_.is_valid_item == false || time_info_.is_expired_) {
return false;
};
// CHANGES: f110327.1L, changes charge_sub_type access field
// to support various making item with timer
const eCHARGE_SUB_TYPE charge_sub_type = eCHARGE_SUB_TYPE(item_rule_info_.charge_sub_type);
switch (charge_sub_type)
{
case eCHARGE_SUB_FIXED_AMOUNT:
case eCHARGE_SUB_FIXED_AMOUNT_WAIT:
case eCHARGE_SUB_RIDER_WITH_PART:
case eCHARGE_SUB_RIDER_WITH_PART_NOTIMER:
case eCHARGE_SUB_FIXED_AMOUNT_EX2:
{
util::YYYYMMDDHHMMSSToSYSTEMTIME(GetDateTime(), sys_time);
return true;
}
break;
case eCHARGE_SUB_FIXED_AMOUNT_EX:
case eCHARGE_SUB_COORDINATE_EX: //__NA001164_20081024_CHAR_WAY_POINT
{
if (IsProgressTime()) {
util::YYYYMMDDHHMMSSToSYSTEMTIME(GetDateTime(), sys_time);
return true;
}
}
break;
case eCHARGE_SUB_FATE:
{
if (shared_.fate_info_.identify_) {
util::YYYYMMDDHHMMSSToSYSTEMTIME(GetDateTime(), sys_time);
return true;
}
}
break;
}
return false;
}
void
SCItemSlot::SetDateTime(DWORD64 d/*second*/)
{
if (!FlowControl::FCAssert(item_rule_info_.is_valid_item != false)) {
return;
}
// CHANGES: f110327.1L, changes charge_sub_type access field
// to support various making item with timer
const eCHARGE_SUB_TYPE charge_sub_type = eCHARGE_SUB_TYPE(item_rule_info_.charge_sub_type);
if (charge_sub_type == eCHARGE_SUB_GENERAL ||
#ifdef _NA_008440_20150818_ADD_CHARGE_SUB_IMMEDIATELY_USE
charge_sub_type == eCHARGE_SUB_IMMEDIATELY_USE ||
charge_sub_type == eCHARGE_SUB_IMMEDIATELY_USE_AND_DELETE ||
#endif // _NA_008440_20150818_ADD_CHARGE_SUB_IMMEDIATELY_USE
charge_sub_type == eCHARGE_SUB_COORDINATE)
{
return;
}
// (NOTE) rider|rider parts (no timer item...)
if (charge_sub_type == eCHARGE_SUB_RIDER_WITH_PART)
{
if (item_rule_info_.is_rider_parts)
{
// parts는 착용시점부터 차감된다. rider는 아이템 설정되는 시점부터.
// 사용 시간 입력(초단위로 입력)
time_info_.date_time_ = d; // start by 'Fireup_DateTime'
return;
}
}
else if (charge_sub_type == eCHARGE_SUB_RIDER_WITH_PART_NOTIMER)
{
// (NOTE) 하기 사항을 만족시킬 때, d의 값은 0, 날짜는 설정해야 한다. parts는 필요 없지만...
d = 0;
if (item_rule_info_.is_rider) {
shared_.rider_info_.is_unlimited_period_ = true;
}
if (item_rule_info_.is_rider_parts) {
shared_.rider_parts_info_.is_unlimited_period_ = true;
}
}
switch(charge_sub_type)
{
case eCHARGE_SUB_FIXED_AMOUNT:
case eCHARGE_SUB_FIXED_AMOUNT_WAIT:
case eCHARGE_SUB_FATE:
case eCHARGE_SUB_RIDER_WITH_PART:
case eCHARGE_SUB_RIDER_WITH_PART_NOTIMER:
{
time_t now;
util::TimeSync::time(&now);
tm* local_time = ::localtime(&now);
//local_time->tm_hour += (int)(d / (60*60));
local_time->tm_sec += (int)d;
if (mktime(local_time) != (time_t)-1)
{ // m_DateTime 날짜로 교체
util::GetDateTime_YYYYMMDDHHMMSS(local_time->tm_year + 1900,
local_time->tm_mon + 1,
local_time->tm_mday,
local_time->tm_hour,
local_time->tm_min,
local_time->tm_sec,
time_info_.date_time_);
}
}
break;
case eCHARGE_SUB_FIXED_AMOUNT_EX:
case eCHARGE_SUB_COORDINATE_EX:
case eCHARGE_SUB_FIXED_AMOUNT_EX2:
{
//----------------------------------------------------------------------
// 주의!!!!!!임시
// 유료화 유효기간 오류 때문에 유효 만료시키기 위한 꽁수-_-;
// 20061219000000 값보다 큰 시간이 들어 올 수 없다.
assert(d <= 20061219000000);
// 시간 셋팅(초단위)
// 다만 초단위의 숫자는 무시됨!(시간단위로 계산됨)
// if it will be 30시간 이용 아이템
time_info_.date_time_ = d;
}
break;
case eCHARGE_SUB_FIXED_QUANTITY:
{
// 사용 시간 입력(초단위로 입력)
// if it will be 30시간 이용 아이템
time_info_.date_time_ = d;
}
break;
}
}
void
SCItemSlot::SetFixedDateTime(DWORD64 d)
{
time_info_.date_time_ = d;
}
bool
SCItemSlot::_UpdateTime()
{
// eCHARGE_SUB_FIXED_QUANTITY만 해당
assert(item_rule_info_.is_valid_item &&
item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_QUANTITY);
ASSERT(0 != time_info_.date_time_);
if (time_info_.last_checked_ > 0)
{
DWORD cur_check_time = GetTickCount();
DWORD used_time = cur_check_time - time_info_.last_checked_;
if (used_time >= 1000) //< 1초 이상만 계산
{
DWORD minute = used_time / 1000;
DWORD remainder = used_time % 1000;
if (time_info_.date_time_ > minute)
{
time_info_.date_time_ -= minute;
time_info_.last_checked_ = cur_check_time - remainder;
}
else
{
time_info_.date_time_ = 0;
time_info_.last_checked_ = 0;
return true;
}
}
}
return false;
}
bool
SCItemSlot::FireUp_DateTime()
{
if (time_info_.is_progress_ != false) {
return false;
}
// (NOTE) add rule, timer가 존재하는 rider parts는 첫 장착시 타이머 동작이라는 개념이 있다.
if (item_rule_info_.is_rider) {
return false; // assert (false) condition
}
if (item_rule_info_.is_rider_parts && shared_.rider_parts_info_.is_unlimited_period_) {
return false;
}
if (time_info_.date_time_ != 0)
{
time_t now;
util::TimeSync::time(&now);
tm* local_time = ::localtime(&now);
//LocalTime->tm_hour += (int)(time_info_.date_time_/(60*60));
//LocalTime->tm_min += (int()(time_info_.date_time_/60);
local_time->tm_sec += (int)time_info_.date_time_;
if (mktime(local_time) != (time_t)-1)
{
// time_info_.date_time_ 날짜로 교체
util::GetDateTime_YYYYMMDDHHMMSS(local_time->tm_year + 1900,
local_time->tm_mon + 1,
local_time->tm_mday,
local_time->tm_hour,
local_time->tm_min,
local_time->tm_sec,
time_info_.date_time_);
time_info_.is_progress_ = true;
return true;
}
}
return false;
}
// (returns)
// - eCHARGE_SUB_FIXED_AMOUNT_EX 타입과 같이 처음 장착한 경우를 구분해야 하는 경우 (start timer) 구분
// if (start_timer) then true
// else then false
BOOL
SCItemSlot::OnEquip()
{
// <- 아이템 검증이 필요한가?...
if (time_info_.is_expired_) {
return false;
}
// CHANGES: f110327.1L, changes charge_sub_type access field
// to support various making item with timer
const eCHARGE_SUB_TYPE charge_sub_type = eCHARGE_SUB_TYPE(item_rule_info_.charge_sub_type);
switch(charge_sub_type)
{
case eCHARGE_SUB_FIXED_AMOUNT://< 정액제 : 일정 기간제 (2007-06-07 24:12:30)
case eCHARGE_SUB_COORDINATE_EX:
case eCHARGE_SUB_RIDER_WITH_PART_NOTIMER: //이것은 기한 없는 아템이므로 선택사항 아님
case eCHARGE_SUB_FIXED_AMOUNT_EX2:
// nothing to do
break;
case eCHARGE_SUB_FIXED_AMOUNT_EX://< 확장정액제 : 착용시 부터 일정 기간 사용 (30시간 -> 2007-06-07 24:12:30)
case eCHARGE_SUB_RIDER_WITH_PART: //__NA1390_1391_090915_RIDING_SYSTEM_ITEM_PART__
if (FireUp_DateTime() != false) {
return true;
}
break;
case eCHARGE_SUB_FIXED_QUANTITY://< 정량제 : 사용 기간제 (30시간)
// 장착했을 때
// 타이머 시작?
ASSERT(time_info_.date_time_ != 0);
ASSERT(time_info_.last_checked_ == 0);
time_info_.last_checked_ = GetTickCount();
break;
case eCHARGE_SUB_FATE:
if (shared_.fate_info_.identify_) {
return true;
}
break;
}
return false;
}
void
SCItemSlot::OnUnEquip()
{
if (time_info_.is_expired_) {
return;
}
const eCHARGE_SUB_TYPE charge_sub_type = \
static_cast<eCHARGE_SUB_TYPE>(item_rule_info_.charge_sub_type);
switch(charge_sub_type)
{
case eCHARGE_SUB_FIXED_AMOUNT://< 정액제 : 일정 기간제 (2007-06-07 24:12:30)
case eCHARGE_SUB_FIXED_AMOUNT_EX://< 확장정액제 : 착용시 부터 일정 기간 사용 (30시간 -> 2007-06-07 24:12:30)
case eCHARGE_SUB_FATE:
case eCHARGE_SUB_COORDINATE_EX:
case eCHARGE_SUB_RIDER_WITH_PART: //__NA1390_1391_090915_RIDING_SYSTEM_ITEM_PART__
case eCHARGE_SUB_FIXED_AMOUNT_EX2:
{
// nothing to do
}
break;
case eCHARGE_SUB_FIXED_QUANTITY://< 정량제 : 사용 기간제 (30시간)
{
// 장착해제했을 때
// 타이머 해제?
time_info_.is_expired_ = _UpdateTime();
time_info_.last_checked_ = 0;
}
break;
}
}
BOOL
SCItemSlot::Update(BOOL is_pcroom_user)
{
// 하기 조건들이면 여기에 진입은 안 해야겠지만...
if (item_info_ == NULL ||
item_info_->m_Code == 0 ||
item_rule_info_.is_valid_item == false)
{
return true;
}
if (!FlowControl::FCAssert(item_code_ == item_info_->m_Code)) {
return false;
}
if (time_info_.is_expired_) {
return false;
}
if (slot_updater_.SlotUpdate(this, is_pcroom_user) == false) {
return false;
}
const eCHARGE_SUB_TYPE charge_sub_type = \
static_cast<eCHARGE_SUB_TYPE>(item_rule_info_.charge_sub_type);
//eCHARGE_PC_ROOM의 경우는 타이머 기반은 아니다...
if (charge_sub_type == eCHARGE_PC_ROOM && is_pcroom_user == false) {
return false;
}
// 타이머 동작하는 아이템인 경우, 이곳을 통과한다.
if ((item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Timer) == 0) {
return true;
}
DWORD64 curr_time_wz = 0; // Webzen Time Format
// 주기적인 검사 수행
// eCHARGE_SUB_FIXED_AMOUNT < 정액제 : 일정 기간제 (2007-06-07 24:12:30)
// eCHARGE_SUB_FIXED_AMOUNT_EX < 확장정액제 : 착용시 부터 일정 기간 사용 (30시간 -> 2007-06-07 24:12:30)
// eCHARGE_SUB_FIXED_AMOUNT_WAIT< 기한 만료시 일주일 대기, 대기 시간도 지나면 삭제
// eCHARGE_SUB_FIXED_QUANTITY < 정량제 : 사용 기간제 (30시간)
// eCHARGE_SUB_FATE < 럭키 아이템 형식: { 무제한, 시간 제한, 시간 만료시 사용 불가 }
// eCHARGE_SUB_COORDINATE_EX < 이중 타이머: 사용 기간 만료시 삭제 + 등록된 웨이포인트 삭제시 다음 삭제 가능 시점 설정
// eCHARGE_SUB_RIDER_WITH_PART < 연관 타이머:
// - 라이더: 입수 시점부터 일정 기간 사용 후, 사용 불가 형태로 설정
// - 파츠: 장착 시점부터 일정 기간 사용 후, 사용 불가 형태로 설정
// eCHARGE_SUB_RIDER_WITH_PART_NOTIMER < 연관 타이머:
// - 라이더: 기간 없음(eCHARGE_SUB_GENERAL), 장착된 파츠는 기간 존재할 수 있음.
// - 파츠: 기간 없음, 라이더에 장착된 다른 파츠는 기간 존재 가능
// 장착되지 않고 독립적으로 존재시 'eCHARGE_SUB_GENERAL'와 동일
switch(charge_sub_type)
{
case eCHARGE_SUB_FIXED_AMOUNT:
case eCHARGE_SUB_FIXED_AMOUNT_EX2:
{ //< 정액제 : 일정 기간제 (2007-06-07 24:12:30)
util::GetDateTime_YYYYMMDDHHMMSS(curr_time_wz);
if (curr_time_wz > time_info_.date_time_) {
time_info_.is_expired_ = true;
return false;
}
}
break;
case eCHARGE_SUB_FIXED_AMOUNT_EX:
{ //< 확장정액제 : 착용시 부터 일정 기간 사용 (30시간 -> 2007-06-07 24:12:30)
if (false != time_info_.is_progress_)
{
util::GetDateTime_YYYYMMDDHHMMSS(curr_time_wz);
if (curr_time_wz > time_info_.date_time_)
{
time_info_.is_expired_ = true;
time_info_.is_progress_ = false;
return false;
}
}
}
break;
case eCHARGE_SUB_FIXED_AMOUNT_WAIT:
{ //기한 만료시 일주일 대기, 대기 시간도 지나면 삭제
util::GetDateTime_YYYYMMDDHHMMSS(curr_time_wz);
if (time_info_.is_expired_wait_)
{
// 일주일의 대기시간 마저 지나면 삭제한다.
if (curr_time_wz > time_info_.date_time_)
{
time_info_.is_expired_ = true;
time_info_.is_expired_wait_ = false;
return false;
}
}
else {
// 기간이 다 되면 일주일의 대기시간을 준다.
if (curr_time_wz > time_info_.date_time_)
{
time_info_.is_expired_wait_ = true;
SetDateTime(FIXED_AMOUNT_EXPIRE_WAIT_TIME);
return false;
}
}
}
break;
case eCHARGE_SUB_FIXED_QUANTITY:
{ //< 정량제 : 사용 기간제 (30시간)
if (time_info_.is_expired_ == false)
{
time_info_.is_expired_ = _UpdateTime();
}
return !time_info_.is_expired_;
}
break;
case eCHARGE_SUB_FATE:
{ //< 럭키 아이템 형식: { 무제한, 시간 제한, 시간 만료시 사용 불가 }
//무제한 아이템은 시간 갱신 안함
if (shared_.fate_info_.period_ == INFINITE_ITEM_DAY) {
return true;
}
if (time_info_.is_expired_wait_) {
return true;
}
util::GetDateTime_YYYYMMDDHHMMSS(curr_time_wz);
// 기간이 다 되면 사용 불가 상태로 만든다.
if (shared_.fate_info_.identify_ && curr_time_wz > time_info_.date_time_)
{
time_info_.is_expired_wait_ = true;
return false;
}
}
break;
case eCHARGE_SUB_COORDINATE_EX:
{ //< 이중 타이머: 사용 기간 만료시 삭제 + 등록된 웨이포인트 삭제시 다음 삭제 가능 시점 설정
if (false != time_info_.is_progress_)
{
util::GetDateTime_YYYYMMDDHHMMSS(curr_time_wz);
SCWayPointInfo& waypoint_edit = shared_.waypoint_info_.GetEditableObject();
if (curr_time_wz > time_info_.date_time_)
{
time_info_.is_expired_ = true;
time_info_.is_progress_ = false;
waypoint_edit.Clear();
return false;
}
waypoint_edit.Update(curr_time_wz);
}
}
break;
case eCHARGE_SUB_RIDER_WITH_PART: //[09]
case eCHARGE_SUB_RIDER_WITH_PART_NOTIMER: //[10]
{
//[09] 연관 타이머:
// - 라이더: 입수 시점부터 일정 기간 사용 후, 사용 불가 형태로 설정
// - 파츠: 장착 시점부터 일정 기간 사용 후, 사용 불가 형태로 설정
//[10] 연관 타이머:
// - 라이더: 기간 없음(eCHARGE_SUB_GENERAL), 장착된 파츠는 기간 존재할 수 있음.
// - 파츠: 기간 없음, 라이더에 장착된 다른 파츠는 기간 존재 가능
// 장착되지 않고 독립적으로 존재시 'eCHARGE_SUB_GENERAL'와 동일
util::GetDateTime_YYYYMMDDHHMMSS(curr_time_wz);
if (item_rule_info_.is_rider)
{
// (NOTE) Rider 아이템은 기한 만료시 파츠 업데이트가 필요하다.
// Rider 자체에 기한 만료가 아닌 파츠 개별 업데이트시에도 동일하게 false반환으로
//이벤트 발동시킨다.
bool result = shared_.rider_info_._UpdateRider(this, curr_time_wz);
if (result == false) {
// notification to PlayerRider? 장착 아이템 가부 설정 필요
return false;
}
}
else if (item_rule_info_.is_rider_parts)
{
if (shared_.rider_parts_info_.is_unlimited_period_) {
time_info_.date_time_ = curr_time_wz; // 계속적으로 업데이트를 수행한다?
return true;
}
// 독립 아이템으로 존재시에는 SCItemSlot의 시간 정보를 활용한다.
if (time_info_.is_expired_wait_) {
return true;
}
// 장착 한번이라도 했으면, is_progress_ != false
if (time_info_.is_progress_ == false) {
return true;
}
if (curr_time_wz > time_info_.date_time_)
{
time_info_.is_expired_wait_ = true;
time_info_.is_progress_ = false;
return false; // 하위 로직에서 연관 이벤트가 발동해야 한다.
}
}
else
{
ASSERT(!"Unexpected value");
}
}
break;
} //end 'switch'
return true;
}
BOOL
SCItemSlot::DecreasingDura(eDecDuraType eDecType)
{
if (item_rule_info_.is_valid_item == false) {
return false;
}
//assert(item_info_ != 0);
if (item_info_->m_dwDuraStr == 0) {
return false;
}
// WithDura와 같은 내구도로 사용되는 아이템인지의 검증이 필요할 것 같지만...
int fWeaponRatio = 0, fArmorRatio = 0;
if (eDecType == DECDURA_TYPE_ATTACK)
{
fWeaponRatio = 170000;
fArmorRatio = 42500;
}
else
{
fWeaponRatio = 340000;
fArmorRatio = 85000;
}
if (item_info_->IsWeapon())
{
int fSuccessRatio = (int)dRandom(0, fWeaponRatio);
if (fSuccessRatio <= 100)
{
if (duration_ >= 1) {
duration_ -= 1;
}
return true;
}
}
else if (item_info_->IsArmor())
{
int fSuccessRatio = (int)dRandom(0, fArmorRatio);
if (fSuccessRatio <= 100)
{
if (duration_ >= 1) {
duration_ -= 1;
}
return true;
}
}
return false;
}
BOOL
SCItemSlot::StoreDamageNDecreaseDura(const DWORD damage)
{
if (item_rule_info_.is_valid_item == false) {
return false;
}
const DWORD duration_strength = item_info_->m_dwDuraStr;
if (duration_strength == 0) {
return false;
}
#ifdef _NA_0_20111130_DISTROY_WEAPON
if ((duration_ == 0) && damage)
return true;
#endif
m_DamageStoreForDura += damage;
if (m_DamageStoreForDura >= duration_strength)
{
if (duration_ >= 1) {
duration_ -= 1;
}
m_DamageStoreForDura -= duration_strength;
return true;
}
return false;
}
//==================================================================================================
MONEY
SCItemSlot::GetPriceForRepair() const
{
const DURATYPE max_duration = GetMaxDura(); // side-effect FCAssert(WithDura())
if (max_duration == 0) {
return 0;
}
MONEY price_for_buy = GetPriceForBuy();
duration_;
return ns_formula::CalcPriceForDura((DWORD)price_for_buy, duration_, max_duration);
}
// (UNUSED) ??
LEVELTYPE
SCItemSlot::GetLimitLevel() const
{
if (GetItemInfo()->IsAccessory())
{
return CalcLimitLVAccessory(GetItemInfo()->m_LimitEqLevel, GetRank());
}
return GetItemInfo()->m_LimitEqLevel;
}
#if SUN_CODE_BACKUP
// (UNUSED) ??
DWORD
SCItemSlot::GetPhyDef() const
{
WORD PhyDef = GetItemInfo()->m_wPhyDef;
if (GetSet() == 1)
{
PhyDef = CalcPhyDefForDivineArmor(PhyDef, GetItemInfo()->m_LV);
}
return CalcPhyDef(PhyDef, GetEnchant(), GetItemInfo()->m_LV);
}
#endif
//==================================================================================================
// Rank Option
eRANK_LEVEL
SCItemSlot::GetRankLevel() const
{
if (item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Rank)
{
switch(rank_info_.current_rank_)
{
case RANK_F: case RANK_E: case RANK_D: case RANK_C: case RANK_B:
return RANK_LOW;
case RANK_MA: case RANK_A: case RANK_PA:
return RANK_MIDDLE;
case RANK_MS: case RANK_S: case RANK_PS:
return RANK_HIGH;
}
}
ASSERT(!"잘못된 랭크입니다.");
return RANK_LOW;
}
//
//==================================================================================================
//
//--------------------------------------------------------------------------------------------------
// (WARNING) 하기 계산용 함수들의 정확한 결과를 보장하는 것은 외부 제어에 의한 것이다.
// 잘못된 정보의 경우는 사는 가격은 왕창, 파는 가격은 0로 할까? hummm...
// (091001) 일단은 기존 로직대로 하기로 한다. 단 문제 있는 경우는...
MONEY
SCItemSlot::GetDropLevel() const
{
// TODO(WAVERIX) 내부에서 많이 사용하는 함수다.
//잘못된 가격일 경우에 대한 에러 코드 '0'로 설정했을 때의 문제점을 파악하기로 한다.
if (item_rule_info_.is_valid_item == false) {
return 0;
}
// formula
// cur_drop_level = item_info::m_DropLV + enchant_weight + rank_weight(0)
// 인첸트 1단계 당 몬스터 드랍 레벨 2씩 증가
MONEY enchant_weight = (MONEY)GetEnchant() << 1;
MONEY rank_weight = 0; //GetRank() * 0; //...?
bool is_divine = IsDivine();
MONEY cur_drop_level = item_info_->m_DropLV + enchant_weight + rank_weight;
if (is_divine && (item_rule_info_.is_weapon || item_rule_info_.is_armor)) {
cur_drop_level = ns_formula::CalcDropLVForDivine(cur_drop_level);
}
return cur_drop_level;
}
MONEY
SCItemSlot::GetPriceForBuy() const
{
//잘못된 가격일 경우에 대한 에러 코드 '0'로 설정했을 때의 문제점을 파악하기로 한다.
if (item_rule_info_.is_valid_item == false) {
return 0;
}
MONEY drop_level = GetDropLevel();
eRANK rank = GetRank();
BYTE enchant = GetEnchant();
bool is_divine = IsDivine();
MONEY item_price_for_buy =
(MONEY)ns_formula::CalcItemPriceForBuy(drop_level, rank, enchant, is_divine);
// ranges of 'GetNum'
// if duplicated then [0, 256)
// else then 1
item_price_for_buy *= GetNum();
return item_price_for_buy;
}
// 인챈트시 소모 가격 책정용
MONEY
SCItemSlot::GetPriceForUpGradeFare() const
{
//잘못된 가격일 경우에 대한 에러 코드 '0'로 설정했을 때의 문제점을 파악하기로 한다.
if (item_rule_info_.is_valid_item == false) {
return 0;
}
#ifdef _NA_006589_20120415_ENCHANT_PRICE_MODIFY
MONEY drop_level = item_info_->m_DropLV;
#else
DWORD drop_level = GetDropLevel();
#endif
eRANK rank = GetRank();
BYTE enchant = GetEnchant();
bool is_divine = IsDivine();
MONEY item_price_for_upgrade_fare =
(MONEY)ns_formula::CalcItemPriceForUpGradeFare(drop_level, rank, enchant, is_divine);
// enchant가 일어나는 아이템이 중첩이 가능한가? - assert = NO!
// (WAVERIX) (CHANGES) GetNum의 곱셈 제거
return item_price_for_upgrade_fare;
}
MONEY
SCItemSlot::GetPriceForSell() const
{
//잘못된 가격일 경우에 대한 에러 코드 '0'로 설정했을 때의 문제점을 파악하기로 한다.
if (item_rule_info_.is_valid_item == false) {
return 0;
}
// default
MONEY drop_level = GetDropLevel();
eRANK rank = GetRank();
MONEY item_price_for_sell = 0;
// (WAVERIX) (CHANGES) WithDura오용... is_weapon || is_armor라면 assert(WithDura() != 0)
if (item_rule_info_.is_weapon || item_rule_info_.is_armor)
{
BYTE enchant = GetEnchant();
bool is_divine = IsDivine();
MONEY item_price_for_repair = GetPriceForRepair();
item_price_for_sell = (MONEY)ns_formula::CalcItemPriceForSellWithDura(item_info_->m_LV,
drop_level, rank, enchant, is_divine, item_price_for_repair);
}
else if (item_rule_info_.is_accessory)
{
// (NOTE) 거듭되는 의문인데, special accessory는 accessory취급은 하지 않는 것인가?
item_price_for_sell = \
(MONEY)ns_formula::CalcItemPriceForSellWithoutDura(drop_level, rank, 0, 0);
}
else
{
assert(rank == RANK_E);
item_price_for_sell = \
(MONEY)ns_formula::CalcItemPriceForSellWithoutDura(drop_level, RANK_E, 0, 0);
item_price_for_sell *= GetNum();
}
return item_price_for_sell;
}
//==================================================================================================
// Socket Item Option
bool SCItemSlot::ExistEmptySocket(OUT eSOCKET& empty_socket_out) const
{
// 아이템 규칙을 검사한다.
if ((item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Socket) == 0) {
return false;
}
// (WARNING) GetSocketAttrIndex은 존재하는 소켓에 대한 연산이다.
// (BUGFIX) (WOPS:36529) 엘리트 아이템에 속성 추가가 되지 않는 현상
// (CHANGES) 주석 처리
// (NOTE) 이 코드 블록 작업 당시 GetSocketNum()을 순간 착각한 듯. 단순히 허용 개수를 의미한다.
/*
const int number_of_sockets = GetSocketNum();
if (number_of_sockets == SOCKET_MAX)
return false;
*/
// 빈 소켓이 있는지 검사한다.
bool is_find_empty_socket = false;
int socket_index = 0;
for (; socket_index < SOCKET_MAX; ++socket_index)
{
#ifdef _NA_0_20100727_SOCKET_SYSTEM_CONVERT
const SCSocketOptionInfo::AttrValues& socket_attr_value =
socket_info_.socket_attributes_[socket_index];
if (socket_attr_value.first == 0)
{
is_find_empty_socket = true;
break;
}
#else
const SCSocketInfo::AttrValues& socket_attr_value =
socket_info_.socket_attributes_[socket_index];
if (socket_attr_value.attr_index_ == 0) {
is_find_empty_socket = true;
break;
}
#endif // _NA_0_20100727_SOCKET_SYSTEM_CONVERT
}
// 허용 가능한 소켓수를 초과 했는지 검사한다.
const int max_socket_num = GetSocketNum();
if ((is_find_empty_socket == true) && (socket_index < max_socket_num))
{
empty_socket_out = static_cast<eSOCKET>(socket_index);
return true;
}
return false;
}
// 해당 등급의 쟈드가 삽입 가능한지 검사한다.
bool SCItemSlot::IsEnableFillSocketByGrade(const eSOCKET_LEVEL zard_grade) const
{
#ifdef _NA_0_20100727_SOCKET_SYSTEM_CONVERT
const size_t max_filled_socket_list[kZardGradeMax] =
{
0, // 등급 사용 안함
5, // 하급 쟈드 허용 개수
3, // 중급 쟈드 허용 개수
2, // 상급 쟈드 허용 개수
1 // 최상급 쟈드 허용 개수
};
const size_t max_number_of_filled_socket = max_filled_socket_list[zard_grade];
// 해당 등급의 쟈드가 몇개나 박혀 있는지 검사한다.
size_t number_of_filled_socket = 0;
{
const int number_of_socket = GetSocketNum();
for (int i = 0; i < number_of_socket; ++i)
{
const eSOCKET socket_index = static_cast<eSOCKET>(i);
const sSOCKET_OPTION* const socket_option = GetSocketOption(socket_index);
if (socket_option != NULL)
{
if (socket_option->zard_grade == zard_grade)
{
++number_of_filled_socket;
}
}
}
}
// 허용 개수까지 모두 박혀 있는지 검사한다.
if (number_of_filled_socket >= max_number_of_filled_socket)
{
return false;
}
#else
__UNUSED(zard_grade);
#endif // _NA_0_20100727_SOCKET_SYSTEM_CONVERT
return true;
}
//==================================================================================================
// Limited Item Option
//--------------------------------------------------------------------------------------------------
// Limited Control
void
SCItemSlot::SetLimitedIndex(WORD limited_index)
{
if (item_rule_info_.is_valid_item == false ||
limited_index == 0)
{
return;
}
//
if (_CanChangeToLimited() == false) { // important!!
return;
}
// preparing...
// post action = on Recv Serial, change to limited item
// desired next call : 'CalLimited();
shared_.limited_info_.limited_index_ = limited_index; // temp backup
}
//--------------------------------------------------------------------------------------------------
// Limited Control
bool
SCItemSlot::_CanChangeToLimited() const
{
// (WARNING) 리미티드 설정 가능한 것은 방어구 (Armor)뿐이다.
// Constraints#1 - 이미 리미티드가 아니어야 한다.
// Constraints#2 - 방어구인가?
// Constraints#3 - 기타 다른 속성이 없는 가? (러키 등등, shared_정보를 공유하는...)
if (item_rule_info_.is_valid_item == false) {
assert(!"invalid item type");
return false;
}
if (item_rule_info_.is_can_overlap != false) {
//assert(!"invalid item type : enable duplicate");
return false;
}
// Constraints#1 - 이미 리미티드가 아니어야 한다.
if (item_rule_info_.is_limited != false) { // check stored type
//assert(!"already limited item");
return false;
}
// Constraints#2 - 방어구인가?
if (item_rule_info_.is_armor == false) {
//assert(!"must be armor");
return false;
}
// Constraints#3 - 기타 다른 속성이 없는 가? (러키 등등, shared_정보를 공유하는...)
// (WARNING)
if (_CanReuseSharedBlock() == false) {
assert(!"already another item");
return false;
}
nsSlot::ItemRuleInfo item_rule_info; // 외부 설정용 Limited -
if (nsSlot::ItemRuleInfo::GetRuleInfo(&item_rule_info, *this, true, NULL) == false) {
assert(!"other rule exist");
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
// Limited Control
bool
SCItemSlot::_ChangeToLimitedType()
{
// 초기화시에 부여해야 하는 것, 아이템 초기 정보를 설정한다.
nsSlot::ItemRuleInfo item_rule_info; // 외부 설정용 Limited -
if (nsSlot::ItemRuleInfo::GetRuleInfo(&item_rule_info, *this, true, NULL) == false)
{
__debugbreak(); // i want must be true, already checked in '_CanChangeToLimited'
return false; // 아이템 정보가 잘못 되었을 가능성이 높습니다.
}
if (!FlowControl::FCAssert(item_rule_info.is_valid_item && item_rule_info.is_limited)) {
return false;
}
const_cast<nsSlot::ItemRuleInfo&>(item_rule_info_) = item_rule_info;
equip_info_.is_limited_ = true;
return true;
}
//--------------------------------------------------------------------------------------------------
// Limited Control
void
SCItemSlot::CalLimited()
{
// called state:
// on Recv Serial key, called by 'ItemManager::AddSerialCode'
const WORD limited_index = shared_.limited_info_.limited_index_;
if (limited_index == 0) {
return;
}
if (_CanChangeToLimited() == false) {
return;
}
//if (IsOverlap())
//{
// ASSERT(FALSE);
// DISPMSG("Overlap Item must not CalLimited : %d \n", limited_index);
// return;
//}
if (_ChangeToLimitedType() == false) {
return;
}
shared_.limited_info_.CalLimited(item_code_);
//내구도
SetDura(GetMaxDura());
}
// 아이템 복사(for stat change) - serial key not issued, need serial key
// (090929) (ADD-IN)
bool
SCItemSlot::CopyFromSrcForStatChange(SLOTCODE to_change_item_code, const SCItemSlot& src)
{
if (src.item_rule_info_.is_valid_item == false) {
return false;
}
if (src.IsBlocked() || src.IsLocked()) {
return false;
}
//__UNUSED(const BASE_ITEMINFO* src_item_info = src.item_info_;);
if (src.item_rule_info_.is_weapon == false && src.item_rule_info_.is_armor == false) {
return false;
}
// skip! elite check
if (src.item_rule_info_.is_fate || src.item_rule_info_.is_limited) {
return false;
}
const BASE_ITEMINFO* new_item_info = ItemInfoParser::Instance()->GetItemInfo(to_change_item_code);
if (new_item_info == NULL) {
return false;
}
if (!FlowControl::FCAssert(new_item_info->m_wWICode == src.item_info_->m_wWICode &&
new_item_info->m_wVICode == src.item_info_->m_wVICode &&
new_item_info->m_NCode == src.item_info_->m_NCode))
{
return false;
}
SetCode(to_change_item_code); // buildup configurations
if (item_rule_info_.is_valid_item == false) {
return false;
}
// copy options
CopyMemory(item_slot_point_holder_options_, src.item_slot_point_holder_options_,
static_cast<size_t>(&item_slot_point_holder_last_[2] - item_slot_point_holder_options_));
// (NOTE) 각종 필터링에 걸리면 공유 정보는 사용하지 않는다.
// clear shared block
ZeroMemory(&shared_, sizeof(shared_));
//버그수정:36567 2010-02-02 문상현 0905이상모든국가공통적용 헤르메시즘 성서 사용시 내구도 변경되는 버그
DURATYPE duration = src.GetDura();
DURATYPE max_duration = GetMaxDura();
DURATYPE align = duration > max_duration ? max_duration : duration;
SetDura(align);
return true;
}
//--------------------------------------------------------------------------------------------------
// CHANGES: f110327.1L, changes charge_sub_type access field
// to support various making item with timer
// accetable = { sDefault -> sTime, sEquip -> sEquipTime, sEquipEtc -> sEquipEtcTime }
bool SCItemSlot::ChangeItemToUsingTimer()
{
if (item_rule_info_.is_valid_item == false) {
return false;
};
;{ // filters to prevent the below conditions
// can't change item that is not acceptable type like a limited, lucky(fate), etc ...
if (item_rule_info_.is_editable == false) {
return false;
};
if (item_rule_info_.is_can_overlap) {
return false;
};
if (item_rule_info_.is_limited || item_rule_info_.is_fate) {
return false;
};
if (item_rule_info_.is_shell) {
return false;
};
bool only_accept_item_types =
(item_rule_info_.is_normal ||
item_rule_info_.is_armor || item_rule_info_.is_weapon ||
item_rule_info_.is_accessory || item_rule_info_.is_accessory_special ||
//youngmoon 2011-11-25 드랍에 캐쉬아이템중 펫, 탈것 가능하게 한다.
item_rule_info_.is_pet || item_rule_info_.is_rider ||
item_rule_info_.is_costume || item_rule_info_.is_toggle_item
#ifdef _NA_007031_20140116_MODIFIED_PANDORABOX_ITEM_POLICY
|| item_rule_info_.is_waypoint
#endif //_NA_007031_20140116_MODIFIED_PANDORABOX_ITEM_POLICY
#ifdef _NA_008610_20160104_ADD_DECORATECOSTUME
|| item_rule_info_.is_deco_costume
#endif //_NA_008610_20160104_ADD_DECORATECOSTUME
);
if (only_accept_item_types == false) {
return false;
};
};
//
ItemParseType::ValueType parse_type = 0;
if (item_rule_info_.is_armor || item_rule_info_.is_weapon) {
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT_EX) {
return true;
};
if (item_rule_info_.charge_sub_type != eCHARGE_SUB_GENERAL) {
return false; // exist already used timer
};
parse_type = ItemParseType::kEquipTime;
}
else if (item_rule_info_.is_accessory || item_rule_info_.is_accessory_special) {
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT_EX
#ifdef _NA_008150_20150331_MODIFY_EX2_CHARGE_SUB_TYPE_USABLE_ANOTHER_FUNC
|| item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT_EX2
#endif // _NA_008150_20150331_MODIFY_EX2_CHARGE_SUB_TYPE_USABLE_ANOTHER_FUNC
) {
return true;
};
if (item_rule_info_.charge_sub_type != eCHARGE_SUB_GENERAL) {
return false; // exist already used timer
};
parse_type = ItemParseType::kEquipEtcsTime;
}
//youngmoon 2011-11-25 드랍에 캐쉬아이템중 펫, 탈것 가능하게 한다.
else if (item_rule_info_.is_pet) {
#ifdef _NA_008389_20150703_TIMERITEM_PET_DROP_RULE
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT ||
item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_QUANTITY) {
return true;
};
#else
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_QUANTITY) {
return true;
};
#endif //_NA_008389_20150703_TIMERITEM_PET_DROP_RULE
if (item_rule_info_.charge_sub_type != eCHARGE_SUB_GENERAL) {
return false; // exist already used timer
};
parse_type = ItemParseType::kPet;
}
else if (item_rule_info_.is_rider) {
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_RIDER_WITH_PART ||
item_rule_info_.charge_sub_type == eCHARGE_SUB_RIDER_WITH_PART_NOTIMER) {
return true;
};
if (item_rule_info_.charge_sub_type != eCHARGE_SUB_GENERAL) {
return false; // exist already used timer
};
parse_type = ItemParseType::kRider;
}
#ifdef _NA_008610_20160104_ADD_DECORATECOSTUME
else if (item_rule_info_.is_deco_costume)
#else
else if (item_rule_info_.is_costume)
#endif //_NA_008610_20160104_ADD_DECORATECOSTUME
{
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT_EX) {
return true;
}
if (item_rule_info_.charge_sub_type != eCHARGE_SUB_GENERAL) {
return false; // exist already used timer
};
parse_type = ItemParseType::kEquipEtcsTime;
}
else if (item_rule_info_.is_toggle_item) {
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT ||
item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT_EX ||
item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_QUANTITY)
{
return true;
}
if (item_rule_info_.charge_sub_type != eCHARGE_SUB_GENERAL) {
return false; // exist already used timer
};
parse_type = ItemParseType::kEquipEtcsTime;
}
////////
else { //item_rule_info_.is_normal
#ifdef _NA_007031_20140116_MODIFIED_PANDORABOX_ITEM_POLICY
if (item_rule_info_.charge_sub_type > eCHARGE_SUB_GENERAL &&
item_rule_info_.charge_sub_type < eCHARGE_SUB_COUNTS) {
return true;
};
#else
if (item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT ||
item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_AMOUNT_EX2) {
return true;
};
if (item_rule_info_.charge_sub_type != eCHARGE_SUB_GENERAL) {
return false; // exist already used timer
};
#endif //_NA_007031_20140116_MODIFIED_PANDORABOX_ITEM_POLICY
parse_type = ItemParseType::kDefaultTime;
}
//
nsSlot::ItemRuleInfo modifying_rule;
if (nsSlot::ItemRuleInfo::GetRuleInfo(&modifying_rule, *this,
item_rule_info_.is_limited, &parse_type) == false)
{
return false;
};
const_cast<nsSlot::ItemRuleInfo&>(item_rule_info_) = modifying_rule;
ZeroMemory(&time_info_, sizeof(time_info_));
return true;
}
//--------------------------------------------------------------------------------------------------
// Limited Control
BOOL
SCItemSlot::DecreasingMaxDura()
{
if (!IsLimited()) {
return false;
}
int max_duration = shared_.limited_info_.max_duration_;
if (max_duration <= 2) {
return false;
}
max_duration -= 2;
if (max_duration <= 0) {
max_duration = 0;
}
shared_.limited_info_.max_duration_ = static_cast<DURATYPE>(max_duration);
return true;
}
//--------------------------------------------------------------------------------------------------
// Limited Control
void
SCItemSlot::RepairMaxDura()
{
if (item_rule_info_.is_limited == false) {
assert(0);
return;
}
#ifdef __NA_1024_MODIFY_LIMITED_ITEM_REPAIR_COUNT
//체크 안하는걸로 변경
#else
if (GetLimitedRepairCount() <= 0) {
return;
}
#endif
shared_.limited_info_.max_duration_ = shared_.limited_info_.max_duration_for_restore_;
#ifdef __NA_1024_MODIFY_LIMITED_ITEM_REPAIR_COUNT
//체크 안하는걸로 변경
#else
if (shared_.limited_info_.number_of_repairs_) {
--shared_.limited_info_.number_of_repairs_;
}
#endif
}
//--------------------------------------------------------------------------------------------------
// Limited Control
void
SCItemSlot::SetLimitValueRatio(int value)
{
if (item_rule_info_.is_limited == false) {
assert(0);
return;
}
if (value < -100 || 400 < value) {
return;
}
shared_.limited_info_.limit_value_ratio_ = value;
}
//--------------------------------------------------------------------------------------------------
// Limited Control
void
SCItemSlot::SetLimitedDuraMax(WORD value)
{
if (item_rule_info_.is_limited == false) {
assert(0);
return;
}
if (value > 255) {
return;
}
shared_.limited_info_.max_duration_ = DURATYPE(value);
}
//--------------------------------------------------------------------------------------------------
// Limited Control
void
SCItemSlot::SetLimitedDuraMMax(WORD value)
{
if (item_rule_info_.is_limited == false) {
assert(0);
return;
}
if (value > 255) {
return;
}
shared_.limited_info_.max_duration_for_restore_ = DURATYPE(value);
}
//--------------------------------------------------------------------------------------------------
// Limited Control
void
SCItemSlot::SetLimitedRepairCount(BYTE value)
{
if (item_rule_info_.is_limited == false) {
assert(0);
return;
}
if (value > 15) {
return;
}
// TODO(WAVERIX) 수리 회수 제한이 15이다... 검증할 것.
shared_.limited_info_.number_of_repairs_ = value;
}
//--------------------------------------------------------------------------------------------------
// Limited Control - 명공의 망치
//아이템 수리 필요여부
BOOL
SCItemSlot::IsNeedToRepair()
{
if (item_rule_info_.is_editable == false) {
return false;
}
if (item_rule_info_.is_limited == false) {
return false;
}
if (WithDura() == false) {
return false;
}
const DURATYPE max_duration = GetMaxDura();
if (max_duration == duration_ &&
max_duration == GetLimitedDuraMMax())
{
return false;
}
return true;
}
//==================================================================================================
// Fate Item Control
//
bool
SCItemSlot::CalFateInfo()
{
if (IsFateItem() == false) {
return false;
}
// (NOTE) 하기 내용은 사전 Rule검사가 이뤄지는 내용
//if (IsOverlap())
//{
// ASSERT(FALSE);
// DISPMSG("Overlap Item must not CalFate : %d \n", item_code_);
// return FALSE;
//}
//ASSERT(IsFateItem());
FateItemInfoParser* const pFateItemInfoParser = FateItemInfoParser::Instance();
const sFATE_ITEM_INFO* pFateItemInfo =
pFateItemInfoParser->GetFateItemInfoByRefItemCode(item_code_);
if (!FlowControl::FCAssert(pFateItemInfo != NULL)) {
SUNLOG(eCRITICAL_LOG, _T("|[%s]|can't find lucky item info, code=%d|"),
__FUNCTION__, item_code_);
return false;
}
//
SCFateInfo backup = shared_.fate_info_;
if (!shared_.fate_info_.CalFate(item_code_, pFateItemInfo->m_dwIndex)) {
return false;
}
//내구도 - routing duration by item type
SetDura(GetMaxDura());
return true;
}
bool
SCItemSlot::CalFateDateTime(DWORD& OUT date_time)
{
if (IsFateItem() == false) {
return false;
}
// (NOTE) 하기 내용은 사전 Rule검사가 이뤄지는 내용
//if (IsOverlap())
//{
// ASSERT(FALSE);
// DISPMSG("Overlap Item must not CalFate : %d \n", item_code_);
// return FALSE;
//}
//이미 감정 했음.
if (GetFateIdentify()) {
return false;
}
FateItemInfoParser* const pFateItemInfoParser = FateItemInfoParser::Instance();
const sFATE_ITEM_INFO* pFateItemInfo = \
pFateItemInfoParser->GetFateItemInfoByRefItemCode(item_code_);
//
if (!FlowControl::FCAssert(pFateItemInfo != NULL)) {
SUNLOG(eCRITICAL_LOG, _T("|[%s]|can't find lucky item info, code=%d|"),
__FUNCTION__, item_code_);
return false;
}
// (NOTE) ...어캐 검증할 까?
date_time = pFateItemInfoParser->GetRandomkeyFromFateUsingTimeRatio(pFateItemInfo->m_dwIndex);
return true;
}
void
SCItemSlot::SetFateAtkDefRatio(WORD value)
{
if (item_rule_info_.is_fate == false) {
assert(0);
return;
}
if (value > 511) {
value = 511;
}
shared_.fate_info_.ratio_ = value;
}
void
SCItemSlot::SetFateDuraMax(WORD value)
{
if (item_rule_info_.is_fate == false) {
assert(0);
return;
}
const DURATYPE Max_Duration = DURATYPE(-1);
BOOST_STATIC_ASSERT(Max_Duration == 65535);
if (value > Max_Duration) {
value = Max_Duration;
}
shared_.fate_info_.max_duration_ = DURATYPE(value);
}
// Fate Item Control
//==================================================================================================
// NOption < ExtraStone Option
void
SCItemSlot::SetNOptionAttr(int iAttrValueIndex)
{
if (item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_NOption)
{
if (item_info_->m_Code != 0) {
n_option_info_.SetNOptionAttr(item_info_->m_wType, item_info_->m_LV, iAttrValueIndex);
}
return;
}
assert(0);
}
//
//==================================================================================================
// Pet Item Control
// (NOTE) 후우... 이름 너무 Generic하다.
bool
SCItemSlot::StartQuantity()
{
// (THINKING) Pet item일 때, 사용하는데... 타이머가 존재할 수도 있고, 그렇지 않을 수도 있고...
if (item_rule_info_.is_pet == false) {
assert(0);
return false;
}
if (item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Timer)
{
assert(item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_QUANTITY);
if (time_info_.is_expired_) {
return false;
}
ASSERT(time_info_.date_time_ != 0);
ASSERT(time_info_.last_checked_ == 0);
time_info_.last_checked_ = GetTickCount();
return true;
}
return true; // 시간 제한 없는 펫일 경우
}
void
SCItemSlot::EndQuantity()
{
if (item_rule_info_.is_pet == false) {
assert(0);
return;
}
if (item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Timer)
{
assert(item_rule_info_.charge_sub_type == eCHARGE_SUB_FIXED_QUANTITY);
if (time_info_.is_expired_) {
return;
}
time_info_.is_expired_ = _UpdateTime();
time_info_.last_checked_ = 0;
}
}
//==================================================================================================
// Rider & Rider Parts Item Control
//--------------------------------------------------------------------------------------------------
bool
SCItemSlot::GetRiderPartsInfo(eRIDER_PARTS_POS pos, SCRiderPartsData* OUT parts_data) const
{
if (item_rule_info_.is_rider == false) {
assert(0);
return false;
}
// (returns) if exist then Acquire 'SCRiderPartsInfo'
// { exist | empty (cleared stream), check 'parts_type_' }
// else then return 0 { index out of range }
const SCRiderPartsInfo* parts_info = shared_.rider_info_.GetPartsInfo(this, pos);
if (parts_info == NULL) {
return false;
}
*parts_data = *parts_info;
return true;
}
bool
SCItemSlot::GetRiderPartsItem(eRIDER_PARTS_POS pos, SCItemSlot* OUT parts_item) const
{
if (item_rule_info_.is_rider == false) {
assert(0);
return false;
}
const SCRiderPartsInfo* parts_info = shared_.rider_info_.GetPartsInfo(this, pos);
if (parts_info == NULL) {
return false;
}
if (parts_info->item_code_ == 0) {
parts_item->Clear();
return true;
}
if (SCRiderPartsInfo::ExtractToItem(*parts_info, parts_item) == false) {
return false;
}
return true;
}
RC::eITEM_RESULT
SCItemSlot::CanEquipRiderParts(const SCItemSlot& rider_part_item)
{
if (item_rule_info_.is_rider == false ||
rider_part_item.item_rule_info_.is_valid_item == false)
{
assert(0);
return RC::RC_ITEM_INVALID_TYPE;
}
if (rider_part_item.item_rule_info_.is_rider_parts == false) {
return RC::RC_ITEM_INVALID_TYPE;
}
// Locked Blocked
if (lock_info_.locked_ || lock_info_.blocked_ ||
lock_info_.user_blocked_ == false) // UserBlocked|RiderSummoned|PetLocked
{
// (NOTE) 락상태 아니어야 하고, 소환된 상태여야 한다.(with Open RiderInventory)
return RC::RC_ITEM_INVALIDPOS;
}
if (rider_part_item.lock_info_.locked_ || rider_part_item.lock_info_.blocked_ ||
rider_part_item.lock_info_.user_blocked_) // UserBlocked
{
return RC::RC_ITEM_INVALIDPOS;
}
const BASE_ITEMINFO* parts_item_info = rider_part_item.item_info_;
if (item_info_->m_RidingClass.value != parts_item_info->m_RidingClass.value) {
return RC::RC_ITEM_CAN_NOT_EQUIP;
}
//SCRiderPartsInfo parts_info;
//if (SCRiderPartsInfo::ExtractToPartsInfo(rider_part_item, &parts_info) == false)
// return RC::RC_ITEM_INVALID_TYPE;
bool is_valid_pos = \
eRIDER_PARTS_POS::StartIndex <= parts_item_info->m_wEqPos &&
parts_item_info->m_wEqPos < eRIDER_PARTS_POS::EndIndex;
if (!FlowControl::FCAssert(is_valid_pos)) {
return RC::RC_ITEM_INVALIDPOS;
}
eRIDER_PARTS_POS pos = { (BYTE)parts_item_info->m_wEqPos };
RC::eITEM_RESULT result = shared_.rider_info_.CanEquipParts(*this, item_info_,
pos,
rider_part_item,
rider_part_item.item_info_);
return result;
}
bool
SCItemSlot::EquipRiderParts(const SCItemSlot& rider_part_item)
{
if (item_rule_info_.is_rider == false) {
assert(0);
return false;
}
if (rider_part_item.item_rule_info_.is_rider_parts == false)
{
assert(0);
return false;
}
const BASE_ITEMINFO* parts_item_info = rider_part_item.item_info_;
if (item_info_->m_RidingClass.value != parts_item_info->m_RidingClass.value) {
return false;
}
//SCRiderPartsInfo parts_info;
//if (SCRiderPartsInfo::ExtractToPartsInfo(rider_part_item, &parts_info) == false)
// return false;
eRIDER_PARTS_POS pos = { (BYTE)parts_item_info->m_wEqPos };
bool result = shared_.rider_info_.EquipParts(*this, item_info_,
pos, rider_part_item, rider_part_item.item_info_);
return result;
}
bool
SCItemSlot::CanUnEquipRiderParts(eRIDER_PARTS_POS pos, nsSlot::RiderUpdateBits* update_bits_ptr)
{
if (item_rule_info_.is_rider == false) {
assert(0);
return false;
}
bool result = shared_.rider_info_.GetUnEquipChangedBits(*this, pos, update_bits_ptr);
return result;
}
// int pos : eRIDER_PARTS_POS::eValue { 91, 92, 93 }
bool
SCItemSlot::UnEquipRiderParts(eRIDER_PARTS_POS pos, SCItemSlot* rider_part_item)
{
// (WARNING) 제거가 반드시 성공하기 위해서는 CanUnEquip이 필요할 거라 보인다.
rider_part_item->Clear();
if (item_rule_info_.is_rider == false) {
assert(0);
return false;
}
//SCRiderPartsInfo parts_info;
RC::eITEM_RESULT result = shared_.rider_info_.UnEquipParts(*this, pos, rider_part_item);
if (result != RC::RC_ITEM_SUCCESS) {
return false;
}
//if (SCRiderPartsInfo::ExtractToItem(parts_info, rider_part_item) == false) {
// assert(0);
// return false;
//}
return true;
}
nsSlot::RiderUpdateBits
SCItemSlot::RiderSummonStatus(BOOLEAN is_summoned) {
nsSlot::RiderUpdateBits update_bits = { 0, };
if (item_rule_info_.is_rider == false) {
assert(0);
return update_bits;
}
// DONE: update changed status
BOOLEAN pre = !!lock_info_.user_blocked_;
BOOLEAN post = !!is_summoned;
// (NOTE) update_bits(-1) {all_sub & all_add} command는 기한 고려해서 특수하게 처리할까?
// State diagram
// pre | post | result
// 0 0 X
// 0 1 add_rider, add_parts(all) with filter 'timeout'
// 1 0 sub_rider, sub_parts(all) with filter 'timeout'
// 1 1 X
if (pre < post) {
update_bits = shared_.rider_info_.GetUpdateEnableInfo(*this, true);
}
else if (pre > post) {
update_bits = shared_.rider_info_.GetUpdateEnableInfo(*this, false);
}
lock_info_.user_blocked_ = post;
shared_.rider_info_.update_bits_ = update_bits;
return update_bits;
}
//==================================================================================================
// implemented by _NA000109_100427_ITEM_CUSTOMIZING_CONTENTS_
//--------------------------------------------------------------------------------------------------
// fields specification related to the 'Etheria'
// the below diagram show a state flow that
// a default item can change to the etheria and the shell
// - the shell is the empty item which is extracted to etheria
// (custom = { ItemCode=10001 (금속양손도끼) }
//-------------------- function : split to the etheria and the shell -------------------------------
// Axe -|-> the shell
// |-> the etheria
// same slot : Axe = the shell
// add slot : the etheria
// same serial : Axe = the etheria (copied)
// Axe(->) the shell the etheria
// ItemCode (10001) (10001) (10001)
// Number (1) (1) (1) by the etheria
// ImageCode (10001) (10001) (HardCode::ITEMCODE_of_ETHERIA)
// sDefault::ParseType (eParse_Equip) (eParse_Equip) (eParse_Equip) same as default
// sDefault::Block false false false by the etheria
// sDefault::UserBlock false false false by the etheria
// sDefault::History (None) (Shell) (Etheria)
//
//--------------------------- function : combined from the shell -----------------------------------
// the etheria -|-> a combined item
// the shell -|
// same slot : the shell = Axe
// del slot : the etheria
// Axe(<-) the shell the etheria
// ItemCode (10001) (10002) (10001)
// Number (1) (1) (1) by the etheria
// ImageCode (10002) (10002) (HardCode::ITEMCODE_of_ETHERIA)
// sDefault::ParseType (eParse_Equip) (eParse_Equip) (eParse_Equip) same as default
// sDefault::Block false false false
// sDefault::UserBlock false false false
// sDefault::History (Combined) (Shell) (Etheria)
//--------------------------------------------------------------------------------------------------
// the 'History' field specification, referenced by eEtheriaHistory
// value = { 0, 1, 2, 3 };
// {0} : None - default spec.
// {1} : Combined - the combination item, this item is combined from etheria
// {2} : Shell - the shell item, this item is extracted options
// {3} : Etheria - the etheria item, this item has contained all options of the item
//--------------------------------------------------------------------------------------------------
// Shared Block & normal item (no equipment)
//struct sDefault {
// ulong ParseType; //8
//
// ulong Block; //1
// ulong UserBlock; //1
// ulong History; //2
//};
// SerializeItemOption::sDefault::History
//--------------------------------------------------------------------------------------------------
// internal function in a code file.
// reset rules based on the value of a lock_info.history_.
bool SCItemSlot::ChangeImageItemRule(eEtheriaHistory::value_type history)
{
lock_info_.history_.value = history;
//
nsSlot::ItemRuleInfo& item_rule_info = const_cast<nsSlot::ItemRuleInfo&>(item_rule_info_);
item_rule_info.is_shell = false;
item_rule_info.is_etheria = false;
item_rule_info.is_editable = true;
// (f100727.1L) add a rankup enable rule which is changed by a combined item
bool exist_rankup_function = false;
int rank_control_operation = 0; // -1:sub, 0:none, 1:add
if (item_info_->item_rule_info.func_attr.value & item_rule_info.func_attr.eEnable_Rank) {
exist_rankup_function = true;
}
switch (lock_info_.history_.value)
{
case lock_info_.history_.None:
rank_control_operation = exist_rankup_function ? 1 : 0;
break;
case lock_info_.history_.Combined:
// CHANGES, f100823.1L, fix up a data loss about rank information.
// a combined item can't change a rank information, but can query it of a rank.
rank_control_operation = exist_rankup_function ? 1 : 0;
break;
case lock_info_.history_.Shell:
item_rule_info.is_shell = true;
item_rule_info.is_editable = false;
rank_control_operation = exist_rankup_function ? 1 : -1;
break;
case lock_info_.history_.Etheria:
item_rule_info.is_etheria = true;
item_rule_info.is_editable = false;
rank_control_operation = exist_rankup_function ? 1 : 0;
break;
}
// 0 is skipped.
if (rank_control_operation == 0) {
}
else if (rank_control_operation < 0) {
item_rule_info.func_attr.value &= ~item_rule_info.func_attr.eEnable_Rank;
}
else if (rank_control_operation > 0) {
item_rule_info.func_attr.value |= item_rule_info.func_attr.eEnable_Rank;
}
return true;
}
bool SCItemSlot::ChangeImageItem(SLOTCODE image_item_code, eEtheriaHistory::value_type history)
{
const BASE_ITEMINFO* image_item_info = NULL;
if (image_item_code_ != 0 && image_item_code_ == image_item_code) {
image_item_info = image_item_info_;
}
else
{
if (item_code_ != image_item_code) {
ItemInfoParser* item_parser = ItemInfoParser::Instance();
image_item_info = item_parser->GetItemInfo(image_item_code);
}
else {
image_item_info = item_info_;
}
}
if (image_item_info == NULL) {
return false;
}
// change link
image_item_code_ = image_item_code;
image_item_info_ = image_item_info;
// change rule
// CHANGES, f100823.3L, the combined item, combining both same grade a shell and an etheria,
// is not a combined type.
if (history == lock_info_.history_.Combined) {
if (item_info_ == image_item_info_) {
history = lock_info_.history_.None;
}
}
//if (history != lock_info_.history_.None) {
ChangeImageItemRule(history);
//}
return true;
}
bool SCItemSlot::CanExtractToEtheria(RC::eITEM_RESULT* result) const
{
struct ResultMaker {
ResultMaker(RC::eITEM_RESULT* result)
: inter_result_(RC::RC_ITEM_SUCCESS), result_(result) {}
~ResultMaker()
{
if (result_ != NULL) {
*result_ = inter_result_;
}
}
RC::eITEM_RESULT inter_result_;
RC::eITEM_RESULT* result_;
} result_maker(result);
if (item_rule_info_.is_valid_item == false) {
result_maker.inter_result_ = RC::RC_ITEM_INVALIDSTATE;
return false;
}
if ((item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Etherealize) == 0) {
result_maker.inter_result_ = RC::RC_ITEM_CANT_EXTRACT_TO_ETHERIA;
return false;
}
// history control, if the shell item can't use this function
// enabled = eEtheriaHistory::None || eEtheriaHistory::Combined
// disabled = eEtheriaHistory::Shell
if (lock_info_.history_.value == lock_info_.history_.Shell) {
result_maker.inter_result_ = RC::RC_ITEM_ALREADY_EXTRACTED_TO_ETHERIA;
return false;
}
if (lock_info_.blocked_ || lock_info_.locked_ || lock_info_.user_blocked_) {
result_maker.inter_result_ = RC::RC_ITEM_INVALIDPOS;
return false; // passed if the case calling in the ExtractToEtheria function
}
// NOTE: f101112.4L, add a rule whether a lucky item is identified.
if (item_rule_info_.is_fate) {
if (GetFateIdentify() == false) {
result_maker.inter_result_ = RC::RC_ITEM_CANT_EXTRACT_TO_ETHERIA;
return false;
}
}
if (this->IsDestroyItem() != false) {
result_maker.inter_result_ = RC::RC_ITEM_CANT_EXTRACT_TO_ETHERIA;
return false;
}
// debug block
if (image_item_code_ == HardCode::ITEMCODE_of_ETHERIA) {
assert(!"the etheria item can't convert to an another etheria item");
result_maker.inter_result_ = RC::RC_ITEM_INVALID_TYPE;
return false;
}
#ifdef _DEBUG
if (WithDura() == false)
{
DURATYPE number_of_items = GetNum();
if (number_of_items != 1) {
result_maker.inter_result_ = RC::RC_ITEM_INVALID_TYPE;
return false;
}
}
#endif
return true;
}
// this -|-> the shell item
// |-> the etheria item (from making_item)
RC::eITEM_RESULT SCItemSlot::ExtractToEtheria(SCItemSlot* making_item)
{
if (lock_info_.blocked_ || lock_info_.locked_ || lock_info_.user_blocked_) {
return RC::RC_ITEM_INVALIDSTATE;
}
RC::eITEM_RESULT item_result;
if (CanExtractToEtheria(&item_result) == false) {
return item_result; // can't use this function
}
// if the below logic is failed, rollback process is needed
/* RESERVED_SECTION
struct RollbackData {
RollbackData(eEtheriaHistory* history)
: need_rollback_(false)
, history_(history)
{
source_history_ = *history_;
}
~RollbackData()
{
if (need_rollback_ == false) {
return;
}
*history_ = source_history_;
}
bool need_rollback_;
eEtheriaHistory source_history_;
eEtheriaHistory* history_;
} rollback_data(&this->lock_info_.history_);
*/
const SLOTCODE item_code = item_code_;
const SLOTCODE image_item_code = image_item_code_;
ITEMSTREAMEX source_stream;
ITEMPART& item_part = source_stream.Part;
ZeroMemory(&source_stream, sizeof(source_stream));
this->CopyOut(source_stream);
;{ // make clone item
making_item->Clear();
making_item->SetCode(item_code);
DURATYPE duration = item_part.byDura;
if (making_item->WithDura()) {
making_item->SetDura(duration);
}
else {
making_item->SetNum(duration);
}
making_item->CopyPart(source_stream.OptionPart);
};
;{ // the making_item is changed to etheria type
//const_cast<nsSlot::ItemRuleInfo&>(making_item->item_rule_info_).is_etheria = true;
making_item->ChangeImageItem(HardCode::ITEMCODE_of_ETHERIA,
making_item->lock_info_.history_.Etheria);
};
;{ // make to the shell item using this object
// if the process is failed, do roll-backed.
item_part.wCode = image_item_code;
item_part.byDura = 1;
// (f100816.3L) fix up an invalid position which is occurred on change an item status.
const SLOTIDX slot_index = this->GetSlotIdx();
const POSTYPE slot_pos = this->GetPos();
this->Clear();
this->CopyPart(item_part);
this->SetPos(slot_pos);
this->SetSlotIdx(slot_index);
this->ChangeImageItemRule(lock_info_.history_.Shell);
};
return RC::RC_ITEM_SUCCESS;
}
// this check routine should be called by the shell item.
bool SCItemSlot::CanCombineWithEtheria(RC::eITEM_RESULT* result) const
{
struct ResultMaker {
ResultMaker(RC::eITEM_RESULT* result)
: inter_result_(RC::RC_ITEM_SUCCESS), result_(result) {}
~ResultMaker()
{
if (result_ != NULL) {
*result_ = inter_result_;
}
}
RC::eITEM_RESULT inter_result_;
RC::eITEM_RESULT* result_;
} result_maker(result);
if (item_rule_info_.is_valid_item == false) {
result_maker.inter_result_ = RC::RC_ITEM_INVALIDSTATE;
return false;
}
if (item_rule_info_.is_shell == false ||
(item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Etherealize) == 0)
{
result_maker.inter_result_ = RC::RC_ITEM_CANT_COMBINED_WITH_ITEM;
return false;
}
// history control, if the shell item can't use this function
// disabled = eEtheriaHistory::None || eEtheriaHistory::Combined
// enabled = eEtheriaHistory::Shell
if (lock_info_.history_.value != lock_info_.history_.Shell) {
result_maker.inter_result_ = RC::RC_ITEM_CANT_COMBINED_WITH_ITEM;
return false;
}
if (lock_info_.blocked_ || lock_info_.locked_ || lock_info_.user_blocked_) {
result_maker.inter_result_ = RC::RC_ITEM_INVALIDPOS;
return false; // passed if the case calling in the CombineWithEtheria function
}
if (this->IsDestroyItem() != false) {
result_maker.inter_result_ = RC::RC_ITEM_CANT_COMBINED_WITH_ITEM;
return false;
}
// debug block
if (image_item_code_ == HardCode::ITEMCODE_of_ETHERIA) {
assert(!"the etheria item can't combine with an another etheria item");
result_maker.inter_result_ = RC::RC_ITEM_INVALID_TYPE;
return false;
}
#ifdef _DEBUG
// debug block, must be passed if the process step has been reached this point
if (WithDura() == false)
{
DURATYPE number_of_items = GetNum();
if (number_of_items != 1) {
result_maker.inter_result_ = RC::RC_ITEM_INVALID_TYPE;
return false;
}
}
#endif
return true;
}
// this check routine should be called by the etheria item.
bool SCItemSlot::CanCombineWithShell(RC::eITEM_RESULT* result) const
{
struct ResultMaker {
ResultMaker(RC::eITEM_RESULT* result)
: inter_result_(RC::RC_ITEM_SUCCESS), result_(result) {}
~ResultMaker()
{
if (result_ != NULL) {
*result_ = inter_result_;
}
}
RC::eITEM_RESULT inter_result_;
RC::eITEM_RESULT* result_;
} result_maker(result);
if (item_rule_info_.is_valid_item == false) {
result_maker.inter_result_ = RC::RC_ITEM_INVALIDSTATE;
return false;
}
if (item_rule_info_.is_etheria == false) {
result_maker.inter_result_ = RC::RC_ITEM_CANT_COMBINED_WITH_ITEM;
return false;
}
if (lock_info_.blocked_ || lock_info_.locked_ || lock_info_.user_blocked_) {
result_maker.inter_result_ = RC::RC_ITEM_INVALIDPOS;
return false; // passed if the case calling in the CombineWithEtheria function
}
// debug block
if (image_item_code_ != HardCode::ITEMCODE_of_ETHERIA) {
assert(!"the etheria item can't combine with an another etheria item");
result_maker.inter_result_ = RC::RC_ITEM_INVALID_TYPE;
return false;
}
return true;
}
// this(the shell item) -|-> the combination item
// the etheria item -|-> post action=delete
// the etheria item should be cleared, no control in this slot to logic control
RC::eITEM_RESULT SCItemSlot::CombineWithEtheria(const SCItemSlot& etheria_item)
{
if (lock_info_.blocked_ || lock_info_.locked_ || lock_info_.user_blocked_) {
return RC::RC_ITEM_INVALIDSTATE;
}
RC::eITEM_RESULT item_result;
if (etheria_item.CanCombineWithShell(&item_result) == false) {
return item_result;
}
if (this->CanCombineWithEtheria(&item_result) == false) {
return item_result; // can't use this function
}
const BASE_ITEMINFO* etheria_item_info = etheria_item.item_info_;
if (item_info_->m_wType != etheria_item_info->m_wType) {
return RC::RC_ITEM_CANT_COMBINED_WITH_DIFFERENT_ITEM;
}
const bool accept_class = \
(item_info_->m_wEqClass1 && item_info_->m_wEqClass1 == etheria_item_info->m_wEqClass1) ||
(item_info_->m_wEqClass2 && item_info_->m_wEqClass2 == etheria_item_info->m_wEqClass2) ||
(item_info_->m_wEqClass3 && item_info_->m_wEqClass3 == etheria_item_info->m_wEqClass3) ||
(item_info_->m_wEqClass4 && item_info_->m_wEqClass4 == etheria_item_info->m_wEqClass4) ||
(item_info_->m_wEqClass5 && item_info_->m_wEqClass5 == etheria_item_info->m_wEqClass5) ||
//_NA_000000_20130812_NEW_CHARACTER_HELLROID
(item_info_->m_wEqClass7 && item_info_->m_wEqClass7 == etheria_item_info->m_wEqClass7) ||
//_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
(item_info_->m_wEqClass8 && item_info_->m_wEqClass8 == etheria_item_info->m_wEqClass8) ||
// _NA_004965_20120613_NEW_CHARACTER_MYSTIC
(item_info_->m_wEqClass6 && item_info_->m_wEqClass6 == etheria_item_info->m_wEqClass6);
if (accept_class == false) {
return RC::RC_ITEM_CANT_COMBINED_WITH_DIFFERENT_ITEM;
}
// if the below logic is failed, rollback process is needed
/* RESERVED_SECTION
struct RollbackData {
RollbackData(eEtheriaHistory* history)
: need_rollback_(false)
, history_(history)
{
source_history_ = *history_;
}
~RollbackData()
{
if (need_rollback_ == false) {
return;
}
*history_ = source_history_;
}
bool need_rollback_;
eEtheriaHistory source_history_;
eEtheriaHistory* history_;
} rollback_data(&this->lock_info_.history_);
*/
const SLOTCODE shell_item_code = image_item_code_;
ITEMPART shell_item_part;
// (f100816.3L) fix up an invalid position which is occurred on change an item status.
const SLOTIDX slot_index = this->GetSlotIdx();
const POSTYPE slot_pos = this->GetPos();
;{ // clear the shell item
ZeroMemory(&shell_item_part, sizeof(shell_item_part));
this->CopyOutPart(shell_item_part);
this->Clear();
};
const SLOTCODE etheria_item_code = etheria_item.item_code_;
ITEMSTREAMEX etheria_stream;
ZeroMemory(&etheria_stream, sizeof(etheria_stream));
;{ // get option block & copy from the etheria item
//OPTIONPART& etheria_option = etheria_stream.OptionPart;
etheria_item.CopyOut(etheria_stream);
shell_item_part.wCode = etheria_item_code;
shell_item_part.byDura = etheria_stream.Part.byDura;
this->CopyPart(shell_item_part);
this->CopyPart(etheria_stream.OptionPart);
this->SetPos(slot_pos);
this->SetSlotIdx(slot_index);
};
;{ // make to the combination item
this->ChangeImageItem(shell_item_code, lock_info_.history_.Combined);
};
return RC::RC_ITEM_SUCCESS;
}
// it is operated internally. an item object with options is changed to a default item.
bool SCItemSlot::ChangeToShellItem()
{
if (item_rule_info_.is_valid_item == false ||
item_rule_info_.is_shell != false ||
item_rule_info_.is_etheria)
{
return false;
}
if ((item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Etherealize) == 0) {
return false;
}
if (lock_info_.blocked_ || lock_info_.locked_ || lock_info_.user_blocked_) {
return false; // passed if the case calling in the CombineWithEtheria function
}
// debug block
if (image_item_code_ == HardCode::ITEMCODE_of_ETHERIA) {
assert(!"the etheria item can't combine with an another etheria item");
return false;
}
// history control, if the shell item can't use this function
// disabled = eEtheriaHistory::None || eEtheriaHistory::Combined
// enabled = eEtheriaHistory::Shell
if (!(lock_info_.history_.value == lock_info_.history_.None ||
lock_info_.history_.value == lock_info_.history_.Combined))
{
return false;
}
#ifdef _DEBUG
// debug block, must be passed if the process step has been reached this point
if (WithDura() == false)
{
DURATYPE number_of_items = GetNum();
if (number_of_items != 1) {
return false;
}
}
#endif
const SLOTCODE item_code = image_item_code_;
const SLOTIDX slot_index = this->GetSlotIdx();
const POSTYPE slot_pos = this->GetPos();
;{ // change to the shell item
ITEMPART item_part;
ZeroMemory(&item_part, sizeof(item_part));
this->CopyOutPart(item_part);
this->Clear();
item_part.wCode = item_code;
this->CopyPart(item_part);
this->SetPos(slot_pos);
this->SetSlotIdx(slot_index);
};
;{ // change attributes
ChangeImageItem(item_code, lock_info_.history_.Shell);
};
return true;
}
// it is operated internally. an item object with options is changed to an etheria item which
// is equal to the base item except an image link and an uncorrectable mode (is_editable == false)
bool SCItemSlot::ChangeToEtheriaItem()
{
if (item_rule_info_.is_valid_item == false ||
item_rule_info_.is_shell ||
item_rule_info_.is_etheria != false)
{
return false;
}
if ((item_rule_info_.func_attr.value & item_rule_info_.func_attr.eEnable_Etherealize) == 0) {
return false;
}
if (lock_info_.blocked_ || lock_info_.locked_ || lock_info_.user_blocked_) {
return false; // passed if the case calling in the CombineWithEtheria function
}
// debug block
if (image_item_code_ == HardCode::ITEMCODE_of_ETHERIA) {
assert(!"the etheria item can't combine with an another etheria item");
return false;
}
// history control, if the shell item can't use this function
// disabled = eEtheriaHistory::None || eEtheriaHistory::Combined
// enabled = eEtheriaHistory::Shell
if (!(lock_info_.history_.value == lock_info_.history_.None ||
lock_info_.history_.value == lock_info_.history_.Combined))
{
return false;
}
#ifdef _DEBUG
// debug block, must be passed if the process step has been reached this point
if (WithDura() == false)
{
DURATYPE number_of_items = GetNum();
if (number_of_items != 1) {
return false;
}
}
#endif
;{ // change to the etheria item
ChangeImageItem(HardCode::ITEMCODE_of_ETHERIA, lock_info_.history_.Etheria);
};
return true;
}
// _NA_000251_20100727_SOCKET_SYSTEM
bool SCItemSlot::CreateSocketItem(const BYTE number_of_socket, const bool is_recreate)//xiaomi 꼻쉔膠틔돕목綾
{
if (number_of_socket < 0 || number_of_socket > SOCKET_MAX)
{
return false;
}
const nsSlot::ItemRuleInfo& item_rule_info = GetItemRuleInfo();
if (item_rule_info.IsEnableSocket() == false)
{
return false;
}
// 소켓 채우기가 불가능하다면 소켓을 생성하지 않는다.
//xiaomi 혤句穹퓌역왝掘齡(Server
if (CanUseMixture(MIXTURE_SOCKET_HOLE_FILL) == false)
{
if (is_recreate)
{
// 소켓 채우기가 불가능한데 강제로 소켓 생성을 시도하는것은 적합하지 않다.
return false;
}
SetSocketIdentifyType(eSOCKET_FAIL_IDENTIFY_PROCESS);
return true;
}
const eSOCKET_IDENTIFY_TYPE state = GetSocketIdentifyType();
if (is_recreate == false && state != eSOCKET_IDENTIFY_NOT_PROCESS)
{
return false;
}
// 소켓 개수가 입력되었으면
if (number_of_socket > 0)
{
// 다시 생성한다면 이전 소켓 정보는 제거한다.
if (is_recreate)
{
socket_info_.Clear();
}
// 입력한 개수만큼 소켓을 생성한다.
SetSocketNum(number_of_socket);
SetSocketIdentifyType(eSOCKET_IDENTIFIED_ITEM);
return true;
}
SocketItemRatioParser* const parser = SocketItemRatioParser::Instance();
const BASE_ITEMINFO* item_info = GetItemInfo();
const SocketItemRatioInfo::RatioType::Value ratio_type =
parser->GetRatioType(item_info->m_wType, is_recreate);
const SocketItemRatioInfo* const ratio = parser->FindSocketRatio(ratio_type, item_info->m_LV);
if (ratio == NULL)
{
return false;
}
// 안전하게 소켓 정보를 먼저 초기화한다.
socket_info_.Clear();
const int seed = random(1, SocketItemRatioInfo::kMaxRatio);
if (seed <= ratio->socket_creation_ratio_)
{
SetSocketIdentifyType(eSOCKET_UNIDENTIFIED_ITEM);
}
else
{
SetSocketIdentifyType(eSOCKET_FAIL_IDENTIFY_PROCESS);
}
return true;
}
#ifdef _NA_003033_20110831_DICECAST_ITEM_ROUTING
BYTE SCItemSlot::GetDiceCastType()
{
return dicecast_type_;
}
void SCItemSlot::SetDiceCastType(BYTE _type)
{
dicecast_type_ = _type;
}
#endif //_NA_003033_20110831_DICECAST_ITEM_ROUTING
bool SCItemSlot::EnableRandomize() const
{
#ifdef _NA_003740_20111122_RANDOM_ITEM
if (item_rule_info_.IsEnableRandomize() == false)
{
return false;
}
if (item_info_ == NULL)
{
return false;
}
return random_info_.EnableRandomize(*item_info_);
#else
return false;
#endif
}
#ifdef _NA_003740_20111122_RANDOM_ITEM
bool SCItemSlot::Randomize(const RandomValueTypeGrade::Value value_type_grade)
{
if (EnableRandomize() == false)
{
return false;
}
if (item_info_ == NULL)
{
return false;
}
if (random_info_.Randomize(value_type_grade, *item_info_) == false)
{
return false;
}
if (random_info_.CreateItemInfo(*item_info_) == false)
{
return false;
}
return true;
}
RandomValueGrade::Value SCItemSlot::GetRandomOptionGrade(const uint8_t index) const
{
if (EnableRandomize() == false)
{
return RandomValueGrade::kNone;
}
return random_info_.GetRandomOptionGrade(index);
}
#endif // _NA_003740_20111122_RANDOM_ITEM
//--------------------------------------------------------------------------------------------------
SCItemSlot::EditModeTransaction::EditModeTransaction(SCItemSlot* item_slot)
: item_slot_(item_slot),
first_value_(item_slot->item_rule_info_.is_editable != false)
{
const_cast<nsSlot::ItemRuleInfo&>(item_slot_->item_rule_info_).is_editable = !first_value_;
}
SCItemSlot::EditModeTransaction::~EditModeTransaction()
{
const_cast<nsSlot::ItemRuleInfo&>(item_slot_->item_rule_info_).is_editable = first_value_;
}
//const bool first_value_; // to support toggle
//SCItemSlot* const item_slot_;
//==================================================================================================
//==================================================================================================
//==================================================================================================
//==================================================================================================
//==================================================================================================