knightonline/server/AIServer/ServerDlg.cpp

1137 lines
28 KiB
C++
Raw Blame History

#include "stdafx.h"
#include <time.h>
#include <cstdarg>
#include "GameSocket.h"
#include "Npc.h"
#include "User.h"
#include "NpcThread.h"
#include "../GameServer/MagicProcess.h"
#include <boost/foreach.hpp>
#include "../shared/database/OdbcRecordset.h"
#include "../shared/database/MagicTableSet.h"
#include "../shared/database/MagicType1Set.h"
#include "../shared/database/MagicType2Set.h"
#include "../shared/database/MagicType4Set.h"
#include "../shared/database/ObjectPosSet.h"
#include "../shared/database/NpcPosSet.h"
#include "../shared/database/ZoneInfoSet.h"
#include "../shared/database/NpcItemSet.h"
#include "../shared/database/MakeItemGroupSet.h"
#include "../shared/database/NpcTableSet.h"
#include "../shared/database/MakeWeaponTableSet.h"
#include "../shared/database/MakeDefensiveTableSet.h"
#include "../shared/database/MakeGradeItemTableSet.h"
#include "../shared/database/MakeLareItemTableSet.h"
#include "../shared/database/ServerResourceSet.h"
#include "Region.h"
#include "../shared/Ini.h"
#include "../shared/packets.h"
#include "../shared/DateTime.h"
using namespace std;
bool g_bNpcExit = false;
ZoneArray g_arZone;
std::vector<Thread *> g_timerThreads;
CServerDlg::CServerDlg()
{
EventNpcID = 0;
CSWOpen = false;
m_iYear = 0;
m_iMonth = 0;
m_iDate = 0;
m_iHour = 0;
m_iMin = 0;
m_iWeather = 0;
m_iAmount = 0;
m_bIsNight = false;
m_byBattleEvent = BATTLEZONE_CLOSE;
m_sKillKarusNpc = 0;
m_sKillElmoNpc = 0;
KarusBaseMilitaryCampCount = 0;
ElmoradBaseMilitaryCampCount= 0;
KarusEslantMilitaryCampCount= 0;
ElmoradEslantMilitaryCampCount= 0;
MoradonMilitaryCampCount = 0;
}
bool CServerDlg::Startup()
{
g_timerThreads.push_back(new Thread(Timer_CheckAliveTest));
g_timerThreads.push_back(new Thread(Timer_CheckLiveTimes));
m_sMapEventNpc = 0;
m_bFirstServerFlag = false;
// Server Start
DateTime time;
printf("Server started on %04d-%02d-%02d at %02d:%02d\n\n", time.GetYear(), time.GetMonth(), time.GetDay(), time.GetHour(), time.GetMinute());
//----------------------------------------------------------------------
// DB part initialize
//----------------------------------------------------------------------
GetServerInfoIni();
if (!m_GameDB.Connect(m_strGameDSN, m_strGameUID, m_strGamePWD,false))
{
OdbcError *pError = m_GameDB.GetError();
printf("ERROR: Could not connect to the database server, received error:\n%s\n",
pError->ErrorMessage.c_str());
delete pError;
return false;
}
//----------------------------------------------------------------------
// Communication Part Initialize ...
//----------------------------------------------------------------------
if (!m_socketMgr.Listen(m_AIServerPort, MAX_SOCKET))
return false;
//----------------------------------------------------------------------
// Load tables
//----------------------------------------------------------------------
if (!GetMagicTableData()
|| !GetMagicType1Data()
|| !GetMagicType2Data()
|| !GetMagicType4Data()
|| !GetNpcItemTable()
|| !GetMakeItemGroupTable()
|| !GetMakeWeaponItemTableData()
|| !GetMakeDefensiveItemTableData()
|| !GetMakeGradeItemTableData()
|| !GetMakeLareItemTableData()
|| !GetServerResourceTable()
|| !GetObjectPostTableData()
|| !GetNpcTableData(false)
|| !GetNpcTableData(true)
// Load maps
|| !MapFileLoad()
// Spawn NPC threads
|| !CreateNpcThread())
return false;
//----------------------------------------------------------------------
// Start NPC THREAD
//----------------------------------------------------------------------
ResumeAI();
return true;
}
bool CServerDlg::GetMagicTableData()
{
LOAD_TABLE(CMagicTableSet, &m_GameDB, &m_MagictableArray, false, false);
}
bool CServerDlg::GetMagicType1Data()
{
LOAD_TABLE(CMagicType1Set, &m_GameDB, &m_Magictype1Array, false, false);
}
bool CServerDlg::GetMagicType2Data()
{
LOAD_TABLE(CMagicType2Set, &m_GameDB, &m_Magictype2Array, false, false);
}
bool CServerDlg::GetMagicType4Data()
{
LOAD_TABLE(CMagicType4Set, &m_GameDB, &m_Magictype4Array, false, false);
}
bool CServerDlg::GetMakeWeaponItemTableData()
{
LOAD_TABLE(CMakeWeaponTableSet, &m_GameDB, &m_MakeWeaponItemArray, true, false);
}
bool CServerDlg::GetMakeDefensiveItemTableData()
{
LOAD_TABLE(CMakeDefensiveTableSet, &m_GameDB, &m_MakeDefensiveItemArray, true, false);
}
bool CServerDlg::GetMakeGradeItemTableData()
{
LOAD_TABLE(CMakeGradeItemTableSet, &m_GameDB, &m_MakeGradeItemArray, false, false);
}
bool CServerDlg::GetMakeLareItemTableData()
{
LOAD_TABLE(CMakeLareItemTableSet, &m_GameDB, &m_MakeLareItemArray, false, false);
}
bool CServerDlg::GetServerResourceTable()
{
LOAD_TABLE(CServerResourceSet, &m_GameDB, &m_ServerResourceArray, false, false);
}
bool CServerDlg::GetNpcItemTable()
{
LOAD_TABLE(CNpcItemSet, &m_GameDB, &m_NpcItemArray, false, false);
}
bool CServerDlg::GetMakeItemGroupTable()
{
LOAD_TABLE(CMakeItemGroupSet, &m_GameDB, &m_MakeItemGroupArray, false, false);
}
bool CServerDlg::GetObjectPostTableData()
{
LOAD_TABLE(CObjectPosSet, &m_GameDB, &m_ObjectEventArray, false, false);
}
bool CServerDlg::GetNpcTableData(bool bNpcData /*= true*/)
{
if (bNpcData) { LOAD_TABLE(CNpcTableSet, &m_GameDB, &m_arNpcTable, false, false); }
else { LOAD_TABLE(CMonTableSet, &m_GameDB, &m_arMonTable, false, false); }
}
bool CServerDlg::CreateNpcThread()
{
m_TotalNPC = m_sMapEventNpc;
MaxMonsterID = m_sMapEventNpc;
m_CurrentNPC = 0;
LOAD_TABLE_ERROR_ONLY(CNpcPosSet, &m_GameDB, nullptr, false, false);
Guard lock(m_npcThreadLock);
foreach_stlmap_nolock (itr, g_arZone)
{
CNpcThread * pNpcThread = new CNpcThread();
m_arNpcThread.insert(make_pair(itr->first, pNpcThread));
foreach_stlmap (npcItr, m_arNpc)
{
if (npcItr->second->GetZoneID() != itr->first)
continue;
CNpc * pNpc = npcItr->second;
if (pNpc != nullptr)
{
pNpc->Init();
pNpcThread->m_pNpcs.insert(pNpc);
}
}
}
printf("Monster Init - %d, threads = %lld\n", (uint16) m_TotalNPC, (long long) m_arNpcThread.size());
return true;
}
void CServerDlg::UserEventRoomUpdate(uint16 uid, uint16 RoomEvent)
{
CUser *TargetUser = g_pMain->GetUserPtr(uid);
if(TargetUser == nullptr)
return;
TargetUser->SetUserEventRoom(RoomEvent);
TargetUser->SetUnitEventRoom(RoomEvent);
}
bool CServerDlg::LoadSpawnCallback(OdbcCommand *dbCommand)
{
// Avoid allocating stack space for these.
// This method will only ever run in the same thread.
static int nRandom = 0;
static double dbSpeed = 0;
static CNpcTable * pNpcTable = nullptr;
static CRoomEvent* pRoom = nullptr;
static char szPath[500];
static float fRandom_X = 0.0f, fRandom_Z = 0.0f;
static uint8 rand = myrand(1,4);
// Unfortunately we cannot simply read what we need directly
// into the CNpc instance. We have to resort to creating
// copies of the data to allow for the way they handle multiple spawns...
// Best we can do, I think, is to avoid allocating it on the stack.
static uint8 bNumNpc, bZoneID, bActType, bRegenType, bDungeonFamily, bSpecialType,
bTrapNumber, bDotCnt;
static uint8 isNPC;
static uint16 sSid, sRegTime, iRange, xiDontKnow, EveTRoom;
static uint32 nServerNum;
static int16 bDirection;
static int32 iLeftX, iTopZ, iRightX, iBottomZ,
iLimitMinX, iLimitMinZ, iLimitMaxX, iLimitMaxZ;
string strName;
dbCommand->FetchByte(1, bZoneID);
dbCommand->FetchUInt16(2, sSid);
dbCommand->FetchString(3, strName);
dbCommand->FetchByte(4, isNPC);
dbCommand->FetchByte(5, bActType);
dbCommand->FetchByte(6, bDungeonFamily);
dbCommand->FetchByte(7, bSpecialType);
dbCommand->FetchByte(8, bTrapNumber);
dbCommand->FetchInt32(9, iLeftX);
dbCommand->FetchInt32(10, iTopZ);
dbCommand->FetchByte(11, bNumNpc);
dbCommand->FetchUInt16(12, iRange);
dbCommand->FetchUInt16(13, xiDontKnow);// iRange
dbCommand->FetchUInt16(14, sRegTime);
dbCommand->FetchInt16(15, bDirection);
dbCommand->FetchString(16, szPath, sizeof(szPath));
dbCommand->FetchUInt16(17, EveTRoom);
isNPC--;
uint8 bPathSerial = 1;
if((bSpecialType==7 && bTrapNumber==rand) || bSpecialType!=7)
for (uint8 j = 0; j < bNumNpc; j++)
{
CNpc * pNpc = new CNpc();
pNpc->m_byMoveType = bActType;// bActType;
pNpc->m_byInitMoveType = bActType;
bool isMonster = isNPC == 1 ? false : true;
if (isMonster)
{
pNpcTable = m_arMonTable.GetData(sSid);
}
else
{
pNpc->m_byMoveType = bActType;
pNpcTable = m_arNpcTable.GetData(sSid);
}
if (pNpcTable == nullptr)
{
printf("NPC %d not found in %s table.\n", sSid, isNPC ? "K_MONSTER" : "K_NPC");
delete pNpc;
return false;
}
uint16 myID = ++m_TotalNPC;
++MaxMonsterID;
pNpc->Load(myID, pNpcTable, !isNPC);
pNpc->m_byBattlePos = 0;
if (pNpc->m_byMoveType >= 2)
{
pNpc->m_byBattlePos = myrand(1, 3);
if (pNpc->m_byMoveType == 5 || pNpc->m_byMoveType == 4)
pNpc->m_byBattlePos = 0;
pNpc->m_byPathCount = bPathSerial++;
}
pNpc->InitPos();
pNpc->m_bZone = bZoneID;
nRandom = iRange;
if (nRandom <= 0)
fRandom_X = (float)iLeftX;
else
fRandom_X = (float)(myrand((iLeftX - nRandom) * 10, (iLeftX + nRandom) * 10) / 10);
nRandom = iRange;
if (nRandom <= 0)
fRandom_Z = (float)iTopZ;
else
fRandom_Z = (float)(myrand((iTopZ - nRandom) * 10, (iTopZ + nRandom) * 10) / 10);
pNpc->SetPosition(fRandom_X, 0.0f, fRandom_Z);
pNpc->m_sRegenTime = sRegTime * SECOND;
pNpc->m_byDirection = bDirection;
pNpc->m_sMaxPathCount = strlen(szPath) / 8;
if (pNpc->m_byMoveType == 2 && pNpc->m_sMaxPathCount == 0)
{
pNpc->m_byMoveType = 1;
TRACE("##### ServerDlg:CreateNpcThread - Path type Error : nid=%d, sid=%d, name=%s, acttype=%d, path=%d #####\n",
pNpc->GetID(), pNpc->GetProtoID(), pNpc->GetName().c_str(), pNpc->m_byMoveType, pNpc->m_sMaxPathCount);
}
if (pNpc->m_sMaxPathCount > 0)
{
int index = 0;
__Vector3 vStart;
vStart.Set(pNpc->GetX(), 0, pNpc->GetZ());
for (int l = 0; l < pNpc->m_sMaxPathCount; l++)
{
if(l > 5000)
break;
static char szX[5], szZ[5];
memset(szX, 0, sizeof(szX));
memset(szZ, 0, sizeof(szZ));
memcpy(szX, szPath + index, 4);
index += 4;
memcpy(szZ, szPath + index, 4);
index += 4;
float myX = 0.0f, myZ = 0.0f;
__Vector3 vEnd, vNewPos;
float fDis = 0.0f;
myX = (float)atoi(szX);
myZ = (float)atoi(szZ);
if(myX < 1 || myZ < 1)
continue;
if (l > 0)
vStart.Set(pNpc->m_PathList.pPattenPos[l-1].x, 0, pNpc->m_PathList.pPattenPos[l-1].z);
vEnd.Set(myX, 0, myZ);
fDis = pNpc->GetDistance(vStart, vEnd);
if(fDis > pNpc->GetProto()->m_bySpeed_1)
{
for(;;)
{
pNpc->GetVectorPosition(vStart, vEnd, pNpc->GetProto()->m_bySpeed_1, &vNewPos);
//printf("%d,%d-%d,%d/(%d,%d)\n",uint16(vStart.x),uint16(vStart.z),uint16(myX),uint16(myZ),uint16(vNewPos.x),uint16(vNewPos.z));
pNpc->m_PathList.pPattenPos[l].x = (short)vNewPos.x;
pNpc->m_PathList.pPattenPos[l].z = (short)vNewPos.z;
vStart.Set(vNewPos.x, 0, vNewPos.z);
fDis = pNpc->GetDistance(vStart, vEnd);
if(fDis > pNpc->GetProto()->m_bySpeed_1)
{
l++;
pNpc->m_sMaxPathCount++;
}
else
{
l++;
pNpc->m_sMaxPathCount++;
pNpc->m_PathList.pPattenPos[l].x = (short)vEnd.x;
pNpc->m_PathList.pPattenPos[l].z = (short)vEnd.z;
//printf("%d,%d-%d,%d/(%d,%d)\n",uint16(vStart.x),uint16(vStart.z),uint16(myX),uint16(myZ),uint16(vEnd.x),uint16(vEnd.z));
break;
}
}
}
else
{
pNpc->m_PathList.pPattenPos[l].x = (short)myX;
pNpc->m_PathList.pPattenPos[l].z = (short)myZ;
}
}
}
pNpc->m_nInitMinX = pNpc->m_nLimitMinX = iLeftX - nRandom;
pNpc->m_nInitMinY = pNpc->m_nLimitMinZ = iTopZ - nRandom;
pNpc->m_nInitMaxX = pNpc->m_nLimitMaxX = iLeftX + nRandom;
pNpc->m_nInitMaxY = pNpc->m_nLimitMaxZ = iTopZ + nRandom;
// dungeon work
pNpc->m_byDungeonFamily = bDungeonFamily;
pNpc->m_bySpecialType = (NpcSpecialType) bSpecialType;
pNpc->m_byRegenType = bRegenType;
pNpc->m_byTrapNumber = bTrapNumber;
pNpc->m_oSocketID = -1;
pNpc->m_bEventRoom = 0;
pNpc->SetNPCEventRoom(0);
pNpc->SetUnitEventRoom(0);
pNpc->m_pMap = GetZoneByID(pNpc->GetZoneID());
if (pNpc->GetMap() == nullptr)
{
printf(_T("ERROR: NPC %d in zone %d that does not exist."), sSid, bZoneID);
delete pNpc;
return false;
}
if (!m_arNpc.PutData(pNpc->GetID(), pNpc))
{
--m_TotalNPC;
TRACE("Npc PutData Fail - %d\n", pNpc->GetID());
delete pNpc;
continue;
}
if (pNpc->GetMap()->m_byRoomEvent > 0 && pNpc->m_byDungeonFamily > 0)
{
pRoom = pNpc->GetMap()->m_arRoomEventArray.GetData(pNpc->m_byDungeonFamily);
if (pRoom == nullptr)
{
printf("ERROR: Map Room Npc Fail!!\n");
printf("### Map - Room Array MonsterNid Fail : nid=%d, sid=%d zid= %d###\n",
pNpc->GetID(), pNpc->GetProtoID(), pNpc->GetZoneID());
delete pNpc;
return false;
}
// this is why their CSTLMap class sucks.
int *pInt = new int;
*pInt = pNpc->GetID();
if (!pRoom->m_mapRoomNpcArray.PutData(*pInt, pInt))
{
delete pInt;
TRACE("### Map - Room Array MonsterNid Fail : nid=%d, sid=%d ###\n",
pNpc->GetID(), pNpc->GetProtoID());
}
}
}
return true;
}
void CServerDlg::ResumeAI()
{
Guard lock(m_npcThreadLock);
foreach (itr, m_arNpcThread)
itr->second->m_thread.start(NpcThreadProc, itr->second);
m_zoneEventThread.start(ZoneEventThreadProc, this);
}
bool CServerDlg::MapFileLoad()
{
ZoneInfoMap zoneMap;
m_sTotalMap = 0;
LOAD_TABLE_ERROR_ONLY(CZoneInfoSet, &m_GameDB, &zoneMap, false, false);
foreach (itr, zoneMap)
{
_ZONE_INFO *pZone = itr->second;
MAP *pMap = new MAP();
if (!pMap->Initialize(pZone))
{
printf("ERROR: Unable to load SMD - %s\n", pZone->m_MapName.c_str());
delete pZone;
delete pMap;
g_arZone.DeleteAllData();
m_sTotalMap = 0;
return false;
}
delete pZone;
g_arZone.PutData(pMap->m_nZoneNumber, pMap);
m_sTotalMap++;
}
return true;
}
/**
* @brief Gets & formats a cached server resource (_SERVER_RESOURCE entry).
*
* @param nResourceID Identifier for the resource.
* @param result The string to store the formatted result in.
*/
void CServerDlg::GetServerResource(int nResourceID, string * result, ...)
{
_SERVER_RESOURCE *pResource = m_ServerResourceArray.GetData(nResourceID);
if (pResource == nullptr)
{
*result = nResourceID;
return;
}
va_list args;
va_start(args, result);
_string_format(pResource->strResource, result, args);
va_end(args);
}
// game server<65><72> <20><><EFBFBD><EFBFBD> npc<70><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>..
void CServerDlg::AllNpcInfo()
{
Packet result(NPC_INFO_ALL);
result.SByte();
foreach_stlmap_nolock (itr, g_arZone)
{
uint32 nZone = itr->first;
uint8 bCount = 0;
result.clear();
result << bCount;
foreach_stlmap (itr, m_arNpc)
{
CNpc *pNpc = itr->second;
if (pNpc == nullptr
|| pNpc->GetZoneID() != nZone)
continue;
pNpc->FillNpcInfo(result);
if (++bCount == NPC_NUM)
{
result.put(0, bCount);
m_socketMgr.SendAllCompressed(&result);
// Reset packet buffer
bCount = 0;
result.clear();
result << bCount;
}
}
if (bCount != 0 && bCount < NPC_NUM)
{
result.put(0, bCount);
m_socketMgr.SendAllCompressed(&result);
}
Packet serverInfo(AG_SERVER_INFO, uint8(nZone));
serverInfo << uint16(m_TotalNPC);
m_socketMgr.SendAll(&serverInfo);
}
}
Unit * CServerDlg::GetUnitPtr(uint16 id)
{
if (id < NPC_BAND)
return GetUserPtr(id);
return GetNpcPtr(id);
}
CNpc * CServerDlg::GetNpcPtr(uint16 npcId)
{
return m_arNpc.GetData(npcId);
}
CUser* CServerDlg::GetUserPtr(uint16 sessionId)
{
Guard lock(m_userLock);
auto itr = m_pUser.find(sessionId);
if (itr == m_pUser.end())
return nullptr;
return itr->second;
}
bool CServerDlg::SetUserPtr(uint16 sessionId, CUser * pUser)
{
if (sessionId >= MAX_USER)
return false;
Guard lock(m_userLock);
auto itr = m_pUser.find(sessionId);
if (itr != m_pUser.end())
{
TRACE("Warning: User %u has not been removed from the session map.\n", sessionId);
return false;
}
m_pUser[sessionId] = pUser;
return true;
}
void CServerDlg::DeleteUserPtr(uint16 sessionId)
{
Guard lock(m_userLock);
auto itr = m_pUser.find(sessionId);
if (itr != m_pUser.end())
{
delete itr->second;
m_pUser.erase(itr);
}
}
void CServerDlg::CheckAliveTest()
{
Packet result(AG_CHECK_ALIVE_REQ);
SessionMap sessMap = m_socketMgr.GetActiveSessionMap();
uint32 count = 0, sessCount = sessMap.size();
BOOST_FOREACH (auto itr, sessMap)
{
if (itr.second->Send(&result))
count++;
}
if (sessCount > 0 && count == 0)
DeleteAllUserList();
//printf("Delete all user list???");
}
uint32 THREADCALL CServerDlg::Timer_CheckAliveTest(void * lpParam)
{
while (g_bRunning)
{
g_pMain->CheckAliveTest();
sleep(10 * SECOND);
}
return 0;
}
uint32 THREADCALL CServerDlg::Timer_CheckLiveTimes(void * lpParam)
{
while (g_bRunning)
{
g_pMain->CheckLiveTimes();
sleep(1 * SECOND);
}
return 0;
}
void CServerDlg::CheckLiveTimes()
{
std::vector<uint16> deleted;
foreach_stlmap_nolock (itr, m_NpcLiveTimeArray)
{
if (int32(UNIXTIME) - itr->second->SpawnedTime > itr->second->Duration)
{
CNpc *pNpc = GetNpcPtr(itr->second->Nid);
if (pNpc != nullptr)
pNpc->Dead();
deleted.push_back(itr->second->nIndex);
}
}
foreach (itr, deleted)
m_NpcLiveTimeArray.DeleteData(*itr);
}
void CServerDlg::DeleteAllUserList(CGameSocket *pSock)
{
// If a cconnected, show it...
if (pSock != nullptr)
{
printf("Game Server disconnected - %s\n", pSock->GetRemoteIP().c_str());
return;
}
// Server didn't disconnect?
if (!m_bFirstServerFlag)
return;
// If there's no servers even connected, cleanup.
TRACE("*** DeleteAllUserList - Start *** \n");
foreach_stlmap_nolock (itr, g_arZone)
{
MAP * pMap = itr->second;
if (pMap == nullptr)
continue;
for (int i = 0; i < pMap->GetXRegionMax(); i++)
{
for (int j = 0; j < pMap->GetZRegionMax(); j++)
pMap->m_ppRegion[i][j].m_RegionUserArray.DeleteAllData();
}
}
Guard lock(m_userLock);
foreach (itr, m_pUser)
{
if (itr->second == nullptr)
continue;
delete itr->second;
}
m_pUser.clear();
// Party Array Delete
m_arParty.DeleteAllData();
m_bFirstServerFlag = false;
TRACE("*** DeleteAllUserList - End *** \n");
printf("[ DELETE All User List ]\n");
}
void CServerDlg::Send(Packet * pkt)
{
m_socketMgr.SendAll(pkt);
}
void CServerDlg::GameServerAcceptThread()
{
m_socketMgr.RunServer();
}
bool CServerDlg::AddObjectEventNpc(_OBJECT_EVENT* pEvent, MAP * pMap)
{
int sSid = 0;
if (pEvent->sType == OBJECT_GATE
|| pEvent->sType == OBJECT_GATE2
|| pEvent->sType == OBJECT_GATE_LEVER
|| pEvent->sType == OBJECT_ANVIL
|| pEvent->sType == OBJECT_ARTIFACT)
sSid = pEvent->sIndex;
else
sSid =pEvent->sControlNpcID;
if (sSid <= 0)
return false;
CNpcTable * pNpcTable = m_arNpcTable.GetData(sSid);
if(pNpcTable == nullptr) {
//printf("#### AddObjectEventNpc Fail : [sid = %d], zone=%d #####\n", pEvent->sIndex, zone_number);
return false;
}
CNpc *pNpc = new CNpc();
pNpc->m_byMoveType = 0;
pNpc->m_byInitMoveType = 0;
pNpc->m_byBattlePos = 0;
pNpc->m_byObjectType = SPECIAL_OBJECT;
pNpc->m_byGateOpen = (pEvent->sStatus == 1);
pNpc->m_bZone = pMap->m_nZoneNumber;
pNpc->SetPosition(pEvent->fPosX, pEvent->fPosY, pEvent->fPosZ);
pNpc->m_nInitMinX = (int)pEvent->fPosX-1;
pNpc->m_nInitMinY = (int)pEvent->fPosZ-1;
pNpc->m_nInitMaxX = (int)pEvent->fPosX+1;
pNpc->m_nInitMaxY = (int)pEvent->fPosZ+1;
pNpc->Load(m_sMapEventNpc++, pNpcTable, false);
pNpc->m_pMap = pMap;
pNpc->SetUnitEventRoom(pEvent->RoomEvent);
pNpc->SetNPCEventRoom(pEvent->RoomEvent);
if (pNpc->GetMap() == nullptr
|| !m_arNpc.PutData(pNpc->GetID(), pNpc))
{
m_sMapEventNpc--;
printf("Npc PutData Fail - %d\n", pNpc->GetProtoID());
delete pNpc;
return false;
}
m_TotalNPC = m_sMapEventNpc;
return true;
}
CNpc * CServerDlg::SpawnEventNpc(uint16 sSid, bool bIsMonster, uint8 byZone, float fX, float fY, float fZ, uint16 Radius, uint16 sDuration, uint8 nation, int16 socketID, uint16 nEventRoom, bool nIsPet, std::string strPetName, std::string strUserName, uint64 nSerial, uint16 UserId /* = -1*/)
{
static float fRandom_X = 0.0f, fRandom_Z = 0.0f;
CNpcTable * proto = nullptr;
MAP * pZone = GetZoneByID(byZone);
if (pZone == nullptr)
return nullptr;
if (bIsMonster)
proto = m_arMonTable.GetData(sSid);
else
proto = m_arNpcTable.GetData(sSid);
if (proto == nullptr)
return nullptr;
Guard lock(m_npcThreadLock);
auto itr = m_arNpcThread.find(byZone);
if (itr == m_arNpcThread.end())
return false;
CNpc * pNpc = new CNpc();
pNpc->nIsPet = nIsPet;
pNpc->strUserName = strUserName;
pNpc->strPetName = strPetName;
pNpc->nSerial = nSerial;
pNpc->UserId = UserId;
pNpc->m_bIsEventNpc = true;
pNpc->m_byMoveType = (bIsMonster ? 1 : 0);
pNpc->m_byInitMoveType = pNpc->m_byMoveType;
pNpc->m_bZone = byZone;
uint16 nRandom = Radius;
if (nRandom <= 0)
fRandom_X = (float)fX;
else
fRandom_X = (float)(myrand((fX - nRandom) * 10, (fX + nRandom) * 10) / 10);
nRandom = Radius;
if (nRandom <= 0)
fRandom_Z = (float)fZ;
else
fRandom_Z = (float)(myrand((fZ - nRandom) * 10, (fZ + nRandom) * 10) / 10);
pNpc->SetPosition(fRandom_X, 0.0f, fRandom_Z);
pNpc->m_pMap = pZone;
pNpc->m_oSocketID = socketID;
pNpc->m_bEventRoom = nEventRoom;
pNpc->SetNPCEventRoom(nEventRoom);
pNpc->SetUnitEventRoom(nEventRoom);
uint16 myID = ++m_TotalNPC;
Guard lock2(m_freeIdsLock);
if(freeIDs.size() > 0)
{
myID = freeIDs.back();
freeIDs.pop_back();
myID -= NPC_BAND;
}else
myID = ++MaxMonsterID;
pNpc->Load(myID, proto, bIsMonster, nation);
pNpc->m_byBattlePos = 0;
if(pNpc->GetProtoID() != 7032
&& pNpc->GetProtoID() != 7033
&& pNpc->GetProtoID() != 7034
&& pNpc->GetProtoID() != 8110)
pNpc->InitPos();
if(pNpc->GetZoneID() == ZONE_STONE1)
{
if((pNpc->GetSPosX() / 10) == 126 && pNpc->GetProtoID() == 7032)
{
pNpc->SetPosition(126.2194f,-0.34175f,209.0543f);
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
if((pNpc->GetSPosX() / 10) == 97 && pNpc->GetProtoID() == 7032)
{
pNpc->SetPosition(97.34771f,-0.13837f,128.5445f);
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
}
if(pNpc->GetZoneID() == ZONE_STONE2)
{
if((pNpc->GetSPosX() / 10) == 128 && pNpc->GetProtoID() == 7033)
{
pNpc->SetPosition(128.124f,-0.468628f,208.7566f);
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
if((pNpc->GetSPosX() / 10) == 152 && pNpc->GetProtoID() == 7033)
{
pNpc->SetPosition(152.245f,0.216793f,123.7196f);
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
if((pNpc->GetSPosX() / 10) == 99 && pNpc->GetProtoID() == 7033)
{
pNpc->SetPosition(99.81824f,7.528255f,46.26767f);
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
}
if(pNpc->GetZoneID() == ZONE_STONE3)
{
if((pNpc->GetSPosX() / 10) == 131 && pNpc->GetProtoID() == 7034)
{
pNpc->SetPosition(131.124f,-0.440191f,208.4271f);
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
if((pNpc->GetSPosX() / 10) == 144 && pNpc->GetProtoID() == 7034)
{
pNpc->SetPosition(144.4414f,0.366179f,121.3319f);
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
if((pNpc->GetSPosX() / 10) == 100 && pNpc->GetProtoID() == 7034)
{
pNpc->SetPosition(100.9698f,1.411695f,46.68652f);
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
}
if(pNpc->GetZoneID() == ZONE_JURAD_MOUNTAIN)
{
if(pNpc->GetProtoID() == 8110)
{
pNpc->m_byMoveType = 4;
pNpc->m_sMaxPathCount = 0;
}
if((pNpc->GetSPosX() / 10) == 512 && (pNpc->GetSPosZ() / 10) == 256 && pNpc->GetProtoID() == 8110)
pNpc->SetPosition(512.10f,18.80f,256.40f);
if((pNpc->GetSPosX() / 10) == 512 && (pNpc->GetSPosZ() / 10) == 767 && pNpc->GetProtoID() == 8110)
pNpc->SetPosition(512.10f,18.80f,767.10f);
if((pNpc->GetSPosX() / 10) == 715 && pNpc->GetProtoID() == 8110)
pNpc->SetPosition(715.30f,18.80f,172.00f);
if((pNpc->GetSPosX() / 10) == 799 && pNpc->GetProtoID() == 8110)
pNpc->SetPosition(799.80f,18.80f,375.60f);
if((pNpc->GetSPosX() / 10) == 308 && pNpc->GetProtoID() == 8110)
pNpc->SetPosition(308.50f,18.80f,847.80f);
if((pNpc->GetSPosX() / 10) == 224 && pNpc->GetProtoID() == 8110)
pNpc->SetPosition(224.00f,18.80f,644.90f);
}
pNpc->Init();
m_arNpc.PutData(pNpc->GetID(), pNpc);
itr->second->AddNPC(pNpc);
pNpc->m_nInitMinX = pNpc->m_nLimitMinX = (int)fX - nRandom;
pNpc->m_nInitMinY = pNpc->m_nLimitMinZ = (int)fZ - nRandom;
pNpc->m_nInitMaxX = pNpc->m_nLimitMaxX = (int)fX + nRandom;
pNpc->m_nInitMaxY = pNpc->m_nLimitMaxZ = (int)fZ + nRandom;
if (sDuration > 0) // Duration npc or monsters
{
_NPC_LIVE_TIME * pData = new _NPC_LIVE_TIME();
pData->nIndex = EventNpcID++;
pData->SocketID = socketID;
pData->Nid = pNpc->m_sNid;
pData->Duration = sDuration;
pData->SpawnedTime = int32(UNIXTIME);
if (!m_NpcLiveTimeArray.PutData(pData->nIndex,pData))
delete pData;
}
return pNpc;
}
void CServerDlg::NpcUpdate(uint16 sSid, bool bIsMonster, uint8 byGroup, uint16 sPid)
{
CNpcTable * proto = nullptr;
if (bIsMonster)
proto = m_arMonTable.GetData(sSid);
else
proto = m_arNpcTable.GetData(sSid);
if (proto == nullptr)
return;
if (byGroup > 0)
proto->m_byGroupSpecial = byGroup;
if (sPid > 0)
proto->m_sPid = sPid;
}
MAP * CServerDlg::GetZoneByID(int zonenumber)
{
return g_arZone.GetData(zonenumber);
}
void CServerDlg::GetServerInfoIni()
{
CIni ini("./AIServer.ini");
ini.GetString("ODBC", "GAME_DSN", "KO_GAME", m_strGameDSN, false);
ini.GetString("ODBC", "GAME_UID", "username", m_strGameUID, false);
ini.GetString("ODBC", "GAME_PWD", "password", m_strGamePWD, false);
CIni ini2(CONF_GAME_SERVER);
KarusBaseMilitaryCampCount = ini2.GetInt("MILITARY_CAMP","ZONE_KARUS_BASE",0);
if (KarusBaseMilitaryCampCount > 3)
KarusBaseMilitaryCampCount = 3;
ElmoradBaseMilitaryCampCount = ini2.GetInt("MILITARY_CAMP","ZONE_ELMORAD_BASE",0);
if (ElmoradBaseMilitaryCampCount > 3)
ElmoradBaseMilitaryCampCount = 3;
KarusEslantMilitaryCampCount = ini2.GetInt("MILITARY_CAMP","ZONE_KARUS_ESLANT",0);
if (KarusEslantMilitaryCampCount > 3)
KarusEslantMilitaryCampCount = 3;
ElmoradEslantMilitaryCampCount = ini2.GetInt("MILITARY_CAMP","ZONE_ELMORAD_ESLANT",0);
if (ElmoradEslantMilitaryCampCount > 3)
ElmoradEslantMilitaryCampCount = 3;
MoradonMilitaryCampCount = ini2.GetInt("MILITARY_CAMP","ZONE_MORADON",0);
if (MoradonMilitaryCampCount > 5)
MoradonMilitaryCampCount = 5;
m_AIServerPort = ini.GetInt("SETTINGS","PORT", 10020);
}
void CServerDlg::SendSystemMsg(std::string & pMsg, int type)
{
Packet result(AG_SYSTEM_MSG, uint8(type));
result << pMsg;
Send(&result);
}
void CServerDlg::ResetBattleZone()
{
TRACE("ServerDlg - ResetBattleZone() : start \n");
foreach_stlmap_nolock (itr, g_arZone)
{
MAP *pMap = itr->second;
if (pMap == nullptr || pMap->m_byRoomEvent == 0)
continue;
//if( pMap->IsRoomStatusCheck() == true ) continue; // <20><>ü<EFBFBD><C3BC><EFBFBD><EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD> <20>Ǿ<EFBFBD><C7BE>ٸ<EFBFBD>
pMap->InitializeRoom();
}
TRACE("ServerDlg - ResetBattleZone() : end \n");
}
CServerDlg::~CServerDlg()
{
g_bNpcExit = true;
printf("Waiting for NPC threads to exit...");
Guard lock(m_npcThreadLock);
foreach (itr, m_arNpcThread)
{
CNpcThread * pThread = itr->second;
pThread->m_thread.waitForExit();
delete pThread;
}
m_arNpcThread.clear();
printf(" exited.\n");
printf("Waiting for zone event thread to exit...");
m_zoneEventThread.waitForExit();
printf(" exited.\n");
printf("Waiting for timer threads to exit...");
foreach (itr, g_timerThreads)
{
(*itr)->waitForExit();
delete (*itr);
}
printf(" exited.\n");
printf("Freeing user sessions...");
for (int i = 0; i < MAX_USER; i++)
{
if (m_pUser[i] != nullptr)
{
delete m_pUser[i];
m_pUser[i] = nullptr;
}
}
printf(" done.\n");
m_ZoneNpcList.clear();
printf("Shutting down socket system...");
m_socketMgr.Shutdown();
printf(" done.\n");
}