void CUser::MoveProcess(Packet & pkt)
{
	ASSERT(GetMap() != nullptr);
	if (m_bWarp || isDead()) 
		return;

	uint16 will_x, will_z, will_y;
	int16 speed=0;
	float real_x, real_z, real_y;
	uint8 echo;

	pkt >> will_x >> will_z >> will_y >> speed >> echo;
	real_x = will_x/10.0f; real_z = will_z/10.0f; real_y = will_y/10.0f;

	if (!isGM())
	{
		// TO-DO: Handle proper speed checks against server-side amounts.
		// We should also avoid relying on what the client has sent us.
		if (speed > 200)	// What is the signifance of this number? Considering 90 is light feet...
			// We shouldn't be using magic numbers at all here.
		{
			Disconnect();
			return;
		}
	}

	if (!GetMap()->IsValidPosition(real_x, real_z, real_y)) 
		return;

	if (m_oldx != GetX()
		|| m_oldz != GetZ())
	{
		m_oldx = GetX();
		m_oldy = GetY();
		m_oldz = GetZ();
	}

	// TO-DO: Ensure this is checked properly to prevent speedhacking
	SetPosition(real_x, real_y, real_z);

	if (RegisterRegion())
	{
		g_pMain->RegionNpcInfoForMe(this);
		g_pMain->RegionUserInOutForMe(this);
		g_pMain->MerchantUserInOutForMe(this);
	}

	if (m_bInvisibilityType == INVIS_DISPEL_ON_MOVE)
		CMagicProcess::RemoveStealth(this, INVIS_DISPEL_ON_MOVE);

	Packet result(WIZ_MOVE);
	result << GetSocketID() << will_x << will_z << will_y << speed << echo;
	SendToRegion(&result);

	GetMap()->CheckEvent(real_x, real_z, this);

	result.Initialize(AG_USER_MOVE);
	result << GetSocketID() << m_curx << m_curz << m_cury << speed;
	Send_AIServer(&result);
}
void CUser::UserInOut(uint8 bType)
{
	if (GetRegion() == nullptr)
		return;

	Packet result;

	if (bType != INOUT_OUT)
		ResetGMVisibility();

	GetInOut(result, bType);

	if (bType == INOUT_OUT)
		GetRegion()->Remove(this);
	else
		GetRegion()->Add(this);

	SendToRegion(&result, this, GetEventRoom());

	if (bType == INOUT_OUT || !isBlinking())
	{
		result.Initialize(AG_USER_INOUT);
		result.SByte();
		result << bType << GetSocketID() << GetName() << m_curx << m_curz;
		Send_AIServer(&result);
	}
}
void CUser::MoveProcess(Packet & pkt)
{
	ASSERT(GetMap() != nullptr);
	if (m_bWarp || isDead()) 
		return;

	uint16 will_x, will_z, will_y;
	int16 speed=0;
	float real_x, real_z, real_y;
	uint8 echo;

	pkt >> will_x >> will_z >> will_y >> speed >> echo;
	real_x = will_x/10.0f; real_z = will_z/10.0f; real_y = will_y/10.0f;

	m_sSpeed = speed;
	SpeedHackUser();

	if (!GetMap()->IsValidPosition(real_x, real_z, real_y)) 
		return;

	if (m_oldx != GetX()
		|| m_oldz != GetZ())
	{
		m_oldx = GetX();
		m_oldy = GetY();
		m_oldz = GetZ();
	}

	// TODO: Ensure this is checked properly to prevent speedhacking
	SetPosition(real_x, real_y, real_z);

	if (RegisterRegion())
	{
		g_pMain->RegionNpcInfoForMe(this);
		g_pMain->RegionUserInOutForMe(this);
		g_pMain->MerchantUserInOutForMe(this);
	}

	if (m_bInvisibilityType == INVIS_DISPEL_ON_MOVE)
		CMagicProcess::RemoveStealth(this, INVIS_DISPEL_ON_MOVE);

	Packet result(WIZ_MOVE);
	result << GetSocketID() << will_x << will_z << will_y << speed << echo;
	SendToRegion(&result);

	GetMap()->CheckEvent(real_x, real_z, this);

	result.Initialize(AG_USER_MOVE);
	result << GetSocketID() << m_curx << m_curz << m_cury << speed;
	Send_AIServer(&result);
}
Exemple #4
0
/**
* @brief        Changes an NPC's mana.
*
* @param        amount        The amount to adjust the mana by.
*/
void CNpc::MSpChange(int amount)
{
#if 0 // TODO: Implement this
        // Glorious copypasta.
        // TODO: Make this behave unsigned.
        m_iMP += amount;
        if (m_iMP < 0)
                m_iMP = 0;
        else if (m_iMP > m_iMaxMP)
                m_iMP = m_iMaxMP;

        Packet result(AG_USER_SET_MP);
        result << GetID() << m_iMP;
        Send_AIServer(&result);
#endif
}
Exemple #5
0
/**
* @brief        Sends a gate status.
*
* @param        ObjectType  object type
* @param        bFlag          The flag (open or shut).
* @param        bSendAI        true to update the AI server.
*/
void CNpc::SendGateFlag(uint8 objectType,uint8 bFlag /*= -1*/, bool bSendAI /*= true*/)
{
        Packet result(WIZ_OBJECT_EVENT, uint8(objectType));

        // If there's a flag to set, set it now.
        if (bFlag >= 0)
                m_byGateOpen = (bFlag == 1);

        // Tell everyone nearby our new status.
        result << uint8(1) << GetID() << m_byGateOpen;
        SendToRegion(&result);

        // Tell the AI server our new status
        if (bSendAI)
        {
                result.Initialize(AG_NPC_GATE_OPEN);
                result << GetID() << m_byGateOpen;
                Send_AIServer(&result);
        }
}
void CUser::MoveProcess(Packet & pkt)
{
	ASSERT(GetMap() != NULL);
	if (m_bWarp || isDead()) 
		return;
		
	uint16 will_x, will_z, will_y, speed=0;
	float real_x, real_z, real_y;
	uint8 echo;

	pkt >> will_x >> will_z >> will_y >> speed >> echo;
	real_x = will_x/10.0f; real_z = will_z/10.0f; real_y = will_y/10.0f;

	if (!GetMap()->IsValidPosition(real_x, real_z, real_y)) 
		return;

	// TO-DO: Ensure this is checked properly to prevent speedhacking
	m_curx = real_x;
	m_curz = real_z;
	m_cury = real_y;

	if (RegisterRegion())
	{
		g_pMain->RegionNpcInfoForMe(this);
		g_pMain->RegionUserInOutForMe(this);
		g_pMain->MerchantUserInOutForMe(this);
	}

	if (m_bInvisibilityType == INVIS_DISPEL_ON_MOVE)
		StateChangeServerDirect(7, INVIS_NONE);

	Packet result(WIZ_MOVE);
	result << GetSocketID() << will_x << will_z << will_y << speed << echo;
	SendToRegion(&result);

	GetMap()->CheckEvent(real_x, real_z, this);

	result.Initialize(AG_USER_MOVE);
	result << GetSocketID() << m_curx << m_curz << m_cury << speed;
	Send_AIServer(&result);
}
Exemple #7
0
/**
 * @brief	Changes an NPC's hitpoints.
 *
 * @param	amount   	The amount to adjust the HP by.
 * @param	pAttacker	The attacker.
 * @param	bSendToAI	true to update the AI server.
 */
