UpdateServerPlayer::UpdateServerPlayer (Socket * pSocket )
	 throw(Error )
//: m_pSocket(pSocket), m_PlayerStatus(USPS_NONE)
: m_PlayerStatus(USPS_NONE)
{
	__BEGIN_TRY

	m_pSocket = pSocket;

	getCurrentTime(m_ExpireTime);
	m_ExpireTime.tv_sec += maxIdleSec;

	Assert(m_pInputStream == NULL);
	Assert(m_pOutputStream == NULL);

	try {
		// 소켓입력스트림은 그대로 생성해준다.
		m_pInputStream = new SocketInputStream(m_pSocket, clientBufferSize);
	} catch (Error& t) {
		filelog("updateServerPlayerBUG.txt", "%s", t.toString().c_str());
		throw;
	} catch (Throwable& t) {
		filelog("updateServerPlayerBUG.txt", "%s", t.toString().c_str());
	}

	__END_CATCH
}
Exemple #2
0
void startConnMgrWatch(HWND hWnd){
	HRESULT hr;
	hEdit=hWnd;
	if(WM_CM_STATUS_CHANGE==WM_USER+1234){	// do only once, if 1234 then not registered
		WM_CM_STATUS_CHANGE = RegisterWindowMessage( CONNMGR_STATUS_CHANGE_NOTIFICATION_MSG );
		if(WM_CM_STATUS_CHANGE==0) //failed
		{
			logMsg(L"RegisterWindowMessage failed: %i\n", GetLastError());
		}
		else
			logMsg(L"RegisterWindowMessage OK: id=%08x\n", WM_CM_STATUS_CHANGE);
		//DEBUGMSG(1, (L"RegisterWindowMessage =0x%x.\r\n", WM_CM_STATUS_CHANGE));
		//logMsg(L"RegisterWindowMessage =0x%x.\r\n", WM_CM_STATUS_CHANGE);
	}
	// after you registered for the CONNMGR_STATUS_CHANGE_NOTIFICATION_MSG and got a constant you can watch for changes
	hr = ConnMgrRegisterForStatusChangeNotification(TRUE, hWnd);
	if(hr==S_OK)
		filelog(L"ConnMgrRegisterForStatusChangeNotification OK\n");
	else if(hr==E_HANDLE)
		filelog(L"ConnMgrRegisterForStatusChangeNotification Invalid handle!\n");
	else if(hr==E_ACCESSDENIED)
		filelog(L"ConnMgrRegisterForStatusChangeNotification Access denied!\n");
	else
		filelog(L"ConnMgrRegisterForStatusChangeNotification Unknown error code: %i!\n", hr);

	return;
}
void CGSMSSendHandler::execute (CGSMSSend* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX
		
#ifdef __GAME_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer);
	Assert(pGamePlayer != NULL);

	PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pGamePlayer->getCreature());
	Assert(pPC != NULL);

	filelog("SMS.log", "[%s:%s] %s", pGamePlayer->getID().c_str(), pPC->getName().c_str(), pPacket->toString().c_str());
	GCAddressListVerify gcVerify;

	if (pPC->getSMSCharge() < pPacket->getNumbersList().size() )
	{
		filelog("SMS.log", "[%s:%s] Charge가 모자랍니다.", pGamePlayer->getID().c_str(), pPC->getName().c_str());
		gcVerify.setCode(GCAddressListVerify::SMS_SEND_FAIL);
		gcVerify.setParameter(GCAddressListVerify::SMS_SEND_FAIL_NOT_ENOUGH_CHARGE);
		pGamePlayer->sendPacket(&gcVerify);
		return;
	}

	pPC->setSMSCharge(pPC->getSMSCharge() - pPacket->getNumbersList().size());

	char buffer[100];
	sprintf(buffer, "SMSCharge=%u", pPC->getSMSCharge());
	pPC->tinysave(buffer);

	list<string>::const_iterator itr = pPacket->getNumbersList().begin();
	list<string>::const_iterator endItr = pPacket->getNumbersList().end();

	for (; itr != endItr ; ++itr )
	{
		if (SMSServiceThread::Instance().isValidNumber(*itr ) )
		{
			SMSMessage* pMsg = new SMSMessage(pPC->getName(), *itr, pPacket->getCallerNumber(), pPacket->getMessage());
			SMSServiceThread::Instance().pushMessage(pMsg);
		}
	}

	gcVerify.setCode(GCAddressListVerify::SMS_SEND_OK);
	gcVerify.setParameter(pPC->getSMSCharge());
	pGamePlayer->sendPacket(&gcVerify);

#endif
	
	__END_DEBUG_EX __END_CATCH
}
// 실행 함수
void PKTConnectAcceptHandler::execute(MPlayer* pPlayer, MPacket* pPacket )
{
	//cout << "--------------------------------------------------" << endl;
	//cout << "RECV [" << pPlayer->getJob()->getName() << "] ConnectAccept" << endl;
	//cout << "--------------------------------------------------" << endl;

	filelog(MOFUS_LOG_FILE, "RECV [%s] ConnectAccept", pPlayer->getJob()->getName().c_str());
	filelog(MOFUS_PACKET_FILE, "RECV : [%s] %s", pPlayer->getJob()->getName().c_str(), pPacket->toString().c_str());

	// 유저 인포를 요청. 파워포인트 가져오기
	pPlayer->sendUserInfo();
}
void CGCrashReportHandler::execute (CGCrashReport* pPacket , Player* pPlayer)
	throw(ProtocolException, Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __GAME_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer);

	Creature* pCreature = pGamePlayer->getCreature();

	Statement* pStmt = NULL;

	try
	{
		BEGIN_DB
		{
			pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();
			pStmt->executeQuery("INSERT INTO `CrashReportLog` (`PlayerID`, `Name`, `ReportTime`, `ExecutableTime`, `Version`, `Address`, `Message`, `OS`, `CallStack`) VALUES ('%s', '%s', now(), '%s', %u, '%s', '%s', '%s', '%s')", pGamePlayer->getID().c_str(), pCreature->getName().c_str(), pPacket->getExecutableTime().c_str(), pPacket->getVersion(), pPacket->getAddress().c_str(), pPacket->getMessage().c_str(), pPacket->getOS().c_str(), pPacket->getCallStack().c_str());

			SAFE_DELETE(pStmt);
		}
		END_DB(pStmt)
			// 누가 이상한거 날리면 무시하자
	} catch(...) { filelog("CrashReport.log", "%s", pPacket->toString().c_str()); }

