Jump to content
  • -1

Server kick out on Any dungeon


ALF
Go to solution Solved by Sonitex,

Question

  • VIP
Posted (edited)

Hello Metin2dev,

 

I got a problem when users are doing any dungeon they are kicked out and i checked the server side i got this game.core

 

Example. now there was players on Demons Tower floor 3 and after that server kicked them out 

happen on every dungeon

spacer.png

 

Anyone have anyidea how can i fix this  ? please is urgent i need help

Edited by Arkane2
2 (see edit history)

" Don`t pretend things change if you always do the same thing"

"Don`t give up on a dream for how long it will take, time will pass the same"

Link to post

11 answers to this question

Recommended Posts

  • 0
  • VIP
  • Solution
	void CQuestManager::CancelServerTimers(DWORD arg)
	{
		vector<pair<string, DWORD>> ServerTimersToDelete;

		for (auto& kv : m_mapServerTimer) {
			if (kv.first.second == arg) {
				LPEVENT event = kv.second;
				event_cancel(&event);
				ServerTimersToDelete.push_back(kv.first);
			}
		}

		// Delete all the required server timers
		for (auto &timer : ServerTimersToDelete)
			m_mapServerTimer.erase(timer);

		// Clean up
		ServerTimersToDelete.clear();
	}

Crash occurs because the game is deleting timers while iterating through them. Code above should fix this issue :) 

  • Love 2
Link to post
  • 1

yeah, your issue is the following: You upgraded to c++11 or higher, right?

There's a huge difference in deletion via iterator. In old c++ the iterator has to be increased manually after deleting the entry from map.

Since c++11 this does not happen anymore. It'll automatically advance the iterator to the next element.

 

But! Your code is still increasing the iter even if it already deleted an entry. You can figure out that his behaviour causes a lot of trouble. You may want to change it to this:

 


	    void CQuestManager::CancelServerTimers(DWORD arg)

	    {

	        for (auto it = m_mapServerTimer.begin(); it != m_mapServerTimer.end(); /**/)

	        {

	            if (it->first.second != arg)

	            {

	                ++it;

	            }

	            else

	            {

	                auto event = it->second;

	                event_cancel(&event);

	                it = m_mapServerTimer.erase(it);

	            }

	        }

	    }


 

What does this code do? It changes your loop to not increase the iterator by itself anymore. Instead it advances every time when it->first.second != arg. If it is indeed the timer you want to clear it'll instead just call erase on the map which will automatically advance the iterator for you. In your old loop the iterator would be advanced twice because you're increasing it in your loop too AND with calling erase().

 

Above code from Sonitex should also fix this issue!

To give another way of Sonitex's solution you can also do this:

 


	void CQuestManager::CancelServerTimers(DWORD arg)

	    {

	        uint32_t x = 0;

	        for (const auto& kv : m_mapServerTimer) {

	            if (kv.first.second == arg) {

	                LPEVENT event = kv.second;

	                event_cancel(&event);

	                m_mapServerTimer.erase(m_mapServerTimer.begin() + x);

	            }

	            x++;

	        }

	    }


 

It works without storing a vector and instead uses x as an index variable that increases with each "iteration". Note that I also added const to prevent useless copy instructions. All 3 solutions should fix your problem, pick what you think suits best :D

Edited by Vanilla (see edit history)
  • Love 1

We are the tortured.
We're not your friends.
As long as we're not visible.
We are unfixable.

Link to post
  • 0

can you upload dungeon.cpp and questmanager.cpp? Especially the functions that are quoted here so we can see what happens and what triggers the core crash.

We are the tortured.
We're not your friends.
As long as we're not visible.
We are unfixable.

Link to post
  • 0

It may or may not your error, but there was a dungeon core downer thing with party what worked in every dungeon (if the dungeon was not solo-only)

It's still not fixed in most server and a lot of  server can be offed with that.

 

Edit: It's posted to this forum too

 

Edited by TMP4 (see edit history)
Link to post
  • 0
  • VIP

thnx @TMP4 but i was thinking same but that was already fixed    i just find this on my dungeon.cpp 

 

if (!pDungeon) //

{ //sys_err("M2_NEW CDungeon failed"); /

/return NULL;

 

Dungeon.cpp

Spoiler
#include "stdafx.h"
#include "dungeon.h"
#include "char.h"
#include "char_manager.h"
#include "party.h"
#include "affect.h"
#include "packet.h"
#include "desc.h"
#include "config.h"
#include "regen.h"
#include "start_position.h"
#include "item.h"
#include "item_manager.h"
#include "utils.h"
#include "questmanager.h"

CDungeon::CDungeon(IdType id, long lOriginalMapIndex, long lMapIndex)
	: m_id(id),
	m_lOrigMapIndex(lOriginalMapIndex),
	m_lMapIndex(lMapIndex),
	m_map_Area(SECTREE_MANAGER::instance().GetDungeonArea(lOriginalMapIndex))
{
	Initialize();
	//sys_log(0,"DUNGEON create orig %d real %d", lOriginalMapIndex, lMapIndex);
}

CDungeon::~CDungeon()
{
	if (m_pParty != NULL)
	{
		m_pParty->SetDungeon_for_Only_party (NULL);
	}
	//sys_log(0,"DUNGEON destroy orig %d real %d", m_lOrigMapIndex, m_lMapIndex	);
	ClearRegen();
	event_cancel(&deadEvent);
	// <Factor>
	event_cancel(&exit_all_event_);
	event_cancel(&jump_to_event_);
}

void CDungeon::Initialize()
{
	deadEvent = NULL;
	// <Factor>
	exit_all_event_ = NULL;
	jump_to_event_ = NULL;
	regen_id_ = 0;

	m_iMobKill = 0;
	m_iStoneKill = 0;
	m_bUsePotion = false;
	m_bUseRevive = false;

	m_iMonsterCount = 0;

	m_bExitAllAtEliminate = false;
	m_bWarpAtEliminate = false;

	m_iWarpDelay = 0;
	m_lWarpMapIndex = 0;
	m_lWarpX = 0;
	m_lWarpY = 0;

	m_stRegenFile = "";

	m_pParty = NULL;
}

void CDungeon::SetFlag(std::string name, int value)
{
	itertype(m_map_Flag) it =  m_map_Flag.find(name);
	if (it != m_map_Flag.end())
		it->second = value;
	else
		m_map_Flag.insert(make_pair(name, value));
}

int CDungeon::GetFlag(std::string name)
{
	itertype(m_map_Flag) it =  m_map_Flag.find(name);
	if (it != m_map_Flag.end())
		return it->second;
	else
		return 0;
}

struct FSendDestPosition
{
	FSendDestPosition(long x, long y)
	{
		p1.bHeader = HEADER_GC_DUNGEON;
		p1.subheader = DUNGEON_SUBHEADER_GC_DESTINATION_POSITION;
		p2.x = x;
		p2.y = y;
		p1.size = sizeof(p1)+sizeof(p2);
	}

	void operator()(LPCHARACTER ch)
	{
		ch->GetDesc()->BufferedPacket(&p1, sizeof(TPacketGCDungeon));
		ch->GetDesc()->Packet(&p2, sizeof(TPacketGCDungeonDestPosition));
	}

	TPacketGCDungeon p1;
	TPacketGCDungeonDestPosition p2;
};

void CDungeon::SendDestPositionToParty(LPPARTY pParty, long x, long y)
{
	if (m_map_pkParty.find(pParty) == m_map_pkParty.end())
	{
		sys_err("PARTY %u not in DUNGEON %d", pParty->GetLeaderPID(), m_lMapIndex);
		return;
	}

	FSendDestPosition f(x, y);
	pParty->ForEachNearMember(f);
}

struct FWarpToDungeon
{
	FWarpToDungeon(long lMapIndex, LPDUNGEON d)
		: m_lMapIndex(lMapIndex), m_pkDungeon(d)
		{
			LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(lMapIndex);
			m_x = pkSectreeMap->m_setting.posSpawn.x;
			m_y = pkSectreeMap->m_setting.posSpawn.y;
		}

	void operator () (LPCHARACTER ch)
	{
		ch->SaveExitLocation();
		ch->WarpSet(m_x, m_y, m_lMapIndex);
		//m_pkDungeon->IncPartyMember(ch->GetParty());
	}

	long m_lMapIndex;
	long m_x;
	long m_y;
	LPDUNGEON m_pkDungeon;
};

void CDungeon::Join(LPCHARACTER ch)
{
	if (SECTREE_MANAGER::instance().GetMap(m_lMapIndex) == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}
	FWarpToDungeon(m_lMapIndex, this) (ch);
}

void CDungeon::JoinParty(LPPARTY pParty)
{
	pParty->SetDungeon(this); // @warme011 the begin of the nightmare
	m_map_pkParty.insert(std::make_pair(pParty,0));

	if (SECTREE_MANAGER::instance().GetMap(m_lMapIndex) == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}
	FWarpToDungeon f(m_lMapIndex, this);
	pParty->ForEachOnlineMember(f);
	//sys_log(0, "DUNGEON-PARTY join %p %p", this, pParty);
}

void CDungeon::QuitParty(LPPARTY pParty)
{
	pParty->SetDungeon(NULL);
	//sys_log(0, "DUNGEON-PARTY quit %p %p", this, pParty);
	TPartyMap::iterator it = m_map_pkParty.find(pParty); // @warme011 boom! crash!

	if (it != m_map_pkParty.end())
		m_map_pkParty.erase(it);
}

EVENTINFO(dungeon_id_info)
{
	CDungeon::IdType dungeon_id;

	dungeon_id_info()
	: dungeon_id(0)
	{
	}
};

EVENTFUNC(dungeon_dead_event)
{
	dungeon_id_info* info = dynamic_cast<dungeon_id_info*>( event->info );

	if ( info == NULL )
	{
		sys_err( "dungeon_dead_event> <Factor> Null pointer" );
		return 0;
	}

	LPDUNGEON pDungeon = CDungeonManager::instance().Find(info->dungeon_id);
	if (pDungeon == NULL) {
		return 0;
	}

	pDungeon->deadEvent = NULL;

	CDungeonManager::instance().Destroy(info->dungeon_id);
	return 0;
}

void CDungeon::IncMember(LPCHARACTER ch)
{
	if (m_set_pkCharacter.find(ch) == m_set_pkCharacter.end())
		m_set_pkCharacter.insert(ch);

	event_cancel(&deadEvent);
}

void CDungeon::DecMember(LPCHARACTER ch)
{
	itertype(m_set_pkCharacter) it = m_set_pkCharacter.find(ch);

	if (it == m_set_pkCharacter.end()) {
		return;
	}

	m_set_pkCharacter.erase(it);

	if (m_set_pkCharacter.empty())
	{
		dungeon_id_info* info = AllocEventInfo<dungeon_id_info>();
		info->dungeon_id = m_id;

		event_cancel(&deadEvent);
		deadEvent = event_create(dungeon_dead_event, info, PASSES_PER_SEC(10));
	}
}

void CDungeon::IncPartyMember(LPPARTY pParty, LPCHARACTER ch)
{
	//sys_log(0, "DUNGEON-PARTY inc %p %p", this, pParty);
	TPartyMap::iterator it = m_map_pkParty.find(pParty);

	if (it != m_map_pkParty.end())
		it->second++;
	else
		m_map_pkParty.insert(std::make_pair(pParty,1));

	IncMember(ch);
}

void CDungeon::DecPartyMember(LPPARTY pParty, LPCHARACTER ch)
{
	//sys_log(0, "DUNGEON-PARTY dec %p %p", this, pParty);
	TPartyMap::iterator it = m_map_pkParty.find(pParty);

	if (it == m_map_pkParty.end())
		sys_err("cannot find party");
	else
	{
		it->second--;

		if (it->second == 0)
			QuitParty(pParty);
	}

	DecMember(ch);
}

struct FWarpToPosition
{
	long lMapIndex;
	long x;
	long y;
	FWarpToPosition(long lMapIndex, long x, long y)
		: lMapIndex(lMapIndex), x(x), y(y)
		{}

	void operator()(LPENTITY ent)
	{
		if (!ent->IsType(ENTITY_CHARACTER)) {
			return;
		}
		LPCHARACTER ch = (LPCHARACTER)ent;
		if (!ch->IsPC()) {
			return;
		}
		if (ch->GetMapIndex() == lMapIndex)
		{
			ch->Show(lMapIndex, x, y, 0);
			ch->Stop();
		}
		else
		{
			ch->WarpSet(x,y,lMapIndex);
		}
	}
};

struct FWarpToPositionForce
{
	long lMapIndex;
	long x;
	long y;
	FWarpToPositionForce(long lMapIndex, long x, long y)
		: lMapIndex(lMapIndex), x(x), y(y)
		{}

	void operator()(LPENTITY ent)
	{
		if (!ent->IsType(ENTITY_CHARACTER)) {
			return;
		}
		LPCHARACTER ch = (LPCHARACTER)ent;
		if (!ch->IsPC()) {
			return;
		}
		ch->WarpSet(x,y,lMapIndex);
	}
};

void CDungeon::JumpAll(long lFromMapIndex, int x, int y)
{
	x *= 100;
	y *= 100;

	LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(lFromMapIndex);

	if (!pMap)
	{
		sys_err("cannot find map by index %d", lFromMapIndex);
		return;
	}

	FWarpToPosition f(m_lMapIndex, x, y);

	// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
	pMap->for_each(f);
}

void CDungeon::WarpAll(long lFromMapIndex, int x, int y)
{
	x *= 100;
	y *= 100;

	LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(lFromMapIndex);

	if (!pMap)
	{
		sys_err("cannot find map by index %d", lFromMapIndex);
		return;
	}

	FWarpToPositionForce f(m_lMapIndex, x, y);

	// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
	pMap->for_each(f);
}

void CDungeon::JumpParty(LPPARTY pParty, long lFromMapIndex, int x, int y)
{
	x *= 100;
	y *= 100;

	LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(lFromMapIndex);

	if (!pMap)
	{
		sys_err("cannot find map by index %d", lFromMapIndex);
		return;
	}

	if (pParty->GetDungeon_for_Only_party() == NULL)
	{
		if (m_pParty == NULL)
		{
			m_pParty = pParty;
		}
		else if (m_pParty != pParty)
		{
			sys_err ("Dungeon already has party. Another party cannot jump in dungeon : index %d", GetMapIndex());
			return;
		}
		pParty->SetDungeon_for_Only_party (this);
	}

	FWarpToPosition f(m_lMapIndex, x, y);

	pParty->ForEachOnMapMember(f, lFromMapIndex);
}

void CDungeon::SetPartyNull()
{
	m_pParty = NULL;
}


void CDungeonManager::Destroy(CDungeon::IdType dungeon_id)
{
	sys_log(0, "DUNGEON destroy : map index %u", dungeon_id);
	LPDUNGEON pDungeon = Find(dungeon_id);
	if (pDungeon == NULL) {
		return;
	}
	m_map_pkDungeon.erase(dungeon_id);

	long lMapIndex = pDungeon->m_lMapIndex;
	m_map_pkMapDungeon.erase(lMapIndex);

	DWORD server_timer_arg = lMapIndex;
	quest::CQuestManager::instance().CancelServerTimers(server_timer_arg);

	SECTREE_MANAGER::instance().DestroyPrivateMap(lMapIndex);
	M2_DELETE(pDungeon);
}

LPDUNGEON CDungeonManager::Find(CDungeon::IdType dungeon_id)
{
	itertype(m_map_pkDungeon) it = m_map_pkDungeon.find(dungeon_id);
	if (it != m_map_pkDungeon.end())
		return it->second;
	return NULL;
}

LPDUNGEON CDungeonManager::FindByMapIndex(long lMapIndex)
{
	itertype(m_map_pkMapDungeon) it = m_map_pkMapDungeon.find(lMapIndex);
	if (it != m_map_pkMapDungeon.end()) {
		return it->second;
	}
	return NULL;
}

LPDUNGEON CDungeonManager::Create(long lOriginalMapIndex)
{
	DWORD lMapIndex = SECTREE_MANAGER::instance().CreatePrivateMap(lOriginalMapIndex);

	if (!lMapIndex)
	{
		sys_log( 0, "Fail to Create Dungeon : OrginalMapindex %d NewMapindex %d", lOriginalMapIndex, lMapIndex );
		return NULL;
	}

	// <Factor> TODO: Change id assignment, or drop it
	CDungeon::IdType id = next_id_++;
	while (Find(id) != NULL) {
		id = next_id_++;
	}

	LPDUNGEON pDungeon = M2_NEW CDungeon(id, lOriginalMapIndex, lMapIndex);

	m_map_pkDungeon.insert(std::make_pair(id, pDungeon));
	m_map_pkMapDungeon.insert(std::make_pair(lMapIndex, pDungeon));

	return pDungeon;
}

CDungeonManager::CDungeonManager()
	: next_id_(0)
{
}

CDungeonManager::~CDungeonManager()
{
}

void CDungeon::UniqueSetMaxHP(const std::string& key, int iMaxHP)
{
	TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
	if (it == m_map_UniqueMob.end())
	{
		sys_err("Unknown Key : %s", key.c_str());
		return;
	}
	it->second->SetMaxHP(iMaxHP);
}

void CDungeon::UniqueSetHP(const std::string& key, int iHP)
{
	TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
	if (it == m_map_UniqueMob.end())
	{
		sys_err("Unknown Key : %s", key.c_str());
		return;
	}
	it->second->SetHP(iHP);
}

void CDungeon::UniqueSetDefGrade(const std::string& key, int iGrade)
{
	TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
	if (it == m_map_UniqueMob.end())
	{
		sys_err("Unknown Key : %s", key.c_str());
		return;
	}
	it->second->PointChange(POINT_DEF_GRADE,iGrade - it->second->GetPoint(POINT_DEF_GRADE));
}

void CDungeon::SpawnMoveUnique(const char* key, DWORD vnum, const char* pos_from, const char* pos_to)
{
	TAreaMap::iterator it_to = m_map_Area.find(pos_to);
	if (it_to == m_map_Area.end())
	{
		sys_err("Wrong position string : %s", pos_to);
		return;
	}

	TAreaMap::iterator it_from = m_map_Area.find(pos_from);
	if (it_from == m_map_Area.end())
	{
		sys_err("Wrong position string : %s", pos_from);
		return;
	}

	TAreaInfo & ai = it_from->second;
	TAreaInfo & ai_to = it_to->second;
	int dir = ai.dir;
	if (dir==-1)
		dir = number(0,359);

	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}
	for (int i=0;i<100;i++)
	{
		int dx = number(ai.sx, ai.ex);
		int dy = number(ai.sy, ai.ey);
		int tx = number(ai_to.sx, ai_to.ex);
		int ty = number(ai_to.sy, ai_to.ey);

		LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+dx, pkSectreeMap->m_setting.iBaseY+dy, 0, false, dir);

		if (ch)
		{
			m_map_UniqueMob.insert(make_pair(std::string(key), ch));
			ch->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
			ch->SetDungeon(this);

			if (ch->Goto(pkSectreeMap->m_setting.iBaseX+tx, pkSectreeMap->m_setting.iBaseY+ty))
				ch->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
		}
		else
		{
			sys_err("Cannot spawn at %d %d", pkSectreeMap->m_setting.iBaseX+((ai.sx+ai.ex)>>1), pkSectreeMap->m_setting.iBaseY+((ai.sy+ai.ey)>>1));
		}
	}

}

