void CNpc::NpcInOut(BYTE Type, float fx, float fz, float fy) { int send_index = 0; char buff[1024]; memset( buff, 0x00, 1024 ); C3DMap *pMap = m_pMain->GetZoneByID(getZoneID()); if (pMap == NULL) return; m_pMap = pMap; if( Type == NPC_OUT ) { pMap->RegionNpcRemove( m_sRegion_X, m_sRegion_Z, m_sNid ); } else { pMap->RegionNpcAdd( m_sRegion_X, m_sRegion_Z, m_sNid ); m_fCurX = fx; m_fCurZ = fz; m_fCurY = fy; } SetByte( buff, WIZ_NPC_INOUT, send_index ); SetByte( buff, Type, send_index ); SetShort( buff, m_sNid, send_index ); if( Type == NPC_OUT ) { m_pMain->Send_Region(buff, send_index, GetMap(), m_sRegion_X, m_sRegion_Z); return; } GetNpcInfo(buff, send_index); m_pMain->Send_Region(buff, send_index, GetMap(), m_sRegion_X, m_sRegion_Z); }
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; }
void CAISocket::RecvNpcGiveItem(Packet & pkt) { Packet result(WIZ_ITEM_DROP); short sUid, sNid, regionx, regionz; float fX, fZ, fY; BYTE byCount, bZone; int nItemNumber[NPC_HAVE_ITEM_LIST]; short sCount[NPC_HAVE_ITEM_LIST]; CUser* pUser = NULL; pkt >> sUid >> sNid >> bZone >> regionx >> regionz >> fX >> fZ >> fY >> byCount; for (int i = 0; i < byCount; i++) pkt >> nItemNumber[i] >> sCount[i]; if (sUid < 0 || sUid >= MAX_USER) return; C3DMap *pMap = g_pMain->GetZoneByID(bZone); if (pMap == NULL) return; _ZONE_ITEM *pItem = new _ZONE_ITEM; for(int i=0; i<6; i++) { pItem->itemid[i] = 0; pItem->count[i] = 0; } pItem->time = TimeGet(); pItem->x = fX; pItem->z = fZ; pItem->y = fY; for(int i=0; i<byCount; i++) { if( g_pMain->GetItemPtr(nItemNumber[i]) ) { pItem->itemid[i] = nItemNumber[i]; pItem->count[i] = sCount[i]; } } if (!pMap->RegionItemAdd(regionx, regionz, pItem )) { delete pItem; return; } pUser = g_pMain->GetUserPtr(sUid); if (pUser == NULL) return; result << sNid << uint32(pItem->bundle_index); if (!pUser->isInParty()) pUser->Send(&result); else g_pMain->Send_PartyMember(pUser->m_sPartyIndex, &result); }
void CNpc::RegisterRegion() { int iRegX = 0, iRegZ = 0, old_region_x = 0, old_region_z = 0; iRegX = (int)(m_fCurX / VIEW_DISTANCE); iRegZ = (int)(m_fCurZ / VIEW_DISTANCE); if (m_sRegion_X != iRegX || m_sRegion_Z != iRegZ) { C3DMap* pMap = GetMap(); if (pMap == NULL) return; old_region_x = m_sRegion_X; old_region_z = m_sRegion_Z; pMap->RegionNpcRemove(m_sRegion_X, m_sRegion_Z, m_sNid); m_sRegion_X = iRegX; m_sRegion_Z = iRegZ; pMap->RegionNpcAdd(m_sRegion_X, m_sRegion_Z, m_sNid); RemoveRegion( old_region_x - m_sRegion_X, old_region_z - m_sRegion_Z ); // delete npc 는 계산 방향이 진행방향의 반대... InsertRegion( m_sRegion_X - old_region_x, m_sRegion_Z - old_region_z ); // add npc 는 계산 방향이 진행방향... } }
int CNpc::GetRegionNpcList(int region_x, int region_z, char *buff, int &t_count) { if( m_pMain->m_bPointCheckFlag == FALSE) return 0; // 포인터 참조하면 안됨 int buff_index = 0, i=0, j=0; int user_count = 0, nid = -1; C3DMap* pMap = GetMap(); CNpc* pNpc = NULL; if (pMap == NULL || region_x < 0 || region_z < 0 || region_x > pMap->GetXRegionMax() || region_z > pMap->GetZRegionMax() ) return 0; EnterCriticalSection( &g_region_critical ); map < int, int* >::iterator Iter1; map < int, int* >::iterator Iter2; Iter1 = pMap->m_ppRegion[region_x][region_z].m_RegionNpcArray.m_UserTypeMap.begin(); Iter2 = pMap->m_ppRegion[region_x][region_z].m_RegionNpcArray.m_UserTypeMap.end(); for( ; Iter1 != Iter2; Iter1++ ) { nid = *( (*Iter1).second ); if( nid < 0 ) continue; pNpc = (CNpc*)m_pMain->m_arNpcArray.GetData(nid); if( pNpc) { SetShort( buff, pNpc->m_sNid, buff_index ); t_count++; } } LeaveCriticalSection( &g_region_critical ); return buff_index; }
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; } }
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]; 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]; if (sUid < 0 || sUid >= MAX_USER) return; C3DMap *pMap = g_pMain->GetZoneByID(bZone); if (pMap == nullptr) return; _LOOT_BUNDLE * pBundle = new _LOOT_BUNDLE; pBundle->tDropTime = UNIXTIME; pBundle->x = fX; pBundle->z = fZ; pBundle->y = fY; 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; pUser = g_pMain->GetUserPtr(sUid); if (pUser != nullptr) if (pUser->m_bPremiumType != 0) coinAmount = coinAmount * (100 + g_pMain->m_PremiumItemArray.GetData(pUser->m_bPremiumType)->NoahPercent) / 100; pItem.sCount = coinAmount; } pBundle->Items.push_back(pItem); // emplace_back() would be so much more useful here, but requires C++11. } } if (!pMap->RegionItemAdd(regionx, regionz, pBundle)) { delete pBundle; return; } if (pUser == nullptr) return; result << sNid << pBundle->nBundleID; if (!pUser->isInParty()) pUser->Send(&result); else g_pMain->Send_PartyMember(pUser->GetPartyID(), &result); }
void CAISocket::RecvNpcGiveItem(char* pBuf) { int index = 0, send_index = 0; char send_buff[1024]; short sUid, sNid, sZone, regionx, regionz; float fX, fZ, fY; BYTE byCount; int nItemNumber[NPC_HAVE_ITEM_LIST]; short sCount[NPC_HAVE_ITEM_LIST]; _ZONE_ITEM* pItem = NULL; C3DMap* pMap = NULL; CUser* pUser = NULL; sUid = GetShort(pBuf,index); // Item을 가져갈 사람의 아이디... (이것을 참조해서 작업하셈~) sNid = GetShort(pBuf,index); sZone = GetShort(pBuf, index); regionx = GetShort( pBuf, index ); regionz = GetShort( pBuf, index ); fX = Getfloat(pBuf,index); fZ = Getfloat(pBuf,index); fY = Getfloat(pBuf,index); byCount = GetByte(pBuf,index); for(int i=0; i<byCount; i++) { nItemNumber[i] = GetDWORD(pBuf, index); sCount[i] = GetShort(pBuf,index); } if( sUid < 0 || sUid >= MAX_USER ) return; pMap = m_pMain->GetZoneByID(sZone); if (pMap == NULL) return; pItem = new _ZONE_ITEM; for(int i=0; i<6; i++) { pItem->itemid[i] = 0; pItem->count[i] = 0; } pItem->bundle_index = pMap->m_wBundle; pItem->time = TimeGet(); pItem->x = fX; pItem->z = fZ; pItem->y = fY; for(int i=0; i<byCount; i++) { if( m_pMain->m_ItemtableArray.GetData(nItemNumber[i]) ) { pItem->itemid[i] = nItemNumber[i]; pItem->count[i] = sCount[i]; } } if (!pMap->RegionItemAdd(regionx, regionz, pItem )) { delete pItem; return; } pUser = m_pMain->GetUserPtr(sUid); if (pUser == NULL) return; send_index = 0; SetByte( send_buff, WIZ_ITEM_DROP, send_index ); SetShort( send_buff, sNid, send_index ); SetDWORD( send_buff, pItem->bundle_index, send_index ); if( pUser->m_sPartyIndex == -1 ) pUser->Send( send_buff, send_index ); else m_pMain->Send_PartyMember( pUser->m_sPartyIndex, send_buff, send_index ); }
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; }