void CUser::Attack(Packet & pkt)
{
if (!isInGame())
return;
int16 sid = -1, tid = -1, damage, delaytime, distance;
uint8 bType, bResult = 0, unknown;
Unit * pTarget = nullptr;
pkt >> bType >> bResult >> tid >> delaytime >> distance >> unknown;
if (m_bResHpType == USER_SITDOWN || isIncapacitated() || isInEnemySafetyArea())
return;
if (isInSpecialEventZone()
&& !g_pMain->pSpecialEvent.opened
&& !g_pMain->pCindWar.isON())
return;
if (!g_pMain->pSpecialEvent.opened
&& g_pMain->isCindirellaZone(GetZoneID())
&& g_pMain->pCindWar.isON()
&& !g_pMain->pCindWar.isStarted())
return;
RemoveStealth();
// If you're holding a weapon, do a client-based (ugh, do not trust!) delay check.
_ITEM_TABLE pRightTable = GetItemPrototype(RIGHTHAND), pLeftTable = GetItemPrototype(LEFTHAND);
bool nocheck = false;
if ((isGM() || isGMUser()) && (!pRightTable.isnull() && pRightTable.GetNum() == 389158000) || (!pLeftTable.isnull() && pLeftTable.GetNum() == 389158000)) nocheck = true;
if ((!pRightTable.isnull() && pRightTable.isBow()) || (!pLeftTable.isnull() && pLeftTable.isBow())) return;
if (!nocheck && m_lastrattacktime > UNIXTIME2) return;
m_lastrattacktime = UNIXTIME2 + PLAYER_R_HIT_REQUEST_INTERVAL;
uint32 m_range = 0;
if (!pRightTable.isnull() && !isMage())
{
if (pRightTable.isTimingDelay())
{
if (delaytime < (pRightTable.m_sDelay + 9) || distance > pRightTable.m_sRange)
return;
}
else if (pRightTable.isWirinomUniqDelay() || pRightTable.isWirinomRebDelay() || pRightTable.isGargesSwordDelay())
{
if (delaytime < (pRightTable.m_sDelay - 4) || distance > pRightTable.m_sRange)
return;
}
else
{
if (delaytime < pRightTable.m_sDelay || distance > pRightTable.m_sRange)
return;
}
m_range = pRightTable.m_sRange;
}
// Empty handed.
else if (delaytime < 100 && !nocheck)
return;
pTarget = g_pMain->GetUnitPtr(tid, GetZoneID());
if (!pTarget)
return;
if (GetZoneID() == ZONE_JURAID_MOUNTAIN
&& pTarget->isNPC()
&& !CheckDevaAttack(pTarget->isNPC(), pTarget->isNPC() ? TO_NPC(pTarget)->GetProtoID() : 0))
return;
if (pTarget->isNPC())
{
uint8 type = TO_NPC(pTarget)->GetType();
if (type == NPC_GUARD_TOWER1 || type == NPC_GUARD_TOWER2 || type == NPC_SOCCER_BAAL)
return;
if (GetZoneID() == ZONE_DELOS)
{
if (!TO_NPC(pTarget)->isMonster()
&& type != NPC_DESTROYED_ARTIFACT
&& type != NPC_OBJECT_FLAG
&& type != NPC_GATE)
return;
if (type == NPC_DESTROYED_ARTIFACT
&& (!g_pMain->isCswActive() || !g_pMain->isCswWarActive() || !isInClan()
|| g_pMain->pSiegeWar.sMasterKnights == GetClanID()))
return;
}
uint8 m_sByGroup = TO_NPC(pTarget)->GetByGroup();
if (m_sByGroup == 3)
return;
}
if (!isAttackable(pTarget))
return;
if (!isInAttackRange(pTarget))
return;
if (!CanAttack(pTarget))
return;
bResult = ATTACK_FAIL;
if (isInTempleEventZone() && (!isSameEventRoom(pTarget) || !g_pMain->pTempleEvent.isAttackable))
return;
if (isInTempleQuestEventZone() && (!isSameEventRoom(pTarget) && m_ismsevent))
return;
if (pTarget->isPlayer() && pTarget->hasBuff(BUFF_TYPE_FREEZE))
return;
/*if (m_range && pTarget)
{
float mesafe = GetDistanceSqrt(pTarget);
if (mesafe + 2.0f > (float)m_range)
return;
}*/
damage = GetDamage(pTarget);
// Can't use R attacks in the Snow War.
if (GetZoneID() == ZONE_SNOW_BATTLE && g_pMain->m_byBattleOpen == SNOW_BATTLE)
damage = 0;
else if (GetZoneID() == ZONE_CHAOS_DUNGEON && g_pMain->pTempleEvent.isAttackable)
damage = 500 / 10;
if (GetZoneID() == ZONE_DUNGEON_DEFENCE)
{
_DUNGEON_DEFENCE_ROOM_INFO* pRoomBilgi = g_pMain->m_DungeonDefenceRoomListArray.GetData(GetEventRoom());
if (pRoomBilgi != nullptr) {
if (pRoomBilgi->m_DefenceisStarted == true)
damage = 500 / 10;
}
}
if (isInTempleEventZone() && !virt_eventattack_check())
return;
if (isInTempleEventZone() && (!isSameEventRoom(pTarget) || !g_pMain->pTempleEvent.isAttackable))
return;
if (pTarget->isNPC())
{
if (TO_NPC(pTarget)->GetType() == NPC_PRISON)
{
if (GetMana() < ((int32)m_MaxMp * 5 / 100))
return;
_ITEM_DATA* pItem;
_ITEM_TABLE pTable = GetItemPrototype(RIGHTHAND, pItem);
if (pItem == nullptr || pTable.isnull()
|| pItem->sDuration <= 0 // are we supposed to wear the pickaxe on use? Need to verify.
|| !pTable.isPunishmentStick())
damage = 0;
else
{
damage = 1;
MSpChange(-((int32)m_MaxMp * 5 / 100));
}
}
else if (TO_NPC(pTarget)->GetType() == NPC_FOSIL)
{
_ITEM_DATA* pItem;
_ITEM_TABLE pTable = GetItemPrototype(RIGHTHAND, pItem);
if (pItem == nullptr || pTable.isnull()
|| pItem->sDuration <= 0 // are we supposed to wear the pickaxe on use? Need to verify.
|| !pTable.isPickaxe())
damage = 0;
else
damage = 1;
}
else if (TO_NPC(pTarget)->m_OrgNation == 3) // R Atack Kapatıldı 27.09.2020
{
damage = 0;
}
else if (TO_NPC(pTarget)->GetType() == NPC_OBJECT_FLAG && TO_NPC(pTarget)->GetProtoID() == 511)
damage = 1;
else if (TO_NPC(pTarget)->GetType() == NPC_REFUGEE)
{
if (TO_NPC(pTarget)->isMonster())
{
if (TO_NPC(pTarget)->GetProtoID() == 3202 || TO_NPC(pTarget)->GetProtoID() == 3203
|| TO_NPC(pTarget)->GetProtoID() == 3252 || TO_NPC(pTarget)->GetProtoID() == 3253)
damage = 20;
else
damage = 10;
}
else
damage = 10;
}
else if (TO_NPC(pTarget)->GetType() == NPC_TREE /*|| TO_NPC(pTarget)->GetType() == NPC_SANTA*/)
damage = 20;
else if (TO_NPC(pTarget)->GetNation() == (uint8)Nation::NONE && TO_NPC(pTarget)->GetType() == NPC_PARTNER_TYPE)
damage = 0;
else if (VaccuniAttack())
damage = 30000;
else if (TO_NPC(pTarget)->GetType() == NPC_BORDER_MONUMENT)
damage = 10;
}
if (damage > 0)
{
pTarget->HpChange(-damage, this);
if (pTarget->isDead())
bResult = ATTACK_TARGET_DEAD;
else
bResult = ATTACK_SUCCESS;
// Every attack takes a little of your weapon's durability.
ItemWoreOut(ATTACK, damage);
// Every hit takes a little of the defender's armour durability.
if (pTarget->isPlayer())
TO_USER(pTarget)->ItemWoreOut(DEFENCE, damage);
}
Packet result(WIZ_ATTACK, bType);
result << bResult << GetSocketID() << tid << unknown;
SendToRegion(&result, nullptr, GetEventRoom());
}