knightonline/server/GameServer/AISocket.cpp

1100 lines
26 KiB
C++

#include "stdafx.h"
#include "Map.h"
#include "AISocket.h"
#include "Npc.h"
#include "MagicProcess.h"
using std::string;
bool CAISocket::HandlePacket(Packet & pkt)
{
switch (pkt.GetOpcode())
{
case AG_CHECK_ALIVE_REQ:
RecvCheckAlive(pkt);
break;
case AI_SERVER_CONNECT:
LoginProcess(pkt);
break;
case AG_SERVER_INFO:
RecvServerInfo(pkt);
break;
case NPC_INFO_ALL:
RecvNpcInfoAll(pkt);
break;
case MOVE_RESULT:
RecvNpcMoveResult(pkt);
break;
case MOVE_END_RESULT:
break;
case AG_ATTACK_REQ:
RecvNpcAttack(pkt);
break;
// The AI server should send magic system requests to us.
// It shouldn't have to duplicate all the processing code.
case AG_MAGIC_ATTACK_REQ:
CMagicProcess::MagicPacket(pkt);
break;
case AG_NPC_INFO:
RecvNpcInfo(pkt);
break;
case AG_NPC_REGION_UPDATE:
RecvNpcRegionUpdate(pkt);
break;
case AG_USER_EXP:
RecvUserExp(pkt);
break;
case AG_SYSTEM_MSG:
RecvSystemMsg(pkt);
break;
case AG_NPC_GIVE_ITEM:
RecvNpcGiveItem(pkt);
break;
case AG_NPC_GATE_DESTORY:
RecvGateDestory(pkt);
break;
case AG_DEAD:
RecvNpcDead(pkt);
break;
case AG_NPC_INOUT:
RecvNpcInOut(pkt);
break;
case AG_BATTLE_EVENT:
RecvBattleEvent(pkt);
break;
case AG_NPC_EVENT_ITEM:
RecvNpcEventItem(pkt);
break;
case AG_NPC_GATE_OPEN:
RecvGateOpen(pkt);
break;
case AG_COMPRESSED:
RecvCompressed(pkt);
break;
case AG_NPC_HP_CHANGE:
RecvNpcHpChange(pkt);
break;
}
return true;
}
void CAISocket::OnConnect()
{
KOSocket::OnConnect();
// Set a flag to indicate whether we've ever connected before or not
// This is used accordingly by the AI server when we tell it what our status is.
// Kind of messy, and needs looking into further.
m_bHasConnected = true;
}
void CAISocket::OnDisconnect()
{
TRACE("*** CloseProcess - socketID=%d... ***\n", GetSocketID());
g_pMain->DeleteAllNpcList();
g_pMain->m_sErrorSocketCount = 3; // yup, we're definitely disconnected (magic number!)
}
void CAISocket::LoginProcess(Packet & pkt)
{
uint8 bReconnect = pkt.read<uint8>();
TRACE("Connected to the AI server\n");
if (bReconnect == 1)
TRACE("**** ReConnect - socket = %d ****\n ", GetSocketID());
g_pMain->m_bServerCheckFlag = true;
g_pMain->SendAllUserInfo();
}
void CAISocket::RecvServerInfo(Packet & pkt)
{
int size = g_pMain->m_ZoneArray.GetSize();
uint16 sTotalMonster;
uint8 bZone;
pkt >> bZone >> sTotalMonster;
g_pMain->m_sZoneCount++;
if (g_pMain->m_sZoneCount == size)
{
g_pMain->m_sZoneCount = 0;
g_pMain->m_bFirstServerFlag = true;
g_pMain->m_bPointCheckFlag = true;
g_pMain->m_NationMonumentInformationArray.DeleteAllData();
printf("All spawn data loaded.\n");
}
}
void CAISocket::RecvNpcInfoAll(Packet & pkt)
{
uint8 bCount = pkt.read<uint8>(); // max of 20
pkt.SByte();
for (int i = 0; i < bCount; i++)
{
int16 bDirection;
std::string strName;
CNpc* pNpc = new CNpc();
pNpc->Initialize();
uint16 EventRoom;
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_oSocketID >> EventRoom
>> pNpc->m_sFireR >> pNpc->m_sColdR >> pNpc->m_sLightningR
>> pNpc->m_sMagicR >> pNpc->m_sDiseaseR >> pNpc->m_sPoisonR >> pNpc->m_bIsEventNpc >> pNpc->nIsPet >> pNpc->strPetName >> pNpc->strUserName >> pNpc->nSerial >> pNpc->UserId;
pNpc->SetNPCEventRoom(EventRoom);
pNpc->SetUnitEventRoom(EventRoom);
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());
}
}
void CAISocket::RecvNpcMoveResult(Packet & pkt)
{
uint8 flag; // 01(INFO_MODIFY), 02(INFO_DELETE)
uint16 sNid;
float fX, fY, fZ, fSecForMetor;
pkt >> flag >> sNid >> fX >> fZ >> fY >> fSecForMetor;
CNpc * pNpc = g_pMain->GetNpcPtr(sNid);
if (pNpc == nullptr)
return;
if (pNpc->isDead())
{
Packet result(AG_NPC_HP_REQ);
result << sNid << pNpc->m_iHP;
Send(&result);
}
pNpc->MoveResult(fX, fY, fZ, (float)1000 / 1000);
}
void CAISocket::RecvNpcAttack(Packet & pkt)
{
CNpc * pAttacker;
Unit * pTarget;
uint16 sAttackerID, sTargetID;
int16 sDamage;
uint8 bResult = ATTACK_FAIL;
pkt >> sAttackerID >> sTargetID;
pAttacker = g_pMain->GetNpcPtr(sAttackerID);
pTarget = g_pMain->GetUnitPtr(sTargetID);
if (pAttacker == nullptr
|| pAttacker->isPlayer()
|| pTarget == nullptr
|| pTarget->isBlinking()
|| pAttacker->isDead()
|| pTarget->isDead()
|| !pTarget->isAttackable()
|| pAttacker->GetDamage(pTarget) < 1)
return;
if (pAttacker->GetEventRoom() != pTarget->GetEventRoom())
return;
// TODO: Wrap this up into its own virtual method
sDamage = pAttacker->GetDamage(pTarget);
if (sDamage > 0)
{
pTarget->HpChange(-(sDamage), pAttacker);
if (pTarget->isDead())
bResult = ATTACK_TARGET_DEAD;
else
bResult = ATTACK_SUCCESS;
// Every hit takes a little of the defender's armour durability.
if (pTarget->isPlayer())
TO_USER(pTarget)->ItemWoreOut(DEFENCE, sDamage);
}
Packet result(WIZ_ATTACK, uint8(LONG_ATTACK));
result << bResult << sAttackerID << sTargetID;
pAttacker->SendToRegion(&result);
}
void CAISocket::RecvNpcInfo(Packet & pkt)
{
std::string strName;
uint8 Mode;
uint16 sNid;
int16 byDirection;
bool bCreated = false;
uint16 EventRoom = 0;
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_oSocketID >> EventRoom
>> pNpc->m_sFireR >> pNpc->m_sColdR >> pNpc->m_sLightningR
>> pNpc->m_sMagicR >> pNpc->m_sDiseaseR >> pNpc->m_sPoisonR >> pNpc->m_bIsEventNpc >> pNpc->nIsPet >> pNpc->strPetName >> pNpc->strUserName >> pNpc->nSerial >> pNpc->UserId;
if(pNpc->GetProtoID() == 8110)
pNpc->m_JuraidGateOpen = 1;
if(pNpc->GetZoneID() == ZONE_JURAD_MOUNTAIN)
{
if((pNpc->GetSPosX() / 10) == 512 && (pNpc->GetSPosZ() / 10) == 256 && pNpc->GetProtoID() == 8110)
{
g_pMain->pTempleEvent.JuraidElmoGateID3[EventRoom] = sNid;
byDirection = 90;
}
if((pNpc->GetSPosX() / 10) == 512 && (pNpc->GetSPosZ() / 10) == 767 && pNpc->GetProtoID() == 8110)
g_pMain->pTempleEvent.JuraidKarusGateID3[EventRoom] = sNid;
if((pNpc->GetSPosX() / 10) == 308 && pNpc->GetProtoID() == 8110)
{
g_pMain->pTempleEvent.JuraidKarusGateID2[EventRoom] = sNid;
byDirection = 135;
}
if((pNpc->GetSPosX() / 10) == 715 && pNpc->GetProtoID() == 8110)
{
g_pMain->pTempleEvent.JuraidElmoGateID2[EventRoom] = sNid;
byDirection = 225;
}
if((pNpc->GetSPosX() / 10) == 224 && pNpc->GetProtoID() == 8110)
{
g_pMain->pTempleEvent.JuraidKarusGateID1[EventRoom] = sNid;
byDirection = 90;
}
if((pNpc->GetSPosX() / 10) == 799 && pNpc->GetProtoID() == 8110)
g_pMain->pTempleEvent.JuraidElmoGateID1[EventRoom] = sNid;
}
if(pNpc->GetZoneID() == ZONE_STONE1)
{
if(pNpc->GetProtoID() == 7032)
byDirection = 225;
else if(pNpc->GetProtoID() == 7000
|| pNpc->GetProtoID() == 7001
|| pNpc->GetProtoID() == 7003)
{
uint16 RandomMap[MAX_MONSTER_STONE_EVENT_ROOM];
memset(RandomMap, 0, sizeof(RandomMap));
int i = 0;
foreach_stlmap_nolock (itr, g_pMain->m_MonsterRespawnListRandomArray)
{
_MONSTER_RESPAWN_LIST_RANDOM * pRandom = itr->second;
if(pRandom == nullptr)
continue;
if(pRandom->ZoneID != ZONE_STONE1
|| pRandom->Family != g_pMain->Zone1Family[EventRoom])
continue;
if((pRandom->isBoss == 0
&& pNpc->GetProtoID() == 7003)
|| (pRandom->isBoss == 1
&& pNpc->GetProtoID() != 7003))
continue;
if(pRandom->isBoss == 1
&& pNpc->GetProtoID() == 7003)
{
g_pMain->Zone1Boss[EventRoom] = pRandom->sSid;
pNpc->m_sSid = pRandom->sSid;
pNpc->m_sPid = pRandom->sPid;
pNpc->m_strName = pRandom->strName;
}else if(pNpc->GetProtoID() != 7003
&& pRandom->isBoss == 0)
{
RandomMap[i] = pRandom->sIndex;
i++;
}
}
if(pNpc->GetProtoID() != 7003 && i > 0)
{
uint16 Randomized = myrand(0,i-1);
_MONSTER_RESPAWN_LIST_RANDOM * kRandom = g_pMain->m_MonsterRespawnListRandomArray.GetData(RandomMap[Randomized]);
if(kRandom != nullptr)
{
pNpc->m_sSid = kRandom->sSid;
pNpc->m_sPid = kRandom->sPid;
pNpc->m_strName = kRandom->strName;
}
}
}
}
if(pNpc->GetZoneID() == ZONE_STONE2)
{
if(pNpc->GetProtoID() == 7033)
byDirection = 225;
else if(pNpc->GetProtoID() == 7005
|| pNpc->GetProtoID() == 7006
|| pNpc->GetProtoID() == 7008
|| pNpc->GetProtoID() == 7040)
{
uint16 RandomMap[MAX_MONSTER_STONE_EVENT_ROOM];
memset(RandomMap, 0, sizeof(RandomMap));
int i = 0;
foreach_stlmap_nolock (itr, g_pMain->m_MonsterRespawnListRandomArray)
{
_MONSTER_RESPAWN_LIST_RANDOM * pRandom = itr->second;
if(pRandom == nullptr)
continue;
if(pRandom->ZoneID != ZONE_STONE2
|| pRandom->Family != g_pMain->Zone2Family[EventRoom])
continue;
if((pRandom->isBoss == 0
&& pNpc->GetProtoID() == 7008)
|| (pRandom->isBoss == 1
&& pNpc->GetProtoID() != 7008))
continue;
if(pRandom->isBoss == 1
&& pNpc->GetProtoID() == 7008)
{
g_pMain->Zone2Boss[EventRoom] = pRandom->sSid;
pNpc->m_sSid = pRandom->sSid;
pNpc->m_sPid = pRandom->sPid;
pNpc->m_strName = pRandom->strName;
}else if(pNpc->GetProtoID() != 7008
&& pRandom->isBoss == 0)
{
RandomMap[i] = pRandom->sIndex;
i++;
}
}
if(pNpc->GetProtoID() != 7008 && i > 0)
{
uint16 Randomized = myrand(0,i-1);
_MONSTER_RESPAWN_LIST_RANDOM * kRandom = g_pMain->m_MonsterRespawnListRandomArray.GetData(RandomMap[Randomized]);
if(kRandom != nullptr)
{
pNpc->m_sSid = kRandom->sSid;
pNpc->m_sPid = kRandom->sPid;
pNpc->m_strName = kRandom->strName;
}
}
}
}
if(pNpc->GetZoneID() == ZONE_STONE3)
{
if(pNpc->GetProtoID() == 7034)
byDirection = 225;
else if(pNpc->GetProtoID() == 7011
|| pNpc->GetProtoID() == 7010
|| pNpc->GetProtoID() == 7013)
{
uint16 RandomMap[MAX_MONSTER_STONE_EVENT_ROOM];
memset(RandomMap, 0, sizeof(RandomMap));
int i = 0;
foreach_stlmap_nolock (itr, g_pMain->m_MonsterRespawnListRandomArray)
{
_MONSTER_RESPAWN_LIST_RANDOM * pRandom = itr->second;
if(pRandom == nullptr)
continue;
if(pRandom->ZoneID != ZONE_STONE3
|| pRandom->Family != g_pMain->Zone3Family[EventRoom])
continue;
if((pRandom->isBoss == 0
&& pNpc->GetProtoID() == 7013)
|| (pRandom->isBoss == 1
&& pNpc->GetProtoID() != 7013))
continue;
if(pRandom->isBoss == 1
&& pNpc->GetProtoID() == 7013)
{
g_pMain->Zone3Boss[EventRoom] = pRandom->sSid;
pNpc->m_sSid = pRandom->sSid;
pNpc->m_sPid = pRandom->sPid;
pNpc->m_strName = pRandom->strName;
}else if(pNpc->GetProtoID() != 7013
&& pRandom->isBoss == 0)
{
RandomMap[i] = pRandom->sIndex;
i++;
}
}
if(pNpc->GetProtoID() != 7013 && i > 0)
{
uint16 Randomized = myrand(0,i-1);
_MONSTER_RESPAWN_LIST_RANDOM * kRandom = g_pMain->m_MonsterRespawnListRandomArray.GetData(RandomMap[Randomized]);
if(kRandom != nullptr)
{
pNpc->m_sSid = kRandom->sSid;
pNpc->m_sPid = kRandom->sPid;
pNpc->m_strName = kRandom->strName;
}
}
}
}
if (pNpc->nIsPet)
{
CPet * mPet = g_pMain->GetPetPtr(pNpc->nSerial);
if (mPet != nullptr)
{
mPet->m_pNpc = pNpc;
mPet->m_pNpc->m_sNid = mPet->m_sNid;
mPet->mode = 4;
pNpc->m_iMaxHP = mPet->m_sMaxHp;
pNpc->m_iHP = mPet->m_sHp;
}
else
return;
}
if (strName.empty() || strName.length() > MAX_NPC_SIZE)
{
pNpc->DecRef();
return;
}
pNpc->SetUnitEventRoom(EventRoom);
pNpc->SetNPCEventRoom(EventRoom);
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());
if(g_pMain->m_byBattleSiegeWarOpen && pNpc->m_sSid == 541)
g_pMain->KickOutZoneUsers(ZONE_DELOS,ZONE_DELOS);
}
void CAISocket::RecvNpcRegionUpdate(Packet & pkt)
{
uint16 sNpcID;
float fX, fY, fZ;
pkt >> sNpcID >> fX >> fY >> fZ;
CNpc * pNpc = g_pMain->GetNpcPtr(sNpcID);
if (pNpc == nullptr)
return;
pNpc->SetPosition(fX, fY, fZ);
pNpc->RegisterRegion();
}
void CAISocket::RecvUserExp(Packet & pkt)
{
uint16 tid;
pkt >> tid;
CUser* pUser = g_pMain->GetUserPtr(tid);
if (pUser == nullptr)
return;
pUser->RecvUserExp(pkt);
}
void CAISocket::RecvSystemMsg(Packet & pkt)
{
Packet result;
std::string strSysMsg;
uint8 bType;
pkt >> bType >> strSysMsg;
ChatPacket::Construct(&result, bType, &strSysMsg);
g_pMain->Send_All(&result);
}
void CAISocket::RecvNpcGiveItem(Packet & pkt)
{
Packet result(WIZ_ITEM_DROP);
short sUid, sNid, regionx, regionz;
float fX, fZ, fY;
uint8 byCount, bZone;
int nItemNumber[NPC_HAVE_ITEM_LIST];
uint8 nSlotIndex[NPC_HAVE_ITEM_LIST];
short sCount[NPC_HAVE_ITEM_LIST];
CUser* pUser = nullptr;
pkt >> sUid >> sNid >> bZone >> regionx >> regionz >> fX >> fZ >> fY >> byCount;
for (int i = 0; i < byCount; i++)
{
pkt >> nItemNumber[i] >> sCount[i];
nSlotIndex[i] = i;
}
if (sUid < 0 || sUid >= MAX_USER)
return;
C3DMap *pMap = g_pMain->GetZoneByID(bZone);
if (pMap == nullptr)
return;
pUser = g_pMain->GetUserPtr(sUid);
if (pUser == nullptr)
return;
_LOOT_BUNDLE * pBundle = new _LOOT_BUNDLE;
pBundle->tDropTime = uint32(UNIXTIME);
pBundle->x = fX;
pBundle->z = fZ;
pBundle->y = fY;
pBundle->LooterID = -1;
pBundle->ItemsCount = 0;
memset(pBundle->Items, 0, sizeof(pBundle->Items));
for (int i = 0; i < byCount; i++)
{
if (g_pMain->GetItemPtr(nItemNumber[i]))
{
_LOOT_ITEM pItem(nItemNumber[i], sCount[i]);
if (nItemNumber[i] == ITEM_GOLD)
{
// Add on any additional coins earned because of a global coin event.
// NOTE: Officially it caps at SHRT_MAX, but that's really only for technical reasons.
// Using the unsigned range gives us a little bit of wiggle room.
uint32 coinAmount = sCount[i] * (100 + g_pMain->m_byCoinEventAmount) / 100;
if (sCount[i] + coinAmount > USHRT_MAX)
coinAmount = USHRT_MAX;
pItem.sCount = coinAmount;
}
pBundle->Items[nSlotIndex[i]] = pItem; // emplace_back() would be so much more useful here, but requires C++11.
pBundle->ItemsCount++;
}
}
if (!pMap->RegionItemAdd(regionx, regionz, pBundle))
{
delete pBundle;
return;
}
result << sNid << pBundle->nBundleID << uint8(2);
pBundle->LooterID = pUser->GetID();
if (!pUser->isInParty())
{
pUser->Send(&result);
if(pUser->isSummonPet && pUser->SummonPetID > 0 )
{
_ITEM_TABLE * pItemData = nullptr;
if((pItemData = pUser->GetItemPrototype(SHOULDER)) == nullptr
|| !pItemData->isPet())
return;
_ITEM_DATA *pItem = nullptr;
if ((pItem = pUser->GetItem(SHOULDER)) == nullptr
|| pItem->nNum != pItemData->Getnum())
return;
CPet *newPet = g_pMain->GetPetPtr(pItem->nSerialNum);
if(newPet == nullptr || newPet->m_pNpc == nullptr)
return;
if(newPet->m_pNpc == nullptr)
return;
if(newPet->mode != 8)
return;
newPet->AddtoMovingMap(fX,fY,fZ,0,true,pBundle->nBundleID);
/*if(newPet->mode == 8 )
{
for (int i = 0; i < byCount; i++)
{
pBundle->LooterID = pUser->SummonPetID;
pUser->GiveItem(nItemNumber[i],sCount[i]);
}
}*/
}
}
else
{
g_pMain->Send_PartyMember(pUser->GetPartyID(), &result);
_PARTY_GROUP* pParty = g_pMain->GetPartyPtr(pUser->GetPartyID());
if (pParty == nullptr)
return;
for (int i = 0; i < MAX_PARTY_USERS; i++)
{
CUser *pUsers = g_pMain->GetUserPtr(pParty->uid[i]);
if (pUsers == nullptr)
continue;
if(pUser->isSummonPet && pUser->SummonPetID > 0 )
{
_ITEM_TABLE * pItemDatas = nullptr;
if((pItemDatas = pUsers->GetItemPrototype(SHOULDER)) == nullptr
|| !pItemDatas->isPet())
return;
_ITEM_DATA *pItems = nullptr;
if ((pItems = pUsers->GetItem(SHOULDER)) == nullptr
|| pItems->nNum != pItemDatas->Getnum())
return;
CPet *newPets = g_pMain->GetPetPtr(pItems->nSerialNum);
if(newPets == nullptr)
return;
if(newPets->m_pNpc == nullptr)
return;
if(newPets->mode != 8)
return;
if(!pUsers->isInRange(pBundle->x, pBundle->z, RANGE_50M))
return;
newPets->AddtoMovingMap(fX,fY,fZ,0,true,pBundle->nBundleID);
/*if(newPets->mode == 8 )
{
for (int i = 0; i < byCount; i++)
{
pBundle->LooterID = pUser->SummonPetID;
pUsers->GiveItem(nItemNumber[i],sCount[i]);
}
}*/
}
}
}
}
void CAISocket::RecvCheckAlive(Packet & pkt)
{
Packet result(AG_CHECK_ALIVE_REQ);
g_pMain->m_sErrorSocketCount = 0;
Send(&result);
foreach_stlmap(itr,g_pMain->m_arBotArray)
{
CBot * pBot = itr->second;
if(pBot != nullptr)
{
if(pBot->isInGame())
{
if((pBot->m_bResHpType == USER_MINING || pBot->m_bResHpType == USER_FLASHING) && pBot->m_iGold + 15 < uint32(UNIXTIME))
{
Packet result(WIZ_MINING, uint8(MiningAttempt));
uint16 resultCode = MiningResultSuccess, Random = myrand(0,10000);
uint16 sEffect = 0;
if(Random > 4000 || pBot->m_bResHpType == USER_SITDOWN) // EXP
sEffect = 13082; // "XP" effect
else
sEffect = 13081; // "Item" effect
result << resultCode << pBot->GetID() << sEffect;
pBot->SendToRegion(&result);
pBot->m_iGold = uint32(UNIXTIME);
}
else if(pBot->isMerchanting() && !pBot->MerchantChat.empty() && pBot->m_iLoyalty < uint32(UNIXTIME) - 99)
{
Packet result(WIZ_CHAT);
ChatPacket::Construct(&result, MERCHANT_CHAT, &pBot->MerchantChat, &pBot->GetName(), pBot->m_bNation, pBot->GetID());
pBot->SendToRegion(&result);
pBot->m_iLoyalty = uint32(UNIXTIME);
}
}
}
}
}
void CAISocket::RecvGateDestory(Packet & pkt)
{
uint16 nid, sCurZone, rX, rZ;
bool bGateStatus;
pkt >> nid >> bGateStatus >> sCurZone >> rX >> rZ;
CNpc* pNpc = g_pMain->GetNpcPtr(nid);
if (pNpc == nullptr)
return;
pNpc->m_byGateOpen = bGateStatus;
TRACE("RecvGateDestory - (%d,%s), gate_status=%d\n", pNpc->GetID(), pNpc->GetName().c_str(), pNpc->m_byGateOpen);
}
// TODO: 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);
if(pNpc->m_bIsEventNpc)
g_pMain->m_arNpcArray.DeleteData(pNpc->GetID());
}
void CAISocket::RecvNpcInOut(Packet & pkt)
{
uint8 bType;
uint16 sNid;
float fX, fZ, fY;
pkt >> bType >> sNid >> fX >> fZ >> fY;
CNpc * pNpc = g_pMain->GetNpcPtr(sNid);
if (pNpc)
pNpc->SendInOut(bType, fX, fZ, fY);
}
void CAISocket::RecvBattleEvent(Packet & pkt)
{
string chatstr, strMaxUserName, strKnightsName;
CUser* pUser = nullptr;
CKnights* pKnights = nullptr;
uint8 bType, bResult;
pkt >> bType >> bResult;
if (bType == BATTLE_EVENT_OPEN)
{
}
else if (bType == BATTLE_MAP_EVENT_RESULT)
{
if (!g_pMain->isWarOpen())
{
TRACE("#### RecvBattleEvent Fail : battleopen = %d, type = %d\n", g_pMain->m_byBattleOpen, bType);
return;
}
if (bResult == KARUS)
g_pMain->m_byKarusOpenFlag = true;
else if (bResult == ELMORAD)
g_pMain->m_byElmoradOpenFlag = true;
}
else if (bType == BATTLE_EVENT_RESULT)
{
if (!g_pMain->isWarOpen())
{
TRACE("#### RecvBattleEvent Fail : battleopen = %d, type=%d\n", g_pMain->m_byBattleOpen, bType);
return;
}
pkt.SByte();
pkt >> strMaxUserName;
if (!strMaxUserName.empty()
&& !g_pMain->m_byBattleSave)
{
Packet result(WIZ_BATTLE_EVENT, bType);
result.SByte();
result << bResult << strMaxUserName;
g_pMain->AddDatabaseRequest(result);
g_pMain->m_byBattleSave = true;
}
}
else if (bType == BATTLE_EVENT_MAX_USER)
{
pkt.SByte();
pkt >> strMaxUserName;
if (!strMaxUserName.empty())
{
pUser = g_pMain->GetUserPtr(strMaxUserName, TYPE_CHARACTER);
if (pUser != nullptr)
{
pKnights = g_pMain->GetClanPtr(pUser->GetClanID());
if (pKnights)
strKnightsName = pKnights->m_strName;
if (g_pMain->m_byBattleZone + ZONE_BATTLE_BASE == ZONE_BATTLE
|| g_pMain->m_byBattleZone + ZONE_BATTLE_BASE == ZONE_BATTLE2
|| g_pMain->m_byBattleZone + ZONE_BATTLE_BASE == ZONE_BATTLE6
|| g_pMain->m_byBattleZone + ZONE_BATTLE_BASE == ZONE_BATTLE3
|| g_pMain->m_byBattleZone + ZONE_BATTLE_BASE == ZONE_BATTLE4)
{
if (pUser->GetNation() == KARUS)
g_pMain->m_sKilledElmoNpc++;
else
g_pMain->m_sKilledKarusNpc++;
if (g_pMain->m_sKilledKarusNpc == 3 || g_pMain->m_sKilledElmoNpc == 3)
{
g_pMain->m_bResultDelay = true;
g_pMain->m_bResultDelayVictory = pUser->GetNation();
if(g_pMain->m_byBattleZone + ZONE_BATTLE_BASE != ZONE_BATTLE4)
g_pMain->BattleZoneResult(pUser->GetNation());
if(g_pMain->m_byBattleZone + ZONE_BATTLE_BASE == ZONE_BATTLE4
&& (pUser->GetNation() == 1 && g_pMain->m_sKarusMonuments >= 7)
&& (pUser->GetNation() == 2 && g_pMain->m_sElmoMonuments >= 7))
g_pMain->BattleZoneResult(pUser->GetNation());
}
}
}
}
int nResourceID = 0;
switch (bResult)
{
case 1: // captain
nResourceID = IDS_KILL_CAPTAIN;
break;
case 3: // Karus warder 1
nResourceID = IDS_KILL_KARUS_GUARD1;
break;
case 4: // Karus warder 2
nResourceID = IDS_KILL_KARUS_GUARD2;
break;
case 5: // El Morad warder 1
nResourceID = IDS_KILL_ELMO_GUARD1;
break;
case 6: // El Morad warder 2
nResourceID = IDS_KILL_ELMO_GUARD2;
break;
case 7: // Karus Keeper
nResourceID = IDS_KILL_GATEKEEPER;
break;
case 8: // El Morad Keeper
nResourceID = IDS_KILL_GATEKEEPER;
break;
}
if (nResourceID == 0)
{
TRACE("RecvBattleEvent: could not establish resource for result %d", bResult);
return;
}
g_pMain->GetServerResource(nResourceID, &chatstr, strKnightsName.c_str(), strMaxUserName.c_str());
Packet result;
string finalstr;
g_pMain->GetServerResource(IDP_ANNOUNCEMENT, &finalstr, chatstr.c_str());
ChatPacket::Construct(&result, WAR_SYSTEM_CHAT, &finalstr);
g_pMain->Send_All(&result);
ChatPacket::Construct(&result, PUBLIC_CHAT, &finalstr);
g_pMain->Send_All(&result);
}
}
void CAISocket::RecvNpcEventItem(Packet & pkt)
{
uint16 sUid, sNid;
uint32 nItemID, nCount;
pkt >> sUid >> sNid >> nItemID >> nCount;
CUser *pUser = g_pMain->GetUserPtr(sUid);
if (pUser == nullptr)
return;
pUser->GiveItem(nItemID, nCount);
}
void CAISocket::RecvGateOpen(Packet & pkt)
{
uint16 sNid, sEventID;
bool bFlag;
pkt >> sNid >> sEventID >> bFlag;
CNpc *pNpc = g_pMain->GetNpcPtr(sNid);
if (pNpc == nullptr)
{
TRACE("#### RecvGateOpen Npc Pointer null : nid=%d ####\n", sNid);
return;
}
pNpc->m_byGateOpen = bFlag; // possibly not needed (we'll do it below), but need to make sure.
_OBJECT_EVENT *pEvent = pNpc->GetMap()->GetObjectEvent(sEventID);
if (pEvent == nullptr)
{
TRACE("#### RecvGateOpen Npc Object fail : nid=%d, sid=%d ####\n", sNid, sEventID);
return;
}
if (pNpc->isGate())
pNpc->SendGateFlag(bFlag, false);
}
void CAISocket::RecvCompressed(Packet & pkt)
{
uint32 compressedLength, originalLength;
uint32 crc;
pkt >> compressedLength >> originalLength >> crc;
char *decompressedBuffer = new char[originalLength];
// Does the length match what it's supposed to be
uint32 result = lzf_decompress(pkt.contents() + pkt.rpos(), compressedLength, decompressedBuffer, originalLength);
if (result
!= originalLength)
{
delete [] decompressedBuffer;
return;
}
pkt.Initialize(*decompressedBuffer);
if (originalLength > 1)
pkt.append(decompressedBuffer + 1, originalLength - 1);
delete [] decompressedBuffer;
HandlePacket(pkt);
}
void CAISocket::RecvNpcHpChange(Packet & pkt)
{
Unit * pAttacker = nullptr;
int16 nid, sAttackerID;
int32 nHP, nAmount;
pkt >> nid >> sAttackerID >> nHP >> nAmount;
CNpc * pNpc = g_pMain->GetNpcPtr(nid);
if (pNpc == nullptr)
return;
pAttacker = g_pMain->GetUnitPtr(sAttackerID);
pNpc->HpChange(nAmount, pAttacker, false);
}