1634 lines
50 KiB
C++
1634 lines
50 KiB
C++
#include "stdafx.h"
|
|
#include "Gamefield.h"
|
|
|
|
#include <NPCInfoParser.h>
|
|
#include <CollectionParser.h>
|
|
//==================================================================================================
|
|
|
|
#include "./GameServerEx.h"
|
|
#include "./ObjectFactory.h"
|
|
|
|
#include "./Map.h"
|
|
#include "./GameZone.h"
|
|
#include "./GameInstanceDungeon.h"
|
|
#include "./MovingPlanner.h"
|
|
#include "./World/GameWarControlManager.h"
|
|
#include "./World/HighLoadBalancer.h"
|
|
#include "./TriggerManagerEx.h"
|
|
|
|
#include "./SummonedNPCs.h"
|
|
#include "./NpcAI/TargetFinder.h"
|
|
#include "./NpcAI/NPCStateManager.h"
|
|
#include "./UnitGroupManager.h"
|
|
#include "./UnitGroupInfoManager.h"
|
|
#include "./DropManager.h"
|
|
#include "./EffectManager.h"
|
|
#include "./Status/StatusManager.h"
|
|
|
|
#include "./Player.h"
|
|
#include "./Monster.h"
|
|
#include "./LuckyMonster.h"
|
|
#include "./SSQMonster.h"
|
|
#include "./MapObject.h"
|
|
#include "./Item.h"
|
|
#include "./MapNpc.h"
|
|
#include "./TotemNpc.h"
|
|
#include "./Summoned.h"
|
|
#include "./FriendMonster.h"
|
|
#include "./SyncMerchant.h"
|
|
|
|
#include "./Collection.h"
|
|
#include "./CollectionManager.h"
|
|
#include "./CrystalWarp.h"
|
|
#include "GameMissionRoom.h"
|
|
|
|
//==================================================================================================
|
|
__IMPL_CUSTOMPOOL_PTR(GameField);
|
|
|
|
const DWORD GameField::SECTOR_SYNC_UPDATE_INTERVAL = 50;
|
|
|
|
GameField::GameField()
|
|
: instanced_resourse_(false)
|
|
, m_pHLB( 0 )
|
|
, npc_trigger_events_(NULL)
|
|
{
|
|
m_pEffectManager = new EffectManager( this );
|
|
m_pTriggerManager = new TriggerManagerEx;
|
|
m_pUnitRegenManager = new UnitRegenManager;
|
|
m_pUnitGroupMgr = new UnitGroupManager;
|
|
m_pCollectionManager = new CollectionManager(this);
|
|
|
|
m_SyncUpdater.SetTimer(SECTOR_SYNC_UPDATE_INTERVAL);
|
|
}
|
|
|
|
GameField::~GameField()
|
|
{
|
|
SAFE_DELETE( m_pUnitGroupMgr );
|
|
SAFE_DELETE( m_pUnitRegenManager );
|
|
SAFE_DELETE( m_pEffectManager );
|
|
SAFE_DELETE( m_pTriggerManager );
|
|
SAFE_DELETE( m_pCollectionManager );
|
|
if (npc_trigger_events_) {
|
|
TAllocDelete(ns_trigger::TriggerNpcLinkMatchTable, npc_trigger_events_);
|
|
npc_trigger_events_ = NULL;
|
|
};
|
|
}
|
|
|
|
|
|
|
|
VOID GameField::Release()
|
|
{
|
|
m_pEffectManager->Release();
|
|
m_pTriggerManager->Release();
|
|
m_pCollectionManager->Release();
|
|
//__NA000000_20090320_DELAY_ITEM_DROP_TIME
|
|
g_DropManager.OnFieldRelease(m_pGameZone->GetKey());
|
|
|
|
// (WAVERIX)(080816)(MINOR-FIX)
|
|
// ObjectFactory::Instance()-> ==> pObjectFactory->
|
|
|
|
ObjectFactory* const pObjectFactory = ObjectFactory::Instance();
|
|
{
|
|
// NPC
|
|
for(_NPC_HASH::iterator it = m_NPCHash.begin(); it != m_NPCHash.end(); ++it)
|
|
{
|
|
NPC* npc = it->second;
|
|
if (npc != NULL)
|
|
{
|
|
npc->OnLeaveField();
|
|
}
|
|
}
|
|
for(_NPC_HASH::iterator it = m_NPCHash.begin(); it != m_NPCHash.end(); ++it)
|
|
{
|
|
NPC* npc = it->second;
|
|
if (npc != NULL)
|
|
{
|
|
pObjectFactory->FreeObject(npc);
|
|
npc = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
// MapObject
|
|
_MAPOBJECT_HASH::iterator it = m_MapObjectHash.begin(), end = m_MapObjectHash.end();
|
|
for( ; it != end ; ++it )
|
|
{
|
|
MapObject* pMapObject = it->second;
|
|
pMapObject->OnLeaveField();
|
|
pObjectFactory->FreeObject( pMapObject );
|
|
}
|
|
}
|
|
|
|
{
|
|
// 아이템 제거
|
|
_ITEM_HASH::iterator end = m_FieldItemHash.end();
|
|
for( _ITEM_HASH::iterator it = m_FieldItemHash.begin(); it != end ; ++it )
|
|
{
|
|
Item* pItem = it->second;
|
|
pItem->OnLeaveField();
|
|
pObjectFactory->FreeObject( pItem );
|
|
}
|
|
}
|
|
{
|
|
// 채집물 제거
|
|
_COLLECTION_HASH::iterator end = m_FieldCollectHash.end();
|
|
for( _COLLECTION_HASH::iterator it = m_FieldCollectHash.begin(); it != end ; ++it )
|
|
{
|
|
Collection* pCollection = it->second;
|
|
pCollection->OnLeaveField();
|
|
pObjectFactory->FreeObject( pCollection );
|
|
}
|
|
}
|
|
m_FieldCollectHash.clear();
|
|
//
|
|
m_NPCHash.clear();
|
|
m_NPCHashForUnitID.clear();
|
|
m_MapObjectHash.clear();
|
|
m_FieldItemHash.clear();
|
|
m_PlayerHash.clear();
|
|
m_CharacterHash.clear();
|
|
|
|
m_pUnitGroupMgr->Clear();
|
|
m_pUnitRegenManager->Release();
|
|
|
|
instanced_resourse_ = false;
|
|
if (npc_trigger_events_) {
|
|
TAllocDelete(ns_trigger::TriggerNpcLinkMatchTable, npc_trigger_events_);
|
|
npc_trigger_events_ = NULL;
|
|
};
|
|
// NOTE: f110531.4L
|
|
HighLoadBalancer::Instance()->UnRegisterBuffer( this );
|
|
|
|
Field::Release();
|
|
}
|
|
|
|
|
|
//────────────────────────────────────────────────────────────────
|
|
|
|
// GameField::BuildSector의 후신
|
|
VOID GameField::BuildInstanceInfo()
|
|
{
|
|
if (instanced_resourse_) {
|
|
return;
|
|
};
|
|
// 트리거에서 MapObject의 제어를 하는 구문이 존재 하므로 로딩(TriggerManager->Init())
|
|
// 이전에 생성 해야 하지만, 그럴경우 MapObject 생성에 의한 BuildInstanceInfo()의 재기 호출이 발생 할 수 있다.
|
|
// instanced_resourse_ 설정을 최상위로 변경 재기 호출을 막는다.
|
|
// 기존 BuildInstanceInfo가 재기 호출 되었던 부분이 의도된 것이라면 이후 사이드 이펙트를 예측하기
|
|
// 어려운 부분이 있다. 허나 Init()에 "트리거를 두번 초기화 하지 않는다." 는 정의가 있는 걸로 보아
|
|
// 문제가 없어 보인다. TriggerManagerEx::m_bInitCompleted 값의 사용 방법으로 보아 BuildInstanceInfo 의
|
|
// 재기를 막기 위한 방편으로 보여 진다. (주의 필요) [5/18/2010 lst1024]
|
|
|
|
instanced_resourse_ = true;
|
|
|
|
if( m_MapObjectHash.size() == 0 )
|
|
AddMapObjectAll();
|
|
|
|
// 트리거 로딩
|
|
if( m_tszTriggerGroupName[0] != '0')
|
|
{
|
|
TriggerGroupInfo* pGroupInfo = GetFieldInfo()->GetTriggerGroupInfo( m_tszTriggerGroupName );
|
|
ASSERT( pGroupInfo && "트리거 그룹이 없습니다!!(World.txt참고)" );
|
|
|
|
if( pGroupInfo )
|
|
{
|
|
#ifdef _NA_002098_20110307_ADD_NPC_CONTROL_TRIGGER_BASE
|
|
if (npc_trigger_events_ == NULL) {
|
|
npc_trigger_events_ = TAllocNew(ns_trigger::TriggerNpcLinkMatchTable);
|
|
};
|
|
npc_trigger_events_->Init(this);
|
|
m_pTriggerManager->Init(*pGroupInfo, this);
|
|
// post event
|
|
if (npc_trigger_events_->IsExistTriggerAreaEvent() == false) {
|
|
TAllocDelete(ns_trigger::TriggerNpcLinkMatchTable, npc_trigger_events_);
|
|
npc_trigger_events_ = NULL;
|
|
}
|
|
#else
|
|
m_pTriggerManager->Init(*pGroupInfo, this);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
SUNLOG( eCRITICAL_LOG
|
|
, "Map:%d,Field:%d,TriggerGroupName:%s"
|
|
, m_pGameZone->GetMapCode()
|
|
, m_pFieldInfo->GetFieldCode()
|
|
, m_tszTriggerGroupName
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//────────────────────────────────────────────────────────────────
|
|
|
|
//────────────────────────────────────────────────────────────────
|
|
|
|
VOID
|
|
GameField::Init(
|
|
GameZone* pZone
|
|
, FieldInfo* pFieldInfo
|
|
, const TCHAR* pszGroupName
|
|
, UnitRegenInfoManager* pUnitRegenInfoMgr
|
|
, UnitGroupInfoManager* pUnitGroupInfoMgr
|
|
, bool bPreMapLoading, bool bUsingViewPort, bool bPreRegen
|
|
)
|
|
{
|
|
m_pGameZone = pZone;
|
|
|
|
m_bPreRegen = bPreRegen;
|
|
if( pszGroupName )
|
|
{
|
|
_tcsncpy( m_tszTriggerGroupName, pszGroupName, MAX_MAPNAME_LENGTH );
|
|
// (WAVERIX)(080815)(BUG-FIX) - Buffer Overrun
|
|
// - (OLD) CHAR m_tszTriggerGroupName[MAX_MAPNAME_LENGTH]; 선언에 대한
|
|
// m_tszTriggerGroupName[MAX_MAPNAME_LENGTH] = '\0'; 처리
|
|
// - (NEW) CHAR m_tszTriggerGroupName[MAX_MAPNAME_LENGTH+1]; (변경)
|
|
m_tszTriggerGroupName[MAX_MAPNAME_LENGTH] = '\0';
|
|
}
|
|
else
|
|
{
|
|
m_tszTriggerGroupName[0] = '0';
|
|
m_tszTriggerGroupName[1] = '\0';
|
|
}
|
|
|
|
instanced_resourse_ = false;
|
|
// NOTE: f110531.4L
|
|
HighLoadBalancer::Instance()->RegisterBuffer( this );
|
|
|
|
Field::Init( pFieldInfo, bPreMapLoading, bUsingViewPort, bPreRegen );
|
|
|
|
m_pMovingPlanner->Init( this );
|
|
|
|
ASSERT( m_pUnitGroupMgr->GetCount() == 0 );
|
|
m_pUnitGroupMgr->Clear();
|
|
m_pUnitGroupInfoMgr = pUnitGroupInfoMgr;
|
|
|
|
m_pUnitRegenManager->Init( this, pUnitRegenInfoMgr, bPreRegen );
|
|
|
|
#ifdef _NA_007992_20150127_EVENT_MONSTER_INVASION
|
|
//마을이면 Init()에서 BuildInstanceInfo()를 호출하고
|
|
//마을이 아니면 EnterField()에서 한다
|
|
if (pZone->GetZoneType() == eZONETYPE_VILLAGE) {
|
|
BuildInstanceInfo();
|
|
}
|
|
#endif //_NA_007992_20150127_EVENT_MONSTER_INVASION
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
BOOL GameField::EnterField( Object *pObject, const WzVector *pwzVec, int iAngle )
|
|
{
|
|
const eOBJECT_TYPE objectType = pObject->GetObjectType();
|
|
|
|
// (WAVERIX)(080917)(NOTE)
|
|
// - 이걸 수행한 이유는 아무래도 일전의 불량 관리 CharacterHash에서 문제를 야기했을 가능성이 있다. 검증 후 불필요하게 만들자.
|
|
if( NULL != FindObject( objectType, pObject->GetObjectKey() ) )
|
|
return FALSE;
|
|
|
|
//__NA_276_20070213_UNIT_TRIGGER
|
|
DWORD npc_unit_id = 0;
|
|
if (pObject->IsEqualObjectKind(NPC_OBJECT))
|
|
{
|
|
NPC* pNPC = static_cast<NPC*>(pObject);
|
|
npc_unit_id = pNPC->GetRegenID();
|
|
if (npc_unit_id != 0)
|
|
{
|
|
if( NULL != FindNPCForUnitID(npc_unit_id))
|
|
return FALSE;
|
|
}
|
|
}
|
|
// (WAVERIX)(080917)(BUG-FIX) Field::EnterField 상태에서 GameField에 목록이 없는 상태에서 처리되는 상황 배제 목적
|
|
_AddObject( pObject );
|
|
const BOOL bEnterField = Field::EnterField( pObject, pwzVec, iAngle );
|
|
if( !bEnterField )
|
|
{
|
|
_DeleteObject( pObject );
|
|
return FALSE;
|
|
}
|
|
|
|
GameZone* const pGameZone = GetGameZone();
|
|
if( !pGameZone ) // GameZone이 없는데 성공을 반환하고 있다. 그 이유 및 타당성을 검증하라. (일단은 문의함... 찝찝하지만 넘어가자.
|
|
return TRUE;
|
|
|
|
#ifdef _NA_007992_20150127_EVENT_MONSTER_INVASION
|
|
if (pGameZone->GetZoneType() != eZONETYPE_VILLAGE) {
|
|
BuildInstanceInfo();
|
|
}
|
|
#endif //_NA_007992_20150127_EVENT_MONSTER_INVASION
|
|
|
|
pGameZone->SetZone( pObject, GetFieldCode(), 0, NULL );
|
|
if((objectType & CHARACTER_OBJECT) == CHARACTER_OBJECT)
|
|
{
|
|
Character* const pCharacter = static_cast<Character*>(pObject);
|
|
pCharacter->ChangePolicy(pGameZone);
|
|
|
|
// (CHANGES) (f100514.3L) add the flag to prevent ANY actions that
|
|
// a player do a delayed spiking whether the player request a LEAVE.
|
|
pCharacter->GetStatusManager()->ChangeInterState(eCHAR_STATE_ZONE_TRANSACTION, false);
|
|
// 공격 불가 상태로 전환시킨다.
|
|
sPOLICY_ZONE& rPolicyment = pGameZone->Policyment;
|
|
if(rPolicyment.FIELD & rPolicyment.ENABLE_SSQ_CONTROL)
|
|
{ //assert( GetTypeOfIndun() == INDUN_KIND_SS_QUEST );
|
|
GameWarControlManager::OnMsg(GameSSQCtrlCmd::CharacterState::Enter(pCharacter),
|
|
static_cast<GameInstanceDungeon*>(pGameZone));
|
|
}
|
|
}
|
|
#ifdef _NA_002098_20110307_ADD_NPC_CONTROL_TRIGGER_BASE
|
|
if (npc_unit_id != 0 && npc_trigger_events_ != NULL)
|
|
{
|
|
if (npc_trigger_events_->CheckExistAreaEvent(npc_unit_id))
|
|
{
|
|
NPC* npc = static_cast<NPC*>(pObject);
|
|
const sPOLICY_CHARACTER& CharPolicy = npc->Policyment;
|
|
npc->ChangePolicyPostEnterField(CharPolicy.PCC_EXIST_AREA_EVENT_NPC,
|
|
CharPolicy.PCC_DISABLE_ALL,
|
|
NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (npc_trigger_events_ != NULL && pObject->IsEqualObjectKind(NPC_OBJECT))
|
|
{
|
|
NPC* npc = static_cast<NPC*>(pObject);
|
|
MONSTERCODE monster_code = npc->GetBaseInfo()->m_MonsterCode;
|
|
if (npc_trigger_events_->CheckExistMonsterAreaEvent(monster_code))
|
|
{
|
|
const sPOLICY_CHARACTER& CharPolicy = npc->Policyment;
|
|
npc->ChangePolicyPostEnterField(CharPolicy.PCC_EXIST_AREA_EVENT_NPC,
|
|
CharPolicy.PCC_DISABLE_ALL,
|
|
NULL);
|
|
|
|
//!~ arycoat 2014.10.16
|
|
const int iTile = npc->GetPathExplorer()->GetTile();
|
|
if (GameField* game_field = npc->GetField()) {
|
|
if (ns_trigger::TriggerNpcLinkMatchTable* table =
|
|
game_field->GetNpcTriggerEvents())
|
|
{
|
|
#ifdef NA_007907_20141222_MODIFY_MONSTER_MOVE_TRIGGER
|
|
npc->Update(1);
|
|
#endif // NA_007907_20141222_MODIFY_MONSTER_MOVE_TRIGGER
|
|
table->OnChangeTile(-1, iTile, npc);
|
|
}
|
|
}
|
|
//~!
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
BOOL GameField::LeaveField( Object *pObject )
|
|
{
|
|
// (WAVERIX)(080917)(BUG-FIX) Field::LeaveField 이후 Object 제거하도록 수정
|
|
// 버퍼 초기화가 필요하다.
|
|
// 타락한 사원 관련
|
|
if(pObject->IsEqualObjectKind(CHARACTER_OBJECT))
|
|
{
|
|
Character* const pCharacter = static_cast<Character*>( pObject );
|
|
// (CHANGES) (f100514.3L) add the flag to prevent ANY actions that
|
|
// a player do a delayed spiking whether the player request a LEAVE.
|
|
pCharacter->GetStatusManager()->ChangeInterState(eCHAR_STATE_ZONE_TRANSACTION, true);
|
|
GameZone* const pGameZone = GetGameZone();
|
|
sPOLICY_ZONE& rPolicyment = pGameZone->Policyment;
|
|
if( rPolicyment.FIELD & rPolicyment.ENABLE_SSQ_CONTROL )
|
|
{
|
|
GameWarControlManager::OnMsg( GameSSQCtrlCmd::CharacterState::Leave( pCharacter ), static_cast<GameInstanceDungeon*>(pGameZone) );
|
|
}
|
|
}
|
|
|
|
const BOOL bLeavedSuccess = Field::LeaveField( pObject );
|
|
_DeleteObject( pObject );
|
|
// NOTE: f110531.4L
|
|
if (m_PlayerHash.empty()) {
|
|
HighLoadBalancer::Instance()->Update(this, true);
|
|
}
|
|
|
|
if( !bLeavedSuccess )
|
|
SUNLOG(eCRITICAL_LOG, "Field::LeaveField Fail Error! Caution!!!!!!!!!! %8X",
|
|
pObject->GetObjectType());
|
|
|
|
return bLeavedSuccess;
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
MapNpc* GameField::FindMapNpc(const Object::Key object_key) const
|
|
{
|
|
const MapObject* const map_object = FindMapObject(object_key);
|
|
if (map_object == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
const Object::Key link_obj_key = map_object->GetLinkedNpcObjectKey();
|
|
return static_cast<MapNpc*>(FindObject(MAPNPC_OBJECT, link_obj_key));
|
|
}
|
|
|
|
MapObject* GameField::FindMapObject(const Object::Key object_key) const
|
|
{
|
|
_MAPOBJECT_HASH::const_iterator it = m_MapObjectHash.find(object_key);
|
|
if (it != m_MapObjectHash.end())
|
|
{
|
|
Object* const object = it->second;
|
|
if (obj_util::IsValid(object, __FUNCTION__, __LINE__) == false)
|
|
{
|
|
return NULL;
|
|
}
|
|
return it->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
Character* GameField::FindCharacter(const Object::Key object_key) const
|
|
{
|
|
_CHARACTER_HASH::const_iterator it = m_CharacterHash.find(object_key);
|
|
if (it != m_CharacterHash.end())
|
|
{
|
|
Object* const object = it->second;
|
|
if (obj_util::IsValid(object, __FUNCTION__, __LINE__) == false)
|
|
{
|
|
return NULL;
|
|
}
|
|
return it->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
NPC* GameField::FindNPCForUnitID(const DWORD unit_id) const
|
|
{
|
|
_NPC_HASH::const_iterator it = m_NPCHashForUnitID.find(unit_id);
|
|
if (it != m_NPCHashForUnitID.end())
|
|
{
|
|
Object* const object = it->second;
|
|
if (obj_util::IsValid(object, __FUNCTION__, __LINE__) == false)
|
|
{
|
|
return NULL;
|
|
}
|
|
return it->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void GameField::_LinkedMapNpc(Object* pObj)
|
|
{
|
|
ASSERT(pObj);
|
|
ASSERT(MAPNPC_OBJECT == pObj->GetObjectType());
|
|
|
|
MapNpc* pMapNpc = static_cast<MapNpc*>(pObj);
|
|
MapObject* pMapObject = FindMapObject(pMapNpc->GetMapObjectID());
|
|
|
|
if (NULL != pMapObject)
|
|
pMapObject->SetLinkedNpcObjectKey(pMapNpc->GetObjectKey());
|
|
}
|
|
|
|
void GameField::_UnLinkedMapNpc(Object* pObj)
|
|
{
|
|
ASSERT(pObj);
|
|
ASSERT(MAPNPC_OBJECT == pObj->GetObjectType());
|
|
|
|
MapNpc* pMapNpc = static_cast<MapNpc*>(pObj);
|
|
MapObject* pMapObject = FindMapObject(pMapNpc->GetMapObjectID());
|
|
|
|
if (NULL != pMapObject)
|
|
pMapObject->SetLinkedNpcObjectKey(0);
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
void GameField::_AddObject( Object* pObj )
|
|
{
|
|
if( NULL != FindObject( pObj->GetObjectType(), pObj->GetObjectKey() ) )
|
|
return;
|
|
|
|
switch( pObj->GetObjectType() )
|
|
{
|
|
case OBJECT_OBJECT:
|
|
case CHARACTER_OBJECT:
|
|
case NONCHARACTER_OBJECT:
|
|
case NPC_OBJECT:
|
|
ASSERT(!"NPC_OBJECT Object add Error!");
|
|
break;
|
|
case PLAYER_OBJECT:
|
|
m_PlayerHash[pObj->GetObjectKey()] = static_cast<Player*>(pObj);
|
|
m_CharacterHash[pObj->GetObjectKey()] = static_cast<Character*>(pObj);
|
|
break;
|
|
case MONSTER_OBJECT:
|
|
case SUMMON_OBJECT:
|
|
case MAPNPC_OBJECT:
|
|
case MERCHANT_OBJECT:
|
|
case LUCKYMON_OBJECT:
|
|
case TOTEMNPC_OBJECT:
|
|
case SSQMONSTER_OBJECT:
|
|
case CRYSTALWARP_OBJECT:
|
|
case FRIEND_MONSTER_OBJECT:
|
|
case SYNC_MERCHANT_OBJECT:
|
|
if (NPC* npc = static_cast<NPC*>(pObj))
|
|
{
|
|
DWORD object_key = npc->GetObjectKey();
|
|
m_NPCHash[object_key] = npc;
|
|
m_CharacterHash[object_key] = npc;
|
|
const DWORD unit_id = npc->GetRegenID();
|
|
if (unit_id == 0) {
|
|
break;
|
|
};
|
|
_NPC_HASH::_Pairib result = \
|
|
m_NPCHashForUnitID.insert(_NPC_HASH::value_type(unit_id, npc));
|
|
if (result.second == false) {
|
|
assert(!"unexpected status");
|
|
SUNLOG(eCRITICAL_LOG, "Can not add m_NPCHashForUnitID map(%u)", unit_id);
|
|
break;
|
|
};
|
|
};
|
|
break;
|
|
case ITEM_OBJECT:
|
|
case MONEY_OBJECT:
|
|
m_FieldItemHash[pObj->GetObjectKey()] = static_cast<Item *>(pObj);
|
|
break;
|
|
case COLLECTION_OBJECT:
|
|
m_FieldCollectHash[pObj->GetObjectKey()] = static_cast<Collection*>(pObj);
|
|
break;
|
|
default:
|
|
ASSERT(!"default Object add Error!");
|
|
break;
|
|
}
|
|
|
|
if (MAPNPC_OBJECT == pObj->GetObjectType())
|
|
_LinkedMapNpc(pObj);
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
bool GameField::_DeleteObject( Object* pObj )
|
|
{
|
|
const eOBJECT_TYPE objType = pObj->GetObjectType();
|
|
|
|
if( NULL == FindObject( objType, pObj->GetObjectKey() ) )
|
|
return false;
|
|
|
|
if (MAPNPC_OBJECT == pObj->GetObjectType())
|
|
_UnLinkedMapNpc(pObj);
|
|
|
|
switch( pObj->GetObjectType() )
|
|
{
|
|
case OBJECT_OBJECT:
|
|
case CHARACTER_OBJECT:
|
|
case NONCHARACTER_OBJECT:
|
|
case NPC_OBJECT:
|
|
ASSERT(!"NPC_OBJECT Object rem Error!");
|
|
return false;
|
|
case PLAYER_OBJECT:
|
|
m_PlayerHash.erase( pObj->GetObjectKey() );
|
|
m_CharacterHash.erase( pObj->GetObjectKey() );
|
|
break;
|
|
case MONSTER_OBJECT:
|
|
case SUMMON_OBJECT:
|
|
case MERCHANT_OBJECT:
|
|
case MAPNPC_OBJECT:
|
|
case LUCKYMON_OBJECT:
|
|
case TOTEMNPC_OBJECT:
|
|
case SSQMONSTER_OBJECT:
|
|
case CRYSTALWARP_OBJECT:
|
|
case FRIEND_MONSTER_OBJECT:
|
|
case SYNC_MERCHANT_OBJECT:
|
|
if (DWORD object_key = pObj->GetObjectKey())
|
|
{
|
|
m_NPCHash.erase(object_key);
|
|
m_CharacterHash.erase(object_key);
|
|
const DWORD unit_id = static_cast<NPC*>(pObj)->GetRegenID();
|
|
if (unit_id != 0) {
|
|
m_NPCHashForUnitID.erase(unit_id);
|
|
};
|
|
};
|
|
break;
|
|
case ITEM_OBJECT:
|
|
case MONEY_OBJECT:
|
|
m_FieldItemHash.erase( pObj->GetObjectKey() );
|
|
break;
|
|
case COLLECTION_OBJECT:
|
|
m_FieldCollectHash.erase( pObj->GetObjectKey() );
|
|
break;
|
|
default:
|
|
ASSERT(!"default Object rem Error!");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//==================================================================================================
|
|
|
|
void GameField::DestroyObject( Object* pObj )
|
|
{
|
|
// (NOTE) important, designed by __NA000000_090310_GAMEFIELD_RECURSIVELY_CALL_PROBLEM_FIX__
|
|
pObj->RequestDelete();
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
VOID GameField::AddMapObjectAll()
|
|
{
|
|
ASSERT( m_pSharedFieldInfo );
|
|
|
|
// 맵오브젝트 생성
|
|
MAPOBJECT_INFO_HASH & rMapObjectInfoTable = m_pSharedFieldInfo->GetMapObjectInfoHashTable();
|
|
MAPOBJECT_INFO *pMapInfo = NULL;
|
|
MAPOBJECT_INFO_HASH_IT it, end = rMapObjectInfoTable.end();
|
|
for( it = rMapObjectInfoTable.begin() ; it != end ; ++it )
|
|
{
|
|
pMapInfo = (it->second);
|
|
|
|
// 맵오브젝트
|
|
MapObject* pMapObject = static_cast<MapObject *>(ObjectFactory::Instance()->AllocObject(MAP_OBJECT));
|
|
pMapObject->Init();
|
|
pMapObject->SetObjectKey( pMapInfo->dwMapObjectID );
|
|
pMapObject->SetPos( &pMapInfo->wvPos );
|
|
m_MapObjectHash[pMapObject->GetObjectKey()] = pMapObject;
|
|
|
|
DWORD dwCode = pMapInfo->dwExtraInfos[eMAPOBJECT_MONSTER];
|
|
ASSERT(SAFE_NUMERIC_TYPECAST( DWORD, dwCode, WORD ));
|
|
WORD NPCCode = (WORD)dwCode;
|
|
|
|
//_NA_0_20100222_UNIT_TRIGGERS_REGEN
|
|
// 맵오브젝트에 연결된 몬스터의 경우 미리 생성되어 진다.
|
|
// 예외로 헬론의 성 서브 미션의 경우 트리거 액션에 의해 생성되어 진다.
|
|
const DWORD dwRegenType = pMapInfo->dwExtraInfos[eMAPOBJECT_LINKED_MONSTER_REGEN_TYPE];
|
|
const bool bPreRegen = !((dwRegenType & REGEN_TYPE_TRIGGER) == REGEN_TYPE_TRIGGER);
|
|
|
|
if( 0 != dwCode && false != bPreRegen)
|
|
{
|
|
if( !NPCInfoParser::Instance()->GetNPCInfo( NPCCode ) )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[Field:%u]MapObject Monster(%u) Is Not Found", GetFieldCode(), pMapInfo->dwExtraInfos[eMAPOBJECT_MONSTER] );
|
|
SUNLOG( eCRITICAL_LOG, "[Field:%u]MapObject(ID:%u),(ExtraInfoValue)[TYPE(1):%u,MONSTER(2):%u,(Reserved:%u,%u)]",
|
|
GetFieldCode(),
|
|
pMapInfo->dwMapObjectID,
|
|
pMapInfo->dwExtraInfos[eMAPOBJECT_TYPE],
|
|
pMapInfo->dwExtraInfos[eMAPOBJECT_MONSTER],
|
|
pMapInfo->dwExtraInfos[eMAPOBJECT_USE_ALPHA],
|
|
pMapInfo->dwExtraInfos[eMAPOBJECT_LINKED_MONSTER_REGEN_TYPE]
|
|
);
|
|
}
|
|
else
|
|
{
|
|
MapNpc* pNPC = CreateMapNPC( NPCCode, &pMapInfo->wvPos, pMapInfo );
|
|
ASSERT( pNPC );
|
|
}
|
|
}
|
|
|
|
// (lst1024)(채집) 필드 생성시 오브젝트중 채집물은 모두 생성해 둔다.
|
|
if( 0 != pMapInfo->CollectionID )
|
|
{
|
|
if( NULL == CollectionParser::Instance()->FindCollectionInfo(pMapInfo->CollectionID) )
|
|
{
|
|
char ch[5] = {0,};
|
|
|
|
SUNLOG( eCRITICAL_LOG,
|
|
"轟랬冷돕꽃섞膠斤口. "
|
|
"Field[%u] MapObjectKey[%u] CollectionID[%s] "
|
|
"ExtraInfoValue[TYPE(1):%u,MONSTER(2):%u,(Reserved:%u,%u)]",
|
|
GetFieldCode(),
|
|
pMapInfo->dwMapObjectID,
|
|
WzIDToString(ch,pMapInfo->CollectionID),
|
|
pMapInfo->dwExtraInfos[eMAPOBJECT_TYPE],
|
|
pMapInfo->dwExtraInfos[eMAPOBJECT_MONSTER],
|
|
pMapInfo->dwExtraInfos[eMAPOBJECT_USE_ALPHA],
|
|
pMapInfo->dwExtraInfos[eMAPOBJECT_LINKED_MONSTER_REGEN_TYPE] );
|
|
}
|
|
else
|
|
{
|
|
Collection* pCollection = CreateCollection( pMapInfo );
|
|
ASSERT( pCollection );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
VOID
|
|
GameField::Update(DWORD delta_tick)
|
|
{
|
|
if (!IsReady()) {
|
|
return;
|
|
}
|
|
|
|
#ifdef _NA_007992_20150127_EVENT_MONSTER_INVASION
|
|
GameZone* zone = GetGameZone();
|
|
if (zone != NULL && zone->GetZoneType() == eZONETYPE_VILLAGE)
|
|
{
|
|
m_pTriggerManager->Update();
|
|
if (m_PlayerHash.empty()) {
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_PlayerHash.empty()) {
|
|
return;
|
|
}
|
|
m_pTriggerManager->Update();
|
|
}
|
|
#else
|
|
|
|
if (m_PlayerHash.empty()) {
|
|
return;
|
|
}
|
|
m_pTriggerManager->Update();
|
|
#endif //_NA_007992_20150127_EVENT_MONSTER_INVASION
|
|
|
|
m_pUnitRegenManager->Update();
|
|
m_pEffectManager->Update( GetTickCount() );
|
|
m_pCollectionManager->Update();
|
|
|
|
ObjectFactory* const object_factory = ObjectFactory::Instance();
|
|
|
|
// 아이템
|
|
for (_ITEM_HASH::iterator it = m_FieldItemHash.begin(); it != m_FieldItemHash.end();)
|
|
{
|
|
Item* item = it->second;
|
|
if (item == NULL)
|
|
{
|
|
m_FieldItemHash.erase(it++);
|
|
}
|
|
else if (item->Update(delta_tick) == FALSE)
|
|
{
|
|
Field::LeaveField(item);
|
|
m_FieldItemHash.erase(it++);
|
|
object_factory->FreeObject(item);
|
|
item = NULL;
|
|
}
|
|
else
|
|
{
|
|
++it;
|
|
}
|
|
}
|
|
|
|
// 몬스터
|
|
for (_NPC_HASH::iterator it = m_NPCHash.begin(); it != m_NPCHash.end();)
|
|
{
|
|
NPC* npc = it->second;
|
|
if (npc == NULL)
|
|
{
|
|
m_NPCHash.erase(it++);
|
|
}
|
|
//#ifdef _NA_004126_20120111_CHANGE_GAME_SERVER_OBJECT_FACTORY
|
|
else if (npc->IsDeleted())
|
|
{
|
|
const Object::Key key = npc->GetObjectKey();
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|%d|Object is already deleted.|ObjectKey = %d|"),
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
key
|
|
);
|
|
m_NPCHash.erase(it++);
|
|
m_CharacterHash.erase(key);
|
|
}
|
|
//#endif
|
|
else if (npc->Update(delta_tick) == FALSE)
|
|
{
|
|
const CODETYPE monster_object_key = npc->GetObjectKey();
|
|
if (npc->IsEqualObjectKind(MONSTER_OBJECT))
|
|
{
|
|
if (npc->GetUnitRegenInfo()) //< 임시
|
|
{
|
|
ASSERT(npc->GetRegenID());
|
|
|
|
// 럭키 몬스터의 경우 소멸조건에 따라 다음 리젠타임이 달라진다.
|
|
DWORD regen_time = npc->GetUnitRegenInfo()->GetRegenTime();
|
|
if (npc->IsEqualObjectKind(LUCKYMON_OBJECT))
|
|
{
|
|
LuckyMonster* lucky_monster = static_cast<LuckyMonster*>(npc);
|
|
if (lucky_monster->GetRunAwayRegenTime())
|
|
{
|
|
regen_time = lucky_monster->GetRunAwayRegenTime();
|
|
}
|
|
}
|
|
m_pUnitRegenManager->AddOnWaiting(npc->GetRegenID(), regen_time);
|
|
}
|
|
}
|
|
|
|
Field::LeaveField(npc);
|
|
|
|
m_NPCHash.erase(it++);
|
|
m_CharacterHash.erase(monster_object_key); // (WAVERIX)(080822)(BUG-FIX) erase가 없었다.
|
|
|
|
//__NA_276_20070213_UNIT_TRIGGER
|
|
const DWORD regen_id = npc->GetRegenID();
|
|
if (regen_id != 0)
|
|
{
|
|
m_NPCHashForUnitID.erase(regen_id);
|
|
}
|
|
object_factory->FreeObject(npc);
|
|
npc = NULL;
|
|
}
|
|
else
|
|
{
|
|
++it;
|
|
}
|
|
}
|
|
|
|
Field::Update(delta_tick);
|
|
|
|
// NOTE: f110531.4L
|
|
if (m_SyncUpdater.IsExpired())
|
|
{
|
|
HighLoadBalancer::Instance()->Update(this, true);
|
|
}
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
Item* GameField::CreateItem( const WzVector* pvPos, DWORD dwPlayerKey, DWORD dwFromMonsterKey, SCItemSlot & slot )
|
|
{
|
|
Item* pFieldItem = static_cast<Item *>(ObjectFactory::Instance()->AllocObject( ITEM_OBJECT ));
|
|
pFieldItem->Init();
|
|
pFieldItem->CreateItem( dwPlayerKey, dwFromMonsterKey, slot );
|
|
if( FALSE == EnterField( pFieldItem, pvPos, 0 ) )
|
|
{
|
|
ObjectFactory::Instance()->FreeObject( pFieldItem );
|
|
SUNLOG( eCRITICAL_LOG, "[Item EnterField] Pos[%f, %f, %f] is failed!", pvPos->x, pvPos->y, pvPos->z );
|
|
return FALSE;
|
|
}
|
|
return pFieldItem;
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
Item* GameField::CreateMoney( const WzVector* pvPos, DWORD dwPlayerKey, DWORD dwFromMonsterKey, const MONEY& Money)
|
|
{
|
|
Item* pFieldMoneyItem = static_cast<Item *>(ObjectFactory::Instance()->AllocObject( MONEY_OBJECT ));
|
|
pFieldMoneyItem->Init();
|
|
pFieldMoneyItem->CreateMoney( dwPlayerKey, dwFromMonsterKey, Money );
|
|
|
|
if( FALSE == EnterField( pFieldMoneyItem, pvPos, 0 ) )
|
|
{
|
|
ObjectFactory::Instance()->FreeObject( pFieldMoneyItem );
|
|
SUNLOG( eCRITICAL_LOG, "[Item EnterField] Pos[%f, %f, %f] is failed!", pvPos->x, pvPos->y, pvPos->z );
|
|
return NULL;
|
|
}
|
|
return pFieldMoneyItem;
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
#include <GroupParser.h>
|
|
|
|
boost::shared_ptr<Monster> GameField::CreateMonster( WORD NPCCode, const WzVector *pvPos,
|
|
WORD wGroupID, int iAngle, BYTE byMoveType, DWORD dwMoveAreaID, WORD MissionAreaID/*미션전용임시*/ )
|
|
{
|
|
boost::shared_ptr<Monster>pSpawnMonster( AllocMonster( NPCCode, byMoveType, dwMoveAreaID ));
|
|
|
|
if( !pSpawnMonster ) return boost::shared_ptr<Monster>((Monster*)0);
|
|
|
|
if( 0 != wGroupID )
|
|
{
|
|
DWORD dwNewGroupID = MAKEDWORD(MissionAreaID,wGroupID);
|
|
UnitGroupInfo* pGroupInfo = m_pUnitGroupInfoMgr->Find( dwNewGroupID );
|
|
if( !pGroupInfo )
|
|
{
|
|
BASE_GROUPINFO* pBaseGroupInfo = GroupParser::Instance()->GetGroupInfo( wGroupID );
|
|
ASSERT(pBaseGroupInfo);
|
|
if( !pBaseGroupInfo )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[Field:%u],Group[%u,%u] pBaseGroupInfo is NULL", GetFieldCode(), dwNewGroupID, wGroupID );
|
|
}
|
|
else
|
|
{
|
|
pGroupInfo = new UnitGroupInfo;
|
|
pGroupInfo->SetID(dwNewGroupID);
|
|
pGroupInfo->SetLeaderRegenID(0);
|
|
m_pUnitGroupInfoMgr->Insert( dwNewGroupID, pGroupInfo );
|
|
}
|
|
}
|
|
|
|
if( pGroupInfo && 0 == pGroupInfo->GetLeaderRegenID() )
|
|
{
|
|
BASE_GROUPINFO* pBaseGroupInfo = GroupParser::Instance()->GetGroupInfo( wGroupID );
|
|
ASSERT(pBaseGroupInfo);
|
|
if( pBaseGroupInfo && NPCCode == pBaseGroupInfo->dwLeaderCode )
|
|
{
|
|
pGroupInfo->SetLeaderRegenID(pSpawnMonster->GetObjectKey());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//SUNLOG( eCRITICAL_LOG, "그룹[%u]이미 리더[%u]가 존재함[%u]2!", wGroupID, pGroupInfo->GetLeaderRegenID(), NPCCode );
|
|
}
|
|
|
|
pSpawnMonster->SetUnitGroupInfo( pGroupInfo );
|
|
}
|
|
|
|
if( !EnterField( pSpawnMonster.get(), pvPos, iAngle ) )
|
|
{
|
|
ObjectFactory::Instance()->FreeObject( pSpawnMonster.get() );
|
|
return boost::shared_ptr<Monster>((Monster*)0);
|
|
}
|
|
//岬밍斤口渴놔 by:枷쟁팃숲� 2021-06-28
|
|
//SUNLOG( eCRITICAL_LOG, "MonsterID[%u],[Field:%u],Group[%u,%u]",NPCCode, GetFieldCode(), wGroupID, wGroupID );
|
|
return pSpawnMonster;
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
boost::shared_ptr<Monster> GameField::CreateSummonByNPC( WORD NPCCode, const WzVector* pvPos, Character *pSummoner, SummonedNPCs *pOwnerSummonNPCs )
|
|
{
|
|
BASE_NPCINFO* pInfo = NPCInfoParser::Instance()->GetNPCInfo( NPCCode );
|
|
ASSERT( pInfo );
|
|
if( !pInfo )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, _T("It isn't exist NPC Info for Code[%u]]"), NPCCode );
|
|
return boost::shared_ptr<Monster>((Monster*)0);
|
|
}
|
|
|
|
|
|
boost::shared_ptr<Monster>pMonster = boost::shared_ptr<Monster>(ObjectFactory::Instance()->AllocObject( MONSTER_OBJECT ));
|
|
if (pMonster == NULL) {
|
|
return boost::shared_ptr<Monster>((Monster*)0);
|
|
}
|
|
|
|
pMonster->InitMonster( NPCCode, 0, 0 );
|
|
// NPC에 소환인포 포인터 공유
|
|
pMonster->SetSummonerKey( pSummoner->GetObjectKey() );
|
|
// 소환자의 타겟을 추적하도록 NPC의 상태를 바꾼다.
|
|
if( pSummoner->GetTargetChar() )
|
|
{
|
|
pMonster->SetTargetChar( pSummoner->GetTargetChar() );
|
|
pMonster->ChangeState( STATE_ID_HELP );
|
|
}
|
|
|
|
if( !EnterField( pMonster.get(), pvPos, -1 ) )
|
|
{
|
|
ObjectFactory::Instance()->FreeObject( pMonster.get() );
|
|
return boost::shared_ptr<Monster>((Monster*)0);
|
|
}
|
|
|
|
// 소환자의 소환인포에 몬스터 수 증가
|
|
pOwnerSummonNPCs->IncreaseSummoned( NPCCode, pMonster.get() );
|
|
|
|
return pMonster;
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
Summoned* GameField::CreateSummonByPlayer( WORD NPCCode, const WzVector* pvPos, Character *pSummoner,
|
|
SummonedNPCs* pOwnerSummonNPCs, DWORD dwExpireTime, SLOTCODE SkillCode, const PLAYER_SUMMON_INFO* const summon_info)
|
|
{
|
|
Summoned *pSummoned = static_cast<Summoned*>(ObjectFactory::Instance()->AllocObject( SUMMON_OBJECT ));
|
|
pSummoned->InitSummoned( NPCCode, SkillCode, pSummoner, dwExpireTime );
|
|
|
|
if (summon_info != NULL)
|
|
{
|
|
pSummoned->SetHP(summon_info->hp);
|
|
pSummoned->SetMP(summon_info->mp);
|
|
const eSUMMON_COMMAND command = (summon_info->command == eSUMMON_COMMAND_ATTACK) ?
|
|
eSUMMON_COMMAND_DELEGATE_ATTACK : summon_info->command;
|
|
pSummoned->SetCommandState(command, 0);
|
|
}
|
|
|
|
if( !EnterField( pSummoned, pvPos, -1 ) )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[CreateSummonByPlayer EnterField][Key:%u,Code:%u] Pos[%f, %f, %f] is failed!",
|
|
pSummoned->GetObjectKey(), NPCCode, pvPos->x, pvPos->y, pvPos->z );
|
|
ObjectFactory::Instance()->FreeObject( pSummoned );
|
|
return NULL;
|
|
}
|
|
// 소환자의 소환인포에 몬스터 수 증가
|
|
pOwnerSummonNPCs->IncreaseSummoned( NPCCode, pSummoned );
|
|
// (CHANGES) (100205) (WAVERIX) 플레이어에 의한 소환수의 경우 AI update를 위해 세부 룰을 변경.
|
|
const sPOLICY_CHARACTER& CharPolicyment = pSummoned->Policyment;
|
|
pSummoned->ChangePolicyPostEnterField(CharPolicyment.PCC_CONTINUING_NPC_UPDATE,
|
|
CharPolicyment.PCC_DISABLE_ALL,
|
|
pSummoner);
|
|
|
|
return pSummoned;
|
|
}
|
|
|
|
//죽은 몬스터를 소환한다.
|
|
//제거후 소환자옆에 생성한다.
|
|
// __NA_S00015_20080828_NEW_HOPE_SHADOW
|
|
Summoned* GameField::CreateSummonDeadMonster( WORD NPCCode, const WzVector* pvPos, Character *pSummoner, SummonedNPCs* pOwnerSummonNPCs, SLOTCODE SkillCode )
|
|
{
|
|
Summoned *pSummoned = static_cast<Summoned*>(ObjectFactory::Instance()->AllocObject( SUMMON_OBJECT ));
|
|
pSummoned->InitSummonedDeadMonster( NPCCode, SkillCode, pSummoner );
|
|
|
|
if( !EnterField( pSummoned, pvPos, -1 ) )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[CreateSummonByPlayer EnterField][Key:%u,Code:%u] Pos[%f, %f, %f] is failed!",
|
|
pSummoned->GetObjectKey(), NPCCode, pvPos->x, pvPos->y, pvPos->z );
|
|
ObjectFactory::Instance()->FreeObject( pSummoned );
|
|
return NULL;
|
|
}
|
|
// 소환자의 소환인포에 몬스터 수 증가
|
|
pOwnerSummonNPCs->IncreaseSummoned( NPCCode, pSummoned );
|
|
// (CHANGES) (100205) (WAVERIX) 플레이어에 의한 소환수의 경우 AI update를 위해 세부 룰을 변경.
|
|
const sPOLICY_CHARACTER& CharPolicyment = pSummoned->Policyment;
|
|
pSummoned->ChangePolicyPostEnterField(CharPolicyment.PCC_CONTINUING_NPC_UPDATE,
|
|
CharPolicyment.PCC_DISABLE_ALL,
|
|
pSummoner);
|
|
|
|
return pSummoned;
|
|
}
|
|
|
|
CrystalWarp* GameField::CreateSummonCrystalWarp( WORD NPCCode, const WzVector* pvPos, DWORD dwGuildGuid, DWORD dwExpireTime )
|
|
{
|
|
CrystalWarp* pCrystalWarp = static_cast<CrystalWarp*>(ObjectFactory::Instance()->AllocObject( CRYSTALWARP_OBJECT ));
|
|
pCrystalWarp->InitCrystalWarp( NPCCode, dwGuildGuid, dwExpireTime );
|
|
|
|
if( !EnterField( pCrystalWarp, pvPos, -1 ) )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[CreateSummonCrystalWarp] [Key:%u,Code:%u] Pos[%f, %f, %f] is failed!",
|
|
pCrystalWarp->GetObjectKey(), NPCCode, pvPos->x, pvPos->y, pvPos->z );
|
|
ObjectFactory::Instance()->FreeObject( pCrystalWarp );
|
|
return NULL;
|
|
}
|
|
|
|
return pCrystalWarp;
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
MapNpc* GameField::CreateMapNPC( WORD NPCCode, const WzVector* pvPos, MAPOBJECT_INFO *pMapInfo )
|
|
{
|
|
MapNpc *pMapNpc = static_cast<MapNpc*>(ObjectFactory::Instance()->AllocObject( MAPNPC_OBJECT ));
|
|
pMapNpc->InitMapNPC( NPCCode, pMapInfo );
|
|
|
|
int dir = static_cast<int>(WZRAD2DEG(pMapInfo->wzRot.z));
|
|
dir %= 360;
|
|
if (dir < 0)
|
|
dir += 360;
|
|
|
|
if( !EnterField(pMapNpc, pvPos, dir) )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[CreateMapNPC EnterField][Key:%u,Code:%u] Pos[%f, %f, %f] is failed!",
|
|
pMapNpc->GetObjectKey(), NPCCode, pvPos->x, pvPos->y, pvPos->z );
|
|
|
|
ObjectFactory::Instance()->FreeObject( pMapNpc );
|
|
return NULL;
|
|
}
|
|
|
|
return pMapNpc;
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
TotemNpc* GameField::CreateTotemNPC( WORD NPCCode, const WzVector* pvPos, Player* pSummoner, SCItemSlot & IN slot )
|
|
{
|
|
TotemNpc *pTotemNpc = static_cast<TotemNpc*>(ObjectFactory::Instance()->AllocObject( TOTEMNPC_OBJECT ));
|
|
pTotemNpc->InitTotemNpc( NPCCode, pSummoner, slot );
|
|
|
|
if( !EnterField( pTotemNpc, pvPos, -1 ) )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[CreateTotemNPC EnterField][Key:%u,Code:%u] Pos[%f, %f, %f] is failed!",
|
|
pTotemNpc->GetObjectKey(), NPCCode, pvPos->x, pvPos->y, pvPos->z );
|
|
|
|
ObjectFactory::Instance()->FreeObject( pTotemNpc );
|
|
return NULL;
|
|
}
|
|
|
|
return pTotemNpc;
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
//{__NA001283_20090225_COLLECTION_USE
|
|
Collection* GameField::CreateCollection( MAPOBJECT_INFO *pMapInfo )
|
|
{
|
|
Collection* pCollection = static_cast<Collection*>(ObjectFactory::Instance()->AllocObject( COLLECTION_OBJECT ));
|
|
pCollection->InitCollection( pMapInfo );
|
|
pCollection->SetObjectKey( pMapInfo->dwMapObjectID );
|
|
pCollection->SetPos( &pMapInfo->wvPos );
|
|
|
|
int dir = static_cast<int>(WZRAD2DEG(pMapInfo->wzRot.z));
|
|
dir %= 360;
|
|
if (dir < 0)
|
|
dir += 360;
|
|
|
|
if( !EnterField( pCollection, &pMapInfo->wvPos, dir ) )
|
|
{
|
|
char ch[5] = {0,};
|
|
SUNLOG( eCRITICAL_LOG, "[CreateCollection EnterField][Key:%u,wzId:%s] Pos[%f, %f, %f] is failed!",
|
|
pCollection->GetObjectKey(), WzIDToString(ch, pMapInfo->CollectionID), pMapInfo->wvPos.x, pMapInfo->wvPos.y, pMapInfo->wvPos.z );
|
|
|
|
ObjectFactory::Instance()->FreeObject( pCollection );
|
|
return NULL;
|
|
}
|
|
|
|
return pCollection;
|
|
}
|
|
//}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
boost::shared_ptr<Monster> GameField::SpawnMonster( UnitRegenInfo* pUnitRegenInfo )
|
|
{
|
|
int npc_code = pUnitRegenInfo->GetRandomNPCCode();
|
|
const int npc_unit_type = pUnitRegenInfo->GetUnitType();
|
|
|
|
#ifdef _NA_003649_20111115_BATTLE_ZONE_HARDMODE
|
|
;{
|
|
MONSTERCODE replaace_monster_code = \
|
|
AppliedNpcDependencyChain::Instance()->GetRepleaceMonsterCode(GetGameZone(), npc_code, true);
|
|
|
|
if (replaace_monster_code) {
|
|
npc_code = replaace_monster_code;
|
|
}
|
|
};
|
|
#endif //_NA_003649_20111115_BATTLE_ZONE_HARDMODE
|
|
|
|
boost::shared_ptr<Monster> pSpawnMonster = AllocMonster( npc_code, npc_unit_type, 0 );
|
|
|
|
if( !pSpawnMonster )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[SpawnMonster] 밍膠�냥呵겨!" );
|
|
return boost::shared_ptr<Monster>((Monster*)0);
|
|
}
|
|
|
|
pSpawnMonster->SetUnitRegenInfo( pUnitRegenInfo );
|
|
|
|
if( 0 != pUnitRegenInfo->GetGroupID() )
|
|
{
|
|
UnitGroupInfo* pGroupInfo = m_pUnitGroupInfoMgr->Find( pUnitRegenInfo->GetGroupID() );
|
|
if( pGroupInfo )
|
|
pSpawnMonster->SetUnitGroupInfo( pGroupInfo );
|
|
}
|
|
|
|
const WORD pos_index = pUnitRegenInfo->GetRandomPosIndex();
|
|
const WzVector& vStartPos = pUnitRegenInfo->GetStartPos(pos_index);
|
|
|
|
NPCStateManager* const state_manager = pSpawnMonster->GetStateManager();
|
|
state_manager->SetMovePosIndex(pos_index);
|
|
|
|
if( pUnitRegenInfo->GetDir() > 360 )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[SpawnMonster] Dir[%f] is over!", pUnitRegenInfo->GetDir() );
|
|
pUnitRegenInfo->SetDir( (float)( (int)pUnitRegenInfo->GetDir() % 360 ) );
|
|
}
|
|
|
|
if( FALSE == EnterField( pSpawnMonster.get(), &vStartPos, (int)pUnitRegenInfo->GetDir() ) )
|
|
{
|
|
ObjectFactory::Instance()->FreeObject( pSpawnMonster.get() );
|
|
SUNLOG( eCRITICAL_LOG, "[SpawnMonster EnterField][Field:%u,Code:%u] Pos[%f, %f, %f] is failed!",
|
|
GetFieldCode(), npc_code, vStartPos.x, vStartPos.y, vStartPos.z );
|
|
return boost::shared_ptr<Monster>((Monster*)0);
|
|
}
|
|
|
|
return pSpawnMonster;
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
boost::shared_ptr<Monster> GameField::AllocMonster( WORD NPCCode, BYTE byMoveType, DWORD dwMoveAreaID )
|
|
{
|
|
|
|
BASE_NPCINFO *pBaseNPCInfo = NPCInfoParser::Instance()->GetNPCInfo( NPCCode );
|
|
if( !pBaseNPCInfo )
|
|
{
|
|
SUNLOG( eCRITICAL_LOG, "[AllocMonster] MonterCode(%d)IsNotFound", NPCCode );
|
|
return boost::shared_ptr<Monster>((Monster*)0);
|
|
}
|
|
|
|
boost::shared_ptr<Monster>pSpawnMonster;
|
|
|
|
ObjectFactory* const pObjectFactory = ObjectFactory::Instance();
|
|
switch( pBaseNPCInfo->m_byGrade )
|
|
{
|
|
case eNPC_LUCKY_MONSTER:
|
|
{
|
|
pSpawnMonster = boost::shared_ptr<Monster>( pObjectFactory->AllocObject( LUCKYMON_OBJECT ) );
|
|
}
|
|
break;
|
|
case eNPC_SSQ_MONSTER:
|
|
{
|
|
pSpawnMonster = boost::shared_ptr<Monster>( pObjectFactory->AllocObject( SSQMONSTER_OBJECT ) );
|
|
}
|
|
break;
|
|
case eNPC_FRIEND_MONSTER:
|
|
{
|
|
pSpawnMonster = boost::shared_ptr<Monster>(pObjectFactory->AllocObject(FRIEND_MONSTER_OBJECT));
|
|
}
|
|
break;
|
|
case eNPC_MOVE_SYNC_MERCHANT:
|
|
{
|
|
pSpawnMonster= boost::shared_ptr<Monster>( pObjectFactory->AllocObject( SYNC_MERCHANT_OBJECT ) );
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
pSpawnMonster = boost::shared_ptr<Monster>( pObjectFactory->AllocObject( MONSTER_OBJECT ) );
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (pSpawnMonster == NULL) {
|
|
SUNLOG( eCRITICAL_LOG, "[AllocMonster] MonterCode(%d)/Type(%d) alloc fail", NPCCode, pBaseNPCInfo->m_byGrade );
|
|
//return boost::make_shared<Monster>(NULL);
|
|
return boost::shared_ptr<Monster>((Monster*)NULL);
|
|
}
|
|
|
|
pSpawnMonster->InitMonster( NPCCode, byMoveType, dwMoveAreaID );
|
|
|
|
return pSpawnMonster;
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
void GameField::KillAllNPC(Player* player, int range, const FLOAT damage_percent)
|
|
{
|
|
const WzVector& player_pos = *player->GetPosPtr();
|
|
const float range_square = float(range * range);
|
|
|
|
for (_NPC_HASH::iterator it = m_NPCHash.begin(); it != m_NPCHash.end(); ++it)
|
|
{
|
|
NPC* const npc = it->second;
|
|
if (npc == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
//#ifdef _NA_004126_20120111_CHANGE_GAME_SERVER_OBJECT_FACTORY
|
|
if (npc->IsDeleted())
|
|
{
|
|
const Object::Key key = npc->GetObjectKey();
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|%d|Object is already deleted.|ObjectKey = %d|"),
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
key
|
|
);
|
|
continue;
|
|
}
|
|
//#endif
|
|
const WzVector& npc_pos = *npc->GetPosPtr();
|
|
const float dist_square = VectorLength2(&(npc_pos - player_pos));
|
|
if ((dist_square <= range_square) && (player->IsFriend(npc) == USER_RELATION_ENEMY))
|
|
{
|
|
if (damage_percent)
|
|
{
|
|
GmDamageNPC(player, npc, damage_percent);
|
|
}
|
|
else
|
|
{
|
|
KillNPC(player, npc, TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
// _NA_0_20100222_UNIT_TRIGGERS_ADD
|
|
VOID GameField::KillOneMonster( NPC* pNPC, Player* pPlayer, BOOL IsExpItemDrop )
|
|
{
|
|
if(pPlayer)
|
|
{
|
|
KillNPC(pPlayer, pNPC, IsExpItemDrop);
|
|
}
|
|
else
|
|
{
|
|
DestroyObject(pNPC); // (WAVERIX) (090121) leave_field + delete_object
|
|
//pNPC is a garbage
|
|
}
|
|
}
|
|
|
|
//보상없이 몬스터를 사라지게 한다.
|
|
void GameField::KillMonster(MONSTERCODE monster_code, Player* player, BOOL is_exp_item_drop)
|
|
{
|
|
for (_NPC_HASH::iterator it = m_NPCHash.begin(); it != m_NPCHash.end(); ++it)
|
|
{
|
|
NPC* const npc = it->second;
|
|
if (npc == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
//#ifdef _NA_004126_20120111_CHANGE_GAME_SERVER_OBJECT_FACTORY
|
|
if (npc->IsDeleted())
|
|
{
|
|
const Object::Key key = npc->GetObjectKey();
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|%d|Object is already deleted.|ObjectKey = %d|"),
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
key
|
|
);
|
|
continue;
|
|
}
|
|
//#endif
|
|
if (npc->GetBaseInfo()->m_MonsterCode != monster_code)
|
|
{
|
|
continue;
|
|
}
|
|
KillOneMonster(npc, player, is_exp_item_drop);
|
|
}
|
|
}
|
|
|
|
VOID GameField::AddExpAllMember( DWORD64 Exp )
|
|
{
|
|
_PLAYER_HASH::iterator it = m_PlayerHash.begin(), end = m_PlayerHash.end();
|
|
for( ; it != end ; )
|
|
{
|
|
Player* pPlayer = (Player*)it->second;
|
|
++it;
|
|
if( pPlayer )
|
|
{
|
|
pPlayer->AddExp( Exp, 0, 0, TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
VOID GameField::KillAllItem( Player *pPlayer, int iRange )
|
|
{
|
|
// (NOTE) important, designed by __NA000000_090310_GAMEFIELD_RECURSIVELY_CALL_PROBLEM_FIX__
|
|
const WzVector& playerPos = *pPlayer->GetPosPtr();
|
|
const float rangeSquare = float(iRange * iRange);
|
|
_ITEM_HASH::iterator it = m_FieldItemHash.begin(), end = m_FieldItemHash.end();
|
|
for( ; it != end; ++it)
|
|
{
|
|
Item* pItem = it->second;
|
|
const WzVector& itemPos = *pItem->GetPosPtr();
|
|
float fDistSquare = VectorLength2(&(playerPos - itemPos));
|
|
if(fDistSquare <= rangeSquare)
|
|
pItem->RequestDelete();
|
|
}
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
BOOL GameField::KillNPC(Player* pPlayer, NPC* pNPC, BOOL bIsDrop, BOOLEAN bBrd)
|
|
{
|
|
// (WAVERIX) (090121) (CODE-REVISION)
|
|
// - 컴파일된 데이터의 이상인지 비정상적인 동작을 보이는 부분이 존재한다.
|
|
// 코드 재정렬을 수행하면 해결되므로 간단히 재정렬을 수행하기로 한다.
|
|
if( !pPlayer || !pNPC )
|
|
return FALSE;
|
|
//
|
|
if(pNPC->IsDeleteReserved())
|
|
return FALSE;
|
|
//
|
|
if(pNPC->IsAlive() == FALSE)
|
|
return FALSE;
|
|
|
|
/*
|
|
// NPC의 최대HP 만큼 데미지를 주려고 했으나, 데미지 타입이 WORD이므로 최대HP를 타입캐스팅할 때 수치가 잘못된다!
|
|
// 따라서 일단 현재 HP를 1로 셋팅한 후에 데미지 100을 주어서 몬스터를 죽이는 방식으로 바꾸었다.
|
|
pNPC->SetHP( 1 );
|
|
DAMAGETYPE wDamage = 100;
|
|
*/
|
|
// 운영팀의 요청으로 원래대로 처리함(2006.7.21)
|
|
// (WAVERIX) Dummy Code : Compile Issue
|
|
static NPC* npc_s = 0;
|
|
; npc_s = pNPC;
|
|
const DWORD maxHP = npc_s->GetMaxHP();
|
|
const DWORD maxSD = npc_s->GetMaxSD();
|
|
|
|
// f100908.1L
|
|
DamageArgs damage_args(pPlayer, eATTACK_TYPE_MELEE);
|
|
;{
|
|
//damage_args.option_.is_critical_;
|
|
//damage_args.option_.is_mirror_;
|
|
//damage_args.limit_hp_;
|
|
//damage_args.attack_regist_kind_;
|
|
//damage_args.sd_apply_;
|
|
damage_args.damage_ = maxHP;
|
|
};
|
|
|
|
// 정상적으로 경험치, 아이템분배를 처리한다면,
|
|
if( bIsDrop )
|
|
{
|
|
pNPC->SetHP( 1 );
|
|
pNPC->Damaged(&damage_args);
|
|
//pNPC->Damaged( pPlayer, eATTACK_TYPE_MELEE, wDamage, FALSE ); //요기에서 내부적으로 OnDead를 호출한다.
|
|
}
|
|
// 단순히 NPC를 죽이려고 한다면,
|
|
else
|
|
{
|
|
pNPC->SetHP( 0 );
|
|
pNPC->StopMoving();
|
|
DestroyObject( pNPC );
|
|
}
|
|
|
|
// (WAVERIX) (NOTE) 이 시점 해당 오브젝트는 Free되어 있는 상태일 확률이 높다. 사용시 주의!
|
|
if (bBrd)
|
|
{
|
|
MSGSUB_BATTLE_PLAYER_ATTACK_BRD msg_brd;
|
|
msg_brd.Clear();
|
|
//msg_brd.dwClientSerial = 0;
|
|
pPlayer->GetPos( &msg_brd.wvCurPos );
|
|
msg_brd.dwAttackerKey = pPlayer->GetObjectKey();
|
|
//msg_brd.style_presentation = 0; //_NA003109_STYLE_PRESENTATION_IMPROVEMENT
|
|
msg_brd.byAttackType = eATTACK_SEQUENCE_FIRST;
|
|
msg_brd.dwTargetKey = pNPC->GetObjectKey();
|
|
msg_brd.wDamage = damage_args.damage_;
|
|
msg_brd.dwTargetHP = pNPC->GetHP();
|
|
//msg_brd.byEffect = 0; // GM명령어로 죽이는 것이지만 이 값에 대한 세팅을 해주어야 함!!(20060115)
|
|
pPlayer->SendPacketAroundForSync(&msg_brd);
|
|
};
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL GameField::GmDamageNPC(Player* pPlayer, NPC* pNPC, const FLOAT fDamagePercent)
|
|
{
|
|
// implemented by _NA001385_20090924_DOMINATION_
|
|
if( !pPlayer || !pNPC )
|
|
return FALSE;
|
|
//
|
|
if(pNPC->IsDeleteReserved())
|
|
return FALSE;
|
|
//
|
|
if(pNPC->IsAlive() == FALSE)
|
|
return FALSE;
|
|
|
|
if (fDamagePercent)
|
|
{
|
|
const DWORD curHp = pNPC->GetHP();
|
|
const DWORD maxHp = pNPC->GetMaxHP();
|
|
const FLOAT fDamage = (FLOAT)maxHp * fDamagePercent;
|
|
const DWORD dwDamage = (DWORD)fDamage;
|
|
|
|
pNPC->DecreaseHP(dwDamage);
|
|
pNPC->SendHPChange();
|
|
}
|
|
else
|
|
{
|
|
const DWORD maxHP = pNPC->GetMaxHP();
|
|
const DWORD maxSD = pNPC->GetMaxSD();
|
|
// f100908.1L
|
|
DamageArgs damage_args(pPlayer, eATTACK_TYPE_MELEE);
|
|
;{
|
|
damage_args.damage_ = maxHP;
|
|
};
|
|
|
|
pNPC->SetHP(1);
|
|
pNPC->Damaged(&damage_args);
|
|
//pNPC->Damaged(pPlayer, eATTACK_TYPE_MELEE, wDamage, FALSE); //요기에서 내부적으로 OnDead를 호출한다.
|
|
|
|
;{
|
|
MSGSUB_BATTLE_PLAYER_ATTACK_BRD msg_brd;
|
|
msg_brd.Clear();
|
|
//msg_brd.dwClientSerial = 0;
|
|
pPlayer->GetPos(&msg_brd.wvCurPos);
|
|
msg_brd.dwAttackerKey = pPlayer->GetObjectKey();
|
|
//msg_brd.style_presentation = 0; //_NA003109_STYLE_PRESENTATION_IMPROVEMENT
|
|
msg_brd.byAttackType = eATTACK_SEQUENCE_FIRST;
|
|
msg_brd.dwTargetKey = pNPC->GetObjectKey();
|
|
msg_brd.wDamage = damage_args.damage_;
|
|
msg_brd.dwTargetHP = pNPC->GetHP();
|
|
//msg_brd.byEffect = 0;
|
|
pPlayer->SendPacketAroundForSync(&msg_brd);
|
|
};
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
VOID GameField::SpawnSector( DWORD dwSectorIndex, Object* pObject )
|
|
{
|
|
// 미리 리젠했으면 리턴
|
|
if( m_bPreRegen ) return;
|
|
|
|
// 플레이어 등장인지 체크
|
|
if(pObject->IsEqualObjectKind(PLAYER_OBJECT) == 0)
|
|
return;
|
|
|
|
m_pUnitRegenManager->SpawnSector( dwSectorIndex );
|
|
}
|
|
|
|
|
|
//─────────────────────────────────────────
|
|
|
|
|
|
Object* GameField::FindObject(const eOBJECT_TYPE object_type, const Object::Key object_key) const
|
|
{
|
|
Object* obj = NULL;
|
|
|
|
switch(object_type)
|
|
{
|
|
case OBJECT_OBJECT:
|
|
case CHARACTER_OBJECT:
|
|
case NONCHARACTER_OBJECT:
|
|
case NPC_OBJECT:
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|%d|Invalid object type.|ObjectType = %d|"),
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
object_type
|
|
);
|
|
return NULL;
|
|
}
|
|
break;
|
|
case PLAYER_OBJECT:
|
|
{
|
|
_PLAYER_HASH::const_iterator it = m_PlayerHash.find(object_key);
|
|
if (it != m_PlayerHash.end())
|
|
{
|
|
obj = it->second;
|
|
}
|
|
}
|
|
break;
|
|
case MONSTER_OBJECT:
|
|
case SUMMON_OBJECT:
|
|
case MERCHANT_OBJECT:
|
|
case MAPNPC_OBJECT:
|
|
case LUCKYMON_OBJECT:
|
|
case TOTEMNPC_OBJECT:
|
|
case SSQMONSTER_OBJECT:
|
|
case CRYSTALWARP_OBJECT:
|
|
case FRIEND_MONSTER_OBJECT:
|
|
case SYNC_MERCHANT_OBJECT:
|
|
{
|
|
_NPC_HASH::const_iterator it = m_NPCHash.find(object_key);
|
|
if (it != m_NPCHash.end())
|
|
{
|
|
obj = it->second;
|
|
}
|
|
}
|
|
break;
|
|
case ITEM_OBJECT:
|
|
case MONEY_OBJECT:
|
|
{
|
|
_ITEM_HASH::const_iterator it = m_FieldItemHash.find(object_key);
|
|
if (it != m_FieldItemHash.end())
|
|
{
|
|
obj = it->second;
|
|
}
|
|
}
|
|
break;
|
|
case COLLECTION_OBJECT:
|
|
{
|
|
_COLLECTION_HASH::const_iterator it = m_FieldCollectHash.find(object_key);
|
|
if (it != m_FieldCollectHash.end())
|
|
{
|
|
obj = it->second;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
SUNLOG(
|
|
eCRITICAL_LOG,
|
|
_T("|%s|%d|Invalid object type.|ObjectType = %d|"),
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
object_type
|
|
);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (obj_util::IsValid(obj, __FUNCTION__, __LINE__) == false)
|
|
{
|
|
return NULL;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
// (CHANGES) (f100504.1L) change the interface specification to support a complex condition
|
|
// the replacement facility for SendXXPacketToSector<IsSendPlayer>
|
|
bool IsSendPlayer::ChkCondision(Player* pPlayer)
|
|
{
|
|
return RC::RC_COLLECT_SUCCESS == m_pMgr->ChkCondision(pPlayer,m_CollectionID);
|
|
}
|
|
*/
|