void CDungeon::SpawnUnique(const char* key, DWORD vnum, const char* pos)
{
	TAreaMap::iterator it = m_map_Area.find(pos);
	if (it == m_map_Area.end())
	{
		sys_err("Wrong position string : %s", pos);
		return;
	}

	TAreaInfo & ai = it->second;
	int dir = ai.dir;
	if (dir==-1)
		dir = number(0,359);

	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}
	for (int i=0;i<100;i++)
	{
		int dx = number(ai.sx, ai.ex);
		int dy = number(ai.sy, ai.ey);

		LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+dx, pkSectreeMap->m_setting.iBaseY+dy, 0, false, dir);

		if (ch)
		{
			m_map_UniqueMob.insert(make_pair(std::string(key), ch));
			ch->SetDungeon(this);
			ch->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
			break;
		}
		else
		{
			sys_err("Cannot spawn at %d %d", pkSectreeMap->m_setting.iBaseX+((ai.sx+ai.ex)>>1), pkSectreeMap->m_setting.iBaseY+((ai.sy+ai.ey)>>1));
		}
	}
}

void CDungeon::SetUnique(const char* key, DWORD vid)
{
	LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(vid);
	if (ch)
	{
		m_map_UniqueMob.insert(make_pair(std::string(key), ch));
		ch->AddAffect(AFFECT_DUNGEON_UNIQUE, POINT_NONE, 0, AFF_DUNGEON_UNIQUE, 65535, 0, true);
	}
}

void CDungeon::SpawnStoneDoor(const char* key, const char* pos)
{
	SpawnUnique(key, 13001, pos);
}

void CDungeon::SpawnWoodenDoor(const char* key, const char* pos)
{
	SpawnUnique(key, 13000, pos);
	UniqueSetMaxHP(key, 10000);
	UniqueSetHP(key, 10000);
	UniqueSetDefGrade(key, 300);
}

void CDungeon::PurgeUnique(const std::string& key)
{
	TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
	if (it == m_map_UniqueMob.end())
	{
		sys_err("Unknown Key or Dead: %s", key.c_str());
		return;
	}
	LPCHARACTER ch = it->second;
	m_map_UniqueMob.erase(it);
	M2_DESTROY_CHARACTER(ch);
}

void CDungeon::KillUnique(const std::string& key)
{
	TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
	if (it == m_map_UniqueMob.end())
	{
		sys_err("Unknown Key or Dead: %s", key.c_str());
		return;
	}
	LPCHARACTER ch = it->second;
	m_map_UniqueMob.erase(it);
	ch->Dead();
}

DWORD CDungeon::GetUniqueVid(const std::string& key)
{
	TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
	if (it == m_map_UniqueMob.end())
	{
		sys_err("Unknown Key or Dead: %s", key.c_str());
		return 0;
	}
	LPCHARACTER ch = it->second;
	return ch->GetVID();
}

float CDungeon::GetUniqueHpPerc(const std::string& key)
{
	TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);
	if (it == m_map_UniqueMob.end())
	{
		sys_err("Unknown Key : %s", key.c_str());
		return false;
	}
	return (100.f*it->second->GetHP())/it->second->GetMaxHP();
}

void CDungeon::DeadCharacter(LPCHARACTER ch)
{
	if (!ch->IsPC())
	{
		TUniqueMobMap::iterator it = m_map_UniqueMob.begin();
		while (it!=m_map_UniqueMob.end())
		{
			if (it->second == ch)
			{
				//sys_log(0,"Dead unique %s", it->first.c_str());
				m_map_UniqueMob.erase(it);
				break;
			}
			++it;
		}
	}
}

bool CDungeon::IsUniqueDead(const std::string& key)
{
	TUniqueMobMap::iterator it = m_map_UniqueMob.find(key);

	if (it == m_map_UniqueMob.end())
	{
		sys_err("Unknown Key or Dead : %s", key.c_str());
		return true;
	}

	return it->second->IsDead();
}

void CDungeon::Spawn(DWORD vnum, const char* pos)
{
	//sys_log(0,"DUNGEON Spawn %u %s", vnum, pos);
	TAreaMap::iterator it = m_map_Area.find(pos);

	if (it == m_map_Area.end())
	{
		sys_err("Wrong position string : %s", pos);
		return;
	}

	TAreaInfo & ai = it->second;
	int dir = ai.dir;
	if (dir==-1)
		dir = number(0,359);

	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL)
	{
		sys_err("cannot find map by index %d", m_lMapIndex);
		return;
	}
	int dx = number(ai.sx, ai.ex);
	int dy = number(ai.sy, ai.ey);

	LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+dx, pkSectreeMap->m_setting.iBaseY+dy, 0, false, dir);
	if (ch)
		ch->SetDungeon(this);
}

LPCHARACTER CDungeon::SpawnMob(DWORD vnum, int x, int y, int dir)
{
	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return NULL;
	}
	sys_log(0, "CDungeon::SpawnMob %u %d %d", vnum, x,  y);

	LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+x*100, pkSectreeMap->m_setting.iBaseY+y*100, 0, false, dir == 0 ? -1 : (dir - 1) * 45);

	if (ch)
	{
		ch->SetDungeon(this);
		sys_log(0, "CDungeon::SpawnMob name %s", ch->GetName());
	}

	return ch;
}

LPCHARACTER CDungeon::SpawnMob_ac_dir(DWORD vnum, int x, int y, int dir)
{
	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return NULL;
	}
	sys_log(0, "CDungeon::SpawnMob %u %d %d", vnum, x,  y);

	LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+x*100, pkSectreeMap->m_setting.iBaseY+y*100, 0, false, dir);

	if (ch)
	{
		ch->SetDungeon(this);
		sys_log(0, "CDungeon::SpawnMob name %s", ch->GetName());
	}

	return ch;
}

