knightonline/server/GameServer/Map.cpp

207 lines
5.7 KiB
C++

#include "stdafx.h"
#include "Map.h"
#include <set>
#include "../shared/SMDFile.h"
/* passthru methods */
int C3DMap::GetXRegionMax() { return m_smdFile->GetXRegionMax(); }
int C3DMap::GetZRegionMax() { return m_smdFile->GetZRegionMax(); }
bool C3DMap::IsValidPosition(float x, float z, float y) { return m_smdFile->IsValidPosition(x, z, y); }
_REGENE_EVENT * C3DMap::GetRegeneEvent(int objectindex) { return m_smdFile->GetRegeneEvent(objectindex); }
_WARP_INFO * C3DMap::GetWarp(int warpID) { return m_smdFile->GetWarp(warpID); }
void C3DMap::GetWarpList(int warpGroup, std::set<_WARP_INFO *> & warpEntries) { m_smdFile->GetWarpList(warpGroup, warpEntries); }
C3DMap::C3DMap() : m_smdFile(nullptr), m_ppRegion(nullptr),
m_nZoneNumber(0), m_sMaxUser(150), m_wBundle(1)
{
}
bool C3DMap::Initialize(_ZONE_INFO *pZone)
{
m_nServerNo = pZone->m_nServerNo;
m_nZoneNumber = pZone->m_nZoneNumber;
m_fInitX = pZone->m_fInitX;
m_fInitY = pZone->m_fInitY;
m_fInitZ = pZone->m_fInitZ;
m_smdFile = SMDFile::Load(pZone->m_MapName, true /* load warps & regene events */);
if (m_smdFile != nullptr)
{
SetZoneAttributes(m_nZoneNumber);
m_ppRegion = new CRegion*[m_smdFile->m_nXRegion];
for (int i = 0; i < m_smdFile->m_nXRegion; i++)
m_ppRegion[i] = new CRegion[m_smdFile->m_nZRegion];
}
return (m_smdFile != nullptr);
}
CRegion * C3DMap::GetRegion(uint16 regionX, uint16 regionZ)
{
if (regionX > GetXRegionMax()
|| regionZ > GetZRegionMax())
return nullptr;
Guard lock(m_lock);
return &m_ppRegion[regionX][regionZ];
}
bool C3DMap::RegionItemAdd(uint16 rx, uint16 rz, _LOOT_BUNDLE * pBundle)
{
if (pBundle == nullptr)
return false;
Guard lock(m_lock);
pBundle->nBundleID = m_wBundle++;
std::vector<uint32> willdelete;
foreach_stlmap_nolock(itr,m_RegionItemArray)
{
_LOOT_BUNDLE *Loot = itr->second;
if(uint32(Loot->tDropTime + DROP_MAX_TIME) < uint32(UNIXTIME))
willdelete.push_back(Loot->nBundleID);
}
foreach(itr,willdelete)
m_RegionItemArray.DeleteData(*itr);
m_RegionItemArray.PutData(pBundle->nBundleID, pBundle);
if (m_wBundle == UINT16_MAX)
m_wBundle = 1;
return true;
}
/**
* @brief Removes an item from a region's bundle.
* If the bundle's empty, the bundle is then
* removed from the region.
*
* @param pRegion The region.
* @param pBundle The bundle.
* @param pItem The item being removed from the bundle.
*/
void C3DMap::RegionItemRemove(_LOOT_BUNDLE * pBundle, _LOOT_ITEM * pItem)
{
if (pBundle == nullptr
|| pItem == nullptr)
return;
Guard lock(m_RegionItemArray.m_lock);
// If the bundle exists, and the item matches what the user's removing
// we can remove this item from the bundle.
for(int i = 0; i < NPC_HAVE_ITEM_LIST;i++)
{
_LOOT_ITEM * pLoot = &pBundle->Items[i];
if (pLoot == pItem)
{
memset(pLoot, 0, sizeof(_LOOT_ITEM));
pBundle->ItemsCount--;
// If this was the last item in the bundle, remove the bundle from the region.
if (pBundle->ItemsCount)
return;
m_RegionItemArray.DeleteData(pBundle->nBundleID);
return;
}
}
}
bool C3DMap::CheckEvent(float x, float z, CUser* pUser)
{
if (pUser == nullptr)
return false;
CGameEvent *pEvent;
int event_index = m_smdFile->GetEventID((int)(x / m_smdFile->GetUnitDistance()), (int)(z / m_smdFile->GetUnitDistance()));
if (event_index < 2)
{
if (g_pMain->m_byBattleOpen == NATION_BATTLE && pUser->GetMap()->isWarZone() && g_pMain->m_byBattleZoneType == 0)
{
pEvent = m_EventArray.GetData(1010 + (pUser->GetNation() == ELMORAD ? 1 : 2));
if (pEvent != nullptr)
{
if ((x > pEvent->m_iCond[0] && x < pEvent->m_iCond[1]) && (z > pEvent->m_iCond[2] && z < pEvent->m_iCond[3]))
pUser->ZoneChange(pEvent->m_iExec[0],(float)pEvent->m_iExec[1],(float)pEvent->m_iExec[2]);
else
{
pEvent = m_EventArray.GetData(1010 + pUser->GetNation());
if (pEvent != nullptr)
{
if ((x > pEvent->m_iCond[0] && x < pEvent->m_iCond[1]) && (z > pEvent->m_iCond[2] && z < pEvent->m_iCond[3]))
if (g_pMain->m_bVictory == pUser->GetNation())
pUser->ZoneChange(pEvent->m_iExec[0],(float)pEvent->m_iExec[1],(float)pEvent->m_iExec[2]);
}
}
}
return false;
}
else
return false;
}
if ( g_pMain->m_byBattleOpen == NATION_BATTLE &&
pUser->GetZoneID() != ZONE_KARUS_ESLANT &&
pUser->GetZoneID() != ZONE_ELMORAD_ESLANT )
event_index += g_pMain->m_byBattleZone -1;
if ( g_pMain->m_byBattleOpen == SNOW_BATTLE &&
pUser->GetZoneID() != ZONE_KARUS_ESLANT &&
pUser->GetZoneID() != ZONE_ELMORAD_ESLANT )
event_index += g_pMain->m_byBattleZone +10;
pEvent = m_EventArray.GetData( event_index );
if (pEvent == nullptr)
return false;
if (pEvent->m_bType == 1 && (pEvent->m_iExec[0] > ZONE_BATTLE_BASE && pEvent->m_iExec[0] <= ZONE_BATTLE6) && g_pMain->m_byBattleOpen != NATION_BATTLE )
return false;
else if (pEvent->m_bType == 1 && pEvent->m_iExec[0] == ZONE_SNOW_BATTLE && g_pMain->m_byBattleOpen != SNOW_BATTLE )
return false;
else if (pEvent->m_iExec[0] > ZONE_BATTLE_BASE && pEvent->m_iExec[0] <= ZONE_BATTLE6)
{
if (g_pMain->m_byBattleZoneType == ZONE_ARDREAM && (pUser->GetLevel() < MIN_LEVEL_NIEDS_TRIANGLE || pUser->GetLevel() > MAX_LEVEL_NIEDS_TRIANGLE || !pUser->CanLevelQualify(MAX_LEVEL_NIEDS_TRIANGLE)))
return false;
}
pEvent->RunEvent(pUser);
return true;
}
_OBJECT_EVENT * C3DMap::GetObjectEvent(int objectindex)
{
foreach_stlmap_nolock(itr, g_pMain->m_ObjectEventArray)
{
if (itr->second->sZoneID == m_nZoneNumber
&& itr->second->sIndex == objectindex)
return itr->second;
}
return nullptr;
}
C3DMap::~C3DMap()
{
m_EventArray.DeleteAllData();
if (m_ppRegion != nullptr)
{
for (int i = 0; i <= GetXRegionMax(); i++)
delete [] m_ppRegion[i];
delete [] m_ppRegion;
m_ppRegion = nullptr;
}
if (m_smdFile != nullptr)
m_smdFile->DecRef();
}