示例#1
0
void CAISocket::RecvNpcDead(Packet & pkt)
{
	uint16 nid = pkt.read<uint16>();
	CNpc* pNpc = g_pMain->m_arNpcArray.GetData(nid);
	if (pNpc == NULL)
		return;

	C3DMap* pMap = pNpc->GetMap();
	if (pMap == NULL)
		return;

	if (pNpc->m_byObjectType == SPECIAL_OBJECT)
	{
		_OBJECT_EVENT *pEvent = pMap->GetObjectEvent(pNpc->m_sSid);
		if (pEvent)
			pEvent->byLife = 0;
	}

	pMap->RegionNpcRemove(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, nid);

	Packet result(WIZ_DEAD);
	result << nid;
	g_pMain->Send_Region(&result, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z);

	pNpc->m_sRegion_X = pNpc->m_sRegion_Z = 0;
}
示例#2
0
void CAISocket::RecvNpcInfo(Packet & pkt)
{
	std::string strName;
	uint8 Mode, byDirection;
	uint16 sNid;

	pkt.SByte();
	pkt >> Mode >> sNid;

	CNpc *pNpc = g_pMain->m_arNpcArray.GetData(sNid);
	if (pNpc == NULL)
		return;

	pkt >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2
		>> pNpc->m_bZone >> strName >> pNpc->m_bNation >> pNpc->m_bLevel
		>> pNpc->m_curx >> pNpc->m_curz >> pNpc->m_cury >> byDirection >> pNpc->m_NpcState
		>> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen
		>> pNpc->m_sTotalHitrate >> pNpc->m_sTotalEvasionrate >> pNpc->m_sTotalAc >> pNpc->m_byObjectType
		>> pNpc->m_byTrapNumber;

	if (strName.empty() || strName.length() > MAX_NPC_SIZE)
	{
		pNpc->DecRef();
		return;
	}

	pNpc->m_byDirection = byDirection;
	strcpy(pNpc->m_strName, strName.c_str());

	if (pNpc->GetMap() == NULL)
		return;

	pNpc->InsertRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ());
	pNpc->SetRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ());

	if (pNpc->m_byObjectType == SPECIAL_OBJECT)
	{
		_OBJECT_EVENT *pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid );
		if (pEvent != NULL)
			pEvent->byLife = 1;
	}

	if (Mode == 0)
	{
		TRACE("RecvNpcInfo - dead monster nid=%d, name=%s\n", pNpc->GetID(), pNpc->m_strName);
		return;
	}

	pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY());
}
示例#3
0
void CAISocket::RecvGateOpen( char* pBuf )
{
	int index = 0, nNid = 0, nSid = 0, nGateFlag = 0;
	CNpc* pNpc = NULL;
	_OBJECT_EVENT* pEvent = NULL;

	nNid = GetShort(pBuf, index);
	nSid = GetShort(pBuf, index);
	nGateFlag = GetByte(pBuf, index);

	pNpc = m_pMain->m_arNpcArray.GetData(nNid);
	if (pNpc == NULL)	
	{
		TRACE("#### RecvGateOpen Npc Pointer null : nid=%d ####\n", nNid);
		return;
	}

	pNpc->m_byGateOpen = nGateFlag; // possibly not needed (we'll do it below), but need to make sure.

	pEvent = pNpc->GetMap()->GetObjectEvent(nSid);
	if (pEvent == NULL)	
	{
		TRACE("#### RecvGateOpen Npc Object fail : nid=%d, sid=%d ####\n", nNid, nSid);
		return;
	}

	//TRACE("---> RecvGateOpen Npc Object fail : nid=%d, sid=%d, nGateFlag = %d ####\n", nNid, nSid, nGateFlag);
	if (pNpc->isGate())
		pNpc->SendGateFlag(nGateFlag, false);
}
示例#4
0
// TO-DO: Remove this. NPCs don't just randomly die, it would make sense to do this as a result of the cause, not just because.
void CAISocket::RecvNpcDead(Packet & pkt)
{
	uint16 nid = pkt.read<uint16>();
	CNpc* pNpc = g_pMain->m_arNpcArray.GetData(nid);
	if (pNpc == NULL)
		return;

	C3DMap* pMap = pNpc->GetMap();
	if (pMap == NULL)
		return;

	pNpc->OnDeath(NULL);
}
示例#5
0
// TO-DO: Remove this. NPCs don't just randomly die, it would make sense to do this as a result of the cause, not just because.
void CAISocket::RecvNpcDead(Packet & pkt)
{
	CNpc * pNpc;
	Unit * pAttacker;
	uint16 nid, attackerID;
	pkt >> nid >> attackerID;

	pNpc = g_pMain->GetNpcPtr(nid);
	if (pNpc == nullptr
		|| pNpc->GetMap() == nullptr)
		return;

	pAttacker = g_pMain->GetUnitPtr(attackerID);
	pNpc->OnDeath(pAttacker);
}
示例#6
0
void CAISocket::RecvNpcDead(char* pBuf)
{
	int index = 0, send_index = 0;
	int nid = 0;
	char send_buff[256];
	_OBJECT_EVENT* pEvent = NULL;

	nid = GetShort(pBuf,index);


	if(nid >= NPC_BAND)		{
		CNpc* pNpc = m_pMain->m_arNpcArray.GetData(nid);
		if(!pNpc)	return;

		C3DMap* pMap = pNpc->GetMap();
		if (pMap == NULL)
			return;

		if( pNpc->m_byObjectType == SPECIAL_OBJECT )	{
			pEvent = pMap->GetObjectEvent( pNpc->m_sSid );
			if( pEvent )	pEvent->byLife = 0;
		}

		//pNpc->NpcInOut( NPC_OUT );
		//TRACE("RecvNpcDead - (%d,%s)\n", pNpc->m_sNid, pNpc->m_strName);

		pMap->RegionNpcRemove(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, nid);
		//TRACE("--- RecvNpcDead : Npc를 Region에서 삭제처리.. ,, zone=%d, region_x=%d, y=%d\n", pNpc->m_sZoneIndex, pNpc->m_sRegion_X, pNpc->m_sRegion_Z);

		SetByte( send_buff, WIZ_DEAD, send_index );
		SetShort( send_buff, nid, send_index );
		m_pMain->Send_Region(send_buff, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false);

		pNpc->m_sRegion_X = 0;		pNpc->m_sRegion_Z = 0;
	}
}
示例#7
0
void CAISocket::RecvMagicAttackResult(Packet & pkt)
{
	uint32 magicid;
	uint16 sid, tid;
	uint8 byCommand; 

	/* 
		This is all so redundant...
		When everything's switched over to pass in Packets
		we can just pass it through directly!
		As it is now.. we still need a length (which we can hardcode, but meh)
	*/
	pkt >> byCommand >> magicid >> sid >> tid;

	if (byCommand == MAGIC_CASTING
		|| (byCommand == MAGIC_EFFECTING && sid >= NPC_BAND && tid >= NPC_BAND))
	{
		CNpc *pNpc = g_pMain->m_arNpcArray.GetData(sid);
		if (!pNpc)
			return;

		g_pMain->Send_Region(&pkt, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z);
	}
	else if (byCommand == MAGIC_EFFECTING)
	{
		if (sid >= USER_BAND && sid < NPC_BAND)
		{
			CUser *pUser = g_pMain->GetUserPtr(sid);
			if (pUser == NULL || pUser->isDead())
				return;

			g_pMain->Send_Region(&pkt, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ);
			return;
		}

		// If we're an NPC, casting a skill (rather, it's finished casting) on a player...
		pkt.rpos(0);
		m_MagicProcess.MagicPacket(pkt);
	}
	
}
示例#8
0
void CAISocket::RecvNpcInfo(Packet & pkt)
{
	std::string strName;
	uint8 Mode, byDirection;
	uint16 sNid;

	pkt.SByte();
	pkt >> Mode >> sNid;

	CNpc *pNpc = g_pMain->m_arNpcArray.GetData(sNid);
	if (pNpc == NULL)
		return;

	pkt >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2
		>> pNpc->m_bZoneID >> strName >> pNpc->m_byGroup >> pNpc->m_byLevel 
		>> pNpc->m_fCurX >> pNpc->m_fCurZ >> pNpc->m_fCurY >> byDirection >> pNpc->m_NpcState
		>> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen
		>> pNpc->m_sTotalHitrate >> pNpc->m_sTotalEvasionrate >> pNpc->m_sTotalAc >> pNpc->m_byObjectType;

	if (strName.empty() || strName.length() > MAX_NPC_SIZE)
	{
		delete pNpc;
		return;
	}

	pNpc->m_byDirection = byDirection;
	strcpy(pNpc->m_strName, strName.c_str());

	// Bug? Test?
	// pNpc->m_NpcState = NPC_DEAD;

	if (pNpc->m_NpcState == NPC_LIVE)
	{
		char strLog[256]; 
		CTime t = CTime::GetCurrentTime();
		sprintf_s(strLog, sizeof(strLog), "## time(%d:%d-%d) npc regen check(%d) : nid=%d, name=%s, x=%d, z=%d, rx=%d, rz=%d ## \r\n", t.GetHour(), t.GetMinute(), t.GetSecond(), 
			pNpc->m_NpcState, pNpc->GetID(), pNpc->m_strName, (int)pNpc->m_fCurX, (int)pNpc->m_fCurZ, pNpc->GetRegionX(), pNpc->GetRegionZ());
		EnterCriticalSection( &g_LogFile_critical );
		g_pMain->m_RegionLogFile.Write( strLog, strlen(strLog) );
		LeaveCriticalSection( &g_LogFile_critical );
		TRACE(strLog);
		// to-do: replace with g_pMain->WriteRegionLog(...);
	}


	if (pNpc->GetMap() == NULL)
		return;

	pNpc->InsertRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ());
	pNpc->SetRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ());

	if (pNpc->m_byObjectType == SPECIAL_OBJECT)
	{
		_OBJECT_EVENT *pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid );
		if (pEvent != NULL)
			pEvent->byLife = 1;
	}

	if (Mode == 0)
	{
		TRACE("RecvNpcInfo - dead monster nid=%d, name=%s\n", pNpc->GetID(), pNpc->m_strName);
		return;
	}

	pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY());
}
示例#9
0
void CAISocket::RecvNpcInfoAll(Packet & pkt)
{
	uint8 bCount = pkt.read<uint8>(); // max of 20

	pkt.SByte();
	for (int i = 0; i < bCount; i++)
	{
		uint8 bType, bDirection;
		std::string strName;

		CNpc* pNpc = new CNpc();
		pNpc->Initialize();

		pkt >> bType >> pNpc->m_sNid >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2
			>> pNpc->m_bZoneID >> strName >> pNpc->m_byGroup >> pNpc->m_byLevel >> pNpc->m_fCurX >> pNpc->m_fCurZ >> pNpc->m_fCurY
			>> bDirection >> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen 
			>> pNpc->m_sTotalHitrate >> pNpc->m_sTotalEvasionrate >> pNpc->m_sTotalAc >> pNpc->m_byObjectType;

		if (strName.empty() || strName.length() > MAX_NPC_SIZE)
		{
			delete pNpc;
			continue;
		}

		//TRACE("Recv --> NpcUserInfo : uid = %d, x=%f, z=%f.. \n", nid, fPosX, fPosZ);
		strcpy(pNpc->m_strName, strName.c_str());

		pNpc->m_pMap = g_pMain->GetZoneByID(pNpc->GetZoneID());
		pNpc->m_NpcState = NPC_LIVE;
		pNpc->m_byDirection = bDirection;
		pNpc->SetRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ());

		if (pNpc->GetMap() == NULL)
		{
			delete pNpc;
			pNpc = NULL;
			continue;
		}

		if (pNpc->m_byObjectType == SPECIAL_OBJECT)
		{
			_OBJECT_EVENT* pEvent = pNpc->GetMap()->GetObjectEvent(pNpc->m_sSid);
			if (pEvent != NULL)
				pEvent->byLife = 1;
		}

	//	TRACE("Recv --> NpcUserInfoAll : uid=%d, sid=%d, name=%s, x=%f, z=%f. gate=%d, objecttype=%d \n", nid, sPid, szName, fPosX, fPosZ, byGateOpen, byObjectType);

		if (!g_pMain->m_arNpcArray.PutData(pNpc->GetID(), pNpc))
		{
			TRACE("Npc PutData Fail - %d\n", pNpc->GetID());
			delete pNpc;
			continue;
		}

		if (bType == 0)
		{
			TRACE("Recv --> NpcUserInfoAll : nid=%d, sid=%d, name=%s\n", pNpc->GetID(), pNpc->m_sSid, strName.c_str());
			continue;
		}

		// RegionNpcAdd() 
		pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY());
	}
}
示例#10
0
void CUser::MagicSystem( Packet & pkt )
{
    uint8 command, subcommand;
    uint32 magicid;
    time_t skill_received_time;
    uint16 sid, tid, data1, data2, data3, data4, data5, data6, data7;
    CUser *pUser, *pTargetUser = NULL;
    CNpc *pMon = NULL;

    skill_received_time = GetTickCount(); //Retrieve the time at which the Magic packet is going for internal processing.

    command = pkt.GetOpcode();
    pkt >> subcommand >> magicid >> sid >> tid;

    if( sid < 0 || tid < 0 || tid > INVALID_BAND || sid != (uint16)GetSocketID()) //Return if there's an invalid source or target received.
        return;

    if( sid < MAX_USER )
    {
        if (isDead())
            return;
    }

    if(tid >= NPC_BAND)
    {
        pMon = m_pMain->m_arNpcArray.GetData(tid);
        if( !pMon || pMon->m_NpcState == NPC_DEAD )
            return;
    }
    else if( tid < MAX_USER )
    {
        pTargetUser = m_pMain->GetUserPtr(tid);
        if ( !pTargetUser )
            return;
    }

    /*
    Do ALL required pre-liminary checks here, will wrap that into another function, until then leaving this disabled.
    */
    //if(!CheckSkillCooldown(magicid, skill_received_time)) //Check if the skill is off-cooldown.
    //	return;

    //LogSkillCooldown(magicid, skill_received_time); Use this <if> the skill is successfully casted!

    pkt >> data1 >> data2 >> data3 >> data4 >> data5 >> data6 >> data7;

    switch(command)
    {
    case MAGIC_CASTING:
        break;
    case MAGIC_FLYING:
        break;
    case MAGIC_EFFECTING:
        break;
    case MAGIC_FAIL:
        goto echo;
        break;
    case MAGIC_TYPE3_END: //This is also MAGIC_TYPE4_END
        break;
    case MAGIC_CANCEL:
        break;
    case MAGIC_CANCEL2:
        break;
    }

echo :
    Packet result(WIZ_MAGIC_PROCESS);
    result << subcommand << magicid << sid << tid << data1 << data2 << data3 << data4 << data5 << data6 << data7;

    if (sid < MAX_USER)
    {
        m_pMain->Send_Region( &result, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ );
    }
    else if ( sid >= NPC_BAND)
    {
        m_pMain->Send_Region( &result, pMon->GetMap(), pMon->m_sRegion_X, pMon->m_sRegion_Z );
    }
}
示例#11
0
void CAISocket::RecvNpcInfo(char* pBuf)
{
	int index = 0;

	BYTE		Mode;			// 01(INFO_MODIFY)	: NPC 정보 변경
								// 02(INFO_DELETE)	: NPC 정보 삭제
	short		nid;			// NPC index
	short		sid;			// NPC index
	short		sPid;			// NPC Picture Number
	short		sSize = 100;	// NPC Size
	int			iWeapon_1;		// 오른손 무기
	int			iWeapon_2;		// 왼손  무기
	BYTE        bZone;			// Current zone number
	char		szName[MAX_NPC_SIZE+1];		// NPC Name
	BYTE		byGroup;		// 소속 집단
	BYTE		byLevel;			// level
	float		fPosX;			// X Position
	float		fPosZ;			// Z Position
	float		fPosY;			// Y Position
	BYTE		byDirection;	// 방향
	BYTE		tState;			// NPC 상태
								// 00	: NPC Dead
								// 01	: NPC Live
	BYTE		tNpcKind;		// 00	: Monster
								// 01	: NPC
	int		iSellingGroup;
  	int		nMaxHP;			// 최대 HP
	int		nHP;			// 현재 HP
	BYTE		byGateOpen;
	short		sHitRate;		// 공격 성공률
	BYTE		byObjectType;	// 보통 : 0, 특수 : 1

	Mode = GetByte(pBuf, index);
	nid = GetShort(pBuf, index);
	sid = GetShort(pBuf, index);
	sPid = GetShort(pBuf, index);
	sSize = GetShort(pBuf, index);
	iWeapon_1 = GetDWORD(pBuf, index);
	iWeapon_2 = GetDWORD(pBuf, index);
	bZone = GetByte(pBuf, index);
	int nLength = GetVarString(szName, pBuf, sizeof(BYTE), index);
	if(nLength < 0 || nLength > MAX_NPC_SIZE) return;		// 잘못된 monster 아이디 
	byGroup = GetByte(pBuf, index);
	byLevel  = GetByte(pBuf, index);
	fPosX = Getfloat(pBuf, index);
	fPosZ = Getfloat(pBuf, index);
	fPosY = Getfloat(pBuf, index);
	byDirection = GetByte(pBuf, index);
	tState = GetByte(pBuf, index);
	tNpcKind = GetByte(pBuf, index);
	iSellingGroup = GetDWORD(pBuf, index);
	nMaxHP = GetDWORD(pBuf, index);
	nHP = GetDWORD(pBuf, index);
	byGateOpen = GetByte(pBuf, index);
	sHitRate = GetShort(pBuf, index);
	byObjectType = GetByte(pBuf, index);

	CNpc* pNpc = NULL;

	pNpc = m_pMain->m_arNpcArray.GetData(nid);
	if(!pNpc)	return;

	pNpc->m_NpcState = NPC_DEAD;

	if( pNpc->m_NpcState == NPC_LIVE )	{	// 살아 있는데 또 정보를 받는 경우
		char strLog[256]; 
		CTime t = CTime::GetCurrentTime();
		sprintf_s(strLog, sizeof(strLog), "## time(%d:%d-%d) npc regen check(%d) : nid=%d, name=%s, x=%d, z=%d, rx=%d, rz=%d ## \r\n", t.GetHour(), t.GetMinute(), t.GetSecond(), pNpc->m_NpcState, nid, szName, (int)pNpc->m_fCurX, (int)pNpc->m_fCurZ, pNpc->m_sRegion_X, pNpc->m_sRegion_Z);
		EnterCriticalSection( &g_LogFile_critical );
		m_pMain->m_RegionLogFile.Write( strLog, strlen(strLog) );
		LeaveCriticalSection( &g_LogFile_critical );
		TRACE(strLog);
		// to-do: replace with m_pMain->WriteRegionLog(...);
	}

	pNpc->m_NpcState = NPC_LIVE;
	
	pNpc->m_sNid = nid;
	pNpc->m_sSid = sid;
	pNpc->m_sPid = sPid;
	pNpc->m_sSize = sSize;
	pNpc->m_iWeapon_1 = iWeapon_1;
	pNpc->m_iWeapon_2 = iWeapon_2;
	strcpy(pNpc->m_strName, szName);
	pNpc->m_byGroup = byGroup;
	pNpc->m_byLevel = byLevel;
	pNpc->m_bCurZone = bZone;
	pNpc->m_pMap = m_pMain->GetZoneByID(bZone);
	pNpc->m_fCurX = fPosX;
	pNpc->m_fCurZ = fPosZ;
	pNpc->m_fCurY = fPosY;
	pNpc->m_byDirection = byDirection;
	pNpc->m_NpcState = tState;
	pNpc->m_tNpcType = tNpcKind;
	pNpc->m_iSellingGroup = iSellingGroup;
	pNpc->m_iMaxHP = nMaxHP;
	pNpc->m_iHP = nHP;
	pNpc->m_byGateOpen = byGateOpen;
	pNpc->m_sHitRate = sHitRate;
	pNpc->m_byObjectType = byObjectType;

	if (pNpc->GetMap() == NULL)
		return;

	int nRegX = (int)fPosX / VIEW_DISTANCE;
	int nRegZ = (int)fPosZ / VIEW_DISTANCE;

	pNpc->m_sRegion_X = nRegX;
	pNpc->m_sRegion_Z = nRegZ;

	_OBJECT_EVENT* pEvent = NULL;
	if( pNpc->m_byObjectType == SPECIAL_OBJECT )	{
		pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid );
		if( pEvent )	pEvent->byLife = 1;
	}

	if(Mode == 0)	{
		TRACE("RecvNpcInfo - dead monster nid=%d, name=%s\n", pNpc->m_sNid, pNpc->m_strName);
		return;
	}

	pNpc->NpcInOut(NPC_IN, fPosX, fPosZ, fPosY);
}
示例#12
0
void CAISocket::RecvMagicAttackResult(char* pBuf)
{
	int index = 0, send_index = 1, sid = -1, tid = -1, magicid=0;
	BYTE byCommand; 
	short data0, data1, data2, data3, data4, data5;

	CNpc* pNpc = NULL;
	CUser* pUser = NULL;
	char send_buff[1024];

	//byType = GetByte(pBuf,index);				// who ( 1:mon->user 2:mon->mon )
	//byAttackType = GetByte(pBuf,index);			// attack type ( 1:long attack, 2:magic attack
	byCommand = GetByte(pBuf,index);			// magic type ( 1:casting, 2:flying, 3:effecting, 4:fail )
	magicid = GetDWORD(pBuf,index);
	sid = GetShort(pBuf,index);
	tid = GetShort(pBuf,index);
	data0 = GetShort(pBuf,index);
	data1 = GetShort(pBuf,index);
	data2 = GetShort(pBuf,index);
	data3 = GetShort(pBuf,index);
	data4 = GetShort(pBuf,index);
	data5 = GetShort(pBuf,index);

	SetByte( send_buff, byCommand, send_index );
	SetDWORD( send_buff, magicid, send_index );
	SetShort( send_buff, sid, send_index );
	SetShort( send_buff, tid, send_index );
	SetShort( send_buff, data0, send_index );
	SetShort( send_buff, data1, send_index );
	SetShort( send_buff, data2, send_index );
	SetShort( send_buff, data3, send_index );
	SetShort( send_buff, data4, send_index );
	SetShort( send_buff, data5, send_index );

	if(byCommand == 0x01)	{		// casting
		pNpc = m_pMain->m_arNpcArray.GetData(sid);
		if(!pNpc)	return;
		index = 0;
		SetByte( send_buff, WIZ_MAGIC_PROCESS, index );
		m_pMain->Send_Region(send_buff, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false);
	}
	else if(byCommand == 0x03)	{	// effecting
		//pNpc = m_pMain->m_arNpcArray.GetData(tid);
		//if(!pNpc)	return;
		if( sid >= USER_BAND && sid < NPC_BAND)	{
			pUser = m_pMain->GetUserPtr(sid);
			if (pUser == NULL || pUser->isDead())
				return;

			index = 0;
			SetByte( send_buff, WIZ_MAGIC_PROCESS, index );
			m_pMain->Send_Region(send_buff, send_index, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ, NULL, false);
		}
		else if(sid >= NPC_BAND)	{
			if(tid >= NPC_BAND)	{
				pNpc = m_pMain->m_arNpcArray.GetData(tid);
				if(!pNpc)	return;
				index = 0;
				SetByte( send_buff, WIZ_MAGIC_PROCESS, index );
				m_pMain->Send_Region(send_buff, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false);
				return;
			}
			send_index = 0;
			SetByte( send_buff, byCommand, send_index );
			SetDWORD( send_buff, magicid, send_index );
			SetShort( send_buff, sid, send_index );
			SetShort( send_buff, tid, send_index );
			SetShort( send_buff, data0, send_index );
			SetShort( send_buff, data1, send_index );
			SetShort( send_buff, data2, send_index );
			SetShort( send_buff, data3, send_index );
			SetShort( send_buff, data4, send_index );
			SetShort( send_buff, data5, send_index );
			m_MagicProcess.MagicPacket(send_buff, send_index);
		}
	}
	
}
示例#13
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);
		}
	}
}
示例#14
0
// ai server에 처음 접속시 npc의 모든 정보를 받아온다..
void CAISocket::RecvNpcInfoAll(char* pBuf)
{
	int index = 0;
	BYTE		byCount = 0;			// 마리수
	BYTE        byType;				// 0:처음에 등장하지 않는 몬스터, 1:등장
	short		nid;				// NPC index
	short		sid;				// NPC index
	BYTE		bZone;				// Current zone number
	short		sPid;				// NPC Picture Number
	short		sSize = 100;				// NPC Size
	int			iweapon_1;
	int			iweapon_2;
	char		szName[MAX_NPC_SIZE+1];		// NPC Name
	BYTE		byGroup;		// 소속 집단
	BYTE		byLevel;		// level
	float		fPosX;			// X Position
	float		fPosZ;			// Z Position
	float		fPosY;			// Y Position
	BYTE		byDirection;	// 
	BYTE		tNpcType;		// 00	: Monster
								// 01	: NPC
	int		iSellingGroup;
  	int		nMaxHP;			// 최대 HP
	int		nHP;			// 현재 HP
	BYTE		byGateOpen;		// 성문일경우 열림과 닫힘 정보
	short		sHitRate;
	BYTE		byObjectType;	// 보통 : 0, 특수 : 1

	byCount = GetByte(pBuf, index);

	for(int i=0; i<byCount; i++)
	{
		byType = GetByte(pBuf, index);
		nid = GetShort(pBuf, index);
		sid = GetShort(pBuf, index);
		sPid = GetShort(pBuf, index);
		sSize = GetShort(pBuf, index);
		iweapon_1 = GetDWORD(pBuf, index);
		iweapon_2 = GetDWORD(pBuf, index);
		bZone = GetByte(pBuf, index);
		int nLength = GetVarString(szName, pBuf, sizeof(BYTE), index);
		byGroup = GetByte(pBuf, index);
		byLevel  = GetByte(pBuf, index);
		fPosX = Getfloat(pBuf, index);
		fPosZ = Getfloat(pBuf, index);
		fPosY = Getfloat(pBuf, index);
		byDirection = GetByte(pBuf, index);
		tNpcType = GetByte(pBuf, index);
		iSellingGroup = GetDWORD(pBuf, index);
		nMaxHP = GetDWORD(pBuf, index);
		nHP = GetDWORD(pBuf, index);
		byGateOpen = GetByte(pBuf, index);
		sHitRate = GetShort(pBuf, index);
		byObjectType = GetByte(pBuf, index);

		//TRACE("RecvNpcInfoAll  : nid=%d, szName=%s, count=%d\n", nid, szName, byCount);

		if(nLength < 0 || nLength > MAX_NPC_SIZE)	{
			TRACE("#### RecvNpcInfoAll Fail : szName=%s\n", szName);
			continue;		// 잘못된 monster 아이디 
		}

		//TRACE("Recv --> NpcUserInfo : uid = %d, x=%f, z=%f.. \n", nid, fPosX, fPosZ);

		CNpc* pNpc = NULL;
		pNpc = new CNpc;
		if(pNpc == NULL)	{ 
			TRACE("#### Recv --> NpcUserInfoAll POINT Fail: uid=%d, sid=%d, name=%s, zone=%d, x=%f, z=%f.. \n", nid, sPid, szName, bZone, fPosX, fPosZ);
			continue;
		}
		pNpc->Initialize();

		pNpc->m_sNid = nid;
		pNpc->m_sSid = sid;
		pNpc->m_sPid = sPid;
		pNpc->m_sSize = sSize;
		pNpc->m_iWeapon_1 = iweapon_1;
		pNpc->m_iWeapon_2 = iweapon_2;
		strcpy(pNpc->m_strName, szName);
		pNpc->m_byGroup = byGroup;
		pNpc->m_byLevel = byLevel;
		pNpc->m_bCurZone = bZone;
		pNpc->m_pMap = m_pMain->GetZoneByID(bZone);
		pNpc->m_fCurX = fPosX;
		pNpc->m_fCurZ = fPosZ;
		pNpc->m_fCurY = fPosY;
		pNpc->m_byDirection = byDirection;
		pNpc->m_NpcState = NPC_LIVE;
		pNpc->m_tNpcType = tNpcType;
		pNpc->m_iSellingGroup = iSellingGroup;
		pNpc->m_iMaxHP = nMaxHP;
		pNpc->m_iHP = nHP;
		pNpc->m_byGateOpen = byGateOpen;
		pNpc->m_sHitRate = sHitRate;
		pNpc->m_byObjectType = byObjectType;
		pNpc->m_NpcState = NPC_LIVE;

		int nRegX = (int)fPosX / VIEW_DISTANCE;
		int nRegZ = (int)fPosZ / VIEW_DISTANCE;

		pNpc->m_sRegion_X = nRegX;
		pNpc->m_sRegion_Z = nRegZ;

		if (pNpc->GetMap() == NULL)
		{
			delete pNpc;
			pNpc = NULL;
			continue;
		}

		_OBJECT_EVENT* pEvent = NULL;
		if (pNpc->m_byObjectType == SPECIAL_OBJECT)
		{
			pEvent = pNpc->GetMap()->GetObjectEvent(pNpc->m_sSid);
			if( pEvent )	pEvent->byLife = 1;
		}

	//	TRACE("Recv --> NpcUserInfoAll : uid=%d, sid=%d, name=%s, x=%f, z=%f. gate=%d, objecttype=%d \n", nid, sPid, szName, fPosX, fPosZ, byGateOpen, byObjectType);

		if( !m_pMain->m_arNpcArray.PutData( pNpc->m_sNid, pNpc) ) {
			TRACE("Npc PutData Fail - %d\n", pNpc->m_sNid);
			delete pNpc;
			pNpc = NULL;
			continue;
		}

		if( byType == 0 )	{
			TRACE("Recv --> NpcUserInfoAll : 등록하면 안돼여,, uid=%d, sid=%d, name=%s\n", nid, sPid, szName);
			continue;		// region에 등록하지 말기...
		}

		pNpc->GetMap()->RegionNpcAdd(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, pNpc->m_sNid);
	}
}
示例#15
0
void CAISocket::RecvNpcInfoAll(Packet & pkt)
{
	uint8 bCount = pkt.read<uint8>(); // max of 20

	pkt.SByte();
	for (int i = 0; i < bCount; i++)
	{
		uint8 bDirection;
		std::string strName;

		CNpc* pNpc = new CNpc();
		pNpc->Initialize();

		pkt >> pNpc->m_NpcState >> pNpc->m_sNid >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2
			>> pNpc->m_bZone >> strName >> pNpc->m_bNation >> pNpc->m_bLevel
			>> pNpc->m_curx >> pNpc->m_curz >> pNpc->m_cury >> bDirection
			>> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen
			>> pNpc->m_fTotalHitrate >> pNpc->m_fTotalEvasionrate 
			>> pNpc->m_sTotalAc >> pNpc->m_sTotalHit 
			>> pNpc->m_byObjectType
			>> pNpc->m_byTrapNumber >> pNpc->m_bMonster
			>> pNpc->m_sFireR >> pNpc->m_sColdR >> pNpc->m_sLightningR
			>> pNpc->m_sMagicR >> pNpc->m_sDiseaseR >> pNpc->m_sPoisonR;

		if (strName.empty())
			strName = "<the spawn with no name>";

		if (strName.length() > MAX_NPC_SIZE)
		{
			pNpc->DecRef();
			continue;
		}

		pNpc->m_pMap = g_pMain->GetZoneByID(pNpc->GetZoneID());
		if (pNpc->GetMap() == nullptr)
		{
			pNpc->DecRef();
			continue;
		}

		//TRACE("Recv --> NpcUserInfo : uid = %d, x=%f, z=%f.. \n", nid, fPosX, fPosZ);
		pNpc->m_strName = strName;

		pNpc->m_byDirection = bDirection;
		pNpc->SetRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ());

		if (pNpc->m_byObjectType == SPECIAL_OBJECT)
		{
			_OBJECT_EVENT* pEvent = pNpc->GetMap()->GetObjectEvent(pNpc->m_sSid);
			if (pEvent != nullptr)
				pEvent->byLife = 1;
		}

		//	TRACE("Recv --> NpcUserInfoAll : uid=%d, sid=%d, name=%s, x=%f, z=%f. gate=%d, objecttype=%d \n", nid, sPid, szName, fPosX, fPosZ, byGateOpen, byObjectType);

		if (!g_pMain->m_arNpcArray.PutData(pNpc->GetID(), pNpc))
		{
			TRACE("Npc PutData Fail - %d\n", pNpc->GetID());
			pNpc->DecRef();
			continue;
		}

		if (pNpc->m_NpcState == NPC_DEAD)
		{
			TRACE("Recv --> NpcUserInfoAll : nid=%d, sid=%d, name=%s\n", pNpc->GetID(), pNpc->m_sSid, strName.c_str());
			continue;
		}

		pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY());
	}
}
示例#16
0
void CAISocket::RecvNpcInfo(Packet & pkt)
{
	std::string strName;
	uint8 Mode, byDirection;
	uint16 sNid;
	bool bCreated = false;

	pkt.SByte();
	pkt >> Mode >> sNid;

	CNpc *pNpc = g_pMain->GetNpcPtr(sNid);
	if (pNpc == nullptr)
	{
		pNpc = new CNpc();
		pNpc->m_sNid = sNid;
		bCreated = true;
	}

	pkt >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2
		>> pNpc->m_bZone >> strName >> pNpc->m_bNation >> pNpc->m_bLevel
		>> pNpc->m_curx >> pNpc->m_curz >> pNpc->m_cury >> byDirection
		>> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen
		>> pNpc->m_fTotalHitrate >> pNpc->m_fTotalEvasionrate 
		>> pNpc->m_sTotalAc >> pNpc->m_sTotalHit 
		>> pNpc->m_byObjectType
		>> pNpc->m_byTrapNumber >> pNpc->m_bMonster
		>> pNpc->m_sFireR >> pNpc->m_sColdR >> pNpc->m_sLightningR
		>> pNpc->m_sMagicR >> pNpc->m_sDiseaseR >> pNpc->m_sPoisonR;

	if (strName.empty() || strName.length() > MAX_NPC_SIZE)
	{
		pNpc->DecRef();
		return;
	}

	pNpc->m_NpcState = Mode;
	pNpc->m_byDirection = byDirection;
	pNpc->m_strName = strName;

	pNpc->m_pMap = g_pMain->GetZoneByID(pNpc->GetZoneID());
	if (pNpc->GetMap() == nullptr)
	{
		pNpc->DecRef();
		return;
	}

	pNpc->RegisterRegion();

	if (pNpc->m_byObjectType == SPECIAL_OBJECT)
	{
		_OBJECT_EVENT *pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid );
		if (pEvent != nullptr)
			pEvent->byLife = 1;
	}

	if (bCreated)
		g_pMain->m_arNpcArray.PutData(pNpc->GetID(), pNpc);

	if (pNpc->m_NpcState == NPC_DEAD)
	{
		TRACE("RecvNpcInfo - dead monster nid=%d, name=%s\n", pNpc->GetID(), pNpc->GetName().c_str());
		return;
	}

	pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY());
}
示例#17
0
bool CServerDlg::LoadSpawnCallback(OdbcCommand *dbCommand)
{
    // Avoid allocating stack space for these.
    // This method will only ever run in the same thread.
    static int nRandom = 0;
    static double dbSpeed = 0;
    static CNpcTable * pNpcTable = NULL;
    static CRoomEvent* pRoom = NULL;
    static char szPath[500];
    static float fRandom_X = 0.0f, fRandom_Z = 0.0f;

    // Unfortunately we cannot simply read what we need directly
    // into the CNpc instance. We have to resort to creating
    // copies of the data to allow for the way they handle multiple spawns...
    // Best we can do, I think, is to avoid allocating it on the stack.
    static uint8	bNumNpc, bZoneID, bActType, bRegenType, bDungeonFamily, bSpecialType,
              bTrapNumber, bDirection, bDotCnt;
    static uint16	sSid, sRegTime;
    static uint32	nServerNum;
    static int32	iLeftX, iTopZ, iRightX, iBottomZ,
              iLimitMinX, iLimitMinZ, iLimitMaxX, iLimitMaxZ;

    dbCommand->FetchByte(1, bZoneID);
    dbCommand->FetchUInt16(2, sSid);
    dbCommand->FetchByte(3, bActType);
    dbCommand->FetchByte(4, bRegenType);
    dbCommand->FetchByte(5, bDungeonFamily);
    dbCommand->FetchByte(6, bSpecialType);
    dbCommand->FetchByte(7, bTrapNumber);
    dbCommand->FetchInt32(8, iLeftX);
    dbCommand->FetchInt32(9, iTopZ);
    dbCommand->FetchInt32(10, iRightX);
    dbCommand->FetchInt32(11, iBottomZ);
    dbCommand->FetchInt32(12, iLimitMinZ);
    dbCommand->FetchInt32(13, iLimitMinX);
    dbCommand->FetchInt32(14, iLimitMaxX);
    dbCommand->FetchInt32(15, iLimitMaxZ);
    dbCommand->FetchByte(16, bNumNpc);
    dbCommand->FetchUInt16(17, sRegTime);
    dbCommand->FetchByte(18, bDirection);
    dbCommand->FetchByte(19, bDotCnt);
    dbCommand->FetchString(20, szPath, sizeof(szPath));

    nServerNum = GetServerNumber(bZoneID);

    if (m_byZone == nServerNum || m_byZone == UNIFY_ZONE)
    {
        uint8 bPathSerial = 1;
        for (uint8 j = 0; j < bNumNpc; j++)
        {
            CNpc * pNpc = new CNpc();

            pNpc->m_byMoveType = bActType;
            pNpc->m_byInitMoveType = bActType;

            bool bMonster = (bActType < 100);
            if (bMonster)
            {
                pNpcTable = m_arMonTable.GetData(sSid);
            }
            else
            {
                pNpc->m_byMoveType = bActType - 100;
                pNpcTable = m_arNpcTable.GetData(sSid);
            }

            if (pNpcTable == NULL)
            {
                printf("NPC %d not found in %s table.\n", pNpc->m_sNid, bMonster ? "K_MONSTER" : "K_NPC");
                delete pNpc;
                return false;
            }

            pNpc->Load(m_TotalNPC++, pNpcTable);
            pNpc->m_byBattlePos = 0;

            if (pNpc->m_byMoveType >= 2)
            {
                pNpc->m_byBattlePos = myrand(1, 3);
                pNpc->m_byPathCount = bPathSerial++;
            }

            pNpc->InitPos();

            pNpc->m_bCurZone = bZoneID;

            nRandom = abs(iLeftX - iRightX);
            if (nRandom <= 1)
                fRandom_X = (float)iLeftX;
            else
            {
                if (iLeftX < iRightX)
                    fRandom_X = (float)myrand(iLeftX, iRightX);
                else
                    fRandom_X = (float)myrand(iRightX, iLeftX);
            }

            nRandom = abs(iTopZ - iBottomZ);
            if (nRandom <= 1)
                fRandom_Z = (float)iTopZ;
            else
            {
                if (iTopZ < iBottomZ)
                    fRandom_Z = (float)myrand(iTopZ, iBottomZ);
                else
                    fRandom_Z = (float)myrand(iBottomZ, iTopZ);
            }

            pNpc->m_fCurX	= fRandom_X;
            pNpc->m_fCurY	= 0;
            pNpc->m_fCurZ	= fRandom_Z;

            pNpc->m_sRegenTime		= sRegTime * SECOND;
            pNpc->m_byDirection		= bDirection;
            pNpc->m_sMaxPathCount	= bDotCnt;

            if ((pNpc->m_byMoveType == 2 || pNpc->m_byMoveType == 3) && bDotCnt == 0)
            {
                pNpc->m_byMoveType = 1;
                TRACE("##### ServerDlg:CreateNpcThread - Path type Error :  nid=%d, sid=%d, name=%s, acttype=%d, path=%d #####\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byMoveType, pNpc->m_sMaxPathCount);
            }

            if (bDotCnt > 0)
            {
                int index = 0;
                for (int l = 0; l < bDotCnt; l++)
                {
                    static char szX[5], szZ[5];

                    memset(szX, 0, sizeof(szX));
                    memset(szZ, 0, sizeof(szZ));

                    memcpy(szX, szPath + index, 4);
                    index += 4;

                    memcpy(szZ, szPath + index, 4);
                    index += 4;

                    pNpc->m_PathList.pPattenPos[l].x = atoi(szX);
                    pNpc->m_PathList.pPattenPos[l].z = atoi(szZ);
                }
            }

            pNpc->m_tItemPer		= pNpcTable->m_tItemPer;	// NPC Type
            pNpc->m_tDnPer			= pNpcTable->m_tDnPer;	// NPC Type

            pNpc->m_nInitMinX = pNpc->m_nLimitMinX		= iLeftX;
            pNpc->m_nInitMinY = pNpc->m_nLimitMinZ		= iTopZ;
            pNpc->m_nInitMaxX = pNpc->m_nLimitMaxX		= iRightX;
            pNpc->m_nInitMaxY = pNpc->m_nLimitMaxZ		= iBottomZ;

            // dungeon work
            pNpc->m_byDungeonFamily	= bDungeonFamily;
            pNpc->m_bySpecialType	= bSpecialType;
            pNpc->m_byRegenType		= bRegenType;
            pNpc->m_byTrapNumber    = bTrapNumber;

            if (pNpc->m_byDungeonFamily > 0)
            {
                pNpc->m_nLimitMinX = iLimitMinX;
                pNpc->m_nLimitMinZ = iLimitMinZ;
                pNpc->m_nLimitMaxX = iLimitMaxX;
                pNpc->m_nLimitMaxZ = iLimitMaxZ;
            }

            pNpc->m_pZone = GetZoneByID(pNpc->m_bCurZone);
            if (pNpc->GetMap() == NULL)
            {
                printf(_T("Error: NPC %d in zone %d that does not exist."), sSid, bZoneID);
                delete pNpc;
                return false;
            }

            if (!m_arNpc.PutData(pNpc->m_sNid, pNpc))
            {
                --m_TotalNPC;
                TRACE("Npc PutData Fail - %d\n", pNpc->m_sNid);
                delete pNpc;
                continue;
            }

            pNpc->SetUid(pNpc->m_fCurX, pNpc->m_fCurZ, pNpc->m_sNid + NPC_BAND);

            if (pNpc->GetMap()->m_byRoomEvent > 0 && pNpc->m_byDungeonFamily > 0)
            {
                pRoom = pNpc->GetMap()->m_arRoomEventArray.GetData(pNpc->m_byDungeonFamily);
                if (pRoom == NULL)
                {
                    printf("Error : CServerDlg,, Map Room Npc Fail!!\n");
                    delete pNpc;
                    return false;
                }

                // this is why their CSTLMap class sucks.
                int *pInt = new int;
                *pInt = pNpc->m_sNid;
                if (!pRoom->m_mapRoomNpcArray.PutData(pNpc->m_sNid, pInt))
                {
                    delete pInt;
                    TRACE("### Map - Room Array MonsterNid Fail : nid=%d, sid=%d ###\n",
                          pNpc->m_sNid, pNpc->m_proto->m_sSid);
                }
            }
        }
    }

    return true;
}
示例#18
0
//	Npc Thread 를 만든다.
BOOL CServerDlg::CreateNpcThread()
{
    BOOL	bMoveNext	= TRUE;
    int		nSerial		= m_sMapEventNpc;
    int		nPathSerial = 1;
    int		nNpcCount	= 0;
    int		i=0, j=0;
    int nRandom = 0, nServerNum = 0;
    double  dbSpeed = 0;

    m_TotalNPC = 0;			// DB에 있는 수
    m_CurrentNPC = 0;
    m_CurrentNPCError = 0;

    CNpcTable*	pNpcTable = NULL;
    CRoomEvent* pRoom = NULL;

    CNpcPosSet NpcPosSet;

    char szPath[500];
    char szX[5];
    char szZ[5];

    float fRandom_X = 0.0f;
    float fRandom_Z = 0.0f;

    int nMonsterNumber = 0;

    try
    {
        if(NpcPosSet.IsOpen()) NpcPosSet.Close();
        if(!NpcPosSet.Open())	{
            AfxMessageBox(_T("MONSTER_POS DB Open Fail!"));
            return FALSE;
        }
        if(NpcPosSet.IsBOF())	{
            AfxMessageBox(_T("MONSTER_POS DB Empty!"));
            return FALSE;
        }

        NpcPosSet.MoveFirst();

        while(!NpcPosSet.IsEOF())	{
            nMonsterNumber = NpcPosSet.m_NumNPC;
            //if( NpcPosSet.m_ZoneID == 101 )	{	// 테스트를 위해서,,
            //	nMonsterNumber = 1;
            //if(nMonsterNumber > 4)	{
            //	nMonsterNumber = nMonsterNumber / 4;
            //}
            //}
            nServerNum = 0;
            nServerNum = GetServerNumber( NpcPosSet.m_ZoneID );

            if( m_byZone == nServerNum || m_byZone == UNIFY_ZONE)	{
                for(j=0; j<nMonsterNumber; j++)		{
                    CNpc*		pNpc		= new CNpc();

                    pNpc->m_byMoveType = NpcPosSet.m_ActType;
                    pNpc->m_byInitMoveType = NpcPosSet.m_ActType;

                    bool bMonster = (NpcPosSet.m_ActType < 100);
                    if (bMonster)
                        pNpcTable = m_arMonTable.GetData(NpcPosSet.m_NpcID);
                    else
                    {
                        pNpc->m_byMoveType = NpcPosSet.m_ActType - 100;
                        //pNpc->m_byInitMoveType = NpcPosSet.m_ActType - 100;
                        pNpcTable = m_arNpcTable.GetData(NpcPosSet.m_NpcID);
                    }

                    if (pNpcTable == NULL)
                    {
                        char buff[128] = {0};
                        sprintf(buff, "NPC %d not found in %s table.", pNpc->m_sNid, bMonster ? "K_MONSTER" : "K_NPC");
                        AfxMessageBox(buff);
                        delete pNpc;
                        return FALSE;
                    }

                    pNpc->Load(nSerial++, pNpcTable);
                    pNpc->m_byBattlePos = 0;

                    if(pNpc->m_byMoveType >= 2)	{
                        pNpc->m_byBattlePos = myrand( 1, 3 );
                        pNpc->m_byPathCount = nPathSerial++;
                    }

                    pNpc->InitPos();

                    if( bMoveNext )	{
                        bMoveNext = FALSE;
                        nNpcCount = NpcPosSet.m_NumNPC;
                    }

                    //////// MONSTER POS ////////////////////////////////////////
                    pNpc->m_bCurZone = NpcPosSet.m_ZoneID;

                    // map에 몬스터의 위치를 랜덤하게 위치시킨다.. (테스트 용 : 수정-DB에서 읽어오는데로 몬 위치 결정)
                    nRandom = abs(NpcPosSet.m_LeftX - NpcPosSet.m_RightX);
                    if(nRandom <= 1)
                        fRandom_X = (float)NpcPosSet.m_LeftX;
                    else	{
                        if(NpcPosSet.m_LeftX < NpcPosSet.m_RightX)
                            fRandom_X = (float)myrand(NpcPosSet.m_LeftX, NpcPosSet.m_RightX);
                        else
                            fRandom_X = (float)myrand(NpcPosSet.m_RightX, NpcPosSet.m_LeftX);
                    }
                    nRandom = abs(NpcPosSet.m_TopZ - NpcPosSet.m_BottomZ);
                    if(nRandom <= 1)
                        fRandom_Z = (float)NpcPosSet.m_TopZ;
                    else	{
                        if(NpcPosSet.m_TopZ < NpcPosSet.m_BottomZ)
                            fRandom_Z = (float)myrand(NpcPosSet.m_TopZ, NpcPosSet.m_BottomZ);
                        else
                            fRandom_Z = (float)myrand(NpcPosSet.m_BottomZ, NpcPosSet.m_TopZ);
                    }

                    pNpc->m_fCurX	= fRandom_X;
                    pNpc->m_fCurY	= 0;
                    pNpc->m_fCurZ	= fRandom_Z;

                    pNpc->m_sRegenTime		= NpcPosSet.m_RegTime * 1000;	// 초(DB)단위-> 밀리세컨드로
                    pNpc->m_byDirection = NpcPosSet.m_byDirection;
                    pNpc->m_sMaxPathCount = NpcPosSet.m_DotCnt;

                    if( pNpc->m_byMoveType >= 2 && NpcPosSet.m_DotCnt == 0 )	{
                        pNpc->m_byMoveType = 1;
                        TRACE("##### ServerDlg:CreateNpcThread - Path type Error :  nid=%d, sid=%d, name=%s, acttype=%d, path=%d #####\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byMoveType, pNpc->m_sMaxPathCount);
                    }

                    int index = 0;
                    strcpy_s(szPath, sizeof(szPath), NpcPosSet.m_path);

                    if(NpcPosSet.m_DotCnt != 0)	{
                        for(int l = 0; l<NpcPosSet.m_DotCnt; l++)	{
                            memset(szX, 0x00, 5);
                            memset(szZ, 0x00, 5);
                            GetString(szX, szPath, 4, index);
                            GetString(szZ, szPath, 4, index);
                            pNpc->m_PathList.pPattenPos[l].x = atoi(szX);
                            pNpc->m_PathList.pPattenPos[l].z = atoi(szZ);
                            //	TRACE(" l=%d, x=%d, z=%d\n", l, pNpc->m_PathList.pPattenPos[l].x, pNpc->m_PathList.pPattenPos[l].z);
                        }
                    }

                    //pNpc->m_byType			= NpcPosSet.m_byType;

                    pNpc->m_tItemPer		= pNpcTable->m_tItemPer;	// NPC Type
                    pNpc->m_tDnPer			= pNpcTable->m_tDnPer;	// NPC Type

                    pNpc->m_nInitMinX = pNpc->m_nLimitMinX		= NpcPosSet.m_LeftX;
                    pNpc->m_nInitMinY = pNpc->m_nLimitMinZ		= NpcPosSet.m_TopZ;
                    pNpc->m_nInitMaxX = pNpc->m_nLimitMaxX		= NpcPosSet.m_RightX;
                    pNpc->m_nInitMaxY = pNpc->m_nLimitMaxZ		= NpcPosSet.m_BottomZ;
                    // dungeon work
                    pNpc->m_byDungeonFamily	= NpcPosSet.m_DungeonFamily;
                    pNpc->m_bySpecialType	= NpcPosSet.m_SpecialType;
                    pNpc->m_byRegenType		= NpcPosSet.m_RegenType;
                    pNpc->m_byTrapNumber    = NpcPosSet.m_TrapNumber;

                    if( pNpc->m_byDungeonFamily > 0 )	{
                        pNpc->m_nLimitMinX = NpcPosSet.m_LimitMinX;
                        pNpc->m_nLimitMinZ = NpcPosSet.m_LimitMinZ;
                        pNpc->m_nLimitMaxX = NpcPosSet.m_LimitMaxX;
                        pNpc->m_nLimitMaxZ = NpcPosSet.m_LimitMaxZ;
                    }

                    pNpc->m_pZone = GetZoneByID(pNpc->m_bCurZone);
                    if (pNpc->GetMap() == NULL)		{
                        AfxMessageBox("Error : CServerDlg,, Invaild zone Index!!");
                        delete pNpc;
                        return FALSE;
                    }

                    if( !m_arNpc.PutData( pNpc->m_sNid, pNpc) )		{
                        TRACE("Npc PutData Fail - %d\n", pNpc->m_sNid);
                        delete pNpc;
                        pNpc = NULL;
                        continue;
                    }

                    pNpc->SetUid(pNpc->m_fCurX, pNpc->m_fCurZ, pNpc->m_sNid + NPC_BAND);

                    //
                    if (pNpc->GetMap()->m_byRoomEvent > 0 && pNpc->m_byDungeonFamily > 0 )	{
                        pRoom = pNpc->GetMap()->m_arRoomEventArray.GetData( pNpc->m_byDungeonFamily );
                        if (pRoom == NULL)
                        {
                            TRACE("Error : CServerDlg,, Map Room Npc Fail!! : nid=%d, sid=%d, name=%s, fam=%d, zone=%d\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byDungeonFamily, pNpc->m_bCurZone);
                            AfxMessageBox("Error : CServerDlg,, Map Room Npc Fail!!");
                            delete pNpc;
                            return FALSE;
                        }

                        int *pInt = new int;
                        *pInt = pNpc->m_sNid;
                        if( !pRoom->m_mapRoomNpcArray.PutData( pNpc->m_sNid, pInt ) )	{
                            TRACE("### Map - Room Array MonsterNid Fail : nid=%d, sid=%d ###\n", pNpc->m_sNid, pNpc->m_proto->m_sSid);
                        }
                    }


                    m_TotalNPC = nSerial;

                    if(--nNpcCount > 0) continue;

                    bMoveNext = TRUE;
                    nNpcCount = 0;

                }
            }

            nPathSerial = 1;
            NpcPosSet.MoveNext();
        }

        NpcPosSet.Close();
    }
    catch(CDBException* e)
    {
        e->ReportError();
        e->Delete();

        return FALSE;
    }

    int step = 0, nThreadNumber = 0;
    CNpcThread* pNpcThread = NULL;

    foreach_stlmap (itr, m_arNpc)
    {
        if (step == 0)
            pNpcThread = new CNpcThread;

        CNpc *pNpc = pNpcThread->m_pNpc[step] = itr->second;
        pNpc->m_sThreadNumber = nThreadNumber;
        pNpc->Init();

        ++step;

        if( step == NPC_NUM )
        {
            pNpcThread->m_sThreadNumber = nThreadNumber++;
            pNpcThread->m_pThread = AfxBeginThread(NpcThreadProc, &(pNpcThread->m_ThreadInfo), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
            m_arNpcThread.push_back( pNpcThread );
            step = 0;
        }
    }
    if( step != 0 )
    {
        pNpcThread->m_sThreadNumber = nThreadNumber++;
        pNpcThread->m_pThread = AfxBeginThread(NpcThreadProc, &(pNpcThread->m_ThreadInfo), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
        m_arNpcThread.push_back( pNpcThread );
    }

    m_pZoneEventThread = AfxBeginThread(ZoneEventThreadProc, (LPVOID)(this), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);

    //TRACE("m_TotalNPC = %d \n", m_TotalNPC);
    AddToList("[Monster Init - %d, threads=%d]", m_TotalNPC, m_arNpcThread.size());
    return TRUE;
}
示例#19
0
void CAISocket::RecvNpcAttack(Packet & pkt)
{
	int nHP = 0, temp_damage = 0;
	int16 sid, tid;
	BYTE type, bResult, byAttackType = 0;
	float fDir=0.0f;
	short damage = 0;
	CNpc* pNpc = NULL, *pMon = NULL;
	CUser* pUser = NULL;
	_OBJECT_EVENT* pEvent = NULL;

	pkt >> type >> bResult >> sid >> tid >> damage >> nHP >> byAttackType;

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

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

		// NPC died
		if (bResult == 4)
			pNpc->OnDeath();
		else 
		{
			Packet result(WIZ_ATTACK, byAttackType);
			result << bResult << sid << tid;
			pNpc->SendToRegion(&result);
		}

		pUser = g_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 (bResult == 2 || bResult== 4)		// 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 == 2)		// npc attack -> user
	{
		pNpc = g_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 = g_pMain->GetUserPtr(tid);
			if(pUser == NULL)	
				return;

			pUser->HpChange(-damage, 1, true);
			pUser->ItemWoreOut(DEFENCE, damage);

			Packet result(WIZ_ATTACK, byAttackType);
			result	<< uint8(bResult == 3 ? 0 : bResult)
					<< sid << tid;
			pNpc->SendToRegion(&result);

			//TRACE("RecvNpcAttack ==> sid = %d, tid = %d, result = %d\n", sid, tid, result);

			// user dead
			if (bResult == 2) 
			{
				if (pUser->m_bResHpType == USER_DEAD)
					return;

				pUser->OnDeath();
				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);

				if( pUser->m_pUserData->m_bFame == COMMAND_CAPTAIN )	{	// ���ֱ����� �ִ� ������ �״´ٸ�,, ���� ���� ��Ż
					pUser->ChangeFame(CHIEF);

					TRACE("---> AISocket->RecvNpcAttack() Dead Captain Deprive - %s\n", pUser->m_pUserData->m_id);
					if (pUser->getNation() == KARUS)		g_pMain->Announcement( KARUS_CAPTAIN_DEPRIVE_NOTIFY, KARUS );
					else if (pUser->getNation() == ELMORAD)	g_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 = g_pMain->m_arNpcArray.GetData(tid);
			if(!pMon)	return;
			pMon->m_iHP -= damage;
			if( pMon->m_iHP < 0 )
				pMon->m_iHP = 0;

			Packet result(WIZ_ATTACK, byAttackType);
			result << bResult << sid << tid;
			if (bResult == 2)	{		// 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;
				}
			}
			pNpc->SendToRegion(&result);
		}
	}
}