#include "StdAfx.h"
#include "CheatManager.h"

#include "Protocol_Cheat.h"
#include "Cheat_Common.h"
#include "Player_Common.h"
#include "Npc_Common.h"
#include "StageManager.h"
#include "WorldManager.h"
#include "SceneManager.h"
#include "ChatManager.h"
#include "ObjectManager.h"
#include "ItemManager.h"
#include "UIManager.h"
#include "UIRootNode.h"
#include "GameResourceManager.h"
#include "GameUIManager.h"
#include "RevivalWindow.h"
#include "Hero.h"
#include "UIMsgboxEvent.h"
#include "Application.h"
#include "GMTool.h"
#include "resource.h"
#include "NoticeMsgPlane.h"

cCheatManager* cCheatManager::mInstance = 0;

cCheatManager::cCheatManager()
#ifdef _GMTOOL
: mCommandMap( 128 )
, mShotMode( false )
, mEarMode( true )
, mHideMode( false )
, mUndeadMode( false )
, mWatchMode( false )
#endif
{
	assert( mInstance == 0 && "bad singleton" );
	mInstance = this;

#ifdef _GMTOOL
	mCommandMap.Insert( L"shot", CHEAT_COMM_SHOT );
	mCommandMap.Insert( L"in", CHEAT_COMM_IN );
	mCommandMap.Insert( L"speed", CHEAT_COMM_SPEEDUP );
	mCommandMap.Insert( L"ear", CHEAT_COMM_EAR );
	mCommandMap.Insert( L"hide", CHEAT_COMM_HIDE );
	mCommandMap.Insert( L"undead", CHEAT_COMM_UNDEAD );
	mCommandMap.Insert( L"info", CHEAT_COMM_INFO );
	mCommandMap.Insert( L"watch", CHEAT_COMM_WATCH );
	mCommandMap.Insert( L"kick", CHEAT_COMM_KICK );
	mCommandMap.Insert( L"recover", CHEAT_COMM_RECOVER );
	mCommandMap.Insert( L"rebirth", CHEAT_COMM_REBIRTH );
	mCommandMap.Insert( L"teleport", CHEAT_COMM_TELEPORT );
	mCommandMap.Insert( L"go", CHEAT_COMM_GO );
	mCommandMap.Insert( L"chase", CHEAT_COMM_CHASE );
	mCommandMap.Insert( L"move", CHEAT_COMM_MOVE );
	mCommandMap.Insert( L"call", CHEAT_COMM_CALL );
	mCommandMap.Insert( L"nochat", CHEAT_COMM_NO_CHAT );
	mCommandMap.Insert( L"allowchat", CHEAT_COMM_ALLOW_CHAT );
//	mCommandMap.Insert( L"stop", CHEAT_COMM_STOP );
//	mCommandMap.Insert( L"cancelstop", CHEAT_COMM_CANCEL_STOP );
	mCommandMap.Insert( L"notice_server", CHEAT_COMM_NOTICE_SERVER );
	mCommandMap.Insert( L"notice_channel", CHEAT_COMM_NOTICE_CHANNEL );
	mCommandMap.Insert( L"notice_area", CHEAT_COMM_NOTICE_AREA );
	mCommandMap.Insert( L"removei", CHEAT_COMM_REMOVE_ITEM );
	mCommandMap.Insert( L"removem", CHEAT_COMM_REMOVE_MONSTER );
	mCommandMap.Insert( L"levelup", CHEAT_COMM_LEVELUP );
	mCommandMap.Insert( L"skillup", CHEAT_COMM_SKILLUP );
	mCommandMap.Insert( L"make", CHEAT_COMM_MAKE );
	mCommandMap.Insert( L"gold", CHEAT_COMM_GOLD );
	mCommandMap.Insert( L"summon", CHEAT_COMM_SUMMON );
	mCommandMap.Insert( L"remove", CHEAT_COMM_REMOVE );
	mCommandMap.Insert( L"kill", CHEAT_COMM_KILL );
// 	mCommandMap.Insert( L"exp", CHEAT_COMM_EXP );
// 	mCommandMap.Insert( L"sxp", CHEAT_COMM_SXP );
// 	mCommandMap.Insert( L"drop", CHEAT_COMM_DROP );

#endif
}

cCheatManager::~cCheatManager()
{
	assert( mInstance );
	mInstance = 0;
}

#ifdef _GMTOOL
void cCheatManager::Clear()
{
	mShotMode = false;
	mEarMode = true;
	mHideMode = false;
	mUndeadMode = false;
	mWatchMode = false;
}

