#include "StdAfx.h" #include "npcscript.h" #include "NPC_Common.h" #include "./util/FileLoader.h" #include "tokenizer.h" #include "Stage_Common.h" #include "BaseObject_Common.h" #include "Token.h" #include "Parser.h" #ifdef _CLIENT #include "GameResourceManager.h" #endif cNPCScript* cNPCScript::mpNPCScript = NULL; cNPCScript::cNPCScript() { /// ½Ì±ÛÅæ if( mpNPCScript ) { assert(NULL); } else { mpNPCScript = this; } mpNPCListMap = new cPointHashMap( 999 ); mpNPCRegenMap = new cPointHashMap( 999 ); mpModelNumberMap = new cPointHashMap( 10 ); mpNpcFuncMap = new cNpcFuncMap( 100 ); } cNPCScript::~cNPCScript() { } bool cNPCScript::Init() { /// NPC °íÀ¯ ¸®½ºÆ® ·Îµå if( !LoadNPCList() ) { assert(NULL); return false; } #ifndef _CLIENT if( LoadNPCStore() == false ) { assert(NULL); return false; } #endif return true; } bool cNPCScript::StageInit( unsigned short mapNumber, unsigned char levelMode ) { if( mapNumber == MAP_NONE ) { cPointHashMap* pNPCRegenMap = new cPointHashMap; for( unsigned short mapNum = MAP_MIN ; mapNum <= MAP_MAX ; ++mapNum ) { /// ¸Ê¿¡ À§Ä¡ÇÑ NPC ·Îµå if( !LoadNPCRegen( mapNum, levelMode, pNPCRegenMap ) ) { assert(NULL); return false; } } mpNPCRegenMap->Insert( levelMode, pNPCRegenMap ); } else { cPointHashMap* pNPCRegenMap = new cPointHashMap; /// ¸Ê¿¡ À§Ä¡ÇÑ NPC ·Îµå if( !LoadNPCRegen( mapNumber, levelMode, pNPCRegenMap ) ) { assert(NULL); return false; } mpNPCRegenMap->Insert( levelMode, pNPCRegenMap ); } return true; } void cNPCScript::Release() { if( mpNpcFuncMap ) { cNpcFuncMap::cIterator i = mpNpcFuncMap->Begin(); cNpcFuncMap::cIterator end = mpNpcFuncMap->End(); for( ; i != end; ++i ) { sNpcFuncData* data = (sNpcFuncData*)(i->mSecond); SAFE_DELETE( data ); } mpNpcFuncMap->Clear(); } SAFE_DELETE( mpNpcFuncMap ); ReleaseModelNumber(); ReleaseNPCRegen(); ReleaseNPCList(); } bool cNPCScript::LoadNPCList() { cFileLoader loader; cString pathName = "./Script/Resource/NPCList.txt"; if( loader.Open( pathName, true ) == false ) { assert( 0 && "failed to load NPCList.txt" ); cString msg; msg.Format("[%s]", pathName.Cstr() ); MessageBoxA( NULL, msg.Cstr(), "fail to open file", MB_OK | MB_ICONERROR ); return false; } cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() ); cString str; while( tokenizer.IsEnd() == false ) { /// NPC ¹øÈ£ if( tokenizer.GetNext( &str ) == false ) { goto ERR; } unsigned long npcClassIdx = str.ToInt(); /// NPC À̸§ if( tokenizer.GetNext( &str ) == false ) { goto ERR; } TCHAR name[32]; // #ifdef _CLIENT // _stprintf_s( name, _T( "%s" ), GAMERESOURCEMAN->GetNpcName( str.ToInt() ) ); // #else _stprintf_s( name, _T( "%d" ), str.ToInt() ); //#endif /// npc type if( tokenizer.GetNext( &str ) == false ) { goto ERR; } short type = (short)str.ToInt(); /// NPC Á÷¾÷ À妽º if( tokenizer.GetNext( &str ) == false ) { goto ERR; } TCHAR jobName[32]; // #ifdef _CLIENT // _stprintf_s( jobName, _T( "%s" ), GAMERESOURCEMAN->GetNpcName( str.ToInt() ) ); // #else _stprintf_s( jobName, _T( "%d" ), str.ToInt() ); //#endif /// NPC ¾Ö´Ï¸ÞÀÌ¼Ç ÆÄÀÏ ¹øÈ£(KFM)] if( tokenizer.GetNext( &str ) == false ) { goto ERR; } unsigned int modelIndex = str.ToInt(); /// NPC ¹øÈ£ if( tokenizer.GetNext( &str ) == false ) { goto ERR; } unsigned long jobIconLarge = str.ToInt(); if( tokenizer.GetNext( &str ) == false ) { goto ERR; } unsigned long jobIconSmall = str.ToInt(); if( tokenizer.GetNext( &str ) == false ) { goto ERR; } unsigned long jobIconIndexTarget = str.ToInt(); sNPCList* pList = new sNPCList; pList->mNpcClassIdx = npcClassIdx; _stprintf_s( pList->mName, _T( "%s" ), name ); _stprintf_s( pList->mJobName, _T( "%s" ), jobName ); pList->mType = type; pList->mModelIndex = modelIndex; pList->mJobIconIndexLarge = jobIconLarge; pList->mJobIconIndexSmall = jobIconSmall; pList->mJobIconIndexTarget = jobIconIndexTarget; /// ÇØ½¬¿¡ NPC º°·Î ±â·Ï if( mpNPCListMap->Insert( pList->mNpcClassIdx, pList ) == false ) { assert(0); return false; } } return true; ERR: cString msg; msg.Format("[%s] [Line:%d]", pathName.Cstr(), tokenizer.mLine ); MessageBoxA( NULL, msg.Cstr(), "fail to parser", MB_OK | MB_ICONERROR ); assert(0); return false; } sNPCList* cNPCScript::GetNPCList( unsigned long idx ) { sNPCList* NPClist; NPClist = (sNPCList*)mpNPCListMap->GetAt( idx ); if( !NPClist ) { assert(NULL); return NULL; } return NPClist; } void cNPCScript::ReleaseNPCList() { if( mpNPCListMap ) { sNPCList* pInfo = NULL; cPointHashMap::cIterator i = mpNPCListMap->Begin(); cPointHashMap::cIterator end = mpNPCListMap->End(); for( ; i != end; ++i ) { pInfo = (sNPCList*)((*i).mSecond); if( pInfo ) { delete pInfo; pInfo = NULL; } } mpNPCListMap->Clear(); SAFE_DELETE( mpNPCListMap ); } } bool cNPCScript::LoadNPCRegen( unsigned short mapNumber, unsigned char levelMode, tPointerHashMap* pNPCRegenMap ) { if( pNPCRegenMap == NULL ) return false; cFileLoader loader; cString pathName; pathName.Format( "./Script/Resource/NPCRegen%d_%d.txt", mapNumber, levelMode ); unsigned long insertidx = 1; if( loader.Open( pathName, true ) == false ) { /// ÆÄÀÏÀ» ÀÐÁö ¸øÇϸé Á¤»ó¸®ÅÏ return true; } if( loader.GetSize() == 0 ) return true; cTokenizer tokenizer( loader.GetBufferPtr(), loader.GetSize(), " \t\r\n", pathName.Cstr() ); cString str; cHashSet* pMondelNumberHashSet = (cHashSet*)mpModelNumberMap->GetAt( mapNumber ); if( pMondelNumberHashSet == NULL ) { pMondelNumberHashSet = new cHashSet; /// ¸Ê¿¡ ÇØ´çÇÏ´Â ¸ðµ¨ Á¤º¸ ÇØ½¬¼ÂÀ» ±â·Ï if( mpModelNumberMap->Insert( mapNumber, pMondelNumberHashSet ) == false ) { assert(NULL); return false; } } while( tokenizer.IsEnd() == false ) { /// NPC ¹øÈ£(°íÀ¯¹øÈ£ ¾Æ´Ô-Á¾·ù¹øÈ£) if( tokenizer.GetNext( &str ) == false ) { return false; } unsigned long npcClassIdx = str.ToInt(); /// NPC »ý¼ºÀ§Ä¡ x if( tokenizer.GetNext( &str ) == false ) { return false; } float posX = str.ToFloat(); /// NPC »ý¼ºÀ§Ä¡ y if( tokenizer.GetNext( &str ) == false ) { return false; } float posY = str.ToFloat(); /// NPC ¹æÇâ if( tokenizer.GetNext( &str ) == false ) { return false; } float direction = str.ToFloat(); sNPCRegen* pList = new sNPCRegen; pList->mNpcClassIdx = npcClassIdx; pList->mMapNumber = mapNumber; pList->mPosX = posX; pList->mPosY = posY; pList->mDirection = S_ToRadian( direction ); /// npc °íÀ¯¹øÈ£°¡ ¸Ê³Ñ¹ö ÀÚ¸®±îÁö ħ¹üÇϴ°ÍÀ» ¹æÁö if( MAPNUMBER_UNIT <= insertidx ) { assert(NULL); return false; } /// NPC °íÀ¯ À妽º¸¦ °ãÄ¡Áö ¾Ê°Ô ÇϱâÀ§ÇØ ¸Ê³Ñ¹ö¸¦ Æ÷ÇÔÇØ °íÀ¯¹øÈ£¸¦ ¸¸µé¾ú´Ù. if( pNPCRegenMap->Insert( ( mapNumber * MAPNUMBER_UNIT ) + insertidx, pList ) == false ) { assert(0); return false; } ++insertidx; /// Ŭ¶óÀÌ¾ðÆ®¿¡ loadstage½ÃÁ¡¿¡ ¸ÕÀú µ¥ÀÌŸ¸¦ Àоî¿Í¾ß ÇÒ npc ¸ñ·Ï ±â·Ï if( pMondelNumberHashSet->GetCount( pList->mNpcClassIdx ) == 0 ) { pMondelNumberHashSet->Insert( pList->mNpcClassIdx ); } } return true; } sNPCRegen* cNPCScript::GetNPCRegen( unsigned char levelMode, unsigned long idx ) { if( mpNPCRegenMap == NULL ) return NULL; cPointHashMap* pRegenMap = (cPointHashMap*)mpNPCRegenMap->GetAt( levelMode ); if( pRegenMap == NULL ) return NULL; sNPCRegen* pNPCRegen; pNPCRegen = (sNPCRegen*)pRegenMap->GetAt( idx ); /// ¾ø´Â °æ¿ì NPC¸¦ »èÁ¦ ÇѰæ¿ì if( !pNPCRegen ) { return NULL; } return pNPCRegen; } void cNPCScript::ReleaseNPCRegen() { if( mpNPCRegenMap ) { cPointHashMap::cIterator iT = mpNPCRegenMap->Begin(); cPointHashMap::cIterator eT = mpNPCRegenMap->End(); for( ; iT != eT ; ++iT ) { cPointHashMap* pRegenMap = (cPointHashMap*)(*iT).mSecond; if( pRegenMap == NULL ) continue; sNPCRegen* pInfo = NULL; cPointHashMap::cIterator i = pRegenMap->Begin(); cPointHashMap::cIterator end = pRegenMap->End(); for( ; i != end; ++i ) { pInfo = (sNPCRegen*)((*i).mSecond); if( pInfo ) { delete pInfo; pInfo = NULL; } } pRegenMap->Clear(); SAFE_DELETE( pRegenMap ); } mpNPCRegenMap->Clear(); SAFE_DELETE( mpNPCRegenMap ); } } void cNPCScript::ReleaseModelNumber() { if( mpModelNumberMap ) { cHashSet* pInfo = NULL; cPointHashMap::cIterator i = mpModelNumberMap->Begin(); cPointHashMap::cIterator end = mpModelNumberMap->End(); for( ; i != end; ++i ) { pInfo = (cHashSet*)(*i).mSecond; if( pInfo ) { SAFE_DELETE(pInfo); } } mpModelNumberMap->Clear(); SAFE_DELETE( mpModelNumberMap ); } } bool cNPCScript::LoadNPCStore() { /// ÆÄÀÏ ·Îµù cFileLoader loader; cString pathName; pathName.Format( "./Script/Resource/NPC_Func.txt" ); if( loader.Open( pathName, true ) == false ) { return false; } /// ·º¼­¿¡ ¹äÁÖ°í ÆÄ½Ì cToken token; cNpcLexer lexer( loader.GetBufferPtr(), loader.GetSize() ); cParser parser( &lexer, pathName ); while( lexer.IsEnd() == false ) { lexer.GetNextToken( &token ); switch( token.mType ) { case eTOKEN_ERROR: return false; case eTOKEN_NULL: continue; case eTOKEN_NPC_TELLING: { /// Npc ´ëÈ­ À妽º unsigned int i = parser.ParseInt(); /// ¼¼ºÎ·Îµù sNpcFuncData* data = new sNpcFuncData; memset( data, 0, sizeof(sNpcFuncData) ); LoadNpcStoreDetail( parser, data ); /// Npc ´ëÈ­ ¹è¿­¿¡ Ãß°¡ if( mpNpcFuncMap->Insert( i, data ) == false ) { assert( 0 && "failed to insert mpNpcFuncMap, maybe already exist" ); return false; } } break; default: assert( 0 && "invalid token" ); return false; } } return true; } bool cNPCScript::LoadNpcStoreDetail( cParser& parser, sNpcFuncData* data ) { if( parser.ExpectTokenString( "{" ) == false ) return false; cToken token; cLexer* lexer = parser.GetLexer(); unsigned long openCnt = 1; int& count = data->mFuncCount; while( lexer->GetNextToken( &token ) ) { if( token == "{" ) ++openCnt; if( token == "}" ) --openCnt; if( openCnt == 0 ) break; switch( token.mType ) { case eTOKEN_NPC_STORE: { data->mFunc[count] = NPC_FUNC_STORE; assert( count < NPC_FUNCHAVE_MAX ); if( count < NPC_FUNCHAVE_MAX ) count++; } break; case eTOKEN_NPC_WAREHOUSE: { data->mFunc[count] = NPC_FUNC_WAREHOUSE; assert( count < NPC_FUNCHAVE_MAX ); if( count < NPC_FUNCHAVE_MAX ) count++; } break; case eTOKEN_NPC_GUILD: { data->mFunc[count] = NPC_FUNC_GUILD; assert( count < NPC_FUNCHAVE_MAX ); if( count < NPC_FUNCHAVE_MAX ) count++; } break; case eTOKEN_NPC_FORTUNETAROT: { data->mFunc[count] = NPC_FUNC_FORTUNETAROT; assert( count < NPC_FUNCHAVE_MAX ); if( count < NPC_FUNCHAVE_MAX ) count++; /// Ÿ·Î ¿ä±ÝÁ¤º¸ data->mTarotPrice = (unsigned long)parser.ParseInt(); // Ä«µå Á¤º¸ if( parser.ExpectTokenString( "{" ) == false ) return false; int cnt = 0; while( token != "}" ) { lexer->GetNextToken( &token ); if( token.mType == eTOKEN_INT ) { data->mTarotIndex[cnt] = (unsigned long)token.ToInt(); cnt++; } if( cnt > 22 ) { assert(0); break; } } } break; case eTOKEN_NPC_TAROT: { // À¯ÀúÇüÅ Ÿ·Ô data->mFunc[count] = NPC_FUNC_TAROT; assert( count < NPC_FUNCHAVE_MAX ); if( count < NPC_FUNCHAVE_MAX ) count++; /// Ÿ·Î ¿ä±ÝÁ¤º¸ data->mTarotPrice = (unsigned long)parser.ParseInt(); // Ä«µå Á¤º¸ if( parser.ExpectTokenString( "{" ) == false ) return false; int cnt = 0; while( token != "}" ) { lexer->GetNextToken( &token ); if( token.mType == eTOKEN_INT ) { data->mTarotIndex[cnt] = (unsigned long)token.ToInt(); cnt++; } if( cnt > 22 ) { assert(0); break; } } } break; case eTOKEN_NPC_FORTUNESPREAD: { /// º¸À¯ÇÑ ½ºÇÁ·¹µå À妽º if( parser.ExpectTokenString( "{" ) == false ) return false; int cnt = 0; while( token != "}" ) { lexer->GetNextToken( &token ); if( token.mType == eTOKEN_INT ) { data->mSpreadIndex[cnt] = (unsigned long)token.ToInt(); cnt++; } if( cnt > 5 ) { assert(0); break; } } data->mSpreadCount = cnt; } break; case eTOKEN_NPC_SPREAD: { /// º¸À¯ÇÑ ½ºÇÁ·¹µå À妽º if( parser.ExpectTokenString( "{" ) == false ) return false; int cnt = 0; while( token != "}" ) { lexer->GetNextToken( &token ); if( token.mType == eTOKEN_INT ) { data->mSpreadIndex[cnt] = (unsigned long)token.ToInt(); cnt++; } if( cnt > 5 ) { assert(0); break; } } data->mSpreadCount = cnt; } break; case eTOKEN_NPC_DEAL: { data->mFunc[count] = NPC_FUNC_DEAL; assert( count < NPC_FUNCHAVE_MAX ); if( count < NPC_FUNCHAVE_MAX ) count++; } break; case eTOKEN_NPC_THEME: { data->mFunc[count] = NPC_FUNC_THEME; assert( count < NPC_FUNCHAVE_MAX ); if ( count < NPC_FUNCHAVE_MAX ) count++; /// Å׸¶ ´øÁ¯ À妽º Á¤º¸ data->mThemeIndex = (unsigned long)parser.ParseInt(); } break; case eTOKEN_NPC_SKILLPREVIEW: { data->mFunc[count] = NPC_FUNC_SKILLPREVIEW; assert( count < NPC_FUNCHAVE_MAX ); if ( count < NPC_FUNCHAVE_MAX ) count++; // Á÷¾÷ Á¤º¸ À妽º µÎ°³ parser.ParseInt(); parser.ParseInt(); } break; } } return 0; } bool cNPCScript::IsHaveNpcFunc( unsigned long classIdx, unsigned int func ) { sNpcFuncData* data = (sNpcFuncData*)mpNpcFuncMap->GetAt( classIdx ); if( !data ) { assert(0); return false; } for( int i = 0; i < data->mFuncCount; ++i ) { if( data->mFunc[i] == func ) return true; } return false; } sNpcFuncData* cNPCScript::GetNpcFuncData( unsigned long classIdx ) { return (sNpcFuncData*)mpNpcFuncMap->GetAt( classIdx ); } cNpcLexer::cNpcLexer( const char* buffer, unsigned int size ) : cLexer( buffer, size ) { BindKeyword( "npc_telling", eTOKEN_NPC_TELLING ); BindKeyword( "store", eTOKEN_NPC_STORE ); BindKeyword( "warehouse", eTOKEN_NPC_WAREHOUSE ); BindKeyword( "default", eTOKEN_NPC_DEFAULT ); BindKeyword( "disjoint", eTOKEN_NPC_DISJOINT ); BindKeyword( "guild", eTOKEN_NPC_GUILD ); BindKeyword( "fortunetarot", eTOKEN_NPC_FORTUNETAROT ); BindKeyword( "tarot", eTOKEN_NPC_TAROT ); BindKeyword( "deal", eTOKEN_NPC_DEAL ); BindKeyword( "fortunespread", eTOKEN_NPC_SPREAD ); BindKeyword( "spread", eTOKEN_NPC_SPREAD ); BindKeyword( "quest", eTOKEN_NPC_QUEST ); BindKeyword( "theme", eTOKEN_NPC_THEME ); BindKeyword( "skillpreview", eTOKEN_NPC_SKILLPREVIEW ); BindKeyword( "text", eTOKEN_NPC_TEXT ); BindKeyword( "page", eTOKEN_NPC_PAGE ); BindKeyword( "new", eTOKEN_NPC_NEW ); BindKeyword( "play", eTOKEN_NPC_PLAY ); BindKeyword( "complete", eTOKEN_NPC_COMPLETE ); BindKeyword( "answer", eTOKEN_NPC_ANSWER ); BindKeyword( "sound", eTOKEN_NPC_SOUND ); BindKeyword( "scene", eTOKEN_NPC_SCENE ); BindKeyword( "next", eTOKEN_NPC_NEXT ); BindKeyword( "EVENT_YES", eTOKEN_NPC_EVENTYES ); BindKeyword( "EVENT_REWARD", eTOKEN_NPC_EVENTREWARD ); BindKeyword( "EVENT_COMPLETE", eTOKEN_NPC_EVENTCOMPLETE ); BindKeyword( "event_yes", eTOKEN_NPC_EVENTYES ); BindKeyword( "event_reward", eTOKEN_NPC_EVENTREWARD ); BindKeyword( "event_complete", eTOKEN_NPC_EVENTCOMPLETE ); }