void CDungeon::SpawnNameMob(DWORD vnum, int x, int y, const char* name)
{
	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}

	LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+x, pkSectreeMap->m_setting.iBaseY+y, 0, false, -1);
	if (ch)
	{
		ch->SetName(name);
		ch->SetDungeon(this);
	}
}

void CDungeon::SpawnGotoMob(long lFromX, long lFromY, long lToX, long lToY)
{
	const int MOB_GOTO_VNUM = 20039;

	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}

	sys_log(0, "SpawnGotoMob %d %d to %d %d", lFromX, lFromY, lToX, lToY);

	lFromX = pkSectreeMap->m_setting.iBaseX+lFromX*100;
	lFromY = pkSectreeMap->m_setting.iBaseY+lFromY*100;

	LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(MOB_GOTO_VNUM, m_lMapIndex, lFromX, lFromY, 0, false, -1);

	if (ch)
	{
		char buf[30+1];
		snprintf(buf, sizeof(buf), ". %ld %ld", lToX, lToY);

		ch->SetName(buf);
		ch->SetDungeon(this);
	}
}

LPCHARACTER CDungeon::SpawnGroup(DWORD vnum, long x, long y, float radius, bool bAggressive, int count)
{
	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return NULL;
	}

	int iRadius = (int) radius;

	int sx = pkSectreeMap->m_setting.iBaseX + x - iRadius;
	int sy = pkSectreeMap->m_setting.iBaseY + y - iRadius;
	int ex = sx + iRadius;
	int ey = sy + iRadius;

	LPCHARACTER ch = NULL;

	while (count--)
	{
		LPCHARACTER chLeader = CHARACTER_MANAGER::instance().SpawnGroup(vnum, m_lMapIndex, sx, sy, ex, ey, NULL, bAggressive, this);
		if (chLeader && !ch)
			ch = chLeader;
	}

	return ch;
}

void CDungeon::SpawnRegen(const char* filename, bool bOnce)
{
	if (!filename)
	{
		sys_err("CDungeon::SpawnRegen(filename=NULL, bOnce=%d) - m_lMapIndex[%d]", bOnce, m_lMapIndex);
		return;
	}

	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (!pkSectreeMap)
	{
		sys_err("CDungeon::SpawnRegen(filename=%s, bOnce=%d) - m_lMapIndex[%d]", filename, bOnce, m_lMapIndex);
		return;
	}
	regen_do(filename, m_lMapIndex, pkSectreeMap->m_setting.iBaseX, pkSectreeMap->m_setting.iBaseY, this, bOnce);
}

void CDungeon::AddRegen(LPREGEN regen)
{
	regen->id = regen_id_++;
	m_regen.push_back(regen);
}

void CDungeon::ClearRegen()
{
	for (itertype(m_regen) it = m_regen.begin(); it != m_regen.end(); ++it)
	{
		LPREGEN regen = *it;

		event_cancel(&regen->event);
		M2_DELETE(regen);
	}
	m_regen.clear();
}

bool CDungeon::IsValidRegen(LPREGEN regen, size_t regen_id) {
	itertype(m_regen) it = std::find(m_regen.begin(), m_regen.end(), regen);
	if (it == m_regen.end()) {
		return false;
	}
	LPREGEN found = *it;
	return (found->id == regen_id);
}

void CDungeon::SpawnMoveGroup(DWORD vnum, const char* pos_from, const char* pos_to, int count)
{
	TAreaMap::iterator it_to = m_map_Area.find(pos_to);

	if (it_to == m_map_Area.end())
	{
		sys_err("Wrong position string : %s", pos_to);
		return;
	}

	TAreaMap::iterator it_from = m_map_Area.find(pos_from);

	if (it_from == m_map_Area.end())
	{
		sys_err("Wrong position string : %s", pos_from);
		return;
	}

	TAreaInfo & ai = it_from->second;
	TAreaInfo & ai_to = it_to->second;
	int dir = ai.dir;

	if (dir == -1)
		dir = number(0,359);

	LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkSectreeMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}

	while (count--)
	{
		int tx = number(ai_to.sx, ai_to.ex)+pkSectreeMap->m_setting.iBaseX;
		int ty = number(ai_to.sy, ai_to.ey)+pkSectreeMap->m_setting.iBaseY;
		CHARACTER_MANAGER::instance().SpawnMoveGroup(vnum, m_lMapIndex, pkSectreeMap->m_setting.iBaseX+ai.sx, pkSectreeMap->m_setting.iBaseY+ai.sy, pkSectreeMap->m_setting.iBaseX+ai.ex, pkSectreeMap->m_setting.iBaseY+ai.ey, tx, ty, NULL, true);
	}
}

namespace
{
	// DUNGEON_KILL_ALL_BUG_FIX
	struct FKillSectree
	{
		void operator () (LPENTITY ent)
		{
			if (ent->IsType(ENTITY_CHARACTER))
			{
				LPCHARACTER ch = (LPCHARACTER) ent;

#ifdef NEW_PET_SYSTEM
				if (!ch->IsPC() && !ch->IsPet() && !ch->IsNewPet())
#else
				if (!ch->IsPC() && !ch->IsPet())
#endif
					ch->Dead();
			}
		}
	};
	// END_OF_DUNGEON_KILL_ALL_BUG_FIX

	struct FPurgeSectree
	{
		void operator () (LPENTITY ent)
		{
			if (ent->IsType(ENTITY_CHARACTER))
			{
				LPCHARACTER ch = (LPCHARACTER) ent;

#ifdef NEW_PET_SYSTEM
				if (!ch->IsPC() && !ch->IsPet() && !ch->IsNewPet())
#else
				if (!ch->IsPC() && !ch->IsPet())
#endif
				{
					M2_DESTROY_CHARACTER(ch);
				}
			}
			else if (ent->IsType(ENTITY_ITEM))
			{
				LPITEM item = (LPITEM) ent;
				M2_DESTROY_ITEM(item);
			}
			else
				sys_err("unknown entity type %d is in dungeon", ent->GetType());
		}
	};
}

// DUNGEON_KILL_ALL_BUG_FIX
void CDungeon::KillAll()
{
	LPSECTREE_MAP pkMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}
	FKillSectree f;
	pkMap->for_each(f);
}
// END_OF_DUNGEON_KILL_ALL_BUG_FIX

void CDungeon::Purge()
{
	LPSECTREE_MAP pkMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);
	if (pkMap == NULL) {
		sys_err("CDungeon: SECTREE_MAP not found for #%ld", m_lMapIndex);
		return;
	}
	FPurgeSectree f;
	pkMap->for_each(f);
}

void CDungeon::IncKillCount(LPCHARACTER pkKiller, LPCHARACTER pkVictim)
{
	if (pkVictim->IsStone())
		m_iStoneKill ++;
	else
		m_iMobKill ++;
}

void CDungeon::UsePotion(LPCHARACTER ch)
{
	m_bUsePotion = true;
}

void CDungeon::UseRevive(LPCHARACTER ch)
{
	m_bUseRevive = true;
}

bool CDungeon::IsUsePotion()
{
	return m_bUsePotion;
}

bool CDungeon::IsUseRevive()
{
	return m_bUseRevive;
}

int CDungeon::GetKillMobCount()
{
	return m_iMobKill;
}
int CDungeon::GetKillStoneCount()
{
	return m_iStoneKill;
}

struct FCountMonster
{
	int n;
	FCountMonster() : n(0) {};
	void operator()(LPENTITY ent)
	{
		if (ent->IsType(ENTITY_CHARACTER))
		{
			LPCHARACTER ch = (LPCHARACTER) ent;
			if (!ch->IsPC())
				n++;
		}
	}
};

int CDungeon::CountRealMonster()
{
	LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lOrigMapIndex);

	if (!pMap)
	{
		sys_err("cannot find map by index %d", m_lOrigMapIndex);
		return 0;
	}

	FCountMonster f;

	// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
	pMap->for_each(f);
	return f.n;
}

struct FExitDungeon
{
	void operator()(LPENTITY ent)
	{
		if (ent->IsType(ENTITY_CHARACTER))
		{
			LPCHARACTER ch = (LPCHARACTER) ent;

			if (ch->IsPC())
				ch->ExitToSavedLocation();
		}
	}
};

void CDungeon::ExitAll()
{
	LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);

	if (!pMap)
	{
		sys_err("cannot find map by index %d", m_lMapIndex);
		return;
	}

	FExitDungeon f;

	// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
	pMap->for_each(f);
}

// DUNGEON_NOTICE
namespace
{
	struct FNotice
	{
		FNotice(const char * psz) : m_psz(psz)
		{
		}

		void operator() (LPENTITY ent)
		{
			if (ent->IsType(ENTITY_CHARACTER))
			{
				LPCHARACTER ch = (LPCHARACTER) ent;
				ch->ChatPacket(CHAT_TYPE_NOTICE, "%s", m_psz);
			}
		}

		const char * m_psz;
	};
}

void CDungeon::Notice(const char* msg)
{
	sys_log(0, "XXX Dungeon Notice %p %s", this, msg);
	LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);

	if (!pMap)
	{
		sys_err("cannot find map by index %d", m_lMapIndex);
		return;
	}

	FNotice f(msg);
	pMap->for_each(f);
}
// END_OF_DUNGEON_NOTICE

struct FExitDungeonToStartPosition
{
	void operator () (LPENTITY ent)
	{
		if (ent->IsType(ENTITY_CHARACTER))
		{
			LPCHARACTER ch = (LPCHARACTER) ent;

			if (ch->IsPC())
			{
				PIXEL_POSITION posWarp;

				// 현재 맵 인덱스를 넣는 것이 아니라 시작하는 맵 인덱스를 넣는다.
				if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(g_start_map[ch->GetEmpire()], ch->GetEmpire(), posWarp))
					ch->WarpSet(posWarp.x, posWarp.y);
				else
					ch->ExitToSavedLocation();
			}
		}
	}
};

void CDungeon::ExitAllToStartPosition()
{
	LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);

	if (!pMap)
	{
		sys_err("cannot find map by index %d", m_lMapIndex);
		return;
	}

	FExitDungeonToStartPosition f;

	// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
	pMap->for_each(f);
}

EVENTFUNC(dungeon_jump_to_event)
{
	dungeon_id_info * info = dynamic_cast<dungeon_id_info *>(event->info);

	if ( info == NULL )
	{
		sys_err( "dungeon_jump_to_event> <Factor> Null pointer" );
		return 0;
	}

	LPDUNGEON pDungeon = CDungeonManager::instance().Find(info->dungeon_id);
	pDungeon->jump_to_event_ = NULL;

	if (pDungeon)
		pDungeon->JumpToEliminateLocation();
	else
		sys_err("cannot find dungeon with map index %u", info->dungeon_id);

	return 0;
}

EVENTFUNC(dungeon_exit_all_event)
{
	dungeon_id_info * info = dynamic_cast<dungeon_id_info *>(event->info);

	if ( info == NULL )
	{
		sys_err( "dungeon_exit_all_event> <Factor> Null pointer" );
		return 0;
	}

	LPDUNGEON pDungeon = CDungeonManager::instance().Find(info->dungeon_id);
	pDungeon->exit_all_event_ = NULL;

	if (pDungeon)
		pDungeon->ExitAll();

	return 0;
}

void CDungeon::CheckEliminated()
{
	if (m_iMonsterCount > 0)
		return;

	if (m_bExitAllAtEliminate)
	{
		sys_log(0, "CheckEliminated: exit");
		m_bExitAllAtEliminate = false;

		if (m_iWarpDelay)
		{
			dungeon_id_info* info = AllocEventInfo<dungeon_id_info>();
			info->dungeon_id = m_id;

			event_cancel(&exit_all_event_);
			exit_all_event_ = event_create(dungeon_exit_all_event, info, PASSES_PER_SEC(m_iWarpDelay));
		}
		else
		{
			ExitAll();
		}
	}
	else if (m_bWarpAtEliminate)
	{
		sys_log(0, "CheckEliminated: warp");
		m_bWarpAtEliminate = false;

		if (m_iWarpDelay)
		{
			dungeon_id_info* info = AllocEventInfo<dungeon_id_info>();
			info->dungeon_id = m_id;

			event_cancel(&jump_to_event_);
			jump_to_event_ = event_create(dungeon_jump_to_event, info, PASSES_PER_SEC(m_iWarpDelay));
		}
		else
		{
			JumpToEliminateLocation();
		}
	}
	else
		sys_log(0, "CheckEliminated: none");
}

void CDungeon::SetExitAllAtEliminate(long time)
{
	sys_log(0, "SetExitAllAtEliminate: time %d", time);
	m_bExitAllAtEliminate = true;
	m_iWarpDelay = time;
}