bool cCheatManager::Interpret( const charT* src, unsigned int srcLen )
{
	if( src == 0 || src[0] != '/' || srcLen < 3 )
		return false;

	cTokenizerT tokenizer( &src[1], srcLen-1, L" \t\r\n" );
	cStringT str;

	if( tokenizer.GetNext( &str ) == false )
		return false;

	/// 명령어를 검사
	str.ToLower();
	cCommandMap::cIterator i = mCommandMap.Find( str );
	if( i == mCommandMap.End() )
		return false;

	unsigned int commIndex = i->mSecond;

	/// 인자를 추가
	const wchar_t* argStr = tokenizer.GetTail();

	mArgArray.Clear();

	while( tokenizer.IsEnd() == false )
	{
		if( tokenizer.GetNext( &str ) == false )
			return false;

		mArgArray.PushBack( str );
	}

	/// 명령을 처리
	return HandleCommand( commIndex, argStr, mArgArray );
}

bool cCheatManager::HandleCommand( unsigned int commIndex, const wchar_t* argStr, const tArray<cStringT>& argArray )
{
	switch( commIndex )
	{
	case CHEAT_COMM_SHOT:			return HandleCommand_Shot( argStr, argArray );
	case CHEAT_COMM_IN:				return HandleCommand_In( argStr, argArray );
	case CHEAT_COMM_SPEEDUP:		return HandleCommand_SpeedUp( argStr, argArray );
	case CHEAT_COMM_EAR:			return HandleCommand_Ear( argStr, argArray );
	case CHEAT_COMM_HIDE:			return HandleCommand_Hide( argStr, argArray );
	case CHEAT_COMM_UNDEAD:			return HandleCommand_Undead( argStr, argArray );
	case CHEAT_COMM_INFO:			return HandleCommand_Info( argStr, argArray );
	case CHEAT_COMM_WATCH:			return HandleCommand_Watch( argStr, argArray );
	case CHEAT_COMM_KICK:			return HandleCommand_Kick( argStr, argArray );
	case CHEAT_COMM_RECOVER:		return HandleCommand_Recover( argStr, argArray );
	case CHEAT_COMM_REBIRTH:		return HandleCommand_Rebirth( argStr, argArray );
	case CHEAT_COMM_TELEPORT:		return HandleCommand_Teleport( argStr, argArray );
	case CHEAT_COMM_GO:				return HandleCommand_Go( argStr, argArray );
	case CHEAT_COMM_CHASE:			return HandleCommand_Chase( argStr, argArray );
	case CHEAT_COMM_MOVE:			return HandleCommand_Move( argStr, argArray );
	case CHEAT_COMM_CALL:			return HandleCommand_Call( argStr, argArray );
	case CHEAT_COMM_NO_CHAT:		return HandleCommand_NoChat( argStr, argArray );
	case CHEAT_COMM_ALLOW_CHAT:		return HandleCommand_AllowChat( argStr, argArray );
	case CHEAT_COMM_STOP:			return HandleCommand_Stop( argStr, argArray );
	case CHEAT_COMM_CANCEL_STOP:	return HandleCommand_CancelStop( argStr, argArray );
	case CHEAT_COMM_NOTICE_SERVER:	return HandleCommand_NoticeServer( argStr, argArray );
	case CHEAT_COMM_NOTICE_CHANNEL:	return HandleCommand_NoticeChannel( argStr, argArray );
	case CHEAT_COMM_NOTICE_AREA:	return HandleCommand_NoticeArea( argStr, argArray );
	case CHEAT_COMM_REMOVE_ITEM:	return HandleCommand_RemoveItem( argStr, argArray );
	case CHEAT_COMM_REMOVE_MONSTER:	return HandleCommand_RemoveMonster( argStr, argArray );
	case CHEAT_COMM_LEVELUP:		return HandleCommand_LevelUp( argStr, argArray );
	case CHEAT_COMM_SKILLUP:		return HandleCommand_SkillUp( argStr, argArray );
	case CHEAT_COMM_MAKE:			return HandleCommand_Make( argStr, argArray );
	case CHEAT_COMM_GOLD:			return HandleCommand_Gold( argStr, argArray );
	case CHEAT_COMM_SUMMON:			return HandleCommand_Summon( argStr, argArray );
	case CHEAT_COMM_REMOVE:			return HandleCommand_Remove( argStr, argArray );
	case CHEAT_COMM_KILL:			return HandleCommand_Kill( argStr, argArray );
	case CHEAT_COMM_EXP:			return HandleCommand_Exp( argStr, argArray );
	case CHEAT_COMM_SXP:			return HandleCommand_Sxp( argStr, argArray );
	case CHEAT_COMM_DROP:			return HandleCommand_Drop( argStr, argArray );

	}
	return false;
}