#endif	// __GAME_SERVER__

    __END_DEBUG_EX __END_CATCH
}
Exemple #6
0
bool GuildUnion::removeGuild(GuildID_t gID ) throw(Error)
{
	if (m_MasterGuildID == gID ) return false;

	list<GuildID_t>::iterator itr = findGuildItr(gID);
	if (itr == m_Guilds.end() ) return false;

	m_Guilds.erase(itr);

	Statement* pStmt = NULL;

	BEGIN_DB
	{
		pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();
		pStmt->executeQuery("DELETE FROM GuildUnionMember WHERE UnionID = %u and OwnerGuildID = %u", m_UnionID, gID);
		if (pStmt->getAffectedRowCount() < 1 )
		{
			filelog("GuildUnion.log", "[%u:%u] 탈퇴하려는데 해당 레코드가 없습니다.", m_UnionID, gID);
		}

		SAFE_DELETE(pStmt);
	}
	END_DB(pStmt);

	return true;
}
Exemple #7
0
//////////////////////////////////////////////////////////////////////////////
/// \brief 
/// \param fmt 
/// \param ... 
//////////////////////////////////////////////////////////////////////////////
void XMLUtil::filelog(char* fmt, ...)
{
	ofstream file(XML_ERROR_FILENAME, ios::out | ios::app);
	if (file.is_open())
	{
		va_list valist;
		va_start(valist, fmt);
		char message_buffer[30000] = {0, };
		int nchars = vsnprintf(message_buffer, 30000, fmt, valist);
		if (nchars == -1 || nchars > 30000)
		{
			filelog(NULL, "filelog buffer overflow!");
			throw("filelog() : more buffer size needed for log");
		}
		va_end(valist);

		time_t now = time(0);
		char time_buffer[256] = {0, };
		sprintf(time_buffer, "%s : ", ctime(&now));

		file.write(time_buffer, (streamsize)strlen(time_buffer));
		file.write(message_buffer, (streamsize)strlen(message_buffer));
		file.write("\n", (streamsize)strlen("\n"));
	}
}
Exemple #8
0
void finish(struct transfer *transfer, struct trdata *data)
{
    filelog("finish %ls at %zi, total %zi", transfer->path, transfer->curpos, transfer->curpos - data->startpos);
#ifdef HAVE_XATTR
    if(confgetint("reqstat", "xa"))
	xainc(transfer->path, "user.dc-bytes", transfer->curpos - data->startpos);
#endif
}
// 실행 함수
void PKTUserInfoHandler::execute(GameServerPlayer* pPlayer, MPacket* pPacket )
{
	//cout << "--------------------------------------------------" << endl;
	//cout << "RECV UserInfo" << endl;
	//cout << "--------------------------------------------------" << endl;

	filelog(MOFUS_LOG_FILE, "RECV UserInfo");
	filelog(MOFUS_PACKET_FILE, "RECV : %s", pPacket->toString().c_str());

	PKTPowerPoint pkt;
	strcpy(pkt.sCharName, "슬11");
	pkt.nPowerPoint = 300;
	pkt.nContinue = rand() % 2;
	pkt.nOnGameCode = 1;
	//cout << "sending PowerPoint : " << endl << pkt.toString() << endl;
	pPlayer->sendPacket(&pkt);
}
Exemple #10
0
void request(struct transfer *transfer, struct trdata *data)
{
    filelog("request %ls", transfer->path);
#ifdef HAVE_XATTR
    if(confgetint("reqstat", "xa"))
	xainc(transfer->path, "user.dc-req", 1);
#endif
}
Exemple #11
0
void start(struct transfer *transfer, struct trdata *data)
{
    filelog("start %ls at %zi", transfer->path, data->startpos);
#ifdef HAVE_XATTR
    if(confgetint("reqstat", "xa"))
	xainc(transfer->path, "user.dc-started", 1);
#endif
}
Exemple #12
0
// 패킷의 크기를 반환한다.
MPacketSize_t MPacketManager::getPacketSize(MPacketID_t ID ) const
{
	if (ID < 0 || ID >= PTC_SEND_MAX )
	{
		filelog(MOFUS_ERROR_FILE, "MPacketManager::createPacket() out of ID");
		Assert(false);
	}

	return m_pImpl->pCreators[ID]->getSize();
}
Exemple #13
0
// 패킷을 실행한다.
void MPacketManager::execute(GameServerPlayer* pPlayer, MPacket* pPacket )
{
	Assert(pPlayer != NULL);
	Assert(pPacket != NULL);

	MPacketID_t ID = pPacket->getID();

	if (ID < 0 || ID >= PTC_SEND_MAX )
	{
		filelog(MOFUS_ERROR_FILE, "MPacketManager::createPacket() out of ID");
		Assert(false);
	}

	if (m_pImpl->pHandlers[ID] == NULL )
	{
		filelog(MOFUS_ERROR_FILE, "MPacketManager::execute() Handler is NULL");
		Assert(false);
	}

	m_pImpl->pHandlers[ID]->execute(pPlayer, pPacket);
}
//////////////////////////////////////////////////////////////////////////////
// 머리위에 GlobalChat 스트링을 띄울때 사용하는 패킷이다.
// 이 크리처를 볼 수 있는 모든 플레이어에게 브로드캐스트한다.
// 일단은 현재 존의 모든 플레이어(또는 전체 플레이어)에게 
// GCGlobalChat 패킷을 브로드캐스트한다.
//////////////////////////////////////////////////////////////////////////////
void CGGlobalChatHandler::execute (CGGlobalChat* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX
		
#ifdef __GAME_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer);

	if (pGamePlayer->getPlayerStatus() == GPS_NORMAL) {

		if (pGamePlayer->isPenaltyFlag(PENALTY_TYPE_MUTE)) {
			return;
		}
		Creature* pCreature = pGamePlayer->getCreature();

		Assert(pCreature != NULL);

		// 서버에서 클라이언트로 전송하므로 GC- 패킷을 사용해야 한다.
		GCGlobalChat gcGlobalChat;

		uint i = pPacket->getMessage().find_first_of('*' , 0);

		if (i == 0) return;

		// text color setting
		gcGlobalChat.setColor(pPacket->getColor());

		// 크리처 이름과 메시지를 패킷에 대입한다.
		StringStream msg;
		msg << pCreature->getName() << " " << pPacket->getMessage();
	
		gcGlobalChat.setMessage(msg.toString());
		gcGlobalChat.setRace(pCreature->getRace());
	
		// 주변 PC들에게 브로드캐스트한다.
		pCreature->getZone()->broadcastPacket(&gcGlobalChat , pCreature);


		// 채팅 로그를 남긴다. by sigi. 2002.10.30
		if (LogNameManager::getInstance().isExist(pCreature->getName() ))
		{
			filelog("chatLog.txt", "[Global] %s> %s", pCreature->getName().c_str(), pPacket->getMessage().c_str());
		}
	}
	
#endif
		
	__END_DEBUG_EX __END_CATCH
}
void NetmarbleGuildRegisterThread::run() throw(Error) {
    __BEGIN_DEBUG

    string host = g_pConfig->getProperty("DB_HOST");
    string db = g_pConfig->getProperty("DB_DB");
    string user = g_pConfig->getProperty("DB_USER");
    string password = g_pConfig->getProperty("DB_PASSWORD");

    Connection* pConnection = new Connection(host, db, user, password);
    g_pDatabaseManager->addConnection((int)Thread::self(), pConnection);
    //cout << "******************************************************" << endl;
    //cout << " THREAD CONNECT DB " << endl;
    //cout << "******************************************************" << endl;

    // create PLAYER Database Connection
    string dist_host = g_pConfig->getProperty("UI_DB_HOST");
    string dist_db = "DARKEDEN";
    string dist_user = g_pConfig->getProperty("UI_DB_USER");
    string dist_password = g_pConfig->getProperty("UI_DB_PASSWORD");

    Connection* pDistConnection = new Connection(dist_host, dist_db, dist_user, dist_password);
    g_pDatabaseManager->addDistConnection(((int)Thread::self()), pDistConnection);
    //cout << "******************************************************" << endl;
    //cout << " THREAD CONNECT UIIRIBUTION DB " << endl << " TID Number = " << (int)Thread::self() << endl;
    //cout << "******************************************************" << endl;

    Py_Initialize();

    PyRun_SimpleString("import httdlib, urllib");

    try {
        Timeval dummyQueryTime;
        getCurrentTime(dummyQueryTime);

        while (true) {
            // ±æµå µî·Ï
            registerGuild();

            // for context switch
            usleep(100);
        }
    }
    catch (Throwable& t) {
        filelog("NetmarbleGuildRegisterThread.log", "%s", t.toString().c_str());
        throw;
    }

    Py_Finalize();

    __END_DEBUG
}
Exemple #16
0
// 패킷 생성자를 추가한다.
void MPacketManager::IMPL::addCreator(MPacket* pPacket )
{
	Assert(pPacket != NULL);

	// 중복 검사
	if (pCreators[pPacket->getID()] != NULL )
	{
		filelog(MOFUS_ERROR_FILE, "MPacketManager::IMPL::addCreator() dup creator");
		Assert(false);
	}
	
	// 생성자를 추가한다.
	pCreators[pPacket->getID()] = pPacket;
}
Exemple #17
0
// 패킷 핸들러를 추가한다.
void MPacketManager::IMPL::addHandler(MPacketHandler* pHandler )
{
	Assert(pHandler != NULL);

	// 중복 검사
	if (pHandlers[pHandler->getID()] != NULL )
	{
		filelog(MOFUS_ERROR_FILE, "MPacketManager::IMPL::addHandler() dup handler");
		Assert(false);
	}

	// 핸들러를 추가한다.
	pHandlers[pHandler->getID()] = pHandler;
}
Exemple #18
0
//////////////////////////////////////////////////////////////////////////////
// 생성자
// 마스크를 초기화한다.
//////////////////////////////////////////////////////////////////////////////
IceWave::IceWave()
	    throw()
{
	__BEGIN_TRY

	int index=0;

	for (int i=-3; i<=3; ++i )
	{
		for (int j=-3; j<=3; ++j )
		{
			filelog("IceWave.log", "%d:(%d,%d)", index, i, j);
			m_pIceWaveMask[index++].set(i, j);
		}
	}

	for (int i=0; i<8; ++i )
	{
		for (int j=1; j<=2; ++j )
		{
			int ox = dirMoveMask[i].x * j * 3 + dirMoveMask[i].x * 2;
			int oy = dirMoveMask[i].y * j * 3 + dirMoveMask[i].y * 2;

			for (int k=-1; k<=1; ++k )
			{
				for (int l=-1; l<=1; ++l )
				{
					filelog("IceWave.log", "%d:(%d,%d)", index, ox+k, oy+l);
					m_pIceWaveMask[index++].set(ox+k, oy+l);
				}
			}
		}
	}

	__END_CATCH
}
Exemple #19
0
GQuestElement::ResultType GQuestStatus::checkElements(GQuestInfo::ElementType type)
{
	switch (m_pGQuestInfo->getCheckType(type) )
	{
		case GQuestInfo::SEQUENCE:
			return checkElementsSEQ(type);
		case GQuestInfo::AND:
			return checkElementsAND(type);
		case GQuestInfo::OR:
			return checkElementsOR(type);
		default:
			filelog("GQuestBug.log", "%u - GQuestStatus::checkElements(%u) : Invalid checkType : %d", m_pGQuestInfo->getQuestID(), type, m_pGQuestInfo->getCheckType(type));
			Assert(false);
	}

	return GQuestElement::FAIL;
}
Exemple #20
0
//////////////////////////////////////////////////////////////////////////////
// Destructor
//////////////////////////////////////////////////////////////////////////////
Creature::~Creature () 
    throw()
{
	__BEGIN_TRY

	m_pPlayer = NULL;	// delete´Â ¿ÜºÎ¿¡¼­ ÇÑ´Ù.
	SAFE_DELETE(m_pEffectManager);

	if (m_CClass == CREATURE_CLASS_SLAYER || m_CClass == CREATURE_CLASS_VAMPIRE )
	{
		if (!m_bDeriveDestructed )
		{
			filelog("destructor.log", "Name : %s Class : %d value : %d" , m_Owner.c_str(), (int)m_CClass, m_Value);
		}
	}

	__END_CATCH
}
Exemple #21
0
void logMsg (const wchar_t *fmt, ...)
{
        va_list vl;
        va_start(vl,fmt);
        wchar_t bufW[1024]; // to bad CE hasn't got wvnsprintf
        wvsprintf(bufW,fmt,vl);
        char bufOutA[512];

		filelog(L"%s", bufW);

		//convert to char
        WideCharToMultiByte(CP_ACP,0,bufW,-1,bufOutA,400, NULL, NULL);

		if(hEdit){
			int iLen = PostMessage(hEdit, WM_GETTEXTLENGTH, 0, 0);
			iLen+=wcslen(bufW);
			if(iLen>32000)
			{
				//clear text
				PostMessage(hEdit,WM_SETTEXT,0,0);
				iLen=wcslen(bufW);
				PostMessage(hEdit, WM_SETTEXT, NULL, (LPARAM)bufW);
			}
			else{
				TCHAR* buffer=(TCHAR*)calloc((2+iLen), sizeof(TCHAR));
				PostMessage(hEdit,WM_GETTEXT, iLen * sizeof(TCHAR), reinterpret_cast<LPARAM>(buffer));
				wcscat(buffer, bufW);
				//DEBUGMSG(1, (buffer));
				//addText(hEdit, bufW);
				PostMessage(hEdit, WM_SETTEXT, NULL, (LPARAM)buffer);
				free (buffer);
			}
			PostMessage(hEdit, EM_SETSEL, 0, MAKELONG(0xffff,0xffff));
			PostMessage(hEdit, EM_SCROLLCARET, 0,0);
			UpdateWindow(hEdit);
		}

#ifdef DEBUG
		DEBUGMSG(1, (bufW));
#else
		RETAILMSG(1, (bufW));
#endif
}
Exemple #22
0
void dumpConnections(HWND hWnd){
	hEdit=hWnd;

	HANDLE hConnMgrReady = ConnMgrApiReadyEvent();
	DWORD dwWait = WaitForSingleObject(hConnMgrReady, 3000);
	switch (dwWait){
		case WAIT_OBJECT_0:
			break;
		case WAIT_FAILED:
			break;
		case WAIT_ABANDONED:
			break;
		default:
			break;
	}
	CloseHandle(hConnMgrReady);

	filelog(L"dumpConnections...\n");

	CONNMGR_CONNECTION_DETAILED_STATUS* pStatusBuffer=NULL;
	DWORD dwBufferSize=0;
	HRESULT hResult=0;
	//query the needed buffer size
	hResult = ConnMgrQueryDetailedStatus(NULL, &dwBufferSize);
	if(hResult==(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)))
	{
		BYTE* bv = (BYTE*) malloc(dwBufferSize);
		CONNMGR_CONNECTION_DETAILED_STATUS *s= (CONNMGR_CONNECTION_DETAILED_STATUS*)&bv[0];
		hResult= ConnMgrQueryDetailedStatus(s, &dwBufferSize);

		for (CONNMGR_CONNECTION_DETAILED_STATUS *p= s ; p ; p= p->pNext)
		{
		   dump_details(p);
		}
		free(pStatusBuffer);
		free(bv);
	}
}
bool ActionRedeemMotorcycle::load(Item* pItem, Slayer* pSlayer, Zone* pZone, ZoneCoord_t x, ZoneCoord_t y) const
	throw()
{
	bool bFound = false;

	__BEGIN_TRY

	// 단서가 되는 아이템이 키가 아니라면 false를 리턴.
	if (pItem->getItemClass() != Item::ITEM_CLASS_KEY) return false;

	Key* pKey = dynamic_cast<Key*>(pItem);
	ItemID_t   targetID = pKey->getTarget();

	try {

	// 키가 맞다면 키의 타겟이 되는 아이템의 아이템 ID를 얻어낸다.
	Statement* pStmt    = NULL;
	Result*    pResult  = NULL;

	// targetID가 0인 경우는.. targetID(motorcycleObject의 ItemID)가 설정이 안된 경우다.
	// 이 때는 임시로 targetID를 key의 ItemID와 같게 하면 된다...고 본다.
	// targetID가 motorcycle의 itemID로 들어가기 때문에..
	// broadcasting 등에서.. Assert()에 의해서 다운되었다...고 보여진다.  - -;
	// by sigi. 2002.12.25 x-mas T_T;
	if (targetID==0)
	{
		targetID = pKey->setNewMotorcycle(pSlayer);
/*		// (!) MotorcycleObject를 생성하고 MotorcycleItemID==Target를 받아야 한다.
		// 이 코드 제발 함수로 빼기를.. -_-; by sigi
		list<OptionType_t> optionNULL;
		Item* pMotorcycle = g_pItemFactoryManager->createItem(Item::ITEM_CLASS_MOTORCYCLE, 0, optionNULL);
		Assert(pMotorcycle != NULL);
		(pZone->getObjectRegistry()).registerObject(pMotorcycle);

		pMotorcycle->create(pSlayer->getName(), STORAGE_ZONE, pZone->getZoneID(), pSlayer->getX(), pSlayer->getY());
		pKey->setTarget(pMotorcycle->getItemID());

		targetID = pMotorcycle->getItemID();

		// targetID를 DB에도 update시켜야 한다.
		BEGIN_DB
		{
			pStmt   = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();
			pResult = pStmt->executeQuery(
						"UPDATE KeyObject SET Target=%d WHERE ItemID=%d", 
									targetID, pKey->getItemID());

			SAFE_DELETE(pStmt);
		}
		END_DB(pStmt)

		// 밑에서 pMotorcycle을 사용해도 되겠지만, 기존 코드 안 건드릴려고 여기서 지운다. 
		SAFE_DELETE(pMotorcycle);*/
	}
	else
	{
		// 한번 모터사이클이랑 키랑 연결됐는데 모터사이클을 누가 자꾸 지우나보다.
		// 키에 연결된 모터사이클이 실제로 디비에 있는지 체크하고 없으면 새로 만들어서 넣어준다.
		BEGIN_DB
		{
			pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();
			pResult = pStmt->executeQuery("SELECT ItemID FROM MotorcycleObject WHERE ItemID=%lu", targetID);

			if (!pResult->next() )
			{
				Key* pKey = dynamic_cast<Key*>(pItem);
				Assert(pKey != NULL);

				targetID = pKey->setNewMotorcycle(pSlayer);
			}

			SAFE_DELETE(pStmt);
		}
		END_DB(pStmt);
	}

	
	// 필살 방어 코드 -_-;
	if (targetID==0)
	{
		filelog("errorLog.txt", "[ActionRedeemMotorcycle] itemID=%d, motorItemID=%d", (int)pItem->getItemID(), (int)targetID);
		return false;
	}

	// DB에 쿼리하기 전에 먼저 객체가 생성되어 있지는 않은지 체크한다.
	if (g_pParkingCenter->hasMotorcycleBox(targetID)) 
	{
		// 자꾸 다운되어서 혹시나 하고..
		// 일단 주석처리한다.  by sigi. 2002.11.16
		/*
		if (!pSlayer->hasRideMotorcycle()
			&& !pSlayer->isFlag(Effect::EFFECT_CLASS_COMA))
		{
			//return false;

			// by sigi. 2002.11.14
			MotorcycleBox* pMotorcycleBox = g_pParkingCenter->getMotorcycleBox(targetID);

			// 있다면 소환한다.
			if (pMotorcycleBox!=NULL
				&& !pMotorcycleBox->isTransport())
			{
				Zone* pMotorZone = pMotorcycleBox->getZone();
				ZoneCoord_t motorX = pMotorcycleBox->getX();
				ZoneCoord_t motorY = pMotorcycleBox->getY();
				Motorcycle* pMotorcycle = pMotorcycleBox->getMotorcycle();

				// 같은 존에 있는 경우
				// 거리가 너무 가까우면 부르지 말자~
				if (pMotorZone!=pZone
					|| pSlayer->getDistance(motorX, motorY) > 15)
				{
					// 다른 zone으로 이동중이라고 표시한다.
					pMotorcycleBox->setTransport();

					// motorcycle을 slayer의 zone으로 옮긴다.
					pMotorZone->transportItem(motorX, motorY, pMotorcycle, 
												pZone, pSlayer->getX(), pSlayer->getY());

					// Use OK 대용이다.
					// Use하면 아이템이 사라지던가 그렇지 싶다. - -;
					//GCCannotUse _GCCannotUse;
					//_GCCannotUse.setObjectID(pPacket->getObjectID());
					//pGamePlayer->sendPacket(&_GCCannotUse);

					// 한동안 delay를 줘야하는데..
				}
			}

			return true;
		}
		*/

		return false;
	}

	ItemID_t     itemID;
	ItemType_t   itemType;
	string 		 optionType;
	Durability_t durability;

	BEGIN_DB
	{
		StringStream sql;
		sql << "SELECT ItemID, ItemType, OptionType, Durability "
		    << "FROM MotorcycleObject where ItemID = " << targetID;
		
		pStmt   = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();
		pResult = pStmt->executeQuery(sql.toString());

		// by sigi. 2002.10.14
		// 결과물이 없다면 모터사이클이 없는 거쥐.
		if (pResult->getRowCount() <= 0) 
		{
			bFound = false;

			itemID     = targetID;
			itemType   = 0;
			optionType = "";
			durability = 300;
		}
		else 
		{
			bFound = true;

			pResult->next();

			itemID     = pResult->getInt(1);
			itemType   = pResult->getInt(2);
			optionType = pResult->getString(3);
			durability = pResult->getInt(4);
		}


			// 모터사이클 객체를 생성한다.
			list<OptionType_t> optionTypes;
			setOptionTypeFromField(optionTypes, optionType);
			Motorcycle* pMotorcycle = new Motorcycle(itemType, optionTypes);

			Assert(pMotorcycle != NULL);

			pMotorcycle->setItemID(itemID);
			pMotorcycle->setDurability(durability);

			// 존에다 붙이기 전에 oid를 새로 할당받는다.
			(pZone->getObjectRegistry()).registerObject(pMotorcycle);
			
			// 생성한 모터사이클을 존에다 갖다붙인다.
			TPOINT pt = pZone->addItem(pMotorcycle, x, y, false);
			if (pt.x == -1)
			{
				// 오토바이를 존에다 더할 수 없었다. 씨바.
				filelog("motorError.txt", "ActionRedeemMotorcycle::load() : 모터사이클을 존에다 더할 수 없습니다. zoneID=%d, xy=(%d, %d)", (int)pZone->getZoneID(), (int)x, (int)y);	// by sigi. 2002.12.24
				throw Error("ActionRedeemMotorcycle::load() : 모터사이클을 존에다 더할 수 없습니다");
			}
			
			// by sigi. 2002.10.14
			if (!bFound)
			{
				pStmt->executeQuery(
				"INSERT IGNORE INTO MotorcycleObject (ItemID, ObjectID, ItemType, OwnerID, Storage, StorageID, X, Y, OptionType, Durability) Values (%d, %d, %d, '', %d, %d, %d, %d, '', %d)",
					itemID, pMotorcycle->getObjectID(), itemType, STORAGE_ZONE, pZone->getZoneID(), pt.x, pt.y, durability);
			}

			// 모터사이클을 뻑킹 센터에 등록해준다.
			MotorcycleBox* pBox = new MotorcycleBox(pMotorcycle, pZone, pt.x, pt.y);
			Assert(pBox != NULL);

			try {
				g_pParkingCenter->addMotorcycleBox(pBox);
			} catch (DuplicatedException& de) {	// by sigi. 2002.12.24
				filelog("motorError.txt", "%s - itemID=%d, motorid=%d", de.toString().c_str(), itemID, pMotorcycle->getObjectID());
			}

			bFound = true;
		//}
		
		SAFE_DELETE(pStmt);
	}
	END_DB(pStmt)

	} catch (Throwable& t) {	// by sigi. 2002.12.25
		filelog("motorError.txt", "%s - itemID=%d, motorItemID=%d", t.toString().c_str(), (int)pItem->getItemID(), (int)targetID);
		// 일단 다운은 막자.
		//throw;
	}

	__END_CATCH

	return bFound;
}
Exemple #24
0
//----------------------------------------------------------------------
// remove effect from target
//----------------------------------------------------------------------
void EffectDecayItem::unaffect (Zone* pZone , ZoneCoord_t x , ZoneCoord_t y , Object* pTarget)
	throw(Error)
{
	__BEGIN_TRY

	// 올바른 좌표이어야 한다.
	Assert(isValidZoneCoord(pZone, x, y));

	// TempItem 변수를 잡는다.
	Item* pTempItem = NULL;

	// 여기서는 지정 아이템이 없을 수 있으며, 또 다른 아이템이 놓여 있을 수도 있다.
	// 이 경우는 오리지널 아이템과 지금 현재 바닥에 있는 아이템을 비교하여 삭제해야 한다.
	// 없을 경우는 무시하면 된다.
	Tile & tile = pZone->getTile(x, y);

	if (tile.hasItem()) {

		pTempItem = tile.getItem();

		if (pTempItem != NULL) {
			// ObjectID가 같다는 말은 같은 아이템이란 말이다.
			//if (pTempItem->getObjectID() == m_ObjectID) {
			if (pTempItem->getObjectID() == m_ObjectID) {

				pZone->deleteItem(pTempItem , x, y);

				// 아이템이 사라졌다는 패킷을 날린다.
				GCDeleteObject gcDeleteObject;
				gcDeleteObject.setObjectID(m_ObjectID);

				pZone->broadcastPacket(x, y , &gcDeleteObject);

				if (m_bDeleteFromDB)
				{
					//ItemInfo* pItemInfo = g_pItemInfoManager->getItemInfo(pTempItem->getItemClass(), pTempItem->getItemType());
					//Assert(pItemInfo!=NULL);

					// 유니크 아이템인 경우 개수를 줄인다.
					if (pTempItem->isUnique())
					{
						// create한 아이템이 아닌 경우만 지워준다.
						if (pTempItem->getCreateType()!=Item::CREATE_TYPE_CREATE)
							UniqueItemManager::deleteItem(pTempItem->getItemClass(), pTempItem->getItemType());

						filelog("uniqueItem.txt", "[EffectDecayItem] %s", pTempItem->toString().c_str());
					}

					// ItemTraceLog 를 남긴다
					/*
					 * 존에 떨어진 아이템중 expire time인것들 모두 로그를 빼버린다.
					if (pTempItem != NULL && pTempItem->isTraceItem() )
					{
						char zoneName[15];
						sprintf(zoneName, "%4d%3d%3d", pZone->getZoneID(), x, y);
						remainTraceLog(pTempItem, zoneName, "GOD", ITEM_LOG_DELETE, DETAIL_TIMEOUT);
					}
					*/

					// 돈 로그 남기자
					if (pTempItem->getItemClass() == Item::ITEM_CLASS_MONEY )
					{
						Money* pMoney = dynamic_cast<Money*>(pTempItem);
						if (pMoney->getAmount() >= g_pVariableManager->getMoneyTraceLogLimit() )
						{
							char zoneName[15];
							sprintf(zoneName, "%4d%3d%3d", pZone->getZoneID(), x, y);
							remainMoneyTraceLog(zoneName, "GOD", ITEM_LOG_DELETE, DETAIL_TIMEOUT, pMoney->getAmount());
						}
					}

					pTempItem->destroy();
				}

				SAFE_DELETE(pTempItem);
			}
		}
	}

	pTarget = NULL;

	__END_CATCH
}
void CGDisplayItemHandler::execute (CGDisplayItem* pPacket , Player* pPlayer)
	 throw(Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX
		
#ifdef __GAME_SERVER__
	
//#ifndef __TEST_SERVER__
//	return;
//#endif

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer);
	Assert(pGamePlayer != NULL);

	PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pGamePlayer->getCreature());
	Assert(pPC != NULL);

	Inventory* pInventory = pPC->getInventory();
	Assert(pInventory != NULL);

	Store* pStore = pPC->getStore();
	Assert(pStore != NULL);

	GCSystemMessage errorMsg;
	GCNoticeEvent errorNotice;

	if (pPacket->getIndex() > MAX_ITEM_NUM )
	{
		filelog("Store.log", "[%s:%s] (%u) 잘못된 인덱스입니다.",
				pGamePlayer->getID().c_str(), pPC->getName().c_str(), pPacket->getIndex());
		return;
	}

	if (pPacket->getX() >= pInventory->getWidth() || pPacket->getY() >= pInventory->getHeight() )
	{
		filelog("Store.log", "[%s:%s] (%u,%u) 인벤토리 좌표를 잘못 보내줬습니다..",
				pGamePlayer->getID().c_str(), pPC->getName().c_str(), pPacket->getX(), pPacket->getY());
		return;
	}

	Item* pItem = pInventory->getItem(pPacket->getX(), pPacket->getY());
	if (pItem == NULL || pItem->getObjectID() != pPacket->getItemObjectID() )
	{
		filelog("Store.log", "[%s:%s] (%u, %u) : %u 아이템 좌표가 잘못되었거나 오브젝트 아이디가 잘못되었습니다.",
				pGamePlayer->getID().c_str(), pPC->getName().c_str(), pPacket->getX(), pPacket->getY(), pPacket->getItemObjectID());
		return;
	}

	if (pPC->getZone()->getTradeManager()->getTradeInfo(pPC->getName() ) != NULL )
	{
		filelog("Store.log", "[%s:%s] : 거래중에는 물건을 올려놓을 수 없습니다.",
				pGamePlayer->getID().c_str(), pPC->getName().c_str());
		return;
	}

	if (pStore->hasItem(pItem ) )
	{
		filelog("Store.log", "[%s:%s] (%u, %u) 이미 아이템이 상점에 있습니다.",
				pGamePlayer->getID().c_str(), pPC->getName().c_str(), pItem->getObjectID(), pPacket->getIndex());
//		errorMsg.setMessage("이미 진열된 아이템입니다.");
		errorNotice.setCode(NOTICE_EVENT_ALREADY_DISPLAYED);
		pGamePlayer->sendPacket(&errorNotice);
		return;
	}

	if (pItem->isTimeLimitItem() || !canSell(pItem ) || !canTrade(pItem ) || !canTradeInventoryItem(pItem ) )
	{
		filelog("Store.log", "[%s:%s] (%s) 팔 수 없는 아이템입니다.",
				pGamePlayer->getID().c_str(), pPC->getName().c_str(), pItem->toString().c_str());
//		errorMsg.setMessage("판매할 수 없는 아이템입니다.");
		errorNotice.setCode(NOTICE_EVENT_CANNOT_SELL);
		pGamePlayer->sendPacket(&errorNotice);
		return;
	}

	BYTE result = pStore->setStoreItem(pPacket->getIndex(), pItem, pPacket->getPrice());
	if ( result != 0 )
	{
		filelog("Store.log", "[%s:%s] (%u) 아이템을 놓을 수 없습니다.",
				pGamePlayer->getID().c_str(), pPC->getName().c_str(), result);
		return;
	}

	GCMyStoreInfo gcInfo;
	gcInfo.setStoreInfo(&(pStore->getStoreInfo()));
	pGamePlayer->sendPacket(&gcInfo);

	if (pStore->isOpen() )
	{
		GCAddStoreItem gcAdd;
		gcAdd.setOwnerObjectID(pPC->getObjectID());
		gcAdd.setIndex(pPacket->getIndex());
		pStore->getStoreItem(pPacket->getIndex() ).makeStoreItemInfo(gcAdd.getItem());
		pPC->getZone()->broadcastPacket(pPC->getX(), pPC->getY(), &gcAdd, pPC);
	}