void CDungeon::SetWarpAtEliminate(long time, long lMapIndex, int x, int y, const char* regen_file)
{
	m_bWarpAtEliminate = true;
	m_iWarpDelay = time;
	m_lWarpMapIndex = lMapIndex;
	m_lWarpX = x;
	m_lWarpY = y;

	if (!regen_file || !*regen_file)
		m_stRegenFile.clear();
	else
		m_stRegenFile = regen_file;

	sys_log(0, "SetWarpAtEliminate: time %d map %d %dx%d regenfile %s", time, lMapIndex, x, y, m_stRegenFile.c_str());
}

void CDungeon::JumpToEliminateLocation()
{
	LPDUNGEON pDungeon = CDungeonManager::instance().FindByMapIndex(m_lWarpMapIndex);

	if (pDungeon)
	{
		pDungeon->JumpAll(m_lMapIndex, m_lWarpX, m_lWarpY);

		if (!m_stRegenFile.empty())
		{
			pDungeon->SpawnRegen(m_stRegenFile.c_str());
			m_stRegenFile.clear();
		}
	}
	else
	{
		// 일반 맵으로 워프
		LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);

		if (!pMap)
		{
			sys_err("no map by index %d", m_lMapIndex);
			return;
		}

		FWarpToPosition f(m_lWarpMapIndex, m_lWarpX * 100, m_lWarpY * 100);

		// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
		pMap->for_each(f);
	}
}

struct FNearPosition
{
	long x;
	long y;
	int dist;
	bool ret;

	FNearPosition(long x, long y, int d) :
		x(x), y(y), dist(d), ret(true)
	{
	}

	void operator()(LPENTITY ent)
	{
		if (ret == false)
			return;

		if (ent->IsType(ENTITY_CHARACTER))
		{
			LPCHARACTER ch = (LPCHARACTER) ent;

			if (ch->IsPC())
			{
				if (DISTANCE_APPROX(ch->GetX() - x * 100, ch->GetY() - y * 100) > dist * 100)
					ret = false;
			}
		}
	}
};

bool CDungeon::IsAllPCNearTo(int x, int y, int dist)
{
	LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(m_lMapIndex);

	if (!pMap)
	{
		sys_err("cannot find map by index %d", m_lMapIndex);
		return false;
	}

	FNearPosition f(x, y, dist);

	// <Factor> SECTREE::for_each -> SECTREE::for_each_entity
	pMap->for_each(f);

	return f.ret;
}

void CDungeon::CreateItemGroup (std::string& group_name, ItemGroup& item_group)
{
	m_map_ItemGroup.insert (ItemGroupMap::value_type (group_name, item_group));
}

const CDungeon::ItemGroup* CDungeon::GetItemGroup (std::string& group_name)
{
	ItemGroupMap::iterator it = m_map_ItemGroup.find (group_name);
	if (it != m_map_ItemGroup.end())
		return &(it->second);
	else
		return NULL;
}

 

so i removed it i will try if is work now if not i leave here my .cpp files 

 

Questmanager.cpp

Spoiler

#include "stdafx.h"
#include <fstream>
#include "constants.h"
#include "buffer_manager.h"
#include "packet.h"
#include "desc_client.h"
#include "desc_manager.h"
#include "char.h"
#include "char_manager.h"
#include "questmanager.h"
#include "lzo_manager.h"
#include "item.h"
#include "config.h"
#include "xmas_event.h"
#include "target.h"
#include "party.h"
#include "locale_service.h"

#include "dungeon.h"

DWORD g_GoldDropTimeLimitValue = 0;
extern bool DropEvent_CharStone_SetValue(const std::string& name, int value);
extern bool DropEvent_RefineBox_SetValue (const std::string& name, int value);

namespace quest
{
    using namespace std;

    CQuestManager::CQuestManager()
        : m_pSelectedDungeon(NULL), m_dwServerTimerArg(0), m_iRunningEventIndex(0), L(NULL), m_bNoSend (false),
        m_CurrentRunningState(NULL), m_pCurrentCharacter(NULL), m_pCurrentNPCCharacter(NULL), m_pCurrentPartyMember(NULL),
        m_pCurrentPC(NULL),  m_iCurrentSkin(0), m_bError(false), m_pOtherPCBlockRootPC(NULL)
    {
    }

    CQuestManager::~CQuestManager()
    {
        Destroy();
    }

    void CQuestManager::Destroy()
    {
        if (L)
        {
            lua_close(L);
            L = NULL;
        }
    }    

    bool CQuestManager::Initialize()
    {
        if (g_bAuthServer)
            return true;

        if (!InitializeLua())
            return false;

        m_pSelectedDungeon = NULL;

        m_mapEventName.insert(TEventNameMap::value_type("click", QUEST_CLICK_EVENT));        // NPC를 클릭
        m_mapEventName.insert(TEventNameMap::value_type("kill", QUEST_KILL_EVENT));        // Mob을 사냥
        m_mapEventName.insert(TEventNameMap::value_type("timer", QUEST_TIMER_EVENT));        // 미리 지정해둔 시간이 지남
        m_mapEventName.insert(TEventNameMap::value_type("levelup", QUEST_LEVELUP_EVENT));    // 레벨업을 함
        m_mapEventName.insert(TEventNameMap::value_type("login", QUEST_LOGIN_EVENT));        // 로그인 시
        m_mapEventName.insert(TEventNameMap::value_type("logout", QUEST_LOGOUT_EVENT));        // 로그아웃 시
        m_mapEventName.insert(TEventNameMap::value_type("button", QUEST_BUTTON_EVENT));        // 퀘스트 버튼을 누름
        m_mapEventName.insert(TEventNameMap::value_type("info", QUEST_INFO_EVENT));        // 퀘스트 정보창을 염
        m_mapEventName.insert(TEventNameMap::value_type("chat", QUEST_CHAT_EVENT));        // 특정 키워드로 대화를 함
        m_mapEventName.insert(TEventNameMap::value_type("in", QUEST_ATTR_IN_EVENT));        // 맵의 특정 속성에 들어감
        m_mapEventName.insert(TEventNameMap::value_type("out", QUEST_ATTR_OUT_EVENT));        // 맵의 특정 속성에서 나옴
        m_mapEventName.insert(TEventNameMap::value_type("use", QUEST_ITEM_USE_EVENT));        // 퀘스트 아이템을 사용
        m_mapEventName.insert(TEventNameMap::value_type("server_timer", QUEST_SERVER_TIMER_EVENT));    // 서버 타이머 (아직 테스트 안됐음)
        m_mapEventName.insert(TEventNameMap::value_type("enter", QUEST_ENTER_STATE_EVENT));    // 현재 스테이트가 됨
        m_mapEventName.insert(TEventNameMap::value_type("leave", QUEST_LEAVE_STATE_EVENT));    // 현재 스테이트에서 다른 스테이트로 바뀜
        m_mapEventName.insert(TEventNameMap::value_type("letter", QUEST_LETTER_EVENT));        // 로긴 하거나 스테이트가 바껴 새로 정보를 세팅해줘야함
        m_mapEventName.insert(TEventNameMap::value_type("take", QUEST_ITEM_TAKE_EVENT));    // 아이템을 받음
        m_mapEventName.insert(TEventNameMap::value_type("target", QUEST_TARGET_EVENT));        // 타겟
        m_mapEventName.insert(TEventNameMap::value_type("party_kill", QUEST_PARTY_KILL_EVENT));    // 파티 멤버가 몬스터를 사냥 (리더에게 옴)
        m_mapEventName.insert(TEventNameMap::value_type("unmount", QUEST_UNMOUNT_EVENT));
        m_mapEventName.insert(TEventNameMap::value_type("pick", QUEST_ITEM_PICK_EVENT));    // 떨어져있는 아이템을 습득함.
        m_mapEventName.insert(TEventNameMap::value_type("sig_use", QUEST_SIG_USE_EVENT));        // Special item group에 속한 아이템을 사용함.
        m_mapEventName.insert(TEventNameMap::value_type("item_informer", QUEST_ITEM_INFORMER_EVENT));    // 독일선물기능테스트

        m_bNoSend = false;

        m_iCurrentSkin = QUEST_SKIN_NORMAL;

        {
            ifstream inf((g_stQuestDir + "/questnpc.txt").c_str());
            int line = 0;

            if (!inf.is_open())
                sys_err( "QUEST Cannot open 'questnpc.txt'");
            else
                sys_log(0, "QUEST can open 'questnpc.txt' (%s)", g_stQuestDir.c_str() );

            while (1)
            {
                unsigned int vnum;

                inf >> vnum;

                line++;

                if (inf.fail())
                    break;

                string s;
                getline(inf, s);
                unsigned int li = 0, ri = s.size()-1;
                while (li < s.size() && isspace(s[li])) li++;
                while (ri > 0 && isspace(s[ri])) ri--;

                if (ri < li) 
                {
                    sys_err("QUEST questnpc.txt:%d:npc name error",line);
                    continue;
                }

                s = s.substr(li, ri-li+1);

                int    n = 0;
                str_to_number(n, s.c_str());
                if (n)
                    continue;

                //cout << '-' << s << '-' << endl;
                if ( test_server )
                    sys_log(0, "QUEST reading script of %s(%d)", s.c_str(), vnum);
                m_mapNPC[vnum].Set(vnum, s);
                m_mapNPCNameID = vnum;
            }

            // notarget quest
            m_mapNPC[0].Set(0, "notarget");
        }

        if (g_iUseLocale)
        {
            SetEventFlag("guild_withdraw_delay", 1);
            SetEventFlag("guild_disband_delay", 1);
        }
        else
        {
            SetEventFlag("guild_withdraw_delay", 3);
            SetEventFlag("guild_disband_delay", 7);
        }
        return true;
    }

    unsigned int CQuestManager::FindNPCIDByName(const string& name)
    {
        map<string, unsigned int>::iterator it = m_mapNPCNameID.find(name);
        return it != m_mapNPCNameID.end() ? it->second : 0;
    }

    void CQuestManager::SelectItem(unsigned int pc, unsigned int selection)
    {
        PC* pPC = GetPC(pc);
        if (pPC && pPC->IsRunning() && pPC->GetRunningQuestState()->suspend_state == SUSPEND_STATE_SELECT_ITEM)
        {
            pPC->SetSendDoneFlag();
            pPC->GetRunningQuestState()->args=1;
            lua_pushnumber(pPC->GetRunningQuestState()->co,selection);

            if (!RunState(*pPC->GetRunningQuestState()))
            {
                CloseState(*pPC->GetRunningQuestState());
                pPC->EndRunning();
            }
        }
    }

    void CQuestManager::Confirm(unsigned int pc, EQuestConfirmType confirm, unsigned int pc2)
    {
        PC* pPC = GetPC(pc);

        if (!pPC->IsRunning())
        {
            sys_err("no quest running for pc, cannot process input : %u", pc);
            return;
        }

        if (pPC->GetRunningQuestState()->suspend_state != SUSPEND_STATE_CONFIRM)
        {
            sys_err("not wait for a confirm : %u %d", pc, pPC->GetRunningQuestState()->suspend_state);
            return;
        }

        if (pc2 && !pPC->IsConfirmWait(pc2))
        {
            sys_err("not wait for a confirm : %u %d", pc, pPC->GetRunningQuestState()->suspend_state);
            return;
        }

        pPC->ClearConfirmWait();

        pPC->SetSendDoneFlag();

        pPC->GetRunningQuestState()->args=1;
        lua_pushnumber(pPC->GetRunningQuestState()->co, confirm);

        AddScript("[END_CONFIRM_WAIT]");
        SetSkinStyle(QUEST_SKIN_NOWINDOW);
        SendScript();

        if (!RunState(*pPC->GetRunningQuestState()))
        {
            CloseState(*pPC->GetRunningQuestState());
            pPC->EndRunning();
        }

    }

    void CQuestManager::Input(unsigned int pc, const char* msg)
    {
        PC* pPC = GetPC(pc);
        if (!pPC)
        {
            sys_err("no pc! : %u",pc);
            return;
        }

        if (!pPC->IsRunning())
        {
            sys_err("no quest running for pc, cannot process input : %u", pc);
            return;
        }

        if (pPC->GetRunningQuestState()->suspend_state != SUSPEND_STATE_INPUT)
        {
            sys_err("not wait for a input : %u %d", pc, pPC->GetRunningQuestState()->suspend_state);
            return;
        }

        pPC->SetSendDoneFlag();

        pPC->GetRunningQuestState()->args=1;
        lua_pushstring(pPC->GetRunningQuestState()->co,msg);

        if (!RunState(*pPC->GetRunningQuestState()))
        {
            CloseState(*pPC->GetRunningQuestState());
            pPC->EndRunning();
        }
    }

