1654 lines
50 KiB
C++
1654 lines
50 KiB
C++
#include "stdafx.h"
|
||
#include "Gamefield.h"
|
||
|
||
#include <NPCInfoParser.h>
|
||
#include <MapInfoParser.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
|
||
, "뒈暠덜쯤:%d,끝쒼덜쯤:%d,뇰랙포莉츰냔:%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 呵겨댄轎! 쒸멩!!!!!!!!!! %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(!"雷棍榴檄");
|
||
SUNLOG(eCRITICAL_LOG, "轟랬警속 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]灌冷돕뒈暠뚤蹶밍膠 (%u)", GetFieldCode(), pMapInfo->dwExtraInfos[eMAPOBJECT_MONSTER] );
|
||
SUNLOG( eCRITICAL_LOG, "[Field:%u]뒈暠뚤蹶(ID:%u),(띨棍斤口令)[잚謹(1):%u,밍膠(2):%u,(괏즛:%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,
|
||
"冷꼇돕꽃섞斤口. "
|
||
"끝쒼[%u] 뒈暠뚤蹶Key[%u] 꽃섞포ID[%s] "
|
||
"윈嵐斤口令[잚謹(1):%u,밍膠(2):%u,(괏즛:%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|뚤蹶綠굳�뇜.|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] 貫零[%f, %f, %f] 呵겨!", 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] 貫零[%f, %f, %f]呵겨!", pvPos->x, pvPos->y, pvPos->z );
|
||
return NULL;
|
||
}
|
||
return pFieldMoneyItem;
|
||
}
|
||
|
||
|
||
//─────────────────────────────────────────
|
||
|
||
#include <GroupParser.h>
|
||
|
||
Monster* GameField::CreateMonster( WORD NPCCode, const WzVector *pvPos,
|
||
WORD wGroupID, int iAngle, BYTE byMoveType, DWORD dwMoveAreaID, WORD MissionAreaID/*미션전용임시*/ )
|
||
{
|
||
Monster *pSpawnMonster = AllocMonster( NPCCode, byMoveType, dwMoveAreaID );
|
||
|
||
if( !pSpawnMonster ) return NULL;
|
||
|
||
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, "[끝쒼덜쯤:%u],Group[%u,%u] pBaseGroupInfo 槨 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, pvPos, iAngle ) )
|
||
{
|
||
ObjectFactory::Instance()->FreeObject( pSpawnMonster );
|
||
return NULL;
|
||
}
|
||
|
||
return pSpawnMonster;
|
||
}
|
||
|
||
|
||
//─────────────────────────────────────────
|
||
|
||
|
||
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("꼇닸瞳덜쯤돨 NPC 斤口[%u]]"), NPCCode );
|
||
return NULL;
|
||
}
|
||
|
||
|
||
Monster *pMonster = static_cast<Monster*>(ObjectFactory::Instance()->AllocObject( MONSTER_OBJECT ));
|
||
if (pMonster == NULL) {
|
||
return NULL;
|
||
}
|
||
|
||
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, pvPos, -1 ) )
|
||
{
|
||
ObjectFactory::Instance()->FreeObject( pMonster );
|
||
return NULL;
|
||
}
|
||
|
||
// 소환자의 소환인포에 몬스터 수 증가
|
||
pOwnerSummonNPCs->IncreaseSummoned( NPCCode, pMonster );
|
||
|
||
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,NPC덜쯤:%u] 貫零[%f, %f, %f] 呵겨!",
|
||
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,NPC덜쯤:%u] 貫零[%f, %f, %f] 呵겨!",
|
||
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,NPC덜쯤:%u] 貫零[%f, %f, %f] 呵겨!",
|
||
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,NPC덜쯤:%u] 貫零[%f, %f, %f] 呵겨!",
|
||
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,NPC덜쯤:%u] 貫零[%f, %f, %f] 呵겨!",
|
||
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] 貫零[%f, %f, %f] 呵겨!",
|
||
pCollection->GetObjectKey(), WzIDToString(ch, pMapInfo->CollectionID), pMapInfo->wvPos.x, pMapInfo->wvPos.y, pMapInfo->wvPos.z );
|
||
|
||
ObjectFactory::Instance()->FreeObject( pCollection );
|
||
return NULL;
|
||
}
|
||
|
||
return pCollection;
|
||
}
|
||
//}
|
||
|
||
//─────────────────────────────────────────
|
||
|
||
|
||
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
|
||
|
||
Monster* pSpawnMonster = AllocMonster( npc_code, npc_unit_type, 0 );
|
||
|
||
if( !pSpawnMonster )
|
||
{
|
||
SUNLOG( eCRITICAL_LOG, "[SpawnMonster] AllocMonster 呵겨!" );
|
||
return NULL;
|
||
}
|
||
|
||
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] 약잼[%f]낚놔렀鍋!", pUnitRegenInfo->GetDir() );
|
||
pUnitRegenInfo->SetDir( (float)( (int)pUnitRegenInfo->GetDir() % 360 ) );
|
||
}
|
||
|
||
BASE_NPCINFO *pMonsterInfo = NPCInfoParser::Instance()->GetNPCInfo(npc_code);
|
||
if (pMonsterInfo->m_bIsNotice)
|
||
{
|
||
|
||
TCHAR message[MAX_NOTICE_LEN + 1];
|
||
wsprintf(message,_T("溝固:[%u] 놔君瞳죄뒈暠“{%u}”뒈혐"),npc_code,GetFieldCode());
|
||
SUNLOG(eCRITICAL_LOG, "溝固:[%u] 놔君瞳죄뒈暠“{%u}”뒈혐", npc_code, GetFieldCode());
|
||
|
||
PlayerManager::Instance()->SendGmNotice(message,eNOTICE_WORLD); //xiaomi 警속밍膠릿삶무멩
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
if( FALSE == EnterField( pSpawnMonster, &vStartPos, (int)pUnitRegenInfo->GetDir() ) )
|
||
{
|
||
ObjectFactory::Instance()->FreeObject( pSpawnMonster );
|
||
SUNLOG( eCRITICAL_LOG, "[SpawnMonster EnterField][끝쒼덜쯤:%u,NPC덜쯤:%u] 貫零[%f, %f, %f] 呵겨!",
|
||
GetFieldCode(), npc_code, vStartPos.x, vStartPos.y, vStartPos.z );
|
||
return NULL;
|
||
}
|
||
|
||
return pSpawnMonster;
|
||
}
|
||
|
||
|
||
//─────────────────────────────────────────
|
||
|
||
|
||
Monster* GameField::AllocMonster( WORD NPCCode, BYTE byMoveType, DWORD dwMoveAreaID )
|
||
{
|
||
|
||
BASE_NPCINFO *pBaseNPCInfo = NPCInfoParser::Instance()->GetNPCInfo( NPCCode );
|
||
if( !pBaseNPCInfo )
|
||
{
|
||
SUNLOG( eCRITICAL_LOG, "[AllocMonster] 밍膠(%d)灌冷돕", NPCCode );
|
||
return NULL;
|
||
}
|
||
|
||
Monster *pSpawnMonster = NULL;
|
||
|
||
ObjectFactory* const pObjectFactory = ObjectFactory::Instance();
|
||
switch( pBaseNPCInfo->m_byGrade )
|
||
{
|
||
case eNPC_LUCKY_MONSTER:
|
||
{
|
||
LuckyMonster* pLuckyMonster = static_cast<LuckyMonster *>( pObjectFactory->AllocObject( LUCKYMON_OBJECT ) );
|
||
pSpawnMonster = pLuckyMonster;
|
||
}
|
||
break;
|
||
case eNPC_SSQ_MONSTER:
|
||
{
|
||
SSQMonster* pMonster = static_cast<SSQMonster *>( pObjectFactory->AllocObject( SSQMONSTER_OBJECT ) );
|
||
pSpawnMonster = pMonster;
|
||
}
|
||
break;
|
||
case eNPC_FRIEND_MONSTER:
|
||
{
|
||
FriendMonster* pFriendMonster = static_cast<FriendMonster*>(pObjectFactory->AllocObject(FRIEND_MONSTER_OBJECT));
|
||
pSpawnMonster = pFriendMonster;
|
||
}
|
||
break;
|
||
case eNPC_MOVE_SYNC_MERCHANT:
|
||
{
|
||
SyncMerchant* pSyncMerchant = static_cast<SyncMerchant*>( pObjectFactory->AllocObject( SYNC_MERCHANT_OBJECT ) );
|
||
pSpawnMonster = pSyncMerchant;
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
Monster* pMonster = static_cast<Monster *>( pObjectFactory->AllocObject( MONSTER_OBJECT ) );
|
||
pSpawnMonster = pMonster;
|
||
}
|
||
break;
|
||
}
|
||
|
||
if (pSpawnMonster == NULL) {
|
||
SUNLOG( eCRITICAL_LOG, "[AllocMonster] 밍膠(%d)/잚謹(%d)롸토呵겨", NPCCode, pBaseNPCInfo->m_byGrade );
|
||
return 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|뚤蹶綠굳�뇜.|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|뚤蹶綠굳�뇜.|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|뚤蹶잚謹轟槻.|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|뚤蹶잚謹轟槻.|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);
|
||
}
|
||
*/
|