void CNpc::HpChange(int amount, Unit *pAttacker /*= nullptr*/, bool bSendToAI /*= true*/) 
{
	// Glorious copypasta.
	if (amount < 0 && -amount > m_iHP)
		m_iHP = 0;
	else if (amount >= 0 && m_iHP + amount > m_iMaxHP)
		m_iHP = m_iMaxHP;
	else
		m_iHP += amount;

	if (bSendToAI)
	{
		// NOTE: This will handle the death notification/looting.
		Packet result(AG_NPC_HP_CHANGE);
		result << GetID() << pAttacker->GetID() << m_iHP << amount;
		Send_AIServer(&result);
	}

	if (pAttacker != nullptr
		&& pAttacker->isPlayer())
		TO_USER(pAttacker)->SendTargetHP(0, GetID(), amount);
}
Exemple #8
0
void CNpc::SendHpChangeToAI(uint16 sTargetID, int amount, AttributeType attributeType /*= AttributeNone*/)
{
        Packet result(AG_NPC_HP_CHANGE);
        result << GetID() << sTargetID << m_iHP << amount << uint8(attributeType);
        Send_AIServer(&result);
}
void CUser::ZoneChange(int zone, float x, float z)
{
	m_bZoneChangeFlag = true;

	C3DMap* pMap = nullptr;
	_ZONE_SERVERINFO *pInfo = nullptr;

	pMap = g_pMain->GetZoneByID(zone);
	if (!pMap) 
		return;

	if( pMap->m_bType == 2 ) {	// If Target zone is frontier zone.
		if( GetLevel() < 20 && g_pMain->m_byBattleOpen != SNOW_BATTLE)
			return;
	}

	if( g_pMain->m_byBattleOpen == NATION_BATTLE )	{		// Battle zone open
		if( m_bZone == BATTLE_ZONE )	{
			if( pMap->m_bType == 1 && m_bNation != zone && (zone < 10 || zone > 21))	{	// ???? ?????? ???? ????..
				if( m_bNation == KARUS && !g_pMain->m_byElmoradOpenFlag )	{
					TRACE("#### ZoneChange Fail ,,, id=%s, nation=%d, flag=%d\n", GetName().c_str(), m_bNation, g_pMain->m_byElmoradOpenFlag);
					return;
				}
				else if( m_bNation == ELMORAD && !g_pMain->m_byKarusOpenFlag )	{
					TRACE("#### ZoneChange Fail ,,, id=%s, nation=%d, flag=%d\n", GetName().c_str(), m_bNation, g_pMain->m_byKarusOpenFlag);
					return;
				}
			}
		}
		else if( pMap->m_bType == 1 && m_bNation != zone && (zone < 10 || zone > 21)) {		// ???? ?????? ???? ????..
			return;
		}
//
		else if( pMap->m_bType == 2 && zone == ZONE_RONARK_LAND ) {	 // You can't go to frontier zone when Battlezone is open.
			Packet result(WIZ_WARP_LIST, uint8(2));
			result << uint8(0);
			Send(&result);
			return;
		}
//
	}
	else if( g_pMain->m_byBattleOpen == SNOW_BATTLE )	{					// Snow Battle zone open
		if( pMap->m_bType == 1 && m_bNation != zone ) {		// ???? ?????? ???? ????..
			return;
		}
		else if( pMap->m_bType == 2 && (zone == ZONE_RONARK_LAND || zone == ZONE_BATTLE ) ) {			// You can't go to frontier zone when Battlezone is open.
			return;
		}
	}
	else	{					// Battle zone close
		if( pMap->m_bType == 1 && m_bNation != zone && (zone < 10 || zone > 21))
			return;
	}

	m_bWarp = 0x01;

	UserInOut(INOUT_OUT);

	if( m_bZone == ZONE_SNOW_BATTLE )	{
		//TRACE("ZoneChange - name=%s\n", m_id);
		SetMaxHp( 1 );
	}

	bool bSameZone = (GetZoneID() == zone);
	m_bZone = zone;
	m_curx = x;
	m_curz = z;

	if (!bSameZone)
	{
		SetZoneAbilityChange();

		// Reset the user's anger gauge when leaving the zone
		// Unknown if this is official behaviour, but it's logical.
		if (GetAngerGauge() > 0)
			UpdateAngerGauge(0);

		/* 
			Here we also send a clan packet with subopcode 0x16 (with a byte flag of 2) if war zone/Moradon
			or subopcode 0x17 (with nWarEnemyID) for all else
		*/
#if 0
		if (isInClan())
		{
			CKnights * pKnights = g_pMain->GetClanPtr(GetClanID());
			if (pKnights != nullptr
					&& pKnights->bKnightsWarStarted)
			{
				Packet clanPacket(WIZ_KNIGHTS_PROCESS);
				if ((GetZoneID() / 100) == 1
					|| GetZoneID() == 21)
					clanPacket << uint8(0x17) << uint8(2);
				else 
					clanPacket << uint16(0x16) << uint16(0 /*nWarEnemyID*/);

				Send(&clanPacket);
			}
		}
#endif


		if (GetZoneID() == ZONE_SNOW_BATTLE)
		{
			SetMaxHp();
		}

		if (isInParty())
			PartyRemove(GetSocketID());

		ResetWindows();
	}


	m_pMap = pMap;

	if( g_pMain->m_nServerNo != pMap->m_nServerNo ) {
		pInfo = g_pMain->m_ServerArray.GetData( pMap->m_nServerNo );
		if( !pInfo ) 
			return;

		UserDataSaveToAgent();

		m_bLogout = 2;	// server change flag
		SendServerChange(pInfo->strServerIP, 2);
		return;
	}
	
	SetRegion(GetNewRegionX(), GetNewRegionZ());

	Packet result(WIZ_ZONE_CHANGE, uint8(3)); // magic numbers, sigh.
	result << uint16(GetZoneID()) << GetSPosX() << GetSPosZ() << GetSPosY() << g_pMain->m_byOldVictory;
	Send(&result);

	if (!m_bZoneChangeSameZone)
	{
		m_sWhoKilledMe = -1;
		m_iLostExp = 0;
		m_bRegeneType = 0;
		m_tLastRegeneTime = 0;
		m_sBind = -1;
		InitType3();
		InitType4();
		CMagicProcess::CheckExpiredType9Skills(this, true);
		SetUserAbility();
	}	

	result.Initialize(AG_ZONE_CHANGE);
	result << GetSocketID() << GetZoneID();
	Send_AIServer(&result);

	m_bZoneChangeSameZone = false;
	m_bZoneChangeFlag = false;
}
void CUser::Regene(uint8 regene_type, uint32 magicid /*= 0*/)
{
	ASSERT(GetMap() != nullptr);

	_OBJECT_EVENT* pEvent = nullptr;
	_HOME_INFO* pHomeInfo = nullptr;
	float x = 0.0f, z = 0.0f;

	if (!isDead())
		return;

	if (regene_type != 1 && regene_type != 2)
		regene_type = 1;

	if (regene_type == 2) 
	{
		magicid = 490041;	// The Stone of Ressurection magic ID

		// Is our level high enough to be able to resurrect using this skill?
		if (GetLevel() <= 5
			// Do we have enough resurrection stones?
				|| !RobItem(379006000, 3 * GetLevel()))
				return;
	}

	// If we're in a home zone, we'll want the coordinates from there. Otherwise, assume our own home zone.
	pHomeInfo = g_pMain->m_HomeArray.GetData(GetZoneID() <= ZONE_ELMORAD ? GetZoneID() : GetNation());
	if (pHomeInfo == nullptr)
		return;

	UserInOut(INOUT_OUT);

	pEvent = GetMap()->GetObjectEvent(m_sBind);	

	// If we're not using a spell to resurrect.
	if (magicid == 0) 
	{
		// Resurrect at a bind/respawn point
		if (pEvent != nullptr && pEvent->byLife == 1)
		{
			SetPosition(pEvent->fPosX + x, 0.0f, pEvent->fPosZ + z);
		}
		// Are we trying to respawn in a home zone?
		else if (GetZoneID() <= ZONE_ELMORAD) 
		{
			// Use the proper respawn area for our nation, as the opposite nation can
			// enter this zone at a war's invasion stage.
			if (GetNation() == KARUS) 
			{
				x = (float)(pHomeInfo->KarusZoneX + myrand(0, pHomeInfo->KarusZoneLX));
				z = (float)(pHomeInfo->KarusZoneZ + myrand(0, pHomeInfo->KarusZoneLZ));			
			}
			else 
			{
				x = (float)(pHomeInfo->ElmoZoneX + myrand(0, pHomeInfo->ElmoZoneLX));
				z = (float)(pHomeInfo->ElmoZoneZ + myrand(0, pHomeInfo->ElmoZoneLZ));
			}		
		}
		else
		{
			// If we're in a war zone (aside from snow wars, which apparently use different coords), use BattleZone coordinates.
			if (GetZoneID() != ZONE_SNOW_BATTLE 
				&& GetZoneID() == (ZONE_BATTLE_BASE + g_pMain->m_byBattleZone))
			{
				x = (float)(pHomeInfo->BattleZoneX + myrand(0, pHomeInfo->BattleZoneLX));
				z = (float)(pHomeInfo->BattleZoneZ + myrand(0, pHomeInfo->BattleZoneLZ));
			}
			// If we died in the Moradon arena, we need to spawn near the Arena.
			else if (GetZoneID() == ZONE_MORADON && isInArena())
			{
				x = (float)(MINI_ARENA_RESPAWN_X + myrand(-MINI_ARENA_RESPAWN_RADIUS, MINI_ARENA_RESPAWN_RADIUS));
				z = (float)(MINI_ARENA_RESPAWN_Z + myrand(-MINI_ARENA_RESPAWN_RADIUS, MINI_ARENA_RESPAWN_RADIUS));
			}
			// For all else, just grab the start position (/town coordinates) from the START_POSITION table.
			else
			{
				short sx, sz;
				GetStartPosition(sx, sz);

				x = sx;
				z = sz;
			}
		}

		SetPosition(x, 0.0f, z);

		m_bResHpType = USER_STANDING;	
		m_bRegeneType = REGENE_NORMAL;
	}
	else // we're respawning using a resurrect skill.
	{
		_MAGIC_TYPE5 * pType = g_pMain->m_Magictype5Array.GetData(magicid);     
		if (pType == nullptr)
			return;

		MSpChange(-m_iMaxMp); // reset us to 0 MP. 

		if (m_sWhoKilledMe == -1) 
			ExpChange((m_iLostExp * pType->bExpRecover) / 100); // Restore 

		m_bResHpType = USER_STANDING;
		m_bRegeneType = REGENE_MAGIC;
	}

	Packet result(WIZ_REGENE);
	result << GetSPosX() << GetSPosZ() << GetSPosY();
	Send(&result);

	HpChange(GetMaxHealth());

	m_tLastRegeneTime = UNIXTIME;
	m_sWhoKilledMe = -1;
	m_iLostExp = 0;

	if (magicid == 0)
		BlinkStart();

	if (!isBlinking())
	{
		result.Initialize(AG_USER_REGENE);
		result << GetSocketID() << m_sHp;
		Send_AIServer(&result);
	}

	SetRegion(GetNewRegionX(), GetNewRegionZ());

	UserInOut(INOUT_RESPAWN);		

	g_pMain->RegionUserInOutForMe(this);
	g_pMain->RegionNpcInfoForMe(this);

	InitializeStealth();
	SendUserStatusUpdate(USER_STATUS_DOT, USER_STATUS_CURE);
	SendUserStatusUpdate(USER_STATUS_POISON, USER_STATUS_CURE);

	if (isInArena())
		SendUserStatusUpdate(USER_STATUS_SPEED, USER_STATUS_CURE);

	RecastSavedMagic();

	// If we actually respawned (i.e. we weren't resurrected by a skill)...
	if (magicid == 0)
	{
		// In PVP zones (not war zones), we must kick out players if they no longer
		// have any national points.
		if (GetMap()->isNationPVPZone() 
			&& GetMap()->isWarZone()
			&& GetLoyalty() == 0)
			KickOutZoneUser(false);
	}
}
Exemple #11
0
void CUser::Regene(uint8 regene_type, uint32 magicid /*= 0*/)
{
    ASSERT(GetMap() != NULL);

    CUser* pUser = NULL;
    _OBJECT_EVENT* pEvent = NULL;
    _HOME_INFO* pHomeInfo = NULL;
    _MAGIC_TYPE5* pType = NULL;

    if (!isDead())
        return;

    InitType3();
    InitType4();

    if (regene_type != 1 && regene_type != 2) {
        regene_type = 1;
    }

    if (regene_type == 2) {
        magicid = 490041;	// The Stone of Ressurection magic ID

        if (!RobItem(379006000, 3 * GetLevel())) {
            return;	// Subtract resurrection stones.
        }

        if (GetLevel() <= 5) {
            return;	// 5 level minimum.
        }
    }

    pHomeInfo = g_pMain->m_HomeArray.GetData(m_bNation);
    if (!pHomeInfo) return;

    UserInOut(INOUT_OUT);

    float x = 0.0f, z = 0.0f;
    x = (float)(myrand( 0, 400 )/100.0f);
    z = (float)(myrand( 0, 400 )/100.0f);
    if( x < 2.5f )	x = 1.5f + x;
    if( z < 2.5f )	z = 1.5f + z;

    pEvent = GetMap()->GetObjectEvent(m_sBind);

    // TO-DO: Clean this entire thing up. Wow.
    if (magicid == 0) {
        if( pEvent && pEvent->byLife == 1 ) {		// Bind Point
            m_curx = pEvent->fPosX + x;
            m_curz = pEvent->fPosZ + z;
            m_cury = 0;
        }
        else if( m_bNation != m_bZone) {	// Free Zone or Opposite Zone
            if(m_bZone > 200) {		// Frontier Zone...
                x = (float)(pHomeInfo->FreeZoneX + myrand(0, pHomeInfo->FreeZoneLX));
                z = (float)(pHomeInfo->FreeZoneZ + myrand(0, pHomeInfo->FreeZoneLZ));
            }
//
            else if(m_bZone > 100 && m_bZone < 200) {		// Battle Zone...
                /*
                				m_bResHpType = USER_STANDING;
                				HpChange( m_iMaxHp );
                				KickOutZoneUser();	// Go back to your own zone!
                				return;
                */
                x = (float)(pHomeInfo->BattleZoneX + myrand(0, pHomeInfo->BattleZoneLX));
                z = (float)(pHomeInfo->BattleZoneZ + myrand(0, pHomeInfo->BattleZoneLZ));
                if (m_bZone == ZONE_SNOW_BATTLE) {
                    x = (float)(pHomeInfo->FreeZoneX + myrand(0, pHomeInfo->FreeZoneLX));
                    z = (float)(pHomeInfo->FreeZoneZ + myrand(0, pHomeInfo->FreeZoneLZ));
                }
            }
            else if (m_bZone > 10 && m_bZone < 20) {
                x = (float)(527 + myrand(0, 10));
                z = (float)(543 + myrand(0, 10));
            }
            else if (m_bZone < 3) {	// Specific Lands...
                if (m_bNation == KARUS) {
                    x = (float)(pHomeInfo->ElmoZoneX + myrand(0, pHomeInfo->ElmoZoneLX));
                    z = (float)(pHomeInfo->ElmoZoneZ + myrand(0, pHomeInfo->ElmoZoneLZ));
                }
                else if (m_bNation == ELMORAD) {
                    x = (float)(pHomeInfo->KarusZoneX + myrand(0, pHomeInfo->KarusZoneLX));
                    z = (float)(pHomeInfo->KarusZoneZ + myrand(0, pHomeInfo->KarusZoneLZ));
                }
                else return;
            }
            else
            {
                short sx, sz;
                GetStartPosition(sx, sz);

                x = sx;
                z = sz;
            }

            m_curx = x;
            m_curz = z;
        }
        else {
            if (m_bNation == KARUS) {
                x = (float)(pHomeInfo->KarusZoneX + myrand(0, pHomeInfo->KarusZoneLX));
                z = (float)(pHomeInfo->KarusZoneZ + myrand(0, pHomeInfo->KarusZoneLZ));
            }
            else if (m_bNation == ELMORAD) {
                x = (float)(pHomeInfo->ElmoZoneX + myrand(0, pHomeInfo->ElmoZoneLX));
                z = (float)(pHomeInfo->ElmoZoneZ + myrand(0, pHomeInfo->ElmoZoneLZ));
            }
            else return;

            m_curx = x;
            m_curz = z;
        }
    }

    Packet result(WIZ_REGENE);
    result << GetSPosX() << GetSPosZ() << GetSPosY();
    Send(&result);

    if (magicid > 0) {	// Clerical Resurrection.
        pType = g_pMain->m_Magictype5Array.GetData(magicid);
        if ( !pType ) return;

        m_bResHpType = USER_STANDING;
        MSpChange(-m_iMaxMp);					// Empty out MP.

        if (m_sWhoKilledMe == -1 && regene_type == 1) {
            ExpChange((m_iLostExp * pType->bExpRecover) / 100);		// Restore Target Experience.
        }

        m_bRegeneType = REGENE_MAGIC;
    }
    else {		// Normal Regene.
//
        m_bAbnormalType = ABNORMAL_BLINKING;
//
        m_bResHpType = USER_STANDING;
        m_bRegeneType = REGENE_NORMAL;
    }

    HpChange(m_iMaxHp);

    m_tLastRegeneTime = UNIXTIME;
    m_sWhoKilledMe = -1;
    m_iLostExp = 0;

    if (!isBlinking())
    {
        result.Initialize(AG_USER_REGENE);
        result << GetSocketID() << m_sHp;
        Send_AIServer(&result);
    }

    SetRegion(GetNewRegionX(), GetNewRegionZ());

    UserInOut(INOUT_RESPAWN);

    g_pMain->RegionUserInOutForMe(this);
    g_pMain->RegionNpcInfoForMe(this);

    BlinkStart();

    if (isInParty())
    {
        // TO-DO: Wrap these up into Party-specific methods (nothing for that yet)
        // UPDATE: Sticking them in the CUser class for the moment. Need to have them make sense, though.
        if (!m_bType3Flag)
            SendPartyStatusUpdate(1);

        m_buffLock.Acquire();
        if (m_buffMap.empty())
            SendPartyStatusUpdate(2);
        m_buffLock.Release();
    }
}
Exemple #12
0
void CUser::Attack(Packet & pkt)
{
    Packet result;
    int16 sid = -1, tid = -1, damage, delaytime, distance;
    uint8 bType, bResult;

    CUser* pTUser = NULL;

    pkt >> bType >> bResult >> tid >> delaytime >> distance;

//	delaytime = delaytime / 100.0f;
//	distance = distance / 10.0f;

    if (isBlinking()
            || isDead())
        return;

    // If you're holding a weapon, do a client-based (ugh, do not trust!) delay check.
    _ITEM_TABLE *pTable = GetItemPrototype(RIGHTHAND);
    if (pTable != NULL)
    {
        if (delaytime < pTable->m_sDelay
                || distance > pTable->m_sRange)
            return;
    }
    // Empty handed.
    else if (delaytime < 100)
        return;

    // We're attacking a player...
    if (tid < MAX_USER)
    {
        pTUser = g_pMain->GetUserPtr(tid);

        if (pTUser == NULL || pTUser->isDead() || pTUser->isBlinking()
                || (pTUser->GetNation() == GetNation() && GetZoneID() != 48 /* TO-DO: implement better checks */)
                || !isAttackZone())
            bResult = 0;
        else
        {
            damage = GetDamage(pTUser, NULL);
            if (GetZoneID() == ZONE_SNOW_BATTLE && g_pMain->m_byBattleOpen == SNOW_BATTLE)
                damage = 0;

            if (damage <= 0)
                bResult = 0;
            else
            {
                // TO-DO: Move all this redundant code into appropriate event-based methods so that all the other cases don't have to copypasta (and forget stuff).
                pTUser->HpChange(-damage, this);
                if (pTUser->isDead())
                    bResult = 2;

                ItemWoreOut(ATTACK, damage);
                pTUser->ItemWoreOut(DEFENCE, damage);
                SendTargetHP(0, tid, -damage);
            }
        }
    }
    // We're attacking an NPC...
    else if (tid >= NPC_BAND)
    {
        // AI hasn't loaded yet
        if (g_pMain->m_bPointCheckFlag == false)
            return;

        CNpc *pNpc = g_pMain->m_arNpcArray.GetData(tid);
        if (pNpc != NULL && pNpc->isAlive()
                && (pNpc->GetNation() == 0
                    || pNpc->GetNation() != GetNation()))
        {
            result.SetOpcode(AG_ATTACK_REQ);
            result	<< bType << bResult
                    << GetSocketID() << tid
                    << uint16(m_sTotalHit * m_bAttackAmount / 100)
                    << uint16(m_sTotalAc + m_sACAmount)
                    << m_sTotalHitrate /* this is actually a float. screwed up naming... */
                    << m_sTotalEvasionrate /* also a float */
                    << m_sItemAc
                    << m_bMagicTypeLeftHand << m_bMagicTypeRightHand
                    << m_sMagicAmountLeftHand << m_sMagicAmountRightHand;
            Send_AIServer(&result);
            return;
        }
    }

    result.SetOpcode(WIZ_ATTACK);
    result << bType << bResult << GetSocketID() << tid;
    SendToRegion(&result);

    if (tid < NPC_BAND
            && bResult == 2 // 2 means a player died.
            && pTUser)
    {
        pTUser->Send(&result);
        TRACE("*** User Attack Dead, id=%s, result=%d, type=%d, HP=%d\n", pTUser->GetName(), bResult, pTUser->m_bResHpType, pTUser->m_sHp);
    }
}
void CUser::ZoneChange(uint16 sNewZone, float x, float z)
{
	C3DMap * pMap = g_pMain->GetZoneByID(sNewZone);
	if (pMap == nullptr) 
		return;

	ZoneChangeError errorReason;
	if (!CanChangeZone(pMap, errorReason))
	{
		Packet result;

		switch (errorReason)
		{
		case ZoneChangeErrorWrongLevel:
			/* this will depend on the zone */
			break;

		case ZoneChangeErrorWarActive:
			result.Initialize(WIZ_WARP_LIST);
			result << uint8(2) << uint8(4);
			Send(&result);
			break;

		case ZoneChangeErrorNeedLoyalty:
			/* does this have an error? */
			break;
		}

		return;
	}

	m_bWarp = true;
	m_bZoneChangeFlag = true;

	UserInOut(INOUT_OUT);

	if (sNewZone == ZONE_SNOW_BATTLE)
		SetMaxHp(1);

	if (GetZoneID() != sNewZone)
	{
		SetZoneAbilityChange();

		// Reset the user's anger gauge when leaving the zone
		// Unknown if this is official behaviour, but it's logical.
		if (GetAngerGauge() > 0)
			UpdateAngerGauge(0);

		/* 
			Here we also send a clan packet with subopcode 0x16 (with a byte flag of 2) if war zone/Moradon
			or subopcode 0x17 (with nWarEnemyID) for all else
		*/
#if 0
		if (isInClan())
		{
			CKnights * pKnights = g_pMain->GetClanPtr(GetClanID());
			if (pKnights != nullptr
					&& pKnights->bKnightsWarStarted)
			{
				Packet clanPacket(WIZ_KNIGHTS_PROCESS);
				if (pMap->isWarZone() || byNewZone == ZONE_MORADON)
					clanPacket << uint8(0x17) << uint8(2);
				else 
					clanPacket << uint16(0x16) << uint16(0 /*nWarEnemyID*/);

				Send(&clanPacket);
			}
		}
#endif


		if (sNewZone == ZONE_SNOW_BATTLE)
			SetMaxHp();

		if (isInParty())
			PartyRemove(GetSocketID());

		ResetWindows();
	}

	m_bZone = (uint8) sNewZone; // this is 2 bytes to support the warp data loaded from SMDs. It should not go above a byte, however.
	SetPosition(x, 0.0f, z);
	m_pMap = pMap;

	if (g_pMain->m_nServerNo != pMap->m_nServerNo)
	{
		_ZONE_SERVERINFO *pInfo = g_pMain->m_ServerArray.GetData(pMap->m_nServerNo);
		if (pInfo == nullptr) 
			return;

		UserDataSaveToAgent();

		m_bLogout = 2;	// server change flag
		SendServerChange(pInfo->strServerIP, 2);
		return;
	}
	
	SetRegion(GetNewRegionX(), GetNewRegionZ());

	Packet result(WIZ_ZONE_CHANGE, uint8(ZoneChangeTeleport));
	result << uint16(GetZoneID()) << GetSPosX() << GetSPosZ() << GetSPosY() << g_pMain->m_byOldVictory;
	Send(&result);

	if (!m_bZoneChangeSameZone)
	{
		m_sWhoKilledMe = -1;
		m_iLostExp = 0;
		m_bRegeneType = 0;
		m_tLastRegeneTime = 0;
		m_sBind = -1;
		InitType3();
		InitType4();
		CMagicProcess::CheckExpiredType9Skills(this, true);
		SetUserAbility();
	}	

	result.Initialize(AG_ZONE_CHANGE);
	result << GetSocketID() << GetZoneID();
	Send_AIServer(&result);

	m_bZoneChangeSameZone = false;
	m_bZoneChangeFlag = false;
}