    void CQuestManager::Select(unsigned int pc, unsigned int selection)
    {
        PC* pPC;

        if ((pPC = GetPC(pc)) && pPC->IsRunning() && pPC->GetRunningQuestState()->suspend_state==SUSPEND_STATE_SELECT)
        {
            pPC->SetSendDoneFlag();

            if (!pPC->GetRunningQuestState()->chat_scripts.empty())
            {
                // 채팅 이벤트인 경우
                // 현재 퀘스트는 어느 퀘스트를 실행할 것인가를 고르는 퀘스트 이므로
                // 끝내고 선택된 퀘스트를 실행한다.
                QuestState& old_qs = *pPC->GetRunningQuestState();
                CloseState(old_qs);

                if (selection >= pPC->GetRunningQuestState()->chat_scripts.size())
                {
                    pPC->SetSendDoneFlag();
                    GotoEndState(old_qs);
                    pPC->EndRunning();
                }
                else
                {
                    AArgScript* pas = pPC->GetRunningQuestState()->chat_scripts[selection];
                    ExecuteQuestScript(*pPC, pas->quest_index, pas->state_index, pas->script.GetCode(), pas->script.GetSize());
                }
            }
            else
            {
                // on default 
                pPC->GetRunningQuestState()->args=1;
                lua_pushnumber(pPC->GetRunningQuestState()->co,selection+1);

                if (!RunState(*pPC->GetRunningQuestState()))
                {
                    CloseState(*pPC->GetRunningQuestState());
                    pPC->EndRunning();
                }
            }
        }
        else
        {
            sys_err("wrong QUEST_SELECT request! : %d",pc);
        }
    }

    void CQuestManager::Resume(unsigned int pc)
    {
        PC * pPC;

        if ((pPC = GetPC(pc)) && pPC->IsRunning() && pPC->GetRunningQuestState()->suspend_state == SUSPEND_STATE_PAUSE)
        {
            pPC->SetSendDoneFlag();
            pPC->GetRunningQuestState()->args = 0;

            if (!RunState(*pPC->GetRunningQuestState()))
            {
                CloseState(*pPC->GetRunningQuestState());
                pPC->EndRunning();
            }
        }
        else
        {
            //cerr << pPC << endl;
            //cerr << pPC->IsRunning() << endl;
            //cerr << pPC->GetRunningQuestState()->suspend_state;
            //cerr << SUSPEND_STATE_WAIT << endl;
            //cerr << "wrong QUEST_WAIT request! : " << pc << endl;
            sys_err("wrong QUEST_WAIT request! : %d",pc);
        }
    }

