487 lines
11 KiB
C++
487 lines
11 KiB
C++
#include "stdafx.h"
|
||
#include "MAP.h"
|
||
#include "ServerDlg.h"
|
||
#include "Region.h"
|
||
#include "Npc.h"
|
||
#include "User.h"
|
||
#include "RoomEvent.h"
|
||
#include "../shared/packets.h"
|
||
#include <fstream>
|
||
#include <set>
|
||
#include "../shared/SMDFile.h"
|
||
|
||
INLINE int ParseSpace( char* tBuf, char* sBuf)
|
||
{
|
||
int i = 0, index = 0;
|
||
bool flag = false;
|
||
|
||
while (sBuf[index] == ' ' || sBuf[index] == '\t')
|
||
index++;
|
||
|
||
while (sBuf[index] !=' ' && sBuf[index] !='\t' && sBuf[index] != 0)
|
||
{
|
||
tBuf[i++] = sBuf[index++];
|
||
flag = true;
|
||
}
|
||
tBuf[i] = 0;
|
||
|
||
while (sBuf[index] == ' ' || sBuf[index] == '\t')
|
||
index++;
|
||
|
||
return !flag ? 0 : index;
|
||
};
|
||
|
||
using namespace std;
|
||
|
||
/* passthru methods */
|
||
int MAP::GetMapSize() { return m_smdFile->GetMapSize(); }
|
||
float MAP::GetUnitDistance() { return m_smdFile->GetUnitDistance(); }
|
||
int MAP::GetXRegionMax() { return m_smdFile->GetXRegionMax(); }
|
||
int MAP::GetZRegionMax() { return m_smdFile->GetZRegionMax(); }
|
||
short * MAP::GetEventIDs() { return m_smdFile->GetEventIDs(); }
|
||
|
||
MAP::MAP() : m_smdFile(nullptr), m_ppRegion(nullptr),
|
||
m_fHeight(nullptr), m_byRoomType(0), m_byRoomEvent(0),
|
||
m_byRoomStatus(RoomStatusInitialised), m_byInitRoomCount(0),
|
||
m_nZoneNumber(0), m_sKarusRoom(0), m_sElmoradRoom(0)
|
||
{
|
||
}
|
||
|
||
bool MAP::Initialize(_ZONE_INFO *pZone)
|
||
{
|
||
m_nZoneNumber = pZone->m_nZoneNumber;
|
||
m_byRoomEvent = pZone->m_byRoomEvent;
|
||
|
||
m_smdFile = SMDFile::Load(pZone->m_MapName);
|
||
|
||
if (m_smdFile != nullptr)
|
||
{
|
||
SetZoneAttributes(m_nZoneNumber);
|
||
foreach_stlmap_nolock(itr, g_pMain->m_ObjectEventArray)
|
||
{
|
||
if (itr->second->sZoneID == m_nZoneNumber)
|
||
{
|
||
_OBJECT_EVENT * pEvent = itr->second;
|
||
if (pEvent->sType == OBJECT_GATE
|
||
|| pEvent->sType == OBJECT_GATE2
|
||
|| pEvent->sType == OBJECT_GATE_LEVER
|
||
|| pEvent->sType == OBJECT_ANVIL
|
||
|| pEvent->sType == OBJECT_ARTIFACT
|
||
|| pEvent->sType == OBJECT_GATE_UNK)
|
||
g_pMain->AddObjectEventNpc(pEvent, this);
|
||
|
||
}
|
||
}
|
||
|
||
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]();
|
||
}
|
||
|
||
if (m_byRoomEvent > 0)
|
||
{
|
||
if (!LoadRoomEvent())
|
||
{
|
||
printf("ERROR: Unable to load room event (%d.aievt) for map - %s\n",
|
||
m_byRoomEvent, pZone->m_MapName.c_str());
|
||
m_byRoomEvent = 0;
|
||
}
|
||
else
|
||
{
|
||
m_byRoomEvent = 1;
|
||
}
|
||
}
|
||
|
||
return (m_smdFile != nullptr);
|
||
}
|
||
|
||
MAP::~MAP()
|
||
{
|
||
RemoveMapData();
|
||
|
||
if (m_smdFile != nullptr)
|
||
m_smdFile->DecRef();
|
||
}
|
||
|
||
void MAP::RemoveMapData()
|
||
{
|
||
if( m_ppRegion ) {
|
||
for(int i=0; i <= GetXRegionMax(); i++) {
|
||
delete[] m_ppRegion[i];
|
||
m_ppRegion[i] = nullptr;
|
||
}
|
||
delete[] m_ppRegion;
|
||
m_ppRegion = nullptr;
|
||
}
|
||
|
||
if (m_fHeight)
|
||
{
|
||
delete[] m_fHeight;
|
||
m_fHeight = nullptr;
|
||
}
|
||
|
||
m_arRoomEventArray.DeleteAllData();
|
||
}
|
||
|
||
bool MAP::IsMovable(int dest_x, int dest_y)
|
||
{
|
||
return m_smdFile->GetEventID(dest_x, dest_y) == 0;
|
||
}
|
||
|
||
void MAP::RegionUserAdd(int rx, int rz, int uid)
|
||
{
|
||
if (rx < 0 || rz < 0 || rx > GetXRegionMax() || rz > GetZRegionMax())
|
||
return;
|
||
|
||
Guard lock(m_lock);
|
||
CRegion * pRegion = &m_ppRegion[rx][rz];
|
||
|
||
if (pRegion == nullptr)
|
||
return;
|
||
|
||
int *pInt = new int;
|
||
*pInt = uid;
|
||
if (!pRegion->m_RegionUserArray.PutData(uid, pInt))
|
||
delete pInt;
|
||
|
||
pRegion->m_byMoving = !pRegion->m_RegionUserArray.IsEmpty();
|
||
}
|
||
|
||
bool MAP::RegionUserRemove(int rx, int rz, int uid)
|
||
{
|
||
if (rx < 0 || rz < 0 || rx > GetXRegionMax() || rz > GetZRegionMax())
|
||
return false;
|
||
|
||
Guard lock(m_lock);
|
||
CRegion * pRegion = &m_ppRegion[rx][rz];
|
||
|
||
if (pRegion == nullptr)
|
||
return false;
|
||
|
||
pRegion->m_RegionUserArray.DeleteData(uid);
|
||
pRegion->m_byMoving = !pRegion->m_RegionUserArray.IsEmpty();
|
||
return true;
|
||
}
|
||
|
||
void MAP::RegionNpcAdd(int rx, int rz, int nid)
|
||
{
|
||
if (rx < 0 || rz < 0 || rx > GetXRegionMax() || rz > GetZRegionMax())
|
||
return;
|
||
|
||
Guard lock(m_lock);
|
||
int *pInt = new int;
|
||
*pInt = nid;
|
||
if (!m_ppRegion[rx][rz].m_RegionNpcArray.PutData(nid, pInt))
|
||
delete pInt;
|
||
}
|
||
|
||
bool MAP::RegionNpcRemove(int rx, int rz, int nid)
|
||
{
|
||
if (rx < 0 || rz < 0 || rx > GetXRegionMax() || rz > GetZRegionMax())
|
||
return false;
|
||
|
||
Guard lock(m_lock);
|
||
m_ppRegion[rx][rz].m_RegionNpcArray.DeleteData( nid );
|
||
return true;
|
||
}
|
||
|
||
|
||
CRegion * MAP::GetRegion(uint16 regionX, uint16 regionZ)
|
||
{
|
||
if (regionX > GetXRegionMax()
|
||
|| regionZ > GetZRegionMax())
|
||
return nullptr;
|
||
|
||
Guard lock(m_lock);
|
||
return &m_ppRegion[regionX][regionZ];
|
||
}
|
||
|
||
bool MAP::LoadRoomEvent()
|
||
{
|
||
uint32 length, count;
|
||
string filename = string_format(MAP_DIR "%d.aievt", m_byRoomEvent);
|
||
char byte;
|
||
char buf[4096];
|
||
char first[1024];
|
||
char temp[1024];
|
||
int index = 0;
|
||
int t_index = 0, logic=0, exec=0;
|
||
int event_num = 0, nation = 0;
|
||
|
||
CRoomEvent* pEvent = nullptr;
|
||
ifstream is(filename);
|
||
if (!is)
|
||
{
|
||
printf("ERROR: %s does not exist or no permission to access.\n", filename.c_str());
|
||
return false;
|
||
}
|
||
|
||
is.seekg(0, is.end);
|
||
length = (uint32)is.tellg();
|
||
is.seekg (0, is.beg);
|
||
|
||
count = 0;
|
||
|
||
while (count < length)
|
||
{
|
||
is.read(&byte, 1);
|
||
count ++;
|
||
|
||
if( byte != '\r' && byte != '\n' ) buf[index++] = byte;
|
||
|
||
if((byte == '\n' || count == length ) && index > 1 ) {
|
||
buf[index] = (uint8) 0;
|
||
t_index = 0;
|
||
|
||
if( buf[t_index] == ';' || buf[t_index] == '/' ) { // <20>ּ<EFBFBD><D6BC><EFBFBD> <20><><EFBFBD><EFBFBD> ó<><C3B3>
|
||
index = 0;
|
||
continue;
|
||
}
|
||
|
||
t_index += ParseSpace( first, buf + t_index );
|
||
|
||
if( !strcmp( first, "ROOM" ) ) {
|
||
logic = 0; exec = 0;
|
||
t_index += ParseSpace( temp, buf + t_index ); event_num = atoi( temp );
|
||
|
||
if( m_arRoomEventArray.IsExist(event_num) ) {
|
||
TRACE("Event Double !!\n" );
|
||
goto cancel_event_load;
|
||
}
|
||
|
||
pEvent = nullptr;
|
||
pEvent = SetRoomEvent( event_num );
|
||
}
|
||
else if( !strcmp( first, "TYPE" ) ) {
|
||
t_index += ParseSpace( temp, buf + t_index ); m_byRoomType = atoi( temp );
|
||
}
|
||
else if( !strcmp( first, "L" ) ) {
|
||
if( !pEvent ) {
|
||
goto cancel_event_load;
|
||
}
|
||
}
|
||
else if( !strcmp( first, "E" ) ) {
|
||
if (!pEvent
|
||
|| exec >= MAX_CHECK_EVENT)
|
||
goto cancel_event_load;
|
||
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_Exec[exec].sNumber = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_Exec[exec].sOption_1 = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_Exec[exec].sOption_2 = atoi( temp );
|
||
exec++;
|
||
}
|
||
else if( !strcmp( first, "A" ) ) {
|
||
if (!pEvent
|
||
|| logic >= MAX_CHECK_EVENT)
|
||
goto cancel_event_load;
|
||
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_Logic[logic].sNumber = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_Logic[logic].sOption_1 = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_Logic[logic].sOption_2 = atoi( temp );
|
||
logic++;
|
||
pEvent->m_byCheck = logic;
|
||
}
|
||
else if( !strcmp( first, "O" ) ) {
|
||
if( !pEvent ) {
|
||
goto cancel_event_load;
|
||
}
|
||
}
|
||
else if( !strcmp( first, "NATION" ) ) {
|
||
if( !pEvent ) {
|
||
goto cancel_event_load;
|
||
}
|
||
|
||
t_index += ParseSpace( temp, buf + t_index ); nation = atoi( temp );
|
||
if( nation == KARUS ) {
|
||
m_sKarusRoom++;
|
||
}
|
||
else if( nation == ELMORAD ) {
|
||
m_sElmoradRoom++;
|
||
}
|
||
}
|
||
else if( !strcmp( first, "POS" ) ) {
|
||
if( !pEvent ) {
|
||
goto cancel_event_load;
|
||
}
|
||
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_iInitMinX = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_iInitMinZ = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_iInitMaxX = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_iInitMaxZ = atoi( temp );
|
||
}
|
||
else if( !strcmp( first, "POSEND" ) ) {
|
||
if( !pEvent ) {
|
||
goto cancel_event_load;
|
||
}
|
||
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_iEndMinX = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_iEndMinZ = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_iEndMaxX = atoi( temp );
|
||
t_index += ParseSpace( temp, buf + t_index ); pEvent->m_iEndMaxZ = atoi( temp );
|
||
}
|
||
else if( !strcmp( first, "END" ) ) {
|
||
if( !pEvent ) {
|
||
goto cancel_event_load;
|
||
}
|
||
}
|
||
|
||
index = 0;
|
||
}
|
||
}
|
||
|
||
is.close();
|
||
|
||
return true;
|
||
|
||
cancel_event_load:
|
||
printf("Unable to load AI EVT (%d.aievt), failed in or near event number %d.\n",
|
||
m_byRoomEvent, event_num);
|
||
is.close();
|
||
return false;
|
||
}
|
||
|
||
int MAP::IsRoomCheck(float fx, float fz)
|
||
{
|
||
int nX = (int)fx, nZ = (int)fz;
|
||
int minX=0, minZ=0, maxX=0, maxZ=0;
|
||
int room_number = 0;
|
||
|
||
foreach_stlmap_nolock (itr, m_arRoomEventArray)
|
||
{
|
||
CRoomEvent * pRoom = itr->second;
|
||
if (pRoom == nullptr
|
||
|| pRoom->isCleared())
|
||
continue;
|
||
|
||
if (pRoom->isInitialised())
|
||
{
|
||
minX = pRoom->m_iInitMinX; minZ = pRoom->m_iInitMinZ;
|
||
maxX = pRoom->m_iInitMaxX; maxZ = pRoom->m_iInitMaxZ;
|
||
}
|
||
else if (pRoom->isInProgress())
|
||
{
|
||
if (pRoom->m_Logic[0].sNumber != 4)
|
||
continue;
|
||
|
||
minX = pRoom->m_iEndMinX; minZ = pRoom->m_iEndMinZ;
|
||
maxX = pRoom->m_iEndMaxX; maxZ = pRoom->m_iEndMaxZ;
|
||
}
|
||
|
||
CRect r(minX, minZ, maxX, maxZ);
|
||
if (r.PtInRect(nX, nZ))
|
||
{
|
||
if (pRoom->isInitialised())
|
||
{
|
||
pRoom->m_byStatus = RoomStatusInProgress;
|
||
pRoom->m_tDelayTime = UNIXTIME;
|
||
room_number = itr->first;
|
||
TRACE(" Room Check - number = %d, x=%d, z=%d\n", room_number, nX, nZ);
|
||
//wsprintf(notify, "** <20>˸<EFBFBD> : [%d Zone][%d] <20>濡 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ű<EFBFBD><C5B0><EFBFBD> ȯ<><C8AF><EFBFBD>մϴ<D5B4> **", m_nZoneNumber, pRoom->m_sRoomNumber);
|
||
//g_pMain->SendSystemMsg(notify, PUBLIC_CHAT);
|
||
}
|
||
else if(pRoom->isInProgress())// room already in progress
|
||
{
|
||
pRoom->m_byStatus = RoomStatusCleared;
|
||
//wsprintf(notify, "** <20>˸<EFBFBD> : [%d Zone][%d] <20><>ǥ<EFBFBD><C7A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD> <20>˴ϴ٤<CFB4> **", m_nZoneNumber, pRoom->m_sRoomNumber);
|
||
//g_pMain->SendSystemMsg(notify, PUBLIC_CHAT);
|
||
}
|
||
|
||
return room_number;
|
||
}
|
||
}
|
||
|
||
return room_number;
|
||
}
|
||
|
||
CRoomEvent* MAP::SetRoomEvent( int number )
|
||
{
|
||
CRoomEvent* pEvent = m_arRoomEventArray.GetData( number );
|
||
if( pEvent ) {
|
||
TRACE("#### SetRoom Error : double event number = %d ####\n", number);
|
||
return nullptr;
|
||
}
|
||
|
||
pEvent = new CRoomEvent();
|
||
pEvent->m_iZoneNumber = m_nZoneNumber;
|
||
pEvent->m_sRoomNumber = number;
|
||
if( !m_arRoomEventArray.PutData( pEvent->m_sRoomNumber, pEvent) ) {
|
||
delete pEvent;
|
||
pEvent = nullptr;
|
||
return nullptr;
|
||
}
|
||
|
||
return pEvent;
|
||
}
|
||
|
||
bool MAP::IsRoomStatusCheck()
|
||
{
|
||
int nClearRoom = 1,
|
||
nTotalRoom = m_arRoomEventArray.GetSize() + 1;
|
||
|
||
if (m_byRoomStatus == RoomStatusInProgress)
|
||
m_byInitRoomCount++;
|
||
|
||
foreach_stlmap_nolock (itr, m_arRoomEventArray)
|
||
{
|
||
CRoomEvent *pRoom = itr->second;
|
||
if (pRoom == nullptr)
|
||
{
|
||
TRACE("#### IsRoomStatusCheck Error : room empty number = %d ####\n", itr->first);
|
||
continue;
|
||
}
|
||
|
||
if (m_byRoomStatus == RoomStatusInitialised)
|
||
{
|
||
if (pRoom->isCleared())
|
||
nClearRoom += 1;
|
||
|
||
if (m_byRoomType == 0)
|
||
{
|
||
if (nTotalRoom == nClearRoom)
|
||
{
|
||
m_byRoomStatus = RoomStatusInProgress;
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
else if (m_byRoomStatus == RoomStatusInProgress)
|
||
{
|
||
if (m_byInitRoomCount >= 10)
|
||
{
|
||
pRoom->InitializeRoom();
|
||
nClearRoom += 1;
|
||
if (nTotalRoom == nClearRoom)
|
||
{
|
||
m_byRoomStatus = RoomStatusCleared;
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
else if (m_byRoomStatus == RoomStatusCleared)
|
||
{
|
||
m_byRoomStatus = RoomStatusInitialised;
|
||
m_byInitRoomCount = 0;
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
|
||
void MAP::InitializeRoom()
|
||
{
|
||
foreach_stlmap_nolock (itr, m_arRoomEventArray)
|
||
{
|
||
CRoomEvent *pRoom = itr->second;
|
||
if (pRoom == nullptr)
|
||
{
|
||
TRACE("#### InitializeRoom Error : room empty number = %d ####\n", itr->first);
|
||
continue;
|
||
}
|
||
|
||
pRoom->InitializeRoom();
|
||
m_byRoomStatus = RoomStatusInitialised;
|
||
m_byInitRoomCount = 0;
|
||
}
|
||
} |