bool cCheatManager::HandleCommand_Shot( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	bool mode = false;

	if( argArray[0].CompareNoCase( L"on" ) == 0 )
	{
		mode = true;
	}
	else if( argArray[0].CompareNoCase( L"off" ) == 0 )
	{
		mode = false;
	}
	else
	{
		return false;
	}

	///
	mShotMode = mode;

	if( SCENEMAN )
	{
		SCENEMAN->SetScreenShotMode( mShotMode );
	}
	
	if( UIMAN )
	{
		cUIRootNode* uiroot = UIMAN->GetRootNode();
		if( uiroot )
		{
			if( mShotMode )
				uiroot->Hide();
			else
				uiroot->Show();
		}
	}
	return true;
}

bool cCheatManager::HandleCommand_In( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 0 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_IN msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_IN_REQ;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_SpeedUp( const wchar_t* argStr, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	eCHEAT_SPEEDUP speedUp = (eCHEAT_SPEEDUP)argArray[0].ToInt();
	if( speedUp >= eCHEATSPEEDUP_MAX )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_SPEEDUP msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_SPEEDUP_REQ;
		msg.mSpeedUp = speedUp;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Ear( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	bool mode = false;

	if( argArray[0].CompareNoCase( L"on" ) == 0 )
	{
		mode = true;
	}
	else if( argArray[0].CompareNoCase( L"off" ) == 0 )
	{
		mode = false;
	}
	else
	{
		return false;
	}
	
	if( mode == mEarMode )
	{
		return true;
	}

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_EAR msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_EAR_REQ;
		msg.mMode = mode;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Hide( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	bool mode = false;

	if( argArray[0].CompareNoCase( L"on" ) == 0 )
	{
		mode = true;
	}
	else if( argArray[0].CompareNoCase( L"off" ) == 0 )
	{
		mode = false;
	}
	else
	{
		return false;
	}

	if( mode == mHideMode )
	{
		return true;
	}

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_HIDE msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_HIDE_REQ;
		msg.mMode = mode;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Undead( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	bool mode = false;

	if( argArray[0].CompareNoCase( L"on" ) == 0 )
	{
		mode = true;
	}
	else if( argArray[0].CompareNoCase( L"off" ) == 0 )
	{
		mode = false;
	}
	else
	{
		return false;
	}

	if( mode == mUndeadMode )
	{
		return true;
	}

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_UNDEAD msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_UNDEAD_REQ;
		msg.mMode = mode;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Info( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	const cStringT& charName = argArray[0];

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_INFO msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_INFO_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Watch( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	bool mode = false;

	if( argArray[0].CompareNoCase( L"on" ) == 0 )
	{
		mode = true;
	}
	else if( argArray[0].CompareNoCase( L"off" ) == 0 )
	{
		mode = false;
	}
	else
	{
		return false;
	}

	if( mode == mWatchMode )
	{
		return true;
	}

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_WATCH msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_WATCH_REQ;
		msg.mMode = mode;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Kick( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	const cStringT& charName = argArray[0];

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_KICK msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_KICK_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Recover( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 0 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_RECOVER msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_RECOVER_REQ;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Rebirth( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 0 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_REBIRTH msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_REBIRTH_REQ;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Teleport( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 2 )
		return false;

	///
	float x = (float)argArray[0].ToInt()*100;
	float y = (float)argArray[1].ToInt()*100;
	float z = 0.0f;

	/// 내 캐릭터 이동
	if( WORLDMAN && WORLDMAN->CalcHeight( &z, x, y ) )
	{
		HERO->SetState( eOBJECT_STATE_IDLE );
		HERO->SetPos( NiPoint3(x, y, z) );
	}
	else
	{
		assert( 0 );
		return true;
	}

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_TELEPORT msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_TELEPORT_REQ;
		msg.mDestX = x;
		msg.mDestY = y;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Go( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 3 )
		return false;

	unsigned char mapNum = (unsigned char)argArray[0].ToInt();
	float x = argArray[1].ToInt() * 100.0f;
	float y = argArray[2].ToInt() * 100.0f;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_GO msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_GO_REQ;
		msg.mMapNum = mapNum;
		msg.mDestX = x;
		msg.mDestY = y;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Chase( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	const cStringT& charName = argArray[0];

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_CHASE msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_CHASE_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Move( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 4 )
		return false;

	const cStringT& charName = argArray[0];
	unsigned char mapNum = (unsigned char)argArray[1].ToInt();
	float x = argArray[2].ToInt() * 100.0f;
	float y = argArray[3].ToInt() * 100.0f;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_MOVE msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_MOVE_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );
		msg.mMapNum = mapNum;
		msg.mDestX = x;
		msg.mDestY = y;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Call( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	const cStringT& charName = argArray[0];

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_CALL msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_CALL_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_NoChat( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 2 )
		return false;

	const cStringT& charName = argArray[0];
	unsigned long duration = argArray[1].ToInt();

	if( duration < 1 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_NO_CHAT msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_NO_CHAT_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );
		msg.mDuration = duration;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_AllowChat( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	const cStringT& charName = argArray[0];

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_ALLOW_CHAT msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_ALLOW_CHAT_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Stop( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 2 )
		return false;

	const cStringT& charName = argArray[0];
	unsigned long duration = argArray[1].ToInt() * 60 * 1000;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_STOP msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_STOP_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );
		msg.mDuration = duration;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_CancelStop( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	const cStringT& charName = argArray[0];

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_CANCEL_STOP msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_CANCEL_STOP_REQ;
		::Sstrncpy( msg.mCharName, MAX_NAME_BUFFER_SIZE, charName.Cstr(), MAX_NAME_SIZE );

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_NoticeServer( const wchar_t* argStr, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() == 0 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_NOTICE_SERVER msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_NOTICE_SERVER_REQ;
		::Sstrncpy( msg.mMessage, MAX_CHAT_BUFFER_SIZE, argStr, NOTICEMSG_TEXT_LENGTH );

		NETWORK->SendNetworkMsg( (char*)&msg, (unsigned short)msg.GetMsgLength() );
	}
	return true;
}

bool cCheatManager::HandleCommand_NoticeChannel( const wchar_t* argStr, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() == 0 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_NOTICE_CHANNEL msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_NOTICE_CHANNEL_REQ;
		::Sstrncpy( msg.mMessage, MAX_CHAT_BUFFER_SIZE, argStr, NOTICEMSG_TEXT_LENGTH );

		NETWORK->SendNetworkMsg( (char*)&msg, (unsigned short)msg.GetMsgLength() );
	}
	return true;
}

bool cCheatManager::HandleCommand_NoticeArea( const wchar_t* argStr, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() == 0 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_NOTICE_AREA msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_NOTICE_AREA_REQ;
		::Sstrncpy( msg.mMessage, MAX_CHAT_BUFFER_SIZE, argStr, NOTICEMSG_TEXT_LENGTH );

		NETWORK->SendNetworkMsg( (char*)&msg, (unsigned short)msg.GetMsgLength() );
	}
	return true;
}

bool cCheatManager::HandleCommand_RemoveItem( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 0 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_REMOVE_ITEM msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_REMOVE_ITEM_REQ;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}


bool cCheatManager::HandleCommand_RemoveMonster( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 0 )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_REMOVE_MONSTER msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_REMOVE_MONSTER_REQ;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_LevelUp( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	unsigned char add = (unsigned char)argArray[0].ToInt();

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_LEVELUP msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_LEVELUP_REQ;
		msg.mAddedValue = add;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_SkillUp( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	unsigned char add = (unsigned char)argArray[0].ToInt();

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_SKILLUP msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_SKILLUP_REQ;
		msg.mAddedValue = add;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Make( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 아이템 잠금 검사
	if( ITEMMAN->IsLocked() )
		return false;

	/// 인자 검사
	if( argArray.GetSize() != 2 )
		return false;

	///
	unsigned long itemIndex = argArray[0].ToInt();
	unsigned char count = (unsigned char)argArray[1].ToInt();

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_MAKE msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_MAKE_REQ;
		msg.mItemIndex = itemIndex;
		msg.mCount = count;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Gold( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	unsigned long val = argArray[0].ToInt();

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_GOLD msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_GOLD_REQ;
		msg.mValue = val;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Summon( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 2 )
		return false;

	///
	unsigned long monsterNum = argArray[0].ToInt();
	unsigned char val = argArray[1].ToInt();

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_SUMMON msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_SUMMON_REQ;
		msg.mMonsterNum = monsterNum;
		msg.mValue = val;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Remove( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 0 )
		return false;

	cBaseObject* pTarget = HERO->GetTargetObject();
	if( pTarget == NULL )
		return false;

	if( pTarget->GetObjectType() != eOBJECTTYPE_MONSTER )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_REMOVE msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_REMOVE_REQ;
		msg.mObjIndex = pTarget->GetObjectID();

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Kill( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 0 )
		return false;

	cBaseObject* pTarget = HERO->GetTargetObject();
	if( pTarget == NULL )
		return false;

	if( pTarget->GetObjectType() != eOBJECTTYPE_MONSTER )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_KILL msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_KILL_REQ;
		msg.mObjIndex = pTarget->GetObjectID();

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Exp( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	int val = argArray[0].ToInt();

	if( val < GMTOOL->MIN_PERCENT || val > GMTOOL->MAX_PERCENT )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_EXP msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_EXP_REQ;
		msg.mExpUpPercent = (short)val;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Sxp( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	int val = argArray[0].ToInt();

	if( val < GMTOOL->MIN_PERCENT || val > GMTOOL->MAX_PERCENT )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_SXP msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_SXP_REQ;
		msg.mSxpUpPercent = (short)val;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}

bool cCheatManager::HandleCommand_Drop( const wchar_t* /*argStr*/, const tArray<cStringT>& argArray )
{
	/// 인자 검사
	if( argArray.GetSize() != 1 )
		return false;

	///
	int val = argArray[0].ToInt();

	if( val < GMTOOL->MIN_PERCENT || val > GMTOOL->MAX_PERCENT )
		return false;

	/// 메시지 전송
	if( NETWORK->IsConnected() )
	{
		MSG_REQ_CHEAT_DROP msg;
		::memset( &msg, 0, sizeof(msg) );
		msg.Category = NM_CHEAT;
		msg.Protocol = NM_CHEAT_DROP_REQ;
		msg.mDropUpPercent = (short)val;

		NETWORK->SendNetworkMsg( (char*)&msg, sizeof(msg) );
	}
	return true;
}
#endif // _GMTOOL

void cCheatManager::NetworkMsgParser( MSGROOT* msg )
{
	cHero* hero = HERO;

	switch( msg->Protocol )
	{
	case NM_CHEAT_IN_SYN:
		{
			MSG_SYN_CHEAT_IN* syn = (MSG_SYN_CHEAT_IN*)msg;

			/// 해당 캐릭터를 삭제
			OBJECTMAN->RemovePlayer( syn->mObjIndex );
		}
		break;
	case NM_CHEAT_RECOVER_SYN:
		{
			MSG_SYN_CHEAT_RECOVER* syn = (MSG_SYN_CHEAT_RECOVER*)msg;

			cPlayer* player = OBJECTMANAGER->GetPlayer( syn->mObjIndex );
			if( player == 0 )
				return;

			player->HPChange( syn->mMaxHP, syn->mMaxHP, false );
			player->MPChange( syn->mMaxMP, syn->mMaxMP );
		}
		break;
	case NM_CHEAT_REBIRTH_SYN:
		{
			MSG_SYN_CHEAT_REBIRTH* syn = (MSG_SYN_CHEAT_REBIRTH*)msg;

			cPlayer* player = OBJECTMANAGER->GetPlayer( syn->mObjIndex );
			if( player == 0 )
				return;

			player->SetState( eOBJECT_STATE_IDLE );
			player->HPChange( syn->mMaxHP, syn->mMaxHP, false );
			player->MPChange( syn->mMaxMP, syn->mMaxMP );
		}
		break;
	case NM_CHEAT_TELEPORT_SYN:
		{
			MSG_SYN_CHEAT_TELEPORT* syn = (MSG_SYN_CHEAT_TELEPORT*)msg;

			cPlayer* player = OBJECTMAN->GetPlayer( syn->mObjIndex );
			if( player == 0 )
			{
				assert(0);
				return;
			}

			/// 높이값 계산
			if( WORLDMAN == 0 )
			{
				assert(0);
				return;
			}

			NiPoint3 pos( (float)syn->mDestX, (float)syn->mDestY, 0.0f );
			if( WORLDMAN->CalcHeight( &pos.z, pos.x, pos.y ) == false )
			{
				assert(0);
				return;
			}

			player->SetState( eOBJECT_STATE_IDLE );
			player->SetPos( pos );
		}
		break;
	case NM_CHEAT_NOTICE_SERVER_SYN:
		{
			MSG_SYN_CHEAT_NOTICE_SERVER* syn = (MSG_SYN_CHEAT_NOTICE_SERVER*)msg;

			CHATMANAGER->AddNoticeMsg( syn->mMessage, eCOLOR_YELLOW );
		}
		break;
	case NM_CHEAT_NOTICE_CHANNEL_SYN:
		{
			MSG_SYN_CHEAT_NOTICE_CHANNEL* syn = (MSG_SYN_CHEAT_NOTICE_CHANNEL*)msg;

			CHATMANAGER->AddNoticeMsg( syn->mMessage, eCOLOR_YELLOW );
		}
		break;
	case NM_CHEAT_NOTICE_AREA_SYN:
		{
			MSG_SYN_CHEAT_NOTICE_AREA* syn = (MSG_SYN_CHEAT_NOTICE_AREA*)msg;

			CHATMANAGER->AddNoticeMsg( syn->mMessage, eCOLOR_YELLOW );
		}
		break;
	case NM_CHEAT_STOP_SYN:
		{
			MSG_SYN_CHEAT_STOP* syn = (MSG_SYN_CHEAT_STOP*)msg;

			cPlayer* player = OBJECTMAN->GetPlayer( syn->mObjIndex );
			if( player == 0 )
			{
				assert(0);
				return;
			}

			player->SetStopFlag( eSTOP_CHEATSTOP );
		}
		break;
	case NM_CHEAT_CANCEL_STOP_SYN:
		{
			MSG_SYN_CHEAT_CANCEL_STOP* syn = (MSG_SYN_CHEAT_CANCEL_STOP*)msg;

			cPlayer* player = OBJECTMAN->GetPlayer( syn->mObjIndex );
			if( player == 0 )
			{
				assert(0);
				return;
			}

			player->SetStopFlag( eSTOP_NONE );
			player->SetState( eOBJECT_STATE_IDLE );
		}
		break;
	case NM_CHEAT_NO_CHAT_SYN:
		{
			TCHAR msg[ MAX_LOADSTRING ];
			if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_NOCHAT_RES_SUCCESS, msg, MAX_LOADSTRING ) == 0 )
			{
				CHATMANAGER->AddSystemMsg( eSYSTEM_GM, L"운영자에 의해 채팅이 금지 되었습니다." );
			}
			else
			{
				CHATMANAGER->AddSystemMsg( eSYSTEM_GM, msg );
			}
		}
		break;
	case NM_CHEAT_ALLOW_CHAT_SYN:
		{
			TCHAR msg[ MAX_LOADSTRING ];
			if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_ALLOW_CHAT_RES_SUCCESS, msg, MAX_LOADSTRING ) == 0 )
			{
				CHATMANAGER->AddSystemMsg( eSYSTEM_GM, L"운영자에 의해 채팅 금지 상태가 해제 되었습니다." );
			}
			else
			{
				CHATMANAGER->AddSystemMsg( eSYSTEM_GM, msg );
			}

		}
		break;

#ifdef _GMTOOL
	case NM_CHEAT_IN_RES:
		{
			MSG_RES_CHEAT_IN* res = (MSG_RES_CHEAT_IN*)msg;

			mHideMode = true;
			mUndeadMode = true;
			
 			TCHAR msg[ MAX_LOADSTRING ];
 			if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_IN_RES_GM, msg, MAX_LOADSTRING ) == 0 )
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat: /hide on, /undead on" );	
			else 
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
		}
		break;
	case NM_CHEAT_EAR_RES:
		{
			MSG_RES_CHEAT_EAR* res = (MSG_RES_CHEAT_EAR*)msg;
			
			mEarMode = res->mMode;

			if( mEarMode )
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat: /ear on" );
			else
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat: /ear off" );
		}
		break;
	case NM_CHEAT_HIDE_RES:
		{
			MSG_RES_CHEAT_HIDE* res = (MSG_RES_CHEAT_HIDE*)msg;

			mHideMode = res->mMode;

			TCHAR on [ MAX_LOADSTRING ];
			TCHAR off[ MAX_LOADSTRING ];
			if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_HIDE_RES_ON_GM,   on, MAX_LOADSTRING ) == 0 || 
				LoadString( GetModuleHandle(NULL), IDS_GMTOOL_HIDE_RES_OFF_GM, off, MAX_LOADSTRING ) == 0 )
			{
				if( mHideMode )
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat: /hide on" );
				else
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat: /hide off" );
			}
			else 
			{
				if( mHideMode )
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, on );
				else
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, off );
			}
		}
		break;
	case NM_CHEAT_UNDEAD_RES:
		{
			MSG_RES_CHEAT_UNDEAD* res = (MSG_RES_CHEAT_UNDEAD*)msg;

			mUndeadMode = res->mMode;
			
			TCHAR on [ MAX_LOADSTRING ];
			TCHAR off[ MAX_LOADSTRING ];
			if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_UNDEAD_RES_ON_GM,   on, MAX_LOADSTRING ) == 0 || 
				LoadString( GetModuleHandle(NULL), IDS_GMTOOL_UNDEAD_RES_OFF_GM, off, MAX_LOADSTRING ) == 0 )
			{
				if( mUndeadMode )
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat: /undead on" );
				else
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat: /undead off" );
			}
			else
			{
				if( mUndeadMode )
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, on );
				else
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, off);
			}
		}
		break;
	case NM_CHEAT_INFO_RES:
		{
			MSG_RES_CHEAT_INFO* res = (MSG_RES_CHEAT_INFO*)msg;

			int xpos = (int)(res->mPosX * 0.01);
			int ypos = (int)(res->mPosY * 0.01);

			LPCTSTR job = GAMERESOURCEMAN->GetJobName( res->mJob );

			cStringT str;
			str.Format( _T("[%s-%d] %d(%d,%d), %d"), /*res->mUserID,*/ job, res->mLevel, 
													res->mMapNum, xpos, ypos, res->mMoney );
			CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, (LPCTSTR)str.Cstr() );
		}
		break;
	case NM_CHEAT_WATCH_RES:
		{
			MSG_RES_CHEAT_UNDEAD* res = (MSG_RES_CHEAT_UNDEAD*)msg;

			mWatchMode = res->mMode;
		}
		break;
	case NM_CHEAT_KICK_RES:
		{
			// 서버로부터 연결이 해제 되었을 경우...
			UIMAN->CreateModal(	/*eStage_Login*/eStage_Game, eMBEVENT_PLAYER_KICKED, 
				GAMERESOURCEMAN->GetGameText( 182 ),
				GAMERESOURCEMAN->GetGameText( 301 ),
				eSKIN_OK );			
		}
		break;
	case NM_CHEAT_KICK_RES_GM:
		{
			MSG_RES_CHEAT_KICK_GM* res = (MSG_RES_CHEAT_KICK_GM*)msg;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_KICK_SUCCESS )
			{
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_KICK_RES_SUCCESS_GM, msg, MAX_LOADSTRING ) == 0 )
				{	
					/// 결과 출력
					cStringT str;
					str.Format( L"Cheat: /kick %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					/// 결과 출력
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
			}
			else
			{
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_KICK_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					/// 결과 출력
					cStringT str;
					str.Format( L"Cheat Failed: /kick %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					/// 결과 출력
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
			}
		}
		break;
	case NM_CHEAT_RECOVER_RES:
		{
			MSG_RES_CHEAT_RECOVER* res = (MSG_RES_CHEAT_RECOVER*)msg;

			if( hero == 0 )
				return;

			hero->HPChange( res->mMaxHP, res->mMaxHP, false );
			hero->MPChange( res->mMaxMP, res->mMaxMP );
		}
		break;
	case NM_CHEAT_REBIRTH_RES:
		{
			MSG_RES_CHEAT_REBIRTH* res = (MSG_RES_CHEAT_REBIRTH*)msg;

			if( hero == 0 )
				return;

			cRevivalWindow* win = GAMEUI->GetReVivalWindow();
			if( win )
				win->Hide();

			hero->SetState( eOBJECT_STATE_IDLE );
			hero->HPChange( res->mMaxHP, res->mMaxHP, false );
			hero->MPChange( res->mMaxMP, res->mMaxMP );
		}
		break;
	case NM_CHEAT_STOP_RES:
		{
			MSG_ERROR* res = (MSG_ERROR*)msg;

			if( hero == 0 )
				return;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_STOP_SUCCESS )
			{
				hero->SetStopFlag( eSTOP_CHEATSTOP );

				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_STOP_RES_SUCCESS, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_GM, L"운영자에 의해 캐릭터의 이동, 스킬 사용, 공격, 거래, 아이템 습득, 창고 이용이 금지 되었습니다." );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_GM, msg );
				}
			}
			else
			{
				/// 에러 출력
				assert( 0 && "Cheat Failed: /stop" );
			}
		
		}
		break;
	case NM_CHEAT_STOP_RES_GM:
		{
			MSG_RES_CHEAT_STOP_GM* res = (MSG_RES_CHEAT_STOP_GM*)msg;

			if( hero == 0 )
				return;
			
			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_STOP_SUCCESS )
			{
				/// 결과 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_STOP_RES_SUCCESS_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					cStringT str;
					str.Format( L"Cheat: /stop %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
			}
			else
			{
				/// 에러 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_STOP_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /stop" );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
				}
			}
		}
		break;
	case NM_CHEAT_CANCEL_STOP_RES:
		{
			MSG_ERROR* res = (MSG_ERROR*)msg;

			if( hero == 0 )
				return;

			if( res->ErrorCode == ERROR_CHEAT_STOP_SUCCESS )
			{
				hero->SetStopFlag( eSTOP_NONE );
				hero->SetState( eOBJECT_STATE_IDLE );
				
				TCHAR msg[ MAX_LOADSTRING ];
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_CANCEL_STOP_RES_SUCCESS, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_GM, L"운영자에 의해 캐릭터의 이동, 스킬 사용, 공격, 거래, 아이템 습득, 창고 이용의 금지상태가 해제 되었습니다." );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_GM, msg );
				}
			}
			else
			{
				/// 에러 출력
				assert( 0 && "Cheat Failed: /cancelstop" );
			}
		}
		break;
	case NM_CHEAT_CANCEL_STOP_RES_GM:
		{
			MSG_RES_CHEAT_CANCEL_STOP_GM* res = (MSG_RES_CHEAT_CANCEL_STOP_GM*)msg;

			if( hero == 0 )
				return;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_NO_ERROR )
			{
				/// 결과 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_CANCEL_STOP_RES_SUCCESS_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					cStringT str;
					str.Format( L"Cheat: /cancelstop %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}

			}
			else
			{
				/// 에러 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_CANCEL_STOP_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /cancelstop" );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
				}
			}
		}
		break;
	case NM_CHEAT_MAKE_RES:
		{
			MSG_RES_CHEAT_MAKE* res = (MSG_RES_CHEAT_MAKE*)msg;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_MAKE_SUCCESS )
			{
				sInventory* ptr = res->inventory;

				for( int cnt = 0; cnt < res->rowCount ; ++cnt, ptr++ )
					ITEMMAN->CheatMakeItem( ptr );
			}
			else
			{
				/// 에러 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_MAKE_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /make" );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
				}
			}
		}
		break;
	case NM_CHEAT_NO_CHAT_RES_GM:
		{
			MSG_RES_CHEAT_NO_CHAT_GM* res = (MSG_RES_CHEAT_NO_CHAT_GM*)msg;

			if( hero == 0 )
				return;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_NO_ERROR )
			{
				/// 결과 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_NOCHAT_RES_SUCCESS_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					cStringT str;
					str.Format( L"Cheat: /nochat %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
			}
			else
			{
				/// 에러 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_NOCHAT_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /nochat" );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
				}
			
			}
		}
		break;
	case NM_CHEAT_ALLOW_CHAT_RES_GM:
		{
			MSG_RES_CHEAT_ALLOW_CHAT_GM* res = (MSG_RES_CHEAT_ALLOW_CHAT_GM*)msg;

			if( hero == 0 )
				return;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_NO_ERROR )
			{
				/// 결과 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_ALLOW_CHAT_RES_SUCCESS_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					cStringT str;
					str.Format( L"Cheat: /allowchat %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
			}
			else
			{
				/// 에러 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_ALLOW_CHAT_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /allowchat" );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
				}
			}
		}
		break;
	case NM_CHEAT_CALL_RES_GM:
		{
			
			MSG_RES_CHEAT_CALL_GM* res = (MSG_RES_CHEAT_CALL_GM*)msg;

			if( hero == 0 )
				return;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_NO_ERROR )
			{
				/// 결과 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_CALL_RES_SUCCESS_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					cStringT str;
					str.Format( L"Cheat: /call %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
			}
			else
			{
				/// 에러 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_CALL_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /call" );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
				}

			}
		}
		break;
	case NM_CHEAT_CHASE_RES_GM:
		{
			MSG_RES_CHEAT_CHASE_GM* res = (MSG_RES_CHEAT_CHASE_GM*)msg;

			if( hero == 0 )
				return;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_NO_ERROR )
			{
				/// 결과 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_CHASE_RES_SUCCESS_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					cStringT str;
					str.Format( L"Cheat: /chase %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
			}
			else
			{
				/// 에러 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_CHASE_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /chase" );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
				}
			}
		}
		break;
	case NM_CHEAT_MOVE_RES_GM:
		{
			MSG_RES_CHEAT_MOVE_GM* res = (MSG_RES_CHEAT_MOVE_GM*)msg;

			if( hero == 0 )
				return;

			TCHAR msg[ MAX_LOADSTRING ];
			if( res->ErrorCode == ERROR_CHEAT_NO_ERROR )
			{
				/// 결과 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_MOVE_RES_SUCCESS_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					cStringT str;
					str.Format( L"Cheat: /move %s", res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
				else
				{
					cStringT str;
					str.Format( L"%s %s", msg, res->mCharName );
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
				}
			}
			else
			{
				/// 에러 출력
				if( LoadString( GetModuleHandle(NULL), IDS_GMTOOL_MOVE_RES_FAIL_GM, msg, MAX_LOADSTRING ) == 0 )
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /move" );
				}
				else
				{
					CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, msg );
				}
			}
		}
		break;
	case NM_CHEAT_EXP_RES_GM:
		{
			MSG_RES_CHEAT_EXP_GM* res = (MSG_RES_CHEAT_EXP_GM*)msg;

			if( hero == 0 )
				return;

			if( res->ErrorCode == 0 )
			{
				/// 결과 출력
				cStringT str;
				str.Format( L"Cheat: /exp %d%%", res->mExpUpPercent );
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
			}
			else
			{
				/// 에러 출력
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /exp" );
			}
		}
		break;

	case NM_CHEAT_SXP_RES_GM:
		{
			MSG_RES_CHEAT_SXP_GM* res = (MSG_RES_CHEAT_SXP_GM*)msg;

			if( hero == 0 )
				return;

			if( res->ErrorCode == 0 )
			{
				/// 결과 출력
				cStringT str;
				str.Format( L"Cheat: /sxp %d%%", res->mSxpUpPercent );
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
			}
			else
			{
				/// 에러 출력
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /sxp" );
			}
		}
		break;

	case NM_CHEAT_DROP_RES_GM:
		{
			MSG_RES_CHEAT_DROP_GM* res = (MSG_RES_CHEAT_DROP_GM*)msg;

			if( hero == 0 )
				return;

			if( res->ErrorCode == 0 )
			{
				/// 결과 출력
				cStringT str;
				str.Format( L"Cheat: /drop %d%%", res->mDropUpPercent );
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, str.Cstr() );
			}
			else
			{
				/// 에러 출력
				CHATMANAGER->AddSystemMsg( eSYSTEM_NORMAL, L"Cheat Failed: /drop" );
			}
		}
		break;
#endif // _GMTOOL
	}
}