    void CQuestManager::EnterState(DWORD pc, DWORD quest_index, int state)
    {
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return;

            m_mapNPC[QUEST_NO_NPC].OnEnterState(*pPC, quest_index, state);
        }
        else
            sys_err("QUEST no such pc id : %d", pc);
    }

    void CQuestManager::LeaveState(DWORD pc, DWORD quest_index, int state)
    {
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return;

            m_mapNPC[QUEST_NO_NPC].OnLeaveState(*pPC, quest_index, state);
        }
        else
            sys_err("QUEST no such pc id : %d", pc);
    }

    void CQuestManager::Letter(DWORD pc, DWORD quest_index, int state)
    {
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return;

            m_mapNPC[QUEST_NO_NPC].OnLetter(*pPC, quest_index, state);
        }
        else
            sys_err("QUEST no such pc id : %d", pc);
    }

    void CQuestManager::LogoutPC(LPCHARACTER ch)
    {
        PC * pPC = GetPC(ch->GetPlayerID());

        if (pPC && pPC->IsRunning())
        {
            CloseState(*pPC->GetRunningQuestState());
            pPC->CancelRunning();
        }

        // 지우기 전에 로그아웃 한다.
        Logout(ch->GetPlayerID());

        if (ch == m_pCurrentCharacter)
        {
            m_pCurrentCharacter = NULL;
            m_pCurrentPC = NULL;
        }
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    //
    // Quest Event 관련
    //
    ///////////////////////////////////////////////////////////////////////////////////////////
    void CQuestManager::Login(unsigned int pc, const char * c_pszQuest)
    {
        PC * pPC;

        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return;

            m_mapNPC[QUEST_NO_NPC].OnLogin(*pPC, c_pszQuest);
        }
        else
        {
            sys_err("QUEST no such pc id : %d", pc);
        }
    }

    void CQuestManager::Logout(unsigned int pc)
    {
        PC * pPC;

        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return;

            m_mapNPC[QUEST_NO_NPC].OnLogout(*pPC);
        }
        else
            sys_err("QUEST no such pc id : %d", pc);
    }

    void CQuestManager::Kill(unsigned int pc, unsigned int npc)
    {
        //m_CurrentNPCRace = npc;
        PC * pPC;

        sys_log(0, "CQuestManager::Kill QUEST_KILL_EVENT (pc=%d, npc=%d)", pc, npc);

        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return;

            /* [hyo] 몹 kill시 중복 카운팅 이슈 관련한 수정사항
               quest script에 when 171.kill begin ... 등의 코드로 인하여 스크립트가 처리되었더라도
               바로 return하지 않고 다른 검사도 수행하도록 변경함. (2011/07/21)
            */   
            // call script
            
            //m_mapNPC[npc].OnKill(*pPC);
            if(npc > 0)
            {
                m_mapNPC[npc].OnKill(*pPC);
            }

            LPCHARACTER ch = GetCurrentCharacterPtr();
            LPPARTY pParty = ch->GetParty();
            LPCHARACTER leader = pParty ? pParty->GetLeaderCharacter() : ch;

            if (leader)
            {
                m_pCurrentPartyMember = ch;

                if (m_mapNPC[npc].OnPartyKill(*GetPC(leader->GetPlayerID())))
                    return;

                pPC = GetPC(pc);
            }

            if (m_mapNPC[QUEST_NO_NPC].OnKill(*pPC))
                return;

            if (leader)
            {
                m_pCurrentPartyMember = ch;
                m_mapNPC[QUEST_NO_NPC].OnPartyKill(*GetPC(leader->GetPlayerID()));
            }
        }
        else
            sys_err("QUEST: no such pc id : %d", pc);
    }

    bool CQuestManager::ServerTimer(unsigned int npc, unsigned int arg)
    {
        SetServerTimerArg(arg);
        sys_log(0, "XXX ServerTimer Call NPC %p", GetPCForce(0));
        m_pCurrentPC = GetPCForce(0);
        m_pCurrentCharacter = NULL;
        m_pSelectedDungeon = NULL;
        return m_mapNPC[npc].OnServerTimer(*m_pCurrentPC);
    }

    bool CQuestManager::Timer(unsigned int pc, unsigned int npc)
    {
        PC* pPC;

        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
            {
                return false;
            }
            // call script
            return m_mapNPC[npc].OnTimer(*pPC);
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST TIMER_EVENT no such pc id : %d", pc);
            return false;
        }
        //cerr << "QUEST TIMER" << endl;
    }

    void CQuestManager::LevelUp(unsigned int pc)
    {
        PC * pPC;

        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return;

            m_mapNPC[QUEST_NO_NPC].OnLevelUp(*pPC);
        }
        else
        {
            sys_err("QUEST LEVELUP_EVENT no such pc id : %d", pc);
        }
    }

    void CQuestManager::AttrIn(unsigned int pc, LPCHARACTER ch, int attr)
    {
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            m_pCurrentPartyMember = ch;
            if (!CheckQuestLoaded(pPC))
                return;

            // call script
            m_mapNPC[attr+QUEST_ATTR_NPC_START].OnAttrIn(*pPC);
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST no such pc id : %d", pc);
        }
    }

    void CQuestManager::AttrOut(unsigned int pc, LPCHARACTER ch, int attr)
    {
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            //m_pCurrentCharacter = ch;
            m_pCurrentPartyMember = ch;
            if (!CheckQuestLoaded(pPC))
                return;

            // call script
            m_mapNPC[attr+QUEST_ATTR_NPC_START].OnAttrOut(*pPC);
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST no such pc id : %d", pc);
        }
    }

    bool CQuestManager::Target(unsigned int pc, DWORD dwQuestIndex, const char * c_pszTargetName, const char * c_pszVerb)
    {
        PC * pPC;

        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return false;

            bool bRet;
            return m_mapNPC[QUEST_NO_NPC].OnTarget(*pPC, dwQuestIndex, c_pszTargetName, c_pszVerb, bRet);
        }

        return false;
    }

    void CQuestManager::QuestInfo(unsigned int pc, unsigned int quest_index)
    {
        PC* pPC;

        if ((pPC = GetPC(pc)))
        {
            // call script
            if (!CheckQuestLoaded(pPC))
            {
                LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pc);

                if (ch)
                    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퀘스트를 로드하는 중입니다. 잠시만 기다려 주십시오."));

                return;
            }

            m_mapNPC[QUEST_NO_NPC].OnInfo(*pPC, quest_index);
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST INFO_EVENT no such pc id : %d", pc);
        }
    }

    void CQuestManager::QuestButton(unsigned int pc, unsigned int quest_index)
    {
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            // call script
            if (!CheckQuestLoaded(pPC))
            {
                LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pc);
                if (ch)
                {
                    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퀘스트를 로드하는 중입니다. 잠시만 기다려 주십시오."));
                }
                return;
            }
            m_mapNPC[QUEST_NO_NPC].OnButton(*pPC, quest_index);
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST CLICK_EVENT no such pc id : %d", pc);
        }
    }

    bool CQuestManager::TakeItem(unsigned int pc, unsigned int npc, LPITEM item)
    {
        //m_CurrentNPCRace = npc;
        PC* pPC;

        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
            {
                LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pc);
                if (ch)
                {
                    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퀘스트를 로드하는 중입니다. 잠시만 기다려 주십시오."));
                }
                return false;
            }
            // call script
            SetCurrentItem(item);
            return m_mapNPC[npc].OnTakeItem(*pPC);
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST USE_ITEM_EVENT no such pc id : %d", pc);
            return false;
        }
    }

    bool CQuestManager::UseItem(unsigned int pc, LPITEM item, bool bReceiveAll)
    {
        if (test_server)
            sys_log( 0, "questmanager::UseItem Start : itemVnum : %d PC : %d", item->GetOriginalVnum(), pc);
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
            {
                LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pc);
                if (ch)
                {
                    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퀘스트를 로드하는 중입니다. 잠시만 기다려 주십시오."));
                }
                return false;
            }
            // call script
            SetCurrentItem(item);
            /*
            if (test_server)
            {
                sys_log( 0, "Quest UseItem Start : itemVnum : %d PC : %d", item->GetOriginalVnum(), pc);
                itertype(m_mapNPC) it = m_mapNPC.begin();
                itertype(m_mapNPC) end = m_mapNPC.end();
                for( ; it != end ; ++it)
                {
                    sys_log( 0, "Quest UseItem : vnum : %d item Vnum : %d", it->first, item->GetOriginalVnum());
                }
            }
            if(test_server)
            sys_log( 0, "questmanager:useItem: mapNPCVnum : %d\n", m_mapNPC[item->GetVnum()].GetVnum());
            */

            return m_mapNPC[item->GetVnum()].OnUseItem(*pPC, bReceiveAll);
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST USE_ITEM_EVENT no such pc id : %d", pc);
            return false;
        }
    }

    // Speical Item Group에 정의된 Group Use
    bool CQuestManager::SIGUse(unsigned int pc, DWORD sig_vnum, LPITEM item, bool bReceiveAll)
    {
        if (test_server)
            sys_log( 0, "questmanager::SIGUse Start : itemVnum : %d PC : %d", item->GetOriginalVnum(), pc);
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
            {
                LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pc);
                if (ch)
                {
                    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퀘스트를 로드하는 중입니다. 잠시만 기다려 주십시오."));
                }
                return false;
            }
            // call script
            SetCurrentItem(item);

            return m_mapNPC[sig_vnum].OnSIGUse(*pPC, bReceiveAll);
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST USE_ITEM_EVENT no such pc id : %d", pc);
            return false;
        }
    }

    bool CQuestManager::GiveItemToPC(unsigned int pc, LPCHARACTER pkChr)
    {
        if (!pkChr->IsPC())
            return false;

        PC * pPC = GetPC(pc);

        if (pPC)
        {
            if (!CheckQuestLoaded(pPC))
                return false;

            TargetInfo * pInfo = CTargetManager::instance().GetTargetInfo(pc, TARGET_TYPE_VID, pkChr->GetVID());

            if (pInfo)
            {
                bool bRet;

                if (m_mapNPC[QUEST_NO_NPC].OnTarget(*pPC, pInfo->dwQuestIndex, pInfo->szTargetName, "click", bRet))
                    return true;
            }
        }

        return false;
    }

    bool CQuestManager::Click(unsigned int pc, LPCHARACTER pkChrTarget)
    {
        PC * pPC = GetPC(pc);

        if (pPC)
        {
            if (!CheckQuestLoaded(pPC))
            {
                LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pc);

                if (ch)
                    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퀘스트를 로드하는 중입니다. 잠시만 기다려 주십시오."));

                return false;
            }

            TargetInfo * pInfo = CTargetManager::instance().GetTargetInfo(pc, TARGET_TYPE_VID, pkChrTarget->GetVID());
            if (test_server)
            {
                sys_log(0, "CQuestManager::Click(pid=%d, npc_name=%s) - target_info(%x)", pc, pkChrTarget->GetName(), pInfo);
            }

            if (pInfo)
            {
                bool bRet;
                if (m_mapNPC[QUEST_NO_NPC].OnTarget(*pPC, pInfo->dwQuestIndex, pInfo->szTargetName, "click", bRet))
                    return bRet;
            }

            DWORD dwCurrentNPCRace = pkChrTarget->GetRaceNum();

            if (pkChrTarget->IsNPC())
            {
                map<unsigned int, NPC>::iterator it = m_mapNPC.find(dwCurrentNPCRace);

                if (it == m_mapNPC.end())
                {
                    sys_err("CQuestManager::Click(pid=%d, target_npc_name=%s) - NOT EXIST NPC RACE VNUM[%d]",
                            pc, 
                            pkChrTarget->GetName(), 
                            dwCurrentNPCRace);
                    return false;
                }

                // call script
                if (it->second.HasChat())
                {
                    // if have chat, give chat
                    if (test_server)
                        sys_log(0, "CQuestManager::Click->OnChat");

                    if (!it->second.OnChat(*pPC))
                    {
                        if (test_server)
                            sys_log(0, "CQuestManager::Click->OnChat Failed");

                        return it->second.OnClick(*pPC);
                    }

                    return true;
                }
                else
                {
                    // else click
                    return it->second.OnClick(*pPC);
                }
            }
            return false;
        }
        else
        {
            //cout << "no such pc id : " << pc;
            sys_err("QUEST CLICK_EVENT no such pc id : %d", pc);
            return false;
        }
        //cerr << "QUEST CLICk" << endl;
    }

    void CQuestManager::Unmount(unsigned int pc)
    {
        PC * pPC;

        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
                return;

            m_mapNPC[QUEST_NO_NPC].OnUnmount(*pPC);
        }
        else
            sys_err("QUEST no such pc id : %d", pc);
    }
    //독일 선물 기능 테스트
    void CQuestManager::ItemInformer(unsigned int pc,unsigned int vnum)
    {
        
        PC* pPC;
        pPC = GetPC(pc);
        
        m_mapNPC[QUEST_NO_NPC].OnItemInformer(*pPC,vnum);
    }
    ///////////////////////////////////////////////////////////////////////////////////////////
    // END OF 퀘스트 이벤트 처리
    ///////////////////////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////////////////////
    void CQuestManager::LoadStartQuest(const string& quest_name, unsigned int idx)
    {
        for (itertype(g_setQuestObjectDir) it = g_setQuestObjectDir.begin(); it != g_setQuestObjectDir.end(); ++it)
        {
            const string& stQuestObjectDir = *it;
            string full_name = stQuestObjectDir + "/begin_condition/" + quest_name;
            ifstream inf(full_name.c_str());

            if (inf.is_open())
            {
                sys_log(0, "QUEST loading begin condition for %s", quest_name.c_str());

                istreambuf_iterator<char> ib(inf), ie;
                copy(ib, ie, back_inserter(m_hmQuestStartScript[idx]));
            }
        }
    }

    bool CQuestManager::CanStartQuest(unsigned int quest_index, const PC& pc)
    {
        return CanStartQuest(quest_index);
    }

    bool CQuestManager::CanStartQuest(unsigned int quest_index)
    {
        THashMapQuestStartScript::iterator it;

        if ((it = m_hmQuestStartScript.find(quest_index)) == m_hmQuestStartScript.end())
            return true;
        else
        {
            int x = lua_gettop(L);
            lua_dobuffer(L, &(it->second[0]), it->second.size(), "StartScript");
            int bStart = lua_toboolean(L, -1);
            lua_settop(L, x);
            return bStart != 0;
        }
    }

    bool CQuestManager::CanEndQuestAtState(const string& quest_name, const string& state_name)
    {
        return false;
    }

    void CQuestManager::DisconnectPC(LPCHARACTER ch)
    {
        m_mapPC.erase(ch->GetPlayerID());
    }

    PC * CQuestManager::GetPCForce(unsigned int pc)
    {
        PCMap::iterator it;

        if ((it = m_mapPC.find(pc)) == m_mapPC.end())
        {
            PC * pPC = &m_mapPC[pc];
            pPC->SetID(pc);
            return pPC;
        }

        return &it->second;
    }

    PC * CQuestManager::GetPC(unsigned int pc)
    {
        PCMap::iterator it;

        LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindByPID(pc);

        if (!pkChr)
            return NULL;

        m_pCurrentPC = GetPCForce(pc);
        m_pCurrentCharacter = pkChr;
        m_pSelectedDungeon = NULL;
        return (m_pCurrentPC);
    }

    void CQuestManager::ClearScript()
    {
        m_strScript.clear();
        m_iCurrentSkin = QUEST_SKIN_NORMAL;
    }

    void CQuestManager::AddScript(const string& str)
    {
        m_strScript+=str;
    }

    void CQuestManager::SendScript()
    {
        if (m_bNoSend)
        {
            m_bNoSend = false;
            ClearScript();
            return;
        }

        if (m_strScript=="[DONE]" || m_strScript == "[NEXT]")
        {
            if (m_pCurrentPC && !m_pCurrentPC->GetAndResetDoneFlag() && m_strScript=="[DONE]" && m_iCurrentSkin == QUEST_SKIN_NORMAL && !IsError())
            {
                ClearScript();
                return;
            }
            m_iCurrentSkin = QUEST_SKIN_NOWINDOW;
        }

        //sys_log(0, "Send Quest Script to %s", GetCurrentCharacterPtr()->GetName());
        //send -_-!
        struct ::packet_script packet_script;

        packet_script.header = HEADER_GC_SCRIPT;
        packet_script.skin = m_iCurrentSkin;
        packet_script.src_size = m_strScript.size();
        packet_script.size = packet_script.src_size + sizeof(struct packet_script);

        TEMP_BUFFER buf;
        buf.write(&packet_script, sizeof(struct packet_script));
        buf.write(&m_strScript[0], m_strScript.size());

        GetCurrentCharacterPtr()->GetDesc()->Packet(buf.read_peek(), buf.size());

        if (test_server)
            sys_log(0, "m_strScript %s size %d", m_strScript.c_str(), buf.size());

        ClearScript();
    }

    const char* CQuestManager::GetQuestStateName(const string& quest_name, const int state_index)
    {
        int x = lua_gettop(L);
        lua_getglobal(L, quest_name.c_str());
        if (lua_isnil(L,-1))
        {
            sys_err("QUEST wrong quest state file %s.%d", quest_name.c_str(), state_index);
            lua_settop(L,x);
            return "";
        }
        lua_pushnumber(L, state_index);
        lua_gettable(L, -2);

        const char* str = lua_tostring(L, -1);
        lua_settop(L, x);
        return str;
    }

    int CQuestManager::GetQuestStateIndex(const string& quest_name, const string& state_name)
    {
        int x = lua_gettop(L);
        lua_getglobal(L, quest_name.c_str());
        if (lua_isnil(L,-1))
        {
            sys_err("QUEST wrong quest state file %s.%s",quest_name.c_str(),state_name.c_str()  );
            lua_settop(L,x);
            return 0;
        }
        lua_pushstring(L, state_name.c_str());
        lua_gettable(L, -2);

        int v = (int)rint(lua_tonumber(L,-1));
        lua_settop(L, x);
        if ( test_server )
            sys_log( 0,"[QUESTMANAGER] GetQuestStateIndex x(%d) v(%d) %s %s", v,x, quest_name.c_str(), state_name.c_str() );
        return v;
    }

    void CQuestManager::SetSkinStyle(int iStyle)
    {
        if (iStyle<0 || iStyle >= QUEST_SKIN_COUNT)
        {
            m_iCurrentSkin = QUEST_SKIN_NORMAL;
        }
        else
            m_iCurrentSkin = iStyle;
    }

    unsigned int CQuestManager::LoadTimerScript(const string& name)
    {
        map<string, unsigned int>::iterator it;
        if ((it = m_mapTimerID.find(name)) != m_mapTimerID.end())
        {
            return it->second;
        }
        else
        {
            unsigned int new_id = UINT_MAX - m_mapTimerID.size();

            m_mapNPC[new_id].Set(new_id, name);
            m_mapTimerID.insert(make_pair(name, new_id));

            return new_id;
        }
    }

    unsigned int CQuestManager::GetCurrentNPCRace()
    {
        return GetCurrentNPCCharacterPtr() ? GetCurrentNPCCharacterPtr()->GetRaceNum() : 0;
    }

    LPITEM CQuestManager::GetCurrentItem()
    {
        return GetCurrentCharacterPtr() ? GetCurrentCharacterPtr()->GetQuestItemPtr() : NULL; 
    }

    void CQuestManager::ClearCurrentItem()
    {
        if (GetCurrentCharacterPtr())
            GetCurrentCharacterPtr()->ClearQuestItemPtr();
    }

    void CQuestManager::SetCurrentItem(LPITEM item)
    {
        if (GetCurrentCharacterPtr())
            GetCurrentCharacterPtr()->SetQuestItemPtr(item);
    }

    LPCHARACTER CQuestManager::GetCurrentNPCCharacterPtr()
    { 
        return GetCurrentCharacterPtr() ? GetCurrentCharacterPtr()->GetQuestNPC() : NULL; 
    }

    const string & CQuestManager::GetCurrentQuestName()
    {
        return GetCurrentPC()->GetCurrentQuestName();
    }

    LPDUNGEON CQuestManager::GetCurrentDungeon()
    {
        LPCHARACTER ch = GetCurrentCharacterPtr();

        if (!ch)
        {
            if (m_pSelectedDungeon)
                return m_pSelectedDungeon;
            return NULL;
        }

        return ch->GetDungeonForce();
    }

    void CQuestManager::RegisterQuest(const string & stQuestName, unsigned int idx)
    {
        assert(idx > 0);

        itertype(m_hmQuestName) it;

        if ((it = m_hmQuestName.find(stQuestName)) != m_hmQuestName.end())
            return;

        m_hmQuestName.insert(make_pair(stQuestName, idx));
        LoadStartQuest(stQuestName, idx);
        m_mapQuestNameByIndex.insert(make_pair(idx, stQuestName));

        sys_log(0, "QUEST: Register %4u %s", idx, stQuestName.c_str());
    }

    unsigned int CQuestManager::GetQuestIndexByName(const string& name)
    {
        THashMapQuestName::iterator it = m_hmQuestName.find(name);

        if (it == m_hmQuestName.end())
            return 0; // RESERVED

        return it->second;
    }

    const string & CQuestManager::GetQuestNameByIndex(unsigned int idx)
    {
        itertype(m_mapQuestNameByIndex) it;

        if ((it = m_mapQuestNameByIndex.find(idx)) == m_mapQuestNameByIndex.end())
        {
            sys_err("cannot find quest name by index %u", idx);
            assert(!"cannot find quest name by index");

            static std::string st = "";
            return st;
        }

        return it->second;
    }

    void CQuestManager::SendEventFlagList(LPCHARACTER ch)
    {
        itertype(m_mapEventFlag) it;
        for (it = m_mapEventFlag.begin(); it != m_mapEventFlag.end(); ++it)
        {
            const string& flagname = it->first;
            int value = it->second;

            if (!test_server && value == 1 && flagname == "valentine_drop")
                ch->ChatPacket(CHAT_TYPE_INFO, "%s %d prob 800", flagname.c_str(), value);
            else if (!test_server && value == 1 && flagname == "newyear_wonso")
                ch->ChatPacket(CHAT_TYPE_INFO, "%s %d prob 500", flagname.c_str(), value);
            else if (!test_server && value == 1 && flagname == "newyear_fire")
                ch->ChatPacket(CHAT_TYPE_INFO, "%s %d prob 1000", flagname.c_str(), value);
            else
                ch->ChatPacket(CHAT_TYPE_INFO, "%s %d", flagname.c_str(), value);
        }
    }

    void CQuestManager::RequestSetEventFlag(const string& name, int value)
    {
        TPacketSetEventFlag p;
        strlcpy(p.szFlagName, name.c_str(), sizeof(p.szFlagName));
        p.lValue = value;
        db_clientdesc->DBPacket(HEADER_GD_SET_EVENT_FLAG, 0, &p, sizeof(TPacketSetEventFlag));
    }

    void CQuestManager::SetEventFlag(const string& name, int value)
    {
        static const char*    DROPEVENT_CHARTONE_NAME        = "drop_char_stone";
        static const int    DROPEVENT_CHARTONE_NAME_LEN = strlen(DROPEVENT_CHARTONE_NAME);

        int prev_value = m_mapEventFlag[name];

        sys_log(0, "QUEST eventflag %s %d prev_value %d", name.c_str(), value, m_mapEventFlag[name]);
        m_mapEventFlag[name] = value;

        if (name == "mob_item")
        {
            CHARACTER_MANAGER::instance().SetMobItemRate(value);
        }
        else if (name == "mob_dam")
        {
            CHARACTER_MANAGER::instance().SetMobDamageRate(value);
        }
        else if (name == "mob_gold")
        {
            CHARACTER_MANAGER::instance().SetMobGoldAmountRate(value);
        }
        else if (name == "mob_gold_pct")
        {
            CHARACTER_MANAGER::instance().SetMobGoldDropRate(value);
        }
        else if (name == "user_dam")
        {
            CHARACTER_MANAGER::instance().SetUserDamageRate(value);
        }
        else if (name == "user_dam_buyer")
        {
            CHARACTER_MANAGER::instance().SetUserDamageRatePremium(value);
        }
        else if (name == "mob_exp")
        {
            CHARACTER_MANAGER::instance().SetMobExpRate(value);
        }
        else if (name == "mob_item_buyer")
        {
            CHARACTER_MANAGER::instance().SetMobItemRatePremium(value);
        }
        else if (name == "mob_exp_buyer")
        {
            CHARACTER_MANAGER::instance().SetMobExpRatePremium(value);
        }
        else if (name == "mob_gold_buyer")
        {
            CHARACTER_MANAGER::instance().SetMobGoldAmountRatePremium(value);
        }
        else if (name == "mob_gold_pct_buyer")
        {
            CHARACTER_MANAGER::instance().SetMobGoldDropRatePremium(value);
        }
        else if (name == "crcdisconnect")
        {
            DESC_MANAGER::instance().SetDisconnectInvalidCRCMode(value != 0);
        }
        else if (!name.compare(0,5,"xmas_"))
        {
            xmas::ProcessEventFlag(name, prev_value, value);
        }
        else if (name == "newyear_boom")
        {
            const DESC_MANAGER::DESC_SET & c_ref_set = DESC_MANAGER::instance().GetClientSet();

            for (itertype(c_ref_set) it = c_ref_set.begin(); it != c_ref_set.end(); ++it)
            {
                LPCHARACTER ch = (*it)->GetCharacter();

                if (!ch)
                    continue;

                ch->ChatPacket(CHAT_TYPE_COMMAND, "newyear_boom %d", value);
            }
        }
        else if ( name == "eclipse" )
        {
            std::string mode("");

            if ( value == 1 )
            {
                mode = "dark";
            }
            else
            {
                mode = "light";
            }
            
            const DESC_MANAGER::DESC_SET & c_ref_set = DESC_MANAGER::instance().GetClientSet();

            for (itertype(c_ref_set) it = c_ref_set.begin(); it != c_ref_set.end(); ++it)
            {
                LPCHARACTER ch = (*it)->GetCharacter();
                if (!ch)
                    continue;

                ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode %s", mode.c_str());
            }
        }
        else if (name == "day")
        {
            const DESC_MANAGER::DESC_SET & c_ref_set = DESC_MANAGER::instance().GetClientSet();

            for (itertype(c_ref_set) it = c_ref_set.begin(); it != c_ref_set.end(); ++it)
            {
                LPCHARACTER ch = (*it)->GetCharacter();
                if (!ch)
                    continue;
                if (value)
                {
                    // 밤
                    ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode dark");
                }
                else
                {
                    // 낮
                    ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode light");
                }
            }

            if (value && !prev_value)
            {
                // 없으면 만들어준다
                struct SNPCSellFireworkPosition
                {
                    long lMapIndex;
                    int x;
                    int y;
                } positions[] = {
                    {    1,    615,    618 },
                    {    3,    500,    625 },
                    {    21,    598,    665 },
                    {    23,    476,    360 },
                    {    41,    318,    629 },
                    {    43,    478,    375 },
                    {    0,    0,    0   },
                };

                SNPCSellFireworkPosition* p = positions;
                while (p->lMapIndex)
                {
                    if (map_allow_find(p->lMapIndex))
                    {
                        PIXEL_POSITION posBase;
                        if (!SECTREE_MANAGER::instance().GetMapBasePositionByMapIndex(p->lMapIndex, posBase))
                        {
                            sys_err("cannot get map base position %d", p->lMapIndex);
                            ++p;
                            continue;
                        }

                        CHARACTER_MANAGER::instance().SpawnMob(xmas::MOB_XMAS_FIRWORK_SELLER_VNUM, p->lMapIndex, posBase.x + p->x * 100, posBase.y + p->y * 100, 0, false, -1);
                    }
                    p++;
                }
            }
            else if (!value && prev_value)
            {
                // 있으면 지워준다
                CharacterVectorInteractor i;

                if (CHARACTER_MANAGER::instance().GetCharactersByRaceNum(xmas::MOB_XMAS_FIRWORK_SELLER_VNUM, i))
                {
                    CharacterVectorInteractor::iterator it = i.begin();

                    while (it != i.end()) {
                        M2_DESTROY_CHARACTER(*it++);
                    }
                }
            }
        }
        else if (name == "pre_event_hc" && true == LC_IsEurope())
        {
            const DWORD EventNPC = 20090;

            struct SEventNPCPosition
            {
                long lMapIndex;
                int x;
                int y;
            } positions[] = {
                { 3, 588, 617 },
                { 23, 397, 250 },
                { 43, 567, 426 },
                { 0, 0, 0 },
            };

            if (value && !prev_value)
            {
                SEventNPCPosition* pPosition = positions;

                while (pPosition->lMapIndex)
                {
                    if (map_allow_find(pPosition->lMapIndex))
                    {
                        PIXEL_POSITION pos;

                        if (!SECTREE_MANAGER::instance().GetMapBasePositionByMapIndex(pPosition->lMapIndex, pos))
                        {
                            sys_err("cannot get map base position %d", pPosition->lMapIndex);
                            ++pPosition;
                            continue;
                        }

                        CHARACTER_MANAGER::instance().SpawnMob(EventNPC, pPosition->lMapIndex, pos.x+pPosition->x*100, pos.y+pPosition->y*100, 0, false, -1);
                    }
                    pPosition++;
                }
            }
            else if (!value && prev_value)
            {
                CharacterVectorInteractor i;

                if (CHARACTER_MANAGER::instance().GetCharactersByRaceNum(EventNPC, i))
                {
                    CharacterVectorInteractor::iterator it = i.begin();

                    while (it != i.end())
                    {
                        LPCHARACTER ch = *it++;

                        switch (ch->GetMapIndex())
                        {
                            case 3:
                            case 23:
                            case 43:
                                M2_DESTROY_CHARACTER(ch);
                                break;
                        }
                    }
                }
            }
        }
        else if (name.compare(0, DROPEVENT_CHARTONE_NAME_LEN, DROPEVENT_CHARTONE_NAME)== 0)
        {
            DropEvent_CharStone_SetValue(name, value);
        }
        else if (name.compare(0, strlen("refine_box"), "refine_box")== 0)
        {
            DropEvent_RefineBox_SetValue(name, value);
        }
        else if (name == "gold_drop_limit_time")
        {
            g_GoldDropTimeLimitValue = value * 1000;
        }
        else if (name == "new_xmas_event")
        {
            // 20126 new산타.
            static DWORD new_santa = 20126;
            if (value != 0)
            {
                CharacterVectorInteractor i;
                bool map1_santa_exist = false;
                bool map21_santa_exist = false;
                bool map41_santa_exist = false;
                
                if (CHARACTER_MANAGER::instance().GetCharactersByRaceNum(new_santa, i))
                {
                    CharacterVectorInteractor::iterator it = i.begin();

                    while (it != i.end())
                    {
                        LPCHARACTER tch = *(it++);

                        if (tch->GetMapIndex() == 1)
                        {
                            map1_santa_exist = true;
                        }
                        else if (tch->GetMapIndex() == 21)
                        {
                            map21_santa_exist = true;
                        }
                        else if (tch->GetMapIndex() == 41)
                        {
                            map41_santa_exist = true;
                        }
                    }
                }

                if (map_allow_find(1) && !map1_santa_exist)
                {
                    LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(1);
                    CHARACTER_MANAGER::instance().SpawnMob(new_santa, 1, pkSectreeMap->m_setting.iBaseX + 60800, pkSectreeMap->m_setting.iBaseY + 61700, 0, false, 90, true);
                }
                if (map_allow_find(21) && !map21_santa_exist)
                {
                    LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(21);
                    CHARACTER_MANAGER::instance().SpawnMob(new_santa, 21, pkSectreeMap->m_setting.iBaseX + 59600, pkSectreeMap->m_setting.iBaseY + 61000, 0, false, 110, true);
                }
                if (map_allow_find(41) && !map41_santa_exist)
                {
                    LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(41);
                    CHARACTER_MANAGER::instance().SpawnMob(new_santa, 41, pkSectreeMap->m_setting.iBaseX + 35700, pkSectreeMap->m_setting.iBaseY + 74300, 0, false, 140, true);
                }
            }
            else
            {
                CharacterVectorInteractor i;
                CHARACTER_MANAGER::instance().GetCharactersByRaceNum(new_santa, i);
                
                for (CharacterVectorInteractor::iterator it = i.begin(); it != i.end(); it++)
                {
                    M2_DESTROY_CHARACTER(*it);
                }
            }
        }
    }

    int    CQuestManager::GetEventFlag(const string& name)
    {
        map<string,int>::iterator it = m_mapEventFlag.find(name);

        if (it == m_mapEventFlag.end())
            return 0;

        return it->second;
    }

    void CQuestManager::BroadcastEventFlagOnLogin(LPCHARACTER ch)
    {
        int iEventFlagValue;

        if ((iEventFlagValue = quest::CQuestManager::instance().GetEventFlag("xmas_snow")))
        {
            ch->ChatPacket(CHAT_TYPE_COMMAND, "xmas_snow %d", iEventFlagValue);
        }

        if ((iEventFlagValue = quest::CQuestManager::instance().GetEventFlag("xmas_boom")))
        {
            ch->ChatPacket(CHAT_TYPE_COMMAND, "xmas_boom %d", iEventFlagValue);
        }

        if ((iEventFlagValue = quest::CQuestManager::instance().GetEventFlag("xmas_tree")))
        {
            ch->ChatPacket(CHAT_TYPE_COMMAND, "xmas_tree %d", iEventFlagValue);
        }

        if ((iEventFlagValue = quest::CQuestManager::instance().GetEventFlag("day")))
        {
            ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode dark");
        }

        if ((iEventFlagValue = quest::CQuestManager::instance().GetEventFlag("newyear_boom")))
        {
            ch->ChatPacket(CHAT_TYPE_COMMAND, "newyear_boom %d", iEventFlagValue);
        }

        if ( (iEventFlagValue = quest::CQuestManager::instance().GetEventFlag("eclipse")) )
        {
            std::string mode;

            if ( iEventFlagValue == 1 ) mode = "dark";
            else mode = "light";

            ch->ChatPacket(CHAT_TYPE_COMMAND, "DayMode %s", mode.c_str());
        }
    }

    void CQuestManager::Reload()
    {
        lua_close(L);
        m_mapNPC.clear();
        m_mapNPCNameID.clear();
        m_hmQuestName.clear();
        m_mapTimerID.clear();
        m_hmQuestStartScript.clear();
        m_mapEventName.clear();
        L = NULL;
        Initialize();

        for (itertype(m_registeredNPCVnum) it = m_registeredNPCVnum.begin(); it != m_registeredNPCVnum.end(); ++it)
        {
            char buf[256];
            DWORD dwVnum = *it;
            snprintf(buf, sizeof(buf), "%u", dwVnum);
            m_mapNPC[dwVnum].Set(dwVnum, buf);
        }
    }

    bool CQuestManager::ExecuteQuestScript(PC& pc, DWORD quest_index, const int state, const char* code, const int code_size, vector<AArgScript*>* pChatScripts, bool bUseCache)
    {
        return ExecuteQuestScript(pc, CQuestManager::instance().GetQuestNameByIndex(quest_index), state, code, code_size, pChatScripts, bUseCache);
    }

    bool CQuestManager::ExecuteQuestScript(PC& pc, const string& quest_name, const int state, const char* code, const int code_size, vector<AArgScript*>* pChatScripts, bool bUseCache)
    {
        // 실행공간을 생성
        QuestState qs = CQuestManager::instance().OpenState(quest_name, state);
        if (pChatScripts)
            qs.chat_scripts.swap(*pChatScripts);

        // 코드를 읽어들임
        if (bUseCache)
        {
            lua_getglobal(qs.co, "__codecache");
            // stack : __codecache
            lua_pushnumber(qs.co, (long)code);
            // stack : __codecache (codeptr)
            lua_rawget(qs.co, -2);
            // stack : __codecache (compiled-code)
            if (lua_isnil(qs.co, -1))
            {
                // cache miss

                // load code to lua,
                // save it to cache
                // and only function remain in stack
                lua_pop(qs.co, 1);
                // stack : __codecache
                luaL_loadbuffer(qs.co, code, code_size, quest_name.c_str());
                // stack : __codecache (compiled-code)
                lua_pushnumber(qs.co, (long)code);
                // stack : __codecache (compiled-code) (codeptr)
                lua_pushvalue(qs.co, -2);
                // stack : __codecache (compiled-code) (codeptr) (compiled_code)
                lua_rawset(qs.co, -4);
                // stack : __codecache (compiled-code)
                lua_remove(qs.co, -2);
                // stack : (compiled-code)
            }
            else
            {
                // cache hit
                lua_remove(qs.co, -2);
                // stack : (compiled-code)
            }
        }
        else
            luaL_loadbuffer(qs.co, code, code_size, quest_name.c_str());

        // 플레이어와 연결
        pc.SetQuest(quest_name, qs);

        // 실행
        QuestState& rqs = *pc.GetRunningQuestState();
        if (!CQuestManager::instance().RunState(rqs))
        {
            CQuestManager::instance().CloseState(rqs);
            pc.EndRunning();
            return false;
        }
        return true;
    }

    void CQuestManager::RegisterNPCVnum(DWORD dwVnum)
    {
        if (m_registeredNPCVnum.find(dwVnum) != m_registeredNPCVnum.end())
            return;

        m_registeredNPCVnum.insert(dwVnum);

        char buf[256];
        DIR* dir;

        for (itertype(g_setQuestObjectDir) it = g_setQuestObjectDir.begin(); it != g_setQuestObjectDir.end(); ++it)
        {
            const string& stQuestObjectDir = *it;
            snprintf(buf, sizeof(buf), "%s/%u", stQuestObjectDir.c_str(), dwVnum);
            sys_log(0, "%s", buf);

            if ((dir = opendir(buf)))
            {
                closedir(dir);
                snprintf(buf, sizeof(buf), "%u", dwVnum);
                sys_log(0, "%s", buf);

                m_mapNPC[dwVnum].Set(dwVnum, buf);
            }
        }
    }

    void CQuestManager::WriteRunningStateToSyserr()
    {
        const char * state_name = GetQuestStateName(GetCurrentQuestName(), GetCurrentState()->st);

        string event_index_name = "";
        for (itertype(m_mapEventName) it = m_mapEventName.begin(); it != m_mapEventName.end(); ++it)
        {
            if (it->second == m_iRunningEventIndex)
            {
                event_index_name = it->first;
                break;
            }
        }

        sys_err("LUA_ERROR: quest %s.%s %s", GetCurrentQuestName().c_str(), state_name, event_index_name.c_str() );
        if (GetCurrentCharacterPtr() && test_server)
            GetCurrentCharacterPtr()->ChatPacket(CHAT_TYPE_PARTY, "LUA_ERROR: quest %s.%s %s", GetCurrentQuestName().c_str(), state_name, event_index_name.c_str() );
    }

