void CUser::LoginProcess(Packet & pkt)
{
	// Enforce only one login request per session
	// It's common for players to spam this at the server list when a response isn't received immediately.
	if (!m_strAccountID.empty())
		return;

	Packet result(WIZ_LOGIN);
	CUser * pUser;
	std::string strAccountID, strPasswd;
	pkt >> strAccountID >> strPasswd;
	if (strAccountID.empty() || strAccountID.size() > MAX_ID_SIZE
		|| strPasswd.empty() || strPasswd.size() > MAX_PW_SIZE)
		goto fail_return;

	pUser = g_pMain->GetUserPtr(strAccountID, TYPE_ACCOUNT);
	if (pUser && (pUser->GetSocketID() != GetSocketID()))
	{
		pUser->Disconnect();
		goto fail_return;
	}

	result << strPasswd;
	m_strAccountID = strAccountID;
	g_pMain->AddDatabaseRequest(result, this);
	return;

fail_return:
	result << uint8(-1);
	Send(&result);
}
void CUser::SelCharToAgent(Packet & pkt)
{
	Packet result(WIZ_SEL_CHAR);
	std::string strUserID, strAccountID;
	uint8 bInit;

	pkt >> strAccountID >> strUserID >> bInit;
	if (strAccountID.empty() || strAccountID.size() > MAX_ID_SIZE
		|| strUserID.empty() || strUserID.size() > MAX_ID_SIZE
		|| strAccountID != m_strAccountID)
	{
		Disconnect();
		return;
	}

	// Disconnect any currently logged in sessions.
	CUser *pUser = g_pMain->GetUserPtr(strUserID, TYPE_CHARACTER);

	if (pUser && (pUser->GetSocketID() != GetSocketID()))
	{
		pUser->Disconnect();

		// And reject the login attempt (otherwise we'll probably desync char data)
		result << uint8(0);
		Send(&result);
		return;
	}

	result << strUserID << bInit;
	g_pMain->AddDatabaseRequest(result, this);
}
Beispiel #3
0
void CUser::ChatTargetSelect(Packet & pkt)
{
	uint8 type = pkt.read<uint8>();

	// TO-DO: Replace this with an enum
	// Attempt to find target player in-game
	if (type == 1)
	{
		Packet result(WIZ_CHAT_TARGET, type);
		std::string strUserID;
		pkt >> strUserID;
		if (strUserID.empty() || strUserID.size() > MAX_ID_SIZE)
			return;

		CUser *pUser = g_pMain->GetUserPtr(strUserID, TYPE_CHARACTER);
		if (pUser == nullptr || pUser == this)
		{
			result << int16(0); 
		}
		else if (pUser->isBlockingPrivateChat())
		{
			result << int16(-1);
		}
		else
		{
			m_sPrivateChatUser = pUser->GetSocketID();
			result << int16(1) << pUser->GetName();
		}
		Send(&result);
	}
void CUser::PartyProcess(char *pBuf)
{
	int index = 0, idlength = 0, memberid = -1;
	char strid[MAX_ID_SIZE+1]; memset( strid, 0x00, MAX_ID_SIZE+1 );
	BYTE subcommand, result;
	CUser* pUser = NULL;

	subcommand = GetByte( pBuf, index );
	switch( subcommand ) {
	case PARTY_CREATE:
		idlength = GetShort( pBuf, index );
		if (idlength <= 0 || idlength > MAX_ID_SIZE) return ;
		GetString( strid, pBuf, idlength, index );
		pUser = m_pMain->GetUserPtr(strid, TYPE_CHARACTER);
		if( pUser ) {
			memberid = pUser->GetSocketID();
			PartyRequest( memberid, TRUE );
		}
		break;
	case PARTY_PERMIT:
		result = GetByte( pBuf, index );
		if( result ) 
			PartyInsert();
		else							
			PartyCancel();
		break;
	case PARTY_INSERT:
		idlength = GetShort( pBuf, index );
		if (idlength <= 0 || idlength > MAX_ID_SIZE) return ;
		GetString( strid, pBuf, idlength, index );
		pUser = m_pMain->GetUserPtr(strid, TYPE_CHARACTER);
		if( pUser ) {
			memberid = pUser->GetSocketID();
			PartyRequest( memberid, FALSE );
		}
		break;
	case PARTY_REMOVE:
		memberid = GetShort( pBuf, index );
		PartyRemove( memberid );
		break;
	case PARTY_DELETE:
		PartyDelete();
		break;
	}
}
void CUdpSocket::RecvDestroyKnights( char* pBuf )
{
	int send_index = 0, knightsindex = 0, index = 0, flag = 0;
	char send_buff[128]; memset( send_buff, 0x00, 128 );
	char finalstr[128]; memset( finalstr, 0x00, 128 );
	CKnights*	pKnights = NULL;
	CUser* pTUser = NULL;

	knightsindex = GetShort( pBuf, index );

	pKnights = m_pMain->m_KnightsArray.GetData( knightsindex );
	if( !pKnights )		{
		TRACE("UDP - ### RecvDestoryKnights  Fail == index = %d ###\n", knightsindex);
		return;
	}

	flag = pKnights->m_byFlag;

	// 클랜이나 기사단이 파괴된 메시지를 보내고 유저 데이타를 초기화
	if( flag == CLAN_TYPE)
		sprintf( finalstr, "#### %s 클랜이 해체되었습니다 ####", pKnights->m_strName );
	else if( flag == KNIGHTS_TYPE )
		sprintf( finalstr, "#### %s 기사단이 해체되었습니다 ####", pKnights->m_strName );

	memset( send_buff, 0x00, 128 );		send_index = 0;
	SetByte( send_buff, WIZ_CHAT, send_index );
	SetByte( send_buff, KNIGHTS_CHAT, send_index );
	SetByte( send_buff, 1, send_index );
	SetShort( send_buff, -1, send_index );
	SetShort( send_buff, strlen(finalstr), send_index );
	SetString( send_buff, finalstr, strlen(finalstr), send_index );
	m_pMain->Send_KnightsMember( knightsindex, send_buff, send_index );

	for (int i = 0; i < MAX_USER; i++)
	{
		pTUser = m_pMain->GetUnsafeUserPtr(i);
		if (pTUser == NULL || pTUser->m_pUserData->m_bKnights != knightsindex)
			continue;

		pTUser->m_pUserData->m_bKnights = 0;
		pTUser->m_pUserData->m_bFame = 0;

		m_pMain->m_KnightsManager.RemoveKnightsUser( knightsindex, pTUser->m_pUserData->m_id );

		memset( send_buff, 0x00, 128 ); send_index = 0;
		SetByte( send_buff, WIZ_KNIGHTS_PROCESS, send_index );
		SetByte( send_buff, KNIGHTS_MODIFY_FAME, send_index );
		SetByte( send_buff, 0x01, send_index );
		SetShort( send_buff, pTUser->GetSocketID(), send_index );
		SetShort( send_buff, pTUser->m_pUserData->m_bKnights, send_index );
		SetByte( send_buff, pTUser->m_pUserData->m_bFame, send_index );
		m_pMain->Send_Region( send_buff, send_index, pTUser->GetMap(), pTUser->m_RegionX, pTUser->m_RegionZ, NULL, false );
	}
	
	m_pMain->m_KnightsArray.DeleteData( knightsindex );
	//TRACE("UDP - RecvDestoryKnights - index=%d\n", knightsindex);
}
void CUser::SelCharToAgent(char *pBuf)
{
	int index = 0, send_index = 0, retvalue = 0;
	char userid[MAX_ID_SIZE+1], accountid[MAX_ID_SIZE+1];
	memset( userid, NULL, MAX_ID_SIZE+1 );
	memset( accountid, NULL, MAX_ID_SIZE+1 );
	char send_buff[256];
	memset( send_buff, NULL, 256);
	CUser* pUser = NULL;
	CTime t = CTime::GetCurrentTime();
	BYTE	bInit = 0x01;

	if (!GetKOString(pBuf, accountid, index, MAX_ID_SIZE)
		|| !GetKOString(pBuf, userid, index, MAX_ID_SIZE))
		goto fail_return;

	bInit = GetByte( pBuf, index );
	
	if( _strnicmp( accountid, m_strAccountID, MAX_ID_SIZE ) != 0 ) {
		Close();
		return;
	}

	pUser = m_pMain->GetUserPtr(userid, TYPE_CHARACTER);
	if( pUser && (pUser->GetSocketID() != GetSocketID()) ) {
		pUser->Close();
		goto fail_return;
	}

	SetByte( send_buff, WIZ_SEL_CHAR, send_index );
	SetShort( send_buff, m_Sid, send_index );
	SetKOString(send_buff, m_strAccountID, send_index);
	SetKOString(send_buff, userid, send_index);
	SetByte( send_buff, bInit, send_index );

	m_pMain->WriteLog("[SelCharToAgent : %d:%d:%d] - acname=%s, name=%s, TH: %lu, Rear : %d\r\n", t.GetHour(), t.GetMinute(), t.GetSecond(), m_strAccountID, userid, GetCurrentThreadId(), m_pMain->m_LoggerSendQueue.GetRearPointer());

	retvalue = m_pMain->m_LoggerSendQueue.PutData( send_buff, send_index );
	if (retvalue < SMQ_FULL)
		return;

	DEBUG_LOG("SelChar Send Fail : %d", retvalue);

fail_return:
	send_index = 0;
	SetByte( send_buff, WIZ_SEL_CHAR, send_index );
	SetByte( send_buff, 0x00, send_index );
	Send( send_buff, send_index );
}
void CUser::PartyBBSRegister(char *pBuf)
{
	CUser* pUser = NULL;
	int index = 0, send_index = 0;	// Basic Initializations. 			
	BYTE result = 0; short bbs_len = 0;
	char send_buff[256]; memset(send_buff, NULL, 256);
	int i = 0, counter = 0;

	if (m_sPartyIndex != -1) goto fail_return;	// You are already in a party!
	if (m_bNeedParty == 2) goto fail_return;	// You are already on the BBS!

	m_bNeedParty = 2;	// Success! Now you officially need a party!!!
	result = 1;

	SetByte(send_buff, 2, send_index);	// Send new 'Need Party Status' to region!!!
	SetByte(send_buff, m_bNeedParty, send_index);
	StateChange(send_buff);

	send_index = 0; memset(send_buff, NULL, 256);	// Now, let's find out which page the user is on.
	for (i = 0 ; i < MAX_USER ; i++) {
		pUser = m_pMain->GetUnsafeUserPtr(i);
		if (pUser == NULL
			|| pUser->getNation() != getNation()
			|| pUser->m_bNeedParty == 1) 
			continue;

		if( !(   ( pUser->m_pUserData->m_bLevel <= (int)(m_pUserData->m_bLevel * 1.5) && pUser->m_pUserData->m_bLevel >= (int)(m_pUserData->m_bLevel * 1.5)) 
			  || ( pUser->m_pUserData->m_bLevel <= (m_pUserData->m_bLevel+8) && pUser->m_pUserData->m_bLevel >= ((int)(m_pUserData->m_bLevel)-8) ) 
		) ) continue;

		if (pUser->GetSocketID() == GetSocketID()) break;
		counter++;		
	}

	SetShort(send_buff, counter / MAX_BBS_PAGE, send_index);
	PartyBBSNeeded(send_buff, PARTY_BBS_REGISTER);
	return;

fail_return:
	SetByte(send_buff, WIZ_PARTY_BBS, send_index);
	SetByte(send_buff, PARTY_BBS_REGISTER, send_index);
	SetByte(send_buff, result, send_index);
	Send(send_buff, send_index);
	return;
}
void CUdpSocket::RecvModifyFame( char* pBuf, BYTE command )
{
	int index = 0, send_index = 0, knightsindex = 0, idlen = 0, vicechief = 0;
	char send_buff[128]; memset( send_buff, 0x00, 128 );
	char finalstr[128]; memset( finalstr, 0x00, 128 );
	char userid[MAX_ID_SIZE+1]; memset( userid, 0x00, MAX_ID_SIZE+1 );
	CUser* pTUser = NULL;
	CKnights*	pKnights = NULL;

	knightsindex = GetShort( pBuf, index );
	idlen = GetShort( pBuf, index );
	GetString( userid, pBuf, idlen, index );

	pTUser = m_pMain->GetUserPtr(userid, TYPE_CHARACTER);
	pKnights = m_pMain->m_KnightsArray.GetData( knightsindex );

	switch( command ) {
	case KNIGHTS_REMOVE:
		if( pTUser ) {
			pTUser->m_pUserData->m_bKnights = 0;
			pTUser->m_pUserData->m_bFame = 0;
			sprintf( finalstr, "#### %s님이 추방되셨습니다. ####", pTUser->m_pUserData->m_id );
			m_pMain->m_KnightsManager.RemoveKnightsUser( knightsindex, pTUser->m_pUserData->m_id );
		}
		else	{
			m_pMain->m_KnightsManager.RemoveKnightsUser( knightsindex, userid );
		}
		break;
	case KNIGHTS_ADMIT:
		if( pTUser )
			pTUser->m_pUserData->m_bFame = KNIGHT;
		break;
	case KNIGHTS_REJECT:
		if( pTUser ) {
			pTUser->m_pUserData->m_bKnights = 0;
			pTUser->m_pUserData->m_bFame = 0;
			m_pMain->m_KnightsManager.RemoveKnightsUser( knightsindex, pTUser->m_pUserData->m_id );
		}
		break;
	case KNIGHTS_CHIEF+0x10:
		if( pTUser )	{
			pTUser->m_pUserData->m_bFame = CHIEF;
			m_pMain->m_KnightsManager.ModifyKnightsUser( knightsindex, pTUser->m_pUserData->m_id );
			sprintf( finalstr, "#### %s님이 단장으로 임명되셨습니다. ####", pTUser->m_pUserData->m_id );
		}
		break;
	case KNIGHTS_VICECHIEF+0x10:
		if( pTUser )	{
			pTUser->m_pUserData->m_bFame = VICECHIEF;
			m_pMain->m_KnightsManager.ModifyKnightsUser( knightsindex, pTUser->m_pUserData->m_id );
			sprintf( finalstr, "#### %s님이 부단장으로 임명되셨습니다. ####", pTUser->m_pUserData->m_id );
		}
		break;
	case KNIGHTS_OFFICER+0x10:
		if( pTUser )
			pTUser->m_pUserData->m_bFame = OFFICER;
		break;
	case KNIGHTS_PUNISH+0x10:
		if( pTUser )
			pTUser->m_pUserData->m_bFame = PUNISH;
		break;
	}

	if( pTUser ) {
		//TRACE("UDP - RecvModifyFame - command=%d, nid=%d, name=%s, index=%d, fame=%d\n", command, pTUser->GetSocketID(), pTUser->m_pUserData->m_id, knightsindex, pTUser->m_pUserData->m_bFame);
		memset( send_buff, 0x00, 128 ); send_index = 0;
		SetByte( send_buff, WIZ_KNIGHTS_PROCESS, send_index );
		SetByte( send_buff, KNIGHTS_MODIFY_FAME, send_index );
		SetByte( send_buff, 0x01, send_index );
		if( command == KNIGHTS_REMOVE )	{
			SetShort( send_buff, pTUser->GetSocketID(), send_index );
			SetShort( send_buff, pTUser->m_pUserData->m_bKnights, send_index );
			SetByte( send_buff, pTUser->m_pUserData->m_bFame, send_index );
			m_pMain->Send_Region( send_buff, send_index, pTUser->GetMap(), pTUser->m_RegionX, pTUser->m_RegionZ, NULL, false );
		}
		else	{
			SetShort( send_buff, pTUser->GetSocketID(), send_index );
			SetShort( send_buff, pTUser->m_pUserData->m_bKnights, send_index );
			SetByte( send_buff, pTUser->m_pUserData->m_bFame, send_index );
			pTUser->Send( send_buff, send_index );
		}

		if( command == KNIGHTS_REMOVE )	{
			memset( send_buff, 0x00, 128 );		send_index = 0;
			SetByte( send_buff, WIZ_CHAT, send_index );
			SetByte( send_buff, KNIGHTS_CHAT, send_index );
			SetByte( send_buff, 1, send_index );
			SetShort( send_buff, -1, send_index );
			SetShort( send_buff, strlen(finalstr), send_index );
			SetString( send_buff, finalstr, strlen(finalstr), send_index );
			pTUser->Send( send_buff, send_index );
		}
	}

	memset( send_buff, 0x00, 128 );		send_index = 0;
	SetByte( send_buff, WIZ_CHAT, send_index );
	SetByte( send_buff, KNIGHTS_CHAT, send_index );
	SetByte( send_buff, 1, send_index );
	SetShort( send_buff, -1, send_index );
	SetShort( send_buff, strlen(finalstr), send_index );
	SetString( send_buff, finalstr, strlen(finalstr), send_index );
	m_pMain->Send_KnightsMember( knightsindex, send_buff, send_index );
}
Beispiel #9
0
void CAISocket::RecvNpcAttack(char* pBuf)
{
	int index = 0, send_index = 0, sid = -1, tid = -1, nHP = 0, temp_damage = 0;
	BYTE type, result, byAttackType = 0;
	float fDir=0.0f;
	short damage = 0;
	CNpc* pNpc = NULL, *pMon = NULL;
	CUser* pUser = NULL;
	char pOutBuf[1024];
	_OBJECT_EVENT* pEvent = NULL;

	type = GetByte(pBuf,index);
	result = GetByte(pBuf,index);
	sid = GetShort(pBuf,index);
	tid = GetShort(pBuf,index);
	damage = GetShort(pBuf,index);
	nHP = GetDWORD(pBuf,index);
	byAttackType = GetByte(pBuf, index);

	//TRACE("CAISocket-RecvNpcAttack : sid=%s, tid=%d, zone_num=%d\n", sid, tid, m_iZoneNum);

	if(type == 0x01)			// user attack -> npc
	{
		pNpc = m_pMain->m_arNpcArray.GetData(tid);
		if(!pNpc)	return;
		pNpc->m_iHP -= damage;
		if( pNpc->m_iHP < 0 )
			pNpc->m_iHP = 0;

		if(result == 0x04)	{								// 마법으로 죽는경우
			SetByte( pOutBuf, WIZ_DEAD, send_index );
			SetShort( pOutBuf, tid, send_index );
			m_pMain->Send_Region(pOutBuf, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false);
		}
		else {

			SetByte(pOutBuf, WIZ_ATTACK, send_index);
			SetByte( pOutBuf, byAttackType, send_index );		// 직접:1, 마법:2, 지속마법:3
			//if(result == 0x04)								// 마법으로 죽는경우
			//	SetByte( pOutBuf, 0x02, send_index );
			//else											// 단순공격으로 죽는경우
				SetByte( pOutBuf, result, send_index );
			SetShort( pOutBuf, sid, send_index );
			SetShort( pOutBuf, tid, send_index );
		
			m_pMain->Send_Region(pOutBuf, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false);

		}

		pUser = m_pMain->GetUserPtr(sid);
		if (pUser != NULL) 
		{
			pUser->SendTargetHP( 0, tid, -damage ); 
			if( byAttackType != MAGIC_ATTACK && byAttackType != DURATION_ATTACK) {
				pUser->ItemWoreOut(ATTACK, damage);

			// LEFT HAND!!! by Yookozuna
			temp_damage = damage * pUser->m_bMagicTypeLeftHand / 100 ;

			switch (pUser->m_bMagicTypeLeftHand) {	// LEFT HAND!!!
				case ITEM_TYPE_HP_DRAIN :	// HP Drain		
					pUser->HpChange(temp_damage, 0);	
					break;
				case ITEM_TYPE_MP_DRAIN :	// MP Drain		
					pUser->MSpChange(temp_damage);
					break;
				}				
			
			temp_damage = 0;	// reset data;

			// RIGHT HAND!!! by Yookozuna
			temp_damage = damage * pUser->m_bMagicTypeRightHand / 100 ;

			switch (pUser->m_bMagicTypeRightHand) {	// LEFT HAND!!!
				case ITEM_TYPE_HP_DRAIN :	// HP Drain		
					pUser->HpChange(temp_damage, 0);			
					break;
				case ITEM_TYPE_MP_DRAIN :	// MP Drain		
					pUser->MSpChange(temp_damage);
					break;
				}	
//		
			}
		}

		if(result == 0x02 || result == 0x04)		// npc dead
		{
			pNpc->GetMap()->RegionNpcRemove(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, tid);
			
//			TRACE("--- Npc Dead : Npc를 Region에서 삭제처리.. ,, region_x=%d, y=%d\n", pNpc->m_sRegion_X, pNpc->m_sRegion_Z);
			pNpc->m_sRegion_X = 0;		pNpc->m_sRegion_Z = 0;
			pNpc->m_NpcState = NPC_DEAD;
			if( pNpc->m_byObjectType == SPECIAL_OBJECT )	{
				pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid );
				if( pEvent )	pEvent->byLife = 0;
			}
			if (pNpc->m_tNpcType == 2 && pUser != NULL) // EXP 
				pUser->GiveItem(900001000, 1);	
		}
	}
	else if(type == 0x02)		// npc attack -> user
	{
		pNpc = m_pMain->m_arNpcArray.GetData(sid);
		if(!pNpc)	return;

		//TRACE("CAISocket-RecvNpcAttack 222 : sid=%s, tid=%d, zone_num=%d\n", sid, tid, m_iZoneNum);
		if( tid >= USER_BAND && tid < NPC_BAND)
		{
			pUser = m_pMain->GetUserPtr(tid);
			if(pUser == NULL)	
				return;

			// sungyong 2002. 02.04
/*			if( sHP <= 0 && pUser->m_pUserData->m_sHp > 0 ) {
				TRACE("Npc Attack : id=%s, result=%d, AI_HP=%d, GM_HP=%d\n", pUser->m_pUserData->m_id, result, sHP, pUser->m_pUserData->m_sHp);
				if(result == 0x02)
					pUser->HpChange(-1000, 1);
			}
			else	
				pUser->HpChange(-damage, 1);
			*/  
			// ~sungyong 2002. 02.04
			if( pUser->m_MagicProcess.m_bMagicState == CASTING ) 
				pUser->m_MagicProcess.IsAvailable( 0, -1, -1, MAGIC_EFFECTING ,0,0,0 );
			pUser->HpChange(-damage, 1, true);
			pUser->ItemWoreOut(DEFENCE, damage);

			SetByte(pOutBuf, WIZ_ATTACK, send_index);
			SetByte( pOutBuf, byAttackType, send_index );
			if(result == 0x03)
				SetByte( pOutBuf, 0x00, send_index );
			else
				SetByte( pOutBuf, result, send_index );
			SetShort( pOutBuf, sid, send_index );
			SetShort( pOutBuf, tid, send_index );
			
			m_pMain->Send_Region(pOutBuf, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false);

//			TRACE("RecvNpcAttack : id=%s, result=%d, AI_HP=%d, GM_HP=%d\n", pUser->m_pUserData->m_id, result, sHP, pUser->m_pUserData->m_sHp);
			//TRACE("RecvNpcAttack ==> sid = %d, tid = %d, result = %d\n", sid, tid, result);

			if(result == 0x02) {		// user dead
				if (pUser->m_bResHpType == USER_DEAD)
					return;
				// 유저에게는 바로 데드 패킷을 날림... (한 번 더 보냄, 유령을 없애기 위해서)
				send_index = 0;
				SetByte(pOutBuf, WIZ_DEAD, send_index);
				SetShort(pOutBuf, pUser->GetSocketID(), send_index);
				m_pMain->Send_Region(pOutBuf, send_index, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ);

				pUser->m_bResHpType = USER_DEAD;
				DEBUG_LOG("*** User Dead, id=%s, result=%d, AI_HP=%d, GM_HP=%d, x=%d, z=%d", pUser->m_pUserData->m_id, result, nHP, pUser->m_pUserData->m_sHp, (int)pUser->m_pUserData->m_curx, (int)pUser->m_pUserData->m_curz);

				send_index = 0;
				if( pUser->m_pUserData->m_bFame == COMMAND_CAPTAIN )	{	// 지휘권한이 있는 유저가 죽는다면,, 지휘 권한 박탈
					pUser->m_pUserData->m_bFame = CHIEF;
					SetByte( pOutBuf, WIZ_AUTHORITY_CHANGE, send_index );
					SetByte( pOutBuf, COMMAND_AUTHORITY, send_index );
					SetShort( pOutBuf, pUser->GetSocketID(), send_index );
					SetByte( pOutBuf, pUser->m_pUserData->m_bFame, send_index );
					m_pMain->Send_Region( pOutBuf, send_index, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ );
					// sungyong tw
					pUser->Send( pOutBuf, send_index );
					// ~sungyong tw
					TRACE("---> AISocket->RecvNpcAttack() Dead Captain Deprive - %s\n", pUser->m_pUserData->m_id);
					if( pUser->m_pUserData->m_bNation == KARUS )			m_pMain->Announcement( KARUS_CAPTAIN_DEPRIVE_NOTIFY, KARUS );
					else if( pUser->m_pUserData->m_bNation == ELMORAD )	m_pMain->Announcement( ELMORAD_CAPTAIN_DEPRIVE_NOTIFY, ELMORAD );

				}

				if(pNpc->m_tNpcType == NPC_PATROL_GUARD)	{	// 경비병에게 죽는 경우라면..
					pUser->ExpChange( -pUser->m_iMaxExp/100 );
					//TRACE("RecvNpcAttack : 경험치를 1%깍기 id = %s\n", pUser->m_pUserData->m_id);
				}
				else {
//
					if( pUser->m_pUserData->m_bZone != pUser->m_pUserData->m_bNation && pUser->m_pUserData->m_bZone < 3) {
						pUser->ExpChange(-pUser->m_iMaxExp / 100);
						//TRACE("정말로 1%만 깍였다니까요 ㅠ.ㅠ");
					}
//				
					else {
						pUser->ExpChange( -pUser->m_iMaxExp/20 );
					}
					//TRACE("RecvNpcAttack : 경험치를 5%깍기 id = %s\n", pUser->m_pUserData->m_id);
				}
			}
		}
		else if(tid >= NPC_BAND)		// npc attack -> monster
		{
			pMon = m_pMain->m_arNpcArray.GetData(tid);
			if(!pMon)	return;
			pMon->m_iHP -= damage;
			if( pMon->m_iHP < 0 )
				pMon->m_iHP = 0;

			send_index = 0;
			SetByte(pOutBuf, WIZ_ATTACK, send_index);
			SetByte( pOutBuf, byAttackType, send_index );
			SetByte( pOutBuf, result, send_index );
			SetShort( pOutBuf, sid, send_index );
			SetShort( pOutBuf, tid, send_index );
			if(result == 0x02)	{		// npc dead
				pNpc->GetMap()->RegionNpcRemove(pMon->m_sRegion_X, pMon->m_sRegion_Z, tid);
//				TRACE("--- Npc Dead : Npc를 Region에서 삭제처리.. ,, region_x=%d, y=%d\n", pMon->m_sRegion_X, pMon->m_sRegion_Z);
				pMon->m_sRegion_X = 0;		pMon->m_sRegion_Z = 0;
				pMon->m_NpcState = NPC_DEAD;
				if( pNpc->m_byObjectType == SPECIAL_OBJECT )	{
					pEvent = pNpc->GetMap()->GetObjectEvent( pMon->m_sSid );
					if( pEvent )	pEvent->byLife = 0;
				}
			}

			m_pMain->Send_Region(pOutBuf, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false);
		}
	}
}