#include "stdafx.h" #include #include "questmanager.h" #include "questlua.h" #include "config.h" #include "desc.h" #include "char.h" #include "char_manager.h" #include "buffer_manager.h" #include "db.h" #include "xmas_event.h" #include "locale_service.h" #include "regen.h" #include "affect.h" #include "guild.h" #include "guild_manager.h" #include "sectree_manager.h" #undef sys_err #ifndef __WIN32__ #define sys_err(fmt, args...) quest::CQuestManager::instance().QuestError(__FUNCTION__, __LINE__, fmt, ##args) #else #define sys_err(fmt, ...) quest::CQuestManager::instance().QuestError(__FUNCTION__, __LINE__, fmt, __VA_ARGS__) #endif namespace quest { using namespace std; string ScriptToString(const string& str) { lua_State* L = CQuestManager::instance().GetLuaState(); int x = lua_gettop(L); int errcode = lua_dobuffer(L, ("return "+str).c_str(), str.size()+7, "ScriptToString"); string retstr; if (!errcode) { if (lua_isstring(L,-1)) retstr = lua_tostring(L, -1); } else { sys_err("LUA ScriptRunError (code:%d src:[%s])", errcode, str.c_str()); } lua_settop(L,x); return retstr; } void FSetWarpLocation::operator() (LPCHARACTER ch) { if (ch->IsPC()) { ch->SetWarpLocation (map_index, x, y); } } void FSetQuestFlag::operator() (LPCHARACTER ch) { if (!ch->IsPC()) return; PC * pPC = CQuestManager::instance().GetPCForce(ch->GetPlayerID()); if (pPC) pPC->SetFlag(flagname, value); } bool FPartyCheckFlagLt::operator() (LPCHARACTER ch) { if (!ch->IsPC()) return false; PC * pPC = CQuestManager::instance().GetPCForce(ch->GetPlayerID()); bool returnBool; if (pPC) { int flagValue = pPC->GetFlag(flagname); if (value > flagValue) returnBool = true; else returnBool = false; } return returnBool; } FPartyChat::FPartyChat(int ChatType, const char* str) : iChatType(ChatType), str(str) { } void FPartyChat::operator() (LPCHARACTER ch) { ch->ChatPacket(iChatType, "%s", str); } void FPartyClearReady::operator() (LPCHARACTER ch) { ch->RemoveAffect(AFFECT_DUNGEON_READY); } void FSendPacket::operator() (LPENTITY ent) { if (ent->IsType(ENTITY_CHARACTER)) { LPCHARACTER ch = (LPCHARACTER) ent; if (ch->GetDesc()) { ch->GetDesc()->Packet(buf.read_peek(), buf.size()); } } } void FSendPacketToEmpire::operator() (LPENTITY ent) { if (ent->IsType(ENTITY_CHARACTER)) { LPCHARACTER ch = (LPCHARACTER) ent; if (ch->GetDesc()) { if (ch->GetEmpire() == bEmpire) ch->GetDesc()->Packet(buf.read_peek(), buf.size()); } } } void FWarpEmpire::operator() (LPENTITY ent) { if (ent->IsType(ENTITY_CHARACTER)) { LPCHARACTER ch = (LPCHARACTER) ent; if (ch->IsPC() && ch->GetEmpire() == m_bEmpire) { ch->WarpSet(m_x, m_y, m_lMapIndexTo); } } } FBuildLuaGuildWarList::FBuildLuaGuildWarList(lua_State * lua_state) : L(lua_state), m_count(1) { lua_newtable(lua_state); } void FBuildLuaGuildWarList::operator() (DWORD g1, DWORD g2) { CGuild* g = CGuildManager::instance().FindGuild(g1); if (!g) return; if (g->GetGuildWarType(g2) == GUILD_WAR_TYPE_FIELD) return; if (g->GetGuildWarState(g2) != GUILD_WAR_ON_WAR) return; lua_newtable(L); lua_pushnumber(L, g1); lua_rawseti(L, -2, 1); lua_pushnumber(L, g2); lua_rawseti(L, -2, 2); lua_rawseti(L, -2, m_count++); } bool IsScriptTrue(const char* code, int size) { if (size==0) return true; lua_State* L = CQuestManager::instance().GetLuaState(); int x = lua_gettop(L); int errcode = lua_dobuffer(L, code, size, "IsScriptTrue"); int bStart = lua_toboolean(L, -1); if (errcode) { char buf[100]; snprintf(buf, sizeof(buf), "LUA ScriptRunError (code:%%d src:[%%%ds])", size); sys_err(buf, errcode, code); } lua_settop(L,x); return bStart != 0; } void combine_lua_string(lua_State * L, ostringstream & s) { char buf[32]; int n = lua_gettop(L); int i; for (i = 1; i <= n; ++i) { if (lua_isstring(L,i)) //printf("%s\n",lua_tostring(L,i)); s << lua_tostring(L, i); else if (lua_isnumber(L, i)) { snprintf(buf, sizeof(buf), "%.14g\n", lua_tonumber(L,i)); s << buf; } } } int highscore_show(lua_State* L) { CQuestManager & q = CQuestManager::instance(); const char * pszBoardName = lua_tostring(L, 1); DWORD mypid = q.GetCurrentCharacterPtr()->GetPlayerID(); bool bOrder = (int) lua_tonumber(L, 2) != 0 ? true : false; DBManager::instance().ReturnQuery(QID_HIGHSCORE_SHOW, mypid, NULL, "SELECT h.pid, p.name, h.value FROM highscore%s as h, player%s as p WHERE h.board = '%s' AND h.pid = p.id ORDER BY h.value %s LIMIT 10", get_table_postfix(), get_table_postfix(), pszBoardName, bOrder ? "DESC" : ""); return 0; } int highscore_register(lua_State* L) { CQuestManager & q = CQuestManager::instance(); THighscoreRegisterQueryInfo * qi = M2_NEW THighscoreRegisterQueryInfo; strncpy(qi->szBoard, lua_tostring(L, 1), sizeof(qi->szBoard)); qi->dwPID = q.GetCurrentCharacterPtr()->GetPlayerID(); qi->iValue = (int) lua_tonumber(L, 2); qi->bOrder = (int) lua_tonumber(L, 3); DBManager::instance().ReturnQuery(QID_HIGHSCORE_REGISTER, qi->dwPID, qi, "SELECT value FROM highscore%s WHERE board='%s' AND pid=%u", get_table_postfix(), qi->szBoard, qi->dwPID); return 1; } // // "member" Lua functions // int member_chat(lua_State* L) { ostringstream s; combine_lua_string(L, s); CQuestManager::Instance().GetCurrentPartyMember()->ChatPacket(CHAT_TYPE_TALKING, "%s", s.str().c_str()); return 0; } int member_clear_ready(lua_State* L) { LPCHARACTER ch = CQuestManager::instance().GetCurrentPartyMember(); ch->RemoveAffect(AFFECT_DUNGEON_READY); return 0; } int member_set_ready(lua_State* L) { LPCHARACTER ch = CQuestManager::instance().GetCurrentPartyMember(); ch->AddAffect(AFFECT_DUNGEON_READY, POINT_NONE, 0, AFF_DUNGEON_READY, 65535, 0, true); return 0; } int mob_spawn(lua_State* L) { if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4)) { sys_err("invalid argument"); return 0; } DWORD mob_vnum = (DWORD)lua_tonumber(L, 1); int local_x = (int) lua_tonumber(L, 2)*100; int local_y = (int) lua_tonumber(L, 3)*100; float radius = (float) lua_tonumber(L, 4)*100; bool bAggressive = lua_toboolean(L, 5); DWORD count = (lua_isnumber(L, 6))?(DWORD) lua_tonumber(L, 6):1; if (count == 0) count = 1; else if (count > 10) { sys_err("count bigger than 10"); count = 10; } LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(ch->GetMapIndex()); if (pMap == NULL) { return 0; } DWORD dwQuestIdx = CQuestManager::instance().GetCurrentPC()->GetCurrentQuestIndex(); bool ret = false; LPCHARACTER mob = NULL; while (count--) { for (int loop = 0; loop < 8; ++loop) { float angle = number(0, 999) * M_PI * 2 / 1000; float r = number(0, 999) * radius / 1000; int x = local_x + pMap->m_setting.iBaseX + (int)(r * cos(angle)); int y = local_y + pMap->m_setting.iBaseY + (int)(r * sin(angle)); mob = CHARACTER_MANAGER::instance().SpawnMob(mob_vnum, ch->GetMapIndex(), x, y, 0); if (mob) break; } if (mob) { if (bAggressive) mob->SetAggressive(); mob->SetQuestBy(dwQuestIdx); if (!ret) { ret = true; lua_pushnumber(L, (DWORD) mob->GetVID()); } } } if (!ret) lua_pushnumber(L, 0); return 1; } int mob_spawn_group(lua_State* L) { if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4) || !lua_isnumber(L, 6)) { sys_err("invalid argument"); lua_pushnumber(L, 0); return 1; } DWORD group_vnum = (DWORD)lua_tonumber(L, 1); int local_x = (int) lua_tonumber(L, 2) * 100; int local_y = (int) lua_tonumber(L, 3) * 100; float radius = (float) lua_tonumber(L, 4) * 100; bool bAggressive = lua_toboolean(L, 5); DWORD count = (DWORD) lua_tonumber(L, 6); if (count == 0) count = 1; else if (count > 10) { sys_err("count bigger than 10"); count = 10; } LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(ch->GetMapIndex()); if (pMap == NULL) { lua_pushnumber(L, 0); return 1; } DWORD dwQuestIdx = CQuestManager::instance().GetCurrentPC()->GetCurrentQuestIndex(); bool ret = false; LPCHARACTER mob = NULL; while (count--) { for (int loop = 0; loop < 8; ++loop) { float angle = number(0, 999) * M_PI * 2 / 1000; float r = number(0, 999)*radius/1000; int x = local_x + pMap->m_setting.iBaseX + (int)(r * cos(angle)); int y = local_y + pMap->m_setting.iBaseY + (int)(r * sin(angle)); mob = CHARACTER_MANAGER::instance().SpawnGroup(group_vnum, ch->GetMapIndex(), x, y, x, y, NULL, bAggressive); if (mob) break; } if (mob) { mob->SetQuestBy(dwQuestIdx); if (!ret) { ret = true; lua_pushnumber(L, (DWORD) mob->GetVID()); } } } if (!ret) lua_pushnumber(L, 0); return 1; } // // global Lua functions // // // Registers Lua function table // void CQuestManager::AddLuaFunctionTable(const char * c_pszName, luaL_reg * preg) { lua_newtable(L); while ((preg->name)) { lua_pushstring(L, preg->name); lua_pushcfunction(L, preg->func); lua_rawset(L, -3); preg++; } lua_setglobal(L, c_pszName); } void CQuestManager::BuildStateIndexToName(const char* questName) { int x = lua_gettop(L); lua_getglobal(L, questName); if (lua_isnil(L,-1)) { sys_err("QUEST wrong quest state file for quest %s",questName); lua_settop(L,x); return; } for (lua_pushnil(L); lua_next(L, -2);) { if (lua_isstring(L, -2) && lua_isnumber(L, -1)) { lua_pushvalue(L, -2); lua_rawset(L, -4); } else { lua_pop(L, 1); } } lua_settop(L, x); } /** * @version 05/06/08 Bang2ni - __get_guildid_byname ½ºÅ©¸³Æ® ÇÔ¼ö µî·Ï */ bool CQuestManager::InitializeLua() { L = lua_open(); luaopen_base(L); luaopen_table(L); luaopen_string(L); luaopen_math(L); //TEMP luaopen_io(L); luaopen_debug(L); RegisterAffectFunctionTable(); RegisterBuildingFunctionTable(); RegisterDungeonFunctionTable(); RegisterGameFunctionTable(); RegisterGuildFunctionTable(); RegisterHorseFunctionTable(); #ifdef __PET_SYSTEM__ RegisterPetFunctionTable(); #endif RegisterITEMFunctionTable(); RegisterMarriageFunctionTable(); RegisterNPCFunctionTable(); RegisterPartyFunctionTable(); RegisterPCFunctionTable(); RegisterQuestFunctionTable(); RegisterTargetFunctionTable(); RegisterArenaFunctionTable(); RegisterForkedFunctionTable(); RegisterMonarchFunctionTable(); RegisterOXEventFunctionTable(); RegisterMgmtFunctionTable(); RegisterBattleArenaFunctionTable(); RegisterDanceEventFunctionTable(); RegisterDragonLairFunctionTable(); RegisterSpeedServerFunctionTable(); RegisterDragonSoulFunctionTable(); { luaL_reg member_functions[] = { { "chat", member_chat }, { "set_ready", member_set_ready }, { "clear_ready", member_clear_ready }, { NULL, NULL } }; AddLuaFunctionTable("member", member_functions); } { luaL_reg highscore_functions[] = { { "register", highscore_register }, { "show", highscore_show }, { NULL, NULL } }; AddLuaFunctionTable("highscore", highscore_functions); } { luaL_reg mob_functions[] = { { "spawn", mob_spawn }, { "spawn_group", mob_spawn_group }, { NULL, NULL } }; AddLuaFunctionTable("mob", mob_functions); } // // global namespace functions // RegisterGlobalFunctionTable(L); // LUA_INIT_ERROR_MESSAGE { char settingsFileName[256]; snprintf(settingsFileName, sizeof(settingsFileName), "%s/settings.lua", LocaleService_GetBasePath().c_str()); int settingsLoadingResult = lua_dofile(L, settingsFileName); sys_log(0, "LoadSettings(%s), returns %d", settingsFileName, settingsLoadingResult); if (settingsLoadingResult != 0) { sys_err("LOAD_SETTINS_FAILURE(%s)", settingsFileName); return false; } } { char questlibFileName[256]; snprintf(questlibFileName, sizeof(questlibFileName), "%s/questlib.lua", LocaleService_GetQuestPath().c_str()); int questlibLoadingResult = lua_dofile(L, questlibFileName); sys_log(0, "LoadQuestlib(%s), returns %d", questlibFileName, questlibLoadingResult); if (questlibLoadingResult != 0) { sys_err("LOAD_QUESTLIB_FAILURE(%s)", questlibFileName); return false; } } if (LC_IsEurope()) { char translateFileName[256]; snprintf(translateFileName, sizeof(translateFileName), "%s/translate.lua", LocaleService_GetBasePath().c_str()); int translateLoadingResult = lua_dofile(L, translateFileName); sys_log(0, "LoadTranslate(%s), returns %d", translateFileName, translateLoadingResult); if (translateLoadingResult != 0) { sys_err("LOAD_TRANSLATE_ERROR(%s)", translateFileName); return false; } } { char questLocaleFileName[256]; if (LC_IsEurope()) { snprintf(questLocaleFileName, sizeof(questLocaleFileName), "%s/locale.lua", g_stQuestDir.c_str()); } else { snprintf(questLocaleFileName, sizeof(questLocaleFileName), "%s/locale_%s.lua", g_stQuestDir.c_str(), g_stLocale.c_str()); } int questLocaleLoadingResult = lua_dofile(L, questLocaleFileName); sys_log(0, "LoadQuestLocale(%s), returns %d", questLocaleFileName, questLocaleLoadingResult); if (questLocaleLoadingResult != 0) { sys_err("LoadQuestLocale(%s) FAILURE", questLocaleFileName); return false; } } // END_OF_LUA_INIT_ERROR_MESSAGE for (itertype(g_setQuestObjectDir) it = g_setQuestObjectDir.begin(); it != g_setQuestObjectDir.end(); ++it) { const string& stQuestObjectDir = *it; char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "%s/state/", stQuestObjectDir.c_str()); DIR * pdir = opendir(buf); int iQuestIdx = 0; if (pdir) { dirent * pde; while ((pde = readdir(pdir))) { if (pde->d_name[0] == '.') continue; snprintf(buf + 11, sizeof(buf) - 11, "%s", pde->d_name); RegisterQuest(pde->d_name, ++iQuestIdx); int ret = lua_dofile(L, (stQuestObjectDir + "/state/" + pde->d_name).c_str()); sys_log(0, "QUEST: loading %s, returns %d", (stQuestObjectDir + "/state/" + pde->d_name).c_str(), ret); BuildStateIndexToName(pde->d_name); } closedir(pdir); } } lua_setgcthreshold(L, 0); lua_newtable(L); lua_setglobal(L, "__codecache"); return true; } void CQuestManager::GotoSelectState(QuestState& qs) { lua_checkstack(qs.co, 1); //int n = lua_gettop(L); int n = luaL_getn(qs.co, -1); qs.args = n; //cout << "select here (1-" << qs.args << ")" << endl; // ostringstream os; os << "[QUESTION "; for (int i=1; i<=n; i++) { lua_rawgeti(qs.co,-1,i); if (lua_isstring(qs.co,-1)) { //printf("%d\t%s\n",i,lua_tostring(qs.co,-1)); if (i != 1) os << "|"; os << i << ";" << lua_tostring(qs.co,-1); } else { sys_err("SELECT wrong data %s", lua_typename(qs.co, -1)); sys_err("here"); } lua_pop(qs.co,1); } os << "]"; AddScript(os.str()); qs.suspend_state = SUSPEND_STATE_SELECT; if ( test_server ) sys_log( 0, "%s", m_strScript.c_str() ); SendScript(); } EVENTINFO(confirm_timeout_event_info) { DWORD dwWaitPID; DWORD dwReplyPID; confirm_timeout_event_info() : dwWaitPID( 0 ) , dwReplyPID( 0 ) { } }; EVENTFUNC(confirm_timeout_event) { confirm_timeout_event_info * info = dynamic_cast(event->info); if ( info == NULL ) { sys_err( "confirm_timeout_event> Null pointer" ); return 0; } LPCHARACTER chWait = CHARACTER_MANAGER::instance().FindByPID(info->dwWaitPID); LPCHARACTER chReply = NULL; //CHARACTER_MANAGER::info().FindByPID(info->dwReplyPID); if (chReply) { // ½Ã°£ Áö³ª¸é ¾Ë¾Æ¼­ ´ÝÈû } if (chWait) { CQuestManager::instance().Confirm(info->dwWaitPID, CONFIRM_TIMEOUT); } return 0; } void CQuestManager::GotoConfirmState(QuestState & qs) { qs.suspend_state = SUSPEND_STATE_CONFIRM; DWORD dwVID = (DWORD) lua_tonumber(qs.co, -3); const char* szMsg = lua_tostring(qs.co, -2); int iTimeout = (int) lua_tonumber(qs.co, -1); sys_log(0, "GotoConfirmState vid %u msg '%s', timeout %d", dwVID, szMsg, iTimeout); // 1. »ó´ë¹æ¿¡°Ô È®ÀÎâ ¶ç¿ò // 2. ³ª¿¡°Ô È®ÀÎ ±â´Ù¸°´Ù°í Ç¥½ÃÇϴ â ¶ç¿ò // 3. ŸÀӾƿô ¼³Á¤ (ŸÀӾƿô µÇ¸é »ó´ë¹æ â ´Ý°í ³ª¿¡°Ôµµ â ´ÝÀ¸¶ó°í º¸³¿) // 1 // »ó´ë¹æÀÌ ¾ø´Â °æ¿ì´Â ±×³É »ó´ë¹æ¿¡°Ô º¸³»Áö ¾Ê´Â´Ù. ŸÀӾƿô¿¡ ÀÇÇؼ­ ³Ñ¾î°¡°ÔµÊ LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(dwVID); if (ch && ch->IsPC()) { ch->ConfirmWithMsg(szMsg, iTimeout, GetCurrentCharacterPtr()->GetPlayerID()); } // 2 GetCurrentPC()->SetConfirmWait((ch && ch->IsPC())?ch->GetPlayerID():0); ostringstream os; os << "[CONFIRM_WAIT timeout;" << iTimeout << "]"; AddScript(os.str()); SendScript(); // 3 confirm_timeout_event_info* info = AllocEventInfo(); info->dwWaitPID = GetCurrentCharacterPtr()->GetPlayerID(); info->dwReplyPID = (ch && ch->IsPC()) ? ch->GetPlayerID() : 0; event_create(confirm_timeout_event, info, PASSES_PER_SEC(iTimeout)); } void CQuestManager::GotoSelectItemState(QuestState& qs) { qs.suspend_state = SUSPEND_STATE_SELECT_ITEM; AddScript("[SELECT_ITEM]"); SendScript(); } void CQuestManager::GotoInputState(QuestState & qs) { qs.suspend_state = SUSPEND_STATE_INPUT; AddScript("[INPUT]"); SendScript(); // ½Ã°£ Á¦ÇÑÀ» °Ë //event_create(input_timeout_event, dwEI, PASSES_PER_SEC(iTimeout)); } void CQuestManager::GotoPauseState(QuestState & qs) { qs.suspend_state = SUSPEND_STATE_PAUSE; AddScript("[NEXT]"); SendScript(); } void CQuestManager::GotoEndState(QuestState & qs) { AddScript("[DONE]"); SendScript(); } // // * OpenState // // The beginning of script // QuestState CQuestManager::OpenState(const string& quest_name, int state_index) { QuestState qs; qs.args=0; qs.st = state_index; qs.co = lua_newthread(L); qs.ico = lua_ref(L, 1/*qs.co*/); return qs; } // // * RunState // // decides script to wait for user input, or finish // bool CQuestManager::RunState(QuestState & qs) { ClearError(); m_CurrentRunningState = &qs; int ret = lua_resume(qs.co, qs.args); if (ret == 0) { if (lua_gettop(qs.co) == 0) { // end of quest GotoEndState(qs); return false; } if (!strcmp(lua_tostring(qs.co, 1), "select")) { GotoSelectState(qs); return true; } if (!strcmp(lua_tostring(qs.co, 1), "wait")) { GotoPauseState(qs); return true; } if (!strcmp(lua_tostring(qs.co, 1), "input")) { GotoInputState(qs); return true; } if (!strcmp(lua_tostring(qs.co, 1), "confirm")) { GotoConfirmState(qs); return true; } if (!strcmp(lua_tostring(qs.co, 1), "select_item")) { GotoSelectItemState(qs); return true; } } else { sys_err("LUA_ERROR: %s", lua_tostring(qs.co, 1)); } WriteRunningStateToSyserr(); SetError(); GotoEndState(qs); return false; } // // * CloseState // // makes script end // void CQuestManager::CloseState(QuestState& qs) { if (qs.co) { //cerr << "ICO "<