#ifndef __WIN32__
    void CQuestManager::QuestError(const char* func, int line, const char* fmt, ...)
    {
        char szMsg[4096];
        va_list args;

        va_start(args, fmt);
        vsnprintf(szMsg, sizeof(szMsg), fmt, args);
        va_end(args);

        _sys_err(func, line, "%s", szMsg);
        if (test_server)
        {
            LPCHARACTER ch = GetCurrentCharacterPtr();
            if (ch)
            {
                ch->ChatPacket(CHAT_TYPE_PARTY, "error occurred on [%s:%d]", func,line);
                ch->ChatPacket(CHAT_TYPE_PARTY, "%s", szMsg);
            }
        }
    }
#else
    void CQuestManager::QuestError(const char* func, int line, const char* fmt, ...)
    {
        char szMsg[4096];
        va_list args;

        va_start(args, fmt);
        vsnprintf(szMsg, sizeof(szMsg), fmt, args);
        va_end(args);

        _sys_err(func, line, "%s", szMsg);
        if (test_server)
        {
            LPCHARACTER ch = GetCurrentCharacterPtr();
            if (ch)
            {
                ch->ChatPacket(CHAT_TYPE_PARTY, "error occurred on [%s:%d]", func,line);
                ch->ChatPacket(CHAT_TYPE_PARTY, "%s", szMsg);
            }
        }
    }
