Files
Sun1602/Server/GameServer/DropManager.cpp
T
2022-10-26 12:25:11 +08:00

1014 lines
37 KiB
C++

#include "stdafx.h"
#include "./DropManager.h"
//==================================================================================================
#include <SCItemSlot.h>
#include <NumericValues.h>
//
#include <ServerOptionParserEx.h>
#include "StatisticsManager.h"
#include "FunctionalRestrictManager.h"
#include "GameZone.h"
#include "GameField.h"
#include "GameHuntingRoom.h"
#include "ItemManager.h"
#include "StatusManager.h"
//
#include "QuestInfoManagerEx.h"
#include "QuestManager_Concrete.h"
#include "GameParty/NewGamePartyManager.h"
#include <GameInstanceDungeon.h>
#include <GameMissionRoom.h>
#include "DropRatioInfoList.h"
//==================================================================================================
DropManager g_DropManager;
//==================================================================================================
namespace ns_functor {
;
inline static BOOL _CheckValidPlayer(Player* IN player, GameZone* IN drop_zone)
{
GameZone* pPlayerZone = player->GetGameZonePtr();
return (pPlayerZone && (pPlayerZone->GetKey() == drop_zone->GetKey()) && player->IsAlive());
}
inline static BOOL _CheckFindQuest(Player* IN player, QCODE questCode)
{
return player && player->GetQuestManager()->FindQuest(questCode);
}
class QuestItemDropControl
{
typedef DWORD QUEST_IDX_BITSET;
typedef QCODE QUEST_CODE_TYPE;
typedef DWORD QUEST_DROPIDX_TYPE;
static const DWORD MAX_QUEST_ITEM_DROP_NUM = BASE_NPCINFO::MAX_QUEST_ITEM_DROP_NUM;
static const QUEST_IDX_BITSET QUEST_IDX_BITSET_EMPTY = 0;
public:
QuestItemDropControl(const BASE_NPCINFO* pInfo)
: m_pNpcInfo(pInfo)
{
#ifdef _NA_004509_20120314_QUESTDROPINDEX10
BOOST_STATIC_ASSERT(MAX_QUEST_ITEM_DROP_NUM==10);
#else
BOOST_STATIC_ASSERT(MAX_QUEST_ITEM_DROP_NUM==5);
#endif //_NA_004509_20120314_QUESTDROPINDEX10
m_QuestCodes = m_pNpcInfo->m_QuestCode;
m_QuestDrops = m_pNpcInfo->m_dwQuestDropIndex;
ZeroMemory(m_Quests, sizeof(m_Quests));
}
BOOL CheckAndAlignQuest(const DWORD index)
{
if (MAX_QUEST_ITEM_DROP_NUM > index)
{
if (m_QuestCodes[index] && m_QuestDrops[index])
{
m_CheckIndex = index;
return true;
}
}
m_CheckIndex = MAX_QUEST_ITEM_DROP_NUM;
return false;
}
QCODE GetCurCheckQuestCode() {
return MAX_QUEST_ITEM_DROP_NUM > m_CheckIndex ? m_QuestCodes[m_CheckIndex] : 0;
}
DWORD GetCurCheckQuestDrop() {
return MAX_QUEST_ITEM_DROP_NUM > m_CheckIndex ? m_QuestDrops[m_CheckIndex] : 0;
}
private:
const BASE_NPCINFO* m_pNpcInfo;
const QUEST_CODE_TYPE* m_QuestCodes;
const QUEST_DROPIDX_TYPE* m_QuestDrops;
DWORD m_CheckIndex;
Quest* m_Quests[MAX_QUEST_ITEM_DROP_NUM];
};
class SearchPartyHasQuest : public std::unary_function<Character*, BOOL>
{
public:
SearchPartyHasQuest(QuestItemDropControl& IN rDropControl, Player* IN pMember)
: m_rDropControl(rDropControl), m_pMember(pMember)
{
m_bSatisfy = false;
}
void Reuse() { m_bSatisfy = false; }
BOOL IsSatisfy() const { return m_bSatisfy; }
BOOL operator () (Player* player) const
{
if (m_bSatisfy) {
return true;
};
if (_CheckValidPlayer(player, m_pMember->GetGameZonePtr()) &&
_CheckFindQuest(player, m_rDropControl.GetCurCheckQuestCode()))
{
m_bSatisfy = true;
return true;
}
return false;
}
private:
QuestItemDropControl& m_rDropControl;
mutable BOOL m_bSatisfy;
Player* m_pMember;
};
//==================================================================================================
#if defined(_YJ_TOOLTIP_ON_TEXT_001277) && !defined(__NA_0_20081124_PARTY_REFACTORING_GAMESERVER)
#error "Impossible Build!! - Reason: Violation Dependency Chain"
#endif
template<typename _PackType>
class AcquireQuestItem : public std::unary_function<Character*, void>
{
public:
AcquireQuestItem(QCODE aQuestCode, ZONEKEY aZoneKey, SCItemSlot* pQuestItem)
: m_QuestCode(aQuestCode) // 퀘스트 코드
, m_ZoneKey(aZoneKey) // 소유권자의 존키
, m_pQuestItem(pQuestItem) // 생성된 퀘스트아이템 슬롯
{
}
void operator() (Character* character) const
{
Player* player = static_cast<Player*>(character);
if (player == NULL) {
return;
};
GameZone* game_zone = character->GetGameZonePtr();
if (game_zone == NULL) {
return;
};
if (!(player->IsDead()) && // 생존
(game_zone->GetKey() == m_ZoneKey) && // 소유권자와 같은 존
(player->GetQuestManager()->FindQuest(m_QuestCode))) // 퀘스트 소유
{
#ifdef _YJ_TOOLTIP_ON_TEXT_001277
WORD itemCode = m_pQuestItem->GetItemCode();
POSTYPE itemNum = m_pQuestItem->GetNum();
m_Packet.m_QuestCode = m_QuestCode;
//!~ #3669 퀘스트 아이템 수집 완료시, 더이상 퀘스트 아이템을 입수하지 않음 - arycoat 2011.11.15
ItemManager* item_manager = player->GetItemManager();
QuestInfo* quest_info = g_QuestInfoManager.FindQuestInfo(m_QuestCode);
if(!quest_info) {
SUNLOG(eCRITICAL_LOG, _T("[%s:%d] cannot find quest info : %d"),
__FUNCTION__, __LINE__, m_QuestCode);
return;
}
QUEST_CONDITION_ITEM_INFO* quest_condition_item_info = \
static_cast<QUEST_CONDITION_ITEM_INFO*>(
quest_info->FindCompleteCondition(eQUEST_CONDITION_ITEM));
if(!quest_condition_item_info) {
SUNLOG(eCRITICAL_LOG, _T("[%s:%d] cannot find quest complete condition item info : %d"),
__FUNCTION__, __LINE__, m_QuestCode);
return;
}
for(int i = 0; i < quest_condition_item_info->GetItemArrayCount(); ++i)
{
if(quest_condition_item_info->GetItemCode(i) == itemCode)
{
// 충분한 개수의 아이템이 있는지 체크
int item_count = quest_condition_item_info->GetItemNum(i);
int ExistCount = item_manager->ExistItem(SI_INVENTORY, itemCode, item_count);
if (ExistCount >= item_count)
return;
}
}
//~!
RC::eITEM_RESULT ret = player->GetItemManager()->Obtain( \
(*m_pQuestItem), itemNum, &m_Packet.m_TotalInfo);
if (ret == RC::RC_ITEM_SUCCESS)
player->SendPacket(&m_Packet, m_Packet.GetSize());
#else
static SCItemSlot ItemSlot;
ItemSlot = *m_pQuestItem;
if (RC::RC_ITEM_SUCCESS == player->GetItemManager()->Pick(1, ItemSlot, &m_Packet.m_ItemInfo))
{
player->SendPacket(&m_Packet, m_Packet.GetSize());
}
#endif
}
}
private:
QCODE m_QuestCode;
ZONEKEY m_ZoneKey;
SCItemSlot* m_pQuestItem;
mutable _PackType m_Packet;
};
}; //end of namespace 'ns_functor'
//==================================================================================================
//
//{__NA000000_20090320_DELAY_ITEM_DROP_TIME
struct DropManager::DelayDropInfo
{
DelayDropInfo()
{
ZeroMemory(this, static_cast<size_t>(\
reinterpret_cast<char*>(&drop_timer_) - reinterpret_cast<char*>(this)));
monster_grade_ = eNPC_GENERAL;
}
//
GameField* game_field_;
DWORD sector_index_;
WzVector drop_center_pos_;
//
Player* owner_;
DWORD monster_key_;
const BASE_NPCINFO* monster_info_;
eNPC_GRADE monster_grade_;
LEVELTYPE monster_display_level_;
//
util::Timer drop_timer_;
};
struct DropManager::DelayedFieldObject
{
GameField* game_field_;
util::SimpleTimer delayed_drop_timer_;
DWORD monster_key_;
PLAYERKEY player_key_;
bool is_item_object;
WzVector drop_center_pos_;
//
MONEY scheduled_drop_money_;
SCItemSlot scheduled_drop_item_;
};
//==================================================================================================
//
void DropManager::Init(DWORD pool_size)
{
__UNUSED(pool_size);
}
void DropManager::OnFieldRelease(ZONEKEY zone_key)
{
DELAY_DROPINFO_LIST::_Pairii ranges = delay_drop_info_list_.equal_range(zone_key);
if (ranges.first == ranges.second) { // changes comparision
return;
};
DELAY_DROPINFO_LIST::const_iterator it = ranges.first;
for (; it != ranges.second; ++it)
{
DelayDropInfo* delay_drop_info = it->second;
if (FlowControl::FCAssert(delay_drop_info != NULL) == false) {
continue;
};
TAllocDelete(DelayDropInfo, delay_drop_info);
};
delay_drop_info_list_.erase(ranges.first, ranges.second);
//
}
void DropManager::DelayedDrop_(GameField* game_field, DWORD sector_index, const WzVector* origin_pos,
Player* owner, DWORD monster_key, const BASE_NPCINFO* monster_info,
eNPC_GRADE npc_grade, LEVELTYPE monster_display_level)
{
static const DWORD& kDelayInterval = \
ServerOptionParserEx::Instance()->GetServerOption().m_DelayDropTime;
if (game_field == NULL) {
return;
};
DelayDropInfo* const delay_drop_info = TAllocNew(DelayDropInfo);
delay_drop_info->game_field_ = game_field;
delay_drop_info->sector_index_ = sector_index;
delay_drop_info->owner_ = owner;
delay_drop_info->monster_key_ = monster_key;
delay_drop_info->monster_info_ = monster_info;
delay_drop_info->monster_grade_ = npc_grade;
delay_drop_info->monster_display_level_ = monster_display_level;
delay_drop_info->drop_center_pos_ = *origin_pos;
delay_drop_info->drop_timer_.SetTimer(kDelayInterval);
ZONEKEY zone_key = game_field->GetGameZone()->GetKey();
delay_drop_info_list_.insert(DELAY_DROPINFO_LIST::value_type(zone_key, delay_drop_info));
}
void DropManager::UpdateDelayedItemDrop()
{
DELAY_DROPINFO_LIST::iterator it = delay_drop_info_list_.begin();
while (it != delay_drop_info_list_.end())
{
DelayDropInfo* delay_drop_info = it->second;
if (FlowControl::FCAssert(delay_drop_info != NULL) == false) {
it = delay_drop_info_list_.erase(it);
continue;
};
const bool dropped = (delay_drop_info->drop_timer_.IsExpiredManual(false) != false);
if (dropped)
{
this->InstantDrop_(delay_drop_info->game_field_, delay_drop_info->sector_index_,
&delay_drop_info->drop_center_pos_, delay_drop_info->owner_,
delay_drop_info->monster_key_, delay_drop_info->monster_info_,
delay_drop_info->monster_grade_, delay_drop_info->monster_display_level_);
//
TAllocDelete(DelayDropInfo, delay_drop_info);
it = delay_drop_info_list_.erase(it);
continue;
};
//
++it;
//
}; //end 'while'
}
//}__NA000000_20090320_DELAY_ITEM_DROP_TIME
//==================================================================================================
//==================================================================================================
//==================================================================================================
DropManager::DropManager()
{
}
DropManager::~DropManager()
{
}
void DropManager::Release()
{
DELAYEDFOBJ_LIST::const_iterator it = delayed_field_object_list_.begin();
const DELAYEDFOBJ_LIST::const_iterator end = delayed_field_object_list_.end();
// CHANGES: f110715.2L, fixed the infinite loop
for (; it != end; ++it)
{
DelayedFieldObject* delayed_field_object = *it;
TAllocDelete(DelayedFieldObject, delayed_field_object);
}
delayed_field_object_list_.clear();
drop_core_.Unload();
}
void DropManager::InstantDrop_(GameField* game_field, DWORD sector_index,
const WzVector* origin_pos, Player* owner,
DWORD monster_key, const BASE_NPCINFO* monster_info,
eNPC_GRADE npc_grade, LEVELTYPE monster_display_level)
{
__UNUSED(sector_index);
if (game_field == NULL) {
return;
};
GameZone* const game_zone = game_field->GetGameZone();
if (game_zone == NULL) {
return;
};
if (g_FunctionalRestrictMgr.IsRestrictFunction(eFUNCTIONALRESTRICT_USE_MONSTERDROP))
{
static bool reported = false;
if (reported == false)
{
SUNLOG(eCRITICAL_LOG, "몬스터 드랍 서비스가 중지중입니다");
reported = true;
};
return;
};
if (FlowControl::FCAssert(npc_grade < eNPC_GRADE_MAX) == false) {
return;
};
// NOTE: f110414.4L, apply weight value about heim based on number of party members.
float heim_weight_based_on_party_members = 1.0f;
DWORD owner_key = 0;
//----------------------------------------------------------------------------------------------
if (owner)
{
// 딜레이 드랍에 따라 간단한 유효성 체크 한다.
if (0 == owner->GetObjectKey())
{
SUNLOG(eCRITICAL_LOG, _T("|[%s]|유효하지 않은 플레이어키|"), __FUNCTION__);
return;
};
GameZone* const game_zone_of_owner = owner->GetGameZonePtr();
if (game_zone_of_owner == NULL)
{
// 몬스터 잡은후 접속 종료시
SUNLOG(eCRITICAL_LOG, _T("|[%s]|유효하지 않은 Owner|"), __FUNCTION__);
return;
};
if (game_zone_of_owner != game_zone)
{
SUNLOG(eCRITICAL_LOG, _T("|[%s]|Owner의 존키와 필드의 존키가 일치하지 않는다"), __FUNCTION__);
return;
};
// 파티 상태이면 아이템 분배 시스템을 적용 시키고 있는 시점이다.
const WORD party_key = owner->GetPartyState().GetPartyKey();
if (party_key)
{
owner_key = owner->GetObjectKey();
#ifdef _NA_0_20111021_EDIT_HEIM_DROP_RATIO_BY_PARTY_USER_COUNT // _CHINA
int party_members = NewGamePartyManager::Instance()->FindNearPartyUserCount(owner);
heim_weight_based_on_party_members = ns_formula::GetRoomHeimPartyBonusFactor(party_members);
#else
// CHANGES: f110414.4L, apply weight value about heim based on number of party members.
const BaseParty* party = static_cast<const BaseParty*>(\
NewGamePartyManager::Instance()->FindParty(party_key));
if (party != NULL)
{
int number_of_party_members = party->GetMemberNum();
#ifdef _NA_004651_20120404_CHANGE_PARTY_HEIM_WEIGHT_v02
bool zone_type_top_of_trial = false;
if (game_zone->GetZoneType() == eZONETYPE_INSTANCE)
{
GameInstanceDungeon* instance_dungeon = \
static_cast<GameInstanceDungeon*>(game_zone);
if (instance_dungeon && \
instance_dungeon->GetTypeOfIndun() == INDUN_KIND_TOP_OF_TRIAL)
{
zone_type_top_of_trial = true;
}
}
/* // 빛의 시련 하임 드랍 방식을 미션 드랍 방식을 따르도록 함 - arycoat 2014.08.11
#ifdef _NA_007156_20140703_TOP_OF_TRIAL_LIGHT
if (game_zone->GetZoneType() == eZONETYPE_MISSION)
{
GameMissionRoom* mission_room = static_cast<GameMissionRoom*>(game_zone);
if (mission_room) {
PartyZoneType party_zone_type = mission_room->GetPartyZoneType();
if (party_zone_type == PartyOfTopOfTrialLight_normal ||
party_zone_type == PartyOfTopOfTrialLight_cash) {
zone_type_top_of_trial = true;
}
}
}
#endif //_NA_007156_20140703_TOP_OF_TRIAL_LIGHT
*/
heim_weight_based_on_party_members = \
(zone_type_top_of_trial) ? \
ns_formula::GetRoomHeimPartyBonusFactorType2(number_of_party_members) : \
ns_formula::GetRoomHeimPartyBonusFactor(number_of_party_members);
#else
heim_weight_based_on_party_members =
ns_formula::GetRoomHeimPartyBonusFactor(number_of_party_members);
#endif //_NA_004651_20120404_CHANGE_PARTY_HEIM_WEIGHT_v02
};
#endif //_NA_0_20111021_EDIT_HEIM_DROP_RATIO_BY_PARTY_USER_COUNT
}
else
{
const SERVER_COMMON_OPTION& server_option = \
ServerOptionParserEx::Instance()->GetServerOption();
if (server_option.m_byApplyItemOwnerShipByLevel != false)
{
//레벨차가 10이하만 소유권 존재.
int LVInterval = (owner->GetLevel() - monster_display_level);
if (LVInterval < DONT_DROP_LEVEL_INTERVAL) {
owner_key = owner->GetObjectKey();
};
}
else
{
owner_key = owner->GetObjectKey();
};
}
}
//----------------------------------------------------------------------------------------------
#if SUN_CODE_BACKUP
FLOAT PlusBonusPercent = 1.0f;
if (game_zone->GetZoneType() == eZONETYPE_HUNTING)
{
// 헌팅 보너스 가중치
// ???? -> 경쟁헌팅으로 바꿔야 하지 않나?
GameHuntingRoom* pHuntingRoom = static_cast<GameHuntingRoom*>(game_zone);
if (pHuntingRoom->GetAdditionalInfo()->m_Bonus == eHUNTING_BONUS_TYPE_ITEM) {
PlusBonusPercent = 1.1f;
};
}
#endif
// CHANGES: f110715.2L, removed the unused section
// CHANGES: f110414.4L, apply HEIM weight value about heim based on number of party members.
// subtract default percentage to prevent the point that is percentage of a percentage.
float added_bonus_percentage = heim_weight_based_on_party_members;
//----------------------------------------------------------------------------------------------
// 퀘스트 아이템 드랍
DropQuest(game_field, monster_info, owner,
npc_grade, added_bonus_percentage,
game_zone, origin_pos, monster_key, owner_key);
//----------------------------------------------------------------------------------------------
static SCItemSlot dropping_item_slot_static;
//
typedef const DWORD DropIndexArray[_countof(monster_info->m_dwFieldDropIndex)];
const DropIndexArray* __drop_index_array
= (monster_info->m_bRegion == 0) ? &monster_info->m_dwDropIndex // 공통 Drop
: (g_pGameServer->GetServerType() == FIELD_SERVER) ? &monster_info->m_dwFieldDropIndex // 필드 Drop
: &monster_info->m_dwBattleDropIndex; // 배틀존 Drop
//
const DropIndexArray& drop_index_array = *__drop_index_array;
bool gm_drop_process = false;
;{
const StatusField& status_field = owner->GetStatusManager()->Status;
if (status_field.FIELD & status_field.ENABLE_GM_DROP_LIST_ALL) {
gm_drop_process = true;
};
};
// 기본 아이템 드랍
for (int i = 0; i < _countof(drop_index_array); ++i)
{
const DWORD drop_index = drop_index_array[i];
if (0 == drop_index) {
continue;
};
BOOST_STATIC_ASSERT(\
_countof(drop_index_array) == _countof(monster_info->m_bOwnerShipForDropIndex));
//------------------------------------------------------------------------------------------
if (gm_drop_process)
{
DWORD temp_player_key = owner_key;
if (monster_info->m_bOwnerShipForDropIndex[i] == false) {
temp_player_key = 0;
};
this->GMDrop(game_field, origin_pos, owner,
monster_key, monster_info, game_zone->GetZoneType(), drop_index,
npc_grade, added_bonus_percentage, temp_player_key);
continue;
};
//------------------------------------------------------------------------------------------
// NOTE: default drop processing
int number_of_drop_items = 0;
MONEY dropping_money = 0;
DWORD decided_seed_value = 0;
eDROP_TYPE_ dropping_type;
SCItemSlot& dropping_item_slot = dropping_item_slot_static;
bool does_drop_exist = (drop_core_.Drop(game_zone->GetZoneType(),
drop_index, npc_grade, added_bonus_percentage,
dropping_type, dropping_money, dropping_item_slot,
decided_seed_value, &number_of_drop_items) != false);
if (does_drop_exist == false) {
continue;
};
DWORD temp_player_key = owner_key;
// 소유권이 없다면
if (monster_info->m_bOwnerShipForDropIndex[i] == false) {
temp_player_key = 0;
};
//------------------------------------------------------------------------------------------
;;;; if (dropping_type == DROP_TYPE_ITEM)
{
if (temp_player_key != 0) {
temp_player_key = GetSecondItemOwnershipUserKey(owner, dropping_item_slot);
};
// NOTE: f110401.3L
for (int counter = 0; counter < number_of_drop_items; ++counter)
{
this->DropItem(game_field, origin_pos,
monster_key, temp_player_key, monster_info, dropping_item_slot);
};
}
else if (dropping_type == DROP_TYPE_MONEY)
{
ASSERT(decided_seed_value != 0 && number_of_drop_items == 1);
const int log_type = (decided_seed_value > 1) ?
MONEY_MONSTER_JACKPOT_DROP : MONEY_MONSTER_DROP;
// 몬스터 돈 드랍 로그
GAMELOG->LogMonsterMoneyDrop(log_type,
dropping_money, monster_info->m_MonsterCode,
npc_grade, game_zone->GetMapCode(), *origin_pos, game_zone->GetKey());
#ifdef _NA_007750_20141113_WZDAT_MODIFY_LOG
GameBattleResult* battle_result = game_zone->GetGameBattleResult();
if (battle_result != NULL)
{
battle_result->AddToTalDropHeim(dropping_money);
}
#endif // _NA_007750_20141113_WZDAT_MODIFY_LOG
if (temp_player_key != 0) {
temp_player_key = GetSecondHeimOwnershipUserKey(owner);
};
this->DropMoney((log_type == MONEY_MONSTER_JACKPOT_DROP),
game_field, origin_pos, monster_key, temp_player_key, dropping_money);
};
//------------------------------------------------------------------------------------------
}; //end 'for'
}
DWORD DropManager::GetSecondItemOwnershipUserKey(Player* pre_owner, SCItemSlot& dropped_item)
{
// NOTE: f110424.1L, logic improvements
DWORD default_owner_key = pre_owner->GetObjectKey();
GameField* const game_field = pre_owner->GetField();
if (game_field == NULL) {
return 0;
};
const BASE_ITEMINFO* const item_info = dropped_item.GetItemInfo();
// REMOVED: rules = 배틀서버는 아이템별로 아이템분배 적용여부를 확인한다.
//if (g_pGameServer->GetServerType() == BATTLE_SERVER && \
// item_info->IsApplyItemDistribution() == false) {
// return default_owner_key;
//};
#ifdef _NA_003033_20110831_DICECAST_ITEM_ROUTING
if(item_info)
{
// 주사위 방식 획득 아이템도 분배규칙을 적용하지 않음.
if(BYTE dicecast_type = item_info->dice_cast_type > 0)
{
bool all_party_member_obtain_type = false;
#ifdef _NA_004204_20120131_BATTLE_ZONE_PARTY_OBTAIN
// 파티원 전원 획득 존에서는 주사위 적용안함. arycoat.2012.02.08
sPOLICY_ZONE& Policyment = game_field->GetGameZone()->Policyment;
if(Policyment.FIELD & Policyment.ENABLE_ITEM_OBTAIN_ALL_PARTY_MEMBER) {
all_party_member_obtain_type = true;
}
#endif //_NA_004204_20120131_BATTLE_ZONE_PARTY_OBTAIN
eITEM_DISTRIBUTION_TYPE type = \
static_cast<eITEM_DISTRIBUTION_TYPE>( \
NewGamePartyManager::Instance()->GetDistributionType( \
pre_owner->GetPartyState().GetPartyKey()));
if( all_party_member_obtain_type == false &&
(type == eITEM_DISTRIBUTION_DICE_AND_DEFAULT || \
type == eITEM_DISTRIBUTION_DICE_AND_FIFO))
{
dropped_item.SetDiceCastType(dicecast_type);
return default_owner_key;
}
}
}
#endif //_NA_003033_20110831_DICECAST_ITEM_ROUTING
#ifdef _NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
if(item_info)
{
// AC아이템은 분배규칙을 적용하지 않음. arycoat - 2011.07.20
const eITEMTYPE type = static_cast<eITEMTYPE>(item_info->m_wType);
if (type == eITEMTYPE_AC)
{
return default_owner_key;
}
}
DWORD next_owner_key = default_owner_key;
if (WORD party_key = pre_owner->GetPartyState().GetPartyKey())
{
const eCHAR_TYPE char_type = item_info->GetFirstAvailableClass();
if (NewGamePartyManager* party_manager = NewGamePartyManager::Instance()) {
next_owner_key = party_manager->GetDistributionMemberKey(party_key,
default_owner_key, char_type);
if(next_owner_key != 0) {
// 아이템 소유권자가 죽었거나 다른맵에 있을경우 자유획득 - arycoat 2011.07.20
Player* player = PlayerManager::Instance()->FindPlayerByObjKey(next_owner_key);
if(player) {
if(player->IsDead() || player->GetField() != game_field) {
next_owner_key = 0;
}
}
else {
next_owner_key = 0;
}
}
};
}
#else
DWORD next_owner_key = default_owner_key;
if (WORD party_key = pre_owner->GetPartyState().GetPartyKey())
{
const eCHAR_TYPE char_type = item_info->GetFirstAvailableClass();
if (NewGamePartyManager* party_manager = NewGamePartyManager::Instance()) {
next_owner_key = party_manager->GetDistributionMemberKey(party_key,
default_owner_key, char_type);
// no-check member_key integrity
};
}
#endif //_NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
return next_owner_key;
}
DWORD DropManager::GetSecondHeimOwnershipUserKey(Player* pre_owner)
{
GameField *game_field = pre_owner->GetField();
if (game_field == NULL) {
return 0;
};
const DWORD default_owner_key = pre_owner->GetObjectKey();
#ifdef _NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
// 하임은 분배규칙을 적용하지 않음. arycoat - 2011.07.20
#else
const WORD party_key = pre_owner->GetPartyState().GetPartyKey();
if (party_key == 0) {
return default_owner_key;
};
//
DWORD member_key = NewGamePartyManager::Instance()->GetDistributionMemberKey(
party_key, default_owner_key, eCHAR_TYPE_MAX);
if (Player* member = PlayerManager::Instance()->FindPlayerByObjKey(member_key)) {
return member_key;
}
#endif //_NA_002399_20110323_ITEM_ROUTING_METHOD_CHANGE
return default_owner_key;
}
void DropManager::DropQuest(GameField* game_field, const BASE_NPCINFO* monster_info,
Player* owner,
eNPC_GRADE npc_grade, float added_bonus_percentage, GameZone* game_zone,
const WzVector* creating_pos, DWORD monster_key, DWORD unused__owner_object_key)
{
__UNUSED((game_field, creating_pos, monster_key, unused__owner_object_key));
// assert(owner->GetPlayerKey() == dwPlayerKey)
GameZone* game_zone_of_owner = owner->GetGameZonePtr();
if (game_zone_of_owner == NULL) {
return;
};
ns_functor::QuestItemDropControl questControl(monster_info);
ns_functor::SearchPartyHasQuest searchControl(questControl, owner);
WORD PartyKey = owner->GetPartyState().GetPartyKey();
MONEY DroppedMoney = 0;
DWORD dwDecidedSeed = 0;
static SCItemSlot QuestItemSlot;
eDROP_TYPE_ DroppedType;
int number_of_drop_items = 0;
for (DWORD index = 0 ; index < BASE_NPCINFO::MAX_QUEST_ITEM_DROP_NUM; ++index)
{
if (false == questControl.CheckAndAlignQuest(index)) {
continue;
};
if (!NewGamePartyManager::Instance()->For_eachPlayers(PartyKey, searchControl)) {
searchControl(owner);
};
if (searchControl.IsSatisfy() &&
drop_core_.Drop(game_zone->GetZoneType(), questControl.GetCurCheckQuestDrop(),
npc_grade,
added_bonus_percentage, DroppedType, DroppedMoney,
QuestItemSlot, dwDecidedSeed, &number_of_drop_items))
{
if (DROP_TYPE_ITEM != DroppedType || number_of_drop_items != 1)
{
SUNLOG(eCRITICAL_LOG,
_T("Drop of QuestItem is WRONG!!! : ")
_T("MONSTER_NAME[%s], MONSTER_CODE[%d], QUEST_NUM[%d], ")
_T("number of separately paid items = %d"),
monster_info->m_pszName, monster_info->m_NCode, index,
number_of_drop_items);
return;
}
// 아이템 획득
#ifdef _YJ_TOOLTIP_ON_TEXT_001277
ns_functor::AcquireQuestItem<MSG_CG_QUEST_ITEM_OBTAIN_CMD> Opr(\
questControl.GetCurCheckQuestCode(),
game_zone_of_owner->GetKey(), &QuestItemSlot);
if (!NewGamePartyManager::Instance()->For_eachPlayers(PartyKey, Opr))
{
Opr(owner);
}
#else
AcquireQuestItem<MSG_CG_ITEM_PICK_ACK> Opr(questControl.GetCurCheckQuestCode(), game_zone_of_owner->GetKey(), &QuestItemSlot);
if (!NewGamePartyManager::Instance()->For_eachPlayers(PartyKey, Opr))
{
Opr(owner);
}
#endif
}
searchControl.Reuse();
}
}
void DropManager::DropMoney(bool jackpot,
GameField* game_field, const WzVector* origin_pos, DWORD monster_key, DWORD player_key,
MONEY& dropped_money)
{
// 드랍 하임율 2배
if (eSERVER_TESTLIVE == g_pGameServer->GetMode()) {
dropped_money <<= 1;
};
if (dropped_money == 0) {
SUNLOG(eCRITICAL_LOG, "몬스터 드랍되는 돈이 0이다.\n");
};
WzVector droppable_pos;
if (jackpot == false)
{
if (game_field->GetRandomPosInAround(origin_pos, 2, droppable_pos) == false) {
droppable_pos = *origin_pos;
};
bool succeeded_dropped = this->DropMoneyToField(\
game_field, &droppable_pos, player_key, monster_key, dropped_money);
assert(succeeded_dropped);__TOUCHED(succeeded_dropped);
return;
};
assert(jackpot != false);
//< 1만 이상의 금액일 때 잭팟
// NOTE: delayed dropping jackpot playing
MONEY remains_money = dropped_money;
DWORD sliced_money_tokens[4] =
{
util::LL_Round(remains_money * 0.03f),
util::LL_Round(remains_money * 0.04f),
util::LL_Round(remains_money * 0.05f),
util::LL_Round(remains_money * 0.06f),
};
for (int interval_index = 0; remains_money > 0; ++interval_index, (interval_index &= 0x1F))
{
BOOST_STATIC_ASSERT(util::bit_count_<_countof(sliced_money_tokens)>::value == 1);
MONEY sliced_money = sliced_money_tokens[\
interval_index & (_countof(sliced_money_tokens) - 1)];
if (remains_money < sliced_money) {
sliced_money = remains_money;
};
remains_money -= sliced_money;
//
if (game_field->GetRandomPosInAround(origin_pos, 3, droppable_pos) == false) {
droppable_pos = *origin_pos;
};
bool succeeded_dropped = DropMoneyToField(\
game_field, &droppable_pos, player_key, monster_key, sliced_money,
(100 * interval_index));
assert(succeeded_dropped);__TOUCHED(succeeded_dropped);
};
// 잭팟 통계로 기록(성현창)
//g_pGameServer->AddJackpot(dropped_money);
g_StatisticsManager.PlusStatisticType(eSTATISTIC_JACKPOT_COUNT, 1);
g_StatisticsManager.PlusStatisticType(eSTATISTIC_JACKPOT_MONEY, dropped_money);
}
void DropManager::DropItem(GameField* game_field, const WzVector* creating_pos,
DWORD monster_key, DWORD player_key, const BASE_NPCINFO* npc_info,
SCItemSlot& dropped_item_slot)
{
// (CHANGES) (WAVERIX) add item rule check
const nsSlot::ItemRuleInfo& item_rule_info = dropped_item_slot.GetItemRuleInfo();
if (item_rule_info.is_valid_item == false) {
return;
};
WzVector droppable_pos;
if (game_field->GetRandomPosInAround(creating_pos, 3, droppable_pos) == false) {
droppable_pos = *creating_pos;
};
BOOL dropped_result = DropItemToField(game_field, &droppable_pos,
player_key, monster_key, dropped_item_slot);
if (dropped_result != false)
{
GameZone* game_zone = game_field->GetGameZone();
// 몬스터 아이템 드랍 로그 남기기
GAMELOG->LogMonsterItemDrop(dropped_item_slot,
npc_info->m_MonsterCode, npc_info->m_Level,
game_zone->GetMapCode(), droppable_pos, game_zone->GetKey());
// 몬스터 아이템 드랍 로그 남기기 끝
};
}
bool DropManager::DropItemToField(GameField* game_field, const WzVector* creating_pos,
PLAYERKEY player_key, DWORD from_monster_key,
SCItemSlot& drop_item_slot, DWORD delaying_interval)
{
if (game_field == NULL || game_field->IsReady() == false) {
return false;
}
else if (delaying_interval == 0)
{ // instant drop
Item* field_item = game_field->CreateItem(creating_pos,
player_key, from_monster_key, drop_item_slot);
if (field_item != NULL) {
return true;
};
}
else if (DelayedFieldObject* scheduled_item = TAllocNew(DelayedFieldObject))
{ // delayed drop
scheduled_item->drop_center_pos_ = *creating_pos;
scheduled_item->game_field_ = game_field;
scheduled_item->delayed_drop_timer_.SetTimer(delaying_interval);
scheduled_item->monster_key_ = from_monster_key;
scheduled_item->player_key_ = player_key;
scheduled_item->is_item_object = true;
scheduled_item->scheduled_drop_item_.Copy(drop_item_slot);
delayed_field_object_list_.push_back(scheduled_item);
return true;
}
return false;
}
bool DropManager::DropMoneyToField(GameField* game_field, const WzVector* creating_pos,
PLAYERKEY player_key, DWORD from_monster_key, const MONEY& money, DWORD delaying_interval)
{
if (game_field == NULL || game_field->IsReady() == false) {
return false;
}
else if (delaying_interval == 0)
{ // instant drop
Item* field_item = game_field->CreateMoney(creating_pos,
player_key, from_monster_key, money);
if (field_item != NULL) {
return true;
};
}
else if (DelayedFieldObject* scheduled_item = TAllocNew(DelayedFieldObject))
{ // delayed drop
scheduled_item->drop_center_pos_ = *creating_pos;
scheduled_item->game_field_ = game_field;
scheduled_item->delayed_drop_timer_.SetTimer(delaying_interval);
scheduled_item->monster_key_ = from_monster_key;
scheduled_item->player_key_ = player_key;
scheduled_item->is_item_object = false;
scheduled_item->scheduled_drop_money_ = money;
delayed_field_object_list_.push_back(scheduled_item);
return true;
}
return false;
}
void DropManager::Process()
{
UpdateDelayedItemDrop();
DELAYEDFOBJ_LIST::iterator it = delayed_field_object_list_.begin();
const DELAYEDFOBJ_LIST::const_iterator end = delayed_field_object_list_.end();
while (it != end)
{
DelayedFieldObject* scheduled_item = *it;
if (scheduled_item->delayed_drop_timer_.IsExpired() == false) {
++it;
continue;
};
//
if (scheduled_item->is_item_object)
{
scheduled_item->game_field_->CreateItem(\
&scheduled_item->drop_center_pos_, scheduled_item->player_key_,
scheduled_item->monster_key_, scheduled_item->scheduled_drop_item_);
}
else
{
scheduled_item->game_field_->CreateMoney(\
&scheduled_item->drop_center_pos_, scheduled_item->player_key_,
scheduled_item->monster_key_, scheduled_item->scheduled_drop_money_);
};
TAllocDelete(DelayedFieldObject, scheduled_item);
it = delayed_field_object_list_.erase(it);
}
}
BOOL DropManager::Load(eSCRIPT_CODE script_code,
const TCHAR* file_name, BOOL bBigData, eSEPERATOR_MODE mode,
const TCHAR* pack_file_name, BOOL bReload)
{
// NOTE: f110401.1L, added by _NA002479_20110401_DROP_RATIO_SELECTOR_EXTENTION
drop_core_.SetupDropRatioTable(g_pGameServer->GetServerType() != FIELD_SERVER);
//
return drop_core_.Load(script_code, file_name, bBigData, mode, pack_file_name, bReload);
}
BOOL DropManager::SolarLoad(eSCRIPT_CODE script_code, BYTE* pSTREAM, DWORD dwSize, BOOL bBigData)
{
// NOTE: f110401.1L, added by _NA002479_20110401_DROP_RATIO_SELECTOR_EXTENTION
drop_core_.SetupDropRatioTable(g_pGameServer->GetServerType() != FIELD_SERVER);
//
const char* file_name = FindFileName(script_code);
drop_core_.InsertFileName(script_code, file_name);
return drop_core_.SolarLoad(script_code, pSTREAM, dwSize, bBigData);
}
//==================================================================================================
//==================================================================================================