// Npc Thread 를 만든다. BOOL CServerDlg::CreateNpcThread() { BOOL bMoveNext = TRUE; int nSerial = m_sMapEventNpc; int nPathSerial = 1; int nNpcCount = 0; int i=0, j=0; int nRandom = 0, nServerNum = 0; double dbSpeed = 0; m_TotalNPC = 0; // DB에 있는 수 m_CurrentNPC = 0; m_CurrentNPCError = 0; CNpcTable* pNpcTable = NULL; CRoomEvent* pRoom = NULL; CNpcPosSet NpcPosSet; char szPath[500]; char szX[5]; char szZ[5]; float fRandom_X = 0.0f; float fRandom_Z = 0.0f; int nMonsterNumber = 0; try { if(NpcPosSet.IsOpen()) NpcPosSet.Close(); if(!NpcPosSet.Open()) { AfxMessageBox(_T("MONSTER_POS DB Open Fail!")); return FALSE; } if(NpcPosSet.IsBOF()) { AfxMessageBox(_T("MONSTER_POS DB Empty!")); return FALSE; } NpcPosSet.MoveFirst(); while(!NpcPosSet.IsEOF()) { nMonsterNumber = NpcPosSet.m_NumNPC; //if( NpcPosSet.m_ZoneID == 101 ) { // 테스트를 위해서,, // nMonsterNumber = 1; //if(nMonsterNumber > 4) { // nMonsterNumber = nMonsterNumber / 4; //} //} nServerNum = 0; nServerNum = GetServerNumber( NpcPosSet.m_ZoneID ); if( m_byZone == nServerNum || m_byZone == UNIFY_ZONE) { for(j=0; j<nMonsterNumber; j++) { CNpc* pNpc = new CNpc(); pNpc->m_byMoveType = NpcPosSet.m_ActType; pNpc->m_byInitMoveType = NpcPosSet.m_ActType; bool bMonster = (NpcPosSet.m_ActType < 100); if (bMonster) pNpcTable = m_arMonTable.GetData(NpcPosSet.m_NpcID); else { pNpc->m_byMoveType = NpcPosSet.m_ActType - 100; //pNpc->m_byInitMoveType = NpcPosSet.m_ActType - 100; pNpcTable = m_arNpcTable.GetData(NpcPosSet.m_NpcID); } if (pNpcTable == NULL) { char buff[128] = {0}; sprintf(buff, "NPC %d not found in %s table.", pNpc->m_sNid, bMonster ? "K_MONSTER" : "K_NPC"); AfxMessageBox(buff); delete pNpc; return FALSE; } pNpc->Load(nSerial++, pNpcTable); pNpc->m_byBattlePos = 0; if(pNpc->m_byMoveType >= 2) { pNpc->m_byBattlePos = myrand( 1, 3 ); pNpc->m_byPathCount = nPathSerial++; } pNpc->InitPos(); if( bMoveNext ) { bMoveNext = FALSE; nNpcCount = NpcPosSet.m_NumNPC; } //////// MONSTER POS //////////////////////////////////////// pNpc->m_bCurZone = NpcPosSet.m_ZoneID; // map에 몬스터의 위치를 랜덤하게 위치시킨다.. (테스트 용 : 수정-DB에서 읽어오는데로 몬 위치 결정) nRandom = abs(NpcPosSet.m_LeftX - NpcPosSet.m_RightX); if(nRandom <= 1) fRandom_X = (float)NpcPosSet.m_LeftX; else { if(NpcPosSet.m_LeftX < NpcPosSet.m_RightX) fRandom_X = (float)myrand(NpcPosSet.m_LeftX, NpcPosSet.m_RightX); else fRandom_X = (float)myrand(NpcPosSet.m_RightX, NpcPosSet.m_LeftX); } nRandom = abs(NpcPosSet.m_TopZ - NpcPosSet.m_BottomZ); if(nRandom <= 1) fRandom_Z = (float)NpcPosSet.m_TopZ; else { if(NpcPosSet.m_TopZ < NpcPosSet.m_BottomZ) fRandom_Z = (float)myrand(NpcPosSet.m_TopZ, NpcPosSet.m_BottomZ); else fRandom_Z = (float)myrand(NpcPosSet.m_BottomZ, NpcPosSet.m_TopZ); } pNpc->m_fCurX = fRandom_X; pNpc->m_fCurY = 0; pNpc->m_fCurZ = fRandom_Z; pNpc->m_sRegenTime = NpcPosSet.m_RegTime * 1000; // 초(DB)단위-> 밀리세컨드로 pNpc->m_byDirection = NpcPosSet.m_byDirection; pNpc->m_sMaxPathCount = NpcPosSet.m_DotCnt; if( pNpc->m_byMoveType >= 2 && NpcPosSet.m_DotCnt == 0 ) { pNpc->m_byMoveType = 1; TRACE("##### ServerDlg:CreateNpcThread - Path type Error : nid=%d, sid=%d, name=%s, acttype=%d, path=%d #####\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byMoveType, pNpc->m_sMaxPathCount); } int index = 0; strcpy_s(szPath, sizeof(szPath), NpcPosSet.m_path); if(NpcPosSet.m_DotCnt != 0) { for(int l = 0; l<NpcPosSet.m_DotCnt; l++) { memset(szX, 0x00, 5); memset(szZ, 0x00, 5); GetString(szX, szPath, 4, index); GetString(szZ, szPath, 4, index); pNpc->m_PathList.pPattenPos[l].x = atoi(szX); pNpc->m_PathList.pPattenPos[l].z = atoi(szZ); // TRACE(" l=%d, x=%d, z=%d\n", l, pNpc->m_PathList.pPattenPos[l].x, pNpc->m_PathList.pPattenPos[l].z); } } //pNpc->m_byType = NpcPosSet.m_byType; pNpc->m_tItemPer = pNpcTable->m_tItemPer; // NPC Type pNpc->m_tDnPer = pNpcTable->m_tDnPer; // NPC Type pNpc->m_nInitMinX = pNpc->m_nLimitMinX = NpcPosSet.m_LeftX; pNpc->m_nInitMinY = pNpc->m_nLimitMinZ = NpcPosSet.m_TopZ; pNpc->m_nInitMaxX = pNpc->m_nLimitMaxX = NpcPosSet.m_RightX; pNpc->m_nInitMaxY = pNpc->m_nLimitMaxZ = NpcPosSet.m_BottomZ; // dungeon work pNpc->m_byDungeonFamily = NpcPosSet.m_DungeonFamily; pNpc->m_bySpecialType = NpcPosSet.m_SpecialType; pNpc->m_byRegenType = NpcPosSet.m_RegenType; pNpc->m_byTrapNumber = NpcPosSet.m_TrapNumber; if( pNpc->m_byDungeonFamily > 0 ) { pNpc->m_nLimitMinX = NpcPosSet.m_LimitMinX; pNpc->m_nLimitMinZ = NpcPosSet.m_LimitMinZ; pNpc->m_nLimitMaxX = NpcPosSet.m_LimitMaxX; pNpc->m_nLimitMaxZ = NpcPosSet.m_LimitMaxZ; } pNpc->m_pZone = GetZoneByID(pNpc->m_bCurZone); if (pNpc->GetMap() == NULL) { AfxMessageBox("Error : CServerDlg,, Invaild zone Index!!"); delete pNpc; return FALSE; } if( !m_arNpc.PutData( pNpc->m_sNid, pNpc) ) { TRACE("Npc PutData Fail - %d\n", pNpc->m_sNid); delete pNpc; pNpc = NULL; continue; } pNpc->SetUid(pNpc->m_fCurX, pNpc->m_fCurZ, pNpc->m_sNid + NPC_BAND); // if (pNpc->GetMap()->m_byRoomEvent > 0 && pNpc->m_byDungeonFamily > 0 ) { pRoom = pNpc->GetMap()->m_arRoomEventArray.GetData( pNpc->m_byDungeonFamily ); if (pRoom == NULL) { TRACE("Error : CServerDlg,, Map Room Npc Fail!! : nid=%d, sid=%d, name=%s, fam=%d, zone=%d\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byDungeonFamily, pNpc->m_bCurZone); AfxMessageBox("Error : CServerDlg,, Map Room Npc Fail!!"); delete pNpc; return FALSE; } int *pInt = new int; *pInt = pNpc->m_sNid; if( !pRoom->m_mapRoomNpcArray.PutData( pNpc->m_sNid, pInt ) ) { TRACE("### Map - Room Array MonsterNid Fail : nid=%d, sid=%d ###\n", pNpc->m_sNid, pNpc->m_proto->m_sSid); } } m_TotalNPC = nSerial; if(--nNpcCount > 0) continue; bMoveNext = TRUE; nNpcCount = 0; } } nPathSerial = 1; NpcPosSet.MoveNext(); } NpcPosSet.Close(); } catch(CDBException* e) { e->ReportError(); e->Delete(); return FALSE; } int step = 0, nThreadNumber = 0; CNpcThread* pNpcThread = NULL; foreach_stlmap (itr, m_arNpc) { if (step == 0) pNpcThread = new CNpcThread; CNpc *pNpc = pNpcThread->m_pNpc[step] = itr->second; pNpc->m_sThreadNumber = nThreadNumber; pNpc->Init(); ++step; if( step == NPC_NUM ) { pNpcThread->m_sThreadNumber = nThreadNumber++; pNpcThread->m_pThread = AfxBeginThread(NpcThreadProc, &(pNpcThread->m_ThreadInfo), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); m_arNpcThread.push_back( pNpcThread ); step = 0; } } if( step != 0 ) { pNpcThread->m_sThreadNumber = nThreadNumber++; pNpcThread->m_pThread = AfxBeginThread(NpcThreadProc, &(pNpcThread->m_ThreadInfo), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); m_arNpcThread.push_back( pNpcThread ); } m_pZoneEventThread = AfxBeginThread(ZoneEventThreadProc, (LPVOID)(this), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); //TRACE("m_TotalNPC = %d \n", m_TotalNPC); AddToList("[Monster Init - %d, threads=%d]", m_TotalNPC, m_arNpcThread.size()); return TRUE; }
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 = NULL; static CRoomEvent* pRoom = NULL; static char szPath[500]; static float fRandom_X = 0.0f, fRandom_Z = 0.0f; // 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, bDirection, bDotCnt; static uint16 sSid, sRegTime; static uint32 nServerNum; static int32 iLeftX, iTopZ, iRightX, iBottomZ, iLimitMinX, iLimitMinZ, iLimitMaxX, iLimitMaxZ; dbCommand->FetchByte(1, bZoneID); dbCommand->FetchUInt16(2, sSid); dbCommand->FetchByte(3, bActType); dbCommand->FetchByte(4, bRegenType); dbCommand->FetchByte(5, bDungeonFamily); dbCommand->FetchByte(6, bSpecialType); dbCommand->FetchByte(7, bTrapNumber); dbCommand->FetchInt32(8, iLeftX); dbCommand->FetchInt32(9, iTopZ); dbCommand->FetchInt32(10, iRightX); dbCommand->FetchInt32(11, iBottomZ); dbCommand->FetchInt32(12, iLimitMinZ); dbCommand->FetchInt32(13, iLimitMinX); dbCommand->FetchInt32(14, iLimitMaxX); dbCommand->FetchInt32(15, iLimitMaxZ); dbCommand->FetchByte(16, bNumNpc); dbCommand->FetchUInt16(17, sRegTime); dbCommand->FetchByte(18, bDirection); dbCommand->FetchByte(19, bDotCnt); dbCommand->FetchString(20, szPath, sizeof(szPath)); nServerNum = GetServerNumber(bZoneID); if (m_byZone == nServerNum || m_byZone == UNIFY_ZONE) { uint8 bPathSerial = 1; for (uint8 j = 0; j < bNumNpc; j++) { CNpc * pNpc = new CNpc(); pNpc->m_byMoveType = bActType; pNpc->m_byInitMoveType = bActType; bool bMonster = (bActType < 100); if (bMonster) { pNpcTable = m_arMonTable.GetData(sSid); } else { pNpc->m_byMoveType = bActType - 100; pNpcTable = m_arNpcTable.GetData(sSid); } if (pNpcTable == NULL) { printf("NPC %d not found in %s table.\n", pNpc->m_sNid, bMonster ? "K_MONSTER" : "K_NPC"); delete pNpc; return false; } pNpc->Load(m_TotalNPC++, pNpcTable); pNpc->m_byBattlePos = 0; if (pNpc->m_byMoveType >= 2) { pNpc->m_byBattlePos = myrand(1, 3); pNpc->m_byPathCount = bPathSerial++; } pNpc->InitPos(); pNpc->m_bCurZone = bZoneID; nRandom = abs(iLeftX - iRightX); if (nRandom <= 1) fRandom_X = (float)iLeftX; else { if (iLeftX < iRightX) fRandom_X = (float)myrand(iLeftX, iRightX); else fRandom_X = (float)myrand(iRightX, iLeftX); } nRandom = abs(iTopZ - iBottomZ); if (nRandom <= 1) fRandom_Z = (float)iTopZ; else { if (iTopZ < iBottomZ) fRandom_Z = (float)myrand(iTopZ, iBottomZ); else fRandom_Z = (float)myrand(iBottomZ, iTopZ); } pNpc->m_fCurX = fRandom_X; pNpc->m_fCurY = 0; pNpc->m_fCurZ = fRandom_Z; pNpc->m_sRegenTime = sRegTime * SECOND; pNpc->m_byDirection = bDirection; pNpc->m_sMaxPathCount = bDotCnt; if ((pNpc->m_byMoveType == 2 || pNpc->m_byMoveType == 3) && bDotCnt == 0) { pNpc->m_byMoveType = 1; TRACE("##### ServerDlg:CreateNpcThread - Path type Error : nid=%d, sid=%d, name=%s, acttype=%d, path=%d #####\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byMoveType, pNpc->m_sMaxPathCount); } if (bDotCnt > 0) { int index = 0; for (int l = 0; l < bDotCnt; l++) { 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; pNpc->m_PathList.pPattenPos[l].x = atoi(szX); pNpc->m_PathList.pPattenPos[l].z = atoi(szZ); } } pNpc->m_tItemPer = pNpcTable->m_tItemPer; // NPC Type pNpc->m_tDnPer = pNpcTable->m_tDnPer; // NPC Type pNpc->m_nInitMinX = pNpc->m_nLimitMinX = iLeftX; pNpc->m_nInitMinY = pNpc->m_nLimitMinZ = iTopZ; pNpc->m_nInitMaxX = pNpc->m_nLimitMaxX = iRightX; pNpc->m_nInitMaxY = pNpc->m_nLimitMaxZ = iBottomZ; // dungeon work pNpc->m_byDungeonFamily = bDungeonFamily; pNpc->m_bySpecialType = bSpecialType; pNpc->m_byRegenType = bRegenType; pNpc->m_byTrapNumber = bTrapNumber; if (pNpc->m_byDungeonFamily > 0) { pNpc->m_nLimitMinX = iLimitMinX; pNpc->m_nLimitMinZ = iLimitMinZ; pNpc->m_nLimitMaxX = iLimitMaxX; pNpc->m_nLimitMaxZ = iLimitMaxZ; } pNpc->m_pZone = GetZoneByID(pNpc->m_bCurZone); if (pNpc->GetMap() == NULL) { printf(_T("Error: NPC %d in zone %d that does not exist."), sSid, bZoneID); delete pNpc; return false; } if (!m_arNpc.PutData(pNpc->m_sNid, pNpc)) { --m_TotalNPC; TRACE("Npc PutData Fail - %d\n", pNpc->m_sNid); delete pNpc; continue; } pNpc->SetUid(pNpc->m_fCurX, pNpc->m_fCurZ, pNpc->m_sNid + NPC_BAND); if (pNpc->GetMap()->m_byRoomEvent > 0 && pNpc->m_byDungeonFamily > 0) { pRoom = pNpc->GetMap()->m_arRoomEventArray.GetData(pNpc->m_byDungeonFamily); if (pRoom == NULL) { printf("Error : CServerDlg,, Map Room Npc Fail!!\n"); delete pNpc; return false; } // this is why their CSTLMap class sucks. int *pInt = new int; *pInt = pNpc->m_sNid; if (!pRoom->m_mapRoomNpcArray.PutData(pNpc->m_sNid, pInt)) { delete pInt; TRACE("### Map - Room Array MonsterNid Fail : nid=%d, sid=%d ###\n", pNpc->m_sNid, pNpc->m_proto->m_sSid); } } } } return true; }