#endif	// __GAME_SERVER__
		
	__END_DEBUG_EX __END_CATCH
}
Exemple #26
0
void CLLoginHandler::execute (CLLogin* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX
		
#ifdef __LOGIN_SERVER__

	Assert(pPacket != NULL);
	Assert(pPlayer != NULL);

	//cout << pPacket->toString().c_str() << endl;

	LoginPlayer* pLoginPlayer = dynamic_cast<LoginPlayer*>(pPlayer);
	Statement*   pStmt        = NULL;

	// 좌우 공백 제거. by sigi. 2002.12.6
	pPacket->setID(trim(pPacket->getID()));

	string          connectIP            = pLoginPlayer->getSocket()->getHost();
	string			connectMAC			 = pPacket->getMacAddress();
	string          ID                   = pPacket->getID();

	// MAC address setting
	pLoginPlayer->setMacAddress(pPacket->getRareMacAddress());

	bool bFreePass = false;	//by sigi. 2002.10.23j

	// web login
	bool bWebLogin = pPacket->isWebLogin();
//	static bool bWebLogin = g_pConfig->getPropertyInt("WebLogin") != 0;

	// set web login player
	if (bWebLogin ) 
		pLoginPlayer->setWebLogin();

//	cout << pPacket->toString() << endl;

	if (isBlockIP(connectIP) )
	{
		LCLoginError lcLoginError;
		lcLoginError.setErrorID(IP_DENYED);
		pLoginPlayer->sendPacket(&lcLoginError);

		filelog("loginfail.txt", "Error Code: IP_DENYED, 1, PlayerID : %s", pPacket->getID().c_str());
		return;
	}

	// 사내테스트 버전에서는 '#sigi'  <-- 이런 식으로 계정이 들어온다.
	if (ID[0]==SYMBOL_TEST_CLIENT)
	{
		ID = ID.c_str()+1;
		pPacket->setID(ID);

		// 웹 로그인 체크
		if (bWebLogin )
		{
			//cout << "WebLogin" << endl;

			if (!checkWebLogin(pPacket, pPlayer ) )
			{
				return;
			}
			//else
				//cout << "Web Login OK" << endl;
		}
		else
		{
			//cout << "not WebLogin" << endl;

			// 넷마블에서 접속하는 경우
			// by sigi. 2002.10.23
			if (!checkNetMarbleClient(pPacket, pPlayer ))
			{
				return;
			}
		}
	
		bFreePass = pLoginPlayer->isFreePass();
		if (!bWebLogin && bFreePass)
		{
			// 웹로그인이 아닌 FreePass 는 넷마블 사용자로 ID 앞에 예약문자가 하나더 있다.
			ID = ID.c_str()+1;
			pPacket->setID(ID);
		}

//		cout << "테스트 클라이언트" << endl;
		BEGIN_DB
		{
			// 증거를 남긴다.
			pStmt = g_pDatabaseManager->getConnection("DARKEDEN")->createStatement();
			pStmt->executeQuery(
				"INSERT INTO TestClientUser (PlayerID, IP, LoginDate) VALUES ('%s', '%s', now())", 
				ID.c_str(), connectIP.c_str());

			SAFE_DELETE(pStmt);
		} 
		END_DB(pStmt)
	}
////////////////////////////////////////////////////////////////////////////////
// 액션을 실행한다.
////////////////////////////////////////////////////////////////////////////////
void ActionTradeGiftBox::execute(Creature * pCreature1 , Creature * pCreature2) 
	throw(Error)
{
	__BEGIN_TRY

	Assert(pCreature1 != NULL);
	Assert(pCreature2 != NULL);
	Assert(pCreature1->isNPC());
	Assert(pCreature2->isPC());

	PlayerCreature* pPC = dynamic_cast<PlayerCreature*>(pCreature2);
	Assert(pPC != NULL);

	Player* pPlayer = pPC->getPlayer();
	Assert(pPlayer != NULL);

	Inventory* pInventory = pPC->getInventory();
	Assert(pInventory != NULL);

	Zone* pZone = pPC->getZone();
	Assert(pZone != NULL);

	FlagSet* pFlagSet = pPC->getFlagSet();

	Item::ItemClass ItemClass;
	ItemType_t		ItemType;
	OptionType_t	OptionType;

	Item*			pItem;
	Item*			pGiftBoxItem;

	// 이미 선물을 교환해 갔다면
	if (pFlagSet->isOn(FLAGSET_TRADE_GIFT_BOX_2002_12 ) )
	{
		GCNPCResponse response;
		response.setCode(NPC_RESPONSE_TRADE_GIFT_BOX_ALREADY_TRADE);
		pPlayer->sendPacket(&response);

		GCNPCResponse quit;
		quit.setCode(NPC_RESPONSE_QUIT_DIALOGUE);
		pPlayer->sendPacket(&quit);

		return;
	}

	// 빨간 선물 상자가 있는지 확인한다.
	CoordInven_t X,Y;
	pGiftBoxItem = pInventory->findItem(Item::ITEM_CLASS_EVENT_GIFT_BOX, 1, X, Y);
	if (pGiftBoxItem == NULL )
	{
		GCNPCResponse response;
		response.setCode(NPC_RESPONSE_TRADE_GIFT_BOX_NO_ITEM);
		pPlayer->sendPacket(&response);

		GCNPCResponse quit;
		quit.setCode(NPC_RESPONSE_QUIT_DIALOGUE);
		pPlayer->sendPacket(&quit);

		return;
	}

	LuaSelectItem*	pLuaSelectItem = NULL;
	string			luaFileName;

	if (pPC->isSlayer() )
	{
		// 루아에 슬레이어 능력치의 합을 set한다.
		Slayer* pSlayer = dynamic_cast<Slayer*>(pPC);
		Assert(pSlayer != NULL);

		Attr_t sum = pSlayer->getSTR(ATTR_BASIC )
				   + pSlayer->getDEX(ATTR_BASIC )
				   + pSlayer->getINT(ATTR_BASIC);

		m_pLuaSlayerItem->setSum(sum);
		pLuaSelectItem = m_pLuaSlayerItem;
		luaFileName = m_SlayerFilename;

	}
	else if (pPC->isVampire() )
	{
		// 루아에 뱀파이어의 레벨을 set한다.
		Vampire* pVampire = dynamic_cast<Vampire*>(pPC);
		Assert(pVampire != NULL);

		int level = pVampire->getLevel();
		m_pLuaVampireItem->setLevel(level);
		pLuaSelectItem = m_pLuaVampireItem;
		luaFileName = m_VampireFilename;
	}

	//--------------------------------------------------------
	// 속도 체크를 위해서 1000번 돌려보는 코드
	// 결과는.. 0.07초 정도 나왔다. 감덩~ -_-;
	/*
	Timeval beforeTime;
	getCurrentTime(beforeTime);

	for (int i=0; i<1000; i++)
	{
		// 루아의 계산 결과를 받아 아이템을 생성한다.
		pLuaSelectItem->prepare();
		
		int result = pLuaSelectItem->executeFile(luaFileName);
		LuaState::logError(result);
		pLuaSelectItem->clear();
	}

	Timeval afterTime;
	getCurrentTime(afterTime);

	cout << "luaExecute time before : " << beforeTime.tv_sec  << "." << beforeTime.tv_usec << endl;
	cout << "luaExecute time after  : " << afterTime.tv_sec  << "." << afterTime.tv_usec << endl;
	*/
	//--------------------------------------------------------

	// 루아의 계산 결과를 받아 아이템을 생성한다.
	pLuaSelectItem->prepare();
	
	int result = pLuaSelectItem->executeFile(luaFileName);
	LuaState::logError(result);

	ItemClass 	= pLuaSelectItem->getItemClass();
	ItemType  	= pLuaSelectItem->getItemType();
	OptionType	= pLuaSelectItem->getOptionType();

	pLuaSelectItem->clear();

	if(ItemClass >= Item::ITEM_CLASS_MAX )
	//||  ItemType  >= ITEM_TYPE_MAX || ItemType  < 0
	//	|| OptionType == 0)
	{
		filelog("XMasEventError.txt", "[ ItemInfo Error ] : ItemClass = %d , ItemType = %d , OptionType = %d", ItemClass, ItemType, OptionType);

		GCNPCResponse quit;
		quit.setCode(NPC_RESPONSE_QUIT_DIALOGUE);
		pPlayer->sendPacket(&quit);

		return;
	}

	// 클라이언트에 선물상자를 지우도록 한다.
	GCDeleteInventoryItem gcDeleteInventoryItem;
	gcDeleteInventoryItem.setObjectID(pGiftBoxItem->getObjectID());
	pPlayer->sendPacket(&gcDeleteInventoryItem);

	// 선물상자를 지운다.
	pInventory->deleteItem(X, Y);
	// ItemTraceLog 를 남긴다
	if (pGiftBoxItem != NULL && pGiftBoxItem->isTraceItem() )
	{
		remainTraceLog(pGiftBoxItem, pCreature2->getName(), pCreature1->getName(), ITEM_LOG_DELETE, DETAIL_EVENTNPC);
	}
	pGiftBoxItem->destroy();
	SAFE_DELETE(pGiftBoxItem);


	// 선물(Item)을 만든다.
	list<OptionType_t> optionTypeList;
	if (OptionType != 0 )
		optionTypeList.push_back(OptionType);

	pItem = g_pItemFactoryManager->createItem(ItemClass, ItemType, optionTypeList);
	Assert(pItem != NULL);


	// 선물을 인벤토리에 추가한다.
	pZone->getObjectRegistry().registerObject(pItem);
	pInventory->addItem(X, Y, pItem);
	pItem->create(pPC->getName(), STORAGE_INVENTORY, 0, X, Y);

	// ItemTraceLog 를 남긴다
	if (pItem != NULL && pItem->isTraceItem() )
	{
		remainTraceLog(pItem, pCreature1->getName(), pCreature2->getName(), ITEM_LOG_CREATE, DETAIL_EVENTNPC);
	}

	// 클라이언트에 선물이 추가되었음을 알린다.
	GCCreateItem gcCreateItem;
	makeGCCreateItem(&gcCreateItem, pItem, X, Y);
	pPlayer->sendPacket(&gcCreateItem);

	// Flag을 켠다.
	pFlagSet->turnOn(FLAGSET_TRADE_GIFT_BOX_2002_12);

	// Flag을 저장한다.
	pFlagSet->save(pPC->getName());

	// 아이템 교환이 이루어 졌다고 클라이언트에 알린다.
	GCNPCResponse response;
	response.setCode(NPC_RESPONSE_TRADE_GIFT_BOX_OK);
	pPlayer->sendPacket(&response);

	GCNPCResponse quit;
	quit.setCode(NPC_RESPONSE_QUIT_DIALOGUE);
	pPlayer->sendPacket(&quit);

	__END_CATCH
}
void CGShopRequestSellHandler::executeOpSwapAdvancementItem(CGShopRequestSell* pPacket, Player* pPlayer)
	throw(ProtocolException, Error)
{
	__BEGIN_TRY

#ifdef __GAME_SERVER__

	ObjectID_t      NPCID        = pPacket->getObjectID();
	ObjectID_t      ITEMOID      = pPacket->getItemObjectID();
	GamePlayer*     pGamePlayer  = dynamic_cast<GamePlayer*>(pPlayer);
	Creature*       pCreature    = pGamePlayer->getCreature();
	PlayerCreature* pPC          = dynamic_cast<PlayerCreature*>(pCreature);

	if (!pPC->isAdvanced() )
	{
		return sendFailPacket(pPacket, pPlayer);
	}

	Zone* pZone = pPC->getZone();
	if (pZone == NULL) return sendFailPacket(pPacket, pPlayer);

	Creature*		pNPCBase = pZone->getCreature(NPCID); 
	if (pNPCBase == NULL || !pNPCBase->isNPC()) return sendFailPacket(pPacket, pPlayer);
	NPC* pNPC = dynamic_cast<NPC*>(pNPCBase);
	
	Inventory* pInventory  = pPC->getInventory();
	Item*      pItem       = pInventory->getItemWithObjectID(ITEMOID);

	if (pItem == NULL || pItem->isTimeLimitItem() )
	{
		return sendFailPacket(pPacket, pPlayer);
	}

	Item::ItemClass iClass = Item::ITEM_CLASS_MAX;
	ItemType_t		iType = 0;
	Grade_t			iGrade = 0;
	FlagSetType		fType = FLAGSET_MAX;

	ItemInfo* pItemInfo = g_pItemInfoManager->getItemInfo(pItem->getItemClass(), pItem->getItemType());
	Assert(pItemInfo!=NULL);

	switch (pItem->getItemClass() )
	{
		case Item::ITEM_CLASS_SWORD:
		case Item::ITEM_CLASS_BLADE:
		case Item::ITEM_CLASS_AR:
		case Item::ITEM_CLASS_SR:
		case Item::ITEM_CLASS_SG:
		case Item::ITEM_CLASS_SMG:
			{
				switch (pItem->getItemType() )
				{
					case 9:
						{
							iClass = pItem->getItemClass();
							iType = 14;
							iGrade = 2;
							break;
						}
					case 11:
						{
							iClass = pItem->getItemClass();
							iType = 14;
							iGrade = 4;
							break;
						}
					case 12:
						{
							iClass = pItem->getItemClass();
							iType = 14;
							iGrade = 6;
							break;
						}
					case 13:
						{
							iClass = pItem->getItemClass();
							iType = 14;
							iGrade = 8;
							break;
						}
					default:
						break;
				}
				if (iClass == Item::ITEM_CLASS_SG ) iClass = Item::ITEM_CLASS_SR;
				if (iClass == Item::ITEM_CLASS_SMG ) iClass = Item::ITEM_CLASS_AR;
				break;
			}
		case Item::ITEM_CLASS_CROSS:
		case Item::ITEM_CLASS_MACE:
			{
				switch (pItem->getItemType() )
				{
					case 7:
						{
							iClass = pItem->getItemClass();
							iType = 12;
							iGrade = 2;
							break;
						}
					case 9:
						{
							iClass = pItem->getItemClass();
							iType = 12;
							iGrade = 4;
							break;
						}
					case 10:
						{
							iClass = pItem->getItemClass();
							iType = 12;
							iGrade = 6;
							break;
						}
					case 11:
						{
							iClass = pItem->getItemClass();
							iType = 12;
							iGrade = 8;
							break;
						}
					default:
						break;
				}
				break;
			}

		case Item::ITEM_CLASS_COAT:
		case Item::ITEM_CLASS_TROUSER:
			{
				switch (pItem->getItemType() )
				{
					case 14:
					case 15:
						{
							iClass = pItem->getItemClass();
							iType = 24 + (pItem->getItemType()%2);
							iGrade = 2;
							break;
						}
					case 18:
					case 19:
					case 20:
					case 21:
					case 22:
					case 23:
						{
							iClass = pItem->getItemClass();
							iType = 24 + (pItem->getItemType()%2);
							iGrade = 4 + (((pItem->getItemType()-18)/2)*2);
							break;
						}
					default:
						break;
				}
				break;
			}
		case Item::ITEM_CLASS_VAMPIRE_WEAPON:
			{
				switch (pItem->getItemType() )
				{
					case 14:
						{
							iClass = pItem->getItemClass();
							iType = 19;
							iGrade = 2;
							break;
						}
					case 16:
						{
							iClass = pItem->getItemClass();
							iType = 19;
							iGrade = 4;
							break;
						}
					case 17:
						{
							iClass = pItem->getItemClass();
							iType = 19;
							iGrade = 6;
							break;
						}
					case 18:
						{
							iClass = pItem->getItemClass();
							iType = 19;
							iGrade = 8;
							break;
						}
					default:
						break;
				}
				break;
			}
		case Item::ITEM_CLASS_VAMPIRE_COAT:
			{
				switch (pItem->getItemType() )
				{
					case 10:
					case 11:
						{
							iClass = pItem->getItemClass();
							iType = 20 + (pItem->getItemType()%2);
							iGrade = 2;
							break;
						}
					case 14:
					case 15:
					case 16:
					case 17:
					case 18:
					case 19:
						{
							iClass = pItem->getItemClass();
							iType = 20 + (pItem->getItemType()%2);
							iGrade = 4 + (((pItem->getItemType()-14)/2)*2);
							break;
						}
					default:
						break;
				}
				break;
			}
		case Item::ITEM_CLASS_OUSTERS_CHAKRAM:
			{
				switch (pItem->getItemType() )
				{
					case 9:
						{
							iClass = pItem->getItemClass();
							iType = 14;
							iGrade = 2;
							break;
						}
					case 10:
						{
							iClass = pItem->getItemClass();
							iType = 14;
							iGrade = 4;
							break;
						}
					case 11:
						{
							iClass = pItem->getItemClass();
							iType = 14;
							iGrade = 6;
							break;
						}
					case 13:
						{
							iClass = pItem->getItemClass();
							iType = 14;
							iGrade = 8;
							break;
						}
					default:
						break;
				}
				break;
			}
		case Item::ITEM_CLASS_OUSTERS_WRISTLET:
			{
				switch (pItem->getItemType() )
				{
					case 9:
					case 30:
					case 31:
					case 39:
						{
							iClass = pItem->getItemClass();
							iType = 42;
							iGrade = pItemInfo->getItemLevel() * 2 - 16;
							break;
						}
					case 19:
					case 32:
					case 33:
					case 40:
						{
							iClass = pItem->getItemClass();
							iType = 43;
							iGrade = pItemInfo->getItemLevel() * 2 - 16;
							break;
						}
					case 29:
					case 34:
					case 35:
					case 41:
						{
							iClass = pItem->getItemClass();
							iType = 44;
							iGrade = pItemInfo->getItemLevel() * 2 - 16;
							break;
						}
					default:
						break;
				}
				break;
			}
		case Item::ITEM_CLASS_OUSTERS_COAT:
		case Item::ITEM_CLASS_OUSTERS_BOOTS:
			{
				switch (pItem->getItemType() )
				{
					case 7:
						{
							iClass = pItem->getItemClass();
							iType = 12;
							iGrade = 2;
							break;
						}
					case 8:
						{
							iClass = pItem->getItemClass();
							iType = 12;
							iGrade = 4;
							break;
						}
					case 9:
						{
							iClass = pItem->getItemClass();
							iType = 12;
							iGrade = 6;
							break;
						}
					case 11:
						{
							iClass = pItem->getItemClass();
							iType = 12;
							iGrade = 8;
							break;
						}
					default:
						break;
				}
				break;
			}
		default:
			break;
	}

	switch (iClass )
	{
		case Item::ITEM_CLASS_SWORD:
		case Item::ITEM_CLASS_BLADE:
		case Item::ITEM_CLASS_AR:
		case Item::ITEM_CLASS_SR:
		case Item::ITEM_CLASS_CROSS:
		case Item::ITEM_CLASS_MACE:
		case Item::ITEM_CLASS_VAMPIRE_WEAPON:
		case Item::ITEM_CLASS_OUSTERS_CHAKRAM:
		case Item::ITEM_CLASS_OUSTERS_WRISTLET:
			fType = FLAGSET_SWAP_WEAPON;
			break;
		case Item::ITEM_CLASS_COAT:
		case Item::ITEM_CLASS_VAMPIRE_COAT:
		case Item::ITEM_CLASS_OUSTERS_COAT:
			fType = FLAGSET_SWAP_COAT;
			break;
		case Item::ITEM_CLASS_TROUSER:
		case Item::ITEM_CLASS_OUSTERS_BOOTS:
			fType = FLAGSET_SWAP_TROUSER;
			break;
		default:
			break;
	}

	if (iClass == Item::ITEM_CLASS_MAX || fType == FLAGSET_MAX )
	{
		sendFailPacket(pPacket, pPlayer);
		return;
	}

	FlagSet* pFlagSet = pPC->getFlagSet();
	if (pFlagSet->isOn(fType) )
	{
		sendFailPacket(pPacket, pPlayer);
		return;
	}

	Item* pNewItem = g_pItemFactoryManager->createItem(iClass, iType, pItem->getOptionTypeList());
	if (pNewItem == NULL )
	{
		sendFailPacket(pPacket, pPlayer);
		return;
	}
	pNewItem->setGrade(iGrade);

	_TPOINT tp;
	if (!pInventory->getEmptySlot(pNewItem, tp) )
	{
		SAFE_DELETE(pNewItem);
		sendFailPacket(pPacket, pPlayer);
		return;
	}

	filelog("ItemSwap.log", "[%s:%s] %s <-> %s",
			pGamePlayer->getID().c_str(), pPC->getName().c_str(), pItem->toString().c_str(), pNewItem->toString().c_str());

	pNewItem->setTraceItem(bTraceLog(pNewItem ));

	pInventory->deleteItem(ITEMOID);
	pItem->whenPCLost(pPC);

	if (!pItem->destroy())
	{
		filelog("shopDBBug.txt", "NoSuchItemInDB-destroy: %s", pItem->toString().c_str());

		throw DisconnectException("아이템 지울려는데 DB에 없다.");
	}

	pZone->registerObject(pNewItem);

	GCShopSellOK okpkt;
	okpkt.setObjectID(NPCID);
	okpkt.setShopVersion(-1);
	okpkt.setItemObjectID(ITEMOID);
	okpkt.setPrice(0);
	pGamePlayer->sendPacket(&okpkt);

	// 삭제할 아이템의 ItemTrace Log 를 남겨야 한다면 남긴다
	if (pItem != NULL && pItem->isTraceItem() )
	{
		remainTraceLog(pItem, pCreature->getName() , pNPC->getName(), ITEM_LOG_DELETE, DETAIL_SHOPSELL);
	}

	// 인벤토리에 추가
	Assert(pInventory->addItem(pNewItem, tp ));

	// DB 에 생성
	pNewItem->create(pPC->getName(), STORAGE_INVENTORY, 0, tp.x, tp.y);

	// 교환해줄 아이템의 ItemTrace Log 를 남겨야 한다면 남긴다
	if (pNewItem->isTraceItem() )
	{
		remainTraceLog(pNewItem, pNPC->getName() , pCreature->getName(), ITEM_LOG_CREATE, DETAIL_SHOPBUY);
	}

	pFlagSet->turnOn(fType);
	pFlagSet->save(pPC->getName());

	GCCreateItem gcCI;
	makeGCCreateItem(&gcCI, pNewItem, tp.x, tp.y);

	pGamePlayer->sendPacket(&gcCI);

#endif

	__END_CATCH
}
//////////////////////////////////////////////////////////////////////////////
//
// 모터 사이클을 처리한다.
//
//////////////////////////////////////////////////////////////////////////////
void CGShopRequestSellHandler::executeMotorcycle (CGShopRequestSell* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __GAME_SERVER__

	// 패킷 정보를 뽑아낸다.
	ObjectID_t      NPCID       = pPacket->getObjectID();
	ObjectID_t      ITEMOID     = pPacket->getItemObjectID();
	GamePlayer*     pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer);
	Creature*       pCreature   = pGamePlayer->getCreature();
	PlayerCreature* pPC         = dynamic_cast<PlayerCreature*>(pCreature);

	Zone* pZone = pPC->getZone();
	if (pZone == NULL) return sendFailPacket(pPacket, pPlayer);

	Creature* pNPCBase = NULL;
	/*
	try 
	{ 
		pNPCBase = pZone->getCreature(NPCID); 
	} 
	catch (NoSuchElementException & nsee) 
	{ 
		pNPCBase = NULL; 
	}
	*/

	// NoSuch제거. by sigi. 2002.5.2
	pNPCBase = pZone->getCreature(NPCID); 

	if (pNPCBase == NULL || !pNPCBase->isNPC()) return sendFailPacket(pPacket, pPlayer);

	NPC*        pNPC    = dynamic_cast<NPC*>(pNPCBase);
	int         CenterX = pNPC->getX();
	int         CenterY = pNPC->getY();
	
	// 플레이어가 팔려고 하는 아이템을 가지고 있는지 검사
	Inventory* pInventory  = pPC->getInventory();
	Gold_t     playerMoney = pPC->getGold();
	Item*      pItem       = pInventory->getItemWithObjectID(ITEMOID);
	if (pItem == NULL) return sendFailPacket(pPacket, pPlayer);

	// 주위 일정 범위를 검색해서, 모터 사이클이 있는지 확인한다.
	try
	{
		for (int zx=CenterX-5; zx<=CenterX+5; zx++)
		{
			for (int zy=CenterY-5; zy<=CenterY+5; zy++)
			{
				// 바운드를 넘어가지 않는가를 체크
				if (!isValidZoneCoord(pZone, zx, zy)) continue;

				Tile & tile = pZone->getTile(zx, zy);
				if (tile.hasItem())
				{
					Item* pItemOnTile = tile.getItem();
					if (pItemOnTile == NULL) continue;

					// 만일 아이템이 타일 위에 있을 경우, 모터 사이클인지 확인한다.
					if (pItemOnTile->getItemClass() == Item::ITEM_CLASS_MOTORCYCLE)
					{
						DWORD    targetID     = dynamic_cast<Key*>(pItem)->getTarget();
						ItemID_t motorcycleID = pItemOnTile->getItemID();

						if (targetID == motorcycleID)
						{
							// 모터사이클을 DB에서 삭제한다.
							pItemOnTile->destroy();

							// 플레이어의 인벤토리에서 열쇠를 제거한다.
							pInventory->deleteItem(ITEMOID);
							pItem->destroy();
							SAFE_DELETE(pItem);
							
							// 열쇠 값이 아니라, 오토바이 값을 줘야 한다.
							Price_t itemPrice = g_pPriceManager->getPrice(pItemOnTile, pNPC->getMarketCondBuy(), SHOP_RACK_NORMAL, pPC);

							// 플레이어의 돈을 늘린다.
							//pPC->setGoldEx(playerMoney+itemPrice);
							// by sigi. 2002.9.4
							pPC->increaseGoldEx(itemPrice);

							// 물건을 판 플레이어에게 GCShopSellOK를...보낸다.
							GCShopSellOK okpkt;
							okpkt.setObjectID(NPCID);
							if (!pItemOnTile->getOptionTypeList().empty()) okpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_SPECIAL));
							else                                   okpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_NORMAL));
							okpkt.setItemObjectID(ITEMOID);
							okpkt.setPrice(playerMoney+itemPrice);
							pPlayer->sendPacket(&okpkt);

							// 뻑킹 센터에서 박스를 삭제해 준다.
							if (g_pParkingCenter->hasMotorcycleBox(motorcycleID)) 
								g_pParkingCenter->deleteMotorcycleBox(motorcycleID);

							// NPC에게 자리가 충분하다면 플레이어가 판 아이템을 보관한다.
							// 단 스페셜 아이템만을 보관한다. 노말 아이템은 그냥 버림.
							//if (pItemOnTile->getOptionType() != 0)
							//{
							//	index = pNPC->getFirstEmptySlot(SHOP_RACK_SPECIAL);
							//	if (index < SHOP_RACK_INDEX_MAX)
							//	{
							//		pNPC->insertShopItem(SHOP_RACK_SPECIAL, index, pItemOnTile);
							//		// 스페셜 아이템을 NPC가 진열장에 추가했으므로, 상점 버전이 올라간다.
							//		pNPC->increaseShopVersion(SHOP_RACK_SPECIAL);
							//	}
							//}
							//else
							//{
							//	SAFE_DELETE(pItemOnTile);
							//}

							// 모터 사이클을 찾았으므로, 할 일이 끝났다. 
							return;
						}
					}
				}
			} // end of for (ZoneCoord_t zy=CenterY-5; zy<=CenterY+5; zy++)
		} // end of for (ZoneCoord_t zx=CenterX-5; zx<=CenterX+5; zx++)
	}
	catch (Throwable & t)
	{
		filelog("shopbug_packet.log", "%s", t.toString().c_str());
	}

	// FOR 루프를 다 돌고, 이까지 왔다는 것은 근처에 오토바이가 없다는 말이당...
	// 그러므로 모터 사이클 팔기가 실패했다는 것을 알린다.
	GCShopSellFail failpkt;
	failpkt.setObjectID(NPCID);
	pPlayer->sendPacket(&failpkt);
	
