Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1273
Server/RylServerProject/RylGameLibrary/Map/FieldMap/Cell.cpp
Normal file
1273
Server/RylServerProject/RylGameLibrary/Map/FieldMap/Cell.cpp
Normal file
File diff suppressed because it is too large
Load Diff
329
Server/RylServerProject/RylGameLibrary/Map/FieldMap/Cell.h
Normal file
329
Server/RylServerProject/RylGameLibrary/Map/FieldMap/Cell.h
Normal file
@@ -0,0 +1,329 @@
|
||||
#ifndef _CCELL_H_
|
||||
#define _CCELL_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma warning(disable:4800)
|
||||
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <boost/pool/pool_alloc.hpp>
|
||||
#include <Creature/CreatureStructure.h>
|
||||
|
||||
#include <Network/Packet/PacketStruct/CharMovepacket.h>
|
||||
#include <Network/Packet/PacketStruct/AddressPacket.h>
|
||||
#include <Network/Packet/PacketStruct/CharAttackPacketStruct.h>
|
||||
#include <Network/Packet/PacketStruct/CharItemPacketStruct.h>
|
||||
|
||||
// 전방 참조
|
||||
class CParty;
|
||||
class CCreature;
|
||||
class CAggresiveCreature;
|
||||
class CMonster;
|
||||
class CCharacter;
|
||||
class CSiegeObject;
|
||||
class CBuffer;
|
||||
struct PktBase;
|
||||
struct PktMVEx;
|
||||
|
||||
namespace Item
|
||||
{
|
||||
class CItem;
|
||||
};
|
||||
|
||||
|
||||
class CCell
|
||||
{
|
||||
public:
|
||||
|
||||
enum ErrorCode
|
||||
{
|
||||
S_SUCCESS = 0,
|
||||
S_AUTO_ROUTING = 1,
|
||||
|
||||
E_NOT_ENOUGH_MEMORY = 2,
|
||||
E_NOT_OWNER_OF_ITEM = 3,
|
||||
E_NOT_ITEM = 4,
|
||||
E_CREATE_ITEM_FAIL = 5,
|
||||
E_NOT_EXIST_GUILD = 6,
|
||||
E_GOLD_OVERFLOW = 7
|
||||
};
|
||||
|
||||
enum Const
|
||||
{
|
||||
CONNECT_NUM = 9,
|
||||
|
||||
CHECK_TIME = 100, // 아이템이 사라져야 하는지 체크하는 간격 (10초)
|
||||
ITEM_RIGHT_TIME = 1600, // 플레이어가 드랍한 아이템의 경우 소유권은 10초, 다시 2분 30초 후엔 사라진다.
|
||||
ITEM_LIFE_TIME = 1800, // 맵에 아이템이 남아있는 시간 (3분)
|
||||
NO_OWNER_TIME = 1500, // 아이템에 소유권이 지정되어 있지 않은 시간 (2분 30초)
|
||||
|
||||
BROADCASTING_TIME = 10, // 기존 브로드 캐스팅 타임 (1초)
|
||||
|
||||
MONEY_BIT = 0x80000000,
|
||||
TYPE_CHECK_BIT = 0xF0000000,
|
||||
ITEM_PROTOTYPE_ID_BIT = 0x0000FFFF,
|
||||
MAX_MONEY_AMOUNT = 0x0FFFFFFF
|
||||
};
|
||||
|
||||
enum TurnConst
|
||||
{
|
||||
TURN_OF_CHARACTER = 0,
|
||||
TURN_OF_SIEGE_OBJECT = 1,
|
||||
TURN_OF_MONSTER = 2,
|
||||
|
||||
TURN_END = 3
|
||||
};
|
||||
|
||||
enum Weather
|
||||
{
|
||||
WEATHER_FINE = 0, // 맑음
|
||||
WEATHER_RAIN = 1, // 비
|
||||
WEATHER_SNOW = 2, // 눈
|
||||
|
||||
MAX_WEATHER = 3
|
||||
};
|
||||
|
||||
enum ItemAutoRouting
|
||||
{
|
||||
NONE = 0, // 루팅 하지 않는다.
|
||||
PARTY = 1, // 파티원에게 루팅
|
||||
GUILD = 2, // 길드원에게 루팅
|
||||
};
|
||||
|
||||
enum ConnectCell
|
||||
{
|
||||
NO = 0,
|
||||
UP = 1,
|
||||
DOWN = 2,
|
||||
LEFT = 3,
|
||||
RIGHT = 4,
|
||||
UPPERLEFT = 5,
|
||||
UPPERRIGHT = 6,
|
||||
LOWERLEFT = 7,
|
||||
LOWERRIGHT = 8
|
||||
};
|
||||
|
||||
enum CellSize
|
||||
{
|
||||
CELL_SIZE_DEFAULT = 128,
|
||||
CELL_SIZE_BATTLE_SERVER = 70,
|
||||
CELL_DISTANCE = 32,
|
||||
CELL_RESOLUTION = 5
|
||||
};
|
||||
static unsigned char ms_CellSize;
|
||||
|
||||
struct IDField
|
||||
{
|
||||
enum
|
||||
{
|
||||
MAX_UID = UCHAR_MAX
|
||||
};
|
||||
|
||||
unsigned long dwUID; // 유니크 ID (생성된 순서에 따라 차례대로...)
|
||||
unsigned short wMapIndex; // 가상 맵의 경우 그 인덱스
|
||||
unsigned char cCellX; // 셀 인덱스 X
|
||||
unsigned char cCellZ; // 셀 인덱스 Z
|
||||
};
|
||||
|
||||
struct ItemInfo
|
||||
{
|
||||
Position m_Pos; // 월드맵 상의 위치
|
||||
|
||||
union
|
||||
{
|
||||
unsigned __int64 m_nUniqueID; // 유니크 ID
|
||||
IDField m_Field;
|
||||
|
||||
} UID;
|
||||
|
||||
Item::CItem* m_lpItem; // 아이템
|
||||
unsigned long m_dwGold; // 돈
|
||||
|
||||
unsigned long m_dwOwnerID; // 소유권
|
||||
unsigned short m_wPulse; // 소멸까지 남은 펄스
|
||||
|
||||
unsigned char m_cAutoRouting; // 오토루팅될 아이템인가? (ItemAutoRouting enum 참고)
|
||||
|
||||
ItemInfo();
|
||||
void MakeFieldObject(FieldObject& fieldObject);
|
||||
};
|
||||
|
||||
typedef std::list<CMonster*, boost::fast_pool_allocator<CMonster*> > MonsterList;
|
||||
typedef std::list<CCharacter*, boost::fast_pool_allocator<CCharacter*> > CharacterList;
|
||||
typedef std::list<ItemInfo, boost::fast_pool_allocator<ItemInfo> > ItemList;
|
||||
typedef std::list<CSiegeObject*, boost::fast_pool_allocator<CSiegeObject*> > SiegeObjectList;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 초기화
|
||||
|
||||
CCell();
|
||||
~CCell();
|
||||
|
||||
|
||||
void Initialize(unsigned char cIndexX, unsigned char cIndexZ); // 셀 좌표를 초기화하고, 소트된 링크를 생성한다.
|
||||
void SetMapIndex(unsigned short wMapIndex) { m_wMapIndex = wMapIndex; }
|
||||
unsigned short GetMapIndex() { return m_wMapIndex; }
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// interface
|
||||
|
||||
CCell* GetConnectCell(unsigned int Dir);
|
||||
void SetConnectCell(unsigned int Dir, CCell* lpConnectedCell);
|
||||
bool IsNearCell(CCell* lpNearCell);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 셀 정보
|
||||
|
||||
unsigned char GetIndexX() const { return m_cIndexX; }
|
||||
unsigned char GetIndexZ() const { return m_cIndexZ; }
|
||||
size_t GetMonsterNum() const { return m_lstMonster.size(); }
|
||||
size_t GetCharacterNum() const { return m_lstCharacter.size(); }
|
||||
size_t GetItemNum() const { return m_lstItem.size(); }
|
||||
size_t GetSiegeObjectNum() const { return m_lstSiegeObject.size(); }
|
||||
size_t GetNearCellCharacterNum() const;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 셀에 크리쳐 추가 및 삭제, 얻어 오기.
|
||||
|
||||
void SetCreature(unsigned long dwCID, CCreature* lpCreature, CCell* lpLastLogoutCell = 0);
|
||||
void DeleteCreature(unsigned long dwCID, CCell* lpPrepareLoginCell = 0);
|
||||
CCreature* GetCreature(unsigned long dwCID);
|
||||
|
||||
CAggresiveCreature* GetFirstAggresiveCreature();
|
||||
CAggresiveCreature* GetNextAggresiveCreature();
|
||||
|
||||
void KillAll(CCharacter* lpAttacker);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 몬스터 관련 처리
|
||||
|
||||
bool IsMonster() const { return !(m_lstMonster.empty()); }
|
||||
CMonster* GetFirstMonster();
|
||||
CMonster* GetNextMonster() { return (++m_MonsterIt != m_lstMonster.end()) ? *m_MonsterIt : NULL; }
|
||||
|
||||
void LogoutAllMonster() { m_lstMonster.clear(); }
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 공성 오브젝트 관련 처리
|
||||
|
||||
bool IsSiegeObject() { return !(m_lstSiegeObject.empty()); }
|
||||
CSiegeObject* GetFirstAirShip();
|
||||
CSiegeObject* GetNextAirShip();
|
||||
CSiegeObject* GetFirstSiegeObject();
|
||||
CSiegeObject* GetNextSiegeObject();
|
||||
|
||||
void UpgradeByEmblem(unsigned long dwCID);
|
||||
void DegradeByEmblem();
|
||||
|
||||
bool IsDetectionCell() { return ( 0 != m_dwCastleEmblemCID ); }
|
||||
void DetectionAttack(CSiegeObject* lpEmblem, CAggresiveCreature* lpTargetCreature);
|
||||
bool SendStealthInfo(CCharacter& character, bool bUseStealth);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 캐릭터 관련 처리
|
||||
|
||||
bool IsCharacter() { return !(m_lstCharacter.empty()); }
|
||||
CCharacter* GetFirstCharacter();
|
||||
CCharacter* GetNextCharacter() { return (++m_CharacterIt != m_lstCharacter.end()) ? *m_CharacterIt : NULL; }
|
||||
|
||||
template<typename FnProcess>
|
||||
inline void ProcessAllMonster(FnProcess fnProcess)
|
||||
{
|
||||
std::for_each(m_lstMonster.begin(), m_lstMonster.end(), fnProcess);
|
||||
}
|
||||
|
||||
template<typename FnProcess>
|
||||
inline void ProcessAllCharacter(FnProcess fnProcess)
|
||||
{
|
||||
std::for_each(m_lstCharacter.begin(), m_lstCharacter.end(), fnProcess);
|
||||
}
|
||||
|
||||
void RespawnAllCharacter(unsigned char cExceptNation);
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 아이템 관련 처리
|
||||
|
||||
bool IsItem(void) { return !(m_lstItem.empty()); }
|
||||
|
||||
void SetItem(const Position& Pos, Item::CItem* lpItem, unsigned long dwGold,
|
||||
unsigned long dwOwnerID, unsigned char cAutoRouting, CCell::ItemInfo& cellItemInfo);
|
||||
|
||||
CCell::ErrorCode GetItem(unsigned long dwCreatureID, unsigned __int64 nItemInfoID,
|
||||
Item::CItem** lppItem, unsigned long& dwMoney_Out);
|
||||
|
||||
void CheckDeleteItem(void);
|
||||
void DeleteAllItem(void);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 셀 관련 브로드 캐스팅
|
||||
|
||||
void PrepareBroadCast();
|
||||
void BroadCast(unsigned long dwCurrentPulse);
|
||||
|
||||
// 만든 패킷을, Wrap하지 말고 보낸다(내부에서 Wrap함. srvState나 usError는 넣을수 없다.)
|
||||
// 패킷 순서가 바뀔 수 있으므로 주의한다.
|
||||
|
||||
void SendAllNearCellCharacter(const PktBase* lpPktBase, unsigned short usLength, unsigned char cCMD);
|
||||
void SendAllCharacter(const PktBase* lpPktBase, unsigned short usLength, unsigned char cCMD);
|
||||
|
||||
void SendNowAllNearCellCharacter(const char* szData, unsigned short usLength, unsigned char cCMD);
|
||||
void SendNowAllCharacter(const char* szData, unsigned short usLength, unsigned char cCMD);
|
||||
|
||||
void SendAttackInfo(unsigned long AttackerID_In, const AtType &AtType_In,
|
||||
unsigned char DefenserNum_In, DefenserNode* lpNode_In);
|
||||
|
||||
void SendCastObjectInfo(unsigned long SenderID, unsigned long ReceiverID, CastObject& CastObject_In);
|
||||
|
||||
private:
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 패킷 전송 관련 (내부에서만 호출하는 함수들)
|
||||
|
||||
void SendPullDownInfo(unsigned long dwOwnerID, ItemInfo& itemInfo);
|
||||
void SendPickUpInfo(unsigned long dwCreatureID, unsigned __int64 nItemInfoID);
|
||||
|
||||
void SendCellLogin(CAggresiveCreature* lpAggresiveCreature, CCell* lpLastLogoutCell);
|
||||
void SendCellLogout(CAggresiveCreature* lpAggresiveCreature, CCell* lpPrepareLoginCell);
|
||||
|
||||
// 버퍼를 전부 Release한다.
|
||||
static void ReleaseAllBuffer(CBuffer*& lpBuffer);
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// 데이터
|
||||
|
||||
CCell* m_lpConnectCell[CONNECT_NUM]; // 주변 연결 리스트. 자기 자신도 포함한다.
|
||||
CCell* m_lpSortedConnectedCell[CONNECT_NUM]; // 주변 연결 리스트를 포인터순으로 소팅한 배열.
|
||||
|
||||
CharacterList m_lstCharacter;
|
||||
MonsterList m_lstMonster;
|
||||
ItemList m_lstItem;
|
||||
SiegeObjectList m_lstSiegeObject; // 단지 리스트를 가지고 있을 뿐, 모든 공성 오브젝트는 CSiegeObjectMgr 이 관리한다.
|
||||
|
||||
MonsterList::iterator m_MonsterIt; // 범용적... 한 녀석이 다 쓰기 전에 다른 녀석이 달라고 하면 곤란합니다.
|
||||
CharacterList::iterator m_CharacterIt; // 범용적... 한 녀석이 다 쓰기 전에 다른 녀석이 달라고 하면 곤란합니다.
|
||||
SiegeObjectList::iterator m_SiegeObjectIt; // 범용적... 한 녀석이 다 쓰기 전에 다른 녀석이 달라고 하면 곤란합니다.
|
||||
|
||||
CBuffer* m_lpBroadcast2ndBuffer; // 브로드캐스트 2nd버퍼(새 브로드캐스트 버퍼, 캐릭터 및 아이템용)
|
||||
|
||||
unsigned long m_dwCastleEmblemCID; // 성 상징물의 디텍션 범위에 있는 셀이면 상징물의 CID를 가지고 있다.
|
||||
|
||||
unsigned short m_wMapIndex; // 맵 인덱스
|
||||
unsigned char m_cIndexX; // 맵 X좌표
|
||||
unsigned char m_cIndexZ; // 맵 Z좌표
|
||||
|
||||
unsigned char m_cTurnOfGetAggresiveCreature;
|
||||
|
||||
CCell::Weather m_eWeather; // 현재 날씨
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,568 @@
|
||||
#include "stdafx.h"
|
||||
#include "Cell.h"
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/FieldMap/VirtualArea/VirtualArea.h>
|
||||
#include <Map/FieldMap/VirtualArea/VirtualAreaMgr.h>
|
||||
|
||||
#include <Utility/Compress/MiniLZO/miniLZOWrapper.h>
|
||||
|
||||
#include <Creature/Creature.h>
|
||||
#include <Creature/AggresiveCreature.h>
|
||||
#include <Creature/Character/Character.h>
|
||||
#include <Creature/Monster/Monster.h>
|
||||
#include <Creature/Monster/VirtualMonsterMgr.h>
|
||||
#include <Creature/Siege/SiegeObject.h>
|
||||
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/CharItemPacket.h>
|
||||
#include <Network/Packet/PacketStruct/CharBroadCastPacket.h>
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
|
||||
#include <Network/Packet/PacketStruct/CastlePacket.h>
|
||||
|
||||
__declspec(thread) static char g_BroadcastBuffer[PktMaxLen];
|
||||
|
||||
void CCell::ReleaseAllBuffer(CBuffer*& lpBuffer)
|
||||
{
|
||||
// 일전에 전송했던 buffer를 전부 Release한다.
|
||||
CBuffer* lpPos = lpBuffer;
|
||||
CBuffer* lpDel = lpBuffer;
|
||||
|
||||
while (0 != lpPos)
|
||||
{
|
||||
lpDel = lpPos;
|
||||
lpPos = lpPos->next();
|
||||
|
||||
SAFE_RELEASE_BUFFER(lpDel);
|
||||
}
|
||||
|
||||
lpBuffer = 0;
|
||||
}
|
||||
|
||||
|
||||
void CCell::PrepareBroadCast()
|
||||
{
|
||||
// 일전에 전송했던 buffer를 전부 Release한다.
|
||||
ReleaseAllBuffer(m_lpBroadcast2ndBuffer);
|
||||
|
||||
if (m_lstCharacter.empty() && m_lstMonster.empty())
|
||||
{
|
||||
// 이 셀에는 몬스터도, 캐릭터도 없다. 처리하지 않는다.
|
||||
return;
|
||||
}
|
||||
|
||||
// 캐릭터 데이터를 생성한다.
|
||||
const int MAX_BROADCAST_BUFFER_SIZE = 14 * 1024;
|
||||
CBufferFactory& bufferFactory = CCellManager::GetInstance().GetBufferFactory();
|
||||
|
||||
// 캐릭터 데이터를 생성한다.
|
||||
CharacterList::iterator char_pos = m_lstCharacter.begin();
|
||||
CharacterList::iterator char_end = m_lstCharacter.end();
|
||||
|
||||
CBuffer* lpBroadcastBuffer = CREATE_BUFFER(bufferFactory, MAX_BROADCAST_BUFFER_SIZE);
|
||||
|
||||
for (; char_pos != char_end && 0 != lpBroadcastBuffer; )
|
||||
{
|
||||
CCharacter* lpCharacter = *char_pos;
|
||||
|
||||
//if (0 != lpCharacter && !lpCharacter->IsRideArms() &&
|
||||
|
||||
// 우선 병기에 타고 있어도 보낸다.
|
||||
if (0 != lpCharacter &&
|
||||
lpCharacter->IsOperationFlagSet(CCharacter::CHAR_INFO_LOADED))
|
||||
{
|
||||
Broadcast2nd::CSerializeCharacterData& charData =
|
||||
lpCharacter->GetSerializeData();
|
||||
|
||||
if (lpBroadcastBuffer->push(
|
||||
charData.GetDeltaBroadcastData(),
|
||||
charData.GetDeltaBroadcastDataLen()))
|
||||
{
|
||||
// 데이터 저장 성공
|
||||
++char_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 버퍼가 꽉 찬 경우, 버퍼를 비워 주고, 계속 진행한다.
|
||||
lpBroadcastBuffer->next(m_lpBroadcast2ndBuffer);
|
||||
m_lpBroadcast2ndBuffer = lpBroadcastBuffer;
|
||||
|
||||
lpBroadcastBuffer = CREATE_BUFFER(bufferFactory, MAX_BROADCAST_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 캐릭터가 복사 대상이 아닌 경우이다.
|
||||
++char_pos;
|
||||
}
|
||||
}
|
||||
|
||||
// 몬스터 데이터를 생성한다.
|
||||
MonsterList::iterator mon_pos = m_lstMonster.begin();
|
||||
MonsterList::iterator mon_end = m_lstMonster.end();
|
||||
|
||||
for (; mon_pos != mon_end && 0 != lpBroadcastBuffer; )
|
||||
{
|
||||
CMonster* lpMonster = *mon_pos;
|
||||
|
||||
if (0 != lpMonster)
|
||||
{
|
||||
Broadcast2nd::CSerializeMonsterData& monsterData = lpMonster->GetSerializeData();
|
||||
|
||||
if (lpBroadcastBuffer->push(
|
||||
monsterData.GetDeltaBroadcastData(),
|
||||
monsterData.GetDeltaBroadcastDataLen()))
|
||||
{
|
||||
// 데이터 저장 성공
|
||||
++mon_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 버퍼가 꽉 찬 경우, 버퍼를 비워 주고, 계속 진행한다.
|
||||
lpBroadcastBuffer->next(m_lpBroadcast2ndBuffer);
|
||||
m_lpBroadcast2ndBuffer = lpBroadcastBuffer;
|
||||
|
||||
lpBroadcastBuffer = CREATE_BUFFER(bufferFactory, MAX_BROADCAST_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++mon_pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != lpBroadcastBuffer)
|
||||
{
|
||||
if(0 < lpBroadcastBuffer->length())
|
||||
{
|
||||
lpBroadcastBuffer->next(m_lpBroadcast2ndBuffer);
|
||||
m_lpBroadcast2ndBuffer = lpBroadcastBuffer;
|
||||
|
||||
lpBroadcastBuffer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
SAFE_RELEASE_BUFFER(lpBroadcastBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SendBroadcastPacket(CCell& sendCell,
|
||||
char* szBroadcastBuffer,
|
||||
unsigned short usPacketLength,
|
||||
unsigned char cBroadcastType,
|
||||
unsigned char cDataType,
|
||||
unsigned long dwCurrentPulse)
|
||||
{
|
||||
// 패킷 헤더 작성
|
||||
Broadcast2nd::PktBroadcast* lpBroadcast =
|
||||
reinterpret_cast<Broadcast2nd::PktBroadcast*>(szBroadcastBuffer);
|
||||
|
||||
lpBroadcast->m_dwCurrentPulse = dwCurrentPulse;
|
||||
lpBroadcast->m_cBroadcastType = cBroadcastType;
|
||||
lpBroadcast->m_cDataType = cDataType;
|
||||
|
||||
sendCell.SendAllCharacter(lpBroadcast, usPacketLength, CmdCellBroadCast2nd);
|
||||
}
|
||||
|
||||
|
||||
void CCell::BroadCast(unsigned long dwCurrentPulse)
|
||||
{
|
||||
if (!m_lstCharacter.empty())
|
||||
{
|
||||
// 본 셀에 보낼 캐릭터가 있는 경우에만 전송
|
||||
|
||||
// 현재 셀의 캐릭터에게, 주변 셀의 캐릭터 정보를 전부 보낸다.
|
||||
// 버퍼 데이터를 가능한 많이 모아서 압축한 다음 한번에 많이 보낸다.
|
||||
CCell** lppCellPos = m_lpConnectCell;
|
||||
CCell** lppCellEnd = m_lpConnectCell + CONNECT_NUM;
|
||||
|
||||
char* szBufferPos = g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast);
|
||||
char* szBufferEnd = g_BroadcastBuffer + sizeof(g_BroadcastBuffer);
|
||||
|
||||
CCell* lpCell = 0;
|
||||
CBuffer* lpBuffer = 0;
|
||||
|
||||
unsigned long dwCompressed = PktMaxLen;
|
||||
unsigned short usPacketLength = 0;
|
||||
|
||||
for (; lppCellPos != lppCellEnd; ++lppCellPos)
|
||||
{
|
||||
lpCell = *lppCellPos;
|
||||
|
||||
if (0 != lpCell)
|
||||
{
|
||||
lpBuffer = lpCell->m_lpBroadcast2ndBuffer;
|
||||
|
||||
while(0 != lpBuffer)
|
||||
{
|
||||
size_t nBufferLen = lpBuffer->length();
|
||||
|
||||
if (szBufferPos + nBufferLen < szBufferEnd)
|
||||
{
|
||||
// 버퍼가 아직 비어 있다.
|
||||
memcpy(szBufferPos, lpBuffer->rd_ptr(), nBufferLen);
|
||||
szBufferPos += nBufferLen;
|
||||
|
||||
lpBuffer = lpBuffer->next();
|
||||
}
|
||||
else
|
||||
{
|
||||
SendBroadcastPacket(*this, g_BroadcastBuffer,
|
||||
static_cast<unsigned short>(szBufferPos - g_BroadcastBuffer),
|
||||
Broadcast2nd::PktBroadcast::BROADCAST,
|
||||
Broadcast2nd::PktBroadcast::CHAR_DATA, dwCurrentPulse);
|
||||
|
||||
// 버퍼가 가득 찼다. 일단 전송하고, 버퍼 위치를 처음으로 돌린다.
|
||||
szBufferPos = g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 최종으로 보낸다. (보낼 데이터 길이가 없더라도 보내야 한다)
|
||||
SendBroadcastPacket(*this, g_BroadcastBuffer,
|
||||
static_cast<unsigned short>(szBufferPos - g_BroadcastBuffer),
|
||||
Broadcast2nd::PktBroadcast::BROADCAST_END,
|
||||
Broadcast2nd::PktBroadcast::CHAR_DATA, dwCurrentPulse);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SendCharInfoToOthers(CCharacter& character,
|
||||
CCell** lppSendCell, const int nMaxSendCell)
|
||||
{
|
||||
// 우선 병기에 타고 있어도 보낸다.
|
||||
//if (!character.IsRideArms())
|
||||
{
|
||||
const unsigned short MAX_PKT_DATA = sizeof(Broadcast2nd::PktBroadcast) +
|
||||
Broadcast2nd::CSerializeCharacterData::MAX_CHARACTER_DATA * 2;
|
||||
|
||||
char szPacketBuffer[MAX_PKT_DATA];
|
||||
|
||||
Broadcast2nd::PktBroadcast* lpBroadcast =
|
||||
reinterpret_cast<Broadcast2nd::PktBroadcast*>(szPacketBuffer);
|
||||
|
||||
Broadcast2nd::CSerializeCharacterData& characterData = character.GetSerializeData();
|
||||
unsigned short usCharacterDataLen = characterData.GetBroadcastDataLen();
|
||||
|
||||
// 좌표가 바뀌었기 때문에, 데이터를 갱신해서 보낸다 (Delta는 갱신하지 않는다)
|
||||
characterData.PrepareBroadcastData(character);
|
||||
|
||||
lpBroadcast->m_dwCurrentPulse = 0;
|
||||
lpBroadcast->m_cBroadcastType = Broadcast2nd::PktBroadcast::LOGIN;
|
||||
lpBroadcast->m_cDataType = Broadcast2nd::PktBroadcast::CHAR_DATA;
|
||||
|
||||
memcpy(lpBroadcast + 1, characterData.GetBroadcastData(), usCharacterDataLen);
|
||||
|
||||
CCell** lppSendPos = lppSendCell;
|
||||
CCell** lppSendEnd = lppSendCell + nMaxSendCell;
|
||||
|
||||
for (; lppSendPos != lppSendEnd; ++lppSendPos)
|
||||
{
|
||||
CCell* lpSendPos = *lppSendPos;
|
||||
if (0 != lpSendPos)
|
||||
{
|
||||
lpSendPos->SendAllCharacter(lpBroadcast,
|
||||
sizeof(Broadcast2nd::PktBroadcast) + usCharacterDataLen,
|
||||
CmdCellBroadCast2nd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Interface/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 캐릭터 셀 로그인
|
||||
//
|
||||
// Parameter :
|
||||
// 1st : 크리쳐 주소
|
||||
// 2st : 마지막으로 로그아웃한 셀 (로그인, 리젠, 순간이동등의 경우는 0)
|
||||
//
|
||||
// Do :
|
||||
// 셀안으로 캐릭터가 로그인했음을 주변 셀에 알려 준다.
|
||||
//
|
||||
// Return :
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void CCell::SendCellLogin(CAggresiveCreature* lpAggresiveCreature, CCell* lpLastLogoutCell)
|
||||
{
|
||||
if (0 != lpAggresiveCreature)
|
||||
{
|
||||
unsigned long dwCID = lpAggresiveCreature->GetCID();
|
||||
|
||||
// 현재 셀과, 마지막으로 로그아웃한 셀과의 차집합을 구한다.
|
||||
// lpSendCell에는 내가 내 캐릭터 데이터를 보내고,
|
||||
// 나에게 캐릭터 데이터를 보내야 할 녀석들이 들어 있다.
|
||||
CCell* lpSendCell[CONNECT_NUM];
|
||||
|
||||
CCell** lppSendPos = 0;
|
||||
CCell** lppSendEnd = 0;
|
||||
CCell* lpSendPos = 0;
|
||||
|
||||
if (0 != lpLastLogoutCell)
|
||||
{
|
||||
std::fill_n(lpSendCell, int(CONNECT_NUM), reinterpret_cast<CCell*>(0));
|
||||
|
||||
std::set_difference(
|
||||
m_lpSortedConnectedCell,
|
||||
m_lpSortedConnectedCell + CONNECT_NUM,
|
||||
lpLastLogoutCell->m_lpSortedConnectedCell,
|
||||
lpLastLogoutCell->m_lpSortedConnectedCell + CONNECT_NUM,
|
||||
lpSendCell);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(m_lpSortedConnectedCell, m_lpSortedConnectedCell + CONNECT_NUM, lpSendCell);
|
||||
}
|
||||
|
||||
switch(Creature::GetCreatureType(dwCID))
|
||||
{
|
||||
case Creature::CT_PC:
|
||||
{
|
||||
CCharacter* lpCharacter = static_cast<CCharacter*>(lpAggresiveCreature);
|
||||
|
||||
// 내 정보를 다른 캐릭터들에게 보내는 루틴이다.
|
||||
SendCharInfoToOthers(*lpCharacter, lpSendCell, CONNECT_NUM);
|
||||
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (0 != lpDispatch)
|
||||
{
|
||||
// 주변의 캐릭터/몬스터 정보를 나에게 보낸다.
|
||||
char* szDataPos = g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast);
|
||||
char* szDataEnd = g_BroadcastBuffer + PktMaxLen - 1024;
|
||||
|
||||
// 헤더 기록
|
||||
Broadcast2nd::PktBroadcast* lpBroadcast =
|
||||
reinterpret_cast<Broadcast2nd::PktBroadcast*>(g_BroadcastBuffer);
|
||||
|
||||
lpBroadcast->m_dwCurrentPulse = 0;
|
||||
lpBroadcast->m_cBroadcastType = Broadcast2nd::PktBroadcast::LOGIN;
|
||||
lpBroadcast->m_cDataType = Broadcast2nd::PktBroadcast::CHAR_DATA;
|
||||
|
||||
// 루프를 돈다.
|
||||
lppSendPos = lpSendCell;
|
||||
lppSendEnd = lpSendCell + CONNECT_NUM;
|
||||
|
||||
for (; lppSendPos != lppSendEnd; ++lppSendPos)
|
||||
{
|
||||
lpSendPos = *lppSendPos;
|
||||
if (0 != lpSendPos)
|
||||
{
|
||||
// 데이터를 모아서 보낸다.
|
||||
CCell::CharacterList::iterator char_pos = lpSendPos->m_lstCharacter.begin();
|
||||
CCell::CharacterList::iterator char_end = lpSendPos->m_lstCharacter.end();
|
||||
|
||||
for (; char_pos != char_end; )
|
||||
{
|
||||
CCharacter* lpOtherCharacter = *char_pos;
|
||||
|
||||
Broadcast2nd::CSerializeCharacterData& characterData =
|
||||
lpOtherCharacter->GetSerializeData();
|
||||
|
||||
unsigned short usCharacterDataLen =
|
||||
characterData.GetBroadcastDataLen();
|
||||
|
||||
// 병기에 타고 있어서 보내지 않으면 문제가 생김(By Minbobo)
|
||||
/*if (lpOtherCharacter->IsRideArms())
|
||||
{
|
||||
// 병기에 타고 있으면 보내지 않음.
|
||||
++char_pos;
|
||||
}*/
|
||||
|
||||
if (szDataPos + usCharacterDataLen < szDataEnd)
|
||||
{
|
||||
// 버퍼가 아직 남아 있으면, 버퍼링. 아니면 전송.
|
||||
|
||||
memcpy(szDataPos, characterData.GetBroadcastData(), usCharacterDataLen);
|
||||
szDataPos += usCharacterDataLen;
|
||||
|
||||
++char_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 패킷을 보낸다.
|
||||
lpDispatch->GetSendStream().WrapCompress(g_BroadcastBuffer,
|
||||
static_cast<unsigned short>(szDataPos - g_BroadcastBuffer),
|
||||
CmdCellBroadCast2nd, 0, 0);
|
||||
|
||||
// 버퍼 위치 초기화
|
||||
szDataPos = g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast);
|
||||
}
|
||||
}
|
||||
|
||||
// 데이터를 모아서 보낸다.
|
||||
CCell::MonsterList::iterator mon_pos = lpSendPos->m_lstMonster.begin();
|
||||
CCell::MonsterList::iterator mon_end = lpSendPos->m_lstMonster.end();
|
||||
|
||||
for (; mon_pos != mon_end; )
|
||||
{
|
||||
CMonster* lpMonster = *mon_pos;
|
||||
|
||||
Broadcast2nd::CSerializeMonsterData& monsterData =
|
||||
lpMonster->GetSerializeData();
|
||||
|
||||
unsigned short usMonsterData = monsterData.GetBroadcastDataLen();
|
||||
|
||||
if (szDataPos + usMonsterData < szDataEnd)
|
||||
{
|
||||
// 버퍼가 아직 남아 있으면, 버퍼링. 아니면 전송.
|
||||
memcpy(szDataPos, monsterData.GetBroadcastData(), usMonsterData);
|
||||
szDataPos += usMonsterData;
|
||||
|
||||
++mon_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 패킷을 보낸다.
|
||||
lpDispatch->GetSendStream().WrapCompress(g_BroadcastBuffer,
|
||||
static_cast<unsigned short>(szDataPos - g_BroadcastBuffer),
|
||||
CmdCellBroadCast2nd, 0, 0);
|
||||
|
||||
// 버퍼 위치 초기화
|
||||
szDataPos = g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 데이터가 있으면
|
||||
if (g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast) < szDataPos)
|
||||
{
|
||||
// 패킷을 보낸다.
|
||||
lpDispatch->GetSendStream().WrapCompress(g_BroadcastBuffer,
|
||||
static_cast<unsigned short>(szDataPos - g_BroadcastBuffer),
|
||||
CmdCellBroadCast2nd, 0, 0);
|
||||
}
|
||||
|
||||
// 주변 셀의 아이템 데이터를 모아서 내 캐릭터에 보낸다.
|
||||
// 이때, 버퍼 길이를 초과하지 않도록 한다. 셀당 최대치는 14k정도로 한다.
|
||||
szDataPos = g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast);
|
||||
lpBroadcast->m_dwCurrentPulse = 0;
|
||||
lpBroadcast->m_cBroadcastType = Broadcast2nd::PktBroadcast::LOGIN;
|
||||
lpBroadcast->m_cDataType = Broadcast2nd::PktBroadcast::ITEM_DATA;
|
||||
|
||||
// 루프를 돈다.
|
||||
lppSendPos = lpSendCell;
|
||||
lppSendEnd = lpSendCell + CONNECT_NUM;
|
||||
|
||||
for (; lppSendPos != lppSendEnd; ++lppSendPos)
|
||||
{
|
||||
lpSendPos = *lppSendPos;
|
||||
if (0 != lpSendPos)
|
||||
{
|
||||
// 데이터를 모아서 보낸다.
|
||||
CCell::ItemList::iterator item_pos = lpSendPos->m_lstItem.begin();
|
||||
CCell::ItemList::iterator item_end = lpSendPos->m_lstItem.end();
|
||||
|
||||
for (; item_pos != item_end; )
|
||||
{
|
||||
ItemInfo& itemInfo = (*item_pos);
|
||||
|
||||
// 버퍼가 아직 남아 있으면 버퍼링, 아니면 전송
|
||||
if (szDataPos + sizeof(FieldObject) < szDataEnd)
|
||||
{
|
||||
itemInfo.MakeFieldObject(*reinterpret_cast<FieldObject*>(szDataPos));
|
||||
|
||||
szDataPos += sizeof(FieldObject);
|
||||
++item_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 패킷을 보낸다.
|
||||
lpDispatch->GetSendStream().WrapCompress(g_BroadcastBuffer,
|
||||
static_cast<unsigned short>(szDataPos - g_BroadcastBuffer),
|
||||
CmdCellBroadCast2nd, 0, 0);
|
||||
|
||||
// 버퍼 위치 초기화
|
||||
szDataPos = g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 데이터가 있으면
|
||||
if (szDataPos != g_BroadcastBuffer + sizeof(Broadcast2nd::PktBroadcast))
|
||||
{
|
||||
// 패킷을 보낸다.
|
||||
lpDispatch->GetSendStream().WrapCompress(g_BroadcastBuffer,
|
||||
static_cast<unsigned short>(szDataPos - g_BroadcastBuffer),
|
||||
CmdCellBroadCast2nd, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Creature::CT_MONSTER:
|
||||
case Creature::CT_SUMMON:
|
||||
case Creature::CT_STRUCT:
|
||||
{
|
||||
CMonster* lpMonster = static_cast<CMonster*>(lpAggresiveCreature);
|
||||
|
||||
// 자신의 정보를 주변 캐릭터들에게 뿌린다.
|
||||
const unsigned short MAX_PKT_DATA = sizeof(Broadcast2nd::PktBroadcast) +
|
||||
Broadcast2nd::CSerializeMonsterData::MAX_MONSTER_DATA * 2;
|
||||
|
||||
char szPacketBuffer[MAX_PKT_DATA];
|
||||
|
||||
Broadcast2nd::PktBroadcast* lpBroadcast =
|
||||
reinterpret_cast<Broadcast2nd::PktBroadcast*>(szPacketBuffer);
|
||||
|
||||
Broadcast2nd::CSerializeMonsterData& monsterData = lpMonster->GetSerializeData();
|
||||
unsigned short usMonsterDataLen = monsterData.GetBroadcastDataLen();
|
||||
|
||||
// 좌표가 바뀌었기 때문에, 데이터를 갱신해서 보낸다 (Delta는 갱신하지 않는다)
|
||||
monsterData.PrepareBroadcastData(*lpMonster);
|
||||
|
||||
lpBroadcast->m_dwCurrentPulse = 0;
|
||||
lpBroadcast->m_cBroadcastType = Broadcast2nd::PktBroadcast::LOGIN;
|
||||
lpBroadcast->m_cDataType = Broadcast2nd::PktBroadcast::CHAR_DATA;
|
||||
|
||||
memcpy(lpBroadcast + 1, monsterData.GetBroadcastData(), usMonsterDataLen);
|
||||
|
||||
lppSendPos = lpSendCell;
|
||||
lppSendEnd = lpSendCell + CONNECT_NUM;
|
||||
|
||||
for (; lppSendPos != lppSendEnd; ++lppSendPos)
|
||||
{
|
||||
CCell* lpSendPos = *lppSendPos;
|
||||
if (0 != lpSendPos)
|
||||
{
|
||||
lpSendPos->SendAllCharacter(lpBroadcast,
|
||||
sizeof(Broadcast2nd::PktBroadcast) + usMonsterDataLen,
|
||||
CmdCellBroadCast2nd);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Interface/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 캐릭터 셀 로그 아웃
|
||||
//
|
||||
// Parameter :
|
||||
// 1st : 크리쳐 주소
|
||||
// 2st : 로그아웃한 후 로그인하려는 셀 (로그아웃 등으로 없을 경우에는 0을 넣는다.)
|
||||
//
|
||||
// Do :
|
||||
// 주변 셀에 내가 로그아웃한다고 알린다.
|
||||
// 보이지 않아야 될 캐릭터들을 전부 지우게 한다.
|
||||
//
|
||||
// Return :
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void CCell::SendCellLogout(CAggresiveCreature* lpAggresiveCreature, CCell* lpPrepareLoginCell)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
1303
Server/RylServerProject/RylGameLibrary/Map/FieldMap/CellManager.cpp
Normal file
1303
Server/RylServerProject/RylGameLibrary/Map/FieldMap/CellManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,176 @@
|
||||
#ifndef _CELL_MANAGER_H_
|
||||
#define _CELL_MANAGER_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <Creature/CreatureStructure.h>
|
||||
#include <Stream/Buffer/BufferFactory.h>
|
||||
|
||||
class CCell;
|
||||
namespace VirtualArea
|
||||
{
|
||||
class CBGServerMgr;
|
||||
}
|
||||
|
||||
|
||||
class CBuffer;
|
||||
class CCharacter;
|
||||
|
||||
class CCellManager
|
||||
{
|
||||
public:
|
||||
|
||||
static CCellManager& GetInstance();
|
||||
|
||||
void Destroy();
|
||||
|
||||
bool CheckPositionInZone(Position Pos);
|
||||
|
||||
void Load(void);
|
||||
bool LoadComplete(void) { return m_bLoadComplete; }
|
||||
|
||||
bool SummonMonster(int nKID, Position Pos, CCharacter* lpMaster);
|
||||
bool AdminSummonMonster(int nKID, Position Pos);
|
||||
|
||||
// Normal 상태에서 wMoving의 확률로 Moving. (디폴트는 20%)
|
||||
// 이동을 20프로에서 80프로로 변경 2008.07.10
|
||||
void SetMoving(bool bMoving, unsigned short wMoving = 20) { m_bMoving = bMoving; m_wNumMoving = wMoving; }
|
||||
void SetAvoid(bool bAvoid) { m_bAvoid = bAvoid; }
|
||||
|
||||
bool IsMoving(void) const { return m_bMoving; }
|
||||
bool IsAvoid(void) const { return m_bAvoid; }
|
||||
unsigned short GetMovingNum(void) const { return m_wNumMoving; }
|
||||
|
||||
// 아이템 아이디로 셀 포인터 얻기
|
||||
CCell* GetCell(unsigned __int64 nItemID);
|
||||
|
||||
// 셀 번호로 셀 포인터 얻기
|
||||
CCell* GetCell(unsigned short wMapIndex, unsigned char cCellX, unsigned char cCellZ);
|
||||
|
||||
// 월드 좌표로 셀 포인터 얻기
|
||||
CCell* GetCell(unsigned short wMapIndex, unsigned long dwPosX, unsigned long dwPosY, unsigned long dwPosZ);
|
||||
CCell* GetCell(unsigned short wMapIndex, POS& Pos);
|
||||
|
||||
void LowerResolution(int nHighX, int nHighZ, int *nLowX, int *nLowZ);
|
||||
void HigherResolution(int nLowX, int nLowZ, int *nHighX, int *nHighZ);
|
||||
|
||||
bool IsCampCreateArea(Position Pos);
|
||||
bool IsSafetyZone(Position Pos);
|
||||
|
||||
CBufferFactory& GetBufferFactory() { return m_BufferFactory; }
|
||||
|
||||
template<typename FnRefCell>
|
||||
inline bool ProcessAllCell(FnRefCell fnRefCell)
|
||||
{
|
||||
if (0 != m_CellData)
|
||||
{
|
||||
CCell* lpCellPos = m_CellData;
|
||||
CCell* lpCellEnd = m_CellData + CCell::ms_CellSize * CCell::ms_CellSize;
|
||||
|
||||
for (; lpCellPos != lpCellEnd; ++lpCellPos)
|
||||
{
|
||||
fnRefCell(*lpCellPos);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename FnRefCell, typename Arg1>
|
||||
inline bool ProcessAllCell(FnRefCell fnRefCell, Arg1 arg1)
|
||||
{
|
||||
if (0 != m_CellData)
|
||||
{
|
||||
CCell* lpCellPos = m_CellData;
|
||||
CCell* lpCellEnd = m_CellData + CCell::ms_CellSize * CCell::ms_CellSize;
|
||||
|
||||
for (; lpCellPos != lpCellEnd; ++lpCellPos)
|
||||
{
|
||||
fnRefCell(*lpCellPos, arg1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// 셀 통계 내는 함수들
|
||||
|
||||
bool CheckCellAggresiveCreatures(void); // 셀 내에 겹치는 CID가 있는지 검사
|
||||
bool CheckCellStatus(void); // 셀 내에 사용자 분포 출력
|
||||
|
||||
|
||||
private:
|
||||
|
||||
enum
|
||||
{
|
||||
BGM_TEXTURE_SIZE = 128,
|
||||
SECTOR_SIZE = 31508
|
||||
};
|
||||
|
||||
// 클라이언트에서 사용중인 BGM트리거를 수정하였습니다. (같은 리소스 사용을 위해...)
|
||||
struct SafetyZoneInfo
|
||||
{
|
||||
enum EventKey
|
||||
{
|
||||
EK_BGM_ONCE_SAFE = 0,
|
||||
EK_BGM_LOOP_SAFE = 1,
|
||||
EK_BGM_LOOP_UNSAFE = 2,
|
||||
EK_BGM_ONCE_UNSAFE = 3,
|
||||
EK_NOTBGM_SAFE = 4,
|
||||
EK_BGM_TURN_AMB_SAFE = 5,
|
||||
EK_BGM_TURN_AMB_UNSAFE = 6,
|
||||
EK_CAMP_UNCREATE = 9,
|
||||
EK_ESF_SAFE = 10,
|
||||
EK_ESF_UNSAFE = 11
|
||||
};
|
||||
|
||||
unsigned long m_dwSectorX;
|
||||
unsigned long m_dwSectorY;
|
||||
|
||||
char m_szFilename[MAX_PATH];
|
||||
|
||||
unsigned long m_dwEventNum;
|
||||
|
||||
std::vector<unsigned long> m_vecEventKey;
|
||||
std::vector<unsigned long> m_vecBGMColorKey;
|
||||
|
||||
unsigned long m_aryColorTable[BGM_TEXTURE_SIZE][BGM_TEXTURE_SIZE];
|
||||
};
|
||||
|
||||
CCellManager();
|
||||
~CCellManager();
|
||||
|
||||
bool InitAI(void);
|
||||
bool CreateCell(void);
|
||||
bool SetWeather(const char* szFileName);
|
||||
bool LoginMonster(const char* szFileName, unsigned short wMapIndex = 0);
|
||||
bool LoadSafetyZone(const char* szFileName);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CCell* m_CellData;
|
||||
unsigned char* m_WeatherRate;
|
||||
|
||||
unsigned short m_wNumMoving;
|
||||
unsigned short m_usSummonCount;
|
||||
|
||||
CPoolBufferFactory m_BufferFactory;
|
||||
|
||||
std::vector<SafetyZoneInfo *> m_vecSafetyZone;
|
||||
|
||||
bool m_bMoving;
|
||||
bool m_bAvoid;
|
||||
bool m_bLoadComplete;
|
||||
bool m_bPadding[1];
|
||||
|
||||
friend class VirtualArea::CBGServerMgr; // LoginMonster() 호출을 위해...
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,764 @@
|
||||
#include "stdafx.h"
|
||||
#include "MineralVeinMgr.h"
|
||||
|
||||
#include <Utility/DelimitedFile.h>
|
||||
#include <Utility/Math/Math.h>
|
||||
#include <Utility/Compress/MiniLZO/MiniLZOWrapper.h>
|
||||
#include <Utility/Resource/EnsureCleanup.h>
|
||||
|
||||
#include <Network/Packet/PacketStruct/CastlePacket.h>
|
||||
|
||||
|
||||
#define ENCODEHEADER(Start_In, Length_In, PageNum_In, PageVer_In) CXORCrypt::GetInstance().EncodeHeader((Start_In), (Length_In), (PageNum_In), (PageVer_In))
|
||||
#define DECODEHEADER(Start_In, Length_In, PageNum_In, PageVer_In) CXORCrypt::GetInstance().DecodeHeader((Start_In), (Length_In), (PageNum_In), (PageVer_In))
|
||||
#define COMPRESS(In, In_len, Out, Out_len) CMiniLZO::Compress((In), (In_len), (Out), (Out_len))
|
||||
#define DECOMPRESS(In, In_len, Out, Out_len) CMiniLZO::Decompress((In), (In_len), (Out), (Out_len))
|
||||
|
||||
#include <Network/XORCrypt/XORCrypt.h>
|
||||
|
||||
// 클라이언트에서도 쓰이므로 include를 명시한다.
|
||||
#include <Log/ServerLog.h>
|
||||
#include "GMMemory.h"
|
||||
|
||||
CMineralVeinMgr& CMineralVeinMgr::GetInstance()
|
||||
{
|
||||
static CMineralVeinMgr ms_this;
|
||||
return ms_this;
|
||||
}
|
||||
|
||||
|
||||
CMineralVeinMgr::CMineralVeinMgr()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
CMineralVeinMgr::~CMineralVeinMgr()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool CMineralVeinMgr::Initialize()
|
||||
{
|
||||
std::fill_n( m_dwColorTable[0], int(COLOR_IMAGE_SIZE * COLOR_IMAGE_SIZE), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CMineralVeinMgr::Destroy()
|
||||
{
|
||||
MineralVeinMap::iterator itr = m_mapMineralVein.begin();
|
||||
MineralVeinMap::iterator end = m_mapMineralVein.end();
|
||||
|
||||
while ( itr != end )
|
||||
{
|
||||
if ( itr->second )
|
||||
{
|
||||
delete itr->second;
|
||||
itr->second = NULL;
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
m_mapMineralVein.clear();
|
||||
}
|
||||
|
||||
|
||||
bool CMineralVeinMgr::LoadMineralVeinsFromFiles(const char* szTextFile, const char* szImageFile)
|
||||
{
|
||||
Destroy() ;
|
||||
|
||||
// 텍스트 파일 체크
|
||||
if ( !szTextFile )
|
||||
{
|
||||
ERRLOG0(g_Log, "광물 배치 스크립트 읽기 실패 : txt 파일이 존재하지 않습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 이미지 파일명 체크
|
||||
char szTempImageFile[ MAX_PATH ];
|
||||
if ( !szImageFile )
|
||||
{
|
||||
strcpy(szTempImageFile, szTextFile);
|
||||
if ( strtok(szTempImageFile, ".") )
|
||||
{
|
||||
strcat(szTempImageFile, ".tga");
|
||||
|
||||
FILE* fp = fopen(szTempImageFile, "rb");
|
||||
if ( !fp )
|
||||
{
|
||||
ERRLOG1(g_Log, "광물 배치 스크립트 읽기 실패 : 이미지 파일 %s 가 존재하지 않습니다.", szTempImageFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG1(g_Log, "광물 배치 스크립트 읽기 실패 : 파일명이 이상합니다. - %s", szTextFile);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(szTempImageFile, szImageFile);
|
||||
}
|
||||
|
||||
char szTempBuf[ MAX_PATH ];
|
||||
unsigned long dwTempValue;
|
||||
int iLineCount = 0;
|
||||
CDelimitedFile DelimitedFile; // 객체 소멸시, 자동 Close.
|
||||
|
||||
// 매크로에 로그 코드 삽입을 잊지 말 것.
|
||||
// 매크로에서 \뒤에 공백이나 문자 삽입되지 않도록 주의할 것.
|
||||
// ( '이스케이프 시퀀스가 잘못되었습니다' 에러 발생 )
|
||||
#define READ_DATA(ColumnName, Argument) \
|
||||
if (!DelimitedFile.ReadData(Argument)) { \
|
||||
ERRLOG2(g_Log, "몬스터 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", iLineCount, #ColumnName); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define READ_STRING(ColumnName, Buffer, BufferSize) \
|
||||
if (!DelimitedFile.ReadString(Buffer, BufferSize)) { \
|
||||
ERRLOG2(g_Log, "몬스터 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", iLineCount, #ColumnName); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
// 텍스트 파일 로드
|
||||
if (!DelimitedFile.Open(szTextFile))
|
||||
{
|
||||
ERRLOG1(g_Log, "광물 배치 스크립트 읽기 실패 : %s 파일이 존재하지 않습니다.", szTextFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
MineralVeinInfo* pCurrentVeinInfo = NULL;
|
||||
|
||||
while ( DelimitedFile.ReadLine2nd() )
|
||||
{
|
||||
++iLineCount;
|
||||
|
||||
READ_STRING("TYPE", szTempBuf, MAX_TYPE_STRING_LEN);
|
||||
|
||||
if(stricmp(szTempBuf, "\r\n") == 0)
|
||||
continue;
|
||||
|
||||
if (!stricmp(szTempBuf, "VEIN_COLOR"))
|
||||
{
|
||||
READ_STRING("VEIN_COLOR_VALUE", szTempBuf, MAX_HEXA_COLOR_LEN);
|
||||
dwTempValue = Math::Convert::Atoi(szTempBuf);
|
||||
|
||||
MineralVeinMap::iterator itr = m_mapMineralVein.find(dwTempValue);
|
||||
if (itr != m_mapMineralVein.end())
|
||||
{
|
||||
ERRLOG1(g_Log, "VeinColor : 0x%08x 중복되는 광맥 ID 가 존재합니다.", dwTempValue);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
MineralVeinInfo* pVeinInfo = new MineralVeinInfo;
|
||||
pVeinInfo->m_dwVeinColor = dwTempValue;
|
||||
m_mapMineralVein.insert(std::make_pair(dwTempValue, pVeinInfo)).second ;
|
||||
|
||||
pCurrentVeinInfo = pVeinInfo;
|
||||
}
|
||||
}
|
||||
else if (!stricmp(szTempBuf, "VEIN_NAME"))
|
||||
{
|
||||
if ( pCurrentVeinInfo )
|
||||
{
|
||||
READ_STRING("VEIN_NAME_VALUE", szTempBuf, MineralVeinInfo::MAX_VEIN_NAME_LEN);
|
||||
strncpy(pCurrentVeinInfo->m_szVeinName, szTempBuf, strlen(szTempBuf)-1);
|
||||
pCurrentVeinInfo->m_szVeinName[MineralVeinInfo::MAX_VEIN_NAME_LEN - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else if (!stricmp(szTempBuf, "FERTILITY"))
|
||||
{
|
||||
if ( pCurrentVeinInfo )
|
||||
{
|
||||
READ_DATA("FERTILITY_VALUE", pCurrentVeinInfo->m_dwMaxFertility);
|
||||
}
|
||||
}
|
||||
else if (!stricmp(szTempBuf, "MINERAL"))
|
||||
{
|
||||
if ( pCurrentVeinInfo )
|
||||
{
|
||||
MineralInfo mineralInfo;
|
||||
|
||||
READ_DATA("MINERAL_ID", mineralInfo.m_dwMineralID);
|
||||
READ_DATA("MIN_VALUE", mineralInfo.m_cMin);
|
||||
READ_DATA("MAX_VALUE", mineralInfo.m_cMax);
|
||||
|
||||
pCurrentVeinInfo->m_lstMineralInfo.push_back(mineralInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG1(g_Log, "광물 배치 스크립트 로드 실패 : 존재하지 않는 타입이 있습니다. Type - %s", szTempBuf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 이미지 파일 로드
|
||||
FILE* pTgaFile = fopen(szTempImageFile, "rb");
|
||||
if ( !pTgaFile )
|
||||
{
|
||||
ERRLOG1(g_Log, "광물 배치 스크립트 읽기 실패 : 이미지 파일 %s 가 존재하지 않습니다.", szTempImageFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
sTargaHeader tgaHeader;
|
||||
bool bFlipVertical;
|
||||
int iWidth, iHeight, iScanLineSize;
|
||||
|
||||
if (!fread(&tgaHeader, sizeof(sTargaHeader), 1, pTgaFile))
|
||||
{
|
||||
ERRLOG1(g_Log, "광물 배치 스크립트 읽기 실패 : TGA 파일(%s) 헤더 읽기 실패", szTempImageFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
bFlipVertical = ((tgaHeader.ImageDescriptor & 0x20) != 0 );
|
||||
tgaHeader.ImageDescriptor = tgaHeader.ImageDescriptor & 0xF;
|
||||
iWidth = tgaHeader.Width;
|
||||
iHeight = tgaHeader.Height;
|
||||
iScanLineSize = iWidth * (tgaHeader.PixelSize / 8);
|
||||
|
||||
if ( bFlipVertical )
|
||||
{
|
||||
for (int i=0; i<iHeight; ++i)
|
||||
{
|
||||
fread(m_dwColorTable[i], iScanLineSize, 1, pTgaFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=iHeight-1; i>=0; --i)
|
||||
{
|
||||
fread(m_dwColorTable[i], iScanLineSize, 1, pTgaFile);
|
||||
}
|
||||
}
|
||||
|
||||
fclose( pTgaFile );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMineralVeinMgr::SaveMineralVeinsToText(const char* szScriptFile)
|
||||
{
|
||||
if ( m_mapMineralVein.empty() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t tempSize = 0;
|
||||
unsigned long dwVeinCount = static_cast<unsigned long>(m_mapMineralVein.size());
|
||||
MineralVeinMap::iterator itr = m_mapMineralVein.begin();
|
||||
MineralVeinMap::iterator end = m_mapMineralVein.end();
|
||||
|
||||
FILE* fp = fopen(szScriptFile, "wt");
|
||||
|
||||
while (itr != end)
|
||||
{
|
||||
MineralVeinInfo* pVeinInfo = itr->second;
|
||||
if ( pVeinInfo )
|
||||
{
|
||||
fprintf(fp, "VEIN_COLOR 0x%08x \n", pVeinInfo->m_dwVeinColor);
|
||||
fprintf(fp, "VEIN_NAME %s \n", pVeinInfo->m_szVeinName);
|
||||
fprintf(fp, "FERTILITY %d \n", pVeinInfo->m_dwMaxFertility);
|
||||
|
||||
// 광물 정보 저장
|
||||
MineralInfoList::iterator listItr = pVeinInfo->m_lstMineralInfo.begin();
|
||||
MineralInfoList::iterator listEnd = pVeinInfo->m_lstMineralInfo.end();
|
||||
|
||||
while ( listItr != listEnd )
|
||||
{
|
||||
const MineralInfo& mineralInfo = (*listItr);
|
||||
|
||||
fprintf(fp, "MINERAL %d %d %d \n", mineralInfo.m_dwMineralID, mineralInfo.m_cMin, mineralInfo.m_cMax);
|
||||
|
||||
++listItr;
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// 이미지 파일명 체크
|
||||
char szTempImageFile[ MAX_PATH ];
|
||||
strcpy(szTempImageFile, szScriptFile);
|
||||
if ( strtok(szTempImageFile, ".") )
|
||||
{
|
||||
strcat(szTempImageFile, ".tga");
|
||||
}
|
||||
|
||||
sTargaHeader tgaHeader;
|
||||
|
||||
ZeroMemory(&tgaHeader, sizeof(sTargaHeader));
|
||||
|
||||
tgaHeader.ImageType = 2;
|
||||
tgaHeader.Width = COLOR_IMAGE_SIZE;
|
||||
tgaHeader.Height = COLOR_IMAGE_SIZE;
|
||||
tgaHeader.PixelSize = 32;
|
||||
tgaHeader.ImageDescriptor = 1;
|
||||
|
||||
bool bFlipVertical;
|
||||
int iWidth, iHeight, iScanLineSize;
|
||||
|
||||
bFlipVertical = ((tgaHeader.ImageDescriptor & 0x20) != 0 );
|
||||
tgaHeader.ImageDescriptor = tgaHeader.ImageDescriptor & 0xF;
|
||||
iWidth = tgaHeader.Width;
|
||||
iHeight = tgaHeader.Height;
|
||||
iScanLineSize = iWidth * (tgaHeader.PixelSize / 8);
|
||||
|
||||
fp = fopen(szTempImageFile, "wb");
|
||||
|
||||
fwrite(&tgaHeader, sizeof(sTargaHeader), 1, fp);
|
||||
|
||||
if ( bFlipVertical )
|
||||
{
|
||||
for (int i=0; i<iHeight; ++i)
|
||||
{
|
||||
fwrite(m_dwColorTable[i], iScanLineSize, 1, fp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=iHeight-1; i>=0; --i)
|
||||
{
|
||||
fwrite(m_dwColorTable[i], iScanLineSize, 1, fp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMineralVeinMgr::SaveMineralVeinsToBinary(const char* szBinaryFile, const char* szTrashFile)
|
||||
{
|
||||
if ( m_mapMineralVein.empty() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE hFile = CreateFile(szBinaryFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) { return false; }
|
||||
|
||||
CEnsureCloseHandle writeFile(hFile);
|
||||
|
||||
size_t tempSize = 0;
|
||||
unsigned long dwVeinCount = static_cast<unsigned long>(m_mapMineralVein.size());
|
||||
MineralVeinMap::iterator itr = m_mapMineralVein.begin();
|
||||
MineralVeinMap::iterator end = m_mapMineralVein.end();
|
||||
|
||||
while (itr != end)
|
||||
{
|
||||
MineralVeinInfo* pVeinInfo = itr->second;
|
||||
if ( pVeinInfo )
|
||||
{
|
||||
tempSize += pVeinInfo->m_lstMineralInfo.size() * sizeof(MineralInfo) + sizeof(unsigned long);
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
tempSize += m_mapMineralVein.size() * sizeof(MineralVeinInfo) + sizeof(unsigned long);
|
||||
tempSize += COLOR_IMAGE_SIZE * COLOR_IMAGE_SIZE * sizeof(unsigned long);
|
||||
const size_t MAX_SCRIPT_FILE_SIZE = tempSize;
|
||||
|
||||
char *pInputBuffer = new char[MAX_SCRIPT_FILE_SIZE];
|
||||
char *pOutputBuffer = new char[MAX_SCRIPT_FILE_SIZE];
|
||||
|
||||
CEnsureDeleteArray<char> input(pInputBuffer);
|
||||
CEnsureDeleteArray<char> output(pOutputBuffer);
|
||||
|
||||
if (0 == pInputBuffer || 0 == pOutputBuffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char *InputStartPointer = pInputBuffer;
|
||||
char *OutputStartPointer = pOutputBuffer;
|
||||
|
||||
unsigned long dwInputBufferSize = 0;
|
||||
unsigned long dwOutputBufferSize = 0;
|
||||
|
||||
// MineralVeinInfo 갯수 저장
|
||||
memcpy(pInputBuffer, &dwVeinCount, sizeof(unsigned long));
|
||||
dwInputBufferSize += sizeof(unsigned long);
|
||||
pInputBuffer += sizeof(unsigned long);
|
||||
|
||||
// Image 저장
|
||||
for (int i=0; i<COLOR_IMAGE_SIZE; ++i)
|
||||
{
|
||||
memcpy(pInputBuffer, m_dwColorTable[i], sizeof(unsigned long) * COLOR_IMAGE_SIZE);
|
||||
dwInputBufferSize += sizeof(unsigned long) * COLOR_IMAGE_SIZE;
|
||||
pInputBuffer += sizeof(unsigned long) * COLOR_IMAGE_SIZE;
|
||||
}
|
||||
|
||||
unsigned long dwMineralCount;
|
||||
itr = m_mapMineralVein.begin();
|
||||
end = m_mapMineralVein.end();
|
||||
|
||||
while ( itr != end )
|
||||
{
|
||||
MineralVeinInfo* pVeinInfo = itr->second;
|
||||
if ( pVeinInfo )
|
||||
{
|
||||
// 광물수 저장
|
||||
dwMineralCount = static_cast<unsigned long>( pVeinInfo->m_lstMineralInfo.size() );
|
||||
memcpy(pInputBuffer, &dwMineralCount, sizeof(unsigned long));
|
||||
dwInputBufferSize += sizeof(unsigned long);
|
||||
pInputBuffer += sizeof(unsigned long);
|
||||
|
||||
// Vein 정보 저장
|
||||
memcpy(pInputBuffer, pVeinInfo, 56); //sizeof(MineralVeinInfo));
|
||||
dwInputBufferSize += 56; //sizeof(MineralVeinInfo);
|
||||
pInputBuffer += 56; //sizeof(MineralVeinInfo);
|
||||
|
||||
// 광물 정보 저장
|
||||
MineralInfoList::iterator listItr = pVeinInfo->m_lstMineralInfo.begin();
|
||||
MineralInfoList::iterator listEnd = pVeinInfo->m_lstMineralInfo.end();
|
||||
|
||||
while ( listItr != listEnd )
|
||||
{
|
||||
const MineralInfo& mineralInfo = (*listItr);
|
||||
memcpy(pInputBuffer, &mineralInfo, sizeof(MineralInfo));
|
||||
dwInputBufferSize += sizeof(MineralInfo);
|
||||
pInputBuffer += sizeof(MineralInfo);
|
||||
|
||||
++listItr;
|
||||
}
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
ENCODEHEADER(InputStartPointer, dwInputBufferSize, 0, 3);
|
||||
COMPRESS(InputStartPointer, dwInputBufferSize, pOutputBuffer, &dwOutputBufferSize);
|
||||
|
||||
// 파일에 쓰기
|
||||
unsigned long dwWritten = 0;
|
||||
|
||||
// 쓰레기(더미) 자료
|
||||
HANDLE hTrashFile = CreateFile(szTrashFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hTrashFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ERRLOG1(g_Log, "%s 파일을 열 수 없습니다.", szTrashFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
CEnsureCloseHandle trashFile(hTrashFile);
|
||||
|
||||
unsigned long dwRead = 0;
|
||||
unsigned long dwFileHighSize = 0;
|
||||
unsigned long dwFileSize = GetFileSize(hTrashFile, &dwFileHighSize);
|
||||
|
||||
char* lpAllocated = new char[dwFileSize];
|
||||
if (NULL == lpAllocated)
|
||||
{
|
||||
ERRLOG0(g_Log, "메모리 할당에 실패하였습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CEnsureDeleteArray<char> allocated(lpAllocated);
|
||||
|
||||
if (false == ReadFile(hTrashFile, lpAllocated, dwFileSize, &dwRead, NULL))
|
||||
{
|
||||
ERRLOG0(g_Log, "쓰레기 파일을 읽을 수 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteFile(hFile, &dwFileSize, sizeof(unsigned long), &dwWritten, 0);
|
||||
WriteFile(hFile, lpAllocated, dwFileSize, &dwWritten, 0);
|
||||
|
||||
// 올바른 자료
|
||||
WriteFile(hFile, &dwInputBufferSize, sizeof(unsigned long), &dwWritten, 0);
|
||||
WriteFile(hFile, pOutputBuffer, dwOutputBufferSize, &dwWritten, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMineralVeinMgr::LoadMineralVeinsFromBinary(const char* szBinaryFile)
|
||||
{
|
||||
Destroy() ;
|
||||
|
||||
HANDLE hFile = CreateFile(szBinaryFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) { return false; }
|
||||
|
||||
CEnsureCloseHandle readFile(hFile);
|
||||
|
||||
unsigned long dwRead = 0;
|
||||
unsigned long dwFileHighSize = 0;
|
||||
unsigned long dwFileSize = GetFileSize(hFile, &dwFileHighSize);
|
||||
|
||||
char* lpAllocated = new char[dwFileSize];
|
||||
if (NULL == lpAllocated)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CEnsureDeleteArray<char> allocated(lpAllocated);
|
||||
|
||||
if (!ReadFile(hFile, lpAllocated, dwFileSize, &dwRead, NULL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long dwHeaderSize = sizeof(unsigned long) + *reinterpret_cast<unsigned long*>(lpAllocated) + sizeof(unsigned long);
|
||||
unsigned long dwBufferSize = *reinterpret_cast<unsigned long*>(lpAllocated + dwHeaderSize - sizeof(unsigned long));
|
||||
|
||||
char* lpBuffer = new char[dwBufferSize];
|
||||
if (NULL == lpBuffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CEnsureDeleteArray<char> buffer(lpBuffer);
|
||||
|
||||
char* lpBufferStartPointer = lpBuffer;
|
||||
|
||||
DECOMPRESS(lpAllocated + dwHeaderSize, dwFileSize - dwHeaderSize, lpBuffer, &dwBufferSize);
|
||||
DECODEHEADER(lpBuffer, dwBufferSize, 0, 3);
|
||||
|
||||
// MineralVein 갯수 얻어오기
|
||||
unsigned long dwVeinCount = *reinterpret_cast<unsigned long*>(lpBuffer);
|
||||
lpBuffer += sizeof(unsigned long);
|
||||
|
||||
// Image 읽기
|
||||
for (int h=0; h<COLOR_IMAGE_SIZE; ++h)
|
||||
{
|
||||
memcpy(m_dwColorTable[h], lpBuffer, sizeof(unsigned long) * COLOR_IMAGE_SIZE);
|
||||
lpBuffer += sizeof(unsigned long) * COLOR_IMAGE_SIZE;
|
||||
}
|
||||
|
||||
for (int i=0; i< (int)dwVeinCount; ++i)
|
||||
{
|
||||
// 광물 갯수 읽기
|
||||
unsigned long dwMineralCount = *reinterpret_cast<unsigned long*>(lpBuffer);
|
||||
lpBuffer += sizeof(unsigned long);
|
||||
|
||||
MineralVeinInfo* lpVeinInfo = new MineralVeinInfo;
|
||||
|
||||
// 광맥 정보 얻기
|
||||
MineralVeinInfo* lpTempVeinInfo = reinterpret_cast<MineralVeinInfo*>(lpBuffer);
|
||||
lpBuffer += 56; // std::list doesnt have a static size between VS versions
|
||||
|
||||
if ( lpVeinInfo && lpTempVeinInfo )
|
||||
{
|
||||
// 광맥 정보 셋팅
|
||||
lpVeinInfo->m_dwVeinColor = lpTempVeinInfo->m_dwVeinColor;
|
||||
strcpy(lpVeinInfo->m_szVeinName, lpTempVeinInfo->m_szVeinName);
|
||||
lpVeinInfo->m_dwMaxFertility = lpTempVeinInfo->m_dwMaxFertility;
|
||||
lpVeinInfo->m_dwNowFertility = lpTempVeinInfo->m_dwMaxFertility;
|
||||
|
||||
for (int j=0; j<(int)dwMineralCount; ++j)
|
||||
{
|
||||
// 광물 정보 얻어와서 셋팅
|
||||
MineralInfo* lpMineralInfo = reinterpret_cast<MineralInfo*>(lpBuffer);
|
||||
dwBufferSize -= sizeof(MineralInfo);
|
||||
lpBuffer += sizeof(MineralInfo);
|
||||
|
||||
lpVeinInfo->m_lstMineralInfo.push_back(*lpMineralInfo);
|
||||
}
|
||||
|
||||
// 광맥 추가
|
||||
m_mapMineralVein.insert(std::make_pair(lpVeinInfo->m_dwVeinColor, lpVeinInfo)).second;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG0(g_Log, "광물 배치 스크립트 로드 실패 : 읽어온 정보 혹은 new 로 생성한 포인터가 NULL 입니다.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MineralVeinInfo* CMineralVeinMgr::GetMineralVein(unsigned long dwVeinColor) const
|
||||
{
|
||||
if ( 0 != dwVeinColor )
|
||||
{
|
||||
MineralVeinMap::const_iterator itr = m_mapMineralVein.find(dwVeinColor);
|
||||
if ( itr != m_mapMineralVein.end() )
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MineralVeinInfo* CMineralVeinMgr::GetMineralVein(float fX, float fZ) const
|
||||
{
|
||||
int iIdxX = static_cast<int>( (fX - 315) * 512 / 3465.f ) ;
|
||||
int iIdxZ = static_cast<int>( 512 - (fZ - 315) * 512 / 3465.f ) ;
|
||||
|
||||
unsigned long dwVeinColor = m_dwColorTable[ iIdxZ ][ iIdxX ];
|
||||
|
||||
return GetMineralVein(dwVeinColor);
|
||||
}
|
||||
|
||||
unsigned long CMineralVeinMgr::GetVeinColor(float fX, float fZ) const
|
||||
{
|
||||
int iIdxX = static_cast<int>( (fX - 315) * 512 / 3465.f ) ;
|
||||
int iIdxZ = static_cast<int>( 512 - (fZ - 315) * 512 / 3465.f ) ;
|
||||
|
||||
return m_dwColorTable[ iIdxZ ][ iIdxX ];
|
||||
}
|
||||
|
||||
const char* CMineralVeinMgr::GetVeinName(float fX, float fZ) const
|
||||
{
|
||||
MineralVeinInfo* pVeinInfo = GetMineralVein(fX, fZ);
|
||||
if (pVeinInfo)
|
||||
{
|
||||
return pVeinInfo->m_szVeinName;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CMineralVeinMgr::GetVeinNum() const
|
||||
{
|
||||
return static_cast<int>( m_mapMineralVein.size() );
|
||||
}
|
||||
|
||||
void CMineralVeinMgr::InitializeMiningCampNum()
|
||||
{
|
||||
m_mapCampNum.clear();
|
||||
}
|
||||
|
||||
void CMineralVeinMgr::CalculateMiningCampNum(float fX, float fZ)
|
||||
{
|
||||
MineralVeinInfo* lpVeinInfo = GetMineralVein(fX, fZ);
|
||||
if ( lpVeinInfo )
|
||||
{
|
||||
VeinToCampNumMap::iterator itr = m_mapCampNum.find( lpVeinInfo->m_dwVeinColor );
|
||||
if ( itr != m_mapCampNum.end() )
|
||||
{
|
||||
++(itr->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mapCampNum.insert( std::make_pair(lpVeinInfo->m_dwVeinColor, 1) ).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CMineralVeinMgr::GetMiningCampNum(unsigned long dwVeinColor)
|
||||
{
|
||||
VeinToCampNumMap::iterator itr = m_mapCampNum.find( dwVeinColor );
|
||||
if ( itr != m_mapCampNum.end() )
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CMineralVeinMgr::CalculateFertility(unsigned long dwProcessType)
|
||||
{
|
||||
if(PktProcessMining::TEMPORARY_PROCESS != dwProcessType)
|
||||
return;
|
||||
|
||||
|
||||
MineralVeinMap::iterator itr = m_mapMineralVein.begin();
|
||||
MineralVeinMap::iterator end = m_mapMineralVein.end();
|
||||
|
||||
while ( itr != end )
|
||||
{
|
||||
MineralVeinInfo* lpVeinInfo = itr->second;
|
||||
if ( lpVeinInfo )
|
||||
{
|
||||
VeinToCampNumMap::iterator pos = m_mapCampNum.find( itr->first );
|
||||
if ( pos != m_mapCampNum.end() )
|
||||
{
|
||||
// 지력은 해당지역에서 마이닝을 하고 있는 캠프가 몇개냐에 따라서
|
||||
// 해당 캠프 수만큼 준다.
|
||||
if ( (unsigned long)pos->second > lpVeinInfo->m_dwNowFertility )
|
||||
{
|
||||
lpVeinInfo->m_dwNowFertility = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpVeinInfo->m_dwNowFertility -= pos->second;
|
||||
}
|
||||
}
|
||||
else if (lpVeinInfo->m_dwNowFertility < lpVeinInfo->m_dwMaxFertility)
|
||||
{
|
||||
unsigned long dwAddValue = static_cast<unsigned long>(ceil(lpVeinInfo->m_dwMaxFertility * 0.1f));
|
||||
if (dwAddValue + lpVeinInfo->m_dwNowFertility > lpVeinInfo->m_dwMaxFertility)
|
||||
{
|
||||
lpVeinInfo->m_dwNowFertility = lpVeinInfo->m_dwMaxFertility;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpVeinInfo->m_dwNowFertility += dwAddValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void CMineralVeinMgr::SerializeOutFertility(unsigned long* lpData_Out, unsigned short& wSize)
|
||||
{
|
||||
MineralVeinMap::iterator itr = m_mapMineralVein.begin();
|
||||
MineralVeinMap::iterator end = m_mapMineralVein.end();
|
||||
|
||||
while ( itr != end )
|
||||
{
|
||||
MineralVeinInfo* lpVeinInfo = itr->second;
|
||||
if ( lpVeinInfo )
|
||||
{
|
||||
*lpData_Out = lpVeinInfo->m_dwVeinColor;
|
||||
++lpData_Out;
|
||||
wSize += sizeof(unsigned long);
|
||||
|
||||
*lpData_Out = lpVeinInfo->m_dwNowFertility;
|
||||
++lpData_Out;
|
||||
wSize += sizeof(unsigned long);
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DB 에서 얻어온 현재 지력값을 설정하는 함수
|
||||
bool CMineralVeinMgr::SetNowFertility(unsigned short wNum, unsigned long* szDataFromDB)
|
||||
{
|
||||
unsigned long dwVeinColor, dwNowFertility;
|
||||
|
||||
for (int i=0; i<wNum; ++i)
|
||||
{
|
||||
dwVeinColor = *szDataFromDB;
|
||||
++szDataFromDB;
|
||||
|
||||
dwNowFertility = *szDataFromDB;
|
||||
++szDataFromDB;
|
||||
|
||||
SetNowFertility(dwVeinColor, dwNowFertility);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMineralVeinMgr::SetNowFertility(unsigned long dwVeinColor, unsigned long dwFertility)
|
||||
{
|
||||
MineralVeinMap::iterator pos = m_mapMineralVein.find(dwVeinColor);
|
||||
if (pos != m_mapMineralVein.end())
|
||||
{
|
||||
MineralVeinInfo* lpVeinInfo = pos->second;
|
||||
lpVeinInfo->m_dwNowFertility = dwFertility;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#ifndef __MINERAL_VEIN_MANAGER_H__
|
||||
#define __MINERAL_VEIN_MANAGER_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#define g_MinveralVeinMgr CMineralVeinMgr::GetInstance()
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
// 광물 정보 구조체
|
||||
struct MineralInfo
|
||||
{
|
||||
unsigned short m_dwMineralID; // 광물 Item ID
|
||||
unsigned char m_cMin; // 광물 추출 Min
|
||||
unsigned char m_cMax; // 광물 추출 Max
|
||||
};
|
||||
typedef std::list<MineralInfo> MineralInfoList;
|
||||
|
||||
|
||||
// 광맥 정보 구조체
|
||||
struct MineralVeinInfo
|
||||
{
|
||||
enum Length
|
||||
{
|
||||
MAX_VEIN_NAME_LEN = 32
|
||||
};
|
||||
|
||||
char m_szVeinName[ MAX_VEIN_NAME_LEN ]; // 광맥 이름
|
||||
unsigned long m_dwVeinColor; // 광맥의 색상 ID
|
||||
unsigned long m_dwMaxFertility; // 광맥의 최대 지력
|
||||
unsigned long m_dwNowFertility; // 광맥의 현재 지력 (DB 에서 얻어오는 값)
|
||||
MineralInfoList m_lstMineralInfo; // 광물 리스트
|
||||
};
|
||||
typedef std::map<unsigned long, MineralVeinInfo*> MineralVeinMap;
|
||||
|
||||
|
||||
// TGA 파일 헤더
|
||||
#pragma pack (1)
|
||||
struct sTargaHeader {
|
||||
unsigned char IDLength, ColorMapType, ImageType ;
|
||||
unsigned short ColorMapOrigin, ColorMapSize ;
|
||||
unsigned char ColorMapEntrySize ;
|
||||
unsigned short XOrigin, YOrigin, Width, Height ;
|
||||
unsigned char PixelSize ;
|
||||
unsigned char ImageDescriptor ;
|
||||
};
|
||||
#pragma pack (8)
|
||||
|
||||
// 광맥 관리 클래스
|
||||
class CMineralVeinMgr
|
||||
{
|
||||
public:
|
||||
enum Const
|
||||
{
|
||||
MAX_TYPE_STRING_LEN = 32,
|
||||
MAX_HEXA_COLOR_LEN = 10,
|
||||
|
||||
COLOR_IMAGE_SIZE = 512
|
||||
};
|
||||
|
||||
static CMineralVeinMgr& GetInstance();
|
||||
|
||||
bool Initialize();
|
||||
void Destroy();
|
||||
|
||||
bool LoadMineralVeinsFromFiles(const char* szTextFile, const char* szImageFile = 0);
|
||||
bool SaveMineralVeinsToText(const char* szScriptFile);
|
||||
bool SaveMineralVeinsToBinary(const char* szBinaryFile, const char* szTrashFile = 0);
|
||||
bool LoadMineralVeinsFromBinary(const char* szBinaryFile);
|
||||
|
||||
MineralVeinInfo* GetMineralVein(unsigned long dwVeinColor) const;
|
||||
MineralVeinInfo* GetMineralVein(float fX, float fZ) const;
|
||||
unsigned long GetVeinColor(float fX, float fZ) const;
|
||||
const char* GetVeinName(float fX, float fZ) const;
|
||||
int GetVeinNum() const;
|
||||
|
||||
// 지력 프로세스 함수
|
||||
void InitializeMiningCampNum(); // 지력당 채굴기 수를 0 으로 리셋
|
||||
void CalculateMiningCampNum(float fX, float fZ); // 채굴기 위치에 해당하는 지력의 요새 수를 증가해주는 함수
|
||||
int GetMiningCampNum(unsigned long dwVeinColor); // 현재 지역의 채굴중인 채굴기 수를 리턴
|
||||
void CalculateFertility(unsigned long dwProcessType); // 지력 업데이트
|
||||
void SerializeOutFertility(unsigned long* lpData_Out, unsigned short& wSize);
|
||||
|
||||
|
||||
// DB 에서 얻어온 현재 지력값을 설정하는 함수
|
||||
bool SetNowFertility(unsigned short wNum, unsigned long* szDataFromDB);
|
||||
bool SetNowFertility(unsigned long dwVeinColor, unsigned long dwFertility);
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<unsigned long, int> VeinToCampNumMap; // < VeinColor, MiningCampNum >
|
||||
|
||||
CMineralVeinMgr();
|
||||
~CMineralVeinMgr();
|
||||
|
||||
MineralVeinMap m_mapMineralVein;
|
||||
VeinToCampNumMap m_mapCampNum;
|
||||
unsigned long m_dwColorTable[ COLOR_IMAGE_SIZE ][ COLOR_IMAGE_SIZE ];
|
||||
};
|
||||
|
||||
#endif // __MINERAL_VEIN_MANAGER_H__
|
||||
@@ -0,0 +1,336 @@
|
||||
#include "stdafx.h"
|
||||
#include "VirtualArea.h"
|
||||
|
||||
#include <Map/FieldMap/VirtualArea/VirtualAreaMgr.h>
|
||||
#include <Creature/Monster/VirtualMonsterMgr.h>
|
||||
|
||||
using namespace VirtualArea;
|
||||
|
||||
|
||||
CVirtualArea::CVirtualArea(const VirtualArea::ProtoType* lpProtoType, unsigned short wMapIndex)
|
||||
: m_CellData(NULL), m_dwVID(0), m_wMapIndex(wMapIndex), m_pVirtualMonsterMgr(NULL)
|
||||
{
|
||||
m_CharacterList.clear();
|
||||
m_SpectatorList.clear();
|
||||
|
||||
if (lpProtoType)
|
||||
{
|
||||
m_dwVID = lpProtoType->m_dwVID;
|
||||
CreateCell(lpProtoType->m_wWidth, lpProtoType->m_wHeight, wMapIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CVirtualArea::~CVirtualArea()
|
||||
{
|
||||
if (NULL != m_CellData)
|
||||
{
|
||||
delete [] m_CellData;
|
||||
m_CellData = NULL;
|
||||
}
|
||||
|
||||
m_CharacterList.clear();
|
||||
m_SpectatorList.clear();
|
||||
|
||||
if (m_pVirtualMonsterMgr)
|
||||
{
|
||||
delete m_pVirtualMonsterMgr;
|
||||
m_pVirtualMonsterMgr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CVirtualArea::CreateCell(unsigned short wWidth, unsigned short wHeight, unsigned short wMapIndex)
|
||||
{
|
||||
int nX = 0;
|
||||
int nZ = 0;
|
||||
|
||||
m_CellData = new CCell[wWidth * wHeight];
|
||||
if (NULL == m_CellData)
|
||||
{
|
||||
ERRLOG0(g_Log, "셀을 할당하는데 실패했습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make Cell Link
|
||||
for (nZ = 0; nZ < wHeight; ++nZ)
|
||||
{
|
||||
for (nX = 0; nX < wWidth; ++nX)
|
||||
{
|
||||
// UP, UpperLeft, UpperRight
|
||||
if (nZ > 0)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::UP, &m_CellData[nX + (nZ - 1) * wWidth]);
|
||||
|
||||
if (nX > 0)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::UPPERLEFT, &m_CellData[nX - 1 + (nZ - 1) * wWidth]);
|
||||
}
|
||||
|
||||
if (nX < wWidth - 1)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::UPPERRIGHT, &m_CellData[nX + 1 + (nZ - 1) * wWidth]);
|
||||
}
|
||||
}
|
||||
|
||||
// Down, DnLeft, DnRight
|
||||
if (nZ < wWidth - 1)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::DOWN, &m_CellData[nX + (nZ + 1) * wWidth]);
|
||||
|
||||
if (nX > 0)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::LOWERLEFT, &m_CellData[nX - 1 + (nZ + 1) * wWidth]);
|
||||
}
|
||||
|
||||
if (nX < wWidth - 1)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::LOWERRIGHT, &m_CellData[nX + 1 + (nZ + 1) * wWidth]);
|
||||
}
|
||||
}
|
||||
|
||||
// Left
|
||||
if (nX > 0)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::LEFT, &m_CellData[nX - 1 + nZ * wWidth]);
|
||||
}
|
||||
|
||||
// Right
|
||||
if (nX < wWidth - 1)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::RIGHT, &m_CellData[nX + 1 + nZ * wWidth]);
|
||||
}
|
||||
|
||||
// itself
|
||||
m_CellData[nX + nZ * wWidth].SetConnectCell(CCell::NO, &m_CellData[nX + nZ * wWidth]);
|
||||
}
|
||||
}
|
||||
|
||||
// 2004 / 06 / 14 : sparrowhawk changed.
|
||||
// 링크를 생성한 후 초기화를 해야 한다.
|
||||
for (nZ = 0; nZ < wHeight; ++nZ)
|
||||
{
|
||||
for (nX = 0; nX < wWidth; ++nX)
|
||||
{
|
||||
m_CellData[nX + nZ * wWidth].Initialize(nX, nZ);
|
||||
m_CellData[nX + nZ * wWidth].SetMapIndex(wMapIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CVirtualArea::CreateVirtualMonsterManager()
|
||||
{
|
||||
if (m_pVirtualMonsterMgr)
|
||||
{
|
||||
delete m_pVirtualMonsterMgr;
|
||||
m_pVirtualMonsterMgr = NULL;
|
||||
}
|
||||
|
||||
m_pVirtualMonsterMgr = new CVirtualMonsterMgr();
|
||||
}
|
||||
|
||||
|
||||
void CVirtualArea::ProcessAllMonster()
|
||||
{
|
||||
if (m_pVirtualMonsterMgr)
|
||||
{
|
||||
m_pVirtualMonsterMgr->ProcessAllMonster();
|
||||
}
|
||||
}
|
||||
|
||||
void CVirtualArea::ProcessMonsterRegenHPAndMP()
|
||||
{
|
||||
if (m_pVirtualMonsterMgr)
|
||||
{
|
||||
m_pVirtualMonsterMgr->ProcessMonsterRegenHPAndMP();
|
||||
}
|
||||
}
|
||||
|
||||
void CVirtualArea::ProcessSummonMonsterDead()
|
||||
{
|
||||
if (m_pVirtualMonsterMgr)
|
||||
{
|
||||
m_pVirtualMonsterMgr->ProcessSummonMonsterDead();
|
||||
}
|
||||
}
|
||||
|
||||
void CVirtualArea::ProcessDeleteItem()
|
||||
{
|
||||
if (NULL == m_CellData)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CCell* lpCellPastEnd = m_CellData + GetWidth() * GetHeight();
|
||||
|
||||
for (CCell* lpCell = m_CellData; lpCell != lpCellPastEnd; ++lpCell)
|
||||
{
|
||||
lpCell->CheckDeleteItem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CVirtualArea::ProcessAllCellPrepareBroadCast()
|
||||
{
|
||||
if (NULL == m_CellData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CCell* lpCellPastEnd = m_CellData + GetWidth() * GetHeight();
|
||||
|
||||
for (CCell* lpCell = m_CellData; lpCell != lpCellPastEnd; ++lpCell)
|
||||
{
|
||||
lpCell->PrepareBroadCast();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CVirtualArea::ProcessAllCellBroadCast(unsigned long dwCurrentPulse)
|
||||
{
|
||||
if (NULL == m_CellData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CCell* lpCellPastEnd = m_CellData + GetWidth() * GetHeight();
|
||||
|
||||
for (CCell* lpCell = m_CellData; lpCell != lpCellPastEnd; ++lpCell)
|
||||
{
|
||||
lpCell->BroadCast(dwCurrentPulse);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
unsigned short CVirtualArea::GetStartX()
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pProtoType->m_wStartX;
|
||||
}
|
||||
|
||||
|
||||
unsigned short CVirtualArea::GetStartZ()
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pProtoType->m_wStartZ;
|
||||
}
|
||||
|
||||
|
||||
unsigned short CVirtualArea::GetWidth()
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pProtoType->m_wWidth;
|
||||
}
|
||||
|
||||
unsigned short CVirtualArea::GetHeight()
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pProtoType->m_wHeight;
|
||||
}
|
||||
|
||||
unsigned char CVirtualArea::GetVirtualZone()
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pProtoType->m_cZone;
|
||||
}
|
||||
|
||||
Position CVirtualArea::GetStartPosition(unsigned char cNation)
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return Position(0, 0, 0);
|
||||
}
|
||||
|
||||
if (cNation >= CClass::MAX_RACE)
|
||||
{
|
||||
ERRLOG1(g_Log, "VirtualArea StartPos 얻기 실패!! Nation : %d", cNation);
|
||||
return Position(0, 0, 0);
|
||||
}
|
||||
|
||||
return pProtoType->m_StartPos[cNation];
|
||||
}
|
||||
|
||||
|
||||
Position CVirtualArea::GetRespawnPosition(unsigned char cNation, int nIndex)
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return Position(0, 0, 0);
|
||||
}
|
||||
|
||||
if (cNation >= CClass::MAX_RACE || nIndex < 0 || nIndex >= VirtualArea::MAX_VIRTUAL_AREA_RESPAWN_POINT)
|
||||
{
|
||||
ERRLOG3(g_Log, "VirtualArea RespawnPos 얻기 실패!! Nation : %d, Index : %d, MAX_VIRTUAL_AREA_RESPAWN_POINT : %d",
|
||||
cNation, nIndex, VirtualArea::MAX_VIRTUAL_AREA_RESPAWN_POINT);
|
||||
return Position(0, 0, 0);
|
||||
}
|
||||
|
||||
return pProtoType->m_RespawnPos[cNation][nIndex];
|
||||
}
|
||||
|
||||
unsigned char CVirtualArea::GetMaxRespawnPos()
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return pProtoType->m_cMaxRespawnPos;
|
||||
}
|
||||
|
||||
const char* CVirtualArea::GetMapTypeName()
|
||||
{
|
||||
const VirtualArea::ProtoType* pProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType(m_dwVID);
|
||||
if (NULL == pProtoType)
|
||||
{
|
||||
ERRLOG1(g_Log, "VID : 0x%x VirtualAreaProtoType 을 얻기 실패!!", m_dwVID);
|
||||
return "에러야!!";
|
||||
}
|
||||
|
||||
return pProtoType->m_szMapType;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#ifndef _VIRTUAL_AREA_H_
|
||||
#define _VIRTUAL_AREA_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Map/FieldMap/Cell.h>
|
||||
|
||||
// 전방 참조
|
||||
class CCharacter;
|
||||
class CMonster;
|
||||
class CVirtualMonsterMgr;
|
||||
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
// 전방 참조
|
||||
struct ProtoType;
|
||||
class CVirtualAreaMgr;
|
||||
|
||||
|
||||
class CVirtualArea
|
||||
{
|
||||
public:
|
||||
virtual void Process() { }
|
||||
virtual unsigned short Enter(CCharacter* lpCharacter, unsigned char cMoveType) { return 0; }
|
||||
virtual bool Leave(CCharacter* lpCharacter) { return false; }
|
||||
|
||||
|
||||
unsigned long GetVID() { return m_dwVID; }
|
||||
CCell* GetCell(int nIndex) { return &m_CellData[nIndex]; }
|
||||
unsigned short GetVirtualType() { return static_cast<unsigned short>(m_dwVID >> 16); }
|
||||
unsigned short GetMapIndex() { return m_wMapIndex; }
|
||||
|
||||
void CreateVirtualMonsterManager();
|
||||
CVirtualMonsterMgr* GetMonsterManager() { return m_pVirtualMonsterMgr; }
|
||||
|
||||
|
||||
// 스크립트에서 읽은 프로토 타입의 값을 리턴해주는 함수들
|
||||
unsigned short GetStartX();
|
||||
unsigned short GetStartZ();
|
||||
unsigned short GetWidth();
|
||||
unsigned short GetHeight();
|
||||
unsigned char GetVirtualZone();
|
||||
Position GetStartPosition(unsigned char cNation);
|
||||
Position GetRespawnPosition(unsigned char cNation, int nIndex);
|
||||
unsigned char GetMaxRespawnPos();
|
||||
const char* GetMapTypeName();
|
||||
|
||||
// Type 정의
|
||||
typedef std::list<CCharacter* > CharacterList;
|
||||
typedef std::list<CMonster* > MonsterList;
|
||||
|
||||
// 몬스터 처리
|
||||
void ProcessAllMonster();
|
||||
void ProcessMonsterRegenHPAndMP();
|
||||
void ProcessSummonMonsterDead();
|
||||
|
||||
// Item 처리
|
||||
void ProcessDeleteItem();
|
||||
|
||||
// Cell BroadCasting
|
||||
bool ProcessAllCellPrepareBroadCast();
|
||||
bool ProcessAllCellBroadCast(unsigned long dwCurrentPulse);
|
||||
|
||||
protected:
|
||||
|
||||
CVirtualArea(const VirtualArea::ProtoType* lpProtoType, unsigned short wMapIndex);
|
||||
virtual ~CVirtualArea();
|
||||
|
||||
virtual unsigned short AddCharacter(CCharacter* lpCharacter) { return 0; }
|
||||
virtual unsigned short AddSpectator(CCharacter* lpSpectator) { return 0; }
|
||||
|
||||
bool CreateCell(unsigned short wWidth, unsigned short wHeight, unsigned short wMapIndex);
|
||||
|
||||
CCell* m_CellData;
|
||||
unsigned long m_dwVID;
|
||||
unsigned short m_wMapIndex;
|
||||
|
||||
|
||||
CharacterList m_CharacterList;
|
||||
CharacterList m_SpectatorList;
|
||||
|
||||
CVirtualMonsterMgr* m_pVirtualMonsterMgr;
|
||||
|
||||
friend class CVirtualAreaMgr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _VIRTUAL_AREA_H_
|
||||
@@ -0,0 +1,89 @@
|
||||
#ifndef __VIRTUAL_AREA_CONSTANTS_H__
|
||||
#define __VIRTUAL_AREA_CONSTANTS_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
// 헤더 파일 빼기
|
||||
#include <Creature/CreatureStructure.h>
|
||||
#include <Creature/Character/CharacterClass.h>
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
enum VirtualAreaType
|
||||
{
|
||||
// MapIndex 에 들어가는 Flag 와 VID(VirtualAreaID) 에 사용한다.
|
||||
BGSERVERMAP = 0x8000,
|
||||
DUELMAP = 0x4000,
|
||||
DUNGEON = 0x2000
|
||||
};
|
||||
|
||||
enum MapType
|
||||
{
|
||||
FRAG = 0, // 스코어 경쟁 게임 방
|
||||
STATUE = 1, // 석상 점령 게임 방
|
||||
|
||||
MAX_MAP_TYPE
|
||||
};
|
||||
|
||||
enum MoveType
|
||||
{
|
||||
TYPE_PLAYER = 0, // 게임 참전자
|
||||
TYPE_SPECTATOR = 1, // 게임 관전자
|
||||
|
||||
MAX_ENTER_TYPE
|
||||
};
|
||||
|
||||
enum Status
|
||||
{
|
||||
START_WAITING = 0, // GameStart() 를 호출하기 전까지...
|
||||
GAME_PLAYING = 1, // 게임 진행 상태
|
||||
GAME_RESTING = 2, // 게임이 끝나고 휴식 상태
|
||||
MOVEZONE_WAITING = 3, // 게임이 끝나고, 존 이동될때까지의 상태
|
||||
|
||||
MAX_STATUS_TYPE = 4
|
||||
};
|
||||
|
||||
enum Score
|
||||
{
|
||||
FRAG_SCORE = 1,
|
||||
|
||||
HOSTILITY_STATUE_SCORE = 0,
|
||||
NEUTRALITY_STATUE_SCORE = 0,
|
||||
FRIENDLY_STATUE_SCORE = 2,
|
||||
FRIENDLY_LOADING_STATUE_SCORE = 1
|
||||
};
|
||||
|
||||
enum Const
|
||||
{
|
||||
MAX_MAP_TYPE_NAME = 32,
|
||||
MAX_FILE_NAME = 128,
|
||||
MAX_VIRTUAL_AREA_RESPAWN_POINT = 3,
|
||||
MAX_LOBBY_RESPAWN_POS = 2,
|
||||
|
||||
MILLISEC_PER_MINUTE = 60000, // 1분 (60000 ms)
|
||||
MILEAGE_PER_MINUTE_FOR_WIN = 20, // 1분 공헌메달 보상 수치 (이긴 경우)
|
||||
MILEAGE_PER_MINUTE_FOR_DRAW = 10, // 1분 공헌메달 보상 수치 (비긴 경우)
|
||||
|
||||
MOVEZONE_WAIT_TIME = 10000, // 10초 후 존이동
|
||||
};
|
||||
|
||||
|
||||
// 초기값
|
||||
const unsigned char DefaultMaxCharacterNumOfNation[MAX_MAP_TYPE] = { 60, 120 }; // 60명, 120명
|
||||
const unsigned short DefaultTargetScore[MAX_MAP_TYPE] = { 500, 6 }; // 500점, 6점
|
||||
const unsigned char DefaultLimitMin[MAX_MAP_TYPE] = { 25, 50 }; // 25분, 50분
|
||||
const unsigned char DefaultRestMin[MAX_MAP_TYPE] = { 5, 10 }; // 5분, 10분
|
||||
|
||||
// BATTLE_SERVER 대기존 리스폰 좌표
|
||||
const POS RespawnPos[CClass::MAX_RACE][MAX_LOBBY_RESPAWN_POS] =
|
||||
{ // Human
|
||||
{ { 2165, 1135, 1005 }, { 1727, 1135, 1005 } },
|
||||
|
||||
// Akhan
|
||||
{ { 2119, 1132, 1841 }, { 1683, 1132, 1841 } }
|
||||
};
|
||||
|
||||
static const char* ms_szVirtualAreaScriptFileName = "./Script/Game/VirtualAreaScript.txt";
|
||||
}
|
||||
|
||||
#endif // __VIRTUAL_AREA_CONSTANTS_H__
|
||||
@@ -0,0 +1,444 @@
|
||||
#include "stdafx.h"
|
||||
#include "VirtualAreaMgr.h"
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
#include <Utility/DelimitedFile.h>
|
||||
|
||||
#include <Map/FieldMap/VirtualArea/VirtualArea.h>
|
||||
#include <Map/FieldMap/VirtualArea/BGServer/BGServerMgr.h>
|
||||
#include <Map/FieldMap/VirtualArea/Duel/DuelMgr.h>
|
||||
#include <Map/FieldMap/VirtualArea/Dungeon/DungeonMgr.h>
|
||||
|
||||
#include <Creature/Character/Character.h>
|
||||
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
|
||||
using namespace VirtualArea;
|
||||
|
||||
|
||||
CVirtualAreaMgr& CVirtualAreaMgr::GetInstance()
|
||||
{
|
||||
static CVirtualAreaMgr ms_this;
|
||||
return ms_this;
|
||||
};
|
||||
|
||||
|
||||
CVirtualAreaMgr::CVirtualAreaMgr()
|
||||
: m_BGServerMgr(CBGServerMgr::GetInstance()),
|
||||
m_DuelMgr(CDuelMgr::GetInstance()),
|
||||
m_DungeonMgr(CDungeonMgr::GetInstance()),
|
||||
m_VirtualAreaProtoTypeArray(NULL), m_VirtualAreaProtoTypeNum(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CVirtualAreaMgr::~CVirtualAreaMgr()
|
||||
{
|
||||
DestroyVirtualAreaProtoTypeArray();
|
||||
}
|
||||
|
||||
|
||||
// Script 파일 로드
|
||||
bool CVirtualAreaMgr::LoadVirtualAreaProtoType(const char* szFileName)
|
||||
{
|
||||
int nIndex = 0;
|
||||
int nLineCount = 0;
|
||||
char strTemp[MAX_PATH];
|
||||
|
||||
CDelimitedFile DelimitedFile; // 객체 소멸시, 자동 Close.
|
||||
std::vector<VirtualArea::ProtoType> virtualAreaProtoTypeVector;
|
||||
|
||||
virtualAreaProtoTypeVector.reserve(10);
|
||||
VirtualArea::ProtoType tempProtoType;
|
||||
|
||||
// 매크로에 로그 코드 삽입을 잊지 말 것.
|
||||
// 매크로에서 \뒤에 공백이나 문자 삽입되지 않도록 주의할 것.
|
||||
// ( '이스케이프 시퀀스가 잘못되었습니다' 에러 발생 )
|
||||
#define READ_DATA(ColumnName, Argument) \
|
||||
if (!DelimitedFile.ReadData(Argument)) { \
|
||||
ERRLOG2(g_Log, "Virtual Area 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount, #ColumnName); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define READ_STRING(ColumnName, Buffer, BufferSize) \
|
||||
if (!DelimitedFile.ReadString(Buffer, BufferSize)) { \
|
||||
ERRLOG2(g_Log, "Virtual Area 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount, #ColumnName); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define READ_POSITION(ColumnName, Pos) \
|
||||
if (!DelimitedFile.ReadData(Pos.m_fPointX)) { \
|
||||
ERRLOG2(g_Log, "Virtual Area 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount, #ColumnName); \
|
||||
return false; \
|
||||
} \
|
||||
if (!DelimitedFile.ReadData(Pos.m_fPointY)) { \
|
||||
ERRLOG2(g_Log, "Virtual Area 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount, #ColumnName); \
|
||||
return false; \
|
||||
} \
|
||||
if (!DelimitedFile.ReadData(Pos.m_fPointZ)) { \
|
||||
ERRLOG2(g_Log, "Virtual Area 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount, #ColumnName); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define READ_DATA_ARRAY(ColumnName, Argument, ArgumentNum) \
|
||||
for (nIndex=0; nIndex < ArgumentNum; ++nIndex) { \
|
||||
READ_DATA(ColumnName, Argument[nIndex]); \
|
||||
}
|
||||
|
||||
#define READ_DATA_BOOL(ColumnName, Argument) \
|
||||
if (!DelimitedFile.ReadString(strTemp, MAX_PATH)) { \
|
||||
ERRLOG2(g_Log, "Virtual Area 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount, #ColumnName); \
|
||||
return false; \
|
||||
} \
|
||||
Argument = (!strcmp(strTemp, "O")) ? true : false;
|
||||
|
||||
|
||||
if (!DelimitedFile.Open(szFileName ? szFileName : ms_szVirtualAreaScriptFileName))
|
||||
{
|
||||
ERRLOG1(g_Log, "%s 파일을 열 수 없습니다.", szFileName ? szFileName : ms_szVirtualAreaScriptFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (DelimitedFile.ReadLine())
|
||||
{
|
||||
++nLineCount;
|
||||
|
||||
// 순서가 바뀌면 곤란하다니깐~!!! (버럭!)
|
||||
READ_STRING("VID", strTemp, MAX_PATH);
|
||||
tempProtoType.m_dwVID = Math::Convert::Atoi(strTemp);
|
||||
|
||||
READ_STRING("MapType", tempProtoType.m_szMapType, VirtualArea::MAX_MAP_TYPE_NAME);
|
||||
tempProtoType.m_cMapType = m_MapTypeMatching.m_matchMap.find(tempProtoType.m_szMapType)->second;
|
||||
|
||||
READ_DATA("Zone", tempProtoType.m_cZone);
|
||||
READ_DATA("StartX", tempProtoType.m_wStartX);
|
||||
READ_DATA("StartZ", tempProtoType.m_wStartZ);
|
||||
READ_DATA("Width", tempProtoType.m_wWidth);
|
||||
READ_DATA("Height", tempProtoType.m_wHeight);
|
||||
|
||||
READ_STRING("ArrangementFile", strTemp, MAX_PATH);
|
||||
if (0 == stricmp(strTemp, "N/A"))
|
||||
{
|
||||
tempProtoType.m_szArrangementFileName[0] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(tempProtoType.m_szArrangementFileName, strTemp);
|
||||
}
|
||||
|
||||
READ_POSITION("StartPosition(HUMAN)", tempProtoType.m_StartPos[CClass::HUMAN]);
|
||||
READ_POSITION("StartPosition(AKHAN)", tempProtoType.m_StartPos[CClass::AKHAN]);
|
||||
|
||||
tempProtoType.m_cMaxRespawnPos = 1;
|
||||
READ_POSITION("RespawnPos1(HUMAN)", tempProtoType.m_RespawnPos[CClass::HUMAN][0]);
|
||||
READ_POSITION("RespawnPos2(HUMAN)", tempProtoType.m_RespawnPos[CClass::HUMAN][1]);
|
||||
READ_POSITION("RespawnPos3(HUMAN)", tempProtoType.m_RespawnPos[CClass::HUMAN][2]);
|
||||
READ_POSITION("RespawnPos1(AKHAN)", tempProtoType.m_RespawnPos[CClass::AKHAN][0]);
|
||||
READ_POSITION("RespawnPos2(AKHAN)", tempProtoType.m_RespawnPos[CClass::AKHAN][1]);
|
||||
READ_POSITION("RespawnPos3(AKHAN)", tempProtoType.m_RespawnPos[CClass::AKHAN][2]);
|
||||
|
||||
for (int i=1; i<VirtualArea::MAX_VIRTUAL_AREA_RESPAWN_POINT; ++i)
|
||||
{
|
||||
if (tempProtoType.m_RespawnPos[CClass::HUMAN][i].m_fPointX != 0 &&
|
||||
tempProtoType.m_RespawnPos[CClass::HUMAN][i].m_fPointZ != 0)
|
||||
{
|
||||
++tempProtoType.m_cMaxRespawnPos;
|
||||
}
|
||||
}
|
||||
|
||||
virtualAreaProtoTypeVector.push_back(tempProtoType);
|
||||
}
|
||||
|
||||
std::sort(virtualAreaProtoTypeVector.begin(), virtualAreaProtoTypeVector.end());
|
||||
|
||||
for (std::vector<VirtualArea::ProtoType>::iterator itr = virtualAreaProtoTypeVector.begin();
|
||||
itr != virtualAreaProtoTypeVector.end() - 1; ++itr)
|
||||
{
|
||||
if (itr->m_dwVID == (itr+1)->m_dwVID)
|
||||
{
|
||||
ERRLOG1(g_Log, "겹치는 VirtualArea ID가 있습니다. VID:%d", itr->m_dwVID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_VirtualAreaProtoTypeNum = virtualAreaProtoTypeVector.size();
|
||||
m_VirtualAreaProtoTypeArray = new VirtualArea::ProtoType[m_VirtualAreaProtoTypeNum];
|
||||
if (NULL == m_VirtualAreaProtoTypeArray)
|
||||
{
|
||||
ERRLOG0(g_Log, "VirtualArea 스크립트 초기화 실패 : 메모리 부족");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::copy(virtualAreaProtoTypeVector.begin(), virtualAreaProtoTypeVector.end(), m_VirtualAreaProtoTypeArray);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CVirtualAreaMgr::DestroyVirtualAreaProtoTypeArray()
|
||||
{
|
||||
m_VirtualAreaProtoTypeNum = 0;
|
||||
|
||||
if (0 != m_VirtualAreaProtoTypeArray)
|
||||
{
|
||||
delete [] m_VirtualAreaProtoTypeArray;
|
||||
m_VirtualAreaProtoTypeArray = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CVirtualArea* CVirtualAreaMgr::GetVirtualArea(unsigned short wMapIndex)
|
||||
{
|
||||
if (VirtualArea::BGSERVERMAP == (wMapIndex & VirtualArea::BGSERVERMAP))
|
||||
{
|
||||
return m_BGServerMgr.GetVirtualArea(wMapIndex);
|
||||
}
|
||||
else if (VirtualArea::DUELMAP == (wMapIndex & VirtualArea::DUELMAP))
|
||||
{
|
||||
}
|
||||
else if (VirtualArea::DUNGEON == (wMapIndex & VirtualArea::DUNGEON))
|
||||
{
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
class CFindProtoTypeFromVID : public std::unary_function<VirtualArea::ProtoType, bool>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CFindProtoTypeFromVID(unsigned long dwVID)
|
||||
: m_dwVID(dwVID)
|
||||
{ }
|
||||
|
||||
bool operator() (VirtualArea::ProtoType& protoType)
|
||||
{
|
||||
return (m_dwVID == protoType.m_dwVID);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
const unsigned long m_dwVID;
|
||||
};
|
||||
|
||||
|
||||
const VirtualArea::ProtoType* CVirtualAreaMgr::GetVirtualAreaProtoType(unsigned long dwVID)
|
||||
{
|
||||
VirtualArea::ProtoType* lpProtoType = NULL;
|
||||
|
||||
if (0 != dwVID)
|
||||
{
|
||||
CFindProtoTypeFromVID findVID(dwVID);
|
||||
lpProtoType = std::find_if(&m_VirtualAreaProtoTypeArray[0], &m_VirtualAreaProtoTypeArray[m_VirtualAreaProtoTypeNum], findVID);
|
||||
}
|
||||
|
||||
return lpProtoType;
|
||||
}
|
||||
|
||||
|
||||
const VirtualArea::ProtoType* CVirtualAreaMgr::GetVirtualAreaProtoType(char* szMapType)
|
||||
{
|
||||
for (size_t nIndex = 0; nIndex < m_VirtualAreaProtoTypeNum; nIndex++)
|
||||
{
|
||||
if (0 == strncmp(szMapType, m_VirtualAreaProtoTypeArray[nIndex].m_szMapType, VirtualArea::MAX_MAP_TYPE_NAME))
|
||||
{
|
||||
return m_VirtualAreaProtoTypeArray + nIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool CVirtualAreaMgr::EnterVirtualArea(CCharacter* lpCharacter, unsigned short wMapIndex, unsigned char cMoveType)
|
||||
{
|
||||
if (NULL == lpCharacter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CVirtualArea* lpVirtualArea = GetVirtualArea(wMapIndex);
|
||||
if (NULL == lpVirtualArea)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 캐릭터가 존재하지 않는 가상 존(MapIndex : %d)으로 이동하려고 합니다.", lpCharacter->GetCID(), wMapIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (VirtualArea::BGSERVERMAP == (wMapIndex & VirtualArea::BGSERVERMAP))
|
||||
{
|
||||
return m_BGServerMgr.Enter(lpCharacter, wMapIndex, cMoveType);
|
||||
}
|
||||
else if (VirtualArea::DUELMAP == (wMapIndex & VirtualArea::DUELMAP))
|
||||
{
|
||||
}
|
||||
else if (VirtualArea::DUNGEON == (wMapIndex & VirtualArea::DUNGEON))
|
||||
{
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CVirtualAreaMgr::LeaveVirtualArea(CCharacter* lpCharacter)
|
||||
{
|
||||
if (NULL == lpCharacter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned short wCurrentMapIndex = lpCharacter->GetMapIndex();
|
||||
CVirtualArea* lpVirtualArea = GetVirtualArea(wCurrentMapIndex);
|
||||
if (NULL == lpVirtualArea)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 캐릭터가 존재하지 않는 가상 존(MapIndex : %d)에서 나가려고 합니다.", lpCharacter->GetCID(), wCurrentMapIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (VirtualArea::BGSERVERMAP == (wCurrentMapIndex & VirtualArea::BGSERVERMAP))
|
||||
{
|
||||
return m_BGServerMgr.Leave(lpCharacter);
|
||||
}
|
||||
else if (VirtualArea::DUELMAP == (wCurrentMapIndex & VirtualArea::DUELMAP))
|
||||
{
|
||||
}
|
||||
else if (VirtualArea::DUNGEON == (wCurrentMapIndex & VirtualArea::DUNGEON))
|
||||
{
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CVirtualAreaMgr::ProcessAllVirtualArea()
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
m_BGServerMgr.Process();
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_DeulMgr.Process();
|
||||
// m_DungeonMgr.Process();
|
||||
}
|
||||
}
|
||||
|
||||
void CVirtualAreaMgr::ProcessAllMonster()
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
m_BGServerMgr.ProcessAllMonster();
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_DeulMgr.ProcessAllMonster();
|
||||
// m_DungeonMgr.ProcessAllMonster();
|
||||
}
|
||||
}
|
||||
|
||||
void CVirtualAreaMgr::ProcessMonsterRegenHPAndMP()
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
m_BGServerMgr.ProcessMonsterRegenHPAndMP();
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_DeulMgr.ProcessMonsterRegenHPAndMP();
|
||||
// m_DungeonMgr.ProcessMonsterRegenHPAndMP();
|
||||
}
|
||||
}
|
||||
|
||||
void CVirtualAreaMgr::ProcessSummonMonsterDead()
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
m_BGServerMgr.ProcessSummonMonsterDead();
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_DuelMgr.ProcessSummonMonsterDead();
|
||||
// m_DungeonMgr.ProcessSummonMonsterDead();
|
||||
}
|
||||
}
|
||||
|
||||
bool CVirtualAreaMgr::ProcessAllCellPrepareBroadCast()
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
m_BGServerMgr.ProcessAllCellPrepareBroadCast();
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_DuelMgr.ProcessAllCellPrepareBroadCast();
|
||||
// m_DungeonMgr.ProcessAllCellPrepareBroadCast();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CVirtualAreaMgr::ProcessAllCellBroadCast(unsigned long dwCurrentPulse)
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
m_BGServerMgr.ProcessAllCellBroadCast(dwCurrentPulse);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_DuelMgr.ProcessAllCellBroadCast();
|
||||
// m_DungeonMgr.ProcessAllCellBroadCast();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CVirtualAreaMgr::ProcessDeleteItem()
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
m_BGServerMgr.ProcessDeleteItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_DuelMgr.ProcessDeleteItem();
|
||||
// m_DungeonMgr.ProcessDeleteItem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// BattleGround Server 관련 함수
|
||||
|
||||
bool CVirtualAreaMgr::CreateBGServer() // Battle Ground Server Map 과 Cell 생성
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
return m_BGServerMgr.CreateBGServerMap();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CVirtualAreaMgr::SendBGServerMapList(CCharacter* lpCharacter)
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
return m_BGServerMgr.SendMapList(lpCharacter);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CVirtualAreaMgr::SendBGServerResultList(CCharacter* lpCharacter)
|
||||
{
|
||||
if (SERVER_ID::BATTLE_SERVER == CServerSetup::GetInstance().GetServerZone())
|
||||
{
|
||||
return m_BGServerMgr.SendResultList(lpCharacter);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#ifndef _VIRTUAL_AREA_MANAGER_H_
|
||||
#define _VIRTUAL_AREA_MANAGER_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <Map/FieldMap/VirtualArea/VirtualAreaStructure.h>
|
||||
|
||||
|
||||
class CCell;
|
||||
class CCharacter;
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
// 전방 참조
|
||||
|
||||
class CBGServerMgr;
|
||||
class CDuelMgr;
|
||||
class CDungeonMgr;
|
||||
class CVirtualArea;
|
||||
|
||||
|
||||
class CVirtualAreaMgr
|
||||
{
|
||||
public:
|
||||
|
||||
enum Const
|
||||
{
|
||||
VIRTUALAREA_PULSE = 20 // 2초에 한번씩 처리
|
||||
};
|
||||
|
||||
static CVirtualAreaMgr& GetInstance();
|
||||
|
||||
// Script 파일 로드
|
||||
bool LoadVirtualAreaProtoType(const char* szFileName = 0);
|
||||
|
||||
CVirtualArea* GetVirtualArea(unsigned short wMapIndex);
|
||||
|
||||
const VirtualArea::ProtoType* GetVirtualAreaProtoType(unsigned long dwVID);
|
||||
const VirtualArea::ProtoType* GetVirtualAreaProtoType(char* szMapType);
|
||||
|
||||
bool EnterVirtualArea(CCharacter* lpCharacter, unsigned short wMapIndex, unsigned char cMoveType);
|
||||
bool LeaveVirtualArea(CCharacter* lpCharacter);
|
||||
|
||||
void ProcessAllVirtualArea();
|
||||
void ProcessAllMonster();
|
||||
void ProcessMonsterRegenHPAndMP();
|
||||
void ProcessSummonMonsterDead();
|
||||
void ProcessDeleteItem();
|
||||
|
||||
// Cell BroadCasting
|
||||
bool ProcessAllCellPrepareBroadCast();
|
||||
bool ProcessAllCellBroadCast(unsigned long dwCurrentPulse);
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// BattleGround Server 관련 함수
|
||||
bool CreateBGServer(); // Battle Ground Server Map 과 Cell 생성
|
||||
|
||||
bool SendBGServerMapList(CCharacter* lpCharacter);
|
||||
bool SendBGServerResultList(CCharacter* lpCharacter);
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Duel 관련 함수
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Dungeon 관련 함수
|
||||
|
||||
|
||||
|
||||
private:
|
||||
CVirtualAreaMgr();
|
||||
~CVirtualAreaMgr();
|
||||
|
||||
|
||||
void DestroyVirtualAreaProtoTypeArray();
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// member variable
|
||||
|
||||
CBGServerMgr& m_BGServerMgr;
|
||||
CDuelMgr& m_DuelMgr;
|
||||
CDungeonMgr& m_DungeonMgr;
|
||||
|
||||
|
||||
VirtualArea::ProtoType* m_VirtualAreaProtoTypeArray;
|
||||
size_t m_VirtualAreaProtoTypeNum;
|
||||
|
||||
const VirtualArea::MapTypeMatching m_MapTypeMatching;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// BattleGround Server 변수
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Duel 변수
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Dungeon 변수
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _VIRTUAL_AREA_MANAGER_H_
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "stdafx.h"
|
||||
#include "VirtualAreaStructure.h"
|
||||
|
||||
|
||||
VirtualArea::MapTypeMatching::MapTypeMatching()
|
||||
{
|
||||
m_matchMap.clear();
|
||||
m_matchMap.insert(make_pair("BG_FRAG", VirtualArea::FRAG));
|
||||
m_matchMap.insert(make_pair("BG_STATUE", VirtualArea::STATUE));
|
||||
m_matchMap.insert(make_pair("DUEL_FRAG", VirtualArea::FRAG));
|
||||
m_matchMap.insert(make_pair("DUEL_STATUE", VirtualArea::STATUE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
VirtualArea::MapInfo::MapInfo()
|
||||
: m_cMapType(0), m_cMaxCharNumOfNation(0), m_cRemainPlayMin(0),
|
||||
m_cRemainRestMin(0), m_wTargetScore(0), m_cLimitMin(0), m_cRestMin(0)
|
||||
{
|
||||
std::fill_n(m_cCurrentCharNum, int(CClass::MAX_RACE), 0);
|
||||
std::fill_n(m_wScore, int(CClass::MAX_RACE), 0);
|
||||
|
||||
m_PersonalInfoMap.clear();
|
||||
}
|
||||
|
||||
VirtualArea::MapInfo::MapInfo(unsigned char cMapType)
|
||||
: m_cMapType(cMapType), m_cMaxCharNumOfNation(DefaultMaxCharacterNumOfNation[cMapType]),
|
||||
m_cRemainPlayMin(DefaultLimitMin[cMapType]), m_cRemainRestMin(DefaultRestMin[cMapType]),
|
||||
m_wTargetScore(DefaultTargetScore[cMapType]),
|
||||
m_cLimitMin(DefaultLimitMin[cMapType]), m_cRestMin(DefaultRestMin[cMapType])
|
||||
{
|
||||
std::fill_n(m_cCurrentCharNum, int(CClass::MAX_RACE), 0);
|
||||
std::fill_n(m_wScore, int(CClass::MAX_RACE), 0);
|
||||
|
||||
m_PersonalInfoMap.clear();
|
||||
}
|
||||
|
||||
void VirtualArea::MapInfo::Initialize()
|
||||
{
|
||||
m_cRemainPlayMin = m_cLimitMin;
|
||||
m_cRemainRestMin = m_cRestMin;
|
||||
|
||||
std::fill_n(m_cCurrentCharNum, int(CClass::MAX_RACE), 0);
|
||||
std::fill_n(m_wScore, int(CClass::MAX_RACE), 0);
|
||||
|
||||
m_PersonalInfoMap.clear();
|
||||
}
|
||||
|
||||
|
||||
VirtualArea::ResultInfo::ResultInfo()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void VirtualArea::ResultInfo::Initialize()
|
||||
{
|
||||
m_cWinRace = CClass::MAX_RACE;
|
||||
std::fill_n(m_wScore, int(CClass::MAX_RACE), 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#ifndef __VIRTUAL_AREA_STRUCTURE_H__
|
||||
#define __VIRTUAL_AREA_STRUCTURE_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <Map/FieldMap/VirtualArea/VirtualAreaConstants.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
// VirtualArea Info
|
||||
struct ProtoType
|
||||
{
|
||||
unsigned long m_dwVID;
|
||||
unsigned char m_cMapType;
|
||||
unsigned char m_cZone;
|
||||
unsigned short m_wStartX;
|
||||
unsigned short m_wStartZ;
|
||||
unsigned short m_wWidth;
|
||||
unsigned short m_wHeight;
|
||||
unsigned char m_cMaxRespawnPos;
|
||||
char m_szArrangementFileName[MAX_FILE_NAME];
|
||||
char m_szMapType[MAX_MAP_TYPE_NAME];
|
||||
Position m_StartPos[CClass::MAX_RACE];
|
||||
Position m_RespawnPos[CClass::MAX_RACE][MAX_VIRTUAL_AREA_RESPAWN_POINT];
|
||||
|
||||
inline bool operator < (ProtoType& rhs)
|
||||
{ return m_dwVID < rhs.m_dwVID; }
|
||||
};
|
||||
|
||||
// 스크립트의 szMapType 과 cMapType 을 매칭시켜주기 위함
|
||||
// BGServerMap 을 스크립트화 하지 않고, 하드코딩을 하기 때문에 매칭이 필요하다.
|
||||
struct MapTypeMatching
|
||||
{
|
||||
std::map<std::string, unsigned char> m_matchMap;
|
||||
|
||||
MapTypeMatching();
|
||||
};
|
||||
|
||||
|
||||
// 방 정보
|
||||
struct MapInfo
|
||||
{
|
||||
struct PersonalInfo
|
||||
{
|
||||
unsigned char m_cEnteringMin; // 들어온 시점의 남은 경기 시간
|
||||
unsigned char m_cKill; // 내가 죽인 유저 수
|
||||
unsigned char m_cKilled; // 내가 죽은 수
|
||||
|
||||
PersonalInfo(unsigned char cEnteringMin) : m_cEnteringMin(cEnteringMin), m_cKill(0), m_cKilled(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// 배틀 그라운드 하나의 방(가상 맵)이 가져야 하는 변수
|
||||
unsigned char m_cMapType;
|
||||
unsigned char m_cMaxCharNumOfNation; // 한 진영 최대 인원
|
||||
unsigned char m_cRemainPlayMin; // 남은 경기 시간 (분 단위)
|
||||
unsigned char m_cRemainRestMin; // 남은 쉬는 시간 (분 단위)
|
||||
unsigned short m_wTargetScore;
|
||||
unsigned char m_cCurrentCharNum[CClass::MAX_RACE];
|
||||
unsigned short m_wScore[CClass::MAX_RACE];
|
||||
unsigned char m_cLimitMin; // 시간 제한 (분 단위)
|
||||
unsigned char m_cRestMin; // 쉬는 시간 (분 단위)
|
||||
|
||||
// 게임에 들어온 캐릭터의 개인 정보
|
||||
typedef std::map<unsigned long, PersonalInfo> PersonalInfoMap;
|
||||
PersonalInfoMap m_PersonalInfoMap;
|
||||
|
||||
MapInfo();
|
||||
MapInfo(unsigned char cMapType);
|
||||
|
||||
void Initialize();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 방의 결과 정보
|
||||
struct ResultInfo
|
||||
{
|
||||
unsigned short m_wScore[CClass::MAX_RACE];
|
||||
unsigned char m_cWinRace;
|
||||
|
||||
ResultInfo();
|
||||
|
||||
void Initialize();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __VIRTUAL_AREA_STRUCTURE_H__
|
||||
@@ -0,0 +1,873 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Creature/Character/Character.h>
|
||||
#include <Creature/Monster/PatternMonster.h>
|
||||
#include <Creature/Monster/VirtualMonsterMgr.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/SendCharBGServer.h>
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharEtc.h>
|
||||
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
#include <Network/Packet/PacketStruct/BGServerPacket.h>
|
||||
|
||||
#include "BGServerMap.h"
|
||||
|
||||
using namespace VirtualArea;
|
||||
|
||||
CBGServerMap::CBGServerMap(const VirtualArea::ProtoType* lpProtoType, unsigned short wMapNumber)
|
||||
: CVirtualArea(lpProtoType, VirtualArea::BGSERVERMAP | wMapNumber), m_MapInfo(lpProtoType->m_cMapType), m_cStatus(START_WAITING)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CBGServerMap::~CBGServerMap(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned short CBGServerMap::Enter(CCharacter* lpCharacter, unsigned char cMoveType)
|
||||
{
|
||||
if (false == IsPlaying())
|
||||
{
|
||||
return PktBase::SERVER_ERROR;
|
||||
}
|
||||
|
||||
switch (cMoveType)
|
||||
{
|
||||
case TYPE_PLAYER:
|
||||
{
|
||||
return AddCharacter(lpCharacter);
|
||||
}
|
||||
|
||||
case TYPE_SPECTATOR:
|
||||
{
|
||||
return AddSpectator(lpCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
return PktBase::SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMap::Leave(CCharacter* lpCharacter)
|
||||
{
|
||||
if (NULL == lpCharacter) return false;
|
||||
|
||||
char szNation[8];
|
||||
if (lpCharacter->GetRace() == CClass::HUMAN) strcpy(szNation, "HUMAN");
|
||||
else strcpy(szNation, "AKHAN");
|
||||
|
||||
CharacterList::iterator pos = std::find(m_CharacterList.begin(), m_CharacterList.end(), lpCharacter);
|
||||
if (pos != m_CharacterList.end())
|
||||
{
|
||||
--m_MapInfo.m_cCurrentCharNum[ lpCharacter->GetRace() ];
|
||||
m_CharacterList.erase(pos);
|
||||
|
||||
m_MapInfo.m_PersonalInfoMap.erase( lpCharacter->GetCID() );
|
||||
|
||||
// 로그
|
||||
DETLOG5(g_Log, "Battle Server Log :: (Channel : %d, %s) - CID : 0x%08x 캐릭터(%s, %s)가 게임에서 나가셨습니다.",
|
||||
(m_wMapIndex & ~VirtualArea::BGSERVERMAP), GetMapTypeName(),
|
||||
lpCharacter->GetCID(), lpCharacter->GetCharacterName(), szNation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pos = std::find(m_SpectatorList.begin(), m_SpectatorList.end(), lpCharacter);
|
||||
if (pos != m_SpectatorList.end())
|
||||
{
|
||||
m_SpectatorList.erase(pos);
|
||||
|
||||
// 로그
|
||||
DETLOG5(g_Log, "Battle Server Log :: (Channel : %d, %s) - CID : 0x%08x 캐릭터(%s, %s)가 게임에서 나가셨습니다.",
|
||||
(m_wMapIndex & ~VirtualArea::BGSERVERMAP), GetMapTypeName(),
|
||||
lpCharacter->GetCID(), lpCharacter->GetCharacterName(), szNation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
unsigned short CBGServerMap::AddCharacter(CCharacter* lpCharacter)
|
||||
{
|
||||
if (NULL == lpCharacter)
|
||||
{
|
||||
return PktBase::SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (m_MapInfo.m_cMaxCharNumOfNation <= m_MapInfo.m_cCurrentCharNum[ lpCharacter->GetRace() ])
|
||||
{
|
||||
return PktBGServerMoveZone::FAIL_FULL_MAP;
|
||||
}
|
||||
|
||||
// 진입 인원 제한 걸기
|
||||
if (m_MapInfo.m_cCurrentCharNum[ lpCharacter->GetRace() ] >= 10)
|
||||
{
|
||||
if ( (lpCharacter->GetRace() == CClass::HUMAN && m_MapInfo.m_cCurrentCharNum[CClass::HUMAN] >= m_MapInfo.m_cCurrentCharNum[CClass::AKHAN] * 1.5) ||
|
||||
(lpCharacter->GetRace() == CClass::AKHAN && m_MapInfo.m_cCurrentCharNum[CClass::AKHAN] >= m_MapInfo.m_cCurrentCharNum[CClass::HUMAN] * 1.5) )
|
||||
{
|
||||
return PktBGServerMoveZone::FAIL_FIX_RATE;
|
||||
}
|
||||
}
|
||||
|
||||
++m_MapInfo.m_cCurrentCharNum[ lpCharacter->GetRace() ];
|
||||
m_CharacterList.push_back(lpCharacter);
|
||||
|
||||
// 들어왔을때 남은 경기시간을 저장해둔다. (남은 경기시간에 따른 차등 점수를 주기위해서...)
|
||||
MapInfo::PersonalInfo personalInfo(m_MapInfo.m_cRemainPlayMin);
|
||||
m_MapInfo.m_PersonalInfoMap.insert( make_pair(lpCharacter->GetCID(), personalInfo) );
|
||||
|
||||
// 로그 남기기
|
||||
char szNation[8];
|
||||
if (lpCharacter->GetRace() == CClass::HUMAN)
|
||||
{
|
||||
strcpy(szNation, "HUMAN");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(szNation, "AKHAN");
|
||||
}
|
||||
|
||||
DETLOG5(g_Log, "Battle Server Log :: (Channel : %d, %s) - CID : 0x%08x 캐릭터(%s, %s)가 Player 로 들어왔습니다.",
|
||||
(m_wMapIndex & ~VirtualArea::BGSERVERMAP), GetMapTypeName(),
|
||||
lpCharacter->GetCID(), lpCharacter->GetCharacterName(), szNation);
|
||||
|
||||
return PktBase::NO_SERVER_ERR;
|
||||
}
|
||||
|
||||
|
||||
unsigned short CBGServerMap::AddSpectator(CCharacter* lpSpectator)
|
||||
{
|
||||
if (NULL == lpSpectator)
|
||||
{
|
||||
return PktBase::SERVER_ERROR;
|
||||
}
|
||||
|
||||
m_SpectatorList.push_back(lpSpectator);
|
||||
|
||||
// 로그 남기기
|
||||
char szNation[8];
|
||||
if (lpSpectator->GetRace() == CClass::HUMAN) strcpy(szNation, "HUMAN");
|
||||
else strcpy(szNation, "AKHAN");
|
||||
|
||||
DETLOG5(g_Log, "Battle Server Log :: (Channel : %d, %s) - CID : 0x%08x 캐릭터(%s, %s)가 Spectator 로 들어왔습니다.",
|
||||
(m_wMapIndex & ~VirtualArea::BGSERVERMAP), GetMapTypeName(),
|
||||
lpSpectator->GetCID(), lpSpectator->GetCharacterName(), szNation);
|
||||
|
||||
return PktBase::NO_SERVER_ERR;
|
||||
}
|
||||
|
||||
bool CBGServerMap::IsPlayer(CCharacter* lpCharacter)
|
||||
{
|
||||
if (NULL == lpCharacter) return false;
|
||||
|
||||
CharacterList::iterator pos = std::find(m_CharacterList.begin(), m_CharacterList.end(), lpCharacter);
|
||||
if (pos != m_CharacterList.end()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBGServerMap::IsSpectator(CCharacter* lpCharacter)
|
||||
{
|
||||
if (NULL == lpCharacter) return false;
|
||||
|
||||
CharacterList::iterator pos = std::find(m_SpectatorList.begin(), m_SpectatorList.end(), lpCharacter);
|
||||
if (pos != m_SpectatorList.end()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 모두 대기실로 이동
|
||||
bool CBGServerMap::AllRespawn()
|
||||
{
|
||||
if (0 == m_CharacterList.size() && 0 == m_SpectatorList.size()) return true;
|
||||
|
||||
bool bResult = true;
|
||||
CharacterList::iterator pos = m_CharacterList.begin();
|
||||
CharacterList::iterator end = m_CharacterList.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL == (*pos)) continue;
|
||||
|
||||
CGameClientDispatch* lpDispatch = (*pos)->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
if (false == GameClientSendPacket::SendCharBGServerMoveZone(lpDispatch->GetSendStream(), SERVER_ID::BATTLE_SERVER, VirtualArea::TYPE_PLAYER, PktBase::NO_SERVER_ERR))
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 캐릭터가 가상 존(MapIndex : %d)에서 나가는데 실패하였습니다.", (*pos)->GetCID(), (*pos)->GetMapIndex());
|
||||
bResult = false;
|
||||
}
|
||||
|
||||
Position RespawnPos(VirtualArea::RespawnPos[ (*pos)->GetRace() ][ Math::Random::ComplexRandom(VirtualArea::MAX_LOBBY_RESPAWN_POS) ]);
|
||||
RespawnPos.m_fPointX += Math::Random::SimpleRandom(GetTickCount(), 20) - 10;
|
||||
RespawnPos.m_fPointZ += Math::Random::SimpleRandom(GetTickCount(), 20) - 10;
|
||||
|
||||
(*pos)->SetMapIndex(0);
|
||||
(*pos)->GetEnchantInfo().ResetFlag(Skill::SpellID::Hide);
|
||||
(*pos)->MoveTo(RespawnPos, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 캐릭터가 가상 존(MapIndex : %d)에서 나가는데 실패하였습니다.", (*pos)->GetCID(), (*pos)->GetMapIndex());
|
||||
bResult = false;
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
// 스펙테이터 처리
|
||||
pos = m_SpectatorList.begin();
|
||||
end = m_SpectatorList.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL == (*pos)) continue;
|
||||
|
||||
CGameClientDispatch* lpDispatch = (*pos)->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
if (false == GameClientSendPacket::SendCharBGServerMoveZone(lpDispatch->GetSendStream(), SERVER_ID::BATTLE_SERVER, VirtualArea::TYPE_PLAYER, PktBase::NO_SERVER_ERR))
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 캐릭터가 가상 존(MapIndex : %d)에서 나가는데 실패하였습니다.", (*pos)->GetCID(), (*pos)->GetMapIndex());
|
||||
bResult = false;
|
||||
}
|
||||
|
||||
Position RespawnPos(VirtualArea::RespawnPos[ (*pos)->GetRace() ][ Math::Random::ComplexRandom(VirtualArea::MAX_LOBBY_RESPAWN_POS) ]);
|
||||
RespawnPos.m_fPointX += Math::Random::SimpleRandom(GetTickCount(), 20) - 10;
|
||||
RespawnPos.m_fPointZ += Math::Random::SimpleRandom(GetTickCount(), 20) - 10;
|
||||
|
||||
(*pos)->SetMapIndex(0);
|
||||
(*pos)->GetEnchantInfo().ResetFlag(Skill::SpellID::Hide);
|
||||
(*pos)->MoveTo(RespawnPos, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 캐릭터가 가상 존(MapIndex : %d)에서 나가는데 실패하였습니다.", (*pos)->GetCID(), (*pos)->GetMapIndex());
|
||||
bResult = false;
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
// 리스트 클리어
|
||||
m_CharacterList.clear();
|
||||
m_SpectatorList.clear();
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CBGServerMap::Process()
|
||||
{
|
||||
unsigned long dwCurrentTime = timeGetTime();
|
||||
int nMin = 0, nSec = 0;
|
||||
|
||||
if (m_dwRemainTime < dwCurrentTime) nMin = 0;
|
||||
else
|
||||
{
|
||||
nMin = (m_dwRemainTime - dwCurrentTime) / MILLISEC_PER_MINUTE;
|
||||
nSec = (m_dwRemainTime - dwCurrentTime) % MILLISEC_PER_MINUTE;
|
||||
if (nSec > 0) ++nMin;
|
||||
}
|
||||
|
||||
switch (m_cStatus)
|
||||
{
|
||||
// 아직 Start 되지 않은 상태라면 아무것도 하지 않는다.
|
||||
case START_WAITING: return;
|
||||
|
||||
case GAME_PLAYING:
|
||||
{
|
||||
// 1분에 한번씩 남은 시간을 보내준다.
|
||||
if (nMin < m_MapInfo.m_cRemainPlayMin)
|
||||
{
|
||||
// 남은 시간 갱신
|
||||
m_MapInfo.m_cRemainPlayMin = static_cast<unsigned char>(nMin);
|
||||
|
||||
// 방 정보 전송
|
||||
SendMapInfo();
|
||||
}
|
||||
|
||||
// 제한 시간이 다 되었다면,
|
||||
if (0 == m_MapInfo.m_cRemainPlayMin)
|
||||
{
|
||||
// 승패를 체크 및 결과 저장
|
||||
m_ResultInfo.m_cWinRace = RuleCheck(true);
|
||||
std::copy(&m_MapInfo.m_wScore[0], &m_MapInfo.m_wScore[CClass::MAX_RACE], &m_ResultInfo.m_wScore[0]);
|
||||
|
||||
// 결과 전송
|
||||
// 이긴 종족, 혹은 무승부 캐릭터들에게 보상을 준다.
|
||||
SendResultInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ResultInfo.m_cWinRace = RuleCheck();
|
||||
|
||||
// 한 종족이 목표 점수를 달성했을 경우
|
||||
if (CClass::MAX_RACE != m_ResultInfo.m_cWinRace)
|
||||
{
|
||||
// 결과 점수 저장
|
||||
std::copy(&m_MapInfo.m_wScore[0], &m_MapInfo.m_wScore[CClass::MAX_RACE], &m_ResultInfo.m_wScore[0]);
|
||||
|
||||
// 결과 전송
|
||||
// 이긴 종족의 캐릭터들에게 보상을 준다.
|
||||
SendResultInfo();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GAME_RESTING:
|
||||
{
|
||||
// 남은 시간 갱신
|
||||
m_MapInfo.m_cRemainRestMin = static_cast<unsigned char>(nMin);
|
||||
|
||||
// 쉬는 시간이 다 되었다면,
|
||||
if (0 == m_MapInfo.m_cRemainRestMin)
|
||||
{
|
||||
GameStart();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MOVEZONE_WAITING:
|
||||
{
|
||||
// 존이동 시킬 시간이 다 되었다면,
|
||||
if (m_dwRemainTime <= timeGetTime())
|
||||
{
|
||||
SetStatus(GAME_RESTING);
|
||||
m_dwRemainTime = timeGetTime() + m_MapInfo.m_cRestMin * MILLISEC_PER_MINUTE;
|
||||
|
||||
// 캐릭터들을 존 이동 시킨다. (로비로 리스폰)
|
||||
AllRespawn();
|
||||
|
||||
// Item을 모두 지운다.
|
||||
DeleteAllItem();
|
||||
|
||||
// 방 정보 초기화
|
||||
m_MapInfo.Initialize();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMap::GameStart() // 게임을 시작한다.
|
||||
{
|
||||
m_dwRemainTime = timeGetTime() + m_MapInfo.m_cLimitMin * MILLISEC_PER_MINUTE;
|
||||
InitializeGameObject();
|
||||
|
||||
SetStatus(GAME_PLAYING);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMap::InitializeGameObject()
|
||||
{
|
||||
m_CharacterList.clear();
|
||||
m_SpectatorList.clear();
|
||||
|
||||
m_MapInfo.Initialize();
|
||||
m_ResultInfo.Initialize();
|
||||
|
||||
if (STATUE == m_MapInfo.m_cMapType && NULL != GetMonsterManager())
|
||||
{
|
||||
// 모든 석상을 다 죽이고, 아무것도 소환하지 않는다.
|
||||
CVirtualMonsterMgr::MonsterMap::iterator pos = m_pVirtualMonsterMgr->GetMonsterMap().begin();
|
||||
CVirtualMonsterMgr::MonsterMap::iterator end = m_pVirtualMonsterMgr->GetMonsterMap().end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
CMonster* lpMonster = pos->second;
|
||||
if (NULL == lpMonster) continue;
|
||||
|
||||
CStatue* lpStatue = lpMonster->DowncastToStatue();
|
||||
if (NULL != lpStatue)
|
||||
{
|
||||
lpStatue->Rest();
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
|
||||
// 휴먼, 중립, 아칸 석상을 순서대로 소환한다.
|
||||
enum { HUMAN_STATUE = 0, NUETRALITY_STATUE1 = 1, AKHAN_STATUE = 2, NUETRALITY_STATUE2 = 3, NUETRALITY_STATUE3 = 4, NONE = 100 };
|
||||
DWORD dwKind, dwOldKind = NONE;
|
||||
|
||||
pos = m_pVirtualMonsterMgr->GetMonsterMap().begin();
|
||||
end = m_pVirtualMonsterMgr->GetMonsterMap().end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
CMonster* lpMonster = pos->second;
|
||||
if (NULL == lpMonster) continue;
|
||||
|
||||
CStatue* lpStatue = lpMonster->DowncastToStatue();
|
||||
if (NULL != lpStatue)
|
||||
{
|
||||
// 석상 초기화 시키기
|
||||
// !!주의!! 스크립트와 관련이 있다. 순서주의
|
||||
// 종류를 얻어온다. (HUMAN_STATUE = 0, NUETRALITY_STATUE1 = 1, AKHAN_STATUE = 2, NUETRALITY_STATUE2 = 3, NUETRALITY_STATUE3 = 4)
|
||||
dwKind = (lpStatue->GetCID() & ~(Creature::MONSTER_BIT | Creature::MONSTER_KIND_BIT)) >> 16;
|
||||
if (dwOldKind != dwKind)
|
||||
{
|
||||
switch (dwKind)
|
||||
{
|
||||
case HUMAN_STATUE:
|
||||
lpStatue = lpStatue->GetLinkStatue(MonsterInfo::BG_STATUE_HUMAN_COMPLETE1);
|
||||
lpStatue->InitMonster(lpStatue->GetOriginalPos());
|
||||
break;
|
||||
|
||||
case NUETRALITY_STATUE1:
|
||||
case NUETRALITY_STATUE2:
|
||||
case NUETRALITY_STATUE3:
|
||||
lpStatue = lpStatue->GetLinkStatue(MonsterInfo::BG_STATUE_NEUTRALITY1);
|
||||
lpStatue->InitMonster(lpStatue->GetOriginalPos());
|
||||
break;
|
||||
|
||||
case AKHAN_STATUE:
|
||||
lpStatue = lpStatue->GetLinkStatue(MonsterInfo::BG_STATUE_AKHAN_COMPLETE1);
|
||||
lpStatue->InitMonster(lpStatue->GetOriginalPos());
|
||||
break;
|
||||
}
|
||||
|
||||
dwOldKind = dwKind;
|
||||
}
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
// 석상 점령전일때의 초기 점수 계산
|
||||
CalculateScore();
|
||||
|
||||
// 로그 남기기
|
||||
DETLOG4(g_Log, "Battle Server Log :: (Channel : %d, %s) - 석상전을 초기화 합니다. (현재 Score - HM: %d AK: %d)",
|
||||
(m_wMapIndex & ~VirtualArea::BGSERVERMAP), GetMapTypeName(),
|
||||
m_MapInfo.m_wScore[CClass::HUMAN], m_MapInfo.m_wScore[CClass::AKHAN]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char CBGServerMap::RuleCheck(bool bTimeout) // 룰을 체크해서 이긴종족을 리턴
|
||||
{
|
||||
unsigned char cWinNation = CClass::MAX_RACE;
|
||||
|
||||
// 시간이 다 지났다면, 혹은 운영자 명령으로 게임을 중지 시킬경우
|
||||
if (true == bTimeout)
|
||||
{
|
||||
if (m_MapInfo.m_wScore[CClass::HUMAN] > m_MapInfo.m_wScore[CClass::AKHAN])
|
||||
{
|
||||
cWinNation = CClass::HUMAN;
|
||||
}
|
||||
else if (m_MapInfo.m_wScore[CClass::HUMAN] < m_MapInfo.m_wScore[CClass::AKHAN])
|
||||
{
|
||||
cWinNation = CClass::AKHAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 이경우의 CClass::MAX_RACE 은 무승부이다.
|
||||
}
|
||||
|
||||
SetStatus(MOVEZONE_WAITING);
|
||||
m_dwRemainTime = timeGetTime() + MOVEZONE_WAIT_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 목표 점수에 도달했는가 체크
|
||||
if (m_MapInfo.m_wScore[CClass::HUMAN] >= m_MapInfo.m_wTargetScore)
|
||||
{
|
||||
cWinNation = CClass::HUMAN;
|
||||
|
||||
SetStatus(MOVEZONE_WAITING);
|
||||
m_dwRemainTime = timeGetTime() + MOVEZONE_WAIT_TIME;
|
||||
}
|
||||
else if (m_MapInfo.m_wScore[CClass::AKHAN] >= m_MapInfo.m_wTargetScore)
|
||||
{
|
||||
cWinNation = CClass::AKHAN;
|
||||
|
||||
SetStatus(MOVEZONE_WAITING);
|
||||
m_dwRemainTime = timeGetTime() + MOVEZONE_WAIT_TIME;
|
||||
}
|
||||
|
||||
// 이경우의 CClass::MAX_RACE 은 게임이 끝나지 않은 상태이다.
|
||||
}
|
||||
|
||||
return cWinNation;
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMap::AwardToWinner()
|
||||
{
|
||||
unsigned short wAwardBase, wRealPlayMin;
|
||||
unsigned short wPlayMin = m_MapInfo.m_cLimitMin - m_MapInfo.m_cRemainPlayMin;
|
||||
if (0 == wPlayMin) wPlayMin = 1;
|
||||
|
||||
CharacterList winnerList;
|
||||
CharacterList::iterator pos;
|
||||
CharacterList::iterator end;
|
||||
|
||||
if (CClass::MAX_RACE == m_ResultInfo.m_cWinRace)
|
||||
{
|
||||
wAwardBase = m_MapInfo.m_cLimitMin * MILEAGE_PER_MINUTE_FOR_DRAW;
|
||||
|
||||
pos = m_CharacterList.begin();
|
||||
end = m_CharacterList.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
wAwardBase = m_MapInfo.m_cLimitMin * MILEAGE_PER_MINUTE_FOR_WIN;
|
||||
|
||||
FindWinner(winnerList);
|
||||
pos = winnerList.begin();
|
||||
end = winnerList.end();
|
||||
}
|
||||
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
MapInfo::PersonalInfoMap::iterator which = m_MapInfo.m_PersonalInfoMap.find( (*pos)->GetCID() );
|
||||
if (which != m_MapInfo.m_PersonalInfoMap.end())
|
||||
{
|
||||
wRealPlayMin = which->second.m_cEnteringMin - m_MapInfo.m_cRemainPlayMin;
|
||||
unsigned short wAward = wAwardBase * wRealPlayMin / wPlayMin;
|
||||
|
||||
(*pos)->SetMileage((*pos)->GetMileage() + wAward);
|
||||
|
||||
CGameClientDispatch* lpDispatch = (*pos)->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
GameClientSendPacket::SendCharFameInfo(lpDispatch->GetSendStream(), (*pos),
|
||||
"", "", 0, 0, PktFIAck::FAME_INFO, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMap::KillChar(unsigned long dwDeadCID, CCharacter* lpOffencer)
|
||||
{
|
||||
if (NULL == lpOffencer) return;
|
||||
|
||||
AddScore(lpOffencer->GetRace(), FRAG_SCORE);
|
||||
|
||||
// Kill 정보 업데이트
|
||||
UpdateKillInfo(dwDeadCID, lpOffencer->GetCID());
|
||||
|
||||
// 방 정보 전송
|
||||
SendMapInfo();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CBGServerMap::UpdateKillInfo(unsigned long dwDeadCID, unsigned long dwKillerCID)
|
||||
{
|
||||
MapInfo::PersonalInfoMap::iterator pos = m_MapInfo.m_PersonalInfoMap.find( dwDeadCID );
|
||||
if (pos != m_MapInfo.m_PersonalInfoMap.end()) ++pos->second.m_cKilled;
|
||||
|
||||
pos = m_MapInfo.m_PersonalInfoMap.find( dwKillerCID );
|
||||
if (pos != m_MapInfo.m_PersonalInfoMap.end()) ++pos->second.m_cKill;
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMap::AddScore(unsigned char cNation, short wScore)
|
||||
{
|
||||
if (cNation >= CClass::MAX_CLASS) return;
|
||||
m_MapInfo.m_wScore[cNation] += wScore;
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMap::CalculateScore() // 석상 점령전일때 점수 계산
|
||||
{
|
||||
if (STATUE == m_MapInfo.m_cMapType && NULL != GetMonsterManager())
|
||||
{
|
||||
std::fill_n(m_MapInfo.m_wScore, int(CClass::MAX_RACE), 0);
|
||||
|
||||
CVirtualMonsterMgr::MonsterMap::iterator pos = m_pVirtualMonsterMgr->GetMonsterMap().begin();
|
||||
CVirtualMonsterMgr::MonsterMap::iterator end = m_pVirtualMonsterMgr->GetMonsterMap().end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
CMonster* lpMonster = pos->second;
|
||||
if (NULL != lpMonster && lpMonster->GetCurrentState() != STATE_ID_DIE)
|
||||
{
|
||||
switch (lpMonster->GetCID() & Creature::MONSTER_KIND_BIT)
|
||||
{
|
||||
case MonsterInfo::BG_STATUE_HUMAN_LOADING1:
|
||||
{
|
||||
AddScore(CClass::HUMAN, FRIENDLY_LOADING_STATUE_SCORE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MonsterInfo::BG_STATUE_HUMAN_COMPLETE1:
|
||||
{
|
||||
AddScore(CClass::HUMAN, FRIENDLY_STATUE_SCORE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MonsterInfo::BG_STATUE_AKHAN_LOADING1:
|
||||
{
|
||||
AddScore(CClass::AKHAN, FRIENDLY_LOADING_STATUE_SCORE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MonsterInfo::BG_STATUE_AKHAN_COMPLETE1:
|
||||
{
|
||||
AddScore(CClass::AKHAN, FRIENDLY_STATUE_SCORE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MonsterInfo::BG_STATUE_NEUTRALITY1:
|
||||
{
|
||||
AddScore(CClass::AKHAN, NEUTRALITY_STATUE_SCORE);
|
||||
AddScore(CClass::HUMAN, NEUTRALITY_STATUE_SCORE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 자기 방의 정보를 보내주는 함수
|
||||
bool CBGServerMap::SendMapInfo()
|
||||
{
|
||||
if (0 == m_CharacterList.size() && 0 == m_SpectatorList.size()) return true;
|
||||
|
||||
const int MAX_BUFFER = sizeof(PktBGServerMapList) + sizeof(BGServerMapInfoNode);
|
||||
char szBuffer[MAX_BUFFER];
|
||||
|
||||
PktBGServerMapList* lpPktBGSMLAck = reinterpret_cast<PktBGServerMapList *>(szBuffer);
|
||||
BGServerMapInfoNode* lpMapInfoNode = reinterpret_cast<BGServerMapInfoNode *>(lpPktBGSMLAck + 1);
|
||||
|
||||
lpPktBGSMLAck->m_bAll = false;
|
||||
lpPktBGSMLAck->m_cMapInfoNodeNum = 1;
|
||||
|
||||
lpMapInfoNode->m_bPlaying = IsPlaying();
|
||||
lpMapInfoNode->m_cMapType = m_MapInfo.m_cMapType;
|
||||
lpMapInfoNode->m_cMaxCharNumOfNation = m_MapInfo.m_cMaxCharNumOfNation;
|
||||
lpMapInfoNode->m_wTargetScore = m_MapInfo.m_wTargetScore;
|
||||
//lpMapInfoNode->m_cRemainMin = (IsPlaying() == true) ? m_MapInfo.m_cRemainPlayMin : m_MapInfo.m_cRemainRestMin;
|
||||
lpMapInfoNode->m_cRemainMin = (IsPlaying() == true) ? m_MapInfo.m_cRemainPlayMin : 0;
|
||||
|
||||
lpMapInfoNode->m_cCurrentCharNum[CClass::HUMAN] = m_MapInfo.m_cCurrentCharNum[CClass::HUMAN];
|
||||
lpMapInfoNode->m_cCurrentCharNum[CClass::AKHAN] = m_MapInfo.m_cCurrentCharNum[CClass::AKHAN];
|
||||
lpMapInfoNode->m_wScore[CClass::HUMAN] = m_MapInfo.m_wScore[CClass::HUMAN];
|
||||
lpMapInfoNode->m_wScore[CClass::AKHAN] = m_MapInfo.m_wScore[CClass::AKHAN];
|
||||
|
||||
// 캐릭터 처리
|
||||
CharacterList::iterator pos = m_CharacterList.begin();
|
||||
CharacterList::iterator end = m_CharacterList.end();
|
||||
CGameClientDispatch* lpDispatch = NULL;
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL == (*pos)) continue;
|
||||
lpDispatch = (*pos)->GetDispatcher();
|
||||
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
CSendStream& SendStream = lpDispatch->GetSendStream();
|
||||
SendStream.WrapCompress(szBuffer, sizeof(PktBGServerMapList) + sizeof(BGServerMapInfoNode), CmdBGServerMapList, 0, 0);
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
// 스펙테이터 처리
|
||||
pos = m_SpectatorList.begin();
|
||||
end = m_SpectatorList.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL == (*pos)) continue;
|
||||
lpDispatch = (*pos)->GetDispatcher();
|
||||
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
CSendStream& SendStream = lpDispatch->GetSendStream();
|
||||
SendStream.WrapCompress(szBuffer, sizeof(PktBGServerMapList) + sizeof(BGServerMapInfoNode), CmdBGServerMapList, 0, 0);
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMap::SendResultInfo()
|
||||
{
|
||||
const int MAX_BUFFER = sizeof(PktBGServerResultList) + sizeof(BGServerResultInfoNode);
|
||||
char szBuffer[MAX_BUFFER];
|
||||
|
||||
PktBGServerResultList* lpPktBGSRLAck = reinterpret_cast<PktBGServerResultList *>(szBuffer);
|
||||
BGServerResultInfoNode* lpResultInfoNode = reinterpret_cast<BGServerResultInfoNode *>(lpPktBGSRLAck + 1);
|
||||
|
||||
lpPktBGSRLAck->m_bAll = false;
|
||||
lpPktBGSRLAck->m_cResultInfoNodeNum = 1;
|
||||
|
||||
lpResultInfoNode->m_cWinRace = m_ResultInfo.m_cWinRace;
|
||||
lpResultInfoNode->m_wScore[CClass::HUMAN] = m_ResultInfo.m_wScore[CClass::HUMAN];
|
||||
lpResultInfoNode->m_wScore[CClass::AKHAN] = m_ResultInfo.m_wScore[CClass::AKHAN];
|
||||
|
||||
// 캐릭터(플레이어) 처리
|
||||
CharacterList::iterator pos = m_CharacterList.begin();
|
||||
CharacterList::iterator end = m_CharacterList.end();
|
||||
CGameClientDispatch* lpDispatch = NULL;
|
||||
|
||||
unsigned short wAwardBase;
|
||||
if (CClass::MAX_RACE == m_ResultInfo.m_cWinRace) wAwardBase = m_MapInfo.m_cLimitMin * MILEAGE_PER_MINUTE_FOR_DRAW;
|
||||
else wAwardBase = m_MapInfo.m_cLimitMin * MILEAGE_PER_MINUTE_FOR_WIN;
|
||||
|
||||
unsigned short wPlayMin = m_MapInfo.m_cLimitMin - m_MapInfo.m_cRemainPlayMin;
|
||||
if (0 == wPlayMin) wPlayMin = 1;
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL == (*pos)) continue;
|
||||
lpDispatch = (*pos)->GetDispatcher();
|
||||
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
MapInfo::PersonalInfoMap::iterator which = m_MapInfo.m_PersonalInfoMap.find( (*pos)->GetCID() );
|
||||
if (which != m_MapInfo.m_PersonalInfoMap.end())
|
||||
{
|
||||
lpResultInfoNode->m_cPlayMin = which->second.m_cEnteringMin - m_MapInfo.m_cRemainPlayMin;
|
||||
lpResultInfoNode->m_cKill = which->second.m_cKill;
|
||||
lpResultInfoNode->m_cKilled = which->second.m_cKilled;
|
||||
|
||||
RULLOG3(g_Log, "CID:0x%08x 이벤트로그 - %s, Kill : %d, Die : %d",
|
||||
(*pos)->GetCharacterName(), which->second.m_cKill, which->second.m_cKilled);
|
||||
|
||||
// 무승부나 승리팀의 캐릭터인 경우 얻은 마일리지를 보내준다.
|
||||
if (CClass::MAX_RACE == m_ResultInfo.m_cWinRace || (*pos)->GetRace() == m_ResultInfo.m_cWinRace)
|
||||
{
|
||||
unsigned short wAward = wAwardBase * lpResultInfoNode->m_cPlayMin / wPlayMin;
|
||||
lpResultInfoNode->m_wAward = wAward;
|
||||
|
||||
(*pos)->SetMileage((*pos)->GetMileage() + wAward);
|
||||
CGameClientDispatch* lpDispatch = (*pos)->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
GameClientSendPacket::SendCharFameInfo(lpDispatch->GetSendStream(), (*pos),
|
||||
"", "", 0, 0, PktFIAck::FAME_INFO, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
else lpResultInfoNode->m_wAward = 0;
|
||||
|
||||
CSendStream& SendStream = lpDispatch->GetSendStream();
|
||||
SendStream.WrapCompress(szBuffer, sizeof(PktBGServerResultList) + sizeof(BGServerResultInfoNode), CmdBGServerResultList, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
|
||||
// 스펙테이터 처리
|
||||
lpResultInfoNode->m_cPlayMin = 0;
|
||||
lpResultInfoNode->m_wAward = 0;
|
||||
lpResultInfoNode->m_cKill = 0;
|
||||
lpResultInfoNode->m_cKilled = 0;
|
||||
|
||||
pos = m_SpectatorList.begin();
|
||||
end = m_SpectatorList.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL == (*pos)) continue;
|
||||
lpDispatch = (*pos)->GetDispatcher();
|
||||
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
CSendStream& SendStream = lpDispatch->GetSendStream();
|
||||
SendStream.WrapCompress(szBuffer, sizeof(PktBGServerResultList) + sizeof(BGServerResultInfoNode), CmdBGServerResultList, 0, 0);
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CBGServerMap::FindWinner(CharacterList& winnerList)
|
||||
{
|
||||
CharacterList::iterator pos = m_CharacterList.begin();
|
||||
CharacterList::iterator end = m_CharacterList.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
if (m_ResultInfo.m_cWinRace == (*pos)->GetRace())
|
||||
{
|
||||
winnerList.push_back((*pos));
|
||||
}
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMap::DeleteAllItem()
|
||||
{
|
||||
if (NULL == m_CellData)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CCell* lpCellPastEnd = m_CellData + GetWidth() * GetHeight();
|
||||
|
||||
for (CCell* lpCell = m_CellData; lpCell != lpCellPastEnd; ++lpCell)
|
||||
{
|
||||
lpCell->DeleteAllItem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMap::ResetEnteringMin(unsigned char cMin)
|
||||
{
|
||||
if (m_MapInfo.m_PersonalInfoMap.empty()) return;
|
||||
|
||||
MapInfo::PersonalInfoMap::iterator pos = m_MapInfo.m_PersonalInfoMap.begin();
|
||||
MapInfo::PersonalInfoMap::iterator end = m_MapInfo.m_PersonalInfoMap.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
pos->second.m_cEnteringMin = cMin;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#ifndef _BATTLEGROUND_SERVER_MAP_H_
|
||||
#define _BATTLEGROUND_SERVER_MAP_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Map/FieldMap/VirtualArea/VirtualAreaConstants.h>
|
||||
#include <Map/FieldMap/VirtualArea/VirtualAreaStructure.h>
|
||||
#include <Map/FieldMap/VirtualArea/VirtualArea.h>
|
||||
|
||||
class CCharacter;
|
||||
class CMonster;
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
// 전방 참조
|
||||
struct ProtoType;
|
||||
|
||||
class CBGServerMap : public CVirtualArea
|
||||
{
|
||||
public:
|
||||
CBGServerMap(const VirtualArea::ProtoType* lpProtoType, unsigned short wMapNumber);
|
||||
~CBGServerMap(void);
|
||||
|
||||
void Process();
|
||||
unsigned short Enter(CCharacter* lpCharacter, unsigned char cMoveType);
|
||||
bool Leave(CCharacter* lpCharacter);
|
||||
|
||||
bool AllRespawn(); // 모두 대기실로 이동
|
||||
|
||||
// 게임 룰 관련
|
||||
bool GameStart(); // 게임을 시작한다.
|
||||
unsigned char RuleCheck(bool bTimeout = false); // 룰을 체크해서 이긴종족을 리턴
|
||||
void AwardToWinner();
|
||||
void KillChar(unsigned long dwDeadCID, CCharacter* lpOffencer);
|
||||
|
||||
void UpdateKillInfo(unsigned long dwDeadCID, unsigned long dwKillerCID);
|
||||
void AddScore(unsigned char cNation, short wScore);
|
||||
void CalculateScore(); // 석상 점령전일때 점수 계산
|
||||
|
||||
void ResetEnteringMin(unsigned char cMin);
|
||||
|
||||
|
||||
// Get/Set 함수
|
||||
unsigned char GetMapType() { return m_MapInfo.m_cMapType; }
|
||||
MapInfo& GetMapInfo() { return m_MapInfo; }
|
||||
ResultInfo& GetResultInfo() { return m_ResultInfo; }
|
||||
|
||||
unsigned char GetStatus() { return m_cStatus; }
|
||||
void SetStatus(unsigned char cStatus) { m_cStatus = cStatus; }
|
||||
|
||||
void SetRemainTime(unsigned long dwRemainTime) { m_dwRemainTime = dwRemainTime; }
|
||||
|
||||
bool IsPlaying() { return (GAME_PLAYING == m_cStatus); }
|
||||
bool IsResting() { return (GAME_RESTING == m_cStatus); }
|
||||
bool IsPlayer(CCharacter* lpCharacter);
|
||||
bool IsSpectator(CCharacter* lpCharacter);
|
||||
|
||||
|
||||
// 자기 방의 정보를 보내주는 함수
|
||||
bool SendMapInfo();
|
||||
bool SendResultInfo();
|
||||
|
||||
private:
|
||||
|
||||
bool InitializeGameObject();
|
||||
|
||||
void FindWinner(CharacterList& winnerList);
|
||||
|
||||
unsigned short AddCharacter(CCharacter* lpCharacter);
|
||||
unsigned short AddSpectator(CCharacter* lpSpectator);
|
||||
|
||||
// 바닥에 떨어진 Item 모두 지우기
|
||||
void DeleteAllItem();
|
||||
|
||||
// 게임 방 정보
|
||||
MapInfo m_MapInfo;
|
||||
ResultInfo m_ResultInfo;
|
||||
|
||||
unsigned char m_cStatus;
|
||||
unsigned long m_dwRemainTime; // 시간에 관련된 모든 부분에서 남은 시간으로 사용
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _BATTLEGROUND_SERVER_MAP_H_
|
||||
@@ -0,0 +1,487 @@
|
||||
#include "stdafx.h"
|
||||
#include "BGServerMgr.h"
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
#include <Creature/Character/Character.h>
|
||||
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
#include <Network/Packet/PacketStruct/BGServerPacket.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/SendCharBGServer.h>
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/FieldMap/VirtualArea/BGServer/BGServerMap.h>
|
||||
#include <Map/FieldMap/VirtualArea/VirtualAreaMgr.h>
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/Spell/SpellTable.h>
|
||||
#include <Skill/Spell/SpellUtil.h>
|
||||
|
||||
|
||||
using namespace VirtualArea;
|
||||
|
||||
|
||||
|
||||
CBGServerMgr::CBGServerMgr()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CBGServerMgr::~CBGServerMgr()
|
||||
{
|
||||
DestroyBGServerMap();
|
||||
}
|
||||
|
||||
|
||||
CBGServerMgr& CBGServerMgr::GetInstance()
|
||||
{
|
||||
static CBGServerMgr ms_this;
|
||||
return ms_this;
|
||||
}
|
||||
|
||||
bool CBGServerMgr::CreateBGServerMap()
|
||||
{
|
||||
if (m_lstBGServerMap.size() != 0)
|
||||
{
|
||||
DestroyBGServerMap();
|
||||
}
|
||||
|
||||
// Game Room 가상 맵 생성
|
||||
m_lstBGServerMap.push_back( new CBGServerMap( CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType("BG_FRAG"), 1 ) );
|
||||
m_lstBGServerMap.push_back( new CBGServerMap( CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType("BG_FRAG"), 2 ) );
|
||||
m_lstBGServerMap.push_back( new CBGServerMap( CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType("BG_FRAG"), 3 ) );
|
||||
m_lstBGServerMap.push_back( new CBGServerMap( CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType("BG_FRAG"), 4 ) );
|
||||
m_lstBGServerMap.push_back( new CBGServerMap( CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType("BG_FRAG"), 5 ) );
|
||||
m_lstBGServerMap.push_back( new CBGServerMap( CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType("BG_FRAG"), 6 ) );
|
||||
m_lstBGServerMap.push_back( new CBGServerMap( CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType("BG_FRAG"), 7 ) );
|
||||
m_lstBGServerMap.push_back( new CBGServerMap( CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType("BG_STATUE"), 8 ) );
|
||||
|
||||
LoginAllMonster();
|
||||
GameAllStart();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMgr::DestroyBGServerMap()
|
||||
{
|
||||
BGServerMapList::iterator pos = m_lstBGServerMap.begin();
|
||||
BGServerMapList::iterator end = m_lstBGServerMap.end();
|
||||
|
||||
for(; pos != end; ++pos)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
delete (*pos);
|
||||
(*pos) = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
m_lstBGServerMap.clear();
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMgr::Enter(CCharacter* lpCharacter, unsigned short wMapIndex, unsigned char cMoveType)
|
||||
{
|
||||
if (NULL == lpCharacter) { return false; }
|
||||
|
||||
unsigned short wIndex = (wMapIndex & ~VirtualArea::BGSERVERMAP);
|
||||
if (0 == wIndex || wIndex > m_lstBGServerMap.size()) { return false; }
|
||||
|
||||
CBGServerMap* lpBGServerMap = m_lstBGServerMap[wIndex - 1];
|
||||
if (NULL == lpBGServerMap) { return false; }
|
||||
|
||||
unsigned short wError = lpBGServerMap->Enter(lpCharacter, cMoveType);
|
||||
if (PktBase::NO_SERVER_ERR == wError)
|
||||
{
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
if (false == GameClientSendPacket::SendCharBGServerMoveZone(lpDispatch->GetSendStream(), lpBGServerMap->GetVirtualZone(), cMoveType, wError))
|
||||
{
|
||||
lpBGServerMap->Leave(lpCharacter);
|
||||
ERRLOG3(g_Log, "CID:0x%08x 캐릭터가 가상 존(MapIndex : %d)에서 가상 존(MapIndex : %d)으로 이동하는데 실패하였습니다.",
|
||||
lpCharacter->GetCID(), lpCharacter->GetMapIndex(), wMapIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 존 이동 (실제로는 MapIndex 와 좌표가 바뀔 뿐이다.)
|
||||
lpCharacter->SetMapIndex(wMapIndex);
|
||||
lpCharacter->MoveTo(lpBGServerMap->GetStartPosition(lpCharacter->GetRace()), false);
|
||||
|
||||
// HIDE 명령 처리
|
||||
if (VirtualArea::TYPE_SPECTATOR == cMoveType)
|
||||
{
|
||||
lpCharacter->GetEnchantInfo().SetFlag(Skill::SpellID::Hide);
|
||||
}
|
||||
|
||||
// 방 정보를 보내준다.
|
||||
// (지금은 방의 모든 사람에게 다 보내주지만, 구경꾼이 들어올경우에는 그 구경꾼에게만 보내주도록 수정할수 있다.)
|
||||
lpBGServerMap->SendMapInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
lpBGServerMap->Leave(lpCharacter);
|
||||
ERRLOG3(g_Log, "CID:0x%08x 캐릭터가 가상 존(MapIndex : %d)에서 가상 존(MapIndex : %d)으로 이동하는데 실패하였습니다.",
|
||||
lpCharacter->GetCID(), lpCharacter->GetMapIndex(), wMapIndex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PktBase::SERVER_ERROR == wError)
|
||||
{
|
||||
ERRLOG3(g_Log, "CID:0x%08x 캐릭터가 가상 존(MapIndex : %d)에서 가상 존(MapIndex : %d)으로 이동하는데 실패하였습니다.",
|
||||
lpCharacter->GetCID(), lpCharacter->GetMapIndex(), wMapIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharBGServerMoveZone(lpDispatch->GetSendStream(),
|
||||
lpBGServerMap->GetVirtualZone(), cMoveType, wError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMgr::Leave(CCharacter* lpCharacter)
|
||||
{
|
||||
if (NULL == lpCharacter) return false;
|
||||
|
||||
unsigned short wIndex = (lpCharacter->GetMapIndex() & ~VirtualArea::BGSERVERMAP);
|
||||
if (0 == wIndex || wIndex > m_lstBGServerMap.size()) return false;
|
||||
|
||||
CBGServerMap* lpBGServerMap = m_lstBGServerMap[wIndex - 1];
|
||||
if (NULL == lpBGServerMap) return false;
|
||||
|
||||
lpCharacter->SetMapIndex(0);
|
||||
Position RespawnPos(VirtualArea::RespawnPos[ lpCharacter->GetRace() ][ Math::Random::ComplexRandom(VirtualArea::MAX_LOBBY_RESPAWN_POS) ]);
|
||||
RespawnPos.m_fPointX += Math::Random::SimpleRandom(GetTickCount(), 20) - 10;
|
||||
RespawnPos.m_fPointZ += Math::Random::SimpleRandom(GetTickCount(), 20) - 10;
|
||||
lpCharacter->MoveTo(RespawnPos, false);
|
||||
lpCharacter->GetEnchantInfo().ResetFlag(Skill::SpellID::Hide);
|
||||
lpBGServerMap->Leave(lpCharacter);
|
||||
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
if (false == GameClientSendPacket::SendCharBGServerMoveZone(lpDispatch->GetSendStream(), SERVER_ID::BATTLE_SERVER, VirtualArea::TYPE_PLAYER, PktBase::NO_SERVER_ERR))
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 캐릭터가 가상 존(MapIndex : %d)에서 나가는데 실패하였습니다.", lpCharacter->GetCID(), lpCharacter->GetMapIndex());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 플레이어가 나간경우 방 정보를 보내준다.
|
||||
if (lpBGServerMap->IsPlayer(lpCharacter))
|
||||
{
|
||||
lpBGServerMap->SendMapInfo();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMgr::Process()
|
||||
{
|
||||
BGServerMapList::iterator pos = m_lstBGServerMap.begin();
|
||||
BGServerMapList::iterator end = m_lstBGServerMap.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
(*pos)->Process();
|
||||
++pos;
|
||||
}
|
||||
|
||||
static unsigned long s_dwLastTime = 0;
|
||||
unsigned long dwCurrentTime = timeGetTime();
|
||||
if (dwCurrentTime - s_dwLastTime > VirtualArea::MILLISEC_PER_MINUTE)
|
||||
{
|
||||
s_dwLastTime = dwCurrentTime;
|
||||
SendMapListToAllCharacter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CVirtualArea* CBGServerMgr::GetVirtualArea(unsigned short wMapIndex)
|
||||
{
|
||||
unsigned short wIndex = (wMapIndex & ~VirtualArea::BGSERVERMAP);
|
||||
|
||||
if (0 == wIndex || wIndex > m_lstBGServerMap.size())
|
||||
return NULL;
|
||||
|
||||
return reinterpret_cast<CVirtualArea*>(m_lstBGServerMap[wIndex - 1]);
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMgr::SendMapList(CCharacter* lpCharacter)
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck);
|
||||
|
||||
if (NULL == lpCharacter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const int MAX_BUFFER = sizeof(PktBGServerMapList) + PktBGServerMapList::MAX_MAP_NUM * sizeof(BGServerMapInfoNode);
|
||||
char szBuffer[MAX_BUFFER];
|
||||
|
||||
PktBGServerMapList* lpPktBGSMLAck = reinterpret_cast<PktBGServerMapList *>(szBuffer);
|
||||
BGServerMapInfoNode* lpMapInfoNode = reinterpret_cast<BGServerMapInfoNode *>(lpPktBGSMLAck + 1);
|
||||
|
||||
lpPktBGSMLAck->m_bAll = true;
|
||||
lpPktBGSMLAck->m_cMapInfoNodeNum = 0;
|
||||
|
||||
for (unsigned char cIndex = 0; cIndex < PktBGServerMapList::MAX_MAP_NUM && cIndex < m_lstBGServerMap.size();
|
||||
++cIndex, ++lpMapInfoNode, ++lpPktBGSMLAck->m_cMapInfoNodeNum)
|
||||
{
|
||||
CBGServerMap* lpBGServerMap = m_lstBGServerMap[cIndex];
|
||||
if (NULL != lpBGServerMap)
|
||||
{
|
||||
lpMapInfoNode->m_bPlaying = lpBGServerMap->IsPlaying();
|
||||
lpMapInfoNode->m_cMapType = lpBGServerMap->GetMapInfo().m_cMapType;
|
||||
lpMapInfoNode->m_cMaxCharNumOfNation = lpBGServerMap->GetMapInfo().m_cMaxCharNumOfNation;
|
||||
lpMapInfoNode->m_wTargetScore = lpBGServerMap->GetMapInfo().m_wTargetScore;
|
||||
lpMapInfoNode->m_cRemainMin = (lpBGServerMap->IsPlaying() == true) ? lpBGServerMap->GetMapInfo().m_cRemainPlayMin : lpBGServerMap->GetMapInfo().m_cRemainRestMin;
|
||||
|
||||
lpMapInfoNode->m_cCurrentCharNum[CClass::HUMAN] = lpBGServerMap->GetMapInfo().m_cCurrentCharNum[CClass::HUMAN];
|
||||
lpMapInfoNode->m_cCurrentCharNum[CClass::AKHAN] = lpBGServerMap->GetMapInfo().m_cCurrentCharNum[CClass::AKHAN];
|
||||
lpMapInfoNode->m_wScore[CClass::HUMAN] = lpBGServerMap->GetMapInfo().m_wScore[CClass::HUMAN];
|
||||
lpMapInfoNode->m_wScore[CClass::AKHAN] = lpBGServerMap->GetMapInfo().m_wScore[CClass::AKHAN];
|
||||
}
|
||||
}
|
||||
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
return lpDispatch->GetSendStream().WrapCompress(szBuffer, sizeof(PktBGServerMapList) +
|
||||
lpPktBGSMLAck->m_cMapInfoNodeNum * sizeof(BGServerMapInfoNode), CmdBGServerMapList, 0, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMgr::SendResultList(CCharacter* lpCharacter)
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck);
|
||||
|
||||
if (NULL == lpCharacter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const int MAX_BUFFER = sizeof(PktBGServerResultList) + PktBGServerResultList::MAX_MAP_NUM * sizeof(BGServerResultInfoNode);
|
||||
char szBuffer[MAX_BUFFER];
|
||||
|
||||
PktBGServerResultList* lpPktBGSRLAck = reinterpret_cast<PktBGServerResultList *>(szBuffer);
|
||||
BGServerResultInfoNode* lpResultInfoNode = reinterpret_cast<BGServerResultInfoNode *>(lpPktBGSRLAck + 1);
|
||||
|
||||
lpPktBGSRLAck->m_bAll = true;
|
||||
lpPktBGSRLAck->m_cResultInfoNodeNum = 0;
|
||||
|
||||
for (unsigned char cIndex = 0; cIndex < PktBGServerResultList::MAX_MAP_NUM && cIndex < m_lstBGServerMap.size();
|
||||
++cIndex, ++lpResultInfoNode, ++lpPktBGSRLAck->m_cResultInfoNodeNum)
|
||||
{
|
||||
CBGServerMap* lpBGServerMap = m_lstBGServerMap[cIndex];
|
||||
if (NULL != lpBGServerMap)
|
||||
{
|
||||
lpResultInfoNode->m_cWinRace = lpBGServerMap->GetResultInfo().m_cWinRace;
|
||||
lpResultInfoNode->m_cPlayMin = 0;
|
||||
lpResultInfoNode->m_wAward = 0;
|
||||
lpResultInfoNode->m_wScore[CClass::HUMAN] = lpBGServerMap->GetResultInfo().m_wScore[CClass::HUMAN];
|
||||
lpResultInfoNode->m_wScore[CClass::AKHAN] = lpBGServerMap->GetResultInfo().m_wScore[CClass::AKHAN];
|
||||
}
|
||||
}
|
||||
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
return lpDispatch->GetSendStream().WrapCompress(szBuffer, sizeof(PktBGServerResultList) +
|
||||
lpPktBGSRLAck->m_cResultInfoNodeNum * sizeof(BGServerResultInfoNode), CmdBGServerResultList, 0, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBGServerMgr::SendMapListToAllCharacter()
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck);
|
||||
|
||||
if (0 == CCreatureManager::GetInstance().GetCharacterNum()) return true;
|
||||
|
||||
const int MAX_BUFFER = sizeof(PktBGServerMapList) + PktBGServerMapList::MAX_MAP_NUM * sizeof(BGServerMapInfoNode);
|
||||
char szSrcBuffer[MAX_BUFFER], szDstBuffer[MAX_BUFFER];
|
||||
|
||||
PktBGServerMapList* lpPktBGSMLAck = reinterpret_cast<PktBGServerMapList *>(szSrcBuffer);
|
||||
BGServerMapInfoNode* lpMapInfoNode = reinterpret_cast<BGServerMapInfoNode *>(lpPktBGSMLAck + 1);
|
||||
|
||||
lpPktBGSMLAck->m_bAll = true;
|
||||
lpPktBGSMLAck->m_cMapInfoNodeNum = 0;
|
||||
|
||||
for (unsigned char cIndex = 0; cIndex < PktBGServerMapList::MAX_MAP_NUM && cIndex < m_lstBGServerMap.size();
|
||||
++cIndex, ++lpMapInfoNode, ++lpPktBGSMLAck->m_cMapInfoNodeNum)
|
||||
{
|
||||
CBGServerMap* lpBGServerMap = m_lstBGServerMap[cIndex];
|
||||
if (NULL != lpBGServerMap)
|
||||
{
|
||||
lpMapInfoNode->m_bPlaying = lpBGServerMap->IsPlaying();
|
||||
lpMapInfoNode->m_cMapType = lpBGServerMap->GetMapInfo().m_cMapType;
|
||||
lpMapInfoNode->m_cMaxCharNumOfNation = lpBGServerMap->GetMapInfo().m_cMaxCharNumOfNation;
|
||||
lpMapInfoNode->m_wTargetScore = lpBGServerMap->GetMapInfo().m_wTargetScore;
|
||||
lpMapInfoNode->m_cRemainMin = (lpBGServerMap->IsPlaying() == true) ? lpBGServerMap->GetMapInfo().m_cRemainPlayMin : lpBGServerMap->GetMapInfo().m_cRemainRestMin;
|
||||
|
||||
lpMapInfoNode->m_cCurrentCharNum[CClass::HUMAN] = lpBGServerMap->GetMapInfo().m_cCurrentCharNum[CClass::HUMAN];
|
||||
lpMapInfoNode->m_cCurrentCharNum[CClass::AKHAN] = lpBGServerMap->GetMapInfo().m_cCurrentCharNum[CClass::AKHAN];
|
||||
lpMapInfoNode->m_wScore[CClass::HUMAN] = lpBGServerMap->GetMapInfo().m_wScore[CClass::HUMAN];
|
||||
lpMapInfoNode->m_wScore[CClass::AKHAN] = lpBGServerMap->GetMapInfo().m_wScore[CClass::AKHAN];
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long dwDstLength = MAX_BUFFER;
|
||||
unsigned short wSrcLength = sizeof(PktBGServerMapList) + lpPktBGSMLAck->m_cMapInfoNodeNum * sizeof(BGServerMapInfoNode);
|
||||
|
||||
if (PacketWrap::WrapCompress(szDstBuffer, dwDstLength,
|
||||
szSrcBuffer, wSrcLength, CmdBGServerMapList, 0, 0))
|
||||
{
|
||||
// 대기실에 있는 사람들에게만 방정보를 전송해준다.
|
||||
CCreatureManager::GetInstance().SendAllCharacter(
|
||||
szDstBuffer, dwDstLength, CmdBGServerMapList, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CBGServerMgr::LoginAllMonster()
|
||||
{
|
||||
for (size_t nIndex=0; nIndex<m_lstBGServerMap.size(); ++nIndex)
|
||||
{
|
||||
if (m_lstBGServerMap[nIndex])
|
||||
{
|
||||
const VirtualArea::ProtoType* lpProtoType = VirtualArea::CVirtualAreaMgr::GetInstance().GetVirtualAreaProtoType( m_lstBGServerMap[nIndex]->GetVID() );
|
||||
if (lpProtoType && '\0' != lpProtoType->m_szArrangementFileName[0])
|
||||
{
|
||||
m_lstBGServerMap[nIndex]->CreateVirtualMonsterManager();
|
||||
unsigned short wMapIndex = static_cast<unsigned short>(VirtualArea::BGSERVERMAP | (nIndex + 1));
|
||||
CCellManager::GetInstance().LoginMonster(lpProtoType->m_szArrangementFileName, wMapIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBGServerMgr::GameAllStart()
|
||||
{
|
||||
std::for_each(m_lstBGServerMap.begin(), m_lstBGServerMap.end(), std::mem_fun<bool, CBGServerMap>(&CBGServerMap::GameStart));
|
||||
}
|
||||
|
||||
|
||||
void CBGServerMgr::ProcessAllMonster()
|
||||
{
|
||||
BGServerMapList::iterator pos = m_lstBGServerMap.begin();
|
||||
BGServerMapList::iterator end = m_lstBGServerMap.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
(*pos)->ProcessAllMonster();
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
void CBGServerMgr::ProcessMonsterRegenHPAndMP()
|
||||
{
|
||||
BGServerMapList::iterator pos = m_lstBGServerMap.begin();
|
||||
BGServerMapList::iterator end = m_lstBGServerMap.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
(*pos)->ProcessMonsterRegenHPAndMP();
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
void CBGServerMgr::ProcessSummonMonsterDead()
|
||||
{
|
||||
BGServerMapList::iterator pos = m_lstBGServerMap.begin();
|
||||
BGServerMapList::iterator end = m_lstBGServerMap.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
(*pos)->ProcessSummonMonsterDead();
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
void CBGServerMgr::ProcessDeleteItem()
|
||||
{
|
||||
BGServerMapList::iterator pos = m_lstBGServerMap.begin();
|
||||
BGServerMapList::iterator end = m_lstBGServerMap.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
(*pos)->ProcessDeleteItem();
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
bool CBGServerMgr::ProcessAllCellPrepareBroadCast()
|
||||
{
|
||||
BGServerMapList::iterator pos = m_lstBGServerMap.begin();
|
||||
BGServerMapList::iterator end = m_lstBGServerMap.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
(*pos)->ProcessAllCellPrepareBroadCast();
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBGServerMgr::ProcessAllCellBroadCast(unsigned long dwCurrentPulse)
|
||||
{
|
||||
BGServerMapList::iterator pos = m_lstBGServerMap.begin();
|
||||
BGServerMapList::iterator end = m_lstBGServerMap.end();
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
if (NULL != (*pos))
|
||||
{
|
||||
(*pos)->ProcessAllCellBroadCast(dwCurrentPulse);
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifndef _BATTLEGROUND_SERVER_MANAGER_H_
|
||||
#define _BATTLEGROUND_SERVER_MANAGER_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Àü¹æ ÂüÁ¶
|
||||
class CCharacter;
|
||||
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
// Àü¹æ ÂüÁ¶
|
||||
class CVirtualArea;
|
||||
class CBGServerMap;
|
||||
|
||||
|
||||
class CBGServerMgr
|
||||
{
|
||||
public:
|
||||
|
||||
static CBGServerMgr& GetInstance();
|
||||
|
||||
bool CreateBGServerMap();
|
||||
|
||||
void Process();
|
||||
bool Enter(CCharacter* lpCharacter, unsigned short wMapIndex, unsigned char cMoveType);
|
||||
bool Leave(CCharacter* lpCharacter);
|
||||
|
||||
CVirtualArea* GetVirtualArea(unsigned short wMapIndex);
|
||||
|
||||
bool SendMapList(CCharacter* lpCharacter);
|
||||
bool SendResultList(CCharacter* lpCharacter);
|
||||
bool SendMapListToAllCharacter();
|
||||
|
||||
typedef std::vector<CBGServerMap* > BGServerMapList;
|
||||
|
||||
void ProcessAllMonster();
|
||||
void ProcessMonsterRegenHPAndMP();
|
||||
void ProcessSummonMonsterDead();
|
||||
void ProcessDeleteItem();
|
||||
|
||||
// Cell BroadCasting
|
||||
bool ProcessAllCellPrepareBroadCast();
|
||||
bool ProcessAllCellBroadCast(unsigned long dwCurrentPulse);
|
||||
|
||||
private:
|
||||
CBGServerMgr();
|
||||
~CBGServerMgr();
|
||||
|
||||
void DestroyBGServerMap();
|
||||
bool LoginAllMonster();
|
||||
void GameAllStart();
|
||||
|
||||
|
||||
BGServerMapList m_lstBGServerMap;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _BATTLEGROUND_SERVER_MANAGER_H_
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef _DUEL_MAP_H_
|
||||
#define _DUEL_MAP_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
class CDuelMap
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _DUEL_MAP_H_
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "DuelMgr.h"
|
||||
|
||||
using namespace VirtualArea;
|
||||
|
||||
CDuelMgr& CDuelMgr::GetInstance()
|
||||
{
|
||||
static CDuelMgr ms_this;
|
||||
return ms_this;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _DUEL_MANAGER_H_
|
||||
#define _DUEL_MANAGER_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
class CDuelMgr
|
||||
{
|
||||
public:
|
||||
|
||||
static CDuelMgr& GetInstance();
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _DUEL_MANAGER_H_
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef _DUNGEON_H_
|
||||
#define _DUNGEON_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
class CDungeon
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _DUNGEON_H_
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "DungeonMgr.h"
|
||||
|
||||
using namespace VirtualArea;
|
||||
|
||||
CDungeonMgr& CDungeonMgr::GetInstance()
|
||||
{
|
||||
static CDungeonMgr ms_this;
|
||||
return ms_this;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _DUNGEON_MANAGER_H_
|
||||
#define _DUNGEON_MANAGER_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace VirtualArea
|
||||
{
|
||||
class CDungeonMgr
|
||||
{
|
||||
public:
|
||||
|
||||
static CDungeonMgr& GetInstance();
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _DUNGEON_MANAGER_H_
|
||||
Reference in New Issue
Block a user