#endif

    void CQuestManager::AddServerTimer(const std::string& name, DWORD arg, LPEVENT event)
    {
        sys_log(0, "XXX AddServerTimer %s %d %p", name.c_str(), arg, get_pointer(event));
        if (m_mapServerTimer.find(make_pair(name, arg)) != m_mapServerTimer.end())
        {
            sys_err("already registered server timer name:%s arg:%u", name.c_str(), arg);
            return;
        }
        m_mapServerTimer.insert(make_pair(make_pair(name, arg), event));
    }

    void CQuestManager::ClearServerTimerNotCancel(const std::string& name, DWORD arg)
    {
        m_mapServerTimer.erase(make_pair(name, arg));
    }

    void CQuestManager::ClearServerTimer(const std::string& name, DWORD arg)
    {
        itertype(m_mapServerTimer) it = m_mapServerTimer.find(make_pair(name, arg));
        if (it != m_mapServerTimer.end())
        {
            LPEVENT event = it->second;
            event_cancel(&event);
            m_mapServerTimer.erase(it);
        }
    }

    void CQuestManager::CancelServerTimers(DWORD arg)
    {
        itertype(m_mapServerTimer) it = m_mapServerTimer.begin();
        for ( ; it != m_mapServerTimer.end(); ++it) {
            if (it->first.second == arg) {
                LPEVENT event = it->second;
                event_cancel(&event);
                m_mapServerTimer.erase(it);
            }
        }
    }

    void CQuestManager::SetServerTimerArg(DWORD dwArg)
    {
        m_dwServerTimerArg = dwArg;
    }

    DWORD CQuestManager::GetServerTimerArg()
    {
        return m_dwServerTimerArg;
    }

    void CQuestManager::SelectDungeon(LPDUNGEON pDungeon)
    {
        m_pSelectedDungeon = pDungeon;
    }
    
    bool CQuestManager::PickupItem(unsigned int pc, LPITEM item)
    {
        if (test_server)
            sys_log( 0, "questmanager::PickupItem Start : itemVnum : %d PC : %d", item->GetOriginalVnum(), pc);
        PC* pPC;
        if ((pPC = GetPC(pc)))
        {
            if (!CheckQuestLoaded(pPC))
            {
                LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pc);
                if (ch)
                {
                    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("퀘스트를 로드하는 중입니다. 잠시만 기다려 주십시오."));
                }
                return false;
            }
            // call script
            SetCurrentItem(item);

            return m_mapNPC[item->GetVnum()].OnPickupItem(*pPC);
        }
        else
        {
            sys_err("QUEST PICK_ITEM_EVENT no such pc id : %d", pc);
            return false;
        }
    }
    void CQuestManager::BeginOtherPCBlock(DWORD pid)
    {
        LPCHARACTER ch = GetCurrentCharacterPtr();
        if (NULL == ch)
        {
            sys_err("NULL?");
            return;
        }
        /*
        # 1. current pid = pid0 <- It will be m_pOtherPCBlockRootPC.
        begin_other_pc_block(pid1)
            # 2. current pid = pid1
            begin_other_pc_block(pid2)
                # 3. current_pid = pid2
            end_other_pc_block()
        end_other_pc_block()
        */
        // when begin_other_pc_block(pid1)
        if (m_vecPCStack.empty())
        {
            m_pOtherPCBlockRootPC = GetCurrentPC();
        }
        m_vecPCStack.push_back(GetCurrentCharacterPtr()->GetPlayerID());
        GetPC(pid);
    }

    void CQuestManager::EndOtherPCBlock()
    {
        if (m_vecPCStack.size() == 0)
        {
            sys_err("m_vecPCStack is alread empty. CurrentQuest{Name(%s), State(%s)}", GetCurrentQuestName().c_str(), GetCurrentState()->_title.c_str());
            return;
        }
        DWORD pc = m_vecPCStack.back();
        m_vecPCStack.pop_back();
        GetPC(pc);

        if (m_vecPCStack.empty())
        {
            m_pOtherPCBlockRootPC = NULL;
        }
    }

    bool CQuestManager::IsInOtherPCBlock()
    {
        return !m_vecPCStack.empty();
    }

    PC*    CQuestManager::GetOtherPCBlockRootPC()
    {
        return m_pOtherPCBlockRootPC;
    }
}

 

" Don`t pretend things change if you always do the same thing"

"Don`t give up on a dream for how long it will take, time will pass the same"

Link to post
  • 0

Removing this from dungeon.cpp is definitely a bad idea!

	if (!pDungeon)
	{
		sys_err("M2_NEW CDungeon failed");
		return NULL;
	}

It is there to prevent nullptr what will cause core crash.

Edited by TMP4 (see edit history)
Link to post
  • 0
  • VIP
Posted (edited)

so idk what will be the problem and where because this is happening after upgrading the source :c and is getting me sick now this problem is first time that happen

Edited by Arkane2 (see edit history)

" Don`t pretend things change if you always do the same thing"

"Don`t give up on a dream for how long it will take, time will pass the same"

Link to post
  • 0

Which line of this is 1733 on questmanager.cpp? Because it seems like it got a bit cut during copying. Also I've seen some big differences between the clear server timers function.

We are the tortured.
We're not your friends.
As long as we're not visible.
We are unfixable.

Link to post
  • 0
  • VIP
    void CQuestManager::CancelServerTimers(DWORD arg)
    {
        itertype(m_mapServerTimer) it = m_mapServerTimer.begin();
Line> 1733        for ( ; it != m_mapServerTimer.end(); ++it) {
            if (it->first.second == arg) {
                LPEVENT event = it->second;
                event_cancel(&event);
                m_mapServerTimer.erase(it);
            }
        }
    }

this is that function and the line 1733 is

 

        for ( ; it != m_mapServerTimer.end(); ++it) {

 

" Don`t pretend things change if you always do the same thing"

"Don`t give up on a dream for how long it will take, time will pass the same"

Link to post
  • 0
  • VIP
2 minutes ago, Sonitex said:
	void CQuestManager::CancelServerTimers(DWORD arg)
	{
		vector<pair<string, DWORD>> ServerTimersToDelete;

		for (auto& kv : m_mapServerTimer) {
			if (kv.first.second == arg) {
				LPEVENT event = kv.second;
				event_cancel(&event);
				ServerTimersToDelete.push_back(kv.first);
			}
		}

		// Delete all the required server timers
		for (auto &timer : ServerTimersToDelete)
			m_mapServerTimer.erase(timer);

		// Clean up
		ServerTimersToDelete.clear();
	}

Crash occurs because the game is deleting timers while iterating through them. Code above should fix this issue :) 

 

thank you very much dude i will try  :)

" Don`t pretend things change if you always do the same thing"

"Don`t give up on a dream for how long it will take, time will pass the same"

Link to post
  • 0
  • VIP

Problem fixed thanks a lot @vanilla

@Sonitex and other who helped me  :)❤️

" Don`t pretend things change if you always do the same thing"

"Don`t give up on a dream for how long it will take, time will pass the same"

Link to post
Guest
This topic is now closed to further replies.


×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.