#endif

	__END_DEBUG_EX __END_CATCH
}
//////////////////////////////////////////////////////////////////////////////
// 
// 일반 아이템을 처리한다.
//
//////////////////////////////////////////////////////////////////////////////
void CGShopRequestSellHandler::executeNormal (CGShopRequestSell* pPacket , Player* pPlayer)
	 throw(ProtocolException , Error)
{
	__BEGIN_TRY __BEGIN_DEBUG_EX

#ifdef __GAME_SERVER__

	ObjectID_t      NPCID        = pPacket->getObjectID();
	ObjectID_t      ITEMOID      = pPacket->getItemObjectID();
	GamePlayer*     pGamePlayer  = dynamic_cast<GamePlayer*>(pPlayer);
	Creature*       pCreature    = pGamePlayer->getCreature();
	PlayerCreature* pPC          = dynamic_cast<PlayerCreature*>(pCreature);
	BYTE            index        = 0;
	bool            bSpecialItem = false;

	Zone* pZone = pPC->getZone();
	if (pZone == NULL) return sendFailPacket(pPacket, pPlayer);

	Creature* pNPCBase = NULL;
	/*
	try 
	{ 
		pNPCBase = pZone->getCreature(NPCID); 
	}
	catch (NoSuchElementException & nsee) 
	{ 
		pNPCBase = NULL; 
	}
	*/

	// NoSuch제거. by sigi. 2002.5.2
	pNPCBase = pZone->getCreature(NPCID); 

	if (pNPCBase == NULL || !pNPCBase->isNPC()) return sendFailPacket(pPacket, pPlayer);

	NPC* pNPC = dynamic_cast<NPC*>(pNPCBase);
	
	// 플레이어가 팔려고 하는 아이템을 가지고 있는지 검사
	Inventory* pInventory  = pPC->getInventory();
	//Gold_t     playerMoney = pPC->getGold(); 
	Item*      pItem       = pInventory->getItemWithObjectID(ITEMOID);
	ItemNum_t  itemNumber  = pItem->getNum();
	Price_t    itemPrice   = g_pPriceManager->getPrice(pItem, pNPC->getMarketCondBuy(), SHOP_RACK_NORMAL, pPC) * itemNumber;

	// 플레이어의 인벤토리에 아이템을 제거한다.
	pInventory->deleteItem(ITEMOID);
	pItem->whenPCLost(pPC);

	if (!pItem->destroy()) {
		filelog("shopDBBug.txt", "NoSuchItemInDB-destroy: %s", pItem->toString().c_str());

		throw DisconnectException("아이템 지울려는데 DB에 없다.");
	}

	// 만약 벨트라면 안에 있는 포션을 삭제해준다.
	// DB에서 지우는 것은 Belt::destroy()를 부르는 것만으로 포션까지 삭제된다.
	if (pItem->getItemClass() == Item::ITEM_CLASS_BELT) {
		Inventory* pBeltInventory = dynamic_cast<Belt*>(pItem)->getInventory();
		for (int y=0; y<pBeltInventory->getHeight(); y++) {
			for (int x=0; x<pBeltInventory->getWidth(); x++) {
				Item* pBeltItem = pBeltInventory->getItem(x, y);
				if (pBeltItem != NULL) {
					pBeltInventory->deleteItem(x, y);
					SAFE_DELETE(pBeltItem);
				}
			}
		}
	}

	// Skull 일 경우 Variable Manager 에서 머리값 배수 값으로 가격을 새로 계산한다
	if (pItem->getItemClass() == Item::ITEM_CLASS_SKULL)
		itemPrice = itemPrice * (g_pVariableManager->getHeadPriceBonus() / 100);

	// ItemTrace Log 를 남겨야 한다면 남긴다
	if (pItem != NULL && pItem->isTraceItem() )
		remainTraceLog(pItem, pCreature->getName() , pNPC->getName(), ITEM_LOG_DELETE, DETAIL_SHOPSELL);

	// 플레이어에게 물건값을 지불한다.
	// pPC->setGoldEx(playerMoney+itemPrice);
	// by sigi. 2002.9.4
	pPC->increaseGoldEx(itemPrice);

	// 플레이어가 물건 팔 때 처리할 것들을 처리한다.
	pPC->sellItem(pItem);

	if (pItem->getItemClass() == Item::ITEM_CLASS_MOON_CARD && pItem->getItemType() == 4)
		addOlympicStat(pPC, 4, (uint)(itemNumber));

	bool bClearDefaultOptionTypes = false;
	if (pItem->getItemClass() == Item::ITEM_CLASS_EVENT_ITEM && pItem->getItemType() >= 32 && pItem->getItemType() <= 36)
		bClearDefaultOptionTypes = true;

	// NPC에게 자리가 충분하다면 플레이어가 판 아이템을 보관한다.
	// 운영자 명령어로 만든 아이템은 바로 없앤다.
	// 단 스페셜 아이템만을 보관한다. 노말 아이템은 그냥 버림.
	// 퀘스트 아이템은 보관하지 않고 버린다.
	if (pNPC->getShopType()==SHOPTYPE_NORMAL &&
		pItem->getCreateType()!=Item::CREATE_TYPE_CREATE &&
		!pItem->getOptionTypeList().empty() &&
		!pItem->isTimeLimitItem()) {
		bSpecialItem = true;
		index        = pNPC->getFirstEmptySlot(SHOP_RACK_SPECIAL);

		if (index < SHOP_RACK_INDEX_MAX) {
			// 아이템을 추가한다.
			pNPC->insertShopItem(SHOP_RACK_SPECIAL, index, pItem);

			// 스페셜 아이템을 NPC가 진열장에 추가했으므로, 상점 버전이 올라간다.
			pNPC->increaseShopVersion(SHOP_RACK_SPECIAL);

			////////////////////////////////////////////////////////////////////////////
			// 근처의 플레이어들에게는 GCShopBought를...
			////////////////////////////////////////////////////////////////////////////

			int         CenterX       = pNPC->getX();
			int         CenterY       = pNPC->getY();
			Creature*   pNearCreature = NULL;
			Player*     pNearPlayer   = NULL;

			GCShopBought boughtpkt;
			boughtpkt.setObjectID(NPCID);
			if (!pItem->getOptionTypeList().empty()) {
				boughtpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_SPECIAL));
				boughtpkt.setShopType(SHOP_RACK_SPECIAL);
			} else {
				boughtpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_NORMAL));
				boughtpkt.setShopType(SHOP_RACK_NORMAL);
			}
			boughtpkt.setShopIndex(index);
			boughtpkt.setItemObjectID(ITEMOID);
			boughtpkt.setItemClass(pItem->getItemClass());
			boughtpkt.setItemType(pItem->getItemType());
			boughtpkt.setOptionType(pItem->getOptionTypeList());
			boughtpkt.setDurability(pItem->getDurability());
			boughtpkt.setSilver(pItem->getSilver());
			boughtpkt.setGrade(pItem->getGrade());
			boughtpkt.setEnchantLevel(pItem->getEnchantLevel());

			//pZone->broadcastPacket(pNPC->getX(), pNPC->getY(), &boughtpkt, pPC);

			try
			{
				for (int zx=CenterX-5; zx<=CenterX+5; zx++)
				{
					for (int zy=CenterY-5; zy<=CenterY+5; zy++)
					{
						// 바운드를 넘어가지 않는가를 체크
						if (!isValidZoneCoord(pZone, zx, zy)) continue;

						Tile & tile = pZone->getTile(zx, zy);

						// 걸어다니는 크리쳐를 검색	
						if (tile.hasCreature(Creature::MOVE_MODE_WALKING))
						{
							pNearCreature = tile.getCreature(Creature::MOVE_MODE_WALKING);
							if (pNearCreature == NULL) continue;

							// 방금 물건을 판 플레이어라면 생략
							if (pNearCreature->getObjectID() == pPC->getObjectID()) continue;
							
							// 만약 플레이어라면 패킷을 보내준다.
							if (pNearCreature->isPC())
							{
								pNearPlayer = pNearCreature->getPlayer();
								if (pNearPlayer == NULL) continue;
								pNearPlayer->sendPacket(&boughtpkt);
							}
						}
						// 날아다니는 크리쳐를 검색
						if (tile.hasCreature(Creature::MOVE_MODE_FLYING))
						{
							pNearCreature = tile.getCreature(Creature::MOVE_MODE_FLYING);
							if (pNearCreature == NULL) continue;
							
							// 방금 물건을 판 플레이어라면 생략
							if (pNearCreature->getObjectID() == pPC->getObjectID()) continue;

							// 만약 플레이어라면 패킷을 보내준다.
							if (pNearCreature->isPC())
							{
								pNearPlayer = pNearCreature->getPlayer();
								if (pNearPlayer == NULL) continue;
								pNearPlayer->sendPacket(&boughtpkt);
							}
						}

					} // end of for (ZoneCoord_t zy=CenterY-5; zy<=CenterY+5; zy++)
				} // end of for (ZoneCoord_t zx=CenterX-5; zx<=CenterX+5; zx++)
			}
			catch (Throwable & t)
			{
				filelog("shopbug_packet.log", "%s", t.toString().c_str());
			}

		} // if (index < SHOP_RACK_INDEX_MAX)
		else
		{
			SAFE_DELETE(pItem);
		}
	} // if (pItem->getOptionType() != 0)
	else
	{
		bSpecialItem = false;
		SAFE_DELETE(pItem);
	}

	// 물건을 산 플레이어에게 GCShopSellOK를...보낸다.
	GCShopSellOK okpkt;
	okpkt.setObjectID(NPCID);
	if (bSpecialItem) okpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_SPECIAL));
	else              okpkt.setShopVersion(pNPC->getShopVersion(SHOP_RACK_NORMAL));
	okpkt.setItemObjectID(ITEMOID);
	//okpkt.setPrice(playerMoney+itemPrice);
	// playerMoney + itemPrice 가 MAX_MONEY를 넘어갈 수 있다.
	// 2003.1.8 by bezz
	okpkt.setPrice(pPC->getGold());
	pPlayer->sendPacket(&okpkt);
	
	if (bClearDefaultOptionTypes )
	{
		pPC->clearDefaultOptionTypes();
		pPC->initAllStatAndSend();

		if (pPC->isSlayer() )
		{
			Slayer* pSlayer = dynamic_cast<Slayer*>(pPC);
			Assert(pSlayer != NULL);

			pSlayer->sendRealWearingInfo();
		}
		else if (pPC->isVampire() )
		{
			Vampire* pVampire = dynamic_cast<Vampire*>(pPC);
			Assert(pVampire != NULL);

			pVampire->sendRealWearingInfo();
		}
		else if (pPC->isOusters() )
		{
			Ousters* pOusters = dynamic_cast<Ousters*>(pPC);
			Assert(pOusters != NULL);

			pOusters->sendRealWearingInfo();
		}
	}

#endif

	__END_DEBUG_EX __END_CATCH
}